UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

310 lines (307 loc) 10.7 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.VibrantVisualsFileExtensionVariants = void 0; const Log_1 = __importDefault(require("../core/Log")); const ste_events_1 = require("ste-events"); const StorageUtilities_1 = __importStar(require("../storage/StorageUtilities")); const exifrModule = __importStar(require("exifr")); // Handle CJS/ESM interop: esbuild wraps CJS default export, while ts-node uses named exports directly const Exifr = exifrModule.Exifr || exifrModule.default?.Exifr; const ImageCodec_1 = __importDefault(require("../core/ImageCodec")); exports.VibrantVisualsFileExtensionVariants = [ "_mer.png", "_mer.tga", "_mers.png", "_mers.tga", // "_normal.png", <-- too many false positives // "_normal.tga", ".texture_set.json", ]; class TextureDefinition { _file; _isLoaded = false; _isContentProcessed = false; _width; _height; _errorMessage; _errorProcessing; _imageData; _onLoaded = new ste_events_1.EventDispatcher(); id; get width() { return this._width; } get height() { return this._height; } get errorMessage() { return this._errorMessage; } get errorProcessing() { return this._errorProcessing; } get imageData() { return this._imageData; } get data() { if (!this._file || !this._file.content || typeof this._file.content === "string") { return undefined; } return this._file.content; } get isLoaded() { return this._isLoaded; } get file() { return this._file; } get onLoaded() { return this._onLoaded.asEvent(); } set file(newFile) { this._file = newFile; } getPixel(x, y) { if (!this._imageData) { throw new Error("Image data is not available."); } const width = this._width ?? 0; const height = this._height ?? 0; if (x < 0 || x >= width || y < 0 || y >= height) { throw new Error("Invalid pixel coordinates."); } const index = (y * width + x) * 4; return { r: this._imageData[index], g: this._imageData[index + 1], b: this._imageData[index + 2], a: this._imageData[index + 3], }; } get isContentProcessed() { return this._isContentProcessed; } async processContent() { if (this._isContentProcessed) { return; } if (!this._file) { return; } if (!this._file.isContentLoaded) { await this._file.loadContent(); } if (!this._file.content || !(this._file.content instanceof Uint8Array)) { return; } if (this._file.type !== "tga") { const exifr = new Exifr({}); try { await exifr.read(this._file.content); const results = await exifr.parse(); if (!results) { this._errorProcessing = true; this._errorMessage = "No results returned."; } else { this._width = results.ImageWidth; this._height = results.ImageHeight; } } catch (e) { this._errorProcessing = true; this._errorMessage = e.message ? e.message : e.toString(); } } else { try { const decoded = await ImageCodec_1.default.decodeTga(this._file.content); if (decoded) { this._width = decoded.width; this._height = decoded.height; this._imageData = decoded.pixels; } else { this._errorProcessing = true; this._errorMessage = "Failed to decode TGA image."; } } catch (e) { this._errorProcessing = true; this._errorMessage = e.message ? e.message : e.toString(); } } /* this usage of pngjs didn't seem to work for a significant portion of PNGs same with the upnp library if (this._file.type === "png" && this._file.content && this._file.content instanceof Uint8Array) { try { const pngm = PNG.sync.read(Buffer.from(this._file.content.buffer)); if (pngm.width !== this._width || pngm.height !== this._height) { throw new Error("Mismatch in parsed image dimensions."); } this._imageData = new Uint8Array(pngm.data); } catch (e: any) { Log.verbose("Could not get PNG data for " + this._file.extendedPath); } }*/ this._isContentProcessed = true; } unloadContent() { this._isContentProcessed = false; this._imageData = undefined; } /** * Decode image data (PNG or TGA) to raw RGBA pixels. * This is a shared utility method for use by Model2DRenderer, ModelMeshFactory, etc. * * @param data Raw image file bytes * @param fileType File extension ('png' or 'tga') * @returns Decoded pixels with width, height, and RGBA data, or undefined if decoding fails */ static async decodeToPixels(data, fileType) { if (fileType === "tga") { return ImageCodec_1.default.decodeTga(data); } else if (fileType === "png") { return ImageCodec_1.default.decodePng(data); } return undefined; } static async ensureOnFile(file, loadHandler) { let texd; if (file.manager === undefined) { texd = new TextureDefinition(); texd.file = file; file.manager = texd; } if (file.manager !== undefined && file.manager instanceof TextureDefinition) { texd = file.manager; if (!texd.isLoaded) { if (loadHandler) { texd.onLoaded.subscribe(loadHandler); } await texd.load(); } } return texd; } getReferencePath() { if (!this._file) { return undefined; } let projectPath = this._file.storageRelativePath; return TextureDefinition.getTexturePath(projectPath); } static canonicalizeTexturePath(projectPath) { if (projectPath === undefined) { return undefined; } projectPath = projectPath.toLowerCase(); const lastPeriod = projectPath.lastIndexOf("."); if (lastPeriod >= 0) { const removedPart = projectPath.substring(lastPeriod + 1); if (StorageUtilities_1.AllowedExtensionsSet.has(removedPart)) { projectPath = projectPath.substring(0, lastPeriod); } } return projectPath; } static getTexturePath(projectPath) { const lastPeriod = projectPath.lastIndexOf("."); if (lastPeriod >= 0) { projectPath = projectPath.substring(0, lastPeriod); } const ppLower = projectPath.toLowerCase(); const texturesIndex = ppLower.indexOf("/textures/"); if (texturesIndex < 0) { return undefined; } return projectPath.substring(texturesIndex + 1); } persist() { return false; } async load() { if (this._isLoaded) { return; } if (this._file === undefined) { Log_1.default.unexpectedUndefined("TSCDF"); return; } await this._file.loadContent(); if (!this._file.content || typeof this._file.content === "string") { return; } this._isLoaded = true; this._onLoaded.dispatch(this, this); } async addChildItems(project, item) { // Only process VV sidecar files for this specific texture item let pf = item.primaryFile; if (!pf) { await item.ensureStorage(); pf = item.primaryFile; } if (pf) { const parentFolder = pf.parentFolder; if (!parentFolder) { return; } if (!parentFolder.isLoaded) { await parentFolder.load(); } let baseName = StorageUtilities_1.default.getBaseFromName(pf.name); const parentFiles = parentFolder.files; for (const ext of exports.VibrantVisualsFileExtensionVariants) { const vvSidecarFile = parentFiles[baseName + ext]; if (vvSidecarFile !== undefined && vvSidecarFile.extendedPath) { const sidecarItem = project.getItemByExtendedOrProjectPath(vvSidecarFile.extendedPath); if (sidecarItem && sidecarItem !== item) { item.addChildItem(sidecarItem); } } } } } } exports.default = TextureDefinition;