minerender 2.1.0-alpha.140 → 2.1.0-alpha.142

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.
@@ -1,6 +1,7 @@
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";
@@ -17,6 +18,7 @@ var BlockEntities = class {
17
18
  key.rootType = void 0;
18
19
  const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
19
20
  try {
21
+ key.root = await Entities.getDatasetRoot(root);
20
22
  return await AssetLoader.get(key, AssetParser.JSON) ?? {};
21
23
  } catch (error) {
22
24
  log.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
@@ -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\";\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 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,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,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
+ {"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,5 +1,6 @@
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";
@@ -7,11 +8,36 @@ 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)}`);
@@ -22,7 +48,7 @@ var Entities = class {
22
48
  }
23
49
  static async getModelFile(modelKey) {
24
50
  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);
51
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
26
52
  return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.JSON));
27
53
  }
28
54
  /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
@@ -83,7 +109,7 @@ var Entities = class {
83
109
  */
84
110
  static async getAnimations(modelKey) {
85
111
  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);
112
+ 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
113
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.JSON));
88
114
  return file?.animations;
89
115
  }
@@ -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 \"./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 /** 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 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\", 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 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,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 && release(requestedVersion) ? requestedVersion : void 0, requestRoot);
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 = release(requestedVersion);
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 versions = index.map((entry) => ({ name: entry.name, number: release(entry.name) })).filter((entry) => !!entry.number).sort((left, right) => compare(left.number, right.number));
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.name}`;
63
- manifest = await this.manifest(resolvedRoot, selected.name, resolvedRoot);
64
- if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected.name}`);
65
- return { requestedVersion, version: selected.name, root: resolvedRoot, manifest };
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":[]}
@@ -0,0 +1,22 @@
1
+ // src/assets/_versions/DatasetVersions.ts
2
+ var parseRelease = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
3
+ var compare = (left, right) => {
4
+ for (let i = 0; i < 3; i++) {
5
+ const difference = (left[i] ?? 0) - (right[i] ?? 0);
6
+ if (difference) return difference;
7
+ }
8
+ return 0;
9
+ };
10
+ var nearestRelease = (requestedVersion, published) => {
11
+ const requested = parseRelease(requestedVersion);
12
+ if (!requested) return void 0;
13
+ const versions = published.map((name) => ({ name, number: parseRelease(name) })).filter((entry) => !!entry.number).sort((left, right) => compare(left.number, right.number));
14
+ const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
15
+ 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];
16
+ return selected?.name;
17
+ };
18
+ export {
19
+ nearestRelease,
20
+ parseRelease
21
+ };
22
+ //# sourceMappingURL=DatasetVersions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/assets/_versions/DatasetVersions.ts"],"sourcesContent":["/** Parses release versions; snapshots and other names yield undefined. */\nexport const parseRelease = (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/** Selects the nearest patch (older on ties), then the latest earlier release or oldest published release. */\nexport const nearestRelease = (requestedVersion: string, published: readonly string[]): string | undefined => {\n const requested = parseRelease(requestedVersion);\n if (!requested) return undefined;\n const versions = published.map(name => ({ name, number: parseRelease(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 return selected?.name;\n};\n"],"mappings":";AACO,IAAM,eAAe,CAAC,UAAwC,uBAAuB,KAAK,KAAK,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,MAAM,IAAI;AACzI,IAAM,UAAU,CAAC,MAAgB,UAA4B;AACzD,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AACxB,UAAM,cAAc,KAAK,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK;AACjD,QAAI,WAAY,QAAO;AAAA,EAC3B;AACA,SAAO;AACX;AAGO,IAAM,iBAAiB,CAAC,kBAA0B,cAAqD;AAC1G,QAAM,YAAY,aAAa,gBAAgB;AAC/C,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,WAAW,UAAU,IAAI,WAAS,EAAE,MAAM,QAAQ,aAAa,IAAI,EAAE,EAAE,EACxE,OAAO,CAAC,UAAuD,CAAC,CAAC,MAAM,MAAM,EAC7E,KAAK,CAAC,MAAM,UAAU,QAAQ,KAAK,QAAQ,MAAM,MAAM,CAAC;AAC7D,QAAM,WAAW,SAAS,OAAO,WAAS,MAAM,OAAO,CAAC,MAAM,UAAU,CAAC,KAAK,MAAM,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC;AAC9G,QAAM,WAAW,SAAS,KAAK,CAAC,MAAM,UAAU,KAAK,KAAK,KAAK,OAAO,CAAC,KAAK,MAAM,UAAU,CAAC,KAAK,EAAE,IAC9F,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,UAAU,CAAC,KAAK,EAAE,KAAK,QAAQ,KAAK,QAAQ,MAAM,MAAM,CAAC,EAAE,CAAC,KAC9F,SAAS,OAAO,WAAS,QAAQ,MAAM,QAAQ,SAAS,KAAK,CAAC,EAAE,IAAI,KACpE,SAAS,CAAC;AACjB,SAAO,UAAU;AACrB;","names":[]}
@@ -32,6 +32,7 @@ var _Caching = class _Caching {
32
32
  this.entityTextureCache,
33
33
  this.entityAnimationCache,
34
34
  this.blockEntityIndexCache,
35
+ this.entityDatasetVersionCache,
35
36
  this.fontCache,
36
37
  this.unihexCache,
37
38
  this.bannerPatternCache,
@@ -87,6 +88,7 @@ _Caching.entityModelCache = _Caching.createAssetCache();
87
88
  _Caching.entityTextureCache = _Caching.createAssetCache();
88
89
  _Caching.entityAnimationCache = _Caching.createAssetCache();
89
90
  _Caching.blockEntityIndexCache = _Caching.createAssetCache();
91
+ _Caching.entityDatasetVersionCache = _Caching.createAssetCache();
90
92
  _Caching.unihexCache = _Caching.createAssetCache();
91
93
  _Caching.fontCache = _Caching.createAssetCache();
92
94
  _Caching.bannerPatternCache = _Caching.createAssetCache();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/cache/Caching.ts"],"sourcesContent":["import { AsyncLoadingCache, Caches, Loader, LoadingCache, SimpleCache } from \"@inventivetalent/loading-cache\";\nimport { BoxGeometryKey, CacheKey, serializeBoxGeometryKey, serializeImageKey, TextureKey } from \"./CacheKey\";\nimport { Time } from \"@inventivetalent/time\";\nimport { ImageInfo, ImageLoader } from \"../image/ImageLoader\";\nimport { BoxGeometry, Material, Mesh, PixelFormat, RGBAFormat, Texture } from \"three\";\nimport { Materials } from \"../Materials\";\nimport { CompatImage } from \"../canvas/CanvasCompat\";\nimport { Model, TextureAsset } from \"../model/Model\";\nimport { WrappedImage } from \"../WrappedImage\";\nimport { TextureAtlas } from \"../texture/TextureAtlas\";\nimport { ExtractableImageData } from \"../ExtractableImageData\";\nimport { MinecraftTextureMeta } from \"../MinecraftTextureMeta\";\nimport type { EntityModelFile } from \"../entity/EntityModel\";\nimport type { EntityAnimationFile } from \"../entity/EntityAnimation\";\nimport type { BlockEntityIndex } from \"../assets/BlockEntities\";\nimport type { ListAsset } from \"../ListAsset\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport type { AssetKey } from \"../assets/AssetKey\";\nimport type { UnihexFile } from \"../assets/_fonts/Unihex\";\nimport type { BitmapFont } from \"../assets/Fonts\";\nimport type { BannerPattern } from \"../assets/BannerPatterns\";\nimport type { Biome } from \"../assets/Biomes\";\n\n/** Shared in-memory caches for loaded assets and render resources. Persistent stores are managed separately. */\nexport class Caching {\n\n private static _generation = 0;\n\n /** Changes when shared assets are cleared, so derived caches can discard their old values. */\n public static get generation(): number { return this._generation; }\n\n static readonly rawImageCache: AsyncLoadingCache<CacheKey, ImageInfo> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(5))\n .buildAsync<CacheKey, ImageInfo>();\n static readonly imageDataCache: AsyncLoadingCache<CacheKey, ImageData> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(10))\n .buildAsync<CacheKey, ImageData>();\n static readonly canvasImageDataCache: AsyncLoadingCache<CacheKey, ExtractableImageData> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(10))\n .buildAsync<CacheKey, ExtractableImageData>();\n static readonly wrappedImageCache: AsyncLoadingCache<CacheKey, WrappedImage> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(10))\n .buildAsync<CacheKey, WrappedImage>();\n\n static readonly boxGeometryCache: SimpleCache<CacheKey, BoxGeometry> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(20))\n .build<CacheKey, BoxGeometry>();\n\n static readonly textureCache: SimpleCache<CacheKey, Texture> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .build<CacheKey, Texture>();\n\n static readonly materialCache: SimpleCache<CacheKey, Material> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .build<CacheKey, Material>();\n\n static readonly boxMeshCache: SimpleCache<CacheKey, Mesh> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .build<CacheKey, Mesh>();\n\n static readonly textureAssetCache: AsyncLoadingCache<CacheKey, TextureAsset> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, TextureAsset>();\n static readonly textureMetaCache: AsyncLoadingCache<CacheKey, MinecraftTextureMeta> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, MinecraftTextureMeta>();\n\n static readonly rawModelCache: AsyncLoadingCache<CacheKey, Model> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, Model>();\n static readonly mergedModelCache: AsyncLoadingCache<CacheKey, Model> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, Model>();\n static readonly modelTextureAtlasCache: AsyncLoadingCache<CacheKey, TextureAtlas> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, TextureAtlas>();\n\n static readonly blockStateCache: AsyncLoadingCache<CacheKey, BlockState> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, BlockState>();\n\n static readonly listAssetCache: AsyncLoadingCache<CacheKey, ListAsset> = Caching.createAssetCache<ListAsset>();\n\n static readonly blockTintCache: AsyncLoadingCache<CacheKey, number> = Caching.createAssetCache<number>();\n\n static readonly entityModelCache: AsyncLoadingCache<CacheKey, EntityModelFile> = Caching.createAssetCache<EntityModelFile>();\n\n static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey> = Caching.createAssetCache<AssetKey>();\n\n static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile> = Caching.createAssetCache<EntityAnimationFile>();\n static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex> = Caching.createAssetCache<BlockEntityIndex>();\n static readonly unihexCache: AsyncLoadingCache<CacheKey, UnihexFile> = Caching.createAssetCache<UnihexFile>();\n static readonly fontCache: AsyncLoadingCache<CacheKey, BitmapFont> = Caching.createAssetCache<BitmapFont>();\n static readonly bannerPatternCache: AsyncLoadingCache<CacheKey, BannerPattern> = Caching.createAssetCache<BannerPattern>();\n static readonly mineRenderDataCache: AsyncLoadingCache<CacheKey, unknown> = Caching.createAssetCache<unknown>();\n static readonly usernameUuidCache: AsyncLoadingCache<CacheKey, string> = Caches.builder()\n .expireAfterWrite(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, string>();\n static readonly biomeCache: AsyncLoadingCache<CacheKey, Biome> = Caching.createAssetCache<Biome>();\n\n private static createAssetCache<T>(): AsyncLoadingCache<CacheKey, T> {\n return Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, T>();\n }\n\n\n /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */\n private static get all(): { invalidateAll(): void; end(): void }[] {\n return [\n this.rawImageCache,\n this.imageDataCache,\n this.canvasImageDataCache,\n this.wrappedImageCache,\n this.boxGeometryCache,\n this.textureCache,\n this.materialCache,\n this.boxMeshCache,\n this.textureAssetCache,\n this.textureMetaCache,\n this.rawModelCache,\n this.mergedModelCache,\n this.modelTextureAtlasCache,\n this.blockStateCache,\n this.listAssetCache,\n this.blockTintCache,\n this.entityModelCache,\n this.entityTextureCache,\n this.entityAnimationCache,\n this.blockEntityIndexCache,\n this.fontCache,\n this.unihexCache,\n this.bannerPatternCache,\n this.mineRenderDataCache,\n this.usernameUuidCache,\n this.biomeCache\n ];\n }\n\n /** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */\n public static clear() {\n this._generation++;\n for (const cache of this.all) {\n cache.invalidateAll();\n }\n }\n\n /**\n * Clears every cache and stops its expiry timer.\n *\n * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.\n * Use {@link shutdown} to also stop requests and the shared Ticker.\n */\n public static end() {\n this._generation++;\n for (const cache of this.all) {\n cache.invalidateAll();\n cache.end();\n }\n }\n\n public static get cacheSizes() {\n return {\n //TODO\n }\n }\n\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/cache/Caching.ts"],"sourcesContent":["import { AsyncLoadingCache, Caches, Loader, LoadingCache, SimpleCache } from \"@inventivetalent/loading-cache\";\nimport { BoxGeometryKey, CacheKey, serializeBoxGeometryKey, serializeImageKey, TextureKey } from \"./CacheKey\";\nimport { Time } from \"@inventivetalent/time\";\nimport { ImageInfo, ImageLoader } from \"../image/ImageLoader\";\nimport { BoxGeometry, Material, Mesh, PixelFormat, RGBAFormat, Texture } from \"three\";\nimport { Materials } from \"../Materials\";\nimport { CompatImage } from \"../canvas/CanvasCompat\";\nimport { Model, TextureAsset } from \"../model/Model\";\nimport { WrappedImage } from \"../WrappedImage\";\nimport { TextureAtlas } from \"../texture/TextureAtlas\";\nimport { ExtractableImageData } from \"../ExtractableImageData\";\nimport { MinecraftTextureMeta } from \"../MinecraftTextureMeta\";\nimport type { EntityModelFile } from \"../entity/EntityModel\";\nimport type { EntityAnimationFile } from \"../entity/EntityAnimation\";\nimport type { BlockEntityIndex } from \"../assets/BlockEntities\";\nimport type { ListAsset } from \"../ListAsset\";\nimport { BlockState } from \"../model/block/BlockState\";\nimport type { AssetKey } from \"../assets/AssetKey\";\nimport type { UnihexFile } from \"../assets/_fonts/Unihex\";\nimport type { BitmapFont } from \"../assets/Fonts\";\nimport type { BannerPattern } from \"../assets/BannerPatterns\";\nimport type { Biome } from \"../assets/Biomes\";\n\n/** Shared in-memory caches for loaded assets and render resources. Persistent stores are managed separately. */\nexport class Caching {\n\n private static _generation = 0;\n\n /** Changes when shared assets are cleared, so derived caches can discard their old values. */\n public static get generation(): number { return this._generation; }\n\n static readonly rawImageCache: AsyncLoadingCache<CacheKey, ImageInfo> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(5))\n .buildAsync<CacheKey, ImageInfo>();\n static readonly imageDataCache: AsyncLoadingCache<CacheKey, ImageData> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(10))\n .buildAsync<CacheKey, ImageData>();\n static readonly canvasImageDataCache: AsyncLoadingCache<CacheKey, ExtractableImageData> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(10))\n .buildAsync<CacheKey, ExtractableImageData>();\n static readonly wrappedImageCache: AsyncLoadingCache<CacheKey, WrappedImage> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(10))\n .buildAsync<CacheKey, WrappedImage>();\n\n static readonly boxGeometryCache: SimpleCache<CacheKey, BoxGeometry> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(20))\n .build<CacheKey, BoxGeometry>();\n\n static readonly textureCache: SimpleCache<CacheKey, Texture> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .build<CacheKey, Texture>();\n\n static readonly materialCache: SimpleCache<CacheKey, Material> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .build<CacheKey, Material>();\n\n static readonly boxMeshCache: SimpleCache<CacheKey, Mesh> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .build<CacheKey, Mesh>();\n\n static readonly textureAssetCache: AsyncLoadingCache<CacheKey, TextureAsset> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, TextureAsset>();\n static readonly textureMetaCache: AsyncLoadingCache<CacheKey, MinecraftTextureMeta> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, MinecraftTextureMeta>();\n\n static readonly rawModelCache: AsyncLoadingCache<CacheKey, Model> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, Model>();\n static readonly mergedModelCache: AsyncLoadingCache<CacheKey, Model> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, Model>();\n static readonly modelTextureAtlasCache: AsyncLoadingCache<CacheKey, TextureAtlas> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, TextureAtlas>();\n\n static readonly blockStateCache: AsyncLoadingCache<CacheKey, BlockState> = Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, BlockState>();\n\n static readonly listAssetCache: AsyncLoadingCache<CacheKey, ListAsset> = Caching.createAssetCache<ListAsset>();\n\n static readonly blockTintCache: AsyncLoadingCache<CacheKey, number> = Caching.createAssetCache<number>();\n\n static readonly entityModelCache: AsyncLoadingCache<CacheKey, EntityModelFile> = Caching.createAssetCache<EntityModelFile>();\n\n static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey> = Caching.createAssetCache<AssetKey>();\n\n static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile> = Caching.createAssetCache<EntityAnimationFile>();\n static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex> = Caching.createAssetCache<BlockEntityIndex>();\n static readonly entityDatasetVersionCache: AsyncLoadingCache<CacheKey, string> = Caching.createAssetCache<string>();\n static readonly unihexCache: AsyncLoadingCache<CacheKey, UnihexFile> = Caching.createAssetCache<UnihexFile>();\n static readonly fontCache: AsyncLoadingCache<CacheKey, BitmapFont> = Caching.createAssetCache<BitmapFont>();\n static readonly bannerPatternCache: AsyncLoadingCache<CacheKey, BannerPattern> = Caching.createAssetCache<BannerPattern>();\n static readonly mineRenderDataCache: AsyncLoadingCache<CacheKey, unknown> = Caching.createAssetCache<unknown>();\n static readonly usernameUuidCache: AsyncLoadingCache<CacheKey, string> = Caches.builder()\n .expireAfterWrite(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, string>();\n static readonly biomeCache: AsyncLoadingCache<CacheKey, Biome> = Caching.createAssetCache<Biome>();\n\n private static createAssetCache<T>(): AsyncLoadingCache<CacheKey, T> {\n return Caches.builder()\n .expireAfterWrite(Time.minutes(10))\n .expireAfterAccess(Time.minutes(5))\n .expirationInterval(Time.seconds(30))\n .buildAsync<CacheKey, T>();\n }\n\n\n /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */\n private static get all(): { invalidateAll(): void; end(): void }[] {\n return [\n this.rawImageCache,\n this.imageDataCache,\n this.canvasImageDataCache,\n this.wrappedImageCache,\n this.boxGeometryCache,\n this.textureCache,\n this.materialCache,\n this.boxMeshCache,\n this.textureAssetCache,\n this.textureMetaCache,\n this.rawModelCache,\n this.mergedModelCache,\n this.modelTextureAtlasCache,\n this.blockStateCache,\n this.listAssetCache,\n this.blockTintCache,\n this.entityModelCache,\n this.entityTextureCache,\n this.entityAnimationCache,\n this.blockEntityIndexCache,\n this.entityDatasetVersionCache,\n this.fontCache,\n this.unihexCache,\n this.bannerPatternCache,\n this.mineRenderDataCache,\n this.usernameUuidCache,\n this.biomeCache\n ];\n }\n\n /** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */\n public static clear() {\n this._generation++;\n for (const cache of this.all) {\n cache.invalidateAll();\n }\n }\n\n /**\n * Clears every cache and stops its expiry timer.\n *\n * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.\n * Use {@link shutdown} to also stop requests and the shared Ticker.\n */\n public static end() {\n this._generation++;\n for (const cache of this.all) {\n cache.invalidateAll();\n cache.end();\n }\n }\n\n public static get cacheSizes() {\n return {\n //TODO\n }\n }\n\n}\n"],"mappings":"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","names":[]}
@@ -1259,6 +1259,12 @@ declare function sampleEntityAnimation(animation: EntityAnimation, time: number,
1259
1259
 
1260
1260
  /** Loads entity and block-entity geometry, texture selections, and animation clips from the dataset. */
1261
1261
  declare class Entities {
1262
+ /**
1263
+ * Resolves `root` (default: the active version). Uses the exact dataset when published or when the
1264
+ * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
1265
+ * Textures keep the requested root.
1266
+ */
1267
+ static getDatasetRoot(root?: string): Promise<Maybe<string>>;
1262
1268
  /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
1263
1269
  static getEntityList(): Promise<string[]>;
1264
1270
  private static getModelFile;
@@ -2756,6 +2762,7 @@ declare class Caching {
2756
2762
  static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey>;
2757
2763
  static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile>;
2758
2764
  static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex>;
2765
+ static readonly entityDatasetVersionCache: AsyncLoadingCache<CacheKey, string>;
2759
2766
  static readonly unihexCache: AsyncLoadingCache<CacheKey, UnihexFile>;
2760
2767
  static readonly fontCache: AsyncLoadingCache<CacheKey, BitmapFont>;
2761
2768
  static readonly bannerPatternCache: AsyncLoadingCache<CacheKey, BannerPattern>;