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.
@@ -353,6 +353,7 @@ var init_Caching = __esm({
353
353
  this.entityTextureCache,
354
354
  this.entityAnimationCache,
355
355
  this.blockEntityIndexCache,
356
+ this.entityDatasetVersionCache,
356
357
  this.fontCache,
357
358
  this.unihexCache,
358
359
  this.bannerPatternCache,
@@ -408,6 +409,7 @@ var init_Caching = __esm({
408
409
  _Caching.entityTextureCache = _Caching.createAssetCache();
409
410
  _Caching.entityAnimationCache = _Caching.createAssetCache();
410
411
  _Caching.blockEntityIndexCache = _Caching.createAssetCache();
412
+ _Caching.entityDatasetVersionCache = _Caching.createAssetCache();
411
413
  _Caching.unihexCache = _Caching.createAssetCache();
412
414
  _Caching.fontCache = _Caching.createAssetCache();
413
415
  _Caching.bannerPatternCache = _Caching.createAssetCache();
@@ -3234,23 +3236,39 @@ var init_MinecraftCubeTexture = __esm({
3234
3236
  }
3235
3237
  });
3236
3238
 
3239
+ // src/assets/_versions/DatasetVersions.ts
3240
+ var parseRelease, compare2, nearestRelease;
3241
+ var init_DatasetVersions = __esm({
3242
+ "src/assets/_versions/DatasetVersions.ts"() {
3243
+ parseRelease = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
3244
+ compare2 = (left, right) => {
3245
+ for (let i = 0; i < 3; i++) {
3246
+ const difference = (left[i] ?? 0) - (right[i] ?? 0);
3247
+ if (difference) return difference;
3248
+ }
3249
+ return 0;
3250
+ };
3251
+ nearestRelease = (requestedVersion, published) => {
3252
+ const requested = parseRelease(requestedVersion);
3253
+ if (!requested) return void 0;
3254
+ const versions = published.map((name) => ({ name, number: parseRelease(name) })).filter((entry) => !!entry.number).sort((left, right) => compare2(left.number, right.number));
3255
+ const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
3256
+ 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];
3257
+ return selected?.name;
3258
+ };
3259
+ }
3260
+ });
3261
+
3237
3262
  // src/assets/MineRenderData.ts
3238
- var object2, release, compare2, MineRenderData;
3263
+ var object2, MineRenderData;
3239
3264
  var init_MineRenderData = __esm({
3240
3265
  "src/assets/MineRenderData.ts"() {
3266
+ init_DatasetVersions();
3241
3267
  init_AssetKey();
3242
3268
  init_AssetLoader();
3243
3269
  init_AssetParsers();
3244
3270
  init_Caching();
3245
3271
  object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
3246
- release = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
3247
- compare2 = (left, right) => {
3248
- for (let i = 0; i < 3; i++) {
3249
- const difference = (left[i] ?? 0) - (right[i] ?? 0);
3250
- if (difference) return difference;
3251
- }
3252
- return 0;
3253
- };
3254
3272
  MineRenderData = class {
3255
3273
  /** Loads one registry. Missing files and invalid data reject the request. */
3256
3274
  static async get(dataset, root) {
@@ -3280,9 +3298,9 @@ var init_MineRenderData = __esm({
3280
3298
  const scope = AssetLoader.persistentScope;
3281
3299
  return this.cached(`resolve:${requestRoot === void 0 ? "sources" : "explicit"}:${root}`, scope, defaultRoot, async () => {
3282
3300
  const requestedVersion = root.slice(root.lastIndexOf("/") + 1);
3283
- let manifest = await this.manifest(root, requestRoot !== void 0 && release(requestedVersion) ? requestedVersion : void 0, requestRoot);
3301
+ let manifest = await this.manifest(root, requestRoot !== void 0 && parseRelease(requestedVersion) ? requestedVersion : void 0, requestRoot);
3284
3302
  if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };
3285
- const requested = release(requestedVersion);
3303
+ const requested = parseRelease(requestedVersion);
3286
3304
  if (!requested) {
3287
3305
  throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);
3288
3306
  }
@@ -3294,14 +3312,12 @@ var init_MineRenderData = __esm({
3294
3312
  }
3295
3313
  return value.versions;
3296
3314
  });
3297
- const versions = index.map((entry) => ({ name: entry.name, number: release(entry.name) })).filter((entry) => !!entry.number).sort((left, right) => compare2(left.number, right.number));
3298
- const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
3299
- 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];
3315
+ const selected = nearestRelease(requestedVersion, index.map((entry) => entry.name));
3300
3316
  if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);
3301
- const resolvedRoot = `${base}/${selected.name}`;
3302
- manifest = await this.manifest(resolvedRoot, selected.name, resolvedRoot);
3303
- if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected.name}`);
3304
- return { requestedVersion, version: selected.name, root: resolvedRoot, manifest };
3317
+ const resolvedRoot = `${base}/${selected}`;
3318
+ manifest = await this.manifest(resolvedRoot, selected, resolvedRoot);
3319
+ if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected}`);
3320
+ return { requestedVersion, version: selected, root: resolvedRoot, manifest };
3305
3321
  });
3306
3322
  }
3307
3323
  static async manifest(root, expectedVersion, requestRoot) {
@@ -4421,118 +4437,12 @@ var init_Biomes = __esm({
4421
4437
  }
4422
4438
  });
4423
4439
 
4424
- // src/assets/BlockEntities.ts
4425
- var import_three9, log10, BlockEntities;
4426
- var init_BlockEntities = __esm({
4427
- "src/assets/BlockEntities.ts"() {
4428
- import_three9 = require("three");
4429
- init_AssetKey();
4430
- init_AssetLoader();
4431
- init_source();
4432
- init_Caching();
4433
- init_log();
4434
- log10 = logger("BlockEntities");
4435
- BlockEntities = class {
4436
- /**
4437
- * Loads the block index of a version. Versions and sources without one yield an empty index, and so does
4438
- * a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
4439
- * result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
4440
- */
4441
- static async getIndex(root) {
4442
- const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
4443
- key.rootType = void 0;
4444
- const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
4445
- try {
4446
- return await AssetLoader.get(key, "json" /* JSON */) ?? {};
4447
- } catch (error) {
4448
- log10.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
4449
- return {};
4450
- }
4451
- });
4452
- return index ?? {};
4453
- }
4454
- /** The index entry of a block ID such as `minecraft:chest`. */
4455
- static entry(index, block) {
4456
- const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
4457
- return Array.isArray(entry?.parts) ? entry : void 0;
4458
- }
4459
- /** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
4460
- static resolve(index, block, state = {}) {
4461
- const entry = this.entry(index, block);
4462
- if (!entry) return void 0;
4463
- const value = (property) => String(state[property]).toLowerCase();
4464
- const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
4465
- if (!parts.length) return void 0;
4466
- let rotation = 0;
4467
- if (entry.rotation) {
4468
- const selected = value(entry.rotation.property);
4469
- rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
4470
- if (!Number.isFinite(rotation)) rotation = 0;
4471
- }
4472
- return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
4473
- }
4474
- /** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
4475
- static matrix(resolved, matrix = new import_three9.Matrix4()) {
4476
- 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));
4477
- }
4478
- };
4479
- }
4480
- });
4481
-
4482
- // src/assets/DecoratedPots.ts
4483
- var POTTERY_SHERDS, DecoratedPots;
4484
- var init_DecoratedPots = __esm({
4485
- "src/assets/DecoratedPots.ts"() {
4486
- init_AssetKey();
4487
- POTTERY_SHERDS = Object.freeze([
4488
- "angler",
4489
- "archer",
4490
- "arms_up",
4491
- "blade",
4492
- "brewer",
4493
- "burn",
4494
- "danger",
4495
- "explorer",
4496
- "flow",
4497
- "friend",
4498
- "guster",
4499
- "heart",
4500
- "heartbreak",
4501
- "howl",
4502
- "miner",
4503
- "mourner",
4504
- "plenty",
4505
- "prize",
4506
- "scrape",
4507
- "sheaf",
4508
- "shelter",
4509
- "skull",
4510
- "snort"
4511
- ].map((pattern2) => `minecraft:${pattern2}_pottery_sherd`));
4512
- DecoratedPots = class {
4513
- /** Reads up to four item IDs in back, left, right, front order; missing and unmapped items use plain sides. */
4514
- static getSideTextures(value, root) {
4515
- const items = value === void 0 ? [] : value;
4516
- if (!Array.isArray(items) || items.length > 4) throw new Error("pot_decorations must be an array of at most four item IDs");
4517
- const textures = items.map((item) => {
4518
- if (!isResourceLocation(item)) throw new Error("Pot decorations must be item identifiers");
4519
- const id = item.includes(":") ? item : `minecraft:${item}`;
4520
- return POTTERY_SHERDS.includes(id) ? id.slice("minecraft:".length).replace(/_sherd$/, "_pattern") : "decorated_pot_side";
4521
- });
4522
- return Object.fromEntries(["back", "left", "right", "front"].map((side, index) => [
4523
- side,
4524
- new AssetKey("minecraft", `decorated_pot/${textures[index] ?? "decorated_pot_side"}`, "textures", "entity", "assets", ".png", root)
4525
- ]));
4526
- }
4527
- };
4528
- }
4529
- });
4530
-
4531
4440
  // src/assets/Entities.ts
