UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

423 lines (422 loc) 15.2 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const BlockRenderType_1 = require("./BlockRenderType"); const MinecraftUtilities_1 = __importDefault(require("./MinecraftUtilities")); const Database_1 = __importDefault(require("./Database")); const Utilities_1 = __importDefault(require("../core/Utilities")); const ste_events_1 = require("ste-events"); const Log_1 = __importDefault(require("../core/Log")); const ManagedComponent_1 = require("./ManagedComponent"); const StorageUtilities_1 = __importDefault(require("../storage/StorageUtilities")); class BlockType { data; javaData; _baseType; _baseTypeId = ""; _isCustom = false; _behaviorPackData = null; _behaviorPackFile; _blockResource; _isLoaded = false; _loadedWithComments = false; _properties = {}; behaviorPackBlockTypeDef; _managed = {}; _onLoaded = new ste_events_1.EventDispatcher(); _onComponentAdded = new ste_events_1.EventDispatcher(); _onComponentRemoved = new ste_events_1.EventDispatcher(); _onComponentChanged = new ste_events_1.EventDispatcher(); get numericId() { return this.data.lid; } set numericId(newId) { this.data.lid = newId; } get baseTypeId() { return this._baseTypeId; } get mapColor() { // First check if this specific block type has a map color if (this.data.mc) { return this.data.mc; } // Fall back to the base type's map color from mccat.json if (this._baseType && this._baseType.mapColor) { return this._baseType.mapColor; } // Check the default base type const defaultBaseType = Database_1.default.defaultBlockBaseType; if (defaultBaseType && defaultBaseType.mapColor) { return defaultBaseType.mapColor; } return undefined; } get isCustom() { return this._isCustom; } get baseType() { if (this._baseType !== undefined) { return this._baseType; } return Database_1.default.defaultBlockBaseType; } get catalogResource() { if (this._blockResource) { return this._blockResource; } if (Database_1.default.blocksCatalog) { // First try with shortId (full block name like "acacia_button") let lookupId = this.shortId; if (lookupId) { this._blockResource = Database_1.default.blocksCatalog.getCatalogResource(lookupId); } // Fall back to material if shortId lookup fails if (!this._blockResource) { let mat = this.material; if (mat && mat !== lookupId) { this._blockResource = Database_1.default.blocksCatalog.getCatalogResource(mat); } } } return this._blockResource; } set baseType(baseType) { this._baseType = baseType; this._baseTypeId = baseType.name; } get material() { if (this.data.m) { return this.data.m; } return this.data.n; } renderType = BlockRenderType_1.BlockRenderType.Custom; get icon() { let val = this.data.ic; if (val === undefined && this.baseType !== undefined) { val = this.baseType.icon; } return val; } get title() { let id = this.shortId; // For custom blocks, strip the namespace prefix (e.g., "ec_vv:bushy_cherry" -> "bushy_cherry") const colonIndex = id.indexOf(":"); if (colonIndex >= 0) { id = id.substring(colonIndex + 1); } return Utilities_1.default.humanifyMinecraftName(id); } get friendlyName() { // First check if the base type has a friendly name from mccat.json if (this._baseType && this._baseType.friendlyName) { return this._baseType.friendlyName; } // Fall back to humanified shortId return this.title; } constructor(typeId) { this.javaData = null; this.data = { n: typeId, }; if (typeId.indexOf(":") >= 0 && !typeId.startsWith("minecraft:")) { this._isCustom = true; } } getIcon() { const icon = this.icon; if (icon === undefined) { return this.shortId; } const typeName = MinecraftUtilities_1.default.canonicalizeName(this.id); const lastUnder = typeName.lastIndexOf("_"); let allButLast = typeName; if (lastUnder >= 0) { allButLast = allButLast.substring(0, lastUnder); } switch (icon) { case "st_": return "stone_" + allButLast; case "le_": return "leaves_acacia_carried"; case "pl_": return "planks_" + allButLast; case "_car": return allButLast + "_carried"; case "plant_": return typeName + "_fern_carried"; case "_": return typeName; case "_t": return allButLast + "_top"; case "_br": return allButLast + "_bricks"; case "_carr": return typeName + "_carried"; case "_bl": return allButLast + "_block"; case "_n": return allButLast + "_normal"; case "_blt": return allButLast + "_block_top"; case "mshblk": const lastmb = allButLast.split("_"); return "mushroom_block_skin_" + lastmb[0]; case "ml_sm": const lastml = allButLast.split("_"); return lastml[lastml.length - 2] + "_" + lastml[lastml.length - 1] + "_smooth"; case "l_blt": const lastbt = allButLast.split("_"); return lastbt[lastbt.length - 1] + "_block_top"; case "|": return allButLast; case "|s": return allButLast + "s"; case "l": const last = allButLast.split("_"); return last[last.length - 1]; case "sb_": const fu = allButLast.split("_"); return "stonebricks_" + fu[0]; case "st_l_sm": const lasta = allButLast.split("_"); return "stone_" + lasta[lasta.length - 1] + "_smooth"; case "|rv": // dark_prismarine_stairs => prismarine_dark_stairs let result = ""; const rv = allButLast.split("_"); for (let i = rv.length - 1; i > 0; i--) { if (result.length > 0) { result += "_"; } result += rv[i]; } return result; case "2rv": // yellow_glazed_terracotta => glazed_terracotta_yellow // dark_blue_glazed_terracotta => glazed_terracotta_dark_blue let resultF = ""; const rvF = typeName.split("_"); if (rvF.length >= 2) { resultF = rvF[rvF.length - 2] + "_" + rvF[rvF.length - 1]; for (let i = 0; i < rvF.length - 2; i++) { resultF += "_" + rvF[i]; } } else { resultF = typeName; } return resultF; case "rv": // dark_prismarine => prismarine_dark let resultA = ""; const rvA = typeName.split("_"); for (let i = rvA.length - 1; i >= 0; i--) { if (resultA.length > 0) { resultA += "_"; } resultA += rvA[i]; } return resultA; } if (this.icon !== undefined) { return this.icon; } return this.shortId; } get id() { if (this.behaviorPackBlockTypeDef && this.behaviorPackBlockTypeDef.description) { return this.behaviorPackBlockTypeDef.description.identifier; } if (this.data.n === undefined) { return ""; } if (this.data.n.endsWith("_")) { return this.data.n + this.baseTypeId; } return this.data.n; } set id(newId) { this.data.n = newId; if (this.behaviorPackBlockTypeDef && this.behaviorPackBlockTypeDef.description && newId) { this.behaviorPackBlockTypeDef.description.identifier = newId; } } get onComponentAdded() { return this._onComponentAdded.asEvent(); } get onComponentRemoved() { return this._onComponentRemoved.asEvent(); } get onComponentChanged() { return this._onComponentChanged.asEvent(); } get isLoaded() { return this._isLoaded; } get behaviorPackFile() { return this._behaviorPackFile; } get onLoaded() { return this._onLoaded.asEvent(); } set behaviorPackFile(newFile) { this._behaviorPackFile = newFile; } get shortId() { let id = this.id; if (id.startsWith("minecraft:")) { return id.substring(10, id.length); } return id; } getComponent(id) { if (this.behaviorPackBlockTypeDef === undefined) { return undefined; } if (!Utilities_1.default.isUsableAsObjectKey(id)) { Log_1.default.unsupportedToken(id); throw new Error(); } if (!this._managed[id]) { const comp = this.behaviorPackBlockTypeDef.components[id]; if (comp) { this._managed[id] = new ManagedComponent_1.ManagedComponent(this.behaviorPackBlockTypeDef.components, id, comp); } } return this._managed[id]; } notifyComponentUpdated(id) { const component = this.getComponent(id); if (component === undefined) { Log_1.default.unexpectedUndefined("BTNCU"); } else { this._onComponentChanged.dispatch(this, component); } } getAllComponents() { return this.getComponents(); } getComponents() { const componentSet = []; if (this.behaviorPackBlockTypeDef !== undefined) { for (const componentName in this.behaviorPackBlockTypeDef.components) { const component = this.getComponent(componentName); if (component !== undefined) { componentSet.push(component); } } } return componentSet; } ensurePropertyDefinition(propertyName, propertyDef) { if (!this._properties[propertyName]) { this._properties[propertyName] = propertyDef; } } addComponent(id, componentOrData) { this._ensureBehaviorPackDataInitialized(); const bpData = this.behaviorPackBlockTypeDef; const mc = componentOrData instanceof ManagedComponent_1.ManagedComponent ? componentOrData : new ManagedComponent_1.ManagedComponent(bpData.components, id, componentOrData); bpData.components[id] = mc.getData(); this._managed[id] = mc; this._onComponentAdded.dispatch(this, mc); return mc; } removeComponent(id) { if (this.behaviorPackBlockTypeDef === undefined) { return; } const newBehaviorPacks = {}; const newComponents = {}; for (const name in this.behaviorPackBlockTypeDef.components) { if (name !== id) { const component = this.behaviorPackBlockTypeDef.components[name]; newBehaviorPacks[name] = component; } } for (const name in this._managed) { if (name !== id) { newComponents[name] = this._managed[name]; } } this.behaviorPackBlockTypeDef.components = newBehaviorPacks; this._managed = newComponents; } _ensureBehaviorPackDataInitialized() { if (this.behaviorPackBlockTypeDef === undefined) { this.behaviorPackBlockTypeDef = { description: { identifier: "unknown", }, components: {}, events: {}, }; } } persist() { if (this._behaviorPackFile === undefined) { return false; } Log_1.default.assert(this._behaviorPackData !== null, "BTP"); if (!this._behaviorPackData) { return false; } return this._behaviorPackFile.setObjectContentIfSemanticallyDifferent(this._behaviorPackData); } /** * Loads the definition from the file. * @param preserveComments If true, uses comment-preserving JSON parsing for edit/save cycles. * If false (default), uses efficient standard JSON parsing. * Can be called again with true to "upgrade" a read-only load to read/write. */ async load(preserveComments = false) { // If already loaded with comments, we have the "best" version - nothing more to do if (this._isLoaded && this._loadedWithComments) { return; } // If already loaded without comments and caller doesn't need comments, we're done if (this._isLoaded && !preserveComments) { return; } if (this._behaviorPackFile === undefined) { return; } if (!this._behaviorPackFile.isContentLoaded) { await this._behaviorPackFile.loadContent(); } if (!this._behaviorPackFile.content || this._behaviorPackFile.content instanceof Uint8Array) { this._isLoaded = true; this._loadedWithComments = preserveComments; this._onLoaded.dispatch(this, this); return; } let data = {}; // Use comment-preserving parser only when needed for editing let result = preserveComments ? StorageUtilities_1.default.getJsonObjectWithComments(this._behaviorPackFile) : StorageUtilities_1.default.getJsonObject(this._behaviorPackFile); if (result) { data = result; } this._behaviorPackData = data; const block = data["minecraft:block"]; if (block.description) { this.id = block.description.identifier; } this.behaviorPackBlockTypeDef = block; this._isLoaded = true; this._loadedWithComments = preserveComments; this._onLoaded.dispatch(this, this); } } exports.default = BlockType;