UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

1,316 lines 164 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.vanillaSliceFolderSeeds = exports.remappedMinecraftScriptModules = exports.minecraftScriptModules = exports.AUTOGENERATED_WHOLEFILE_GENERAL_SEPARATOR = exports.AUTOGENERATED_WHOLEFILE_MCFUNCTION_SEPARATOR = exports.AUTOGENERATED_WHOLEFILE_JS_SEPARATOR = exports.AUTOGENERATED_JS_SEPARATOR = exports.AUTOGENERATED_CONTENT_TOKEN = exports.ProjectTargetStrings = exports.FolderContext = exports.ProjectErrorState = exports.ProjectAutoDeploymentMode = void 0; /* * ========================================================================================== * PROJECT - CORE PROJECT MANAGEMENT NOTES * ========================================================================================== * * OVERVIEW: * --------- * Project is the central class for managing a Minecraft content project. It handles: * - Project structure (behavior packs, resource packs, worlds, scripts) * - Item discovery and inference from folder structure * - Pack management (BehaviorManifest, ResourceManifest) * - Validation integration via ProjectInfoSet * - Export/deployment coordination * * PROJECT STRUCTURE: * ------------------ * A project typically contains: * - behaviorPacksContainer/ - Behavior pack folders * - resourcePacksContainer/ - Resource pack folders * - worldContainer/ - World folders * - docsContainer/ - Documentation * - defaultBehaviorPackFolder, defaultResourcePackFolder - Primary packs * * KEY METHOD: _inferProjectItemsFromFolder(): * ------------------------------------------- * This is the monster recursive function that scans a folder tree and creates * ProjectItem objects based on file type and location. Logic includes: * - Path-based type inference (items/ folder → itemTypeBehaviorJson) * - Extension-based inference (.mcfunction, .json, .ts) * - Manifest detection for pack identification * - World detection from level.dat * * PROJECTITEM RELATIONSHIP: * ------------------------- * - Project contains ProjectItem[] in #items * - Items indexed by #itemsByProjectPath (canonicalized storage path) * - Items grouped by #itemsByType for quick type lookups * - Each ProjectItem has storagePath relative to project root * - Items link to IFile via file property, with .manager for type-specific logic * * PACK MANAGEMENT: * ---------------- * - #packs: Pack[] - All discovered packs (behavior, resource, skin, world) * - Pack objects wrap manifest files and provide pack-level operations * - hasMultiplePacksOfSameType affects folder structure assumptions * * VARIANTS: * --------- * - variants: { [label]: ProjectVariant } - Alternative configurations * - Used for multi-target builds (different Minecraft versions, platforms) * - ProjectItemVariantCreateManager handles variant-specific item creation * * LOADING SEQUENCE FOR EXTERNAL USERS: * ------------------------------------ * 1. new Project(creatorTools, folder, prefsFile) - Basic setup * 2. loadPreferencesAndFolder() - Basic loading from prefsFile JSON (isLoaded) * 3. inferProjectItemsFromFolder() - Create ProjectItems from files. * This is a somewhat expensive operation, and only needs to be done on * first instantiation on a folder, or if the folder/file set structure * changes * 4. ensureInflate() - Load file contents and initialize managers (isInflated) * * OPTIONAL ADDITION THINGS YOU SHOULD DO: * --------------------------------------- * * The web app, for example, does these asynchronously after first load. * These operations can take minutes to run, depending on project size. * * processRelations() - Build cross-item dependency graph (best done async) * * * INTERNAL FUNCTIONS * ------------------ * loadFolderStructure() - Discover folder hierarchy and rough mapping * * EVENTS: * ------- * - onPropertyChanged: Project metadata changed * - onLoaded: Folder structure loaded * - onInflated: All items loaded * - onItemChanged/Added/Removed: Item list modifications * - onItemContentChanged: Item file content changed * - onNeedsSaveChanged: Dirty state changed * * WORLD SETTINGS: * --------------- * - worldSettings: IWorldSettings - Default world configuration * - editorWorldSettings: Settings for Editor API worlds * - ensureWorldSettings() / ensureEditorWorldSettings() - Lazy initialization * * RELATED FILES: * -------------- * - ProjectItem.ts: Individual item management * - ProjectUtilities.ts: Static helper methods (moved from Project) * - ProjectExporter.ts: Export/packaging logic * - ProjectInfoSet.ts: Validation integration * - Pack.ts: Pack-level operations * - ProjectItemInference.ts: Item type inference logic * * FOLDER CONTEXTS (FolderContext enum): * ------------------------------------- * Used to identify folder purpose during inference: * - behaviorPack (1), resourcePack (2), skinPack (3) * - world (5), docs (4), typeDefs (6) * - distBuildFolder (7), vscodeFolder (8) * - mctoolsWorkingFolder (13), designPack (14) * * COMMON PATTERNS: * ---------------- * - Get item: project.getItemByProjectPath(storagePath) * - Get items by type: project.getItemsByType(ProjectItemType.entityTypeBehaviorJson) * - Ensure folder: project.ensureDefaultBehaviorPackFolder() * - Save project: project.save() * * ========================================================================================== */ const IFile_1 = require("../storage/IFile"); const IProjectData_1 = require("./IProjectData"); const IProjectData_2 = require("./IProjectData"); const ProjectItem_1 = __importDefault(require("./ProjectItem")); const IProjectItemData_1 = require("./IProjectItemData"); const Utilities_1 = __importDefault(require("./../core/Utilities")); const ste_events_1 = require("ste-events"); const StorageUtilities_1 = __importDefault(require("../storage/StorageUtilities")); const Log_1 = __importDefault(require("../core/Log")); const ProjectUtilities_1 = __importDefault(require("./ProjectUtilities")); const WorldLevelDat_1 = require("../minecraft/WorldLevelDat"); const IWorldSettings_1 = require("../minecraft/IWorldSettings"); const BehaviorManifestDefinition_1 = __importDefault(require("../minecraft/BehaviorManifestDefinition")); const MinecraftUtilities_1 = __importDefault(require("../minecraft/MinecraftUtilities")); const LocManager_1 = __importDefault(require("../minecraft/LocManager")); const ProjectInfoSet_1 = __importDefault(require("../info/ProjectInfoSet")); const ProjectInfoItem_1 = __importDefault(require("../info/ProjectInfoItem")); const ProjectUpdateRunner_1 = __importDefault(require("../updates/ProjectUpdateRunner")); const InfoGeneratorTopicUtilities_1 = __importDefault(require("../info/InfoGeneratorTopicUtilities")); const GeneratorRegistrations_1 = __importDefault(require("../info/registration/GeneratorRegistrations")); const Telemetry_1 = __importDefault(require("../analytics/Telemetry")); const TelemetryStub_1 = __importDefault(require("../analytics/TelemetryStub")); let telemetry = TelemetryStub_1.default; // @ts-ignore - ENABLE_ANALYTICS is injected by webpack and vite configs if (typeof ENABLE_ANALYTICS !== "undefined" && ENABLE_ANALYTICS === true) { telemetry = Telemetry_1.default; } const TelemetryConstants_1 = require("../analytics/TelemetryConstants"); const Status_1 = require("./Status"); const IProjectInfoData_1 = require("../info/IProjectInfoData"); const Pack_1 = __importStar(require("../minecraft/Pack")); const ProjectDeploySync_1 = __importDefault(require("./ProjectDeploySync")); const ICreatorToolsData_1 = require("./ICreatorToolsData"); const ProjectItemRelations_1 = __importDefault(require("./ProjectItemRelations")); const ResourceManifestDefinition_1 = __importDefault(require("../minecraft/ResourceManifestDefinition")); const ProjectLookupUtilities_1 = __importDefault(require("./ProjectLookupUtilities")); const ProjectVariant_1 = __importDefault(require("./ProjectVariant")); const IProjectItemVariant_1 = require("./IProjectItemVariant"); const ProjectItemInference_1 = __importDefault(require("./ProjectItemInference")); const IProjectWorkerManager_1 = require("./IProjectWorkerManager"); const ScriptModuleInfo_1 = require("../langcore/javascript/ScriptModuleInfo"); var ProjectAutoDeploymentMode; (function (ProjectAutoDeploymentMode) { ProjectAutoDeploymentMode[ProjectAutoDeploymentMode["deployOnSave"] = 0] = "deployOnSave"; ProjectAutoDeploymentMode[ProjectAutoDeploymentMode["noAutoDeployment"] = 1] = "noAutoDeployment"; })(ProjectAutoDeploymentMode || (exports.ProjectAutoDeploymentMode = ProjectAutoDeploymentMode = {})); var ProjectErrorState; (function (ProjectErrorState) { ProjectErrorState[ProjectErrorState["noError"] = 0] = "noError"; ProjectErrorState[ProjectErrorState["projectFolderOrFileDoesNotExist"] = 1] = "projectFolderOrFileDoesNotExist"; ProjectErrorState[ProjectErrorState["cabinetFileCouldNotBeProcessed"] = 2] = "cabinetFileCouldNotBeProcessed"; })(ProjectErrorState || (exports.ProjectErrorState = ProjectErrorState = {})); var FolderContext; (function (FolderContext) { FolderContext[FolderContext["unknown"] = 0] = "unknown"; FolderContext[FolderContext["behaviorPack"] = 1] = "behaviorPack"; FolderContext[FolderContext["resourcePack"] = 2] = "resourcePack"; FolderContext[FolderContext["skinPack"] = 3] = "skinPack"; FolderContext[FolderContext["docs"] = 4] = "docs"; FolderContext[FolderContext["world"] = 5] = "world"; FolderContext[FolderContext["typeDefs"] = 6] = "typeDefs"; FolderContext[FolderContext["distBuildFolder"] = 7] = "distBuildFolder"; FolderContext[FolderContext["vscodeFolder"] = 8] = "vscodeFolder"; FolderContext[FolderContext["resourcePackSubPack"] = 9] = "resourcePackSubPack"; FolderContext[FolderContext["metaData"] = 10] = "metaData"; FolderContext[FolderContext["libFolder"] = 11] = "libFolder"; FolderContext[FolderContext["persona"] = 12] = "persona"; FolderContext[FolderContext["mctoolsWorkingFolder"] = 13] = "mctoolsWorkingFolder"; FolderContext[FolderContext["designPack"] = 14] = "designPack"; })(FolderContext || (exports.FolderContext = FolderContext = {})); exports.ProjectTargetStrings = [ "<default>", "Latest Minecraft Bedrock", "Latest Minecraft Bedrock preview", "Latest Minecraft Education", "Latest Minecraft Education preview", ]; exports.AUTOGENERATED_CONTENT_TOKEN = "==== AUTOGENERATED"; exports.AUTOGENERATED_JS_SEPARATOR = "\n// ===== AUTOGENERATED CONTENT ===== CONTENT AT OR BELOW THIS LINE WILL BE WIPED AND UPDATED WHEN USED IN TOOLING"; exports.AUTOGENERATED_WHOLEFILE_JS_SEPARATOR = "// ===== AUTOGENERATED FILE ===== CONTENT WITHIN THIS FILE WILL BE WIPED AND UPDATED WHEN USED IN TOOLING"; exports.AUTOGENERATED_WHOLEFILE_MCFUNCTION_SEPARATOR = "# ===== AUTOGENERATED FILE ===== CONTENT WITHIN THIS FILE WILL BE WIPED AND UPDATED WHEN USED IN TOOLING"; exports.AUTOGENERATED_WHOLEFILE_GENERAL_SEPARATOR = "===== AUTOGENERATED FILE ===== CONTENT WITHIN THIS FILE WILL BE WIPED AND UPDATED WHEN USED IN TOOLING"; exports.minecraftScriptModules = [ { id: "@minecraft/server", module_name: "@minecraft/server", preferredVersion: ScriptModuleInfo_1.ScriptModuleInfoProvider.getLatestVersion("server", true) || "1.17.0-beta", }, { id: "@minecraft/server-gametest", module_name: "@minecraft/server-gametest", preferredVersion: ScriptModuleInfo_1.ScriptModuleInfoProvider.getLatestVersion("server-gametest", true) || "1.0.0-beta", }, { id: "@minecraft/server-ui", module_name: "@minecraft/server-ui", preferredVersion: ScriptModuleInfo_1.ScriptModuleInfoProvider.getLatestVersion("server-ui", true) || "1.5.0-beta", }, { id: "@minecraft/server-admin", module_name: "@minecraft/server-admin", preferredVersion: ScriptModuleInfo_1.ScriptModuleInfoProvider.getLatestVersion("server-admin", true) || "1.0.0-beta", }, { id: "@minecraft/server-net", module_name: "@minecraft/server-net", preferredVersion: ScriptModuleInfo_1.ScriptModuleInfoProvider.getLatestVersion("server-net", true) || "1.0.0-beta", }, { id: "@minecraft/server-editor", module_name: "@minecraft/server-editor", preferredVersion: ScriptModuleInfo_1.ScriptModuleInfoProvider.getLatestVersion("server-editor", true) || "0.1.0-beta", }, ]; exports.remappedMinecraftScriptModules = { "mojang-minecraft": "@minecraft/server", "mojang-gametest": "@minecraft/server-gametest", "mojang-minecraft-ui": "@minecraft/server-ui", "mojang-server-admin": "@minecraft/server-admin", "mojang-net": "@minecraft/server-net", "@minecraft/server-editor-bindings": "@minecraft/server-editor", }; exports.vanillaSliceFolderSeeds = ["vanilla", "chemistry"]; const ProcessItemRelationsBatchSize = 400; class Project { #data; #preferencesFile; #creatorTools; loc; #errorState = ProjectErrorState.noError; #errorMessage; #indevInfoSet = null; differencesFromGitHub; /** Transient action to perform after this project first opens in the editor (not persisted). */ pendingPostCreateAction; /** Transient content definition to generate after this project first opens in the editor (not persisted). */ pendingContentDefinition; #hasMultiplePacksOfSameType; #relationsProcessed = false; #folderStructureLoaded = false; #indevInfoSetNeedsUpdating = false; // Promise to track in-progress info set generation (allows callers to wait for existing operation) #infoSetGenerationPromise = null; /** * Debounce timer for batching external file changes. * When files are added/removed externally (e.g., by MCP), * we batch them into a single re-inference pass. */ #externalChangeDebounceTimer = null; /** Pending external file additions, keyed by storage path */ #pendingExternalAdds = new Set(); /** Pending external file removals, keyed by storage path */ #pendingExternalRemoves = new Set(); /** Debounce time for external file changes in milliseconds */ static EXTERNAL_CHANGE_DEBOUNCE_MS = 500; #mainDeployFolder = null; #projectFolder; #projectCabinetFile = null; #distBuildFolder = null; #libFolder = null; #distBuildScriptsFolder = null; #libScriptsFolder = null; docsContainer; worldContainer = null; #mainDeploySync = null; #isDisposed = false; behaviorPacksContainer; defaultBehaviorPackFolder; skinPacksContainer; defaultSkinPackFolder; personaPacksContainer; defaultPersonaPackFolder; designPacksContainer; defaultDesignPackFolder; projectItemAccessoryFolder; #packs = []; #containerFiles = []; defaultWorldFolder; #defaultScriptsFolder; resourcePacksContainer; defaultResourcePackFolder; creationTime; #items; #itemsByProjectPath = new Map(); #itemsByType = new Map(); changedFilesSinceLastSaved = {}; #isLoaded = false; #isInflated = false; #isProjectFolderEnsured = false; #useProjectNameInProjectStorage = false; #accessoryFilePaths; #accessoryFoldersForFilePaths = null; #accessoryFolders = null; _onPropertyChanged = new ste_events_1.EventDispatcher(); _onLoaded = new ste_events_1.EventDispatcher(); _onInflated = new ste_events_1.EventDispatcher(); _onSaved = new ste_events_1.EventDispatcher(); _onNeedsSaveChanged = new ste_events_1.EventDispatcher(); _onItemChanged = new ste_events_1.EventDispatcher(); _onItemContentChanged = new ste_events_1.EventDispatcher(); _onItemAdded = new ste_events_1.EventDispatcher(); _onItemRemoved = new ste_events_1.EventDispatcher(); #isProcessingRelations = false; #relationsBatchOperId = -1; #itemsToBeProcessed = 0; #itemsProcessed = 0; #pendingProcessingRelationsRequests = []; variants; hasInferredFiles = false; #readOnlySafety = false; #isVanillaEditSession; get unknownFiles() { return [...this._unknownFiles]; } _unknownFiles = new Set(); addUnknownFile(file) { this._unknownFiles.add(file); } get hasMultiplePacksOfSameType() { if (this.#hasMultiplePacksOfSameType !== undefined) { return this.#hasMultiplePacksOfSameType; } // Determine if there are multiple packs of the same type const packTypes = []; for (const pack of this.#packs) { if (packTypes[pack.packType] !== undefined) { this.#hasMultiplePacksOfSameType = true; return true; } else { packTypes[pack.packType] = 1; } } this.#hasMultiplePacksOfSameType = false; return false; } get readOnlySafety() { return this.#readOnlySafety; } set readOnlySafety(newReadOnly) { this.#readOnlySafety = newReadOnly; if (this.#projectFolder) { this.#projectFolder.storage.readOnly = this.#readOnlySafety; } } get creatorTools() { return this.#creatorTools; } /** * Get the project data for persistence. * This includes chat session and other project metadata. */ get projectData() { return this.#data; } get role() { if (this.#data.role === undefined) { return IProjectData_1.ProjectRole.general; } return this.#data.role; } set role(newRole) { this.#data.role = newRole; } get errorState() { return this.#errorState; } get errorMessage() { return this.#errorMessage; } get preferencesFile() { return this.#preferencesFile; } get accessoryFolders() { return this.#accessoryFolders; } set accessoryFolders(folders) { this.#accessoryFolders = folders; } get accessoryFilePaths() { return this.#accessoryFilePaths; } set accessoryFilePaths(files) { this.#accessoryFilePaths = files; } // This property is a maintained and updated "in development" info set // that contains errors and validation information useful while a project is // in develpoment. For other validator suites, instantiate a ProjectInfoSet // with this project in its constructor get indevInfoSet() { if (!this.#indevInfoSet) { this.#indevInfoSet = new ProjectInfoSet_1.default(this, IProjectInfoData_1.ProjectInfoSuite.defaultInDevelopment); } return this.#indevInfoSet; } get collapsedStoragePaths() { if (!this.#data.collapsedStoragePaths) { this.#data.collapsedStoragePaths = []; } return this.#data.collapsedStoragePaths; } set collapsedStoragePaths(newCollapsedPaths) { this.#data.collapsedStoragePaths = newCollapsedPaths; } get packs() { return this.#packs; } hasUnsavedChanges() { for (const filePath in this.changedFilesSinceLastSaved) { return true; } return false; } getBehaviorPackCount() { let count = 0; for (const projectItem of this.items) { if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) { count++; } } return count; } getResourcePackCount() { let count = 0; for (const projectItem of this.items) { if (projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) { count++; } } return count; } getIsPackFolderManaged() { let rpCount = 0; let bpCount = 0; for (const projectItem of this.items) { if (projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) { bpCount++; } else if (projectItem.itemType === IProjectItemData_1.ProjectItemType.resourcePackManifestJson) { rpCount++; } } return bpCount < 2 && rpCount < 2; } get key() { if (this.localFilePath) { return StorageUtilities_1.default.canonicalizePath(this.localFilePath); } if (this.#projectFolder) { if (this.#projectFolder.name && this.#projectFolder.name.length > 0) { return this.#projectFolder.name; } return StorageUtilities_1.default.canonicalizePath(this.#projectFolder.fullPath); } if (this.#preferencesFile) { return StorageUtilities_1.default.canonicalizePath(this.#preferencesFile.name); } return this.title; } get containerName() { if (this.localFilePath) { return StorageUtilities_1.default.getLeafName(this.localFilePath); } if (this.#projectFolder) { if (this.#projectFolder.name && this.#projectFolder.name.length > 0) { return this.#projectFolder.name; } return StorageUtilities_1.default.getLeafName(this.#projectFolder.fullPath); } if (this.#preferencesFile) { return StorageUtilities_1.default.getBaseFromName(this.#preferencesFile.name); } return this.title; } get defaultNamespace() { return this.#data.defaultNamespace; } get effectiveDefaultNamespace() { if (this.#data.defaultNamespace || this.#data.defaultNamespace === "") { return this.#data.defaultNamespace; } return this.effectiveShortName; } set defaultNamespace(newDefaultNamespace) { if (newDefaultNamespace !== this.#data.defaultNamespace) { this.#data.defaultNamespace = newDefaultNamespace; this._onPropertyChanged.dispatch(this, "defaultNamespace"); } } get scriptEntryPoint() { if (this.#data.scriptEntryPoint || this.#data.scriptEntryPoint === "") { return this.#data.scriptEntryPoint; } return this.scriptEntryPoint; } set scriptEntryPoint(newScriptEntryPoint) { if (newScriptEntryPoint !== this.#data.scriptEntryPoint) { this.#data.scriptEntryPoint = newScriptEntryPoint; this._onPropertyChanged.dispatch(this, "scriptEntryPoint"); } } get worldSettings() { return this.#data.worldSettings; } get editorWorldSettings() { return this.#data.editorWorldSettings; } get isMinecraftCreator() { return this.#data.creator?.toLowerCase() === "minecraft"; } async getLookupChoices(lookupId) { return await ProjectLookupUtilities_1.default.getLookup(this, lookupId); } ensureWorldSettings() { if (this.#data.worldSettings === undefined) { if (this.creatorTools.worldSettings) { this.#data.worldSettings = this.creatorTools.worldSettings; } else { this.initializeWorldSettings(); if (this.#data.worldSettings === undefined) { throw new Error(); } } } return this.#data.worldSettings; } ensureEditorWorldSettings() { if (this.#data.editorWorldSettings === undefined) { if (this.creatorTools.editorWorldSettings) { this.#data.editorWorldSettings = this.creatorTools.editorWorldSettings; } else { this.initializeEditorWorldSettings(); if (this.#data.editorWorldSettings === undefined) { throw new Error(); } } } return this.#data.editorWorldSettings; } get usesCustomWorldSettings() { return this.#data.usesCustomWorldSettings; } set usesCustomWorldSettings(newValue) { this.#data.usesCustomWorldSettings = newValue; } get isLoaded() { return this.#isLoaded; } get isInflated() { return this.#isInflated; } get isRelationsProcessed() { return this.#relationsProcessed; } get distBuildFolder() { return this.#distBuildFolder; } set distBuildFolder(folder) { this.#distBuildFolder = folder; } get libFolder() { return this.#libFolder; } set libFolder(folder) { this.#libFolder = folder; } get distScriptsFolder() { return this.#distBuildScriptsFolder; } get libScriptsFolder() { return this.#libScriptsFolder; } get useProjectNameInRootProjectStorage() { return this.#useProjectNameInProjectStorage; } set useProjectNameInRootProjectStorage(newVal) { this.#useProjectNameInProjectStorage = newVal; } get onPropertyChanged() { return this._onPropertyChanged.asEvent(); } get onLoaded() { return this._onLoaded.asEvent(); } get onInflated() { return this._onInflated.asEvent(); } get onSaved() { return this._onSaved.asEvent(); } get onNeedsSaveChanged() { return this._onNeedsSaveChanged.asEvent(); } get onItemChanged() { return this._onItemChanged.asEvent(); } get onItemContentChanged() { return this._onItemContentChanged.asEvent(); } get onItemAdded() { return this._onItemAdded.asEvent(); } get onItemRemoved() { return this._onItemRemoved.asEvent(); } get projectFolderTitle() { return this.#data.projectFolderTitle; } set projectFolderTitle(newTitle) { this.#data.projectFolderTitle = newTitle; } get projectFolder() { return this.#projectFolder; } get accessoryFoldersForFilePaths() { return this.#accessoryFoldersForFilePaths; } get localFolderPath() { return this.#data.localFolderPath; } set localFolderPath(newPath) { this.#data.localFolderPath = newPath; } get mainDeployFolderPath() { return this.#data.mainDeployFolderPath; } set mainDeployFolderPath(newPath) { this.#data.mainDeployFolderPath = newPath; } get localFilePath() { return this.#data.localFilePath; } set localFilePath(newPath) { this.#data.localFilePath = newPath; } get items() { return this.#items; } get gitHubReferences() { if (this.#data.gitHubReferences === undefined) { this.#data.gitHubReferences = []; } return this.#data.gitHubReferences; } async getBehaviorPackScriptsFolder() { const bpFolder = await this.ensureDefaultBehaviorPackFolder(); return bpFolder.folders["scripts"]; } async ensureBehaviorPackScriptsFolder() { const bpFolder = await this.ensureDefaultBehaviorPackFolder(); return bpFolder.ensureFolder("scripts"); } async getMainScriptsFolder() { if (!this.#folderStructureLoaded) { await this.loadFolderStructure(); } if (this.#projectFolder === undefined || this.#projectFolder === null) { throw new Error("Unexpectedly could not create project folder"); } return this.#projectFolder.folders["scripts"]; } async ensureProjectItemAccessoryFolder() { if (this.projectItemAccessoryFolder) { return this.projectItemAccessoryFolder; } if (!this.#folderStructureLoaded) { await this.loadFolderStructure(); } if (this.#projectFolder === undefined || this.#projectFolder === null) { throw new Error("Unexpectedly could not create project folder"); } const defaultDesignFolder = await this.ensureDefaultDesignPackFolder(); this.projectItemAccessoryFolder = defaultDesignFolder.ensureFolder("project_item_data"); return this.projectItemAccessoryFolder; } async ensureMainScriptsFolder() { if (!this.#folderStructureLoaded) { await this.loadFolderStructure(); } if (this.#projectFolder === undefined || this.#projectFolder === null) { throw new Error("Unexpectedly could not create project folder"); } return this.#projectFolder.ensureFolder("scripts"); } async ensureScriptGenFolder() { const scriptsFolder = await this.ensureMainScriptsFolder(); if (!scriptsFolder) { throw new Error("Unexpectedly could not create a main scripts folder"); } return scriptsFolder.ensureFolder("_gen"); } get preferredScriptLanguage() { if (this.#data.preferredScriptLanguage === undefined || this.#data.preferredScriptLanguage === IProjectData_1.ProjectScriptLanguage.typeScript) { return IProjectData_1.ProjectScriptLanguage.typeScript; } return this.#data.preferredScriptLanguage; } set preferredScriptLanguage(newLanguage) { this.#data.preferredScriptLanguage = newLanguage; } get scriptVersion() { if (this.#data.scriptVersion === undefined) { return IProjectData_1.ProjectScriptVersion.latestStable; } return this.#data.scriptVersion; } get messages() { return this.#data.messages; } set scriptVersion(newVersion) { this.#data.scriptVersion = newVersion; } get effectiveEditPreference() { if (this.editPreference === IProjectData_1.ProjectEditPreference.default || !this.editPreference) { if (this.creatorTools.editPreference === ICreatorToolsData_1.CreatorToolsEditPreference.raw) { return IProjectData_1.ProjectEditPreference.raw; } else if (this.creatorTools.editPreference === ICreatorToolsData_1.CreatorToolsEditPreference.editors) { return IProjectData_1.ProjectEditPreference.editors; } else if (this.creatorTools.editPreference === ICreatorToolsData_1.CreatorToolsEditPreference.summarized) { if (this.isVanillaEditSession) { return IProjectData_1.ProjectEditPreference.editors; } return IProjectData_1.ProjectEditPreference.summarized; } return IProjectData_1.ProjectEditPreference.editors; } return this.editPreference; } get editPreference() { if (this.#data.editPreference === undefined) { return IProjectData_1.ProjectEditPreference.default; } return this.#data.editPreference; } set editPreference(newEditPreference) { this.#data.editPreference = newEditPreference; } get contentsModified() { let val = this.#data.contentsModified; if (val === null) { return null; } if (!(val instanceof Date)) { val = new Date(val); } return val; } get created() { let val = this.#data.created; if (!val) { return null; } if (!(val instanceof Date)) { val = new Date(val); } return val; } set created(value) { this.#data.created = value; } get lastOpened() { let val = this.#data.lastOpened; if (!val) { return null; } if (!(val instanceof Date)) { val = new Date(val); } return val; } set lastOpened(value) { this.#data.lastOpened = value; } getItemsCopy() { return this.#items.slice(); } getItemsByType(itemType) { let itemsByTypeArr = this.#itemsByType.get(itemType); if (itemsByTypeArr) { return itemsByTypeArr; } itemsByTypeArr = []; for (const item of this.#items) { if (item.itemType === itemType) { itemsByTypeArr.push(item); } } this.#itemsByType.set(itemType, itemsByTypeArr); return itemsByTypeArr; } initializeWorldSettings() { if (this.#data.worldSettings === undefined) { this.#data.worldSettings = { gameType: WorldLevelDat_1.GameType.creative, generator: WorldLevelDat_1.Generator.infinite, randomSeed: "2000", isEditor: false, backupType: IWorldSettings_1.BackupType.every5Minutes, useCustomSettings: false, }; this.ensureDefaultWorldName(); } } ensureDefaultWorldName() { if (this.worldSettings && this.worldSettings.name === undefined) { this.worldSettings.name = this.name + " " + Utilities_1.default.getDateStr(new Date()); } } initializeEditorWorldSettings() { if (this.#data.editorWorldSettings === undefined) { this.#data.editorWorldSettings = { gameType: WorldLevelDat_1.GameType.creative, generator: WorldLevelDat_1.Generator.infinite, randomSeed: "2000", isEditor: true, backupType: IWorldSettings_1.BackupType.every5Minutes, useCustomSettings: false, }; this.ensureDefaultEditorWorldName(); } } ensureDefaultEditorWorldName() { if (this.editorWorldSettings && this.editorWorldSettings.name === undefined) { this.editorWorldSettings.name = this.name + " " + Utilities_1.default.getDateStr(new Date()); this.save(); } } addMessage(message, context, operation, type, topic) { if (this.#data.messages === undefined) { this.#data.messages = []; } if (type === undefined) { type = Status_1.StatusType.message; } const messageCanon = message.trim().toLowerCase(); if (messageCanon.length > 1) { const status = { time: new Date(), message: message, context: context, operation: operation, topic: topic, type: type, }; this.#data.messages.push(status); } } appendErrors(errorable, operation) { if (!errorable.errorMessages) { return; } for (const err of errorable.errorMessages) { this.creatorTools.notifyStatusUpdate(err.message, Status_1.StatusTopic.general); this.addMessage(err.message, err.context, operation, Status_1.StatusType.message); } } removeItem(item) { const newArr = []; for (let i = 0; i < this.items.length; i++) { if (this.items[i] !== item) { newArr.push(this.items[i]); } } const path = ProjectUtilities_1.default.canonicalizeStoragePath(item.projectPath); if (!Utilities_1.default.isUsableAsObjectKey(path)) { return; } this.#itemsByProjectPath.delete(path); this.#itemsByType.delete(item.itemType); this.#items = newArr; const newDataArr = []; for (let i = 0; i < this.#data.items.length; i++) { if (this.#data.items[i].projectPath !== item.projectPath) { newDataArr.push(this.#data.items[i]); } } this.#data.items = newDataArr; this.#indevInfoSetNeedsUpdating = true; this._onItemRemoved.dispatch(this, item); } updateContentsModified() { this.#data.contentsModified = new Date(); } get modified() { if (this.#preferencesFile != null && this.#preferencesFile.latestModified != null) { if (this.contentsModified != null && this.contentsModified > this.#preferencesFile.latestModified) { return this.contentsModified; } return this.#preferencesFile.latestModified; } else { return this.contentsModified; } } get effectiveShowHiddenItems() { if (this.#data.showHiddenItems === true || this.effectiveEditPreference === IProjectData_1.ProjectEditPreference.raw || this.effectiveEditPreference === IProjectData_1.ProjectEditPreference.editors) { return true; } return false; } get showDevFiles() { return this.#data.showDevFiles === true; } set showDevFiles(show) { if (show !== this.showDevFiles) { this.#data.showDevFiles = show; this._onPropertyChanged.dispatch(this, "showDevFiles"); } } get showHiddenItems() { if (this.#data.showHiddenItems === true) { return true; } return false; } set showHiddenItems(showItems) { if (showItems !== this.showHiddenItems) { this.#data.showHiddenItems = showItems; this._onPropertyChanged.dispatch(this, "showHiddenItems"); } } get showFunctions() { if (this.#data.showFunctions === undefined) { return true; } return this.#data.showFunctions; } set showFunctions(showFunctions) { if (showFunctions !== this.showFunctions) { this.#data.showFunctions = showFunctions; this._onPropertyChanged.dispatch(this, "showFunctions"); } } get showAssets() { if (this.#data.showAssets === undefined) { return true; } return this.#data.showAssets; } set showAssets(showAssets) { if (showAssets !== this.showAssets) { this.#data.showAssets = showAssets; this._onPropertyChanged.dispatch(this, "showAssets"); } } get showTypes() { if (this.#data.showTypes === undefined) { return true; } return this.#data.showTypes; } set showTypes(showTypes) { if (showTypes !== this.showTypes) { this.#data.showTypes = showTypes; this._onPropertyChanged.dispatch(this, "showTypes"); } } get name() { return this.#data.name; } get simplifiedName() { return ProjectUtilities_1.default.getSimplifiedProjectName(this.#data.name); } set name(newName) { this.#data.name = newName; } get lastMapDeployedHash() { return this.#data.lastMapDeployedHash; } get lastMapDeployedDate() { return this.#data.lastMapDeployedDate; } set lastMapDeployedHash(newValue) { this.#data.lastMapDeployedHash = newValue; } set lastMapDeployedDate(newValue) { this.#data.lastMapDeployedDate = newValue; } get deployWorldId() { if (!this.#data.deployWorldId) { this.#data.deployWorldId = Utilities_1.default.createUuid(); } return this.#data.deployWorldId; } set deployWorldId(newValue) { this.#data.deployWorldId = newValue; } get previewImageBase64() { return this.#data.previewImageBase64; } set previewImageBase64(newValue) { this.#data.previewImageBase64 = newValue; } get effectiveCreator() { if (this.#data.creator && this.#data.creator.length > 0) { return this.#data.creator; } if (this.creatorTools.creator && this.creatorTools.creator.length > 0) { return this.creatorTools.creator; } return "contoso"; } get effectiveShortName() { if (this.#data.shortName && this.#data.shortName.length > 0) { return this.#data.shortName; } if (this.effectiveCreator.length > 0 && this.#data.name && this.#data.name.length > 0) { return ProjectUtilities_1.default.getSuggestedProjectShortName(this.effectiveCreator, this.#data.name); } return "cont_game"; } get shortName() { return this.#data.shortName; } set shortName(newShortName) { if (this.#data.shortName !== newShortName) { this.#data.shortName = newShortName; this._onPropertyChanged.dispatch(this, "shortName"); } } get creator() { return this.#data.creator; } set creator(newCreator) { if (this.#data.creator !== newCreator) { this.#data.creator = newCreator; this._onPropertyChanged.dispatch(this, "creator"); } } get title() { if (this.#data.title) { return this.#data.title; } return this.name; } set title(newTitle) { if (this.#data.title !== newTitle) { this.#data.title = newTitle; this._onPropertyChanged.dispatch(this, "title"); } } get track() { return this.#data.track; } set track(newTrack) { if (newTrack !== this.#data.track) { this.#data.track = newTrack; this._onPropertyChanged.dispatch(this, "track"); } } get effectiveTrack() { if (this.#data.track !== undefined) { return this.#data.track; } return this.#creatorTools.effectiveTrack; } set originalFullPath(newOriginalPath) { if (this.#data.originalFullPath !== newOriginalPath) { this.#data.originalFullPath = newOriginalPath; this._onPropertyChanged.dispatch(this, "originalFullPath"); } } get originalFullPath() { return this.#data.originalFullPath; } set originalFileList(newFileList) { if (this.#data.originalFileList !== newFileList) { this.#data.originalFileList = newFileList; this._onPropertyChanged.dispatch(this, "originalFileList"); } } get originalFileList() { return this.#data.originalFileList; } set originalGitHubOwner(newGitHubOwner) { if (this.#data.originalGitHubOwner !== newGitHubOwner) { this.#data.originalGitHubOwner = newGitHubOwner; this._onPropertyChanged.dispatch(this, "originalGitHubOwner"); } } set originalGalleryId(newGalleryId) { if (this.#data.originalGalleryId !== newGalleryId) { this.#data.originalGalleryId = newGalleryId; this._onPropertyChanged.dispatch(this, "originalGalleryId"); } } get originalGalleryId() { return this.#data.originalGalleryId; } set originalSampleId(newSampleId) { if (this.#data.originalSampleId !== newSampleId) { this.#data.originalSampleId = newSampleId; this._onPropertyChanged.dispatch(this, "originalSampleId"); } } get originalSampleId() { return this.#data.originalSampleId; } get originalGitHubOwner() { return this.#data.originalGitHubOwner; } set originalGitHubFolder(newGitHubFolder) { if (this.#data.originalGitHubFolder !== newGitHubFolder) { this.#data.originalGitHubFolder = newGitHubFolder; this._onPropertyChanged.dispatch(this, "originalGitHubFolder"); } } get originalGitHubFolder() { return this.#data.originalGitHubFolder; } set originalGitHubRepoName(newGitHubRepoName) { if (this.#data.originalGitHubRepoName !== newGitHubRepoName) { this.#data.originalGitHubRepoName = newGitHubRepoName; this._onPropertyChanged.dispatch(this, "originalGitHubRepoName"); } } get originalGitHubRepoName() { return this.#data.originalGitHubRepoName; } set originalGitHubBranch(newGitHubBranch) { if (this.#data.originalGitHubBranch !== newGitHubBranch) { this.#data.originalGitHubBranch = newGitHubBranch; this._onPropertyChanged.dispatch(this, "originalGitHubBranch"); } } get originalGitHubBranch() { return this.#data.originalGitHubBranch; } set gitHubOwner(newGitHubOwner) { if (this.#data.gitHubOwner !== newGitHubOwner) { this.#data.gitHubOwner = newGitHubOwner; this._onPropertyChanged.dispatch(this, "gitHubOwner"); } } get gitHubOwner() { return this.#data.gitHubOwner; } set gitHubFolder(newGitHubFolder) { if (this.#data.gitHubFolder !== newGitHubFolder) { this.#data.gitHubFolder = newGitHubFolder; this._onPropertyChanged.dispatch(this, "gitHubFolder"); } } get gitHubFolder() { return this.#data.gitHubFolder; } set gitHubRepoName(newGitHubRepoName) { if (this.#data.gitHubRepoName !== newGitHubRepoName) { this.#data.gitHubRepoName = newGitHubRepoName; this._onPropertyChanged.dispatch(this, "gitHubRepoName"); } } get gitHubRepoName() { return this.#data.gitHubRepoName; } set gitHubBranch(newGitHubBranch) { if (this.#data.gitHubBranch !== newGitHubBranch) { this.#data.gitHubBranch = newGitHubBranch; this._onPropertyChanged.dispatch(this, "gitHubBranch"); } } get gitHubBranch() { return this.#data.gitHubBranch; } get description() { return this.#data.description; } set description(newDescription) { if (this.#data.description !== newDescription) { this.#data.description = newDescription; this._onPropertyChanged.dispatch(this, "description"); } } async applyDescription(newTitle) { this.title = newTitle; if (this.editPreference === IProjectData_1.ProjectEditPreference.summarized && this.defaultBehaviorPackUniqueId) { for (const projectItem of this.items) { const itemFile = projectItem.primaryFile; if (itemFile && projectItem.itemType === IProjectItemData_1.ProjectItemType.behaviorPackManifestJson) { const manifestJson = await BehaviorManifestDefinition_1.default.ensureOnFile(itemFile); if (manifestJson && manifestJson.definition && Utilities_1.default.uuidEqual(manifestJson.definition.header.uuid, this.defaultBehaviorPackUniqueId)) { const header = manifestJson.ensureHeader(this.title, this.description); header.name = newTitle; await manifestJson.save(); } } } } } get autoDeploymentMode() { if (this.#data.autoDeploymentMode === undefined) { return 0; } return this.#data.autoDeploymentMode; } set autoDeploymentMode(newMode) { if (this.#data.autoDeploymentMode !== newMode) { this.#data.autoDeploymentMode = newMode; this._onPropertyChanged.dispatch(this, "autoDeploymentMode"); } } get versionAsArray() { let vmj = this.#data.versionMajor; if (vmj === undefined) { vmj = 0; } let vmi = this.#data.versionMinor; if (vmi === undefined) { vmi = 0; } let vmp = this.#data.versionPatch; if (vmp === undefined) { vmp = 0; } return [vmj, vmi, vmp]; } get versionAsString() { let vmj = this.#data.versionMajor; if (vmj === undefined) { vmj = 0; } let vmi = this.#data.versionMinor; if (vmi === undefined) { vmi = 0; } let vmp = this.#data.versionPatch; if (vmp === undefined) { vmp = 0; } return vmj + "." + vmi + "." + vmp; } get versionMajor() { return this.#data.versionMajor; } set versionMajor(newVersion) { if (this.#data.versionMajor !== newVersion) { this.#data.versionMajor = newVersion; this._onPropertyChanged.dispatch(this, "versionMajor"); } } get versionMinor() { return this.#data.versionMinor; } set versionMinor(newVersion) { if (this.#data.versionMinor !== newVersion) { this.#data.versionMinor = newVersion; this._onPropertyChanged.dispatch(this, "versionMinor"); } } get ve