UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

935 lines (934 loc) 37.6 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 }); exports.EntityPropertyType = exports.AttributeComponents = exports.EntityTypeComponentExtendedCategory = exports.EntityTypeComponentCategory = void 0; const Log_1 = __importDefault(require("../core/Log")); const ste_events_1 = require("ste-events"); const ScriptGen_1 = __importDefault(require("../script/ScriptGen")); const ManagedComponentGroup_1 = __importDefault(require("./ManagedComponentGroup")); const ManagedComponent_1 = require("./ManagedComponent"); const StorageUtilities_1 = __importDefault(require("../storage/StorageUtilities")); const Database_1 = __importDefault(require("./Database")); const MinecraftUtilities_1 = __importDefault(require("./MinecraftUtilities")); const IProjectItemData_1 = require("../app/IProjectItemData"); const EntityTypeResourceDefinition_1 = __importDefault(require("./EntityTypeResourceDefinition")); const SpawnRulesBehaviorDefinition_1 = __importDefault(require("./SpawnRulesBehaviorDefinition")); const Utilities_1 = __importDefault(require("../core/Utilities")); var EntityTypeComponentCategory; (function (EntityTypeComponentCategory) { EntityTypeComponentCategory[EntityTypeComponentCategory["attribute"] = 0] = "attribute"; EntityTypeComponentCategory[EntityTypeComponentCategory["complex"] = 1] = "complex"; EntityTypeComponentCategory[EntityTypeComponentCategory["behavior"] = 2] = "behavior"; EntityTypeComponentCategory[EntityTypeComponentCategory["trigger"] = 3] = "trigger"; })(EntityTypeComponentCategory || (exports.EntityTypeComponentCategory = EntityTypeComponentCategory = {})); var EntityTypeComponentExtendedCategory; (function (EntityTypeComponentExtendedCategory) { EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["attribute"] = 0] = "attribute"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["complex"] = 1] = "complex"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["movementComplex"] = 2] = "movementComplex"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["combatAndHealthComplex"] = 3] = "combatAndHealthComplex"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["sensorComponents"] = 4] = "sensorComponents"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["trigger"] = 5] = "trigger"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["behavior"] = 6] = "behavior"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["movementBehavior"] = 7] = "movementBehavior"; EntityTypeComponentExtendedCategory[EntityTypeComponentExtendedCategory["mobSpecificBehavior"] = 8] = "mobSpecificBehavior"; })(EntityTypeComponentExtendedCategory || (exports.EntityTypeComponentExtendedCategory = EntityTypeComponentExtendedCategory = {})); exports.AttributeComponents = { "minecraft:body_rotation_blocked": "b", "minecraft:can_climb": "b", "minecraft:can_fly": "b", "minecraft:can_power_jump": "b", "minecraft:cannot_be_attacked": "b", "minecraft:color": "s", "minecraft:color2": "s", "minecraft:default_look_angle": "f", "minecraft:fire_immune": "b", "minecraft:floats_in_liquid": "b", "minecraft:flying_speed": "f", "minecraft:friction_modifier": "f", "minecraft:ground_offset": "f", "minecraft:ignore_cannot_be_attacked": "b", "minecraft:input_ground_controlled": "b", "minecraft:is_baby": "b", "minecraft:is_charged": "b", "minecraft:is_chested": "b", "minecraft:is_dyeable": "b", "minecraft:is_hidden_when_invisible": "b", "minecraft:is_ignited": "b", "minecraft:is_illager_captain": "b", "minecraft:is_pregnant": "b", "minecraft:is_saddled": "b", "minecraft:is_sheared": "b", "minecraft:is_stackable": "b", "minecraft:is_stunned": "b", "minecraft:is_tamed": "b", "minecraft:mark_variant": "i", "minecraft:movement_sound_distance_offset": "f", "minecraft:push_through": "f", "minecraft:renders_when_invisible": "b", "minecraft:scale": "f", "minecraft:skin_id": "i", "minecraft:sound_volume": "f", "minecraft:type_family": "family", "minecraft:variant": "i", "minecraft:walk_animation_speed": "f", "minecraft:wants_jockey": "b", }; var EntityPropertyType; (function (EntityPropertyType) { EntityPropertyType[EntityPropertyType["enum"] = 0] = "enum"; EntityPropertyType[EntityPropertyType["boolean"] = 1] = "boolean"; EntityPropertyType[EntityPropertyType["float"] = 2] = "float"; EntityPropertyType[EntityPropertyType["int"] = 3] = "int"; })(EntityPropertyType || (exports.EntityPropertyType = EntityPropertyType = {})); class EntityTypeDefinition { _wrapper; _file; _id; _isLoaded = false; _loadedWithComments = false; /** Set during persist() so the resulting onFileContentUpdated event doesn't wipe our already-current in-memory state. */ _isSelfPersisting = false; _managedComponents = {}; _data; _componentGroups = {}; _events = {}; _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 data() { return this._data; } get componentGroups() { return this._componentGroups; } static getFormIdFromComponentId(componentId) { return componentId.replace(/:/gi, "_").replace(/\./gi, "_"); } static getComponentCategory(id) { if (id.startsWith("minecraft:behavior")) { return EntityTypeComponentCategory.behavior; } else if (id.startsWith("minecraft:on_")) { return EntityTypeComponentCategory.trigger; } else if (exports.AttributeComponents[id] !== undefined) { return EntityTypeComponentCategory.attribute; } return EntityTypeComponentCategory.complex; } static getExtendedComponentCategory(id) { if (id.startsWith("minecraft:behavior.move") || id.startsWith("minecraft:behavior.jump") || id.startsWith("minecraft:behavior.go") || id.startsWith("minecraft:behavior.follow") || id.startsWith("minecraft:behavior.circle")) { return EntityTypeComponentExtendedCategory.movementBehavior; } else if (id.startsWith("minecraft:behavior.dragon") || id.startsWith("minecraft:behavior.enderman") || id.startsWith("minecraft:behavior.guardian") || id.startsWith("minecraft:behavior.ocelot") || id.startsWith("minecraft:behavior.silverfish") || id.startsWith("minecraft:behavior.skeleton") || id.startsWith("minecraft:behavior.slime") || id.startsWith("minecraft:behavior.squid") || id.startsWith("minecraft:behavior.vex") || id.startsWith("minecraft:behavior.wither")) { return EntityTypeComponentExtendedCategory.mobSpecificBehavior; } else if (id.startsWith("minecraft:behavior")) { return EntityTypeComponentExtendedCategory.behavior; } else if (id.startsWith("minecraft:on_")) { return EntityTypeComponentExtendedCategory.trigger; } else if (exports.AttributeComponents[id] !== undefined) { return EntityTypeComponentExtendedCategory.attribute; } else if (id.indexOf("sensor") >= 0) { return EntityTypeComponentExtendedCategory.sensorComponents; } else if (id.indexOf("jump") >= 0 || id.indexOf("climb") >= 0 || id.indexOf("move") >= 0 || id.startsWith("minecraft:navigation") || id.startsWith("minecraft:flying") || id.startsWith("minecraft:friction") || id.startsWith("minecraft:walk_animation")) { return EntityTypeComponentExtendedCategory.movementComplex; } else if (id.indexOf("attack") >= 0 || id.indexOf("combat") >= 0 || id.indexOf("damage") >= 0 || id.startsWith("minecraft:health") || id.startsWith("minecraft:healable") || id.startsWith("minecraft:hurt_on")) { return EntityTypeComponentExtendedCategory.combatAndHealthComplex; } return EntityTypeComponentExtendedCategory.complex; } get formatVersion() { return this._wrapper?.format_version; } static getComponentFromBaseFileName(name) { let canonName = name; if (canonName.startsWith("minecraft_")) { canonName = canonName.substring(10); if (canonName.startsWith("behavior_")) { canonName = "behavior." + canonName.substring(9); } if (canonName.startsWith("movement_")) { canonName = "movement." + canonName.substring(9); } if (canonName.startsWith("navigation_")) { canonName = "navigation." + canonName.substring(11); } if (canonName.startsWith("player_")) { canonName = "player." + canonName.substring(7); } if (canonName.startsWith("jump_")) { canonName = "jump." + canonName.substring(5); } if (canonName.startsWith("horse_")) { canonName = "horse." + canonName.substring(6); } if (canonName.startsWith("annotation_")) { canonName = "annotation." + canonName.substring(11); } } return canonName; } static getComponentCategoryDescription(category) { switch (category) { case EntityTypeComponentCategory.behavior: return "Behavior"; case EntityTypeComponentCategory.attribute: return "Attribute"; case EntityTypeComponentCategory.trigger: return "Trigger"; default: return "Component"; } } static getPluralComponentCategoryDescription(category) { switch (category) { case EntityTypeComponentCategory.behavior: return "Behaviors (AI)"; case EntityTypeComponentCategory.attribute: return "Attributes"; case EntityTypeComponentCategory.trigger: return "Triggers"; default: return "Components"; } } 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._file; } get onLoaded() { return this._onLoaded.asEvent(); } set behaviorPackFile(newFile) { if (this._file) { this._file.onFileContentUpdated.unsubscribe(this._handleFileUpdated); } this._file = newFile; if (this._file) { this._file.onFileContentUpdated.subscribe(this._handleFileUpdated); } } _handleFileUpdated(file, fileB) { // Skip when this update came from our own persist() call — the in-memory // state already matches what we just wrote, so resetting it (and forcing a // re-parse) would leave the editor stuck on "Loading mob definition..." // until the next prop change. if (this._isSelfPersisting) { return; } this._data = undefined; this._isLoaded = false; this._wrapper = undefined; this._managedComponents = {}; } get id() { if (this._id === undefined) { return ""; } return this._id; } set id(newId) { this._id = newId; if (this._data && this._data.description) { this._data.description.identifier = newId; } } get runtimeIdentifier() { if (this._data && this._data.description) { return this._data.description.runtime_identifier; } return undefined; } set runtimeIdentifier(newId) { if (this._data && this._data.description) { this._data.description.runtime_identifier = newId; } } get aliases() { if (!this._data || !this._data.description) { return undefined; } return this._data.description.aliases; } get properties() { if (!this._data || !this._data.description) { return undefined; } return this._data.description.properties; } constructor() { this._handleFileUpdated = this._handleFileUpdated.bind(this); } async getFormatVersionIsCurrent() { const fv = this.getFormatVersionAsNumberArray(); if (fv === undefined || fv.length !== 3) { return false; } return await Database_1.default.isRecentVersionFromVersionArray(fv); } getFormatVersionAsNumberArray() { if (!this._wrapper) { return undefined; } return MinecraftUtilities_1.default.getVersionArrayFrom(this._wrapper.format_version); } removeProperty(propertyName) { if (this._data?.description?.properties) { this._data.description.properties[propertyName] = undefined; } } get shortId() { if (this._id !== undefined) { let val = this._id; if (val.startsWith("minecraft:")) { return val.substring(10, this._id.length); } const firstColon = val.indexOf(":"); if (firstColon >= 0) { val = val.substring(firstColon + 1); } return val; } return undefined; } getComponent(id) { if (this._data === undefined || this._data.components === undefined) { return undefined; } if (!Utilities_1.default.isUsableAsObjectKey(id)) { Log_1.default.unsupportedToken(id); throw new Error(); } if (!this._managedComponents[id]) { const comp = this._data.components[id]; if (comp) { this._managedComponents[id] = new ManagedComponent_1.ManagedComponent(this._data.components, id, comp); } } return this._managedComponents[id]; } getComponentsInBaseAndGroups(id) { if (this._data === undefined) { return []; } let results = []; let comp = this.getComponent(id); if (comp) { results.push(comp); } for (const componentGroupName in this._componentGroups) { const group = this._componentGroups[componentGroupName]; if (group) { comp = group.getComponent(id); if (comp) { results.push(comp); } } } return results; } getCoreAndComponentGroupList() { const componentSets = [this]; const cgs = this.getComponentGroups(); componentSets.push(...cgs); return componentSets; } getAllComponents() { if (this._data === undefined) { return []; } let results = this.getComponents(); for (const componentGroupName in this._componentGroups) { const group = this._componentGroups[componentGroupName]; if (group) { for (const comp of group.getComponents()) { if (comp) { results.push(comp); } } } } return results; } get behaviorPackFormatVersion() { if (!this._wrapper || !this._wrapper.format_version) { return undefined; } return this._wrapper.format_version; } setBehaviorPackFormatVersion(versionStr) { this._ensureBehaviorPackDataInitialized(); if (this._wrapper) { this._wrapper.format_version = versionStr; } } notifyComponentUpdated(id) { const component = this.getComponent(id); if (component === undefined) { Log_1.default.unexpectedUndefined("ETNCU"); } else { this._onComponentChanged.dispatch(this, component); } } getComponents() { const componentSet = []; if (this._data !== undefined) { for (const componentName in this._data.components) { const component = this.getComponent(componentName); if (component !== undefined) { componentSet.push(component); } } } return componentSet; } getComponentGroupsComponentUsedIn(componentName) { const componentGroups = this.getComponentGroups(); const cgsUsedIn = []; for (const cg of componentGroups) { if (cg && cg.getComponent(componentName)) { cgsUsedIn.push(cg); } } return cgsUsedIn; } getComponentGroup(componentGroupName) { if (this._data && this._data.component_groups) { if (!this._componentGroups[componentGroupName] && this._data.component_groups[componentGroupName]) { const componentGroupData = this._data.component_groups[componentGroupName]; const cg = new ManagedComponentGroup_1.default(componentGroupData, componentGroupName); this._componentGroups[componentGroupName] = cg; } return this._componentGroups[componentGroupName]; } return undefined; } getComponentGroups() { const componentGroups = []; if (this._data !== undefined) { for (const componentGroupName in this._data.component_groups) { if (!this._componentGroups[componentGroupName]) { const componentGroupData = this._data.component_groups[componentGroupName]; const cg = new ManagedComponentGroup_1.default(componentGroupData, componentGroupName); this._componentGroups[componentGroupName] = cg; componentGroups.push(cg); } else { componentGroups.push(this._componentGroups[componentGroupName]); } } } return componentGroups; } getEvent(eventName) { try { if (this._data !== undefined && Utilities_1.default.isUsableAsObjectKey(eventName)) { if (!this._events[eventName]) { const eventData = this._data.events[eventName]; this._events[eventName] = eventData; } return this._events[eventName]; } } catch (e) { Log_1.default.verbose("Error getting event " + eventName + ": " + e); } return undefined; } getEffectiveComponents(componentGroupAddRemoveList) { const componentState = JSON.parse(JSON.stringify(this._data?.components)); // clone for (let componentGroupId of componentGroupAddRemoveList) { let isAdd = true; if (componentGroupId.startsWith("-")) { componentGroupId = componentGroupId.substring(1); isAdd = false; } else if (componentGroupId.startsWith("+")) { componentGroupId = componentGroupId.substring(1); } const componentGroup = this.getComponentGroup(componentGroupId); if (componentGroup) { const cgComps = componentGroup.getComponents(); if (isAdd) { for (const cgComp of cgComps) { componentState[cgComp.id] = cgComp.getData(); } } else if (!isAdd) { for (const cgComp of cgComps) { componentState[cgComp.id] = undefined; } } } } return new ManagedComponentGroup_1.default(componentState, this.id); } getEvents() { const events = []; if (this._data !== undefined) { for (const eventName in this._data.events) { if (!this._events[eventName] && Utilities_1.default.isUsableAsObjectKey(eventName)) { const eventData = this._data.events[eventName]; this._events[eventName] = eventData; events.push({ id: eventName, event: eventData }); } else { events.push({ id: eventName, event: this._events[eventName] }); } } } return events; } addComponent(id, componentOrData) { this._ensureBehaviorPackDataInitialized(); const bpData = this._data; const mc = componentOrData instanceof ManagedComponent_1.ManagedComponent ? componentOrData : new ManagedComponent_1.ManagedComponent(bpData.components, id, componentOrData); bpData.components[id] = mc.getData(); this._managedComponents[id] = mc; this._onComponentAdded.dispatch(this, mc); return mc; } addComponentGroup(id, componentOrData) { this._ensureBehaviorPackDataInitialized(); if (id === undefined) { id = "group"; let increment = 0; let cg = this.getComponentGroup(id); while (cg !== undefined && increment < 100) { increment++; id = "group" + increment; cg = this.getComponentGroup(id); } } if (componentOrData === undefined) { componentOrData = {}; } const bpData = this._data; const mcg = componentOrData instanceof ManagedComponentGroup_1.default ? componentOrData : new ManagedComponentGroup_1.default(componentOrData, id); const cgData = mcg.getData(); if (cgData) { bpData.component_groups[id] = cgData; } this._componentGroups[id] = mcg; return mcg; } removeComponent(id) { if (this._data === undefined) { return; } const newBehaviorPacks = {}; const newManagedComponents = {}; for (const name in this._data.components) { if (name !== id && Utilities_1.default.isUsableAsObjectKey(name)) { const componentData = this._data.components[name]; newBehaviorPacks[name] = componentData; } } for (const name in this._managedComponents) { if (name !== id && this._managedComponents[name] && Utilities_1.default.isUsableAsObjectKey(name)) { newManagedComponents[name] = this._managedComponents[name]; } } this._data.components = newBehaviorPacks; this._managedComponents = newManagedComponents; } _ensureBehaviorPackDataInitialized() { if (!this._wrapper) { this._wrapper = { format_version: "1.20.0", }; } if (this._data === undefined) { this._data = { description: { identifier: "unknown", is_experimental: false, is_spawnable: false, is_summonable: false, }, components: {}, component_groups: {}, events: {}, }; if (this._wrapper) { //@ts-ignore this._wrapper["minecraft:entity"] = this._data; } } } getProperties() { if (!this._data || !this._data?.description) { return undefined; } return this._data.description.properties; } getPropertyList() { const props = this.getProperties(); if (!props) { return []; } const propertyList = []; for (const propName in props) { if (props[propName] !== undefined) { propertyList.push(propName); } } return propertyList; } static getPropertyTypeString(stateType) { switch (stateType) { case EntityPropertyType.boolean: return "bool"; case EntityPropertyType.float: return "float"; case EntityPropertyType.enum: return "enum"; } return "int"; } addProperty(propertyName, propertyType) { if (!this._data || !this._data.description) { return; } let dataArr = undefined; let typeStr = EntityTypeDefinition.getPropertyTypeString(propertyType); let defaultValue = false; if (propertyType === EntityPropertyType.float) { dataArr = [0, 1, 2]; defaultValue = 0; } else if (propertyType === EntityPropertyType.enum) { dataArr = ["value1", "value2"]; defaultValue = "value1"; } if (!this._data.description.properties) { this._data.description.properties = {}; } this._data.description.properties[propertyName] = { type: typeStr, values: dataArr, default: defaultValue, }; } addEvent(eventName) { if (!this._data) { return; } if (!this._data.events) { this._data.events = {}; } if (eventName === undefined) { eventName = "eventName"; let increment = 0; let eve = this.getEvent(eventName); while (eve !== undefined && increment < 100) { increment++; eventName = "eventName" + increment; eve = this.getEvent(eventName); } } this._data.events[eventName] = {}; } async addChildItems(project, item, index) { let lootTablePaths = []; const comps = this.getComponentsInBaseAndGroups("minecraft:loot"); for (const comp of comps) { let lootTablePath = comp.getProperty("table"); if (lootTablePath) { lootTablePaths.push(lootTablePath); } } // Use pre-built index for O(1) lookups when available if (index && this.id) { // Entity resources matching this entity's ID const matchingResources = index.getItemsById(index.entityResourcesById, this.id); for (const candItem of matchingResources) { item.addChildItem(candItem); } // Spawn rules matching this entity's ID const matchingSpawnRules = index.getItemsById(index.spawnRulesById, this.id); for (const candItem of matchingSpawnRules) { item.addChildItem(candItem); } // Loot tables by path suffix match if (lootTablePaths.length > 0) { const lootTableItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.lootTableBehavior); for (const candItem of lootTableItems) { for (const lootTablePath of lootTablePaths) { if (candItem.projectPath?.endsWith(lootTablePath)) { item.addChildItem(candItem); } } } } } else { // Fallback: scan items when index is not available const entityResourceItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.entityTypeResource); for (const candItem of entityResourceItems) { if (!candItem.isContentLoaded) { await candItem.loadContent(); } if (candItem.primaryFile) { const etrd = await EntityTypeResourceDefinition_1.default.ensureOnFile(candItem.primaryFile); if (etrd) { const id = etrd.id; if (id === this.id) { item.addChildItem(candItem); } } } } const spawnRuleItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.spawnRuleBehavior); for (const candItem of spawnRuleItems) { if (!candItem.isContentLoaded) { await candItem.loadContent(); } if (candItem.primaryFile) { const srb = await SpawnRulesBehaviorDefinition_1.default.ensureOnFile(candItem.primaryFile); if (srb) { const id = srb.id; if (id === this.id) { item.addChildItem(candItem); } } } } if (lootTablePaths.length > 0) { const lootTableItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.lootTableBehavior); for (const candItem of lootTableItems) { for (const lootTablePath of lootTablePaths) { if (candItem.projectPath?.endsWith(lootTablePath)) { item.addChildItem(candItem); } } } } } } static async ensureOnFile(behaviorPackFile, loadHandler, preserveComments) { let et; if (behaviorPackFile.manager === undefined) { et = new EntityTypeDefinition(); et.behaviorPackFile = behaviorPackFile; behaviorPackFile.manager = et; } if (behaviorPackFile.manager !== undefined && behaviorPackFile.manager instanceof EntityTypeDefinition) { et = behaviorPackFile.manager; if (!et.isLoaded || (preserveComments && !et._loadedWithComments)) { if (loadHandler) { et.onLoaded.subscribe(loadHandler); } await et.load(preserveComments); } } return et; } getScript(isTypeScript) { if (this.shortId === undefined) { return; } const className = ScriptGen_1.default.getClassName(this.shortId); const results = []; results.push("import * as mc from '@minecraft/server';"); results.push("export default class " + className + "Base"); results.push("{"); if (isTypeScript) { results.push(" _entity : mc.Entity;"); results.push(" constructor(entity : mc.Entity) {"); } else { results.push(" _entity;\n"); results.push(" constructor(entity) {"); } results.push(" this._entity = entity;"); results.push(" }\n\n"); if (isTypeScript) { results.push(" static spawn(location : mc.Vector3) {"); } else { results.push(" static spawn(location) {"); } results.push(' const entity = world.getDimension("overworld").spawnEntity("' + this.id + '", location);'); results.push(" const " + ScriptGen_1.default.getInstanceName(this.shortId) + " = new " + className + "(entity);"); results.push(" return " + ScriptGen_1.default.getInstanceName(this.shortId) + ";"); results.push(" }\n"); if (this._data !== undefined) { const healthC = this._data.components["minecraft:health"]; if (healthC !== undefined) { results.push(" fullyHeal() {"); results.push(' this._entity.getComponent("minecraft:health").resetToMaxValue();'); results.push(" }\n"); if (isTypeScript) { results.push(" setHealth(newValue : number) {"); } else { results.push(" setHealth(newValue) {"); } results.push(' this._entity.getComponent("minecraft:health").setCurrent(newValue);'); results.push(" }\n"); } const rideableC = this._data.components["minecraft:rideable"]; if (rideableC !== undefined) { if (isTypeScript) { results.push(" addRider(newRider : mc.Entity) {"); } else { results.push(" addRider(newRider) {"); } results.push(' this._entity.getComponent("minecraft:rideable").addRider(newRider);'); results.push(" }\n"); if (isTypeScript) { results.push(" ejectRider(rider : mc.Entity) {"); } else { results.push(" ejectRider(rider) {"); } results.push(' this._entity.getComponent("minecraft:rideable").addRider(rider);'); results.push(" }\n"); } const tameableC = this._data.components["minecraft:tameable"]; if (tameableC !== undefined) { results.push(" tame() {"); results.push(' return this._entity.getComponent("minecraft:tameable").tame();'); results.push(" }\n"); } } results.push("}"); return results.join("\n"); } persist() { if (this._file === undefined) { return false; } Log_1.default.assert(!this._isLoaded || this._wrapper !== null, "ETDP"); if (!this._wrapper) { return false; } this._isSelfPersisting = true; try { return this._file.setObjectContentIfSemanticallyDifferent(this._wrapper); } finally { this._isSelfPersisting = false; } } /** * Loads the entity type 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 we get here and _isLoaded is true, we need to "upgrade" from read-only to read/write // by re-parsing with comment preservation if (this._file === undefined) { Log_1.default.unexpectedUndefined("ETBPF"); return; } if (!this._file.isContentLoaded) { await this._file.loadContent(); } if (!this._file.content || this._file.content instanceof Uint8Array) { this._isLoaded = true; 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._file) : StorageUtilities_1.default.getJsonObject(this._file); if (result) { data = result; } this._wrapper = data; const entity = data["minecraft:entity"]; if (entity && entity.description) { this.id = entity.description.identifier; } this._data = entity; if (this._data) { if (this._data.components) { for (const compName in this._data.components) { const comp = this._data.components[compName]; if (comp) { this._managedComponents[compName] = new ManagedComponent_1.ManagedComponent(this._data.components, compName, comp); } } } if (this._data.component_groups) { for (const compGroupName in this._data.component_groups) { const compGroup = this._data.component_groups[compGroupName]; if (compGroup) { this._componentGroups[compGroupName] = new ManagedComponentGroup_1.default(compGroup, compGroupName); } } } } this._isLoaded = true; this._loadedWithComments = preserveComments; this._onLoaded.dispatch(this, this); } } exports.default = EntityTypeDefinition;