UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

302 lines (301 loc) 12.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 }); const ModelGeometryDefinition_1 = __importDefault(require("./ModelGeometryDefinition")); const EntityTypeResourceDefinition_1 = __importDefault(require("./EntityTypeResourceDefinition")); const VanillaProjectManager_1 = __importDefault(require("./VanillaProjectManager")); const ProjectItemUtilities_1 = __importDefault(require("../app/ProjectItemUtilities")); const IProjectItemData_1 = require("../app/IProjectItemData"); const Log_1 = __importDefault(require("../core/Log")); class EntityTextureResolver { /** * Resolve all assets (geometry + texture) for an entity. * This is the main entry point for asset resolution. */ static async resolveEntityAssets(options) { const result = { source: "none", warnings: [], }; // If direct data is provided, use it if (options.geometry) { result.geometry = options.geometry; result.source = "data"; } if (options.modelDefinition) { result.modelDefinition = options.modelDefinition; if (!result.geometry && options.modelDefinition.defaultGeometry) { result.geometry = options.modelDefinition.defaultGeometry; } result.source = "data"; } if (options.textureData) { result.textureData = options.textureData; result.source = "data"; } if (options.textureUrl) { result.textureUrl = options.textureUrl; result.source = result.source === "none" ? "url" : result.source; } // If we have all we need from direct data, extract dimensions and return if (result.geometry && (result.textureData || result.textureUrl)) { this._extractTextureDimensions(result); return result; } // Try project lookup if entityTypeId is provided and project is available if (options.entityTypeId && options.project && !options.skipVanilla) { const projectAssets = await this._resolveFromProject(options.entityTypeId, options.project, options.geometryId, options.variantKey); if (projectAssets.geometry) { result.geometry = projectAssets.geometry; result.modelDefinition = projectAssets.modelDefinition; result.geometryId = projectAssets.geometryId; result.source = "project"; } if (projectAssets.textureData) { result.textureData = projectAssets.textureData; result.texturePath = projectAssets.texturePath; } else if (projectAssets.textureUrl) { result.textureUrl = projectAssets.textureUrl; result.texturePath = projectAssets.texturePath; } } // Fall back to vanilla lookup if needed if (options.entityTypeId && !options.skipVanilla && (!result.geometry || !result.textureData)) { const vanillaAssets = await this._resolveFromVanilla(options.entityTypeId, options.geometryId, options.variantKey); if (!result.geometry && vanillaAssets.geometry) { result.geometry = vanillaAssets.geometry; result.modelDefinition = vanillaAssets.modelDefinition; result.geometryId = vanillaAssets.geometryId; result.source = "vanilla"; } if (!result.textureData && !result.textureUrl) { if (vanillaAssets.textureData) { result.textureData = vanillaAssets.textureData; } else if (vanillaAssets.textureUrl) { result.textureUrl = vanillaAssets.textureUrl; } result.texturePath = vanillaAssets.texturePath; } } // Extract texture dimensions from geometry this._extractTextureDimensions(result); return result; } /** * Resolve texture from a project item. * Finds the related texture file for a model or entity definition. */ static async resolveTextureForProjectItem(projectItem, project) { const result = {}; // Try to find a cousin texture item const textureItem = ProjectItemUtilities_1.default.getCousinOfType(projectItem, IProjectItemData_1.ProjectItemType.texture); if (textureItem) { if (!textureItem.isContentLoaded) { await textureItem.loadContent(); } const textureFile = textureItem.primaryFile; if (textureFile) { if (!textureFile.isContentLoaded) { await textureFile.loadContent(); } if (textureFile.content instanceof Uint8Array) { result.textureData = textureFile.content; result.texturePath = textureItem.projectPath ?? undefined; } } } return result; } /** * Load texture data from a URL. */ static async loadTextureFromUrl(url) { try { const response = await fetch(url); if (response.ok) { const buffer = await response.arrayBuffer(); return new Uint8Array(buffer); } } catch (error) { Log_1.default.debug(`Failed to load texture from URL ${url}: ${error}`); } return null; } /** * Load texture data from a file. */ static async loadTextureFromFile(file) { try { if (!file.isContentLoaded) { await file.loadContent(); } if (file.content instanceof Uint8Array) { return file.content; } } catch (error) { Log_1.default.debug(`Failed to load texture from file: ${error}`); } return null; } /** * Canonicalize a texture path by removing extensions and normalizing slashes. */ static canonicalizeTexturePath(path) { // Remove .png, .tga extensions let normalized = path; if (normalized.endsWith(".png") || normalized.endsWith(".tga")) { normalized = normalized.substring(0, normalized.lastIndexOf(".")); } // Normalize slashes normalized = normalized.replace(/\\/g, "/"); // Ensure it starts with textures/ if it's a relative path if (!normalized.startsWith("/") && !normalized.startsWith("textures/")) { normalized = "textures/" + normalized; } return normalized; } /** * Build a URL for a vanilla texture path. */ static buildVanillaTextureUrl(texturePath) { const canonical = this.canonicalizeTexturePath(texturePath); return `/res/latest/van/serve/resource_pack/${canonical}.png`; } /** * Resolve assets from a project. */ static async _resolveFromProject(entityTypeId, project, geometryId, variantKey) { const result = {}; // Normalize entity ID const shortId = entityTypeId.replace("minecraft:", ""); // Find entity resource definition in project const entityItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.entityTypeResource); for (const item of entityItems) { if (!item.isContentLoaded) { await item.loadContent(); } if (item.primaryFile) { const etrd = await EntityTypeResourceDefinition_1.default.ensureOnFile(item.primaryFile); if (etrd && (etrd.id === entityTypeId || etrd.id === `minecraft:${shortId}` || etrd.id === shortId)) { // Found the entity - get geometry and texture const matched = etrd.getMatchedGeometryAndTexture(variantKey || "default"); if (matched.geometryId) { result.geometryId = geometryId || matched.geometryId; // Find the geometry file in project const geoItem = await this._findGeometryInProject(project, result.geometryId); if (geoItem) { result.geometry = geoItem.geometry; result.modelDefinition = geoItem.definition; } } if (matched.texturePath) { result.texturePath = matched.texturePath; // Find the texture file in project const textureData = await this._findTextureInProject(project, matched.texturePath); if (textureData) { result.textureData = textureData; } } break; } } } return result; } /** * Find geometry in a project by geometry ID. */ static async _findGeometryInProject(project, geometryId) { const modelItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.modelGeometryJson); for (const item of modelItems) { if (!item.isContentLoaded) { await item.loadContent(); } if (item.primaryFile) { const modelDef = await ModelGeometryDefinition_1.default.ensureOnFile(item.primaryFile); if (modelDef) { const geometry = modelDef.getById(geometryId); if (geometry) { return { geometry, definition: modelDef }; } } } } return null; } /** * Find texture in a project by texture path. */ static async _findTextureInProject(project, texturePath) { const canonical = this.canonicalizeTexturePath(texturePath); const textureItems = project.getItemsByType(IProjectItemData_1.ProjectItemType.texture); for (const item of textureItems) { if (item.projectPath && item.projectPath.includes(canonical)) { if (!item.isContentLoaded) { await item.loadContent(); } if (item.primaryFile) { return this.loadTextureFromFile(item.primaryFile); } } } return null; } /** * Resolve assets from vanilla resources. */ static async _resolveFromVanilla(entityTypeId, geometryId, variantKey) { const modelData = await VanillaProjectManager_1.default.getVanillaEntityModelData(entityTypeId, variantKey || "default"); if (!modelData) { return {}; } const result = { geometry: modelData.geometry, modelDefinition: modelData.modelDefinition, geometryId: geometryId || modelData.geometryId, texturePath: modelData.texturePath, textureData: modelData.textureData, textureUrl: modelData.textureUrl, }; // If geometryId is specified and different from default, try to find it if (geometryId && geometryId !== modelData.geometryId && modelData.modelDefinition) { const specificGeometry = modelData.modelDefinition.getById(geometryId); if (specificGeometry) { result.geometry = specificGeometry; result.geometryId = geometryId; } } return result; } /** * Extract texture dimensions from geometry description. */ static _extractTextureDimensions(result) { if (!result.geometry) return; const desc = result.geometry.description; if (desc) { result.textureWidth = desc.texture_width; result.textureHeight = desc.texture_height; } else { // Try legacy properties result.textureWidth = result.geometry.texturewidth; result.textureHeight = result.geometry.textureheight; } // Defaults if (!result.textureWidth) result.textureWidth = 64; if (!result.textureHeight) result.textureHeight = 64; } } exports.default = EntityTextureResolver;