minerender 2.1.0-alpha.3 → 2.1.0-alpha.30

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.
@@ -28,14 +28,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  mod
29
29
  ));
30
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
- var __decorateClass = (decorators, target, key, kind) => {
32
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
33
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
34
- if (decorator = decorators[i])
35
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
36
- if (kind && result) __defProp(target, key, result);
37
- return result;
38
- };
39
31
 
40
32
  // ../../node_modules/ts-deepmerge/dist/index.js
41
33
  var require_dist = __commonJS({
@@ -45,8 +37,8 @@ var require_dist = __commonJS({
45
37
  __assign = Object.assign || function(t) {
46
38
  for (var s, i = 1, n = arguments.length; i < n; i++) {
47
39
  s = arguments[i];
48
- for (var p13 in s) if (Object.prototype.hasOwnProperty.call(s, p13))
49
- t[p13] = s[p13];
40
+ for (var p12 in s) if (Object.prototype.hasOwnProperty.call(s, p12))
41
+ t[p12] = s[p12];
50
42
  }
51
43
  return t;
52
44
  };
@@ -90,7 +82,7 @@ var require_dist = __commonJS({
90
82
  return false;
91
83
  };
92
84
  var PROTECTED_KEYS = ["__proto__"];
93
- var merge11 = function() {
85
+ var merge10 = function() {
94
86
  var objects = [];
95
87
  for (var _i = 0; _i < arguments.length; _i++) {
96
88
  objects[_i] = arguments[_i];
@@ -101,9 +93,9 @@ var require_dist = __commonJS({
101
93
  return;
102
94
  }
103
95
  if (Array.isArray(result[key]) && Array.isArray(current[key])) {
104
- result[key] = merge11.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
96
+ result[key] = merge10.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
105
97
  } else if (isObject(result[key]) && isObject(current[key])) {
106
- result[key] = merge11(result[key], current[key]);
98
+ result[key] = merge10(result[key], current[key]);
107
99
  } else {
108
100
  result[key] = current[key];
109
101
  }
@@ -114,18 +106,18 @@ var require_dist = __commonJS({
114
106
  var defaultOptions = {
115
107
  mergeArrays: true
116
108
  };
117
- merge11.options = defaultOptions;
118
- merge11.withOptions = function(options) {
109
+ merge10.options = defaultOptions;
110
+ merge10.withOptions = function(options) {
119
111
  var objects = [];
120
112
  for (var _i = 1; _i < arguments.length; _i++) {
121
113
  objects[_i - 1] = arguments[_i];
122
114
  }
123
- merge11.options = __assign({ mergeArrays: true }, options);
124
- var result = merge11.apply(void 0, __spreadArray([], __read(objects), false));
125
- merge11.options = defaultOptions;
115
+ merge10.options = __assign({ mergeArrays: true }, options);
116
+ var result = merge10.apply(void 0, __spreadArray([], __read(objects), false));
117
+ merge10.options = defaultOptions;
126
118
  return result;
127
119
  };
128
- exports.default = merge11;
120
+ exports.default = merge10;
129
121
  }
130
122
  });
131
123
 
@@ -135,6 +127,7 @@ __export(index_browser_exports, {
135
127
  AXES: () => AXES,
136
128
  ArchiveAssetSource: () => ArchiveAssetSource,
137
129
  AssetKey: () => AssetKey,
130
+ AssetLoadError: () => AssetLoadError,
138
131
  AssetLoader: () => AssetLoader,
139
132
  AssetParser: () => AssetParser,
140
133
  AssetSource: () => AssetSource,
@@ -144,9 +137,9 @@ __export(index_browser_exports, {
144
137
  BUILTIN_GENERATED: () => BUILTIN_GENERATED,
145
138
  BasicAssetKey: () => BasicAssetKey,
146
139
  BatchedExecutor: () => BatchedExecutor,
147
- BlockEntityModels: () => BlockEntityModels,
148
140
  BlockObject: () => BlockObject,
149
141
  BlockStates: () => BlockStates,
142
+ BlockTints: () => BlockTints,
150
143
  BrowserArchiveProxy: () => BrowserArchiveProxy,
151
144
  BrowserCache: () => BrowserCache,
152
145
  BrowserEnv: () => BrowserEnv,
@@ -163,8 +156,8 @@ __export(index_browser_exports, {
163
156
  DISPLAY_POSITIONS: () => DISPLAY_POSITIONS,
164
157
  DefaultBlockStates: () => DefaultBlockStates,
165
158
  DisplayPosition: () => DisplayPosition,
159
+ DisplayTransforms: () => DisplayTransforms,
166
160
  Entities: () => Entities,
167
- EntityModels: () => EntityModels,
168
161
  EntityObject: () => EntityObject,
169
162
  Env: () => Env,
170
163
  Geometries: () => Geometries,
@@ -192,6 +185,7 @@ __export(index_browser_exports, {
192
185
  OrbitControls: () => OrbitControls,
193
186
  PersistentCache: () => PersistentCache,
194
187
  Renderer: () => Renderer,
188
+ RequestError: () => RequestError,
195
189
  Requests: () => Requests,
196
190
  SKIN_PARTS: () => SKIN_PARTS,
197
191
  SceneInspector: () => SceneInspector,
@@ -201,6 +195,7 @@ __export(index_browser_exports, {
201
195
  SchematicParser: () => SchematicParser,
202
196
  SkinObject: () => SkinObject,
203
197
  SkinPart: () => SkinPart,
198
+ SkinTextures: () => SkinTextures,
204
199
  Skins: () => Skins,
205
200
  StructureParser: () => StructureParser,
206
201
  TextureAtlas: () => TextureAtlas,
@@ -215,10 +210,10 @@ __export(index_browser_exports, {
215
210
  addWireframeToObject: () => addWireframeToObject,
216
211
  applyElementRotation: () => applyElementRotation,
217
212
  applyGenericRotation: () => applyGenericRotation,
218
- applyModelPartRotation: () => applyModelPartRotation,
219
213
  axisToVec3: () => axisToVec3,
220
214
  base64decode: () => base64decode,
221
215
  base64encode: () => base64encode,
216
+ capeTextureSizes: () => capeTextureSizes,
222
217
  captureException: () => captureException,
223
218
  changeEvent: () => changeEvent,
224
219
  clampRotationDegrees: () => clampRotationDegrees,
@@ -308,17 +303,20 @@ var _PersistentCache = class _PersistentCache {
308
303
  static open(name) {
309
304
  return Env.provider.openCache(name, _PersistentCache.VERSION);
310
305
  }
306
+ /** Loads a missing entry and stores only non-nullish results. */
311
307
  async getOrLoad(key, loader) {
312
308
  let v = await this.get(key);
313
309
  if (typeof v === "undefined" || v === null) {
314
310
  v = await loader(key);
315
- await this.put(key, v);
311
+ if (typeof v !== "undefined" && v !== null) {
312
+ await this.put(key, v);
313
+ }
316
314
  }
317
315
  return v;
318
316
  }
319
317
  };
320
318
  /** Bump to invalidate every persisted entry. */
321
- _PersistentCache.VERSION = 1;
319
+ _PersistentCache.VERSION = 2;
322
320
  var PersistentCache = _PersistentCache;
323
321
 
324
322
  // src/env/browser/BrowserCache.ts
@@ -419,7 +417,8 @@ var BrowserEnv = class {
419
417
  }
420
418
  openCache(name, version) {
421
419
  return new BrowserCache(import_localforage.default.createInstance({
422
- name,
420
+ // IndexedDB schema upgrades retain records; each cache generation needs its own database.
421
+ name: name + version,
423
422
  version
424
423
  }));
425
424
  }
@@ -436,7 +435,7 @@ registerBrowserEnv();
436
435
  // src/Axis.ts
437
436
  var import_three = require("three");
438
437
  var Axis = /* @__PURE__ */ ((Axis3) => {
439
- Axis3["X"] = "X";
438
+ Axis3["X"] = "x";
440
439
  Axis3["Y"] = "y";
441
440
  Axis3["Z"] = "z";
442
441
  return Axis3;
@@ -444,7 +443,7 @@ var Axis = /* @__PURE__ */ ((Axis3) => {
444
443
  var AXES = Object.values(Axis);
445
444
  function axisToVec3(axis) {
446
445
  switch (axis) {
447
- case "X" /* X */:
446
+ case "x" /* X */:
448
447
  return new import_three.Vector3(1, 0, 0);
449
448
  case "y" /* Y */:
450
449
  return new import_three.Vector3(0, 1, 0);
@@ -547,7 +546,10 @@ function serializeMeshKey(key) {
547
546
  // src/cache/Caching.ts
548
547
  var import_loading_cache = require("@inventivetalent/loading-cache");
549
548
  var import_time = require("@inventivetalent/time");
550
- var Caching = class {
549
+ var _Caching = class _Caching {
550
+ static createAssetCache() {
551
+ return import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
552
+ }
551
553
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
552
554
  static get all() {
553
555
  return [
@@ -564,7 +566,12 @@ var Caching = class {
564
566
  this.rawModelCache,
565
567
  this.mergedModelCache,
566
568
  this.modelTextureAtlasCache,
567
- this.blockStateCache
569
+ this.blockStateCache,
570
+ this.listAssetCache,
571
+ this.defaultBlockStatesCache,
572
+ this.blockTintCache,
573
+ this.entityModelCache,
574
+ this.entityTextureCache
568
575
  ];
569
576
  }
570
577
  static clear() {
@@ -575,8 +582,8 @@ var Caching = class {
575
582
  /**
576
583
  * Clears every cache and stops its expiry timer.
577
584
  *
578
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
579
- * this is called - see {@link shutdown}.
585
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
586
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
580
587
  */
581
588
  static end() {
582
589
  for (const cache of this.all) {
@@ -590,20 +597,26 @@ var Caching = class {
590
597
  };
591
598
  }
592
599
  };
593
- 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();
594
- 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();
595
- Caching.canvasImageDataCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
596
- Caching.wrappedImageCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
597
- Caching.boxGeometryCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(20)).build();
598
- Caching.textureCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
599
- Caching.materialCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
600
- Caching.boxMeshCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
601
- Caching.textureAssetCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
602
- Caching.textureMetaCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
603
- Caching.rawModelCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
604
- Caching.mergedModelCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
605
- Caching.modelTextureAtlasCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
606
- Caching.blockStateCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
600
+ _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();
601
+ _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();
602
+ _Caching.canvasImageDataCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
603
+ _Caching.wrappedImageCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
604
+ _Caching.boxGeometryCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(20)).build();
605
+ _Caching.textureCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
606
+ _Caching.materialCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
607
+ _Caching.boxMeshCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
608
+ _Caching.textureAssetCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
609
+ _Caching.textureMetaCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
610
+ _Caching.rawModelCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
611
+ _Caching.mergedModelCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
612
+ _Caching.modelTextureAtlasCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
613
+ _Caching.blockStateCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
614
+ _Caching.listAssetCache = _Caching.createAssetCache();
615
+ _Caching.defaultBlockStatesCache = _Caching.createAssetCache();
616
+ _Caching.blockTintCache = _Caching.createAssetCache();
617
+ _Caching.entityModelCache = _Caching.createAssetCache();
618
+ _Caching.entityTextureCache = _Caching.createAssetCache();
619
+ var Caching = _Caching;
607
620
 
608
621
  // src/Geometries.ts
609
622
  var Geometries = class _Geometries {
@@ -624,13 +637,14 @@ var Geometries = class _Geometries {
624
637
  };
625
638
 
626
639
  // src/Materials.ts
627
- var import_three6 = require("three");
640
+ var import_three5 = require("three");
628
641
 
629
642
  // src/texture/Textures.ts
630
- var import_three5 = require("three");
643
+ var import_three4 = require("three");
631
644
 
632
645
  // src/texture/TextureLoader.ts
633
- var import_three4 = require("three");
646
+ var import_three3 = require("three");
647
+ var THREE = __toESM(require("three"));
634
648
 
635
649
  // src/canvas/CanvasCompat.ts
636
650
  function createImage(width, height) {
@@ -641,9 +655,7 @@ function createCanvas(width, height) {
641
655
  }
642
656
 
643
657
  // src/request/Requests.ts
644
- var import_axios = __toESM(require("axios"));
645
658
  var import_jobqu = require("jobqu");
646
- var import_time2 = require("@inventivetalent/time");
647
659
 
648
660
  // src/util/log.ts
649
661
  var Reset = "\x1B[0m";
@@ -653,198 +665,170 @@ function prefix(prefix2) {
653
665
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
654
666
  }
655
667
 
656
- // src/util/BatchedExecutor.ts
657
- var BatchedExecutor = class {
658
- constructor(interval = 1, batch = 30) {
659
- this.interval = interval;
660
- this.batch = batch;
661
- this.queue = [];
662
- this.task = setInterval(() => this.run());
663
- }
664
- submit(task) {
665
- this.queue.push(task);
666
- }
667
- run() {
668
- for (let i = 0; i < this.batch; i++) {
669
- this.runNext();
670
- }
671
- }
672
- runNext() {
673
- let next = this.queue.shift();
674
- if (next) next();
668
+ // src/request/Requests.ts
669
+ var p = prefix("Requests");
670
+ var RequestError = class extends Error {
671
+ constructor(message, response, cause) {
672
+ super(message);
673
+ this.response = response;
674
+ this.cause = cause;
675
+ this.name = "RequestError";
675
676
  }
676
677
  };
677
-
678
- // src/util/model.ts
679
- var import_three3 = require("three");
680
- function applyElementRotation(rotation, geometry) {
681
- const origin = new import_three3.Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
682
- geometry.translate(-origin.x, -origin.y, -origin.z);
683
- switch (rotation.axis) {
684
- case "X" /* X */:
685
- geometry.rotateX(toRadians(rotation.angle));
686
- break;
687
- case "y" /* Y */:
688
- geometry.rotateY(toRadians(rotation.angle));
689
- break;
690
- case "z" /* Z */:
691
- geometry.rotateZ(toRadians(rotation.angle));
692
- break;
693
- }
694
- if (rotation.rescale) {
695
- if (Math.abs(rotation.angle) === 22.5) {
696
- const s = 1 / Math.cos(0.39269909262657166);
697
- geometry.scale(s, 1, s);
698
- } else {
699
- const s = 1 / Math.cos(0.7853981852531433);
700
- geometry.scale(s, 1, s);
678
+ async function fetchRequest(config, defaultBaseURL) {
679
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
680
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
681
+ const headers = new Headers(options.headers);
682
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
683
+ headers.set("User-Agent", "MineRender");
684
+ }
685
+ const attemptSignal = AbortSignal.any([
686
+ ...signal ? [signal] : [],
687
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
688
+ ]);
689
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
690
+ attemptSignal.throwIfAborted();
691
+ try {
692
+ const response = await fetch(request);
693
+ const result = {
694
+ data: void 0,
695
+ status: response.status,
696
+ statusText: response.statusText,
697
+ headers: response.headers,
698
+ url: response.url
699
+ };
700
+ if (!response.ok) {
701
+ await response.body?.cancel().catch(() => {
702
+ });
703
+ throw new RequestError(`Request failed with status ${response.status}`, result);
701
704
  }
705
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
706
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
707
+ return { ...result, data };
708
+ } catch (error) {
709
+ attemptSignal.throwIfAborted();
710
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
711
+ throw new RequestError("Network request failed", void 0, error);
712
+ }
713
+ throw error;
702
714
  }
703
- geometry.translate(origin.x, origin.y, origin.z);
704
- }
705
- function applyModelPartRotation(modelPart, geometry) {
706
- const origin = new import_three3.Vector3(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
707
- geometry.translate(-origin.x, -origin.y, -origin.z);
708
- geometry.rotateX(toRadians(modelPart.pitch));
709
- geometry.rotateY(toRadians(modelPart.yaw));
710
- geometry.rotateZ(toRadians(modelPart.roll));
711
- geometry.translate(origin.x, origin.y, origin.z);
712
715
  }
713
- function applyGenericRotation(axis, rotation, obj) {
714
- switch (axis) {
715
- case "X" /* X */:
716
- obj.rotateOnAxis(new import_three3.Vector3(1, 0, 0), toRadians(rotation));
717
- break;
718
- case "y" /* Y */:
719
- obj.rotateOnAxis(new import_three3.Vector3(0, 1, 0), toRadians(rotation));
720
- break;
721
- case "z" /* Z */:
722
- obj.rotateOnAxis(new import_three3.Vector3(0, 0, 1), toRadians(rotation));
723
- break;
716
+ async function abortable(promise, signal) {
717
+ if (!signal) return promise;
718
+ let abort;
719
+ const cancelled = new Promise((_, reject) => {
720
+ abort = () => reject(signal.reason);
721
+ signal.addEventListener("abort", abort, { once: true });
722
+ if (signal.aborted) abort();
723
+ });
724
+ try {
725
+ return await Promise.race([promise, cancelled]);
726
+ } finally {
727
+ signal.removeEventListener("abort", abort);
724
728
  }
725
729
  }
726
- function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
727
- let size = new import_three3.Vector3();
728
- box.getSize(size);
729
- let boxGeo = new import_three3.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
730
- let wireGeo = new import_three3.EdgesGeometry(boxGeo);
731
- let wireMat = new import_three3.LineBasicMaterial({ color, linewidth: w });
732
- let wireframe = new import_three3.LineSegments(wireGeo, wireMat);
733
- obj.add(wireframe);
734
- let axes = new import_three3.AxesHelper(1);
735
- obj.add(axes);
736
- }
737
- function addWireframeToObject(obj, color = 16777215, w = 2) {
738
- let boxGeo = new import_three3.BoxGeometry(16, 16, 16, 1, 1, 1);
739
- let wireGeo = new import_three3.EdgesGeometry(boxGeo);
740
- let wireMat = new import_three3.LineBasicMaterial({ color, linewidth: w });
741
- let wireframe = new import_three3.LineSegments(wireGeo, wireMat);
742
- obj.add(wireframe);
743
- let axes = new import_three3.AxesHelper(1);
744
- obj.add(axes);
745
- }
746
- function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
747
- let wireGeo = new import_three3.EdgesGeometry(geo);
748
- let wireMat = new import_three3.LineBasicMaterial({ color, linewidth: w });
749
- let wireframe = new import_three3.LineSegments(wireGeo, wireMat);
750
- mesh.add(wireframe);
751
- let axes = new import_three3.AxesHelper(1);
752
- mesh.add(axes);
753
- }
754
-
755
- // src/util/performance.ts
756
- function captureException(e, ...extra) {
757
- console.error(e, extra);
758
- }
759
- function timingStart(marker) {
760
- console.time(marker);
761
- }
762
- function timingEnd(marker) {
763
- console.timeEnd(marker);
764
- }
765
-
766
- // src/util/three.ts
767
- function isObject3D(obj) {
768
- return obj.isObject3D;
769
- }
770
- function isMesh(obj) {
771
- return obj.isMesh;
772
- }
773
- function isInstancedMesh(obj) {
774
- return obj.isInstancedMesh;
775
- }
776
- function isPerspectiveCamera(obj) {
777
- return obj.isPerspectiveCamera;
778
- }
779
- function isOrthographicCamera(obj) {
780
- return obj.isOrthographicCamera;
781
- }
782
-
783
- // src/request/Requests.ts
784
- var p = prefix("Requests");
785
- if (typeof window === "undefined") {
786
- import_axios.default.defaults.headers["User-Agent"] = "MineRender";
787
- }
788
- var _Requests = class _Requests {
789
- static genericRequest(request) {
790
- return this.genericQueue.add(request).catch(async (e) => {
791
- console.debug(p, "generic catch", e.code, e);
792
- if (this.shouldRetry(e, request)) {
793
- await sleep(100);
794
- return this.genericRequest(request);
795
- }
796
- throw e;
797
- });
798
- }
799
- static mcAssetRequest(request) {
800
- return this.mcAssetRequestQueue.add(request).catch((e) => {
801
- console.debug(p, "mcAssetRequest catch", e.code, e);
802
- throw e;
803
- });
730
+ var RequestQueue = class {
731
+ constructor() {
732
+ this.pendingRequests = 0;
733
+ this.stopped = new AbortController();
734
+ this.queue = new import_jobqu.JobQueue(
735
+ (request) => fetchRequest(request, this.baseURL),
736
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
737
+ );
804
738
  }
805
- static shouldRetry(e, request) {
806
- if ("code" in e) {
807
- if ("ECONNABORTED" === e.code) {
808
- if ("minerenderRetry" in request) {
809
- if (request["minerenderRetry"] > 0) {
810
- request["minerenderRetry"]--;
811
- return true;
739
+ async request(request) {
740
+ this.pendingRequests++;
741
+ const signal = request.signal;
742
+ try {
743
+ for (let retries = 0; ; retries++) {
744
+ signal?.throwIfAborted();
745
+ try {
746
+ return await abortable(this.queue.add(request), signal);
747
+ } catch (error) {
748
+ console.debug(p, "Request failed", error);
749
+ const delay = this.retryDelay(error, request, retries);
750
+ if (delay === void 0) {
751
+ throw error;
812
752
  }
813
- } else {
814
- request["minerenderRetry"] = 3;
815
- return true;
753
+ await this.waitForRetry(delay, signal);
816
754
  }
817
755
  }
756
+ } finally {
757
+ if (signal?.aborted) {
758
+ this.queue.remove(request);
759
+ }
760
+ this.pendingRequests--;
818
761
  }
819
- return false;
762
+ }
763
+ retryDelay(error, request, retries) {
764
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
765
+ return void 0;
766
+ }
767
+ if (error instanceof RequestError) {
768
+ const status = error.response?.status;
769
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
770
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
771
+ return void 0;
772
+ }
773
+ let delay = 100 * 2 ** retries;
774
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
775
+ if (retryAfter !== void 0 && retryAfter !== null) {
776
+ const seconds = Number(retryAfter);
777
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
778
+ return void 0;
779
+ }
780
+ delay = Math.max(delay, seconds * 1e3);
781
+ }
782
+ return delay;
783
+ }
784
+ async waitForRetry(delay, signal) {
785
+ let timer;
786
+ const waiting = new Promise((resolve) => {
787
+ timer = setTimeout(resolve, delay);
788
+ });
789
+ try {
790
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
791
+ } finally {
792
+ clearTimeout(timer);
793
+ }
794
+ }
795
+ get pendingSize() {
796
+ return this.pendingRequests;
797
+ }
798
+ end() {
799
+ this.queue.end();
800
+ this.stopped.abort(new import_jobqu.JobCancelledError("ended"));
801
+ }
802
+ };
803
+ var Requests = class {
804
+ static genericRequest(request) {
805
+ return this.genericQueue.request(request);
806
+ }
807
+ static mcAssetRequest(request) {
808
+ return this.mcAssetRequestQueue.request(request);
820
809
  }
821
810
  static setMcAssetRoot(root) {
822
- this.mcAssetInstance.defaults.baseURL = root;
811
+ this.mcAssetRequestQueue.baseURL = root;
823
812
  }
813
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
824
814
  static get queueSizes() {
825
815
  return {
826
- generic: this.genericQueue.size,
827
- mcAsset: this.mcAssetRequestQueue.size
816
+ generic: this.genericQueue.pendingSize,
817
+ mcAsset: this.mcAssetRequestQueue.pendingSize
828
818
  };
829
819
  }
830
820
  /**
831
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
832
- * exit until this is called - see {@link shutdown}.
821
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
822
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
823
+ * this cleanup. See {@link shutdown}.
833
824
  */
834
825
  static end() {
835
826
  this.genericQueue.end();
836
827
  this.mcAssetRequestQueue.end();
837
828
  }
838
829
  };
839
- _Requests.axiosInstance = import_axios.default.create({
840
- timeout: 5e3
841
- });
842
- _Requests.mcAssetInstance = import_axios.default.create({
843
- timeout: 5e3
844
- });
845
- _Requests.genericQueue = new import_jobqu.JobQueue((request) => _Requests.axiosInstance.request(request), import_time2.Time.millis(10), 1);
846
- _Requests.mcAssetRequestQueue = new import_jobqu.JobQueue((request) => _Requests.mcAssetInstance.request(request), import_time2.Time.millis(10), 1);
847
- var Requests = _Requests;
830
+ Requests.genericQueue = new RequestQueue();
831
+ Requests.mcAssetRequestQueue = new RequestQueue();
848
832
 
849
833
  // src/WrappedImage.ts
850
834
  var WrappedImage = class {
@@ -882,10 +866,10 @@ var WrappedImage = class {
882
866
  return this.animated ? this.width : this.height;
883
867
  }
884
868
  get frameCount() {
885
- return this.height / this.width;
869
+ return this.height / this.frameHeight;
886
870
  }
887
871
  getFrameY(frame) {
888
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
872
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
889
873
  }
890
874
  getSectionData(sx, sy, sw, sh) {
891
875
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -895,7 +879,7 @@ var WrappedImage = class {
895
879
  }
896
880
  getFrameSectionData(frame) {
897
881
  const y = this.getFrameY(frame);
898
- return this.getSectionData(0, y, this.width, this.width + y);
882
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
899
883
  }
900
884
  };
901
885
 
@@ -909,29 +893,41 @@ var ImageLoader = class _ImageLoader {
909
893
  static async loadAsync(src) {
910
894
  return new Promise((resolve, reject) => {
911
895
  const image = this._createImage();
912
- image.src = src;
913
896
  image.onload = () => resolve(image);
914
- image.onerror = (err) => reject(err);
897
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
898
+ image.src = src;
915
899
  });
916
900
  }
917
901
  static loadElement(src, onload, onerr) {
918
902
  const image = this._createImage();
919
- image.src = src;
920
903
  if (onload)
921
904
  image.onload = onload;
922
905
  if (onerr)
923
906
  image.onerror = onerr;
907
+ image.src = src;
924
908
  return image;
925
909
  }
926
910
  static async loadData(src) {
927
911
  console.debug(p2, "loadData", src);
928
- return await this.infoToData(await this.getInfo(src));
912
+ const image = await this.loadCanvasData(src);
913
+ return image.data.getImageData(0, 0, image.width, image.height);
929
914
  }
930
915
  static async loadCanvasData(src) {
931
- return await this.infoToCanvasData(await this.getInfo(src));
916
+ const keyStr = serializeImageKey({ src });
917
+ const info = this.getInfo(src);
918
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
919
+ try {
920
+ return await this.infoToCanvasData(await info);
921
+ } catch (err) {
922
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
923
+ Caching.rawImageCache.invalidate(keyStr);
924
+ }
925
+ throw err;
926
+ }
932
927
  }
933
928
  static async infoToCanvasData(info) {
934
- const image = await _ImageLoader.loadAsync(info.src);
929
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
930
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
935
931
  const canvas = createCanvas(info.width, info.height);
936
932
  const context = canvas.getContext("2d");
937
933
  context.drawImage(image, 0, 0);
@@ -942,11 +938,8 @@ var ImageLoader = class _ImageLoader {
942
938
  };
943
939
  }
944
940
  static async infoToData(info) {
945
- const image = await _ImageLoader.loadAsync(info.src);
946
- const canvas = createCanvas(info.width, info.height);
947
- const context = canvas.getContext("2d");
948
- context.drawImage(image, 0, 0);
949
- return context.getImageData(0, 0, canvas.width, canvas.height);
941
+ const image = await this.infoToCanvasData(info);
942
+ return image.data.getImageData(0, 0, image.width, image.height);
950
943
  }
951
944
  static async getData(src) {
952
945
  const keyStr = serializeImageKey({ src });
@@ -961,38 +954,25 @@ var ImageLoader = class _ImageLoader {
961
954
  });
962
955
  }
963
956
  static async processResponse(response) {
964
- const src = response.config.url;
957
+ const src = response.url;
965
958
  const data = import_buffer.Buffer.from(response.data);
966
959
  const { width, height, type } = Env.provider.imageSize(data);
960
+ if (!width || !height) {
961
+ throw new Error("Invalid or unsupported image dimensions");
962
+ }
967
963
  return {
968
964
  src,
969
- width: width || 0,
970
- height: height || 0,
965
+ width,
966
+ height,
971
967
  type,
972
968
  data
973
969
  };
974
970
  }
975
971
  static async loadInfo(src) {
976
- if (src.startsWith("data:image/png;base64")) {
977
- return this.processResponse({
978
- config: {
979
- url: src
980
- },
981
- data: import_buffer.Buffer.from(src.substr("data:image/png;base64,".length), "base64")
982
- });
983
- }
984
972
  return Requests.genericRequest({
985
973
  url: src,
986
974
  responseType: "arraybuffer"
987
- }).then(this.processResponse).catch((err) => {
988
- return {
989
- src,
990
- width: 0,
991
- height: 0,
992
- type: void 0,
993
- data: import_buffer.Buffer.from([0])
994
- };
995
- });
975
+ }).then(this.processResponse);
996
976
  }
997
977
  static async getInfo(src) {
998
978
  const keyStr = serializeImageKey({ src });
@@ -1014,38 +994,50 @@ var ImageLoader = class _ImageLoader {
1014
994
 
1015
995
  // src/texture/TextureLoader.ts
1016
996
  var TextureLoader = class {
997
+ /** Reports whether image loading failed, so cached textures can be retried. */
998
+ static hasFailed(texture) {
999
+ return this.failedTextures.has(texture);
1000
+ }
1017
1001
  static createTexture() {
1018
- return new import_three4.Texture();
1002
+ return new import_three3.Texture();
1019
1003
  }
1020
- static loadInBackground(src, format = import_three4.RGBAFormat, rotation = 0) {
1004
+ static loadInBackground(src, format = import_three3.RGBAFormat, rotation = 0) {
1021
1005
  const texture = this.createTexture();
1022
- const image = ImageLoader.loadElement(src);
1023
- image.onload = function() {
1006
+ texture.colorSpace = THREE.SRGBColorSpace;
1007
+ const image = ImageLoader.loadElement(src, () => {
1024
1008
  texture.needsUpdate = true;
1025
- };
1009
+ }, (error) => {
1010
+ this.failedTextures.add(texture);
1011
+ console.warn("Failed to load texture", src, error);
1012
+ });
1026
1013
  texture.image = image;
1027
1014
  texture.format = format;
1028
1015
  texture.rotation = rotation;
1029
1016
  return Textures.initTextureProps(texture);
1030
1017
  }
1031
- static load(src, format = import_three4.RGBAFormat, rotation = 0) {
1032
- const texture = new import_three4.Texture();
1018
+ static load(src, format = import_three3.RGBAFormat, rotation = 0) {
1019
+ const texture = new import_three3.Texture();
1020
+ texture.colorSpace = THREE.SRGBColorSpace;
1033
1021
  ImageLoader.getData(src).then((image) => {
1034
- texture.needsUpdate = true;
1035
1022
  texture.image = image;
1023
+ texture.needsUpdate = true;
1024
+ }).catch((error) => {
1025
+ this.failedTextures.add(texture);
1026
+ console.warn("Failed to load texture", src, error);
1036
1027
  });
1037
1028
  texture.format = format;
1038
1029
  texture.rotation = rotation;
1039
1030
  return Textures.initTextureProps(texture);
1040
1031
  }
1041
1032
  };
1033
+ TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
1042
1034
 
1043
1035
  // src/texture/Textures.ts
1044
- var THREE = __toESM(require("three"));
1036
+ var THREE2 = __toESM(require("three"));
1045
1037
  var Textures = class _Textures {
1046
1038
  static initTextureProps(texture) {
1047
- texture.magFilter = THREE.NearestFilter;
1048
- texture.minFilter = THREE.NearestFilter;
1039
+ texture.magFilter = THREE2.NearestFilter;
1040
+ texture.minFilter = THREE2.NearestFilter;
1049
1041
  texture.anisotropy = 0;
1050
1042
  return texture;
1051
1043
  }
@@ -1053,13 +1045,19 @@ var Textures = class _Textures {
1053
1045
  return TextureLoader.load(key.src, key.format, key.rotation);
1054
1046
  }
1055
1047
  static createAsset(key) {
1056
- return new import_three5.Texture();
1048
+ return new import_three4.Texture();
1057
1049
  }
1058
1050
  static createCanvasTexture(canvas) {
1059
- return this.initTextureProps(new import_three5.CanvasTexture(canvas));
1051
+ const texture = new import_three4.CanvasTexture(canvas);
1052
+ texture.colorSpace = THREE2.SRGBColorSpace;
1053
+ return this.initTextureProps(texture);
1060
1054
  }
1061
1055
  static getImage(key) {
1062
1056
  const keyStr = serializeTextureKey(key);
1057
+ const cached = Caching.textureCache.peek(keyStr);
1058
+ if (cached && TextureLoader.hasFailed(cached)) {
1059
+ Caching.textureCache.invalidate(keyStr);
1060
+ }
1063
1061
  return Caching.textureCache.get(keyStr, (k) => {
1064
1062
  return _Textures.createImage(key);
1065
1063
  });
@@ -1075,26 +1073,26 @@ var _Materials = class _Materials {
1075
1073
  }
1076
1074
  static createImage(key) {
1077
1075
  const transparent = key.transparent || false;
1078
- return new import_three6.MeshBasicMaterial({
1076
+ return new import_three5.MeshBasicMaterial({
1079
1077
  map: Textures.getImage(key.texture),
1080
1078
  transparent,
1081
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1079
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1082
1080
  alphaTest: 0.5
1083
1081
  });
1084
1082
  }
1085
1083
  static createBasicCanvasMaterial(canvas, transparent = false, shade = false) {
1086
1084
  if (shade) {
1087
- return new import_three6.MeshStandardMaterial({
1085
+ return new import_three5.MeshStandardMaterial({
1088
1086
  map: Textures.createCanvasTexture(canvas),
1089
1087
  transparent,
1090
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1088
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1091
1089
  alphaTest: 0.5
1092
1090
  });
1093
1091
  }
1094
- return new import_three6.MeshBasicMaterial({
1092
+ return new import_three5.MeshBasicMaterial({
1095
1093
  map: Textures.createCanvasTexture(canvas),
1096
1094
  transparent,
1097
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1095
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1098
1096
  alphaTest: 0.5
1099
1097
  });
1100
1098
  }
@@ -1103,6 +1101,7 @@ var _Materials = class _Materials {
1103
1101
  uniform bool SHADE;
1104
1102
 
1105
1103
  varying vec2 vUv;
1104
+ varying vec3 vTint;
1106
1105
  varying float light;
1107
1106
  varying float lift;
1108
1107
 
@@ -1115,7 +1114,11 @@ var _Materials = class _Materials {
1115
1114
 
1116
1115
  if (SHADE) {
1117
1116
 
1118
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1117
+ #ifdef USE_INSTANCING
1118
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1119
+ #else
1120
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
1121
+ #endif
1119
1122
 
1120
1123
  float yLight = (1.0+N.y) * 0.5;
1121
1124
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -1133,6 +1136,7 @@ var _Materials = class _Materials {
1133
1136
  }
1134
1137
 
1135
1138
  vUv = uv;
1139
+ vTint = color;
1136
1140
 
1137
1141
  #ifdef USE_INSTANCING
1138
1142
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -1154,12 +1158,14 @@ var _Materials = class _Materials {
1154
1158
  uniform float BRIGHTNESS;
1155
1159
 
1156
1160
  varying vec2 vUv;
1161
+ varying vec3 vTint;
1157
1162
  varying float light;
1158
1163
  varying float lift;
1159
1164
 
1160
1165
  void main(void)
1161
1166
  {
1162
1167
  vec4 color = texture2D(map, vUv);
1168
+ color.rgb *= vTint;
1163
1169
 
1164
1170
  if (color.a < 0.01) discard;
1165
1171
 
@@ -1173,16 +1179,19 @@ var _Materials = class _Materials {
1173
1179
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1174
1180
 
1175
1181
  }
1182
+
1183
+ #include <tonemapping_fragment>
1184
+ #include <colorspace_fragment>
1176
1185
  }
1177
1186
  `;
1178
1187
  try {
1179
- return new import_three6.ShaderMaterial({
1188
+ return new import_three5.ShaderMaterial({
1180
1189
  uniforms: {
1181
1190
  SHADE: { value: true },
1182
1191
  BRIGHTNESS: { value: 1 },
1183
1192
  EMISSIVE: { value: false },
1184
1193
  base: {
1185
- value: new import_three6.Color(12698049)
1194
+ value: new import_three5.Color(12698049)
1186
1195
  /*TODO*/
1187
1196
  },
1188
1197
  map: { value: Textures.createCanvasTexture(canvas) }
@@ -1191,7 +1200,7 @@ var _Materials = class _Materials {
1191
1200
  fragmentShader: fragShader,
1192
1201
  vertexColors: true,
1193
1202
  transparent,
1194
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1203
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1195
1204
  alphaTest: 0.5
1196
1205
  });
1197
1206
  } catch (e) {
@@ -1201,6 +1210,10 @@ var _Materials = class _Materials {
1201
1210
  }
1202
1211
  static getImage(key) {
1203
1212
  const keyStr = serializeMaterialKey(key);
1213
+ const map = Caching.materialCache.peek(keyStr)?.map;
1214
+ if (map && TextureLoader.hasFailed(map)) {
1215
+ Caching.materialCache.invalidate(keyStr);
1216
+ }
1204
1217
  return Caching.materialCache.get(keyStr, (k) => {
1205
1218
  return _Materials.createImage(key);
1206
1219
  });
@@ -1225,10 +1238,10 @@ _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA
1225
1238
  var Materials = _Materials;
1226
1239
 
1227
1240
  // src/Meshes.ts
1228
- var import_three7 = require("three");
1241
+ var import_three6 = require("three");
1229
1242
  var Meshes = class _Meshes {
1230
1243
  static createBox(key) {
1231
- return new import_three7.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1244
+ return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1232
1245
  }
1233
1246
  static getBox(key) {
1234
1247
  const keyStr = serializeMeshKey(key);
@@ -1239,7 +1252,7 @@ var Meshes = class _Meshes {
1239
1252
  };
1240
1253
 
1241
1254
  // src/UVMapper.ts
1242
- var import_three8 = require("three");
1255
+ var import_three9 = require("three");
1243
1256
 
1244
1257
  // src/model/ModelMerger.ts
1245
1258
  var import_ts_deepmerge = __toESM(require_dist());
@@ -1275,6 +1288,7 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1275
1288
  this.rootType = rootType;
1276
1289
  this.extension = extension;
1277
1290
  this.root = root;
1291
+ this.isAssetKey = true;
1278
1292
  }
1279
1293
  static parse(assetType, str, origin) {
1280
1294
  let namespace = origin?.namespace || DEFAULT_NAMESPACE;
@@ -1290,12 +1304,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1290
1304
  split.shift();
1291
1305
  }
1292
1306
  let path = split.join("/");
1293
- let extension = assetType === "textures" ? ".png" : origin?.assetType || ".json";
1307
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1308
+ if (extension && path.endsWith(extension)) {
1309
+ path = path.slice(0, -extension.length);
1310
+ }
1294
1311
  return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1295
1312
  }
1296
1313
  toString() {
1297
1314
  let a = [
1298
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1315
+ this.root ?? AssetLoader.ROOT,
1299
1316
  this.rootType ?? "__rootType__",
1300
1317
  this.assetType ?? "__assetType__",
1301
1318
  this.type ?? "__type__",
@@ -1305,12 +1322,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1305
1322
  return a.join("/");
1306
1323
  }
1307
1324
  getFullPath() {
1308
- let p13 = [];
1325
+ let p12 = [];
1309
1326
  if (this.type) {
1310
- p13.push(this.type);
1327
+ p12.push(this.type);
1311
1328
  }
1312
- p13.push(this.path);
1313
- return p13.join("/");
1329
+ p12.push(this.path);
1330
+ return p12.join("/");
1314
1331
  }
1315
1332
  toNamespacedString() {
1316
1333
  return this.namespace + ":" + this.getFullPath();
@@ -1320,22 +1337,84 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1320
1337
  }
1321
1338
  };
1322
1339
  function isBasicAssetKey(obj) {
1323
- return "namespace" in obj && "path" in obj;
1340
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1324
1341
  }
1325
1342
  function isAssetKey(obj) {
1326
- return isBasicAssetKey(obj) && "parse" in obj;
1343
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1327
1344
  }
1328
1345
 
1346
+ // src/model/DisplayTransforms.ts
1347
+ var import_three7 = require("three");
1348
+
1349
+ // src/model/DisplayPosition.ts
1350
+ var DisplayPosition = /* @__PURE__ */ ((DisplayPosition2) => {
1351
+ DisplayPosition2["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
1352
+ DisplayPosition2["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
1353
+ DisplayPosition2["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
1354
+ DisplayPosition2["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
1355
+ DisplayPosition2["GUI"] = "gui";
1356
+ DisplayPosition2["HEAD"] = "head";
1357
+ DisplayPosition2["GROUND"] = "ground";
1358
+ DisplayPosition2["FIXED"] = "fixed";
1359
+ DisplayPosition2["ON_SHELF"] = "on_shelf";
1360
+ return DisplayPosition2;
1361
+ })(DisplayPosition || {});
1362
+ var DISPLAY_POSITIONS = Object.values(DisplayPosition);
1363
+
1364
+ // src/model/DisplayTransforms.ts
1365
+ var DisplayTransforms = class {
1366
+ /** Resolve hand fallbacks within one model, before inheriting parent display entries. */
1367
+ static withHandFallbacks(display) {
1368
+ if (!display) return void 0;
1369
+ const resolved = { ...display };
1370
+ for (const [left, right] of [
1371
+ ["thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */, "thirdperson_righthand" /* THIRDPERSON_RIGHTHAND */],
1372
+ ["firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */, "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */]
1373
+ ]) {
1374
+ if (resolved[left] === void 0 && resolved[right] !== void 0) resolved[left] = resolved[right];
1375
+ }
1376
+ return resolved;
1377
+ }
1378
+ /** Build a display pose for geometry already centered at the model's [8, 8, 8] pivot. */
1379
+ static getMatrix(display, position) {
1380
+ const transform = this.withHandFallbacks(display)?.[position] ?? {};
1381
+ const left = position === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || position === "thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */;
1382
+ const sign = left ? -1 : 1;
1383
+ const [x, y, z] = transform.rotation ?? [0, 0, 0];
1384
+ const rotation = new import_three7.Quaternion().setFromEuler(new import_three7.Euler(toRadians(x), sign * toRadians(y), sign * toRadians(z), "XYZ"));
1385
+ const translation = new import_three7.Vector3(...transform.translation ?? [0, 0, 0]).clampScalar(-80, 80);
1386
+ translation.x *= sign;
1387
+ const scale = new import_three7.Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
1388
+ return new import_three7.Matrix4().compose(translation, rotation, scale);
1389
+ }
1390
+ static apply(geometry, matrix) {
1391
+ geometry.applyMatrix4(matrix);
1392
+ if (matrix.determinant() < 0) {
1393
+ if (!geometry.index) geometry.setIndex(Array.from({ length: geometry.getAttribute("position").count }, (_, i) => i));
1394
+ const index = geometry.index;
1395
+ for (let i = 0; i < index.count; i += 3) {
1396
+ const second = index.getX(i + 1);
1397
+ index.setX(i + 1, index.getX(i + 2));
1398
+ index.setX(i + 2, second);
1399
+ }
1400
+ index.needsUpdate = true;
1401
+ }
1402
+ }
1403
+ };
1404
+
1329
1405
  // src/model/ModelMerger.ts
1330
1406
  var ModelMerger = class {
1331
1407
  static async mergeWithParents(model) {
1332
1408
  const models = await this.collectAllParents(model);
1333
1409
  let merged = {};
1334
- for (let parentModel of models) {
1335
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1410
+ for (const source of [...models, model]) {
1411
+ const inheritedDisplay = merged.display;
1412
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, source);
1413
+ if (source.display) {
1414
+ merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
1415
+ }
1336
1416
  }
1337
- merged = (0, import_ts_deepmerge.default)(merged, model);
1338
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1417
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1339
1418
  merged.hierarchy.push(`${merged.parent}`);
1340
1419
  return merged;
1341
1420
  }
@@ -1345,6 +1424,7 @@ var ModelMerger = class {
1345
1424
  }
1346
1425
  const models = [];
1347
1426
  const parentKey = AssetKey.parse("models", model.parent);
1427
+ parentKey.root = model.key?.root;
1348
1428
  const parentModel = await Models.getRaw(parentKey);
1349
1429
  if (parentModel) {
1350
1430
  models.unshift(parentModel);
@@ -1354,9 +1434,6 @@ var ModelMerger = class {
1354
1434
  }
1355
1435
  };
1356
1436
 
1357
- // src/assets/Models.ts
1358
- var import_typescript_memoize = require("typescript-memoize");
1359
-
1360
1437
  // src/assets/source/parser/AssetParsers.ts
1361
1438
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1362
1439
  AssetParser2["MODEL"] = "model";
@@ -1370,30 +1447,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1370
1447
  })(AssetParser || {});
1371
1448
 
1372
1449
  // src/assets/Models.ts
1373
- var _Models = class _Models {
1450
+ var Models = class _Models {
1374
1451
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1375
1452
  // the library, and would require an EnvProvider before any entry has had a chance to register
1376
1453
  static get PERSISTENT_CACHE() {
1377
1454
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1378
1455
  }
1379
1456
  static async getItemList() {
1380
- return AssetLoader.get(new AssetKey(
1381
- DEFAULT_NAMESPACE,
1382
- "_list",
1383
- "models",
1384
- "item",
1385
- "assets",
1386
- ".json",
1387
- DEFAULT_ROOT
1388
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1457
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1458
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1459
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1460
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1461
+ }).then((r) => r?.files ?? []);
1389
1462
  }
1390
1463
  static async loadAndMerge(key) {
1391
- const model = await this.getRaw(key);
1464
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1392
1465
  if (!model) {
1393
1466
  return void 0;
1394
1467
  }
1395
1468
  return ModelMerger.mergeWithParents(model);
1396
1469
  }
1470
+ static async getItemModel(key) {
1471
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1472
+ const model = await this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(itemKey.serialize()), async () => {
1473
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1474
+ if (!result) return void 0;
1475
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1476
+ const reference = this.defaultItemModel(result.asset.model, key);
1477
+ const modelKey = AssetKey.parse("models", reference);
1478
+ modelKey.root = key.root;
1479
+ const model2 = await this.getRaw(modelKey);
1480
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1481
+ return model2;
1482
+ });
1483
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1484
+ }
1485
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1486
+ static defaultItemModel(node, key) {
1487
+ if (!node || typeof node.type !== "string") {
1488
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1489
+ }
1490
+ switch (node.type.replace(/^minecraft:/, "")) {
1491
+ case "model":
1492
+ if (typeof node.model === "string" && node.model) return node.model;
1493
+ break;
1494
+ case "condition":
1495
+ return this.defaultItemModel(node.on_false, key);
1496
+ case "select": {
1497
+ const selected = node.property?.replace(/^minecraft:/, "") === "display_context" ? node.cases?.find((entry) => Array.isArray(entry.when) ? entry.when.includes("gui") : entry.when === "gui")?.model : void 0;
1498
+ return this.defaultItemModel(selected ?? node.fallback, key);
1499
+ }
1500
+ case "range_dispatch": {
1501
+ const selected = node.entries?.reduce((match, entry) => {
1502
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1503
+ }, void 0);
1504
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1505
+ }
1506
+ }
1507
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1508
+ }
1397
1509
  static async getRaw(key) {
1398
1510
  if (!key.assetType) {
1399
1511
  key.assetType = "models";
@@ -1403,7 +1515,7 @@ var _Models = class _Models {
1403
1515
  }
1404
1516
  const keyStr = key.serialize();
1405
1517
  return Caching.rawModelCache.get(keyStr, (k) => {
1406
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1518
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1407
1519
  return AssetLoader.get(key, "model" /* MODEL */);
1408
1520
  });
1409
1521
  }).then((asset) => {
@@ -1432,31 +1544,32 @@ var _Models = class _Models {
1432
1544
  return this.PERSISTENT_CACHE.clear();
1433
1545
  }
1434
1546
  };
1435
- __decorateClass([
1436
- (0, import_typescript_memoize.Memoize)()
1437
- ], _Models, "getItemList", 1);
1438
- var Models = _Models;
1439
1547
 
1440
1548
  // src/assets/BlockStates.ts
1441
- var import_typescript_memoize2 = require("typescript-memoize");
1442
1549
  var BlockStates = class {
1443
1550
  static get PERSISTENT_CACHE() {
1444
1551
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1445
1552
  }
1553
+ // BlockState names are hardcoded
1446
1554
  static async getList() {
1447
- return AssetLoader.get(new AssetKey(
1555
+ const key = new AssetKey(
1448
1556
  DEFAULT_NAMESPACE,
1449
1557
  "_list",
1450
1558
  "blockstates",
1451
1559
  void 0,
1452
1560
  "assets",
1453
1561
  ".json",
1454
- DEFAULT_ROOT
1455
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1562
+ AssetLoader.ROOT
1563
+ );
1564
+ return Caching.listAssetCache.get(key.serialize(), () => {
1565
+ return AssetLoader.get(key, "list" /* LIST */);
1566
+ }).then((r) => r?.files ?? []);
1456
1567
  }
1457
1568
  static async getDefaultStates() {
1458
1569
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1459
- return AssetLoader.get(key, "json" /* JSON */);
1570
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1571
+ return AssetLoader.get(key, "json" /* JSON */);
1572
+ });
1460
1573
  }
1461
1574
  static async getDefaultState(key) {
1462
1575
  const defaultStates = await this.getDefaultStates();
@@ -1474,7 +1587,7 @@ var BlockStates = class {
1474
1587
  }
1475
1588
  const keyStr = key.serialize();
1476
1589
  return Caching.blockStateCache.get(keyStr, (k) => {
1477
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1590
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1478
1591
  return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
1479
1592
  });
1480
1593
  }).then((asset) => {
@@ -1495,17 +1608,11 @@ var BlockStates = class {
1495
1608
  await this.PERSISTENT_CACHE.clear();
1496
1609
  }
1497
1610
  };
1498
- __decorateClass([
1499
- (0, import_typescript_memoize2.Memoize)()
1500
- ], BlockStates, "getList", 1);
1501
- __decorateClass([
1502
- (0, import_typescript_memoize2.Memoize)()
1503
- ], BlockStates, "getDefaultStates", 1);
1504
1611
  var DefaultBlockStates = class {
1505
1612
  };
1506
1613
 
1507
1614
  // src/assets/Assets.ts
1508
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1615
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1509
1616
  var DEFAULT_NAMESPACE = "minecraft";
1510
1617
  var Assets = class {
1511
1618
  /**
@@ -1526,8 +1633,145 @@ var Assets = class {
1526
1633
  var AssetSource = class {
1527
1634
  constructor() {
1528
1635
  }
1636
+ /**
1637
+ * Identifies this source's content across sessions for persistent caching. Sources that
1638
+ * cannot tell whether their content changed (an unnamed archive, for example) return
1639
+ * undefined, which keeps their results out of long-lived caches.
1640
+ */
1641
+ get cacheId() {
1642
+ return void 0;
1643
+ }
1644
+ };
1645
+ var AssetLoadError = class extends Error {
1646
+ constructor(source, key, path, cause) {
1647
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1648
+ this.source = source;
1649
+ this.key = key;
1650
+ this.path = path;
1651
+ this.cause = cause;
1652
+ this.name = "AssetLoadError";
1653
+ }
1654
+ };
1655
+
1656
+ // src/util/BatchedExecutor.ts
1657
+ var BatchedExecutor = class {
1658
+ constructor(interval = 1, batch = 30) {
1659
+ this.interval = interval;
1660
+ this.batch = batch;
1661
+ this.queue = [];
1662
+ this.task = setInterval(() => this.run());
1663
+ }
1664
+ submit(task) {
1665
+ this.queue.push(task);
1666
+ }
1667
+ run() {
1668
+ for (let i = 0; i < this.batch; i++) {
1669
+ this.runNext();
1670
+ }
1671
+ }
1672
+ runNext() {
1673
+ let next = this.queue.shift();
1674
+ if (next) next();
1675
+ }
1529
1676
  };
1530
1677
 
1678
+ // src/util/model.ts
1679
+ var import_three8 = require("three");
1680
+ function applyElementRotation(rotation, geometry) {
1681
+ const origin = new import_three8.Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1682
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1683
+ switch (rotation.axis) {
1684
+ case "x" /* X */:
1685
+ geometry.rotateX(toRadians(rotation.angle));
1686
+ break;
1687
+ case "y" /* Y */:
1688
+ geometry.rotateY(toRadians(rotation.angle));
1689
+ break;
1690
+ case "z" /* Z */:
1691
+ geometry.rotateZ(toRadians(rotation.angle));
1692
+ break;
1693
+ }
1694
+ if (rotation.rescale) {
1695
+ if (Math.abs(rotation.angle) === 22.5) {
1696
+ const s = 1 / Math.cos(0.39269909262657166);
1697
+ geometry.scale(s, 1, s);
1698
+ } else {
1699
+ const s = 1 / Math.cos(0.7853981852531433);
1700
+ geometry.scale(s, 1, s);
1701
+ }
1702
+ }
1703
+ geometry.translate(origin.x, origin.y, origin.z);
1704
+ }
1705
+ function applyGenericRotation(axis, rotation, obj) {
1706
+ switch (axis) {
1707
+ case "x" /* X */:
1708
+ obj.rotateOnAxis(new import_three8.Vector3(1, 0, 0), toRadians(rotation));
1709
+ break;
1710
+ case "y" /* Y */:
1711
+ obj.rotateOnAxis(new import_three8.Vector3(0, 1, 0), toRadians(rotation));
1712
+ break;
1713
+ case "z" /* Z */:
1714
+ obj.rotateOnAxis(new import_three8.Vector3(0, 0, 1), toRadians(rotation));
1715
+ break;
1716
+ }
1717
+ }
1718
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1719
+ let size = new import_three8.Vector3();
1720
+ box.getSize(size);
1721
+ let boxGeo = new import_three8.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
1722
+ let wireGeo = new import_three8.EdgesGeometry(boxGeo);
1723
+ let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
1724
+ let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
1725
+ obj.add(wireframe);
1726
+ let axes = new import_three8.AxesHelper(1);
1727
+ obj.add(axes);
1728
+ }
1729
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1730
+ let boxGeo = new import_three8.BoxGeometry(16, 16, 16, 1, 1, 1);
1731
+ let wireGeo = new import_three8.EdgesGeometry(boxGeo);
1732
+ let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
1733
+ let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
1734
+ obj.add(wireframe);
1735
+ let axes = new import_three8.AxesHelper(1);
1736
+ obj.add(axes);
1737
+ }
1738
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1739
+ let wireGeo = new import_three8.EdgesGeometry(geo);
1740
+ let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
1741
+ let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
1742
+ mesh.add(wireframe);
1743
+ let axes = new import_three8.AxesHelper(1);
1744
+ mesh.add(axes);
1745
+ }
1746
+
1747
+ // src/util/performance.ts
1748
+ function captureException(e, ...extra) {
1749
+ console.error(e, extra);
1750
+ }
1751
+ function timingStart(marker) {
1752
+ console.time(marker);
1753
+ }
1754
+ function timingEnd(marker) {
1755
+ console.timeEnd(marker);
1756
+ }
1757
+
1758
+ // src/util/three.ts
1759
+ function isObject3D(obj) {
1760
+ return obj.isObject3D;
1761
+ }
1762
+ function isMesh(obj) {
1763
+ return obj.isMesh;
1764
+ }
1765
+ function isInstancedMesh(obj) {
1766
+ return obj.isInstancedMesh;
1767
+ }
1768
+ function isPerspectiveCamera(obj) {
1769
+ return obj.isPerspectiveCamera;
1770
+ }
1771
+ function isOrthographicCamera(obj) {
1772
+ return obj.isOrthographicCamera;
1773
+ }
1774
+
1531
1775
  // src/nbt/NBTHelper.ts
1532
1776
  var NBTHelper = class {
1533
1777
  static async fromBuffer(buffer) {
@@ -1556,17 +1800,17 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1556
1800
  if (typeof namespaced !== "undefined") {
1557
1801
  return namespaced;
1558
1802
  }
1559
- if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1803
+ if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1560
1804
  console.info(p3, "Retrying", key, "with default root+namespace");
1561
- const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1805
+ const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1562
1806
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
1563
1807
  if (typeof namespacedRooted !== "undefined") {
1564
1808
  return namespacedRooted;
1565
1809
  }
1566
1810
  }
1567
- } else if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1811
+ } else if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1568
1812
  console.info(p3, "Retrying", key, "with default root");
1569
- const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1813
+ const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1570
1814
  const rooted = await this.load(rootKey, parser);
1571
1815
  if (typeof rooted !== "undefined") {
1572
1816
  return rooted;
@@ -1578,31 +1822,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1578
1822
  console.info(p3, "Loading", key);
1579
1823
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1580
1824
  console.debug(p3, url);
1581
- let req = {
1582
- url
1583
- };
1584
- parser.config(req);
1585
- return await Requests.mcAssetRequest(req).then((response) => {
1586
- if (response && response.data) {
1587
- try {
1588
- return parser.parse(response);
1589
- } catch (e) {
1590
- console.warn("Parser failed to process response", response, e);
1591
- throw e;
1592
- }
1593
- }
1594
- return void 0;
1595
- }).catch((err) => {
1596
- if (err.response) {
1597
- let response = err.response;
1598
- if (response.status === 404) {
1599
- console.debug(p3, key, "not found");
1825
+ const request = { url };
1826
+ try {
1827
+ parser.config(request);
1828
+ let response;
1829
+ try {
1830
+ response = await Requests.mcAssetRequest(request);
1831
+ } catch (cause) {
1832
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1600
1833
  return void 0;
1601
1834
  }
1835
+ throw cause;
1602
1836
  }
1603
- console.debug(p3, "Failed to load", key, err?.message);
1604
- return void 0;
1605
- });
1837
+ if (response.data === void 0) {
1838
+ throw new Error("Asset response has no data");
1839
+ }
1840
+ return await parser.parse(response);
1841
+ } catch (cause) {
1842
+ throw new AssetLoadError(this, key, request.url, cause);
1843
+ }
1606
1844
  }
1607
1845
  assetBasePath(key) {
1608
1846
  return `${key.root ?? this.root ?? AssetLoader.ROOT}/${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1615,6 +1853,9 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1615
1853
  get root() {
1616
1854
  return this._root;
1617
1855
  }
1856
+ get cacheId() {
1857
+ return `hosted:${this._root}`;
1858
+ }
1618
1859
  get options() {
1619
1860
  return this._options;
1620
1861
  }
@@ -1691,9 +1932,10 @@ var HostedAssetSource = _HostedAssetSource;
1691
1932
  // src/assets/source/archive/BrowserArchiveProxy.ts
1692
1933
  var import_zip = require("@zip.js/zip.js");
1693
1934
  var BrowserArchiveProxy = class {
1694
- constructor(blob) {
1935
+ constructor(blob, id) {
1695
1936
  this._blob = blob;
1696
1937
  this._reader = new import_zip.ZipReader(new import_zip.BlobReader(this._blob));
1938
+ this.id = id ?? (typeof File !== "undefined" && blob instanceof File ? `${blob.name}:${blob.size}:${blob.lastModified}` : void 0);
1697
1939
  }
1698
1940
  async getEntries() {
1699
1941
  return (await this._reader.getEntries()).map((e) => {
@@ -1709,7 +1951,6 @@ var BrowserArchiveProxy = class {
1709
1951
  };
1710
1952
 
1711
1953
  // src/assets/source/archive/ArchiveAssetSource.ts
1712
- var p4 = prefix("ArchiveAssetSource");
1713
1954
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1714
1955
  constructor(archiveProxy) {
1715
1956
  super();
@@ -1719,6 +1960,10 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1719
1960
  static blob(blob) {
1720
1961
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob));
1721
1962
  }
1963
+ get cacheId() {
1964
+ const id = this._archiveProxy.id;
1965
+ return id === void 0 ? void 0 : `archive:${id}`;
1966
+ }
1722
1967
  async getEntries() {
1723
1968
  return this._archiveProxy.getEntries();
1724
1969
  }
@@ -1728,74 +1973,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1728
1973
  }
1729
1974
  async get(key, parser) {
1730
1975
  const responseParser = HostedAssetSource.PARSER_MAP.get(parser);
1731
- console.log("ArchiveAssetSource.get", key, parser);
1732
- let entries = await this.getEntries();
1733
- const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1734
- console.log(path);
1735
- const entry = await this.getEntry(path);
1736
- console.log(entry);
1737
- if (!entry) {
1738
- return void 0;
1739
- }
1740
- let blob = await entry.getData();
1741
- const url = URL.createObjectURL(blob);
1742
- console.log(url);
1743
- let req = {
1744
- url
1745
- };
1746
- responseParser.config(req);
1747
- return Requests.genericRequest(req).then((response) => {
1748
- if (response && response.data) {
1749
- try {
1750
- return responseParser.parse(response);
1751
- } catch (e) {
1752
- console.warn("Parser failed to process response", response, e);
1753
- throw e;
1754
- }
1755
- }
1756
- return void 0;
1757
- }).catch((err) => {
1758
- if (err.response) {
1759
- let response = err.response;
1760
- if (response.status === 404) {
1761
- console.debug(p4, key, "not found");
1762
- return void 0;
1763
- }
1764
- }
1765
- console.debug(p4, "Failed to load", key, err?.message);
1766
- return void 0;
1767
- });
1976
+ return this.load(key, responseParser);
1768
1977
  }
1769
- //TODO: abstract this
1770
1978
  async load(key, parser) {
1771
- console.info(p4, "Loading", key);
1772
- const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1773
- console.debug(p4, url);
1774
- let req = {
1775
- url
1776
- };
1777
- parser.config(req);
1778
- return await Requests.genericRequest(req).then((response) => {
1779
- if (response && response.data) {
1780
- try {
1781
- return parser.parse(response);
1782
- } catch (e) {
1783
- console.warn("Parser failed to process response", response, e);
1784
- throw e;
1785
- }
1979
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1980
+ let url;
1981
+ try {
1982
+ const entry = await this.getEntry(path);
1983
+ if (!entry) {
1984
+ return void 0;
1786
1985
  }
1787
- return void 0;
1788
- }).catch((err) => {
1789
- if (err.response) {
1790
- let response = err.response;
1791
- if (response.status === 404) {
1792
- console.debug(p4, key, "not found");
1793
- return void 0;
1794
- }
1986
+ url = URL.createObjectURL(await entry.getData());
1987
+ const request = { url };
1988
+ parser.config(request);
1989
+ const response = await Requests.genericRequest(request);
1990
+ if (response.data === void 0) {
1991
+ throw new Error("Asset response has no data");
1795
1992
  }
1796
- console.debug(p4, "Failed to load", key, err?.message);
1797
- return void 0;
1798
- });
1993
+ return await parser.parse(response);
1994
+ } catch (cause) {
1995
+ throw new AssetLoadError(this, key, path, cause);
1996
+ } finally {
1997
+ if (url !== void 0) {
1998
+ URL.revokeObjectURL(url);
1999
+ }
2000
+ }
1799
2001
  }
1800
2002
  assetBasePath(key) {
1801
2003
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1803,18 +2005,54 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1803
2005
  };
1804
2006
 
1805
2007
  // src/assets/AssetLoader.ts
1806
- var import_ts_deepmerge3 = __toESM(require_dist());
1807
- var p5 = prefix("AssetLoader");
2008
+ var p4 = prefix("AssetLoader");
2009
+ var FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
1808
2010
  var _AssetLoader = class _AssetLoader {
2011
+ static get version() {
2012
+ return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
2013
+ }
2014
+ static setVersion(version) {
2015
+ this.ROOT = `https://assets.mcasset.cloud/${version}`;
2016
+ const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
2017
+ const index = this._SOURCES.findIndex((s) => s.key === "mcassets");
2018
+ if (index !== -1) {
2019
+ this._SOURCES[index] = { key: "mcassets", source };
2020
+ } else {
2021
+ this.addSource("mcassets", source);
2022
+ }
2023
+ Caching.clear();
2024
+ }
2025
+ /**
2026
+ * Scope for persistent cache keys. Empty with only the default vanilla sources, so their
2027
+ * entries stay valid across sessions; otherwise it names every added source (resource packs,
2028
+ * mirrors) so their results never masquerade as vanilla assets after a reload.
2029
+ */
2030
+ static get persistentScope() {
2031
+ const parts = [];
2032
+ for (const { key, source } of this._SOURCES) {
2033
+ const id = source.cacheId;
2034
+ if (key === "mcassets" && id === `hosted:${this.ROOT}`) continue;
2035
+ if (key === "mcassets-fallback" && id === `hosted:${FALLBACK_ROOT}`) continue;
2036
+ if (id === void 0) return this.SESSION_SCOPE;
2037
+ parts.push(`${key}=${id}`);
2038
+ }
2039
+ return parts.join("|");
2040
+ }
2041
+ /** Prefixes a persistent cache key with the current source scope. */
2042
+ static persistentKey(key) {
2043
+ const scope = this.persistentScope;
2044
+ return scope ? `${scope}
2045
+ ${key}` : key;
2046
+ }
1809
2047
  static addSource(key, source, override = true) {
1810
2048
  if (override) {
1811
2049
  const existing = this.removeSource(key);
1812
2050
  if (existing) {
1813
- console.log(p5, "Removed existing AssetSource", key);
2051
+ console.log(p4, "Removed existing AssetSource", key);
1814
2052
  }
1815
2053
  }
1816
2054
  this._SOURCES.unshift({ key, source });
1817
- console.log(p5, "Added AssetSource", key);
2055
+ console.log(p4, "Added AssetSource", key);
1818
2056
  }
1819
2057
  static removeSource(key) {
1820
2058
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1827,7 +2065,6 @@ var _AssetLoader = class _AssetLoader {
1827
2065
  return void 0;
1828
2066
  }
1829
2067
  static async getAll(key, parser) {
1830
- console.log(this._SOURCES);
1831
2068
  let promises = [];
1832
2069
  for (const source of this._SOURCES) {
1833
2070
  promises.push(source.source.get(key, parser));
@@ -1836,30 +2073,42 @@ var _AssetLoader = class _AssetLoader {
1836
2073
  return results.filter((r) => r != void 0);
1837
2074
  });
1838
2075
  }
2076
+ /** Returns the first defined result in source-priority order, without merging assets. */
1839
2077
  static async get(key, parser) {
1840
- console.log(this._SOURCES);
1841
- let promises = [];
1842
- for (const source of this._SOURCES) {
1843
- promises.push(source.source.get(key, parser));
1844
- }
1845
- return Promise.all(promises).then((results) => {
1846
- const fallback = results[results.length - 1];
1847
- for (const result of results) {
1848
- if (result) {
1849
- if (fallback) {
1850
- return (0, import_ts_deepmerge3.default)({}, fallback, result);
1851
- }
1852
- return result;
2078
+ const keys = [key];
2079
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
2080
+ keys.push(new AssetKey(
2081
+ key.namespace,
2082
+ key.path,
2083
+ key.assetType === "structure" ? "structures" : "structure",
2084
+ key.type,
2085
+ key.rootType,
2086
+ key.extension,
2087
+ key.root
2088
+ ));
2089
+ }
2090
+ return (await this.getFirst(keys, parser))?.asset;
2091
+ }
2092
+ /** Tries each path within a source before considering lower-priority sources. */
2093
+ static async getFirst(keys, parser) {
2094
+ const sources = [...this._SOURCES];
2095
+ for (const source of sources) {
2096
+ for (const key of keys) {
2097
+ const result = await source.source.get(key, parser);
2098
+ if (result !== void 0) {
2099
+ return { key, asset: result };
1853
2100
  }
1854
2101
  }
1855
- return void 0;
1856
- });
2102
+ }
2103
+ return void 0;
1857
2104
  }
1858
2105
  };
1859
2106
  _AssetLoader.ROOT = DEFAULT_ROOT;
1860
2107
  _AssetLoader._SOURCES = [];
1861
- _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1862
- _AssetLoader.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
2108
+ /** Used when a registered source cannot identify its content, so nothing persists past this session. */
2109
+ _AssetLoader.SESSION_SCOPE = `session:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
2110
+ _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
2111
+ _AssetLoader.addSource("mcassets", new HostedAssetSource(_AssetLoader.ROOT, { retryDefaults: false }));
1863
2112
  var AssetLoader = _AssetLoader;
1864
2113
 
1865
2114
  // src/assets/ModelTextures.ts
@@ -1868,11 +2117,21 @@ var ModelTextures = class {
1868
2117
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
1869
2118
  }
1870
2119
  static async get(key) {
1871
- const asset = await this.preload(key);
1872
- if (asset) {
1873
- return ImageLoader.infoToCanvasData(asset);
2120
+ const keyStr = key.serialize();
2121
+ const pending = this.preload(key);
2122
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
2123
+ try {
2124
+ const asset = await pending;
2125
+ if (asset) {
2126
+ return await ImageLoader.infoToCanvasData(asset);
2127
+ }
2128
+ return void 0;
2129
+ } catch (err) {
2130
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
2131
+ Caching.textureAssetCache.invalidate(keyStr);
2132
+ }
2133
+ throw err;
1874
2134
  }
1875
- return void 0;
1876
2135
  }
1877
2136
  static async preload(key) {
1878
2137
  const keyStr = key.serialize();
@@ -1891,7 +2150,7 @@ var ModelTextures = class {
1891
2150
  }
1892
2151
  const keyStr = key.serialize();
1893
2152
  return Caching.textureMetaCache.get(keyStr, (k) => {
1894
- return this.PERSISTENT_META_CACHE.getOrLoad(keyStr, (k1) => {
2153
+ return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1895
2154
  return AssetLoader.get(key, "meta" /* META */).then((asset) => {
1896
2155
  if (asset)
1897
2156
  asset.key = key;
@@ -2042,17 +2301,20 @@ var TextureAtlas = class {
2042
2301
  // src/model/ModelGenerator.ts
2043
2302
  var ModelGenerator = class {
2044
2303
  static generateItemModel(imageData, layer) {
2304
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
2045
2305
  const mainElement = {
2046
2306
  from: [0, 0, 7.5],
2047
2307
  to: [16, 16, 8.5],
2048
2308
  faces: {
2049
2309
  "south": {
2050
2310
  uv: [0, 0, 16, 16],
2051
- texture: `#${layer}`
2311
+ texture: `#${layer}`,
2312
+ tintindex
2052
2313
  },
2053
2314
  "north": {
2054
2315
  uv: [16, 0, 0, 16],
2055
- texture: `#${layer}`
2316
+ texture: `#${layer}`,
2317
+ tintindex
2056
2318
  }
2057
2319
  },
2058
2320
  shade: true
@@ -2063,11 +2325,19 @@ var ModelGenerator = class {
2063
2325
  ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2064
2326
 
2065
2327
  // src/UVMapper.ts
2066
- var p6 = prefix("UVMapper");
2328
+ var p5 = prefix("UVMapper");
2067
2329
  var DEFAULT_UV = [0, 0, 16, 16];
2068
2330
  var X = 0;
2069
2331
  var Y = 1;
2070
2332
  var Z = 2;
2333
+ var FACE_UV_AXES = {
2334
+ east: [new import_three9.Vector3(0, 0, -1), new import_three9.Vector3(0, -1, 0)],
2335
+ west: [new import_three9.Vector3(0, 0, 1), new import_three9.Vector3(0, -1, 0)],
2336
+ up: [new import_three9.Vector3(1, 0, 0), new import_three9.Vector3(0, 0, 1)],
2337
+ down: [new import_three9.Vector3(1, 0, 0), new import_three9.Vector3(0, 0, -1)],
2338
+ south: [new import_three9.Vector3(1, 0, 0), new import_three9.Vector3(0, -1, 0)],
2339
+ north: [new import_three9.Vector3(-1, 0, 0), new import_three9.Vector3(0, -1, 0)]
2340
+ };
2071
2341
  var UVMapper = class {
2072
2342
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
2073
2343
  if (uvCoord === 0) return 0;
@@ -2163,7 +2433,43 @@ var UVMapper = class {
2163
2433
  return array;
2164
2434
  }
2165
2435
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2166
- return new import_three8.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2436
+ return new import_three9.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2437
+ }
2438
+ static lockUvs(geometry, faces, atlas, rotation) {
2439
+ const uv = geometry.getAttribute("uv");
2440
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2441
+ const faceName = CUBE_FACES[faceIndex];
2442
+ const texture = faces[faceName]?.texture?.substring(1);
2443
+ const position = texture && atlas.positions[texture];
2444
+ const size = texture && atlas.sizes[texture];
2445
+ if (!position || !size) continue;
2446
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2447
+ const uAxis = sourceU.clone().applyEuler(rotation);
2448
+ const vAxis = sourceV.clone().applyEuler(rotation);
2449
+ const normal = vAxis.clone().cross(uAxis);
2450
+ const targetFace = CUBE_FACES.find((name) => {
2451
+ const [u, v] = FACE_UV_AXES[name];
2452
+ return v.clone().cross(u).dot(normal) > 0.5;
2453
+ });
2454
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2455
+ const uu = Math.round(targetU.dot(uAxis));
2456
+ const uvCross = Math.round(targetU.dot(vAxis));
2457
+ const vu = Math.round(targetV.dot(uAxis));
2458
+ const vv = Math.round(targetV.dot(vAxis));
2459
+ for (let corner = 0; corner < 4; corner++) {
2460
+ const index = faceIndex * 4 + corner;
2461
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2462
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2463
+ const lockedU = uu * u + uvCross * v + 0.5;
2464
+ const lockedV = vu * u + vv * v + 0.5;
2465
+ uv.setXY(
2466
+ index,
2467
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2468
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2469
+ );
2470
+ }
2471
+ }
2472
+ uv.needsUpdate = true;
2167
2473
  }
2168
2474
  static async getAtlas(model) {
2169
2475
  const keyStr = model.key.serialize();
@@ -2205,32 +2511,32 @@ var UVMapper = class {
2205
2511
  v1 *= scaleV;
2206
2512
  u2 *= scaleU;
2207
2513
  v2 *= scaleV;
2208
- let tl = new import_three8.Vector2(u1, v1);
2209
- let tr = new import_three8.Vector2(u2, v1);
2210
- let bl = new import_three8.Vector2(u1, v2);
2211
- let br = new import_three8.Vector2(u2, v2);
2514
+ let tl = new import_three9.Vector2(u1, v1);
2515
+ let tr = new import_three9.Vector2(u2, v1);
2516
+ let bl = new import_three9.Vector2(u1, v2);
2517
+ let br = new import_three9.Vector2(u2, v2);
2212
2518
  switch (rotation) {
2213
2519
  case 0:
2214
2520
  case 360:
2215
2521
  default:
2216
2522
  break;
2217
2523
  case 90:
2218
- tl = new import_three8.Vector2(u1, v2);
2219
- tr = new import_three8.Vector2(u1, v1);
2220
- bl = new import_three8.Vector2(u2, v2);
2221
- br = new import_three8.Vector2(u2, v1);
2524
+ tl = new import_three9.Vector2(u1, v2);
2525
+ tr = new import_three9.Vector2(u1, v1);
2526
+ bl = new import_three9.Vector2(u2, v2);
2527
+ br = new import_three9.Vector2(u2, v1);
2222
2528
  break;
2223
2529
  case 180:
2224
- tl = new import_three8.Vector2(u2, v2);
2225
- tr = new import_three8.Vector2(u1, v2);
2226
- bl = new import_three8.Vector2(u2, v1);
2227
- br = new import_three8.Vector2(u1, v1);
2530
+ tl = new import_three9.Vector2(u2, v2);
2531
+ tr = new import_three9.Vector2(u1, v2);
2532
+ bl = new import_three9.Vector2(u2, v1);
2533
+ br = new import_three9.Vector2(u1, v1);
2228
2534
  break;
2229
2535
  case 270:
2230
- tl = new import_three8.Vector2(u2, v1);
2231
- tr = new import_three8.Vector2(u2, v2);
2232
- bl = new import_three8.Vector2(u1, v1);
2233
- br = new import_three8.Vector2(u1, v2);
2536
+ tl = new import_three9.Vector2(u2, v1);
2537
+ tr = new import_three9.Vector2(u2, v2);
2538
+ bl = new import_three9.Vector2(u1, v1);
2539
+ br = new import_three9.Vector2(u1, v2);
2234
2540
  break;
2235
2541
  }
2236
2542
  return [tl, tr, bl, br];
@@ -2240,7 +2546,7 @@ var UVMapper = class {
2240
2546
  const metaMap = {};
2241
2547
  const model = { ...originalModel };
2242
2548
  const isItemModel = !("elements" in model);
2243
- console.debug(p6, "Creating Atlas for", model.key);
2549
+ console.debug(p5, "Creating Atlas for", model.key);
2244
2550
  if (model.textures) {
2245
2551
  const promises = [];
2246
2552
  const uniqueTextureNames = [];
@@ -2254,7 +2560,7 @@ var UVMapper = class {
2254
2560
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2255
2561
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2256
2562
  if (!asset) {
2257
- console.warn(p6, "Missing texture", assetKey);
2563
+ console.warn(p5, "Missing texture", assetKey);
2258
2564
  return;
2259
2565
  }
2260
2566
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2266,7 +2572,7 @@ var UVMapper = class {
2266
2572
  }
2267
2573
  await Promise.all(promises);
2268
2574
  const textureCount = uniqueTextureNames.length;
2269
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2575
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2270
2576
  this.fillMissingTextureKeys(model.textures, textureMap);
2271
2577
  this.fillMissingTextureKeys(model.textures, metaMap);
2272
2578
  const sizes = {};
@@ -2286,7 +2592,7 @@ var UVMapper = class {
2286
2592
  this.fillMissingTextureKeys(model.textures, sizes);
2287
2593
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2288
2594
  const size = Math.ceil(s * maxWidth);
2289
- console.debug(p6, "Atlas size:", size);
2595
+ console.debug(p5, "Atlas size:", size);
2290
2596
  const squaredSize = size * size;
2291
2597
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2292
2598
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2341,10 +2647,10 @@ var UVMapper = class {
2341
2647
  }
2342
2648
  }
2343
2649
  const atlasImageData = image.toDataURL();
2344
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2650
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2345
2651
  this.fillMissingTextureKeys(model.textures, positions);
2346
2652
  if (isItemModel) {
2347
- console.debug(p6, "Generating item model for", model);
2653
+ console.debug(p5, "Generating item model for", model);
2348
2654
  model.elements = [];
2349
2655
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2350
2656
  const textureImage = textureMap[layerName];
@@ -2352,7 +2658,7 @@ var UVMapper = class {
2352
2658
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2353
2659
  }
2354
2660
  }
2355
- console.debug(p6, "Item model elements", model.elements);
2661
+ console.debug(p5, "Item model elements", model.elements);
2356
2662
  }
2357
2663
  if (!model.elements) {
2358
2664
  }
@@ -2370,18 +2676,14 @@ var UVMapper = class {
2370
2676
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2371
2677
  continue;
2372
2678
  }
2679
+ if (!face.texture) continue;
2373
2680
  if (!face.uv) {
2374
2681
  face.uv = this.getFallbackUv(element, faceName);
2375
2682
  }
2376
- let faceTexture = face.texture;
2377
- let texPosition;
2378
- let texSize;
2379
- if (faceTexture) {
2380
- faceTexture = faceTexture.substr(1);
2381
- texPosition = positions[faceTexture] || [0, 0];
2382
- texSize = sizes[faceTexture] || [16, 16];
2383
- }
2384
- let texPosV = new import_three8.Vector2(texPosition[0], texPosition[1]);
2683
+ const faceTexture = face.texture.substr(1);
2684
+ const texPosition = positions[faceTexture] || [0, 0];
2685
+ const texSize = sizes[faceTexture] || [16, 16];
2686
+ let texPosV = new import_three9.Vector2(texPosition[0], texPosition[1]);
2385
2687
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2386
2688
  tl.add(texPosV);
2387
2689
  tr.add(texPosV);
@@ -2412,7 +2714,7 @@ var UVMapper = class {
2412
2714
  hasTransparency
2413
2715
  );
2414
2716
  } else {
2415
- console.warn(p6, "Model does not have any textures", model);
2717
+ console.warn(p5, "Model does not have any textures", model);
2416
2718
  }
2417
2719
  return void 0;
2418
2720
  }
@@ -2454,18 +2756,18 @@ var MinecraftCubeTexture = class {
2454
2756
  }
2455
2757
  getUvEast(w, h, l) {
2456
2758
  return [
2457
- [this.mapW(this.u), this.mapH(this.v + l + h)],
2458
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2459
- [this.mapW(this.u), this.mapH(this.v + l)],
2460
- [this.mapW(this.u + l), this.mapH(this.v + l)]
2759
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2760
+ [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2761
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
2762
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2461
2763
  ];
2462
2764
  }
2463
2765
  getUvWest(w, h, l) {
2464
2766
  return [
2465
- [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2466
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2467
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2468
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
2767
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2768
+ [this.mapW(this.u), this.mapH(this.v + l + h)],
2769
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
2770
+ [this.mapW(this.u), this.mapH(this.v + l)]
2469
2771
  ];
2470
2772
  }
2471
2773
  getUvUp(w, h, l) {
@@ -2478,26 +2780,26 @@ var MinecraftCubeTexture = class {
2478
2780
  }
2479
2781
  getUvDown(w, h, l) {
2480
2782
  return [
2481
- [this.mapW(this.u + l), this.mapH(this.v + l)],
2482
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2483
2783
  [this.mapW(this.u + l), this.mapH(this.v)],
2484
- [this.mapW(this.u + l + w), this.mapH(this.v)]
2784
+ [this.mapW(this.u + l + w), this.mapH(this.v)],
2785
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
2786
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2485
2787
  ];
2486
2788
  }
2487
2789
  getUvSouth(w, h, l) {
2488
2790
  return [
2489
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2490
2791
  [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l + h)],
2491
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
2492
- [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)]
2792
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2793
+ [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)],
2794
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
2493
2795
  ];
2494
2796
  }
2495
2797
  getUvNorth(w, h, l) {
2496
2798
  return [
2497
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2498
2799
  [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2499
- [this.mapW(this.u + l), this.mapH(this.v + l)],
2500
- [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2800
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2801
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2802
+ [this.mapW(this.u + l), this.mapH(this.v + l)]
2501
2803
  ];
2502
2804
  }
2503
2805
  getFaceUv(face, w, h, l) {
@@ -2516,10 +2818,12 @@ var MinecraftCubeTexture = class {
2516
2818
  return this.getUvNorth(w, h, l);
2517
2819
  }
2518
2820
  }
2519
- toUvArray(w, h, l) {
2821
+ toUvArray(w, h, l, mirror = false) {
2520
2822
  const uv = [];
2521
2823
  for (let i = 0; i < CUBE_FACES.length; i++) {
2522
- UVMapper.setFaceUvInArray(uv, i * 4, this.getFaceUv(CUBE_FACES[i], w, h, l));
2824
+ const face = mirror && i < 2 ? CUBE_FACES[1 - i] : CUBE_FACES[i];
2825
+ const corners = this.getFaceUv(face, w, h, l);
2826
+ UVMapper.setFaceUvInArray(uv, i * 4, mirror ? [corners[1], corners[0], corners[3], corners[2]] : corners);
2523
2827
  }
2524
2828
  return uv;
2525
2829
  }
@@ -2549,76 +2853,85 @@ function shutdown() {
2549
2853
  Caching.end();
2550
2854
  }
2551
2855
 
2856
+ // src/error/MineRenderError.ts
2857
+ var MineRenderError = class _MineRenderError extends Error {
2858
+ constructor(msg) {
2859
+ super(msg);
2860
+ Object.setPrototypeOf(this, _MineRenderError.prototype);
2861
+ }
2862
+ get name() {
2863
+ return "MineRenderError";
2864
+ }
2865
+ };
2866
+
2552
2867
  // src/assets/Entities.ts
2553
- var import_typescript_memoize3 = require("typescript-memoize");
2554
2868
  var Entities = class {
2555
- static async getBlockEntityModels() {
2556
- const key = AssetKey.parse("models", "minerender:blockEntityModels");
2557
- console.log(key);
2558
- return AssetLoader.get(key, "json" /* JSON */);
2559
- }
2560
- static async getEntityModels() {
2561
- const key = AssetKey.parse("models", "minerender:entityModels");
2562
- console.log(key);
2563
- return AssetLoader.get(key, "json" /* JSON */);
2564
- }
2565
- // BlockEntity names are hardcoded
2566
- static async getBlockList() {
2567
- const models = await this.getBlockEntityModels();
2568
- if (!models) {
2569
- return [];
2570
- }
2571
- return Object.keys(models);
2572
- }
2573
2869
  static async getEntityList() {
2574
- const models = await this.getEntityModels();
2575
- if (!models) {
2576
- return [];
2577
- }
2578
- return Object.keys(models);
2579
- }
2580
- static async getBlock(modelKey, textureKey) {
2581
- const models = await this.getBlockEntityModels();
2582
- if (!models) {
2583
- return void 0;
2584
- }
2585
- if (!textureKey) {
2586
- textureKey = modelKey;
2587
- }
2588
- const baseKey = modelKey.path.includes("/") ? new BasicAssetKey(modelKey.namespace, modelKey.path.split("/")[0]) : modelKey;
2589
- return {
2590
- key: textureKey,
2591
- parts: models[baseKey.toNamespacedString()]
2870
+ const collect = async (path) => {
2871
+ const prefix2 = path ? `${path}/` : "";
2872
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
2873
+ const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
2874
+ if (!list) return [];
2875
+ const files = list.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
2876
+ const children = await Promise.all(list.directories.map((directory) => collect(`${prefix2}${directory}`)));
2877
+ return [...files, ...children.flat()];
2592
2878
  };
2879
+ return collect("");
2880
+ }
2881
+ static async getEntity(modelKey, textureKey, options) {
2882
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
2883
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
2884
+ const model = await Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
2885
+ if (!model) return void 0;
2886
+ const layerName = options?.layer ?? "main";
2887
+ const layer = model.layers[layerName];
2888
+ if (!layer) {
2889
+ throw new MineRenderError(`Entity ${model.id} has no layer "${layerName}". Available layers: ${Object.keys(model.layers).join(", ")}`);
2890
+ }
2891
+ let texture;
2892
+ if (textureKey) {
2893
+ const path2 = isAssetKey(textureKey) ? textureKey.getFullPath() : textureKey.path;
2894
+ texture = isAssetKey(textureKey) && textureKey.assetType === "textures" && path2.startsWith("entity/") ? textureKey : new AssetKey(textureKey.namespace, path2, "textures", "entity", "assets", ".png", isAssetKey(textureKey) ? textureKey.root : void 0);
2895
+ } else if (layer.textureLocation !== void 0) {
2896
+ texture = AssetKey.parse("textures", layer.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
2897
+ } else {
2898
+ texture = await this.resolveTexture(modelKey);
2899
+ }
2900
+ return { key: textureKey ?? modelKey, texture, layer, id: model.id };
2901
+ }
2902
+ static async resolveTexture(modelKey) {
2903
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
2904
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
2905
+ return Caching.entityTextureCache.get(key.serialize(), async () => {
2906
+ const name = path.split("/").pop();
2907
+ for (const candidate of [path, `${path}/${name}`]) {
2908
+ const texture = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png");
2909
+ if (await ModelTextures.get(texture)) return texture;
2910
+ }
2911
+ const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json");
2912
+ const list = await AssetLoader.get(listKey, "list" /* LIST */);
2913
+ const files = list?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
2914
+ const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
2915
+ if (!file) return void 0;
2916
+ const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json");
2917
+ const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
2918
+ const assets = variant?.assets;
2919
+ const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
2920
+ return typeof textureId === "string" ? AssetKey.parse("textures", textureId) : void 0;
2921
+ });
2593
2922
  }
2594
- static async getEntity(modelKey, textureKey) {
2595
- const models = await this.getEntityModels();
2596
- if (!models) {
2597
- return void 0;
2598
- }
2599
- if (!textureKey) {
2600
- textureKey = modelKey;
2601
- }
2602
- const baseKey = modelKey.path.includes("/") ? new BasicAssetKey(modelKey.namespace, modelKey.path.split("/")[0]) : modelKey;
2603
- return {
2604
- key: textureKey,
2605
- parts: models[baseKey.toNamespacedString()]
2606
- };
2923
+ /** @deprecated Use getEntityList(); block entities share the entity dataset. */
2924
+ static getBlockList() {
2925
+ return this.getEntityList();
2926
+ }
2927
+ /** @deprecated Use getEntity(); block entities share the entity dataset. */
2928
+ static getBlock(modelKey, textureKey, options) {
2929
+ return this.getEntity(modelKey, textureKey, options);
2607
2930
  }
2608
- };
2609
- __decorateClass([
2610
- (0, import_typescript_memoize3.Memoize)()
2611
- ], Entities, "getBlockEntityModels", 1);
2612
- __decorateClass([
2613
- (0, import_typescript_memoize3.Memoize)()
2614
- ], Entities, "getEntityModels", 1);
2615
- var EntityModels = class {
2616
- };
2617
- var BlockEntityModels = class {
2618
2931
  };
2619
2932
 
2620
2933
  // src/renderer/SceneObject.ts
2621
- var import_three9 = require("three");
2934
+ var import_three10 = require("three");
2622
2935
 
2623
2936
  // src/instance/InstanceReference.ts
2624
2937
  var InstanceReference = class {
@@ -2663,28 +2976,17 @@ function isInstanceReference(obj) {
2663
2976
  return obj.isInstanceReference;
2664
2977
  }
2665
2978
 
2666
- // src/error/MineRenderError.ts
2667
- var MineRenderError = class _MineRenderError extends Error {
2668
- constructor(msg) {
2669
- super(msg);
2670
- Object.setPrototypeOf(this, _MineRenderError.prototype);
2671
- }
2672
- get name() {
2673
- return "MineRenderError";
2674
- }
2675
- };
2676
-
2677
2979
  // src/renderer/SceneObject.ts
2678
- var import_ts_deepmerge4 = __toESM(require_dist());
2679
- var p7 = prefix("SceneObject");
2680
- var _SceneObject = class _SceneObject extends import_three9.Object3D {
2980
+ var import_ts_deepmerge3 = __toESM(require_dist());
2981
+ var p6 = prefix("SceneObject");
2982
+ var _SceneObject = class _SceneObject extends import_three10.Object3D {
2681
2983
  constructor(options) {
2682
2984
  super();
2683
2985
  this.isSceneObject = true;
2684
2986
  this.materialCallbacks = {};
2685
2987
  this._isInstanced = false;
2686
2988
  this._instanceCounter = 0;
2687
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2989
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2688
2990
  console.log("SceneObject options", this.options);
2689
2991
  }
2690
2992
  set scene(scene) {
@@ -2715,7 +3017,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2715
3017
  return group;
2716
3018
  }
2717
3019
  createGroup(name, x = 0, y = 0, z = 0, offsetAxis, offset = 0) {
2718
- const obj = new import_three9.Object3D();
3020
+ const obj = new import_three10.Object3D();
2719
3021
  if (name) {
2720
3022
  obj.name = `group:${name}`;
2721
3023
  }
@@ -2765,7 +3067,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2765
3067
  return mesh;
2766
3068
  }
2767
3069
  createMesh(name, geometry, material, offsetAxis, offset = 0) {
2768
- const mesh = new import_three9.Mesh(geometry, material);
3070
+ const mesh = new import_three10.Mesh(geometry, material);
2769
3071
  if (name) {
2770
3072
  mesh.name = `mesh:${name}`;
2771
3073
  }
@@ -2777,7 +3079,8 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2777
3079
  return mesh;
2778
3080
  }
2779
3081
  createInstancedMesh(name, geometry, material, count) {
2780
- const mesh = new import_three9.InstancedMesh(geometry, material, count);
3082
+ const mesh = new import_three10.InstancedMesh(geometry, material, count);
3083
+ mesh.count = 0;
2781
3084
  if (name) {
2782
3085
  mesh.name = `mesh:${name}`;
2783
3086
  }
@@ -2798,15 +3101,8 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2798
3101
  return this.toggleObjectVisibility(this.getMeshByName(name), visible);
2799
3102
  }
2800
3103
  iterateAllMeshes(cb) {
2801
- this.children.forEach((obj) => {
2802
- if (obj.isMesh) {
2803
- cb(obj);
2804
- }
2805
- obj.children.forEach((obj1) => {
2806
- if (obj1.isMesh) {
2807
- cb(obj1);
2808
- }
2809
- });
3104
+ this.traverse((obj) => {
3105
+ if (isMesh(obj)) cb(obj);
2810
3106
  });
2811
3107
  }
2812
3108
  //</editor-fold>
@@ -2854,10 +3150,14 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2854
3150
  nextInstance() {
2855
3151
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2856
3152
  const i = this._instanceCounter++;
2857
- this.setMatrixAt(i, new import_three9.Matrix4());
2858
- console.debug(p7, "nextInstance " + i);
3153
+ this.setMatrixAt(i, new import_three10.Matrix4());
3154
+ const mesh = this.children[0];
3155
+ if (mesh && isInstancedMesh(mesh)) {
3156
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
3157
+ }
3158
+ console.debug(p6, "nextInstance " + i);
2859
3159
  if (i === this.options.maxInstanceCount) {
2860
- console.warn(p7, "Max instance count reached for " + this);
3160
+ console.warn(p6, "Max instance count reached for " + this);
2861
3161
  }
2862
3162
  if (this.scene) {
2863
3163
  this.scene.stats.instanceCount++;
@@ -2867,7 +3167,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2867
3167
  }
2868
3168
  //</editor-fold>
2869
3169
  //<editor-fold desc="TRANSFORMATION">
2870
- getMatrixAt(index, matrix = new import_three9.Matrix4()) {
3170
+ getMatrixAt(index, matrix = new import_three10.Matrix4()) {
2871
3171
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2872
3172
  const child = this.children[0];
2873
3173
  if (child && isInstancedMesh(child)) {
@@ -2886,16 +3186,16 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2886
3186
  }
2887
3187
  setPositionRotationScaleAt(index, position, rotation, scale) {
2888
3188
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2889
- const oldPosition = new import_three9.Vector3();
2890
- const oldRotation = new import_three9.Quaternion();
2891
- const oldScale = new import_three9.Vector3();
2892
- const matrix = new import_three9.Matrix4();
3189
+ const oldPosition = new import_three10.Vector3();
3190
+ const oldRotation = new import_three10.Quaternion();
3191
+ const oldScale = new import_three10.Vector3();
3192
+ const matrix = new import_three10.Matrix4();
2893
3193
  if (!scale || !rotation || !position) {
2894
3194
  this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
2895
3195
  }
2896
3196
  matrix.compose(
2897
3197
  position ? position : oldPosition,
2898
- rotation ? new import_three9.Quaternion().setFromEuler(rotation) : oldRotation,
3198
+ rotation ? new import_three10.Quaternion().setFromEuler(rotation) : oldRotation,
2899
3199
  scale ? scale : oldScale
2900
3200
  );
2901
3201
  this.setMatrixAt(index, matrix);
@@ -2904,7 +3204,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2904
3204
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2905
3205
  this.setPositionRotationScaleAt(index, position);
2906
3206
  }
2907
- getPositionAt(index, vector = new import_three9.Vector3()) {
3207
+ getPositionAt(index, vector = new import_three10.Vector3()) {
2908
3208
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2909
3209
  const matrix = this.getMatrixAt(index);
2910
3210
  vector.setFromMatrixPosition(matrix);
@@ -2914,7 +3214,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2914
3214
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2915
3215
  this.setPositionRotationScaleAt(index, void 0, rotation, void 0);
2916
3216
  }
2917
- getRotationAt(index, euler = new import_three9.Euler()) {
3217
+ getRotationAt(index, euler = new import_three10.Euler()) {
2918
3218
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2919
3219
  const matrix = this.getMatrixAt(index);
2920
3220
  euler.setFromRotationMatrix(matrix);
@@ -2924,7 +3224,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2924
3224
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2925
3225
  this.setPositionRotationScaleAt(index, void 0, void 0, scale);
2926
3226
  }
2927
- getScaleAt(index, vector = new import_three9.Vector3()) {
3227
+ getScaleAt(index, vector = new import_three10.Vector3()) {
2928
3228
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2929
3229
  const matrix = this.getMatrixAt(index);
2930
3230
  vector.setFromMatrixScale(matrix);
@@ -3033,7 +3333,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
3033
3333
  }
3034
3334
  //</editor-fold>
3035
3335
  };
3036
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
3336
+ _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
3037
3337
  instanceMeshes: true,
3038
3338
  maxInstanceCount: 50,
3039
3339
  mergeMeshes: true,
@@ -3044,17 +3344,16 @@ function isSceneObject(obj) {
3044
3344
  return obj.isSceneObject;
3045
3345
  }
3046
3346
 
3047
- // src/entity/scene/EntityObject.ts
3048
- var import_ts_deepmerge5 = __toESM(require_dist());
3049
- var import_three11 = require("three");
3050
- var THREE2 = __toESM(require("three"));
3051
- var EntityObject = class extends SceneObject {
3347
+ // src/entity/scene/EntityObject.ts
3348
+ var import_ts_deepmerge4 = __toESM(require_dist());
3349
+ var import_three12 = require("three");
3350
+ var _EntityObject = class _EntityObject extends SceneObject {
3052
3351
  constructor(entity, options) {
3053
3352
  super();
3054
3353
  this.entity = entity;
3055
3354
  this.isEntityObject = true;
3056
3355
  this.meshesCreated = false;
3057
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3356
+ this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
3058
3357
  }
3059
3358
  async init() {
3060
3359
  this.createMeshes();
@@ -3063,65 +3362,78 @@ var EntityObject = class extends SceneObject {
3063
3362
  dispose() {
3064
3363
  super.dispose();
3065
3364
  }
3066
- async loadTextures() {
3067
- this.imageData = await ModelTextures.get(new AssetKey(
3068
- this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
3069
- this.entity.key.path,
3070
- //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
3365
+ get textureKey() {
3366
+ if (this.entity.texture) return this.entity.texture;
3367
+ const key = this.entity.key;
3368
+ return new AssetKey(
3369
+ key.namespace,
3370
+ isAssetKey(key) ? key.getFullPath() : key.path,
3071
3371
  "textures",
3072
3372
  "entity",
3073
3373
  "assets",
3074
3374
  ".png"
3075
- ));
3375
+ );
3376
+ }
3377
+ async loadTextures() {
3378
+ this.imageData = await ModelTextures.get(this.textureKey);
3076
3379
  }
3077
- //TODO: abstract this, since extracted model data can be used for entities, blocks, players
3078
3380
  createMeshes(force = false) {
3079
3381
  if (this.meshesCreated && !force) return;
3080
- const mat = Materials.MISSING_TEXTURE;
3081
- for (let partName in this.entity.parts) {
3082
- const part = this.entity.parts[partName];
3083
- const texture = new MinecraftCubeTexture(part.textureOffsetU, part.textureOffsetV, part.textureWidth, part.textureHeight);
3084
- const partAnchor = new import_three11.Object3D();
3085
- partAnchor.position.x = part.pivotX;
3086
- partAnchor.position.y = part.pivotY;
3087
- partAnchor.position.z = part.pivotZ;
3088
- for (let cube of part.cubes) {
3089
- const w = cube.maxX - cube.minX;
3090
- const h = cube.maxY - cube.minY;
3091
- const l = cube.maxZ - cube.minZ;
3092
- const uv = texture.toUvArray(w, h, l);
3093
- const cubeGeo = this._getBoxGeometryForDimensionsAndUv(w, h, l, uv).clone();
3094
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3095
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
3096
- applyModelPartRotation(part, cubeGeo);
3097
- const mesh = this.createMesh(partName, cubeGeo, mat);
3098
- partAnchor.add(mesh);
3099
- if (this.options.wireframe) {
3100
- addWireframeToMesh(cubeGeo, mesh);
3101
- }
3102
- }
3103
- this.add(partAnchor);
3104
- }
3382
+ const modelRoot = new import_three12.Object3D();
3383
+ if (this.options.flip) modelRoot.scale.set(-1, -1, 1);
3384
+ this.add(modelRoot);
3385
+ this.createPart("root", this.entity.layer.root, modelRoot, this.entity.layer.texture, Materials.MISSING_TEXTURE);
3105
3386
  this.meshesCreated = true;
3106
3387
  }
3107
- async applyTextures() {
3108
- const textureAsset = await ModelTextures.preload(new AssetKey(
3109
- this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
3110
- this.entity.key.path,
3111
- "textures",
3112
- "entity",
3113
- "assets",
3114
- ".png"
3115
- ));
3116
- if (textureAsset) {
3117
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
3118
- this.iterateAllMeshes((mesh) => {
3119
- mesh.material = mat;
3120
- });
3388
+ createPart(name, part, parent, textureSize, material) {
3389
+ const anchor = this.createGroup(name);
3390
+ anchor.position.fromArray(part.pose.offset);
3391
+ anchor.rotation.set(...part.pose.rotation, "ZYX");
3392
+ anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
3393
+ parent.add(anchor);
3394
+ const size = part.texture ?? textureSize;
3395
+ for (const cube of part.cubes) {
3396
+ const [width, height, depth] = cube.size;
3397
+ const [growX, growY, growZ] = cube.grow ?? [0, 0, 0];
3398
+ const texture = new MinecraftCubeTexture(...cube.uv, ...size);
3399
+ const uv = size[0] === 0 || size[1] === 0 ? new Array(48).fill(0) : texture.toUvArray(width, height, depth, cube.mirror);
3400
+ const geometry = this._getBoxGeometryForDimensionsAndUv(
3401
+ width + growX * 2,
3402
+ height + growY * 2,
3403
+ depth + growZ * 2,
3404
+ uv
3405
+ ).clone();
3406
+ geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
3407
+ const mesh = this.createMesh(name, geometry, material);
3408
+ anchor.add(mesh);
3409
+ if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
3410
+ }
3411
+ for (const [childName, child] of Object.entries(part.children)) {
3412
+ this.createPart(childName, child, anchor, size, material);
3121
3413
  }
3122
3414
  }
3415
+ async applyTextures() {
3416
+ const assetKeyStr = this.textureKey.serialize();
3417
+ const keyStr = `entity:${assetKeyStr}`;
3418
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3419
+ if (!mat) {
3420
+ const pending = this.loadTextures();
3421
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3422
+ await pending;
3423
+ if (!this.imageData) return;
3424
+ const canvas = this.imageData.data.canvas;
3425
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3426
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3427
+ this.imageData = void 0;
3428
+ }
3429
+ this.iterateAllMeshes((mesh) => {
3430
+ mesh.material = mat;
3431
+ });
3432
+ this.notifyDirty();
3433
+ }
3123
3434
  };
3124
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3435
+ _EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, { flip: true });
3436
+ var EntityObject = _EntityObject;
3125
3437
  function isEntityObject(obj) {
3126
3438
  return obj.isEntityObject;
3127
3439
  }
@@ -3132,16 +3444,16 @@ var GuiObject = class extends SceneObject {
3132
3444
  };
3133
3445
 
3134
3446
  // src/inspector/SceneInspector.ts
3135
- var import_three12 = require("three");
3136
- var p8 = prefix("SceneInspector");
3447
+ var import_three13 = require("three");
3448
+ var p7 = prefix("SceneInspector");
3137
3449
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3138
3450
  var SceneInspector = class {
3139
3451
  constructor(renderer) {
3140
3452
  this.renderer = renderer;
3141
- this.mouse = new import_three12.Vector2();
3453
+ this.mouse = new import_three13.Vector2();
3142
3454
  this.objectInfoContainer = document.createElement("div");
3143
3455
  this.objectControlsContainer = document.createElement("div");
3144
- this.raycaster = new import_three12.Raycaster();
3456
+ this.raycaster = new import_three13.Raycaster();
3145
3457
  this.init();
3146
3458
  }
3147
3459
  init() {
@@ -3202,7 +3514,7 @@ var SceneInspector = class {
3202
3514
  }
3203
3515
  selectObject(targetObject, targetIntersection) {
3204
3516
  this.selectedObject = targetObject;
3205
- console.log(p8, "selected", targetObject);
3517
+ console.log(p7, "selected", targetObject);
3206
3518
  this.redraw(targetObject, targetIntersection);
3207
3519
  }
3208
3520
  redraw(targetObject, targetIntersection) {
@@ -3500,7 +3812,7 @@ var SceneStatsDisplay = class {
3500
3812
  };
3501
3813
 
3502
3814
  // src/instance/InstanceManager.ts
3503
- var p9 = prefix("InstanceManager");
3815
+ var p8 = prefix("InstanceManager");
3504
3816
  var InstanceManager = class {
3505
3817
  constructor() {
3506
3818
  this.isInstanceManager = true;
@@ -3508,7 +3820,7 @@ var InstanceManager = class {
3508
3820
  }
3509
3821
  async get(key) {
3510
3822
  if (key in this.instanceCache) {
3511
- console.debug(p9, "key in cache", key);
3823
+ console.debug(p8, "key in cache", key);
3512
3824
  return (await this.instanceCache[key]).nextInstance();
3513
3825
  }
3514
3826
  return void 0;
@@ -3517,13 +3829,17 @@ var InstanceManager = class {
3517
3829
  if (key in this.instanceCache) {
3518
3830
  return await this.get(key);
3519
3831
  }
3520
- console.debug(p9, "key not in cache", key);
3521
- this.instanceCache[key] = new Promise(async (resolve) => {
3522
- const obj = await supplier();
3523
- const instance = obj.nextInstance();
3524
- resolve(instance);
3525
- });
3526
- return await this.instanceCache[key];
3832
+ console.debug(p8, "key not in cache", key);
3833
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3834
+ this.instanceCache[key] = pending;
3835
+ try {
3836
+ return await pending;
3837
+ } catch (error) {
3838
+ if (this.instanceCache[key] === pending) {
3839
+ delete this.instanceCache[key];
3840
+ }
3841
+ throw error;
3842
+ }
3527
3843
  }
3528
3844
  reset() {
3529
3845
  for (let instanceCacheKey in this.instanceCache) {
@@ -3540,20 +3856,6 @@ function isInstanceable(obj) {
3540
3856
  return "nextInstance" in obj;
3541
3857
  }
3542
3858
 
3543
- // src/model/DisplayPosition.ts
3544
- var DisplayPosition = /* @__PURE__ */ ((DisplayPosition2) => {
3545
- DisplayPosition2["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
3546
- DisplayPosition2["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
3547
- DisplayPosition2["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
3548
- DisplayPosition2["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
3549
- DisplayPosition2["GUI"] = "gui";
3550
- DisplayPosition2["HEAD"] = "head";
3551
- DisplayPosition2["GROUND"] = "ground";
3552
- DisplayPosition2["FIXED"] = "fixed";
3553
- return DisplayPosition2;
3554
- })(DisplayPosition || {});
3555
- var DISPLAY_POSITIONS = Object.values(DisplayPosition);
3556
-
3557
3859
  // src/model/GuiLight.ts
3558
3860
  var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
3559
3861
  GuiLight2["FRONT"] = "front";
@@ -3576,11 +3878,96 @@ function isQuadArray(obj) {
3576
3878
  return Array.isArray(obj) && obj.length === 4;
3577
3879
  }
3578
3880
 
3881
+ // src/model/block/blockTints.json
3882
+ var blockTints_default = {
3883
+ "minecraft:large_fern": { source: "grass" },
3884
+ "minecraft:tall_grass": { source: "grass" },
3885
+ "minecraft:grass_block": { source: "grass" },
3886
+ "minecraft:fern": { source: "grass" },
3887
+ "minecraft:grass": { source: "grass" },
3888
+ "minecraft:short_grass": { source: "grass" },
3889
+ "minecraft:potted_fern": { source: "grass" },
3890
+ "minecraft:bush": { source: "grass" },
3891
+ "minecraft:pink_petals": { source: "grass", untinted: [0] },
3892
+ "minecraft:wildflowers": { source: "grass", untinted: [0] },
3893
+ "minecraft:spruce_leaves": { source: "constant", color: 6396257 },
3894
+ "minecraft:birch_leaves": { source: "constant", color: 8431445 },
3895
+ "minecraft:oak_leaves": { source: "constant", color: 4764952 },
3896
+ "minecraft:jungle_leaves": { source: "constant", color: 4764952 },
3897
+ "minecraft:acacia_leaves": { source: "constant", color: 4764952 },
3898
+ "minecraft:dark_oak_leaves": { source: "constant", color: 4764952 },
3899
+ "minecraft:vine": { source: "constant", color: 4764952 },
3900
+ "minecraft:mangrove_leaves": { source: "constant", color: 4764952 },
3901
+ "minecraft:leaf_litter": { source: "constant", color: 6044722 },
3902
+ "minecraft:water_cauldron": { source: "constant", color: 4159204 },
3903
+ "minecraft:redstone_wire": { source: "redstone" },
3904
+ "minecraft:attached_melon_stem": { source: "constant", color: 14731036 },
3905
+ "minecraft:attached_pumpkin_stem": { source: "constant", color: 14731036 },
3906
+ "minecraft:melon_stem": { source: "stem" },
3907
+ "minecraft:pumpkin_stem": { source: "stem" },
3908
+ "minecraft:lily_pad": { source: "constant", color: 7455580 }
3909
+ };
3910
+
3911
+ // src/model/block/BlockTints.ts
3912
+ var rules = blockTints_default;
3913
+ var BlockTints = class {
3914
+ /** Resolves block preview colors without biome context; explicit tints take precedence. */
3915
+ static async get(key, state, model, tints) {
3916
+ const rule = key && rules[key.toNamespacedString()];
3917
+ if (!key || !rule) return tints;
3918
+ const indices = /* @__PURE__ */ new Set();
3919
+ for (const element of model.elements ?? []) {
3920
+ for (const face of Object.values(element.faces)) {
3921
+ const index = face?.tintindex;
3922
+ if (index !== void 0 && index >= 0 && tints?.[index] === void 0 && !rule.untinted?.includes(index)) {
3923
+ indices.add(index);
3924
+ }
3925
+ }
3926
+ }
3927
+ if (!indices.size) return tints;
3928
+ let color;
3929
+ switch (rule.source) {
3930
+ case "constant":
3931
+ color = rule.color;
3932
+ break;
3933
+ case "grass":
3934
+ color = await this.grassColor(key);
3935
+ break;
3936
+ case "redstone": {
3937
+ const power = Number(state.power ?? 0) / 15;
3938
+ const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
3939
+ const green = Math.max(0, power * power * 0.7 - 0.5);
3940
+ const blue = Math.max(0, power * power * 0.6 - 0.7);
3941
+ color = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
3942
+ break;
3943
+ }
3944
+ case "stem": {
3945
+ const age = Number(state.age ?? 0);
3946
+ color = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
3947
+ break;
3948
+ }
3949
+ }
3950
+ return { ...Object.fromEntries([...indices].map((index) => [index, color])), ...tints };
3951
+ }
3952
+ static async grassColor(origin) {
3953
+ const key = AssetKey.parse("textures", "minecraft:colormap/grass", origin);
3954
+ return await Caching.blockTintCache.get(key.serialize(), async () => {
3955
+ const image = await ModelTextures.get(key);
3956
+ if (!image) throw new MineRenderError(`Missing grass colormap: ${key.toNamespacedString()}`);
3957
+ if (image.width !== 256 || image.height !== 256) {
3958
+ throw new MineRenderError("Grass colormaps must be 256 \xD7 256 pixels");
3959
+ }
3960
+ const [red, green, blue] = image.data.getImageData(127, 127, 1, 1).data;
3961
+ return red << 16 | green << 8 | blue;
3962
+ });
3963
+ }
3964
+ };
3965
+
3579
3966
  // src/model/scene/ModelObject.ts
3580
- var import_three15 = require("three");
3967
+ var import_three16 = require("three");
3581
3968
 
3582
3969
  // src/three/BufferGeometryUtils.js
3583
- var import_three14 = require("three");
3970
+ var import_three15 = require("three");
3584
3971
  function computeTangents(geometry) {
3585
3972
  geometry.computeTangents();
3586
3973
  console.warn("THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.");
@@ -3592,7 +3979,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
3592
3979
  const attributes = {};
3593
3980
  const morphAttributes = {};
3594
3981
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
3595
- const mergedGeometry = new import_three14.BufferGeometry();
3982
+ const mergedGeometry = new import_three15.BufferGeometry();
3596
3983
  let offset = 0;
3597
3984
  for (let i = 0; i < geometries.length; ++i) {
3598
3985
  const geometry = geometries[i];
@@ -3716,7 +4103,7 @@ function mergeBufferAttributes(attributes) {
3716
4103
  array.set(attributes[i].array, offset);
3717
4104
  offset += attributes[i].array.length;
3718
4105
  }
3719
- return new import_three14.BufferAttribute(array, itemSize, normalized);
4106
+ return new import_three15.BufferAttribute(array, itemSize, normalized);
3720
4107
  }
3721
4108
  function interleaveAttributes(attributes) {
3722
4109
  let TypedArray;
@@ -3732,7 +4119,7 @@ function interleaveAttributes(attributes) {
3732
4119
  arrayLength += attribute.array.length;
3733
4120
  stride += attribute.itemSize;
3734
4121
  }
3735
- const interleavedBuffer = new import_three14.InterleavedBuffer(new TypedArray(arrayLength), stride);
4122
+ const interleavedBuffer = new import_three15.InterleavedBuffer(new TypedArray(arrayLength), stride);
3736
4123
  let offset = 0;
3737
4124
  const res = [];
3738
4125
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -3741,7 +4128,7 @@ function interleaveAttributes(attributes) {
3741
4128
  const attribute = attributes[j];
3742
4129
  const itemSize = attribute.itemSize;
3743
4130
  const count = attribute.count;
3744
- const iba = new import_three14.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
4131
+ const iba = new import_three15.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
3745
4132
  res.push(iba);
3746
4133
  offset += itemSize;
3747
4134
  for (let c = 0; c < count; c++) {
@@ -3825,13 +4212,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3825
4212
  const name = attributeNames[i];
3826
4213
  const oldAttribute = geometry.getAttribute(name);
3827
4214
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
3828
- const attribute = new import_three14.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
4215
+ const attribute = new import_three15.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3829
4216
  result.setAttribute(name, attribute);
3830
4217
  if (name in morphAttrsArrays) {
3831
4218
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
3832
4219
  const oldMorphAttribute = geometry.morphAttributes[name][j];
3833
4220
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
3834
- const morphAttribute = new import_three14.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
4221
+ const morphAttribute = new import_three15.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3835
4222
  result.morphAttributes[name][j] = morphAttribute;
3836
4223
  }
3837
4224
  }
@@ -3840,11 +4227,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3840
4227
  return result;
3841
4228
  }
3842
4229
  function toTrianglesDrawMode(geometry, drawMode) {
3843
- if (drawMode === import_three14.TrianglesDrawMode) {
4230
+ if (drawMode === import_three15.TrianglesDrawMode) {
3844
4231
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
3845
4232
  return geometry;
3846
4233
  }
3847
- if (drawMode === import_three14.TriangleFanDrawMode || drawMode === import_three14.TriangleStripDrawMode) {
4234
+ if (drawMode === import_three15.TriangleFanDrawMode || drawMode === import_three15.TriangleStripDrawMode) {
3848
4235
  let index = geometry.getIndex();
3849
4236
  if (index === null) {
3850
4237
  const indices = [];
@@ -3862,7 +4249,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
3862
4249
  }
3863
4250
  const numberOfTriangles = index.count - 2;
3864
4251
  const newIndices = [];
3865
- if (drawMode === import_three14.TriangleFanDrawMode) {
4252
+ if (drawMode === import_three15.TriangleFanDrawMode) {
3866
4253
  for (let i = 1; i <= numberOfTriangles; i++) {
3867
4254
  newIndices.push(index.getX(0));
3868
4255
  newIndices.push(index.getX(i));
@@ -3898,15 +4285,15 @@ function computeMorphedAttributes(object) {
3898
4285
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3899
4286
  return null;
3900
4287
  }
3901
- const _vA = new import_three14.Vector3();
3902
- const _vB = new import_three14.Vector3();
3903
- const _vC = new import_three14.Vector3();
3904
- const _tempA = new import_three14.Vector3();
3905
- const _tempB = new import_three14.Vector3();
3906
- const _tempC = new import_three14.Vector3();
3907
- const _morphA = new import_three14.Vector3();
3908
- const _morphB = new import_three14.Vector3();
3909
- const _morphC = new import_three14.Vector3();
4288
+ const _vA = new import_three15.Vector3();
4289
+ const _vB = new import_three15.Vector3();
4290
+ const _vC = new import_three15.Vector3();
4291
+ const _tempA = new import_three15.Vector3();
4292
+ const _tempB = new import_three15.Vector3();
4293
+ const _tempC = new import_three15.Vector3();
4294
+ const _morphA = new import_three15.Vector3();
4295
+ const _morphB = new import_three15.Vector3();
4296
+ const _morphC = new import_three15.Vector3();
3910
4297
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3911
4298
  _vA.fromBufferAttribute(attribute, a2);
3912
4299
  _vB.fromBufferAttribute(attribute, b2);
@@ -4101,8 +4488,8 @@ function computeMorphedAttributes(object) {
4101
4488
  }
4102
4489
  }
4103
4490
  }
4104
- const morphedPositionAttribute = new import_three14.Float32BufferAttribute(modifiedPosition, 3);
4105
- const morphedNormalAttribute = new import_three14.Float32BufferAttribute(modifiedNormal, 3);
4491
+ const morphedPositionAttribute = new import_three15.Float32BufferAttribute(modifiedPosition, 3);
4492
+ const morphedNormalAttribute = new import_three15.Float32BufferAttribute(modifiedNormal, 3);
4106
4493
  return {
4107
4494
  positionAttribute,
4108
4495
  normalAttribute,
@@ -4112,15 +4499,16 @@ function computeMorphedAttributes(object) {
4112
4499
  }
4113
4500
 
4114
4501
  // src/model/scene/ModelObject.ts
4115
- var import_ts_deepmerge6 = __toESM(require_dist());
4116
- var p10 = prefix("ModelObject");
4502
+ var import_ts_deepmerge5 = __toESM(require_dist());
4503
+ var p9 = prefix("ModelObject");
4117
4504
  var _ModelObject = class _ModelObject extends SceneObject {
4118
4505
  constructor(originalModel, options) {
4119
4506
  super(options);
4120
4507
  this.originalModel = originalModel;
4121
4508
  this.isModelObject = true;
4122
4509
  this.meshesCreated = false;
4123
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4510
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4511
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
4124
4512
  console.log("ModelObject options", this.options);
4125
4513
  }
4126
4514
  async init() {
@@ -4142,17 +4530,36 @@ var _ModelObject = class _ModelObject extends SceneObject {
4142
4530
  createMeshes(force = false) {
4143
4531
  if (this.meshesCreated && !force) return;
4144
4532
  const mat = Materials.MISSING_TEXTURE;
4533
+ const displayTransform = this.options.displayPosition ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : void 0;
4145
4534
  let allGeos = [];
4146
4535
  if (this.atlas) {
4147
4536
  if (this.atlas.model.elements) {
4148
4537
  this.atlas.model.elements?.forEach((el) => {
4149
4538
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4150
- elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4151
- elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4539
+ if (this.options.uvLockRotation) {
4540
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three16.Euler(...this.options.uvLockRotation));
4541
+ }
4542
+ if (this.options.tints) {
4543
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4544
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4545
+ const tintIndex = el.faces[faceName]?.tintindex;
4546
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4547
+ const tint = this.options.tints[tintIndex];
4548
+ if (tint === void 0) continue;
4549
+ const color = new import_three16.Color(tint);
4550
+ for (let vertex = 0; vertex < 4; vertex++) {
4551
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4552
+ }
4553
+ }
4554
+ elGeo.setAttribute("color", new import_three16.BufferAttribute(colors, 3));
4555
+ }
4556
+ elGeo.applyMatrix4(new import_three16.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4557
+ elGeo.applyMatrix4(new import_three16.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4152
4558
  if (el.rotation) {
4153
4559
  applyElementRotation(el.rotation, elGeo);
4154
4560
  }
4155
- elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation(-8, -8, -8));
4561
+ elGeo.applyMatrix4(new import_three16.Matrix4().makeTranslation(-8, -8, -8));
4562
+ if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4156
4563
  if (this.options.mergeMeshes) {
4157
4564
  allGeos.push(elGeo);
4158
4565
  } else {
@@ -4163,17 +4570,18 @@ var _ModelObject = class _ModelObject extends SceneObject {
4163
4570
  }
4164
4571
  });
4165
4572
  } else {
4166
- console.debug(p10, this.atlas.model, "has no elements");
4573
+ console.debug(p9, this.atlas.model, "has no elements");
4167
4574
  }
4168
4575
  } else {
4169
- console.debug(p10, "Missing atlas for", this);
4576
+ console.debug(p9, "Missing atlas for", this);
4170
4577
  }
4171
4578
  if (this.options.mergeMeshes) {
4172
4579
  let combinedGeo;
4173
4580
  if (allGeos.length > 0) {
4174
4581
  combinedGeo = mergeBufferGeometries(allGeos);
4175
4582
  } else {
4176
- combinedGeo = new import_three15.BoxGeometry(16, 16, 16);
4583
+ combinedGeo = new import_three16.BoxGeometry(16, 16, 16);
4584
+ if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4177
4585
  }
4178
4586
  combinedGeo.computeBoundingBox();
4179
4587
  let mesh;
@@ -4203,6 +4611,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4203
4611
  /*TODO: get this from render options*/
4204
4612
  );
4205
4613
  this.iterateAllMeshes((mesh) => {
4614
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4206
4615
  mesh.material = mat;
4207
4616
  });
4208
4617
  if (this.atlas.hasAnimation) {
@@ -4218,16 +4627,26 @@ var _ModelObject = class _ModelObject extends SceneObject {
4218
4627
  }
4219
4628
  }
4220
4629
  };
4221
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4630
+ _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4222
4631
  var ModelObject = _ModelObject;
4223
4632
  function isModelObject(obj) {
4224
4633
  return obj.isModelObject;
4225
4634
  }
4226
4635
 
4227
4636
  // src/model/block/scene/BlockObject.ts
4228
- var import_ts_deepmerge7 = __toESM(require_dist());
4229
- var import_three16 = require("three");
4230
- var p11 = prefix("BlockObject");
4637
+ var import_ts_deepmerge6 = __toESM(require_dist());
4638
+ var import_three17 = require("three");
4639
+ var p10 = prefix("BlockObject");
4640
+ function matchesCondition(condition, state) {
4641
+ return Object.entries(condition).every(([key, value]) => {
4642
+ if (Array.isArray(value)) {
4643
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4644
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4645
+ return false;
4646
+ }
4647
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4648
+ });
4649
+ }
4231
4650
  var _BlockObject = class _BlockObject extends SceneObject {
4232
4651
  constructor(blockState, options) {
4233
4652
  super(options);
@@ -4241,11 +4660,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4241
4660
  this._instanceModel = [];
4242
4661
  this._variants = [];
4243
4662
  this._models = [];
4244
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4663
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4245
4664
  }
4246
4665
  async init() {
4247
4666
  if (this.options.applyDefaultState) {
4248
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4667
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4249
4668
  if (defaultState && Object.keys(defaultState).length > 0) {
4250
4669
  const state = {};
4251
4670
  for (let k in defaultState) {
@@ -4256,15 +4675,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4256
4675
  if (this.blockState.variants) {
4257
4676
  await this.setState(Object.keys(this.blockState.variants)[0]);
4258
4677
  } else if (this.blockState.multipart) {
4259
- for (let part of this.blockState.multipart) {
4260
- if (part.when && !("OR" in part.when)) {
4261
- const k = Object.keys(part.when)[0];
4262
- if (k) {
4263
- await this.setState(k, part.when[k].split("|")[0]);
4264
- break;
4265
- }
4266
- }
4267
- }
4678
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4679
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4680
+ await this.setState(state);
4268
4681
  }
4269
4682
  }
4270
4683
  } else {
@@ -4279,7 +4692,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4279
4692
  if (isModelObject(model)) {
4280
4693
  model.removeFromScene();
4281
4694
  } else if (isInstanceReference(model)) {
4282
- model.setScale(new import_three16.Vector3(0, 0, 0));
4695
+ model.setScale(new import_three17.Vector3(0, 0, 0));
4283
4696
  }
4284
4697
  }
4285
4698
  super.removeFromScene();
@@ -4321,55 +4734,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4321
4734
  } else if (this.blockState.multipart) {
4322
4735
  for (let part of this.blockState.multipart) {
4323
4736
  if (!part.apply) {
4324
- console.debug(p11, "Missing apply for blockState part", part);
4737
+ console.debug(p10, "Missing apply for blockState part", part);
4325
4738
  continue;
4326
4739
  }
4327
- if (!part.when) {
4740
+ if (!part.when || matchesCondition(part.when, state)) {
4328
4741
  out.push(this.getSingleVariant(part.apply));
4329
- } else {
4330
- let matches = true;
4331
- if ("OR" in part.when) {
4332
- const or = part.when.OR;
4333
- let anyMatch = false;
4334
- for (let o of or) {
4335
- for (let k in o) {
4336
- const split = o[k].split("|");
4337
- let m = false;
4338
- for (let s of split) {
4339
- if (`${state[k]}` === `${s}`) {
4340
- m = true;
4341
- break;
4342
- }
4343
- }
4344
- if (m) {
4345
- anyMatch = true;
4346
- break;
4347
- }
4348
- }
4349
- }
4350
- if (!anyMatch) {
4351
- matches = false;
4352
- }
4353
- } else {
4354
- for (let k in part.when) {
4355
- const split = part.when[k].split("|");
4356
- let m = false;
4357
- for (let s of split) {
4358
- if (`${state[k]}` === `${s}`) {
4359
- m = true;
4360
- break;
4361
- }
4362
- }
4363
- if (!m) {
4364
- matches = false;
4365
- break;
4366
- }
4367
- }
4368
- }
4369
- if (matches) {
4370
- const variants = part.apply;
4371
- out.push(this.getSingleVariant(variants));
4372
- }
4373
4742
  }
4374
4743
  }
4375
4744
  }
@@ -4384,7 +4753,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4384
4753
  }
4385
4754
  for (let model of this._models) {
4386
4755
  if (isInstanceReference(model)) {
4387
- model.setScale(new import_three16.Vector3(0, 0, 0));
4756
+ model.setScale(new import_three17.Vector3(0, 0, 0));
4388
4757
  } else {
4389
4758
  model.dispose();
4390
4759
  }
@@ -4399,11 +4768,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4399
4768
  }
4400
4769
  }
4401
4770
  getSingleVariant(variants) {
4402
- if (Array.isArray(variants)) {
4403
- return variants[0];
4404
- } else {
4405
- return variants;
4406
- }
4771
+ if (!Array.isArray(variants)) return variants;
4772
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4773
+ const total = variants.reduce((sum, variant) => {
4774
+ const weight = variant.weight ?? 1;
4775
+ if (!Number.isInteger(weight) || weight < 1) {
4776
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4777
+ }
4778
+ return sum + weight;
4779
+ }, 0);
4780
+ let choice = Math.random() * total;
4781
+ for (const variant of variants) {
4782
+ choice -= variant.weight ?? 1;
4783
+ if (choice < 0) return variant;
4784
+ }
4785
+ return variants[variants.length - 1];
4407
4786
  }
4408
4787
  // @deprecated
4409
4788
  async createAVariant(variants, instanceInfo) {
@@ -4411,28 +4790,27 @@ var _BlockObject = class _BlockObject extends SceneObject {
4411
4790
  await this.createVariant(variant);
4412
4791
  }
4413
4792
  async createVariant(variant) {
4414
- const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4415
- const obj = await this.scene.addModel(model, this.options);
4416
- if (isInstanceReference(obj) || obj.isInstanced) {
4417
- this._isInstanced = true;
4418
- this._instanceCounter = 1;
4419
- }
4420
- let rotation = new import_three16.Euler(0, 0, 0);
4793
+ const rotation = new import_three17.Euler();
4421
4794
  if (typeof variant.x !== "undefined") {
4422
4795
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4423
4796
  }
4424
4797
  if (typeof variant.y !== "undefined") {
4425
- if (typeof variant.x !== "undefined") {
4426
- rotation.y = toRadians(clampRotationDegrees(variant.y));
4427
- } else {
4428
- rotation.y = toRadians(clampRotationDegrees(360 - variant.y));
4429
- }
4798
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4799
+ }
4800
+ const modelKey = AssetKey.parse("models", variant.model);
4801
+ modelKey.root = this.blockState.key?.root;
4802
+ const model = await Models.getMerged(modelKey);
4803
+ const options = {
4804
+ ...this.options,
4805
+ tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
4806
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4807
+ };
4808
+ const obj = await this.scene.addModel(model, options);
4809
+ if (isInstanceReference(obj) || obj.isInstanced) {
4810
+ this._isInstanced = true;
4811
+ this._instanceCounter = 1;
4430
4812
  }
4431
4813
  obj.setRotation(rotation);
4432
- setTimeout(() => {
4433
- obj.setRotation(rotation);
4434
- }, 150);
4435
- console.log(obj);
4436
4814
  return obj;
4437
4815
  }
4438
4816
  async resetState() {
@@ -4501,7 +4879,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4501
4879
  setPositionRotationScaleAt(index, position, rotation, scale) {
4502
4880
  super.setPositionRotationScaleAt(index, position, rotation, scale);
4503
4881
  }
4504
- getMatrixAt(index, matrix = new import_three16.Matrix4()) {
4882
+ getMatrixAt(index, matrix = new import_three17.Matrix4()) {
4505
4883
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
4506
4884
  const child = this._models[0];
4507
4885
  if (child && isModelObject(child)) {
@@ -4522,15 +4900,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4522
4900
  }
4523
4901
  }
4524
4902
  setPosition(position) {
4525
- super.setPosition(position);
4903
+ this.position.copy(position);
4526
4904
  for (let model of this._models) {
4527
4905
  model.setPosition(position);
4528
4906
  }
4907
+ this.notifyDirty();
4529
4908
  }
4530
4909
  //TODO: should override rotation + scale methods
4531
4910
  //TODO
4532
4911
  };
4533
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4912
+ _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4534
4913
  applyDefaultState: true
4535
4914
  });
4536
4915
  var BlockObject = _BlockObject;
@@ -4579,8 +4958,8 @@ var StructureParser = class {
4579
4958
  };
4580
4959
 
4581
4960
  // src/renderer/MineRenderScene.ts
4582
- var import_three17 = require("three");
4583
- var import_ts_deepmerge9 = __toESM(require_dist());
4961
+ var import_three19 = require("three");
4962
+ var import_ts_deepmerge8 = __toESM(require_dist());
4584
4963
 
4585
4964
  // src/skin/SkinPart.ts
4586
4965
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5216,62 +5595,52 @@ var baseSkinCoordinates = {
5216
5595
  }
5217
5596
  },
5218
5597
  cape: {
5219
- //TODO
5220
- east: {
5221
- uv: [
5222
- 0,
5223
- 36,
5224
- 4,
5225
- 48
5226
- ]
5227
- },
5228
- west: {
5229
- uv: [
5230
- 8,
5231
- 36,
5232
- 12,
5233
- 48
5234
- ]
5235
- },
5236
- north: {
5237
- uv: [
5238
- 4,
5239
- 36,
5240
- 8,
5241
- 48
5242
- ]
5243
- },
5244
- south: {
5245
- uv: [
5246
- 12,
5247
- 36,
5248
- 16,
5249
- 48
5250
- ]
5251
- },
5252
- up: {
5253
- uv: [
5254
- 4,
5255
- 32,
5256
- 8,
5257
- 36
5258
- ]
5259
- },
5260
- down: {
5261
- uv: [
5262
- 8,
5263
- 32,
5264
- 12,
5265
- 36
5266
- ],
5267
- rotation: 180
5268
- }
5598
+ east: { uv: [0, 1, 1, 17] },
5599
+ west: { uv: [11, 1, 12, 17] },
5600
+ north: { uv: [1, 1, 11, 17] },
5601
+ south: { uv: [12, 1, 22, 17] },
5602
+ up: { uv: [11, 1, 1, 0] },
5603
+ down: { uv: [21, 0, 11, 1] }
5269
5604
  }
5270
5605
  };
5271
5606
  var classicSkinTextureCoordinates = {
5272
5607
  ...baseSkinCoordinates
5273
5608
  };
5274
- var slimSkinTextureCoordinates = { ...baseSkinCoordinates };
5609
+ var slimSkinTextureCoordinates = {
5610
+ ...baseSkinCoordinates,
5611
+ leftArm: {
5612
+ ...baseSkinCoordinates.leftArm,
5613
+ west: { uv: [39, 52, 43, 64] },
5614
+ north: { uv: [36, 52, 39, 64] },
5615
+ south: { uv: [43, 52, 46, 64] },
5616
+ up: { uv: [39, 52, 36, 48] },
5617
+ down: { uv: [42, 48, 39, 52] }
5618
+ },
5619
+ rightArm: {
5620
+ ...baseSkinCoordinates.rightArm,
5621
+ west: { uv: [47, 20, 51, 32] },
5622
+ north: { uv: [44, 20, 47, 32] },
5623
+ south: { uv: [51, 20, 54, 32] },
5624
+ up: { uv: [47, 20, 44, 16] },
5625
+ down: { uv: [50, 16, 47, 20] }
5626
+ },
5627
+ leftSleeve: {
5628
+ ...baseSkinCoordinates.leftSleeve,
5629
+ west: { uv: [55, 52, 59, 64] },
5630
+ north: { uv: [52, 52, 55, 64] },
5631
+ south: { uv: [59, 52, 62, 64] },
5632
+ up: { uv: [55, 52, 52, 48] },
5633
+ down: { uv: [58, 48, 55, 52], rotation: 180 }
5634
+ },
5635
+ rightSleeve: {
5636
+ ...baseSkinCoordinates.rightSleeve,
5637
+ west: { uv: [47, 36, 51, 48] },
5638
+ north: { uv: [44, 36, 47, 48] },
5639
+ south: { uv: [51, 36, 54, 48] },
5640
+ up: { uv: [47, 36, 44, 32] },
5641
+ down: { uv: [50, 32, 47, 36], rotation: 180 }
5642
+ }
5643
+ };
5275
5644
 
5276
5645
  // src/skin/SkinGeometries.ts
5277
5646
  var box8inner = [8, 8, 8];
@@ -5311,15 +5680,118 @@ var slimSkinGeometries = {
5311
5680
  };
5312
5681
 
5313
5682
  // src/skin/scene/SkinObject.ts
5314
- var import_ts_deepmerge8 = __toESM(require_dist());
5683
+ var import_ts_deepmerge7 = __toESM(require_dist());
5684
+
5685
+ // src/skin/SkinTextures.ts
5686
+ var import_three18 = require("three");
5687
+ var SkinTextures = class {
5688
+ static async get(src, legacy) {
5689
+ const image = await ImageLoader.getData(src);
5690
+ const scale = image.width / 64;
5691
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width && image.height !== image.width / 2) {
5692
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; expected 64x64 or 64x32, or an integer-scaled equivalent`);
5693
+ }
5694
+ const isLegacy = legacy ?? image.height === image.width / 2;
5695
+ if (!isLegacy && image.height !== image.width) {
5696
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; non-legacy skins must be square`);
5697
+ }
5698
+ const slim = !isLegacy && this.isSlim(image, scale);
5699
+ const key = `skin:${serializeImageKey({ src })}:${isLegacy}`;
5700
+ const material = Caching.materialCache.get(key, () => {
5701
+ const pixels = isLegacy ? this.normalizeLegacy(image, scale) : new Uint8Array(image.data);
5702
+ return this.createMaterial(pixels, image.width, image.width);
5703
+ });
5704
+ return { material, slim, legacy: isLegacy };
5705
+ }
5706
+ static async getCape(src, layout = "minecraft") {
5707
+ const image = await ImageLoader.getData(src);
5708
+ const scale = image.width / 64;
5709
+ if (layout === "minecraft" && (!Number.isInteger(scale) || scale < 1 || image.height !== image.width / 2)) {
5710
+ throw new MineRenderError(`Invalid cape dimensions ${image.width}x${image.height}; expected 64x32 or an integer-scaled equivalent`);
5711
+ }
5712
+ return Caching.materialCache.get(`cape:${serializeImageKey({ src })}`, () => {
5713
+ return this.createMaterial(new Uint8Array(image.data), image.width, image.height, false);
5714
+ });
5715
+ }
5716
+ static createMaterial(pixels, width, height, transparent = true) {
5717
+ const texture = Textures.initTextureProps(new import_three18.DataTexture(pixels, width, height));
5718
+ texture.colorSpace = import_three18.SRGBColorSpace;
5719
+ texture.flipY = true;
5720
+ texture.needsUpdate = true;
5721
+ return new import_three18.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three18.DoubleSide : import_three18.FrontSide, alphaTest: transparent ? 0.5 : 0 });
5722
+ }
5723
+ static isSlim(image, scale) {
5724
+ for (const [x, y] of [[46, 52], [54, 20]]) {
5725
+ for (let row = y * scale; row < (y + 12) * scale; row++) {
5726
+ for (let column = x * scale; column < (x + 1) * scale; column++) {
5727
+ if (image.data[(row * image.width + column) * 4 + 3] !== 0) return false;
5728
+ }
5729
+ }
5730
+ }
5731
+ return true;
5732
+ }
5733
+ static normalizeLegacy(image, scale) {
5734
+ const pixels = new Uint8Array(image.width * image.width * 4);
5735
+ pixels.set(image.data.subarray(0, image.width * image.width / 2 * 4));
5736
+ for (const [sx, sy, dx, dy, width, height] of [
5737
+ [4, 16, 20, 48, 4, 4],
5738
+ [8, 16, 24, 48, 4, 4],
5739
+ [0, 20, 24, 52, 4, 12],
5740
+ [4, 20, 20, 52, 4, 12],
5741
+ [8, 20, 16, 52, 4, 12],
5742
+ [12, 20, 28, 52, 4, 12],
5743
+ [44, 16, 36, 48, 4, 4],
5744
+ [48, 16, 40, 48, 4, 4],
5745
+ [40, 20, 40, 52, 4, 12],
5746
+ [44, 20, 36, 52, 4, 12],
5747
+ [48, 20, 32, 52, 4, 12],
5748
+ [52, 20, 44, 52, 4, 12]
5749
+ ]) {
5750
+ for (let y = 0; y < height * scale; y++) {
5751
+ for (let x = 0; x < width * scale; x++) {
5752
+ const source = ((sy * scale + y) * image.width + sx * scale + x) * 4;
5753
+ const target = ((dy * scale + y) * image.width + (dx + width) * scale - 1 - x) * 4;
5754
+ pixels.set(image.data.subarray(source, source + 4), target);
5755
+ }
5756
+ }
5757
+ }
5758
+ let clearHat = true;
5759
+ for (let y = 0; y < 32 * scale; y++) {
5760
+ for (let x = 32 * scale; x < image.width; x++) {
5761
+ if (pixels[(y * image.width + x) * 4 + 3] < 128) clearHat = false;
5762
+ }
5763
+ }
5764
+ for (let y = 0; y < image.width; y++) {
5765
+ for (let x = 0; x < image.width; x++) {
5766
+ const alpha = (y * image.width + x) * 4 + 3;
5767
+ if (x < 32 * scale && y < 16 * scale || y >= 16 * scale && y < 32 * scale || x >= 16 * scale && x < 48 * scale && y >= 48 * scale) {
5768
+ pixels[alpha] = 255;
5769
+ } else if (clearHat && x >= 32 * scale && y < 32 * scale) {
5770
+ pixels[alpha] = 0;
5771
+ }
5772
+ }
5773
+ }
5774
+ return pixels;
5775
+ }
5776
+ };
5777
+
5778
+ // src/skin/CapeLayout.ts
5779
+ var capeTextureSizes = {
5780
+ minecraft: [64, 32],
5781
+ optifine: [46, 22],
5782
+ labymod: [22, 17]
5783
+ };
5784
+
5785
+ // src/skin/scene/SkinObject.ts
5315
5786
  var SkinObject = class extends SceneObject {
5316
5787
  constructor(options) {
5317
5788
  super();
5318
5789
  this.slim = false;
5319
- this.legacy = false;
5320
- this.skinTextureWidth = 64;
5321
- this.skinTextureHeight = 64;
5322
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5790
+ this.detectedSlim = false;
5791
+ this.skinLoad = 0;
5792
+ this.capeLoad = 0;
5793
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5794
+ this.slim = this.options.slim ?? false;
5323
5795
  }
5324
5796
  async init() {
5325
5797
  this.createMeshes();
@@ -5328,15 +5800,13 @@ var SkinObject = class extends SceneObject {
5328
5800
  }
5329
5801
  createMeshes() {
5330
5802
  console.log("#createMeshes");
5331
- const mat = Materials.MISSING_TEXTURE;
5803
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5332
5804
  {
5333
5805
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5334
5806
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5335
5807
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5336
- if (!this.legacy) {
5337
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5338
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5339
- }
5808
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5809
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5340
5810
  }
5341
5811
  {
5342
5812
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5379,51 +5849,95 @@ var SkinObject = class extends SceneObject {
5379
5849
  }
5380
5850
  console.log("#createMeshes done");
5381
5851
  }
5382
- setSkinTexture(src) {
5852
+ async setSkinTexture(src) {
5383
5853
  if (typeof src === "undefined") return;
5384
5854
  this.skinTextureSrc = src;
5385
- const mat = Materials.getImage({
5386
- texture: { src },
5387
- transparent: true
5388
- });
5389
- for (let part of SKIN_PARTS) {
5390
- let mesh = this.getMeshByName(part);
5855
+ const load = ++this.skinLoad;
5856
+ const texture = await SkinTextures.get(src, this.options.legacy);
5857
+ if (load !== this.skinLoad) return;
5858
+ this.skinMaterial = texture.material;
5859
+ this.detectedSlim = texture.slim;
5860
+ this.updateSlim(this.options.slim ?? this.detectedSlim);
5861
+ for (const part of SKIN_PARTS) {
5862
+ if (part === "cape" /* CAPE */) continue;
5863
+ const mesh = this.getMeshByName(part);
5391
5864
  if (mesh) {
5392
- mesh.material = mat;
5865
+ mesh.material = texture.material;
5393
5866
  }
5394
5867
  }
5868
+ this.notifyDirty();
5869
+ }
5870
+ /** Load a cape texture in the selected layout, or pass undefined to remove the cape. */
5871
+ async setCapeTexture(src, layout = "minecraft") {
5872
+ const load = ++this.capeLoad;
5873
+ if (src === void 0) {
5874
+ const group = this.getGroupByName("cape" /* CAPE */);
5875
+ if (group) this.remove(group);
5876
+ this.notifyDirty();
5877
+ return;
5878
+ }
5879
+ const material = await SkinTextures.getCape(src, layout);
5880
+ if (load !== this.capeLoad) return;
5881
+ const size = capeTextureSizes[layout];
5882
+ const geometry = this._getBoxGeometryFromDimensions(
5883
+ classicSkinGeometries.cape,
5884
+ classicSkinTextureCoordinates.cape,
5885
+ size,
5886
+ size
5887
+ );
5888
+ const mesh = this.getMeshByName("cape" /* CAPE */);
5889
+ if (mesh) {
5890
+ mesh.material = material;
5891
+ mesh.geometry = geometry;
5892
+ } else {
5893
+ const group = this.createAndAddGroup("cape" /* CAPE */, 0, 24, 2);
5894
+ group.rotation.set(toRadians(-6), Math.PI, 0);
5895
+ const cape = this.createAndAddMesh("cape" /* CAPE */, group, geometry, material);
5896
+ cape.position.set(0, -8, -0.5);
5897
+ }
5898
+ this.notifyDirty();
5395
5899
  }
5396
- //TODO: cape
5900
+ /** Select the arm model, or pass undefined to use texture detection. */
5397
5901
  setSlim(slim) {
5398
- console.log("#setSlim");
5399
- const changed = slim !== this.slim;
5902
+ this.options.slim = slim;
5903
+ this.updateSlim(slim ?? this.detectedSlim);
5904
+ }
5905
+ updateSlim(slim) {
5906
+ if (slim === this.slim) return;
5400
5907
  this.slim = slim;
5401
- if (changed) {
5402
- this.createMeshes();
5403
- }
5404
- if (changed) {
5405
- if (this.skinTextureSrc) {
5406
- this.setSkinTexture(this.skinTextureSrc);
5407
- }
5408
- }
5409
- console.log("#setSlim done");
5908
+ for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
5909
+ const mesh = this.getMeshByName(part);
5910
+ if (mesh) mesh.geometry = this.getBoxGeometry(part);
5911
+ }
5912
+ const offset = slim ? 0.5 : -0.5;
5913
+ const leftArm = this.getGroupByName("leftArm" /* LEFT_ARM */);
5914
+ const rightArm = this.getGroupByName("rightArm" /* RIGHT_ARM */);
5915
+ if (leftArm) leftArm.position.x += offset;
5916
+ if (rightArm) rightArm.position.x -= offset;
5917
+ this.notifyDirty();
5410
5918
  }
5411
- setLegacy(legacy) {
5412
- if (legacy !== this.legacy) {
5413
- }
5414
- this.legacy = legacy;
5919
+ /** Select the texture layout, or pass undefined to detect it from image dimensions. */
5920
+ async setLegacy(legacy) {
5921
+ if (legacy === this.options.legacy) return;
5922
+ this.options.legacy = legacy;
5923
+ if (this.skinTextureSrc) await this.setSkinTexture(this.skinTextureSrc);
5924
+ }
5925
+ dispose() {
5926
+ this.skinLoad++;
5927
+ this.capeLoad++;
5928
+ super.dispose();
5415
5929
  }
5416
5930
  //TODO: layer toggles
5417
5931
  getBoxGeometry(part) {
5418
5932
  console.log("slim", this.slim);
5419
5933
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5420
5934
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5421
- return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [this.skinTextureWidth, this.skinTextureHeight]);
5935
+ return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [64, 64]);
5422
5936
  }
5423
5937
  };
5424
5938
 
5425
5939
  // src/renderer/MineRenderScene.ts
5426
- var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5940
+ var _MineRenderScene = class _MineRenderScene extends import_three19.Scene {
5427
5941
  constructor(options) {
5428
5942
  super();
5429
5943
  this.isMineRenderScene = true;
@@ -5436,7 +5950,7 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5436
5950
  this.dirty = true;
5437
5951
  }
5438
5952
  };
5439
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5953
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5440
5954
  }
5441
5955
  add(...objects) {
5442
5956
  for (const object of objects) {
@@ -5494,7 +6008,14 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5494
6008
  const obj = await objectSupplier();
5495
6009
  if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5496
6010
  console.log("instanceMeshes + key");
5497
- const key = asset.key.serialize();
6011
+ let key = asset.key.serialize();
6012
+ if (isModelObject(obj)) {
6013
+ const { displayPosition, uvLockRotation, tints } = obj.options;
6014
+ if (displayPosition) key += `|display:${displayPosition}`;
6015
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
6016
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
6017
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
6018
+ }
5498
6019
  return this.instanceManager.getOrCreate(key, async () => {
5499
6020
  obj.scene = this;
5500
6021
  await obj.init();
@@ -5521,10 +6042,10 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5521
6042
  this.dirty = true;
5522
6043
  const obj = new SkinObject(options);
5523
6044
  obj.scene = this;
5524
- await obj.init();
5525
6045
  if (skin) {
5526
- obj.setSkinTexture(skin);
6046
+ await obj.setSkinTexture(skin);
5527
6047
  }
6048
+ await obj.init();
5528
6049
  parent.add(obj);
5529
6050
  return obj;
5530
6051
  }
@@ -5532,24 +6053,24 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5532
6053
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5533
6054
  }
5534
6055
  };
5535
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
6056
+ _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5536
6057
  var MineRenderScene = _MineRenderScene;
5537
6058
  function isMineRenderScene(obj) {
5538
6059
  return obj.isMineRenderScene;
5539
6060
  }
5540
6061
 
5541
6062
  // src/renderer/Renderer.ts
5542
- var import_three19 = require("three");
5543
- var import_ts_deepmerge10 = __toESM(require_dist());
6063
+ var import_three21 = require("three");
6064
+ var import_ts_deepmerge9 = __toESM(require_dist());
5544
6065
  var import_stats = __toESM(require("stats.js"));
5545
6066
  var import_postprocessing = require("postprocessing");
5546
6067
 
5547
6068
  // src/three/OrbitControls.js
5548
- var import_three18 = require("three");
6069
+ var import_three20 = require("three");
5549
6070
  var _changeEvent = { type: "change" };
5550
6071
  var _startEvent = { type: "start" };
5551
6072
  var _endEvent = { type: "end" };
5552
- var OrbitControls = class extends import_three18.EventDispatcher {
6073
+ var OrbitControls = class extends import_three20.EventDispatcher {
5553
6074
  constructor(object, domElement) {
5554
6075
  super();
5555
6076
  if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
@@ -5558,7 +6079,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5558
6079
  this.domElement = domElement;
5559
6080
  this.domElement.style.touchAction = "none";
5560
6081
  this.enabled = true;
5561
- this.target = new import_three18.Vector3();
6082
+ this.target = new import_three20.Vector3();
5562
6083
  this.minDistance = 0;
5563
6084
  this.maxDistance = Infinity;
5564
6085
  this.minZoom = 0;
@@ -5580,8 +6101,8 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5580
6101
  this.autoRotate = false;
5581
6102
  this.autoRotateSpeed = 2;
5582
6103
  this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5583
- this.mouseButtons = { LEFT: import_three18.MOUSE.ROTATE, MIDDLE: import_three18.MOUSE.DOLLY, RIGHT: import_three18.MOUSE.PAN };
5584
- this.touches = { ONE: import_three18.TOUCH.ROTATE, TWO: import_three18.TOUCH.DOLLY_PAN };
6104
+ this.mouseButtons = { LEFT: import_three20.MOUSE.ROTATE, MIDDLE: import_three20.MOUSE.DOLLY, RIGHT: import_three20.MOUSE.PAN };
6105
+ this.touches = { ONE: import_three20.TOUCH.ROTATE, TWO: import_three20.TOUCH.DOLLY_PAN };
5585
6106
  this.target0 = this.target.clone();
5586
6107
  this.position0 = this.object.position.clone();
5587
6108
  this.zoom0 = this.object.zoom;
@@ -5610,11 +6131,11 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5610
6131
  state = STATE.NONE;
5611
6132
  };
5612
6133
  this.update = function() {
5613
- const offset = new import_three18.Vector3();
5614
- const quat = new import_three18.Quaternion().setFromUnitVectors(object.up, new import_three18.Vector3(0, 1, 0));
6134
+ const offset = new import_three20.Vector3();
6135
+ const quat = new import_three20.Quaternion().setFromUnitVectors(object.up, new import_three20.Vector3(0, 1, 0));
5615
6136
  const quatInverse = quat.clone().invert();
5616
- const lastPosition = new import_three18.Vector3();
5617
- const lastQuaternion = new import_three18.Quaternion();
6137
+ const lastPosition = new import_three20.Vector3();
6138
+ const lastQuaternion = new import_three20.Quaternion();
5618
6139
  const twoPI = 2 * Math.PI;
5619
6140
  return function update() {
5620
6141
  const position = scope.object.position;
@@ -5700,20 +6221,20 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5700
6221
  };
5701
6222
  let state = STATE.NONE;
5702
6223
  const EPS = 1e-6;
5703
- const spherical = new import_three18.Spherical();
5704
- const sphericalDelta = new import_three18.Spherical();
6224
+ const spherical = new import_three20.Spherical();
6225
+ const sphericalDelta = new import_three20.Spherical();
5705
6226
  let scale = 1;
5706
- const panOffset = new import_three18.Vector3();
6227
+ const panOffset = new import_three20.Vector3();
5707
6228
  let zoomChanged = false;
5708
- const rotateStart = new import_three18.Vector2();
5709
- const rotateEnd = new import_three18.Vector2();
5710
- const rotateDelta = new import_three18.Vector2();
5711
- const panStart = new import_three18.Vector2();
5712
- const panEnd = new import_three18.Vector2();
5713
- const panDelta = new import_three18.Vector2();
5714
- const dollyStart = new import_three18.Vector2();
5715
- const dollyEnd = new import_three18.Vector2();
5716
- const dollyDelta = new import_three18.Vector2();
6229
+ const rotateStart = new import_three20.Vector2();
6230
+ const rotateEnd = new import_three20.Vector2();
6231
+ const rotateDelta = new import_three20.Vector2();
6232
+ const panStart = new import_three20.Vector2();
6233
+ const panEnd = new import_three20.Vector2();
6234
+ const panDelta = new import_three20.Vector2();
6235
+ const dollyStart = new import_three20.Vector2();
6236
+ const dollyEnd = new import_three20.Vector2();
6237
+ const dollyDelta = new import_three20.Vector2();
5717
6238
  const pointers = [];
5718
6239
  const pointerPositions = {};
5719
6240
  function getAutoRotationAngle() {
@@ -5729,7 +6250,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5729
6250
  sphericalDelta.phi -= angle;
5730
6251
  }
5731
6252
  const panLeft = function() {
5732
- const v = new import_three18.Vector3();
6253
+ const v = new import_three20.Vector3();
5733
6254
  return function panLeft2(distance, objectMatrix) {
5734
6255
  v.setFromMatrixColumn(objectMatrix, 0);
5735
6256
  v.multiplyScalar(-distance);
@@ -5737,7 +6258,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5737
6258
  };
5738
6259
  }();
5739
6260
  const panUp = function() {
5740
- const v = new import_three18.Vector3();
6261
+ const v = new import_three20.Vector3();
5741
6262
  return function panUp2(distance, objectMatrix) {
5742
6263
  if (scope.screenSpacePanning === true) {
5743
6264
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -5750,7 +6271,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5750
6271
  };
5751
6272
  }();
5752
6273
  const pan = function() {
5753
- const offset = new import_three18.Vector3();
6274
+ const offset = new import_three20.Vector3();
5754
6275
  return function pan2(deltaX, deltaY) {
5755
6276
  const element = scope.domElement;
5756
6277
  if (scope.object.isPerspectiveCamera) {
@@ -5999,12 +6520,12 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5999
6520
  mouseAction = -1;
6000
6521
  }
6001
6522
  switch (mouseAction) {
6002
- case import_three18.MOUSE.DOLLY:
6523
+ case import_three20.MOUSE.DOLLY:
6003
6524
  if (scope.enableZoom === false) return;
6004
6525
  handleMouseDownDolly(event);
6005
6526
  state = STATE.DOLLY;
6006
6527
  break;
6007
- case import_three18.MOUSE.ROTATE:
6528
+ case import_three20.MOUSE.ROTATE:
6008
6529
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6009
6530
  if (scope.enablePan === false) return;
6010
6531
  handleMouseDownPan(event);
@@ -6015,7 +6536,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6015
6536
  state = STATE.ROTATE;
6016
6537
  }
6017
6538
  break;
6018
- case import_three18.MOUSE.PAN:
6539
+ case import_three20.MOUSE.PAN:
6019
6540
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6020
6541
  if (scope.enableRotate === false) return;
6021
6542
  handleMouseDownRotate(event);
@@ -6071,12 +6592,12 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6071
6592
  switch (pointers.length) {
6072
6593
  case 1:
6073
6594
  switch (scope.touches.ONE) {
6074
- case import_three18.TOUCH.ROTATE:
6595
+ case import_three20.TOUCH.ROTATE:
6075
6596
  if (scope.enableRotate === false) return;
6076
6597
  handleTouchStartRotate();
6077
6598
  state = STATE.TOUCH_ROTATE;
6078
6599
  break;
6079
- case import_three18.TOUCH.PAN:
6600
+ case import_three20.TOUCH.PAN:
6080
6601
  if (scope.enablePan === false) return;
6081
6602
  handleTouchStartPan();
6082
6603
  state = STATE.TOUCH_PAN;
@@ -6087,12 +6608,12 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6087
6608
  break;
6088
6609
  case 2:
6089
6610
  switch (scope.touches.TWO) {
6090
- case import_three18.TOUCH.DOLLY_PAN:
6611
+ case import_three20.TOUCH.DOLLY_PAN:
6091
6612
  if (scope.enableZoom === false && scope.enablePan === false) return;
6092
6613
  handleTouchStartDollyPan();
6093
6614
  state = STATE.TOUCH_DOLLY_PAN;
6094
6615
  break;
6095
- case import_three18.TOUCH.DOLLY_ROTATE:
6616
+ case import_three20.TOUCH.DOLLY_ROTATE:
6096
6617
  if (scope.enableZoom === false && scope.enableRotate === false) return;
6097
6618
  handleTouchStartDollyRotate();
6098
6619
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -6159,7 +6680,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6159
6680
  function trackPointer(event) {
6160
6681
  let position = pointerPositions[event.pointerId];
6161
6682
  if (position === void 0) {
6162
- position = new import_three18.Vector2();
6683
+ position = new import_three20.Vector2();
6163
6684
  pointerPositions[event.pointerId] = position;
6164
6685
  }
6165
6686
  position.set(event.pageX, event.pageY);
@@ -6179,10 +6700,10 @@ var MapControls = class extends OrbitControls {
6179
6700
  constructor(object, domElement) {
6180
6701
  super(object, domElement);
6181
6702
  this.screenSpacePanning = false;
6182
- this.mouseButtons.LEFT = import_three18.MOUSE.PAN;
6183
- this.mouseButtons.RIGHT = import_three18.MOUSE.ROTATE;
6184
- this.touches.ONE = import_three18.TOUCH.PAN;
6185
- this.touches.TWO = import_three18.TOUCH.DOLLY_ROTATE;
6703
+ this.mouseButtons.LEFT = import_three20.MOUSE.PAN;
6704
+ this.mouseButtons.RIGHT = import_three20.MOUSE.ROTATE;
6705
+ this.touches.ONE = import_three20.TOUCH.PAN;
6706
+ this.touches.TWO = import_three20.TOUCH.DOLLY_ROTATE;
6186
6707
  }
6187
6708
  };
6188
6709
 
@@ -6190,8 +6711,6 @@ var MapControls = class extends OrbitControls {
6190
6711
  var _Renderer = class _Renderer {
6191
6712
  constructor(options) {
6192
6713
  this._dirty = true;
6193
- this._animationTimer = void 0;
6194
- this._animationFrame = void 0;
6195
6714
  this._resizeListener = void 0;
6196
6715
  this._disposed = false;
6197
6716
  this._debugHelpers = [];
@@ -6199,9 +6718,9 @@ var _Renderer = class _Renderer {
6199
6718
  this._changeListener = () => {
6200
6719
  this._dirty = true;
6201
6720
  };
6202
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6721
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6203
6722
  this._animationLoop = this.animate.bind(this);
6204
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6723
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6205
6724
  this._scene = this.createScene();
6206
6725
  this._camera = this.createCamera();
6207
6726
  this._renderer = this.createRenderer();
@@ -6221,14 +6740,14 @@ var _Renderer = class _Renderer {
6221
6740
  switch (this.options.camera.type) {
6222
6741
  case "perspective":
6223
6742
  default:
6224
- return new import_three19.PerspectiveCamera(
6743
+ return new import_three21.PerspectiveCamera(
6225
6744
  this.options.camera.perspective.fov,
6226
6745
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6227
6746
  this.options.camera.near,
6228
6747
  this.options.camera.far
6229
6748
  );
6230
6749
  case "orthographic":
6231
- return new import_three19.OrthographicCamera(
6750
+ return new import_three21.OrthographicCamera(
6232
6751
  this.options.camera.orthographic.left ?? this.viewWidth / -2,
6233
6752
  this.options.camera.orthographic.right ?? this.viewWidth / 2,
6234
6753
  this.options.camera.orthographic.top ?? this.viewHeight / 2,
@@ -6239,7 +6758,7 @@ var _Renderer = class _Renderer {
6239
6758
  }
6240
6759
  }
6241
6760
  createRenderer() {
6242
- const renderer = new import_three19.WebGLRenderer({
6761
+ const renderer = new import_three21.WebGLRenderer({
6243
6762
  antialias: this.options.render.antialias,
6244
6763
  alpha: true,
6245
6764
  powerPreference: "high-performance",
@@ -6247,14 +6766,14 @@ var _Renderer = class _Renderer {
6247
6766
  });
6248
6767
  renderer.setClearColor(0, 0);
6249
6768
  renderer.shadowMap.enabled = true;
6250
- renderer.shadowMap.type = import_three19.PCFSoftShadowMap;
6251
- renderer.outputEncoding = import_three19.LinearEncoding;
6769
+ renderer.shadowMap.type = import_three21.PCFSoftShadowMap;
6770
+ renderer.outputColorSpace = import_three21.SRGBColorSpace;
6252
6771
  renderer.setSize(this.viewWidth, this.viewHeight);
6253
6772
  return renderer;
6254
6773
  }
6255
6774
  createComposer() {
6775
+ if (!this.options.composer.enabled) return void 0;
6256
6776
  const composer = new import_postprocessing.EffectComposer(this.renderer);
6257
- if (!this.options.composer.enabled) return composer;
6258
6777
  composer.setSize(this.viewWidth, this.viewHeight);
6259
6778
  composer.addPass(new import_postprocessing.RenderPass(this.scene, this.camera));
6260
6779
  return composer;
@@ -6282,20 +6801,20 @@ var _Renderer = class _Renderer {
6282
6801
  window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6283
6802
  }
6284
6803
  if (this.options.debug.grid) {
6285
- const gridHelper = new import_three19.GridHelper(128, 16);
6804
+ const gridHelper = new import_three21.GridHelper(128, 16);
6286
6805
  this._debugHelpers.push(gridHelper);
6287
6806
  this.scene.add(gridHelper);
6288
- const gridHelper2 = new import_three19.GridHelper(128, 16);
6807
+ const gridHelper2 = new import_three21.GridHelper(128, 16);
6289
6808
  this._debugHelpers.push(gridHelper2);
6290
6809
  gridHelper2.rotation.x = 90 * (Math.PI / 180);
6291
6810
  this.scene.add(gridHelper2);
6292
- const gridHelper3 = new import_three19.GridHelper(128, 16);
6811
+ const gridHelper3 = new import_three21.GridHelper(128, 16);
6293
6812
  this._debugHelpers.push(gridHelper3);
6294
6813
  gridHelper3.rotation.z = 90 * (Math.PI / 180);
6295
6814
  this.scene.add(gridHelper3);
6296
6815
  }
6297
6816
  if (this.options.debug.axes) {
6298
- const axesHelper = new import_three19.AxesHelper(64);
6817
+ const axesHelper = new import_three21.AxesHelper(64);
6299
6818
  this._debugHelpers.push(axesHelper);
6300
6819
  this.scene.add(axesHelper);
6301
6820
  }
@@ -6363,7 +6882,7 @@ var _Renderer = class _Renderer {
6363
6882
  this.camera.updateProjectionMatrix();
6364
6883
  }
6365
6884
  this.renderer.setSize(width, height);
6366
- this.composer.setSize(width, height);
6885
+ this.composer?.setSize(width, height);
6367
6886
  this._dirty = true;
6368
6887
  }
6369
6888
  //<editor-fold desc="RENDER">
@@ -6382,12 +6901,7 @@ var _Renderer = class _Renderer {
6382
6901
  stop() {
6383
6902
  if (this._disposed) return;
6384
6903
  this.renderer.setAnimationLoop(null);
6385
- if (this._animationTimer)
6386
- clearTimeout(this._animationTimer);
6387
- this._animationTimer = void 0;
6388
- if (this._animationFrame)
6389
- cancelAnimationFrame(this._animationFrame);
6390
- this._animationFrame = void 0;
6904
+ this._nextFrameTime = void 0;
6391
6905
  }
6392
6906
  /**
6393
6907
  * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
@@ -6427,25 +6941,30 @@ var _Renderer = class _Renderer {
6427
6941
  }
6428
6942
  }
6429
6943
  this._debugHelpers.length = 0;
6430
- this.composer.dispose();
6944
+ this.composer?.dispose();
6431
6945
  this.renderer.dispose();
6432
6946
  this.renderer.forceContextLoss();
6433
6947
  }
6434
- animate(t) {
6948
+ animate(t = performance.now()) {
6435
6949
  if (this._disposed) return;
6436
- if (this._stats) {
6437
- this._stats.begin();
6438
- }
6439
6950
  if (this._controls?.enabled) {
6440
6951
  this._controls.update();
6441
6952
  }
6442
6953
  if (this._disposed) return;
6443
- if (this.dirty || this.options.render.renderAlways) {
6444
- if (this.options.composer.enabled) {
6445
- this.composer.render();
6446
- } else {
6447
- this.renderer.render(this.scene, this.camera);
6448
- }
6954
+ if (!this.dirty && !this.options.render.renderAlways) return;
6955
+ const interval = this._frameInterval;
6956
+ if (interval) {
6957
+ const next = this._nextFrameTime;
6958
+ if (next !== void 0 && t + 0.1 < next) return;
6959
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6960
+ }
6961
+ if (this._stats) {
6962
+ this._stats.begin();
6963
+ }
6964
+ if (this.options.composer.enabled && this.composer) {
6965
+ this.composer.render();
6966
+ } else {
6967
+ this.renderer.render(this.scene, this.camera);
6449
6968
  }
6450
6969
  this.dirty = false;
6451
6970
  if (this._stats) {
@@ -6484,7 +7003,7 @@ var _Renderer = class _Renderer {
6484
7003
  }
6485
7004
  ///
6486
7005
  };
6487
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
7006
+ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6488
7007
  camera: {
6489
7008
  type: "perspective",
6490
7009
  near: 1,
@@ -6499,8 +7018,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
6499
7018
  top: void 0,
6500
7019
  bottom: void 0
6501
7020
  },
6502
- position: new import_three19.Vector3(50, 50, 50),
6503
- lookingAt: new import_three19.Vector3(0, 0, 0)
7021
+ position: new import_three21.Vector3(50, 50, 50),
7022
+ lookingAt: new import_three21.Vector3(0, 0, 0)
6504
7023
  },
6505
7024
  render: {
6506
7025
  fpsLimit: 60,
@@ -6533,7 +7052,7 @@ var Skins = class {
6533
7052
  return this.fromUsername(uuidOrUsername);
6534
7053
  }
6535
7054
  static async fromUuid(uuid) {
6536
- return this.getSkinProxySkinUrl(uuid);
7055
+ return this.getMcProxySkinUrl(uuid);
6537
7056
  }
6538
7057
  static async fromUsername(username) {
6539
7058
  return this.usernameToUuid(username).then((uuid) => {
@@ -6560,7 +7079,7 @@ var Skins = class {
6560
7079
  return this.capeFromUsername(uuidOrUsername);
6561
7080
  }
6562
7081
  static async capeFromUuid(uuid) {
6563
- return this.getSkinProxyCapeUrl(uuid);
7082
+ return this.getMcProxyCapeUrl(uuid);
6564
7083
  }
6565
7084
  static async capeFromUsername(username) {
6566
7085
  return this.usernameToUuid(username).then((uuid) => {
@@ -6570,19 +7089,31 @@ var Skins = class {
6570
7089
  return void 0;
6571
7090
  });
6572
7091
  }
6573
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
6574
- return this.getCapesDev(uuid, capeType).then((cape) => {
6575
- if (cape) {
6576
- return cape?.stillImageUrl;
6577
- }
6578
- return void 0;
6579
- });
7092
+ /** Returns a full static cape texture for a username or UUID. */
7093
+ static async capeFromCapesDev(player, capeType = "minecraft") {
7094
+ const cape = await this.getCapesDev(player, capeType);
7095
+ return cape?.exists ? cape.imageUrls?.still?.full : void 0;
6580
7096
  }
6581
7097
  //</editor-fold>
6582
7098
  //<editor-fold desc="Helpers">
6583
7099
  static async usernameToUuid(username) {
6584
- return this.usernameToUuidSkinProxy(username);
7100
+ return this.usernameToUuidMcProxy(username);
7101
+ }
7102
+ static async usernameToUuidMcProxy(username) {
7103
+ return Requests.genericRequest({
7104
+ baseURL: "https://mcproxy.dev",
7105
+ url: "/uuid/" + username
7106
+ }).then((res) => {
7107
+ if (res.status === 200) {
7108
+ return res.data["data"]["id"];
7109
+ }
7110
+ return void 0;
7111
+ }).catch((err) => {
7112
+ console.warn(err);
7113
+ return void 0;
7114
+ });
6585
7115
  }
7116
+ /** @deprecated **/
6586
7117
  static async usernameToUuidSkinProxy(username) {
6587
7118
  return Requests.genericRequest({
6588
7119
  baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
@@ -6635,18 +7166,15 @@ var Skins = class {
6635
7166
  return void 0;
6636
7167
  });
6637
7168
  }
6638
- static async getCapesDev(uuid, type = "all") {
7169
+ static async getCapesDev(player, type = "all") {
6639
7170
  return Requests.genericRequest({
6640
7171
  baseURL: "https://api.capes.dev",
6641
- url: "/load/" + uuid + "/" + type
7172
+ url: "/load/" + encodeURIComponent(player) + "/" + encodeURIComponent(type)
6642
7173
  }).then((res) => {
6643
7174
  if (res.status === 200) {
6644
7175
  return res.data;
6645
7176
  }
6646
7177
  return void 0;
6647
- }).catch((err) => {
6648
- console.warn(err);
6649
- return void 0;
6650
7178
  });
6651
7179
  }
6652
7180
  static getCrafatarSkinUrl(uuid) {
@@ -6661,20 +7189,28 @@ var Skins = class {
6661
7189
  static getMineSkinPlayerSkinUrl(uuid) {
6662
7190
  return "https://mineskin.org/skin/player/" + uuid;
6663
7191
  }
7192
+ /** @deprecated **/
6664
7193
  static getSkinProxySkinUrl(uuid) {
6665
7194
  return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6666
7195
  }
7196
+ /** @deprecated **/
6667
7197
  static getSkinProxyCapeUrl(uuid) {
6668
7198
  return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6669
7199
  }
7200
+ static getMcProxySkinUrl(uuid) {
7201
+ return "https://mcproxy.dev/skin/" + uuid;
7202
+ }
7203
+ static getMcProxyCapeUrl(uuid) {
7204
+ return "https://mcproxy.dev/cape/" + uuid;
7205
+ }
6670
7206
  //</editor-fold>
6671
7207
  };
6672
7208
 
6673
7209
  // src/world/Chunk.ts
6674
- var import_three22 = require("three");
7210
+ var import_three24 = require("three");
6675
7211
 
6676
7212
  // src/world/MineRenderWorld.ts
6677
- var import_three21 = require("three");
7213
+ var import_three23 = require("three");
6678
7214
  var MineRenderWorld = class {
6679
7215
  constructor(scene) {
6680
7216
  this._size = 4;
@@ -6685,10 +7221,10 @@ var MineRenderWorld = class {
6685
7221
  }
6686
7222
  getBlockAt(posOrX, y, z) {
6687
7223
  if (typeof posOrX == "number") {
6688
- return this.getBlockAt(new import_three21.Vector3(posOrX, y, z));
7224
+ return this.getBlockAt(new import_three23.Vector3(posOrX, y, z));
6689
7225
  }
6690
7226
  if (isTripleArray(posOrX)) {
6691
- return this.getBlockAt(new import_three21.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7227
+ return this.getBlockAt(new import_three23.Vector3(posOrX[0], posOrX[1], posOrX[2]));
6692
7228
  }
6693
7229
  const chunk = this.getChunkAt(posOrX);
6694
7230
  if (typeof chunk === "undefined") {
@@ -6699,10 +7235,10 @@ var MineRenderWorld = class {
6699
7235
  }
6700
7236
  async setBlockAt(posOrX, yOrBlock, z, block) {
6701
7237
  if (typeof posOrX == "number") {
6702
- return this.setBlockAt(new import_three21.Vector3(posOrX, yOrBlock, z), block);
7238
+ return this.setBlockAt(new import_three23.Vector3(posOrX, yOrBlock, z), block);
6703
7239
  }
6704
7240
  if (isTripleArray(posOrX)) {
6705
- return this.setBlockAt(new import_three21.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7241
+ return this.setBlockAt(new import_three23.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6706
7242
  }
6707
7243
  this.validatePosBounds(posOrX);
6708
7244
  const chunk = this.getOrCreateChunkAt(posOrX);
@@ -6748,14 +7284,14 @@ var MineRenderWorld = class {
6748
7284
  return this._chunks[index];
6749
7285
  }
6750
7286
  static worldToScenePosition(pos) {
6751
- return new import_three21.Vector3(
7287
+ return new import_three23.Vector3(
6752
7288
  pos.x * 16,
6753
7289
  pos.y * 16,
6754
7290
  pos.z * 16
6755
7291
  );
6756
7292
  }
6757
7293
  static sceneToWorldPosition(pos) {
6758
- return new import_three21.Vector3(
7294
+ return new import_three23.Vector3(
6759
7295
  pos.x / 16,
6760
7296
  pos.y / 16,
6761
7297
  pos.z / 16
@@ -6784,7 +7320,7 @@ var MineRenderWorld = class {
6784
7320
  };
6785
7321
 
6786
7322
  // src/world/Chunk.ts
6787
- var p12 = prefix("Chunk");
7323
+ var p11 = prefix("Chunk");
6788
7324
  var Chunk = class _Chunk {
6789
7325
  constructor(scene, x, y, z) {
6790
7326
  this._blocks = [];
@@ -6792,12 +7328,12 @@ var Chunk = class _Chunk {
6792
7328
  this.x = x;
6793
7329
  this.y = y;
6794
7330
  this.z = z;
6795
- let anchor = new import_three22.Object3D();
7331
+ let anchor = new import_three24.Object3D();
6796
7332
  this._anchor = anchor;
6797
7333
  scene.add(anchor);
6798
7334
  anchor.position.set(this.x * 256 + 128 - 8, this.y * 256 + 128 - 8, this.z * 256 + 128 - 8);
6799
7335
  addBox3WireframeToObject(
6800
- new import_three22.Box3(new import_three22.Vector3(0, 0, 0), new import_three22.Vector3(256, 256, 256)),
7336
+ new import_three24.Box3(new import_three24.Vector3(0, 0, 0), new import_three24.Vector3(256, 256, 256)),
6801
7337
  anchor,
6802
7338
  16776960,
6803
7339
  4
@@ -6805,10 +7341,10 @@ var Chunk = class _Chunk {
6805
7341
  }
6806
7342
  getBlockAt(posOrX, y, z) {
6807
7343
  if (typeof posOrX == "number") {
6808
- return this.getBlockAt(new import_three22.Vector3(posOrX, y, z));
7344
+ return this.getBlockAt(new import_three24.Vector3(posOrX, y, z));
6809
7345
  }
6810
7346
  if (isTripleArray(posOrX)) {
6811
- return this.getBlockAt(new import_three22.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7347
+ return this.getBlockAt(new import_three24.Vector3(posOrX[0], posOrX[1], posOrX[2]));
6812
7348
  }
6813
7349
  const pos = this.worldPosToChunkPos(posOrX);
6814
7350
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -6816,10 +7352,10 @@ var Chunk = class _Chunk {
6816
7352
  }
6817
7353
  async setBlockAt(posOrX, yOrBlock, z, block) {
6818
7354
  if (typeof posOrX == "number") {
6819
- return this.setBlockAt(new import_three22.Vector3(posOrX, yOrBlock, z), block);
7355
+ return this.setBlockAt(new import_three24.Vector3(posOrX, yOrBlock, z), block);
6820
7356
  }
6821
7357
  if (isTripleArray(posOrX)) {
6822
- return this.setBlockAt(new import_three22.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7358
+ return this.setBlockAt(new import_three24.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6823
7359
  }
6824
7360
  const worldPos = posOrX;
6825
7361
  const pos = this.worldPosToChunkPos(worldPos);
@@ -6836,7 +7372,7 @@ var Chunk = class _Chunk {
6836
7372
  const index = _Chunk.chunkPosToBlockIndex(pos);
6837
7373
  const current = this._blocks[index];
6838
7374
  if (typeof current !== "undefined") {
6839
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
7375
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6840
7376
  current.object.removeFromScene();
6841
7377
  delete this._blocks[index];
6842
7378
  }
@@ -6865,7 +7401,7 @@ var Chunk = class _Chunk {
6865
7401
  }
6866
7402
  async clear() {
6867
7403
  let promises = [];
6868
- let pos = new import_three22.Vector3();
7404
+ let pos = new import_three24.Vector3();
6869
7405
  for (let x = 0; x < 16; x++) {
6870
7406
  for (let z = 0; z < 16; z++) {
6871
7407
  for (let y = 0; y < 16; y++) {
@@ -6884,14 +7420,14 @@ var Chunk = class _Chunk {
6884
7420
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
6885
7421
  }
6886
7422
  worldPosToChunkPos(pos) {
6887
- return new import_three22.Vector3(
7423
+ return new import_three24.Vector3(
6888
7424
  pos.x - this.x * 16,
6889
7425
  pos.y - this.y * 16,
6890
7426
  pos.z - this.z * 16
6891
7427
  );
6892
7428
  }
6893
7429
  chunkPosToWorldPos(pos) {
6894
- return new import_three22.Vector3(
7430
+ return new import_three24.Vector3(
6895
7431
  this.x * 16 + pos.x,
6896
7432
  this.y * 16 + pos.y,
6897
7433
  this.z * 16 + pos.z