4532
4441
  var Entities;
4533
4442
  var init_Entities = __esm({
4534
4443
  "src/assets/Entities.ts"() {
4535
4444
  init_AssetKey();
4445
+ init_DatasetVersions();
4536
4446
  init_AssetLoader();
4537
4447
  init_source();
4538
4448
  init_Caching();
@@ -4540,11 +4450,36 @@ var init_Entities = __esm({
4540
4450
  init_MineRenderError();
4541
4451
  init_ModelTextures();
4542
4452
  Entities = class {
4453
+ /**
4454
+ * Resolves `root` (default: the active version). Uses the exact dataset when published or when the
4455
+ * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
4456
+ * Textures keep the requested root.
4457
+ */
4458
+ static async getDatasetRoot(root) {
4459
+ const requestRoot = (root ?? AssetLoader.ROOT).replace(/\/+$/, "");
4460
+ const requestedVersion = requestRoot.slice(requestRoot.lastIndexOf("/") + 1);
4461
+ const base = requestRoot.slice(0, requestRoot.lastIndexOf("/"));
4462
+ const selected = await Caching.entityDatasetVersionCache.get(root ?? `sources:${AssetLoader.ROOT}`, async () => {
4463
+ const key = new AssetKey("entity-models", "version", void 0, void 0, void 0, ".json", root);
4464
+ key.rootType = void 0;
4465
+ if (!parseRelease(requestedVersion) || await AssetLoader.get(key, "json" /* JSON */) !== void 0) return requestedVersion;
4466
+ const indexKey = new AssetKey("entity-models", "versions", void 0, void 0, void 0, ".json", base);
4467
+ indexKey.rootType = void 0;
4468
+ const index = await AssetLoader.get(indexKey, "json" /* JSON */);
4469
+ if (index === void 0) return requestedVersion;
4470
+ 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")) {
4471
+ throw new MineRenderError(`Invalid entity model version index at ${base}/entity-models/versions.json`);
4472
+ }
4473
+ return nearestRelease(requestedVersion, index.versions.map((entry) => entry.name)) ?? requestedVersion;
4474
+ });
4475
+ return selected === requestedVersion ? root : `${base}/${selected}`;
4476
+ }
4543
4477
  /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
4544
4478
  static async getEntityList() {
4479
+ const root = await this.getDatasetRoot();
4545
4480
  const collect = async (path) => {
4546
4481
  const prefix2 = path ? `${path}/` : "";
4547
- const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
4482
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json", root);
4548
4483
  const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
4549
4484
  if (!list2) return [];
4550
4485
  const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
@@ -4555,7 +4490,7 @@ var init_Entities = __esm({
4555
4490
  }
4556
4491
  static async getModelFile(modelKey) {
4557
4492
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4558
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
4493
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
4559
4494
  return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4560
4495
  }
4561
4496
  /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
@@ -4616,7 +4551,7 @@ var init_Entities = __esm({
4616
4551
  */
4617
4552
  static async getAnimations(modelKey) {
4618
4553
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4619
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
4554
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
4620
4555
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4621
4556
  return file?.animations;
4622
4557
  }
@@ -4658,6 +4593,115 @@ var init_Entities = __esm({
4658
4593
  }
4659
4594
  });
4660
4595
 
4596
+ // src/assets/BlockEntities.ts
4597
+ var import_three9, log10, BlockEntities;
4598
+ var init_BlockEntities = __esm({
4599
+ "src/assets/BlockEntities.ts"() {
4600
+ import_three9 = require("three");
4601
+ init_AssetKey();
4602
+ init_Entities();
4603
+ init_AssetLoader();
4604
+ init_source();
4605
+ init_Caching();
4606
+ init_log();
4607
+ log10 = logger("BlockEntities");
4608
+ BlockEntities = class {
4609
+ /**
4610
+ * Loads the block index of a version. Versions and sources without one yield an empty index, and so does
4611
+ * a failed load: the index is optional, and blocks must not retry or fail with it one by one. The empty
4612
+ * result is cached like any other; `Caching.clear()` or `AssetLoader.setVersion()` forces a new attempt.
4613
+ */
4614
+ static async getIndex(root) {
4615
+ const key = new AssetKey("entity-models", "blocks", void 0, void 0, void 0, ".json", root);
4616
+ key.rootType = void 0;
4617
+ const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
4618
+ try {
4619
+ key.root = await Entities.getDatasetRoot(root);
4620
+ return await AssetLoader.get(key, "json" /* JSON */) ?? {};
4621
+ } catch (error) {
4622
+ log10.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
4623
+ return {};
4624
+ }
4625
+ });
4626
+ return index ?? {};
4627
+ }
4628
+ /** The index entry of a block ID such as `minecraft:chest`. */
4629
+ static entry(index, block) {
4630
+ const entry = Object.prototype.hasOwnProperty.call(index, block) ? index[block] : void 0;
4631
+ return Array.isArray(entry?.parts) ? entry : void 0;
4632
+ }
4633
+ /** Selects the parts and placement for a block ID such as `minecraft:chest`; undefined when nothing is drawn. */
4634
+ static resolve(index, block, state = {}) {
4635
+ const entry = this.entry(index, block);
4636
+ if (!entry) return void 0;
4637
+ const value = (property) => String(state[property]).toLowerCase();
4638
+ const parts = entry.parts.filter((part) => Object.entries(part.when ?? {}).every(([property, values]) => String(values).split("|").includes(value(property))));
4639
+ if (!parts.length) return void 0;
4640
+ let rotation = 0;
4641
+ if (entry.rotation) {
4642
+ const selected = value(entry.rotation.property);
4643
+ rotation = "degrees" in entry.rotation ? entry.rotation.degrees[selected] : Number(selected) * entry.rotation.step;
4644
+ if (!Number.isFinite(rotation)) rotation = 0;
4645
+ }
4646
+ return { parts, rotation, translation: entry.translation ?? [0, 0, 0] };
4647
+ }
4648
+ /** Placement in block space (0..16 per axis), applied on top of the model's own transform. */
4649
+ static matrix(resolved, matrix = new import_three9.Matrix4()) {
4650
+ 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));
4651
+ }
4652
+ };
4653
+ }
4654
+ });
4655
+
4656
+ // src/assets/DecoratedPots.ts
4657
+ var POTTERY_SHERDS, DecoratedPots;
4658
+ var init_DecoratedPots = __esm({
4659
+ "src/assets/DecoratedPots.ts"() {
4660
+ init_AssetKey();
4661
+ POTTERY_SHERDS = Object.freeze([
4662
+ "angler",
4663
+ "archer",
4664
+ "arms_up",
4665
+ "blade",
4666
+ "brewer",
4667
+ "burn",
4668
+ "danger",
4669
+ "explorer",
4670
+ "flow",
4671
+ "friend",
4672
+ "guster",
4673
+ "heart",
4674
+ "heartbreak",
4675
+ "howl",
4676
+ "miner",
4677
+ "mourner",
4678
+ "plenty",
4679
+ "prize",
4680
+ "scrape",
4681
+ "sheaf",
4682
+ "shelter",
4683
+ "skull",
4684
+ "snort"
4685
+ ].map((pattern2) => `minecraft:${pattern2}_pottery_sherd`));
4686
+ DecoratedPots = class {
4687
+ /** Reads up to four item IDs in back, left, right, front order; missing and unmapped items use plain sides. */
4688
+ static getSideTextures(value, root) {
4689
+ const items = value === void 0 ? [] : value;
4690
+ if (!Array.isArray(items) || items.length > 4) throw new Error("pot_decorations must be an array of at most four item IDs");
4691
+ const textures = items.map((item) => {
4692
+ if (!isResourceLocation(item)) throw new Error("Pot decorations must be item identifiers");
4693
+ const id = item.includes(":") ? item : `minecraft:${item}`;
4694
+ return POTTERY_SHERDS.includes(id) ? id.slice("minecraft:".length).replace(/_sherd$/, "_pattern") : "decorated_pot_side";
4695
+ });
4696
+ return Object.fromEntries(["back", "left", "right", "front"].map((side, index) => [
4697
+ side,
4698
+ new AssetKey("minecraft", `decorated_pot/${textures[index] ?? "decorated_pot_side"}`, "textures", "entity", "assets", ".png", root)
4699
+ ]));
4700
+ }
4701
+ };
4702
+ }
4703
+ });
4704
+
4661
4705
  // src/assets/_fonts/Unihex.ts
4662
4706
  var Unihex_exports = {};
4663
4707
  __export(Unihex_exports, {
@@ -17978,7 +18022,7 @@ var AnvilWorldSource = class {
17978
18022
  read.waiters++;
17979
18023
  return new Promise((resolve, reject) => {
17980
18024
  let finished = false;
17981
- const release2 = () => {
18025
+ const release = () => {
17982
18026
  if (finished) return false;
17983
18027
  finished = true;
17984
18028
  signal?.removeEventListener("abort", abort);
@@ -17986,7 +18030,7 @@ var AnvilWorldSource = class {
17986
18030
  return true;
17987
18031
  };
17988
18032
  const abort = () => {
17989
- if (!release2()) return;
18033
+ if (!release()) return;
17990
18034
  if (!read.waiters && !read.settled) {
17991
18035
  if (this.pending.get(key) === read) this.pending.delete(key);
17992
18036
  read.controller.abort(signal.reason);
@@ -17996,10 +18040,10 @@ var AnvilWorldSource = class {
17996
18040
  signal?.addEventListener("abort", abort, { once: true });
17997
18041
  read.promise.then(
17998
18042
  (data) => {
17999
- if (release2()) resolve(data);
18043
+ if (release()) resolve(data);
18000
18044
  },
18001
18045
  (error) => {
18002
- if (release2()) reject(error);
18046
+ if (release()) reject(error);
18003
18047
  }
18004
18048
  );
18005
18049
  if (signal?.aborted) abort();