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