minerender 2.1.0-beta.6 → 2.1.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/browser/esm/Materials.mjs +3 -1
- package/dist/browser/esm/Materials.mjs.map +1 -1
- package/dist/browser/esm/Ticker.mjs +3 -1
- package/dist/browser/esm/Ticker.mjs.map +1 -1
- package/dist/browser/esm/UVMapper.mjs +9 -9
- package/dist/browser/esm/UVMapper.mjs.map +1 -1
- package/dist/browser/esm/armor/Armor.mjs +84 -0
- package/dist/browser/esm/armor/Armor.mjs.map +1 -0
- package/dist/browser/esm/armor/index.mjs +3 -0
- package/dist/browser/esm/armor/index.mjs.map +1 -0
- package/dist/browser/esm/assets/AssetDefaults.mjs +8 -0
- package/dist/browser/esm/assets/AssetDefaults.mjs.map +1 -0
- package/dist/browser/esm/assets/AssetKey.mjs +1 -1
- package/dist/browser/esm/assets/AssetKey.mjs.map +1 -1
- package/dist/browser/esm/assets/AssetLoader.mjs +5 -5
- package/dist/browser/esm/assets/AssetLoader.mjs.map +1 -1
- package/dist/browser/esm/assets/Assets.mjs +1 -5
- package/dist/browser/esm/assets/Assets.mjs.map +1 -1
- package/dist/browser/esm/assets/BlockEntities.mjs +5 -1
- package/dist/browser/esm/assets/BlockEntities.mjs.map +1 -1
- package/dist/browser/esm/assets/BlockStates.mjs +1 -1
- package/dist/browser/esm/assets/BlockStates.mjs.map +1 -1
- package/dist/browser/esm/assets/Entities.mjs +40 -12
- package/dist/browser/esm/assets/Entities.mjs.map +1 -1
- package/dist/browser/esm/assets/MineRenderData.mjs +8 -17
- package/dist/browser/esm/assets/MineRenderData.mjs.map +1 -1
- package/dist/browser/esm/assets/ModelTextures.mjs +13 -7
- package/dist/browser/esm/assets/ModelTextures.mjs.map +1 -1
- package/dist/browser/esm/assets/Models.mjs +1 -1
- package/dist/browser/esm/assets/Models.mjs.map +1 -1
- package/dist/browser/esm/assets/_fonts/Unihex.mjs +5 -3
- package/dist/browser/esm/assets/_fonts/Unihex.mjs.map +1 -1
- package/dist/browser/esm/assets/_versions/DatasetVersions.mjs +22 -0
- package/dist/browser/esm/assets/_versions/DatasetVersions.mjs.map +1 -0
- package/dist/browser/esm/assets/index.mjs +1 -0
- package/dist/browser/esm/assets/index.mjs.map +1 -1
- package/dist/browser/esm/assets/source/HostedAssetSource.mjs +7 -8
- package/dist/browser/esm/assets/source/HostedAssetSource.mjs.map +1 -1
- package/dist/browser/esm/cache/Caching.mjs +8 -0
- package/dist/browser/esm/cache/Caching.mjs.map +1 -1
- package/dist/browser/esm/entity/scene/EntityObject.mjs +31 -5
- package/dist/browser/esm/entity/scene/EntityObject.mjs.map +1 -1
- package/dist/browser/esm/env/browser/BrowserCache.mjs +3 -3
- package/dist/browser/esm/env/browser/BrowserCache.mjs.map +1 -1
- package/dist/browser/esm/env/browser/BrowserEnv.mjs +11 -4
- package/dist/browser/esm/env/browser/BrowserEnv.mjs.map +1 -1
- package/dist/browser/esm/image/ImageLoader.mjs +3 -3
- package/dist/browser/esm/image/ImageLoader.mjs.map +1 -1
- package/dist/browser/esm/index.browser.d.mts +191 -22
- package/dist/browser/esm/index.browser.mjs.map +1 -1
- package/dist/browser/esm/index.mjs +1 -0
- package/dist/browser/esm/index.mjs.map +1 -1
- package/dist/browser/esm/inspector/SceneInspector.mjs +3 -3
- package/dist/browser/esm/inspector/SceneInspector.mjs.map +1 -1
- package/dist/browser/esm/instance/InstanceManager.mjs +4 -4
- package/dist/browser/esm/instance/InstanceManager.mjs.map +1 -1
- package/dist/browser/esm/model/ItemGlint.mjs +7 -6
- package/dist/browser/esm/model/ItemGlint.mjs.map +1 -1
- package/dist/browser/esm/model/block/scene/BlockObject.mjs +19 -6
- package/dist/browser/esm/model/block/scene/BlockObject.mjs.map +1 -1
- package/dist/browser/esm/model/multiblock/StructureParser.mjs +7 -4
- package/dist/browser/esm/model/multiblock/StructureParser.mjs.map +1 -1
- package/dist/browser/esm/model/scene/ModelObject.mjs +4 -4
- package/dist/browser/esm/model/scene/ModelObject.mjs.map +1 -1
- package/dist/browser/esm/nbt/NBTHelper.mjs +5 -2
- package/dist/browser/esm/nbt/NBTHelper.mjs.map +1 -1
- package/dist/browser/esm/renderer/Renderer.mjs +4 -2
- package/dist/browser/esm/renderer/Renderer.mjs.map +1 -1
- package/dist/browser/esm/renderer/SceneObject.mjs +0 -6
- package/dist/browser/esm/renderer/SceneObject.mjs.map +1 -1
- package/dist/browser/esm/request/Requests.mjs +3 -3
- package/dist/browser/esm/request/Requests.mjs.map +1 -1
- package/dist/browser/esm/scene/SceneDocument.mjs +35 -5
- package/dist/browser/esm/scene/SceneDocument.mjs.map +1 -1
- package/dist/browser/esm/scene/SceneDocumentLoader.mjs +14 -3
- package/dist/browser/esm/scene/SceneDocumentLoader.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinGeometries.mjs +4 -1
- package/dist/browser/esm/skin/SkinGeometries.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinPart.mjs +2 -0
- package/dist/browser/esm/skin/SkinPart.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinTextureCoordinates.mjs +11 -1
- package/dist/browser/esm/skin/SkinTextureCoordinates.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinTextures.mjs +1 -1
- package/dist/browser/esm/skin/SkinTextures.mjs.map +1 -1
- package/dist/browser/esm/skin/Skins.mjs +6 -4
- package/dist/browser/esm/skin/Skins.mjs.map +1 -1
- package/dist/browser/esm/skin/scene/SkinObject.mjs +119 -7
- package/dist/browser/esm/skin/scene/SkinObject.mjs.map +1 -1
- package/dist/browser/esm/texture/PalettedTextures.mjs +46 -0
- package/dist/browser/esm/texture/PalettedTextures.mjs.map +1 -0
- package/dist/browser/esm/texture/TextureLoader.mjs +4 -2
- package/dist/browser/esm/texture/TextureLoader.mjs.map +1 -1
- package/dist/browser/esm/texture/index.mjs +1 -0
- package/dist/browser/esm/texture/index.mjs.map +1 -1
- package/dist/browser/esm/util/log.mjs +75 -0
- package/dist/browser/esm/util/log.mjs.map +1 -1
- package/dist/browser/esm/util/performance.mjs.map +1 -1
- package/dist/browser/esm/util/util.mjs +0 -2
- package/dist/browser/esm/util/util.mjs.map +1 -1
- package/dist/browser/esm/world/Chunk.mjs +70 -38
- package/dist/browser/esm/world/Chunk.mjs.map +1 -1
- package/dist/browser/esm/world/MineRenderWorld.mjs +187 -60
- package/dist/browser/esm/world/MineRenderWorld.mjs.map +1 -1
- package/dist/browser/esm/world/SectionMesh.mjs +65 -9
- package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
- package/dist/browser/esm/world/SectionModels.mjs +21 -15
- package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
- package/dist/browser/esm/world/SectionWorker.mjs +8 -2
- package/dist/browser/esm/world/SectionWorker.mjs.map +1 -1
- package/dist/browser/esm/world/WorldStreamer.mjs +129 -34
- package/dist/browser/esm/world/WorldStreamer.mjs.map +1 -1
- package/dist/browser/esm/world/_culling/BlockCulling.mjs +1 -1
- package/dist/browser/esm/world/_culling/BlockCulling.mjs.map +1 -1
- package/dist/browser/esm/world/_entities/WorldEntities.mjs +3 -1
- package/dist/browser/esm/world/_entities/WorldEntities.mjs.map +1 -1
- package/dist/browser/index.d.ts +191 -22
- package/dist/browser/index.js +4461 -3648
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +13482 -12651
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +179 -21
- package/dist/node/index.d.ts +179 -21
- package/dist/node/index.js +4495 -3666
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +4412 -3586
- package/dist/node/index.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/AssetKey.ts"],"sourcesContent":["import { Serializable } from \"../Serializable\";\nimport { DEFAULT_NAMESPACE } from \"./
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/AssetKey.ts"],"sourcesContent":["import { Serializable } from \"../Serializable\";\nimport { DEFAULT_NAMESPACE } from \"./AssetDefaults\";\nimport { AssetLoader } from \"./AssetLoader\";\n\nexport type AssetType = \"models\" | \"textures\" | \"blockstates\" | string;\n\n/** A Minecraft namespace and path, such as `minecraft` and `zombie`. */\nexport class BasicAssetKey implements Serializable {\n\n readonly namespace: string;\n readonly path: string;\n\n constructor(key: BasicAssetKey);\n constructor(namespace: string, path: string);\n constructor(namespaceOrKey: string | BasicAssetKey, path?: string) {\n if (path) {\n this.namespace = namespaceOrKey as string;\n this.path = path;\n } else {\n this.namespace = (namespaceOrKey as BasicAssetKey).namespace;\n this.path = (namespaceOrKey as BasicAssetKey).path\n }\n }\n\n toNamespacedString() {\n return this.namespace + \":\" + this.path;\n }\n\n toString() {\n return this.toNamespacedString();\n }\n\n serialize(): string {\n return this.toString();\n }\n}\n\n// TODO: rewrite this to be less dumb\n/** Locates an asset by namespace, directory, extension, and optional asset root. */\nexport class AssetKey extends BasicAssetKey {\n\n public readonly isAssetKey: true = true;\n\n /**\n * Creates a key from separate path components. Use {@link parse} for a combined reference.\n *\n * @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.\n * @param type - Subdirectory, such as `block` or `item`.\n * @param rootType - Top-level directory, usually `assets` or `data`.\n * @param root - Base URL override for hosted asset sources.\n */\n constructor(\n readonly namespace: string, readonly path: string,\n public assetType?: AssetType,\n public type?: string,\n public rootType: \"assets\" | \"data\" | string = \"assets\",\n public extension: \".json\" | \".png\" | string = \".json\",\n public root?: string,\n ) {\n super(namespace, path);\n }\n\n\n /**\n * Parses an asset reference such as `minecraft:block/stone`.\n * A missing namespace defaults to the origin's namespace or `minecraft`.\n *\n * @param assetType - Asset category, such as `models` or `textures`.\n * @param str - Path with an optional namespace and file extension.\n * @param origin - Supplies the asset root, default namespace, and non-texture extension.\n * @returns A key with the matching extension removed from its path. Textures use `.png`;\n * other assets use the origin's extension or `.json`.\n */\n public static parse(assetType: AssetType, str: string, origin?: AssetKey): AssetKey {\n let namespace = origin?.namespace || DEFAULT_NAMESPACE;\n if (str.includes(\":\")) {\n let split = str.split(\"\\:\");\n namespace = split[0];\n str = split[1];\n }\n\n let split = str.split(\"\\/\");\n let type: string | undefined = undefined;\n if (split.length > 1) {\n type = split[0];\n split.shift();\n }\n let path = split.join(\"/\");\n\n const extension = assetType === \"textures\" ? \".png\" :\n origin?.extension ?? \".json\";\n if (extension && path.endsWith(extension)) {\n path = path.slice(0, -extension.length);\n }\n\n return new AssetKey(namespace, path, assetType, type, \"assets\", extension, origin?.root);\n }\n\n toString(): string {\n let a = [\n this.root ?? AssetLoader.ROOT,\n this.rootType ?? \"__rootType__\",\n this.assetType ?? \"__assetType__\",\n this.type ?? \"__type__\",\n this.namespace,\n this.path\n ];\n return a.join(\"/\");\n }\n\n /** Joins the type subdirectory and path without adding a namespace or file extension. */\n getFullPath() {\n let p: string[] = [];\n if (this.type) {\n p.push(this.type);\n }\n p.push(this.path);\n return p.join(\"/\");\n }\n\n toNamespacedString() {\n return this.namespace + \":\" + this.getFullPath();\n }\n\n /** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */\n serialize(): string {\n return this.toString();\n }\n}\n\nexport function isResourceLocation(value: unknown): value is string {\n return typeof value === \"string\" && /^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(value);\n}\n\nexport function isBasicAssetKey(obj: any): obj is BasicAssetKey {\n return obj !== null && typeof obj === \"object\"\n && typeof obj.namespace === \"string\" && typeof obj.path === \"string\";\n}\n\nexport function isAssetKey(obj: any): obj is AssetKey {\n return isBasicAssetKey(obj) && (<AssetKey>obj).isAssetKey === true;\n}\n"],"mappings":";AACA,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAKrB,IAAM,gBAAN,MAA4C;AAAA,EAO/C,YAAY,gBAAwC,MAAe;AAC/D,QAAI,MAAM;AACN,WAAK,YAAY;AACjB,WAAK,OAAO;AAAA,IAChB,OAAO;AACH,WAAK,YAAa,eAAiC;AACnD,WAAK,OAAQ,eAAiC;AAAA,IAClD;AAAA,EACJ;AAAA,EAEA,qBAAqB;AACjB,WAAO,KAAK,YAAY,MAAM,KAAK;AAAA,EACvC;AAAA,EAEA,WAAW;AACP,WAAO,KAAK,mBAAmB;AAAA,EACnC;AAAA,EAEA,YAAoB;AAChB,WAAO,KAAK,SAAS;AAAA,EACzB;AACJ;AAIO,IAAM,WAAN,MAAM,kBAAiB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYxC,YACa,WAA4B,MAC9B,WACA,MACA,WAAuC,UACvC,YAAuC,SACvC,MACT;AACE,UAAM,WAAW,IAAI;AAPZ;AAA4B;AAC9B;AACA;AACA;AACA;AACA;AAhBX,SAAgB,aAAmB;AAAA,EAmBnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,OAAc,MAAM,WAAsB,KAAa,QAA6B;AAChF,QAAI,YAAY,QAAQ,aAAa;AACrC,QAAI,IAAI,SAAS,GAAG,GAAG;AACnB,UAAIA,SAAQ,IAAI,MAAM,GAAI;AAC1B,kBAAYA,OAAM,CAAC;AACnB,YAAMA,OAAM,CAAC;AAAA,IACjB;AAEA,QAAI,QAAQ,IAAI,MAAM,GAAI;AAC1B,QAAI,OAA2B;AAC/B,QAAI,MAAM,SAAS,GAAG;AAClB,aAAO,MAAM,CAAC;AACd,YAAM,MAAM;AAAA,IAChB;AACA,QAAI,OAAO,MAAM,KAAK,GAAG;AAEzB,UAAM,YAAY,cAAc,aAAa,SACzC,QAAQ,aAAa;AACzB,QAAI,aAAa,KAAK,SAAS,SAAS,GAAG;AACvC,aAAO,KAAK,MAAM,GAAG,CAAC,UAAU,MAAM;AAAA,IAC1C;AAEA,WAAO,IAAI,UAAS,WAAW,MAAM,WAAW,MAAM,UAAU,WAAW,QAAQ,IAAI;AAAA,EAC3F;AAAA,EAEA,WAAmB;AACf,QAAI,IAAI;AAAA,MACJ,KAAK,QAAQ,YAAY;AAAA,MACzB,KAAK,YAAY;AAAA,MACjB,KAAK,aAAa;AAAA,MAClB,KAAK,QAAQ;AAAA,MACb,KAAK;AAAA,MACL,KAAK;AAAA,IACT;AACA,WAAO,EAAE,KAAK,GAAG;AAAA,EACrB;AAAA;AAAA,EAGA,cAAc;AACV,QAAI,IAAc,CAAC;AACnB,QAAI,KAAK,MAAM;AACX,QAAE,KAAK,KAAK,IAAI;AAAA,IACpB;AACA,MAAE,KAAK,KAAK,IAAI;AAChB,WAAO,EAAE,KAAK,GAAG;AAAA,EACrB;AAAA,EAEA,qBAAqB;AACjB,WAAO,KAAK,YAAY,MAAM,KAAK,YAAY;AAAA,EACnD;AAAA;AAAA,EAGA,YAAoB;AAChB,WAAO,KAAK,SAAS;AAAA,EACzB;AACJ;AAEO,SAAS,mBAAmB,OAAiC;AAChE,SAAO,OAAO,UAAU,YAAY,oCAAoC,KAAK,KAAK;AACtF;AAEO,SAAS,gBAAgB,KAAgC;AAC5D,SAAO,QAAQ,QAAQ,OAAO,QAAQ,YAC/B,OAAO,IAAI,cAAc,YAAY,OAAO,IAAI,SAAS;AACpE;AAEO,SAAS,WAAW,KAA2B;AAClD,SAAO,gBAAgB,GAAG,KAAgB,IAAK,eAAe;AAClE;","names":["split"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/assets/AssetLoader.ts
|
|
2
|
-
import { DEFAULT_ROOT } from "./
|
|
2
|
+
import { DEFAULT_ROOT } from "./AssetDefaults.mjs";
|
|
3
3
|
import { AssetKey } from "./AssetKey.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { logger } from "../util/log.mjs";
|
|
5
5
|
import { HostedAssetSource } from "./source/index.mjs";
|
|
6
6
|
import { Caching } from "../cache/Caching.mjs";
|
|
7
|
-
var
|
|
7
|
+
var log = logger("AssetLoader");
|
|
8
8
|
var AssetLoader = class {
|
|
9
9
|
static get _SOURCES() {
|
|
10
10
|
return this.sources ?? (this.sources = [{ key: "mcassets", source: new HostedAssetSource(this.ROOT, { retryDefaults: false }) }]);
|
|
@@ -59,11 +59,11 @@ ${key}` : key;
|
|
|
59
59
|
if (override) {
|
|
60
60
|
const existing = this.removeSource(key);
|
|
61
61
|
if (existing) {
|
|
62
|
-
|
|
62
|
+
log.info("Removed existing AssetSource", key);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
this._SOURCES.unshift({ key, source });
|
|
66
|
-
|
|
66
|
+
log.info("Added AssetSource", key);
|
|
67
67
|
}
|
|
68
68
|
/** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
|
|
69
69
|
static removeSource(key) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/AssetLoader.ts"],"sourcesContent":["import { Model, TextureAsset } from \"../model/Model\";\nimport { Maybe } from \"../util/util\";\nimport { Requests } from \"../request/Requests\";\nimport { MinecraftAsset } from \"../MinecraftAsset\";\nimport { ImageInfo, ImageLoader } from \"../image/ImageLoader\";\nimport { MinecraftTextureMeta } from \"../MinecraftTextureMeta\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport { DEFAULT_NAMESPACE, DEFAULT_ROOT } from \"./
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/AssetLoader.ts"],"sourcesContent":["import { Model, TextureAsset } from \"../model/Model\";\nimport { Maybe } from \"../util/util\";\nimport { Requests } from \"../request/Requests\";\nimport { MinecraftAsset } from \"../MinecraftAsset\";\nimport { ImageInfo, ImageLoader } from \"../image/ImageLoader\";\nimport { MinecraftTextureMeta } from \"../MinecraftTextureMeta\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport { DEFAULT_NAMESPACE, DEFAULT_ROOT } from \"./AssetDefaults\";\nimport { ListAsset } from \"../ListAsset\";\nimport { AssetKey } from \"./AssetKey\";\nimport { NBTAsset, NBTHelper } from \"../nbt/NBTHelper\";\nimport { logger } from \"../util/log\";\nimport { AssetSource } from \"./source/AssetSource\";\nimport { AssetParser } from \"./source/parser/AssetParsers\";\nimport { HostedAssetSource } from \"./source\";\nimport { Caching } from \"../cache/Caching\";\n\nconst log = logger(\"AssetLoader\");\n\n\n/** Loads assets from a shared, ordered registry of hosted sources and resource packs. */\nexport class AssetLoader {\n\n /** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */\n static ROOT: string = DEFAULT_ROOT;\n\n private static sources: AssetSourceReference[] | undefined;\n\n private static get _SOURCES(): AssetSourceReference[] {\n return this.sources ??= [{ key: \"mcassets\", source: new HostedAssetSource(this.ROOT, { retryDefaults: false }) }];\n }\n\n private static set _SOURCES(sources: AssetSourceReference[]) {\n this.sources = sources;\n }\n\n /** Used when a registered source cannot identify its content, so nothing persists past this session. */\n private static readonly SESSION_SCOPE = `session:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;\n\n public static get version(): string {\n return this.ROOT.substring(this.ROOT.lastIndexOf(\"/\") + 1);\n }\n\n /** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */\n public static setVersion(version: string): void {\n this.ROOT = `https://assets.mcasset.cloud/${version}`;\n const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });\n const index = this._SOURCES.findIndex(s => s.key === \"mcassets\");\n if (index !== -1) {\n this._SOURCES[index] = { key: \"mcassets\", source };\n } else {\n this.addSource(\"mcassets\", source);\n }\n Caching.clear();\n }\n\n /**\n * Scope for persistent cache keys. Empty with only the default vanilla source, so its\n * entries stay valid across sessions; otherwise it names every added source (resource packs,\n * mirrors) so their results never masquerade as vanilla assets after a reload.\n */\n public static get persistentScope(): string {\n const parts: string[] = [];\n for (const { key, source } of this._SOURCES) {\n const id = source.cacheId;\n if (key === \"mcassets\" && id === `hosted:${this.ROOT}`) continue;\n if (id === undefined) return this.SESSION_SCOPE;\n parts.push(`${key}=${id}`);\n }\n return parts.join(\"|\");\n }\n\n /** Prefixes a persistent cache key with the current source scope. */\n public static persistentKey(key: string): string {\n const scope = this.persistentScope;\n return scope ? `${scope}\\n${key}` : key;\n }\n\n /**\n * Registers a source at the highest priority.\n * Call {@link Caching.clear} after changing sources to discard previously loaded assets.\n *\n * @param key - Name used to replace or remove this source.\n * @param override - Removes the first source with this name before adding the new one.\n */\n public static addSource(key: string, source: AssetSource, override: boolean = true) {\n if (override) {\n const existing = this.removeSource(key);\n if (existing) {\n log.info(\"Removed existing AssetSource\", key);\n }\n }\n\n this._SOURCES.unshift({key, source});\n log.info(\"Added AssetSource\", key);\n }\n\n /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */\n public static removeSource(key: string): Maybe<AssetSource> {\n const index = this._SOURCES.findIndex(s => s.key === key);\n if (index != -1) {\n const spliced = this._SOURCES.splice(index, 1);\n if (spliced.length > 0) {\n return spliced[0].source;\n }\n }\n return undefined;\n }\n\n /** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */\n public static async getAll<T extends MinecraftAsset>(key: AssetKey, parser: AssetParser | string): Promise<T[]> {\n const sources = [...this._SOURCES];\n const results: T[] = [];\n for (const { source } of sources) {\n const asset = await source.get<T>(key, parser);\n if (asset != undefined) results.push(asset);\n if (await source.blocks(key)) break;\n }\n return results;\n }\n\n /** Returns the first defined result in source-priority order, without merging assets. */\n public static async get<T extends MinecraftAsset>(key: AssetKey, parser: AssetParser | string): Promise<Maybe<T>> {\n const keys = [key];\n if (key.rootType === \"data\" && (key.assetType === \"structure\" || key.assetType === \"structures\")) {\n keys.push(new AssetKey(key.namespace, key.path,\n key.assetType === \"structure\" ? \"structures\" : \"structure\",\n key.type, key.rootType, key.extension, key.root));\n }\n return (await this.getFirst<T>(keys, parser))?.asset;\n }\n\n /** Tries each path within a source before considering lower-priority sources. */\n public static async getFirst<T extends MinecraftAsset>(keys: readonly AssetKey[], parser: AssetParser | string): Promise<Maybe<{ key: AssetKey; asset: T }>> {\n // Source changes affect later lookups, not the priority of an in-flight lookup.\n const sources = [...this._SOURCES];\n let remaining = [...keys];\n for (const source of sources) {\n for (const key of remaining) {\n const result = await source.source.get<T>(key, parser);\n if (result !== undefined) {\n return { key, asset: result };\n }\n }\n const blocked = await Promise.all(remaining.map(key => source.source.blocks(key)));\n remaining = remaining.filter((_, index) => !blocked[index]);\n if (!remaining.length) break;\n }\n return undefined;\n }\n\n}\n\ninterface AssetSourceReference {\n key: string;\n source: AssetSource;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
import { Models } from "./Models.mjs";
|
|
3
3
|
import { BlockStates } from "./BlockStates.mjs";
|
|
4
4
|
import { AssetKey } from "./AssetKey.mjs";
|
|
5
|
-
var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
|
|
6
|
-
var DEFAULT_NAMESPACE = "minecraft";
|
|
7
5
|
var Assets = class {
|
|
8
6
|
/**
|
|
9
7
|
* @deprecated
|
|
@@ -21,8 +19,6 @@ var Assets = class {
|
|
|
21
19
|
}
|
|
22
20
|
};
|
|
23
21
|
export {
|
|
24
|
-
Assets
|
|
25
|
-
DEFAULT_NAMESPACE,
|
|
26
|
-
DEFAULT_ROOT
|
|
22
|
+
Assets
|
|
27
23
|
};
|
|
28
24
|
//# sourceMappingURL=Assets.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/Assets.ts"],"sourcesContent":["import { Models } from \"./Models\";\nimport { Model } from \"../model/Model\";\nimport { Maybe } from \"../util/util\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport { BlockStates } from \"./BlockStates\";\nimport { AssetKey, AssetType } from \"./AssetKey\";\n\
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/Assets.ts"],"sourcesContent":["import { Models } from \"./Models\";\nimport { Model } from \"../model/Model\";\nimport { Maybe } from \"../util/util\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport { BlockStates } from \"./BlockStates\";\nimport { AssetKey, AssetType } from \"./AssetKey\";\n\n/** Convenience accessors for model and blockstate loading. */\nexport class Assets {\n\n /**\n * @deprecated\n */\n public static parseAssetKey(assetType: AssetType, str: string, origin?: AssetKey): AssetKey {\n return AssetKey.parse(assetType, str, origin);\n }\n\n /** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */\n public static async getModel(key: AssetKey): Promise<Maybe<Model>> {\n return Models.getMerged(key);\n }\n\n /** Loads a blockstate definition. See {@link BlockStates.get}. */\n public static async getBlockState(key: AssetKey): Promise<Maybe<BlockState>> {\n return BlockStates.get(key);\n }\n\n}\n"],"mappings":";AAAA,SAAS,cAAc;AAIvB,SAAS,mBAAmB;AAC5B,SAAS,gBAA2B;AAG7B,IAAM,SAAN,MAAa;AAAA;AAAA;AAAA;AAAA,EAKhB,OAAc,cAAc,WAAsB,KAAa,QAA6B;AACxF,WAAO,SAAS,MAAM,WAAW,KAAK,MAAM;AAAA,EAChD;AAAA;AAAA,EAGA,aAAoB,SAAS,KAAsC;AAC/D,WAAO,OAAO,UAAU,GAAG;AAAA,EAC/B;AAAA;AAAA,EAGA,aAAoB,cAAc,KAA2C;AACzE,WAAO,YAAY,IAAI,GAAG;AAAA,EAC9B;AAEJ;","names":[]}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// src/assets/BlockEntities.ts
|
|
2
2
|
import { Matrix4 } from "three";
|
|
3
3
|
import { AssetKey } from "./AssetKey.mjs";
|
|
4
|
+
import { Entities } from "./Entities.mjs";
|
|
4
5
|
import { AssetLoader } from "./AssetLoader.mjs";
|
|
5
6
|
import { AssetParser } from "./source/index.mjs";
|
|
6
7
|
import { Caching } from "../cache/Caching.mjs";
|
|
8
|
+
import { logger } from "../util/log.mjs";
|
|
9
|
+
var log = logger("BlockEntities");
|
|
7
10
|
var BlockEntities = class {
|
|
8
11
|
/**
|
|
9
12
|
* Loads the block index of a version. Versions and sources without one yield an empty index, and so does
|
|
@@ -15,9 +18,10 @@ var BlockEntities = class {
|
|
|
15
18
|
key.rootType = void 0;
|
|
16
19
|
const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
|
|
17
20
|
try {
|
|
21
|
+
key.root = await Entities.getDatasetRoot(root);
|
|
18
22
|
return await AssetLoader.get(key, AssetParser.JSON) ?? {};
|
|
19
23
|
} catch (error) {
|
|
20
|
-
|
|
24
|
+
log.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
|
|
21
25
|
return {};
|
|
22
26
|
}
|
|
23
27
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/BlockEntities.ts"],"sourcesContent":["import { Matrix4 } from \"three\";\nimport { AssetKey } from \"./AssetKey\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { AssetParser } from \"./source\";\nimport { Caching } from \"../cache/Caching\";\nimport type { MinecraftAsset } from \"../MinecraftAsset\";\nimport type { BlockStateProperties } from \"../model/block/BlockStateProperties\";\nimport type { TripleArray } from \"../model/Model\";\nimport type { Maybe } from \"../util\";\n\n/** One model drawn by a block-entity renderer. */\nexport interface BlockEntityPart {\n model: string;\n /** Model layer; defaults to \"main\". */\n layer?: string;\n /** Set only when the texture differs from the layer's default. */\n textureLocation?: string;\n /** Blockstate multipart syntax: every property must match, and \"a|b\" matches either value. */\n when?: Record<string, string>;\n}\n\n/** Degrees per property value, or degrees per unit of a numeric property. */\nexport type BlockEntityRotation = { property: string; degrees: Record<string, number> } | { property: string; step: number };\n\n/** Models and state-dependent placement for one block ID in the block-entity index. */\nexport interface BlockEntityEntry {\n parts: BlockEntityPart[];\n rotation?: BlockEntityRotation;\n /** Offset in model units, applied before the rotation. */\n translation?: TripleArray;\n}\n\n/** The dataset's `blocks.json`: block ID to the models its block-entity renderer draws. */\nexport type BlockEntityIndex = MinecraftAsset & { [block: string]: BlockEntityEntry };\n\n/** Parts and placement selected by {@link BlockEntities.resolve} for a block's properties. */\nexport interface ResolvedBlockEntity {\n parts: BlockEntityPart[];\n /** Degrees counter-clockwise seen from above, about the block's vertical centre axis. */\n rotation: number;\n translation: TripleArray;\n}\n\n/** Resolves blockstate properties into the entity models used to draw chests, beds, and other block entities. */\nexport class BlockEntities {\n\n /**\n * Loads the block index of a version. Versions and sources without one yield an empty index, and so does\n * a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty\n * result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.\n */\n public static async getIndex(root?: string): Promise<BlockEntityIndex> {\n // The index sits next to the namespace directories, at <root>/entity-models/blocks.json.\n const key = new AssetKey(\"entity-models\", \"blocks\", undefined, undefined, undefined, \".json\", root);\n key.rootType = undefined!;\n const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {\n try {\n return await AssetLoader.get<BlockEntityIndex>(key, AssetParser.JSON) ?? {};\n } catch (error) {\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/BlockEntities.ts"],"sourcesContent":["import { Matrix4 } from \"three\";\nimport { AssetKey } from \"./AssetKey\";\nimport { Entities } from \"./Entities\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { AssetParser } from \"./source\";\nimport { Caching } from \"../cache/Caching\";\nimport type { MinecraftAsset } from \"../MinecraftAsset\";\nimport type { BlockStateProperties } from \"../model/block/BlockStateProperties\";\nimport type { TripleArray } from \"../model/Model\";\nimport type { Maybe } from \"../util\";\nimport { logger } from \"../util/log\";\n\nconst log = logger(\"BlockEntities\");\n\n/** One model drawn by a block-entity renderer. */\nexport interface BlockEntityPart {\n model: string;\n /** Model layer; defaults to \"main\". */\n layer?: string;\n /** Set only when the texture differs from the layer's default. */\n textureLocation?: string;\n /** Blockstate multipart syntax: every property must match, and \"a|b\" matches either value. */\n when?: Record<string, string>;\n}\n\n/** Degrees per property value, or degrees per unit of a numeric property. */\nexport type BlockEntityRotation = { property: string; degrees: Record<string, number> } | { property: string; step: number };\n\n/** Models and state-dependent placement for one block ID in the block-entity index. */\nexport interface BlockEntityEntry {\n parts: BlockEntityPart[];\n rotation?: BlockEntityRotation;\n /** Offset in model units, applied before the rotation. */\n translation?: TripleArray;\n}\n\n/** The dataset's `blocks.json`: block ID to the models its block-entity renderer draws. */\nexport type BlockEntityIndex = MinecraftAsset & { [block: string]: BlockEntityEntry };\n\n/** Parts and placement selected by {@link BlockEntities.resolve} for a block's properties. */\nexport interface ResolvedBlockEntity {\n parts: BlockEntityPart[];\n /** Degrees counter-clockwise seen from above, about the block's vertical centre axis. */\n rotation: number;\n translation: TripleArray;\n}\n\n/** Resolves blockstate properties into the entity models used to draw chests, beds, and other block entities. */\nexport class BlockEntities {\n\n /**\n * Loads the block index of a version. Versions and sources without one yield an empty index, and so does\n * a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty\n * result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.\n */\n public static async getIndex(root?: string): Promise<BlockEntityIndex> {\n // The index sits next to the namespace directories, at <root>/entity-models/blocks.json.\n const key = new AssetKey(\"entity-models\", \"blocks\", undefined, undefined, undefined, \".json\", root);\n key.rootType = undefined!;\n const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {\n try {\n key.root = await Entities.getDatasetRoot(root);\n return await AssetLoader.get<BlockEntityIndex>(key, AssetParser.JSON) ?? {};\n } catch (error) {\n log.warn(\"Could not load the block entity index; block entities are drawn as plain block models\", error);\n return {};\n }\n });\n return index ?? {};\n }\n\n /** The index entry of a block ID such as `minecraft:chest`. */\n public static entry(index: BlockEntityIndex, block: string): Maybe<BlockEntityEntry> {\n const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : undefined;\n return Array.isArray(entry?.parts) ? entry : undefined;\n }\n\n /** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */\n public static resolve(index: BlockEntityIndex, block: string, state: BlockStateProperties = {}): Maybe<ResolvedBlockEntity> {\n const entry = this.entry(index, block);\n if (!entry) return undefined;\n // Default block states may hold booleans, numbers and upper-case enum names.\n const value = (property: string) => String(state[property]).toLowerCase();\n const parts = entry.parts.filter(part => Object.entries(part.when ?? {})\n .every(([property, values]) => String(values).split(\"|\").includes(value(property))));\n if (!parts.length) return undefined;\n let rotation = 0;\n if (entry.rotation) {\n const selected = value(entry.rotation.property);\n rotation = \"degrees\" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;\n if (!Number.isFinite(rotation)) rotation = 0;\n }\n return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };\n }\n\n /** Placement in block space (0..16 per axis), applied on top of the model's own transform. */\n public static matrix(resolved: ResolvedBlockEntity, matrix: Matrix4 = new Matrix4()): Matrix4 {\n return matrix.makeTranslation(8, 0, 8)\n .multiply(new Matrix4().makeRotationY(resolved.rotation * Math.PI / 180))\n .multiply(new Matrix4().makeTranslation(resolved.translation[0] - 8, resolved.translation[1], resolved.translation[2] - 8));\n }\n\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AAKxB,SAAS,cAAc;AAEvB,IAAM,MAAM,OAAO,eAAe;AAoC3B,IAAM,gBAAN,MAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,aAAoB,SAAS,MAA0C;AAEnE,UAAM,MAAM,IAAI,SAAS,iBAAiB,UAAU,QAAW,QAAW,QAAW,SAAS,IAAI;AAClG,QAAI,WAAW;AACf,UAAM,QAAQ,MAAM,QAAQ,sBAAsB,IAAI,IAAI,UAAU,GAAG,YAAY;AAC/E,UAAI;AACA,YAAI,OAAO,MAAM,SAAS,eAAe,IAAI;AAC7C,eAAO,MAAM,YAAY,IAAsB,KAAK,YAAY,IAAI,KAAK,CAAC;AAAA,MAC9E,SAAS,OAAO;AACZ,YAAI,KAAK,yFAAyF,KAAK;AACvG,eAAO,CAAC;AAAA,MACZ;AAAA,IACJ,CAAC;AACD,WAAO,SAAS,CAAC;AAAA,EACrB;AAAA;AAAA,EAGA,OAAc,MAAM,OAAyB,OAAwC;AACjF,UAAM,QAAQ,OAAO,UAAU,eAAe,KAAK,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI;AAClF,WAAO,MAAM,QAAQ,OAAO,KAAK,IAAI,QAAQ;AAAA,EACjD;AAAA;AAAA,EAGA,OAAc,QAAQ,OAAyB,OAAe,QAA8B,CAAC,GAA+B;AACxH,UAAM,QAAQ,KAAK,MAAM,OAAO,KAAK;AACrC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,QAAQ,CAAC,aAAqB,OAAO,MAAM,QAAQ,CAAC,EAAE,YAAY;AACxE,UAAM,QAAQ,MAAM,MAAM,OAAO,UAAQ,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,EAClE,MAAM,CAAC,CAAC,UAAU,MAAM,MAAM,OAAO,MAAM,EAAE,MAAM,GAAG,EAAE,SAAS,MAAM,QAAQ,CAAC,CAAC,CAAC;AACvF,QAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,QAAI,WAAW;AACf,QAAI,MAAM,UAAU;AAChB,YAAM,WAAW,MAAM,MAAM,SAAS,QAAQ;AAC9C,iBAAW,aAAa,MAAM,WAAW,MAAM,SAAS,QAAQ,QAAQ,IAAI,OAAO,QAAQ,IAAI,MAAM,SAAS;AAC9G,UAAI,CAAC,OAAO,SAAS,QAAQ,EAAG,YAAW;AAAA,IAC/C;AACA,WAAO,EAAE,OAAO,UAAU,aAAa,MAAM,eAAe,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA,EAC1E;AAAA;AAAA,EAGA,OAAc,OAAO,UAA+B,SAAkB,IAAI,QAAQ,GAAY;AAC1F,WAAO,OAAO,gBAAgB,GAAG,GAAG,CAAC,EAChC,SAAS,IAAI,QAAQ,EAAE,cAAc,SAAS,WAAW,KAAK,KAAK,GAAG,CAAC,EACvE,SAAS,IAAI,QAAQ,EAAE,gBAAgB,SAAS,YAAY,CAAC,IAAI,GAAG,SAAS,YAAY,CAAC,GAAG,SAAS,YAAY,CAAC,IAAI,CAAC,CAAC;AAAA,EAClI;AAEJ;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/assets/BlockStates.ts
|
|
2
2
|
import { Caching } from "../cache/Caching.mjs";
|
|
3
3
|
import { AssetLoader } from "./AssetLoader.mjs";
|
|
4
|
-
import { DEFAULT_NAMESPACE } from "./
|
|
4
|
+
import { DEFAULT_NAMESPACE } from "./AssetDefaults.mjs";
|
|
5
5
|
import { AssetKey } from "./AssetKey.mjs";
|
|
6
6
|
import { PersistentCache } from "../cache/PersistentCache.mjs";
|
|
7
7
|
import { AssetParser } from "./source/parser/AssetParsers.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/BlockStates.ts"],"sourcesContent":["import { Maybe } from \"../util/util\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport { Caching } from \"../cache/Caching\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { DEFAULT_NAMESPACE } from \"./
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/BlockStates.ts"],"sourcesContent":["import { Maybe } from \"../util/util\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport { Caching } from \"../cache/Caching\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { DEFAULT_NAMESPACE } from \"./AssetDefaults\";\nimport { BlockStatePropertyDefaults } from \"../model/block/BlockStateProperties\";\nimport { AssetKey } from \"./AssetKey\";\nimport { PersistentCache } from \"../cache/PersistentCache\";\nimport { AssetParser } from \"./source/parser/AssetParsers\";\nimport { ListAsset } from \"../ListAsset\";\nimport { MinecraftAsset } from \"../MinecraftAsset\";\nimport { Renames } from \"./Renames\";\nimport { MineRenderData } from \"./MineRenderData\";\n\n/** Loads blockstate definitions and the property defaults used to select block models. */\nexport class BlockStates {\n\n private static _persistentCache: PersistentCache | undefined;\n\n private static get PERSISTENT_CACHE(): PersistentCache {\n return this._persistentCache ??= PersistentCache.open(\"minerender-blockstates\");\n }\n\n // BlockState names are hardcoded\n /** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */\n public static async getList(): Promise<string[]> {\n const key = new AssetKey(\n DEFAULT_NAMESPACE,\n \"_list\",\n \"blockstates\",\n undefined,\n \"assets\",\n \".json\",\n AssetLoader.ROOT\n );\n return Caching.listAssetCache.get(key.serialize(), () => {\n return AssetLoader.get<ListAsset>(key, AssetParser.LIST);\n }).then(r => r?.files ?? []);\n }\n\n public static async getDefaultStates(root?: string): Promise<Maybe<DefaultBlockStates>> {\n return MineRenderData.get(\"blockStates\", root);\n }\n\n /** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */\n public static async getDefaultState(key: AssetKey): Promise<Maybe<BlockStatePropertyDefaults>> {\n const defaultStates = await this.getDefaultStates(key.root);\n if (!defaultStates) {\n return undefined;\n }\n return defaultStates[key.toNamespacedString()] as BlockStatePropertyDefaults;\n }\n\n /** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */\n public static async get(key: AssetKey): Promise<Maybe<BlockState>> {\n if (!key.assetType) {\n key.assetType = \"blockstates\";\n }\n if (!key.extension) {\n key.extension = \".json\";\n }\n // An ID from an older version loads its replacement. The registry fallback can select a table\n // newer than the assets, so a missing replacement keeps the original ID.\n const renamed = await Renames.key(\"blocks\", key);\n const replacement = renamed && await this.get(renamed);\n if (replacement) return replacement;\n const keyStr = key.serialize();\n return Caching.blockStateCache.get(keyStr, k => {\n return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), k1 => {\n return AssetLoader.get<BlockState>(key, AssetParser.BLOCKSTATE);\n })\n }).then(asset => {\n if (asset) {\n asset.key = key;\n }\n return asset;\n })\n }\n\n public static getAll(keys: AssetKey[] | Iterable<AssetKey>): Promise<Maybe<BlockState>[]> {\n const promises: Promise<Maybe<BlockState>>[] = [];\n for (let key of keys) {\n promises.push(this.get(key));\n }\n return Promise.all(promises);\n }\n\n /** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */\n public static async clearCache() {\n await this.PERSISTENT_CACHE.clear();\n }\n\n}\n\nexport class DefaultBlockStates implements MinecraftAsset {\n [k: string]: BlockStatePropertyDefaults;\n}\n"],"mappings":";AAEA,SAAS,eAAe;AACxB,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAElC,SAAS,gBAAgB;AACzB,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAG5B,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAGxB,IAAM,cAAN,MAAkB;AAAA,EAIrB,WAAmB,mBAAoC;AACnD,WAAO,KAAK,qBAAL,KAAK,mBAAqB,gBAAgB,KAAK,wBAAwB;AAAA,EAClF;AAAA;AAAA;AAAA,EAIA,aAAoB,UAA6B;AAC7C,UAAM,MAAM,IAAI;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IAChB;AACA,WAAO,QAAQ,eAAe,IAAI,IAAI,UAAU,GAAG,MAAM;AACrD,aAAO,YAAY,IAAe,KAAK,YAAY,IAAI;AAAA,IAC3D,CAAC,EAAE,KAAK,OAAK,GAAG,SAAS,CAAC,CAAC;AAAA,EAC/B;AAAA,EAEA,aAAoB,iBAAiB,MAAmD;AACpF,WAAO,eAAe,IAAI,eAAe,IAAI;AAAA,EACjD;AAAA;AAAA,EAGA,aAAoB,gBAAgB,KAA2D;AAC3F,UAAM,gBAAgB,MAAM,KAAK,iBAAiB,IAAI,IAAI;AAC1D,QAAI,CAAC,eAAe;AAChB,aAAO;AAAA,IACX;AACA,WAAO,cAAc,IAAI,mBAAmB,CAAC;AAAA,EACjD;AAAA;AAAA,EAGA,aAAoB,IAAI,KAA2C;AAC/D,QAAI,CAAC,IAAI,WAAW;AAChB,UAAI,YAAY;AAAA,IACpB;AACA,QAAI,CAAC,IAAI,WAAW;AAChB,UAAI,YAAY;AAAA,IACpB;AAGA,UAAM,UAAU,MAAM,QAAQ,IAAI,UAAU,GAAG;AAC/C,UAAM,cAAc,WAAW,MAAM,KAAK,IAAI,OAAO;AACrD,QAAI,YAAa,QAAO;AACxB,UAAM,SAAS,IAAI,UAAU;AAC7B,WAAO,QAAQ,gBAAgB,IAAI,QAAQ,OAAK;AAC5C,aAAO,KAAK,iBAAiB,UAAU,YAAY,cAAc,MAAM,GAAG,QAAM;AAC5E,eAAO,YAAY,IAAgB,KAAK,YAAY,UAAU;AAAA,MAClE,CAAC;AAAA,IACL,CAAC,EAAE,KAAK,WAAS;AACb,UAAI,OAAO;AACP,cAAM,MAAM;AAAA,MAChB;AACA,aAAO;AAAA,IACX,CAAC;AAAA,EACL;AAAA,EAEA,OAAc,OAAO,MAAqE;AACtF,UAAM,WAAyC,CAAC;AAChD,aAAS,OAAO,MAAM;AAClB,eAAS,KAAK,KAAK,IAAI,GAAG,CAAC;AAAA,IAC/B;AACA,WAAO,QAAQ,IAAI,QAAQ;AAAA,EAC/B;AAAA;AAAA,EAGA,aAAoB,aAAa;AAC7B,UAAM,KAAK,iBAAiB,MAAM;AAAA,EACtC;AAEJ;AAEO,IAAM,qBAAN,MAAmD;AAE1D;","names":[]}
|
|
@@ -1,17 +1,43 @@
|
|
|
1
1
|
// src/assets/Entities.ts
|
|
2
2
|
import { AssetKey, isAssetKey } from "./AssetKey.mjs";
|
|
3
|
+
import { parseRelease, nearestRelease } from "./_versions/DatasetVersions.mjs";
|
|
3
4
|
import { AssetLoader } from "./AssetLoader.mjs";
|
|
4
5
|
import { AssetParser } from "./source/index.mjs";
|
|
5
6
|
import { Caching } from "../cache/Caching.mjs";
|
|
6
|
-
import { DEFAULT_NAMESPACE } from "./
|
|
7
|
+
import { DEFAULT_NAMESPACE } from "./AssetDefaults.mjs";
|
|
7
8
|
import { MineRenderError } from "../error/MineRenderError.mjs";
|
|
8
9
|
import { ModelTextures } from "./ModelTextures.mjs";
|
|
9
10
|
var Entities = class {
|
|
11
|
+
/**
|
|
12
|
+
* Resolves `root` (default: the active version). Uses the exact dataset when published or when the
|
|
13
|
+
* version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
|
|
14
|
+
* Textures keep the requested root.
|
|
15
|
+
*/
|
|
16
|
+
static async getDatasetRoot(root) {
|
|
17
|
+
const requestRoot = (root ?? AssetLoader.ROOT).replace(/\/+$/, "");
|
|
18
|
+
const requestedVersion = requestRoot.slice(requestRoot.lastIndexOf("/") + 1);
|
|
19
|
+
const base = requestRoot.slice(0, requestRoot.lastIndexOf("/"));
|
|
20
|
+
const selected = await Caching.entityDatasetVersionCache.get(root ?? `sources:${AssetLoader.ROOT}`, async () => {
|
|
21
|
+
const key = new AssetKey("entity-models", "version", void 0, void 0, void 0, ".json", root);
|
|
22
|
+
key.rootType = void 0;
|
|
23
|
+
if (!parseRelease(requestedVersion) || await AssetLoader.get(key, AssetParser.JSON) !== void 0) return requestedVersion;
|
|
24
|
+
const indexKey = new AssetKey("entity-models", "versions", void 0, void 0, void 0, ".json", base);
|
|
25
|
+
indexKey.rootType = void 0;
|
|
26
|
+
const index = await AssetLoader.get(indexKey, AssetParser.JSON);
|
|
27
|
+
if (index === void 0) return requestedVersion;
|
|
28
|
+
if (!index || typeof index !== "object" || Array.isArray(index) || !Array.isArray(index.versions) || !index.versions.every((entry) => entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.name === "string")) {
|
|
29
|
+
throw new MineRenderError(`Invalid entity model version index at ${base}/entity-models/versions.json`);
|
|
30
|
+
}
|
|
31
|
+
return nearestRelease(requestedVersion, index.versions.map((entry) => entry.name)) ?? requestedVersion;
|
|
32
|
+
});
|
|
33
|
+
return selected === requestedVersion ? root : `${base}/${selected}`;
|
|
34
|
+
}
|
|
10
35
|
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
11
36
|
static async getEntityList() {
|
|
37
|
+
const root = await this.getDatasetRoot();
|
|
12
38
|
const collect = async (path) => {
|
|
13
39
|
const prefix = path ? `${path}/` : "";
|
|
14
|
-
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix}_list`, void 0, void 0, "entity-models", ".json");
|
|
40
|
+
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix}_list`, void 0, void 0, "entity-models", ".json", root);
|
|
15
41
|
const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.LIST));
|
|
16
42
|
if (!list) return [];
|
|
17
43
|
const files = list.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix}${file.slice(0, -5)}`);
|
|
@@ -20,9 +46,10 @@ var Entities = class {
|
|
|
20
46
|
};
|
|
21
47
|
return collect("");
|
|
22
48
|
}
|
|
49
|
+
/** @internal */
|
|
23
50
|
static async getModelFile(modelKey) {
|
|
24
51
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
25
|
-
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
52
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
|
|
26
53
|
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.JSON));
|
|
27
54
|
}
|
|
28
55
|
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
@@ -83,7 +110,7 @@ var Entities = class {
|
|
|
83
110
|
*/
|
|
84
111
|
static async getAnimations(modelKey) {
|
|
85
112
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
86
|
-
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
113
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
|
|
87
114
|
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.JSON));
|
|
88
115
|
return file?.animations;
|
|
89
116
|
}
|
|
@@ -92,26 +119,27 @@ var Entities = class {
|
|
|
92
119
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
93
120
|
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
94
121
|
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
|
|
95
|
-
|
|
122
|
+
const texture = await Caching.entityTextureCache.get(key.serialize(), async () => {
|
|
96
123
|
const name = path.split("/").pop();
|
|
97
124
|
for (const candidate of [path, `${path}/${name}`]) {
|
|
98
|
-
const
|
|
99
|
-
if (await ModelTextures.get(
|
|
125
|
+
const texture3 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
|
|
126
|
+
if (await ModelTextures.get(texture3)) return texture3;
|
|
100
127
|
}
|
|
101
128
|
const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
|
|
102
129
|
const list = await AssetLoader.get(listKey, AssetParser.LIST);
|
|
103
130
|
const files = list?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
|
|
104
131
|
const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
|
|
105
|
-
if (!file) return
|
|
132
|
+
if (!file) return Caching.MISSING;
|
|
106
133
|
const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
|
|
107
134
|
const variant = await AssetLoader.get(variantKey, AssetParser.JSON);
|
|
108
135
|
const assets = variant?.assets;
|
|
109
136
|
const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
|
|
110
|
-
if (typeof textureId !== "string") return
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
return
|
|
137
|
+
if (typeof textureId !== "string") return Caching.MISSING;
|
|
138
|
+
const texture2 = AssetKey.parse("textures", textureId);
|
|
139
|
+
texture2.root = root;
|
|
140
|
+
return texture2;
|
|
114
141
|
});
|
|
142
|
+
return texture === Caching.MISSING ? void 0 : texture;
|
|
115
143
|
}
|
|
116
144
|
/** @deprecated Use getEntityList(); block entities share the entity dataset. */
|
|
117
145
|
static getBlockList() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/Entities.ts"],"sourcesContent":["import { AssetKey, BasicAssetKey, isAssetKey } from \"./AssetKey\";\nimport type { EntityLayer, EntityModel, EntityModelFile, EntityModelPass } from \"../entity/EntityModel\";\nimport type { EntityAnimation, EntityAnimationFile } from \"../entity/EntityAnimation\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { AssetParser } from \"./source\";\nimport { Maybe } from \"../util\";\nimport { Caching } from \"../cache/Caching\";\nimport { DEFAULT_NAMESPACE } from \"./Assets\";\nimport type { ListAsset } from \"../ListAsset\";\nimport { MineRenderError } from \"../error/MineRenderError\";\nimport { ModelTextures } from \"./ModelTextures\";\nimport type { MinecraftAsset } from \"../MinecraftAsset\";\n\n/** Loads entity and block-entity geometry, texture selections, and animation clips from the dataset. */\nexport class Entities {\n\n /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */\n public static async getEntityList(): Promise<string[]> {\n const collect = async (path: string): Promise<string[]> => {\n const prefix = path ? `${path}/` : \"\";\n const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix}_list`, undefined, undefined, \"entity-models\", \".json\");\n const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get<ListAsset>(key, AssetParser.LIST));\n if (!list) return [];\n const files = list.files.filter(file => file.endsWith(\".json\") && file !== \"_list.json\")\n .map(file => `${prefix}${file.slice(0, -5)}`);\n const children = await Promise.all(list.directories.map(directory => collect(`${prefix}${directory}`)));\n return [...files, ...children.flat()];\n };\n return collect(\"\");\n }\n\n private static async getModelFile(modelKey: BasicAssetKey): Promise<Maybe<EntityModelFile>> {\n const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;\n const key = new AssetKey(modelKey.namespace, path, undefined, undefined, \"entity-models\", \".json\", isAssetKey(modelKey) ? modelKey.root : undefined);\n return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get<EntityModelFile>(key, AssetParser.JSON));\n }\n\n /** Returns selectable geometry-layer names, or an empty list when the model is missing. */\n public static async getLayerList(modelKey: BasicAssetKey): Promise<string[]> {\n return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});\n }\n\n /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */\n public static async getPassList(modelKey: BasicAssetKey): Promise<EntityModelPass[]> {\n return (await this.getModelFile(modelKey))?.passes ?? [];\n }\n\n /**\n * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.\n * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.\n *\n * @param modelKey - Dataset model, such as `new BasicAssetKey(\"minecraft\", \"zombie\")`.\n * @param textureKey - Texture override for the first selected layer.\n * @param options - Layer selection, conditional passes, and per-layer texture overrides.\n * @returns The selected model, or `undefined` when its dataset file is missing.\n */\n public static async getEntity(modelKey: BasicAssetKey, textureKey?: BasicAssetKey, options?: EntityModelOptions): Promise<Maybe<EntityModel>> {\n const model = await this.getModelFile(modelKey);\n if (!model) return undefined;\n // Without an explicit selection, draw what vanilla draws: main, then the passes enabled for the requested state.\n const passes = options?.layers || options?.layer !== undefined ? [] :\n (model.passes ?? []).filter(pass => pass.when === undefined || options?.when?.includes(pass.when));\n const draws: EntityModelPass[] = [...new Set(options?.layers ?? [options?.layer ?? \"main\"])].map(layer => ({ layer }));\n if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);\n draws.push(...passes);\n const names: string[] = [];\n const selected = draws.map(pass => {\n const layer = model.layers[pass.layer];\n if (!layer) {\n throw new MineRenderError(`Entity ${model.id} has no layer \"${pass.layer}\". Available layers: ${Object.keys(model.layers).join(\", \")}`);\n }\n // A pass may draw geometry that is already selected with another texture.\n let name = pass.layer;\n for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;\n names.push(name);\n return { name, layer, pass };\n });\n const layers: Record<string, EntityLayer> = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {\n const override = options?.textures?.[name] ?? (index === 0 ? textureKey : undefined);\n const textureLocation = pass.textureLocation ?? layer.textureLocation;\n let texture: Maybe<AssetKey>;\n if (override) {\n const path = isAssetKey(override) ? override.getFullPath() : override.path;\n texture = isAssetKey(override) && override.assetType === \"textures\" && path.startsWith(\"entity/\")\n ? override\n : new AssetKey(override.namespace, path, \"textures\", \"entity\", \"assets\", \".png\", isAssetKey(override) ? override.root : undefined);\n } else if (textureLocation !== undefined) {\n texture = AssetKey.parse(\"textures\", textureLocation.replace(/^([^:]+:)?textures\\//, \"$1\"));\n if (isAssetKey(modelKey)) texture.root = modelKey.root;\n } else {\n texture = await this.resolveTexture(modelKey);\n }\n const render = pass.render ?? layer.render;\n return [name, { key: override ?? modelKey, texture, layer, ...(render && { render }), ...(pass.tint && { tint: pass.tint }) }];\n })));\n return { ...layers[names[0]], id: model.id, layers, ...(model.transform && { transform: model.transform }) };\n }\n\n /**\n * Native and sampled vanilla clips by name, or undefined when the model or selected version has none.\n */\n public static async getAnimations(modelKey: BasicAssetKey): Promise<Maybe<Record<string, EntityAnimation>>> {\n const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;\n const key = new AssetKey(modelKey.namespace, path, undefined, undefined, \"entity-models/animations\", \".json\", isAssetKey(modelKey) ? modelKey.root : undefined);\n const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get<EntityAnimationFile>(key, AssetParser.JSON));\n return file?.animations;\n }\n\n /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */\n public static async resolveTexture(modelKey: BasicAssetKey): Promise<Maybe<AssetKey>> {\n const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;\n const root = isAssetKey(modelKey) ? modelKey.root : undefined;\n const key = new AssetKey(modelKey.namespace, path, undefined, undefined, \"entity-models\", \".json\", root);\n return Caching.entityTextureCache.get(key.serialize(), async () => {\n const name = path.split(\"/\").pop()!;\n for (const candidate of [path, `${path}/${name}`]) {\n const texture = new AssetKey(modelKey.namespace, candidate, \"textures\", \"entity\", \"assets\", \".png\", root);\n if (await ModelTextures.get(texture)) return texture;\n }\n const listKey = new AssetKey(modelKey.namespace, \"_list\", `${name}_variant`, undefined, \"data\", \".json\", root);\n const list = await AssetLoader.get<ListAsset>(listKey, AssetParser.LIST);\n const files = list?.files.filter(file => file.endsWith(\".json\") && file !== \"_list.json\");\n const file = files?.find(file => file === \"temperate.json\") ?? files?.[0];\n if (!file) return undefined;\n const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, undefined, \"data\", \".json\", root);\n const variant = await AssetLoader.get<EntityVariant>(variantKey, AssetParser.JSON);\n const assets = variant?.assets;\n const textureId = variant?.asset_id ?? (typeof assets?.wild === \"string\" ? assets.wild :\n Object.values(assets ?? {}).find(value => typeof value === \"string\"));\n if (typeof textureId !== \"string\") return undefined;\n const texture = AssetKey.parse(\"textures\", textureId);\n texture.root = root;\n return texture;\n });\n }\n\n /** @deprecated Use getEntityList(); block entities share the entity dataset. */\n public static getBlockList(): Promise<string[]> {\n return this.getEntityList();\n }\n\n /** @deprecated Use getEntity(); block entities share the entity dataset. */\n public static getBlock(modelKey: BasicAssetKey, textureKey?: BasicAssetKey, options?: EntityModelOptions): Promise<Maybe<EntityModel>> {\n return this.getEntity(modelKey, textureKey, options);\n }\n\n}\n\n/** Selection settings passed as the third argument to {@link Entities.getEntity}. */\nexport interface EntityModelOptions {\n /** Selects one geometry layer without dataset passes. `layers` takes precedence when supplied. */\n layer?: string;\n /** Layer names in draw order; an explicit selection draws exactly these layers and no dataset passes. */\n layers?: string[];\n /**\n * Entity states that enable the dataset's conditional passes, e.g. `[\"powered\"]` for a charged creeper.\n * Without `layer`/`layers`, `main` and every unconditional pass are always drawn.\n */\n when?: string[];\n /** Per-layer texture overrides, keyed like `EntityModel.layers`. The positional texture key applies to the first selected layer. */\n textures?: Record<string, BasicAssetKey>;\n}\n\ninterface EntityVariant extends MinecraftAsset {\n asset_id?: string;\n assets?: Record<string, unknown>;\n}\n"],"mappings":"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","names":["texture","file"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/Entities.ts"],"sourcesContent":["import { AssetKey, BasicAssetKey, isAssetKey } from \"./AssetKey\";\nimport type { EntityLayer, EntityModel, EntityModelFile, EntityModelPass } from \"../entity/EntityModel\";\nimport type { EntityAnimation, EntityAnimationFile } from \"../entity/EntityAnimation\";\nimport { parseRelease, nearestRelease } from \"./_versions/DatasetVersions\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { AssetParser } from \"./source\";\nimport { Maybe } from \"../util\";\nimport { Caching } from \"../cache/Caching\";\nimport { DEFAULT_NAMESPACE } from \"./AssetDefaults\";\nimport type { ListAsset } from \"../ListAsset\";\nimport { MineRenderError } from \"../error/MineRenderError\";\nimport { ModelTextures } from \"./ModelTextures\";\nimport type { MinecraftAsset } from \"../MinecraftAsset\";\n\n/** Loads entity and block-entity geometry, texture selections, and animation clips from the dataset. */\nexport class Entities {\n\n /**\n * Resolves `root` (default: the active version). Uses the exact dataset when published or when the\n * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.\n * Textures keep the requested root.\n */\n public static async getDatasetRoot(root?: string): Promise<Maybe<string>> {\n const requestRoot = (root ?? AssetLoader.ROOT).replace(/\\/+$/, \"\");\n const requestedVersion = requestRoot.slice(requestRoot.lastIndexOf(\"/\") + 1);\n const base = requestRoot.slice(0, requestRoot.lastIndexOf(\"/\"));\n const selected = await Caching.entityDatasetVersionCache.get(root ?? `sources:${AssetLoader.ROOT}`, async () => {\n const key = new AssetKey(\"entity-models\", \"version\", undefined, undefined, undefined, \".json\", root);\n key.rootType = undefined!;\n if (!parseRelease(requestedVersion) || await AssetLoader.get(key, AssetParser.JSON) !== undefined) return requestedVersion;\n const indexKey = new AssetKey(\"entity-models\", \"versions\", undefined, undefined, undefined, \".json\", base);\n indexKey.rootType = undefined!;\n const index = await AssetLoader.get<MinecraftAsset & { versions: { name: string }[] }>(indexKey, AssetParser.JSON);\n if (index === undefined) return requestedVersion;\n if (!index || typeof index !== \"object\" || Array.isArray(index) || !Array.isArray(index.versions)\n || !index.versions.every(entry => entry && typeof entry === \"object\" && !Array.isArray(entry) && typeof entry.name === \"string\")) {\n throw new MineRenderError(`Invalid entity model version index at ${base}/entity-models/versions.json`);\n }\n return nearestRelease(requestedVersion, index.versions.map(entry => entry.name)) ?? requestedVersion;\n });\n return selected === requestedVersion ? root : `${base}/${selected}`;\n }\n\n /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */\n public static async getEntityList(): Promise<string[]> {\n const root = await this.getDatasetRoot();\n const collect = async (path: string): Promise<string[]> => {\n const prefix = path ? `${path}/` : \"\";\n const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix}_list`, undefined, undefined, \"entity-models\", \".json\", root);\n const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get<ListAsset>(key, AssetParser.LIST));\n if (!list) return [];\n const files = list.files.filter(file => file.endsWith(\".json\") && file !== \"_list.json\")\n .map(file => `${prefix}${file.slice(0, -5)}`);\n const children = await Promise.all(list.directories.map(directory => collect(`${prefix}${directory}`)));\n return [...files, ...children.flat()];\n };\n return collect(\"\");\n }\n\n /** @internal */\n public static async getModelFile(modelKey: BasicAssetKey): Promise<Maybe<EntityModelFile>> {\n const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;\n const key = new AssetKey(modelKey.namespace, path, undefined, undefined, \"entity-models\", \".json\", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : undefined));\n return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get<EntityModelFile>(key, AssetParser.JSON));\n }\n\n /** Returns selectable geometry-layer names, or an empty list when the model is missing. */\n public static async getLayerList(modelKey: BasicAssetKey): Promise<string[]> {\n return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});\n }\n\n /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */\n public static async getPassList(modelKey: BasicAssetKey): Promise<EntityModelPass[]> {\n return (await this.getModelFile(modelKey))?.passes ?? [];\n }\n\n /**\n * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.\n * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.\n *\n * @param modelKey - Dataset model, such as `new BasicAssetKey(\"minecraft\", \"zombie\")`.\n * @param textureKey - Texture override for the first selected layer.\n * @param options - Layer selection, conditional passes, and per-layer texture overrides.\n * @returns The selected model, or `undefined` when its dataset file is missing.\n */\n public static async getEntity(modelKey: BasicAssetKey, textureKey?: BasicAssetKey, options?: EntityModelOptions): Promise<Maybe<EntityModel>> {\n const model = await this.getModelFile(modelKey);\n if (!model) return undefined;\n // Without an explicit selection, draw what vanilla draws: main, then the passes enabled for the requested state.\n const passes = options?.layers || options?.layer !== undefined ? [] :\n (model.passes ?? []).filter(pass => pass.when === undefined || options?.when?.includes(pass.when));\n const draws: EntityModelPass[] = [...new Set(options?.layers ?? [options?.layer ?? \"main\"])].map(layer => ({ layer }));\n if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);\n draws.push(...passes);\n const names: string[] = [];\n const selected = draws.map(pass => {\n const layer = model.layers[pass.layer];\n if (!layer) {\n throw new MineRenderError(`Entity ${model.id} has no layer \"${pass.layer}\". Available layers: ${Object.keys(model.layers).join(\", \")}`);\n }\n // A pass may draw geometry that is already selected with another texture.\n let name = pass.layer;\n for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;\n names.push(name);\n return { name, layer, pass };\n });\n const layers: Record<string, EntityLayer> = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {\n const override = options?.textures?.[name] ?? (index === 0 ? textureKey : undefined);\n const textureLocation = pass.textureLocation ?? layer.textureLocation;\n let texture: Maybe<AssetKey>;\n if (override) {\n const path = isAssetKey(override) ? override.getFullPath() : override.path;\n texture = isAssetKey(override) && override.assetType === \"textures\" && path.startsWith(\"entity/\")\n ? override\n : new AssetKey(override.namespace, path, \"textures\", \"entity\", \"assets\", \".png\", isAssetKey(override) ? override.root : undefined);\n } else if (textureLocation !== undefined) {\n texture = AssetKey.parse(\"textures\", textureLocation.replace(/^([^:]+:)?textures\\//, \"$1\"));\n if (isAssetKey(modelKey)) texture.root = modelKey.root;\n } else {\n texture = await this.resolveTexture(modelKey);\n }\n const render = pass.render ?? layer.render;\n return [name, { key: override ?? modelKey, texture, layer, ...(render && { render }), ...(pass.tint && { tint: pass.tint }) }];\n })));\n return { ...layers[names[0]], id: model.id, layers, ...(model.transform && { transform: model.transform }) };\n }\n\n /**\n * Native and sampled vanilla clips by name, or undefined when the model or selected version has none.\n */\n public static async getAnimations(modelKey: BasicAssetKey): Promise<Maybe<Record<string, EntityAnimation>>> {\n const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;\n const key = new AssetKey(modelKey.namespace, path, undefined, undefined, \"entity-models/animations\", \".json\", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : undefined));\n const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get<EntityAnimationFile>(key, AssetParser.JSON));\n return file?.animations;\n }\n\n /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */\n public static async resolveTexture(modelKey: BasicAssetKey): Promise<Maybe<AssetKey>> {\n const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;\n const root = isAssetKey(modelKey) ? modelKey.root : undefined;\n const key = new AssetKey(modelKey.namespace, path, undefined, undefined, \"entity-models\", \".json\", root);\n const texture = await Caching.entityTextureCache.get(key.serialize(), async () => {\n const name = path.split(\"/\").pop()!;\n for (const candidate of [path, `${path}/${name}`]) {\n const texture = new AssetKey(modelKey.namespace, candidate, \"textures\", \"entity\", \"assets\", \".png\", root);\n if (await ModelTextures.get(texture)) return texture;\n }\n const listKey = new AssetKey(modelKey.namespace, \"_list\", `${name}_variant`, undefined, \"data\", \".json\", root);\n const list = await AssetLoader.get<ListAsset>(listKey, AssetParser.LIST);\n const files = list?.files.filter(file => file.endsWith(\".json\") && file !== \"_list.json\");\n const file = files?.find(file => file === \"temperate.json\") ?? files?.[0];\n if (!file) return Caching.MISSING;\n const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, undefined, \"data\", \".json\", root);\n const variant = await AssetLoader.get<EntityVariant>(variantKey, AssetParser.JSON);\n const assets = variant?.assets;\n const textureId = variant?.asset_id ?? (typeof assets?.wild === \"string\" ? assets.wild :\n Object.values(assets ?? {}).find(value => typeof value === \"string\"));\n if (typeof textureId !== \"string\") return Caching.MISSING;\n const texture = AssetKey.parse(\"textures\", textureId);\n texture.root = root;\n return texture;\n });\n return texture === Caching.MISSING ? undefined : texture;\n }\n\n /** @deprecated Use getEntityList(); block entities share the entity dataset. */\n public static getBlockList(): Promise<string[]> {\n return this.getEntityList();\n }\n\n /** @deprecated Use getEntity(); block entities share the entity dataset. */\n public static getBlock(modelKey: BasicAssetKey, textureKey?: BasicAssetKey, options?: EntityModelOptions): Promise<Maybe<EntityModel>> {\n return this.getEntity(modelKey, textureKey, options);\n }\n\n}\n\n/** Selection settings passed as the third argument to {@link Entities.getEntity}. */\nexport interface EntityModelOptions {\n /** Selects one geometry layer without dataset passes. `layers` takes precedence when supplied. */\n layer?: string;\n /** Layer names in draw order; an explicit selection draws exactly these layers and no dataset passes. */\n layers?: string[];\n /**\n * Entity states that enable the dataset's conditional passes, e.g. `[\"powered\"]` for a charged creeper.\n * Without `layer`/`layers`, `main` and every unconditional pass are always drawn.\n */\n when?: string[];\n /** Per-layer texture overrides, keyed like `EntityModel.layers`. The positional texture key applies to the first selected layer. */\n textures?: Record<string, BasicAssetKey>;\n}\n\ninterface EntityVariant extends MinecraftAsset {\n asset_id?: string;\n assets?: Record<string, unknown>;\n}\n"],"mappings":"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","names":["texture","file"]}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
// src/assets/MineRenderData.ts
|
|
2
|
+
import { parseRelease, nearestRelease } from "./_versions/DatasetVersions.mjs";
|
|
2
3
|
import { AssetKey } from "./AssetKey.mjs";
|
|
3
4
|
import { AssetLoader } from "./AssetLoader.mjs";
|
|
4
5
|
import { AssetParser } from "./source/parser/AssetParsers.mjs";
|
|
5
6
|
import { Caching } from "../cache/Caching.mjs";
|
|
6
7
|
var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7
|
-
var release = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
|
|
8
|
-
var compare = (left, right) => {
|
|
9
|
-
for (let i = 0; i < 3; i++) {
|
|
10
|
-
const difference = (left[i] ?? 0) - (right[i] ?? 0);
|
|
11
|
-
if (difference) return difference;
|
|
12
|
-
}
|
|
13
|
-
return 0;
|
|
14
|
-
};
|
|
15
8
|
var MineRenderData = class {
|
|
16
9
|
/** Loads one registry. Missing files and invalid data reject the request. */
|
|
17
10
|
static async get(dataset, root) {
|
|
@@ -41,9 +34,9 @@ var MineRenderData = class {
|
|
|
41
34
|
const scope = AssetLoader.persistentScope;
|
|
42
35
|
return this.cached(`resolve:${requestRoot === void 0 ? "sources" : "explicit"}:${root}`, scope, defaultRoot, async () => {
|
|
43
36
|
const requestedVersion = root.slice(root.lastIndexOf("/") + 1);
|
|
44
|
-
let manifest = await this.manifest(root, requestRoot !== void 0 &&
|
|
37
|
+
let manifest = await this.manifest(root, requestRoot !== void 0 && parseRelease(requestedVersion) ? requestedVersion : void 0, requestRoot);
|
|
45
38
|
if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };
|
|
46
|
-
const requested =
|
|
39
|
+
const requested = parseRelease(requestedVersion);
|
|
47
40
|
if (!requested) {
|
|
48
41
|
throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);
|
|
49
42
|
}
|
|
@@ -55,14 +48,12 @@ var MineRenderData = class {
|
|
|
55
48
|
}
|
|
56
49
|
return value.versions;
|
|
57
50
|
});
|
|
58
|
-
const
|
|
59
|
-
const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
|
|
60
|
-
const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare(left.number, right.number))[0] ?? versions.filter((entry) => compare(entry.number, requested) <= 0).pop() ?? versions[0];
|
|
51
|
+
const selected = nearestRelease(requestedVersion, index.map((entry) => entry.name));
|
|
61
52
|
if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);
|
|
62
|
-
const resolvedRoot = `${base}/${selected
|
|
63
|
-
manifest = await this.manifest(resolvedRoot, selected
|
|
64
|
-
if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected
|
|
65
|
-
return { requestedVersion, version: selected
|
|
53
|
+
const resolvedRoot = `${base}/${selected}`;
|
|
54
|
+
manifest = await this.manifest(resolvedRoot, selected, resolvedRoot);
|
|
55
|
+
if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected}`);
|
|
56
|
+
return { requestedVersion, version: selected, root: resolvedRoot, manifest };
|
|
66
57
|
});
|
|
67
58
|
}
|
|
68
59
|
static async manifest(root, expectedVersion, requestRoot) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/assets/MineRenderData.ts"],"sourcesContent":["import { AssetKey } from \"./AssetKey\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { AssetParser } from \"./source/parser/AssetParsers\";\nimport { Caching } from \"../cache/Caching\";\nimport type { BlockStatePropertyDefaults } from \"../model/block/BlockStateProperties\";\nimport type { BiomeColorKind } from \"./Biomes\";\nimport type { RenameKind } from \"./Renames\";\n\nexport interface MineRenderDatasets {\n itemDefaults: Record<string, Record<string, unknown>>;\n potionColors: {\n effects: Record<string, number>;\n potions: Record<string, { id: string; amplifier: number }[]>;\n };\n blockStates: Record<string, BlockStatePropertyDefaults>;\n blockTints: Record<string, ({ source: \"constant\"; color: number } | { source: \"grass\" | \"stem\" | \"redstone\" }) & {\n untinted?: number[];\n biome?: BiomeColorKind;\n }>;\n blockCulling: {\n profiles: { type: string; group?: string; kind?: string }[];\n blocks: Record<string, number>;\n groups?: Record<string, string[]>;\n };\n fluids: Record<string, { kind: \"water\" | \"lava\"; renderModel: boolean; levelProperty?: string }>;\n dyes: Record<string, { id: number; textureDiffuseColor: number; fireworkColor: number; textColor: number }>;\n legacyBlocks: { blocks: Record<string, string> };\n renames: { format: \"data-fixer-renames\"; baseDataVersion: number }\n & Record<RenameKind, Record<string, { registered: boolean; ranges: { before: number; to: string }[] }>>;\n}\n\nexport interface MineRenderDataManifest {\n schemaVersion: 1;\n minecraftVersion: string;\n dataVersion: number;\n datasets: Partial<Record<keyof MineRenderDatasets, { file: string; sha256: string; bytes: number; provenance: Record<string, unknown> }>>;\n unavailable: Record<string, string>;\n extractor: { repository: string; revision: string; sha256: string };\n}\n\n/** The requested asset version and the published data version used for its registries. */\nexport interface ResolvedMineRenderData {\n requestedVersion: string;\n version: string;\n /** Registry lookup root. Rootless requests still allow registered sources to override this URL. */\n root: string;\n manifest: MineRenderDataManifest;\n}\n\nconst object = (value: unknown): value is Record<string, any> => value !== null && typeof value === \"object\" && !Array.isArray(value);\nconst release = (value: string): number[] | undefined => /^\\d+\\.\\d+(?:\\.\\d+)?$/.test(value) ? value.split(\".\").map(Number) : undefined;\nconst compare = (left: number[], right: number[]): number => {\n for (let i = 0; i < 3; i++) {\n const difference = (left[i] ?? 0) - (right[i] ?? 0);\n if (difference) return difference;\n }\n return 0;\n};\n\n/** Loads extracted Minecraft registries from the active asset sources and version. */\nexport class MineRenderData {\n /** Loads one registry. Missing files and invalid data reject the request. */\n public static async get<K extends keyof MineRenderDatasets>(dataset: K, root?: string): Promise<MineRenderDatasets[K]> {\n root = root?.replace(/\\/+$/, \"\");\n const scope = AssetLoader.persistentScope;\n const defaultRoot = AssetLoader.ROOT;\n const resolved = await this.resolve(root);\n const entry = resolved.manifest.datasets[dataset];\n if (!entry) throw new Error(`MineRender ${dataset} data is unavailable for ${resolved.version}: ${resolved.manifest.unavailable[dataset] ?? \"not listed in the manifest\"}`);\n const file = entry.file;\n const requestRoot = resolved.root === (root ?? defaultRoot).replace(/\\/+$/, \"\") ? root : resolved.root;\n return await this.cached(`${requestRoot === undefined ? \"sources\" : \"explicit\"}:${resolved.root}/${file}:${entry.sha256}`, scope, defaultRoot, async () => {\n const data = await this.load(file.slice(0, -5), requestRoot);\n if (!this.validDataset(dataset, data)) throw new Error(`Invalid MineRender ${dataset} data at ${resolved.root}/minerender-data/${file}`);\n return data as MineRenderDatasets[K];\n });\n }\n\n /**\n * Uses the exact version when published. Otherwise, selects the nearest patch in the same\n * release line (older on ties), then the latest earlier release or the oldest published release.\n * Unpublished snapshots reject.\n */\n public static async resolve(root?: string): Promise<ResolvedMineRenderData> {\n const requestRoot = root?.replace(/\\/+$/, \"\");\n const defaultRoot = AssetLoader.ROOT;\n root = (root ?? defaultRoot).replace(/\\/+$/, \"\");\n const scope = AssetLoader.persistentScope;\n return this.cached(`resolve:${requestRoot === undefined ? \"sources\" : \"explicit\"}:${root}`, scope, defaultRoot, async () => {\n const requestedVersion = root.slice(root.lastIndexOf(\"/\") + 1);\n let manifest = await this.manifest(root, requestRoot !== undefined && release(requestedVersion) ? requestedVersion : undefined, requestRoot);\n if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };\n const requested = release(requestedVersion);\n if (!requested) {\n throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);\n }\n const base = root.slice(0, root.lastIndexOf(\"/\"));\n const index = await this.cached(`versions:${base}`, scope, defaultRoot, async () => {\n const value = await this.load(\"versions\", base);\n if (!object(value) || !Array.isArray(value.versions)\n || !value.versions.every(entry => object(entry) && typeof entry.name === \"string\")) {\n throw new Error(`Invalid MineRender version index at ${base}/minerender-data/versions.json`);\n }\n return value.versions as { name: string }[];\n });\n const versions = index.map(entry => ({ name: entry.name, number: release(entry.name) }))\n .filter((entry): entry is { name: string; number: number[] } => !!entry.number)\n .sort((left, right) => compare(left.number, right.number));\n const sameLine = versions.filter(entry => entry.number[0] === requested[0] && entry.number[1] === requested[1]);\n const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0))\n - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare(left.number, right.number))[0]\n ?? versions.filter(entry => compare(entry.number, requested) <= 0).pop()\n ?? versions[0];\n if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);\n const resolvedRoot = `${base}/${selected.name}`;\n manifest = await this.manifest(resolvedRoot, selected.name, resolvedRoot);\n if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected.name}`);\n return { requestedVersion, version: selected.name, root: resolvedRoot, manifest };\n });\n }\n\n private static async manifest(root: string, expectedVersion: string | undefined, requestRoot?: string): Promise<MineRenderDataManifest | undefined> {\n const data = await this.load(\"manifest\", requestRoot);\n if (data === undefined) return undefined;\n if (!object(data) || data.schemaVersion !== 1 || typeof data.minecraftVersion !== \"string\" || !Number.isInteger(data.dataVersion)\n || !object(data.unavailable) || !Object.values(data.unavailable).every(value => typeof value === \"string\")\n || !object(data.datasets) || !Object.values(data.datasets).every(entry => {\n return object(entry) && typeof entry.file === \"string\" && /^[a-z0-9][a-z0-9._-]*\\.json$/.test(entry.file)\n && typeof entry.sha256 === \"string\" && /^[0-9a-f]{64}$/.test(entry.sha256);\n }) || (expectedVersion !== undefined && data.minecraftVersion !== expectedVersion)) {\n throw new Error(`Invalid MineRender manifest at ${root}/minerender-data/manifest.json`);\n }\n return data as unknown as MineRenderDataManifest;\n }\n\n private static load(file: string, root?: string): Promise<unknown> {\n const key = new AssetKey(\"minerender-data\", file, undefined, undefined, undefined, \".json\", root);\n key.rootType = undefined!;\n return AssetLoader.get(key, AssetParser.JSON);\n }\n\n private static async cached<T>(key: string, scope: string, defaultRoot: string, loader: () => Promise<T>): Promise<T> {\n const checkSources = () => {\n if (AssetLoader.persistentScope !== scope || AssetLoader.ROOT !== defaultRoot) throw new Error(\"Asset sources changed while loading MineRender data; retry the request\");\n };\n checkSources();\n return await Caching.mineRenderDataCache.get(scope ? `${scope}\\n${key}` : key, async () => {\n const value = await loader();\n checkSources();\n return value;\n }) as T;\n }\n\n private static validDataset(dataset: keyof MineRenderDatasets, data: unknown): boolean {\n if (!object(data)) return false;\n if (dataset === \"potionColors\") return object(data.effects) && Object.values(data.effects).every(Number.isInteger)\n && object(data.potions) && Object.values(data.potions).every(effects => Array.isArray(effects)\n && effects.every(effect => object(effect) && typeof effect.id === \"string\" && Number.isInteger(effect.amplifier)));\n if (dataset === \"renames\") return data.format === \"data-fixer-renames\" && Number.isInteger(data.baseDataVersion)\n && [\"blocks\", \"items\", \"entities\"].every(kind => object(data[kind]) && Object.values(data[kind]).every(entry =>\n object(entry) && typeof entry.registered === \"boolean\" && Array.isArray(entry.ranges) && entry.ranges.length > 0\n && entry.ranges.every(range => object(range) && Number.isInteger(range.before) && typeof range.to === \"string\")));\n if (dataset === \"legacyBlocks\") return object(data.blocks) && Object.values(data.blocks).every(value => typeof value === \"string\");\n if (dataset === \"blockCulling\") return Array.isArray(data.profiles)\n && data.profiles.every(profile => object(profile) && typeof profile.type === \"string\")\n && object(data.blocks) && Object.values(data.blocks).every(index => Number.isInteger(index) && index >= 0 && index < data.profiles.length)\n && (data.groups === undefined || object(data.groups) && Object.values(data.groups).every(group =>\n Array.isArray(group) && group.every(type => typeof type === \"string\")));\n return Object.values(data).every(value => {\n if (!object(value)) return false;\n switch (dataset) {\n case \"itemDefaults\": return true;\n case \"blockStates\": return Object.values(value).every(property => object(property) && \"default\" in property && Array.isArray(property.values));\n case \"blockTints\": return [\"constant\", \"grass\", \"stem\", \"redstone\"].includes(value.source)\n && (value.source !== \"constant\" || Number.isInteger(value.color))\n && (value.biome === undefined || [\"grass\", \"foliage\", \"dry_foliage\", \"water\"].includes(value.biome));\n case \"fluids\": return [\"water\", \"lava\"].includes(value.kind) && typeof value.renderModel === \"boolean\"\n && (value.levelProperty === undefined || typeof value.levelProperty === \"string\");\n case \"dyes\": return [value.id, value.textureDiffuseColor, value.fireworkColor, value.textColor].every(Number.isInteger);\n default: return false;\n }\n });\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/assets/MineRenderData.ts"],"sourcesContent":["import { parseRelease, nearestRelease } from \"./_versions/DatasetVersions\";\nimport { AssetKey } from \"./AssetKey\";\nimport { AssetLoader } from \"./AssetLoader\";\nimport { AssetParser } from \"./source/parser/AssetParsers\";\nimport { Caching } from \"../cache/Caching\";\nimport type { BlockStatePropertyDefaults } from \"../model/block/BlockStateProperties\";\nimport type { BiomeColorKind } from \"./Biomes\";\nimport type { RenameKind } from \"./Renames\";\n\nexport interface MineRenderDatasets {\n itemDefaults: Record<string, Record<string, unknown>>;\n potionColors: {\n effects: Record<string, number>;\n potions: Record<string, { id: string; amplifier: number }[]>;\n };\n blockStates: Record<string, BlockStatePropertyDefaults>;\n blockTints: Record<string, ({ source: \"constant\"; color: number } | { source: \"grass\" | \"stem\" | \"redstone\" }) & {\n untinted?: number[];\n biome?: BiomeColorKind;\n }>;\n blockCulling: {\n profiles: { type: string; group?: string; kind?: string }[];\n blocks: Record<string, number>;\n groups?: Record<string, string[]>;\n };\n fluids: Record<string, { kind: \"water\" | \"lava\"; renderModel: boolean; levelProperty?: string }>;\n dyes: Record<string, { id: number; textureDiffuseColor: number; fireworkColor: number; textColor: number }>;\n legacyBlocks: { blocks: Record<string, string> };\n renames: { format: \"data-fixer-renames\"; baseDataVersion: number }\n & Record<RenameKind, Record<string, { registered: boolean; ranges: { before: number; to: string }[] }>>;\n}\n\nexport interface MineRenderDataManifest {\n schemaVersion: 1;\n minecraftVersion: string;\n dataVersion: number;\n datasets: Partial<Record<keyof MineRenderDatasets, { file: string; sha256: string; bytes: number; provenance: Record<string, unknown> }>>;\n unavailable: Record<string, string>;\n extractor: { repository: string; revision: string; sha256: string };\n}\n\n/** The requested asset version and the published data version used for its registries. */\nexport interface ResolvedMineRenderData {\n requestedVersion: string;\n version: string;\n /** Registry lookup root. Rootless requests still allow registered sources to override this URL. */\n root: string;\n manifest: MineRenderDataManifest;\n}\n\nconst object = (value: unknown): value is Record<string, any> => value !== null && typeof value === \"object\" && !Array.isArray(value);\n\n/** Loads extracted Minecraft registries from the active asset sources and version. */\nexport class MineRenderData {\n /** Loads one registry. Missing files and invalid data reject the request. */\n public static async get<K extends keyof MineRenderDatasets>(dataset: K, root?: string): Promise<MineRenderDatasets[K]> {\n root = root?.replace(/\\/+$/, \"\");\n const scope = AssetLoader.persistentScope;\n const defaultRoot = AssetLoader.ROOT;\n const resolved = await this.resolve(root);\n const entry = resolved.manifest.datasets[dataset];\n if (!entry) throw new Error(`MineRender ${dataset} data is unavailable for ${resolved.version}: ${resolved.manifest.unavailable[dataset] ?? \"not listed in the manifest\"}`);\n const file = entry.file;\n const requestRoot = resolved.root === (root ?? defaultRoot).replace(/\\/+$/, \"\") ? root : resolved.root;\n return await this.cached(`${requestRoot === undefined ? \"sources\" : \"explicit\"}:${resolved.root}/${file}:${entry.sha256}`, scope, defaultRoot, async () => {\n const data = await this.load(file.slice(0, -5), requestRoot);\n if (!this.validDataset(dataset, data)) throw new Error(`Invalid MineRender ${dataset} data at ${resolved.root}/minerender-data/${file}`);\n return data as MineRenderDatasets[K];\n });\n }\n\n /**\n * Uses the exact version when published. Otherwise, selects the nearest patch in the same\n * release line (older on ties), then the latest earlier release or the oldest published release.\n * Unpublished snapshots reject.\n */\n public static async resolve(root?: string): Promise<ResolvedMineRenderData> {\n const requestRoot = root?.replace(/\\/+$/, \"\");\n const defaultRoot = AssetLoader.ROOT;\n root = (root ?? defaultRoot).replace(/\\/+$/, \"\");\n const scope = AssetLoader.persistentScope;\n return this.cached(`resolve:${requestRoot === undefined ? \"sources\" : \"explicit\"}:${root}`, scope, defaultRoot, async () => {\n const requestedVersion = root.slice(root.lastIndexOf(\"/\") + 1);\n let manifest = await this.manifest(root, requestRoot !== undefined && parseRelease(requestedVersion) ? requestedVersion : undefined, requestRoot);\n if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };\n const requested = parseRelease(requestedVersion);\n if (!requested) {\n throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);\n }\n const base = root.slice(0, root.lastIndexOf(\"/\"));\n const index = await this.cached(`versions:${base}`, scope, defaultRoot, async () => {\n const value = await this.load(\"versions\", base);\n if (!object(value) || !Array.isArray(value.versions)\n || !value.versions.every(entry => object(entry) && typeof entry.name === \"string\")) {\n throw new Error(`Invalid MineRender version index at ${base}/minerender-data/versions.json`);\n }\n return value.versions as { name: string }[];\n });\n const selected = nearestRelease(requestedVersion, index.map(entry => entry.name));\n if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);\n const resolvedRoot = `${base}/${selected}`;\n manifest = await this.manifest(resolvedRoot, selected, resolvedRoot);\n if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected}`);\n return { requestedVersion, version: selected, root: resolvedRoot, manifest };\n });\n }\n\n private static async manifest(root: string, expectedVersion: string | undefined, requestRoot?: string): Promise<MineRenderDataManifest | undefined> {\n const data = await this.load(\"manifest\", requestRoot);\n if (data === undefined) return undefined;\n if (!object(data) || data.schemaVersion !== 1 || typeof data.minecraftVersion !== \"string\" || !Number.isInteger(data.dataVersion)\n || !object(data.unavailable) || !Object.values(data.unavailable).every(value => typeof value === \"string\")\n || !object(data.datasets) || !Object.values(data.datasets).every(entry => {\n return object(entry) && typeof entry.file === \"string\" && /^[a-z0-9][a-z0-9._-]*\\.json$/.test(entry.file)\n && typeof entry.sha256 === \"string\" && /^[0-9a-f]{64}$/.test(entry.sha256);\n }) || (expectedVersion !== undefined && data.minecraftVersion !== expectedVersion)) {\n throw new Error(`Invalid MineRender manifest at ${root}/minerender-data/manifest.json`);\n }\n return data as unknown as MineRenderDataManifest;\n }\n\n private static load(file: string, root?: string): Promise<unknown> {\n const key = new AssetKey(\"minerender-data\", file, undefined, undefined, undefined, \".json\", root);\n key.rootType = undefined!;\n return AssetLoader.get(key, AssetParser.JSON);\n }\n\n private static async cached<T>(key: string, scope: string, defaultRoot: string, loader: () => Promise<T>): Promise<T> {\n const checkSources = () => {\n if (AssetLoader.persistentScope !== scope || AssetLoader.ROOT !== defaultRoot) throw new Error(\"Asset sources changed while loading MineRender data; retry the request\");\n };\n checkSources();\n return await Caching.mineRenderDataCache.get(scope ? `${scope}\\n${key}` : key, async () => {\n const value = await loader();\n checkSources();\n return value;\n }) as T;\n }\n\n private static validDataset(dataset: keyof MineRenderDatasets, data: unknown): boolean {\n if (!object(data)) return false;\n if (dataset === \"potionColors\") return object(data.effects) && Object.values(data.effects).every(Number.isInteger)\n && object(data.potions) && Object.values(data.potions).every(effects => Array.isArray(effects)\n && effects.every(effect => object(effect) && typeof effect.id === \"string\" && Number.isInteger(effect.amplifier)));\n if (dataset === \"renames\") return data.format === \"data-fixer-renames\" && Number.isInteger(data.baseDataVersion)\n && [\"blocks\", \"items\", \"entities\"].every(kind => object(data[kind]) && Object.values(data[kind]).every(entry =>\n object(entry) && typeof entry.registered === \"boolean\" && Array.isArray(entry.ranges) && entry.ranges.length > 0\n && entry.ranges.every(range => object(range) && Number.isInteger(range.before) && typeof range.to === \"string\")));\n if (dataset === \"legacyBlocks\") return object(data.blocks) && Object.values(data.blocks).every(value => typeof value === \"string\");\n if (dataset === \"blockCulling\") return Array.isArray(data.profiles)\n && data.profiles.every(profile => object(profile) && typeof profile.type === \"string\")\n && object(data.blocks) && Object.values(data.blocks).every(index => Number.isInteger(index) && index >= 0 && index < data.profiles.length)\n && (data.groups === undefined || object(data.groups) && Object.values(data.groups).every(group =>\n Array.isArray(group) && group.every(type => typeof type === \"string\")));\n return Object.values(data).every(value => {\n if (!object(value)) return false;\n switch (dataset) {\n case \"itemDefaults\": return true;\n case \"blockStates\": return Object.values(value).every(property => object(property) && \"default\" in property && Array.isArray(property.values));\n case \"blockTints\": return [\"constant\", \"grass\", \"stem\", \"redstone\"].includes(value.source)\n && (value.source !== \"constant\" || Number.isInteger(value.color))\n && (value.biome === undefined || [\"grass\", \"foliage\", \"dry_foliage\", \"water\"].includes(value.biome));\n case \"fluids\": return [\"water\", \"lava\"].includes(value.kind) && typeof value.renderModel === \"boolean\"\n && (value.levelProperty === undefined || typeof value.levelProperty === \"string\");\n case \"dyes\": return [value.id, value.textureDiffuseColor, value.fireworkColor, value.textColor].every(Number.isInteger);\n default: return false;\n }\n });\n }\n}\n"],"mappings":"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","names":[]}
|