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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,14 +28,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  mod
29
29
  ));
30
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
- var __decorateClass = (decorators, target, key, kind) => {
32
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
33
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
34
- if (decorator = decorators[i])
35
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
36
- if (kind && result) __defProp(target, key, result);
37
- return result;
38
- };
39
31
 
40
32
  // ../../node_modules/ts-deepmerge/dist/index.js
41
33
  var require_dist = __commonJS({
@@ -45,8 +37,8 @@ var require_dist = __commonJS({
45
37
  __assign = Object.assign || function(t) {
46
38
  for (var s, i = 1, n = arguments.length; i < n; i++) {
47
39
  s = arguments[i];
48
- for (var p13 in s) if (Object.prototype.hasOwnProperty.call(s, p13))
49
- t[p13] = s[p13];
40
+ for (var p12 in s) if (Object.prototype.hasOwnProperty.call(s, p12))
41
+ t[p12] = s[p12];
50
42
  }
51
43
  return t;
52
44
  };
@@ -90,7 +82,7 @@ var require_dist = __commonJS({
90
82
  return false;
91
83
  };
92
84
  var PROTECTED_KEYS = ["__proto__"];
93
- var merge11 = function() {
85
+ var merge10 = function() {
94
86
  var objects = [];
95
87
  for (var _i = 0; _i < arguments.length; _i++) {
96
88
  objects[_i] = arguments[_i];
@@ -101,9 +93,9 @@ var require_dist = __commonJS({
101
93
  return;
102
94
  }
103
95
  if (Array.isArray(result[key]) && Array.isArray(current[key])) {
104
- result[key] = merge11.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
96
+ result[key] = merge10.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
105
97
  } else if (isObject(result[key]) && isObject(current[key])) {
106
- result[key] = merge11(result[key], current[key]);
98
+ result[key] = merge10(result[key], current[key]);
107
99
  } else {
108
100
  result[key] = current[key];
109
101
  }
@@ -114,18 +106,18 @@ var require_dist = __commonJS({
114
106
  var defaultOptions = {
115
107
  mergeArrays: true
116
108
  };
117
- merge11.options = defaultOptions;
118
- merge11.withOptions = function(options) {
109
+ merge10.options = defaultOptions;
110
+ merge10.withOptions = function(options) {
119
111
  var objects = [];
120
112
  for (var _i = 1; _i < arguments.length; _i++) {
121
113
  objects[_i - 1] = arguments[_i];
122
114
  }
123
- merge11.options = __assign({ mergeArrays: true }, options);
124
- var result = merge11.apply(void 0, __spreadArray([], __read(objects), false));
125
- merge11.options = defaultOptions;
115
+ merge10.options = __assign({ mergeArrays: true }, options);
116
+ var result = merge10.apply(void 0, __spreadArray([], __read(objects), false));
117
+ merge10.options = defaultOptions;
126
118
  return result;
127
119
  };
128
- exports2.default = merge11;
120
+ exports2.default = merge10;
129
121
  }
130
122
  });
131
123
 
@@ -135,6 +127,7 @@ __export(index_node_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_node_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
  CUBE_FACES: () => CUBE_FACES,
152
145
  Caching: () => Caching,
@@ -161,8 +154,8 @@ __export(index_node_exports, {
161
154
  DISPLAY_POSITIONS: () => DISPLAY_POSITIONS,
162
155
  DefaultBlockStates: () => DefaultBlockStates,
163
156
  DisplayPosition: () => DisplayPosition,
157
+ DisplayTransforms: () => DisplayTransforms,
164
158
  Entities: () => Entities,
165
- EntityModels: () => EntityModels,
166
159
  EntityObject: () => EntityObject,
167
160
  Env: () => Env,
168
161
  Geometries: () => Geometries,
@@ -192,6 +185,7 @@ __export(index_node_exports, {
192
185
  OrbitControls: () => OrbitControls,
193
186
  PersistentCache: () => PersistentCache,
194
187
  Renderer: () => Renderer,
188
+ RequestError: () => RequestError,
195
189
  Requests: () => Requests,
196
190
  SKIN_PARTS: () => SKIN_PARTS,
197
191
  SceneInspector: () => SceneInspector,
@@ -201,6 +195,7 @@ __export(index_node_exports, {
201
195
  SchematicParser: () => SchematicParser,
202
196
  SkinObject: () => SkinObject,
203
197
  SkinPart: () => SkinPart,
198
+ SkinTextures: () => SkinTextures,
204
199
  Skins: () => Skins,
205
200
  StructureParser: () => StructureParser,
206
201
  TextureAtlas: () => TextureAtlas,
@@ -215,10 +210,10 @@ __export(index_node_exports, {
215
210
  addWireframeToObject: () => addWireframeToObject,
216
211
  applyElementRotation: () => applyElementRotation,
217
212
  applyGenericRotation: () => applyGenericRotation,
218
- applyModelPartRotation: () => applyModelPartRotation,
219
213
  axisToVec3: () => axisToVec3,
220
214
  base64decode: () => base64decode,
221
215
  base64encode: () => base64encode,
216
+ capeTextureSizes: () => capeTextureSizes,
222
217
  captureException: () => captureException,
223
218
  changeEvent: () => changeEvent,
224
219
  clampRotationDegrees: () => clampRotationDegrees,
@@ -302,25 +297,29 @@ var Env = class {
302
297
  };
303
298
 
304
299
  // src/cache/PersistentCache.ts
305
- var _PersistentCache = class _PersistentCache {
300
+ var PersistentCache = class _PersistentCache {
306
301
  constructor(backing) {
307
302
  this.backing = backing;
308
303
  }
304
+ static {
305
+ /** Bump to invalidate every persisted entry. */
306
+ this.VERSION = 2;
307
+ }
309
308
  static open(name) {
310
309
  return Env.provider.openCache(name, _PersistentCache.VERSION);
311
310
  }
311
+ /** Loads a missing entry and stores only non-nullish results. */
312
312
  async getOrLoad(key, loader) {
313
313
  let v = await this.get(key);
314
314
  if (typeof v === "undefined" || v === null) {
315
315
  v = await loader(key);
316
- await this.put(key, v);
316
+ if (typeof v !== "undefined" && v !== null) {
317
+ await this.put(key, v);
318
+ }
317
319
  }
318
320
  return v;
319
321
  }
320
322
  };
321
- /** Bump to invalidate every persisted entry. */
322
- _PersistentCache.VERSION = 1;
323
- var PersistentCache = _PersistentCache;
324
323
 
325
324
  // src/env/node/NodeCache.ts
326
325
  var NodeCache = class extends PersistentCache {
@@ -398,7 +397,7 @@ registerNodeEnv();
398
397
  // src/Axis.ts
399
398
  var import_three = require("three");
400
399
  var Axis = /* @__PURE__ */ ((Axis3) => {
401
- Axis3["X"] = "X";
400
+ Axis3["X"] = "x";
402
401
  Axis3["Y"] = "y";
403
402
  Axis3["Z"] = "z";
404
403
  return Axis3;
@@ -406,7 +405,7 @@ var Axis = /* @__PURE__ */ ((Axis3) => {
406
405
  var AXES = Object.values(Axis);
407
406
  function axisToVec3(axis) {
408
407
  switch (axis) {
409
- case "X" /* X */:
408
+ case "x" /* X */:
410
409
  return new import_three.Vector3(1, 0, 0);
411
410
  case "y" /* Y */:
412
411
  return new import_three.Vector3(0, 1, 0);
@@ -494,8 +493,7 @@ function serializeImageKey(key) {
494
493
  return md5(key.src);
495
494
  }
496
495
  function serializeBoxGeometryKey(key) {
497
- var _a;
498
- return md5([key.width, key.height, key.depth, (_a = key.uv) == null ? void 0 : _a.join(":")].join("_"));
496
+ return md5([key.width, key.height, key.depth, key.uv?.join(":")].join("_"));
499
497
  }
500
498
  function serializeTextureKey(key) {
501
499
  return md5([key.src, key.format, key.rotation].join("$"));
@@ -510,7 +508,67 @@ function serializeMeshKey(key) {
510
508
  // src/cache/Caching.ts
511
509
  var import_loading_cache = require("@inventivetalent/loading-cache");
512
510
  var import_time = require("@inventivetalent/time");
513
- var Caching = class {
511
+ var Caching = class _Caching {
512
+ static {
513
+ this.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();
514
+ }
515
+ static {
516
+ this.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();
517
+ }
518
+ static {
519
+ this.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();
520
+ }
521
+ static {
522
+ this.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();
523
+ }
524
+ static {
525
+ this.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();
526
+ }
527
+ static {
528
+ this.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();
529
+ }
530
+ static {
531
+ this.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();
532
+ }
533
+ static {
534
+ this.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();
535
+ }
536
+ static {
537
+ this.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();
538
+ }
539
+ static {
540
+ this.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();
541
+ }
542
+ static {
543
+ this.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();
544
+ }
545
+ static {
546
+ this.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();
547
+ }
548
+ static {
549
+ this.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();
550
+ }
551
+ static {
552
+ this.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();
553
+ }
554
+ static {
555
+ this.listAssetCache = _Caching.createAssetCache();
556
+ }
557
+ static {
558
+ this.defaultBlockStatesCache = _Caching.createAssetCache();
559
+ }
560
+ static {
561
+ this.blockTintCache = _Caching.createAssetCache();
562
+ }
563
+ static {
564
+ this.entityModelCache = _Caching.createAssetCache();
565
+ }
566
+ static {
567
+ this.entityTextureCache = _Caching.createAssetCache();
568
+ }
569
+ static createAssetCache() {
570
+ 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();
571
+ }
514
572
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
515
573
  static get all() {
516
574
  return [
@@ -527,7 +585,12 @@ var Caching = class {
527
585
  this.rawModelCache,
528
586
  this.mergedModelCache,
529
587
  this.modelTextureAtlasCache,
530
- this.blockStateCache
588
+ this.blockStateCache,
589
+ this.listAssetCache,
590
+ this.defaultBlockStatesCache,
591
+ this.blockTintCache,
592
+ this.entityModelCache,
593
+ this.entityTextureCache
531
594
  ];
532
595
  }
533
596
  static clear() {
@@ -538,8 +601,8 @@ var Caching = class {
538
601
  /**
539
602
  * Clears every cache and stops its expiry timer.
540
603
  *
541
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
542
- * this is called - see {@link shutdown}.
604
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
605
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
543
606
  */
544
607
  static end() {
545
608
  for (const cache of this.all) {
@@ -553,20 +616,6 @@ var Caching = class {
553
616
  };
554
617
  }
555
618
  };
556
- 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();
557
- 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();
558
- 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();
559
- 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();
560
- 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();
561
- 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();
562
- 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();
563
- 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();
564
- 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();
565
- 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();
566
- 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();
567
- 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();
568
- 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();
569
- 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();
570
619
 
571
620
  // src/Geometries.ts
572
621
  var Geometries = class _Geometries {
@@ -587,13 +636,14 @@ var Geometries = class _Geometries {
587
636
  };
588
637
 
589
638
  // src/Materials.ts
590
- var import_three6 = require("three");
639
+ var import_three5 = require("three");
591
640
 
592
641
  // src/texture/Textures.ts
593
- var import_three5 = require("three");
642
+ var import_three4 = require("three");
594
643
 
595
644
  // src/texture/TextureLoader.ts
596
- var import_three4 = require("three");
645
+ var import_three3 = require("three");
646
+ var THREE = __toESM(require("three"));
597
647
 
598
648
  // src/canvas/CanvasCompat.ts
599
649
  function createImage(width, height) {
@@ -604,9 +654,7 @@ function createCanvas2(width, height) {
604
654
  }
605
655
 
606
656
  // src/request/Requests.ts
607
- var import_axios = __toESM(require("axios"));
608
657
  var import_jobqu = require("jobqu");
609
- var import_time2 = require("@inventivetalent/time");
610
658
 
611
659
  // src/util/log.ts
612
660
  var Reset = "\x1B[0m";
@@ -616,198 +664,174 @@ function prefix(prefix2) {
616
664
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
617
665
  }
618
666
 
619
- // src/util/BatchedExecutor.ts
620
- var BatchedExecutor = class {
621
- constructor(interval = 1, batch = 30) {
622
- this.interval = interval;
623
- this.batch = batch;
624
- this.queue = [];
625
- this.task = setInterval(() => this.run());
626
- }
627
- submit(task) {
628
- this.queue.push(task);
629
- }
630
- run() {
631
- for (let i = 0; i < this.batch; i++) {
632
- this.runNext();
633
- }
634
- }
635
- runNext() {
636
- let next = this.queue.shift();
637
- if (next) next();
667
+ // src/request/Requests.ts
668
+ var p = prefix("Requests");
669
+ var RequestError = class extends Error {
670
+ constructor(message, response, cause) {
671
+ super(message);
672
+ this.response = response;
673
+ this.cause = cause;
674
+ this.name = "RequestError";
638
675
  }
639
676
  };
640
-
641
- // src/util/model.ts
642
- var import_three3 = require("three");
643
- function applyElementRotation(rotation, geometry) {
644
- const origin = new import_three3.Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
645
- geometry.translate(-origin.x, -origin.y, -origin.z);
646
- switch (rotation.axis) {
647
- case "X" /* X */:
648
- geometry.rotateX(toRadians(rotation.angle));
649
- break;
650
- case "y" /* Y */:
651
- geometry.rotateY(toRadians(rotation.angle));
652
- break;
653
- case "z" /* Z */:
654
- geometry.rotateZ(toRadians(rotation.angle));
655
- break;
656
- }
657
- if (rotation.rescale) {
658
- if (Math.abs(rotation.angle) === 22.5) {
659
- const s = 1 / Math.cos(0.39269909262657166);
660
- geometry.scale(s, 1, s);
661
- } else {
662
- const s = 1 / Math.cos(0.7853981852531433);
663
- geometry.scale(s, 1, s);
677
+ async function fetchRequest(config, defaultBaseURL) {
678
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
679
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
680
+ const headers = new Headers(options.headers);
681
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
682
+ headers.set("User-Agent", "MineRender");
683
+ }
684
+ const attemptSignal = AbortSignal.any([
685
+ ...signal ? [signal] : [],
686
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
687
+ ]);
688
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
689
+ attemptSignal.throwIfAborted();
690
+ try {
691
+ const response = await fetch(request);
692
+ const result = {
693
+ data: void 0,
694
+ status: response.status,
695
+ statusText: response.statusText,
696
+ headers: response.headers,
697
+ url: response.url
698
+ };
699
+ if (!response.ok) {
700
+ await response.body?.cancel().catch(() => {
701
+ });
702
+ throw new RequestError(`Request failed with status ${response.status}`, result);
703
+ }
704
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
705
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
706
+ return { ...result, data };
707
+ } catch (error) {
708
+ attemptSignal.throwIfAborted();
709
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
710
+ throw new RequestError("Network request failed", void 0, error);
664
711
  }
712
+ throw error;
665
713
  }
666
- geometry.translate(origin.x, origin.y, origin.z);
667
- }
668
- function applyModelPartRotation(modelPart, geometry) {
669
- const origin = new import_three3.Vector3(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
670
- geometry.translate(-origin.x, -origin.y, -origin.z);
671
- geometry.rotateX(toRadians(modelPart.pitch));
672
- geometry.rotateY(toRadians(modelPart.yaw));
673
- geometry.rotateZ(toRadians(modelPart.roll));
674
- geometry.translate(origin.x, origin.y, origin.z);
675
714
  }
676
- function applyGenericRotation(axis, rotation, obj) {
677
- switch (axis) {
678
- case "X" /* X */:
679
- obj.rotateOnAxis(new import_three3.Vector3(1, 0, 0), toRadians(rotation));
680
- break;
681
- case "y" /* Y */:
682
- obj.rotateOnAxis(new import_three3.Vector3(0, 1, 0), toRadians(rotation));
683
- break;
684
- case "z" /* Z */:
685
- obj.rotateOnAxis(new import_three3.Vector3(0, 0, 1), toRadians(rotation));
686
- break;
715
+ async function abortable(promise, signal) {
716
+ if (!signal) return promise;
717
+ let abort;
718
+ const cancelled = new Promise((_, reject) => {
719
+ abort = () => reject(signal.reason);
720
+ signal.addEventListener("abort", abort, { once: true });
721
+ if (signal.aborted) abort();
722
+ });
723
+ try {
724
+ return await Promise.race([promise, cancelled]);
725
+ } finally {
726
+ signal.removeEventListener("abort", abort);
687
727
  }
688
728
  }
689
- function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
690
- let size = new import_three3.Vector3();
691
- box.getSize(size);
692
- let boxGeo = new import_three3.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
693
- let wireGeo = new import_three3.EdgesGeometry(boxGeo);
694
- let wireMat = new import_three3.LineBasicMaterial({ color, linewidth: w });
695
- let wireframe = new import_three3.LineSegments(wireGeo, wireMat);
696
- obj.add(wireframe);
697
- let axes = new import_three3.AxesHelper(1);
698
- obj.add(axes);
699
- }
700
- function addWireframeToObject(obj, color = 16777215, w = 2) {
701
- let boxGeo = new import_three3.BoxGeometry(16, 16, 16, 1, 1, 1);
702
- let wireGeo = new import_three3.EdgesGeometry(boxGeo);
703
- let wireMat = new import_three3.LineBasicMaterial({ color, linewidth: w });
704
- let wireframe = new import_three3.LineSegments(wireGeo, wireMat);
705
- obj.add(wireframe);
706
- let axes = new import_three3.AxesHelper(1);
707
- obj.add(axes);
708
- }
709
- function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
710
- let wireGeo = new import_three3.EdgesGeometry(geo);
711
- let wireMat = new import_three3.LineBasicMaterial({ color, linewidth: w });
712
- let wireframe = new import_three3.LineSegments(wireGeo, wireMat);
713
- mesh.add(wireframe);
714
- let axes = new import_three3.AxesHelper(1);
715
- mesh.add(axes);
716
- }
717
-
718
- // src/util/performance.ts
719
- function captureException(e, ...extra) {
720
- console.error(e, extra);
721
- }
722
- function timingStart(marker) {
723
- console.time(marker);
724
- }
725
- function timingEnd(marker) {
726
- console.timeEnd(marker);
727
- }
728
-
729
- // src/util/three.ts
730
- function isObject3D(obj) {
731
- return obj.isObject3D;
732
- }
733
- function isMesh(obj) {
734
- return obj.isMesh;
735
- }
736
- function isInstancedMesh(obj) {
737
- return obj.isInstancedMesh;
738
- }
739
- function isPerspectiveCamera(obj) {
740
- return obj.isPerspectiveCamera;
741
- }
742
- function isOrthographicCamera(obj) {
743
- return obj.isOrthographicCamera;
744
- }
745
-
746
- // src/request/Requests.ts
747
- var p = prefix("Requests");
748
- if (typeof window === "undefined") {
749
- import_axios.default.defaults.headers["User-Agent"] = "MineRender";
750
- }
751
- var _Requests = class _Requests {
752
- static genericRequest(request) {
753
- return this.genericQueue.add(request).catch(async (e) => {
754
- console.debug(p, "generic catch", e.code, e);
755
- if (this.shouldRetry(e, request)) {
756
- await sleep(100);
757
- return this.genericRequest(request);
758
- }
759
- throw e;
760
- });
761
- }
762
- static mcAssetRequest(request) {
763
- return this.mcAssetRequestQueue.add(request).catch((e) => {
764
- console.debug(p, "mcAssetRequest catch", e.code, e);
765
- throw e;
766
- });
729
+ var RequestQueue = class {
730
+ constructor() {
731
+ this.pendingRequests = 0;
732
+ this.stopped = new AbortController();
733
+ this.queue = new import_jobqu.JobQueue(
734
+ (request) => fetchRequest(request, this.baseURL),
735
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
736
+ );
767
737
  }
768
- static shouldRetry(e, request) {
769
- if ("code" in e) {
770
- if ("ECONNABORTED" === e.code) {
771
- if ("minerenderRetry" in request) {
772
- if (request["minerenderRetry"] > 0) {
773
- request["minerenderRetry"]--;
774
- return true;
738
+ async request(request) {
739
+ this.pendingRequests++;
740
+ const signal = request.signal;
741
+ try {
742
+ for (let retries = 0; ; retries++) {
743
+ signal?.throwIfAborted();
744
+ try {
745
+ return await abortable(this.queue.add(request), signal);
746
+ } catch (error) {
747
+ console.debug(p, "Request failed", error);
748
+ const delay = this.retryDelay(error, request, retries);
749
+ if (delay === void 0) {
750
+ throw error;
775
751
  }
776
- } else {
777
- request["minerenderRetry"] = 3;
778
- return true;
752
+ await this.waitForRetry(delay, signal);
779
753
  }
780
754
  }
755
+ } finally {
756
+ if (signal?.aborted) {
757
+ this.queue.remove(request);
758
+ }
759
+ this.pendingRequests--;
781
760
  }
782
- return false;
761
+ }
762
+ retryDelay(error, request, retries) {
763
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
764
+ return void 0;
765
+ }
766
+ if (error instanceof RequestError) {
767
+ const status = error.response?.status;
768
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
769
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
770
+ return void 0;
771
+ }
772
+ let delay = 100 * 2 ** retries;
773
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
774
+ if (retryAfter !== void 0 && retryAfter !== null) {
775
+ const seconds = Number(retryAfter);
776
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
777
+ return void 0;
778
+ }
779
+ delay = Math.max(delay, seconds * 1e3);
780
+ }
781
+ return delay;
782
+ }
783
+ async waitForRetry(delay, signal) {
784
+ let timer;
785
+ const waiting = new Promise((resolve) => {
786
+ timer = setTimeout(resolve, delay);
787
+ });
788
+ try {
789
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
790
+ } finally {
791
+ clearTimeout(timer);
792
+ }
793
+ }
794
+ get pendingSize() {
795
+ return this.pendingRequests;
796
+ }
797
+ end() {
798
+ this.queue.end();
799
+ this.stopped.abort(new import_jobqu.JobCancelledError("ended"));
800
+ }
801
+ };
802
+ var Requests = class {
803
+ static {
804
+ this.genericQueue = new RequestQueue();
805
+ }
806
+ static {
807
+ this.mcAssetRequestQueue = new RequestQueue();
808
+ }
809
+ static genericRequest(request) {
810
+ return this.genericQueue.request(request);
811
+ }
812
+ static mcAssetRequest(request) {
813
+ return this.mcAssetRequestQueue.request(request);
783
814
  }
784
815
  static setMcAssetRoot(root) {
785
- this.mcAssetInstance.defaults.baseURL = root;
816
+ this.mcAssetRequestQueue.baseURL = root;
786
817
  }
818
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
787
819
  static get queueSizes() {
788
820
  return {
789
- generic: this.genericQueue.size,
790
- mcAsset: this.mcAssetRequestQueue.size
821
+ generic: this.genericQueue.pendingSize,
822
+ mcAsset: this.mcAssetRequestQueue.pendingSize
791
823
  };
792
824
  }
793
825
  /**
794
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
795
- * exit until this is called - see {@link shutdown}.
826
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
827
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
828
+ * this cleanup. See {@link shutdown}.
796
829
  */
797
830
  static end() {
798
831
  this.genericQueue.end();
799
832
  this.mcAssetRequestQueue.end();
800
833
  }
801
834
  };
802
- _Requests.axiosInstance = import_axios.default.create({
803
- timeout: 5e3
804
- });
805
- _Requests.mcAssetInstance = import_axios.default.create({
806
- timeout: 5e3
807
- });
808
- _Requests.genericQueue = new import_jobqu.JobQueue((request) => _Requests.axiosInstance.request(request), import_time2.Time.millis(10), 1);
809
- _Requests.mcAssetRequestQueue = new import_jobqu.JobQueue((request) => _Requests.mcAssetInstance.request(request), import_time2.Time.millis(10), 1);
810
- var Requests = _Requests;
811
835
 
812
836
  // src/WrappedImage.ts
813
837
  var WrappedImage = class {
@@ -845,10 +869,10 @@ var WrappedImage = class {
845
869
  return this.animated ? this.width : this.height;
846
870
  }
847
871
  get frameCount() {
848
- return this.height / this.width;
872
+ return this.height / this.frameHeight;
849
873
  }
850
874
  getFrameY(frame) {
851
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
875
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
852
876
  }
853
877
  getSectionData(sx, sy, sw, sh) {
854
878
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -858,7 +882,7 @@ var WrappedImage = class {
858
882
  }
859
883
  getFrameSectionData(frame) {
860
884
  const y = this.getFrameY(frame);
861
- return this.getSectionData(0, y, this.width, this.width + y);
885
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
862
886
  }
863
887
  };
864
888
 
@@ -872,29 +896,41 @@ var ImageLoader = class _ImageLoader {
872
896
  static async loadAsync(src) {
873
897
  return new Promise((resolve, reject) => {
874
898
  const image = this._createImage();
875
- image.src = src;
876
899
  image.onload = () => resolve(image);
877
- image.onerror = (err) => reject(err);
900
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
901
+ image.src = src;
878
902
  });
879
903
  }
880
904
  static loadElement(src, onload, onerr) {
881
905
  const image = this._createImage();
882
- image.src = src;
883
906
  if (onload)
884
907
  image.onload = onload;
885
908
  if (onerr)
886
909
  image.onerror = onerr;
910
+ image.src = src;
887
911
  return image;
888
912
  }
889
913
  static async loadData(src) {
890
914
  console.debug(p2, "loadData", src);
891
- return await this.infoToData(await this.getInfo(src));
915
+ const image = await this.loadCanvasData(src);
916
+ return image.data.getImageData(0, 0, image.width, image.height);
892
917
  }
893
918
  static async loadCanvasData(src) {
894
- return await this.infoToCanvasData(await this.getInfo(src));
919
+ const keyStr = serializeImageKey({ src });
920
+ const info = this.getInfo(src);
921
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
922
+ try {
923
+ return await this.infoToCanvasData(await info);
924
+ } catch (err) {
925
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
926
+ Caching.rawImageCache.invalidate(keyStr);
927
+ }
928
+ throw err;
929
+ }
895
930
  }
896
931
  static async infoToCanvasData(info) {
897
- const image = await _ImageLoader.loadAsync(info.src);
932
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
933
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
898
934
  const canvas = createCanvas2(info.width, info.height);
899
935
  const context = canvas.getContext("2d");
900
936
  context.drawImage(image, 0, 0);
@@ -905,11 +941,8 @@ var ImageLoader = class _ImageLoader {
905
941
  };
906
942
  }
907
943
  static async infoToData(info) {
908
- const image = await _ImageLoader.loadAsync(info.src);
909
- const canvas = createCanvas2(info.width, info.height);
910
- const context = canvas.getContext("2d");
911
- context.drawImage(image, 0, 0);
912
- return context.getImageData(0, 0, canvas.width, canvas.height);
944
+ const image = await this.infoToCanvasData(info);
945
+ return image.data.getImageData(0, 0, image.width, image.height);
913
946
  }
914
947
  static async getData(src) {
915
948
  const keyStr = serializeImageKey({ src });
@@ -924,38 +957,25 @@ var ImageLoader = class _ImageLoader {
924
957
  });
925
958
  }
926
959
  static async processResponse(response) {
927
- const src = response.config.url;
960
+ const src = response.url;
928
961
  const data = import_buffer.Buffer.from(response.data);
929
962
  const { width, height, type } = Env.provider.imageSize(data);
963
+ if (!width || !height) {
964
+ throw new Error("Invalid or unsupported image dimensions");
965
+ }
930
966
  return {
931
967
  src,
932
- width: width || 0,
933
- height: height || 0,
968
+ width,
969
+ height,
934
970
  type,
935
971
  data
936
972
  };
937
973
  }
938
974
  static async loadInfo(src) {
939
- if (src.startsWith("data:image/png;base64")) {
940
- return this.processResponse({
941
- config: {
942
- url: src
943
- },
944
- data: import_buffer.Buffer.from(src.substr("data:image/png;base64,".length), "base64")
945
- });
946
- }
947
975
  return Requests.genericRequest({
948
976
  url: src,
949
977
  responseType: "arraybuffer"
950
- }).then(this.processResponse).catch((err) => {
951
- return {
952
- src,
953
- width: 0,
954
- height: 0,
955
- type: void 0,
956
- data: import_buffer.Buffer.from([0])
957
- };
958
- });
978
+ }).then(this.processResponse);
959
979
  }
960
980
  static async getInfo(src) {
961
981
  const keyStr = serializeImageKey({ src });
@@ -977,25 +997,39 @@ var ImageLoader = class _ImageLoader {
977
997
 
978
998
  // src/texture/TextureLoader.ts
979
999
  var TextureLoader = class {
1000
+ static {
1001
+ this.failedTextures = /* @__PURE__ */ new WeakSet();
1002
+ }
1003
+ /** Reports whether image loading failed, so cached textures can be retried. */
1004
+ static hasFailed(texture) {
1005
+ return this.failedTextures.has(texture);
1006
+ }
980
1007
  static createTexture() {
981
- return new import_three4.Texture();
1008
+ return new import_three3.Texture();
982
1009
  }
983
- static loadInBackground(src, format = import_three4.RGBAFormat, rotation = 0) {
1010
+ static loadInBackground(src, format = import_three3.RGBAFormat, rotation = 0) {
984
1011
  const texture = this.createTexture();
985
- const image = ImageLoader.loadElement(src);
986
- image.onload = function() {
1012
+ texture.colorSpace = THREE.SRGBColorSpace;
1013
+ const image = ImageLoader.loadElement(src, () => {
987
1014
  texture.needsUpdate = true;
988
- };
1015
+ }, (error) => {
1016
+ this.failedTextures.add(texture);
1017
+ console.warn("Failed to load texture", src, error);
1018
+ });
989
1019
  texture.image = image;
990
1020
  texture.format = format;
991
1021
  texture.rotation = rotation;
992
1022
  return Textures.initTextureProps(texture);
993
1023
  }
994
- static load(src, format = import_three4.RGBAFormat, rotation = 0) {
995
- const texture = new import_three4.Texture();
1024
+ static load(src, format = import_three3.RGBAFormat, rotation = 0) {
1025
+ const texture = new import_three3.Texture();
1026
+ texture.colorSpace = THREE.SRGBColorSpace;
996
1027
  ImageLoader.getData(src).then((image) => {
997
- texture.needsUpdate = true;
998
1028
  texture.image = image;
1029
+ texture.needsUpdate = true;
1030
+ }).catch((error) => {
1031
+ this.failedTextures.add(texture);
1032
+ console.warn("Failed to load texture", src, error);
999
1033
  });
1000
1034
  texture.format = format;
1001
1035
  texture.rotation = rotation;
@@ -1004,11 +1038,11 @@ var TextureLoader = class {
1004
1038
  };
1005
1039
 
1006
1040
  // src/texture/Textures.ts
1007
- var THREE = __toESM(require("three"));
1041
+ var THREE2 = __toESM(require("three"));
1008
1042
  var Textures = class _Textures {
1009
1043
  static initTextureProps(texture) {
1010
- texture.magFilter = THREE.NearestFilter;
1011
- texture.minFilter = THREE.NearestFilter;
1044
+ texture.magFilter = THREE2.NearestFilter;
1045
+ texture.minFilter = THREE2.NearestFilter;
1012
1046
  texture.anisotropy = 0;
1013
1047
  return texture;
1014
1048
  }
@@ -1016,13 +1050,19 @@ var Textures = class _Textures {
1016
1050
  return TextureLoader.load(key.src, key.format, key.rotation);
1017
1051
  }
1018
1052
  static createAsset(key) {
1019
- return new import_three5.Texture();
1053
+ return new import_three4.Texture();
1020
1054
  }
1021
1055
  static createCanvasTexture(canvas) {
1022
- return this.initTextureProps(new import_three5.CanvasTexture(canvas));
1056
+ const texture = new import_three4.CanvasTexture(canvas);
1057
+ texture.colorSpace = THREE2.SRGBColorSpace;
1058
+ return this.initTextureProps(texture);
1023
1059
  }
1024
1060
  static getImage(key) {
1025
1061
  const keyStr = serializeTextureKey(key);
1062
+ const cached = Caching.textureCache.peek(keyStr);
1063
+ if (cached && TextureLoader.hasFailed(cached)) {
1064
+ Caching.textureCache.invalidate(keyStr);
1065
+ }
1026
1066
  return Caching.textureCache.get(keyStr, (k) => {
1027
1067
  return _Textures.createImage(key);
1028
1068
  });
@@ -1030,7 +1070,10 @@ var Textures = class _Textures {
1030
1070
  };
1031
1071
 
1032
1072
  // src/Materials.ts
1033
- var _Materials = class _Materials {
1073
+ var Materials = class _Materials {
1074
+ static {
1075
+ this.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1076
+ }
1034
1077
  // resolved lazily: as a static field this decoded an image the moment the library was
1035
1078
  // imported, which needs both a DOM and an EnvProvider to already be in place
1036
1079
  static get MISSING_TEXTURE() {
@@ -1038,26 +1081,26 @@ var _Materials = class _Materials {
1038
1081
  }
1039
1082
  static createImage(key) {
1040
1083
  const transparent = key.transparent || false;
1041
- return new import_three6.MeshBasicMaterial({
1084
+ return new import_three5.MeshBasicMaterial({
1042
1085
  map: Textures.getImage(key.texture),
1043
1086
  transparent,
1044
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1087
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1045
1088
  alphaTest: 0.5
1046
1089
  });
1047
1090
  }
1048
1091
  static createBasicCanvasMaterial(canvas, transparent = false, shade = false) {
1049
1092
  if (shade) {
1050
- return new import_three6.MeshStandardMaterial({
1093
+ return new import_three5.MeshStandardMaterial({
1051
1094
  map: Textures.createCanvasTexture(canvas),
1052
1095
  transparent,
1053
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1096
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1054
1097
  alphaTest: 0.5
1055
1098
  });
1056
1099
  }
1057
- return new import_three6.MeshBasicMaterial({
1100
+ return new import_three5.MeshBasicMaterial({
1058
1101
  map: Textures.createCanvasTexture(canvas),
1059
1102
  transparent,
1060
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1103
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1061
1104
  alphaTest: 0.5
1062
1105
  });
1063
1106
  }
@@ -1066,6 +1109,7 @@ var _Materials = class _Materials {
1066
1109
  uniform bool SHADE;
1067
1110
 
1068
1111
  varying vec2 vUv;
1112
+ varying vec3 vTint;
1069
1113
  varying float light;
1070
1114
  varying float lift;
1071
1115
 
@@ -1078,7 +1122,11 @@ var _Materials = class _Materials {
1078
1122
 
1079
1123
  if (SHADE) {
1080
1124
 
1081
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1125
+ #ifdef USE_INSTANCING
1126
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1127
+ #else
1128
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
1129
+ #endif
1082
1130
 
1083
1131
  float yLight = (1.0+N.y) * 0.5;
1084
1132
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -1096,6 +1144,7 @@ var _Materials = class _Materials {
1096
1144
  }
1097
1145
 
1098
1146
  vUv = uv;
1147
+ vTint = color;
1099
1148
 
1100
1149
  #ifdef USE_INSTANCING
1101
1150
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -1117,12 +1166,14 @@ var _Materials = class _Materials {
1117
1166
  uniform float BRIGHTNESS;
1118
1167
 
1119
1168
  varying vec2 vUv;
1169
+ varying vec3 vTint;
1120
1170
  varying float light;
1121
1171
  varying float lift;
1122
1172
 
1123
1173
  void main(void)
1124
1174
  {
1125
1175
  vec4 color = texture2D(map, vUv);
1176
+ color.rgb *= vTint;
1126
1177
 
1127
1178
  if (color.a < 0.01) discard;
1128
1179
 
@@ -1136,16 +1187,19 @@ var _Materials = class _Materials {
1136
1187
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1137
1188
 
1138
1189
  }
1190
+
1191
+ #include <tonemapping_fragment>
1192
+ #include <colorspace_fragment>
1139
1193
  }
1140
1194
  `;
1141
1195
  try {
1142
- return new import_three6.ShaderMaterial({
1196
+ return new import_three5.ShaderMaterial({
1143
1197
  uniforms: {
1144
1198
  SHADE: { value: true },
1145
1199
  BRIGHTNESS: { value: 1 },
1146
1200
  EMISSIVE: { value: false },
1147
1201
  base: {
1148
- value: new import_three6.Color(12698049)
1202
+ value: new import_three5.Color(12698049)
1149
1203
  /*TODO*/
1150
1204
  },
1151
1205
  map: { value: Textures.createCanvasTexture(canvas) }
@@ -1154,7 +1208,7 @@ var _Materials = class _Materials {
1154
1208
  fragmentShader: fragShader,
1155
1209
  vertexColors: true,
1156
1210
  transparent,
1157
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1211
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1158
1212
  alphaTest: 0.5
1159
1213
  });
1160
1214
  } catch (e) {
@@ -1164,6 +1218,10 @@ var _Materials = class _Materials {
1164
1218
  }
1165
1219
  static getImage(key) {
1166
1220
  const keyStr = serializeMaterialKey(key);
1221
+ const map = Caching.materialCache.peek(keyStr)?.map;
1222
+ if (map && TextureLoader.hasFailed(map)) {
1223
+ Caching.materialCache.invalidate(keyStr);
1224
+ }
1167
1225
  return Caching.materialCache.get(keyStr, (k) => {
1168
1226
  return _Materials.createImage(key);
1169
1227
  });
@@ -1184,14 +1242,12 @@ var _Materials = class _Materials {
1184
1242
  }
1185
1243
  }
1186
1244
  };
1187
- _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1188
- var Materials = _Materials;
1189
1245
 
1190
1246
  // src/Meshes.ts
1191
- var import_three7 = require("three");
1247
+ var import_three6 = require("three");
1192
1248
  var Meshes = class _Meshes {
1193
1249
  static createBox(key) {
1194
- return new import_three7.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1250
+ return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1195
1251
  }
1196
1252
  static getBox(key) {
1197
1253
  const keyStr = serializeMeshKey(key);
@@ -1202,7 +1258,7 @@ var Meshes = class _Meshes {
1202
1258
  };
1203
1259
 
1204
1260
  // src/UVMapper.ts
1205
- var import_three8 = require("three");
1261
+ var import_three9 = require("three");
1206
1262
 
1207
1263
  // src/model/ModelMerger.ts
1208
1264
  var import_ts_deepmerge = __toESM(require_dist());
@@ -1238,9 +1294,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1238
1294
  this.rootType = rootType;
1239
1295
  this.extension = extension;
1240
1296
  this.root = root;
1297
+ this.isAssetKey = true;
1241
1298
  }
1242
1299
  static parse(assetType, str, origin) {
1243
- let namespace = (origin == null ? void 0 : origin.namespace) || DEFAULT_NAMESPACE;
1300
+ let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1244
1301
  if (str.includes(":")) {
1245
1302
  let split2 = str.split(":");
1246
1303
  namespace = split2[0];
@@ -1253,12 +1310,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1253
1310
  split.shift();
1254
1311
  }
1255
1312
  let path = split.join("/");
1256
- let extension = assetType === "textures" ? ".png" : (origin == null ? void 0 : origin.assetType) || ".json";
1257
- return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin == null ? void 0 : origin.root);
1313
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1314
+ if (extension && path.endsWith(extension)) {
1315
+ path = path.slice(0, -extension.length);
1316
+ }
1317
+ return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1258
1318
  }
1259
1319
  toString() {
1260
1320
  let a = [
1261
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1321
+ this.root ?? AssetLoader.ROOT,
1262
1322
  this.rootType ?? "__rootType__",
1263
1323
  this.assetType ?? "__assetType__",
1264
1324
  this.type ?? "__type__",
@@ -1268,12 +1328,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1268
1328
  return a.join("/");
1269
1329
  }
1270
1330
  getFullPath() {
1271
- let p13 = [];
1331
+ let p12 = [];
1272
1332
  if (this.type) {
1273
- p13.push(this.type);
1333
+ p12.push(this.type);
1274
1334
  }
1275
- p13.push(this.path);
1276
- return p13.join("/");
1335
+ p12.push(this.path);
1336
+ return p12.join("/");
1277
1337
  }
1278
1338
  toNamespacedString() {
1279
1339
  return this.namespace + ":" + this.getFullPath();
@@ -1283,22 +1343,84 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1283
1343
  }
1284
1344
  };
1285
1345
  function isBasicAssetKey(obj) {
1286
- return "namespace" in obj && "path" in obj;
1346
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1287
1347
  }
1288
1348
  function isAssetKey(obj) {
1289
- return isBasicAssetKey(obj) && "parse" in obj;
1349
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1290
1350
  }
1291
1351
 
1352
+ // src/model/DisplayTransforms.ts
1353
+ var import_three7 = require("three");
1354
+
1355
+ // src/model/DisplayPosition.ts
1356
+ var DisplayPosition = /* @__PURE__ */ ((DisplayPosition2) => {
1357
+ DisplayPosition2["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
1358
+ DisplayPosition2["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
1359
+ DisplayPosition2["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
1360
+ DisplayPosition2["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
1361
+ DisplayPosition2["GUI"] = "gui";
1362
+ DisplayPosition2["HEAD"] = "head";
1363
+ DisplayPosition2["GROUND"] = "ground";
1364
+ DisplayPosition2["FIXED"] = "fixed";
1365
+ DisplayPosition2["ON_SHELF"] = "on_shelf";
1366
+ return DisplayPosition2;
1367
+ })(DisplayPosition || {});
1368
+ var DISPLAY_POSITIONS = Object.values(DisplayPosition);
1369
+
1370
+ // src/model/DisplayTransforms.ts
1371
+ var DisplayTransforms = class {
1372
+ /** Resolve hand fallbacks within one model, before inheriting parent display entries. */
1373
+ static withHandFallbacks(display) {
1374
+ if (!display) return void 0;
1375
+ const resolved = { ...display };
1376
+ for (const [left, right] of [
1377
+ ["thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */, "thirdperson_righthand" /* THIRDPERSON_RIGHTHAND */],
1378
+ ["firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */, "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */]
1379
+ ]) {
1380
+ if (resolved[left] === void 0 && resolved[right] !== void 0) resolved[left] = resolved[right];
1381
+ }
1382
+ return resolved;
1383
+ }
1384
+ /** Build a display pose for geometry already centered at the model's [8, 8, 8] pivot. */
1385
+ static getMatrix(display, position) {
1386
+ const transform = this.withHandFallbacks(display)?.[position] ?? {};
1387
+ const left = position === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || position === "thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */;
1388
+ const sign = left ? -1 : 1;
1389
+ const [x, y, z] = transform.rotation ?? [0, 0, 0];
1390
+ const rotation = new import_three7.Quaternion().setFromEuler(new import_three7.Euler(toRadians(x), sign * toRadians(y), sign * toRadians(z), "XYZ"));
1391
+ const translation = new import_three7.Vector3(...transform.translation ?? [0, 0, 0]).clampScalar(-80, 80);
1392
+ translation.x *= sign;
1393
+ const scale = new import_three7.Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
1394
+ return new import_three7.Matrix4().compose(translation, rotation, scale);
1395
+ }
1396
+ static apply(geometry, matrix) {
1397
+ geometry.applyMatrix4(matrix);
1398
+ if (matrix.determinant() < 0) {
1399
+ if (!geometry.index) geometry.setIndex(Array.from({ length: geometry.getAttribute("position").count }, (_, i) => i));
1400
+ const index = geometry.index;
1401
+ for (let i = 0; i < index.count; i += 3) {
1402
+ const second = index.getX(i + 1);
1403
+ index.setX(i + 1, index.getX(i + 2));
1404
+ index.setX(i + 2, second);
1405
+ }
1406
+ index.needsUpdate = true;
1407
+ }
1408
+ }
1409
+ };
1410
+
1292
1411
  // src/model/ModelMerger.ts
1293
1412
  var ModelMerger = class {
1294
1413
  static async mergeWithParents(model) {
1295
1414
  const models = await this.collectAllParents(model);
1296
1415
  let merged = {};
1297
- for (let parentModel of models) {
1298
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1416
+ for (const source of [...models, model]) {
1417
+ const inheritedDisplay = merged.display;
1418
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, source);
1419
+ if (source.display) {
1420
+ merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
1421
+ }
1299
1422
  }
1300
- merged = (0, import_ts_deepmerge.default)(merged, model);
1301
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1423
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1302
1424
  merged.hierarchy.push(`${merged.parent}`);
1303
1425
  return merged;
1304
1426
  }
@@ -1308,6 +1430,7 @@ var ModelMerger = class {
1308
1430
  }
1309
1431
  const models = [];
1310
1432
  const parentKey = AssetKey.parse("models", model.parent);
1433
+ parentKey.root = model.key?.root;
1311
1434
  const parentModel = await Models.getRaw(parentKey);
1312
1435
  if (parentModel) {
1313
1436
  models.unshift(parentModel);
@@ -1317,9 +1440,6 @@ var ModelMerger = class {
1317
1440
  }
1318
1441
  };
1319
1442
 
1320
- // src/assets/Models.ts
1321
- var import_typescript_memoize = require("typescript-memoize");
1322
-
1323
1443
  // src/assets/source/parser/AssetParsers.ts
1324
1444
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1325
1445
  AssetParser2["MODEL"] = "model";
@@ -1333,30 +1453,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1333
1453
  })(AssetParser || {});
1334
1454
 
1335
1455
  // src/assets/Models.ts
1336
- var _Models = class _Models {
1456
+ var Models = class _Models {
1337
1457
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1338
1458
  // the library, and would require an EnvProvider before any entry has had a chance to register
1339
1459
  static get PERSISTENT_CACHE() {
1340
1460
  return this._persistentCache ??= PersistentCache.open("minerender-models");
1341
1461
  }
1342
1462
  static async getItemList() {
1343
- return AssetLoader.get(new AssetKey(
1344
- DEFAULT_NAMESPACE,
1345
- "_list",
1346
- "models",
1347
- "item",
1348
- "assets",
1349
- ".json",
1350
- DEFAULT_ROOT
1351
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1463
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1464
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1465
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1466
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1467
+ }).then((r) => r?.files ?? []);
1352
1468
  }
1353
1469
  static async loadAndMerge(key) {
1354
- const model = await this.getRaw(key);
1470
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1355
1471
  if (!model) {
1356
1472
  return void 0;
1357
1473
  }
1358
1474
  return ModelMerger.mergeWithParents(model);
1359
1475
  }
1476
+ static async getItemModel(key) {
1477
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1478
+ const model = await this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(itemKey.serialize()), async () => {
1479
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1480
+ if (!result) return void 0;
1481
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1482
+ const reference = this.defaultItemModel(result.asset.model, key);
1483
+ const modelKey = AssetKey.parse("models", reference);
1484
+ modelKey.root = key.root;
1485
+ const model2 = await this.getRaw(modelKey);
1486
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1487
+ return model2;
1488
+ });
1489
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1490
+ }
1491
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1492
+ static defaultItemModel(node, key) {
1493
+ if (!node || typeof node.type !== "string") {
1494
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1495
+ }
1496
+ switch (node.type.replace(/^minecraft:/, "")) {
1497
+ case "model":
1498
+ if (typeof node.model === "string" && node.model) return node.model;
1499
+ break;
1500
+ case "condition":
1501
+ return this.defaultItemModel(node.on_false, key);
1502
+ case "select": {
1503
+ 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;
1504
+ return this.defaultItemModel(selected ?? node.fallback, key);
1505
+ }
1506
+ case "range_dispatch": {
1507
+ const selected = node.entries?.reduce((match, entry) => {
1508
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1509
+ }, void 0);
1510
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1511
+ }
1512
+ }
1513
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1514
+ }
1360
1515
  static async getRaw(key) {
1361
1516
  if (!key.assetType) {
1362
1517
  key.assetType = "models";
@@ -1366,7 +1521,7 @@ var _Models = class _Models {
1366
1521
  }
1367
1522
  const keyStr = key.serialize();
1368
1523
  return Caching.rawModelCache.get(keyStr, (k) => {
1369
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1524
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1370
1525
  return AssetLoader.get(key, "model" /* MODEL */);
1371
1526
  });
1372
1527
  }).then((asset) => {
@@ -1395,31 +1550,32 @@ var _Models = class _Models {
1395
1550
  return this.PERSISTENT_CACHE.clear();
1396
1551
  }
1397
1552
  };
1398
- __decorateClass([
1399
- (0, import_typescript_memoize.Memoize)()
1400
- ], _Models, "getItemList", 1);
1401
- var Models = _Models;
1402
1553
 
1403
1554
  // src/assets/BlockStates.ts
1404
- var import_typescript_memoize2 = require("typescript-memoize");
1405
1555
  var BlockStates = class {
1406
1556
  static get PERSISTENT_CACHE() {
1407
1557
  return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
1408
1558
  }
1559
+ // BlockState names are hardcoded
1409
1560
  static async getList() {
1410
- return AssetLoader.get(new AssetKey(
1561
+ const key = new AssetKey(
1411
1562
  DEFAULT_NAMESPACE,
1412
1563
  "_list",
1413
1564
  "blockstates",
1414
1565
  void 0,
1415
1566
  "assets",
1416
1567
  ".json",
1417
- DEFAULT_ROOT
1418
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1568
+ AssetLoader.ROOT
1569
+ );
1570
+ return Caching.listAssetCache.get(key.serialize(), () => {
1571
+ return AssetLoader.get(key, "list" /* LIST */);
1572
+ }).then((r) => r?.files ?? []);
1419
1573
  }
1420
1574
  static async getDefaultStates() {
1421
1575
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1422
- return AssetLoader.get(key, "json" /* JSON */);
1576
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1577
+ return AssetLoader.get(key, "json" /* JSON */);
1578
+ });
1423
1579
  }
1424
1580
  static async getDefaultState(key) {
1425
1581
  const defaultStates = await this.getDefaultStates();
@@ -1437,7 +1593,7 @@ var BlockStates = class {
1437
1593
  }
1438
1594
  const keyStr = key.serialize();
1439
1595
  return Caching.blockStateCache.get(keyStr, (k) => {
1440
- return this.PERSISTENT_CACHE.getOrLoad(keyStr, (k1) => {
1596
+ return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1441
1597
  return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
1442
1598
  });
1443
1599
  }).then((asset) => {
@@ -1458,17 +1614,11 @@ var BlockStates = class {
1458
1614
  await this.PERSISTENT_CACHE.clear();
1459
1615
  }
1460
1616
  };
1461
- __decorateClass([
1462
- (0, import_typescript_memoize2.Memoize)()
1463
- ], BlockStates, "getList", 1);
1464
- __decorateClass([
1465
- (0, import_typescript_memoize2.Memoize)()
1466
- ], BlockStates, "getDefaultStates", 1);
1467
1617
  var DefaultBlockStates = class {
1468
1618
  };
1469
1619
 
1470
1620
  // src/assets/Assets.ts
1471
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1621
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1472
1622
  var DEFAULT_NAMESPACE = "minecraft";
1473
1623
  var Assets = class {
1474
1624
  /**
@@ -1489,8 +1639,145 @@ var Assets = class {
1489
1639
  var AssetSource = class {
1490
1640
  constructor() {
1491
1641
  }
1642
+ /**
1643
+ * Identifies this source's content across sessions for persistent caching. Sources that
1644
+ * cannot tell whether their content changed (an unnamed archive, for example) return
1645
+ * undefined, which keeps their results out of long-lived caches.
1646
+ */
1647
+ get cacheId() {
1648
+ return void 0;
1649
+ }
1650
+ };
1651
+ var AssetLoadError = class extends Error {
1652
+ constructor(source, key, path, cause) {
1653
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1654
+ this.source = source;
1655
+ this.key = key;
1656
+ this.path = path;
1657
+ this.cause = cause;
1658
+ this.name = "AssetLoadError";
1659
+ }
1492
1660
  };
1493
1661
 
1662
+ // src/util/BatchedExecutor.ts
1663
+ var BatchedExecutor = class {
1664
+ constructor(interval = 1, batch = 30) {
1665
+ this.interval = interval;
1666
+ this.batch = batch;
1667
+ this.queue = [];
1668
+ this.task = setInterval(() => this.run());
1669
+ }
1670
+ submit(task) {
1671
+ this.queue.push(task);
1672
+ }
1673
+ run() {
1674
+ for (let i = 0; i < this.batch; i++) {
1675
+ this.runNext();
1676
+ }
1677
+ }
1678
+ runNext() {
1679
+ let next = this.queue.shift();
1680
+ if (next) next();
1681
+ }
1682
+ };
1683
+
1684
+ // src/util/model.ts
1685
+ var import_three8 = require("three");
1686
+ function applyElementRotation(rotation, geometry) {
1687
+ const origin = new import_three8.Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1688
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1689
+ switch (rotation.axis) {
1690
+ case "x" /* X */:
1691
+ geometry.rotateX(toRadians(rotation.angle));
1692
+ break;
1693
+ case "y" /* Y */:
1694
+ geometry.rotateY(toRadians(rotation.angle));
1695
+ break;
1696
+ case "z" /* Z */:
1697
+ geometry.rotateZ(toRadians(rotation.angle));
1698
+ break;
1699
+ }
1700
+ if (rotation.rescale) {
1701
+ if (Math.abs(rotation.angle) === 22.5) {
1702
+ const s = 1 / Math.cos(0.39269909262657166);
1703
+ geometry.scale(s, 1, s);
1704
+ } else {
1705
+ const s = 1 / Math.cos(0.7853981852531433);
1706
+ geometry.scale(s, 1, s);
1707
+ }
1708
+ }
1709
+ geometry.translate(origin.x, origin.y, origin.z);
1710
+ }
1711
+ function applyGenericRotation(axis, rotation, obj) {
1712
+ switch (axis) {
1713
+ case "x" /* X */:
1714
+ obj.rotateOnAxis(new import_three8.Vector3(1, 0, 0), toRadians(rotation));
1715
+ break;
1716
+ case "y" /* Y */:
1717
+ obj.rotateOnAxis(new import_three8.Vector3(0, 1, 0), toRadians(rotation));
1718
+ break;
1719
+ case "z" /* Z */:
1720
+ obj.rotateOnAxis(new import_three8.Vector3(0, 0, 1), toRadians(rotation));
1721
+ break;
1722
+ }
1723
+ }
1724
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1725
+ let size = new import_three8.Vector3();
1726
+ box.getSize(size);
1727
+ let boxGeo = new import_three8.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
1728
+ let wireGeo = new import_three8.EdgesGeometry(boxGeo);
1729
+ let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
1730
+ let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
1731
+ obj.add(wireframe);
1732
+ let axes = new import_three8.AxesHelper(1);
1733
+ obj.add(axes);
1734
+ }
1735
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1736
+ let boxGeo = new import_three8.BoxGeometry(16, 16, 16, 1, 1, 1);
1737
+ let wireGeo = new import_three8.EdgesGeometry(boxGeo);
1738
+ let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
1739
+ let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
1740
+ obj.add(wireframe);
1741
+ let axes = new import_three8.AxesHelper(1);
1742
+ obj.add(axes);
1743
+ }
1744
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1745
+ let wireGeo = new import_three8.EdgesGeometry(geo);
1746
+ let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
1747
+ let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
1748
+ mesh.add(wireframe);
1749
+ let axes = new import_three8.AxesHelper(1);
1750
+ mesh.add(axes);
1751
+ }
1752
+
1753
+ // src/util/performance.ts
1754
+ function captureException(e, ...extra) {
1755
+ console.error(e, extra);
1756
+ }
1757
+ function timingStart(marker) {
1758
+ console.time(marker);
1759
+ }
1760
+ function timingEnd(marker) {
1761
+ console.timeEnd(marker);
1762
+ }
1763
+
1764
+ // src/util/three.ts
1765
+ function isObject3D(obj) {
1766
+ return obj.isObject3D;
1767
+ }
1768
+ function isMesh(obj) {
1769
+ return obj.isMesh;
1770
+ }
1771
+ function isInstancedMesh(obj) {
1772
+ return obj.isInstancedMesh;
1773
+ }
1774
+ function isPerspectiveCamera(obj) {
1775
+ return obj.isPerspectiveCamera;
1776
+ }
1777
+ function isOrthographicCamera(obj) {
1778
+ return obj.isOrthographicCamera;
1779
+ }
1780
+
1494
1781
  // src/nbt/NBTHelper.ts
1495
1782
  var NBTHelper = class {
1496
1783
  static async fromBuffer(buffer) {
@@ -1506,7 +1793,83 @@ var p3 = prefix("HostedAssetSource");
1506
1793
  var DEFAULT_OPTIONS = {
1507
1794
  retryDefaults: true
1508
1795
  };
1509
- var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1796
+ var HostedAssetSource = class _HostedAssetSource extends AssetSource {
1797
+ static {
1798
+ this.MODEL = {
1799
+ config(request) {
1800
+ },
1801
+ parse(response) {
1802
+ return response.data;
1803
+ }
1804
+ };
1805
+ }
1806
+ static {
1807
+ this.BLOCKSTATE = {
1808
+ config(request) {
1809
+ },
1810
+ parse(response) {
1811
+ return response.data;
1812
+ }
1813
+ };
1814
+ }
1815
+ static {
1816
+ this.META = {
1817
+ config(request) {
1818
+ },
1819
+ parse(response) {
1820
+ return response.data;
1821
+ }
1822
+ };
1823
+ }
1824
+ static {
1825
+ this.NBT = {
1826
+ config(request) {
1827
+ request.responseType = "arraybuffer";
1828
+ },
1829
+ parse(response) {
1830
+ return NBTHelper.fromBuffer(Buffer.from(response.data));
1831
+ }
1832
+ };
1833
+ }
1834
+ static {
1835
+ this.IMAGE = {
1836
+ config(request) {
1837
+ request.responseType = "arraybuffer";
1838
+ },
1839
+ async parse(response) {
1840
+ return await ImageLoader.processResponse(response);
1841
+ }
1842
+ };
1843
+ }
1844
+ static {
1845
+ this.LIST = {
1846
+ config(request) {
1847
+ },
1848
+ parse(response) {
1849
+ return response.data;
1850
+ }
1851
+ };
1852
+ }
1853
+ static {
1854
+ this.JSON = {
1855
+ config(request) {
1856
+ },
1857
+ parse(response) {
1858
+ return response.data;
1859
+ }
1860
+ };
1861
+ }
1862
+ static {
1863
+ this.PARSER_MAP = /* @__PURE__ */ new Map([
1864
+ ["model" /* MODEL */, _HostedAssetSource.MODEL],
1865
+ ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1866
+ ["meta" /* META */, _HostedAssetSource.META],
1867
+ ["nbt" /* NBT */, _HostedAssetSource.NBT],
1868
+ ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1869
+ ["list" /* LIST */, _HostedAssetSource.LIST],
1870
+ ["json" /* JSON */, _HostedAssetSource.JSON]
1871
+ ]);
1872
+ }
1510
1873
  async loadOrRetryWithDefaults(key, parser) {
1511
1874
  const direct = await this.load(key, parser);
1512
1875
  if (typeof direct !== "undefined") {
@@ -1519,17 +1882,17 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1519
1882
  if (typeof namespaced !== "undefined") {
1520
1883
  return namespaced;
1521
1884
  }
1522
- if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1885
+ if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1523
1886
  console.info(p3, "Retrying", key, "with default root+namespace");
1524
- const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1887
+ const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1525
1888
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
1526
1889
  if (typeof namespacedRooted !== "undefined") {
1527
1890
  return namespacedRooted;
1528
1891
  }
1529
1892
  }
1530
- } else if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1893
+ } else if (typeof key.root !== "undefined" && key.root !== AssetLoader.ROOT || typeof this.root !== "undefined" && this.root !== AssetLoader.ROOT) {
1531
1894
  console.info(p3, "Retrying", key, "with default root");
1532
- const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1895
+ const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, AssetLoader.ROOT);
1533
1896
  const rooted = await this.load(rootKey, parser);
1534
1897
  if (typeof rooted !== "undefined") {
1535
1898
  return rooted;
@@ -1541,31 +1904,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1541
1904
  console.info(p3, "Loading", key);
1542
1905
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1543
1906
  console.debug(p3, url);
1544
- let req = {
1545
- url
1546
- };
1547
- parser.config(req);
1548
- return await Requests.mcAssetRequest(req).then((response) => {
1549
- if (response && response.data) {
1550
- try {
1551
- return parser.parse(response);
1552
- } catch (e) {
1553
- console.warn("Parser failed to process response", response, e);
1554
- throw e;
1555
- }
1556
- }
1557
- return void 0;
1558
- }).catch((err) => {
1559
- if (err.response) {
1560
- let response = err.response;
1561
- if (response.status === 404) {
1562
- console.debug(p3, key, "not found");
1907
+ const request = { url };
1908
+ try {
1909
+ parser.config(request);
1910
+ let response;
1911
+ try {
1912
+ response = await Requests.mcAssetRequest(request);
1913
+ } catch (cause) {
1914
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1563
1915
  return void 0;
1564
1916
  }
1917
+ throw cause;
1565
1918
  }
1566
- console.debug(p3, "Failed to load", key, err == null ? void 0 : err.message);
1567
- return void 0;
1568
- });
1919
+ if (response.data === void 0) {
1920
+ throw new Error("Asset response has no data");
1921
+ }
1922
+ return await parser.parse(response);
1923
+ } catch (cause) {
1924
+ throw new AssetLoadError(this, key, request.url, cause);
1925
+ }
1569
1926
  }
1570
1927
  assetBasePath(key) {
1571
1928
  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 + "/" : ""}`;
@@ -1578,6 +1935,9 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1578
1935
  get root() {
1579
1936
  return this._root;
1580
1937
  }
1938
+ get cacheId() {
1939
+ return `hosted:${this._root}`;
1940
+ }
1581
1941
  get options() {
1582
1942
  return this._options;
1583
1943
  }
@@ -1589,74 +1949,14 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1589
1949
  return this.load(key, responseParser);
1590
1950
  }
1591
1951
  };
1592
- _HostedAssetSource.MODEL = {
1593
- config(request) {
1594
- },
1595
- parse(response) {
1596
- return response.data;
1597
- }
1598
- };
1599
- _HostedAssetSource.BLOCKSTATE = {
1600
- config(request) {
1601
- },
1602
- parse(response) {
1603
- return response.data;
1604
- }
1605
- };
1606
- _HostedAssetSource.META = {
1607
- config(request) {
1608
- },
1609
- parse(response) {
1610
- return response.data;
1611
- }
1612
- };
1613
- _HostedAssetSource.NBT = {
1614
- config(request) {
1615
- request.responseType = "arraybuffer";
1616
- },
1617
- parse(response) {
1618
- return NBTHelper.fromBuffer(Buffer.from(response.data));
1619
- }
1620
- };
1621
- _HostedAssetSource.IMAGE = {
1622
- config(request) {
1623
- request.responseType = "arraybuffer";
1624
- },
1625
- async parse(response) {
1626
- return await ImageLoader.processResponse(response);
1627
- }
1628
- };
1629
- _HostedAssetSource.LIST = {
1630
- config(request) {
1631
- },
1632
- parse(response) {
1633
- return response.data;
1634
- }
1635
- };
1636
- _HostedAssetSource.JSON = {
1637
- config(request) {
1638
- },
1639
- parse(response) {
1640
- return response.data;
1641
- }
1642
- };
1643
- _HostedAssetSource.PARSER_MAP = /* @__PURE__ */ new Map([
1644
- ["model" /* MODEL */, _HostedAssetSource.MODEL],
1645
- ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1646
- ["meta" /* META */, _HostedAssetSource.META],
1647
- ["nbt" /* NBT */, _HostedAssetSource.NBT],
1648
- ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1649
- ["list" /* LIST */, _HostedAssetSource.LIST],
1650
- ["json" /* JSON */, _HostedAssetSource.JSON]
1651
- ]);
1652
- var HostedAssetSource = _HostedAssetSource;
1653
1952
 
1654
1953
  // src/assets/source/archive/BrowserArchiveProxy.ts
1655
1954
  var import_zip = require("@zip.js/zip.js");
1656
1955
  var BrowserArchiveProxy = class {
1657
- constructor(blob) {
1956
+ constructor(blob, id) {
1658
1957
  this._blob = blob;
1659
1958
  this._reader = new import_zip.ZipReader(new import_zip.BlobReader(this._blob));
1959
+ this.id = id ?? (typeof File !== "undefined" && blob instanceof File ? `${blob.name}:${blob.size}:${blob.lastModified}` : void 0);
1660
1960
  }
1661
1961
  async getEntries() {
1662
1962
  return (await this._reader.getEntries()).map((e) => {
@@ -1672,7 +1972,6 @@ var BrowserArchiveProxy = class {
1672
1972
  };
1673
1973
 
1674
1974
  // src/assets/source/archive/ArchiveAssetSource.ts
1675
- var p4 = prefix("ArchiveAssetSource");
1676
1975
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1677
1976
  constructor(archiveProxy) {
1678
1977
  super();
@@ -1682,6 +1981,10 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1682
1981
  static blob(blob) {
1683
1982
  return new _ArchiveAssetSource(new BrowserArchiveProxy(blob));
1684
1983
  }
1984
+ get cacheId() {
1985
+ const id = this._archiveProxy.id;
1986
+ return id === void 0 ? void 0 : `archive:${id}`;
1987
+ }
1685
1988
  async getEntries() {
1686
1989
  return this._archiveProxy.getEntries();
1687
1990
  }
@@ -1691,74 +1994,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1691
1994
  }
1692
1995
  async get(key, parser) {
1693
1996
  const responseParser = HostedAssetSource.PARSER_MAP.get(parser);
1694
- console.log("ArchiveAssetSource.get", key, parser);
1695
- let entries = await this.getEntries();
1696
- const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1697
- console.log(path);
1698
- const entry = await this.getEntry(path);
1699
- console.log(entry);
1700
- if (!entry) {
1701
- return void 0;
1702
- }
1703
- let blob = await entry.getData();
1704
- const url = URL.createObjectURL(blob);
1705
- console.log(url);
1706
- let req = {
1707
- url
1708
- };
1709
- responseParser.config(req);
1710
- return Requests.genericRequest(req).then((response) => {
1711
- if (response && response.data) {
1712
- try {
1713
- return responseParser.parse(response);
1714
- } catch (e) {
1715
- console.warn("Parser failed to process response", response, e);
1716
- throw e;
1717
- }
1718
- }
1719
- return void 0;
1720
- }).catch((err) => {
1721
- if (err.response) {
1722
- let response = err.response;
1723
- if (response.status === 404) {
1724
- console.debug(p4, key, "not found");
1725
- return void 0;
1726
- }
1727
- }
1728
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1729
- return void 0;
1730
- });
1997
+ return this.load(key, responseParser);
1731
1998
  }
1732
- //TODO: abstract this
1733
1999
  async load(key, parser) {
1734
- console.info(p4, "Loading", key);
1735
- const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1736
- console.debug(p4, url);
1737
- let req = {
1738
- url
1739
- };
1740
- parser.config(req);
1741
- return await Requests.genericRequest(req).then((response) => {
1742
- if (response && response.data) {
1743
- try {
1744
- return parser.parse(response);
1745
- } catch (e) {
1746
- console.warn("Parser failed to process response", response, e);
1747
- throw e;
1748
- }
2000
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
2001
+ let url;
2002
+ try {
2003
+ const entry = await this.getEntry(path);
2004
+ if (!entry) {
2005
+ return void 0;
1749
2006
  }
1750
- return void 0;
1751
- }).catch((err) => {
1752
- if (err.response) {
1753
- let response = err.response;
1754
- if (response.status === 404) {
1755
- console.debug(p4, key, "not found");
1756
- return void 0;
1757
- }
2007
+ url = URL.createObjectURL(await entry.getData());
2008
+ const request = { url };
2009
+ parser.config(request);
2010
+ const response = await Requests.genericRequest(request);
2011
+ if (response.data === void 0) {
2012
+ throw new Error("Asset response has no data");
1758
2013
  }
1759
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1760
- return void 0;
1761
- });
2014
+ return await parser.parse(response);
2015
+ } catch (cause) {
2016
+ throw new AssetLoadError(this, key, path, cause);
2017
+ } finally {
2018
+ if (url !== void 0) {
2019
+ URL.revokeObjectURL(url);
2020
+ }
2021
+ }
1762
2022
  }
1763
2023
  assetBasePath(key) {
1764
2024
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1766,18 +2026,64 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1766
2026
  };
1767
2027
 
1768
2028
  // src/assets/AssetLoader.ts
1769
- var import_ts_deepmerge3 = __toESM(require_dist());
1770
- var p5 = prefix("AssetLoader");
1771
- var _AssetLoader = class _AssetLoader {
2029
+ var p4 = prefix("AssetLoader");
2030
+ var FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
2031
+ var AssetLoader = class {
2032
+ static {
2033
+ this.ROOT = DEFAULT_ROOT;
2034
+ }
2035
+ static {
2036
+ this._SOURCES = [];
2037
+ }
2038
+ static {
2039
+ /** Used when a registered source cannot identify its content, so nothing persists past this session. */
2040
+ this.SESSION_SCOPE = `session:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
2041
+ }
2042
+ static get version() {
2043
+ return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
2044
+ }
2045
+ static setVersion(version) {
2046
+ this.ROOT = `https://assets.mcasset.cloud/${version}`;
2047
+ const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
2048
+ const index = this._SOURCES.findIndex((s) => s.key === "mcassets");
2049
+ if (index !== -1) {
2050
+ this._SOURCES[index] = { key: "mcassets", source };
2051
+ } else {
2052
+ this.addSource("mcassets", source);
2053
+ }
2054
+ Caching.clear();
2055
+ }
2056
+ /**
2057
+ * Scope for persistent cache keys. Empty with only the default vanilla sources, so their
2058
+ * entries stay valid across sessions; otherwise it names every added source (resource packs,
2059
+ * mirrors) so their results never masquerade as vanilla assets after a reload.
2060
+ */
2061
+ static get persistentScope() {
2062
+ const parts = [];
2063
+ for (const { key, source } of this._SOURCES) {
2064
+ const id = source.cacheId;
2065
+ if (key === "mcassets" && id === `hosted:${this.ROOT}`) continue;
2066
+ if (key === "mcassets-fallback" && id === `hosted:${FALLBACK_ROOT}`) continue;
2067
+ if (id === void 0) return this.SESSION_SCOPE;
2068
+ parts.push(`${key}=${id}`);
2069
+ }
2070
+ return parts.join("|");
2071
+ }
2072
+ /** Prefixes a persistent cache key with the current source scope. */
2073
+ static persistentKey(key) {
2074
+ const scope = this.persistentScope;
2075
+ return scope ? `${scope}
2076
+ ${key}` : key;
2077
+ }
1772
2078
  static addSource(key, source, override = true) {
1773
2079
  if (override) {
1774
2080
  const existing = this.removeSource(key);
1775
2081
  if (existing) {
1776
- console.log(p5, "Removed existing AssetSource", key);
2082
+ console.log(p4, "Removed existing AssetSource", key);
1777
2083
  }
1778
2084
  }
1779
2085
  this._SOURCES.unshift({ key, source });
1780
- console.log(p5, "Added AssetSource", key);
2086
+ console.log(p4, "Added AssetSource", key);
1781
2087
  }
1782
2088
  static removeSource(key) {
1783
2089
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1789,8 +2095,11 @@ var _AssetLoader = class _AssetLoader {
1789
2095
  }
1790
2096
  return void 0;
1791
2097
  }
2098
+ static {
2099
+ this.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
2100
+ this.addSource("mcassets", new HostedAssetSource(this.ROOT, { retryDefaults: false }));
2101
+ }
1792
2102
  static async getAll(key, parser) {
1793
- console.log(this._SOURCES);
1794
2103
  let promises = [];
1795
2104
  for (const source of this._SOURCES) {
1796
2105
  promises.push(source.source.get(key, parser));
@@ -1799,31 +2108,36 @@ var _AssetLoader = class _AssetLoader {
1799
2108
  return results.filter((r) => r != void 0);
1800
2109
  });
1801
2110
  }
2111
+ /** Returns the first defined result in source-priority order, without merging assets. */
1802
2112
  static async get(key, parser) {
1803
- console.log(this._SOURCES);
1804
- let promises = [];
1805
- for (const source of this._SOURCES) {
1806
- promises.push(source.source.get(key, parser));
1807
- }
1808
- return Promise.all(promises).then((results) => {
1809
- const fallback = results[results.length - 1];
1810
- for (const result of results) {
1811
- if (result) {
1812
- if (fallback) {
1813
- return (0, import_ts_deepmerge3.default)({}, fallback, result);
1814
- }
1815
- return result;
2113
+ const keys = [key];
2114
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
2115
+ keys.push(new AssetKey(
2116
+ key.namespace,
2117
+ key.path,
2118
+ key.assetType === "structure" ? "structures" : "structure",
2119
+ key.type,
2120
+ key.rootType,
2121
+ key.extension,
2122
+ key.root
2123
+ ));
2124
+ }
2125
+ return (await this.getFirst(keys, parser))?.asset;
2126
+ }
2127
+ /** Tries each path within a source before considering lower-priority sources. */
2128
+ static async getFirst(keys, parser) {
2129
+ const sources = [...this._SOURCES];
2130
+ for (const source of sources) {
2131
+ for (const key of keys) {
2132
+ const result = await source.source.get(key, parser);
2133
+ if (result !== void 0) {
2134
+ return { key, asset: result };
1816
2135
  }
1817
2136
  }
1818
- return void 0;
1819
- });
2137
+ }
2138
+ return void 0;
1820
2139
  }
1821
2140
  };
1822
- _AssetLoader.ROOT = DEFAULT_ROOT;
1823
- _AssetLoader._SOURCES = [];
1824
- _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1825
- _AssetLoader.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
1826
- var AssetLoader = _AssetLoader;
1827
2141
 
1828
2142
  // src/assets/ModelTextures.ts
1829
2143
  var ModelTextures = class {
@@ -1831,11 +2145,21 @@ var ModelTextures = class {
1831
2145
  return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
1832
2146
  }
1833
2147
  static async get(key) {
1834
- const asset = await this.preload(key);
1835
- if (asset) {
1836
- return ImageLoader.infoToCanvasData(asset);
2148
+ const keyStr = key.serialize();
2149
+ const pending = this.preload(key);
2150
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
2151
+ try {
2152
+ const asset = await pending;
2153
+ if (asset) {
2154
+ return await ImageLoader.infoToCanvasData(asset);
2155
+ }
2156
+ return void 0;
2157
+ } catch (err) {
2158
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
2159
+ Caching.textureAssetCache.invalidate(keyStr);
2160
+ }
2161
+ throw err;
1837
2162
  }
1838
- return void 0;
1839
2163
  }
1840
2164
  static async preload(key) {
1841
2165
  const keyStr = key.serialize();
@@ -1854,7 +2178,7 @@ var ModelTextures = class {
1854
2178
  }
1855
2179
  const keyStr = key.serialize();
1856
2180
  return Caching.textureMetaCache.get(keyStr, (k) => {
1857
- return this.PERSISTENT_META_CACHE.getOrLoad(keyStr, (k1) => {
2181
+ return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
1858
2182
  return AssetLoader.get(key, "meta" /* META */).then((asset) => {
1859
2183
  if (asset)
1860
2184
  asset.key = key;
@@ -1909,7 +2233,28 @@ var CanvasImage = class {
1909
2233
  };
1910
2234
 
1911
2235
  // src/Ticker.ts
1912
- var _Ticker = class _Ticker {
2236
+ var Ticker = class _Ticker {
2237
+ static {
2238
+ this.TPS = 20;
2239
+ }
2240
+ static {
2241
+ this.counter = 0;
2242
+ }
2243
+ static {
2244
+ this._tickers = /* @__PURE__ */ new Map();
2245
+ }
2246
+ static {
2247
+ this.oneSecondTps = 0;
2248
+ }
2249
+ static {
2250
+ this.oneSecondTicks = 0;
2251
+ }
2252
+ static {
2253
+ this.fiveSecondTps = 0;
2254
+ }
2255
+ static {
2256
+ this.fiveSecondTicks = 0;
2257
+ }
1913
2258
  static schedule(fn, ms) {
1914
2259
  const handle = setInterval(fn, ms);
1915
2260
  const unref = handle.unref;
@@ -1971,14 +2316,6 @@ var _Ticker = class _Ticker {
1971
2316
  this._tickers.clear();
1972
2317
  }
1973
2318
  };
1974
- _Ticker.TPS = 20;
1975
- _Ticker.counter = 0;
1976
- _Ticker._tickers = /* @__PURE__ */ new Map();
1977
- _Ticker.oneSecondTps = 0;
1978
- _Ticker.oneSecondTicks = 0;
1979
- _Ticker.fiveSecondTps = 0;
1980
- _Ticker.fiveSecondTicks = 0;
1981
- var Ticker = _Ticker;
1982
2319
 
1983
2320
  // src/texture/TextureAtlas.ts
1984
2321
  var TextureAtlas = class {
@@ -2004,18 +2341,24 @@ var TextureAtlas = class {
2004
2341
 
2005
2342
  // src/model/ModelGenerator.ts
2006
2343
  var ModelGenerator = class {
2344
+ static {
2345
+ this.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2346
+ }
2007
2347
  static generateItemModel(imageData, layer) {
2348
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
2008
2349
  const mainElement = {
2009
2350
  from: [0, 0, 7.5],
2010
2351
  to: [16, 16, 8.5],
2011
2352
  faces: {
2012
2353
  "south": {
2013
2354
  uv: [0, 0, 16, 16],
2014
- texture: `#${layer}`
2355
+ texture: `#${layer}`,
2356
+ tintindex
2015
2357
  },
2016
2358
  "north": {
2017
2359
  uv: [16, 0, 0, 16],
2018
- texture: `#${layer}`
2360
+ texture: `#${layer}`,
2361
+ tintindex
2019
2362
  }
2020
2363
  },
2021
2364
  shade: true
@@ -2023,14 +2366,21 @@ var ModelGenerator = class {
2023
2366
  return [mainElement];
2024
2367
  }
2025
2368
  };
2026
- ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2027
2369
 
2028
2370
  // src/UVMapper.ts
2029
- var p6 = prefix("UVMapper");
2371
+ var p5 = prefix("UVMapper");
2030
2372
  var DEFAULT_UV = [0, 0, 16, 16];
2031
2373
  var X = 0;
2032
2374
  var Y = 1;
2033
2375
  var Z = 2;
2376
+ var FACE_UV_AXES = {
2377
+ east: [new import_three9.Vector3(0, 0, -1), new import_three9.Vector3(0, -1, 0)],
2378
+ west: [new import_three9.Vector3(0, 0, 1), new import_three9.Vector3(0, -1, 0)],
2379
+ up: [new import_three9.Vector3(1, 0, 0), new import_three9.Vector3(0, 0, 1)],
2380
+ down: [new import_three9.Vector3(1, 0, 0), new import_three9.Vector3(0, 0, -1)],
2381
+ south: [new import_three9.Vector3(1, 0, 0), new import_three9.Vector3(0, -1, 0)],
2382
+ north: [new import_three9.Vector3(-1, 0, 0), new import_three9.Vector3(0, -1, 0)]
2383
+ };
2034
2384
  var UVMapper = class {
2035
2385
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
2036
2386
  if (uvCoord === 0) return 0;
@@ -2126,7 +2476,43 @@ var UVMapper = class {
2126
2476
  return array;
2127
2477
  }
2128
2478
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2129
- return new import_three8.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2479
+ return new import_three9.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2480
+ }
2481
+ static lockUvs(geometry, faces, atlas, rotation) {
2482
+ const uv = geometry.getAttribute("uv");
2483
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2484
+ const faceName = CUBE_FACES[faceIndex];
2485
+ const texture = faces[faceName]?.texture?.substring(1);
2486
+ const position = texture && atlas.positions[texture];
2487
+ const size = texture && atlas.sizes[texture];
2488
+ if (!position || !size) continue;
2489
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2490
+ const uAxis = sourceU.clone().applyEuler(rotation);
2491
+ const vAxis = sourceV.clone().applyEuler(rotation);
2492
+ const normal = vAxis.clone().cross(uAxis);
2493
+ const targetFace = CUBE_FACES.find((name) => {
2494
+ const [u, v] = FACE_UV_AXES[name];
2495
+ return v.clone().cross(u).dot(normal) > 0.5;
2496
+ });
2497
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2498
+ const uu = Math.round(targetU.dot(uAxis));
2499
+ const uvCross = Math.round(targetU.dot(vAxis));
2500
+ const vu = Math.round(targetV.dot(uAxis));
2501
+ const vv = Math.round(targetV.dot(vAxis));
2502
+ for (let corner = 0; corner < 4; corner++) {
2503
+ const index = faceIndex * 4 + corner;
2504
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2505
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2506
+ const lockedU = uu * u + uvCross * v + 0.5;
2507
+ const lockedV = vu * u + vv * v + 0.5;
2508
+ uv.setXY(
2509
+ index,
2510
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2511
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2512
+ );
2513
+ }
2514
+ }
2515
+ uv.needsUpdate = true;
2130
2516
  }
2131
2517
  static async getAtlas(model) {
2132
2518
  const keyStr = model.key.serialize();
@@ -2168,43 +2554,42 @@ var UVMapper = class {
2168
2554
  v1 *= scaleV;
2169
2555
  u2 *= scaleU;
2170
2556
  v2 *= scaleV;
2171
- let tl = new import_three8.Vector2(u1, v1);
2172
- let tr = new import_three8.Vector2(u2, v1);
2173
- let bl = new import_three8.Vector2(u1, v2);
2174
- let br = new import_three8.Vector2(u2, v2);
2557
+ let tl = new import_three9.Vector2(u1, v1);
2558
+ let tr = new import_three9.Vector2(u2, v1);
2559
+ let bl = new import_three9.Vector2(u1, v2);
2560
+ let br = new import_three9.Vector2(u2, v2);
2175
2561
  switch (rotation) {
2176
2562
  case 0:
2177
2563
  case 360:
2178
2564
  default:
2179
2565
  break;
2180
2566
  case 90:
2181
- tl = new import_three8.Vector2(u1, v2);
2182
- tr = new import_three8.Vector2(u1, v1);
2183
- bl = new import_three8.Vector2(u2, v2);
2184
- br = new import_three8.Vector2(u2, v1);
2567
+ tl = new import_three9.Vector2(u1, v2);
2568
+ tr = new import_three9.Vector2(u1, v1);
2569
+ bl = new import_three9.Vector2(u2, v2);
2570
+ br = new import_three9.Vector2(u2, v1);
2185
2571
  break;
2186
2572
  case 180:
2187
- tl = new import_three8.Vector2(u2, v2);
2188
- tr = new import_three8.Vector2(u1, v2);
2189
- bl = new import_three8.Vector2(u2, v1);
2190
- br = new import_three8.Vector2(u1, v1);
2573
+ tl = new import_three9.Vector2(u2, v2);
2574
+ tr = new import_three9.Vector2(u1, v2);
2575
+ bl = new import_three9.Vector2(u2, v1);
2576
+ br = new import_three9.Vector2(u1, v1);
2191
2577
  break;
2192
2578
  case 270:
2193
- tl = new import_three8.Vector2(u2, v1);
2194
- tr = new import_three8.Vector2(u2, v2);
2195
- bl = new import_three8.Vector2(u1, v1);
2196
- br = new import_three8.Vector2(u1, v2);
2579
+ tl = new import_three9.Vector2(u2, v1);
2580
+ tr = new import_three9.Vector2(u2, v2);
2581
+ bl = new import_three9.Vector2(u1, v1);
2582
+ br = new import_three9.Vector2(u1, v2);
2197
2583
  break;
2198
2584
  }
2199
2585
  return [tl, tr, bl, br];
2200
2586
  }
2201
2587
  static async createAtlas(originalModel) {
2202
- var _a;
2203
2588
  const textureMap = {};
2204
2589
  const metaMap = {};
2205
2590
  const model = { ...originalModel };
2206
2591
  const isItemModel = !("elements" in model);
2207
- console.debug(p6, "Creating Atlas for", model.key);
2592
+ console.debug(p5, "Creating Atlas for", model.key);
2208
2593
  if (model.textures) {
2209
2594
  const promises = [];
2210
2595
  const uniqueTextureNames = [];
@@ -2218,7 +2603,7 @@ var UVMapper = class {
2218
2603
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2219
2604
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2220
2605
  if (!asset) {
2221
- console.warn(p6, "Missing texture", assetKey);
2606
+ console.warn(p5, "Missing texture", assetKey);
2222
2607
  return;
2223
2608
  }
2224
2609
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2230,7 +2615,7 @@ var UVMapper = class {
2230
2615
  }
2231
2616
  await Promise.all(promises);
2232
2617
  const textureCount = uniqueTextureNames.length;
2233
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2618
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2234
2619
  this.fillMissingTextureKeys(model.textures, textureMap);
2235
2620
  this.fillMissingTextureKeys(model.textures, metaMap);
2236
2621
  const sizes = {};
@@ -2250,7 +2635,7 @@ var UVMapper = class {
2250
2635
  this.fillMissingTextureKeys(model.textures, sizes);
2251
2636
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2252
2637
  const size = Math.ceil(s * maxWidth);
2253
- console.debug(p6, "Atlas size:", size);
2638
+ console.debug(p5, "Atlas size:", size);
2254
2639
  const squaredSize = size * size;
2255
2640
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2256
2641
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2279,16 +2664,15 @@ var UVMapper = class {
2279
2664
  if (texture.animated) {
2280
2665
  hasAnimation = true;
2281
2666
  const meta = metaMap[textureKey];
2282
- const frameTime = ((_a = meta == null ? void 0 : meta.animation) == null ? void 0 : _a.frametime) ?? 1;
2667
+ const frameTime = meta?.animation?.frametime ?? 1;
2283
2668
  console.log(meta);
2284
2669
  console.log(frameTime);
2285
2670
  let t = 0;
2286
2671
  let f = 0;
2287
2672
  animatorFunctions[textureKey] = () => {
2288
- var _a2;
2289
2673
  if (t++ >= frameTime) {
2290
2674
  t = 0;
2291
- const frames = (_a2 = meta == null ? void 0 : meta.animation) == null ? void 0 : _a2.frames;
2675
+ const frames = meta?.animation?.frames;
2292
2676
  const frame = frames ? frames[f] : f;
2293
2677
  image.putData(texture.getFrameSectionData(frame), x, y, 0, 0, maxWidth, maxWidth);
2294
2678
  f++;
@@ -2306,10 +2690,10 @@ var UVMapper = class {
2306
2690
  }
2307
2691
  }
2308
2692
  const atlasImageData = image.toDataURL();
2309
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2693
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2310
2694
  this.fillMissingTextureKeys(model.textures, positions);
2311
2695
  if (isItemModel) {
2312
- console.debug(p6, "Generating item model for", model);
2696
+ console.debug(p5, "Generating item model for", model);
2313
2697
  model.elements = [];
2314
2698
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2315
2699
  const textureImage = textureMap[layerName];
@@ -2317,7 +2701,7 @@ var UVMapper = class {
2317
2701
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2318
2702
  }
2319
2703
  }
2320
- console.debug(p6, "Item model elements", model.elements);
2704
+ console.debug(p5, "Item model elements", model.elements);
2321
2705
  }
2322
2706
  if (!model.elements) {
2323
2707
  }
@@ -2335,18 +2719,14 @@ var UVMapper = class {
2335
2719
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2336
2720
  continue;
2337
2721
  }
2722
+ if (!face.texture) continue;
2338
2723
  if (!face.uv) {
2339
2724
  face.uv = this.getFallbackUv(element, faceName);
2340
2725
  }
2341
- let faceTexture = face.texture;
2342
- let texPosition;
2343
- let texSize;
2344
- if (faceTexture) {
2345
- faceTexture = faceTexture.substr(1);
2346
- texPosition = positions[faceTexture] || [0, 0];
2347
- texSize = sizes[faceTexture] || [16, 16];
2348
- }
2349
- let texPosV = new import_three8.Vector2(texPosition[0], texPosition[1]);
2726
+ const faceTexture = face.texture.substr(1);
2727
+ const texPosition = positions[faceTexture] || [0, 0];
2728
+ const texSize = sizes[faceTexture] || [16, 16];
2729
+ let texPosV = new import_three9.Vector2(texPosition[0], texPosition[1]);
2350
2730
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2351
2731
  tl.add(texPosV);
2352
2732
  tr.add(texPosV);
@@ -2377,7 +2757,7 @@ var UVMapper = class {
2377
2757
  hasTransparency
2378
2758
  );
2379
2759
  } else {
2380
- console.warn(p6, "Model does not have any textures", model);
2760
+ console.warn(p5, "Model does not have any textures", model);
2381
2761
  }
2382
2762
  return void 0;
2383
2763
  }
@@ -2419,18 +2799,18 @@ var MinecraftCubeTexture = class {
2419
2799
  }
2420
2800
  getUvEast(w, h, l) {
2421
2801
  return [
2422
- [this.mapW(this.u), this.mapH(this.v + l + h)],
2423
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2424
- [this.mapW(this.u), this.mapH(this.v + l)],
2425
- [this.mapW(this.u + l), this.mapH(this.v + l)]
2802
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2803
+ [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2804
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
2805
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2426
2806
  ];
2427
2807
  }
2428
2808
  getUvWest(w, h, l) {
2429
2809
  return [
2430
- [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2431
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2432
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2433
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
2810
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2811
+ [this.mapW(this.u), this.mapH(this.v + l + h)],
2812
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
2813
+ [this.mapW(this.u), this.mapH(this.v + l)]
2434
2814
  ];
2435
2815
  }
2436
2816
  getUvUp(w, h, l) {
@@ -2443,26 +2823,26 @@ var MinecraftCubeTexture = class {
2443
2823
  }
2444
2824
  getUvDown(w, h, l) {
2445
2825
  return [
2446
- [this.mapW(this.u + l), this.mapH(this.v + l)],
2447
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2448
2826
  [this.mapW(this.u + l), this.mapH(this.v)],
2449
- [this.mapW(this.u + l + w), this.mapH(this.v)]
2827
+ [this.mapW(this.u + l + w), this.mapH(this.v)],
2828
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
2829
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2450
2830
  ];
2451
2831
  }
2452
2832
  getUvSouth(w, h, l) {
2453
2833
  return [
2454
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2455
2834
  [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l + h)],
2456
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
2457
- [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)]
2835
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
2836
+ [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)],
2837
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
2458
2838
  ];
2459
2839
  }
2460
2840
  getUvNorth(w, h, l) {
2461
2841
  return [
2462
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2463
2842
  [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
2464
- [this.mapW(this.u + l), this.mapH(this.v + l)],
2465
- [this.mapW(this.u + l + w), this.mapH(this.v + l)]
2843
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
2844
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)],
2845
+ [this.mapW(this.u + l), this.mapH(this.v + l)]
2466
2846
  ];
2467
2847
  }
2468
2848
  getFaceUv(face, w, h, l) {
@@ -2481,10 +2861,12 @@ var MinecraftCubeTexture = class {
2481
2861
  return this.getUvNorth(w, h, l);
2482
2862
  }
2483
2863
  }
2484
- toUvArray(w, h, l) {
2864
+ toUvArray(w, h, l, mirror = false) {
2485
2865
  const uv = [];
2486
2866
  for (let i = 0; i < CUBE_FACES.length; i++) {
2487
- UVMapper.setFaceUvInArray(uv, i * 4, this.getFaceUv(CUBE_FACES[i], w, h, l));
2867
+ const face = mirror && i < 2 ? CUBE_FACES[1 - i] : CUBE_FACES[i];
2868
+ const corners = this.getFaceUv(face, w, h, l);
2869
+ UVMapper.setFaceUvInArray(uv, i * 4, mirror ? [corners[1], corners[0], corners[3], corners[2]] : corners);
2488
2870
  }
2489
2871
  return uv;
2490
2872
  }
@@ -2514,76 +2896,85 @@ function shutdown() {
2514
2896
  Caching.end();
2515
2897
  }
2516
2898
 
2899
+ // src/error/MineRenderError.ts
2900
+ var MineRenderError = class _MineRenderError extends Error {
2901
+ constructor(msg) {
2902
+ super(msg);
2903
+ Object.setPrototypeOf(this, _MineRenderError.prototype);
2904
+ }
2905
+ get name() {
2906
+ return "MineRenderError";
2907
+ }
2908
+ };
2909
+
2517
2910
  // src/assets/Entities.ts
2518
- var import_typescript_memoize3 = require("typescript-memoize");
2519
2911
  var Entities = class {
2520
- static async getBlockEntityModels() {
2521
- const key = AssetKey.parse("models", "minerender:blockEntityModels");
2522
- console.log(key);
2523
- return AssetLoader.get(key, "json" /* JSON */);
2524
- }
2525
- static async getEntityModels() {
2526
- const key = AssetKey.parse("models", "minerender:entityModels");
2527
- console.log(key);
2528
- return AssetLoader.get(key, "json" /* JSON */);
2529
- }
2530
- // BlockEntity names are hardcoded
2531
- static async getBlockList() {
2532
- const models = await this.getBlockEntityModels();
2533
- if (!models) {
2534
- return [];
2535
- }
2536
- return Object.keys(models);
2537
- }
2538
2912
  static async getEntityList() {
2539
- const models = await this.getEntityModels();
2540
- if (!models) {
2541
- return [];
2542
- }
2543
- return Object.keys(models);
2544
- }
2545
- static async getBlock(modelKey, textureKey) {
2546
- const models = await this.getBlockEntityModels();
2547
- if (!models) {
2548
- return void 0;
2549
- }
2550
- if (!textureKey) {
2551
- textureKey = modelKey;
2552
- }
2553
- const baseKey = modelKey.path.includes("/") ? new BasicAssetKey(modelKey.namespace, modelKey.path.split("/")[0]) : modelKey;
2554
- return {
2555
- key: textureKey,
2556
- parts: models[baseKey.toNamespacedString()]
2913
+ const collect = async (path) => {
2914
+ const prefix2 = path ? `${path}/` : "";
2915
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
2916
+ const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
2917
+ if (!list) return [];
2918
+ const files = list.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
2919
+ const children = await Promise.all(list.directories.map((directory) => collect(`${prefix2}${directory}`)));
2920
+ return [...files, ...children.flat()];
2557
2921
  };
2922
+ return collect("");
2923
+ }
2924
+ static async getEntity(modelKey, textureKey, options) {
2925
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
2926
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
2927
+ const model = await Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
2928
+ if (!model) return void 0;
2929
+ const layerName = options?.layer ?? "main";
2930
+ const layer = model.layers[layerName];
2931
+ if (!layer) {
2932
+ throw new MineRenderError(`Entity ${model.id} has no layer "${layerName}". Available layers: ${Object.keys(model.layers).join(", ")}`);
2933
+ }
2934
+ let texture;
2935
+ if (textureKey) {
2936
+ const path2 = isAssetKey(textureKey) ? textureKey.getFullPath() : textureKey.path;
2937
+ 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);
2938
+ } else if (layer.textureLocation !== void 0) {
2939
+ texture = AssetKey.parse("textures", layer.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
2940
+ } else {
2941
+ texture = await this.resolveTexture(modelKey);
2942
+ }
2943
+ return { key: textureKey ?? modelKey, texture, layer, id: model.id };
2944
+ }
2945
+ static async resolveTexture(modelKey) {
2946
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
2947
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
2948
+ return Caching.entityTextureCache.get(key.serialize(), async () => {
2949
+ const name = path.split("/").pop();
2950
+ for (const candidate of [path, `${path}/${name}`]) {
2951
+ const texture = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png");
2952
+ if (await ModelTextures.get(texture)) return texture;
2953
+ }
2954
+ const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json");
2955
+ const list = await AssetLoader.get(listKey, "list" /* LIST */);
2956
+ const files = list?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
2957
+ const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
2958
+ if (!file) return void 0;
2959
+ const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json");
2960
+ const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
2961
+ const assets = variant?.assets;
2962
+ const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
2963
+ return typeof textureId === "string" ? AssetKey.parse("textures", textureId) : void 0;
2964
+ });
2558
2965
  }
2559
- static async getEntity(modelKey, textureKey) {
2560
- const models = await this.getEntityModels();
2561
- if (!models) {
2562
- return void 0;
2563
- }
2564
- if (!textureKey) {
2565
- textureKey = modelKey;
2566
- }
2567
- const baseKey = modelKey.path.includes("/") ? new BasicAssetKey(modelKey.namespace, modelKey.path.split("/")[0]) : modelKey;
2568
- return {
2569
- key: textureKey,
2570
- parts: models[baseKey.toNamespacedString()]
2571
- };
2966
+ /** @deprecated Use getEntityList(); block entities share the entity dataset. */
2967
+ static getBlockList() {
2968
+ return this.getEntityList();
2969
+ }
2970
+ /** @deprecated Use getEntity(); block entities share the entity dataset. */
2971
+ static getBlock(modelKey, textureKey, options) {
2972
+ return this.getEntity(modelKey, textureKey, options);
2572
2973
  }
2573
- };
2574
- __decorateClass([
2575
- (0, import_typescript_memoize3.Memoize)()
2576
- ], Entities, "getBlockEntityModels", 1);
2577
- __decorateClass([
2578
- (0, import_typescript_memoize3.Memoize)()
2579
- ], Entities, "getEntityModels", 1);
2580
- var EntityModels = class {
2581
- };
2582
- var BlockEntityModels = class {
2583
2974
  };
2584
2975
 
2585
2976
  // src/renderer/SceneObject.ts
2586
- var import_three9 = require("three");
2977
+ var import_three10 = require("three");
2587
2978
 
2588
2979
  // src/instance/InstanceReference.ts
2589
2980
  var InstanceReference = class {
@@ -2628,30 +3019,27 @@ function isInstanceReference(obj) {
2628
3019
  return obj.isInstanceReference;
2629
3020
  }
2630
3021
 
2631
- // src/error/MineRenderError.ts
2632
- var MineRenderError = class _MineRenderError extends Error {
2633
- constructor(msg) {
2634
- super(msg);
2635
- Object.setPrototypeOf(this, _MineRenderError.prototype);
2636
- }
2637
- get name() {
2638
- return "MineRenderError";
2639
- }
2640
- };
2641
-
2642
3022
  // src/renderer/SceneObject.ts
2643
- var import_ts_deepmerge4 = __toESM(require_dist());
2644
- var p7 = prefix("SceneObject");
2645
- var _SceneObject = class _SceneObject extends import_three9.Object3D {
3023
+ var import_ts_deepmerge3 = __toESM(require_dist());
3024
+ var p6 = prefix("SceneObject");
3025
+ var SceneObject = class _SceneObject extends import_three10.Object3D {
2646
3026
  constructor(options) {
2647
3027
  super();
2648
3028
  this.isSceneObject = true;
2649
3029
  this.materialCallbacks = {};
2650
3030
  this._isInstanced = false;
2651
3031
  this._instanceCounter = 0;
2652
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
3032
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2653
3033
  console.log("SceneObject options", this.options);
2654
3034
  }
3035
+ static {
3036
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
3037
+ instanceMeshes: true,
3038
+ maxInstanceCount: 50,
3039
+ mergeMeshes: true,
3040
+ wireframe: false
3041
+ });
3042
+ }
2655
3043
  set scene(scene) {
2656
3044
  if (!!this._scene) throw new MineRenderError("Scene already set");
2657
3045
  this._scene = scene;
@@ -2680,7 +3068,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2680
3068
  return group;
2681
3069
  }
2682
3070
  createGroup(name, x = 0, y = 0, z = 0, offsetAxis, offset = 0) {
2683
- const obj = new import_three9.Object3D();
3071
+ const obj = new import_three10.Object3D();
2684
3072
  if (name) {
2685
3073
  obj.name = `group:${name}`;
2686
3074
  }
@@ -2730,7 +3118,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2730
3118
  return mesh;
2731
3119
  }
2732
3120
  createMesh(name, geometry, material, offsetAxis, offset = 0) {
2733
- const mesh = new import_three9.Mesh(geometry, material);
3121
+ const mesh = new import_three10.Mesh(geometry, material);
2734
3122
  if (name) {
2735
3123
  mesh.name = `mesh:${name}`;
2736
3124
  }
@@ -2742,7 +3130,8 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2742
3130
  return mesh;
2743
3131
  }
2744
3132
  createInstancedMesh(name, geometry, material, count) {
2745
- const mesh = new import_three9.InstancedMesh(geometry, material, count);
3133
+ const mesh = new import_three10.InstancedMesh(geometry, material, count);
3134
+ mesh.count = 0;
2746
3135
  if (name) {
2747
3136
  mesh.name = `mesh:${name}`;
2748
3137
  }
@@ -2763,15 +3152,8 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2763
3152
  return this.toggleObjectVisibility(this.getMeshByName(name), visible);
2764
3153
  }
2765
3154
  iterateAllMeshes(cb) {
2766
- this.children.forEach((obj) => {
2767
- if (obj.isMesh) {
2768
- cb(obj);
2769
- }
2770
- obj.children.forEach((obj1) => {
2771
- if (obj1.isMesh) {
2772
- cb(obj1);
2773
- }
2774
- });
3155
+ this.traverse((obj) => {
3156
+ if (isMesh(obj)) cb(obj);
2775
3157
  });
2776
3158
  }
2777
3159
  //</editor-fold>
@@ -2819,10 +3201,14 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2819
3201
  nextInstance() {
2820
3202
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2821
3203
  const i = this._instanceCounter++;
2822
- this.setMatrixAt(i, new import_three9.Matrix4());
2823
- console.debug(p7, "nextInstance " + i);
3204
+ this.setMatrixAt(i, new import_three10.Matrix4());
3205
+ const mesh = this.children[0];
3206
+ if (mesh && isInstancedMesh(mesh)) {
3207
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
3208
+ }
3209
+ console.debug(p6, "nextInstance " + i);
2824
3210
  if (i === this.options.maxInstanceCount) {
2825
- console.warn(p7, "Max instance count reached for " + this);
3211
+ console.warn(p6, "Max instance count reached for " + this);
2826
3212
  }
2827
3213
  if (this.scene) {
2828
3214
  this.scene.stats.instanceCount++;
@@ -2832,7 +3218,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2832
3218
  }
2833
3219
  //</editor-fold>
2834
3220
  //<editor-fold desc="TRANSFORMATION">
2835
- getMatrixAt(index, matrix = new import_three9.Matrix4()) {
3221
+ getMatrixAt(index, matrix = new import_three10.Matrix4()) {
2836
3222
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2837
3223
  const child = this.children[0];
2838
3224
  if (child && isInstancedMesh(child)) {
@@ -2851,16 +3237,16 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2851
3237
  }
2852
3238
  setPositionRotationScaleAt(index, position, rotation, scale) {
2853
3239
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2854
- const oldPosition = new import_three9.Vector3();
2855
- const oldRotation = new import_three9.Quaternion();
2856
- const oldScale = new import_three9.Vector3();
2857
- const matrix = new import_three9.Matrix4();
3240
+ const oldPosition = new import_three10.Vector3();
3241
+ const oldRotation = new import_three10.Quaternion();
3242
+ const oldScale = new import_three10.Vector3();
3243
+ const matrix = new import_three10.Matrix4();
2858
3244
  if (!scale || !rotation || !position) {
2859
3245
  this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
2860
3246
  }
2861
3247
  matrix.compose(
2862
3248
  position ? position : oldPosition,
2863
- rotation ? new import_three9.Quaternion().setFromEuler(rotation) : oldRotation,
3249
+ rotation ? new import_three10.Quaternion().setFromEuler(rotation) : oldRotation,
2864
3250
  scale ? scale : oldScale
2865
3251
  );
2866
3252
  this.setMatrixAt(index, matrix);
@@ -2869,7 +3255,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2869
3255
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2870
3256
  this.setPositionRotationScaleAt(index, position);
2871
3257
  }
2872
- getPositionAt(index, vector = new import_three9.Vector3()) {
3258
+ getPositionAt(index, vector = new import_three10.Vector3()) {
2873
3259
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2874
3260
  const matrix = this.getMatrixAt(index);
2875
3261
  vector.setFromMatrixPosition(matrix);
@@ -2879,7 +3265,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2879
3265
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2880
3266
  this.setPositionRotationScaleAt(index, void 0, rotation, void 0);
2881
3267
  }
2882
- getRotationAt(index, euler = new import_three9.Euler()) {
3268
+ getRotationAt(index, euler = new import_three10.Euler()) {
2883
3269
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2884
3270
  const matrix = this.getMatrixAt(index);
2885
3271
  euler.setFromRotationMatrix(matrix);
@@ -2889,7 +3275,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2889
3275
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2890
3276
  this.setPositionRotationScaleAt(index, void 0, void 0, scale);
2891
3277
  }
2892
- getScaleAt(index, vector = new import_three9.Vector3()) {
3278
+ getScaleAt(index, vector = new import_three10.Vector3()) {
2893
3279
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2894
3280
  const matrix = this.getMatrixAt(index);
2895
3281
  vector.setFromMatrixScale(matrix);
@@ -2993,34 +3379,28 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2993
3379
  this.notifyDirty();
2994
3380
  }
2995
3381
  removeFromScene() {
2996
- var _a;
2997
- (_a = this._scene) == null ? void 0 : _a.remove(this);
3382
+ this._scene?.remove(this);
2998
3383
  this.notifyDirty();
2999
3384
  }
3000
3385
  //</editor-fold>
3001
3386
  };
3002
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
3003
- instanceMeshes: true,
3004
- maxInstanceCount: 50,
3005
- mergeMeshes: true,
3006
- wireframe: false
3007
- });
3008
- var SceneObject = _SceneObject;
3009
3387
  function isSceneObject(obj) {
3010
3388
  return obj.isSceneObject;
3011
3389
  }
3012
3390
 
3013
3391
  // src/entity/scene/EntityObject.ts
3014
- var import_ts_deepmerge5 = __toESM(require_dist());
3015
- var import_three11 = require("three");
3016
- var THREE2 = __toESM(require("three"));
3017
- var EntityObject = class extends SceneObject {
3392
+ var import_ts_deepmerge4 = __toESM(require_dist());
3393
+ var import_three12 = require("three");
3394
+ var EntityObject = class _EntityObject extends SceneObject {
3018
3395
  constructor(entity, options) {
3019
3396
  super();
3020
3397
  this.entity = entity;
3021
3398
  this.isEntityObject = true;
3022
3399
  this.meshesCreated = false;
3023
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3400
+ this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
3401
+ }
3402
+ static {
3403
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, { flip: true });
3024
3404
  }
3025
3405
  async init() {
3026
3406
  this.createMeshes();
@@ -3029,67 +3409,76 @@ var EntityObject = class extends SceneObject {
3029
3409
  dispose() {
3030
3410
  super.dispose();
3031
3411
  }
3032
- async loadTextures() {
3033
- var _a;
3034
- this.imageData = await ModelTextures.get(new AssetKey(
3035
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
3036
- this.entity.key.path,
3037
- //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
3412
+ get textureKey() {
3413
+ if (this.entity.texture) return this.entity.texture;
3414
+ const key = this.entity.key;
3415
+ return new AssetKey(
3416
+ key.namespace,
3417
+ isAssetKey(key) ? key.getFullPath() : key.path,
3038
3418
  "textures",
3039
3419
  "entity",
3040
3420
  "assets",
3041
3421
  ".png"
3042
- ));
3422
+ );
3423
+ }
3424
+ async loadTextures() {
3425
+ this.imageData = await ModelTextures.get(this.textureKey);
3043
3426
  }
3044
- //TODO: abstract this, since extracted model data can be used for entities, blocks, players
3045
3427
  createMeshes(force = false) {
3046
3428
  if (this.meshesCreated && !force) return;
3047
- const mat = Materials.MISSING_TEXTURE;
3048
- for (let partName in this.entity.parts) {
3049
- const part = this.entity.parts[partName];
3050
- const texture = new MinecraftCubeTexture(part.textureOffsetU, part.textureOffsetV, part.textureWidth, part.textureHeight);
3051
- const partAnchor = new import_three11.Object3D();
3052
- partAnchor.position.x = part.pivotX;
3053
- partAnchor.position.y = part.pivotY;
3054
- partAnchor.position.z = part.pivotZ;
3055
- for (let cube of part.cubes) {
3056
- const w = cube.maxX - cube.minX;
3057
- const h = cube.maxY - cube.minY;
3058
- const l = cube.maxZ - cube.minZ;
3059
- const uv = texture.toUvArray(w, h, l);
3060
- const cubeGeo = this._getBoxGeometryForDimensionsAndUv(w, h, l, uv).clone();
3061
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3062
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
3063
- applyModelPartRotation(part, cubeGeo);
3064
- const mesh = this.createMesh(partName, cubeGeo, mat);
3065
- partAnchor.add(mesh);
3066
- if (this.options.wireframe) {
3067
- addWireframeToMesh(cubeGeo, mesh);
3068
- }
3069
- }
3070
- this.add(partAnchor);
3071
- }
3429
+ const modelRoot = new import_three12.Object3D();
3430
+ if (this.options.flip) modelRoot.scale.set(-1, -1, 1);
3431
+ this.add(modelRoot);
3432
+ this.createPart("root", this.entity.layer.root, modelRoot, this.entity.layer.texture, Materials.MISSING_TEXTURE);
3072
3433
  this.meshesCreated = true;
3073
3434
  }
3074
- async applyTextures() {
3075
- var _a;
3076
- const textureAsset = await ModelTextures.preload(new AssetKey(
3077
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
3078
- this.entity.key.path,
3079
- "textures",
3080
- "entity",
3081
- "assets",
3082
- ".png"
3083
- ));
3084
- if (textureAsset) {
3085
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
3086
- this.iterateAllMeshes((mesh) => {
3087
- mesh.material = mat;
3088
- });
3435
+ createPart(name, part, parent, textureSize, material) {
3436
+ const anchor = this.createGroup(name);
3437
+ anchor.position.fromArray(part.pose.offset);
3438
+ anchor.rotation.set(...part.pose.rotation, "ZYX");
3439
+ anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
3440
+ parent.add(anchor);
3441
+ const size = part.texture ?? textureSize;
3442
+ for (const cube of part.cubes) {
3443
+ const [width, height, depth] = cube.size;
3444
+ const [growX, growY, growZ] = cube.grow ?? [0, 0, 0];
3445
+ const texture = new MinecraftCubeTexture(...cube.uv, ...size);
3446
+ const uv = size[0] === 0 || size[1] === 0 ? new Array(48).fill(0) : texture.toUvArray(width, height, depth, cube.mirror);
3447
+ const geometry = this._getBoxGeometryForDimensionsAndUv(
3448
+ width + growX * 2,
3449
+ height + growY * 2,
3450
+ depth + growZ * 2,
3451
+ uv
3452
+ ).clone();
3453
+ geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
3454
+ const mesh = this.createMesh(name, geometry, material);
3455
+ anchor.add(mesh);
3456
+ if (this.options.wireframe) addWireframeToMesh(geometry, mesh);
3457
+ }
3458
+ for (const [childName, child] of Object.entries(part.children)) {
3459
+ this.createPart(childName, child, anchor, size, material);
3089
3460
  }
3090
3461
  }
3462
+ async applyTextures() {
3463
+ const assetKeyStr = this.textureKey.serialize();
3464
+ const keyStr = `entity:${assetKeyStr}`;
3465
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3466
+ if (!mat) {
3467
+ const pending = this.loadTextures();
3468
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3469
+ await pending;
3470
+ if (!this.imageData) return;
3471
+ const canvas = this.imageData.data.canvas;
3472
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3473
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3474
+ this.imageData = void 0;
3475
+ }
3476
+ this.iterateAllMeshes((mesh) => {
3477
+ mesh.material = mat;
3478
+ });
3479
+ this.notifyDirty();
3480
+ }
3091
3481
  };
3092
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3093
3482
  function isEntityObject(obj) {
3094
3483
  return obj.isEntityObject;
3095
3484
  }
@@ -3100,16 +3489,16 @@ var GuiObject = class extends SceneObject {
3100
3489
  };
3101
3490
 
3102
3491
  // src/inspector/SceneInspector.ts
3103
- var import_three12 = require("three");
3104
- var p8 = prefix("SceneInspector");
3492
+ var import_three13 = require("three");
3493
+ var p7 = prefix("SceneInspector");
3105
3494
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3106
3495
  var SceneInspector = class {
3107
3496
  constructor(renderer) {
3108
3497
  this.renderer = renderer;
3109
- this.mouse = new import_three12.Vector2();
3498
+ this.mouse = new import_three13.Vector2();
3110
3499
  this.objectInfoContainer = document.createElement("div");
3111
3500
  this.objectControlsContainer = document.createElement("div");
3112
- this.raycaster = new import_three12.Raycaster();
3501
+ this.raycaster = new import_three13.Raycaster();
3113
3502
  this.init();
3114
3503
  }
3115
3504
  init() {
@@ -3130,8 +3519,7 @@ var SceneInspector = class {
3130
3519
  return out;
3131
3520
  }
3132
3521
  onClick(event) {
3133
- var _a;
3134
- if (((_a = event.target) == null ? void 0 : _a.nodeName) !== "CANVAS") return;
3522
+ if (event.target?.nodeName !== "CANVAS") return;
3135
3523
  if (!event.ctrlKey) return;
3136
3524
  setTimeout(() => {
3137
3525
  this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
@@ -3171,7 +3559,7 @@ var SceneInspector = class {
3171
3559
  }
3172
3560
  selectObject(targetObject, targetIntersection) {
3173
3561
  this.selectedObject = targetObject;
3174
- console.log(p8, "selected", targetObject);
3562
+ console.log(p7, "selected", targetObject);
3175
3563
  this.redraw(targetObject, targetIntersection);
3176
3564
  }
3177
3565
  redraw(targetObject, targetIntersection) {
@@ -3469,7 +3857,7 @@ var SceneStatsDisplay = class {
3469
3857
  };
3470
3858
 
3471
3859
  // src/instance/InstanceManager.ts
3472
- var p9 = prefix("InstanceManager");
3860
+ var p8 = prefix("InstanceManager");
3473
3861
  var InstanceManager = class {
3474
3862
  constructor() {
3475
3863
  this.isInstanceManager = true;
@@ -3477,7 +3865,7 @@ var InstanceManager = class {
3477
3865
  }
3478
3866
  async get(key) {
3479
3867
  if (key in this.instanceCache) {
3480
- console.debug(p9, "key in cache", key);
3868
+ console.debug(p8, "key in cache", key);
3481
3869
  return (await this.instanceCache[key]).nextInstance();
3482
3870
  }
3483
3871
  return void 0;
@@ -3486,13 +3874,17 @@ var InstanceManager = class {
3486
3874
  if (key in this.instanceCache) {
3487
3875
  return await this.get(key);
3488
3876
  }
3489
- console.debug(p9, "key not in cache", key);
3490
- this.instanceCache[key] = new Promise(async (resolve) => {
3491
- const obj = await supplier();
3492
- const instance = obj.nextInstance();
3493
- resolve(instance);
3494
- });
3495
- return await this.instanceCache[key];
3877
+ console.debug(p8, "key not in cache", key);
3878
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3879
+ this.instanceCache[key] = pending;
3880
+ try {
3881
+ return await pending;
3882
+ } catch (error) {
3883
+ if (this.instanceCache[key] === pending) {
3884
+ delete this.instanceCache[key];
3885
+ }
3886
+ throw error;
3887
+ }
3496
3888
  }
3497
3889
  reset() {
3498
3890
  for (let instanceCacheKey in this.instanceCache) {
@@ -3509,20 +3901,6 @@ function isInstanceable(obj) {
3509
3901
  return "nextInstance" in obj;
3510
3902
  }
3511
3903
 
3512
- // src/model/DisplayPosition.ts
3513
- var DisplayPosition = /* @__PURE__ */ ((DisplayPosition2) => {
3514
- DisplayPosition2["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
3515
- DisplayPosition2["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
3516
- DisplayPosition2["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
3517
- DisplayPosition2["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
3518
- DisplayPosition2["GUI"] = "gui";
3519
- DisplayPosition2["HEAD"] = "head";
3520
- DisplayPosition2["GROUND"] = "ground";
3521
- DisplayPosition2["FIXED"] = "fixed";
3522
- return DisplayPosition2;
3523
- })(DisplayPosition || {});
3524
- var DISPLAY_POSITIONS = Object.values(DisplayPosition);
3525
-
3526
3904
  // src/model/GuiLight.ts
3527
3905
  var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
3528
3906
  GuiLight2["FRONT"] = "front";
@@ -3545,11 +3923,96 @@ function isQuadArray(obj) {
3545
3923
  return Array.isArray(obj) && obj.length === 4;
3546
3924
  }
3547
3925
 
3926
+ // src/model/block/blockTints.json
3927
+ var blockTints_default = {
3928
+ "minecraft:large_fern": { source: "grass" },
3929
+ "minecraft:tall_grass": { source: "grass" },
3930
+ "minecraft:grass_block": { source: "grass" },
3931
+ "minecraft:fern": { source: "grass" },
3932
+ "minecraft:grass": { source: "grass" },
3933
+ "minecraft:short_grass": { source: "grass" },
3934
+ "minecraft:potted_fern": { source: "grass" },
3935
+ "minecraft:bush": { source: "grass" },
3936
+ "minecraft:pink_petals": { source: "grass", untinted: [0] },
3937
+ "minecraft:wildflowers": { source: "grass", untinted: [0] },
3938
+ "minecraft:spruce_leaves": { source: "constant", color: 6396257 },
3939
+ "minecraft:birch_leaves": { source: "constant", color: 8431445 },
3940
+ "minecraft:oak_leaves": { source: "constant", color: 4764952 },
3941
+ "minecraft:jungle_leaves": { source: "constant", color: 4764952 },
3942
+ "minecraft:acacia_leaves": { source: "constant", color: 4764952 },
3943
+ "minecraft:dark_oak_leaves": { source: "constant", color: 4764952 },
3944
+ "minecraft:vine": { source: "constant", color: 4764952 },
3945
+ "minecraft:mangrove_leaves": { source: "constant", color: 4764952 },
3946
+ "minecraft:leaf_litter": { source: "constant", color: 6044722 },
3947
+ "minecraft:water_cauldron": { source: "constant", color: 4159204 },
3948
+ "minecraft:redstone_wire": { source: "redstone" },
3949
+ "minecraft:attached_melon_stem": { source: "constant", color: 14731036 },
3950
+ "minecraft:attached_pumpkin_stem": { source: "constant", color: 14731036 },
3951
+ "minecraft:melon_stem": { source: "stem" },
3952
+ "minecraft:pumpkin_stem": { source: "stem" },
3953
+ "minecraft:lily_pad": { source: "constant", color: 7455580 }
3954
+ };
3955
+
3956
+ // src/model/block/BlockTints.ts
3957
+ var rules = blockTints_default;
3958
+ var BlockTints = class {
3959
+ /** Resolves block preview colors without biome context; explicit tints take precedence. */
3960
+ static async get(key, state, model, tints) {
3961
+ const rule = key && rules[key.toNamespacedString()];
3962
+ if (!key || !rule) return tints;
3963
+ const indices = /* @__PURE__ */ new Set();
3964
+ for (const element of model.elements ?? []) {
3965
+ for (const face of Object.values(element.faces)) {
3966
+ const index = face?.tintindex;
3967
+ if (index !== void 0 && index >= 0 && tints?.[index] === void 0 && !rule.untinted?.includes(index)) {
3968
+ indices.add(index);
3969
+ }
3970
+ }
3971
+ }
3972
+ if (!indices.size) return tints;
3973
+ let color;
3974
+ switch (rule.source) {
3975
+ case "constant":
3976
+ color = rule.color;
3977
+ break;
3978
+ case "grass":
3979
+ color = await this.grassColor(key);
3980
+ break;
3981
+ case "redstone": {
3982
+ const power = Number(state.power ?? 0) / 15;
3983
+ const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
3984
+ const green = Math.max(0, power * power * 0.7 - 0.5);
3985
+ const blue = Math.max(0, power * power * 0.6 - 0.7);
3986
+ color = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
3987
+ break;
3988
+ }
3989
+ case "stem": {
3990
+ const age = Number(state.age ?? 0);
3991
+ color = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
3992
+ break;
3993
+ }
3994
+ }
3995
+ return { ...Object.fromEntries([...indices].map((index) => [index, color])), ...tints };
3996
+ }
3997
+ static async grassColor(origin) {
3998
+ const key = AssetKey.parse("textures", "minecraft:colormap/grass", origin);
3999
+ return await Caching.blockTintCache.get(key.serialize(), async () => {
4000
+ const image = await ModelTextures.get(key);
4001
+ if (!image) throw new MineRenderError(`Missing grass colormap: ${key.toNamespacedString()}`);
4002
+ if (image.width !== 256 || image.height !== 256) {
4003
+ throw new MineRenderError("Grass colormaps must be 256 \xD7 256 pixels");
4004
+ }
4005
+ const [red, green, blue] = image.data.getImageData(127, 127, 1, 1).data;
4006
+ return red << 16 | green << 8 | blue;
4007
+ });
4008
+ }
4009
+ };
4010
+
3548
4011
  // src/model/scene/ModelObject.ts
3549
- var import_three15 = require("three");
4012
+ var import_three16 = require("three");
3550
4013
 
3551
4014
  // src/three/BufferGeometryUtils.js
3552
- var import_three14 = require("three");
4015
+ var import_three15 = require("three");
3553
4016
  function computeTangents(geometry) {
3554
4017
  geometry.computeTangents();
3555
4018
  console.warn("THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.");
@@ -3561,7 +4024,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
3561
4024
  const attributes = {};
3562
4025
  const morphAttributes = {};
3563
4026
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
3564
- const mergedGeometry = new import_three14.BufferGeometry();
4027
+ const mergedGeometry = new import_three15.BufferGeometry();
3565
4028
  let offset = 0;
3566
4029
  for (let i = 0; i < geometries.length; ++i) {
3567
4030
  const geometry = geometries[i];
@@ -3685,7 +4148,7 @@ function mergeBufferAttributes(attributes) {
3685
4148
  array.set(attributes[i].array, offset);
3686
4149
  offset += attributes[i].array.length;
3687
4150
  }
3688
- return new import_three14.BufferAttribute(array, itemSize, normalized);
4151
+ return new import_three15.BufferAttribute(array, itemSize, normalized);
3689
4152
  }
3690
4153
  function interleaveAttributes(attributes) {
3691
4154
  let TypedArray;
@@ -3701,7 +4164,7 @@ function interleaveAttributes(attributes) {
3701
4164
  arrayLength += attribute.array.length;
3702
4165
  stride += attribute.itemSize;
3703
4166
  }
3704
- const interleavedBuffer = new import_three14.InterleavedBuffer(new TypedArray(arrayLength), stride);
4167
+ const interleavedBuffer = new import_three15.InterleavedBuffer(new TypedArray(arrayLength), stride);
3705
4168
  let offset = 0;
3706
4169
  const res = [];
3707
4170
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -3710,7 +4173,7 @@ function interleaveAttributes(attributes) {
3710
4173
  const attribute = attributes[j];
3711
4174
  const itemSize = attribute.itemSize;
3712
4175
  const count = attribute.count;
3713
- const iba = new import_three14.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
4176
+ const iba = new import_three15.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
3714
4177
  res.push(iba);
3715
4178
  offset += itemSize;
3716
4179
  for (let c = 0; c < count; c++) {
@@ -3794,13 +4257,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3794
4257
  const name = attributeNames[i];
3795
4258
  const oldAttribute = geometry.getAttribute(name);
3796
4259
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
3797
- const attribute = new import_three14.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
4260
+ const attribute = new import_three15.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
3798
4261
  result.setAttribute(name, attribute);
3799
4262
  if (name in morphAttrsArrays) {
3800
4263
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
3801
4264
  const oldMorphAttribute = geometry.morphAttributes[name][j];
3802
4265
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
3803
- const morphAttribute = new import_three14.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
4266
+ const morphAttribute = new import_three15.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
3804
4267
  result.morphAttributes[name][j] = morphAttribute;
3805
4268
  }
3806
4269
  }
@@ -3809,11 +4272,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
3809
4272
  return result;
3810
4273
  }
3811
4274
  function toTrianglesDrawMode(geometry, drawMode) {
3812
- if (drawMode === import_three14.TrianglesDrawMode) {
4275
+ if (drawMode === import_three15.TrianglesDrawMode) {
3813
4276
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
3814
4277
  return geometry;
3815
4278
  }
3816
- if (drawMode === import_three14.TriangleFanDrawMode || drawMode === import_three14.TriangleStripDrawMode) {
4279
+ if (drawMode === import_three15.TriangleFanDrawMode || drawMode === import_three15.TriangleStripDrawMode) {
3817
4280
  let index = geometry.getIndex();
3818
4281
  if (index === null) {
3819
4282
  const indices = [];
@@ -3831,7 +4294,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
3831
4294
  }
3832
4295
  const numberOfTriangles = index.count - 2;
3833
4296
  const newIndices = [];
3834
- if (drawMode === import_three14.TriangleFanDrawMode) {
4297
+ if (drawMode === import_three15.TriangleFanDrawMode) {
3835
4298
  for (let i = 1; i <= numberOfTriangles; i++) {
3836
4299
  newIndices.push(index.getX(0));
3837
4300
  newIndices.push(index.getX(i));
@@ -3867,15 +4330,15 @@ function computeMorphedAttributes(object) {
3867
4330
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3868
4331
  return null;
3869
4332
  }
3870
- const _vA = new import_three14.Vector3();
3871
- const _vB = new import_three14.Vector3();
3872
- const _vC = new import_three14.Vector3();
3873
- const _tempA = new import_three14.Vector3();
3874
- const _tempB = new import_three14.Vector3();
3875
- const _tempC = new import_three14.Vector3();
3876
- const _morphA = new import_three14.Vector3();
3877
- const _morphB = new import_three14.Vector3();
3878
- const _morphC = new import_three14.Vector3();
4333
+ const _vA = new import_three15.Vector3();
4334
+ const _vB = new import_three15.Vector3();
4335
+ const _vC = new import_three15.Vector3();
4336
+ const _tempA = new import_three15.Vector3();
4337
+ const _tempB = new import_three15.Vector3();
4338
+ const _tempC = new import_three15.Vector3();
4339
+ const _morphA = new import_three15.Vector3();
4340
+ const _morphB = new import_three15.Vector3();
4341
+ const _morphC = new import_three15.Vector3();
3879
4342
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3880
4343
  _vA.fromBufferAttribute(attribute, a2);
3881
4344
  _vB.fromBufferAttribute(attribute, b2);
@@ -4070,8 +4533,8 @@ function computeMorphedAttributes(object) {
4070
4533
  }
4071
4534
  }
4072
4535
  }
4073
- const morphedPositionAttribute = new import_three14.Float32BufferAttribute(modifiedPosition, 3);
4074
- const morphedNormalAttribute = new import_three14.Float32BufferAttribute(modifiedNormal, 3);
4536
+ const morphedPositionAttribute = new import_three15.Float32BufferAttribute(modifiedPosition, 3);
4537
+ const morphedNormalAttribute = new import_three15.Float32BufferAttribute(modifiedNormal, 3);
4075
4538
  return {
4076
4539
  positionAttribute,
4077
4540
  normalAttribute,
@@ -4081,26 +4544,29 @@ function computeMorphedAttributes(object) {
4081
4544
  }
4082
4545
 
4083
4546
  // src/model/scene/ModelObject.ts
4084
- var import_ts_deepmerge6 = __toESM(require_dist());
4085
- var p10 = prefix("ModelObject");
4086
- var _ModelObject = class _ModelObject extends SceneObject {
4547
+ var import_ts_deepmerge5 = __toESM(require_dist());
4548
+ var p9 = prefix("ModelObject");
4549
+ var ModelObject = class _ModelObject extends SceneObject {
4087
4550
  constructor(originalModel, options) {
4088
4551
  super(options);
4089
4552
  this.originalModel = originalModel;
4090
4553
  this.isModelObject = true;
4091
4554
  this.meshesCreated = false;
4092
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4555
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4556
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
4093
4557
  console.log("ModelObject options", this.options);
4094
4558
  }
4559
+ static {
4560
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4561
+ }
4095
4562
  async init() {
4096
4563
  await this.loadTextures();
4097
4564
  this.createMeshes();
4098
4565
  this.applyTextures();
4099
4566
  }
4100
4567
  dispose() {
4101
- var _a;
4102
4568
  super.dispose();
4103
- (_a = this.atlas) == null ? void 0 : _a.dispose();
4569
+ this.atlas?.dispose();
4104
4570
  }
4105
4571
  get textureAtlas() {
4106
4572
  return this.atlas;
@@ -4110,20 +4576,38 @@ var _ModelObject = class _ModelObject extends SceneObject {
4110
4576
  this.atlas = await UVMapper.getAtlas(this.originalModel);
4111
4577
  }
4112
4578
  createMeshes(force = false) {
4113
- var _a;
4114
4579
  if (this.meshesCreated && !force) return;
4115
4580
  const mat = Materials.MISSING_TEXTURE;
4581
+ const displayTransform = this.options.displayPosition ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : void 0;
4116
4582
  let allGeos = [];
4117
4583
  if (this.atlas) {
4118
4584
  if (this.atlas.model.elements) {
4119
- (_a = this.atlas.model.elements) == null ? void 0 : _a.forEach((el) => {
4585
+ this.atlas.model.elements?.forEach((el) => {
4120
4586
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4121
- 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));
4122
- elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4587
+ if (this.options.uvLockRotation) {
4588
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three16.Euler(...this.options.uvLockRotation));
4589
+ }
4590
+ if (this.options.tints) {
4591
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4592
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4593
+ const tintIndex = el.faces[faceName]?.tintindex;
4594
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4595
+ const tint = this.options.tints[tintIndex];
4596
+ if (tint === void 0) continue;
4597
+ const color = new import_three16.Color(tint);
4598
+ for (let vertex = 0; vertex < 4; vertex++) {
4599
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4600
+ }
4601
+ }
4602
+ elGeo.setAttribute("color", new import_three16.BufferAttribute(colors, 3));
4603
+ }
4604
+ 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));
4605
+ elGeo.applyMatrix4(new import_three16.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4123
4606
  if (el.rotation) {
4124
4607
  applyElementRotation(el.rotation, elGeo);
4125
4608
  }
4126
- elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation(-8, -8, -8));
4609
+ elGeo.applyMatrix4(new import_three16.Matrix4().makeTranslation(-8, -8, -8));
4610
+ if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4127
4611
  if (this.options.mergeMeshes) {
4128
4612
  allGeos.push(elGeo);
4129
4613
  } else {
@@ -4134,17 +4618,18 @@ var _ModelObject = class _ModelObject extends SceneObject {
4134
4618
  }
4135
4619
  });
4136
4620
  } else {
4137
- console.debug(p10, this.atlas.model, "has no elements");
4621
+ console.debug(p9, this.atlas.model, "has no elements");
4138
4622
  }
4139
4623
  } else {
4140
- console.debug(p10, "Missing atlas for", this);
4624
+ console.debug(p9, "Missing atlas for", this);
4141
4625
  }
4142
4626
  if (this.options.mergeMeshes) {
4143
4627
  let combinedGeo;
4144
4628
  if (allGeos.length > 0) {
4145
4629
  combinedGeo = mergeBufferGeometries(allGeos);
4146
4630
  } else {
4147
- combinedGeo = new import_three15.BoxGeometry(16, 16, 16);
4631
+ combinedGeo = new import_three16.BoxGeometry(16, 16, 16);
4632
+ if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4148
4633
  }
4149
4634
  combinedGeo.computeBoundingBox();
4150
4635
  let mesh;
@@ -4174,6 +4659,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4174
4659
  /*TODO: get this from render options*/
4175
4660
  );
4176
4661
  this.iterateAllMeshes((mesh) => {
4662
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4177
4663
  mesh.material = mat;
4178
4664
  });
4179
4665
  if (this.atlas.hasAnimation) {
@@ -4189,17 +4675,25 @@ var _ModelObject = class _ModelObject extends SceneObject {
4189
4675
  }
4190
4676
  }
4191
4677
  };
4192
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4193
- var ModelObject = _ModelObject;
4194
4678
  function isModelObject(obj) {
4195
4679
  return obj.isModelObject;
4196
4680
  }
4197
4681
 
4198
4682
  // src/model/block/scene/BlockObject.ts
4199
- var import_ts_deepmerge7 = __toESM(require_dist());
4200
- var import_three16 = require("three");
4201
- var p11 = prefix("BlockObject");
4202
- var _BlockObject = class _BlockObject extends SceneObject {
4683
+ var import_ts_deepmerge6 = __toESM(require_dist());
4684
+ var import_three17 = require("three");
4685
+ var p10 = prefix("BlockObject");
4686
+ function matchesCondition(condition, state) {
4687
+ return Object.entries(condition).every(([key, value]) => {
4688
+ if (Array.isArray(value)) {
4689
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4690
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4691
+ return false;
4692
+ }
4693
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4694
+ });
4695
+ }
4696
+ var BlockObject = class _BlockObject extends SceneObject {
4203
4697
  constructor(blockState, options) {
4204
4698
  super(options);
4205
4699
  this.blockState = blockState;
@@ -4212,11 +4706,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4212
4706
  this._instanceModel = [];
4213
4707
  this._variants = [];
4214
4708
  this._models = [];
4215
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4709
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4710
+ }
4711
+ static {
4712
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4713
+ applyDefaultState: true
4714
+ });
4216
4715
  }
4217
4716
  async init() {
4218
4717
  if (this.options.applyDefaultState) {
4219
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4718
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4220
4719
  if (defaultState && Object.keys(defaultState).length > 0) {
4221
4720
  const state = {};
4222
4721
  for (let k in defaultState) {
@@ -4227,15 +4726,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4227
4726
  if (this.blockState.variants) {
4228
4727
  await this.setState(Object.keys(this.blockState.variants)[0]);
4229
4728
  } else if (this.blockState.multipart) {
4230
- for (let part of this.blockState.multipart) {
4231
- if (part.when && !("OR" in part.when)) {
4232
- const k = Object.keys(part.when)[0];
4233
- if (k) {
4234
- await this.setState(k, part.when[k].split("|")[0]);
4235
- break;
4236
- }
4237
- }
4238
- }
4729
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4730
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4731
+ await this.setState(state);
4239
4732
  }
4240
4733
  }
4241
4734
  } else {
@@ -4250,7 +4743,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4250
4743
  if (isModelObject(model)) {
4251
4744
  model.removeFromScene();
4252
4745
  } else if (isInstanceReference(model)) {
4253
- model.setScale(new import_three16.Vector3(0, 0, 0));
4746
+ model.setScale(new import_three17.Vector3(0, 0, 0));
4254
4747
  }
4255
4748
  }
4256
4749
  super.removeFromScene();
@@ -4292,55 +4785,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4292
4785
  } else if (this.blockState.multipart) {
4293
4786
  for (let part of this.blockState.multipart) {
4294
4787
  if (!part.apply) {
4295
- console.debug(p11, "Missing apply for blockState part", part);
4788
+ console.debug(p10, "Missing apply for blockState part", part);
4296
4789
  continue;
4297
4790
  }
4298
- if (!part.when) {
4791
+ if (!part.when || matchesCondition(part.when, state)) {
4299
4792
  out.push(this.getSingleVariant(part.apply));
4300
- } else {
4301
- let matches = true;
4302
- if ("OR" in part.when) {
4303
- const or = part.when.OR;
4304
- let anyMatch = false;
4305
- for (let o of or) {
4306
- for (let k in o) {
4307
- const split = o[k].split("|");
4308
- let m = false;
4309
- for (let s of split) {
4310
- if (`${state[k]}` === `${s}`) {
4311
- m = true;
4312
- break;
4313
- }
4314
- }
4315
- if (m) {
4316
- anyMatch = true;
4317
- break;
4318
- }
4319
- }
4320
- }
4321
- if (!anyMatch) {
4322
- matches = false;
4323
- }
4324
- } else {
4325
- for (let k in part.when) {
4326
- const split = part.when[k].split("|");
4327
- let m = false;
4328
- for (let s of split) {
4329
- if (`${state[k]}` === `${s}`) {
4330
- m = true;
4331
- break;
4332
- }
4333
- }
4334
- if (!m) {
4335
- matches = false;
4336
- break;
4337
- }
4338
- }
4339
- }
4340
- if (matches) {
4341
- const variants = part.apply;
4342
- out.push(this.getSingleVariant(variants));
4343
- }
4344
4793
  }
4345
4794
  }
4346
4795
  }
@@ -4355,7 +4804,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4355
4804
  }
4356
4805
  for (let model of this._models) {
4357
4806
  if (isInstanceReference(model)) {
4358
- model.setScale(new import_three16.Vector3(0, 0, 0));
4807
+ model.setScale(new import_three17.Vector3(0, 0, 0));
4359
4808
  } else {
4360
4809
  model.dispose();
4361
4810
  }
@@ -4370,11 +4819,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4370
4819
  }
4371
4820
  }
4372
4821
  getSingleVariant(variants) {
4373
- if (Array.isArray(variants)) {
4374
- return variants[0];
4375
- } else {
4376
- return variants;
4377
- }
4822
+ if (!Array.isArray(variants)) return variants;
4823
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4824
+ const total = variants.reduce((sum, variant) => {
4825
+ const weight = variant.weight ?? 1;
4826
+ if (!Number.isInteger(weight) || weight < 1) {
4827
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4828
+ }
4829
+ return sum + weight;
4830
+ }, 0);
4831
+ let choice = Math.random() * total;
4832
+ for (const variant of variants) {
4833
+ choice -= variant.weight ?? 1;
4834
+ if (choice < 0) return variant;
4835
+ }
4836
+ return variants[variants.length - 1];
4378
4837
  }
4379
4838
  // @deprecated
4380
4839
  async createAVariant(variants, instanceInfo) {
@@ -4382,28 +4841,27 @@ var _BlockObject = class _BlockObject extends SceneObject {
4382
4841
  await this.createVariant(variant);
4383
4842
  }
4384
4843
  async createVariant(variant) {
4385
- const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4386
- const obj = await this.scene.addModel(model, this.options);
4387
- if (isInstanceReference(obj) || obj.isInstanced) {
4388
- this._isInstanced = true;
4389
- this._instanceCounter = 1;
4390
- }
4391
- let rotation = new import_three16.Euler(0, 0, 0);
4844
+ const rotation = new import_three17.Euler();
4392
4845
  if (typeof variant.x !== "undefined") {
4393
4846
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4394
4847
  }
4395
4848
  if (typeof variant.y !== "undefined") {
4396
- if (typeof variant.x !== "undefined") {
4397
- rotation.y = toRadians(clampRotationDegrees(variant.y));
4398
- } else {
4399
- rotation.y = toRadians(clampRotationDegrees(360 - variant.y));
4400
- }
4849
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4850
+ }
4851
+ const modelKey = AssetKey.parse("models", variant.model);
4852
+ modelKey.root = this.blockState.key?.root;
4853
+ const model = await Models.getMerged(modelKey);
4854
+ const options = {
4855
+ ...this.options,
4856
+ tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
4857
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4858
+ };
4859
+ const obj = await this.scene.addModel(model, options);
4860
+ if (isInstanceReference(obj) || obj.isInstanced) {
4861
+ this._isInstanced = true;
4862
+ this._instanceCounter = 1;
4401
4863
  }
4402
4864
  obj.setRotation(rotation);
4403
- setTimeout(() => {
4404
- obj.setRotation(rotation);
4405
- }, 150);
4406
- console.log(obj);
4407
4865
  return obj;
4408
4866
  }
4409
4867
  async resetState() {
@@ -4472,7 +4930,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4472
4930
  setPositionRotationScaleAt(index, position, rotation, scale) {
4473
4931
  super.setPositionRotationScaleAt(index, position, rotation, scale);
4474
4932
  }
4475
- getMatrixAt(index, matrix = new import_three16.Matrix4()) {
4933
+ getMatrixAt(index, matrix = new import_three17.Matrix4()) {
4476
4934
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
4477
4935
  const child = this._models[0];
4478
4936
  if (child && isModelObject(child)) {
@@ -4493,18 +4951,15 @@ var _BlockObject = class _BlockObject extends SceneObject {
4493
4951
  }
4494
4952
  }
4495
4953
  setPosition(position) {
4496
- super.setPosition(position);
4954
+ this.position.copy(position);
4497
4955
  for (let model of this._models) {
4498
4956
  model.setPosition(position);
4499
4957
  }
4958
+ this.notifyDirty();
4500
4959
  }
4501
4960
  //TODO: should override rotation + scale methods
4502
4961
  //TODO
4503
4962
  };
4504
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4505
- applyDefaultState: true
4506
- });
4507
- var BlockObject = _BlockObject;
4508
4963
  function isBlockObject(obj) {
4509
4964
  return obj.isBlockObject;
4510
4965
  }
@@ -4529,11 +4984,10 @@ var StructureParser = class {
4529
4984
  throw new MineRenderError("Structure does not have palette(s)");
4530
4985
  }
4531
4986
  const blocks = nbt.blocks.value.value.map((block) => {
4532
- var _a;
4533
4987
  const state = palette.value.value[block.state.value];
4534
4988
  if (state.Name.value === "minecraft:air") return void 0;
4535
4989
  const props = {};
4536
- for (let k in (_a = state.Properties) == null ? void 0 : _a.value) {
4990
+ for (let k in state.Properties?.value) {
4537
4991
  props[k] = state.Properties.value[k].value;
4538
4992
  }
4539
4993
  return {
@@ -4551,8 +5005,8 @@ var StructureParser = class {
4551
5005
  };
4552
5006
 
4553
5007
  // src/renderer/MineRenderScene.ts
4554
- var import_three17 = require("three");
4555
- var import_ts_deepmerge9 = __toESM(require_dist());
5008
+ var import_three19 = require("three");
5009
+ var import_ts_deepmerge8 = __toESM(require_dist());
4556
5010
 
4557
5011
  // src/skin/SkinPart.ts
4558
5012
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5188,62 +5642,52 @@ var baseSkinCoordinates = {
5188
5642
  }
5189
5643
  },
5190
5644
  cape: {
5191
- //TODO
5192
- east: {
5193
- uv: [
5194
- 0,
5195
- 36,
5196
- 4,
5197
- 48
5198
- ]
5199
- },
5200
- west: {
5201
- uv: [
5202
- 8,
5203
- 36,
5204
- 12,
5205
- 48
5206
- ]
5207
- },
5208
- north: {
5209
- uv: [
5210
- 4,
5211
- 36,
5212
- 8,
5213
- 48
5214
- ]
5215
- },
5216
- south: {
5217
- uv: [
5218
- 12,
5219
- 36,
5220
- 16,
5221
- 48
5222
- ]
5223
- },
5224
- up: {
5225
- uv: [
5226
- 4,
5227
- 32,
5228
- 8,
5229
- 36
5230
- ]
5231
- },
5232
- down: {
5233
- uv: [
5234
- 8,
5235
- 32,
5236
- 12,
5237
- 36
5238
- ],
5239
- rotation: 180
5240
- }
5645
+ east: { uv: [0, 1, 1, 17] },
5646
+ west: { uv: [11, 1, 12, 17] },
5647
+ north: { uv: [1, 1, 11, 17] },
5648
+ south: { uv: [12, 1, 22, 17] },
5649
+ up: { uv: [11, 1, 1, 0] },
5650
+ down: { uv: [21, 0, 11, 1] }
5241
5651
  }
5242
5652
  };
5243
5653
  var classicSkinTextureCoordinates = {
5244
5654
  ...baseSkinCoordinates
5245
5655
  };
5246
- var slimSkinTextureCoordinates = { ...baseSkinCoordinates };
5656
+ var slimSkinTextureCoordinates = {
5657
+ ...baseSkinCoordinates,
5658
+ leftArm: {
5659
+ ...baseSkinCoordinates.leftArm,
5660
+ west: { uv: [39, 52, 43, 64] },
5661
+ north: { uv: [36, 52, 39, 64] },
5662
+ south: { uv: [43, 52, 46, 64] },
5663
+ up: { uv: [39, 52, 36, 48] },
5664
+ down: { uv: [42, 48, 39, 52] }
5665
+ },
5666
+ rightArm: {
5667
+ ...baseSkinCoordinates.rightArm,
5668
+ west: { uv: [47, 20, 51, 32] },
5669
+ north: { uv: [44, 20, 47, 32] },
5670
+ south: { uv: [51, 20, 54, 32] },
5671
+ up: { uv: [47, 20, 44, 16] },
5672
+ down: { uv: [50, 16, 47, 20] }
5673
+ },
5674
+ leftSleeve: {
5675
+ ...baseSkinCoordinates.leftSleeve,
5676
+ west: { uv: [55, 52, 59, 64] },
5677
+ north: { uv: [52, 52, 55, 64] },
5678
+ south: { uv: [59, 52, 62, 64] },
5679
+ up: { uv: [55, 52, 52, 48] },
5680
+ down: { uv: [58, 48, 55, 52], rotation: 180 }
5681
+ },
5682
+ rightSleeve: {
5683
+ ...baseSkinCoordinates.rightSleeve,
5684
+ west: { uv: [47, 36, 51, 48] },
5685
+ north: { uv: [44, 36, 47, 48] },
5686
+ south: { uv: [51, 36, 54, 48] },
5687
+ up: { uv: [47, 36, 44, 32] },
5688
+ down: { uv: [50, 32, 47, 36], rotation: 180 }
5689
+ }
5690
+ };
5247
5691
 
5248
5692
  // src/skin/SkinGeometries.ts
5249
5693
  var box8inner = [8, 8, 8];
@@ -5283,15 +5727,118 @@ var slimSkinGeometries = {
5283
5727
  };
5284
5728
 
5285
5729
  // src/skin/scene/SkinObject.ts
5286
- var import_ts_deepmerge8 = __toESM(require_dist());
5730
+ var import_ts_deepmerge7 = __toESM(require_dist());
5731
+
5732
+ // src/skin/SkinTextures.ts
5733
+ var import_three18 = require("three");
5734
+ var SkinTextures = class {
5735
+ static async get(src, legacy) {
5736
+ const image = await ImageLoader.getData(src);
5737
+ const scale = image.width / 64;
5738
+ if (!Number.isInteger(scale) || scale < 1 || image.height !== image.width && image.height !== image.width / 2) {
5739
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; expected 64x64 or 64x32, or an integer-scaled equivalent`);
5740
+ }
5741
+ const isLegacy = legacy ?? image.height === image.width / 2;
5742
+ if (!isLegacy && image.height !== image.width) {
5743
+ throw new MineRenderError(`Invalid skin dimensions ${image.width}x${image.height}; non-legacy skins must be square`);
5744
+ }
5745
+ const slim = !isLegacy && this.isSlim(image, scale);
5746
+ const key = `skin:${serializeImageKey({ src })}:${isLegacy}`;
5747
+ const material = Caching.materialCache.get(key, () => {
5748
+ const pixels = isLegacy ? this.normalizeLegacy(image, scale) : new Uint8Array(image.data);
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 ImageLoader.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.5 : 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
+ for (let y = 0; y < image.width; y++) {
5812
+ for (let x = 0; x < image.width; x++) {
5813
+ const alpha = (y * image.width + x) * 4 + 3;
5814
+ if (x < 32 * scale && y < 16 * scale || y >= 16 * scale && y < 32 * scale || x >= 16 * scale && x < 48 * scale && y >= 48 * scale) {
5815
+ pixels[alpha] = 255;
5816
+ } else if (clearHat && x >= 32 * scale && y < 32 * scale) {
5817
+ pixels[alpha] = 0;
5818
+ }
5819
+ }
5820
+ }
5821
+ return pixels;
5822
+ }
5823
+ };
5824
+
5825
+ // src/skin/CapeLayout.ts
5826
+ var capeTextureSizes = {
5827
+ minecraft: [64, 32],
5828
+ optifine: [46, 22],
5829
+ labymod: [22, 17]
5830
+ };
5831
+
5832
+ // src/skin/scene/SkinObject.ts
5287
5833
  var SkinObject = class extends SceneObject {
5288
5834
  constructor(options) {
5289
5835
  super();
5290
5836
  this.slim = false;
5291
- this.legacy = false;
5292
- this.skinTextureWidth = 64;
5293
- this.skinTextureHeight = 64;
5294
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5837
+ this.detectedSlim = false;
5838
+ this.skinLoad = 0;
5839
+ this.capeLoad = 0;
5840
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5841
+ this.slim = this.options.slim ?? false;
5295
5842
  }
5296
5843
  async init() {
5297
5844
  this.createMeshes();
@@ -5300,15 +5847,13 @@ var SkinObject = class extends SceneObject {
5300
5847
  }
5301
5848
  createMeshes() {
5302
5849
  console.log("#createMeshes");
5303
- const mat = Materials.MISSING_TEXTURE;
5850
+ const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
5304
5851
  {
5305
5852
  const headGroup = this.createAndAddGroup("head", 0, 28, 0, "y" /* Y */, -4);
5306
5853
  const headGeo = this.getBoxGeometry("head" /* HEAD */);
5307
5854
  const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
5308
- if (!this.legacy) {
5309
- const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5310
- const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5311
- }
5855
+ const hatGeo = this.getBoxGeometry("hat" /* HAT */);
5856
+ const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
5312
5857
  }
5313
5858
  {
5314
5859
  const bodyGroup = this.createAndAddGroup("body", 0, 18, 0);
@@ -5351,51 +5896,95 @@ var SkinObject = class extends SceneObject {
5351
5896
  }
5352
5897
  console.log("#createMeshes done");
5353
5898
  }
5354
- setSkinTexture(src) {
5899
+ async setSkinTexture(src) {
5355
5900
  if (typeof src === "undefined") return;
5356
5901
  this.skinTextureSrc = src;
5357
- const mat = Materials.getImage({
5358
- texture: { src },
5359
- transparent: true
5360
- });
5361
- for (let part of SKIN_PARTS) {
5362
- let mesh = this.getMeshByName(part);
5902
+ const load = ++this.skinLoad;
5903
+ const texture = await SkinTextures.get(src, this.options.legacy);
5904
+ if (load !== this.skinLoad) return;
5905
+ this.skinMaterial = texture.material;
5906
+ this.detectedSlim = texture.slim;
5907
+ this.updateSlim(this.options.slim ?? this.detectedSlim);
5908
+ for (const part of SKIN_PARTS) {
5909
+ if (part === "cape" /* CAPE */) continue;
5910
+ const mesh = this.getMeshByName(part);
5363
5911
  if (mesh) {
5364
- mesh.material = mat;
5912
+ mesh.material = texture.material;
5365
5913
  }
5366
5914
  }
5915
+ this.notifyDirty();
5916
+ }
5917
+ /** Load a cape texture in the selected layout, or pass undefined to remove the cape. */
5918
+ async setCapeTexture(src, layout = "minecraft") {
5919
+ const load = ++this.capeLoad;
5920
+ if (src === void 0) {
5921
+ const group = this.getGroupByName("cape" /* CAPE */);
5922
+ if (group) this.remove(group);
5923
+ this.notifyDirty();
5924
+ return;
5925
+ }
5926
+ const material = await SkinTextures.getCape(src, layout);
5927
+ if (load !== this.capeLoad) return;
5928
+ const size = capeTextureSizes[layout];
5929
+ const geometry = this._getBoxGeometryFromDimensions(
5930
+ classicSkinGeometries.cape,
5931
+ classicSkinTextureCoordinates.cape,
5932
+ size,
5933
+ size
5934
+ );
5935
+ const mesh = this.getMeshByName("cape" /* CAPE */);
5936
+ if (mesh) {
5937
+ mesh.material = material;
5938
+ mesh.geometry = geometry;
5939
+ } else {
5940
+ const group = this.createAndAddGroup("cape" /* CAPE */, 0, 24, 2);
5941
+ group.rotation.set(toRadians(-6), Math.PI, 0);
5942
+ const cape = this.createAndAddMesh("cape" /* CAPE */, group, geometry, material);
5943
+ cape.position.set(0, -8, -0.5);
5944
+ }
5945
+ this.notifyDirty();
5367
5946
  }
5368
- //TODO: cape
5947
+ /** Select the arm model, or pass undefined to use texture detection. */
5369
5948
  setSlim(slim) {
5370
- console.log("#setSlim");
5371
- const changed = slim !== this.slim;
5949
+ this.options.slim = slim;
5950
+ this.updateSlim(slim ?? this.detectedSlim);
5951
+ }
5952
+ updateSlim(slim) {
5953
+ if (slim === this.slim) return;
5372
5954
  this.slim = slim;
5373
- if (changed) {
5374
- this.createMeshes();
5375
- }
5376
- if (changed) {
5377
- if (this.skinTextureSrc) {
5378
- this.setSkinTexture(this.skinTextureSrc);
5379
- }
5380
- }
5381
- console.log("#setSlim done");
5955
+ for (const part of ["leftArm" /* LEFT_ARM */, "leftSleeve" /* LEFT_SLEEVE */, "rightArm" /* RIGHT_ARM */, "rightSleeve" /* RIGHT_SLEEVE */]) {
5956
+ const mesh = this.getMeshByName(part);
5957
+ if (mesh) mesh.geometry = this.getBoxGeometry(part);
5958
+ }
5959
+ const offset = slim ? 0.5 : -0.5;
5960
+ const leftArm = this.getGroupByName("leftArm" /* LEFT_ARM */);
5961
+ const rightArm = this.getGroupByName("rightArm" /* RIGHT_ARM */);
5962
+ if (leftArm) leftArm.position.x += offset;
5963
+ if (rightArm) rightArm.position.x -= offset;
5964
+ this.notifyDirty();
5382
5965
  }
5383
- setLegacy(legacy) {
5384
- if (legacy !== this.legacy) {
5385
- }
5386
- this.legacy = legacy;
5966
+ /** Select the texture layout, or pass undefined to detect it from image dimensions. */
5967
+ async setLegacy(legacy) {
5968
+ if (legacy === this.options.legacy) return;
5969
+ this.options.legacy = legacy;
5970
+ if (this.skinTextureSrc) await this.setSkinTexture(this.skinTextureSrc);
5971
+ }
5972
+ dispose() {
5973
+ this.skinLoad++;
5974
+ this.capeLoad++;
5975
+ super.dispose();
5387
5976
  }
5388
5977
  //TODO: layer toggles
5389
5978
  getBoxGeometry(part) {
5390
5979
  console.log("slim", this.slim);
5391
5980
  const coordinates = this.slim ? slimSkinTextureCoordinates : classicSkinTextureCoordinates;
5392
5981
  const geometries = this.slim ? slimSkinGeometries : classicSkinGeometries;
5393
- return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [this.skinTextureWidth, this.skinTextureHeight]);
5982
+ return this._getBoxGeometryFromDimensions(geometries[part], coordinates[part], [64, 64], [64, 64]);
5394
5983
  }
5395
5984
  };
5396
5985
 
5397
5986
  // src/renderer/MineRenderScene.ts
5398
- var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5987
+ var MineRenderScene = class _MineRenderScene extends import_three19.Scene {
5399
5988
  constructor(options) {
5400
5989
  super();
5401
5990
  this.isMineRenderScene = true;
@@ -5404,12 +5993,14 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5404
5993
  this.dirty = true;
5405
5994
  this.observedObjects = /* @__PURE__ */ new Set();
5406
5995
  this.onObjectChange = (event) => {
5407
- var _a;
5408
- if (((_a = event.target) == null ? void 0 : _a.parent) === this) {
5996
+ if (event.target?.parent === this) {
5409
5997
  this.dirty = true;
5410
5998
  }
5411
5999
  };
5412
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
6000
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
6001
+ }
6002
+ static {
6003
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5413
6004
  }
5414
6005
  add(...objects) {
5415
6006
  for (const object of objects) {
@@ -5417,7 +6008,7 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5417
6008
  try {
5418
6009
  super.add(object);
5419
6010
  } finally {
5420
- if ((object == null ? void 0 : object.isObject3D) && object !== this) {
6011
+ if (object?.isObject3D && object !== this) {
5421
6012
  this.updateObjectRegistration(object, object.parent === this);
5422
6013
  }
5423
6014
  }
@@ -5460,15 +6051,21 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5460
6051
  return this.add(...object);
5461
6052
  }
5462
6053
  async addSceneObject(asset, objectSupplier, _options, parent = this) {
5463
- var _a, _b;
5464
6054
  console.log("addSceneObject", asset);
5465
6055
  console.log("parent", parent);
5466
6056
  console.log(_options);
5467
6057
  this.dirty = true;
5468
6058
  const obj = await objectSupplier();
5469
- if (((_a = obj == null ? void 0 : obj.options) == null ? void 0 : _a.instanceMeshes) && asset.key && ((_b = asset.key) == null ? void 0 : _b.assetType) === "models") {
6059
+ if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5470
6060
  console.log("instanceMeshes + key");
5471
- const key = asset.key.serialize();
6061
+ let key = asset.key.serialize();
6062
+ if (isModelObject(obj)) {
6063
+ const { displayPosition, uvLockRotation, tints } = obj.options;
6064
+ if (displayPosition) key += `|display:${displayPosition}`;
6065
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
6066
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
6067
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
6068
+ }
5472
6069
  return this.instanceManager.getOrCreate(key, async () => {
5473
6070
  obj.scene = this;
5474
6071
  await obj.init();
@@ -5495,10 +6092,10 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5495
6092
  this.dirty = true;
5496
6093
  const obj = new SkinObject(options);
5497
6094
  obj.scene = this;
5498
- await obj.init();
5499
6095
  if (skin) {
5500
- obj.setSkinTexture(skin);
6096
+ await obj.setSkinTexture(skin);
5501
6097
  }
6098
+ await obj.init();
5502
6099
  parent.add(obj);
5503
6100
  return obj;
5504
6101
  }
@@ -5506,24 +6103,22 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5506
6103
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5507
6104
  }
5508
6105
  };
5509
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5510
- var MineRenderScene = _MineRenderScene;
5511
6106
  function isMineRenderScene(obj) {
5512
6107
  return obj.isMineRenderScene;
5513
6108
  }
5514
6109
 
5515
6110
  // src/renderer/Renderer.ts
5516
- var import_three19 = require("three");
5517
- var import_ts_deepmerge10 = __toESM(require_dist());
6111
+ var import_three21 = require("three");
6112
+ var import_ts_deepmerge9 = __toESM(require_dist());
5518
6113
  var import_stats = __toESM(require("stats.js"));
5519
6114
  var import_postprocessing = require("postprocessing");
5520
6115
 
5521
6116
  // src/three/OrbitControls.js
5522
- var import_three18 = require("three");
6117
+ var import_three20 = require("three");
5523
6118
  var _changeEvent = { type: "change" };
5524
6119
  var _startEvent = { type: "start" };
5525
6120
  var _endEvent = { type: "end" };
5526
- var OrbitControls = class extends import_three18.EventDispatcher {
6121
+ var OrbitControls = class extends import_three20.EventDispatcher {
5527
6122
  constructor(object, domElement) {
5528
6123
  super();
5529
6124
  if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
@@ -5532,7 +6127,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5532
6127
  this.domElement = domElement;
5533
6128
  this.domElement.style.touchAction = "none";
5534
6129
  this.enabled = true;
5535
- this.target = new import_three18.Vector3();
6130
+ this.target = new import_three20.Vector3();
5536
6131
  this.minDistance = 0;
5537
6132
  this.maxDistance = Infinity;
5538
6133
  this.minZoom = 0;
@@ -5554,8 +6149,8 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5554
6149
  this.autoRotate = false;
5555
6150
  this.autoRotateSpeed = 2;
5556
6151
  this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5557
- this.mouseButtons = { LEFT: import_three18.MOUSE.ROTATE, MIDDLE: import_three18.MOUSE.DOLLY, RIGHT: import_three18.MOUSE.PAN };
5558
- this.touches = { ONE: import_three18.TOUCH.ROTATE, TWO: import_three18.TOUCH.DOLLY_PAN };
6152
+ this.mouseButtons = { LEFT: import_three20.MOUSE.ROTATE, MIDDLE: import_three20.MOUSE.DOLLY, RIGHT: import_three20.MOUSE.PAN };
6153
+ this.touches = { ONE: import_three20.TOUCH.ROTATE, TWO: import_three20.TOUCH.DOLLY_PAN };
5559
6154
  this.target0 = this.target.clone();
5560
6155
  this.position0 = this.object.position.clone();
5561
6156
  this.zoom0 = this.object.zoom;
@@ -5584,11 +6179,11 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5584
6179
  state = STATE.NONE;
5585
6180
  };
5586
6181
  this.update = function() {
5587
- const offset = new import_three18.Vector3();
5588
- const quat = new import_three18.Quaternion().setFromUnitVectors(object.up, new import_three18.Vector3(0, 1, 0));
6182
+ const offset = new import_three20.Vector3();
6183
+ const quat = new import_three20.Quaternion().setFromUnitVectors(object.up, new import_three20.Vector3(0, 1, 0));
5589
6184
  const quatInverse = quat.clone().invert();
5590
- const lastPosition = new import_three18.Vector3();
5591
- const lastQuaternion = new import_three18.Quaternion();
6185
+ const lastPosition = new import_three20.Vector3();
6186
+ const lastQuaternion = new import_three20.Quaternion();
5592
6187
  const twoPI = 2 * Math.PI;
5593
6188
  return function update() {
5594
6189
  const position = scope.object.position;
@@ -5674,20 +6269,20 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5674
6269
  };
5675
6270
  let state = STATE.NONE;
5676
6271
  const EPS = 1e-6;
5677
- const spherical = new import_three18.Spherical();
5678
- const sphericalDelta = new import_three18.Spherical();
6272
+ const spherical = new import_three20.Spherical();
6273
+ const sphericalDelta = new import_three20.Spherical();
5679
6274
  let scale = 1;
5680
- const panOffset = new import_three18.Vector3();
6275
+ const panOffset = new import_three20.Vector3();
5681
6276
  let zoomChanged = false;
5682
- const rotateStart = new import_three18.Vector2();
5683
- const rotateEnd = new import_three18.Vector2();
5684
- const rotateDelta = new import_three18.Vector2();
5685
- const panStart = new import_three18.Vector2();
5686
- const panEnd = new import_three18.Vector2();
5687
- const panDelta = new import_three18.Vector2();
5688
- const dollyStart = new import_three18.Vector2();
5689
- const dollyEnd = new import_three18.Vector2();
5690
- const dollyDelta = new import_three18.Vector2();
6277
+ const rotateStart = new import_three20.Vector2();
6278
+ const rotateEnd = new import_three20.Vector2();
6279
+ const rotateDelta = new import_three20.Vector2();
6280
+ const panStart = new import_three20.Vector2();
6281
+ const panEnd = new import_three20.Vector2();
6282
+ const panDelta = new import_three20.Vector2();
6283
+ const dollyStart = new import_three20.Vector2();
6284
+ const dollyEnd = new import_three20.Vector2();
6285
+ const dollyDelta = new import_three20.Vector2();
5691
6286
  const pointers = [];
5692
6287
  const pointerPositions = {};
5693
6288
  function getAutoRotationAngle() {
@@ -5703,7 +6298,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5703
6298
  sphericalDelta.phi -= angle;
5704
6299
  }
5705
6300
  const panLeft = function() {
5706
- const v = new import_three18.Vector3();
6301
+ const v = new import_three20.Vector3();
5707
6302
  return function panLeft2(distance, objectMatrix) {
5708
6303
  v.setFromMatrixColumn(objectMatrix, 0);
5709
6304
  v.multiplyScalar(-distance);
@@ -5711,7 +6306,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5711
6306
  };
5712
6307
  }();
5713
6308
  const panUp = function() {
5714
- const v = new import_three18.Vector3();
6309
+ const v = new import_three20.Vector3();
5715
6310
  return function panUp2(distance, objectMatrix) {
5716
6311
  if (scope.screenSpacePanning === true) {
5717
6312
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -5724,7 +6319,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5724
6319
  };
5725
6320
  }();
5726
6321
  const pan = function() {
5727
- const offset = new import_three18.Vector3();
6322
+ const offset = new import_three20.Vector3();
5728
6323
  return function pan2(deltaX, deltaY) {
5729
6324
  const element = scope.domElement;
5730
6325
  if (scope.object.isPerspectiveCamera) {
@@ -5973,12 +6568,12 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5973
6568
  mouseAction = -1;
5974
6569
  }
5975
6570
  switch (mouseAction) {
5976
- case import_three18.MOUSE.DOLLY:
6571
+ case import_three20.MOUSE.DOLLY:
5977
6572
  if (scope.enableZoom === false) return;
5978
6573
  handleMouseDownDolly(event);
5979
6574
  state = STATE.DOLLY;
5980
6575
  break;
5981
- case import_three18.MOUSE.ROTATE:
6576
+ case import_three20.MOUSE.ROTATE:
5982
6577
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
5983
6578
  if (scope.enablePan === false) return;
5984
6579
  handleMouseDownPan(event);
@@ -5989,7 +6584,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
5989
6584
  state = STATE.ROTATE;
5990
6585
  }
5991
6586
  break;
5992
- case import_three18.MOUSE.PAN:
6587
+ case import_three20.MOUSE.PAN:
5993
6588
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
5994
6589
  if (scope.enableRotate === false) return;
5995
6590
  handleMouseDownRotate(event);
@@ -6045,12 +6640,12 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6045
6640
  switch (pointers.length) {
6046
6641
  case 1:
6047
6642
  switch (scope.touches.ONE) {
6048
- case import_three18.TOUCH.ROTATE:
6643
+ case import_three20.TOUCH.ROTATE:
6049
6644
  if (scope.enableRotate === false) return;
6050
6645
  handleTouchStartRotate();
6051
6646
  state = STATE.TOUCH_ROTATE;
6052
6647
  break;
6053
- case import_three18.TOUCH.PAN:
6648
+ case import_three20.TOUCH.PAN:
6054
6649
  if (scope.enablePan === false) return;
6055
6650
  handleTouchStartPan();
6056
6651
  state = STATE.TOUCH_PAN;
@@ -6061,12 +6656,12 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6061
6656
  break;
6062
6657
  case 2:
6063
6658
  switch (scope.touches.TWO) {
6064
- case import_three18.TOUCH.DOLLY_PAN:
6659
+ case import_three20.TOUCH.DOLLY_PAN:
6065
6660
  if (scope.enableZoom === false && scope.enablePan === false) return;
6066
6661
  handleTouchStartDollyPan();
6067
6662
  state = STATE.TOUCH_DOLLY_PAN;
6068
6663
  break;
6069
- case import_three18.TOUCH.DOLLY_ROTATE:
6664
+ case import_three20.TOUCH.DOLLY_ROTATE:
6070
6665
  if (scope.enableZoom === false && scope.enableRotate === false) return;
6071
6666
  handleTouchStartDollyRotate();
6072
6667
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -6133,7 +6728,7 @@ var OrbitControls = class extends import_three18.EventDispatcher {
6133
6728
  function trackPointer(event) {
6134
6729
  let position = pointerPositions[event.pointerId];
6135
6730
  if (position === void 0) {
6136
- position = new import_three18.Vector2();
6731
+ position = new import_three20.Vector2();
6137
6732
  pointerPositions[event.pointerId] = position;
6138
6733
  }
6139
6734
  position.set(event.pageX, event.pageY);
@@ -6153,19 +6748,17 @@ var MapControls = class extends OrbitControls {
6153
6748
  constructor(object, domElement) {
6154
6749
  super(object, domElement);
6155
6750
  this.screenSpacePanning = false;
6156
- this.mouseButtons.LEFT = import_three18.MOUSE.PAN;
6157
- this.mouseButtons.RIGHT = import_three18.MOUSE.ROTATE;
6158
- this.touches.ONE = import_three18.TOUCH.PAN;
6159
- this.touches.TWO = import_three18.TOUCH.DOLLY_ROTATE;
6751
+ this.mouseButtons.LEFT = import_three20.MOUSE.PAN;
6752
+ this.mouseButtons.RIGHT = import_three20.MOUSE.ROTATE;
6753
+ this.touches.ONE = import_three20.TOUCH.PAN;
6754
+ this.touches.TWO = import_three20.TOUCH.DOLLY_ROTATE;
6160
6755
  }
6161
6756
  };
6162
6757
 
6163
6758
  // src/renderer/Renderer.ts
6164
- var _Renderer = class _Renderer {
6759
+ var Renderer = class _Renderer {
6165
6760
  constructor(options) {
6166
6761
  this._dirty = true;
6167
- this._animationTimer = void 0;
6168
- this._animationFrame = void 0;
6169
6762
  this._resizeListener = void 0;
6170
6763
  this._disposed = false;
6171
6764
  this._debugHelpers = [];
@@ -6173,9 +6766,9 @@ var _Renderer = class _Renderer {
6173
6766
  this._changeListener = () => {
6174
6767
  this._dirty = true;
6175
6768
  };
6176
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6769
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6177
6770
  this._animationLoop = this.animate.bind(this);
6178
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6771
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6179
6772
  this._scene = this.createScene();
6180
6773
  this._camera = this.createCamera();
6181
6774
  this._renderer = this.createRenderer();
@@ -6187,6 +6780,45 @@ var _Renderer = class _Renderer {
6187
6780
  this.init();
6188
6781
  this._controls = this.createControls();
6189
6782
  }
6783
+ static {
6784
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6785
+ camera: {
6786
+ type: "perspective",
6787
+ near: 1,
6788
+ far: 5e3,
6789
+ perspective: {
6790
+ aspect: void 0,
6791
+ fov: 50
6792
+ },
6793
+ orthographic: {
6794
+ left: void 0,
6795
+ right: void 0,
6796
+ top: void 0,
6797
+ bottom: void 0
6798
+ },
6799
+ position: new import_three21.Vector3(50, 50, 50),
6800
+ lookingAt: new import_three21.Vector3(0, 0, 0)
6801
+ },
6802
+ render: {
6803
+ fpsLimit: 60,
6804
+ stats: false,
6805
+ antialias: true,
6806
+ shade: true,
6807
+ autoResize: true,
6808
+ renderAlways: false
6809
+ },
6810
+ composer: {
6811
+ enabled: true
6812
+ },
6813
+ controls: {
6814
+ enabled: false
6815
+ },
6816
+ debug: {
6817
+ grid: false,
6818
+ axes: false
6819
+ }
6820
+ });
6821
+ }
6190
6822
  //<editor-fold desc="INIT">
6191
6823
  createScene() {
6192
6824
  return new MineRenderScene();
@@ -6195,14 +6827,14 @@ var _Renderer = class _Renderer {
6195
6827
  switch (this.options.camera.type) {
6196
6828
  case "perspective":
6197
6829
  default:
6198
- return new import_three19.PerspectiveCamera(
6830
+ return new import_three21.PerspectiveCamera(
6199
6831
  this.options.camera.perspective.fov,
6200
6832
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6201
6833
  this.options.camera.near,
6202
6834
  this.options.camera.far
6203
6835
  );
6204
6836
  case "orthographic":
6205
- return new import_three19.OrthographicCamera(
6837
+ return new import_three21.OrthographicCamera(
6206
6838
  this.options.camera.orthographic.left ?? this.viewWidth / -2,
6207
6839
  this.options.camera.orthographic.right ?? this.viewWidth / 2,
6208
6840
  this.options.camera.orthographic.top ?? this.viewHeight / 2,
@@ -6213,7 +6845,7 @@ var _Renderer = class _Renderer {
6213
6845
  }
6214
6846
  }
6215
6847
  createRenderer() {
6216
- const renderer = new import_three19.WebGLRenderer({
6848
+ const renderer = new import_three21.WebGLRenderer({
6217
6849
  antialias: this.options.render.antialias,
6218
6850
  alpha: true,
6219
6851
  powerPreference: "high-performance",
@@ -6221,21 +6853,20 @@ var _Renderer = class _Renderer {
6221
6853
  });
6222
6854
  renderer.setClearColor(0, 0);
6223
6855
  renderer.shadowMap.enabled = true;
6224
- renderer.shadowMap.type = import_three19.PCFSoftShadowMap;
6225
- renderer.outputEncoding = import_three19.LinearEncoding;
6856
+ renderer.shadowMap.type = import_three21.PCFSoftShadowMap;
6857
+ renderer.outputColorSpace = import_three21.SRGBColorSpace;
6226
6858
  renderer.setSize(this.viewWidth, this.viewHeight);
6227
6859
  return renderer;
6228
6860
  }
6229
6861
  createComposer() {
6862
+ if (!this.options.composer.enabled) return void 0;
6230
6863
  const composer = new import_postprocessing.EffectComposer(this.renderer);
6231
- if (!this.options.composer.enabled) return composer;
6232
6864
  composer.setSize(this.viewWidth, this.viewHeight);
6233
6865
  composer.addPass(new import_postprocessing.RenderPass(this.scene, this.camera));
6234
6866
  return composer;
6235
6867
  }
6236
6868
  createControls() {
6237
- var _a;
6238
- if (!((_a = this.options.controls) == null ? void 0 : _a.enabled)) return void 0;
6869
+ if (!this.options.controls?.enabled) return void 0;
6239
6870
  const position = this.camera.position.clone();
6240
6871
  const controls = new OrbitControls(this.camera, this.renderer.domElement);
6241
6872
  this.camera.position.copy(position);
@@ -6257,20 +6888,20 @@ var _Renderer = class _Renderer {
6257
6888
  window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6258
6889
  }
6259
6890
  if (this.options.debug.grid) {
6260
- const gridHelper = new import_three19.GridHelper(128, 16);
6891
+ const gridHelper = new import_three21.GridHelper(128, 16);
6261
6892
  this._debugHelpers.push(gridHelper);
6262
6893
  this.scene.add(gridHelper);
6263
- const gridHelper2 = new import_three19.GridHelper(128, 16);
6894
+ const gridHelper2 = new import_three21.GridHelper(128, 16);
6264
6895
  this._debugHelpers.push(gridHelper2);
6265
6896
  gridHelper2.rotation.x = 90 * (Math.PI / 180);
6266
6897
  this.scene.add(gridHelper2);
6267
- const gridHelper3 = new import_three19.GridHelper(128, 16);
6898
+ const gridHelper3 = new import_three21.GridHelper(128, 16);
6268
6899
  this._debugHelpers.push(gridHelper3);
6269
6900
  gridHelper3.rotation.z = 90 * (Math.PI / 180);
6270
6901
  this.scene.add(gridHelper3);
6271
6902
  }
6272
6903
  if (this.options.debug.axes) {
6273
- const axesHelper = new import_three19.AxesHelper(64);
6904
+ const axesHelper = new import_three21.AxesHelper(64);
6274
6905
  this._debugHelpers.push(axesHelper);
6275
6906
  this.scene.add(axesHelper);
6276
6907
  }
@@ -6338,7 +6969,7 @@ var _Renderer = class _Renderer {
6338
6969
  this.camera.updateProjectionMatrix();
6339
6970
  }
6340
6971
  this.renderer.setSize(width, height);
6341
- this.composer.setSize(width, height);
6972
+ this.composer?.setSize(width, height);
6342
6973
  this._dirty = true;
6343
6974
  }
6344
6975
  //<editor-fold desc="RENDER">
@@ -6357,12 +6988,7 @@ var _Renderer = class _Renderer {
6357
6988
  stop() {
6358
6989
  if (this._disposed) return;
6359
6990
  this.renderer.setAnimationLoop(null);
6360
- if (this._animationTimer)
6361
- clearTimeout(this._animationTimer);
6362
- this._animationTimer = void 0;
6363
- if (this._animationFrame)
6364
- cancelAnimationFrame(this._animationFrame);
6365
- this._animationFrame = void 0;
6991
+ this._nextFrameTime = void 0;
6366
6992
  }
6367
6993
  /**
6368
6994
  * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
@@ -6370,7 +6996,6 @@ var _Renderer = class _Renderer {
6370
6996
  * controls must be managed by their owners.
6371
6997
  */
6372
6998
  dispose() {
6373
- var _a;
6374
6999
  if (this._disposed) return;
6375
7000
  this.stop();
6376
7001
  this._disposed = true;
@@ -6384,7 +7009,7 @@ var _Renderer = class _Renderer {
6384
7009
  }
6385
7010
  }
6386
7011
  this._eventDispatchers.clear();
6387
- (_a = this._stats) == null ? void 0 : _a.dom.remove();
7012
+ this._stats?.dom.remove();
6388
7013
  this._stats = void 0;
6389
7014
  this.renderer.domElement.remove();
6390
7015
  this._element = void 0;
@@ -6403,26 +7028,30 @@ var _Renderer = class _Renderer {
6403
7028
  }
6404
7029
  }
6405
7030
  this._debugHelpers.length = 0;
6406
- this.composer.dispose();
7031
+ this.composer?.dispose();
6407
7032
  this.renderer.dispose();
6408
7033
  this.renderer.forceContextLoss();
6409
7034
  }
6410
- animate(t) {
6411
- var _a;
7035
+ animate(t = performance.now()) {
6412
7036
  if (this._disposed) return;
6413
- if (this._stats) {
6414
- this._stats.begin();
6415
- }
6416
- if ((_a = this._controls) == null ? void 0 : _a.enabled) {
7037
+ if (this._controls?.enabled) {
6417
7038
  this._controls.update();
6418
7039
  }
6419
7040
  if (this._disposed) return;
6420
- if (this.dirty || this.options.render.renderAlways) {
6421
- if (this.options.composer.enabled) {
6422
- this.composer.render();
6423
- } else {
6424
- this.renderer.render(this.scene, this.camera);
6425
- }
7041
+ if (!this.dirty && !this.options.render.renderAlways) return;
7042
+ const interval = this._frameInterval;
7043
+ if (interval) {
7044
+ const next = this._nextFrameTime;
7045
+ if (next !== void 0 && t + 0.1 < next) return;
7046
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
7047
+ }
7048
+ if (this._stats) {
7049
+ this._stats.begin();
7050
+ }
7051
+ if (this.options.composer.enabled && this.composer) {
7052
+ this.composer.render();
7053
+ } else {
7054
+ this.renderer.render(this.scene, this.camera);
6426
7055
  }
6427
7056
  this.dirty = false;
6428
7057
  if (this._stats) {
@@ -6438,12 +7067,10 @@ var _Renderer = class _Renderer {
6438
7067
  return this.element === document.body;
6439
7068
  }
6440
7069
  get viewWidth() {
6441
- var _a;
6442
- return this.attachedToBody ? window.innerWidth : ((_a = this.element) == null ? void 0 : _a.offsetWidth) || 0;
7070
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6443
7071
  }
6444
7072
  get viewHeight() {
6445
- var _a;
6446
- return this.attachedToBody ? window.innerHeight : ((_a = this.element) == null ? void 0 : _a.offsetHeight) || 0;
7073
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6447
7074
  }
6448
7075
  get scene() {
6449
7076
  return this._scene;
@@ -6463,44 +7090,6 @@ var _Renderer = class _Renderer {
6463
7090
  }
6464
7091
  ///
6465
7092
  };
6466
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
6467
- camera: {
6468
- type: "perspective",
6469
- near: 1,
6470
- far: 5e3,
6471
- perspective: {
6472
- aspect: void 0,
6473
- fov: 50
6474
- },
6475
- orthographic: {
6476
- left: void 0,
6477
- right: void 0,
6478
- top: void 0,
6479
- bottom: void 0
6480
- },
6481
- position: new import_three19.Vector3(50, 50, 50),
6482
- lookingAt: new import_three19.Vector3(0, 0, 0)
6483
- },
6484
- render: {
6485
- fpsLimit: 60,
6486
- stats: false,
6487
- antialias: true,
6488
- shade: true,
6489
- autoResize: true,
6490
- renderAlways: false
6491
- },
6492
- composer: {
6493
- enabled: true
6494
- },
6495
- controls: {
6496
- enabled: false
6497
- },
6498
- debug: {
6499
- grid: false,
6500
- axes: false
6501
- }
6502
- });
6503
- var Renderer = _Renderer;
6504
7093
 
6505
7094
  // src/skin/Skins.ts
6506
7095
  var Skins = class {
@@ -6512,7 +7101,7 @@ var Skins = class {
6512
7101
  return this.fromUsername(uuidOrUsername);
6513
7102
  }
6514
7103
  static async fromUuid(uuid) {
6515
- return this.getSkinProxySkinUrl(uuid);
7104
+ return this.getMcProxySkinUrl(uuid);
6516
7105
  }
6517
7106
  static async fromUsername(username) {
6518
7107
  return this.usernameToUuid(username).then((uuid) => {
@@ -6539,7 +7128,7 @@ var Skins = class {
6539
7128
  return this.capeFromUsername(uuidOrUsername);
6540
7129
  }
6541
7130
  static async capeFromUuid(uuid) {
6542
- return this.getSkinProxyCapeUrl(uuid);
7131
+ return this.getMcProxyCapeUrl(uuid);
6543
7132
  }
6544
7133
  static async capeFromUsername(username) {
6545
7134
  return this.usernameToUuid(username).then((uuid) => {
@@ -6549,19 +7138,31 @@ var Skins = class {
6549
7138
  return void 0;
6550
7139
  });
6551
7140
  }
6552
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
6553
- return this.getCapesDev(uuid, capeType).then((cape) => {
6554
- if (cape) {
6555
- return cape == null ? void 0 : cape.stillImageUrl;
6556
- }
6557
- return void 0;
6558
- });
7141
+ /** Returns a full static cape texture for a username or UUID. */
7142
+ static async capeFromCapesDev(player, capeType = "minecraft") {
7143
+ const cape = await this.getCapesDev(player, capeType);
7144
+ return cape?.exists ? cape.imageUrls?.still?.full : void 0;
6559
7145
  }
6560
7146
  //</editor-fold>
6561
7147
  //<editor-fold desc="Helpers">
6562
7148
  static async usernameToUuid(username) {
6563
- return this.usernameToUuidSkinProxy(username);
7149
+ return this.usernameToUuidMcProxy(username);
7150
+ }
7151
+ static async usernameToUuidMcProxy(username) {
7152
+ return Requests.genericRequest({
7153
+ baseURL: "https://mcproxy.dev",
7154
+ url: "/uuid/" + username
7155
+ }).then((res) => {
7156
+ if (res.status === 200) {
7157
+ return res.data["data"]["id"];
7158
+ }
7159
+ return void 0;
7160
+ }).catch((err) => {
7161
+ console.warn(err);
7162
+ return void 0;
7163
+ });
6564
7164
  }
7165
+ /** @deprecated **/
6565
7166
  static async usernameToUuidSkinProxy(username) {
6566
7167
  return Requests.genericRequest({
6567
7168
  baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
@@ -6614,18 +7215,15 @@ var Skins = class {
6614
7215
  return void 0;
6615
7216
  });
6616
7217
  }
6617
- static async getCapesDev(uuid, type = "all") {
7218
+ static async getCapesDev(player, type = "all") {
6618
7219
  return Requests.genericRequest({
6619
7220
  baseURL: "https://api.capes.dev",
6620
- url: "/load/" + uuid + "/" + type
7221
+ url: "/load/" + encodeURIComponent(player) + "/" + encodeURIComponent(type)
6621
7222
  }).then((res) => {
6622
7223
  if (res.status === 200) {
6623
7224
  return res.data;
6624
7225
  }
6625
7226
  return void 0;
6626
- }).catch((err) => {
6627
- console.warn(err);
6628
- return void 0;
6629
7227
  });
6630
7228
  }
6631
7229
  static getCrafatarSkinUrl(uuid) {
@@ -6640,20 +7238,28 @@ var Skins = class {
6640
7238
  static getMineSkinPlayerSkinUrl(uuid) {
6641
7239
  return "https://mineskin.org/skin/player/" + uuid;
6642
7240
  }
7241
+ /** @deprecated **/
6643
7242
  static getSkinProxySkinUrl(uuid) {
6644
7243
  return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6645
7244
  }
7245
+ /** @deprecated **/
6646
7246
  static getSkinProxyCapeUrl(uuid) {
6647
7247
  return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6648
7248
  }
7249
+ static getMcProxySkinUrl(uuid) {
7250
+ return "https://mcproxy.dev/skin/" + uuid;
7251
+ }
7252
+ static getMcProxyCapeUrl(uuid) {
7253
+ return "https://mcproxy.dev/cape/" + uuid;
7254
+ }
6649
7255
  //</editor-fold>
6650
7256
  };
6651
7257
 
6652
7258
  // src/world/Chunk.ts
6653
- var import_three22 = require("three");
7259
+ var import_three24 = require("three");
6654
7260
 
6655
7261
  // src/world/MineRenderWorld.ts
6656
- var import_three21 = require("three");
7262
+ var import_three23 = require("three");
6657
7263
  var MineRenderWorld = class {
6658
7264
  constructor(scene) {
6659
7265
  this._size = 4;
@@ -6664,10 +7270,10 @@ var MineRenderWorld = class {
6664
7270
  }
6665
7271
  getBlockAt(posOrX, y, z) {
6666
7272
  if (typeof posOrX == "number") {
6667
- return this.getBlockAt(new import_three21.Vector3(posOrX, y, z));
7273
+ return this.getBlockAt(new import_three23.Vector3(posOrX, y, z));
6668
7274
  }
6669
7275
  if (isTripleArray(posOrX)) {
6670
- return this.getBlockAt(new import_three21.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7276
+ return this.getBlockAt(new import_three23.Vector3(posOrX[0], posOrX[1], posOrX[2]));
6671
7277
  }
6672
7278
  const chunk = this.getChunkAt(posOrX);
6673
7279
  if (typeof chunk === "undefined") {
@@ -6678,10 +7284,10 @@ var MineRenderWorld = class {
6678
7284
  }
6679
7285
  async setBlockAt(posOrX, yOrBlock, z, block) {
6680
7286
  if (typeof posOrX == "number") {
6681
- return this.setBlockAt(new import_three21.Vector3(posOrX, yOrBlock, z), block);
7287
+ return this.setBlockAt(new import_three23.Vector3(posOrX, yOrBlock, z), block);
6682
7288
  }
6683
7289
  if (isTripleArray(posOrX)) {
6684
- return this.setBlockAt(new import_three21.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7290
+ return this.setBlockAt(new import_three23.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6685
7291
  }
6686
7292
  this.validatePosBounds(posOrX);
6687
7293
  const chunk = this.getOrCreateChunkAt(posOrX);
@@ -6709,7 +7315,7 @@ var MineRenderWorld = class {
6709
7315
  console.log("CHUNKS", this._chunks);
6710
7316
  for (let chunk of this._chunks.values()) {
6711
7317
  console.log("dispose chunk", chunk);
6712
- await (chunk == null ? void 0 : chunk.dispose());
7318
+ await chunk?.dispose();
6713
7319
  }
6714
7320
  this._chunks.clear();
6715
7321
  }
@@ -6727,14 +7333,14 @@ var MineRenderWorld = class {
6727
7333
  return this._chunks[index];
6728
7334
  }
6729
7335
  static worldToScenePosition(pos) {
6730
- return new import_three21.Vector3(
7336
+ return new import_three23.Vector3(
6731
7337
  pos.x * 16,
6732
7338
  pos.y * 16,
6733
7339
  pos.z * 16
6734
7340
  );
6735
7341
  }
6736
7342
  static sceneToWorldPosition(pos) {
6737
- return new import_three21.Vector3(
7343
+ return new import_three23.Vector3(
6738
7344
  pos.x / 16,
6739
7345
  pos.y / 16,
6740
7346
  pos.z / 16
@@ -6763,7 +7369,7 @@ var MineRenderWorld = class {
6763
7369
  };
6764
7370
 
6765
7371
  // src/world/Chunk.ts
6766
- var p12 = prefix("Chunk");
7372
+ var p11 = prefix("Chunk");
6767
7373
  var Chunk = class _Chunk {
6768
7374
  constructor(scene, x, y, z) {
6769
7375
  this._blocks = [];
@@ -6771,12 +7377,12 @@ var Chunk = class _Chunk {
6771
7377
  this.x = x;
6772
7378
  this.y = y;
6773
7379
  this.z = z;
6774
- let anchor = new import_three22.Object3D();
7380
+ let anchor = new import_three24.Object3D();
6775
7381
  this._anchor = anchor;
6776
7382
  scene.add(anchor);
6777
7383
  anchor.position.set(this.x * 256 + 128 - 8, this.y * 256 + 128 - 8, this.z * 256 + 128 - 8);
6778
7384
  addBox3WireframeToObject(
6779
- new import_three22.Box3(new import_three22.Vector3(0, 0, 0), new import_three22.Vector3(256, 256, 256)),
7385
+ new import_three24.Box3(new import_three24.Vector3(0, 0, 0), new import_three24.Vector3(256, 256, 256)),
6780
7386
  anchor,
6781
7387
  16776960,
6782
7388
  4
@@ -6784,10 +7390,10 @@ var Chunk = class _Chunk {
6784
7390
  }
6785
7391
  getBlockAt(posOrX, y, z) {
6786
7392
  if (typeof posOrX == "number") {
6787
- return this.getBlockAt(new import_three22.Vector3(posOrX, y, z));
7393
+ return this.getBlockAt(new import_three24.Vector3(posOrX, y, z));
6788
7394
  }
6789
7395
  if (isTripleArray(posOrX)) {
6790
- return this.getBlockAt(new import_three22.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7396
+ return this.getBlockAt(new import_three24.Vector3(posOrX[0], posOrX[1], posOrX[2]));
6791
7397
  }
6792
7398
  const pos = this.worldPosToChunkPos(posOrX);
6793
7399
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -6795,10 +7401,10 @@ var Chunk = class _Chunk {
6795
7401
  }
6796
7402
  async setBlockAt(posOrX, yOrBlock, z, block) {
6797
7403
  if (typeof posOrX == "number") {
6798
- return this.setBlockAt(new import_three22.Vector3(posOrX, yOrBlock, z), block);
7404
+ return this.setBlockAt(new import_three24.Vector3(posOrX, yOrBlock, z), block);
6799
7405
  }
6800
7406
  if (isTripleArray(posOrX)) {
6801
- return this.setBlockAt(new import_three22.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7407
+ return this.setBlockAt(new import_three24.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6802
7408
  }
6803
7409
  const worldPos = posOrX;
6804
7410
  const pos = this.worldPosToChunkPos(worldPos);
@@ -6815,7 +7421,7 @@ var Chunk = class _Chunk {
6815
7421
  const index = _Chunk.chunkPosToBlockIndex(pos);
6816
7422
  const current = this._blocks[index];
6817
7423
  if (typeof current !== "undefined") {
6818
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
7424
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6819
7425
  current.object.removeFromScene();
6820
7426
  delete this._blocks[index];
6821
7427
  }
@@ -6844,7 +7450,7 @@ var Chunk = class _Chunk {
6844
7450
  }
6845
7451
  async clear() {
6846
7452
  let promises = [];
6847
- let pos = new import_three22.Vector3();
7453
+ let pos = new import_three24.Vector3();
6848
7454
  for (let x = 0; x < 16; x++) {
6849
7455
  for (let z = 0; z < 16; z++) {
6850
7456
  for (let y = 0; y < 16; y++) {
@@ -6863,14 +7469,14 @@ var Chunk = class _Chunk {
6863
7469
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
6864
7470
  }
6865
7471
  worldPosToChunkPos(pos) {
6866
- return new import_three22.Vector3(
7472
+ return new import_three24.Vector3(
6867
7473
  pos.x - this.x * 16,
6868
7474
  pos.y - this.y * 16,
6869
7475
  pos.z - this.z * 16
6870
7476
  );
6871
7477
  }
6872
7478
  chunkPosToWorldPos(pos) {
6873
- return new import_three22.Vector3(
7479
+ return new import_three24.Vector3(
6874
7480
  this.x * 16 + pos.x,
6875
7481
  this.y * 16 + pos.y,
6876
7482
  this.z * 16 + pos.z
@@ -6882,6 +7488,7 @@ var Chunk = class _Chunk {
6882
7488
  AXES,
6883
7489
  ArchiveAssetSource,
6884
7490
  AssetKey,
7491
+ AssetLoadError,
6885
7492
  AssetLoader,
6886
7493
  AssetParser,
6887
7494
  AssetSource,
@@ -6891,9 +7498,9 @@ var Chunk = class _Chunk {
6891
7498
  BUILTIN_GENERATED,
6892
7499
  BasicAssetKey,
6893
7500
  BatchedExecutor,
6894
- BlockEntityModels,
6895
7501
  BlockObject,
6896
7502
  BlockStates,
7503
+ BlockTints,
6897
7504
  BrowserArchiveProxy,
6898
7505
  CUBE_FACES,
6899
7506
  Caching,
@@ -6908,8 +7515,8 @@ var Chunk = class _Chunk {
6908
7515
  DISPLAY_POSITIONS,
6909
7516
  DefaultBlockStates,
6910
7517
  DisplayPosition,
7518
+ DisplayTransforms,
6911
7519
  Entities,
6912
- EntityModels,
6913
7520
  EntityObject,
6914
7521
  Env,
6915
7522
  Geometries,
@@ -6939,6 +7546,7 @@ var Chunk = class _Chunk {
6939
7546
  OrbitControls,
6940
7547
  PersistentCache,
6941
7548
  Renderer,
7549
+ RequestError,
6942
7550
  Requests,
6943
7551
  SKIN_PARTS,
6944
7552
  SceneInspector,
@@ -6948,6 +7556,7 @@ var Chunk = class _Chunk {
6948
7556
  SchematicParser,
6949
7557
  SkinObject,
6950
7558
  SkinPart,
7559
+ SkinTextures,
6951
7560
  Skins,
6952
7561
  StructureParser,
6953
7562
  TextureAtlas,
@@ -6962,10 +7571,10 @@ var Chunk = class _Chunk {
6962
7571
  addWireframeToObject,
6963
7572
  applyElementRotation,
6964
7573
  applyGenericRotation,
6965
- applyModelPartRotation,
6966
7574
  axisToVec3,
6967
7575
  base64decode,
6968
7576
  base64encode,
7577
+ capeTextureSizes,
6969
7578
  captureException,
6970
7579
  changeEvent,
6971
7580
  clampRotationDegrees,