minerender 2.1.0-alpha.3 → 2.1.0-alpha.31

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