minerender 2.1.0-beta.7 → 2.1.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +10 -1
  2. package/dist/browser/esm/armor/Armor.mjs +84 -0
  3. package/dist/browser/esm/armor/Armor.mjs.map +1 -0
  4. package/dist/browser/esm/armor/index.mjs +3 -0
  5. package/dist/browser/esm/armor/index.mjs.map +1 -0
  6. package/dist/browser/esm/assets/BlockEntities.mjs +2 -0
  7. package/dist/browser/esm/assets/BlockEntities.mjs.map +1 -1
  8. package/dist/browser/esm/assets/Entities.mjs +39 -11
  9. package/dist/browser/esm/assets/Entities.mjs.map +1 -1
  10. package/dist/browser/esm/assets/MineRenderData.mjs +8 -17
  11. package/dist/browser/esm/assets/MineRenderData.mjs.map +1 -1
  12. package/dist/browser/esm/assets/ModelTextures.mjs +13 -7
  13. package/dist/browser/esm/assets/ModelTextures.mjs.map +1 -1
  14. package/dist/browser/esm/assets/_versions/DatasetVersions.mjs +22 -0
  15. package/dist/browser/esm/assets/_versions/DatasetVersions.mjs.map +1 -0
  16. package/dist/browser/esm/cache/Caching.mjs +8 -0
  17. package/dist/browser/esm/cache/Caching.mjs.map +1 -1
  18. package/dist/browser/esm/entity/scene/EntityObject.mjs +31 -5
  19. package/dist/browser/esm/entity/scene/EntityObject.mjs.map +1 -1
  20. package/dist/browser/esm/env/browser/BrowserEnv.mjs +11 -4
  21. package/dist/browser/esm/env/browser/BrowserEnv.mjs.map +1 -1
  22. package/dist/browser/esm/index.browser.d.mts +129 -13
  23. package/dist/browser/esm/index.browser.mjs.map +1 -1
  24. package/dist/browser/esm/index.mjs +1 -0
  25. package/dist/browser/esm/index.mjs.map +1 -1
  26. package/dist/browser/esm/model/ItemGlint.mjs +7 -6
  27. package/dist/browser/esm/model/ItemGlint.mjs.map +1 -1
  28. package/dist/browser/esm/model/block/scene/BlockObject.mjs +16 -5
  29. package/dist/browser/esm/model/block/scene/BlockObject.mjs.map +1 -1
  30. package/dist/browser/esm/scene/SceneDocument.mjs +35 -5
  31. package/dist/browser/esm/scene/SceneDocument.mjs.map +1 -1
  32. package/dist/browser/esm/scene/SceneDocumentLoader.mjs +14 -3
  33. package/dist/browser/esm/scene/SceneDocumentLoader.mjs.map +1 -1
  34. package/dist/browser/esm/skin/SkinGeometries.mjs +4 -1
  35. package/dist/browser/esm/skin/SkinGeometries.mjs.map +1 -1
  36. package/dist/browser/esm/skin/SkinPart.mjs +2 -0
  37. package/dist/browser/esm/skin/SkinPart.mjs.map +1 -1
  38. package/dist/browser/esm/skin/SkinTextureCoordinates.mjs +11 -1
  39. package/dist/browser/esm/skin/SkinTextureCoordinates.mjs.map +1 -1
  40. package/dist/browser/esm/skin/SkinTextures.mjs +1 -1
  41. package/dist/browser/esm/skin/SkinTextures.mjs.map +1 -1
  42. package/dist/browser/esm/skin/scene/SkinObject.mjs +119 -7
  43. package/dist/browser/esm/skin/scene/SkinObject.mjs.map +1 -1
  44. package/dist/browser/esm/texture/PalettedTextures.mjs +46 -0
  45. package/dist/browser/esm/texture/PalettedTextures.mjs.map +1 -0
  46. package/dist/browser/esm/texture/index.mjs +1 -0
  47. package/dist/browser/esm/texture/index.mjs.map +1 -1
  48. package/dist/browser/esm/util/util.mjs +0 -2
  49. package/dist/browser/esm/util/util.mjs.map +1 -1
  50. package/dist/browser/esm/world/Chunk.mjs +62 -33
  51. package/dist/browser/esm/world/Chunk.mjs.map +1 -1
  52. package/dist/browser/esm/world/MineRenderWorld.mjs +98 -13
  53. package/dist/browser/esm/world/MineRenderWorld.mjs.map +1 -1
  54. package/dist/browser/esm/world/SectionMesh.mjs +65 -9
  55. package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
  56. package/dist/browser/esm/world/SectionModels.mjs +21 -15
  57. package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
  58. package/dist/browser/esm/world/SectionWorker.mjs +8 -2
  59. package/dist/browser/esm/world/SectionWorker.mjs.map +1 -1
  60. package/dist/browser/esm/world/WorldStreamer.mjs +109 -15
  61. package/dist/browser/esm/world/WorldStreamer.mjs.map +1 -1
  62. package/dist/browser/index.d.ts +129 -13
  63. package/dist/browser/index.js +1592 -894
  64. package/dist/browser/index.js.map +1 -1
  65. package/dist/bundle.js +1330 -619
  66. package/dist/bundle.js.map +1 -1
  67. package/dist/node/index.d.mts +117 -12
  68. package/dist/node/index.d.ts +117 -12
  69. package/dist/node/index.js +1505 -793
  70. package/dist/node/index.js.map +1 -1
  71. package/dist/node/index.mjs +1303 -593
  72. package/dist/node/index.mjs.map +1 -1
  73. package/package.json +2 -1
@@ -56,37 +56,6 @@ var init_Env = __esm({
56
56
  }
57
57
  });
58
58
 
59
- // src/cache/PersistentCache.ts
60
- var _PersistentCache, PersistentCache;
61
- var init_PersistentCache = __esm({
62
- "src/cache/PersistentCache.ts"() {
63
- init_Env();
64
- _PersistentCache = class _PersistentCache {
65
- constructor(backing) {
66
- this.backing = backing;
67
- }
68
- /** Opens a named store in the active environment using the current cache schema version. */
69
- static open(name) {
70
- return Env.provider.openCache(name, _PersistentCache.VERSION);
71
- }
72
- /** Loads a missing entry and stores only non-nullish results. */
73
- async getOrLoad(key, loader) {
74
- let v = await this.get(key);
75
- if (typeof v === "undefined" || v === null) {
76
- v = await loader(key);
77
- if (typeof v !== "undefined" && v !== null) {
78
- await this.put(key, v);
79
- }
80
- }
81
- return v;
82
- }
83
- };
84
- /** Bump to invalidate every persisted entry. */
85
- _PersistentCache.VERSION = 2;
86
- PersistentCache = _PersistentCache;
87
- }
88
- });
89
-
90
59
  // src/util/log.ts
91
60
  function readSwitch() {
92
61
  switchRead = true;
@@ -168,6 +137,37 @@ var init_log = __esm({
168
137
  }
169
138
  });
170
139
 
140
+ // src/cache/PersistentCache.ts
141
+ var _PersistentCache, PersistentCache;
142
+ var init_PersistentCache = __esm({
143
+ "src/cache/PersistentCache.ts"() {
144
+ init_Env();
145
+ _PersistentCache = class _PersistentCache {
146
+ constructor(backing) {
147
+ this.backing = backing;
148
+ }
149
+ /** Opens a named store in the active environment using the current cache schema version. */
150
+ static open(name) {
151
+ return Env.provider.openCache(name, _PersistentCache.VERSION);
152
+ }
153
+ /** Loads a missing entry and stores only non-nullish results. */
154
+ async getOrLoad(key, loader) {
155
+ let v = await this.get(key);
156
+ if (typeof v === "undefined" || v === null) {
157
+ v = await loader(key);
158
+ if (typeof v !== "undefined" && v !== null) {
159
+ await this.put(key, v);
160
+ }
161
+ }
162
+ return v;
163
+ }
164
+ };
165
+ /** Bump to invalidate every persisted entry. */
166
+ _PersistentCache.VERSION = 2;
167
+ PersistentCache = _PersistentCache;
168
+ }
169
+ });
170
+
171
171
  // src/Axis.ts
172
172
  function axisToVec3(axis) {
173
173
  switch (axis) {
@@ -264,8 +264,6 @@ async function sleep(timeout) {
264
264
  });
265
265
  }
