UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

320 lines (319 loc) 11.4 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 ste_events_1 = require("ste-events"); const StorageUtilities_1 = __importDefault(require("../storage/StorageUtilities")); const Database_1 = __importDefault(require("./Database")); const MinecraftUtilities_1 = __importDefault(require("./MinecraftUtilities")); const Log_1 = __importDefault(require("../core/Log")); class ModelGeometryDefinition { _file; _isLoaded = false; _loadedWithComments = false; _data; definitions = []; _identifiers = []; _onLoaded = new ste_events_1.EventDispatcher(); get data() { return this._data; } get formatVersion() { return this._data?.format_version; } get isLoaded() { return this._isLoaded; } get defaultGeometry() { if (this.definitions && this.definitions.length > 0) { return this.definitions[0]; } return undefined; } get file() { return this._file; } set file(newFile) { this._file = newFile; } get onLoaded() { return this._onLoaded.asEvent(); } get identifiers() { if (this._identifiers) { return this._identifiers; } if (!this._data || !this._data["minecraft:geometry"] || this._data["minecraft:geometry"].length !== 1 || !this._data["minecraft:geometry"][0].description) { return []; } const ids = []; for (const def of this.definitions) { if (def.description && def.description.identifier) { ids.push(def.description.identifier); } } return ids; } getById(id) { Log_1.default.assert(id !== "minecraft:geometry"); let model = this._data[id]; if (model) { return model; } // Check for v1 format keys with inheritance syntax (e.g., "geometry.sheep.v1.8:geometry.sheep.sheared.v1.8") // When looking for "geometry.sheep.v1.8", check if any key starts with that ID followed by ":" for (const key of Object.keys(this._data || {})) { if (key.startsWith(id + ":")) { return this._data[key]; } } for (const def of this.definitions) { if (def.description && def.description.identifier === id) { return def; } } return undefined; } getVisibleBoundsWidth(defIndex) { if (defIndex < 0 || defIndex >= this.definitions.length) { return; } if (!this.definitions[defIndex]) { return undefined; } if (this.definitions[defIndex].description) { return this.definitions[defIndex].description.visible_bounds_width; } return this.definitions[defIndex].visible_bounds_width; } getVisibleBoundsHeight(defIndex) { if (defIndex < 0 || defIndex >= this.definitions.length) { return; } if (!this.definitions[defIndex]) { return undefined; } if (this.definitions[defIndex].description) { return this.definitions[defIndex].description.visible_bounds_height; } return this.definitions[defIndex].visible_bounds_height; } getVisibleBoundsOffset(defIndex) { if (defIndex < 0 || defIndex >= this.definitions.length) { return; } if (!this.definitions[defIndex]) { return undefined; } if (this.definitions[defIndex].description) { return this.definitions[defIndex].description.visible_bounds_offset; } return this.definitions[defIndex].visible_bounds_offset; } getTextureWidth(defIndex) { if (defIndex < 0 || defIndex >= this.definitions.length) { return; } if (!this.definitions[defIndex]) { return undefined; } if (this.definitions[defIndex].description) { return this.definitions[defIndex].description.texture_width; } return this.definitions[defIndex].texturewidth; } ensureDefault(id) { if (!this._data) { this._data = { format_version: "1.12.0", "minecraft:geometry": [ { description: { identifier: id, texture_width: 128, texture_height: 64, visible_bounds_width: 4, visible_bounds_height: 3.5, visible_bounds_offset: [0, 1.25, 0], }, bones: [], }, ], }; this.persist(); this.populateDefsAndIds(); this._isLoaded = true; } } getTextureHeight(defIndex) { if (defIndex < 0 || defIndex >= this.definitions.length) { return; } if (!this.definitions[defIndex]) { return undefined; } if (this.definitions[defIndex].description) { return this.definitions[defIndex].description.texture_height; } return this.definitions[defIndex].textureheight; } static async ensureOnFile(file, loadHandler) { let rc; if (file.manager === undefined) { rc = new ModelGeometryDefinition(); rc.file = file; file.manager = rc; } if (file.manager !== undefined && file.manager instanceof ModelGeometryDefinition) { rc = file.manager; if (!rc.isLoaded) { if (loadHandler) { rc.onLoaded.subscribe(loadHandler); } await rc.load(); } } return rc; } async getFormatVersionIsCurrent() { const fv = this.getFormatVersion(); if (fv === undefined || fv.length !== 3) { return false; } return await Database_1.default.isRecentVersionFromVersionArray(fv); } getFormatVersion() { if (!this._data || !this._data.format_version) { return [0, 0, 0]; } return MinecraftUtilities_1.default.getVersionArrayFrom(this._data.format_version); } persist() { if (this._file === undefined) { return false; } if (!this._data) { Log_1.default.unexpectedUndefined("MGDP"); return false; } return this._file.setObjectContentIfSemanticallyDifferent(this._data); } ensureDefinition(name) { if (!this._data) { this._data = { format_version: "1.12.0", "minecraft:geometry": [ { description: { identifier: name, texture_width: 32, texture_height: 32, visible_bounds_width: 2, visible_bounds_height: 2, visible_bounds_offset: [0, 0, 0], }, bones: [], }, ], }; } } async save() { if (this._file === undefined) { return; } if (this.persist()) { await this._file.saveContent(false); } } populateDefsAndIds() { this.definitions = []; this._identifiers = []; if (this._data && this._data["minecraft:geometry"]) { for (const def of this._data["minecraft:geometry"]) { if (def.description && def.description.identifier) { this._identifiers.push(def.description.identifier); } this.definitions.push(def); } } else if (this._data) { // look for 1.8.0 style geometries: // { // "format_version": ... // "geometry.foobar": {} // } for (const elt in this._data) { if (elt !== "format_version" && elt.startsWith("geometry.") && this._data[elt]) { this._identifiers.push(elt); this.definitions.push(this._data[elt]); } } } } /** * Load geometry data from a raw JavaScript object (parsed JSON). * Useful for loading geometry data without a file reference. * @param data The geometry JSON data object * @param geometryId Optional specific geometry identifier to select from multi-geometry files */ loadFromData(data, geometryId) { this._data = data; this.populateDefsAndIds(); this._isLoaded = true; // If a specific geometry ID is requested and there are multiple, reorder to make it default if (geometryId && this.definitions.length > 1) { const index = this._identifiers.indexOf(geometryId); if (index > 0) { // Move the requested geometry to the front const [geo] = this.definitions.splice(index, 1); const [id] = this._identifiers.splice(index, 1); this.definitions.unshift(geo); this._identifiers.unshift(id); } } this._onLoaded.dispatch(this, this); } /** * 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._file === undefined) { return; } if (!this._file.isContentLoaded) { await this._file.loadContent(); } if (this._file.content === null || this._file.content instanceof Uint8Array) { this._isLoaded = true; this._loadedWithComments = preserveComments; this._onLoaded.dispatch(this, this); return; } // Use comment-preserving parser only when needed for editing this._data = preserveComments ? StorageUtilities_1.default.getJsonObjectWithComments(this._file) : StorageUtilities_1.default.getJsonObject(this._file); this.populateDefsAndIds(); this._isLoaded = true; this._loadedWithComments = preserveComments; } } exports.default = ModelGeometryDefinition;