@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
320 lines (319 loc) • 11.4 kB
JavaScript
"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;