UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

219 lines (218 loc) 13.1 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 AttachableResourceDefinition_1 = __importDefault(require("../minecraft/AttachableResourceDefinition")); const BiomeBehaviorDefinition_1 = __importDefault(require("../minecraft/BiomeBehaviorDefinition")); const BlockTypeDefinition_1 = __importDefault(require("../minecraft/BlockTypeDefinition")); const EntityTypeDefinition_1 = __importDefault(require("../minecraft/EntityTypeDefinition")); const EntityTypeResourceDefinition_1 = __importDefault(require("../minecraft/EntityTypeResourceDefinition")); const FeatureDefinition_1 = __importDefault(require("../minecraft/FeatureDefinition")); const FeatureRuleDefinition_1 = __importDefault(require("../minecraft/FeatureRuleDefinition")); const FlipbookTextureCatalogDefinition_1 = __importDefault(require("../minecraft/FlipbookTextureCatalogDefinition")); const ItemTextureCatalogDefinition_1 = __importDefault(require("../minecraft/ItemTextureCatalogDefinition")); const ItemTypeDefinition_1 = __importDefault(require("../minecraft/ItemTypeDefinition")); const JigsawProcessorListDefinition_1 = __importDefault(require("../minecraft/JigsawProcessorListDefinition")); const JigsawStructureDefinition_1 = __importDefault(require("../minecraft/JigsawStructureDefinition")); const JigsawStructureSetDefinition_1 = __importDefault(require("../minecraft/JigsawStructureSetDefinition")); const JigsawTemplatePoolDefinition_1 = __importDefault(require("../minecraft/JigsawTemplatePoolDefinition")); const JsonUIResourceDefinition_1 = __importDefault(require("../minecraft/JsonUIResourceDefinition")); const LootTableBehaviorDefinition_1 = __importDefault(require("../minecraft/LootTableBehaviorDefinition")); const MusicDefinitionCatalogDefinition_1 = __importDefault(require("../minecraft/MusicDefinitionCatalogDefinition")); const ParticleEffectResourceDefinition_1 = __importDefault(require("../minecraft/ParticleEffectResourceDefinition")); const RecipeBehaviorDefinition_1 = __importDefault(require("../minecraft/RecipeBehaviorDefinition")); const SkinCatalogDefinition_1 = __importDefault(require("../minecraft/SkinCatalogDefinition")); const SoundCatalogDefinition_1 = __importDefault(require("../minecraft/SoundCatalogDefinition")); const SoundDefinitionCatalogDefinition_1 = __importDefault(require("../minecraft/SoundDefinitionCatalogDefinition")); const SpawnRulesBehaviorDefinition_1 = __importDefault(require("../minecraft/SpawnRulesBehaviorDefinition")); const TerrainTextureCatalogDefinition_1 = __importDefault(require("../minecraft/TerrainTextureCatalogDefinition")); const TextureDefinition_1 = __importDefault(require("../minecraft/TextureDefinition")); const TextureSetDefinition_1 = __importDefault(require("../minecraft/TextureSetDefinition")); const IProjectItemData_1 = require("./IProjectItemData"); const RelationsIndex_1 = __importDefault(require("./RelationsIndex")); const Log_1 = __importDefault(require("../core/Log")); const ITEM_TYPE_CONFIG = new Map([ [IProjectItemData_1.ProjectItemType.entityTypeBehavior, EntityTypeDefinition_1.default], [IProjectItemData_1.ProjectItemType.itemTypeBehavior, ItemTypeDefinition_1.default], [IProjectItemData_1.ProjectItemType.blockTypeBehavior, BlockTypeDefinition_1.default], [IProjectItemData_1.ProjectItemType.entityTypeResource, EntityTypeResourceDefinition_1.default], [IProjectItemData_1.ProjectItemType.skinCatalogJson, SkinCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.lootTableBehavior, LootTableBehaviorDefinition_1.default], [IProjectItemData_1.ProjectItemType.particleJson, ParticleEffectResourceDefinition_1.default], [IProjectItemData_1.ProjectItemType.uiJson, JsonUIResourceDefinition_1.default], [IProjectItemData_1.ProjectItemType.attachableResourceJson, AttachableResourceDefinition_1.default], [IProjectItemData_1.ProjectItemType.itemTextureJson, ItemTextureCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.terrainTextureCatalogResourceJson, TerrainTextureCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.soundDefinitionCatalog, SoundDefinitionCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.musicDefinitionJson, MusicDefinitionCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.soundCatalog, SoundCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.recipeBehavior, RecipeBehaviorDefinition_1.default], [IProjectItemData_1.ProjectItemType.spawnRuleBehavior, SpawnRulesBehaviorDefinition_1.default], [IProjectItemData_1.ProjectItemType.jigsawStructureSet, JigsawStructureSetDefinition_1.default], [IProjectItemData_1.ProjectItemType.jigsawStructure, JigsawStructureDefinition_1.default], [IProjectItemData_1.ProjectItemType.jigsawTemplatePool, JigsawTemplatePoolDefinition_1.default], [IProjectItemData_1.ProjectItemType.jigsawProcessorList, JigsawProcessorListDefinition_1.default], [IProjectItemData_1.ProjectItemType.flipbookTexturesJson, FlipbookTextureCatalogDefinition_1.default], [IProjectItemData_1.ProjectItemType.textureSetJson, TextureSetDefinition_1.default], [IProjectItemData_1.ProjectItemType.texture, TextureDefinition_1.default], [IProjectItemData_1.ProjectItemType.biomeBehavior, BiomeBehaviorDefinition_1.default], [IProjectItemData_1.ProjectItemType.featureBehavior, FeatureDefinition_1.default], [IProjectItemData_1.ProjectItemType.featureRuleBehavior, FeatureRuleDefinition_1.default], ]); class ProjectItemRelations { static clearDependencies(project) { ProjectItemRelations.clearDependenciesForItems(project.getItemsCopy()); } static clearDependenciesForItems(items) { // clear all existing relations for (const item of items) { item.childItems = undefined; item.parentItems = undefined; } } static async calculate(project, onProgress) { const items = project.getItemsCopy(); // clear all existing relations for (const item of items) { item.childItems = undefined; item.parentItems = undefined; } // Only process items that have relation handlers - skip the rest const itemsToProcess = items.filter((item) => ITEM_TYPE_CONFIG.has(item.itemType)); const totalItems = itemsToProcess.length; if (totalItems === 0) { return; } // Pre-build the relations index for O(1) lookups instead of O(n²) scanning const index = new RelationsIndex_1.default(); if (onProgress) { onProgress("Building relations index...", 0); } const indexStartTime = Date.now(); await index.build(project); const indexBuildTime = Date.now() - indexStartTime; Log_1.default.verbose(`[RelationsIndex] Index built in ${indexBuildTime}ms, isBuilt=${index.isBuilt}, entityResources=${index.entityResourcesById.size}, animations=${index.animationsById.size}, models=${index.modelsById.size}`); // Report progress at most ~20 times total (every 5% of progress) const progressInterval = Math.max(100, Math.floor(totalItems / 20)); let lastReportedPercent = -1; const processStartTime = Date.now(); for (let i = 0; i < itemsToProcess.length; i++) { const item = itemsToProcess[i]; await this.calculateForItem(item, index); // Report progress only when percent changes by at least 5% if (onProgress && (i % progressInterval === 0 || i === totalItems - 1)) { const percent = Math.floor((i / totalItems) * 100); if (percent !== lastReportedPercent) { lastReportedPercent = percent; onProgress(`Calculating relations... (${percent}%)`, percent); } } } const processTime = Date.now() - processStartTime; Log_1.default.verbose(`[RelationsIndex] Relations processing completed in ${processTime}ms for ${itemsToProcess.length} items`); project.computeIsVanillaEditSession(); } static async calculateForItems(items, onProgress) { // Only process items that have relation handlers const itemsToProcess = items.filter((item) => ITEM_TYPE_CONFIG.has(item.itemType)); const totalItems = itemsToProcess.length; if (totalItems === 0) { return; } // Pre-build the relations index if we have enough items to justify the overhead let index; if (itemsToProcess.length > 0 && itemsToProcess[0].project) { index = new RelationsIndex_1.default(); if (onProgress) { onProgress("Building relations index...", 0); } await index.build(itemsToProcess[0].project); } // Report progress at most ~20 times total const progressInterval = Math.max(100, Math.floor(totalItems / 20)); let lastReportedPercent = -1; for (let i = 0; i < itemsToProcess.length; i++) { const item = itemsToProcess[i]; await this.calculateForItem(item, index); // Report progress only when percent changes if (onProgress && (i % progressInterval === 0 || i === totalItems - 1)) { const percent = Math.floor((i / totalItems) * 100); if (percent !== lastReportedPercent) { lastReportedPercent = percent; onProgress(`Calculating relations... (${percent}%)`, percent); } } } } static async calculateForItem(item, index) { const project = item.project; const handlerClass = ITEM_TYPE_CONFIG.get(item.itemType); if (handlerClass) { await item.ensureStorage(); if (item.primaryFile) { const handler = await handlerClass.ensureOnFile(item.primaryFile); if (handler) { await handler.addChildItems(project, item, index); } } } } static async deleteLinksFromParents(item) { if (!item.parentItems || item.parentItems.length === 0) { return; } for (const rel of item.parentItems) { if (rel.parentItem && rel.childItem) { if (rel.parentItem.itemType === IProjectItemData_1.ProjectItemType.entityTypeResource) { if (!item.isContentLoaded) { await item.loadContent(); } if (rel.parentItem.primaryFile) { const entityTypeResource = await EntityTypeResourceDefinition_1.default.ensureOnFile(rel.parentItem.primaryFile); if (entityTypeResource) { await entityTypeResource.deleteLinkToChild(rel); } } } else if (rel.parentItem.itemType === IProjectItemData_1.ProjectItemType.particleJson) { if (!item.isContentLoaded) { await item.loadContent(); } if (rel.parentItem.primaryFile) { const particleResource = await ParticleEffectResourceDefinition_1.default.ensureOnFile(rel.parentItem.primaryFile); if (particleResource) { await particleResource.deleteLinkToChild(rel); } } } else if (rel.parentItem.itemType === IProjectItemData_1.ProjectItemType.attachableResourceJson) { if (!item.isContentLoaded) { await item.loadContent(); } if (rel.parentItem.primaryFile) { const attachableResource = await AttachableResourceDefinition_1.default.ensureOnFile(rel.parentItem.primaryFile); if (attachableResource) { await attachableResource.deleteLinkToChild(rel); } } } else if (rel.parentItem.itemType === IProjectItemData_1.ProjectItemType.soundCatalog) { if (!item.isContentLoaded) { await item.loadContent(); } if (rel.parentItem.primaryFile) { const soundCat = await SoundDefinitionCatalogDefinition_1.default.ensureOnFile(rel.parentItem.primaryFile); if (soundCat) { await soundCat.deleteLinkToChild(rel.childItem); } } } } } await this.calculate(item.project); } } exports.default = ProjectItemRelations;