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