minerender 2.1.0-alpha.140 → 2.1.0-alpha.141

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.
@@ -1261,6 +1261,12 @@ declare function sampleEntityAnimation(animation: EntityAnimation, time: number,
1261
1261
 
1262
1262
  /** Loads entity and block-entity geometry, texture selections, and animation clips from the dataset. */
1263
1263
  declare class Entities {
1264
+ /**
1265
+ * Resolves `root` (default: the active version). Uses the exact dataset when published or when the
1266
+ * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
1267
+ * Textures keep the requested root.
1268
+ */
1269
+ static getDatasetRoot(root?: string): Promise<Maybe<string>>;
1264
1270
  /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
1265
1271
  static getEntityList(): Promise<string[]>;
1266
1272
  private static getModelFile;
@@ -2758,6 +2764,7 @@ declare class Caching {
2758
2764
  static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey>;
2759
2765
  static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile>;
2760
2766
  static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex>;
2767
+ static readonly entityDatasetVersionCache: AsyncLoadingCache<CacheKey, string>;
2761
2768
  static readonly unihexCache: AsyncLoadingCache<CacheKey, UnihexFile>;
2762
2769
  static readonly fontCache: AsyncLoadingCache<CacheKey, BitmapFont>;
2763
2770
  static readonly bannerPatternCache: AsyncLoadingCache<CacheKey, BannerPattern>;
@@ -1261,6 +1261,12 @@ declare function sampleEntityAnimation(animation: EntityAnimation, time: number,
1261
1261
 
1262
1262
  /** Loads entity and block-entity geometry, texture selections, and animation clips from the dataset. */
1263
1263
  declare class Entities {
1264
+ /**
1265
+ * Resolves `root` (default: the active version). Uses the exact dataset when published or when the
1266
+ * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
1267
+ * Textures keep the requested root.
1268
+ */
1269
+ static getDatasetRoot(root?: string): Promise<Maybe<string>>;
1264
1270
  /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
1265
1271
  static getEntityList(): Promise<string[]>;
1266
1272
  private static getModelFile;
@@ -2758,6 +2764,7 @@ declare class Caching {
2758
2764
  static readonly entityTextureCache: AsyncLoadingCache<CacheKey, AssetKey>;
2759
2765
  static readonly entityAnimationCache: AsyncLoadingCache<CacheKey, EntityAnimationFile>;
2760
2766
  static readonly blockEntityIndexCache: AsyncLoadingCache<CacheKey, BlockEntityIndex>;
2767
+ static readonly entityDatasetVersionCache: AsyncLoadingCache<CacheKey, string>;
2761
2768
  static readonly unihexCache: AsyncLoadingCache<CacheKey, UnihexFile>;
2762
2769
  static readonly fontCache: AsyncLoadingCache<CacheKey, BitmapFont>;
2763
2770
  static readonly bannerPatternCache: AsyncLoadingCache<CacheKey, BannerPattern>;
@@ -310,6 +310,9 @@ var init_Caching = __esm({
310
310
  static {
311
311
  this.blockEntityIndexCache = _Caching.createAssetCache();
312
312
  }
313
+ static {
314
+ this.entityDatasetVersionCache = _Caching.createAssetCache();
315
+ }
313
316
  static {
314
317
  this.unihexCache = _Caching.createAssetCache();
315
318
  }
@@ -354,6 +357,7 @@ var init_Caching = __esm({
354
357
  this.entityTextureCache,
355
358
  this.entityAnimationCache,
356
359
  this.blockEntityIndexCache,
360
+ this.entityDatasetVersionCache,
357
361
  this.fontCache,
358
362
  this.unihexCache,
359
363
  this.bannerPatternCache,
@@ -3332,23 +3336,39 @@ var init_MinecraftCubeTexture = __esm({
3332
3336
  }
3333
3337
  });
3334
3338
 
3339
+ // src/assets/_versions/DatasetVersions.ts
3340
+ var parseRelease, compare2, nearestRelease;
3341
+ var init_DatasetVersions = __esm({
3342
+ "src/assets/_versions/DatasetVersions.ts"() {
3343
+ parseRelease = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
3344
+ compare2 = (left, right) => {
3345
+ for (let i = 0; i < 3; i++) {
3346
+ const difference = (left[i] ?? 0) - (right[i] ?? 0);
3347
+ if (difference) return difference;
3348
+ }
3349
+ return 0;
3350
+ };
3351
+ nearestRelease = (requestedVersion, published) => {
3352
+ const requested = parseRelease(requestedVersion);
3353
+ if (!requested) return void 0;
3354
+ const versions = published.map((name) => ({ name, number: parseRelease(name) })).filter((entry) => !!entry.number).sort((left, right) => compare2(left.number, right.number));
3355
+ const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
3356
+ const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare2(left.number, right.number))[0] ?? versions.filter((entry) => compare2(entry.number, requested) <= 0).pop() ?? versions[0];
3357
+ return selected?.name;
3358
+ };
3359
+ }
3360
+ });
3361
+
3335
3362
  // src/assets/MineRenderData.ts
3336
- var object2, release, compare2, MineRenderData;
3363
+ var object2, MineRenderData;
3337
3364
  var init_MineRenderData = __esm({
3338
3365
  "src/assets/MineRenderData.ts"() {
3366
+ init_DatasetVersions();
3339
3367
  init_AssetKey();
3340
3368
  init_AssetLoader();
3341
3369
  init_AssetParsers();
3342
3370
  init_Caching();
3343
3371
  object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
3344
- release = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
3345
- compare2 = (left, right) => {
3346
- for (let i = 0; i < 3; i++) {
3347
- const difference = (left[i] ?? 0) - (right[i] ?? 0);
3348
- if (difference) return difference;
3349
- }
3350
- return 0;
3351
- };
3352
3372
  MineRenderData = class {
3353
3373
  /** Loads one registry. Missing files and invalid data reject the request. */
3354
3374
  static async get(dataset, root) {
@@ -3378,9 +3398,9 @@ var init_MineRenderData = __esm({
3378
3398
  const scope = AssetLoader.persistentScope;
3379
3399
  return this.cached(`resolve:${requestRoot === void 0 ? "sources" : "explicit"}:${root}`, scope, defaultRoot, async () => {
3380
3400
  const requestedVersion = root.slice(root.lastIndexOf("/") + 1);
3381
- let manifest = await this.manifest(root, requestRoot !== void 0 && release(requestedVersion) ? requestedVersion : void 0, requestRoot);
3401
+ let manifest = await this.manifest(root, requestRoot !== void 0 && parseRelease(requestedVersion) ? requestedVersion : void 0, requestRoot);
3382
3402
  if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };
3383
- const requested = release(requestedVersion);
3403
+ const requested = parseRelease(requestedVersion);
3384
3404
  if (!requested) {
3385
3405
  throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);
3386
3406
  }
@@ -3392,14 +3412,12 @@ var init_MineRenderData = __esm({
3392
3412
  }
3393
3413
  return value.versions;
3394
3414
  });
3395
- const versions = index.map((entry) => ({ name: entry.name, number: release(entry.name) })).filter((entry) => !!entry.number).sort((left, right) => compare2(left.number, right.number));
3396
- const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
3397
- const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare2(left.number, right.number))[0] ?? versions.filter((entry) => compare2(entry.number, requested) <= 0).pop() ?? versions[0];
3415
+ const selected = nearestRelease(requestedVersion, index.map((entry) => entry.name));
3398
3416
  if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);
3399
- const resolvedRoot = `${base}/${selected.name}`;
3400
- manifest = await this.manifest(resolvedRoot, selected.name, resolvedRoot);
3401
- if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected.name}`);
3402
- return { requestedVersion, version: selected.name, root: resolvedRoot, manifest };
3417
+ const resolvedRoot = `${base}/${selected}`;
3418
+ manifest = await this.manifest(resolvedRoot, selected, resolvedRoot);
3419
+ if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected}`);
3420
+ return { requestedVersion, version: selected, root: resolvedRoot, manifest };
3403
3421
  });
3404
3422
  }
3405
3423
  static async manifest(root, expectedVersion, requestRoot) {
@@ -4521,118 +4539,12 @@ var init_Biomes = __esm({
4521
4539
  }
4522
4540
  });
4523
4541
 
4524
- // src/assets/BlockEntities.ts
4525
- var import_three9, log9, BlockEntities;
4526
- var init_BlockEntities = __esm({
4527
- "src/assets/BlockEntities.ts"() {
4528
- import_three9 = require("three");
4529
- init_AssetKey();
4530
- init_AssetLoader();
4531
- init_source();
4532
- init_Caching();
4533
- init_log();
4534
- log9 = logger("BlockEntities");
4535
- BlockEntities = class {
4536
- /**
4537
- * Loads the block index of a version. Versions and sources without one yield an empty index, and so does
4538
- * a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
4539
- * result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
4540
- */
4541
- static async getIndex(root) {
4542
- const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
4543
- key.rootType = void 0;
4544
- const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
4545
- try {
4546
- return await AssetLoader.get(key, "json" /* JSON */) ?? {};
4547
- } catch (error) {
4548
- log9.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
4549
- return {};
4550
- }
4551
- });
4552
- return index ?? {};
4553
- }
4554
- /** The index entry of a block ID such as `minecraft:chest`. */
4555
- static entry(index, block) {
4556
- const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
4557
- return Array.isArray(entry?.parts) ? entry : void 0;
4558
- }
4559
- /** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
4560
- static resolve(index, block, state = {}) {
4561
- const entry = this.entry(index, block);
4562
- if (!entry) return void 0;
4563
- const value = (property) => String(state[property]).toLowerCase();
4564
- const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
4565
- if (!parts.length) return void 0;
4566
- let rotation = 0;
4567
- if (entry.rotation) {
4568
- const selected = value(entry.rotation.property);
4569
- rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
4570
- if (!Number.isFinite(rotation)) rotation = 0;
4571
- }
4572
- return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
4573
- }
4574
- /** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
4575
- static matrix(resolved, matrix = new import_three9.Matrix4()) {
4576
- return matrix.makeTranslation(8, 0, 8).multiply(new import_three9.Matrix4().makeRotationY(resolved.rotation * Math.PI / 180)).multiply(new import_three9.Matrix4().makeTranslation(resolved.translation[0] - 8, resolved.translation[1], resolved.translation[2] - 8));
4577
- }
4578
- };
4579
- }
4580
- });
4581
-
4582
- // src/assets/DecoratedPots.ts
4583
- var POTTERY_SHERDS, DecoratedPots;
4584
- var init_DecoratedPots = __esm({
4585
- "src/assets/DecoratedPots.ts"() {
4586
- init_AssetKey();
4587
- POTTERY_SHERDS = Object.freeze([
4588
- "angler",
4589
- "archer",
4590
- "arms_up",
4591
- "blade",
4592
- "brewer",
4593
- "burn",
4594
- "danger",
4595
- "explorer",
4596
- "flow",
4597
- "friend",
4598
- "guster",
4599
- "heart",
4600
- "heartbreak",
4601
- "howl",
4602
- "miner",
4603
- "mourner",
4604
- "plenty",
4605
- "prize",
4606
- "scrape",
4607
- "sheaf",
4608
- "shelter",
4609
- "skull",
4610
- "snort"
4611
- ].map((pattern2) => `minecraft:${pattern2}_pottery_sherd`));
4612
- DecoratedPots = class {
4613
- /** Reads up to four item IDs in back, left, right, front order; missing and unmapped items use plain sides. */
4614
- static getSideTextures(value, root) {
4615
- const items = value === void 0 ? [] : value;
4616
- if (!Array.isArray(items) || items.length > 4) throw new Error("pot_decorations must be an array of at most four item IDs");
4617
- const textures = items.map((item) => {
4618
- if (!isResourceLocation(item)) throw new Error("Pot decorations must be item identifiers");
4619
- const id = item.includes(":") ? item : `minecraft:${item}`;
4620
- return POTTERY_SHERDS.includes(id) ? id.slice("minecraft:".length).replace(/_sherd$/, "_pattern") : "decorated_pot_side";
4621
- });
4622
- return Object.fromEntries(["back", "left", "right", "front"].map((side, index) => [
4623
- side,
4624
- new AssetKey("minecraft", `decorated_pot/${textures[index] ?? "decorated_pot_side"}`, "textures", "entity", "assets", ".png", root)
4625
- ]));
4626
- }
4627
- };
4628
- }
4629
- });
4630
-
4631
4542
  // src/assets/Entities.ts
4632
4543
  var Entities;
4633
4544
  var init_Entities = __esm({
4634
4545
  "src/assets/Entities.ts"() {
4635
4546
  init_AssetKey();
4547
+ init_DatasetVersions();
4636
4548
  init_AssetLoader();
4637
4549
  init_source();
4638
4550
  init_Caching();
@@ -4640,11 +4552,36 @@ var init_Entities = __esm({
4640
4552
  init_MineRenderError();
4641
4553
  init_ModelTextures();
4642
4554
  Entities = class {
4555
+ /**
4556
+ * Resolves `root` (default: the active version). Uses the exact dataset when published or when the
4557
+ * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
4558
+ * Textures keep the requested root.
4559
+ */
4560
+ static async getDatasetRoot(root) {
4561
+ const requestRoot = (root ?? AssetLoader.ROOT).replace(/\/+$/, "");
4562
+ const requestedVersion = requestRoot.slice(requestRoot.lastIndexOf("/") + 1);
4563
+ const base = requestRoot.slice(0, requestRoot.lastIndexOf("/"));
4564
+ const selected = await Caching.entityDatasetVersionCache.get(root ?? `sources:${AssetLoader.ROOT}`, async () => {
4565
+ const key = new AssetKey("entity-models", "version", void 0, void 0, void 0, ".json", root);
4566
+ key.rootType = void 0;
4567
+ if (!parseRelease(requestedVersion) || await AssetLoader.get(key, "json" /* JSON */) !== void 0) return requestedVersion;
4568
+ const indexKey = new AssetKey("entity-models", "versions", void 0, void 0, void 0, ".json", base);
4569
+ indexKey.rootType = void 0;
4570
+ const index = await AssetLoader.get(indexKey, "json" /* JSON */);
4571
+ if (index === void 0) return requestedVersion;
4572
+ 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")) {
4573
+ throw new MineRenderError(`Invalid entity model version index at ${base}/entity-models/versions.json`);
4574
+ }
4575
+ return nearestRelease(requestedVersion, index.versions.map((entry) => entry.name)) ?? requestedVersion;
4576
+ });
4577
+ return selected === requestedVersion ? root : `${base}/${selected}`;
4578
+ }
4643
4579
  /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
4644
4580
  static async getEntityList() {
4581
+ const root = await this.getDatasetRoot();
4645
4582
  const collect = async (path) => {
4646
4583
  const prefix2 = path ? `${path}/` : "";
4647
- const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
4584
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json", root);
4648
4585
  const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
4649
4586
  if (!list2) return [];
4650
4587
  const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
@@ -4655,7 +4592,7 @@ var init_Entities = __esm({
4655
4592
  }
4656
4593
  static async getModelFile(modelKey) {
4657
4594
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4658
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
4595
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
4659
4596
  return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4660
4597
  }
4661
4598
  /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
@@ -4716,7 +4653,7 @@ var init_Entities = __esm({
4716
4653
  */
4717
4654
  static async getAnimations(modelKey) {
4718
4655
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4719
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
4656
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
4720
4657
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4721
4658
  return file?.animations;
4722
4659
  }
@@ -4758,6 +4695,115 @@ var init_Entities = __esm({
4758
4695
  }
4759
4696
  });
4760
4697
 
4698
+ // src/assets/BlockEntities.ts
4699
+ var import_three9, log9, BlockEntities;
4700
+ var init_BlockEntities = __esm({
4701
+ "src/assets/BlockEntities.ts"() {
4702
+ import_three9 = require("three");
4703
+ init_AssetKey();
4704
+ init_Entities();
4705
+ init_AssetLoader();
4706
+ init_source();
4707
+ init_Caching();
4708
+ init_log();
4709
+ log9 = logger("BlockEntities");
4710
+ BlockEntities = class {
4711
+ /**
4712
+ * Loads the block index of a version. Versions and sources without one yield an empty index, and so does
4713
+ * a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
4714
+ * result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
4715
+ */
4716
+ static async getIndex(root) {
4717
+ const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
4718
+ key.rootType = void 0;
4719
+ const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
4720
+ try {
4721
+ key.root = await Entities.getDatasetRoot(root);
4722
+ return await AssetLoader.get(key, "json" /* JSON */) ?? {};
4723
+ } catch (error) {
4724
+ log9.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
4725
+ return {};
4726
+ }
4727
+ });
4728
+ return index ?? {};
4729
+ }
4730
+ /** The index entry of a block ID such as `minecraft:chest`. */
4731
+ static entry(index, block) {
4732
+ const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
4733
+ return Array.isArray(entry?.parts) ? entry : void 0;
4734
+ }
4735
+ /** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
4736
+ static resolve(index, block, state = {}) {
4737
+ const entry = this.entry(index, block);
4738
+ if (!entry) return void 0;
4739
+ const value = (property) => String(state[property]).toLowerCase();
4740
+ const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
4741
+ if (!parts.length) return void 0;
4742
+ let rotation = 0;
4743
+ if (entry.rotation) {
4744
+ const selected = value(entry.rotation.property);
4745
+ rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
4746
+ if (!Number.isFinite(rotation)) rotation = 0;
4747
+ }
4748
+ return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
4749
+ }
4750
+ /** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
4751
+ static matrix(resolved, matrix = new import_three9.Matrix4()) {
4752
+ return matrix.makeTranslation(8, 0, 8).multiply(new import_three9.Matrix4().makeRotationY(resolved.rotation * Math.PI / 180)).multiply(new import_three9.Matrix4().makeTranslation(resolved.translation[0] - 8, resolved.translation[1], resolved.translation[2] - 8));
4753
+ }
4754
+ };
4755
+ }
4756
+ });
4757
+
4758
+ // src/assets/DecoratedPots.ts
4759
+ var POTTERY_SHERDS, DecoratedPots;
4760
+ var init_DecoratedPots = __esm({
4761
+ "src/assets/DecoratedPots.ts"() {
4762
+ init_AssetKey();
4763
+ POTTERY_SHERDS = Object.freeze([
4764
+ "angler",
4765
+ "archer",
4766
+ "arms_up",
4767
+ "blade",
4768
+ "brewer",
4769
+ "burn",
4770
+ "danger",
4771
+ "explorer",
4772
+ "flow",
4773
+ "friend",
4774
+ "guster",
4775
+ "heart",
4776
+ "heartbreak",
4777
+ "howl",
4778
+ "miner",
4779
+ "mourner",
4780
+ "plenty",
4781
+ "prize",
4782
+ "scrape",
4783
+ "sheaf",
4784
+ "shelter",
4785
+ "skull",
4786
+ "snort"
4787
+ ].map((pattern2) => `minecraft:${pattern2}_pottery_sherd`));
4788
+ DecoratedPots = class {
4789
+ /** Reads up to four item IDs in back, left, right, front order; missing and unmapped items use plain sides. */
4790
+ static getSideTextures(value, root) {
4791
+ const items = value === void 0 ? [] : value;
4792
+ if (!Array.isArray(items) || items.length > 4) throw new Error("pot_decorations must be an array of at most four item IDs");
4793
+ const textures = items.map((item) => {
4794
+ if (!isResourceLocation(item)) throw new Error("Pot decorations must be item identifiers");
4795
+ const id = item.includes(":") ? item : `minecraft:${item}`;
4796
+ return POTTERY_SHERDS.includes(id) ? id.slice("minecraft:".length).replace(/_sherd$/, "_pattern") : "decorated_pot_side";
4797
+ });
4798
+ return Object.fromEntries(["back", "left", "right", "front"].map((side, index) => [
4799
+ side,
4800
+ new AssetKey("minecraft", `decorated_pot/${textures[index] ?? "decorated_pot_side"}`, "textures", "entity", "assets", ".png", root)
4801
+ ]));
4802
+ }
4803
+ };
4804
+ }
4805
+ });
4806
+
4761
4807
  // src/assets/_fonts/Unihex.ts
4762
4808
  var Unihex_exports = {};
4763
4809
  __export(Unihex_exports, {
@@ -18003,7 +18049,7 @@ var AnvilWorldSource = class {
18003
18049
  read.waiters++;
18004
18050
  return new Promise((resolve, reject) => {
18005
18051
  let finished = false;
18006
- const release2 = () => {
18052
+ const release = () => {
18007
18053
  if (finished) return false;
18008
18054
  finished = true;
18009
18055
  signal?.removeEventListener("abort", abort);
@@ -18011,7 +18057,7 @@ var AnvilWorldSource = class {
18011
18057
  return true;
18012
18058
  };
18013
18059
  const abort = () => {
18014
- if (!release2()) return;
18060
+ if (!release()) return;
18015
18061
  if (!read.waiters && !read.settled) {
18016
18062
  if (this.pending.get(key) === read) this.pending.delete(key);
18017
18063
  read.controller.abort(signal.reason);
@@ -18021,10 +18067,10 @@ var AnvilWorldSource = class {
18021
18067
  signal?.addEventListener("abort", abort, { once: true });
18022
18068
  read.promise.then(
18023
18069
  (data) => {
18024
- if (release2()) resolve(data);
18070
+ if (release()) resolve(data);
18025
18071
  },
18026
18072
  (error) => {
18027
- if (release2()) reject(error);
18073
+ if (release()) reject(error);
18028
18074
  }
18029
18075
  );
18030
18076
  if (signal?.aborted) abort();