266
266
  function yieldToEventLoop() {
267
- const scheduler = globalThis.scheduler;
268
- if (scheduler?.yield) return scheduler.yield();
269
267
  return new Promise((resolve) => {
270
268
  if (typeof MessageChannel !== "undefined") {
271
269
  const channel = new MessageChannel();
@@ -353,9 +351,12 @@ var init_Caching = __esm({
353
351
  this.entityTextureCache,
354
352
  this.entityAnimationCache,
355
353
  this.blockEntityIndexCache,
354
+ this.entityDatasetVersionCache,
356
355
  this.fontCache,
357
356
  this.unihexCache,
358
357
  this.bannerPatternCache,
358
+ this.equipmentCache,
359
+ this.trimCache,
359
360
  this.mineRenderDataCache,
360
361
  this.usernameUuidCache,
361
362
  this.biomeCache
@@ -387,6 +388,8 @@ var init_Caching = __esm({
387
388
  };
388
389
  }
389
390
  };
391
+ /** Cached in place of a missing asset. The caches drop `undefined` results, which would request the asset again. */
392
+ _Caching.MISSING = false;
390
393
  _Caching._generation = 0;
391
394
  _Caching.rawImageCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(5)).buildAsync();
392
395
  _Caching.imageDataCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
@@ -408,9 +411,12 @@ var init_Caching = __esm({
408
411
  _Caching.entityTextureCache = _Caching.createAssetCache();
409
412
  _Caching.entityAnimationCache = _Caching.createAssetCache();
410
413
  _Caching.blockEntityIndexCache = _Caching.createAssetCache();
414
+ _Caching.entityDatasetVersionCache = _Caching.createAssetCache();
411
415
  _Caching.unihexCache = _Caching.createAssetCache();
412
416
  _Caching.fontCache = _Caching.createAssetCache();
413
417
  _Caching.bannerPatternCache = _Caching.createAssetCache();
418
+ _Caching.equipmentCache = _Caching.createAssetCache();
419
+ _Caching.trimCache = _Caching.createAssetCache();
414
420
  _Caching.mineRenderDataCache = _Caching.createAssetCache();
415
421
  _Caching.usernameUuidCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
416
422
  _Caching.biomeCache = _Caching.createAssetCache();
@@ -511,12 +517,12 @@ async function abortable(promise, signal) {
511
517
  signal.removeEventListener("abort", abort);
512
518
  }
513
519
  }
514
- var import_jobqu, log2, RequestError, RequestQueue, Requests;
520
+ var import_jobqu, log3, RequestError, RequestQueue, Requests;
515
521
  var init_Requests = __esm({
516
522
  "src/request/Requests.ts"() {
517
523
  import_jobqu = require("jobqu");
518
524
  init_log();
519
- log2 = logger("Requests");
525
+ log3 = logger("Requests");
520
526
  RequestError = class extends Error {
521
527
  constructor(message, response, cause) {
522
528
  super(message);
@@ -543,7 +549,7 @@ var init_Requests = __esm({
543
549
  try {
544
550
  return await abortable(this.queue.add(request), signal);
545
551
  } catch (error) {
546
- log2.debug("Request failed", error);
552
+ log3.debug("Request failed", error);
547
553
  const delay = this.retryDelay(error, request, retries);
548
554
  if (delay === void 0) {
549
555
  throw error;
@@ -725,7 +731,7 @@ var init_base64 = __esm({
725
731
  });
726
732
 
727
733
  // src/image/ImageLoader.ts
728
- var log3, ImageLoader;
734
+ var log4, ImageLoader;
729
735
  var init_ImageLoader = __esm({
730
736
  "src/image/ImageLoader.ts"() {
731
737
  init_CanvasCompat();
@@ -736,7 +742,7 @@ var init_ImageLoader = __esm({
736
742
  init_WrappedImage();
737
743
  init_base64();
738
744
  init_log();
739
- log3 = logger("ImageLoader");
745
+ log4 = logger("ImageLoader");
740
746
  ImageLoader = class _ImageLoader {
741
747
  static _createImage() {
742
748
  return createImage();
@@ -761,7 +767,7 @@ var init_ImageLoader = __esm({
761
767
  return image;
762
768
  }
763
769
  static async loadData(src) {
764
- log3.debug("loadData", src);
770
+ log4.debug("loadData", src);
765
771
  const image = await this.loadCanvasData(src);
766
772
  return image.data.getImageData(0, 0, image.width, image.height);
767
773
  }
@@ -868,7 +874,7 @@ var init_ImageLoader = __esm({
868
874
  });
869
875
 
870
876
  // src/texture/TextureLoader.ts
871
- var import_three3, THREE, log4, TextureLoader;
877
+ var import_three3, THREE, log5, TextureLoader;
872
878
  var init_TextureLoader = __esm({
873
879
  "src/texture/TextureLoader.ts"() {
874
880
  import_three3 = require("three");
@@ -876,7 +882,7 @@ var init_TextureLoader = __esm({
876
882
  init_ImageLoader();
877
883
  init_Textures();
878
884
  init_log();
879
- log4 = logger("TextureLoader");
885
+ log5 = logger("TextureLoader");
880
886
  TextureLoader = class {
881
887
  /** Reports whether image loading failed, so cached textures can be retried. */
882
888
  static hasFailed(texture) {
@@ -892,7 +898,7 @@ var init_TextureLoader = __esm({
892
898
  texture.needsUpdate = true;
893
899
  }, (error) => {
894
900
  this.failedTextures.add(texture);
895
- log4.warn("Failed to load texture", src, error);
901
+ log5.warn("Failed to load texture", src, error);
896
902
  });
897
903
  texture.image = image;
898
904
  texture.format = format2;
@@ -908,7 +914,7 @@ var init_TextureLoader = __esm({
908
914
  texture.needsUpdate = true;
909
915
  }).catch((error) => {
910
916
  this.failedTextures.add(texture);
911
- log4.warn("Failed to load texture", src, error);
917
+ log5.warn("Failed to load texture", src, error);
912
918
  });
913
919
  texture.format = format2;
914
920
  texture.rotation = rotation;
@@ -984,7 +990,7 @@ var init_Textures = __esm({
984
990
  });
985
991
 
986
992
  // src/Materials.ts
987
- var import_three5, log5, Materials;
993
+ var import_three5, log6, Materials;
988
994
  var init_Materials = __esm({
989
995
  "src/Materials.ts"() {
990
996
  init_CacheKey();
@@ -993,7 +999,7 @@ var init_Materials = __esm({
993
999
  init_TextureLoader();
994
1000
  init_Caching();
995
1001
  init_log();
996
- log5 = logger("Materials");
1002
+ log6 = logger("Materials");
997
1003
  Materials = class _Materials {
998
1004
  /** Shared checkerboard material, created on first access. */
999
1005
  static get MISSING_TEXTURE() {
@@ -1264,7 +1270,7 @@ var init_Materials = __esm({
1264
1270
  Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });
1265
1271
  return material;
1266
1272
  } catch (e) {
1267
- log5.warn(e);
1273
+ log6.warn(e);
1268
1274
  }
1269
1275
  return this.createBasicCanvasMaterial(canvas, transparent, shade);
1270
1276
  }
@@ -1634,7 +1640,7 @@ var init_merge = __esm({
1634
1640
  });
1635
1641
 
1636
1642
  // src/assets/source/HostedAssetSource.ts
1637
- var BINARY_TIMEOUT, log6, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
1643
+ var BINARY_TIMEOUT, log7, DEFAULT_OPTIONS, _HostedAssetSource, HostedAssetSource;
1638
1644
  var init_HostedAssetSource = __esm({
1639
1645
  "src/assets/source/HostedAssetSource.ts"() {
1640
1646
  init_AssetSource();
@@ -1648,7 +1654,7 @@ var init_HostedAssetSource = __esm({
1648
1654
  init_parser();
1649
1655
  init_merge();
1650
1656
  BINARY_TIMEOUT = 6e4;
1651
- log6 = logger("HostedAssetSource");
1657
+ log7 = logger("HostedAssetSource");
1652
1658
  DEFAULT_OPTIONS = {
1653
1659
  retryDefaults: true
1654
1660
  };
@@ -1660,14 +1666,14 @@ var init_HostedAssetSource = __esm({
1660
1666
  return direct;
1661
1667
  }
1662
1668
  if (key.namespace !== DEFAULT_NAMESPACE) {
1663
- log6.debug("Retrying", key, "with default namespace");
1669
+ log7.debug("Retrying", key, "with default namespace");
1664
1670
  const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
1665
1671
  const namespaced = await this.load(namespaceKey, parser);
1666
1672
  if (typeof namespaced !== "undefined") {
1667
1673
  return namespaced;
1668
1674
  }
1669
1675
  if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1670
- log6.debug("Retrying", key, "with default root+namespace");
1676
+ log7.debug("Retrying", key, "with default root+namespace");
1671
1677
  const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1672
1678
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
1673
1679
  if (typeof namespacedRooted !== "undefined") {
@@ -1675,7 +1681,7 @@ var init_HostedAssetSource = __esm({
1675
1681
  }
1676
1682
  }
1677
1683
  } else if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1678
- log6.debug("Retrying", key, "with default root");
1684
+ log7.debug("Retrying", key, "with default root");
1679
1685
  const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1680
1686
  const rooted = await this.load(rootKey, parser);
1681
1687
  if (typeof rooted !== "undefined") {
@@ -1686,7 +1692,7 @@ var init_HostedAssetSource = __esm({
1686
1692
  }
1687
1693
  async load(key, parser) {
1688
1694
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1689
- log6.debug("Loading", url);
1695
+ log7.debug("Loading", url);
1690
1696
  const request = { url };
1691
1697
  try {
1692
1698
  parser.config(request);
@@ -2139,7 +2145,7 @@ var init_source = __esm({
2139
2145
  });
2140
2146
 
2141
2147
  // src/assets/AssetLoader.ts
2142
- var log7, AssetLoader;
2148
+ var log8, AssetLoader;
2143
2149
  var init_AssetLoader = __esm({
2144
2150
  "src/assets/AssetLoader.ts"() {
2145
2151
  init_AssetDefaults();
@@ -2147,7 +2153,7 @@ var init_AssetLoader = __esm({
2147
2153
  init_log();
2148
2154
  init_source();
2149
2155
  init_Caching();
2150
- log7 = logger("AssetLoader");
2156
+ log8 = logger("AssetLoader");
2151
2157
  AssetLoader = class {
2152
2158
  static get _SOURCES() {
2153
2159
  return this.sources ?? (this.sources = [{ key: "mcassets", source: new HostedAssetSource(this.ROOT, { retryDefaults: false }) }]);
@@ -2202,11 +2208,11 @@ ${key}` : key;
2202
2208
  if (override) {
2203
2209
  const existing = this.removeSource(key);
2204
2210
  if (existing) {
2205
- log7.info("Removed existing AssetSource", key);
2211
+ log8.info("Removed existing AssetSource", key);
2206
2212
  }
2207
2213
  }
2208
2214
  this._SOURCES.unshift({ key, source });
2209
- log7.info("Added AssetSource", key);
2215
+ log8.info("Added AssetSource", key);
2210
2216
  }
2211
2217
  /** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
2212
2218
  static removeSource(key) {
@@ -2321,15 +2327,21 @@ var init_ModelTextures = __esm({
2321
2327
  key.extension += ".mcmeta";
2322
2328
  }
2323
2329
  const keyStr = key.serialize();
2324
- return Caching.textureMetaCache.get(keyStr, (k) => {
2325
- return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
2326
- return AssetLoader.get(key, "meta" /* META */).then((asset2) => {
2327
- if (asset2)
2328
- asset2.key = key;
2329
- return asset2;
2330
- });
2330
+ const meta = await Caching.textureMetaCache.get(keyStr, (k) => {
2331
+ return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), async (k1) => {
2332
+ if (AssetLoader.persistentScope === "") {
2333
+ const path = key.getFullPath();
2334
+ const slash = path.lastIndexOf("/");
2335
+ const listKey = new AssetKey(key.namespace, `${path.slice(0, slash + 1)}_list`, "textures", void 0, "assets", ".json", key.root);
2336
+ const list2 = await Caching.listAssetCache.get(listKey.serialize(), () => AssetLoader.get(listKey, "list" /* LIST */)).catch(() => void 0);
2337
+ if (list2 && !list2.files.includes(`${path.slice(slash + 1)}${key.extension}`)) return Caching.MISSING;
2338
+ }
2339
+ const asset2 = await AssetLoader.get(key, "meta" /* META */);
2340
+ if (asset2) asset2.key = key;
2341
+ return asset2 ?? Caching.MISSING;
2331
2342
  });
2332
2343
  });
2344
+ return meta === Caching.MISSING ? void 0 : meta;
2333
2345
  }
2334
2346
  /** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
2335
2347
  static async clearCache() {
@@ -2386,11 +2398,11 @@ var init_CanvasImage = __esm({
2386
2398
  });
2387
2399
 
2388
2400
  // src/Ticker.ts
2389
- var log8, _Ticker, Ticker;
2401
+ var log9, _Ticker, Ticker;
2390
2402
  var init_Ticker = __esm({
2391
2403
  "src/Ticker.ts"() {
2392
2404
  init_log();
2393
- log8 = logger("Ticker");
2405
+ log9 = logger("Ticker");
2394
2406
  _Ticker = class _Ticker {
2395
2407
  static schedule(fn, ms) {
2396
2408
  const handle = setInterval(fn, ms);
@@ -2408,7 +2420,7 @@ var init_Ticker = __esm({
2408
2420
  try {
2409
2421
  t();
2410
2422
  } catch (e) {
2411
- log8.warn(e);
2423
+ log9.warn(e);
2412
2424
  }
2413
2425
  });
2414
2426
  _Ticker.oneSecondTicks++;
@@ -2653,7 +2665,7 @@ var init_cubeUv = __esm({
2653
2665
  });
2654
2666
 
2655
2667
  // src/UVMapper.ts
2656
- var import_three7, log9, X, Y, Z, FACE_UV_AXES, UVMapper, MinecraftFaceUV;
2668
+ var import_three7, log10, X, Y, Z, FACE_UV_AXES, UVMapper, MinecraftFaceUV;
2657
2669
  var init_UVMapper = __esm({
2658
2670
  "src/UVMapper.ts"() {
2659
2671
  import_three7 = require("three");
@@ -2668,7 +2680,7 @@ var init_UVMapper = __esm({
2668
2680
  init_ModelGenerator();
2669
2681
  init_log();
2670
2682
  init_cubeUv();
2671
- log9 = logger("UVMapper");
2683
+ log10 = logger("UVMapper");
2672
2684
  X = 0;
2673
2685
  Y = 1;
2674
2686
  Z = 2;
@@ -2901,7 +2913,7 @@ var init_UVMapper = __esm({
2901
2913
  model.elements = originalModel.elements.map((element) => ({ ...element }));
2902
2914
  }
2903
2915
  const isItemModel = !("elements" in model);
2904
- log9.debug("Creating Atlas for", model.key);
2916
+ log10.debug("Creating Atlas for", model.key);
2905
2917
  if (model.textures) {
2906
2918
  const promises = [];
2907
2919
  const uniqueTextureNames = [];
@@ -2915,7 +2927,7 @@ var init_UVMapper = __esm({
2915
2927
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2916
2928
  promises.push(ModelTextures.get(assetKey).then((asset2) => {
2917
2929
  if (!asset2) {
2918
- log9.warn("Missing texture", assetKey);
2930
+ log10.warn("Missing texture", assetKey);
2919
2931
  return;
2920
2932
  }
2921
2933
  textureMap[textureKey] = new WrappedImage(asset2);
@@ -2927,7 +2939,7 @@ var init_UVMapper = __esm({
2927
2939
  }
2928
2940
  await Promise.all(promises);
2929
2941
  const textureCount = uniqueTextureNames.length;
2930
- log9.debug("Creating Atlas for", textureCount, "textures");
2942
+ log10.debug("Creating Atlas for", textureCount, "textures");
2931
2943
  this.fillMissingTextureKeys(model.textures, textureMap);
2932
2944
  this.fillMissingTextureKeys(model.textures, metaMap);
2933
2945
  const sizes = {};
@@ -2958,7 +2970,7 @@ var init_UVMapper = __esm({
2958
2970
  this.fillMissingTextureKeys(model.textures, sizes);
2959
2971
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2960
2972
  const size = Math.ceil(s * maxWidth);
2961
- log9.debug("Atlas size:", size);
2973
+ log10.debug("Atlas size:", size);
2962
2974
  const squaredSize = size * size;
2963
2975
  const image = new CanvasImage(size, size);
2964
2976
  const missing = Textures.getMissing().image;
@@ -3037,7 +3049,7 @@ var init_UVMapper = __esm({
3037
3049
  }
3038
3050
  this.fillMissingTextureKeys(model.textures, positions);
3039
3051
  if (isItemModel) {
3040
- log9.debug("Generating item model for", model);
3052
+ log10.debug("Generating item model for", model);
3041
3053
  model.elements = [];
3042
3054
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
3043
3055
  const textureImage = textureMap[layerName];
@@ -3053,7 +3065,7 @@ var init_UVMapper = __esm({
3053
3065
  ), layerName));
3054
3066
  }
3055
3067
  }
3056
- log9.debug("Item model elements", model.elements);
3068
+ log10.debug("Item model elements", model.elements);
3057
3069
  }
3058
3070
  if (!model.elements) {
3059
3071
  }
@@ -3110,7 +3122,7 @@ var init_UVMapper = __esm({
3110
3122
  hasTranslucency
3111
3123
  );
3112
3124
  } else {
3113
- log9.warn("Model does not have any textures", model);
3125
+ log10.warn("Model does not have any textures", model);
3114
3126
  }
3115
3127
  return void 0;
3116
3128
  }
@@ -3234,23 +3246,303 @@ var init_MinecraftCubeTexture = __esm({
3234
3246
  }
3235
3247
  });
3236
3248
 
3249
+ // src/assets/_versions/DatasetVersions.ts
3250
+ var parseRelease, compare2, nearestRelease;
3251
+ var init_DatasetVersions = __esm({
3252
+ "src/assets/_versions/DatasetVersions.ts"() {
3253
+ parseRelease = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
3254
+ compare2 = (left, right) => {
3255
+ for (let i = 0; i < 3; i++) {
3256
+ const difference = (left[i] ?? 0) - (right[i] ?? 0);
3257
+ if (difference) return difference;
3258
+ }
3259
+ return 0;
3260
+ };
3261
+ nearestRelease = (requestedVersion, published) => {
3262
+ const requested = parseRelease(requestedVersion);
3263
+ if (!requested) return void 0;
3264
+ const versions = published.map((name) => ({ name, number: parseRelease(name) })).filter((entry) => !!entry.number).sort((left, right) => compare2(left.number, right.number));
3265
+ const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
3266
+ 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];
3267
+ return selected?.name;
3268
+ };
3269
+ }
3270
+ });
3271
+
3272
+ // src/error/MineRenderError.ts
3273
+ var MineRenderError;
3274
+ var init_MineRenderError = __esm({
3275
+ "src/error/MineRenderError.ts"() {
3276
+ MineRenderError = class _MineRenderError extends Error {
3277
+ constructor(msg) {
3278
+ super(msg);
3279
+ Object.setPrototypeOf(this, _MineRenderError.prototype);
3280
+ }
3281
+ get name() {
3282
+ return "MineRenderError";
3283
+ }
3284
+ };
3285
+ }
3286
+ });
3287
+
3288
+ // src/assets/Entities.ts
3289
+ var Entities;
3290
+ var init_Entities = __esm({
3291
+ "src/assets/Entities.ts"() {
3292
+ init_AssetKey();
3293
+ init_DatasetVersions();
3294
+ init_AssetLoader();
3295
+ init_source();
3296
+ init_Caching();
3297
+ init_AssetDefaults();
3298
+ init_MineRenderError();
3299
+ init_ModelTextures();
3300
+ Entities = class {
3301
+ /**
3302
+ * Resolves `root` (default: the active version). Uses the exact dataset when published or when the
3303
+ * version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
3304
+ * Textures keep the requested root.
3305
+ */
3306
+ static async getDatasetRoot(root) {
3307
+ const requestRoot = (root ?? AssetLoader.ROOT).replace(/\/+$/, "");
3308
+ const requestedVersion = requestRoot.slice(requestRoot.lastIndexOf("/") + 1);
3309
+ const base = requestRoot.slice(0, requestRoot.lastIndexOf("/"));
3310
+ const selected = await Caching.entityDatasetVersionCache.get(root ?? `sources:${AssetLoader.ROOT}`, async () => {
3311
+ const key = new AssetKey("entity-models", "version", void 0, void 0, void 0, ".json", root);
3312
+ key.rootType = void 0;
3313
+ if (!parseRelease(requestedVersion) || await AssetLoader.get(key, "json" /* JSON */) !== void 0) return requestedVersion;
3314
+ const indexKey = new AssetKey("entity-models", "versions", void 0, void 0, void 0, ".json", base);
3315
+ indexKey.rootType = void 0;
3316
+ const index = await AssetLoader.get(indexKey, "json" /* JSON */);
3317
+ if (index === void 0) return requestedVersion;
3318
+ 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")) {
3319
+ throw new MineRenderError(`Invalid entity model version index at ${base}/entity-models/versions.json`);
3320
+ }
3321
+ return nearestRelease(requestedVersion, index.versions.map((entry) => entry.name)) ?? requestedVersion;
3322
+ });
3323
+ return selected === requestedVersion ? root : `${base}/${selected}`;
3324
+ }
3325
+ /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
3326
+ static async getEntityList() {
3327
+ const root = await this.getDatasetRoot();
3328
+ const collect = async (path) => {
3329
+ const prefix2 = path ? `${path}/` : "";
3330
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json", root);
3331
+ const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
3332
+ if (!list2) return [];
3333
+ const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
3334
+ const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
3335
+ return [...files, ...children.flat()];
3336
+ };
3337
+ return collect("");
3338
+ }
3339
+ /** @internal */
3340
+ static async getModelFile(modelKey) {
3341
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3342
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
3343
+ return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3344
+ }
3345
+ /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
3346
+ static async getLayerList(modelKey) {
3347
+ return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
3348
+ }
3349
+ /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
3350
+ static async getPassList(modelKey) {
3351
+ return (await this.getModelFile(modelKey))?.passes ?? [];
3352
+ }
3353
+ /**
3354
+ * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
3355
+ * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
3356
+ *
3357
+ * @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
3358
+ * @param textureKey - Texture override for the first selected layer.
3359
+ * @param options - Layer selection, conditional passes, and per-layer texture overrides.
3360
+ * @returns The selected model, or `undefined` when its dataset file is missing.
3361
+ */
3362
+ static async getEntity(modelKey, textureKey, options) {
3363
+ const model = await this.getModelFile(modelKey);
3364
+ if (!model) return void 0;
3365
+ const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
3366
+ const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
3367
+ if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
3368
+ draws.push(...passes);
3369
+ const names = [];
3370
+ const selected = draws.map((pass) => {
3371
+ const layer = model.layers[pass.layer];
3372
+ if (!layer) {
3373
+ throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
3374
+ }
3375
+ let name = pass.layer;
3376
+ for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
3377
+ names.push(name);
3378
+ return { name, layer, pass };
3379
+ });
3380
+ const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
3381
+ const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
3382
+ const textureLocation = pass.textureLocation ?? layer.textureLocation;
3383
+ let texture;
3384
+ if (override) {
3385
+ const path = isAssetKey(override) ? override.getFullPath() : override.path;
3386
+ texture = isAssetKey(override) && override.assetType === "textures" && path.startsWith("entity/") ? override : new AssetKey(override.namespace, path, "textures", "entity", "assets", ".png", isAssetKey(override) ? override.root : void 0);
3387
+ } else if (textureLocation !== void 0) {
3388
+ texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
3389
+ if (isAssetKey(modelKey)) texture.root = modelKey.root;
3390
+ } else {
3391
+ texture = await this.resolveTexture(modelKey);
3392
+ }
3393
+ const render = pass.render ?? layer.render;
3394
+ return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
3395
+ })));
3396
+ return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
3397
+ }
3398
+ /**
3399
+ * Native and sampled vanilla clips by name, or undefined when the model or selected version has none.
3400
+ */
3401
+ static async getAnimations(modelKey) {
3402
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3403
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
3404
+ const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3405
+ return file?.animations;
3406
+ }
3407
+ /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
3408
+ static async resolveTexture(modelKey) {
3409
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3410
+ const root = isAssetKey(modelKey) ? modelKey.root : void 0;
3411
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
3412
+ const texture = await Caching.entityTextureCache.get(key.serialize(), async () => {
3413
+ const name = path.split("/").pop();
3414
+ for (const candidate of [path, `${path}/${name}`]) {
3415
+ const texture3 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
3416
+ if (await ModelTextures.get(texture3)) return texture3;
3417
+ }
3418
+ const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
3419
+ const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
3420
+ const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
3421
+ const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
3422
+ if (!file) return Caching.MISSING;
3423
+ const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
3424
+ const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
3425
+ const assets = variant?.assets;
3426
+ const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
3427
+ if (typeof textureId !== "string") return Caching.MISSING;
3428
+ const texture2 = AssetKey.parse("textures", textureId);
3429
+ texture2.root = root;
3430
+ return texture2;
3431
+ });
3432
+ return texture === Caching.MISSING ? void 0 : texture;
3433
+ }
3434
+ /** @deprecated Use getEntityList(); block entities share the entity dataset. */
3435
+ static getBlockList() {
3436
+ return this.getEntityList();
3437
+ }
3438
+ /** @deprecated Use getEntity(); block entities share the entity dataset. */
3439
+ static getBlock(modelKey, textureKey, options) {
3440
+ return this.getEntity(modelKey, textureKey, options);
3441
+ }
3442
+ };
3443
+ }
3444
+ });
3445
+
3446
+ // src/armor/Armor.ts
3447
+ var Armor_exports = {};
3448
+ __export(Armor_exports, {
3449
+ Armor: () => Armor
3450
+ });
3451
+ var ARMOR_TRANSFORM, Armor;
3452
+ var init_Armor = __esm({
3453
+ "src/armor/Armor.ts"() {
3454
+ init_AssetKey();
3455
+ init_AssetLoader();
3456
+ init_Entities();
3457
+ init_AssetParsers();
3458
+ init_Caching();
3459
+ init_MineRenderError();
3460
+ ARMOR_TRANSFORM = [
3461
+ { rotate: [0, Math.PI, 0] },
3462
+ { scale: [-1, -1, 1] },
3463
+ { translate: [0, -24, 0] }
3464
+ ];
3465
+ Armor = class {
3466
+ /** Loads 1.21.4+ armor in SkinObject's frame, or returns undefined when no layer draws. */
3467
+ static async getEntity(armor) {
3468
+ const model = await Entities.getModelFile(new BasicAssetKey("minecraft", "player"));
3469
+ const layers = {};
3470
+ const slots = { chest: "chestplate", legs: "leggings", feet: "boots", head: "helmet" };
3471
+ for (const slot of Object.keys(slots)) {
3472
+ const value = armor[slot];
3473
+ if (value === void 0) continue;
3474
+ const piece = typeof value === "string" ? { asset: value } : value;
3475
+ const name = slots[slot], geometry = model?.layers[name];
3476
+ if (!geometry) throw new MineRenderError(`Missing armor geometry ${name}; armor needs Minecraft 1.21.4 or later`);
3477
+ const id = this.identifier(piece.asset);
3478
+ const key = new AssetKey(id.namespace, id.path, "equipment", void 0, "assets", ".json");
3479
+ const equipment = await Caching.equipmentCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3480
+ if (!equipment) throw new MineRenderError(`Missing equipment asset ${piece.asset}; armor takes equipment asset IDs such as minecraft:diamond and needs Minecraft 1.21.4 or later`);
3481
+ const layerType = slot === "legs" ? "humanoid_leggings" : "humanoid";
3482
+ const equipmentLayers = equipment.layers[layerType];
3483
+ if (!equipmentLayers?.length) continue;
3484
+ let count = 0;
3485
+ const add = (texture, settings) => {
3486
+ layers[++count === 1 ? name : `${name}#${count}`] = { key: texture, texture, layer: geometry, ...settings };
3487
+ };
3488
+ let glint = piece.glint;
3489
+ for (const layer of equipmentLayers) {
3490
+ let color2;
3491
+ if (layer.dyeable) {
3492
+ const undyed = layer.dyeable.color_when_undyed;
3493
+ color2 = piece.color || (Array.isArray(undyed) ? Math.floor(undyed[0] * 255) << 16 | Math.floor(undyed[1] * 255) << 8 | Math.floor(undyed[2] * 255) : undyed === void 0 ? void 0 : undyed & 16777215);
3494
+ if (color2 === void 0) continue;
3495
+ }
3496
+ const texture = this.identifier(layer.texture);
3497
+ add(
3498
+ new AssetKey(texture.namespace, `equipment/${layerType}/${texture.path}`, "textures", "entity", "assets", ".png"),
3499
+ { ...color2 !== void 0 && { color: color2 }, ...glint && { glint: true } }
3500
+ );
3501
+ glint = false;
3502
+ }
3503
+ if (piece.trim) {
3504
+ const patternId = this.identifier(piece.trim.pattern), materialId = this.identifier(piece.trim.material);
3505
+ const patternKey = new AssetKey(patternId.namespace, patternId.path, "trim_pattern", void 0, "data", ".json");
3506
+ const materialKey = new AssetKey(materialId.namespace, materialId.path, "trim_material", void 0, "data", ".json");
3507
+ const pattern2 = await Caching.trimCache.get(patternKey.serialize(), () => AssetLoader.get(patternKey, "json" /* JSON */));
3508
+ if (!pattern2) throw new MineRenderError(`Missing trim pattern ${piece.trim.pattern}`);
3509
+ const material = await Caching.trimCache.get(materialKey.serialize(), () => AssetLoader.get(materialKey, "json" /* JSON */));
3510
+ if (!material) throw new MineRenderError(`Missing trim material ${piece.trim.material}`);
3511
+ const patternAsset = this.identifier(pattern2.asset_id);
3512
+ const suffix = material.override_armor_assets?.[id.toNamespacedString()] ?? material.asset_name;
3513
+ add(new AssetKey(patternAsset.namespace, `entity/${layerType}/${patternAsset.path}`, "textures", "trims", "assets", ".png"), {
3514
+ palette: {
3515
+ key: new AssetKey("minecraft", "color_palettes/trim_palette", "textures", "trims", "assets", ".png"),
3516
+ permutation: new AssetKey("minecraft", `color_palettes/${suffix}`, "textures", "trims", "assets", ".png")
3517
+ },
3518
+ render: pattern2.decal ? "cutout_z_offset" : "cutout"
3519
+ });
3520
+ }
3521
+ }
3522
+ const first = Object.values(layers)[0];
3523
+ return first ? { ...first, id: "minecraft:player", layers, transform: ARMOR_TRANSFORM } : void 0;
3524
+ }
3525
+ static identifier(value) {
3526
+ if (!isResourceLocation(value) || value.split(/[:/]/).some((part) => !part || part === "." || part === "..")) {
3527
+ throw new MineRenderError(`Invalid armor identifier ${value}`);
3528
+ }
3529
+ const [namespace, path] = value.includes(":") ? value.split(":") : ["minecraft", value];
3530
+ return new BasicAssetKey(namespace, path);
3531
+ }
3532
+ };
3533
+ }
3534
+ });
3535
+
3237
3536
  // src/assets/MineRenderData.ts
3238
- var object2, release, compare2, MineRenderData;
3537
+ var object2, MineRenderData;
3239
3538
  var init_MineRenderData = __esm({
3240
3539
  "src/assets/MineRenderData.ts"() {
3540
+ init_DatasetVersions();
3241
3541
  init_AssetKey();
3242
3542
  init_AssetLoader();
3243
3543
  init_AssetParsers();
3244
3544
  init_Caching();
3245
3545
  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
3546
  MineRenderData = class {
3255
3547
  /** Loads one registry. Missing files and invalid data reject the request. */
3256
3548
  static async get(dataset, root) {
@@ -3280,9 +3572,9 @@ var init_MineRenderData = __esm({
3280
3572
  const scope = AssetLoader.persistentScope;
3281
3573
  return this.cached(`resolve:${requestRoot === void 0 ? "sources" : "explicit"}:${root}`, scope, defaultRoot, async () => {
3282
3574
  const requestedVersion = root.slice(root.lastIndexOf("/") + 1);
3283
- let manifest = await this.manifest(root, requestRoot !== void 0 && release(requestedVersion) ? requestedVersion : void 0, requestRoot);
3575
+ let manifest = await this.manifest(root, requestRoot !== void 0 && parseRelease(requestedVersion) ? requestedVersion : void 0, requestRoot);
3284
3576
  if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };
3285
- const requested = release(requestedVersion);
3577
+ const requested = parseRelease(requestedVersion);
3286
3578
  if (!requested) {
3287
3579
  throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);
3288
3580
  }
@@ -3294,14 +3586,12 @@ var init_MineRenderData = __esm({
3294
3586
  }
3295
3587
  return value.versions;
3296
3588
  });
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];
3589
+ const selected = nearestRelease(requestedVersion, index.map((entry) => entry.name));
3300
3590
  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 };
3591
+ const resolvedRoot = `${base}/${selected}`;
3592
+ manifest = await this.manifest(resolvedRoot, selected, resolvedRoot);
3593
+ if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected}`);
3594
+ return { requestedVersion, version: selected, root: resolvedRoot, manifest };
3305
3595
  });
3306
3596
  }
3307
3597
  static async manifest(root, expectedVersion, requestRoot) {
@@ -3633,22 +3923,6 @@ var init_ItemDefaults = __esm({
3633
3923
  }
3634
3924
  });
3635
3925
 
3636
- // src/error/MineRenderError.ts
3637
- var MineRenderError;
3638
- var init_MineRenderError = __esm({
3639
- "src/error/MineRenderError.ts"() {
3640
- MineRenderError = class _MineRenderError extends Error {
3641
- constructor(msg) {
3642
- super(msg);
3643
- Object.setPrototypeOf(this, _MineRenderError.prototype);
3644
- }
3645
- get name() {
3646
- return "MineRenderError";
3647
- }
3648
- };
3649
- }
3650
- });
3651
-
3652
3926
  // src/texture/Colormaps.ts
3653
3927
  var Colormaps;
3654
3928
  var init_Colormaps = __esm({
@@ -4422,16 +4696,17 @@ var init_Biomes = __esm({
4422
4696
  });
4423
4697
 
4424
4698
  // src/assets/BlockEntities.ts
4425
- var import_three9, log10, BlockEntities;
4699
+ var import_three9, log11, BlockEntities;
4426
4700
  var init_BlockEntities = __esm({
4427
4701
  "src/assets/BlockEntities.ts"() {
4428
4702
  import_three9 = require("three");
4429
4703
  init_AssetKey();
4704
+ init_Entities();
4430
4705
  init_AssetLoader();
4431
4706
  init_source();
4432
4707
  init_Caching();
4433
4708
  init_log();
4434
- log10 = logger("BlockEntities");
4709
+ log11 = logger("BlockEntities");
4435
4710
  BlockEntities = class {
4436
4711
  /**
4437
4712
  * Loads the block index of a version. Versions and sources without one yield an empty index, and so does
@@ -4443,9 +4718,10 @@ var init_BlockEntities = __esm({
4443
4718
  key.rootType = void 0;
4444
4719
  const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
4445
4720
  try {
4721
+ key.root = await Entities.getDatasetRoot(root);
4446
4722
  return await AssetLoader.get(key, "json" /* JSON */) ?? {};
4447
4723
  } catch (error) {
4448
- log10.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
4724
+ log11.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
4449
4725
  return {};
4450
4726
  }
4451
4727
  });
@@ -4528,136 +4804,6 @@ var init_DecoratedPots = __esm({
4528
4804
  }
4529
4805
  });
4530
4806
 
4531
- // src/assets/Entities.ts
4532
- var Entities;
4533
- var init_Entities = __esm({
4534
- "src/assets/Entities.ts"() {
4535
- init_AssetKey();
4536
- init_AssetLoader();
4537
- init_source();
4538
- init_Caching();
4539
- init_AssetDefaults();
4540
- init_MineRenderError();
4541
- init_ModelTextures();
4542
- Entities = class {
4543
- /** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
4544
- static async getEntityList() {
4545
- const collect = async (path) => {
4546
- const prefix2 = path ? `${path}/` : "";
4547
- const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
4548
- const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
4549
- if (!list2) return [];
4550
- const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
4551
- const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
4552
- return [...files, ...children.flat()];
4553
- };
4554
- return collect("");
4555
- }
4556
- static async getModelFile(modelKey) {
4557
- 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);
4559
- return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4560
- }
4561
- /** Returns selectable geometry-layer names, or an empty list when the model is missing. */
4562
- static async getLayerList(modelKey) {
4563
- return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
4564
- }
4565
- /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
4566
- static async getPassList(modelKey) {
4567
- return (await this.getModelFile(modelKey))?.passes ?? [];
4568
- }
4569
- /**
4570
- * Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
4571
- * By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
4572
- *
4573
- * @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
4574
- * @param textureKey - Texture override for the first selected layer.
4575
- * @param options - Layer selection, conditional passes, and per-layer texture overrides.
4576
- * @returns The selected model, or `undefined` when its dataset file is missing.
4577
- */
4578
- static async getEntity(modelKey, textureKey, options) {
4579
- const model = await this.getModelFile(modelKey);
4580
- if (!model) return void 0;
4581
- const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
4582
- const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
4583
- if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
4584
- draws.push(...passes);
4585
- const names = [];
4586
- const selected = draws.map((pass) => {
4587
- const layer = model.layers[pass.layer];
4588
- if (!layer) {
4589
- throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
4590
- }
4591
- let name = pass.layer;
4592
- for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
4593
- names.push(name);
4594
- return { name, layer, pass };
4595
- });
4596
- const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
4597
- const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
4598
- const textureLocation = pass.textureLocation ?? layer.textureLocation;
4599
- let texture;
4600
- if (override) {
4601
- const path = isAssetKey(override) ? override.getFullPath() : override.path;
4602
- texture = isAssetKey(override) && override.assetType === "textures" && path.startsWith("entity/") ? override : new AssetKey(override.namespace, path, "textures", "entity", "assets", ".png", isAssetKey(override) ? override.root : void 0);
4603
- } else if (textureLocation !== void 0) {
4604
- texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
4605
- if (isAssetKey(modelKey)) texture.root = modelKey.root;
4606
- } else {
4607
- texture = await this.resolveTexture(modelKey);
4608
- }
4609
- const render = pass.render ?? layer.render;
4610
- return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
4611
- })));
4612
- return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
4613
- }
4614
- /**
4615
- * Native and sampled vanilla clips by name, or undefined when the model or selected version has none.
4616
- */
4617
- static async getAnimations(modelKey) {
4618
- 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);
4620
- const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4621
- return file?.animations;
4622
- }
4623
- /** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
4624
- static async resolveTexture(modelKey) {
4625
- const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4626
- const root = isAssetKey(modelKey) ? modelKey.root : void 0;
4627
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
4628
- return Caching.entityTextureCache.get(key.serialize(), async () => {
4629
- const name = path.split("/").pop();
4630
- for (const candidate of [path, `${path}/${name}`]) {
4631
- const texture2 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
4632
- if (await ModelTextures.get(texture2)) return texture2;
4633
- }
4634
- const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
4635
- const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
4636
- const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
4637
- const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
4638
- if (!file) return void 0;
4639
- const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
4640
- const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
4641
- const assets = variant?.assets;
4642
- const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
4643
- if (typeof textureId !== "string") return void 0;
4644
- const texture = AssetKey.parse("textures", textureId);
4645
- texture.root = root;
4646
- return texture;
4647
- });
4648
- }
4649
- /** @deprecated Use getEntityList(); block entities share the entity dataset. */
4650
- static getBlockList() {
4651
- return this.getEntityList();
4652
- }
4653
- /** @deprecated Use getEntity(); block entities share the entity dataset. */
4654
- static getBlock(modelKey, textureKey, options) {
4655
- return this.getEntity(modelKey, textureKey, options);
4656
- }
4657
- };
4658
- }
4659
- });
4660
-
4661
4807
  // src/assets/_fonts/Unihex.ts
4662
4808
  var Unihex_exports = {};
4663
4809
  __export(Unihex_exports, {
@@ -4716,7 +4862,7 @@ async function parseUnihex(key) {
4716
4862
  }
4717
4863
  return { indices, rows, metrics };
4718
4864
  } catch (error) {
4719
- log11.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
4865
+ log12.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
4720
4866
  return void 0;
4721
4867
  }
4722
4868
  }
@@ -4735,7 +4881,7 @@ async function loadUnihex(provider, fontKey, characters) {
4735
4881
  return { ...override, from, to };
4736
4882
  });
4737
4883
  } catch (error) {
4738
- log11.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
4884
+ log12.warn(`Could not load Unihex file ${key.toNamespacedString()}`, error);
4739
4885
  return glyphs;
4740
4886
  }
4741
4887
  const file = await Caching.unihexCache.get(key.serialize(), () => parseUnihex(key));
@@ -4783,7 +4929,7 @@ async function loadUnihex(provider, fontKey, characters) {
4783
4929
  }
4784
4930
  return glyphs;
4785
4931
  }
4786
- var import_zip2, log11, ATLAS_SIZE, GLYPH_HEIGHT, UnihexAtlas, atlases;
4932
+ var import_zip2, log12, ATLAS_SIZE, GLYPH_HEIGHT, UnihexAtlas, atlases;
4787
4933
  var init_Unihex = __esm({
4788
4934
  "src/assets/_fonts/Unihex.ts"() {
4789
4935
  import_zip2 = require("@zip.js/zip.js");
@@ -4794,7 +4940,7 @@ var init_Unihex = __esm({
4794
4940
  init_AssetParsers();
4795
4941
  init_CanvasCompat();
4796
4942
  init_log();
4797
- log11 = logger("Unihex");
4943
+ log12 = logger("Unihex");
4798
4944
  ATLAS_SIZE = 512;
4799
4945
  GLYPH_HEIGHT = 16;
4800
4946
  UnihexAtlas = class {
@@ -5797,6 +5943,266 @@ var init_model = __esm({
5797
5943
  }
5798
5944
  });
5799
5945
 
5946
+ // src/model/ItemGlint.ts
5947
+ var ItemGlint_exports = {};
5948
+ __export(ItemGlint_exports, {
5949
+ ItemGlint: () => ItemGlint
5950
+ });
5951
+ var import_three14, ItemGlint;
5952
+ var init_ItemGlint = __esm({
5953
+ "src/model/ItemGlint.ts"() {
5954
+ import_three14 = require("three");
5955
+ init_AssetKey();
5956
+ init_Models();
5957
+ init_ModelTextures();
5958
+ init_Caching();
5959
+ init_Textures();
5960
+ init_Ticker();
5961
+ init_CubeFace();
5962
+ init_DisplayPosition();
5963
+ ItemGlint = class _ItemGlint {
5964
+ constructor(owner, material) {
5965
+ this.owner = owner;
5966
+ this.material = material;
5967
+ this.updateTime();
5968
+ }
5969
+ /** Enables glint for enchantments or a lodestone compass unless a boolean component overrides them. */
5970
+ static enabled(components = {}, itemId) {
5971
+ const override = Models.componentValue(components, "enchantment_glint_override");
5972
+ if (override !== void 0) {
5973
+ if (typeof override !== "boolean") throw new Error("Item enchantment_glint_override must be a boolean");
5974
+ return override;
5975
+ }
5976
+ if (itemId === "minecraft:compass") {
5977
+ Models.componentValue(components, "lodestone_tracker");
5978
+ if (Object.prototype.hasOwnProperty.call(components, "lodestone_tracker") || Object.prototype.hasOwnProperty.call(components, "minecraft:lodestone_tracker")) return true;
5979
+ }
5980
+ const enchantments = Models.componentValue(components, "enchantments");
5981
+ if (enchantments === void 0) return false;
5982
+ if (!enchantments || typeof enchantments !== "object" || Array.isArray(enchantments)) throw new Error("Item enchantments must be an object");
5983
+ return Object.keys(enchantments).length > 0;
5984
+ }
5985
+ /** @internal */
5986
+ static async create(owner, baseMap, root, entityMeshes, kind = "item") {
5987
+ const key = new AssetKey("minecraft", `enchanted_glint_${kind}`, "textures", "misc", "assets", ".png", root);
5988
+ const assetKey = key.serialize(), textureKey = `item-glint:${assetKey}`;
5989
+ let texture = Caching.textureCache.getIfPresent(textureKey);
5990
+ if (!texture) {
5991
+ const pending = ModelTextures.get(key);
5992
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKey);
5993
+ const [image, metadata] = await Promise.all([pending, ModelTextures.getMeta(key)]);
5994
+ if (!image) throw new Error(`Missing ${kind} glint texture ${key.toNamespacedString()}`);
5995
+ if (cachedAsset && Caching.textureAssetCache.getIfPresent(assetKey) !== cachedAsset) return this.create(owner, baseMap, root, entityMeshes, kind);
5996
+ texture = Caching.textureCache.get(textureKey, () => {
5997
+ const texture2 = Textures.createCanvasTexture(image.data.canvas);
5998
+ texture2.wrapS = texture2.wrapT = metadata?.texture?.clamp ? import_three14.ClampToEdgeWrapping : import_three14.RepeatWrapping;
5999
+ if (metadata?.texture?.blur) texture2.magFilter = texture2.minFilter = import_three14.LinearFilter;
6000
+ return texture2;
6001
+ });
6002
+ }
6003
+ const material = new import_three14.ShaderMaterial({
6004
+ name: "item-glint",
6005
+ transparent: true,
6006
+ depthWrite: false,
6007
+ depthFunc: import_three14.EqualDepth,
6008
+ side: import_three14.DoubleSide,
6009
+ forceSinglePass: true,
6010
+ blending: import_three14.CustomBlending,
6011
+ blendSrc: import_three14.SrcColorFactor,
6012
+ blendDst: import_three14.OneFactor,
6013
+ blendSrcAlpha: import_three14.ZeroFactor,
6014
+ blendDstAlpha: import_three14.OneFactor,
6015
+ toneMapped: false,
6016
+ // TextureTransform.ARMOR_ENTITY_GLINT_TEXTURING uses a smaller UV scale than item glint.
6017
+ defines: entityMeshes ? { ENTITY_GLINT: true, ENTITY_GLINT_SCALE: kind === "armor" ? "0.16" : "0.5" } : {},
6018
+ uniforms: {
6019
+ ...!entityMeshes && { baseMap: { value: baseMap } },
6020
+ glintMap: { value: texture },
6021
+ glintOffset: { value: new import_three14.Vector2() },
6022
+ glintAlpha: { value: 0.75 }
6023
+ },
6024
+ vertexShader: `
6025
+ uniform vec2 glintOffset;
6026
+ #ifndef ENTITY_GLINT
6027
+ attribute vec4 uvBounds;
6028
+ attribute vec2 glintUv;
6029
+ flat out vec4 vUvBounds;
6030
+ centroid out vec2 vUv;
6031
+ #endif
6032
+ varying vec2 vGlintUv;
6033
+ void main() {
6034
+ #ifdef ENTITY_GLINT
6035
+ vec2 p = vec2(uv.x, 1.0 - uv.y) * ENTITY_GLINT_SCALE;
6036
+ #else
6037
+ vUv = uv;
6038
+ vUvBounds = uvBounds;
6039
+ vec2 p = glintUv * 8.0;
6040
+ #endif
6041
+ float angle = radians(10.0);
6042
+ vGlintUv = vec2(cos(angle) * p.x - sin(angle) * p.y, sin(angle) * p.x + cos(angle) * p.y) + glintOffset;
6043
+ vec4 mvPosition = vec4(position, 1.0);
6044
+ mvPosition = modelViewMatrix * mvPosition;
6045
+ gl_Position = projectionMatrix * mvPosition;
6046
+ }
6047
+ `,
6048
+ fragmentShader: `
6049
+ #ifndef ENTITY_GLINT
6050
+ uniform sampler2D baseMap;
6051
+ flat in vec4 vUvBounds;
6052
+ centroid in vec2 vUv;
6053
+ #endif
6054
+ uniform sampler2D glintMap;
6055
+ uniform float glintAlpha;
6056
+ varying vec2 vGlintUv;
6057
+ void main() {
6058
+ #ifndef ENTITY_GLINT
6059
+ vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);
6060
+ if (texture2D(baseMap, mapUv).a < 0.01) discard;
6061
+ #endif
6062
+ vec4 color = texture2D(glintMap, vec2(vGlintUv.x, 1.0 - vGlintUv.y));
6063
+ if (color.a < 0.1) discard;
6064
+ gl_FragColor = color;
6065
+ #include <colorspace_fragment>
6066
+ gl_FragColor.rgb *= glintAlpha;
6067
+ }
6068
+ `
6069
+ });
6070
+ if (!entityMeshes) Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
6071
+ const targets = entityMeshes ? [...entityMeshes] : [];
6072
+ if (!entityMeshes) owner.iterateAllMeshes((mesh) => targets.push({ mesh }));
6073
+ for (const { mesh: base, parent = base } of targets) {
6074
+ const pass = new import_three14.Mesh(base.geometry, material);
6075
+ pass.name = `${base.name}:glint`;
6076
+ pass.userData.minerenderItemGlint = true;
6077
+ pass.raycast = () => {
6078
+ };
6079
+ pass.renderOrder = parent.renderOrder + 0.5;
6080
+ parent.add(pass);
6081
+ }
6082
+ return new _ItemGlint(owner, material);
6083
+ }
6084
+ /**
6085
+ * Maps glint before model centering and display transforms. Ordinary sprites approximate Minecraft's shared atlas density.
6086
+ * @internal
6087
+ */
6088
+ static mapUvs(geometry, faces, atlas, itemId, display) {
6089
+ const uv = geometry.getAttribute("uv");
6090
+ const mapped = new Float32Array(uv.count * 2);
6091
+ if (itemId === "minecraft:compass" || itemId === "minecraft:recovery_compass" || itemId === "minecraft:clock") {
6092
+ const positions = geometry.getAttribute("position"), normals = geometry.getAttribute("normal");
6093
+ const scale = display === "gui" /* GUI */ ? 0.5 : display === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || display === "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */ ? 0.75 : 1;
6094
+ const factor = 1 / (16 * 128 * scale);
6095
+ for (let index = 0; index < positions.count; index++) {
6096
+ const x = positions.getX(index), y = positions.getY(index), z = positions.getZ(index);
6097
+ const nx = normals.getX(index), ny = normals.getY(index), nz = normals.getZ(index);
6098
+ const ax = Math.abs(nx), ay = Math.abs(ny), az = Math.abs(nz);
6099
+ let u, v;
6100
+ if (ay >= az && ay >= ax) {
6101
+ u = x;
6102
+ v = ny < 0 ? -z : z;
6103
+ } else if (az >= ax) {
6104
+ u = nz < 0 ? -x : x;
6105
+ v = -y;
6106
+ } else {
6107
+ u = nx < 0 ? -z : z;
6108
+ v = -y;
6109
+ }
6110
+ mapped[index * 2] = u * factor;
6111
+ mapped[index * 2 + 1] = v * factor;
6112
+ }
6113
+ geometry.setAttribute("glintUv", new import_three14.Float32BufferAttribute(mapped, 2));
6114
+ return;
6115
+ }
6116
+ for (const [faceIndex, face] of CUBE_FACES.entries()) {
6117
+ const texture = faces[face]?.texture?.substring(1);
6118
+ const position = texture && atlas.positions[texture] || [0, 0];
6119
+ const size = texture && atlas.sizes[texture] || [atlas.image.width, atlas.image.height];
6120
+ for (let corner = 0; corner < 4; corner++) {
6121
+ const index = faceIndex * 4 + corner;
6122
+ mapped[index * 2] = (uv.getX(index) * atlas.image.width - position[0]) / size[0] / 32;
6123
+ mapped[index * 2 + 1] = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] / 32;
6124
+ }
6125
+ }
6126
+ geometry.setAttribute("glintUv", new import_three14.Float32BufferAttribute(mapped, 2));
6127
+ }
6128
+ updateTime() {
6129
+ const time = Math.trunc(Date.now() * 4);
6130
+ this.material.uniforms.glintOffset.value.set(-(time % 11e4) / 11e4, time % 3e4 / 3e4);
6131
+ }
6132
+ /** @internal */
6133
+ updateSubscription(active) {
6134
+ if (active && this.ticker === void 0) {
6135
+ this.updateTime();
6136
+ this.ticker = Ticker.add(() => {
6137
+ this.updateTime();
6138
+ this.owner.notifyDirty();
6139
+ });
6140
+ } else if (!active) {
6141
+ Ticker.remove(this.ticker);
6142
+ this.ticker = void 0;
6143
+ }
6144
+ }
6145
+ dispose() {
6146
+ Ticker.remove(this.ticker);
6147
+ this.ticker = void 0;
6148
+ this.material.dispose();
6149
+ }
6150
+ };
6151
+ }
6152
+ });
6153
+
6154
+ // src/texture/PalettedTextures.ts
6155
+ var PalettedTextures_exports = {};
6156
+ __export(PalettedTextures_exports, {
6157
+ PalettedTextures: () => PalettedTextures
6158
+ });
6159
+ var PalettedTextures;
6160
+ var init_PalettedTextures = __esm({
6161
+ "src/texture/PalettedTextures.ts"() {
6162
+ init_ModelTextures();
6163
+ init_Caching();
6164
+ init_CanvasImage();
6165
+ init_MineRenderError();
6166
+ PalettedTextures = class {
6167
+ /** Loads a texture with a palette permutation, sharing the resulting canvas between callers. */
6168
+ static async get(texture, key, permutation2) {
6169
+ return Caching.canvasImageDataCache.get(`palette:${texture.serialize()}:${key.serialize()}:${permutation2.serialize()}`, async () => {
6170
+ const source = await ModelTextures.get(texture);
6171
+ if (!source) return void 0;
6172
+ const [palette, replacement] = await Promise.all([ModelTextures.get(key), ModelTextures.get(permutation2)]);
6173
+ if (!palette) throw new MineRenderError(`Missing palette ${key.toNamespacedString()}`);
6174
+ if (!replacement) throw new MineRenderError(`Missing palette ${permutation2.toNamespacedString()}`);
6175
+ const pixels = source.data.getImageData(0, 0, source.width, source.height);
6176
+ const colors2 = palette.data.getImageData(0, 0, palette.width, palette.height).data;
6177
+ const replacements = replacement.data.getImageData(0, 0, replacement.width, replacement.height).data;
6178
+ const image = new CanvasImage(source.width, source.height);
6179
+ const output = image.context.createImageData(source.width, source.height);
6180
+ output.data.set(this.permute(pixels.data, colors2, replacements));
6181
+ image.putData(output);
6182
+ return { data: image.context, width: image.width, height: image.height };
6183
+ });
6184
+ }
6185
+ /** @internal */
6186
+ static permute(pixels, key, permutation2) {
6187
+ if (key.length !== permutation2.length) throw new MineRenderError("Palette images must have the same pixel count");
6188
+ const mapping = /* @__PURE__ */ new Map();
6189
+ for (let i = 0; i < key.length; i += 4) {
6190
+ if (key[i + 3] !== 0) mapping.set(key[i] << 16 | key[i + 1] << 8 | key[i + 2], i);
6191
+ }
6192
+ const output = new Uint8ClampedArray(pixels);
6193
+ for (let i = 0; i < pixels.length; i += 4) {
6194
+ if (pixels[i + 3] === 0) continue;
6195
+ const mapped = mapping.get(pixels[i] << 16 | pixels[i + 1] << 8 | pixels[i + 2]);
6196
+ if (mapped === void 0) continue;
6197
+ output.set(permutation2.subarray(mapped, mapped + 3), i);
6198
+ output[i + 3] = Math.floor(pixels[i + 3] * permutation2[mapped + 3] / 255);
6199
+ }
6200
+ return output;
6201
+ }
6202
+ };
6203
+ }
6204
+ });
6205
+
5800
6206
  // src/entity/scene/EntityObject.ts
5801
6207
  var EntityObject_exports = {};
5802
6208
  __export(EntityObject_exports, {
@@ -5806,13 +6212,13 @@ __export(EntityObject_exports, {
5806
6212
  function isEntityObject(obj) {
5807
6213
  return obj.isEntityObject;
5808
6214
  }
5809
- var import_three14, _EntityObject, EntityObject;
6215
+ var import_three15, ItemGlintClass, PalettedTexturesClass, _EntityObject, EntityObject;
5810
6216
  var init_EntityObject = __esm({
5811
6217
  "src/entity/scene/EntityObject.ts"() {
5812
6218
  init_SceneObject();
5813
6219
  init_Caching();
5814
6220
  init_merge();
5815
- import_three14 = require("three");
6221
+ import_three15 = require("three");
5816
6222
  init_Ticker();
5817
6223
  init_model();
5818
6224
  init_ModelTextures();
@@ -5837,8 +6243,14 @@ var init_EntityObject = __esm({
5837
6243
  this.animationPlayers = [];
5838
6244
  this.partPoses = /* @__PURE__ */ new Map();
5839
6245
  this.options = (0, import_ts_deepmerge.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
5840
- this.addEventListener("added", () => this.updateScrollSubscription());
5841
- this.addEventListener("removed", () => this.updateScrollSubscription());
6246
+ this.addEventListener("added", () => {
6247
+ this.updateScrollSubscription();
6248
+ this.glint?.updateSubscription(!!this.parent);
6249
+ });
6250
+ this.addEventListener("removed", () => {
6251
+ this.updateScrollSubscription();
6252
+ this.glint?.updateSubscription(!!this.parent);
6253
+ });
5842
6254
  }
5843
6255
  /** An optional shared material replaces texture loading for every selected draw; its owner retains disposal. */
5844
6256
  async init(material) {
@@ -5849,12 +6261,26 @@ var init_EntityObject = __esm({
5849
6261
  mesh.material = material;
5850
6262
  });
5851
6263
  this.notifyDirty();
5852
- } else await this.applyTextures();
6264
+ } else {
6265
+ await this.applyTextures();
6266
+ const layers = Object.entries(this.entityLayers).filter(([, layer]) => layer.glint);
6267
+ const meshes = [];
6268
+ for (const [name] of layers) this.getLayerGroup(name)?.traverse((object4) => {
6269
+ if (isMesh(object4)) meshes.push(object4);
6270
+ });
6271
+ if (meshes.length) {
6272
+ const ItemGlint2 = ItemGlintClass ?? (ItemGlintClass = (await Promise.resolve().then(() => (init_ItemGlint(), ItemGlint_exports))).ItemGlint);
6273
+ this.glint = await ItemGlint2.create(this, void 0, this.getTextureKey(layers[0][1]).root, meshes.map((mesh) => ({ mesh })), "armor");
6274
+ this.glint.updateSubscription(!!this.parent);
6275
+ }
6276
+ }
5853
6277
  }
5854
6278
  dispose() {
5855
6279
  super.dispose();
5856
6280
  }
5857
6281
  disposeAndRemoveAllChildren() {
6282
+ this.glint?.dispose();
6283
+ this.glint = void 0;
5858
6284
  this.clearScrollMaterials();
5859
6285
  for (const geometry of this.geometries) geometry.dispose();
5860
6286
  this.geometries.clear();
@@ -6013,17 +6439,21 @@ var init_EntityObject = __esm({
6013
6439
  );
6014
6440
  }
6015
6441
  async loadTextures(layer = this.entity) {
6442
+ if (layer.palette) {
6443
+ const PalettedTextures2 = PalettedTexturesClass ?? (PalettedTexturesClass = (await Promise.resolve().then(() => (init_PalettedTextures(), PalettedTextures_exports))).PalettedTextures);
6444
+ return PalettedTextures2.get(this.getTextureKey(layer), layer.palette.key, layer.palette.permutation);
6445
+ }
6016
6446
  return ModelTextures.get(this.getTextureKey(layer));
6017
6447
  }
6018
6448
  createMeshes(force = false) {
6019
6449
  if (this.meshesCreated && !force) return;
6020
- const modelRoot = new import_three14.Object3D();
6450
+ const modelRoot = new import_three15.Object3D();
6021
6451
  let transformNode = modelRoot;
6022
6452
  const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
6023
6453
  if (transform) {
6024
6454
  for (const [index, op] of transform.entries()) {
6025
6455
  if (index > 0) {
6026
- const child = new import_three14.Object3D();
6456
+ const child = new import_three15.Object3D();
6027
6457
  transformNode.add(child);
6028
6458
  transformNode = child;
6029
6459
  }
@@ -6085,10 +6515,10 @@ var init_EntityObject = __esm({
6085
6515
  this.clearScrollMaterials();
6086
6516
  const results = await Promise.allSettled(Object.entries(this.entityLayers).map(async ([name, layer]) => {
6087
6517
  const mode = layer.render ?? layer.layer.render ?? "cutout";
6088
- const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
6518
+ const tint = (layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint]) ?? layer.color;
6089
6519
  const scroll = Materials.entityModeScroll(mode);
6090
6520
  const assetKeyStr = this.getTextureKey(layer).serialize();
6091
- const keyStr = `entity:${mode}:${tint === void 0 ? "" : new import_three14.Color(tint).getHexString()}:${assetKeyStr}`;
6521
+ const keyStr = `entity:${mode}:${tint === void 0 ? "" : new import_three15.Color(tint).getHexString()}:${assetKeyStr}` + (layer.palette ? `:${layer.palette.key.serialize()}:${layer.palette.permutation.serialize()}` : "");
6092
6522
  let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
6093
6523
  if (!mat) {
6094
6524
  const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
@@ -6153,7 +6583,7 @@ function getMinMax(attribute, start, count) {
6153
6583
  else if (a === 2) value = attribute.getZ(i);
6154
6584
  else if (a === 3) value = attribute.getW(i);
6155
6585
  if (attribute.normalized === true) {
6156
- value = import_three18.MathUtils.normalize(value, attribute.array);
6586
+ value = import_three19.MathUtils.normalize(value, attribute.array);
6157
6587
  }
6158
6588
  }
6159
6589
  output.min[a] = Math.min(output.min[a], value);
@@ -6201,10 +6631,10 @@ function getToBlobPromise(canvas, mimeType) {
6201
6631
  return new Promise((resolve) => canvas.toBlob(resolve, mimeType));
6202
6632
  }
6203
6633
  }
6204
- var import_three18, KHR_mesh_quantization_ExtraAttrTypes, GLTFExporter, WEBGL_CONSTANTS, KHR_MESH_QUANTIZATION, THREE_TO_WEBGL, PATH_PROPERTIES, DEFAULT_SPECULAR_COLOR, GLB_HEADER_BYTES, GLB_HEADER_MAGIC, GLB_VERSION, GLB_CHUNK_PREFIX_BYTES, GLB_CHUNK_TYPE_JSON, GLB_CHUNK_TYPE_BIN, GLTFWriter, GLTFLightExtension, GLTFMaterialsUnlitExtension, GLTFMaterialsClearcoatExtension, GLTFMaterialsDispersionExtension, GLTFMaterialsIridescenceExtension, GLTFMaterialsTransmissionExtension, GLTFMaterialsVolumeExtension, GLTFMaterialsIorExtension, GLTFMaterialsSpecularExtension, GLTFMaterialsSheenExtension, GLTFMaterialsAnisotropyExtension, GLTFMaterialsEmissiveStrengthExtension, GLTFMaterialsBumpExtension, GLTFMeshGpuInstancing;
6634
+ var import_three19, KHR_mesh_quantization_ExtraAttrTypes, GLTFExporter, WEBGL_CONSTANTS, KHR_MESH_QUANTIZATION, THREE_TO_WEBGL, PATH_PROPERTIES, DEFAULT_SPECULAR_COLOR, GLB_HEADER_BYTES, GLB_HEADER_MAGIC, GLB_VERSION, GLB_CHUNK_PREFIX_BYTES, GLB_CHUNK_TYPE_JSON, GLB_CHUNK_TYPE_BIN, GLTFWriter, GLTFLightExtension, GLTFMaterialsUnlitExtension, GLTFMaterialsClearcoatExtension, GLTFMaterialsDispersionExtension, GLTFMaterialsIridescenceExtension, GLTFMaterialsTransmissionExtension, GLTFMaterialsVolumeExtension, GLTFMaterialsIorExtension, GLTFMaterialsSpecularExtension, GLTFMaterialsSheenExtension, GLTFMaterialsAnisotropyExtension, GLTFMaterialsEmissiveStrengthExtension, GLTFMaterialsBumpExtension, GLTFMeshGpuInstancing;
6205
6635
  var init_GLTFExporter = __esm({
6206
6636
  "../../node_modules/three/examples/jsm/exporters/GLTFExporter.js"() {
6207
- import_three18 = require("three");
6637
+ import_three19 = require("three");
6208
6638
  KHR_mesh_quantization_ExtraAttrTypes = {
6209
6639
  POSITION: [
6210
6640
  "byte",
@@ -6383,22 +6813,22 @@ var init_GLTFExporter = __esm({
6383
6813
  };
6384
6814
  KHR_MESH_QUANTIZATION = "KHR_mesh_quantization";
6385
6815
  THREE_TO_WEBGL = {};
6386
- THREE_TO_WEBGL[import_three18.NearestFilter] = WEBGL_CONSTANTS.NEAREST;
6387
- THREE_TO_WEBGL[import_three18.NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
6388
- THREE_TO_WEBGL[import_three18.NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
6389
- THREE_TO_WEBGL[import_three18.LinearFilter] = WEBGL_CONSTANTS.LINEAR;
6390
- THREE_TO_WEBGL[import_three18.LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
6391
- THREE_TO_WEBGL[import_three18.LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
6392
- THREE_TO_WEBGL[import_three18.ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
6393
- THREE_TO_WEBGL[import_three18.RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
6394
- THREE_TO_WEBGL[import_three18.MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
6816
+ THREE_TO_WEBGL[import_three19.NearestFilter] = WEBGL_CONSTANTS.NEAREST;
6817
+ THREE_TO_WEBGL[import_three19.NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
6818
+ THREE_TO_WEBGL[import_three19.NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
6819
+ THREE_TO_WEBGL[import_three19.LinearFilter] = WEBGL_CONSTANTS.LINEAR;
6820
+ THREE_TO_WEBGL[import_three19.LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
6821
+ THREE_TO_WEBGL[import_three19.LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
6822
+ THREE_TO_WEBGL[import_three19.ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
6823
+ THREE_TO_WEBGL[import_three19.RepeatWrapping] = WEBGL_CONSTANTS.REPEAT;
6824
+ THREE_TO_WEBGL[import_three19.MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
6395
6825
  PATH_PROPERTIES = {
6396
6826
  scale: "scale",
6397
6827
  position: "translation",
6398
6828
  quaternion: "rotation",
6399
6829
  morphTargetInfluences: "weights"
6400
6830
  };
6401
- DEFAULT_SPECULAR_COLOR = new import_three18.Color();
6831
+ DEFAULT_SPECULAR_COLOR = new import_three19.Color();
6402
6832
  GLB_HEADER_BYTES = 12;
6403
6833
  GLB_HEADER_MAGIC = 1179937895;
6404
6834
  GLB_VERSION = 2;
@@ -6422,7 +6852,7 @@ var init_GLTFExporter = __esm({
6422
6852
  this.json = {
6423
6853
  asset: {
6424
6854
  version: "2.0",
6425
- generator: "THREE.GLTFExporter r" + import_three18.REVISION
6855
+ generator: "THREE.GLTFExporter r" + import_three19.REVISION
6426
6856
  }
6427
6857
  };
6428
6858
  this.cache = {
@@ -6574,7 +7004,7 @@ var init_GLTFExporter = __esm({
6574
7004
  isNormalizedNormalAttribute(normal) {
6575
7005
  const cache = this.cache;
6576
7006
  if (cache.attributesNormalized.has(normal)) return false;
6577
- const v = new import_three18.Vector3();
7007
+ const v = new import_three19.Vector3();
6578
7008
  for (let i = 0, il = normal.count; i < il; i++) {
6579
7009
  if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1) > 5e-4) return false;
6580
7010
  }
@@ -6591,7 +7021,7 @@ var init_GLTFExporter = __esm({
6591
7021
  const cache = this.cache;
6592
7022
  if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal);
6593
7023
  const attribute = normal.clone();
6594
- const v = new import_three18.Vector3();
7024
+ const v = new import_three19.Vector3();
6595
7025
  for (let i = 0, il = attribute.count; i < il; i++) {
6596
7026
  v.fromBufferAttribute(attribute, i);
6597
7027
  if (v.x === 0 && v.y === 0 && v.z === 0) {
@@ -6635,7 +7065,7 @@ var init_GLTFExporter = __esm({
6635
7065
  async buildMetalRoughTextureAsync(metalnessMap, roughnessMap) {
6636
7066
  if (metalnessMap === roughnessMap) return metalnessMap;
6637
7067
  function getEncodingConversion(map) {
6638
- if (map.colorSpace === import_three18.SRGBColorSpace) {
7068
+ if (map.colorSpace === import_three19.SRGBColorSpace) {
6639
7069
  return function SRGBToLinear(c) {
6640
7070
  return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
6641
7071
  };
@@ -6644,10 +7074,10 @@ var init_GLTFExporter = __esm({
6644
7074
  return c;
6645
7075
  };
6646
7076
  }
6647
- if (metalnessMap instanceof import_three18.CompressedTexture) {
7077
+ if (metalnessMap instanceof import_three19.CompressedTexture) {
6648
7078
  metalnessMap = await this.decompressTextureAsync(metalnessMap);
6649
7079
  }
6650
- if (roughnessMap instanceof import_three18.CompressedTexture) {
7080
+ if (roughnessMap instanceof import_three19.CompressedTexture) {
6651
7081
  roughnessMap = await this.decompressTextureAsync(roughnessMap);
6652
7082
  }
6653
7083
  const metalness = metalnessMap ? metalnessMap.image : null;
@@ -6682,8 +7112,8 @@ var init_GLTFExporter = __esm({
6682
7112
  context.putImageData(composite, 0, 0);
6683
7113
  const reference = metalnessMap || roughnessMap;
6684
7114
  const texture = reference.clone();
6685
- texture.source = new import_three18.TextureSource(canvas);
6686
- texture.colorSpace = import_three18.NoColorSpace;
7115
+ texture.source = new import_three19.TextureSource(canvas);
7116
+ texture.colorSpace = import_three19.NoColorSpace;
6687
7117
  texture.channel = (metalnessMap || roughnessMap).channel;
6688
7118
  if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) {
6689
7119
  console.warn("THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.");
@@ -6704,7 +7134,7 @@ var init_GLTFExporter = __esm({
6704
7134
  * @return {Promise<THREE.Texture>} The derived normal map texture.
6705
7135
  */
6706
7136
  async buildNormalMapTextureAsync(normalMap, flipX, flipY) {
6707
- if (normalMap instanceof import_three18.CompressedTexture) {
7137
+ if (normalMap instanceof import_three19.CompressedTexture) {
6708
7138
  normalMap = await this.decompressTextureAsync(normalMap);
6709
7139
  }
6710
7140
  const image = normalMap.image;
@@ -6723,7 +7153,7 @@ var init_GLTFExporter = __esm({
6723
7153
  }
6724
7154
  context.putImageData(imageData, 0, 0);
6725
7155
  const texture = normalMap.clone();
6726
- texture.source = new import_three18.TextureSource(canvas);
7156
+ texture.source = new import_three19.TextureSource(canvas);
6727
7157
  return texture;
6728
7158
  }
6729
7159
  async decompressTextureAsync(texture, maxTextureSize = Infinity) {
@@ -6787,7 +7217,7 @@ var init_GLTFExporter = __esm({
6787
7217
  else if (a === 2) value = attribute.getZ(i);
6788
7218
  else if (a === 3) value = attribute.getW(i);
6789
7219
  if (attribute.normalized === true) {
6790
- value = import_three18.MathUtils.normalize(value, attribute.array);
7220
+ value = import_three19.MathUtils.normalize(value, attribute.array);
6791
7221
  }
6792
7222
  }
6793
7223
  if (componentType === WEBGL_CONSTANTS.FLOAT) {
@@ -6942,7 +7372,7 @@ var init_GLTFExporter = __esm({
6942
7372
  ctx.scale(1, -1);
6943
7373
  }
6944
7374
  if (image.data !== void 0) {
6945
- if (format2 !== import_three18.RGBAFormat) {
7375
+ if (format2 !== import_three19.RGBAFormat) {
6946
7376
  console.error("GLTFExporter: Only RGBAFormat is supported.", format2);
6947
7377
  }
6948
7378
  if (image.width > options.maxTextureSize || image.height > options.maxTextureSize) {
@@ -6970,7 +7400,7 @@ var init_GLTFExporter = __esm({
6970
7400
  })
6971
7401
  );
6972
7402
  } else {
6973
- imageDef.uri = import_three18.ImageUtils.getDataURL(canvas, mimeType);
7403
+ imageDef.uri = import_three19.ImageUtils.getDataURL(canvas, mimeType);
6974
7404
  }
6975
7405
  const index = json.images.push(imageDef) - 1;
6976
7406
  cachedImages[key] = index;
@@ -7007,7 +7437,7 @@ var init_GLTFExporter = __esm({
7007
7437
  const json = this.json;
7008
7438
  if (cache.textures.has(map)) return cache.textures.get(map);
7009
7439
  if (!json.textures) json.textures = [];
7010
- if (map instanceof import_three18.CompressedTexture) {
7440
+ if (map instanceof import_three19.CompressedTexture) {
7011
7441
  map = await this.decompressTextureAsync(map, options.maxTextureSize);
7012
7442
  }
7013
7443
  const mimeType = map.userData.mimeType;
@@ -7140,7 +7570,7 @@ var init_GLTFExporter = __esm({
7140
7570
  materialDef.alphaCutoff = material.alphaTest;
7141
7571
  }
7142
7572
  }
7143
- if (material.side === import_three18.DoubleSide) materialDef.doubleSided = true;
7573
+ if (material.side === import_three19.DoubleSide) materialDef.doubleSided = true;
7144
7574
  if (material.name !== "") materialDef.name = material.name;
7145
7575
  this.serializeUserData(material, materialDef);
7146
7576
  await this._invokeAllAsync(async function(ext) {
@@ -7389,7 +7819,7 @@ var init_GLTFExporter = __esm({
7389
7819
  } else {
7390
7820
  cameraDef.perspective = {
7391
7821
  aspectRatio: camera.aspect,
7392
- yfov: import_three18.MathUtils.degToRad(camera.fov),
7822
+ yfov: import_three19.MathUtils.degToRad(camera.fov),
7393
7823
  zfar: camera.far <= 0 ? 1e-3 : camera.far,
7394
7824
  znear: camera.near < 0 ? 0 : camera.near
7395
7825
  };
@@ -7417,8 +7847,8 @@ var init_GLTFExporter = __esm({
7417
7847
  const samplers = [];
7418
7848
  for (let i = 0; i < tracks.length; ++i) {
7419
7849
  const track = tracks[i];
7420
- const trackBinding = import_three18.PropertyBinding.parseTrackName(track.name);
7421
- let trackNode = import_three18.PropertyBinding.findNode(root, trackBinding.nodeName);
7850
+ const trackBinding = import_three19.PropertyBinding.parseTrackName(track.name);
7851
+ let trackNode = import_three19.PropertyBinding.findNode(root, trackBinding.nodeName);
7422
7852
  const trackProperty = PATH_PROPERTIES[trackBinding.propertyName];
7423
7853
  if (trackBinding.objectName === "bones") {
7424
7854
  if (trackNode.isSkinnedMesh === true) {
@@ -7440,14 +7870,14 @@ var init_GLTFExporter = __esm({
7440
7870
  if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) {
7441
7871
  interpolation = "CUBICSPLINE";
7442
7872
  outputItemSize /= 3;
7443
- } else if (track.getInterpolation() === import_three18.InterpolateDiscrete) {
7873
+ } else if (track.getInterpolation() === import_three19.InterpolateDiscrete) {
7444
7874
  interpolation = "STEP";
7445
7875
  } else {
7446
7876
  interpolation = "LINEAR";
7447
7877
  }
7448
7878
  samplers.push({
7449
- input: this.processAccessor(new import_three18.BufferAttribute(track.times, inputItemSize)),
7450
- output: this.processAccessor(new import_three18.BufferAttribute(track.values, outputItemSize)),
7879
+ input: this.processAccessor(new import_three19.BufferAttribute(track.times, inputItemSize)),
7880
+ output: this.processAccessor(new import_three19.BufferAttribute(track.values, outputItemSize)),
7451
7881
  interpolation
7452
7882
  });
7453
7883
  channels.push({
@@ -7481,7 +7911,7 @@ var init_GLTFExporter = __esm({
7481
7911
  if (rootJoint === void 0) return null;
7482
7912
  const joints = [];
7483
7913
  const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
7484
- const temporaryBoneInverse = new import_three18.Matrix4();
7914
+ const temporaryBoneInverse = new import_three19.Matrix4();
7485
7915
  for (let i = 0; i < skeleton.bones.length; ++i) {
7486
7916
  joints.push(nodeMap.get(skeleton.bones[i]));
7487
7917
  temporaryBoneInverse.copy(skeleton.boneInverses[i]);
@@ -7489,7 +7919,7 @@ var init_GLTFExporter = __esm({
7489
7919
  }
7490
7920
  if (json.skins === void 0) json.skins = [];
7491
7921
  json.skins.push({
7492
- inverseBindMatrices: this.processAccessor(new import_three18.BufferAttribute(inverseBindMatrices, 16)),
7922
+ inverseBindMatrices: this.processAccessor(new import_three19.BufferAttribute(inverseBindMatrices, 16)),
7493
7923
  joints,
7494
7924
  skeleton: nodeMap.get(rootJoint)
7495
7925
  });
@@ -7651,7 +8081,7 @@ var init_GLTFExporter = __esm({
7651
8081
  * @param {Array<THREE.Object3D>} objects List of objects to process
7652
8082
  */
7653
8083
  async processObjectsAsync(objects) {
7654
- const scene = new import_three18.Scene();
8084
+ const scene = new import_three19.Scene();
7655
8085
  scene.name = "AuxScene";
7656
8086
  for (let i = 0; i < objects.length; i++) {
7657
8087
  scene.children.push(objects[i]);
@@ -7669,7 +8099,7 @@ var init_GLTFExporter = __esm({
7669
8099
  });
7670
8100
  const objectsWithoutScene = [];
7671
8101
  for (let i = 0; i < input.length; i++) {
7672
- if (input[i] instanceof import_three18.Scene) {
8102
+ if (input[i] instanceof import_three19.Scene) {
7673
8103
  await this.processSceneAsync(input[i]);
7674
8104
  } else {
7675
8105
  objectsWithoutScene.push(input[i]);
@@ -8067,10 +8497,10 @@ var init_GLTFExporter = __esm({
8067
8497
  const translationAttr = new Float32Array(mesh.count * 3);
8068
8498
  const rotationAttr = new Float32Array(mesh.count * 4);
8069
8499
  const scaleAttr = new Float32Array(mesh.count * 3);
8070
- const matrix = new import_three18.Matrix4();
8071
- const position = new import_three18.Vector3();
8072
- const quaternion = new import_three18.Quaternion();
8073
- const scale = new import_three18.Vector3();
8500
+ const matrix = new import_three19.Matrix4();
8501
+ const position = new import_three19.Vector3();
8502
+ const quaternion = new import_three19.Quaternion();
8503
+ const scale = new import_three19.Vector3();
8074
8504
  for (let i = 0; i < mesh.count; i++) {
8075
8505
  mesh.getMatrixAt(i, matrix);
8076
8506
  matrix.decompose(position, quaternion, scale);
@@ -8079,9 +8509,9 @@ var init_GLTFExporter = __esm({
8079
8509
  scale.toArray(scaleAttr, i * 3);
8080
8510
  }
8081
8511
  const attributes = {
8082
- TRANSLATION: writer.processAccessor(new import_three18.BufferAttribute(translationAttr, 3)),
8083
- ROTATION: writer.processAccessor(new import_three18.BufferAttribute(rotationAttr, 4)),
8084
- SCALE: writer.processAccessor(new import_three18.BufferAttribute(scaleAttr, 3))
8512
+ TRANSLATION: writer.processAccessor(new import_three19.BufferAttribute(translationAttr, 3)),
8513
+ ROTATION: writer.processAccessor(new import_three19.BufferAttribute(rotationAttr, 4)),
8514
+ SCALE: writer.processAccessor(new import_three19.BufferAttribute(scaleAttr, 3))
8085
8515
  };
8086
8516
  if (mesh.instanceColor)
8087
8517
  attributes._COLOR_0 = writer.processAccessor(mesh.instanceColor);
@@ -8146,8 +8576,8 @@ var init_GLTFExporter = __esm({
8146
8576
  const sourceTracks = clip.tracks;
8147
8577
  for (let i = 0; i < sourceTracks.length; ++i) {
8148
8578
  let sourceTrack = sourceTracks[i];
8149
- const sourceTrackBinding = import_three18.PropertyBinding.parseTrackName(sourceTrack.name);
8150
- const sourceTrackNode = import_three18.PropertyBinding.findNode(root, sourceTrackBinding.nodeName);
8579
+ const sourceTrackBinding = import_three19.PropertyBinding.parseTrackName(sourceTrack.name);
8580
+ const sourceTrackNode = import_three19.PropertyBinding.findNode(root, sourceTrackBinding.nodeName);
8151
8581
  if (sourceTrackBinding.propertyName !== "morphTargetInfluences" || sourceTrackBinding.propertyIndex === void 0) {
8152
8582
  tracks.push(sourceTrack);
8153
8583
  continue;
@@ -8158,7 +8588,7 @@ var init_GLTFExporter = __esm({
8158
8588
  }
8159
8589
  console.warn("THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.");
8160
8590
  sourceTrack = sourceTrack.clone();
8161
- sourceTrack.setInterpolation(import_three18.InterpolateLinear);
8591
+ sourceTrack.setInterpolation(import_three19.InterpolateLinear);
8162
8592
  }
8163
8593
  const targetCount = sourceTrackNode.morphTargetInfluences.length;
8164
8594
  const targetIndex = sourceTrackNode.morphTargetDictionary[sourceTrackBinding.propertyIndex];
@@ -8192,7 +8622,7 @@ var init_GLTFExporter = __esm({
8192
8622
  return clip;
8193
8623
  },
8194
8624
  toTypedBufferAttribute: function(srcAttribute, TypedArray) {
8195
- const dstAttribute = new import_three18.BufferAttribute(new TypedArray(srcAttribute.count * srcAttribute.itemSize), srcAttribute.itemSize, false);
8625
+ const dstAttribute = new import_three19.BufferAttribute(new TypedArray(srcAttribute.count * srcAttribute.itemSize), srcAttribute.itemSize, false);
8196
8626
  if (!srcAttribute.normalized && !srcAttribute.isInterleavedBufferAttribute) {
8197
8627
  dstAttribute.array.set(srcAttribute.array);
8198
8628
  return dstAttribute;
@@ -8270,7 +8700,7 @@ function createGuiTextGeometry(layout, shadow = true) {
8270
8700
  batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
8271
8701
  batches.push(batch);
8272
8702
  }
8273
- const color2 = new import_three20.Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
8703
+ const color2 = new import_three21.Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
8274
8704
  const offset = isShadow ? glyph?.shadowOffset ?? 1 : 0;
8275
8705
  const top = glyph ? 7 - glyph.ascent : 0;
8276
8706
  const height = glyph ? glyph.height * glyph.scale : 8;
@@ -8312,12 +8742,12 @@ function createGuiTextGeometry(layout, shadow = true) {
8312
8742
  }
8313
8743
  }
8314
8744
  }
8315
- return batches.map(({ image, positions, uvs, colors: colors2, indices }) => ({ image, geometry: new import_three20.BufferGeometry().setAttribute("position", new import_three20.Float32BufferAttribute(positions, 3)).setAttribute("uv", new import_three20.Float32BufferAttribute(uvs, 2)).setAttribute("color", new import_three20.Float32BufferAttribute(colors2, 3)).setIndex(indices) }));
8745
+ return batches.map(({ image, positions, uvs, colors: colors2, indices }) => ({ image, geometry: new import_three21.BufferGeometry().setAttribute("position", new import_three21.Float32BufferAttribute(positions, 3)).setAttribute("uv", new import_three21.Float32BufferAttribute(uvs, 2)).setAttribute("color", new import_three21.Float32BufferAttribute(colors2, 3)).setIndex(indices) }));
8316
8746
  }
8317
- var import_three20;
8747
+ var import_three21;
8318
8748
  var init_GuiText = __esm({
8319
8749
  "src/gui/GuiText.ts"() {
8320
- import_three20 = require("three");
8750
+ import_three21 = require("three");
8321
8751
  init_Fonts();
8322
8752
  }
8323
8753
  });
@@ -8326,7 +8756,7 @@ var init_GuiText = __esm({
8326
8756
  function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
8327
8757
  if (crop || !scaling || scaling.type === "stretch") {
8328
8758
  const [x, y, w, h] = crop ?? [0, 0, imageWidth, imageHeight];
8329
- const geometry = new import_three21.PlaneGeometry(width, height);
8759
+ const geometry = new import_three22.PlaneGeometry(width, height);
8330
8760
  const uv = geometry.getAttribute("uv");
8331
8761
  for (let i = 0; i < uv.count; i++) {
8332
8762
  uv.setXY(
@@ -8397,12 +8827,12 @@ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop,
8397
8827
  }
8398
8828
  }
8399
8829
  }
8400
- return new import_three21.BufferGeometry().setAttribute("position", new import_three21.Float32BufferAttribute(positions, 3)).setAttribute("normal", new import_three21.Float32BufferAttribute(normals, 3)).setAttribute("uv", new import_three21.Float32BufferAttribute(uvs, 2)).setIndex(indices);
8830
+ return new import_three22.BufferGeometry().setAttribute("position", new import_three22.Float32BufferAttribute(positions, 3)).setAttribute("normal", new import_three22.Float32BufferAttribute(normals, 3)).setAttribute("uv", new import_three22.Float32BufferAttribute(uvs, 2)).setIndex(indices);
8401
8831
  }
8402
- var import_three21;
8832
+ var import_three22;
8403
8833
  var init_GuiTextureGeometry = __esm({
8404
8834
  "src/gui/GuiTextureGeometry.ts"() {
8405
- import_three21 = require("three");
8835
+ import_three22 = require("three");
8406
8836
  }
8407
8837
  });
8408
8838
 
@@ -8418,7 +8848,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
8418
8848
  const attributes = {};
8419
8849
  const morphAttributes = {};
8420
8850
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
8421
- const mergedGeometry = new import_three22.BufferGeometry();
8851
+ const mergedGeometry = new import_three23.BufferGeometry();
8422
8852
  let offset = 0;
8423
8853
  for (let i = 0; i < geometries.length; ++i) {
8424
8854
  const geometry = geometries[i];
@@ -8542,7 +8972,7 @@ function mergeBufferAttributes(attributes) {
8542
8972
  array.set(attributes[i].array, offset);
8543
8973
  offset += attributes[i].array.length;
8544
8974
  }
8545
- return new import_three22.BufferAttribute(array, itemSize, normalized);
8975
+ return new import_three23.BufferAttribute(array, itemSize, normalized);
8546
8976
  }
8547
8977
  function interleaveAttributes(attributes) {
8548
8978
  let TypedArray;
@@ -8558,7 +8988,7 @@ function interleaveAttributes(attributes) {
8558
8988
  arrayLength += attribute.array.length;
8559
8989
  stride += attribute.itemSize;
8560
8990
  }
8561
- const interleavedBuffer = new import_three22.InterleavedBuffer(new TypedArray(arrayLength), stride);
8991
+ const interleavedBuffer = new import_three23.InterleavedBuffer(new TypedArray(arrayLength), stride);
8562
8992
  let offset = 0;
8563
8993
  const res = [];
8564
8994
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -8567,7 +8997,7 @@ function interleaveAttributes(attributes) {
8567
8997
  const attribute = attributes[j];
8568
8998
  const itemSize = attribute.itemSize;
8569
8999
  const count = attribute.count;
8570
- const iba = new import_three22.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
9000
+ const iba = new import_three23.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
8571
9001
  res.push(iba);
8572
9002
  offset += itemSize;
8573
9003
  for (let c = 0; c < count; c++) {
@@ -8651,13 +9081,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
8651
9081
  const name = attributeNames[i];
8652
9082
  const oldAttribute = geometry.getAttribute(name);
8653
9083
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
8654
- const attribute = new import_three22.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
9084
+ const attribute = new import_three23.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
8655
9085
  result.setAttribute(name, attribute);
8656
9086
  if (name in morphAttrsArrays) {
8657
9087
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
8658
9088
  const oldMorphAttribute = geometry.morphAttributes[name][j];
8659
9089
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
8660
- const morphAttribute = new import_three22.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
9090
+ const morphAttribute = new import_three23.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
8661
9091
  result.morphAttributes[name][j] = morphAttribute;
8662
9092
  }
8663
9093
  }
@@ -8666,11 +9096,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
8666
9096
  return result;
8667
9097
  }
8668
9098
  function toTrianglesDrawMode(geometry, drawMode) {
8669
- if (drawMode === import_three22.TrianglesDrawMode) {
9099
+ if (drawMode === import_three23.TrianglesDrawMode) {
8670
9100
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
8671
9101
  return geometry;
8672
9102
  }
8673
- if (drawMode === import_three22.TriangleFanDrawMode || drawMode === import_three22.TriangleStripDrawMode) {
9103
+ if (drawMode === import_three23.TriangleFanDrawMode || drawMode === import_three23.TriangleStripDrawMode) {
8674
9104
  let index = geometry.getIndex();
8675
9105
  if (index === null) {
8676
9106
  const indices = [];
@@ -8688,7 +9118,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
8688
9118
  }
8689
9119
  const numberOfTriangles = index.count - 2;
8690
9120
  const newIndices = [];
8691
- if (drawMode === import_three22.TriangleFanDrawMode) {
9121
+ if (drawMode === import_three23.TriangleFanDrawMode) {
8692
9122
  for (let i = 1; i <= numberOfTriangles; i++) {
8693
9123
  newIndices.push(index.getX(0));
8694
9124
  newIndices.push(index.getX(i));
@@ -8724,15 +9154,15 @@ function computeMorphedAttributes(object4) {
8724
9154
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
8725
9155
  return null;
8726
9156
  }
8727
- const _vA = new import_three22.Vector3();
8728
- const _vB = new import_three22.Vector3();
8729
- const _vC = new import_three22.Vector3();
8730
- const _tempA = new import_three22.Vector3();
8731
- const _tempB = new import_three22.Vector3();
8732
- const _tempC = new import_three22.Vector3();
8733
- const _morphA = new import_three22.Vector3();
8734
- const _morphB = new import_three22.Vector3();
8735
- const _morphC = new import_three22.Vector3();
9157
+ const _vA = new import_three23.Vector3();
9158
+ const _vB = new import_three23.Vector3();
9159
+ const _vC = new import_three23.Vector3();
9160
+ const _tempA = new import_three23.Vector3();
9161
+ const _tempB = new import_three23.Vector3();
9162
+ const _tempC = new import_three23.Vector3();
9163
+ const _morphA = new import_three23.Vector3();
9164
+ const _morphB = new import_three23.Vector3();
9165
+ const _morphC = new import_three23.Vector3();
8736
9166
  function _calculateMorphedAttributeData(object5, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
8737
9167
  _vA.fromBufferAttribute(attribute, a2);
8738
9168
  _vB.fromBufferAttribute(attribute, b2);
@@ -8927,8 +9357,8 @@ function computeMorphedAttributes(object4) {
8927
9357
  }
8928
9358
  }
8929
9359
  }
8930
- const morphedPositionAttribute = new import_three22.Float32BufferAttribute(modifiedPosition, 3);
8931
- const morphedNormalAttribute = new import_three22.Float32BufferAttribute(modifiedNormal, 3);
9360
+ const morphedPositionAttribute = new import_three23.Float32BufferAttribute(modifiedPosition, 3);
9361
+ const morphedNormalAttribute = new import_three23.Float32BufferAttribute(modifiedNormal, 3);
8932
9362
  return {
8933
9363
  positionAttribute,
8934
9364
  normalAttribute,
@@ -8936,25 +9366,25 @@ function computeMorphedAttributes(object4) {
8936
9366
  morphedNormalAttribute
8937
9367
  };
8938
9368
  }
8939
- var import_three22;
9369
+ var import_three23;
8940
9370
  var init_BufferGeometryUtils = __esm({
8941
9371
  "src/three/BufferGeometryUtils.js"() {
8942
- import_three22 = require("three");
9372
+ import_three23 = require("three");
8943
9373
  }
8944
9374
  });
8945
9375
 
8946
9376
  // src/model/ModelCulling.ts
8947
- var import_three23, ModelCulling;
9377
+ var import_three24, ModelCulling;
8948
9378
  var init_ModelCulling = __esm({
8949
9379
  "src/model/ModelCulling.ts"() {
8950
- import_three23 = require("three");
9380
+ import_three24 = require("three");
8951
9381
  init_CubeFace();
8952
9382
  ModelCulling = class {
8953
9383
  /** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
8954
9384
  static toLocalMask(worldMask, rotation) {
8955
9385
  let localMask = 0;
8956
9386
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
8957
- const normal = new import_three23.Vector3(...offset).applyEuler(rotation);
9387
+ const normal = new import_three24.Vector3(...offset).applyEuler(rotation);
8958
9388
  const worldFace = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
8959
9389
  if (worldFace < 0) return 0;
8960
9390
  if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
@@ -8988,13 +9418,13 @@ var init_ModelCulling = __esm({
8988
9418
  });
8989
9419
 
8990
9420
  // src/skin/Skins.ts
8991
- var log12, Skins;
9421
+ var log13, Skins;
8992
9422
  var init_Skins = __esm({
8993
9423
  "src/skin/Skins.ts"() {
8994
9424
  init_Requests();
8995
9425
  init_Caching();
8996
9426
  init_log();
8997
- log12 = logger("Skins");
9427
+ log13 = logger("Skins");
8998
9428
  Skins = class {
8999
9429
  //<editor-fold desc="Skins">
9000
9430
  /** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
@@ -9066,7 +9496,7 @@ var init_Skins = __esm({
9066
9496
  }
9067
9497
  return void 0;
9068
9498
  }).catch((err) => {
9069
- log12.warn(err);
9499
+ log13.warn(err);
9070
9500
  return void 0;
9071
9501
  });
9072
9502
  }
@@ -9081,7 +9511,7 @@ var init_Skins = __esm({
9081
9511
  }
9082
9512
  return void 0;
9083
9513
  }).catch((err) => {
9084
- log12.warn(err);
9514
+ log13.warn(err);
9085
9515
  return void 0;
9086
9516
  });
9087
9517
  }
@@ -9095,7 +9525,7 @@ var init_Skins = __esm({
9095
9525
  }
9096
9526
  return void 0;
9097
9527
  }).catch((err) => {
9098
- log12.warn(err);
9528
+ log13.warn(err);
9099
9529
  return void 0;
9100
9530
  });
9101
9531
  }
@@ -9119,7 +9549,7 @@ var init_Skins = __esm({
9119
9549
  }
9120
9550
  return void 0;
9121
9551
  }).catch((err) => {
9122
- log12.warn(err);
9552
+ log13.warn(err);
9123
9553
  return void 0;
9124
9554
  });
9125
9555
  }
@@ -9217,10 +9647,10 @@ var init_SkinImage = __esm({
9217
9647
  });
9218
9648
 
9219
9649
  // src/skin/SkinTextures.ts
9220
- var import_three24, SkinTextures;
9650
+ var import_three25, SkinTextures;
9221
9651
  var init_SkinTextures = __esm({
9222
9652
  "src/skin/SkinTextures.ts"() {
9223
- import_three24 = require("three");
9653
+ import_three25 = require("three");
9224
9654
  init_Caching();
9225
9655
  init_CacheKey();
9226
9656
  init_MineRenderError();
@@ -9258,11 +9688,11 @@ var init_SkinTextures = __esm({
9258
9688
  });
9259
9689
  }
9260
9690
  static createMaterial(pixels, width, height, transparent = true) {
9261
- const texture = Textures.initTextureProps(new import_three24.DataTexture(pixels, width, height));
9262
- texture.colorSpace = import_three24.SRGBColorSpace;
9691
+ const texture = Textures.initTextureProps(new import_three25.DataTexture(pixels, width, height));
9692
+ texture.colorSpace = import_three25.SRGBColorSpace;
9263
9693
  texture.flipY = true;
9264
9694
  texture.needsUpdate = true;
9265
- return new import_three24.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three24.DoubleSide : import_three24.FrontSide, alphaTest: transparent ? 0.1 : 0 });
9695
+ return new import_three25.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three25.DoubleSide : import_three25.FrontSide, alphaTest: transparent ? 0.1 : 0 });
9266
9696
  }
9267
9697
  static isSlim(image, scale) {
9268
9698
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -9315,7 +9745,7 @@ var init_SkinTextures = __esm({
9315
9745
  return pixels;
9316
9746
  }
9317
9747
  static makeBaseOpaque(pixels, width, scale) {
9318
- for (const [x0, y0, x1, y1] of [[0, 0, 32, 16], [0, 16, 64, 32], [16, 48, 48, 64]]) {
9748
+ for (const [x0, y0, x1, y1] of [[0, 0, 32, 16], [0, 16, 64, 32], [16, 48, 48, 64], [32, 0, 38, 7]]) {
9319
9749
  for (let y = y0 * scale; y < y1 * scale; y++) {
9320
9750
  for (let x = x0 * scale; x < x1 * scale; x++) pixels[(y * width + x) * 4 + 3] = 255;
9321
9751
  }
@@ -9326,6 +9756,10 @@ var init_SkinTextures = __esm({
9326
9756
  });
9327
9757
 
9328
9758
  // src/skin/PlayerHeadTextures.ts
9759
+ var PlayerHeadTextures_exports = {};
9760
+ __export(PlayerHeadTextures_exports, {
9761
+ PlayerHeadTextures: () => PlayerHeadTextures
9762
+ });
9329
9763
  var PlayerHeadTextures;
9330
9764
  var init_PlayerHeadTextures = __esm({
9331
9765
  "src/skin/PlayerHeadTextures.ts"() {
@@ -9446,10 +9880,10 @@ var init_PlayerHeadTextures = __esm({
9446
9880
  });
9447
9881
 
9448
9882
  // src/model/SpecialItems.ts
9449
- var import_three25, SpecialItems;
9883
+ var import_three26, SpecialItems;
9450
9884
  var init_SpecialItems = __esm({
9451
9885
  "src/model/SpecialItems.ts"() {
9452
- import_three25 = require("three");
9886
+ import_three26 = require("three");
9453
9887
  init_AssetKey();
9454
9888
  init_Entities();
9455
9889
  init_BannerPatterns();
@@ -9487,8 +9921,8 @@ var init_SpecialItems = __esm({
9487
9921
  const sideTextures = DecoratedPots.getSideTextures(components["minecraft:pot_decorations"], root);
9488
9922
  const baseTexture = texture("decorated_pot_base", "decorated_pot");
9489
9923
  const [base, sides] = await Promise.all([
9490
- load("decorated_pot_base", baseTexture, new import_three25.Matrix4()),
9491
- load("decorated_pot_sides", texture("decorated_pot_side", "decorated_pot"), new import_three25.Matrix4())
9924
+ load("decorated_pot_base", baseTexture, new import_three26.Matrix4()),
9925
+ load("decorated_pot_sides", texture("decorated_pot_side", "decorated_pot"), new import_three26.Matrix4())
9492
9926
  ]);
9493
9927
  const layers = {
9494
9928
  base: { key: base.model.key, texture: baseTexture, layer: base.model.layer, render: "solid" }
@@ -9516,7 +9950,7 @@ var init_SpecialItems = __esm({
9516
9950
  const part = await load(
9517
9951
  "player_head",
9518
9952
  skin.texture,
9519
- new import_three25.Matrix4().makeTranslation(8, 0, 8).multiply(new import_three25.Matrix4().makeScale(-1, -1, 1)),
9953
+ new import_three26.Matrix4().makeTranslation(8, 0, 8).multiply(new import_three26.Matrix4().makeScale(-1, -1, 1)),
9520
9954
  { head: [0, Math.PI, 0] }
9521
9955
  );
9522
9956
  const main = { ...part.model, texture: skin.texture, render: "translucent" };
@@ -9533,7 +9967,7 @@ var init_SpecialItems = __esm({
9533
9967
  const statue = await load(
9534
9968
  special.pose === "standing" ? "copper_golem" : `copper_golem_${special.pose}`,
9535
9969
  key,
9536
- new import_three25.Matrix4().makeTranslation(8, 24, 8).multiply(new import_three25.Matrix4().makeScale(-1, -1, 1))
9970
+ new import_three26.Matrix4().makeTranslation(8, 24, 8).multiply(new import_three26.Matrix4().makeScale(-1, -1, 1))
9537
9971
  );
9538
9972
  const pose = statue.model.layer.root.pose;
9539
9973
  statue.rotations.root = [pose.rotation[0], Math.PI, Math.PI];
@@ -9549,7 +9983,7 @@ var init_SpecialItems = __esm({
9549
9983
  const part = await load(
9550
9984
  trident ? "trident" : "conduit",
9551
9985
  texture(trident ? "trident" : "conduit/base", ""),
9552
- trident ? new import_three25.Matrix4().makeScale(1, -1, -1) : new import_three25.Matrix4().makeTranslation(8, 8, 8),
9986
+ trident ? new import_three26.Matrix4().makeScale(1, -1, -1) : new import_three26.Matrix4().makeTranslation(8, 8, 8),
9553
9987
  {},
9554
9988
  trident ? ["main"] : ["shell"]
9555
9989
  );
@@ -9570,7 +10004,7 @@ var init_SpecialItems = __esm({
9570
10004
  const patterns = await BannerPatterns.getLayers(components["minecraft:banner_patterns"], banner ? "banner" : "shield", root);
9571
10005
  const patterned = banner || color2 !== void 0 || patterns.length > 0;
9572
10006
  const baseTexture = texture(banner ? "banner_base" : patterned ? "shield_base" : "shield_base_nopattern", "");
9573
- const transform = banner ? new import_three25.Matrix4().makeTranslation(8, 0, 8).multiply(new import_three25.Matrix4().makeScale(2 / 3, -2 / 3, -2 / 3)) : new import_three25.Matrix4().makeScale(1, -1, -1);
10007
+ const transform = banner ? new import_three26.Matrix4().makeTranslation(8, 0, 8).multiply(new import_three26.Matrix4().makeScale(2 / 3, -2 / 3, -2 / 3)) : new import_three26.Matrix4().makeScale(1, -1, -1);
9574
10008
  const part = await load(banner ? "standing_banner" : "shield", baseTexture, transform, {}, banner ? ["main", "flag"] : ["main"]);
9575
10009
  const layers = Object.fromEntries(Object.entries(part.model.layers ?? { main: part.model }).map(([name, layer]) => [name, { ...layer, render: "solid" }]));
9576
10010
  let overlay2;
@@ -9608,7 +10042,7 @@ var init_SpecialItems = __esm({
9608
10042
  case "minecraft:chest":
9609
10043
  case "chest": {
9610
10044
  const angle = -(special.openness ?? 0) * Math.PI / 2;
9611
- const chest = await load("chest", texture(special.texture, "chest"), new import_three25.Matrix4(), {
10045
+ const chest = await load("chest", texture(special.texture, "chest"), new import_three26.Matrix4(), {
9612
10046
  lid: [angle, 0, 0],
9613
10047
  lock: [angle, 0, 0]
9614
10048
  });
@@ -9630,18 +10064,18 @@ var init_SpecialItems = __esm({
9630
10064
  if (!Object.prototype.hasOwnProperty.call(directions, orientation)) throw new Error(`Unsupported shulker-box orientation ${orientation}`);
9631
10065
  if (typeof openness !== "number" || !Number.isFinite(openness)) throw new Error("Shulker-box openness must be finite");
9632
10066
  if (typeof special.texture !== "string" || !special.texture) throw new Error("Shulker-box texture is required");
9633
- const transform = new import_three25.Matrix4().makeTranslation(8, 8, 8).multiply(new import_three25.Matrix4().makeScale(0.9995, 0.9995, 0.9995)).multiply(new import_three25.Matrix4().makeRotationFromEuler(new import_three25.Euler(...directions[orientation], "XYZ"))).multiply(new import_three25.Matrix4().makeScale(1, -1, -1)).multiply(new import_three25.Matrix4().makeTranslation(0, -16, 0));
10067
+ const transform = new import_three26.Matrix4().makeTranslation(8, 8, 8).multiply(new import_three26.Matrix4().makeScale(0.9995, 0.9995, 0.9995)).multiply(new import_three26.Matrix4().makeRotationFromEuler(new import_three26.Euler(...directions[orientation], "XYZ"))).multiply(new import_three26.Matrix4().makeScale(1, -1, -1)).multiply(new import_three26.Matrix4().makeTranslation(0, -16, 0));
9634
10068
  const box = await load("shulker_box", texture(special.texture, "shulker"), transform, { lid: [0, openness * Math.PI * 1.5, 0] });
9635
10069
  box.positions = { lid: [0, 24 - openness * 8, 0] };
9636
10070
  return [box];
9637
10071
  }
9638
10072
  case "minecraft:bed":
9639
10073
  case "bed": {
9640
- const transform = new import_three25.Matrix4().makeTranslation(0, 9, 0).multiply(new import_three25.Matrix4().makeRotationX(Math.PI / 2)).multiply(new import_three25.Matrix4().makeTranslation(8, 8, 8)).multiply(new import_three25.Matrix4().makeRotationZ(Math.PI)).multiply(new import_three25.Matrix4().makeTranslation(-8, -8, -8));
10074
+ const transform = new import_three26.Matrix4().makeTranslation(0, 9, 0).multiply(new import_three26.Matrix4().makeRotationX(Math.PI / 2)).multiply(new import_three26.Matrix4().makeTranslation(8, 8, 8)).multiply(new import_three26.Matrix4().makeRotationZ(Math.PI)).multiply(new import_three26.Matrix4().makeTranslation(-8, -8, -8));
9641
10075
  const key = texture(special.texture, "bed");
9642
10076
  return Promise.all([
9643
10077
  load("bed_head", key, transform),
9644
- load("bed_foot", key, new import_three25.Matrix4().makeTranslation(0, 0, -16).multiply(transform))
10078
+ load("bed_foot", key, new import_three26.Matrix4().makeTranslation(0, 0, -16).multiply(transform))
9645
10079
  ]);
9646
10080
  }
9647
10081
  case "minecraft:head":
@@ -9652,266 +10086,63 @@ var init_SpecialItems = __esm({
9652
10086
  zombie: "zombie_head",
9653
10087
  creeper: "creeper_head",
9654
10088
  dragon: "dragon_skull",
9655
- piglin: "piglin_head"
9656
- };
9657
- const id = Object.prototype.hasOwnProperty.call(models, special.kind) ? models[special.kind] : void 0;
9658
- if (!id) throw new Error(`Unsupported special item head kind ${special.kind}`);
9659
- const animation = (special.animation ?? 0) * Math.PI * 0.2;
9660
- const rotations = { head: [0, Math.PI, 0] };
9661
- if (special.kind === "dragon") rotations.jaw = [(Math.sin(animation) + 1) * 0.2, 0, 0];
9662
- if (special.kind === "piglin") {
9663
- rotations.left_ear = [0, 0, -(Math.cos(animation * 1.2) + 2.5) * 0.2];
9664
- rotations.right_ear = [0, 0, (Math.cos(animation) + 2.5) * 0.2];
9665
- }
9666
- return [await load(
9667
- id,
9668
- special.texture ? texture(special.texture, "") : void 0,
9669
- new import_three25.Matrix4().makeTranslation(8, 0, 8).multiply(new import_three25.Matrix4().makeScale(-1, -1, 1)),
9670
- rotations
9671
- )];
9672
- }
9673
- }
9674
- }
9675
- /** An owned material with model-preview shading; its entity texture remains shared. */
9676
- static createMaterial(source, shade) {
9677
- const material = source.clone();
9678
- if (shade) {
9679
- material.onBeforeCompile = (shader) => {
9680
- shader.vertexShader = `varying float itemLight;
9681
- ${shader.vertexShader}`.replace("#include <begin_vertex>", `
9682
- #include <begin_vertex>
9683
- vec3 N = inverseTransformDirection(normalMatrix * normal, viewMatrix);
9684
- itemLight = (1.0 + N.y) * 0.25 - N.x * N.x * 0.15 + N.z * N.z * 0.05 + 0.5;
9685
- `);
9686
- shader.fragmentShader = `varying float itemLight;
9687
- ${shader.fragmentShader}`.replace(
9688
- "#include <color_fragment>",
9689
- "#include <color_fragment>\ndiffuseColor.rgb *= itemLight;"
9690
- );
9691
- };
9692
- material.customProgramCacheKey = () => "special-item-side";
9693
- }
9694
- return material;
9695
- }
9696
- };
9697
- }
9698
- });
9699
-
9700
- // src/model/GuiLight.ts
9701
- var GuiLight;
9702
- var init_GuiLight = __esm({
9703
- "src/model/GuiLight.ts"() {
9704
- GuiLight = /* @__PURE__ */ ((GuiLight2) => {
9705
- GuiLight2["FRONT"] = "front";
9706
- GuiLight2["SIDE"] = "side";
9707
- return GuiLight2;
9708
- })(GuiLight || {});
9709
- }
9710
- });
9711
-
9712
- // src/model/ItemGlint.ts
9713
- var import_three26, ItemGlint;
9714
- var init_ItemGlint = __esm({
9715
- "src/model/ItemGlint.ts"() {
9716
- import_three26 = require("three");
9717
- init_AssetKey();
9718
- init_Models();
9719
- init_ModelTextures();
9720
- init_Caching();
9721
- init_Textures();
9722
- init_Ticker();
9723
- init_CubeFace();
9724
- init_DisplayPosition();
9725
- ItemGlint = class _ItemGlint {
9726
- constructor(owner, material) {
9727
- this.owner = owner;
9728
- this.material = material;
9729
- this.updateTime();
9730
- }
9731
- /** Enables glint for enchantments or a lodestone compass unless a boolean component overrides them. */
9732
- static enabled(components = {}, itemId) {
9733
- const override = Models.componentValue(components, "enchantment_glint_override");
9734
- if (override !== void 0) {
9735
- if (typeof override !== "boolean") throw new Error("Item enchantment_glint_override must be a boolean");
9736
- return override;
9737
- }
9738
- if (itemId === "minecraft:compass") {
9739
- Models.componentValue(components, "lodestone_tracker");
9740
- if (Object.prototype.hasOwnProperty.call(components, "lodestone_tracker") || Object.prototype.hasOwnProperty.call(components, "minecraft:lodestone_tracker")) return true;
9741
- }
9742
- const enchantments = Models.componentValue(components, "enchantments");
9743
- if (enchantments === void 0) return false;
9744
- if (!enchantments || typeof enchantments !== "object" || Array.isArray(enchantments)) throw new Error("Item enchantments must be an object");
9745
- return Object.keys(enchantments).length > 0;
9746
- }
9747
- /** @internal */
9748
- static async create(owner, baseMap, root, entityMeshes) {
9749
- const key = new AssetKey("minecraft", "enchanted_glint_item", "textures", "misc", "assets", ".png", root);
9750
- const assetKey = key.serialize(), textureKey = `item-glint:${assetKey}`;
9751
- let texture = Caching.textureCache.getIfPresent(textureKey);
9752
- if (!texture) {
9753
- const pending = ModelTextures.get(key);
9754
- const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKey);
9755
- const [image, metadata] = await Promise.all([pending, ModelTextures.getMeta(key)]);
9756
- if (!image) throw new Error(`Missing item glint texture ${key.toNamespacedString()}`);
9757
- if (cachedAsset && Caching.textureAssetCache.getIfPresent(assetKey) !== cachedAsset) return this.create(owner, baseMap, root, entityMeshes);
9758
- texture = Caching.textureCache.get(textureKey, () => {
9759
- const texture2 = Textures.createCanvasTexture(image.data.canvas);
9760
- texture2.wrapS = texture2.wrapT = metadata?.texture?.clamp ? import_three26.ClampToEdgeWrapping : import_three26.RepeatWrapping;
9761
- if (metadata?.texture?.blur) texture2.magFilter = texture2.minFilter = import_three26.LinearFilter;
9762
- return texture2;
9763
- });
9764
- }
9765
- const material = new import_three26.ShaderMaterial({
9766
- name: "item-glint",
9767
- transparent: true,
9768
- depthWrite: false,
9769
- depthFunc: import_three26.EqualDepth,
9770
- side: import_three26.DoubleSide,
9771
- forceSinglePass: true,
9772
- blending: import_three26.CustomBlending,
9773
- blendSrc: import_three26.SrcColorFactor,
9774
- blendDst: import_three26.OneFactor,
9775
- blendSrcAlpha: import_three26.ZeroFactor,
9776
- blendDstAlpha: import_three26.OneFactor,
9777
- toneMapped: false,
9778
- defines: entityMeshes ? { ENTITY_GLINT: true } : {},
9779
- uniforms: {
9780
- ...!entityMeshes && { baseMap: { value: baseMap } },
9781
- glintMap: { value: texture },
9782
- glintOffset: { value: new import_three26.Vector2() },
9783
- glintAlpha: { value: 0.75 }
9784
- },
9785
- vertexShader: `
9786
- uniform vec2 glintOffset;
9787
- #ifndef ENTITY_GLINT
9788
- attribute vec4 uvBounds;
9789
- attribute vec2 glintUv;
9790
- flat out vec4 vUvBounds;
9791
- centroid out vec2 vUv;
9792
- #endif
9793
- varying vec2 vGlintUv;
9794
- void main() {
9795
- #ifdef ENTITY_GLINT
9796
- vec2 p = vec2(uv.x, 1.0 - uv.y) * 0.5;
9797
- #else
9798
- vUv = uv;
9799
- vUvBounds = uvBounds;
9800
- vec2 p = glintUv * 8.0;
9801
- #endif
9802
- float angle = radians(10.0);
9803
- vGlintUv = vec2(cos(angle) * p.x - sin(angle) * p.y, sin(angle) * p.x + cos(angle) * p.y) + glintOffset;
9804
- vec4 mvPosition = vec4(position, 1.0);
9805
- mvPosition = modelViewMatrix * mvPosition;
9806
- gl_Position = projectionMatrix * mvPosition;
9807
- }
9808
- `,
9809
- fragmentShader: `
9810
- #ifndef ENTITY_GLINT
9811
- uniform sampler2D baseMap;
9812
- flat in vec4 vUvBounds;
9813
- centroid in vec2 vUv;
9814
- #endif
9815
- uniform sampler2D glintMap;
9816
- uniform float glintAlpha;
9817
- varying vec2 vGlintUv;
9818
- void main() {
9819
- #ifndef ENTITY_GLINT
9820
- vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);
9821
- if (texture2D(baseMap, mapUv).a < 0.01) discard;
9822
- #endif
9823
- vec4 color = texture2D(glintMap, vec2(vGlintUv.x, 1.0 - vGlintUv.y));
9824
- if (color.a < 0.1) discard;
9825
- gl_FragColor = color;
9826
- #include <colorspace_fragment>
9827
- gl_FragColor.rgb *= glintAlpha;
9828
- }
9829
- `
9830
- });
9831
- if (!entityMeshes) Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
9832
- const targets = entityMeshes ? [...entityMeshes] : [];
9833
- if (!entityMeshes) owner.iterateAllMeshes((mesh) => targets.push({ mesh }));
9834
- for (const { mesh: base, parent = base } of targets) {
9835
- const pass = new import_three26.Mesh(base.geometry, material);
9836
- pass.name = `${base.name}:glint`;
9837
- pass.userData.minerenderItemGlint = true;
9838
- pass.raycast = () => {
9839
- };
9840
- pass.renderOrder = parent.renderOrder + 0.5;
9841
- parent.add(pass);
9842
- }
9843
- return new _ItemGlint(owner, material);
9844
- }
9845
- /**
9846
- * Maps glint before model centering and display transforms. Ordinary sprites approximate Minecraft's shared atlas density.
9847
- * @internal
9848
- */
9849
- static mapUvs(geometry, faces, atlas, itemId, display) {
9850
- const uv = geometry.getAttribute("uv");
9851
- const mapped = new Float32Array(uv.count * 2);
9852
- if (itemId === "minecraft:compass" || itemId === "minecraft:recovery_compass" || itemId === "minecraft:clock") {
9853
- const positions = geometry.getAttribute("position"), normals = geometry.getAttribute("normal");
9854
- const scale = display === "gui" /* GUI */ ? 0.5 : display === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || display === "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */ ? 0.75 : 1;
9855
- const factor = 1 / (16 * 128 * scale);
9856
- for (let index = 0; index < positions.count; index++) {
9857
- const x = positions.getX(index), y = positions.getY(index), z = positions.getZ(index);
9858
- const nx = normals.getX(index), ny = normals.getY(index), nz = normals.getZ(index);
9859
- const ax = Math.abs(nx), ay = Math.abs(ny), az = Math.abs(nz);
9860
- let u, v;
9861
- if (ay >= az && ay >= ax) {
9862
- u = x;
9863
- v = ny < 0 ? -z : z;
9864
- } else if (az >= ax) {
9865
- u = nz < 0 ? -x : x;
9866
- v = -y;
9867
- } else {
9868
- u = nx < 0 ? -z : z;
9869
- v = -y;
9870
- }
9871
- mapped[index * 2] = u * factor;
9872
- mapped[index * 2 + 1] = v * factor;
9873
- }
9874
- geometry.setAttribute("glintUv", new import_three26.Float32BufferAttribute(mapped, 2));
9875
- return;
9876
- }
9877
- for (const [faceIndex, face] of CUBE_FACES.entries()) {
9878
- const texture = faces[face]?.texture?.substring(1);
9879
- const position = texture && atlas.positions[texture] || [0, 0];
9880
- const size = texture && atlas.sizes[texture] || [atlas.image.width, atlas.image.height];
9881
- for (let corner = 0; corner < 4; corner++) {
9882
- const index = faceIndex * 4 + corner;
9883
- mapped[index * 2] = (uv.getX(index) * atlas.image.width - position[0]) / size[0] / 32;
9884
- mapped[index * 2 + 1] = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] / 32;
10089
+ piglin: "piglin_head"
10090
+ };
10091
+ const id = Object.prototype.hasOwnProperty.call(models, special.kind) ? models[special.kind] : void 0;
10092
+ if (!id) throw new Error(`Unsupported special item head kind ${special.kind}`);
10093
+ const animation = (special.animation ?? 0) * Math.PI * 0.2;
10094
+ const rotations = { head: [0, Math.PI, 0] };
10095
+ if (special.kind === "dragon") rotations.jaw = [(Math.sin(animation) + 1) * 0.2, 0, 0];
10096
+ if (special.kind === "piglin") {
10097
+ rotations.left_ear = [0, 0, -(Math.cos(animation * 1.2) + 2.5) * 0.2];
10098
+ rotations.right_ear = [0, 0, (Math.cos(animation) + 2.5) * 0.2];
10099
+ }
10100
+ return [await load(
10101
+ id,
10102
+ special.texture ? texture(special.texture, "") : void 0,
10103
+ new import_three26.Matrix4().makeTranslation(8, 0, 8).multiply(new import_three26.Matrix4().makeScale(-1, -1, 1)),
10104
+ rotations
10105
+ )];
9885
10106
  }
9886
10107
  }
9887
- geometry.setAttribute("glintUv", new import_three26.Float32BufferAttribute(mapped, 2));
9888
10108
  }
9889
- updateTime() {
9890
- const time = Math.trunc(Date.now() * 4);
9891
- this.material.uniforms.glintOffset.value.set(-(time % 11e4) / 11e4, time % 3e4 / 3e4);
9892
- }
9893
- /** @internal */
9894
- updateSubscription(active) {
9895
- if (active && this.ticker === void 0) {
9896
- this.updateTime();
9897
- this.ticker = Ticker.add(() => {
9898
- this.updateTime();
9899
- this.owner.notifyDirty();
9900
- });
9901
- } else if (!active) {
9902
- Ticker.remove(this.ticker);
9903
- this.ticker = void 0;
10109
+ /** An owned material with model-preview shading; its entity texture remains shared. */
10110
+ static createMaterial(source, shade) {
10111
+ const material = source.clone();
10112
+ if (shade) {
10113
+ material.onBeforeCompile = (shader) => {
10114
+ shader.vertexShader = `varying float itemLight;
10115
+ ${shader.vertexShader}`.replace("#include <begin_vertex>", `
10116
+ #include <begin_vertex>
10117
+ vec3 N = inverseTransformDirection(normalMatrix * normal, viewMatrix);
10118
+ itemLight = (1.0 + N.y) * 0.25 - N.x * N.x * 0.15 + N.z * N.z * 0.05 + 0.5;
10119
+ `);
10120
+ shader.fragmentShader = `varying float itemLight;
10121
+ ${shader.fragmentShader}`.replace(
10122
+ "#include <color_fragment>",
10123
+ "#include <color_fragment>\ndiffuseColor.rgb *= itemLight;"
10124
+ );
10125
+ };
10126
+ material.customProgramCacheKey = () => "special-item-side";
9904
10127
  }
9905
- }
9906
- dispose() {
9907
- Ticker.remove(this.ticker);
9908
- this.ticker = void 0;
9909
- this.material.dispose();
10128
+ return material;
9910
10129
  }
9911
10130
  };
9912
10131
  }
9913
10132
  });
9914
10133
 
10134
+ // src/model/GuiLight.ts
10135
+ var GuiLight;
10136
+ var init_GuiLight = __esm({
10137
+ "src/model/GuiLight.ts"() {
10138
+ GuiLight = /* @__PURE__ */ ((GuiLight2) => {
10139
+ GuiLight2["FRONT"] = "front";
10140
+ GuiLight2["SIDE"] = "side";
10141
+ return GuiLight2;
10142
+ })(GuiLight || {});
10143
+ }
10144
+ });
10145
+
9915
10146
  // src/model/scene/ModelObject.ts
9916
10147
  var ModelObject_exports = {};
9917
10148
  __export(ModelObject_exports, {
@@ -9921,7 +10152,7 @@ __export(ModelObject_exports, {
9921
10152
  function isModelObject(obj) {
9922
10153
  return obj.isModelObject;
9923
10154
  }
9924
- var import_three27, log13, _ModelObject, ModelObject;
10155
+ var import_three27, log14, _ModelObject, ModelObject;
9925
10156
  var init_ModelObject = __esm({
9926
10157
  "src/model/scene/ModelObject.ts"() {
9927
10158
  init_SceneObject();
@@ -9941,7 +10172,7 @@ var init_ModelObject = __esm({
9941
10172
  init_GuiLight();
9942
10173
  init_ItemTints();
9943
10174
  init_ItemGlint();
9944
- log13 = logger("ModelObject");
10175
+ log14 = logger("ModelObject");
9945
10176
  _ModelObject = class _ModelObject extends SceneObject {
9946
10177
  constructor(originalModel, options) {
9947
10178
  super(options);
@@ -10123,10 +10354,10 @@ var init_ModelObject = __esm({
10123
10354
  }
10124
10355
  });
10125
10356
  } else {
10126
- log13.debug(this.atlas.model, "has no elements");
10357
+ log14.debug(this.atlas.model, "has no elements");
10127
10358
  }
10128
10359
  } else {
10129
- log13.debug("Missing atlas for", this);
10360
+ log14.debug("Missing atlas for", this);
10130
10361
  }
10131
10362
  if (this.options.mergeMeshes) {
10132
10363
  let combinedGeo;
@@ -10939,7 +11170,7 @@ __export(BlockObject_exports, {
10939
11170
  function isBlockObject(obj) {
10940
11171
  return obj.isBlockObject;
10941
11172
  }
10942
- var import_three34, log16, _BlockObject, BlockObject;
11173
+ var import_three34, log17, _BlockObject, BlockObject;
10943
11174
  var init_BlockObject = __esm({
10944
11175
  "src/model/block/scene/BlockObject.ts"() {
10945
11176
  init_SceneObject();
@@ -10959,7 +11190,7 @@ var init_BlockObject = __esm({
10959
11190
  init_Entities();
10960
11191
  init_Biomes();
10961
11192
  init_log();
10962
- log16 = logger("BlockObject");
11193
+ log17 = logger("BlockObject");
10963
11194
  _BlockObject = class _BlockObject extends SceneObject {
10964
11195
  constructor(blockState3, options) {
10965
11196
  super(options);
@@ -11051,20 +11282,28 @@ var init_BlockObject = __esm({
11051
11282
  if (!key || this.options.displayPosition) return false;
11052
11283
  const generation = this._entityGeneration;
11053
11284
  const created = [];
11285
+ const placement = new import_three34.Matrix4();
11054
11286
  let resolved;
11055
11287
  try {
11056
11288
  resolved = BlockEntities.resolve(await BlockEntities.getIndex(key.root), key.toNamespacedString(), this.state);
11057
11289
  if (!resolved) return false;
11290
+ BlockEntities.matrix(resolved, placement);
11058
11291
  for (const part of resolved.parts) {
11059
11292
  const [namespace, path] = part.model.includes(":") ? part.model.split(":") : [key.namespace, part.model];
11060
- const texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
11293
+ let texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
11294
+ if (part.textureLocation === void 0 && namespace === "minecraft" && path === "player_head") {
11295
+ const { PlayerHeadTextures: PlayerHeadTextures2 } = await Promise.resolve().then(() => (init_PlayerHeadTextures(), PlayerHeadTextures_exports));
11296
+ texture = (await PlayerHeadTextures2.get(void 0, key.root)).texture;
11297
+ }
11061
11298
  if (texture) texture.root = key.root;
11062
11299
  const entity = await Entities.getEntity(new BasicAssetKey(namespace, path), texture, { layer: part.layer });
11063
11300
  if (!entity) throw new MineRenderError(`Missing entity model ${part.model}`);
11064
- created.push(await this.scene.addEntity(entity, { wireframe: this.options.wireframe }));
11301
+ const object4 = await this.scene.addEntity(entity, { wireframe: this.options.wireframe });
11302
+ this.placeEntity(object4, placement);
11303
+ created.push(object4);
11065
11304
  }
11066
11305
  } catch (error) {
11067
- log16.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
11306
+ log17.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
11068
11307
  this.removeEntities(created);
11069
11308
  return false;
11070
11309
  }
@@ -11072,18 +11311,21 @@ var init_BlockObject = __esm({
11072
11311
  this.removeEntities(created);
11073
11312
  return true;
11074
11313
  }
11075
- BlockEntities.matrix(resolved, this._entityPlacement);
11314
+ this._entityPlacement.copy(placement);
11076
11315
  this._entities = created;
11077
11316
  this.placeEntities();
11078
11317
  this.setVisible(this.visible);
11079
11318
  return true;
11080
11319
  }
11081
11320
  placeEntities() {
11082
- const matrix = new import_three34.Matrix4().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
11083
11321
  for (const entity of this._entities) {
11084
- matrix.decompose(entity.position, entity.quaternion, entity.scale);
11322
+ this.placeEntity(entity, this._entityPlacement);
11085
11323
  }
11086
11324
  }
11325
+ placeEntity(entity, placement) {
11326
+ const matrix = new import_three34.Matrix4().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(placement);
11327
+ matrix.decompose(entity.position, entity.quaternion, entity.scale);
11328
+ }
11087
11329
  get isOccluding() {
11088
11330
  if (!this.visible) {
11089
11331
  return false;
@@ -11377,6 +11619,7 @@ __export(index_browser_exports, {
11377
11619
  AnvilParser: () => AnvilParser,
11378
11620
  AnvilWorldSource: () => AnvilWorldSource,
11379
11621
  ArchiveAssetSource: () => ArchiveAssetSource,
11622
+ Armor: () => Armor,
11380
11623
  AssetKey: () => AssetKey,
11381
11624
  AssetLoadError: () => AssetLoadError,
11382
11625
  AssetLoader: () => AssetLoader,
@@ -11459,6 +11702,7 @@ __export(index_browser_exports, {
11459
11702
  OrbitControls: () => OrbitControls,
11460
11703
  PackFormats: () => PackFormats,
11461
11704
  PackMetadata: () => PackMetadata,
11705
+ PalettedTextures: () => PalettedTextures,
11462
11706
  PersistentCache: () => PersistentCache,
11463
11707
  PlayerHeadTextures: () => PlayerHeadTextures,
11464
11708
  Renames: () => Renames,
@@ -11593,6 +11837,7 @@ module.exports = __toCommonJS(index_browser_exports);
11593
11837
 
11594
11838
  // src/env/browser/BrowserEnv.ts
11595
11839
  init_Env();
11840
+ init_log();
11596
11841
 
11597
11842
  // src/env/browser/BrowserCache.ts
11598
11843
  init_PersistentCache();
@@ -11693,6 +11938,7 @@ function probeImageSize(data) {
11693
11938
 
11694
11939
  // src/env/browser/BrowserEnv.ts
11695
11940
  var import_meta = {};
11941
+ var log2 = logger("BrowserEnv");
11696
11942
  function lazyLocalForage(options) {
11697
11943
  let instance;
11698
11944
  const store = () => instance ?? (instance = import("localforage").then((module2) => module2.default.createInstance(options)));
@@ -11708,7 +11954,8 @@ function lazyLocalForage(options) {
11708
11954
  };
11709
11955
  }
11710
11956
  var BrowserEnv = class {
11711
- constructor() {
11957
+ constructor(options = {}) {
11958
+ this.options = options;
11712
11959
  this.name = "browser";
11713
11960
  }
11714
11961
  createCanvas(width, height) {
@@ -11737,14 +11984,18 @@ var BrowserEnv = class {
11737
11984
  createWorker(name) {
11738
11985
  if (name !== "section" || typeof Worker === "undefined") return void 0;
11739
11986
  try {
11987
+ const sectionWorker = this.options.sectionWorker;
11988
+ if (typeof sectionWorker === "function") return sectionWorker();
11989
+ if (sectionWorker !== void 0) return new Worker(sectionWorker, { type: "module" });
11740
11990
  return new Worker(new URL("./section.worker.mjs", import_meta.url), { type: "module" });
11741
- } catch {
11991
+ } catch (error) {
11992
+ log2.warn("Could not start the section worker, so sections build on the main thread. Pass sectionWorker to registerBrowserEnv to load it from another URL.", error);
11742
11993
  return void 0;
11743
11994
  }
11744
11995
  }
11745
11996
  };
11746
- function registerBrowserEnv() {
11747
- const env = new BrowserEnv();
11997
+ function registerBrowserEnv(options) {
11998
+ const env = new BrowserEnv(options);
11748
11999
  Env.register(env);
11749
12000
  return env;
11750
12001
  }
@@ -11816,6 +12067,9 @@ function shutdown() {
11816
12067
  Caching.end();
11817
12068
  }
11818
12069
 
12070
+ // src/armor/index.ts
12071
+ init_Armor();
12072
+
11819
12073
  // src/assets/index.ts
11820
12074
  init_AssetDefaults();
11821
12075
  init_AssetKey();
@@ -11907,10 +12161,10 @@ init_EntityObject();
11907
12161
  init_MineRenderError();
11908
12162
 
11909
12163
  // src/export/SceneExporter.ts
11910
- var import_three19 = require("three");
12164
+ var import_three20 = require("three");
11911
12165
 
11912
12166
  // ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
11913
- var import_three16 = require("three");
12167
+ var import_three17 = require("three");
11914
12168
  var OBJExporter = class {
11915
12169
  /**
11916
12170
  * Parses the given 3D object and generates the OBJ output.
@@ -11925,17 +12179,17 @@ var OBJExporter = class {
11925
12179
  let indexVertex = 0;
11926
12180
  let indexVertexUvs = 0;
11927
12181
  let indexNormals = 0;
11928
- const vertex = new import_three16.Vector3();
11929
- const color2 = new import_three16.Color();
11930
- const normal = new import_three16.Vector3();
11931
- const uv = new import_three16.Vector2();
12182
+ const vertex = new import_three17.Vector3();
12183
+ const color2 = new import_three17.Color();
12184
+ const normal = new import_three17.Vector3();
12185
+ const uv = new import_three17.Vector2();
11932
12186
  const face = [];
11933
12187
  function parseMesh(mesh) {
11934
12188
  let nbVertex = 0;
11935
12189
  let nbNormals = 0;
11936
12190
  let nbVertexUvs = 0;
11937
12191
  const geometry = mesh.geometry;
11938
- const normalMatrixWorld = new import_three16.Matrix3();
12192
+ const normalMatrixWorld = new import_three17.Matrix3();
11939
12193
  const vertices = geometry.getAttribute("position");
11940
12194
  const normals = geometry.getAttribute("normal");
11941
12195
  const uvs = geometry.getAttribute("uv");
@@ -12026,7 +12280,7 @@ var OBJExporter = class {
12026
12280
  output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
12027
12281
  if (colors2 !== void 0) {
12028
12282
  color2.fromBufferAttribute(colors2, i);
12029
- import_three16.ColorManagement.workingToColorSpace(color2, import_three16.SRGBColorSpace);
12283
+ import_three17.ColorManagement.workingToColorSpace(color2, import_three17.SRGBColorSpace);
12030
12284
  output += " " + color2.r + " " + color2.g + " " + color2.b;
12031
12285
  }
12032
12286
  output += "\n";
@@ -12055,7 +12309,7 @@ var OBJExporter = class {
12055
12309
  };
12056
12310
 
12057
12311
  // ../../node_modules/three/examples/jsm/exporters/PLYExporter.js
12058
- var import_three17 = require("three");
12312
+ var import_three18 = require("three");
12059
12313
  var PLYExporter = class {
12060
12314
  /**
12061
12315
  * Parses the given 3D object and generates the PLY output.
@@ -12156,7 +12410,7 @@ var PLYExporter = class {
12156
12410
  includeIndices = false;
12157
12411
  }
12158
12412
  });
12159
- const tempColor = new import_three17.Color();
12413
+ const tempColor = new import_three18.Color();
12160
12414
  includeIndices = includeIndices && excludeAttributes.indexOf("index") === -1;
12161
12415
  includeNormals = includeNormals && excludeAttributes.indexOf("normal") === -1;
12162
12416
  includeColors = includeColors && excludeAttributes.indexOf("color") === -1;
@@ -12205,8 +12459,8 @@ property list uchar int vertex_index
12205
12459
  `;
12206
12460
  }
12207
12461
  header += "end_header\n";
12208
- const vertex = new import_three17.Vector3();
12209
- const normalMatrixWorld = new import_three17.Matrix3();
12462
+ const vertex = new import_three18.Vector3();
12463
+ const normalMatrixWorld = new import_three18.Matrix3();
12210
12464
  let result = null;
12211
12465
  if (options.binary === true) {
12212
12466
  const headerBin = new TextEncoder().encode(header);
@@ -12284,7 +12538,7 @@ property list uchar int vertex_index
12284
12538
  if (includeColors === true) {
12285
12539
  if (colors2 != null) {
12286
12540
  tempColor.fromBufferAttribute(colors2, i);
12287
- import_three17.ColorManagement.workingToColorSpace(tempColor, import_three17.SRGBColorSpace);
12541
+ import_three18.ColorManagement.workingToColorSpace(tempColor, import_three18.SRGBColorSpace);
12288
12542
  const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
12289
12543
  const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
12290
12544
  const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
@@ -12386,7 +12640,7 @@ property list uchar int vertex_index
12386
12640
  if (includeColors === true) {
12387
12641
  if (colors2 != null) {
12388
12642
  tempColor.fromBufferAttribute(colors2, i);
12389
- import_three17.ColorManagement.workingToColorSpace(tempColor, import_three17.SRGBColorSpace);
12643
+ import_three18.ColorManagement.workingToColorSpace(tempColor, import_three18.SRGBColorSpace);
12390
12644
  const r = colorIsFloat ? tempColor.r : Math.round(tempColor.r * colorScale);
12391
12645
  const g = colorIsFloat ? tempColor.g : Math.round(tempColor.g * colorScale);
12392
12646
  const b = colorIsFloat ? tempColor.b : Math.round(tempColor.b * colorScale);
@@ -12538,10 +12792,10 @@ var SceneExporter = class {
12538
12792
  }
12539
12793
  };
12540
12794
  function localMatrix(object4) {
12541
- return object4.matrixAutoUpdate ? new import_three19.Matrix4().compose(object4.position, object4.quaternion, object4.scale) : object4.matrix.clone();
12795
+ return object4.matrixAutoUpdate ? new import_three20.Matrix4().compose(object4.position, object4.quaternion, object4.scale) : object4.matrix.clone();
12542
12796
  }
12543
12797
  function createSnapshot(root, gltf, bakeColors = false) {
12544
- const scene = new import_three19.Scene();
12798
+ const scene = new import_three20.Scene();
12545
12799
  const geometries = [];
12546
12800
  const materials = [];
12547
12801
  const textures = [];
@@ -12559,7 +12813,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
12559
12813
  if (!uniforms.map?.value?.isTexture || !uniforms.SHADE || !uniforms.BRIGHTNESS || !uniforms.EMISSIVE) {
12560
12814
  throw new MineRenderError("glTF export does not support this custom ShaderMaterial");
12561
12815
  }
12562
- material = new import_three19.MeshBasicMaterial({
12816
+ material = new import_three20.MeshBasicMaterial({
12563
12817
  map: uniforms.map.value,
12564
12818
  vertexColors: source.vertexColors,
12565
12819
  transparent: source.transparent,
@@ -12569,7 +12823,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
12569
12823
  });
12570
12824
  material.name = source.name;
12571
12825
  } else if (shader.isShaderMaterial) {
12572
- material = new import_three19.MeshBasicMaterial({ vertexColors: source.vertexColors });
12826
+ material = new import_three20.MeshBasicMaterial({ vertexColors: source.vertexColors });
12573
12827
  material.name = source.name;
12574
12828
  } else {
12575
12829
  const copySource = Object.create(source);
@@ -12623,11 +12877,11 @@ function createSnapshot(root, gltf, bakeColors = false) {
12623
12877
  const material = copyMaterial(sourceMaterial, geometry);
12624
12878
  if (!sourceMaterial.vertexColors) geometry.deleteAttribute("color");
12625
12879
  if (bakeColors || instanceColor) {
12626
- const tint = (material.color ?? new import_three19.Color()).clone();
12880
+ const tint = (material.color ?? new import_three20.Color()).clone();
12627
12881
  if (instanceColor) tint.multiply(instanceColor);
12628
12882
  if (bakeColors) {
12629
12883
  const original = geometry.getAttribute("color");
12630
- const colors2 = new import_three19.Float32BufferAttribute(new Float32Array(geometry.getAttribute("position").count * 3), 3);
12884
+ const colors2 = new import_three20.Float32BufferAttribute(new Float32Array(geometry.getAttribute("position").count * 3), 3);
12631
12885
  for (let i = 0; i < colors2.count; i++) {
12632
12886
  colors2.setXYZ(i, (original?.getX(i) ?? 1) * tint.r, (original?.getY(i) ?? 1) * tint.g, (original?.getZ(i) ?? 1) * tint.b);
12633
12887
  }
@@ -12636,7 +12890,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
12636
12890
  material.color.copy(tint);
12637
12891
  }
12638
12892
  }
12639
- const copy = new import_three19.Mesh(geometry, material);
12893
+ const copy = new import_three20.Mesh(geometry, material);
12640
12894
  copy.name = mesh.name;
12641
12895
  copy.renderOrder = mesh.renderOrder;
12642
12896
  scene.add(copy);
@@ -12650,9 +12904,9 @@ function createSnapshot(root, gltf, bakeColors = false) {
12650
12904
  const instanced = mesh;
12651
12905
  if (instanced.isInstancedMesh) {
12652
12906
  for (let i = 0; i < instanced.count; i++) {
12653
- const matrix = new import_three19.Matrix4();
12907
+ const matrix = new import_three20.Matrix4();
12654
12908
  instanced.getMatrixAt(i, matrix);
12655
- const color2 = instanced.instanceColor ? new import_three19.Color().fromBufferAttribute(instanced.instanceColor, i) : void 0;
12909
+ const color2 = instanced.instanceColor ? new import_three20.Color().fromBufferAttribute(instanced.instanceColor, i) : void 0;
12656
12910
  addMesh(mesh, world.clone().multiply(matrix), color2);
12657
12911
  }
12658
12912
  } else {
@@ -12664,7 +12918,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
12664
12918
  try {
12665
12919
  const ancestors = [];
12666
12920
  for (let parent = root.parent; parent; parent = parent.parent) ancestors.unshift(parent);
12667
- const world = new import_three19.Matrix4();
12921
+ const world = new import_three20.Matrix4();
12668
12922
  for (const ancestor of ancestors) {
12669
12923
  if (!ancestor.visible) return { scene, dispose };
12670
12924
  world.multiply(localMatrix(ancestor));
@@ -12678,7 +12932,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
12678
12932
  }
12679
12933
  function selectAlphaMode(material, geometry) {
12680
12934
  const texture = material.map;
12681
- if (material.type !== "MeshBasicMaterial" || !material.transparent || !material.depthWrite || material.opacity !== 1 || material.alphaMap || !texture?.isDataTexture || texture.format !== import_three19.RGBAFormat || texture.type !== import_three19.UnsignedByteType || texture.wrapS !== import_three19.ClampToEdgeWrapping || texture.wrapT !== import_three19.ClampToEdgeWrapping || texture.magFilter !== import_three19.NearestFilter || texture.minFilter !== import_three19.NearestFilter || texture.anisotropy > 1 || texture.offset.x !== 0 || texture.offset.y !== 0 || texture.repeat.x !== 1 || texture.repeat.y !== 1 || texture.rotation !== 0 || !texture.matrixAutoUpdate && !texture.matrix.elements.every((value, i) => value === (i % 4 === 0 ? 1 : 0))) return;
12935
+ if (material.type !== "MeshBasicMaterial" || !material.transparent || !material.depthWrite || material.opacity !== 1 || material.alphaMap || !texture?.isDataTexture || texture.format !== import_three20.RGBAFormat || texture.type !== import_three20.UnsignedByteType || texture.wrapS !== import_three20.ClampToEdgeWrapping || texture.wrapT !== import_three20.ClampToEdgeWrapping || texture.magFilter !== import_three20.NearestFilter || texture.minFilter !== import_three20.NearestFilter || texture.anisotropy > 1 || texture.offset.x !== 0 || texture.offset.y !== 0 || texture.repeat.x !== 1 || texture.repeat.y !== 1 || texture.rotation !== 0 || !texture.matrixAutoUpdate && !texture.matrix.elements.every((value, i) => value === (i % 4 === 0 ? 1 : 0))) return;
12682
12936
  const uv = geometry.getAttribute(texture.channel === 0 ? "uv" : `uv${texture.channel}`);
12683
12937
  const colors2 = geometry.getAttribute("color");
12684
12938
  if (!uv || material.vertexColors && colors2?.itemSize === 4) return;
@@ -12715,7 +12969,7 @@ function selectAlphaMode(material, geometry) {
12715
12969
  }
12716
12970
  function copyDataTexture(source) {
12717
12971
  const image = source.image;
12718
- if (!image.data || source.format !== import_three19.RGBAFormat || source.type !== import_three19.UnsignedByteType) {
12972
+ if (!image.data || source.format !== import_three20.RGBAFormat || source.type !== import_three20.UnsignedByteType) {
12719
12973
  throw new MineRenderError("glTF export requires RGBA unsigned-byte data textures");
12720
12974
  }
12721
12975
  const canvas = createCanvas(image.width, image.height);
@@ -12726,8 +12980,8 @@ function copyDataTexture(source) {
12726
12980
  context.putImageData(pixels, 0, 0);
12727
12981
  const copySource = Object.create(source);
12728
12982
  copySource.userData = {};
12729
- copySource.source = new import_three19.TextureSource(canvas);
12730
- return new import_three19.Texture().copy(copySource);
12983
+ copySource.source = new import_three20.TextureSource(canvas);
12984
+ return new import_three20.Texture().copy(copySource);
12731
12985
  }
12732
12986
 
12733
12987
  // src/export/VideoExporter.ts
@@ -13090,7 +13344,7 @@ init_SceneObject();
13090
13344
  init_util();
13091
13345
  init_log();
13092
13346
  init_three();
13093
- var log14 = logger("SceneInspector");
13347
+ var log15 = logger("SceneInspector");
13094
13348
  var help = "<span>Ctrl/Cmd+Click to Select<br/></span><br/>";
13095
13349
  var SceneInspector = class {
13096
13350
  constructor(renderer) {
@@ -13184,7 +13438,7 @@ var SceneInspector = class {
13184
13438
  }
13185
13439
  selectObject(targetObject, targetIntersection, instance = this.getIntersectionInstance(targetIntersection)) {
13186
13440
  this.selectedObject = targetObject;
13187
- log14.debug("selected", targetObject);
13441
+ log15.debug("selected", targetObject);
13188
13442
  this.redraw(targetObject, targetIntersection, instance);
13189
13443
  }
13190
13444
  redraw(targetObject, targetIntersection, instance) {
@@ -13444,7 +13698,7 @@ var SceneStatsDisplay = class {
13444
13698
 
13445
13699
  // src/instance/InstanceManager.ts
13446
13700
  init_log();
13447
- var log15 = logger("InstanceManager");
13701
+ var log16 = logger("InstanceManager");
13448
13702
  var InstanceManager = class {
13449
13703
  constructor() {
13450
13704
  this.isInstanceManager = true;
@@ -13453,7 +13707,7 @@ var InstanceManager = class {
13453
13707
  /** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
13454
13708
  async get(key) {
13455
13709
  if (key in this.instanceCache) {
13456
- log15.debug("key in cache", key);
13710
+ log16.debug("key in cache", key);
13457
13711
  return (await this.instanceCache[key]).nextInstance();
13458
13712
  }
13459
13713
  return void 0;
@@ -13463,7 +13717,7 @@ var InstanceManager = class {
13463
13717
  if (key in this.instanceCache) {
13464
13718
  return await this.get(key);
13465
13719
  }
13466
- log15.debug("key not in cache", key);
13720
+ log16.debug("key not in cache", key);
13467
13721
  const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
13468
13722
  this.instanceCache[key] = pending;
13469
13723
  try {
@@ -14337,12 +14591,13 @@ function isFlyControls(obj) {
14337
14591
  }
14338
14592
 
14339
14593
  // src/renderer/MineRenderScene.ts
14340
- var import_three36 = require("three");
14594
+ var import_three37 = require("three");
14341
14595
  init_SceneObject();
14342
14596
  init_merge();
14343
14597
 
14344
14598
  // src/skin/scene/SkinObject.ts
14345
14599
  init_SceneObject();
14600
+ var import_three36 = require("three");
14346
14601
 
14347
14602
  // src/skin/SkinPart.ts
14348
14603
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -14359,11 +14614,21 @@ var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
14359
14614
  SkinPart2["RIGHT_TROUSERS"] = "rightTrousers";
14360
14615
  SkinPart2["LEFT_TROUSERS"] = "leftTrousers";
14361
14616
  SkinPart2["CAPE"] = "cape";
14617
+ SkinPart2["LEFT_EAR"] = "leftEar";
14618
+ SkinPart2["RIGHT_EAR"] = "rightEar";
14362
14619
  return SkinPart2;
14363
14620
  })(SkinPart || {});
14364
14621
  var SKIN_PARTS = Object.values(SkinPart);
14365
14622
 
14366
14623
  // src/skin/SkinTextureCoordinates.ts
14624
+ var earCoordinates = {
14625
+ west: { uv: [24, 1, 25, 7] },
14626
+ east: { uv: [31, 1, 32, 7] },
14627
+ south: { uv: [25, 1, 31, 7] },
14628
+ north: { uv: [32, 1, 38, 7] },
14629
+ up: { uv: [25, 0, 31, 1] },
14630
+ down: { uv: [31, 1, 37, 0] }
14631
+ };
14367
14632
  var baseSkinCoordinates = {
14368
14633
  head: {
14369
14634
  west: {
@@ -14984,7 +15249,9 @@ var baseSkinCoordinates = {
14984
15249
  south: { uv: [12, 1, 22, 17] },
14985
15250
  up: { uv: [11, 1, 1, 0] },
14986
15251
  down: { uv: [21, 0, 11, 1] }
14987
- }
15252
+ },
15253
+ leftEar: earCoordinates,
15254
+ rightEar: earCoordinates
14988
15255
  };
14989
15256
  var classicSkinTextureCoordinates = {
14990
15257
  ...baseSkinCoordinates
@@ -15035,6 +15302,7 @@ var box4_12_4outer = [4.5, 12.5, 4.5];
15035
15302
  var box3_12_4inner = [3, 12, 4];
15036
15303
  var box3_12_4outer = [3.5, 12.5, 4.5];
15037
15304
  var box10_16_1 = [10, 16, 1];
15305
+ var box8_8_3ear = [8, 8, 3];
15038
15306
  var baseSkinGeometries = {
15039
15307
  head: box8inner,
15040
15308
  hat: box8outer,
@@ -15048,7 +15316,9 @@ var baseSkinGeometries = {
15048
15316
  leftTrousers: box4_12_4outer,
15049
15317
  rightLeg: box4_12_4inner,
15050
15318
  rightTrousers: box4_12_4outer,
15051
- cape: box10_16_1
15319
+ cape: box10_16_1,
15320
+ leftEar: box8_8_3ear,
15321
+ rightEar: box8_8_3ear
15052
15322
  };
15053
15323
  var classicSkinGeometries = { ...{}, ...baseSkinGeometries };
15054
15324
  var slimSkinGeometries = {
@@ -15077,6 +15347,12 @@ var capeTextureSizes = {
15077
15347
  };
15078
15348
 
15079
15349
  // src/skin/scene/SkinObject.ts
15350
+ var ArmorClass;
15351
+ var EntityObjectClass;
15352
+ function hasCubes(part) {
15353
+ return part.cubes.length > 0 || Object.values(part.children).some(hasCubes);
15354
+ }
15355
+ var UPSIDE_DOWN_OFFSET = (1.8 + 0.1) * 16 / 0.9375;
15080
15356
  var SkinObject = class extends SceneObject {
15081
15357
  constructor(options) {
15082
15358
  super();
@@ -15084,27 +15360,42 @@ var SkinObject = class extends SceneObject {
15084
15360
  this.detectedSlim = false;
15085
15361
  this.skinLoad = 0;
15086
15362
  this.capeLoad = 0;
15363
+ this.armorLoad = 0;
15364
+ this.armorObjects = [];
15087
15365
  this.options = (0, import_ts_deepmerge.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
15088
15366
  this.slim = this.options.slim ?? false;
15089
15367
  }
15090
15368
  async init() {
15091
15369
  const cape = this.getGroupByName("cape" /* CAPE */);
15370
+ const capeOnBody = cape?.parent === this.getGroupByName("body" /* BODY */);
15092
15371
  this.createMeshes();
15093
- if (cape) this.getGroupByName("body" /* BODY */).attach(cape);
15372
+ if (cape) {
15373
+ const body = this.getGroupByName("body" /* BODY */);
15374
+ if (capeOnBody) body.add(cape);
15375
+ else body.attach(cape);
15376
+ }
15377
+ for (const { part, object: object4 } of this.armorObjects) this.getGroupByName(part).add(object4);
15378
+ this.updateEars();
15379
+ this.updateUpsideDown();
15094
15380
  }
15095
15381
  removeMeshes() {
15096
15382
  }
15097
15383
  createMeshes() {
15098
15384
  const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
15385
+ this.model?.removeFromParent();
15386
+ const model = this.model = new import_three36.Object3D();
15387
+ this.add(model);
15099
15388
  {
15100
- const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
15389
+ const headGroup = this.createGroup("head", 0, 28, 0, "y" /* Y */, -4);
15390
+ model.add(headGroup);
15101
15391
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
15102
15392
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
15103
15393
  const hatGeo = this.getBoxGeometry("hat" /* HAT */);
15104
15394
  const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
15105
15395
  }
15106
15396
  {
15107
- const bodyGroup = this.createAndAddGroup("body", 0, 24, 0);
15397
+ const bodyGroup = this.createGroup("body", 0, 24, 0);
15398
+ model.add(bodyGroup);
15108
15399
  const bodyGeo = this.getBoxGeometry("body" /* BODY */);
15109
15400
  const body = this.createAndAddMesh("body", bodyGroup, bodyGeo, mat, "y" /* Y */, -6);
15110
15401
  const jacketGeo = this.getBoxGeometry("jacket" /* JACKET */);
@@ -15112,7 +15403,8 @@ var SkinObject = class extends SceneObject {
15112
15403
  }
15113
15404
  {
15114
15405
  {
15115
- const leftArmGroup = this.createAndAddGroup("leftArm", 5, 22, 0);
15406
+ const leftArmGroup = this.createGroup("leftArm", 5, 22, 0);
15407
+ model.add(leftArmGroup);
15116
15408
  const leftArmGeo = this.getBoxGeometry("leftArm" /* LEFT_ARM */);
15117
15409
  const leftArm = this.createAndAddMesh("leftArm", leftArmGroup, leftArmGeo, mat, "y" /* Y */, -4);
15118
15410
  leftArm.position.x = this.slim ? 0.5 : 1;
@@ -15121,7 +15413,8 @@ var SkinObject = class extends SceneObject {
15121
15413
  leftSleeve.position.x = this.slim ? 0.5 : 1;
15122
15414
  }
15123
15415
  {
15124
- const rightArmGroup = this.createAndAddGroup("rightArm", -5, 22, 0);
15416
+ const rightArmGroup = this.createGroup("rightArm", -5, 22, 0);
15417
+ model.add(rightArmGroup);
15125
15418
  const rightArmGeo = this.getBoxGeometry("rightArm" /* RIGHT_ARM */);
15126
15419
  const rightArm = this.createAndAddMesh("rightArm", rightArmGroup, rightArmGeo, mat, "y" /* Y */, -4);
15127
15420
  rightArm.position.x = this.slim ? -0.5 : -1;
@@ -15132,14 +15425,16 @@ var SkinObject = class extends SceneObject {
15132
15425
  }
15133
15426
  {
15134
15427
  {
15135
- const leftLegGroup = this.createAndAddGroup("leftLeg", 1.9, 12, 0);
15428
+ const leftLegGroup = this.createGroup("leftLeg", 1.9, 12, 0);
15429
+ model.add(leftLegGroup);
15136
15430
  const leftLegGeo = this.getBoxGeometry("leftLeg" /* LEFT_LEG */);
15137
15431
  const leftLeg = this.createAndAddMesh("leftLeg", leftLegGroup, leftLegGeo, mat, "y" /* Y */, -6);
15138
15432
  const leftTrousersGeo = this.getBoxGeometry("leftTrousers" /* LEFT_TROUSERS */);
15139
15433
  const leftTrousers = this.createAndAddMesh("leftTrousers", leftLegGroup, leftTrousersGeo, mat, "y" /* Y */, -6);
15140
15434
  }
15141
15435
  {
15142
- const rightLegGroup = this.createAndAddGroup("rightLeg", -1.9, 12, 0);
15436
+ const rightLegGroup = this.createGroup("rightLeg", -1.9, 12, 0);
15437
+ model.add(rightLegGroup);
15143
15438
  const rightLegGeo = this.getBoxGeometry("rightLeg" /* RIGHT_LEG */);
15144
15439
  const rightLeg = this.createAndAddMesh("rightLeg", rightLegGroup, rightLegGeo, mat, "y" /* Y */, -6);
15145
15440
  const rightTrousersGeo = this.getBoxGeometry("rightTrousers" /* RIGHT_TROUSERS */);
@@ -15206,6 +15501,54 @@ var SkinObject = class extends SceneObject {
15206
15501
  }
15207
15502
  this.notifyDirty();
15208
15503
  }
15504
+ /**
15505
+ * Loads armor from 1.21.4+ equipment assets, or pass undefined to remove it.
15506
+ * Each piece moves with the skin part it covers.
15507
+ */
15508
+ async setArmor(armor) {
15509
+ const load = ++this.armorLoad;
15510
+ const objects = [];
15511
+ if (armor) {
15512
+ const Armor2 = ArmorClass ?? (ArmorClass = (await Promise.resolve().then(() => (init_Armor(), Armor_exports))).Armor);
15513
+ const EntityObject2 = EntityObjectClass ?? (EntityObjectClass = (await Promise.resolve().then(() => (init_EntityObject(), EntityObject_exports))).EntityObject);
15514
+ const model = await Armor2.getEntity(armor);
15515
+ if (model) {
15516
+ const parts = { head: "head", body: "body", left_arm: "leftArm", right_arm: "rightArm", left_leg: "leftLeg", right_leg: "rightLeg" };
15517
+ for (const [name, part] of Object.entries(parts)) {
15518
+ const layers = {};
15519
+ for (const [draw, layer] of Object.entries(model.layers)) {
15520
+ const child = layer.layer.root.children[name];
15521
+ if (!child || !hasCubes(child)) continue;
15522
+ const pose = { offset: [0, 0, 0], rotation: [0, 0, 0] };
15523
+ layers[draw] = { ...layer, layer: { ...layer.layer, root: {
15524
+ pose,
15525
+ cubes: [],
15526
+ children: { [name]: { ...child, pose } }
15527
+ } } };
15528
+ }
15529
+ const first = Object.values(layers)[0];
15530
+ if (!first) continue;
15531
+ const object4 = new EntityObject2({ ...first, id: model.id, layers }, { flip: false });
15532
+ object4.rotation.x = Math.PI;
15533
+ objects.push({ part, object: object4 });
15534
+ }
15535
+ }
15536
+ }
15537
+ const results = await Promise.allSettled(objects.map(({ object: object4 }) => object4.init()));
15538
+ const failure = results.find((result) => result.status === "rejected");
15539
+ if (load !== this.armorLoad || failure) {
15540
+ for (const { object: object4 } of objects) object4.dispose();
15541
+ if (load === this.armorLoad && failure?.status === "rejected") throw failure.reason;
15542
+ return;
15543
+ }
15544
+ for (const { object: object4 } of this.armorObjects) {
15545
+ object4.dispose();
15546
+ object4.removeFromParent();
15547
+ }
15548
+ this.armorObjects = objects;
15549
+ for (const { part, object: object4 } of objects) this.getGroupByName(part)?.add(object4);
15550
+ this.notifyDirty();
15551
+ }
15209
15552
  /** Select the arm model, or pass undefined to use texture detection. */
15210
15553
  setSlim(slim) {
15211
15554
  this.options.slim = slim;
@@ -15224,6 +15567,39 @@ var SkinObject = class extends SceneObject {
15224
15567
  }
15225
15568
  this.notifyDirty();
15226
15569
  }
15570
+ /** Shows or hides deadmau5's ears, which vanilla draws from the skin texture at 24,0 for that player only. */
15571
+ setEars(ears) {
15572
+ if (ears === (this.options.ears ?? false)) return;
15573
+ this.options.ears = ears;
15574
+ this.updateEars();
15575
+ }
15576
+ updateEars() {
15577
+ const head = this.getGroupByName("head" /* HEAD */);
15578
+ if (!head) return;
15579
+ for (const [part, x] of [["leftEar" /* LEFT_EAR */, 6], ["rightEar" /* RIGHT_EAR */, -6]]) {
15580
+ const ear = this.getMeshByName(part);
15581
+ if (!this.options.ears) {
15582
+ ear?.removeFromParent();
15583
+ } else if (!ear) {
15584
+ const mesh = this.createAndAddMesh(part, head, this.getBoxGeometry(part), this.skinMaterial ?? Materials.MISSING_TEXTURE);
15585
+ mesh.position.set(x, 9, 0.5);
15586
+ }
15587
+ }
15588
+ this.notifyDirty();
15589
+ }
15590
+ /** Turns the player upside down, as vanilla does for players named Dinnerbone or Grumm. */
15591
+ setUpsideDown(upsideDown) {
15592
+ if (upsideDown === (this.options.upsideDown ?? false)) return;
15593
+ this.options.upsideDown = upsideDown;
15594
+ this.updateUpsideDown();
15595
+ }
15596
+ updateUpsideDown() {
15597
+ if (!this.model) return;
15598
+ const upsideDown = this.options.upsideDown ?? false;
15599
+ this.model.position.y = upsideDown ? UPSIDE_DOWN_OFFSET : 0;
15600
+ this.model.rotation.z = upsideDown ? Math.PI : 0;
15601
+ this.notifyDirty();
15602
+ }
15227
15603
  /** Select the texture layout, or pass undefined to detect it from image dimensions. */
15228
15604
  async setLegacy(legacy) {
15229
15605
  if (legacy === this.options.legacy) return;
@@ -15233,6 +15609,11 @@ var SkinObject = class extends SceneObject {
15233
15609
  dispose() {
15234
15610
  this.skinLoad++;
15235
15611
  this.capeLoad++;
15612
+ this.armorLoad++;
15613
+ for (const { object: object4 } of this.armorObjects.splice(0)) {
15614
+ object4.dispose();
15615
+ object4.removeFromParent();
15616
+ }
15236
15617
  super.dispose();
15237
15618
  }
15238
15619
  //TODO: layer toggles
@@ -15252,10 +15633,10 @@ function isBlockObject2(obj) {
15252
15633
  }
15253
15634
  var ModelObjectClass;
15254
15635
  var BlockObjectClass;
15255
- var EntityObjectClass;
15636
+ var EntityObjectClass2;
15256
15637
  var GuiObjectClass;
15257
15638
  var ItemTintsClass;
15258
- var _MineRenderScene = class _MineRenderScene extends import_three36.Scene {
15639
+ var _MineRenderScene = class _MineRenderScene extends import_three37.Scene {
15259
15640
  constructor(options) {
15260
15641
  super();
15261
15642
  this.isMineRenderScene = true;
@@ -15393,7 +15774,7 @@ var _MineRenderScene = class _MineRenderScene extends import_three36.Scene {
15393
15774
  }
15394
15775
  /** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
15395
15776
  async addEntity(entity, options, parent = this) {
15396
- const EntityObject2 = EntityObjectClass ?? (EntityObjectClass = (await Promise.resolve().then(() => (init_EntityObject(), EntityObject_exports))).EntityObject);
15777
+ const EntityObject2 = EntityObjectClass2 ?? (EntityObjectClass2 = (await Promise.resolve().then(() => (init_EntityObject(), EntityObject_exports))).EntityObject);
15397
15778
  return this.addSceneObject(entity, () => new EntityObject2(entity, options), options, parent);
15398
15779
  }
15399
15780
  /**
@@ -15417,7 +15798,7 @@ function isMineRenderScene(obj) {
15417
15798
  }
15418
15799
 
15419
15800
  // src/renderer/Renderer.ts
15420
- var import_three38 = require("three");
15801
+ var import_three39 = require("three");
15421
15802
  init_merge();
15422
15803
  var import_stats = __toESM(require("stats.js"));
15423
15804
  var import_postprocessing = require("postprocessing");
@@ -15426,11 +15807,11 @@ init_Model();
15426
15807
  init_three();
15427
15808
 
15428
15809
  // src/three/OrbitControls.js
15429
- var import_three37 = require("three");
15810
+ var import_three38 = require("three");
15430
15811
  var _changeEvent = { type: "change" };
15431
15812
  var _startEvent = { type: "start" };
15432
15813
  var _endEvent = { type: "end" };
15433
- var OrbitControls = class extends import_three37.EventDispatcher {
15814
+ var OrbitControls = class extends import_three38.EventDispatcher {
15434
15815
  constructor(object4, domElement) {
15435
15816
  super();
15436
15817
  if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
@@ -15439,7 +15820,7 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15439
15820
  this.domElement = domElement;
15440
15821
  this.domElement.style.touchAction = "none";
15441
15822
  this.enabled = true;
15442
- this.target = new import_three37.Vector3();
15823
+ this.target = new import_three38.Vector3();
15443
15824
  this.minDistance = 0;
15444
15825
  this.maxDistance = Infinity;
15445
15826
  this.minZoom = 0;
@@ -15461,8 +15842,8 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15461
15842
  this.autoRotate = false;
15462
15843
  this.autoRotateSpeed = 2;
15463
15844
  this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
15464
- this.mouseButtons = { LEFT: import_three37.MOUSE.ROTATE, MIDDLE: import_three37.MOUSE.DOLLY, RIGHT: import_three37.MOUSE.PAN };
15465
- this.touches = { ONE: import_three37.TOUCH.ROTATE, TWO: import_three37.TOUCH.DOLLY_PAN };
15845
+ this.mouseButtons = { LEFT: import_three38.MOUSE.ROTATE, MIDDLE: import_three38.MOUSE.DOLLY, RIGHT: import_three38.MOUSE.PAN };
15846
+ this.touches = { ONE: import_three38.TOUCH.ROTATE, TWO: import_three38.TOUCH.DOLLY_PAN };
15466
15847
  this.target0 = this.target.clone();
15467
15848
  this.position0 = this.object.position.clone();
15468
15849
  this.zoom0 = this.object.zoom;
@@ -15491,11 +15872,11 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15491
15872
  state = STATE.NONE;
15492
15873
  };
15493
15874
  this.update = function() {
15494
- const offset = new import_three37.Vector3();
15495
- const quat = new import_three37.Quaternion().setFromUnitVectors(object4.up, new import_three37.Vector3(0, 1, 0));
15875
+ const offset = new import_three38.Vector3();
15876
+ const quat = new import_three38.Quaternion().setFromUnitVectors(object4.up, new import_three38.Vector3(0, 1, 0));
15496
15877
  const quatInverse = quat.clone().invert();
15497
- const lastPosition = new import_three37.Vector3();
15498
- const lastQuaternion = new import_three37.Quaternion();
15878
+ const lastPosition = new import_three38.Vector3();
15879
+ const lastQuaternion = new import_three38.Quaternion();
15499
15880
  const twoPI = 2 * Math.PI;
15500
15881
  return function update() {
15501
15882
  const position = scope.object.position;
@@ -15581,20 +15962,20 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15581
15962
  };
15582
15963
  let state = STATE.NONE;
15583
15964
  const EPS = 1e-6;
15584
- const spherical = new import_three37.Spherical();
15585
- const sphericalDelta = new import_three37.Spherical();
15965
+ const spherical = new import_three38.Spherical();
15966
+ const sphericalDelta = new import_three38.Spherical();
15586
15967
  let scale = 1;
15587
- const panOffset = new import_three37.Vector3();
15968
+ const panOffset = new import_three38.Vector3();
15588
15969
  let zoomChanged = false;
15589
- const rotateStart = new import_three37.Vector2();
15590
- const rotateEnd = new import_three37.Vector2();
15591
- const rotateDelta = new import_three37.Vector2();
15592
- const panStart = new import_three37.Vector2();
15593
- const panEnd = new import_three37.Vector2();
15594
- const panDelta = new import_three37.Vector2();
15595
- const dollyStart = new import_three37.Vector2();
15596
- const dollyEnd = new import_three37.Vector2();
15597
- const dollyDelta = new import_three37.Vector2();
15970
+ const rotateStart = new import_three38.Vector2();
15971
+ const rotateEnd = new import_three38.Vector2();
15972
+ const rotateDelta = new import_three38.Vector2();
15973
+ const panStart = new import_three38.Vector2();
15974
+ const panEnd = new import_three38.Vector2();
15975
+ const panDelta = new import_three38.Vector2();
15976
+ const dollyStart = new import_three38.Vector2();
15977
+ const dollyEnd = new import_three38.Vector2();
15978
+ const dollyDelta = new import_three38.Vector2();
15598
15979
  const pointers = [];
15599
15980
  const pointerPositions = {};
15600
15981
  function getAutoRotationAngle() {
@@ -15610,7 +15991,7 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15610
15991
  sphericalDelta.phi -= angle;
15611
15992
  }
15612
15993
  const panLeft = function() {
15613
- const v = new import_three37.Vector3();
15994
+ const v = new import_three38.Vector3();
15614
15995
  return function panLeft2(distance, objectMatrix) {
15615
15996
  v.setFromMatrixColumn(objectMatrix, 0);
15616
15997
  v.multiplyScalar(-distance);
@@ -15618,7 +15999,7 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15618
15999
  };
15619
16000
  }();
15620
16001
  const panUp = function() {
15621
- const v = new import_three37.Vector3();
16002
+ const v = new import_three38.Vector3();
15622
16003
  return function panUp2(distance, objectMatrix) {
15623
16004
  if (scope.screenSpacePanning === true) {
15624
16005
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -15631,7 +16012,7 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15631
16012
  };
15632
16013
  }();
15633
16014
  const pan = function() {
15634
- const offset = new import_three37.Vector3();
16015
+ const offset = new import_three38.Vector3();
15635
16016
  return function pan2(deltaX, deltaY) {
15636
16017
  const element = scope.domElement;
15637
16018
  if (scope.object.isPerspectiveCamera) {
@@ -15880,12 +16261,12 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15880
16261
  mouseAction = -1;
15881
16262
  }
15882
16263
  switch (mouseAction) {
15883
- case import_three37.MOUSE.DOLLY:
16264
+ case import_three38.MOUSE.DOLLY:
15884
16265
  if (scope.enableZoom === false) return;
15885
16266
  handleMouseDownDolly(event);
15886
16267
  state = STATE.DOLLY;
15887
16268
  break;
15888
- case import_three37.MOUSE.ROTATE:
16269
+ case import_three38.MOUSE.ROTATE:
15889
16270
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
15890
16271
  if (scope.enablePan === false) return;
15891
16272
  handleMouseDownPan(event);
@@ -15896,7 +16277,7 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15896
16277
  state = STATE.ROTATE;
15897
16278
  }
15898
16279
  break;
15899
- case import_three37.MOUSE.PAN:
16280
+ case import_three38.MOUSE.PAN:
15900
16281
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
15901
16282
  if (scope.enableRotate === false) return;
15902
16283
  handleMouseDownRotate(event);
@@ -15952,12 +16333,12 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15952
16333
  switch (pointers.length) {
15953
16334
  case 1:
15954
16335
  switch (scope.touches.ONE) {
15955
- case import_three37.TOUCH.ROTATE:
16336
+ case import_three38.TOUCH.ROTATE:
15956
16337
  if (scope.enableRotate === false) return;
15957
16338
  handleTouchStartRotate();
15958
16339
  state = STATE.TOUCH_ROTATE;
15959
16340
  break;
15960
- case import_three37.TOUCH.PAN:
16341
+ case import_three38.TOUCH.PAN:
15961
16342
  if (scope.enablePan === false) return;
15962
16343
  handleTouchStartPan();
15963
16344
  state = STATE.TOUCH_PAN;
@@ -15968,12 +16349,12 @@ var OrbitControls = class extends import_three37.EventDispatcher {
15968
16349
  break;
15969
16350
  case 2:
15970
16351
  switch (scope.touches.TWO) {
15971
- case import_three37.TOUCH.DOLLY_PAN:
16352
+ case import_three38.TOUCH.DOLLY_PAN:
15972
16353
  if (scope.enableZoom === false && scope.enablePan === false) return;
15973
16354
  handleTouchStartDollyPan();
15974
16355
  state = STATE.TOUCH_DOLLY_PAN;
15975
16356
  break;
15976
- case import_three37.TOUCH.DOLLY_ROTATE:
16357
+ case import_three38.TOUCH.DOLLY_ROTATE:
15977
16358
  if (scope.enableZoom === false && scope.enableRotate === false) return;
15978
16359
  handleTouchStartDollyRotate();
15979
16360
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -16040,7 +16421,7 @@ var OrbitControls = class extends import_three37.EventDispatcher {
16040
16421
  function trackPointer(event) {
16041
16422
  let position = pointerPositions[event.pointerId];
16042
16423
  if (position === void 0) {
16043
- position = new import_three37.Vector2();
16424
+ position = new import_three38.Vector2();
16044
16425
  pointerPositions[event.pointerId] = position;
16045
16426
  }
16046
16427
  position.set(event.pageX, event.pageY);
@@ -16060,16 +16441,16 @@ var MapControls = class extends OrbitControls {
16060
16441
  constructor(object4, domElement) {
16061
16442
  super(object4, domElement);
16062
16443
  this.screenSpacePanning = false;
16063
- this.mouseButtons.LEFT = import_three37.MOUSE.PAN;
16064
- this.mouseButtons.RIGHT = import_three37.MOUSE.ROTATE;
16065
- this.touches.ONE = import_three37.TOUCH.PAN;
16066
- this.touches.TWO = import_three37.TOUCH.DOLLY_ROTATE;
16444
+ this.mouseButtons.LEFT = import_three38.MOUSE.PAN;
16445
+ this.mouseButtons.RIGHT = import_three38.MOUSE.ROTATE;
16446
+ this.touches.ONE = import_three38.TOUCH.PAN;
16447
+ this.touches.TWO = import_three38.TOUCH.DOLLY_ROTATE;
16067
16448
  }
16068
16449
  };
16069
16450
 
16070
16451
  // src/renderer/Renderer.ts
16071
16452
  init_log();
16072
- var log17 = logger("Renderer");
16453
+ var log18 = logger("Renderer");
16073
16454
  var _Renderer = class _Renderer {
16074
16455
  constructor(options, surface) {
16075
16456
  this._width = 0;
@@ -16136,14 +16517,14 @@ var _Renderer = class _Renderer {
16136
16517
  switch (this.options.camera.type) {
16137
16518
  case "perspective":
16138
16519
  default:
16139
- return new import_three38.PerspectiveCamera(
16520
+ return new import_three39.PerspectiveCamera(
16140
16521
  this.options.camera.perspective.fov,
16141
16522
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
16142
16523
  this.options.camera.near,
16143
16524
  this.options.camera.far
16144
16525
  );
16145
16526
  case "orthographic":
16146
- return new import_three38.OrthographicCamera(
16527
+ return new import_three39.OrthographicCamera(
16147
16528
  this.options.camera.orthographic.left ?? this.viewWidth / -2,
16148
16529
  this.options.camera.orthographic.right ?? this.viewWidth / 2,
16149
16530
  this.options.camera.orthographic.top ?? this.viewHeight / 2,
@@ -16159,7 +16540,7 @@ var _Renderer = class _Renderer {
16159
16540
  }
16160
16541
  const pixelRatio = this.options.render.pixelRatio ?? 1;
16161
16542
  this._surface?.resize?.(Math.floor(this.viewWidth * pixelRatio), Math.floor(this.viewHeight * pixelRatio));
16162
- const renderer = new import_three38.WebGLRenderer({
16543
+ const renderer = new import_three39.WebGLRenderer({
16163
16544
  canvas: this._surface?.canvas,
16164
16545
  context: this._surface?.context,
16165
16546
  antialias: this.options.render.antialias,
@@ -16169,8 +16550,8 @@ var _Renderer = class _Renderer {
16169
16550
  });
16170
16551
  renderer.setClearColor(0, 0);
16171
16552
  renderer.shadowMap.enabled = true;
16172
- renderer.shadowMap.type = import_three38.PCFShadowMap;
16173
- renderer.outputColorSpace = import_three38.SRGBColorSpace;
16553
+ renderer.shadowMap.type = import_three39.PCFShadowMap;
16554
+ renderer.outputColorSpace = import_three39.SRGBColorSpace;
16174
16555
  if (this._surface) {
16175
16556
  renderer.setDrawingBufferSize(this.viewWidth, this.viewHeight, pixelRatio);
16176
16557
  } else {
@@ -16193,8 +16574,8 @@ var _Renderer = class _Renderer {
16193
16574
  initialTarget() {
16194
16575
  const target = this.options.camera.lookingAt;
16195
16576
  if (isVector3(target)) return target.clone();
16196
- if (isTripleArray(target)) return new import_three38.Vector3(target[0], target[1], target[2]);
16197
- return new import_three38.Vector3();
16577
+ if (isTripleArray(target)) return new import_three39.Vector3(target[0], target[1], target[2]);
16578
+ return new import_three39.Vector3();
16198
16579
  }
16199
16580
  createControlsFor(mode, target) {
16200
16581
  let controls;
@@ -16227,7 +16608,7 @@ var _Renderer = class _Renderer {
16227
16608
  let target;
16228
16609
  if (isFlyControls(current)) {
16229
16610
  const distance = this._orbitDistance ?? (this.camera.position.distanceTo(this.initialTarget()) || 1);
16230
- target = new import_three38.Vector3(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
16611
+ target = new import_three39.Vector3(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
16231
16612
  } else {
16232
16613
  target = current.target.clone();
16233
16614
  this._orbitDistance = this.camera.position.distanceTo(target);
@@ -16267,20 +16648,20 @@ var _Renderer = class _Renderer {
16267
16648
  window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
16268
16649
  }
16269
16650
  if (this.options.debug.grid) {
16270
- const gridHelper = new import_three38.GridHelper(128, 16);
16651
+ const gridHelper = new import_three39.GridHelper(128, 16);
16271
16652
  this._debugHelpers.push(gridHelper);
16272
16653
  this.scene.add(gridHelper);
16273
- const gridHelper2 = new import_three38.GridHelper(128, 16);
16654
+ const gridHelper2 = new import_three39.GridHelper(128, 16);
16274
16655
  this._debugHelpers.push(gridHelper2);
16275
16656
  gridHelper2.rotation.x = 90 * (Math.PI / 180);
16276
16657
  this.scene.add(gridHelper2);
16277
- const gridHelper3 = new import_three38.GridHelper(128, 16);
16658
+ const gridHelper3 = new import_three39.GridHelper(128, 16);
16278
16659
  this._debugHelpers.push(gridHelper3);
16279
16660
  gridHelper3.rotation.z = 90 * (Math.PI / 180);
16280
16661
  this.scene.add(gridHelper3);
16281
16662
  }
16282
16663
  if (this.options.debug.axes) {
16283
- const axesHelper = new import_three38.AxesHelper(64);
16664
+ const axesHelper = new import_three39.AxesHelper(64);
16284
16665
  this._debugHelpers.push(axesHelper);
16285
16666
  this.scene.add(axesHelper);
16286
16667
  }
@@ -16314,10 +16695,10 @@ var _Renderer = class _Renderer {
16314
16695
  this._element = element;
16315
16696
  this._element.appendChild(this.renderer.domElement);
16316
16697
  if (this.viewWidth == 0) {
16317
- log17.warn("0 element width");
16698
+ log18.warn("0 element width");
16318
16699
  }
16319
16700
  if (this.viewHeight == 0) {
16320
- log17.warn("0 element height");
16701
+ log18.warn("0 element height");
16321
16702
  }
16322
16703
  this.resize(this.viewWidth, this.viewHeight);
16323
16704
  }
@@ -16613,8 +16994,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge.default)({}, {
16613
16994
  top: void 0,
16614
16995
  bottom: void 0
16615
16996
  },
16616
- position: new import_three38.Vector3(50, 50, 50),
16617
- lookingAt: new import_three38.Vector3(0, 0, 0)
16997
+ position: new import_three39.Vector3(50, 50, 50),
16998
+ lookingAt: new import_three39.Vector3(0, 0, 0)
16618
16999
  },
16619
17000
  render: {
16620
17001
  fpsLimit: 60,
@@ -16741,6 +17122,23 @@ var itemContext = (withDisplayContext) => (value, path) => {
16741
17122
  }
16742
17123
  });
16743
17124
  };
17125
+ function entityAnimation(value, path) {
17126
+ const animation = object3(value, path);
17127
+ if (["name", "clips"].filter((key) => animation[key] !== void 0).length !== 1) {
17128
+ fail(path, "expected exactly one of name or clips");
17129
+ }
17130
+ fields(value, path, { name: text, clips: (value2, path2) => {
17131
+ list((value3, path3) => {
17132
+ fields(value3, path3, { name: text, weight: nonnegative }, ["name"]);
17133
+ })(value2, path2);
17134
+ if (!value2.length) fail(path2, "expected at least one clip");
17135
+ const names = /* @__PURE__ */ new Set();
17136
+ for (const [index, clip] of value2.entries()) {
17137
+ if (names.has(clip.name)) fail(`${path2}[${index}].name`, `duplicate clip "${clip.name}"`);
17138
+ names.add(clip.name);
17139
+ }
17140
+ }, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean });
17141
+ }
16744
17142
  function guiLayer(value, path) {
16745
17143
  const layer = object3(value, path);
16746
17144
  if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
@@ -16781,13 +17179,27 @@ function validateObject(value, path) {
16781
17179
  const required = ["id", "type"];
16782
17180
  const renderOptions = { wireframe: boolean };
16783
17181
  switch (input.type) {
16784
- case "skin":
17182
+ case "skin": {
17183
+ const piece = (value2, path2) => {
17184
+ if (typeof value2 === "string") asset(value2, path2);
17185
+ else fields(value2, path2, {
17186
+ asset,
17187
+ color,
17188
+ glint: boolean,
17189
+ trim: (value3, path3) => {
17190
+ fields(value3, path3, { pattern: asset, material: asset }, ["pattern", "material"]);
17191
+ }
17192
+ }, ["asset"]);
17193
+ };
16785
17194
  fields(value, path, {
16786
17195
  ...common,
16787
17196
  skin: text,
16788
17197
  cape: (value2, path2) => {
16789
17198
  fields(value2, path2, { texture: text, layout: enumeration(["minecraft", "optifine", "labymod"]) }, ["texture"]);
16790
17199
  },
17200
+ armor: (value2, path2) => {
17201
+ fields(value2, path2, { head: piece, chest: piece, legs: piece, feet: piece });
17202
+ },
16791
17203
  hiddenParts: list(enumeration(SKIN_PARTS)),
16792
17204
  pose: (value2, path2) => {
16793
17205
  fields(value2, path2, {
@@ -16801,10 +17213,11 @@ function validateObject(value, path) {
16801
17213
  });
16802
17214
  },
16803
17215
  options: (value2, path2) => {
16804
- fields(value2, path2, { slim: boolean, legacy: boolean });
17216
+ fields(value2, path2, { slim: boolean, legacy: boolean, ears: boolean, upsideDown: boolean });
16805
17217
  }
16806
17218
  }, required);
16807
17219
  break;
17220
+ }
16808
17221
  case "block":
16809
17222
  fields(value, path, {
16810
17223
  ...common,
@@ -16843,9 +17256,7 @@ function validateObject(value, path) {
16843
17256
  })
16844
17257
  });
16845
17258
  },
16846
- animation: (value2, path2) => {
16847
- fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
16848
- }
17259
+ animation: entityAnimation
16849
17260
  }, [...required, "asset"]);
16850
17261
  if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
16851
17262
  break;
@@ -16953,7 +17364,7 @@ async function decodeSceneDocument(value) {
16953
17364
  }
16954
17365
 
16955
17366
  // src/scene/SceneDocumentLoader.ts
16956
- var import_three40 = require("three");
17367
+ var import_three41 = require("three");
16957
17368
  init_AssetKey();
16958
17369
  init_AssetLoader();
16959
17370
  init_BlockStates();
@@ -17015,7 +17426,7 @@ var SceneDocumentLoader = class {
17015
17426
  if (definition.minecraftVersion !== void 0 && definition.minecraftVersion !== AssetLoader.version) {
17016
17427
  throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion("${definition.minecraftVersion}") before loading it`);
17017
17428
  }
17018
- const root = new import_three40.Group();
17429
+ const root = new import_three41.Group();
17019
17430
  root.name = "MineRender scene document";
17020
17431
  const objects = [];
17021
17432
  let disposed = false;
@@ -17055,7 +17466,7 @@ var SceneDocumentLoader = class {
17055
17466
  return this.loadValidatedObject(scene, definition, parent);
17056
17467
  }
17057
17468
  static async loadValidatedObject(scene, definition, parent) {
17058
- const root = new import_three40.Group();
17469
+ const root = new import_three41.Group();
17059
17470
  root.name = definition.name ?? definition.id;
17060
17471
  root.userData.sceneObjectId = definition.id;
17061
17472
  root.position.fromArray(definition.position ?? [0, 0, 0]);
@@ -17074,6 +17485,7 @@ var SceneDocumentLoader = class {
17074
17485
  await skin.setSkinTexture(texture);
17075
17486
  await content.initialize(skin);
17076
17487
  if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);
17488
+ if (definition.armor) await skin.setArmor(definition.armor);
17077
17489
  for (const [part, rotation] of Object.entries(definition.pose ?? {})) {
17078
17490
  skin.getGroupByName(part)?.rotation.set(...rotation, "XYZ");
17079
17491
  }
@@ -17112,10 +17524,20 @@ var SceneDocumentLoader = class {
17112
17524
  const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
17113
17525
  object4 = entity;
17114
17526
  if (definition.animation) {
17527
+ const animation = definition.animation;
17115
17528
  const animations = await Entities.getAnimations(key);
17116
- const clip = animations?.[definition.animation.name];
17117
- if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${definition.animation.name}"`);
17118
- entity.playAnimation(clip, definition.animation);
17529
+ if (animation.name !== void 0) {
17530
+ const clip = animations && Object.prototype.hasOwnProperty.call(animations, animation.name) ? animations[animation.name] : void 0;
17531
+ if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${animation.name}"`);
17532
+ entity.playAnimation(clip, animation);
17533
+ } else {
17534
+ const clips = animation.clips.map(({ name }) => {
17535
+ const clip = animations && Object.prototype.hasOwnProperty.call(animations, name) ? animations[name] : void 0;
17536
+ if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${name}"`);
17537
+ return clip;
17538
+ });
17539
+ entity.playAnimations(clips, { ...animation, weights: animation.clips.map((clip) => clip.weight ?? 1) });
17540
+ }
17119
17541
  }
17120
17542
  break;
17121
17543
  }
@@ -17164,6 +17586,7 @@ init_Skins();
17164
17586
 
17165
17587
  // src/texture/index.ts
17166
17588
  init_Colormaps();
17589
+ init_PalettedTextures();
17167
17590
  init_TextureAtlas();
17168
17591
  init_TextureLoader();
17169
17592
  init_Textures();
@@ -17953,7 +18376,7 @@ var AnvilWorldSource = class {
17953
18376
  read.waiters++;
17954
18377
  return new Promise((resolve, reject) => {
17955
18378
  let finished = false;
17956
- const release2 = () => {
18379
+ const release = () => {
17957
18380
  if (finished) return false;
17958
18381
  finished = true;
17959
18382
  signal?.removeEventListener("abort", abort);
@@ -17961,7 +18384,7 @@ var AnvilWorldSource = class {
17961
18384
  return true;
17962
18385
  };
17963
18386
  const abort = () => {
17964
- if (!release2()) return;
18387
+ if (!release()) return;
17965
18388
  if (!read.waiters && !read.settled) {
17966
18389
  if (this.pending.get(key) === read) this.pending.delete(key);
17967
18390
  read.controller.abort(signal.reason);
@@ -17971,10 +18394,10 @@ var AnvilWorldSource = class {
17971
18394
  signal?.addEventListener("abort", abort, { once: true });
17972
18395
  read.promise.then(
17973
18396
  (data) => {
17974
- if (release2()) resolve(data);
18397
+ if (release()) resolve(data);
17975
18398
  },
17976
18399
  (error) => {
17977
- if (release2()) reject(error);
18400
+ if (release()) reject(error);
17978
18401
  }
17979
18402
  );
17980
18403
  if (signal?.aborted) abort();
@@ -17996,20 +18419,22 @@ var AnvilWorldSource = class {
17996
18419
  };
17997
18420
 
17998
18421
  // src/world/Chunk.ts
17999
- var import_three47 = require("three");
18422
+ init_BlockObject();
18423
+ var import_three48 = require("three");
18000
18424
  init_BlockStates();
18001
18425
  init_AssetKey();
18002
18426
 
18003
18427
  // src/world/MineRenderWorld.ts
18004
- var import_three45 = require("three");
18428
+ var import_three46 = require("three");
18005
18429
  init_Model();
18006
18430
  init_util();
18007
18431
  init_AssetKey();
18008
18432
  init_BlockStates();
18433
+ init_BlockEntities();
18009
18434
  init_CubeFace();
18010
18435
 
18011
18436
  // src/world/SectionModels.ts
18012
- var import_three41 = require("three");
18437
+ var import_three42 = require("three");
18013
18438
  init_AssetKey();
18014
18439
  init_Models();
18015
18440
  init_CubeFace();
@@ -18035,7 +18460,7 @@ function cached(map, key, load) {
18035
18460
  }
18036
18461
  function compactQuads(geometry, keep) {
18037
18462
  const quads = keep.flatMap((kept, index) => kept ? [index] : []);
18038
- const compact = new import_three41.BufferGeometry();
18463
+ const compact = new import_three42.BufferGeometry();
18039
18464
  for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3, shade: 1 })) {
18040
18465
  const source2 = geometry.getAttribute(name);
18041
18466
  const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : name === "shade" ? [1] : void 0;
@@ -18047,7 +18472,7 @@ function compactQuads(geometry, keep) {
18047
18472
  }
18048
18473
  }
18049
18474
  }
18050
- compact.setAttribute(name, new import_three41.BufferAttribute(values, size));
18475
+ compact.setAttribute(name, new import_three42.BufferAttribute(values, size));
18051
18476
  }
18052
18477
  const source = geometry.getIndex();
18053
18478
  const indices = [];
@@ -18103,6 +18528,10 @@ var SectionModels = class {
18103
18528
  biomeTint: source ? [...templates.values()].some((template) => template.biomeTint?.some((value) => value === 1)) || void 0 : void 0
18104
18529
  };
18105
18530
  }
18531
+ /** Starts loading the state's models and atlases so a later `prepareState` with the same properties finds them loaded. */
18532
+ async preload(blockState3, properties = {}) {
18533
+ await this.state(blockState3, properties);
18534
+ }
18106
18535
  async state(blockState3, properties) {
18107
18536
  let states = this.states.get(blockState3);
18108
18537
  if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
@@ -18125,22 +18554,24 @@ var SectionModels = class {
18125
18554
  async prepare(blockState3, properties) {
18126
18555
  const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
18127
18556
  const groups = BlockStateResolver.matching(blockState3, state);
18128
- if (!groups.length) return void 0;
18557
+ if (!groups.length || groups.some((group) => Array.isArray(group) && !group.length)) return void 0;
18558
+ const variants = groups.flatMap((group) => Array.isArray(group) ? group : [group]);
18559
+ if (variants.some((variant) => !variant.model)) return void 0;
18560
+ const settled = await Promise.allSettled(variants.map(async (variant) => {
18561
+ const modelKey = AssetKey.parse("models", variant.model);
18562
+ modelKey.root = blockState3.key?.root;
18563
+ const model = await Models.getMerged(modelKey);
18564
+ if (!model?.elements?.length) return void 0;
18565
+ const atlas = await UVMapper.getAtlas(model);
18566
+ const rotation = BlockStateResolver.rotation(variant);
18567
+ if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
18568
+ return { model, atlas, rotation };
18569
+ }));
18129
18570
  const prepared = /* @__PURE__ */ new Map();
18130
- for (const group of groups) {
18131
- const choices = Array.isArray(group) ? group : [group];
18132
- if (!choices.length) return void 0;
18133
- for (const variant of choices) {
18134
- if (!variant.model) return void 0;
18135
- const modelKey = AssetKey.parse("models", variant.model);
18136
- modelKey.root = blockState3.key?.root;
18137
- const model = await Models.getMerged(modelKey);
18138
- if (!model?.elements?.length) return void 0;
18139
- const atlas = await UVMapper.getAtlas(model);
18140
- const rotation = BlockStateResolver.rotation(variant);
18141
- if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
18142
- prepared.set(variant, { model, atlas, rotation });
18143
- }
18571
+ for (const [i, result] of settled.entries()) {
18572
+ if (result.status === "rejected") throw result.reason;
18573
+ if (!result.value) return void 0;
18574
+ prepared.set(variants[i], result.value);
18144
18575
  }
18145
18576
  return { state, groups, choices: prepared };
18146
18577
  }
@@ -18157,7 +18588,7 @@ var SectionModels = class {
18157
18588
  });
18158
18589
  await object4.init();
18159
18590
  let geometry = object4.children[0].geometry;
18160
- geometry.applyMatrix4(new import_three41.Matrix4().makeRotationFromEuler(rotation));
18591
+ geometry.applyMatrix4(new import_three42.Matrix4().makeRotationFromEuler(rotation));
18161
18592
  object4.clear();
18162
18593
  const keep = [];
18163
18594
  const cullFaces = [];
@@ -18173,7 +18604,7 @@ var SectionModels = class {
18173
18604
  cullFaces.push(0);
18174
18605
  continue;
18175
18606
  }
18176
- const normal = new import_three41.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
18607
+ const normal = new import_three42.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
18177
18608
  const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
18178
18609
  cullFaces.push(world < 0 ? 0 : 1 << world);
18179
18610
  }
@@ -18277,10 +18708,10 @@ function resolveSavedEntity(entity) {
18277
18708
 
18278
18709
  // src/world/_entities/WorldEntities.ts
18279
18710
  init_BannerPatterns();
18280
- var import_three44 = require("three");
18711
+ var import_three45 = require("three");
18281
18712
 
18282
18713
  // src/world/_picking/Picking.ts
18283
- var import_three42 = require("three");
18714
+ var import_three43 = require("three");
18284
18715
  init_three();
18285
18716
  function pickableMeshes(root, scene, raycaster) {
18286
18717
  const result = [];
@@ -18308,16 +18739,16 @@ function hitNormal(hit) {
18308
18739
  const mesh = hit.object;
18309
18740
  const matrix = mesh.matrixWorld.clone();
18310
18741
  if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
18311
- const instance = new import_three42.Matrix4();
18742
+ const instance = new import_three43.Matrix4();
18312
18743
  mesh.getMatrixAt(hit.instanceId, instance);
18313
18744
  matrix.multiply(instance);
18314
18745
  }
18315
- return hit.face.normal.clone().applyNormalMatrix(new import_three42.Matrix3().getNormalMatrix(matrix));
18746
+ return hit.face.normal.clone().applyNormalMatrix(new import_three43.Matrix3().getNormalMatrix(matrix));
18316
18747
  }
18317
18748
 
18318
18749
  // src/world/_entities/WorldEntities.ts
18319
18750
  init_log();
18320
- var log18 = logger("WorldEntities");
18751
+ var log19 = logger("WorldEntities");
18321
18752
  var WorldEntities = class {
18322
18753
  constructor(scene) {
18323
18754
  this.scene = scene;
@@ -18338,7 +18769,7 @@ var WorldEntities = class {
18338
18769
  const owner = owners.get(mesh);
18339
18770
  return {
18340
18771
  type: owner.type,
18341
- position: new import_three44.Vector3(...owner.position),
18772
+ position: new import_three45.Vector3(...owner.position),
18342
18773
  object: owner.object,
18343
18774
  point: hit.point.clone(),
18344
18775
  normal: hitNormal(hit),
@@ -18386,7 +18817,7 @@ var WorldEntities = class {
18386
18817
  placement.owner.set(object4, { type: key.toNamespacedString(), position: placement.position });
18387
18818
  this.scene.add(object4);
18388
18819
  } catch (error) {
18389
- log18.warn(`Could not draw saved entity ${placement.key.toNamespacedString()}, skipping it`, error);
18820
+ log19.warn(`Could not draw saved entity ${placement.key.toNamespacedString()}, skipping it`, error);
18390
18821
  } finally {
18391
18822
  if (object4 && !placement.owner.has(object4)) object4.dispose();
18392
18823
  }
@@ -18599,7 +19030,8 @@ function skipsBlockFace(data, rule, block, neighbor, face) {
18599
19030
 
18600
19031
  // src/world/MineRenderWorld.ts
18601
19032
  init_log();
18602
- var log19 = logger("MineRenderWorld");
19033
+ var log20 = logger("MineRenderWorld");
19034
+ var YIELD_INTERVAL_MS = 8;
18603
19035
  var MineRenderWorld = class {
18604
19036
  constructor(scene, options = {}) {
18605
19037
  this._chunks = /* @__PURE__ */ new Map();
@@ -18713,7 +19145,7 @@ var MineRenderWorld = class {
18713
19145
  failures.set(chunk, error);
18714
19146
  if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
18715
19147
  }
18716
- if (performance.now() - sliceStart > 8) {
19148
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
18717
19149
  await yieldToEventLoop();
18718
19150
  sliceStart = performance.now();
18719
19151
  }
@@ -18726,25 +19158,25 @@ var MineRenderWorld = class {
18726
19158
  }
18727
19159
  getBlockAt(posOrX, y, z) {
18728
19160
  if (typeof posOrX == "number") {
18729
- return this.getBlockAt(new import_three45.Vector3(posOrX, y, z));
19161
+ return this.getBlockAt(new import_three46.Vector3(posOrX, y, z));
18730
19162
  }
18731
19163
  if (isTripleArray(posOrX)) {
18732
- return this.getBlockAt(new import_three45.Vector3(posOrX[0], posOrX[1], posOrX[2]));
19164
+ return this.getBlockAt(new import_three46.Vector3(posOrX[0], posOrX[1], posOrX[2]));
18733
19165
  }
18734
19166
  this.validatePosBounds(posOrX);
18735
19167
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
18736
19168
  }
18737
19169
  getBiomeAt(posOrX, y, z) {
18738
- if (typeof posOrX === "number") return this.getBiomeAt(new import_three45.Vector3(posOrX, y, z));
18739
- if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three45.Vector3(...posOrX));
19170
+ if (typeof posOrX === "number") return this.getBiomeAt(new import_three46.Vector3(posOrX, y, z));
19171
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three46.Vector3(...posOrX));
18740
19172
  this.validatePosBounds(posOrX);
18741
19173
  const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
18742
19174
  const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
18743
19175
  return this.biomes.get(`${cx}_${cz}`)?.get(cy)?.[Math.floor(lx / 4) + Math.floor(lz / 4) * 4 + Math.floor(ly / 4) * 16];
18744
19176
  }
18745
19177
  getLightAt(posOrX, y, z) {
18746
- if (typeof posOrX === "number") return this.getLightAt(new import_three45.Vector3(posOrX, y, z));
18747
- if (isTripleArray(posOrX)) return this.getLightAt(new import_three45.Vector3(...posOrX));
19178
+ if (typeof posOrX === "number") return this.getLightAt(new import_three46.Vector3(posOrX, y, z));
19179
+ if (isTripleArray(posOrX)) return this.getLightAt(new import_three46.Vector3(...posOrX));
18748
19180
  this.validatePosBounds(posOrX);
18749
19181
  const { x, y: py, z: pz } = posOrX;
18750
19182
  const cx = Math.floor(x / 16), cy = Math.floor(py / 16), cz = Math.floor(pz / 16);
@@ -18762,10 +19194,10 @@ var MineRenderWorld = class {
18762
19194
  }
18763
19195
  async setBlockAt(posOrX, yOrBlock, z, block) {
18764
19196
  if (typeof posOrX == "number") {
18765
- return this.setBlockAt(new import_three45.Vector3(posOrX, yOrBlock, z), block);
19197
+ return this.setBlockAt(new import_three46.Vector3(posOrX, yOrBlock, z), block);
18766
19198
  }
18767
19199
  if (isTripleArray(posOrX)) {
18768
- return this.setBlockAt(new import_three45.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
19200
+ return this.setBlockAt(new import_three46.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
18769
19201
  }
18770
19202
  return this.placeBlock(posOrX, yOrBlock);
18771
19203
  }
@@ -18776,10 +19208,10 @@ var MineRenderWorld = class {
18776
19208
  }
18777
19209
  async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
18778
19210
  if (typeof posOrX === "number") {
18779
- return this.setBlockVisibleAt(new import_three45.Vector3(posOrX, yOrVisible, z), visible);
19211
+ return this.setBlockVisibleAt(new import_three46.Vector3(posOrX, yOrVisible, z), visible);
18780
19212
  }
18781
19213
  if (isTripleArray(posOrX)) {
18782
- return this.setBlockVisibleAt(new import_three45.Vector3(...posOrX), yOrVisible);
19214
+ return this.setBlockVisibleAt(new import_three46.Vector3(...posOrX), yOrVisible);
18783
19215
  }
18784
19216
  this.validatePosBounds(posOrX);
18785
19217
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
@@ -18805,7 +19237,7 @@ var MineRenderWorld = class {
18805
19237
  const collect = async (positions2) => {
18806
19238
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
18807
19239
  };
18808
- const place = (block) => this.placeBlock(new import_three45.Vector3(...block.position), block, collect);
19240
+ const place = (block) => this.placeBlock(new import_three46.Vector3(...block.position), block, collect);
18809
19241
  const keys = /* @__PURE__ */ new Map();
18810
19242
  const types = /* @__PURE__ */ new Set();
18811
19243
  for (const block of multiblock.blocks) {
@@ -18814,15 +19246,18 @@ var MineRenderWorld = class {
18814
19246
  const key = AssetKey.parse("blockstates", block.type);
18815
19247
  keys.set(key.serialize(), key);
18816
19248
  }
18817
- await BlockStates.getAll(keys.values());
19249
+ const loaded = await BlockStates.getAll(keys.values());
19250
+ const states = new Map([...keys.keys()].map((key, i) => [key, loaded[i]]));
18818
19251
  if (!useBatches) {
18819
19252
  for (const block of multiblock.blocks) await place(block);
18820
19253
  return;
18821
19254
  }
18822
19255
  if (!executor) {
18823
19256
  const groups2 = /* @__PURE__ */ new Map();
18824
- const position = new import_three45.Vector3();
19257
+ const distinct = /* @__PURE__ */ new Map();
19258
+ const position = new import_three46.Vector3();
18825
19259
  for (const block of multiblock.blocks) {
19260
+ if (this.sectionModels && !Chunk.isAir(block)) distinct.set(ChunkData.paletteKey(block), block);
18826
19261
  const [x, y, z] = block.position;
18827
19262
  this.validatePosBounds(position.set(x, y, z));
18828
19263
  const cx = Math.floor(x / 16), cy = Math.floor(y / 16), cz = Math.floor(z / 16);
@@ -18833,6 +19268,16 @@ var MineRenderWorld = class {
18833
19268
  if (!group) groups2.set(chunk, group = []);
18834
19269
  group.push({ index: (y - cy * 16) * 256 + (z - cz * 16) * 16 + x - cx * 16, block });
18835
19270
  }
19271
+ if (this.sectionModels) {
19272
+ for (const block of distinct.values()) {
19273
+ const state = states.get(AssetKey.parse("blockstates", block.type).serialize());
19274
+ if (!state) continue;
19275
+ void (async () => {
19276
+ if (state.key && BlockEntities.entry(await BlockEntities.getIndex(state.key.root), state.key.toNamespacedString())) return;
19277
+ await this.sectionModels.preload(state, block.properties);
19278
+ })().catch(() => void 0);
19279
+ }
19280
+ }
18836
19281
  await this.placeChunkGroups(groups2, changes);
18837
19282
  return;
18838
19283
  }
@@ -18861,14 +19306,14 @@ var MineRenderWorld = class {
18861
19306
  try {
18862
19307
  positions = await chunk.placeBlocks(blocks);
18863
19308
  } finally {
18864
- positions ?? (positions = blocks.map(({ index }) => new import_three45.Vector3(
19309
+ positions ?? (positions = blocks.map(({ index }) => new import_three46.Vector3(
18865
19310
  chunk.x * 16 + index % 16,
18866
19311
  chunk.y * 16 + Math.floor(index / 256),
18867
19312
  chunk.z * 16 + Math.floor(index / 16) % 16
18868
19313
  )));
18869
19314
  for (const pos of positions) changes.set(`${pos.x},${pos.y},${pos.z}`, pos);
18870
19315
  }
18871
- if (performance.now() - sliceStart > 8) {
19316
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
18872
19317
  await yieldToEventLoop();
18873
19318
  sliceStart = performance.now();
18874
19319
  }
@@ -18876,6 +19321,62 @@ var MineRenderWorld = class {
18876
19321
  }
18877
19322
  /** Replaces a chunk column's blocks, biomes, and saved light and, with `renderEntities`, its supported saved mobs. */
18878
19323
  async placeChunk(chunk, executor) {
19324
+ return this.placeColumn(chunk, executor);
19325
+ }
19326
+ /**
19327
+ * Replaces parsed columns in input order, then refreshes neighboring geometry once.
19328
+ * Duplicate coordinates retain their order. A failed column stops placement; queued refreshes finish before rejection.
19329
+ */
19330
+ async placeChunks(chunks) {
19331
+ const columns = [];
19332
+ for (const chunk of chunks) {
19333
+ const { x, z } = chunk ?? {};
19334
+ if (![x, z].every(Number.isSafeInteger)) {
19335
+ throw new RangeError("Chunk column coordinates must be safe integers");
19336
+ }
19337
+ const sections = Array.from(chunk.sections, (section) => {
19338
+ const { y } = section ?? {};
19339
+ if (!Number.isSafeInteger(y)) throw new RangeError("Chunk section coordinates must be safe integers");
19340
+ return { ...section, y };
19341
+ });
19342
+ columns.push({ ...chunk, x, z, sections });
19343
+ }
19344
+ if (!columns.length) return;
19345
+ await this.culling;
19346
+ let failed = false, failure, sliceStart = performance.now();
19347
+ try {
19348
+ for (const column of columns) {
19349
+ await this.placeColumn(column, void 0, true);
19350
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
19351
+ await yieldToEventLoop();
19352
+ sliceStart = performance.now();
19353
+ }
19354
+ }
19355
+ } catch (error) {
19356
+ failed = true;
19357
+ failure = error;
19358
+ } finally {
19359
+ try {
19360
+ const failures = await this.refreshBiomes(true);
19361
+ if (failures.size) log20.warn("Failed to refresh biome colors", failures.values().next().value);
19362
+ } catch (error) {
19363
+ if (!failed) {
19364
+ failed = true;
19365
+ failure = error;
19366
+ }
19367
+ }
19368
+ try {
19369
+ await this.updateCulling([]);
19370
+ } catch (error) {
19371
+ if (!failed) {
19372
+ failed = true;
19373
+ failure = error;
19374
+ }
19375
+ }
19376
+ }
19377
+ if (failed) throw failure;
19378
+ }
19379
+ async placeColumn(chunk, executor, deferCulling = false) {
18879
19380
  if (![chunk.x, chunk.z].every(Number.isSafeInteger)) {
18880
19381
  throw new RangeError("Chunk column coordinates must be safe integers");
18881
19382
  }
@@ -18913,7 +19414,7 @@ var MineRenderWorld = class {
18913
19414
  }
18914
19415
  for (const section of chunk.sections) {
18915
19416
  if (section.biomes) {
18916
- const position = new import_three45.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
19417
+ const position = new import_three46.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
18917
19418
  this.validatePosBounds(position);
18918
19419
  const copy = [...section.biomes];
18919
19420
  if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
@@ -18929,7 +19430,7 @@ var MineRenderWorld = class {
18929
19430
  for (const section of chunk.sections) {
18930
19431
  if (!executor) {
18931
19432
  if (!occupiedSections.has(section.y)) continue;
18932
- const position = new import_three45.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
19433
+ const position = new import_three46.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
18933
19434
  this.validatePosBounds(position);
18934
19435
  const target = this.getOrCreateChunkAt(position);
18935
19436
  try {
@@ -18937,7 +19438,7 @@ var MineRenderWorld = class {
18937
19438
  } finally {
18938
19439
  this.markSectionChanged(target);
18939
19440
  }
18940
- if (performance.now() - sliceStart > 8) {
19441
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
18941
19442
  await yieldToEventLoop();
18942
19443
  sliceStart = performance.now();
18943
19444
  }
@@ -18960,9 +19461,12 @@ var MineRenderWorld = class {
18960
19461
  await placeEntities?.();
18961
19462
  } finally {
18962
19463
  this.markBiomesChanged(chunk.x, chunk.z, void 0, false);
18963
- const failures = await this.refreshBiomes();
18964
- if (failures.size) log19.warn("Failed to refresh biome colors", failures.values().next().value);
18965
- await this.updateCulling([...changes.values()]);
19464
+ if (deferCulling) await this.updateCulling([...changes.values()], true);
19465
+ else {
19466
+ const failures = await this.refreshBiomes();
19467
+ if (failures.size) log20.warn("Failed to refresh biome colors", failures.values().next().value);
19468
+ await this.updateCulling([...changes.values()]);
19469
+ }
18966
19470
  }
18967
19471
  }
18968
19472
  /**
@@ -18992,14 +19496,14 @@ var MineRenderWorld = class {
18992
19496
  for (const { x, z } of columns.values()) {
18993
19497
  this.entities?.clearColumn(x, z);
18994
19498
  await this.clearChunkColumn(x, z);
18995
- if (performance.now() - sliceStart > 8) {
19499
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
18996
19500
  await yieldToEventLoop();
18997
19501
  sliceStart = performance.now();
18998
19502
  }
18999
19503
  }
19000
19504
  } finally {
19001
19505
  const failures = await this.refreshBiomes(true);
19002
- if (failures.size) log19.warn("Failed to refresh biome colors", failures.values().next().value);
19506
+ if (failures.size) log20.warn("Failed to refresh biome colors", failures.values().next().value);
19003
19507
  await this.updateCulling([]);
19004
19508
  }
19005
19509
  }
@@ -19062,7 +19566,7 @@ var MineRenderWorld = class {
19062
19566
  this.sectionModels?.clear();
19063
19567
  }
19064
19568
  updateCulling(positions, defer = false) {
19065
- const neighbor = new import_three45.Vector3();
19569
+ const neighbor = new import_three46.Vector3();
19066
19570
  for (const pos of positions) {
19067
19571
  const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
19068
19572
  const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
@@ -19131,15 +19635,25 @@ var MineRenderWorld = class {
19131
19635
  for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
19132
19636
  await chunk.refreshLight(indices === "all" ? void 0 : indices);
19133
19637
  chunk.refreshAmbientOcclusion(this._ambientOcclusion);
19134
- if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
19638
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
19135
19639
  await yieldToEventLoop();
19136
19640
  sliceStart = performance.now();
19137
19641
  }
19138
19642
  }
19139
- const builds = await Promise.allSettled([...batch.keys()].map(async (chunk) => {
19140
- await chunk.rebuildSectionMesh();
19141
- batch.delete(chunk);
19142
- }));
19643
+ const pending = [];
19644
+ for (const chunk of [...batch.keys()]) {
19645
+ const build = (async () => {
19646
+ await chunk.rebuildSectionMesh();
19647
+ batch.delete(chunk);
19648
+ })();
19649
+ void build.catch(() => void 0);
19650
+ pending.push(build);
19651
+ if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
19652
+ await yieldToEventLoop();
19653
+ sliceStart = performance.now();
19654
+ }
19655
+ }
19656
+ const builds = await Promise.allSettled(pending);
19143
19657
  const failure = builds.find((result) => result.status === "rejected");
19144
19658
  if (failure?.status === "rejected") throw failure.reason;
19145
19659
  } catch (error) {
@@ -19222,7 +19736,7 @@ var MineRenderWorld = class {
19222
19736
  }
19223
19737
  /** Converts block coordinates to scene units by multiplying each component by 16. */
19224
19738
  static worldToScenePosition(pos) {
19225
- return new import_three45.Vector3(
19739
+ return new import_three46.Vector3(
19226
19740
  pos.x * 16,
19227
19741
  pos.y * 16,
19228
19742
  pos.z * 16
@@ -19230,7 +19744,7 @@ var MineRenderWorld = class {
19230
19744
  }
19231
19745
  /** Converts scene units to block coordinates without rounding to an integer block. */
19232
19746
  static sceneToWorldPosition(pos) {
19233
- return new import_three45.Vector3(
19747
+ return new import_three46.Vector3(
19234
19748
  pos.x / 16,
19235
19749
  pos.y / 16,
19236
19750
  pos.z / 16
@@ -19254,7 +19768,7 @@ init_Model();
19254
19768
  init_BlockEntities();
19255
19769
 
19256
19770
  // src/world/SectionMesh.ts
19257
- var import_three46 = require("three");
19771
+ var import_three47 = require("three");
19258
19772
  init_CanvasCompat();
19259
19773
  init_Materials();
19260
19774
 
@@ -19531,6 +20045,8 @@ function sectionGeometryTransferables(pages) {
19531
20045
 
19532
20046
  // src/world/SectionWorker.ts
19533
20047
  init_Env();
20048
+ init_log();
20049
+ var log21 = logger("SectionWorker");
19534
20050
  var _SectionWorker = class _SectionWorker {
19535
20051
  constructor(worker) {
19536
20052
  this.worker = worker;
@@ -19544,8 +20060,12 @@ var _SectionWorker = class _SectionWorker {
19544
20060
  if (reply.type === "pages") pending.resolve(reply.pages);
19545
20061
  else pending.reject(new Error(reply.message));
19546
20062
  });
19547
- worker.addEventListener("error", (event) => this.fail(event.message || "Section worker failed"));
19548
- worker.addEventListener("messageerror", () => this.fail("Section worker message could not be deserialized"));
20063
+ const fallBack = (message) => {
20064
+ log21.warn(`${message}, so sections build on the main thread`);
20065
+ this.fail(message);
20066
+ };
20067
+ worker.addEventListener("error", (event) => fallBack(event.message || "Section worker failed"));
20068
+ worker.addEventListener("messageerror", () => fallBack("Section worker message could not be deserialized"));
19549
20069
  }
19550
20070
  /** The shared worker, or undefined when the environment has none or a previous worker failed. */
19551
20071
  static shared() {
@@ -19582,8 +20102,11 @@ _SectionWorker.initialized = false;
19582
20102
  var SectionWorker = _SectionWorker;
19583
20103
 
19584
20104
  // src/world/SectionMesh.ts
20105
+ var BLOCK_SIZE = 16;
20106
+ var QUAD_VERTICES = 4;
20107
+ var QUAD_INDICES = 6;
19585
20108
  var templateCache = /* @__PURE__ */ new WeakMap();
19586
- var WATER_TINT = new import_three46.Color(4159204).toArray();
20109
+ var WATER_TINT = new import_three47.Color(4159204).toArray();
19587
20110
  function toInput(entries, maxAtlasSize, fluids, lighting) {
19588
20111
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
19589
20112
  const atlases2 = [];
@@ -19618,8 +20141,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19618
20141
  if (!data) {
19619
20142
  const indices = template.geometry.getIndex();
19620
20143
  const position = template.geometry.getAttribute("position");
19621
- const quads = indices.count / 6;
19622
- if (indices.count % 6 !== 0 || position.count !== quads * 4) {
20144
+ const quads = indices.count / QUAD_INDICES;
20145
+ if (indices.count % QUAD_INDICES !== 0 || position.count !== quads * QUAD_VERTICES) {
19623
20146
  throw new RangeError("Section template geometry must hold four vertices and six indices per quad");
19624
20147
  }
19625
20148
  data = {
@@ -19629,8 +20152,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19629
20152
  uvs: new Float32Array(quads * 8),
19630
20153
  uvBounds: new Float32Array(quads * 16),
19631
20154
  colors: new Float32Array(quads * 12),
19632
- shade: new Float32Array(quads * 4),
19633
- indices: new Uint16Array(quads * 6),
20155
+ shade: new Float32Array(quads * QUAD_VERTICES),
20156
+ indices: new Uint16Array(quads * QUAD_INDICES),
19634
20157
  cullFaces: new Uint8Array(template.cullFaces),
19635
20158
  biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
19636
20159
  atlas: 0,
@@ -19642,7 +20165,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19642
20165
  const bounds = template.geometry.getAttribute("uvBounds");
19643
20166
  const color2 = template.geometry.getAttribute("color");
19644
20167
  const shade = template.geometry.getAttribute("shade");
19645
- for (let vertex = 0; vertex < quads * 4; vertex++) {
20168
+ for (let vertex = 0; vertex < quads * QUAD_VERTICES; vertex++) {
19646
20169
  data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
19647
20170
  data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
19648
20171
  data.uvs.set([uv.getX(vertex), uv.getY(vertex)], vertex * 2);
@@ -19655,7 +20178,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19655
20178
  data.colors.set([color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1], vertex * 3);
19656
20179
  data.shade[vertex] = shade?.getX(vertex) ?? 1;
19657
20180
  }
19658
- for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - 4 * Math.floor(i2 / 6);
20181
+ for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - QUAD_VERTICES * Math.floor(i2 / QUAD_INDICES);
19659
20182
  templateCache.set(template, data);
19660
20183
  }
19661
20184
  id = input.templateData.length;
@@ -19688,7 +20211,55 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
19688
20211
  }
19689
20212
  return { input, atlases: atlases2 };
19690
20213
  }
19691
- var SectionMesh = class _SectionMesh extends import_three46.Group {
20214
+ function sortTransparentQuads(mesh) {
20215
+ const index = mesh.geometry.getIndex();
20216
+ if (index.count <= QUAD_INDICES) return;
20217
+ index.setUsage(import_three47.DynamicDrawUsage);
20218
+ const count = index.count / QUAD_INDICES;
20219
+ let source, centers, depths, order;
20220
+ const view = new import_three47.Matrix4(), localCamera = new import_three47.Vector3(), key = new import_three47.Vector3(), previous = new import_three47.Vector3();
20221
+ let previousOrthographic;
20222
+ mesh.onBeforeRender = (_renderer, _scene, camera) => {
20223
+ localCamera.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(view.copy(mesh.matrixWorld).invert());
20224
+ const orthographic = !!camera.isOrthographicCamera;
20225
+ if (orthographic) {
20226
+ view.multiplyMatrices(camera.matrixWorldInverse, mesh.matrixWorld);
20227
+ key.set(view.elements[2], view.elements[6], view.elements[10]);
20228
+ } else {
20229
+ key.copy(localCamera).divideScalar(BLOCK_SIZE).floor();
20230
+ }
20231
+ if (orthographic === previousOrthographic && key.equals(previous)) return;
20232
+ previous.copy(key);
20233
+ previousOrthographic = orthographic;
20234
+ if (!centers) {
20235
+ source = new Uint32Array(index.array);
20236
+ centers = new Float32Array(count * 3);
20237
+ depths = new Float32Array(count);
20238
+ order = Uint32Array.from({ length: count }, (_, quad) => quad);
20239
+ const positions = mesh.geometry.getAttribute("position");
20240
+ for (let quad = 0; quad < count; quad++) {
20241
+ for (let axis = 0; axis < 3; axis++) {
20242
+ let center = 0;
20243
+ for (let corner = 0; corner < QUAD_VERTICES; corner++) center += positions.getComponent(quad * QUAD_VERTICES + corner, axis);
20244
+ centers[quad * 3 + axis] = center / QUAD_VERTICES;
20245
+ }
20246
+ }
20247
+ }
20248
+ for (let quad = 0; quad < count; quad++) {
20249
+ const x = centers[quad * 3], y = centers[quad * 3 + 1], z = centers[quad * 3 + 2];
20250
+ depths[quad] = orthographic ? key.x * x + key.y * y + key.z * z : -((x - localCamera.x) ** 2 + (y - localCamera.y) ** 2 + (z - localCamera.z) ** 2);
20251
+ }
20252
+ order.sort((a, b) => depths[a] - depths[b] || a - b);
20253
+ if (!order.some((quad, offset) => index.array[offset * QUAD_INDICES] !== source[quad * QUAD_INDICES])) return;
20254
+ for (let offset = 0; offset < count; offset++) {
20255
+ for (let indexOffset = 0; indexOffset < QUAD_INDICES; indexOffset++) {
20256
+ index.array[offset * QUAD_INDICES + indexOffset] = source[order[offset] * QUAD_INDICES + indexOffset];
20257
+ }
20258
+ }
20259
+ index.needsUpdate = true;
20260
+ };
20261
+ }
20262
+ var SectionMesh = class _SectionMesh extends import_three47.Group {
19692
20263
  constructor() {
19693
20264
  super(...arguments);
19694
20265
  this.ownedMeshes = [];
@@ -19697,7 +20268,11 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
19697
20268
  /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
19698
20269
  getBlockIndex(hit) {
19699
20270
  if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
19700
- return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
20271
+ const mesh = hit.object;
20272
+ const owners = this.blockIndices.get(mesh);
20273
+ if (!owners) return void 0;
20274
+ const vertex = mesh.geometry.getIndex().getX(hit.faceIndex * 3);
20275
+ return owners[Math.floor(vertex / QUAD_VERTICES)];
19701
20276
  }
19702
20277
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
19703
20278
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
@@ -19719,27 +20294,28 @@ var SectionMesh = class _SectionMesh extends import_three46.Group {
19719
20294
  for (const { atlas, x, y } of page.placements) {
19720
20295
  context.drawImage(atlases2[atlas].image.canvas, x, y);
19721
20296
  }
19722
- const geometry = new import_three46.BufferGeometry();
19723
- geometry.setAttribute("position", new import_three46.Float32BufferAttribute(page.positions.buffer, 3));
19724
- geometry.setAttribute("normal", new import_three46.Float32BufferAttribute(page.normals.buffer, 3));
19725
- geometry.setAttribute("uv", new import_three46.Float32BufferAttribute(page.uvs.buffer, 2));
19726
- geometry.setAttribute("uvBounds", new import_three46.Float32BufferAttribute(page.uvBounds.buffer, 4));
19727
- geometry.setAttribute("color", new import_three46.Float32BufferAttribute(page.colors.buffer, 3));
19728
- geometry.setAttribute("shade", new import_three46.Float32BufferAttribute(page.shade.buffer, 1));
19729
- geometry.setIndex(new import_three46.Uint32BufferAttribute(page.indices.buffer, 1));
20297
+ const geometry = new import_three47.BufferGeometry();
20298
+ geometry.setAttribute("position", new import_three47.Float32BufferAttribute(page.positions.buffer, 3));
20299
+ geometry.setAttribute("normal", new import_three47.Float32BufferAttribute(page.normals.buffer, 3));
20300
+ geometry.setAttribute("uv", new import_three47.Float32BufferAttribute(page.uvs.buffer, 2));
20301
+ geometry.setAttribute("uvBounds", new import_three47.Float32BufferAttribute(page.uvBounds.buffer, 4));
20302
+ geometry.setAttribute("color", new import_three47.Float32BufferAttribute(page.colors.buffer, 3));
20303
+ geometry.setAttribute("shade", new import_three47.Float32BufferAttribute(page.shade.buffer, 1));
20304
+ geometry.setIndex(new import_three47.Uint32BufferAttribute(page.indices.buffer, 1));
19730
20305
  geometry.computeBoundingBox();
19731
20306
  geometry.computeBoundingSphere();
19732
20307
  const transparent = page.layer === 2 ? atlases2[page.placements[0].atlas].hasTranslucency : page.layer === 1;
19733
20308
  const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
19734
- material.side = import_three46.FrontSide;
20309
+ material.side = import_three47.FrontSide;
19735
20310
  if (page.layer === 2) {
19736
- material.side = import_three46.DoubleSide;
19737
- material.forceSinglePass = true;
19738
20311
  material.depthWrite = !material.transparent;
20312
+ material.side = import_three47.DoubleSide;
20313
+ material.forceSinglePass = true;
19739
20314
  }
19740
20315
  material.vertexColors = true;
19741
20316
  const texture = material.uniforms?.map?.value ?? material.map;
19742
- const mesh = new import_three46.Mesh(geometry, material);
20317
+ const mesh = new import_three47.Mesh(geometry, material);
20318
+ if (transparent) sortTransparentQuads(mesh);
19743
20319
  section.add(mesh);
19744
20320
  section.blockIndices.set(mesh, page.blockIndices);
19745
20321
  const unsubscribe = [];
@@ -19780,7 +20356,7 @@ init_CubeFace();
19780
20356
  init_BlockTints();
19781
20357
  init_Biomes();
19782
20358
  init_InstanceReference();
19783
- var WATER_TINT2 = new import_three47.Color(4159204).toArray();
20359
+ var WATER_TINT2 = new import_three48.Color(4159204).toArray();
19784
20360
  var Chunk = class _Chunk {
19785
20361
  constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0, biomeBlend) {
19786
20362
  this.onBlocksChanged = onBlocksChanged;
@@ -19798,7 +20374,7 @@ var Chunk = class _Chunk {
19798
20374
  this.sectionBlocks = /* @__PURE__ */ new Map();
19799
20375
  this.hiddenBlocks = /* @__PURE__ */ new Set();
19800
20376
  this.fluidCells = new Uint8Array(4096);
19801
- this.blockPosition = new import_three47.Vector3();
20377
+ this.blockPosition = new import_three48.Vector3();
19802
20378
  this.meshDirty = false;
19803
20379
  this.meshGeneration = 0;
19804
20380
  this.blockChanges = /* @__PURE__ */ new Set();
@@ -19858,7 +20434,7 @@ var Chunk = class _Chunk {
19858
20434
  const info = owner.chunk.renderedBlocks.get(owner.index);
19859
20435
  if (!info) continue;
19860
20436
  return {
19861
- position: new import_three47.Vector3(
20437
+ position: new import_three48.Vector3(
19862
20438
  owner.chunk.x * 16 + owner.index % 16,
19863
20439
  owner.chunk.y * 16 + Math.floor(owner.index / 256),
19864
20440
  owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
@@ -19873,18 +20449,18 @@ var Chunk = class _Chunk {
19873
20449
  }
19874
20450
  getBlockAt(posOrX, y, z) {
19875
20451
  if (typeof posOrX == "number") {
19876
- return this.getBlockAt(new import_three47.Vector3(posOrX, y, z));
20452
+ return this.getBlockAt(new import_three48.Vector3(posOrX, y, z));
19877
20453
  }
19878
20454
  if (isTripleArray(posOrX)) {
19879
- return this.getBlockAt(new import_three47.Vector3(posOrX[0], posOrX[1], posOrX[2]));
20455
+ return this.getBlockAt(new import_three48.Vector3(posOrX[0], posOrX[1], posOrX[2]));
19880
20456
  }
19881
20457
  const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
19882
20458
  const index = _Chunk.chunkPosToBlockIndex(pos);
19883
20459
  return this.renderedBlocks.get(index);
19884
20460
  }
19885
20461
  getBiomeAt(posOrX, y, z) {
19886
- if (typeof posOrX === "number") return this.getBiomeAt(new import_three47.Vector3(posOrX, y, z));
19887
- if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three47.Vector3(...posOrX));
20462
+ if (typeof posOrX === "number") return this.getBiomeAt(new import_three48.Vector3(posOrX, y, z));
20463
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three48.Vector3(...posOrX));
19888
20464
  const pos = this.worldPosToChunkPos(posOrX);
19889
20465
  _Chunk.chunkPosToBlockIndex(pos);
19890
20466
  return this.biomeAt ? this.biomeAt(posOrX.x, posOrX.y, posOrX.z) : this.biomes?.[Math.floor(pos.x / 4) + Math.floor(pos.z / 4) * 4 + Math.floor(pos.y / 4) * 16];
@@ -19962,17 +20538,17 @@ var Chunk = class _Chunk {
19962
20538
  this.hiddenBlocks.add(index);
19963
20539
  this.renderedBlocks.get(index)?.object?.setVisible(false);
19964
20540
  }
19965
- const positions = blocks.map(({ index }) => new import_three47.Vector3(...this.positionAt(index)));
20541
+ const positions = blocks.map(({ index }) => new import_three48.Vector3(...this.positionAt(index)));
19966
20542
  if (this.onBlocksChanged) await this.onBlocksChanged(positions, deferCulling);
19967
20543
  else await this.rebuildSectionMesh();
19968
20544
  }
19969
20545
  }
19970
20546
  async setBlockAt(posOrX, yOrBlock, z, block) {
19971
20547
  if (typeof posOrX == "number") {
19972
- return this.setBlockAt(new import_three47.Vector3(posOrX, yOrBlock, z), block);
20548
+ return this.setBlockAt(new import_three48.Vector3(posOrX, yOrBlock, z), block);
19973
20549
  }
19974
20550
  if (isTripleArray(posOrX)) {
19975
- return this.setBlockAt(new import_three47.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
20551
+ return this.setBlockAt(new import_three48.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
19976
20552
  }
19977
20553
  const worldPos = posOrX;
19978
20554
  const pos = this.worldPosToChunkPos(worldPos);
@@ -20034,8 +20610,10 @@ var Chunk = class _Chunk {
20034
20610
  if (rejected?.status === "rejected") throw rejected.reason;
20035
20611
  }
20036
20612
  const positions = [];
20037
- let failed = false, failure;
20038
- for (const { index, key, block } of placements) {
20613
+ const jobs = /* @__PURE__ */ new Map();
20614
+ let failureOrder = Infinity, failure;
20615
+ for (const [order, { index, key, block }] of placements.entries()) {
20616
+ jobs.delete(index);
20039
20617
  this.hiddenBlocks.delete(index);
20040
20618
  this.data.assign(index, this.data.intern(block), block?.nbt);
20041
20619
  const readBlock = this.data.snapshot(index);
@@ -20045,13 +20623,12 @@ var Chunk = class _Chunk {
20045
20623
  this.fluidCells[index] = 0;
20046
20624
  this.renderedBlocks.delete(index);
20047
20625
  this.objectBlocks.delete(index);
20048
- const worldPos = new import_three47.Vector3(
20626
+ const worldPos = new import_three48.Vector3(
20049
20627
  this.x * 16 + index % 16,
20050
20628
  this.y * 16 + Math.floor(index / 256),
20051
20629
  this.z * 16 + Math.floor(index / 16) % 16
20052
20630
  );
20053
20631
  positions.push(worldPos);
20054
- let object4;
20055
20632
  try {
20056
20633
  if (!readBlock) continue;
20057
20634
  const resolved = resolutions.get(key);
@@ -20073,7 +20650,7 @@ var Chunk = class _Chunk {
20073
20650
  this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0, biomeTint: context?.tint })));
20074
20651
  this.meshDirty = true;
20075
20652
  } else {
20076
- object4 = await this.scene.addBlock(blockState3, {
20653
+ jobs.set(index, { order, readBlock, blockState: blockState3, position: MineRenderWorld.worldToScenePosition(worldPos), options: {
20077
20654
  mergeMeshes: true,
20078
20655
  instanceMeshes: true,
20079
20656
  maxInstanceCount: 2e3,
@@ -20081,13 +20658,12 @@ var Chunk = class _Chunk {
20081
20658
  variantPosition,
20082
20659
  biome: context?.biome,
20083
20660
  biomePosition: this.biomePosition(index, blockState3, stored)
20084
- });
20085
- object4.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
20661
+ } });
20662
+ continue;
20086
20663
  }
20087
20664
  this.renderedBlocks.set(index, { get block() {
20088
20665
  return readBlock();
20089
- }, object: object4 });
20090
- if (object4) this.objectBlocks.add(index);
20666
+ }, object: void 0 });
20091
20667
  } catch (error) {
20092
20668
  if (preserveDataOnFailure && readBlock) {
20093
20669
  this.renderedBlocks.set(index, { get block() {
@@ -20095,12 +20671,35 @@ var Chunk = class _Chunk {
20095
20671
  }, object: void 0 });
20096
20672
  } else this.data.assign(index, 0);
20097
20673
  this.fluidCells[index] = 0;
20098
- object4?.removeFromScene();
20099
- if (!failed) failure = error;
20100
- failed = true;
20674
+ if (order < failureOrder) {
20675
+ failureOrder = order;
20676
+ failure = error;
20677
+ }
20101
20678
  }
20102
20679
  }
20103
- if (failed) throw failure;
20680
+ const pending = [...jobs];
20681
+ const objects = await Promise.allSettled(pending.map(([, job]) => this.createBlockObject(job.blockState, job.position, job.options)));
20682
+ for (const [i, [index, { order, readBlock }]] of pending.entries()) {
20683
+ const result = objects[i];
20684
+ if (result.status === "fulfilled") {
20685
+ this.renderedBlocks.set(index, { get block() {
20686
+ return readBlock();
20687
+ }, object: result.value });
20688
+ this.objectBlocks.add(index);
20689
+ } else {
20690
+ if (preserveDataOnFailure) {
20691
+ this.renderedBlocks.set(index, { get block() {
20692
+ return readBlock();
20693
+ }, object: void 0 });
20694
+ } else this.data.assign(index, 0);
20695
+ this.fluidCells[index] = 0;
20696
+ if (order < failureOrder) {
20697
+ failureOrder = order;
20698
+ failure = result.reason;
20699
+ }
20700
+ }
20701
+ }
20702
+ if (failureOrder < Infinity) throw failure;
20104
20703
  return positions;
20105
20704
  }
20106
20705
  /** Replaces every cell from parsed section data. The caller refreshes neighbor culling. */
@@ -20171,37 +20770,42 @@ var Chunk = class _Chunk {
20171
20770
  failed = true;
20172
20771
  }
20173
20772
  }
20174
- for (const { index, blockState: blockState3, biome } of perBlocks) {
20175
- let object4;
20176
- try {
20177
- object4 = await this.scene.addBlock(blockState3, {
20178
- mergeMeshes: true,
20179
- instanceMeshes: true,
20180
- maxInstanceCount: 2e3,
20181
- initialState: this.data.stateAt(this.data.idAt(index)).properties,
20182
- variantPosition: this.positionAt(index),
20183
- biome,
20184
- biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
20185
- });
20186
- object4.setPosition(new import_three47.Vector3(
20187
- this.x * 256 + index % 16 * 16,
20188
- this.y * 256 + Math.floor(index / 256) * 16,
20189
- this.z * 256 + Math.floor(index / 16) % 16 * 16
20190
- ));
20191
- this.renderedBlocks.get(index).object = object4;
20773
+ const objects = await Promise.allSettled(perBlocks.map(({ index, blockState: blockState3, biome }) => this.createBlockObject(blockState3, new import_three48.Vector3(
20774
+ this.x * 256 + index % 16 * 16,
20775
+ this.y * 256 + Math.floor(index / 256) * 16,
20776
+ this.z * 256 + Math.floor(index / 16) % 16 * 16
20777
+ ), {
20778
+ mergeMeshes: true,
20779
+ instanceMeshes: true,
20780
+ maxInstanceCount: 2e3,
20781
+ initialState: this.data.stateAt(this.data.idAt(index)).properties,
20782
+ variantPosition: this.positionAt(index),
20783
+ biome,
20784
+ biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
20785
+ })));
20786
+ for (const [i, { index }] of perBlocks.entries()) {
20787
+ const result = objects[i];
20788
+ if (result.status === "fulfilled") {
20789
+ this.renderedBlocks.get(index).object = result.value;
20192
20790
  this.objectBlocks.add(index);
20193
- } catch (error) {
20791
+ } else {
20194
20792
  this.data.assign(index, 0);
20195
20793
  this.fluidCells[index] = 0;
20196
20794
  this.renderedBlocks.delete(index);
20197
20795
  this.objectBlocks.delete(index);
20198
- object4?.removeFromScene();
20199
- if (!failed) failure = error;
20796
+ if (!failed) failure = result.reason;
20200
20797
  failed = true;
20201
20798
  }
20202
20799
  }
20203
20800
  if (failed) throw failure;
20204
20801
  }
20802
+ createBlockObject(blockState3, position, options) {
20803
+ return this.scene.addSceneObject(blockState3, () => {
20804
+ const object4 = new BlockObject(blockState3, options);
20805
+ object4.position.copy(position);
20806
+ return object4;
20807
+ }, options);
20808
+ }
20205
20809
  positionAt(index) {
20206
20810
  return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
20207
20811
  }
@@ -20256,11 +20860,11 @@ var Chunk = class _Chunk {
20256
20860
  const context = {};
20257
20861
  if (source && prepared2?.biomeTint) {
20258
20862
  const color2 = await biomeColor(source);
20259
- if (color2 !== void 0) context.tint = new import_three47.Color(color2).toArray();
20863
+ if (color2 !== void 0) context.tint = new import_three48.Color(color2).toArray();
20260
20864
  }
20261
20865
  if (fluid?.kind === "water") {
20262
20866
  const color2 = await biomeColor("water");
20263
- if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three47.Color(color2).toArray();
20867
+ if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three48.Color(color2).toArray();
20264
20868
  }
20265
20869
  contexts.set(index, context);
20266
20870
  }));
@@ -20298,7 +20902,7 @@ var Chunk = class _Chunk {
20298
20902
  context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
20299
20903
  if (fluid?.kind === "water" && await available()) {
20300
20904
  const color2 = await Biomes.getColor(biome, "water", blockState3?.key);
20301
- if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three47.Color(color2).toArray();
20905
+ if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three48.Color(color2).toArray();
20302
20906
  }
20303
20907
  }
20304
20908
  for (const index of indices2) contexts.set(index, context);
@@ -20490,7 +21094,7 @@ var Chunk = class _Chunk {
20490
21094
  async clear(notify = true) {
20491
21095
  if (this.blockChanges.size) await Promise.allSettled(this.blockChanges);
20492
21096
  const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
20493
- new import_three47.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
21097
+ new import_three48.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
20494
21098
  )) : [];
20495
21099
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
20496
21100
  this.sectionBlocks.clear();
@@ -20526,14 +21130,14 @@ var Chunk = class _Chunk {
20526
21130
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
20527
21131
  }
20528
21132
  worldPosToChunkPos(pos) {
20529
- return new import_three47.Vector3(
21133
+ return new import_three48.Vector3(
20530
21134
  pos.x - this.x * 16,
20531
21135
  pos.y - this.y * 16,
20532
21136
  pos.z - this.z * 16
20533
21137
  );
20534
21138
  }
20535
21139
  chunkPosToWorldPos(pos) {
20536
- return new import_three47.Vector3(
21140
+ return new import_three48.Vector3(
20537
21141
  this.x * 16 + pos.x,
20538
21142
  this.y * 16 + pos.y,
20539
21143
  this.z * 16 + pos.z
@@ -20542,6 +21146,7 @@ var Chunk = class _Chunk {
20542
21146
  };
20543
21147
 
20544
21148
  // src/world/WorldStreamer.ts
21149
+ var MAX_PREFETCHED_COLUMNS = 4;
20545
21150
  var WorldStreamer = class {
20546
21151
  constructor(world, source, options = {}) {
20547
21152
  this.world = world;
@@ -20551,6 +21156,7 @@ var WorldStreamer = class {
20551
21156
  this.missing = /* @__PURE__ */ new Map();
20552
21157
  this.failed = /* @__PURE__ */ new Map();
20553
21158
  this.desired = [];
21159
+ this.reads = /* @__PURE__ */ new Map();
20554
21160
  this.disposed = false;
20555
21161
  this.loadRadius = options.loadRadius ?? 2;
20556
21162
  this.unloadRadius = options.unloadRadius ?? Math.min(32, this.loadRadius + 1);
@@ -20595,6 +21201,12 @@ var WorldStreamer = class {
20595
21201
  if (this.loading && !this.within(this.loading.position, this.loadRadius)) {
20596
21202
  this.loading.controller.abort();
20597
21203
  }
21204
+ for (const [key, read] of this.reads) {
21205
+ if (!this.within(read.position, this.loadRadius)) {
21206
+ read.controller.abort();
21207
+ if (read.ready) this.reads.delete(key);
21208
+ }
21209
+ }
20598
21210
  }
20599
21211
  return this.running ?? (this.running = Promise.resolve().then(() => this.drain()));
20600
21212
  }
@@ -20615,8 +21227,11 @@ var WorldStreamer = class {
20615
21227
  this.desired = [];
20616
21228
  this.center = void 0;
20617
21229
  this.loading?.controller.abort();
21230
+ for (const read of this.reads.values()) read.controller.abort();
20618
21231
  return this.disposal ?? (this.disposal = Promise.resolve().then(async () => {
20619
21232
  await this.running?.catch(() => void 0);
21233
+ await Promise.all([...this.reads.values()].map((read) => read.promise));
21234
+ this.reads.clear();
20620
21235
  try {
20621
21236
  await this.unloadMany([...this.owned.values()]);
20622
21237
  } finally {
@@ -20642,6 +21257,10 @@ var WorldStreamer = class {
20642
21257
  await this.unloadMany(obsolete);
20643
21258
  continue;
20644
21259
  }
21260
+ if (this.world.placeChunks) {
21261
+ if (await this.placeReadyChunks()) continue;
21262
+ return;
21263
+ }
20645
21264
  const position = this.desired.find((position2) => this.needsLoad(position2));
20646
21265
  if (!position) return;
20647
21266
  let chunk;
@@ -20664,26 +21283,105 @@ var WorldStreamer = class {
20664
21283
  continue;
20665
21284
  }
20666
21285
  this.owned.set(this.key(position), position);
21286
+ await this.placeOwnedColumns([position], () => this.world.placeChunk(chunk));
21287
+ }
21288
+ } finally {
21289
+ for (const [key, read] of this.reads) {
21290
+ read.controller.abort();
21291
+ if (read.ready) this.reads.delete(key);
21292
+ }
21293
+ this.running = void 0;
21294
+ }
21295
+ }
21296
+ fillReadSlots() {
21297
+ while (!this.disposed && this.reads.size < MAX_PREFETCHED_COLUMNS) {
21298
+ const position = this.desired.find((position2) => this.needsLoad(position2) && !this.reads.has(this.key(position2)));
21299
+ if (!position) return;
21300
+ const key = this.key(position);
21301
+ const read = {
21302
+ position,
21303
+ controller: new AbortController(),
21304
+ promise: Promise.resolve(),
21305
+ ready: false,
21306
+ failed: false
21307
+ };
21308
+ this.reads.set(key, read);
21309
+ read.promise = (async () => {
20667
21310
  try {
20668
- await this.world.placeChunk(chunk);
20669
- this.loaded.set(this.key(position), position);
21311
+ read.chunk = await this.source.getChunk(position.x, position.z, read.controller.signal);
21312
+ if (read.chunk) this.validateChunk(read.chunk, position);
20670
21313
  } catch (error) {
20671
- try {
20672
- await this.unloadMany([position]);
20673
- } catch (cleanupError) {
20674
- const failure = error instanceof Error ? error : new Error(String(error));
20675
- try {
20676
- Object.defineProperty(failure, "cause", { value: cleanupError, configurable: true });
20677
- } catch {
20678
- throw Object.assign(new Error(failure.message), { cause: cleanupError });
20679
- }
20680
- throw failure;
21314
+ read.failed = true;
21315
+ read.error = error;
21316
+ } finally {
21317
+ read.ready = true;
21318
+ if (read.controller.signal.aborted || this.disposed || !this.within(position, this.loadRadius)) {
21319
+ this.reads.delete(key);
20681
21320
  }
20682
- throw error;
21321
+ }
21322
+ })();
21323
+ }
21324
+ }
21325
+ /** Places only the ready prefix, so later source reads cannot delay the nearest ready column. */
21326
+ async placeReadyChunks() {
21327
+ this.fillReadSlots();
21328
+ const position = this.desired.find((position2) => this.needsLoad(position2));
21329
+ if (!position) {
21330
+ if (!this.reads.size) return false;
21331
+ await Promise.all([...this.reads.values()].map((read) => read.promise));
21332
+ return true;
21333
+ }
21334
+ const head = this.reads.get(this.key(position));
21335
+ if (!head) {
21336
+ for (let index = this.desired.length - 1; index >= 0; index--) {
21337
+ const key = this.key(this.desired[index]);
21338
+ if (this.reads.get(key)?.ready) {
21339
+ this.reads.delete(key);
21340
+ return true;
20683
21341
  }
20684
21342
  }
20685
- } finally {
20686
- this.running = void 0;
21343
+ await Promise.race([...this.reads.values()].map((read) => read.promise));
21344
+ return true;
21345
+ }
21346
+ if (!head.ready) {
21347
+ await head.promise;
21348
+ return true;
21349
+ }
21350
+ const chunks = [], positions = [];
21351
+ for (const desired of this.desired) {
21352
+ if (!this.needsLoad(desired)) continue;
21353
+ const key = this.key(desired), read = this.reads.get(key);
21354
+ if (!read?.ready) break;
21355
+ this.reads.delete(key);
21356
+ if (read.failed) this.failed.set(key, { ...desired, error: read.error });
21357
+ else if (!read.chunk) this.missing.set(key, desired);
21358
+ else {
21359
+ chunks.push(read.chunk);
21360
+ positions.push(desired);
21361
+ }
21362
+ }
21363
+ if (!chunks.length) return true;
21364
+ for (const position2 of positions) this.owned.set(this.key(position2), position2);
21365
+ await this.placeOwnedColumns(positions, () => this.world.placeChunks(chunks));
21366
+ return true;
21367
+ }
21368
+ async placeOwnedColumns(positions, place) {
21369
+ try {
21370
+ await place();
21371
+ for (const position of positions) this.loaded.set(this.key(position), position);
21372
+ } catch (error) {
21373
+ try {
21374
+ await this.unloadMany(positions);
21375
+ } catch (cleanupError) {
21376
+ const failure = error instanceof Error ? error : new Error(String(error));
21377
+ try {
21378
+ Object.defineProperty(failure, "cause", { value: cleanupError, configurable: true });
21379
+ } catch {
21380
+ throw Object.assign(new Error(failure.message), { cause: cleanupError });
21381
+ }
21382
+ throw failure;
21383
+ }
21384
+ throw error;
20687
21385
  }
20688
21386
  }
20689
21387
  needsLoad(position) {