UNPKG

@xmcl/resourcepack

Version:
399 lines (393 loc) 12 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // index.ts var resourcepack_exports = {}; __export(resourcepack_exports, { ModelLoader: () => ModelLoader, ResourceLocation: () => ResourceLocation, ResourceManager: () => ResourceManager, ResourcePack: () => ResourcePack, readIcon: () => readIcon, readPackMeta: () => readPackMeta, readPackMetaAndIcon: () => readPackMetaAndIcon }); module.exports = __toCommonJS(resourcepack_exports); var import_system2 = require("@xmcl/system"); // resourceManager.ts var ResourceManager = class { constructor(list = []) { this.list = list; } get allResourcePacks() { return this.list.map((l) => l.info); } /** * Add a new resource source as the first priority of the resource list. */ async addResourcePack(resourcePack) { let info; try { info = await resourcePack.info(); } catch { info = { pack_format: -1, description: "" }; } const domains = await resourcePack.domains(); const wrapper = { info, source: resourcePack, domains }; this.list.push(wrapper); return wrapper; } remove(index) { return this.list.splice(index, 1)[0]; } /** * Clear all resource packs in this manager */ clear() { return this.list.splice(0, this.list.length); } /** * Swap the resource source priority. */ swap(first, second) { if (first >= this.list.length || first < 0 || second >= this.list.length || second < 0) { throw new Error("Illegal index"); } const fir = this.list[first]; this.list[first] = this.list[second]; this.list[second] = fir; } /** * Get the resource in that location. This will walk through current resource source list to load the resource. * @param location The resource location */ async get(location) { for (let i = this.list.length - 1; i >= 0; i--) { const src = this.list[i]; const resource = await src.source.get(location); if (resource) { return resource; } } return void 0; } }; // resourcePack.ts var import_system = require("@xmcl/system"); var ResourceLocation = class { constructor(domain, path) { this.domain = domain; this.path = path; } static deconstruct(path, appendPath = "") { const splitPath = path.split(":"); const domain = splitPath.length > 1 && splitPath[0] ? splitPath[0] : "minecraft"; let resourcePath = splitPath.length > 1 ? splitPath[1] : splitPath[0]; if (appendPath.length > 0) { if (appendPath.charAt(appendPath.length - 1) !== "/") { appendPath = appendPath + "/"; } if (!resourcePath.startsWith(appendPath)) { resourcePath = appendPath + resourcePath; } } return new ResourceLocation(domain, resourcePath); } /** * build from texture path */ static ofTexturePath(location) { if (typeof location === "string") { location = ResourceLocation.deconstruct(location); } return new ResourceLocation(location.domain, `textures/${location.path}.png`); } /** * build from model path */ static ofBlockModelPath(location) { location = ResourceLocation.deconstruct(location.toString(), "block/"); return new ResourceLocation(location.domain, `models/${location.path}.json`); } static ofItemModelPath(location) { location = ResourceLocation.deconstruct(location.toString(), "item/"); return new ResourceLocation(location.domain, `models/${location.path}.json`); } static ofModelPath(location) { if (typeof location === "string") { location = ResourceLocation.deconstruct(location); } return new ResourceLocation(location.domain, `models/${location.path}.json`); } /** * build from block state path */ static ofBlockStatePath(location) { if (typeof location === "string") { location = ResourceLocation.deconstruct(location); } return new ResourceLocation(location.domain, `blockstates/${location.path}.json`); } /** * from absoluted path */ static fromPath(location) { return ResourceLocation.deconstruct(location.toString()); } static getAssetsPath(location) { if (typeof location === "string") { location = ResourceLocation.deconstruct(location); } return `assets/${location.domain}/${location.path}`; } toString() { return `${this.domain}:${this.path}`; } }; var ResourcePack = class { constructor(fs) { this.fs = fs; } /** * Load the resource content * @param location The resource location * @param type The output type of the resource */ async load(location, type) { const p = this.getPath(location); if (await this.fs.existsFile(p)) { return this.fs.readFile(p, type); } return void 0; } /** * Load the resource metadata which is localted at <resource-path>.mcmeta */ async loadMetadata(location) { const p = this.getPath(location); const name = p.substring(0, p.lastIndexOf(".")); const metafileName = name + ".mcmeta"; return await this.fs.existsFile(metafileName) ? JSON.parse((await this.fs.readFile(metafileName, "utf-8")).replace(/^\uFEFF/, "")) : {}; } /** * Get the url of the resource location. * Please notice that this is depended on `FileSystem` implementation of the `getUrl`. * * @returns The absolute url like `file://` or `http://` depending on underlaying `FileSystem`. * @see {@link FileSystem} */ getUrl(location) { const p = this.getPath(location); return this.fs.getUrl(p); } /** * Get the resource on the resource location. * * It can be undefined if there is no resource at that location. * @param location THe resource location */ async get(location) { if (await this.has(location)) { return { location, url: this.getUrl(location), read: (encoding) => this.load(location, encoding), readMetadata: () => this.loadMetadata(location) }; } } /** * Does the resource pack has the resource */ has(location) { return this.fs.existsFile(this.getPath(location)); } /** * The owned domain. You can think about the modids. */ async domains() { const files = await this.fs.listFiles("assets"); const result = []; for (const f of files) { if (await this.fs.isDirectory("assets/" + f)) { result.push(f); } } return result; } /** * The pack info, just like resource pack */ async info() { const { pack } = await this.fs.readFile("pack.mcmeta", "utf-8").then( (s) => JSON.parse(s.replace(/^\uFEFF/, "")), () => { throw new Error("Illegal Resourcepack: Cannot find pack.mcmeta!"); } ); if (!pack) { throw new Error("Illegal Resourcepack: pack.mcmeta doesn't contain the pack metadata!"); } return pack; } /** * The icon of the resource pack */ icon() { return this.fs.readFile("pack.png"); } getPath(location) { return `assets/${location.domain}/${location.path}`; } static async open(resourcePack) { return new ResourcePack(await (0, import_system.resolveFileSystem)(resourcePack)); } }; // modelLoader.ts var ModelLoader = class { /** * @param loader The resource loader */ constructor(loader) { this.loader = loader; } static findRealTexturePath(model, variantKey) { let texturePath = model.textures[variantKey]; while (texturePath.startsWith("#")) { const next = model.textures[texturePath.substring(1, texturePath.length)]; if (!next) { return void 0; } texturePath = next; } return texturePath; } /** * All required texture raw resources */ textures = {}; /** * All the resolved model */ models = {}; /** * Load a model by search its parent. It will throw an error if the model is not found. */ async loadModel(modelPath, folder = "block") { const path = ResourceLocation.deconstruct(modelPath, folder); const resourceLocation = ResourceLocation.ofModelPath(path); const cacheName = resourceLocation.toString(); if (this.models[cacheName] !== void 0) { return this.models[cacheName]; } const resource = await this.loader.get(resourceLocation); if (!resource) { throw new Error(`Model ${modelPath} (${resourceLocation}) not found`); } const baseModel = JSON.parse(await resource.read("utf-8")); if (!baseModel.textures) { baseModel.textures = {}; } if (baseModel.parent) { const parentModel = await this.loadModel(baseModel.parent, ""); if (!parentModel) { throw new Error(`Missing parent model ${baseModel.parent} for ${resource.location}`); } if (!baseModel.elements) { baseModel.elements = parentModel.elements; } if (!baseModel.ambientocclusion) { baseModel.ambientocclusion = parentModel.ambientocclusion; } if (!baseModel.display) { baseModel.display = parentModel.display; } if (!baseModel.overrides) { baseModel.overrides = parentModel.overrides; } if (parentModel.textures) { Object.assign(baseModel.textures, parentModel.textures); } } baseModel.ambientocclusion = baseModel.ambientocclusion || false; baseModel.overrides = baseModel.overrides || []; delete baseModel.parent; const model = baseModel; const reg = this.textures; for (const variant of Object.keys(model.textures)) { const texPath = ModelLoader.findRealTexturePath(model, variant); if (texPath) { const load = await this.loader.get(ResourceLocation.ofTexturePath(texPath)); if (load) { reg[texPath] = load; } } } this.models[cacheName] = model; return model; } }; // index.ts async function readPackMeta(resourcePack) { const system = await (0, import_system2.resolveFileSystem)(resourcePack); try { if (!await system.existsFile("pack.mcmeta")) { throw new Error("Illegal Resourcepack: Cannot find pack.mcmeta!"); } const metadata = JSON.parse((await system.readFile("pack.mcmeta", "utf-8")).replace(/^\uFEFF/, "")); if (!metadata.pack) { throw new Error("Illegal Resourcepack: pack.mcmeta doesn't contain the pack metadata!"); } return metadata.pack; } finally { if (system !== resourcePack) system.close(); } } async function readIcon(resourcePack) { const system = await (0, import_system2.resolveFileSystem)(resourcePack); try { return system.readFile("pack.png"); } finally { if (system !== resourcePack) system.close(); } } async function readPackMetaAndIcon(resourcePack) { const system = await (0, import_system2.resolveFileSystem)(resourcePack); try { return { metadata: await readPackMeta(system), icon: await readIcon(system).catch(() => void 0) }; } finally { if (system !== resourcePack) system.close(); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ModelLoader, ResourceLocation, ResourceManager, ResourcePack, readIcon, readPackMeta, readPackMetaAndIcon }); //# sourceMappingURL=index.js.map