minerender 2.1.0-alpha.2 → 2.1.0-alpha.20

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,
@@ -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,
@@ -302,25 +296,29 @@ var Env = class {
302
296
  };
303
297
 
304
298
  // src/cache/PersistentCache.ts
305
- var _PersistentCache = class _PersistentCache {
299
+ var PersistentCache = class _PersistentCache {
306
300
  constructor(backing) {
307
301
  this.backing = backing;
308
302
  }
303
+ static {
304
+ /** Bump to invalidate every persisted entry. */
305
+ this.VERSION = 2;
306
+ }
309
307
  static open(name) {
310
308
  return Env.provider.openCache(name, _PersistentCache.VERSION);
311
309
  }
310
+ /** Loads a missing entry and stores only non-nullish results. */
312
311
  async getOrLoad(key, loader) {
313
312
  let v = await this.get(key);
314
313
  if (typeof v === "undefined" || v === null) {
315
314
  v = await loader(key);
316
- await this.put(key, v);
315
+ if (typeof v !== "undefined" && v !== null) {
316
+ await this.put(key, v);
317
+ }
317
318
  }
318
319
  return v;
319
320
  }
320
321
  };
321
- /** Bump to invalidate every persisted entry. */
322
- _PersistentCache.VERSION = 1;
323
- var PersistentCache = _PersistentCache;
324
322
 
325
323
  // src/env/node/NodeCache.ts
326
324
  var NodeCache = class extends PersistentCache {
@@ -398,7 +396,7 @@ registerNodeEnv();
398
396
  // src/Axis.ts
399
397
  var import_three = require("three");
400
398
  var Axis = /* @__PURE__ */ ((Axis3) => {
401
- Axis3["X"] = "X";
399
+ Axis3["X"] = "x";
402
400
  Axis3["Y"] = "y";
403
401
  Axis3["Z"] = "z";
404
402
  return Axis3;
@@ -406,7 +404,7 @@ var Axis = /* @__PURE__ */ ((Axis3) => {
406
404
  var AXES = Object.values(Axis);
407
405
  function axisToVec3(axis) {
408
406
  switch (axis) {
409
- case "X" /* X */:
407
+ case "x" /* X */:
410
408
  return new import_three.Vector3(1, 0, 0);
411
409
  case "y" /* Y */:
412
410
  return new import_three.Vector3(0, 1, 0);
@@ -494,8 +492,7 @@ function serializeImageKey(key) {
494
492
  return md5(key.src);
495
493
  }
496
494
  function serializeBoxGeometryKey(key) {
497
- var _a;
498
- return md5([key.width, key.height, key.depth, (_a = key.uv) == null ? void 0 : _a.join(":")].join("_"));
495
+ return md5([key.width, key.height, key.depth, key.uv?.join(":")].join("_"));
499
496
  }
500
497
  function serializeTextureKey(key) {
501
498
  return md5([key.src, key.format, key.rotation].join("$"));
@@ -510,7 +507,61 @@ function serializeMeshKey(key) {
510
507
  // src/cache/Caching.ts
511
508
  var import_loading_cache = require("@inventivetalent/loading-cache");
512
509
  var import_time = require("@inventivetalent/time");
513
- var Caching = class {
510
+ var Caching = class _Caching {
511
+ static {
512
+ 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();
513
+ }
514
+ static {
515
+ 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();
516
+ }
517
+ static {
518
+ 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();
519
+ }
520
+ static {
521
+ 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();
522
+ }
523
+ static {
524
+ 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();
525
+ }
526
+ static {
527
+ 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();
528
+ }
529
+ static {
530
+ 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();
531
+ }
532
+ static {
533
+ 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();
534
+ }
535
+ static {
536
+ 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();
537
+ }
538
+ static {
539
+ 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();
540
+ }
541
+ static {
542
+ 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();
543
+ }
544
+ static {
545
+ 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();
546
+ }
547
+ static {
548
+ 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();
549
+ }
550
+ static {
551
+ 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();
552
+ }
553
+ static {
554
+ this.listAssetCache = _Caching.createAssetCache();
555
+ }
556
+ static {
557
+ this.defaultBlockStatesCache = _Caching.createAssetCache();
558
+ }
559
+ static {
560
+ this.entityModelsCache = _Caching.createAssetCache();
561
+ }
562
+ static createAssetCache() {
563
+ 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();
564
+ }
514
565
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
515
566
  static get all() {
516
567
  return [
@@ -527,7 +578,10 @@ var Caching = class {
527
578
  this.rawModelCache,
528
579
  this.mergedModelCache,
529
580
  this.modelTextureAtlasCache,
530
- this.blockStateCache
581
+ this.blockStateCache,
582
+ this.listAssetCache,
583
+ this.defaultBlockStatesCache,
584
+ this.entityModelsCache
531
585
  ];
532
586
  }
533
587
  static clear() {
@@ -538,8 +592,8 @@ var Caching = class {
538
592
  /**
539
593
  * Clears every cache and stops its expiry timer.
540
594
  *
541
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
542
- * this is called - see {@link shutdown}.
595
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
596
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
543
597
  */
544
598
  static end() {
545
599
  for (const cache of this.all) {
@@ -553,20 +607,6 @@ var Caching = class {
553
607
  };
554
608
  }
555
609
  };
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
610
 
571
611
  // src/Geometries.ts
572
612
  var Geometries = class _Geometries {
@@ -587,13 +627,14 @@ var Geometries = class _Geometries {
587
627
  };
588
628
 
589
629
  // src/Materials.ts
590
- var import_three6 = require("three");
630
+ var import_three5 = require("three");
591
631
 
592
632
  // src/texture/Textures.ts
593
- var import_three5 = require("three");
633
+ var import_three4 = require("three");
594
634
 
595
635
  // src/texture/TextureLoader.ts
596
- var import_three4 = require("three");
636
+ var import_three3 = require("three");
637
+ var THREE = __toESM(require("three"));
597
638
 
598
639
  // src/canvas/CanvasCompat.ts
599
640
  function createImage(width, height) {
@@ -604,9 +645,7 @@ function createCanvas2(width, height) {
604
645
  }
605
646
 
606
647
  // src/request/Requests.ts
607
- var import_axios = __toESM(require("axios"));
608
648
  var import_jobqu = require("jobqu");
609
- var import_time2 = require("@inventivetalent/time");
610
649
 
611
650
  // src/util/log.ts
612
651
  var Reset = "\x1B[0m";
@@ -616,198 +655,174 @@ function prefix(prefix2) {
616
655
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
617
656
  }
618
657
 
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();
658
+ // src/request/Requests.ts
659
+ var p = prefix("Requests");
660
+ var RequestError = class extends Error {
661
+ constructor(message, response, cause) {
662
+ super(message);
663
+ this.response = response;
664
+ this.cause = cause;
665
+ this.name = "RequestError";
638
666
  }
639
667
  };
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);
668
+ async function fetchRequest(config, defaultBaseURL) {
669
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
670
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
671
+ const headers = new Headers(options.headers);
672
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
673
+ headers.set("User-Agent", "MineRender");
674
+ }
675
+ const attemptSignal = AbortSignal.any([
676
+ ...signal ? [signal] : [],
677
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
678
+ ]);
679
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
680
+ attemptSignal.throwIfAborted();
681
+ try {
682
+ const response = await fetch(request);
683
+ const result = {
684
+ data: void 0,
685
+ status: response.status,
686
+ statusText: response.statusText,
687
+ headers: response.headers,
688
+ url: response.url
689
+ };
690
+ if (!response.ok) {
691
+ await response.body?.cancel().catch(() => {
692
+ });
693
+ throw new RequestError(`Request failed with status ${response.status}`, result);
664
694
  }
695
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
696
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
697
+ return { ...result, data };
698
+ } catch (error) {
699
+ attemptSignal.throwIfAborted();
700
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
701
+ throw new RequestError("Network request failed", void 0, error);
702
+ }
703
+ throw error;
665
704
  }
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
705
  }
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;
706
+ async function abortable(promise, signal) {
707
+ if (!signal) return promise;
708
+ let abort;
709
+ const cancelled = new Promise((_, reject) => {
710
+ abort = () => reject(signal.reason);
711
+ signal.addEventListener("abort", abort, { once: true });
712
+ if (signal.aborted) abort();
713
+ });
714
+ try {
715
+ return await Promise.race([promise, cancelled]);
716
+ } finally {
717
+ signal.removeEventListener("abort", abort);
687
718
  }
688
719
  }
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
- });
720
+ var RequestQueue = class {
721
+ constructor() {
722
+ this.pendingRequests = 0;
723
+ this.stopped = new AbortController();
724
+ this.queue = new import_jobqu.JobQueue(
725
+ (request) => fetchRequest(request, this.baseURL),
726
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
727
+ );
767
728
  }
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;
729
+ async request(request) {
730
+ this.pendingRequests++;
731
+ const signal = request.signal;
732
+ try {
733
+ for (let retries = 0; ; retries++) {
734
+ signal?.throwIfAborted();
735
+ try {
736
+ return await abortable(this.queue.add(request), signal);
737
+ } catch (error) {
738
+ console.debug(p, "Request failed", error);
739
+ const delay = this.retryDelay(error, request, retries);
740
+ if (delay === void 0) {
741
+ throw error;
775
742
  }
776
- } else {
777
- request["minerenderRetry"] = 3;
778
- return true;
743
+ await this.waitForRetry(delay, signal);
779
744
  }
780
745
  }
746
+ } finally {
747
+ if (signal?.aborted) {
748
+ this.queue.remove(request);
749
+ }
750
+ this.pendingRequests--;
781
751
  }
782
- return false;
752
+ }
753
+ retryDelay(error, request, retries) {
754
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
755
+ return void 0;
756
+ }
757
+ if (error instanceof RequestError) {
758
+ const status = error.response?.status;
759
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
760
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
761
+ return void 0;
762
+ }
763
+ let delay = 100 * 2 ** retries;
764
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
765
+ if (retryAfter !== void 0 && retryAfter !== null) {
766
+ const seconds = Number(retryAfter);
767
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
768
+ return void 0;
769
+ }
770
+ delay = Math.max(delay, seconds * 1e3);
771
+ }
772
+ return delay;
773
+ }
774
+ async waitForRetry(delay, signal) {
775
+ let timer;
776
+ const waiting = new Promise((resolve) => {
777
+ timer = setTimeout(resolve, delay);
778
+ });
779
+ try {
780
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
781
+ } finally {
782
+ clearTimeout(timer);
783
+ }
784
+ }
785
+ get pendingSize() {
786
+ return this.pendingRequests;
787
+ }
788
+ end() {
789
+ this.queue.end();
790
+ this.stopped.abort(new import_jobqu.JobCancelledError("ended"));
791
+ }
792
+ };
793
+ var Requests = class {
794
+ static {
795
+ this.genericQueue = new RequestQueue();
796
+ }
797
+ static {
798
+ this.mcAssetRequestQueue = new RequestQueue();
799
+ }
800
+ static genericRequest(request) {
801
+ return this.genericQueue.request(request);
802
+ }
803
+ static mcAssetRequest(request) {
804
+ return this.mcAssetRequestQueue.request(request);
783
805
  }
784
806
  static setMcAssetRoot(root) {
785
- this.mcAssetInstance.defaults.baseURL = root;
807
+ this.mcAssetRequestQueue.baseURL = root;
786
808
  }
809
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
787
810
  static get queueSizes() {
788
811
  return {
789
- generic: this.genericQueue.size,
790
- mcAsset: this.mcAssetRequestQueue.size
812
+ generic: this.genericQueue.pendingSize,
813
+ mcAsset: this.mcAssetRequestQueue.pendingSize
791
814
  };
792
815
  }
793
816
  /**
794
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
795
- * exit until this is called - see {@link shutdown}.
817
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
818
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
819
+ * this cleanup. See {@link shutdown}.
796
820
  */
797
821
  static end() {
798
822
  this.genericQueue.end();
799
823
  this.mcAssetRequestQueue.end();
800
824
  }
801
825
  };
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
826
 
812
827
  // src/WrappedImage.ts
813
828
  var WrappedImage = class {
@@ -845,10 +860,10 @@ var WrappedImage = class {
845
860
  return this.animated ? this.width : this.height;
846
861
  }
847
862
  get frameCount() {
848
- return this.height / this.width;
863
+ return this.height / this.frameHeight;
849
864
  }
850
865
  getFrameY(frame) {
851
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
866
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
852
867
  }
853
868
  getSectionData(sx, sy, sw, sh) {
854
869
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -858,7 +873,7 @@ var WrappedImage = class {
858
873
  }
859
874
  getFrameSectionData(frame) {
860
875
  const y = this.getFrameY(frame);
861
- return this.getSectionData(0, y, this.width, this.width + y);
876
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
862
877
  }
863
878
  };
864
879
 
@@ -872,29 +887,41 @@ var ImageLoader = class _ImageLoader {
872
887
  static async loadAsync(src) {
873
888
  return new Promise((resolve, reject) => {
874
889
  const image = this._createImage();
875
- image.src = src;
876
890
  image.onload = () => resolve(image);
877
- image.onerror = (err) => reject(err);
891
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
892
+ image.src = src;
878
893
  });
879
894
  }
880
895
  static loadElement(src, onload, onerr) {
881
896
  const image = this._createImage();
882
- image.src = src;
883
897
  if (onload)
884
898
  image.onload = onload;
885
899
  if (onerr)
886
900
  image.onerror = onerr;
901
+ image.src = src;
887
902
  return image;
888
903
  }
889
904
  static async loadData(src) {
890
905
  console.debug(p2, "loadData", src);
891
- return await this.infoToData(await this.getInfo(src));
906
+ const image = await this.loadCanvasData(src);
907
+ return image.data.getImageData(0, 0, image.width, image.height);
892
908
  }
893
909
  static async loadCanvasData(src) {
894
- return await this.infoToCanvasData(await this.getInfo(src));
910
+ const keyStr = serializeImageKey({ src });
911
+ const info = this.getInfo(src);
912
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
913
+ try {
914
+ return await this.infoToCanvasData(await info);
915
+ } catch (err) {
916
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
917
+ Caching.rawImageCache.invalidate(keyStr);
918
+ }
919
+ throw err;
920
+ }
895
921
  }
896
922
  static async infoToCanvasData(info) {
897
- const image = await _ImageLoader.loadAsync(info.src);
923
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
924
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
898
925
  const canvas = createCanvas2(info.width, info.height);
899
926
  const context = canvas.getContext("2d");
900
927
  context.drawImage(image, 0, 0);
@@ -905,11 +932,8 @@ var ImageLoader = class _ImageLoader {
905
932
  };
906
933
  }
907
934
  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);
935
+ const image = await this.infoToCanvasData(info);
936
+ return image.data.getImageData(0, 0, image.width, image.height);
913
937
  }
914
938
  static async getData(src) {
915
939
  const keyStr = serializeImageKey({ src });
@@ -924,38 +948,25 @@ var ImageLoader = class _ImageLoader {
924
948
  });
925
949
  }
926
950
  static async processResponse(response) {
927
- const src = response.config.url;
951
+ const src = response.url;
928
952
  const data = import_buffer.Buffer.from(response.data);
929
953
  const { width, height, type } = Env.provider.imageSize(data);
954
+ if (!width || !height) {
955
+ throw new Error("Invalid or unsupported image dimensions");
956
+ }
930
957
  return {
931
958
  src,
932
- width: width || 0,
933
- height: height || 0,
959
+ width,
960
+ height,
934
961
  type,
935
962
  data
936
963
  };
937
964
  }
938
965
  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
966
  return Requests.genericRequest({
948
967
  url: src,
949
968
  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
- });
969
+ }).then(this.processResponse);
959
970
  }
960
971
  static async getInfo(src) {
961
972
  const keyStr = serializeImageKey({ src });
@@ -977,25 +988,39 @@ var ImageLoader = class _ImageLoader {
977
988
 
978
989
  // src/texture/TextureLoader.ts
979
990
  var TextureLoader = class {
991
+ static {
992
+ this.failedTextures = /* @__PURE__ */ new WeakSet();
993
+ }
994
+ /** Reports whether image loading failed, so cached textures can be retried. */
995
+ static hasFailed(texture) {
996
+ return this.failedTextures.has(texture);
997
+ }
980
998
  static createTexture() {
981
- return new import_three4.Texture();
999
+ return new import_three3.Texture();
982
1000
  }
983
- static loadInBackground(src, format = import_three4.RGBAFormat, rotation = 0) {
1001
+ static loadInBackground(src, format = import_three3.RGBAFormat, rotation = 0) {
984
1002
  const texture = this.createTexture();
985
- const image = ImageLoader.loadElement(src);
986
- image.onload = function() {
1003
+ texture.colorSpace = THREE.SRGBColorSpace;
1004
+ const image = ImageLoader.loadElement(src, () => {
987
1005
  texture.needsUpdate = true;
988
- };
1006
+ }, (error) => {
1007
+ this.failedTextures.add(texture);
1008
+ console.warn("Failed to load texture", src, error);
1009
+ });
989
1010
  texture.image = image;
990
1011
  texture.format = format;
991
1012
  texture.rotation = rotation;
992
1013
  return Textures.initTextureProps(texture);
993
1014
  }
994
- static load(src, format = import_three4.RGBAFormat, rotation = 0) {
995
- const texture = new import_three4.Texture();
1015
+ static load(src, format = import_three3.RGBAFormat, rotation = 0) {
1016
+ const texture = new import_three3.Texture();
1017
+ texture.colorSpace = THREE.SRGBColorSpace;
996
1018
  ImageLoader.getData(src).then((image) => {
997
- texture.needsUpdate = true;
998
1019
  texture.image = image;
1020
+ texture.needsUpdate = true;
1021
+ }).catch((error) => {
1022
+ this.failedTextures.add(texture);
1023
+ console.warn("Failed to load texture", src, error);
999
1024
  });
1000
1025
  texture.format = format;
1001
1026
  texture.rotation = rotation;
@@ -1004,11 +1029,11 @@ var TextureLoader = class {
1004
1029
  };
1005
1030
 
1006
1031
  // src/texture/Textures.ts
1007
- var THREE = __toESM(require("three"));
1032
+ var THREE2 = __toESM(require("three"));
1008
1033
  var Textures = class _Textures {
1009
1034
  static initTextureProps(texture) {
1010
- texture.magFilter = THREE.NearestFilter;
1011
- texture.minFilter = THREE.NearestFilter;
1035
+ texture.magFilter = THREE2.NearestFilter;
1036
+ texture.minFilter = THREE2.NearestFilter;
1012
1037
  texture.anisotropy = 0;
1013
1038
  return texture;
1014
1039
  }
@@ -1016,13 +1041,19 @@ var Textures = class _Textures {
1016
1041
  return TextureLoader.load(key.src, key.format, key.rotation);
1017
1042
  }
1018
1043
  static createAsset(key) {
1019
- return new import_three5.Texture();
1044
+ return new import_three4.Texture();
1020
1045
  }
1021
1046
  static createCanvasTexture(canvas) {
1022
- return this.initTextureProps(new import_three5.CanvasTexture(canvas));
1047
+ const texture = new import_three4.CanvasTexture(canvas);
1048
+ texture.colorSpace = THREE2.SRGBColorSpace;
1049
+ return this.initTextureProps(texture);
1023
1050
  }
1024
1051
  static getImage(key) {
1025
1052
  const keyStr = serializeTextureKey(key);
1053
+ const cached = Caching.textureCache.peek(keyStr);
1054
+ if (cached && TextureLoader.hasFailed(cached)) {
1055
+ Caching.textureCache.invalidate(keyStr);
1056
+ }
1026
1057
  return Caching.textureCache.get(keyStr, (k) => {
1027
1058
  return _Textures.createImage(key);
1028
1059
  });
@@ -1030,7 +1061,10 @@ var Textures = class _Textures {
1030
1061
  };
1031
1062
 
1032
1063
  // src/Materials.ts
1033
- var _Materials = class _Materials {
1064
+ var Materials = class _Materials {
1065
+ static {
1066
+ this.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1067
+ }
1034
1068
  // resolved lazily: as a static field this decoded an image the moment the library was
1035
1069
  // imported, which needs both a DOM and an EnvProvider to already be in place
1036
1070
  static get MISSING_TEXTURE() {
@@ -1038,26 +1072,26 @@ var _Materials = class _Materials {
1038
1072
  }
1039
1073
  static createImage(key) {
1040
1074
  const transparent = key.transparent || false;
1041
- return new import_three6.MeshBasicMaterial({
1075
+ return new import_three5.MeshBasicMaterial({
1042
1076
  map: Textures.getImage(key.texture),
1043
1077
  transparent,
1044
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1078
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1045
1079
  alphaTest: 0.5
1046
1080
  });
1047
1081
  }
1048
1082
  static createBasicCanvasMaterial(canvas, transparent = false, shade = false) {
1049
1083
  if (shade) {
1050
- return new import_three6.MeshStandardMaterial({
1084
+ return new import_three5.MeshStandardMaterial({
1051
1085
  map: Textures.createCanvasTexture(canvas),
1052
1086
  transparent,
1053
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1087
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1054
1088
  alphaTest: 0.5
1055
1089
  });
1056
1090
  }
1057
- return new import_three6.MeshBasicMaterial({
1091
+ return new import_three5.MeshBasicMaterial({
1058
1092
  map: Textures.createCanvasTexture(canvas),
1059
1093
  transparent,
1060
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1094
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1061
1095
  alphaTest: 0.5
1062
1096
  });
1063
1097
  }
@@ -1066,6 +1100,7 @@ var _Materials = class _Materials {
1066
1100
  uniform bool SHADE;
1067
1101
 
1068
1102
  varying vec2 vUv;
1103
+ varying vec3 vTint;
1069
1104
  varying float light;
1070
1105
  varying float lift;
1071
1106
 
@@ -1078,7 +1113,11 @@ var _Materials = class _Materials {
1078
1113
 
1079
1114
  if (SHADE) {
1080
1115
 
1081
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1116
+ #ifdef USE_INSTANCING
1117
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1118
+ #else
1119
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
1120
+ #endif
1082
1121
 
1083
1122
  float yLight = (1.0+N.y) * 0.5;
1084
1123
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -1096,6 +1135,7 @@ var _Materials = class _Materials {
1096
1135
  }
1097
1136
 
1098
1137
  vUv = uv;
1138
+ vTint = color;
1099
1139
 
1100
1140
  #ifdef USE_INSTANCING
1101
1141
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -1117,12 +1157,14 @@ var _Materials = class _Materials {
1117
1157
  uniform float BRIGHTNESS;
1118
1158
 
1119
1159
  varying vec2 vUv;
1160
+ varying vec3 vTint;
1120
1161
  varying float light;
1121
1162
  varying float lift;
1122
1163
 
1123
1164
  void main(void)
1124
1165
  {
1125
1166
  vec4 color = texture2D(map, vUv);
1167
+ color.rgb *= vTint;
1126
1168
 
1127
1169
  if (color.a < 0.01) discard;
1128
1170
 
@@ -1136,16 +1178,19 @@ var _Materials = class _Materials {
1136
1178
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1137
1179
 
1138
1180
  }
1181
+
1182
+ #include <tonemapping_fragment>
1183
+ #include <colorspace_fragment>
1139
1184
  }
1140
1185
  `;
1141
1186
  try {
1142
- return new import_three6.ShaderMaterial({
1187
+ return new import_three5.ShaderMaterial({
1143
1188
  uniforms: {
1144
1189
  SHADE: { value: true },
1145
1190
  BRIGHTNESS: { value: 1 },
1146
1191
  EMISSIVE: { value: false },
1147
1192
  base: {
1148
- value: new import_three6.Color(12698049)
1193
+ value: new import_three5.Color(12698049)
1149
1194
  /*TODO*/
1150
1195
  },
1151
1196
  map: { value: Textures.createCanvasTexture(canvas) }
@@ -1154,7 +1199,7 @@ var _Materials = class _Materials {
1154
1199
  fragmentShader: fragShader,
1155
1200
  vertexColors: true,
1156
1201
  transparent,
1157
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1202
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1158
1203
  alphaTest: 0.5
1159
1204
  });
1160
1205
  } catch (e) {
@@ -1164,6 +1209,10 @@ var _Materials = class _Materials {
1164
1209
  }
1165
1210
  static getImage(key) {
1166
1211
  const keyStr = serializeMaterialKey(key);
1212
+ const map = Caching.materialCache.peek(keyStr)?.map;
1213
+ if (map && TextureLoader.hasFailed(map)) {
1214
+ Caching.materialCache.invalidate(keyStr);
1215
+ }
1167
1216
  return Caching.materialCache.get(keyStr, (k) => {
1168
1217
  return _Materials.createImage(key);
1169
1218
  });
@@ -1184,14 +1233,12 @@ var _Materials = class _Materials {
1184
1233
  }
1185
1234
  }
1186
1235
  };
1187
- _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1188
- var Materials = _Materials;
1189
1236
 
1190
1237
  // src/Meshes.ts
1191
- var import_three7 = require("three");
1238
+ var import_three6 = require("three");
1192
1239
  var Meshes = class _Meshes {
1193
1240
  static createBox(key) {
1194
- return new import_three7.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1241
+ return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1195
1242
  }
1196
1243
  static getBox(key) {
1197
1244
  const keyStr = serializeMeshKey(key);
@@ -1238,9 +1285,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1238
1285
  this.rootType = rootType;
1239
1286
  this.extension = extension;
1240
1287
  this.root = root;
1288
+ this.isAssetKey = true;
1241
1289
  }
1242
1290
  static parse(assetType, str, origin) {
1243
- let namespace = (origin == null ? void 0 : origin.namespace) || DEFAULT_NAMESPACE;
1291
+ let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1244
1292
  if (str.includes(":")) {
1245
1293
  let split2 = str.split(":");
1246
1294
  namespace = split2[0];
@@ -1253,12 +1301,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1253
1301
  split.shift();
1254
1302
  }
1255
1303
  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);
1304
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1305
+ if (extension && path.endsWith(extension)) {
1306
+ path = path.slice(0, -extension.length);
1307
+ }
1308
+ return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1258
1309
  }
1259
1310
  toString() {
1260
1311
  let a = [
1261
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1312
+ this.root ?? AssetLoader.ROOT,
1262
1313
  this.rootType ?? "__rootType__",
1263
1314
  this.assetType ?? "__assetType__",
1264
1315
  this.type ?? "__type__",
@@ -1268,12 +1319,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1268
1319
  return a.join("/");
1269
1320
  }
1270
1321
  getFullPath() {
1271
- let p13 = [];
1322
+ let p12 = [];
1272
1323
  if (this.type) {
1273
- p13.push(this.type);
1324
+ p12.push(this.type);
1274
1325
  }
1275
- p13.push(this.path);
1276
- return p13.join("/");
1326
+ p12.push(this.path);
1327
+ return p12.join("/");
1277
1328
  }
1278
1329
  toNamespacedString() {
1279
1330
  return this.namespace + ":" + this.getFullPath();
@@ -1283,10 +1334,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1283
1334
  }
1284
1335
  };
1285
1336
  function isBasicAssetKey(obj) {
1286
- return "namespace" in obj && "path" in obj;
1337
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1287
1338
  }
1288
1339
  function isAssetKey(obj) {
1289
- return isBasicAssetKey(obj) && "parse" in obj;
1340
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1290
1341
  }
1291
1342
 
1292
1343
  // src/model/ModelMerger.ts
@@ -1295,10 +1346,10 @@ var ModelMerger = class {
1295
1346
  const models = await this.collectAllParents(model);
1296
1347
  let merged = {};
1297
1348
  for (let parentModel of models) {
1298
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1349
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, parentModel);
1299
1350
  }
1300
- merged = (0, import_ts_deepmerge.default)(merged, model);
1301
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1351
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, model);
1352
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1302
1353
  merged.hierarchy.push(`${merged.parent}`);
1303
1354
  return merged;
1304
1355
  }
@@ -1308,6 +1359,7 @@ var ModelMerger = class {
1308
1359
  }
1309
1360
  const models = [];
1310
1361
  const parentKey = AssetKey.parse("models", model.parent);
1362
+ parentKey.root = model.key?.root;
1311
1363
  const parentModel = await Models.getRaw(parentKey);
1312
1364
  if (parentModel) {
1313
1365
  models.unshift(parentModel);
@@ -1317,9 +1369,6 @@ var ModelMerger = class {
1317
1369
  }
1318
1370
  };
1319
1371
 
1320
- // src/assets/Models.ts
1321
- var import_typescript_memoize = require("typescript-memoize");
1322
-
1323
1372
  // src/assets/source/parser/AssetParsers.ts
1324
1373
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1325
1374
  AssetParser2["MODEL"] = "model";
@@ -1333,30 +1382,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1333
1382
  })(AssetParser || {});
1334
1383
 
1335
1384
  // src/assets/Models.ts
1336
- var _Models = class _Models {
1385
+ var Models = class _Models {
1337
1386
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1338
1387
  // the library, and would require an EnvProvider before any entry has had a chance to register
1339
1388
  static get PERSISTENT_CACHE() {
1340
1389
  return this._persistentCache ??= PersistentCache.open("minerender-models");
1341
1390
  }
1342
1391
  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) ?? []);
1392
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1393
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1394
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1395
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1396
+ }).then((r) => r?.files ?? []);
1352
1397
  }
1353
1398
  static async loadAndMerge(key) {
1354
- const model = await this.getRaw(key);
1399
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1355
1400
  if (!model) {
1356
1401
  return void 0;
1357
1402
  }
1358
1403
  return ModelMerger.mergeWithParents(model);
1359
1404
  }
1405
+ static async getItemModel(key) {
1406
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1407
+ const model = await this.PERSISTENT_CACHE.getOrLoad(itemKey.serialize(), async () => {
1408
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1409
+ if (!result) return void 0;
1410
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1411
+ const reference = this.defaultItemModel(result.asset.model, key);
1412
+ const modelKey = AssetKey.parse("models", reference);
1413
+ modelKey.root = key.root;
1414
+ const model2 = await this.getRaw(modelKey);
1415
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1416
+ return model2;
1417
+ });
1418
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1419
+ }
1420
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1421
+ static defaultItemModel(node, key) {
1422
+ if (!node || typeof node.type !== "string") {
1423
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1424
+ }
1425
+ switch (node.type.replace(/^minecraft:/, "")) {
1426
+ case "model":
1427
+ if (typeof node.model === "string" && node.model) return node.model;
1428
+ break;
1429
+ case "condition":
1430
+ return this.defaultItemModel(node.on_false, key);
1431
+ case "select": {
1432
+ 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;
1433
+ return this.defaultItemModel(selected ?? node.fallback, key);
1434
+ }
1435
+ case "range_dispatch": {
1436
+ const selected = node.entries?.reduce((match, entry) => {
1437
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1438
+ }, void 0);
1439
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1440
+ }
1441
+ }
1442
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1443
+ }
1360
1444
  static async getRaw(key) {
1361
1445
  if (!key.assetType) {
1362
1446
  key.assetType = "models";
@@ -1395,19 +1479,15 @@ var _Models = class _Models {
1395
1479
  return this.PERSISTENT_CACHE.clear();
1396
1480
  }
1397
1481
  };
1398
- __decorateClass([
1399
- (0, import_typescript_memoize.Memoize)()
1400
- ], _Models, "getItemList", 1);
1401
- var Models = _Models;
1402
1482
 
1403
1483
  // src/assets/BlockStates.ts
1404
- var import_typescript_memoize2 = require("typescript-memoize");
1405
1484
  var BlockStates = class {
1406
1485
  static get PERSISTENT_CACHE() {
1407
1486
  return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
1408
1487
  }
1488
+ // BlockState names are hardcoded
1409
1489
  static async getList() {
1410
- return AssetLoader.get(new AssetKey(
1490
+ const key = new AssetKey(
1411
1491
  DEFAULT_NAMESPACE,
1412
1492
  "_list",
1413
1493
  "blockstates",
@@ -1415,11 +1495,16 @@ var BlockStates = class {
1415
1495
  "assets",
1416
1496
  ".json",
1417
1497
  DEFAULT_ROOT
1418
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1498
+ );
1499
+ return Caching.listAssetCache.get(key.serialize(), () => {
1500
+ return AssetLoader.get(key, "list" /* LIST */);
1501
+ }).then((r) => r?.files ?? []);
1419
1502
  }
1420
1503
  static async getDefaultStates() {
1421
1504
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1422
- return AssetLoader.get(key, "json" /* JSON */);
1505
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1506
+ return AssetLoader.get(key, "json" /* JSON */);
1507
+ });
1423
1508
  }
1424
1509
  static async getDefaultState(key) {
1425
1510
  const defaultStates = await this.getDefaultStates();
@@ -1458,17 +1543,11 @@ var BlockStates = class {
1458
1543
  await this.PERSISTENT_CACHE.clear();
1459
1544
  }
1460
1545
  };
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
1546
  var DefaultBlockStates = class {
1468
1547
  };
1469
1548
 
1470
1549
  // src/assets/Assets.ts
1471
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1550
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1472
1551
  var DEFAULT_NAMESPACE = "minecraft";
1473
1552
  var Assets = class {
1474
1553
  /**
@@ -1490,23 +1569,236 @@ var AssetSource = class {
1490
1569
  constructor() {
1491
1570
  }
1492
1571
  };
1572
+ var AssetLoadError = class extends Error {
1573
+ constructor(source, key, path, cause) {
1574
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1575
+ this.source = source;
1576
+ this.key = key;
1577
+ this.path = path;
1578
+ this.cause = cause;
1579
+ this.name = "AssetLoadError";
1580
+ }
1581
+ };
1493
1582
 
1494
- // src/nbt/NBTHelper.ts
1495
- var NBTHelper = class {
1496
- static async fromBuffer(buffer) {
1497
- const prismarineNbt = await import("prismarine-nbt");
1498
- const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1499
- return parsed;
1583
+ // src/util/BatchedExecutor.ts
1584
+ var BatchedExecutor = class {
1585
+ constructor(interval = 1, batch = 30) {
1586
+ this.interval = interval;
1587
+ this.batch = batch;
1588
+ this.queue = [];
1589
+ this.task = setInterval(() => this.run());
1590
+ }
1591
+ submit(task) {
1592
+ this.queue.push(task);
1593
+ }
1594
+ run() {
1595
+ for (let i = 0; i < this.batch; i++) {
1596
+ this.runNext();
1597
+ }
1598
+ }
1599
+ runNext() {
1600
+ let next = this.queue.shift();
1601
+ if (next) next();
1500
1602
  }
1501
1603
  };
1502
1604
 
1503
- // src/assets/source/HostedAssetSource.ts
1504
- var import_ts_deepmerge2 = __toESM(require_dist());
1605
+ // src/util/model.ts
1606
+ var import_three7 = require("three");
1607
+ function applyElementRotation(rotation, geometry) {
1608
+ const origin = new import_three7.Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1609
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1610
+ switch (rotation.axis) {
1611
+ case "x" /* X */:
1612
+ geometry.rotateX(toRadians(rotation.angle));
1613
+ break;
1614
+ case "y" /* Y */:
1615
+ geometry.rotateY(toRadians(rotation.angle));
1616
+ break;
1617
+ case "z" /* Z */:
1618
+ geometry.rotateZ(toRadians(rotation.angle));
1619
+ break;
1620
+ }
1621
+ if (rotation.rescale) {
1622
+ if (Math.abs(rotation.angle) === 22.5) {
1623
+ const s = 1 / Math.cos(0.39269909262657166);
1624
+ geometry.scale(s, 1, s);
1625
+ } else {
1626
+ const s = 1 / Math.cos(0.7853981852531433);
1627
+ geometry.scale(s, 1, s);
1628
+ }
1629
+ }
1630
+ geometry.translate(origin.x, origin.y, origin.z);
1631
+ }
1632
+ function applyModelPartRotation(modelPart, geometry) {
1633
+ const origin = new import_three7.Vector3(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
1634
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1635
+ geometry.rotateX(toRadians(modelPart.pitch));
1636
+ geometry.rotateY(toRadians(modelPart.yaw));
1637
+ geometry.rotateZ(toRadians(modelPart.roll));
1638
+ geometry.translate(origin.x, origin.y, origin.z);
1639
+ }
1640
+ function applyGenericRotation(axis, rotation, obj) {
1641
+ switch (axis) {
1642
+ case "x" /* X */:
1643
+ obj.rotateOnAxis(new import_three7.Vector3(1, 0, 0), toRadians(rotation));
1644
+ break;
1645
+ case "y" /* Y */:
1646
+ obj.rotateOnAxis(new import_three7.Vector3(0, 1, 0), toRadians(rotation));
1647
+ break;
1648
+ case "z" /* Z */:
1649
+ obj.rotateOnAxis(new import_three7.Vector3(0, 0, 1), toRadians(rotation));
1650
+ break;
1651
+ }
1652
+ }
1653
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1654
+ let size = new import_three7.Vector3();
1655
+ box.getSize(size);
1656
+ let boxGeo = new import_three7.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
1657
+ let wireGeo = new import_three7.EdgesGeometry(boxGeo);
1658
+ let wireMat = new import_three7.LineBasicMaterial({ color, linewidth: w });
1659
+ let wireframe = new import_three7.LineSegments(wireGeo, wireMat);
1660
+ obj.add(wireframe);
1661
+ let axes = new import_three7.AxesHelper(1);
1662
+ obj.add(axes);
1663
+ }
1664
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1665
+ let boxGeo = new import_three7.BoxGeometry(16, 16, 16, 1, 1, 1);
1666
+ let wireGeo = new import_three7.EdgesGeometry(boxGeo);
1667
+ let wireMat = new import_three7.LineBasicMaterial({ color, linewidth: w });
1668
+ let wireframe = new import_three7.LineSegments(wireGeo, wireMat);
1669
+ obj.add(wireframe);
1670
+ let axes = new import_three7.AxesHelper(1);
1671
+ obj.add(axes);
1672
+ }
1673
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1674
+ let wireGeo = new import_three7.EdgesGeometry(geo);
1675
+ let wireMat = new import_three7.LineBasicMaterial({ color, linewidth: w });
1676
+ let wireframe = new import_three7.LineSegments(wireGeo, wireMat);
1677
+ mesh.add(wireframe);
1678
+ let axes = new import_three7.AxesHelper(1);
1679
+ mesh.add(axes);
1680
+ }
1681
+
1682
+ // src/util/performance.ts
1683
+ function captureException(e, ...extra) {
1684
+ console.error(e, extra);
1685
+ }
1686
+ function timingStart(marker) {
1687
+ console.time(marker);
1688
+ }
1689
+ function timingEnd(marker) {
1690
+ console.timeEnd(marker);
1691
+ }
1692
+
1693
+ // src/util/three.ts
1694
+ function isObject3D(obj) {
1695
+ return obj.isObject3D;
1696
+ }
1697
+ function isMesh(obj) {
1698
+ return obj.isMesh;
1699
+ }
1700
+ function isInstancedMesh(obj) {
1701
+ return obj.isInstancedMesh;
1702
+ }
1703
+ function isPerspectiveCamera(obj) {
1704
+ return obj.isPerspectiveCamera;
1705
+ }
1706
+ function isOrthographicCamera(obj) {
1707
+ return obj.isOrthographicCamera;
1708
+ }
1709
+
1710
+ // src/nbt/NBTHelper.ts
1711
+ var NBTHelper = class {
1712
+ static async fromBuffer(buffer) {
1713
+ const prismarineNbt = await import("prismarine-nbt");
1714
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1715
+ return parsed;
1716
+ }
1717
+ };
1718
+
1719
+ // src/assets/source/HostedAssetSource.ts
1720
+ var import_ts_deepmerge2 = __toESM(require_dist());
1505
1721
  var p3 = prefix("HostedAssetSource");
1506
1722
  var DEFAULT_OPTIONS = {
1507
1723
  retryDefaults: true
1508
1724
  };
1509
- var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1725
+ var HostedAssetSource = class _HostedAssetSource extends AssetSource {
1726
+ static {
1727
+ this.MODEL = {
1728
+ config(request) {
1729
+ },
1730
+ parse(response) {
1731
+ return response.data;
1732
+ }
1733
+ };
1734
+ }
1735
+ static {
1736
+ this.BLOCKSTATE = {
1737
+ config(request) {
1738
+ },
1739
+ parse(response) {
1740
+ return response.data;
1741
+ }
1742
+ };
1743
+ }
1744
+ static {
1745
+ this.META = {
1746
+ config(request) {
1747
+ },
1748
+ parse(response) {
1749
+ return response.data;
1750
+ }
1751
+ };
1752
+ }
1753
+ static {
1754
+ this.NBT = {
1755
+ config(request) {
1756
+ request.responseType = "arraybuffer";
1757
+ },
1758
+ parse(response) {
1759
+ return NBTHelper.fromBuffer(Buffer.from(response.data));
1760
+ }
1761
+ };
1762
+ }
1763
+ static {
1764
+ this.IMAGE = {
1765
+ config(request) {
1766
+ request.responseType = "arraybuffer";
1767
+ },
1768
+ async parse(response) {
1769
+ return await ImageLoader.processResponse(response);
1770
+ }
1771
+ };
1772
+ }
1773
+ static {
1774
+ this.LIST = {
1775
+ config(request) {
1776
+ },
1777
+ parse(response) {
1778
+ return response.data;
1779
+ }
1780
+ };
1781
+ }
1782
+ static {
1783
+ this.JSON = {
1784
+ config(request) {
1785
+ },
1786
+ parse(response) {
1787
+ return response.data;
1788
+ }
1789
+ };
1790
+ }
1791
+ static {
1792
+ this.PARSER_MAP = /* @__PURE__ */ new Map([
1793
+ ["model" /* MODEL */, _HostedAssetSource.MODEL],
1794
+ ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1795
+ ["meta" /* META */, _HostedAssetSource.META],
1796
+ ["nbt" /* NBT */, _HostedAssetSource.NBT],
1797
+ ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1798
+ ["list" /* LIST */, _HostedAssetSource.LIST],
1799
+ ["json" /* JSON */, _HostedAssetSource.JSON]
1800
+ ]);
1801
+ }
1510
1802
  async loadOrRetryWithDefaults(key, parser) {
1511
1803
  const direct = await this.load(key, parser);
1512
1804
  if (typeof direct !== "undefined") {
@@ -1541,31 +1833,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1541
1833
  console.info(p3, "Loading", key);
1542
1834
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1543
1835
  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");
1836
+ const request = { url };
1837
+ try {
1838
+ parser.config(request);
1839
+ let response;
1840
+ try {
1841
+ response = await Requests.mcAssetRequest(request);
1842
+ } catch (cause) {
1843
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1563
1844
  return void 0;
1564
1845
  }
1846
+ throw cause;
1565
1847
  }
1566
- console.debug(p3, "Failed to load", key, err == null ? void 0 : err.message);
1567
- return void 0;
1568
- });
1848
+ if (response.data === void 0) {
1849
+ throw new Error("Asset response has no data");
1850
+ }
1851
+ return await parser.parse(response);
1852
+ } catch (cause) {
1853
+ throw new AssetLoadError(this, key, request.url, cause);
1854
+ }
1569
1855
  }
1570
1856
  assetBasePath(key) {
1571
1857
  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 + "/" : ""}`;
@@ -1589,67 +1875,6 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1589
1875
  return this.load(key, responseParser);
1590
1876
  }
1591
1877
  };
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
1878
 
1654
1879
  // src/assets/source/archive/BrowserArchiveProxy.ts
1655
1880
  var import_zip = require("@zip.js/zip.js");
@@ -1672,7 +1897,6 @@ var BrowserArchiveProxy = class {
1672
1897
  };
1673
1898
 
1674
1899
  // src/assets/source/archive/ArchiveAssetSource.ts
1675
- var p4 = prefix("ArchiveAssetSource");
1676
1900
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1677
1901
  constructor(archiveProxy) {
1678
1902
  super();
@@ -1691,74 +1915,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1691
1915
  }
1692
1916
  async get(key, parser) {
1693
1917
  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
- });
1918
+ return this.load(key, responseParser);
1731
1919
  }
1732
- //TODO: abstract this
1733
1920
  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
- }
1921
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1922
+ let url;
1923
+ try {
1924
+ const entry = await this.getEntry(path);
1925
+ if (!entry) {
1926
+ return void 0;
1749
1927
  }
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
- }
1928
+ url = URL.createObjectURL(await entry.getData());
1929
+ const request = { url };
1930
+ parser.config(request);
1931
+ const response = await Requests.genericRequest(request);
1932
+ if (response.data === void 0) {
1933
+ throw new Error("Asset response has no data");
1758
1934
  }
1759
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1760
- return void 0;
1761
- });
1935
+ return await parser.parse(response);
1936
+ } catch (cause) {
1937
+ throw new AssetLoadError(this, key, path, cause);
1938
+ } finally {
1939
+ if (url !== void 0) {
1940
+ URL.revokeObjectURL(url);
1941
+ }
1942
+ }
1762
1943
  }
1763
1944
  assetBasePath(key) {
1764
1945
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1766,18 +1947,23 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1766
1947
  };
1767
1948
 
1768
1949
  // src/assets/AssetLoader.ts
1769
- var import_ts_deepmerge3 = __toESM(require_dist());
1770
- var p5 = prefix("AssetLoader");
1771
- var _AssetLoader = class _AssetLoader {
1950
+ var p4 = prefix("AssetLoader");
1951
+ var AssetLoader = class {
1952
+ static {
1953
+ this.ROOT = DEFAULT_ROOT;
1954
+ }
1955
+ static {
1956
+ this._SOURCES = [];
1957
+ }
1772
1958
  static addSource(key, source, override = true) {
1773
1959
  if (override) {
1774
1960
  const existing = this.removeSource(key);
1775
1961
  if (existing) {
1776
- console.log(p5, "Removed existing AssetSource", key);
1962
+ console.log(p4, "Removed existing AssetSource", key);
1777
1963
  }
1778
1964
  }
1779
1965
  this._SOURCES.unshift({ key, source });
1780
- console.log(p5, "Added AssetSource", key);
1966
+ console.log(p4, "Added AssetSource", key);
1781
1967
  }
1782
1968
  static removeSource(key) {
1783
1969
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1789,8 +1975,11 @@ var _AssetLoader = class _AssetLoader {
1789
1975
  }
1790
1976
  return void 0;
1791
1977
  }
1978
+ static {
1979
+ this.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1980
+ this.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
1981
+ }
1792
1982
  static async getAll(key, parser) {
1793
- console.log(this._SOURCES);
1794
1983
  let promises = [];
1795
1984
  for (const source of this._SOURCES) {
1796
1985
  promises.push(source.source.get(key, parser));
@@ -1799,31 +1988,36 @@ var _AssetLoader = class _AssetLoader {
1799
1988
  return results.filter((r) => r != void 0);
1800
1989
  });
1801
1990
  }
1991
+ /** Returns the first defined result in source-priority order, without merging assets. */
1802
1992
  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;
1993
+ const keys = [key];
1994
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
1995
+ keys.push(new AssetKey(
1996
+ key.namespace,
1997
+ key.path,
1998
+ key.assetType === "structure" ? "structures" : "structure",
1999
+ key.type,
2000
+ key.rootType,
2001
+ key.extension,
2002
+ key.root
2003
+ ));
2004
+ }
2005
+ return (await this.getFirst(keys, parser))?.asset;
2006
+ }
2007
+ /** Tries each path within a source before considering lower-priority sources. */
2008
+ static async getFirst(keys, parser) {
2009
+ const sources = [...this._SOURCES];
2010
+ for (const source of sources) {
2011
+ for (const key of keys) {
2012
+ const result = await source.source.get(key, parser);
2013
+ if (result !== void 0) {
2014
+ return { key, asset: result };
1816
2015
  }
1817
2016
  }
1818
- return void 0;
1819
- });
2017
+ }
2018
+ return void 0;
1820
2019
  }
1821
2020
  };
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
2021
 
1828
2022
  // src/assets/ModelTextures.ts
1829
2023
  var ModelTextures = class {
@@ -1831,11 +2025,21 @@ var ModelTextures = class {
1831
2025
  return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
1832
2026
  }
1833
2027
  static async get(key) {
1834
- const asset = await this.preload(key);
1835
- if (asset) {
1836
- return ImageLoader.infoToCanvasData(asset);
2028
+ const keyStr = key.serialize();
2029
+ const pending = this.preload(key);
2030
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
2031
+ try {
2032
+ const asset = await pending;
2033
+ if (asset) {
2034
+ return await ImageLoader.infoToCanvasData(asset);
2035
+ }
2036
+ return void 0;
2037
+ } catch (err) {
2038
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
2039
+ Caching.textureAssetCache.invalidate(keyStr);
2040
+ }
2041
+ throw err;
1837
2042
  }
1838
- return void 0;
1839
2043
  }
1840
2044
  static async preload(key) {
1841
2045
  const keyStr = key.serialize();
@@ -1909,7 +2113,28 @@ var CanvasImage = class {
1909
2113
  };
1910
2114
 
1911
2115
  // src/Ticker.ts
1912
- var _Ticker = class _Ticker {
2116
+ var Ticker = class _Ticker {
2117
+ static {
2118
+ this.TPS = 20;
2119
+ }
2120
+ static {
2121
+ this.counter = 0;
2122
+ }
2123
+ static {
2124
+ this._tickers = /* @__PURE__ */ new Map();
2125
+ }
2126
+ static {
2127
+ this.oneSecondTps = 0;
2128
+ }
2129
+ static {
2130
+ this.oneSecondTicks = 0;
2131
+ }
2132
+ static {
2133
+ this.fiveSecondTps = 0;
2134
+ }
2135
+ static {
2136
+ this.fiveSecondTicks = 0;
2137
+ }
1913
2138
  static schedule(fn, ms) {
1914
2139
  const handle = setInterval(fn, ms);
1915
2140
  const unref = handle.unref;
@@ -1971,14 +2196,6 @@ var _Ticker = class _Ticker {
1971
2196
  this._tickers.clear();
1972
2197
  }
1973
2198
  };
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
2199
 
1983
2200
  // src/texture/TextureAtlas.ts
1984
2201
  var TextureAtlas = class {
@@ -2004,18 +2221,24 @@ var TextureAtlas = class {
2004
2221
 
2005
2222
  // src/model/ModelGenerator.ts
2006
2223
  var ModelGenerator = class {
2224
+ static {
2225
+ this.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2226
+ }
2007
2227
  static generateItemModel(imageData, layer) {
2228
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
2008
2229
  const mainElement = {
2009
2230
  from: [0, 0, 7.5],
2010
2231
  to: [16, 16, 8.5],
2011
2232
  faces: {
2012
2233
  "south": {
2013
2234
  uv: [0, 0, 16, 16],
2014
- texture: `#${layer}`
2235
+ texture: `#${layer}`,
2236
+ tintindex
2015
2237
  },
2016
2238
  "north": {
2017
2239
  uv: [16, 0, 0, 16],
2018
- texture: `#${layer}`
2240
+ texture: `#${layer}`,
2241
+ tintindex
2019
2242
  }
2020
2243
  },
2021
2244
  shade: true
@@ -2023,14 +2246,21 @@ var ModelGenerator = class {
2023
2246
  return [mainElement];
2024
2247
  }
2025
2248
  };
2026
- ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2027
2249
 
2028
2250
  // src/UVMapper.ts
2029
- var p6 = prefix("UVMapper");
2251
+ var p5 = prefix("UVMapper");
2030
2252
  var DEFAULT_UV = [0, 0, 16, 16];
2031
2253
  var X = 0;
2032
2254
  var Y = 1;
2033
2255
  var Z = 2;
2256
+ var FACE_UV_AXES = {
2257
+ east: [new import_three8.Vector3(0, 0, -1), new import_three8.Vector3(0, -1, 0)],
2258
+ west: [new import_three8.Vector3(0, 0, 1), new import_three8.Vector3(0, -1, 0)],
2259
+ up: [new import_three8.Vector3(1, 0, 0), new import_three8.Vector3(0, 0, 1)],
2260
+ down: [new import_three8.Vector3(1, 0, 0), new import_three8.Vector3(0, 0, -1)],
2261
+ south: [new import_three8.Vector3(1, 0, 0), new import_three8.Vector3(0, -1, 0)],
2262
+ north: [new import_three8.Vector3(-1, 0, 0), new import_three8.Vector3(0, -1, 0)]
2263
+ };
2034
2264
  var UVMapper = class {
2035
2265
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
2036
2266
  if (uvCoord === 0) return 0;
@@ -2128,6 +2358,42 @@ var UVMapper = class {
2128
2358
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2129
2359
  return new import_three8.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2130
2360
  }
2361
+ static lockUvs(geometry, faces, atlas, rotation) {
2362
+ const uv = geometry.getAttribute("uv");
2363
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2364
+ const faceName = CUBE_FACES[faceIndex];
2365
+ const texture = faces[faceName]?.texture?.substring(1);
2366
+ const position = texture && atlas.positions[texture];
2367
+ const size = texture && atlas.sizes[texture];
2368
+ if (!position || !size) continue;
2369
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2370
+ const uAxis = sourceU.clone().applyEuler(rotation);
2371
+ const vAxis = sourceV.clone().applyEuler(rotation);
2372
+ const normal = vAxis.clone().cross(uAxis);
2373
+ const targetFace = CUBE_FACES.find((name) => {
2374
+ const [u, v] = FACE_UV_AXES[name];
2375
+ return v.clone().cross(u).dot(normal) > 0.5;
2376
+ });
2377
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2378
+ const uu = Math.round(targetU.dot(uAxis));
2379
+ const uvCross = Math.round(targetU.dot(vAxis));
2380
+ const vu = Math.round(targetV.dot(uAxis));
2381
+ const vv = Math.round(targetV.dot(vAxis));
2382
+ for (let corner = 0; corner < 4; corner++) {
2383
+ const index = faceIndex * 4 + corner;
2384
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2385
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2386
+ const lockedU = uu * u + uvCross * v + 0.5;
2387
+ const lockedV = vu * u + vv * v + 0.5;
2388
+ uv.setXY(
2389
+ index,
2390
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2391
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2392
+ );
2393
+ }
2394
+ }
2395
+ uv.needsUpdate = true;
2396
+ }
2131
2397
  static async getAtlas(model) {
2132
2398
  const keyStr = model.key.serialize();
2133
2399
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -2199,12 +2465,11 @@ var UVMapper = class {
2199
2465
  return [tl, tr, bl, br];
2200
2466
  }
2201
2467
  static async createAtlas(originalModel) {
2202
- var _a;
2203
2468
  const textureMap = {};
2204
2469
  const metaMap = {};
2205
2470
  const model = { ...originalModel };
2206
2471
  const isItemModel = !("elements" in model);
2207
- console.debug(p6, "Creating Atlas for", model.key);
2472
+ console.debug(p5, "Creating Atlas for", model.key);
2208
2473
  if (model.textures) {
2209
2474
  const promises = [];
2210
2475
  const uniqueTextureNames = [];
@@ -2218,7 +2483,7 @@ var UVMapper = class {
2218
2483
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2219
2484
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2220
2485
  if (!asset) {
2221
- console.warn(p6, "Missing texture", assetKey);
2486
+ console.warn(p5, "Missing texture", assetKey);
2222
2487
  return;
2223
2488
  }
2224
2489
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2230,7 +2495,7 @@ var UVMapper = class {
2230
2495
  }
2231
2496
  await Promise.all(promises);
2232
2497
  const textureCount = uniqueTextureNames.length;
2233
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2498
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2234
2499
  this.fillMissingTextureKeys(model.textures, textureMap);
2235
2500
  this.fillMissingTextureKeys(model.textures, metaMap);
2236
2501
  const sizes = {};
@@ -2250,7 +2515,7 @@ var UVMapper = class {
2250
2515
  this.fillMissingTextureKeys(model.textures, sizes);
2251
2516
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2252
2517
  const size = Math.ceil(s * maxWidth);
2253
- console.debug(p6, "Atlas size:", size);
2518
+ console.debug(p5, "Atlas size:", size);
2254
2519
  const squaredSize = size * size;
2255
2520
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2256
2521
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2279,16 +2544,15 @@ var UVMapper = class {
2279
2544
  if (texture.animated) {
2280
2545
  hasAnimation = true;
2281
2546
  const meta = metaMap[textureKey];
2282
- const frameTime = ((_a = meta == null ? void 0 : meta.animation) == null ? void 0 : _a.frametime) ?? 1;
2547
+ const frameTime = meta?.animation?.frametime ?? 1;
2283
2548
  console.log(meta);
2284
2549
  console.log(frameTime);
2285
2550
  let t = 0;
2286
2551
  let f = 0;
2287
2552
  animatorFunctions[textureKey] = () => {
2288
- var _a2;
2289
2553
  if (t++ >= frameTime) {
2290
2554
  t = 0;
2291
- const frames = (_a2 = meta == null ? void 0 : meta.animation) == null ? void 0 : _a2.frames;
2555
+ const frames = meta?.animation?.frames;
2292
2556
  const frame = frames ? frames[f] : f;
2293
2557
  image.putData(texture.getFrameSectionData(frame), x, y, 0, 0, maxWidth, maxWidth);
2294
2558
  f++;
@@ -2306,10 +2570,10 @@ var UVMapper = class {
2306
2570
  }
2307
2571
  }
2308
2572
  const atlasImageData = image.toDataURL();
2309
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2573
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2310
2574
  this.fillMissingTextureKeys(model.textures, positions);
2311
2575
  if (isItemModel) {
2312
- console.debug(p6, "Generating item model for", model);
2576
+ console.debug(p5, "Generating item model for", model);
2313
2577
  model.elements = [];
2314
2578
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2315
2579
  const textureImage = textureMap[layerName];
@@ -2317,7 +2581,7 @@ var UVMapper = class {
2317
2581
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2318
2582
  }
2319
2583
  }
2320
- console.debug(p6, "Item model elements", model.elements);
2584
+ console.debug(p5, "Item model elements", model.elements);
2321
2585
  }
2322
2586
  if (!model.elements) {
2323
2587
  }
@@ -2335,17 +2599,13 @@ var UVMapper = class {
2335
2599
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2336
2600
  continue;
2337
2601
  }
2602
+ if (!face.texture) continue;
2338
2603
  if (!face.uv) {
2339
2604
  face.uv = this.getFallbackUv(element, faceName);
2340
2605
  }
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
- }
2606
+ const faceTexture = face.texture.substr(1);
2607
+ const texPosition = positions[faceTexture] || [0, 0];
2608
+ const texSize = sizes[faceTexture] || [16, 16];
2349
2609
  let texPosV = new import_three8.Vector2(texPosition[0], texPosition[1]);
2350
2610
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2351
2611
  tl.add(texPosV);
@@ -2377,7 +2637,7 @@ var UVMapper = class {
2377
2637
  hasTransparency
2378
2638
  );
2379
2639
  } else {
2380
- console.warn(p6, "Model does not have any textures", model);
2640
+ console.warn(p5, "Model does not have any textures", model);
2381
2641
  }
2382
2642
  return void 0;
2383
2643
  }
@@ -2515,17 +2775,20 @@ function shutdown() {
2515
2775
  }
2516
2776
 
2517
2777
  // src/assets/Entities.ts
2518
- var import_typescript_memoize3 = require("typescript-memoize");
2519
2778
  var Entities = class {
2520
2779
  static async getBlockEntityModels() {
2521
2780
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2522
2781
  console.log(key);
2523
- return AssetLoader.get(key, "json" /* JSON */);
2782
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2783
+ return AssetLoader.get(key, "json" /* JSON */);
2784
+ });
2524
2785
  }
2525
2786
  static async getEntityModels() {
2526
2787
  const key = AssetKey.parse("models", "minerender:entityModels");
2527
2788
  console.log(key);
2528
- return AssetLoader.get(key, "json" /* JSON */);
2789
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2790
+ return AssetLoader.get(key, "json" /* JSON */);
2791
+ });
2529
2792
  }
2530
2793
  // BlockEntity names are hardcoded
2531
2794
  static async getBlockList() {
@@ -2571,12 +2834,6 @@ var Entities = class {
2571
2834
  };
2572
2835
  }
2573
2836
  };
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
2837
  var EntityModels = class {
2581
2838
  };
2582
2839
  var BlockEntityModels = class {
@@ -2640,18 +2897,26 @@ var MineRenderError = class _MineRenderError extends Error {
2640
2897
  };
2641
2898
 
2642
2899
  // 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 {
2900
+ var import_ts_deepmerge3 = __toESM(require_dist());
2901
+ var p6 = prefix("SceneObject");
2902
+ var SceneObject = class _SceneObject extends import_three9.Object3D {
2646
2903
  constructor(options) {
2647
2904
  super();
2648
2905
  this.isSceneObject = true;
2649
2906
  this.materialCallbacks = {};
2650
2907
  this._isInstanced = false;
2651
2908
  this._instanceCounter = 0;
2652
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2909
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2653
2910
  console.log("SceneObject options", this.options);
2654
2911
  }
2912
+ static {
2913
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2914
+ instanceMeshes: true,
2915
+ maxInstanceCount: 50,
2916
+ mergeMeshes: true,
2917
+ wireframe: false
2918
+ });
2919
+ }
2655
2920
  set scene(scene) {
2656
2921
  if (!!this._scene) throw new MineRenderError("Scene already set");
2657
2922
  this._scene = scene;
@@ -2743,6 +3008,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2743
3008
  }
2744
3009
  createInstancedMesh(name, geometry, material, count) {
2745
3010
  const mesh = new import_three9.InstancedMesh(geometry, material, count);
3011
+ mesh.count = 0;
2746
3012
  if (name) {
2747
3013
  mesh.name = `mesh:${name}`;
2748
3014
  }
@@ -2820,9 +3086,13 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2820
3086
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2821
3087
  const i = this._instanceCounter++;
2822
3088
  this.setMatrixAt(i, new import_three9.Matrix4());
2823
- console.debug(p7, "nextInstance " + i);
3089
+ const mesh = this.children[0];
3090
+ if (mesh && isInstancedMesh(mesh)) {
3091
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
3092
+ }
3093
+ console.debug(p6, "nextInstance " + i);
2824
3094
  if (i === this.options.maxInstanceCount) {
2825
- console.warn(p7, "Max instance count reached for " + this);
3095
+ console.warn(p6, "Max instance count reached for " + this);
2826
3096
  }
2827
3097
  if (this.scene) {
2828
3098
  this.scene.stats.instanceCount++;
@@ -2993,34 +3263,29 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2993
3263
  this.notifyDirty();
2994
3264
  }
2995
3265
  removeFromScene() {
2996
- var _a;
2997
- (_a = this._scene) == null ? void 0 : _a.remove(this);
3266
+ this._scene?.remove(this);
2998
3267
  this.notifyDirty();
2999
3268
  }
3000
3269
  //</editor-fold>
3001
3270
  };
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
3271
  function isSceneObject(obj) {
3010
3272
  return obj.isSceneObject;
3011
3273
  }
3012
3274
 
3013
3275
  // src/entity/scene/EntityObject.ts
3014
- var import_ts_deepmerge5 = __toESM(require_dist());
3276
+ var import_ts_deepmerge4 = __toESM(require_dist());
3015
3277
  var import_three11 = require("three");
3016
- var THREE2 = __toESM(require("three"));
3278
+ var THREE3 = __toESM(require("three"));
3017
3279
  var EntityObject = class extends SceneObject {
3018
3280
  constructor(entity, options) {
3019
3281
  super();
3020
3282
  this.entity = entity;
3021
3283
  this.isEntityObject = true;
3022
3284
  this.meshesCreated = false;
3023
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3285
+ this.options = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3286
+ }
3287
+ static {
3288
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3024
3289
  }
3025
3290
  async init() {
3026
3291
  this.createMeshes();
@@ -3029,17 +3294,19 @@ var EntityObject = class extends SceneObject {
3029
3294
  dispose() {
3030
3295
  super.dispose();
3031
3296
  }
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,
3297
+ get textureKey() {
3298
+ return new AssetKey(
3299
+ this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
3036
3300
  this.entity.key.path,
3037
3301
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
3038
3302
  "textures",
3039
3303
  "entity",
3040
3304
  "assets",
3041
3305
  ".png"
3042
- ));
3306
+ );
3307
+ }
3308
+ async loadTextures() {
3309
+ this.imageData = await ModelTextures.get(this.textureKey);
3043
3310
  }
3044
3311
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
3045
3312
  createMeshes(force = false) {
@@ -3058,8 +3325,8 @@ var EntityObject = class extends SceneObject {
3058
3325
  const l = cube.maxZ - cube.minZ;
3059
3326
  const uv = texture.toUvArray(w, h, l);
3060
3327
  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));
3328
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3329
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
3063
3330
  applyModelPartRotation(part, cubeGeo);
3064
3331
  const mesh = this.createMesh(partName, cubeGeo, mat);
3065
3332
  partAnchor.add(mesh);
@@ -3072,24 +3339,25 @@ var EntityObject = class extends SceneObject {
3072
3339
  this.meshesCreated = true;
3073
3340
  }
3074
3341
  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
- });
3089
- }
3342
+ const assetKeyStr = this.textureKey.serialize();
3343
+ const keyStr = `entity:${assetKeyStr}`;
3344
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3345
+ if (!mat) {
3346
+ const pending = this.loadTextures();
3347
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3348
+ await pending;
3349
+ if (!this.imageData) return;
3350
+ const canvas = this.imageData.data.canvas;
3351
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3352
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3353
+ this.imageData = void 0;
3354
+ }
3355
+ this.iterateAllMeshes((mesh) => {
3356
+ mesh.material = mat;
3357
+ });
3358
+ this.notifyDirty();
3090
3359
  }
3091
3360
  };
3092
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3093
3361
  function isEntityObject(obj) {
3094
3362
  return obj.isEntityObject;
3095
3363
  }
@@ -3101,7 +3369,7 @@ var GuiObject = class extends SceneObject {
3101
3369
 
3102
3370
  // src/inspector/SceneInspector.ts
3103
3371
  var import_three12 = require("three");
3104
- var p8 = prefix("SceneInspector");
3372
+ var p7 = prefix("SceneInspector");
3105
3373
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3106
3374
  var SceneInspector = class {
3107
3375
  constructor(renderer) {
@@ -3130,8 +3398,7 @@ var SceneInspector = class {
3130
3398
  return out;
3131
3399
  }
3132
3400
  onClick(event) {
3133
- var _a;
3134
- if (((_a = event.target) == null ? void 0 : _a.nodeName) !== "CANVAS") return;
3401
+ if (event.target?.nodeName !== "CANVAS") return;
3135
3402
  if (!event.ctrlKey) return;
3136
3403
  setTimeout(() => {
3137
3404
  this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
@@ -3171,7 +3438,7 @@ var SceneInspector = class {
3171
3438
  }
3172
3439
  selectObject(targetObject, targetIntersection) {
3173
3440
  this.selectedObject = targetObject;
3174
- console.log(p8, "selected", targetObject);
3441
+ console.log(p7, "selected", targetObject);
3175
3442
  this.redraw(targetObject, targetIntersection);
3176
3443
  }
3177
3444
  redraw(targetObject, targetIntersection) {
@@ -3469,7 +3736,7 @@ var SceneStatsDisplay = class {
3469
3736
  };
3470
3737
 
3471
3738
  // src/instance/InstanceManager.ts
3472
- var p9 = prefix("InstanceManager");
3739
+ var p8 = prefix("InstanceManager");
3473
3740
  var InstanceManager = class {
3474
3741
  constructor() {
3475
3742
  this.isInstanceManager = true;
@@ -3477,7 +3744,7 @@ var InstanceManager = class {
3477
3744
  }
3478
3745
  async get(key) {
3479
3746
  if (key in this.instanceCache) {
3480
- console.debug(p9, "key in cache", key);
3747
+ console.debug(p8, "key in cache", key);
3481
3748
  return (await this.instanceCache[key]).nextInstance();
3482
3749
  }
3483
3750
  return void 0;
@@ -3486,13 +3753,17 @@ var InstanceManager = class {
3486
3753
  if (key in this.instanceCache) {
3487
3754
  return await this.get(key);
3488
3755
  }
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];
3756
+ console.debug(p8, "key not in cache", key);
3757
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3758
+ this.instanceCache[key] = pending;
3759
+ try {
3760
+ return await pending;
3761
+ } catch (error) {
3762
+ if (this.instanceCache[key] === pending) {
3763
+ delete this.instanceCache[key];
3764
+ }
3765
+ throw error;
3766
+ }
3496
3767
  }
3497
3768
  reset() {
3498
3769
  for (let instanceCacheKey in this.instanceCache) {
@@ -4081,26 +4352,29 @@ function computeMorphedAttributes(object) {
4081
4352
  }
4082
4353
 
4083
4354
  // 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 {
4355
+ var import_ts_deepmerge5 = __toESM(require_dist());
4356
+ var p9 = prefix("ModelObject");
4357
+ var ModelObject = class _ModelObject extends SceneObject {
4087
4358
  constructor(originalModel, options) {
4088
4359
  super(options);
4089
4360
  this.originalModel = originalModel;
4090
4361
  this.isModelObject = true;
4091
4362
  this.meshesCreated = false;
4092
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4363
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4364
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
4093
4365
  console.log("ModelObject options", this.options);
4094
4366
  }
4367
+ static {
4368
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4369
+ }
4095
4370
  async init() {
4096
4371
  await this.loadTextures();
4097
4372
  this.createMeshes();
4098
4373
  this.applyTextures();
4099
4374
  }
4100
4375
  dispose() {
4101
- var _a;
4102
4376
  super.dispose();
4103
- (_a = this.atlas) == null ? void 0 : _a.dispose();
4377
+ this.atlas?.dispose();
4104
4378
  }
4105
4379
  get textureAtlas() {
4106
4380
  return this.atlas;
@@ -4110,14 +4384,30 @@ var _ModelObject = class _ModelObject extends SceneObject {
4110
4384
  this.atlas = await UVMapper.getAtlas(this.originalModel);
4111
4385
  }
4112
4386
  createMeshes(force = false) {
4113
- var _a;
4114
4387
  if (this.meshesCreated && !force) return;
4115
4388
  const mat = Materials.MISSING_TEXTURE;
4116
4389
  let allGeos = [];
4117
4390
  if (this.atlas) {
4118
4391
  if (this.atlas.model.elements) {
4119
- (_a = this.atlas.model.elements) == null ? void 0 : _a.forEach((el) => {
4392
+ this.atlas.model.elements?.forEach((el) => {
4120
4393
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4394
+ if (this.options.uvLockRotation) {
4395
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three15.Euler(...this.options.uvLockRotation));
4396
+ }
4397
+ if (this.options.tints) {
4398
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4399
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4400
+ const tintIndex = el.faces[faceName]?.tintindex;
4401
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4402
+ const tint = this.options.tints[tintIndex];
4403
+ if (tint === void 0) continue;
4404
+ const color = new import_three15.Color(tint);
4405
+ for (let vertex = 0; vertex < 4; vertex++) {
4406
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4407
+ }
4408
+ }
4409
+ elGeo.setAttribute("color", new import_three15.BufferAttribute(colors, 3));
4410
+ }
4121
4411
  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
4412
  elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4123
4413
  if (el.rotation) {
@@ -4134,10 +4424,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
4134
4424
  }
4135
4425
  });
4136
4426
  } else {
4137
- console.debug(p10, this.atlas.model, "has no elements");
4427
+ console.debug(p9, this.atlas.model, "has no elements");
4138
4428
  }
4139
4429
  } else {
4140
- console.debug(p10, "Missing atlas for", this);
4430
+ console.debug(p9, "Missing atlas for", this);
4141
4431
  }
4142
4432
  if (this.options.mergeMeshes) {
4143
4433
  let combinedGeo;
@@ -4174,6 +4464,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4174
4464
  /*TODO: get this from render options*/
4175
4465
  );
4176
4466
  this.iterateAllMeshes((mesh) => {
4467
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4177
4468
  mesh.material = mat;
4178
4469
  });
4179
4470
  if (this.atlas.hasAnimation) {
@@ -4189,17 +4480,25 @@ var _ModelObject = class _ModelObject extends SceneObject {
4189
4480
  }
4190
4481
  }
4191
4482
  };
4192
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4193
- var ModelObject = _ModelObject;
4194
4483
  function isModelObject(obj) {
4195
4484
  return obj.isModelObject;
4196
4485
  }
4197
4486
 
4198
4487
  // src/model/block/scene/BlockObject.ts
4199
- var import_ts_deepmerge7 = __toESM(require_dist());
4488
+ var import_ts_deepmerge6 = __toESM(require_dist());
4200
4489
  var import_three16 = require("three");
4201
- var p11 = prefix("BlockObject");
4202
- var _BlockObject = class _BlockObject extends SceneObject {
4490
+ var p10 = prefix("BlockObject");
4491
+ function matchesCondition(condition, state) {
4492
+ return Object.entries(condition).every(([key, value]) => {
4493
+ if (Array.isArray(value)) {
4494
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4495
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4496
+ return false;
4497
+ }
4498
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4499
+ });
4500
+ }
4501
+ var BlockObject = class _BlockObject extends SceneObject {
4203
4502
  constructor(blockState, options) {
4204
4503
  super(options);
4205
4504
  this.blockState = blockState;
@@ -4212,11 +4511,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4212
4511
  this._instanceModel = [];
4213
4512
  this._variants = [];
4214
4513
  this._models = [];
4215
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4514
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4515
+ }
4516
+ static {
4517
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4518
+ applyDefaultState: true
4519
+ });
4216
4520
  }
4217
4521
  async init() {
4218
4522
  if (this.options.applyDefaultState) {
4219
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4523
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4220
4524
  if (defaultState && Object.keys(defaultState).length > 0) {
4221
4525
  const state = {};
4222
4526
  for (let k in defaultState) {
@@ -4227,15 +4531,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4227
4531
  if (this.blockState.variants) {
4228
4532
  await this.setState(Object.keys(this.blockState.variants)[0]);
4229
4533
  } 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
- }
4534
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4535
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4536
+ await this.setState(state);
4239
4537
  }
4240
4538
  }
4241
4539
  } else {
@@ -4292,55 +4590,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4292
4590
  } else if (this.blockState.multipart) {
4293
4591
  for (let part of this.blockState.multipart) {
4294
4592
  if (!part.apply) {
4295
- console.debug(p11, "Missing apply for blockState part", part);
4593
+ console.debug(p10, "Missing apply for blockState part", part);
4296
4594
  continue;
4297
4595
  }
4298
- if (!part.when) {
4596
+ if (!part.when || matchesCondition(part.when, state)) {
4299
4597
  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
4598
  }
4345
4599
  }
4346
4600
  }
@@ -4370,11 +4624,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4370
4624
  }
4371
4625
  }
4372
4626
  getSingleVariant(variants) {
4373
- if (Array.isArray(variants)) {
4374
- return variants[0];
4375
- } else {
4376
- return variants;
4377
- }
4627
+ if (!Array.isArray(variants)) return variants;
4628
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4629
+ const total = variants.reduce((sum, variant) => {
4630
+ const weight = variant.weight ?? 1;
4631
+ if (!Number.isInteger(weight) || weight < 1) {
4632
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4633
+ }
4634
+ return sum + weight;
4635
+ }, 0);
4636
+ let choice = Math.random() * total;
4637
+ for (const variant of variants) {
4638
+ choice -= variant.weight ?? 1;
4639
+ if (choice < 0) return variant;
4640
+ }
4641
+ return variants[variants.length - 1];
4378
4642
  }
4379
4643
  // @deprecated
4380
4644
  async createAVariant(variants, instanceInfo) {
@@ -4382,28 +4646,24 @@ var _BlockObject = class _BlockObject extends SceneObject {
4382
4646
  await this.createVariant(variant);
4383
4647
  }
4384
4648
  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);
4649
+ const rotation = new import_three16.Euler();
4392
4650
  if (typeof variant.x !== "undefined") {
4393
4651
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4394
4652
  }
4395
4653
  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
- }
4654
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4655
+ }
4656
+ const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4657
+ const options = {
4658
+ ...this.options,
4659
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4660
+ };
4661
+ const obj = await this.scene.addModel(model, options);
4662
+ if (isInstanceReference(obj) || obj.isInstanced) {
4663
+ this._isInstanced = true;
4664
+ this._instanceCounter = 1;
4401
4665
  }
4402
4666
  obj.setRotation(rotation);
4403
- setTimeout(() => {
4404
- obj.setRotation(rotation);
4405
- }, 150);
4406
- console.log(obj);
4407
4667
  return obj;
4408
4668
  }
4409
4669
  async resetState() {
@@ -4493,18 +4753,15 @@ var _BlockObject = class _BlockObject extends SceneObject {
4493
4753
  }
4494
4754
  }
4495
4755
  setPosition(position) {
4496
- super.setPosition(position);
4756
+ this.position.copy(position);
4497
4757
  for (let model of this._models) {
4498
4758
  model.setPosition(position);
4499
4759
  }
4760
+ this.notifyDirty();
4500
4761
  }
4501
4762
  //TODO: should override rotation + scale methods
4502
4763
  //TODO
4503
4764
  };
4504
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4505
- applyDefaultState: true
4506
- });
4507
- var BlockObject = _BlockObject;
4508
4765
  function isBlockObject(obj) {
4509
4766
  return obj.isBlockObject;
4510
4767
  }
@@ -4529,11 +4786,10 @@ var StructureParser = class {
4529
4786
  throw new MineRenderError("Structure does not have palette(s)");
4530
4787
  }
4531
4788
  const blocks = nbt.blocks.value.value.map((block) => {
4532
- var _a;
4533
4789
  const state = palette.value.value[block.state.value];
4534
4790
  if (state.Name.value === "minecraft:air") return void 0;
4535
4791
  const props = {};
4536
- for (let k in (_a = state.Properties) == null ? void 0 : _a.value) {
4792
+ for (let k in state.Properties?.value) {
4537
4793
  props[k] = state.Properties.value[k].value;
4538
4794
  }
4539
4795
  return {
@@ -4552,7 +4808,7 @@ var StructureParser = class {
4552
4808
 
4553
4809
  // src/renderer/MineRenderScene.ts
4554
4810
  var import_three17 = require("three");
4555
- var import_ts_deepmerge9 = __toESM(require_dist());
4811
+ var import_ts_deepmerge8 = __toESM(require_dist());
4556
4812
 
4557
4813
  // src/skin/SkinPart.ts
4558
4814
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5283,7 +5539,7 @@ var slimSkinGeometries = {
5283
5539
  };
5284
5540
 
5285
5541
  // src/skin/scene/SkinObject.ts
5286
- var import_ts_deepmerge8 = __toESM(require_dist());
5542
+ var import_ts_deepmerge7 = __toESM(require_dist());
5287
5543
  var SkinObject = class extends SceneObject {
5288
5544
  constructor(options) {
5289
5545
  super();
@@ -5291,7 +5547,7 @@ var SkinObject = class extends SceneObject {
5291
5547
  this.legacy = false;
5292
5548
  this.skinTextureWidth = 64;
5293
5549
  this.skinTextureHeight = 64;
5294
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5550
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5295
5551
  }
5296
5552
  async init() {
5297
5553
  this.createMeshes();
@@ -5395,7 +5651,7 @@ var SkinObject = class extends SceneObject {
5395
5651
  };
5396
5652
 
5397
5653
  // src/renderer/MineRenderScene.ts
5398
- var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5654
+ var MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5399
5655
  constructor(options) {
5400
5656
  super();
5401
5657
  this.isMineRenderScene = true;
@@ -5404,12 +5660,14 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5404
5660
  this.dirty = true;
5405
5661
  this.observedObjects = /* @__PURE__ */ new Set();
5406
5662
  this.onObjectChange = (event) => {
5407
- var _a;
5408
- if (((_a = event.target) == null ? void 0 : _a.parent) === this) {
5663
+ if (event.target?.parent === this) {
5409
5664
  this.dirty = true;
5410
5665
  }
5411
5666
  };
5412
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5667
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5668
+ }
5669
+ static {
5670
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5413
5671
  }
5414
5672
  add(...objects) {
5415
5673
  for (const object of objects) {
@@ -5417,7 +5675,7 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5417
5675
  try {
5418
5676
  super.add(object);
5419
5677
  } finally {
5420
- if ((object == null ? void 0 : object.isObject3D) && object !== this) {
5678
+ if (object?.isObject3D && object !== this) {
5421
5679
  this.updateObjectRegistration(object, object.parent === this);
5422
5680
  }
5423
5681
  }
@@ -5460,15 +5718,20 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5460
5718
  return this.add(...object);
5461
5719
  }
5462
5720
  async addSceneObject(asset, objectSupplier, _options, parent = this) {
5463
- var _a, _b;
5464
5721
  console.log("addSceneObject", asset);
5465
5722
  console.log("parent", parent);
5466
5723
  console.log(_options);
5467
5724
  this.dirty = true;
5468
5725
  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") {
5726
+ if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5470
5727
  console.log("instanceMeshes + key");
5471
- const key = asset.key.serialize();
5728
+ let key = asset.key.serialize();
5729
+ if (isModelObject(obj)) {
5730
+ const { uvLockRotation, tints } = obj.options;
5731
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
5732
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
5733
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
5734
+ }
5472
5735
  return this.instanceManager.getOrCreate(key, async () => {
5473
5736
  obj.scene = this;
5474
5737
  await obj.init();
@@ -5506,763 +5769,310 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5506
5769
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5507
5770
  }
5508
5771
  };
5509
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5510
- var MineRenderScene = _MineRenderScene;
5511
5772
  function isMineRenderScene(obj) {
5512
5773
  return obj.isMineRenderScene;
5513
5774
  }
5514
5775
 
5515
5776
  // src/renderer/Renderer.ts
5516
- var import_three18 = require("three");
5517
- var import_ts_deepmerge10 = __toESM(require_dist());
5777
+ var import_three19 = require("three");
5778
+ var import_ts_deepmerge9 = __toESM(require_dist());
5518
5779
  var import_stats = __toESM(require("stats.js"));
5519
5780
  var import_postprocessing = require("postprocessing");
5520
- var _Renderer = class _Renderer {
5521
- constructor(options) {
5522
- this._dirty = true;
5523
- this._animationTimer = void 0;
5524
- this._animationFrame = void 0;
5525
- this._resizeListener = void 0;
5526
- this._disposed = false;
5527
- this._debugHelpers = [];
5528
- this._eventDispatchers = /* @__PURE__ */ new Map();
5529
- this._changeListener = () => {
5530
- this._dirty = true;
5781
+
5782
+ // src/three/OrbitControls.js
5783
+ var import_three18 = require("three");
5784
+ var _changeEvent = { type: "change" };
5785
+ var _startEvent = { type: "start" };
5786
+ var _endEvent = { type: "end" };
5787
+ var OrbitControls = class extends import_three18.EventDispatcher {
5788
+ constructor(object, domElement) {
5789
+ super();
5790
+ if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5791
+ if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5792
+ this.object = object;
5793
+ this.domElement = domElement;
5794
+ this.domElement.style.touchAction = "none";
5795
+ this.enabled = true;
5796
+ this.target = new import_three18.Vector3();
5797
+ this.minDistance = 0;
5798
+ this.maxDistance = Infinity;
5799
+ this.minZoom = 0;
5800
+ this.maxZoom = Infinity;
5801
+ this.minPolarAngle = 0;
5802
+ this.maxPolarAngle = Math.PI;
5803
+ this.minAzimuthAngle = -Infinity;
5804
+ this.maxAzimuthAngle = Infinity;
5805
+ this.enableDamping = false;
5806
+ this.dampingFactor = 0.05;
5807
+ this.enableZoom = true;
5808
+ this.zoomSpeed = 1;
5809
+ this.enableRotate = true;
5810
+ this.rotateSpeed = 1;
5811
+ this.enablePan = true;
5812
+ this.panSpeed = 1;
5813
+ this.screenSpacePanning = true;
5814
+ this.keyPanSpeed = 7;
5815
+ this.autoRotate = false;
5816
+ this.autoRotateSpeed = 2;
5817
+ this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5818
+ this.mouseButtons = { LEFT: import_three18.MOUSE.ROTATE, MIDDLE: import_three18.MOUSE.DOLLY, RIGHT: import_three18.MOUSE.PAN };
5819
+ this.touches = { ONE: import_three18.TOUCH.ROTATE, TWO: import_three18.TOUCH.DOLLY_PAN };
5820
+ this.target0 = this.target.clone();
5821
+ this.position0 = this.object.position.clone();
5822
+ this.zoom0 = this.object.zoom;
5823
+ this._domElementKeyEvents = null;
5824
+ this.getPolarAngle = function() {
5825
+ return spherical.phi;
5531
5826
  };
5532
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
5533
- this._animationLoop = this.animate.bind(this);
5534
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
5535
- this._scene = this.createScene();
5536
- this._camera = this.createCamera();
5537
- this._renderer = this.createRenderer();
5538
- this._composer = this.createComposer();
5539
- if (this.options.render.stats) {
5540
- this._stats = new import_stats.default();
5541
- document.body.appendChild(this._stats.dom);
5542
- }
5543
- this.init();
5544
- }
5545
- //<editor-fold desc="INIT">
5546
- createScene() {
5547
- return new MineRenderScene();
5548
- }
5549
- createCamera() {
5550
- switch (this.options.camera.type) {
5551
- case "perspective":
5552
- default:
5553
- return new import_three18.PerspectiveCamera(
5554
- this.options.camera.perspective.fov,
5555
- this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
5556
- this.options.camera.near,
5557
- this.options.camera.far
5558
- );
5559
- case "orthographic":
5560
- return new import_three18.OrthographicCamera(
5561
- this.options.camera.orthographic.left ?? this.viewWidth / -2,
5562
- this.options.camera.orthographic.right ?? this.viewWidth / 2,
5563
- this.options.camera.orthographic.top ?? this.viewHeight / 2,
5564
- this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
5565
- this.options.camera.near,
5566
- this.options.camera.far
5567
- );
5827
+ this.getAzimuthalAngle = function() {
5828
+ return spherical.theta;
5829
+ };
5830
+ this.getDistance = function() {
5831
+ return this.object.position.distanceTo(this.target);
5832
+ };
5833
+ this.saveState = function() {
5834
+ scope.target0.copy(scope.target);
5835
+ scope.position0.copy(scope.object.position);
5836
+ scope.zoom0 = scope.object.zoom;
5837
+ };
5838
+ this.reset = function() {
5839
+ scope.target.copy(scope.target0);
5840
+ scope.object.position.copy(scope.position0);
5841
+ scope.object.zoom = scope.zoom0;
5842
+ scope.object.updateProjectionMatrix();
5843
+ scope.dispatchEvent(_changeEvent);
5844
+ scope.update();
5845
+ state = STATE.NONE;
5846
+ };
5847
+ this.update = function() {
5848
+ const offset = new import_three18.Vector3();
5849
+ const quat = new import_three18.Quaternion().setFromUnitVectors(object.up, new import_three18.Vector3(0, 1, 0));
5850
+ const quatInverse = quat.clone().invert();
5851
+ const lastPosition = new import_three18.Vector3();
5852
+ const lastQuaternion = new import_three18.Quaternion();
5853
+ const twoPI = 2 * Math.PI;
5854
+ return function update() {
5855
+ const position = scope.object.position;
5856
+ offset.copy(position).sub(scope.target);
5857
+ offset.applyQuaternion(quat);
5858
+ spherical.setFromVector3(offset);
5859
+ if (scope.autoRotate && state === STATE.NONE) {
5860
+ rotateLeft(getAutoRotationAngle());
5861
+ }
5862
+ if (scope.enableDamping) {
5863
+ spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5864
+ spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5865
+ } else {
5866
+ spherical.theta += sphericalDelta.theta;
5867
+ spherical.phi += sphericalDelta.phi;
5868
+ }
5869
+ let min = scope.minAzimuthAngle;
5870
+ let max = scope.maxAzimuthAngle;
5871
+ if (isFinite(min) && isFinite(max)) {
5872
+ if (min < -Math.PI) min += twoPI;
5873
+ else if (min > Math.PI) min -= twoPI;
5874
+ if (max < -Math.PI) max += twoPI;
5875
+ else if (max > Math.PI) max -= twoPI;
5876
+ if (min <= max) {
5877
+ spherical.theta = Math.max(min, Math.min(max, spherical.theta));
5878
+ } else {
5879
+ spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
5880
+ }
5881
+ }
5882
+ spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5883
+ spherical.makeSafe();
5884
+ spherical.radius *= scale;
5885
+ spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5886
+ if (scope.enableDamping === true) {
5887
+ scope.target.addScaledVector(panOffset, scope.dampingFactor);
5888
+ } else {
5889
+ scope.target.add(panOffset);
5890
+ }
5891
+ offset.setFromSpherical(spherical);
5892
+ offset.applyQuaternion(quatInverse);
5893
+ position.copy(scope.target).add(offset);
5894
+ scope.object.lookAt(scope.target);
5895
+ if (scope.enableDamping === true) {
5896
+ sphericalDelta.theta *= 1 - scope.dampingFactor;
5897
+ sphericalDelta.phi *= 1 - scope.dampingFactor;
5898
+ panOffset.multiplyScalar(1 - scope.dampingFactor);
5899
+ } else {
5900
+ sphericalDelta.set(0, 0, 0);
5901
+ panOffset.set(0, 0, 0);
5902
+ }
5903
+ scale = 1;
5904
+ if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5905
+ scope.dispatchEvent(_changeEvent);
5906
+ lastPosition.copy(scope.object.position);
5907
+ lastQuaternion.copy(scope.object.quaternion);
5908
+ zoomChanged = false;
5909
+ return true;
5910
+ }
5911
+ return false;
5912
+ };
5913
+ }();
5914
+ this.dispose = function() {
5915
+ scope.domElement.removeEventListener("contextmenu", onContextMenu);
5916
+ scope.domElement.removeEventListener("pointerdown", onPointerDown);
5917
+ scope.domElement.removeEventListener("pointercancel", onPointerCancel);
5918
+ scope.domElement.removeEventListener("wheel", onMouseWheel);
5919
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
5920
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5921
+ if (scope._domElementKeyEvents !== null) {
5922
+ scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
5923
+ }
5924
+ };
5925
+ const scope = this;
5926
+ const STATE = {
5927
+ NONE: -1,
5928
+ ROTATE: 0,
5929
+ DOLLY: 1,
5930
+ PAN: 2,
5931
+ TOUCH_ROTATE: 3,
5932
+ TOUCH_PAN: 4,
5933
+ TOUCH_DOLLY_PAN: 5,
5934
+ TOUCH_DOLLY_ROTATE: 6
5935
+ };
5936
+ let state = STATE.NONE;
5937
+ const EPS = 1e-6;
5938
+ const spherical = new import_three18.Spherical();
5939
+ const sphericalDelta = new import_three18.Spherical();
5940
+ let scale = 1;
5941
+ const panOffset = new import_three18.Vector3();
5942
+ let zoomChanged = false;
5943
+ const rotateStart = new import_three18.Vector2();
5944
+ const rotateEnd = new import_three18.Vector2();
5945
+ const rotateDelta = new import_three18.Vector2();
5946
+ const panStart = new import_three18.Vector2();
5947
+ const panEnd = new import_three18.Vector2();
5948
+ const panDelta = new import_three18.Vector2();
5949
+ const dollyStart = new import_three18.Vector2();
5950
+ const dollyEnd = new import_three18.Vector2();
5951
+ const dollyDelta = new import_three18.Vector2();
5952
+ const pointers = [];
5953
+ const pointerPositions = {};
5954
+ function getAutoRotationAngle() {
5955
+ return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
5568
5956
  }
5569
- }
5570
- createRenderer() {
5571
- const renderer = new import_three18.WebGLRenderer({
5572
- antialias: this.options.render.antialias,
5573
- alpha: true,
5574
- powerPreference: "high-performance",
5575
- depth: true
5576
- });
5577
- renderer.setClearColor(0, 0);
5578
- renderer.shadowMap.enabled = true;
5579
- renderer.shadowMap.type = import_three18.PCFSoftShadowMap;
5580
- renderer.outputEncoding = import_three18.LinearEncoding;
5581
- renderer.setSize(this.viewWidth, this.viewHeight);
5582
- return renderer;
5583
- }
5584
- createComposer() {
5585
- const composer = new import_postprocessing.EffectComposer(this.renderer);
5586
- if (!this.options.composer.enabled) return composer;
5587
- composer.setSize(this.viewWidth, this.viewHeight);
5588
- composer.addPass(new import_postprocessing.RenderPass(this.scene, this.camera));
5589
- return composer;
5590
- }
5591
- //</editor-fold>
5592
- init() {
5593
- if (this._disposed) return;
5594
- if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
5595
- window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
5957
+ function getZoomScale() {
5958
+ return Math.pow(0.95, scope.zoomSpeed);
5596
5959
  }
5597
- if (this.options.debug.grid) {
5598
- const gridHelper = new import_three18.GridHelper(128, 16);
5599
- this._debugHelpers.push(gridHelper);
5600
- this.scene.add(gridHelper);
5601
- const gridHelper2 = new import_three18.GridHelper(128, 16);
5602
- this._debugHelpers.push(gridHelper2);
5603
- gridHelper2.rotation.x = 90 * (Math.PI / 180);
5604
- this.scene.add(gridHelper2);
5605
- const gridHelper3 = new import_three18.GridHelper(128, 16);
5606
- this._debugHelpers.push(gridHelper3);
5607
- gridHelper3.rotation.z = 90 * (Math.PI / 180);
5608
- this.scene.add(gridHelper3);
5960
+ function rotateLeft(angle) {
5961
+ sphericalDelta.theta -= angle;
5609
5962
  }
5610
- if (this.options.debug.axes) {
5611
- const axesHelper = new import_three18.AxesHelper(64);
5612
- this._debugHelpers.push(axesHelper);
5613
- this.scene.add(axesHelper);
5963
+ function rotateUp(angle) {
5964
+ sphericalDelta.phi -= angle;
5614
5965
  }
5615
- if (this.options.camera.position) {
5616
- if (isVector3(this.options.camera.position)) {
5617
- this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
5618
- } else if (isTripleArray(this.options.camera.position)) {
5619
- this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
5966
+ const panLeft = function() {
5967
+ const v = new import_three18.Vector3();
5968
+ return function panLeft2(distance, objectMatrix) {
5969
+ v.setFromMatrixColumn(objectMatrix, 0);
5970
+ v.multiplyScalar(-distance);
5971
+ panOffset.add(v);
5972
+ };
5973
+ }();
5974
+ const panUp = function() {
5975
+ const v = new import_three18.Vector3();
5976
+ return function panUp2(distance, objectMatrix) {
5977
+ if (scope.screenSpacePanning === true) {
5978
+ v.setFromMatrixColumn(objectMatrix, 1);
5979
+ } else {
5980
+ v.setFromMatrixColumn(objectMatrix, 0);
5981
+ v.crossVectors(scope.object.up, v);
5982
+ }
5983
+ v.multiplyScalar(distance);
5984
+ panOffset.add(v);
5985
+ };
5986
+ }();
5987
+ const pan = function() {
5988
+ const offset = new import_three18.Vector3();
5989
+ return function pan2(deltaX, deltaY) {
5990
+ const element = scope.domElement;
5991
+ if (scope.object.isPerspectiveCamera) {
5992
+ const position = scope.object.position;
5993
+ offset.copy(position).sub(scope.target);
5994
+ let targetDistance = offset.length();
5995
+ targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
5996
+ panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
5997
+ panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
5998
+ } else if (scope.object.isOrthographicCamera) {
5999
+ panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
6000
+ panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
6001
+ } else {
6002
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
6003
+ scope.enablePan = false;
6004
+ }
6005
+ };
6006
+ }();
6007
+ function dollyOut(dollyScale) {
6008
+ if (scope.object.isPerspectiveCamera) {
6009
+ scale /= dollyScale;
6010
+ } else if (scope.object.isOrthographicCamera) {
6011
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
6012
+ scope.object.updateProjectionMatrix();
6013
+ zoomChanged = true;
6014
+ } else {
6015
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6016
+ scope.enableZoom = false;
5620
6017
  }
5621
6018
  }
5622
- if (this.options.camera.lookingAt) {
5623
- if (isVector3(this.options.camera.lookingAt)) {
5624
- this.camera.lookAt(this.options.camera.lookingAt);
5625
- } else if (isTripleArray(this.options.camera.lookingAt)) {
5626
- this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6019
+ function dollyIn(dollyScale) {
6020
+ if (scope.object.isPerspectiveCamera) {
6021
+ scale *= dollyScale;
6022
+ } else if (scope.object.isOrthographicCamera) {
6023
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
6024
+ scope.object.updateProjectionMatrix();
6025
+ zoomChanged = true;
6026
+ } else {
6027
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6028
+ scope.enableZoom = false;
5627
6029
  }
5628
6030
  }
5629
- if (this.options.render.autoResize && !this._resizeListener) {
5630
- this._resizeListener = () => {
5631
- this.resize(this.viewWidth, this.viewHeight);
5632
- };
5633
- window.addEventListener("resize", this._resizeListener);
5634
- }
5635
- }
5636
- get element() {
5637
- return this._element;
5638
- }
5639
- appendTo(element) {
5640
- if (this._disposed) return;
5641
- this._element = element;
5642
- this._element.appendChild(this.renderer.domElement);
5643
- if (this.viewWidth == 0) {
5644
- console.warn("0 element width");
5645
- }
5646
- if (this.viewHeight == 0) {
5647
- console.warn("0 element height");
6031
+ function handleMouseDownRotate(event) {
6032
+ rotateStart.set(event.clientX, event.clientY);
5648
6033
  }
5649
- this.resize(this.viewWidth, this.viewHeight);
5650
- }
5651
- /**
5652
- * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
5653
- * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
5654
- */
5655
- registerEventDispatcher(dispatcher, changeEvent2 = "change") {
5656
- if (this._disposed) return;
5657
- let events = this._eventDispatchers.get(dispatcher);
5658
- if (!events) {
5659
- events = /* @__PURE__ */ new Set();
5660
- this._eventDispatchers.set(dispatcher, events);
6034
+ function handleMouseDownDolly(event) {
6035
+ dollyStart.set(event.clientX, event.clientY);
5661
6036
  }
5662
- if (events.has(changeEvent2)) return;
5663
- events.add(changeEvent2);
5664
- dispatcher.addEventListener(changeEvent2, this._changeListener);
5665
- }
5666
- resize(width, height) {
5667
- if (this._disposed) return;
5668
- if (isPerspectiveCamera(this.camera)) {
5669
- this.camera.aspect = width / height;
5670
- this.camera.updateProjectionMatrix();
5671
- } else if (isOrthographicCamera(this.camera)) {
5672
- this.camera.left = width / -2;
5673
- this.camera.right = width / 2;
5674
- this.camera.top = height / 2;
5675
- this.camera.bottom = height / -2;
5676
- this.camera.updateProjectionMatrix();
6037
+ function handleMouseDownPan(event) {
6038
+ panStart.set(event.clientX, event.clientY);
5677
6039
  }
5678
- this.renderer.setSize(width, height);
5679
- this.composer.setSize(width, height);
5680
- this._dirty = true;
5681
- }
5682
- //<editor-fold desc="RENDER">
5683
- get dirty() {
5684
- return this._dirty || this.scene.dirty;
5685
- }
5686
- set dirty(dirty) {
5687
- this._dirty = dirty;
5688
- this.scene.dirty = dirty;
5689
- }
5690
- start() {
5691
- if (this._disposed) return;
5692
- this.stop();
5693
- this.renderer.setAnimationLoop(this._animationLoop);
5694
- }
5695
- stop() {
5696
- if (this._disposed) return;
5697
- this.renderer.setAnimationLoop(null);
5698
- if (this._animationTimer)
5699
- clearTimeout(this._animationTimer);
5700
- this._animationTimer = void 0;
5701
- if (this._animationFrame)
5702
- cancelAnimationFrame(this._animationFrame);
5703
- this._animationFrame = void 0;
5704
- }
5705
- /**
5706
- * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
5707
- * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
5708
- * controls must be managed by their owners.
5709
- */
5710
- dispose() {
5711
- var _a;
5712
- if (this._disposed) return;
5713
- this.stop();
5714
- this._disposed = true;
5715
- if (this._resizeListener) {
5716
- window.removeEventListener("resize", this._resizeListener);
5717
- this._resizeListener = void 0;
6040
+ function handleMouseMoveRotate(event) {
6041
+ rotateEnd.set(event.clientX, event.clientY);
6042
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6043
+ const element = scope.domElement;
6044
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6045
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6046
+ rotateStart.copy(rotateEnd);
6047
+ scope.update();
5718
6048
  }
5719
- for (const [dispatcher, events] of this._eventDispatchers) {
5720
- for (const event of events) {
5721
- dispatcher.removeEventListener(event, this._changeListener);
6049
+ function handleMouseMoveDolly(event) {
6050
+ dollyEnd.set(event.clientX, event.clientY);
6051
+ dollyDelta.subVectors(dollyEnd, dollyStart);
6052
+ if (dollyDelta.y > 0) {
6053
+ dollyOut(getZoomScale());
6054
+ } else if (dollyDelta.y < 0) {
6055
+ dollyIn(getZoomScale());
5722
6056
  }
6057
+ dollyStart.copy(dollyEnd);
6058
+ scope.update();
5723
6059
  }
5724
- this._eventDispatchers.clear();
5725
- (_a = this._stats) == null ? void 0 : _a.dom.remove();
5726
- this._stats = void 0;
5727
- this.renderer.domElement.remove();
5728
- this._element = void 0;
5729
- this.scene.clear();
5730
- for (const helper of this._debugHelpers) {
5731
- helper.geometry.dispose();
5732
- const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
5733
- for (const material of materials) {
5734
- material.dispose();
5735
- }
6060
+ function handleMouseMovePan(event) {
6061
+ panEnd.set(event.clientX, event.clientY);
6062
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6063
+ pan(panDelta.x, panDelta.y);
6064
+ panStart.copy(panEnd);
6065
+ scope.update();
5736
6066
  }
5737
- this._debugHelpers.length = 0;
5738
- this.composer.dispose();
5739
- this.renderer.dispose();
5740
- this.renderer.forceContextLoss();
5741
- }
5742
- animate(t) {
5743
- if (this._disposed) return;
5744
- if (this._stats) {
5745
- this._stats.begin();
6067
+ function handleMouseUp() {
5746
6068
  }
5747
- if (this.dirty || this.options.render.renderAlways) {
5748
- if (this.options.composer.enabled) {
5749
- this.composer.render();
5750
- } else {
5751
- this.renderer.render(this.scene, this.camera);
6069
+ function handleMouseWheel(event) {
6070
+ if (event.deltaY < 0) {
6071
+ dollyIn(getZoomScale());
6072
+ } else if (event.deltaY > 0) {
6073
+ dollyOut(getZoomScale());
5752
6074
  }
5753
- }
5754
- this.dirty = false;
5755
- if (this._stats) {
5756
- this._stats.end();
5757
- }
5758
- }
5759
- //</editor-fold>
5760
- toImage() {
5761
- return this.renderer.domElement.toDataURL();
5762
- }
5763
- ///
5764
- get attachedToBody() {
5765
- return this.element === document.body;
5766
- }
5767
- get viewWidth() {
5768
- var _a;
5769
- return this.attachedToBody ? window.innerWidth : ((_a = this.element) == null ? void 0 : _a.offsetWidth) || 0;
5770
- }
5771
- get viewHeight() {
5772
- var _a;
5773
- return this.attachedToBody ? window.innerHeight : ((_a = this.element) == null ? void 0 : _a.offsetHeight) || 0;
5774
- }
5775
- get scene() {
5776
- return this._scene;
5777
- }
5778
- get camera() {
5779
- return this._camera;
5780
- }
5781
- get renderer() {
5782
- return this._renderer;
5783
- }
5784
- get composer() {
5785
- return this._composer;
5786
- }
5787
- ///
5788
- };
5789
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
5790
- camera: {
5791
- type: "perspective",
5792
- near: 1,
5793
- far: 5e3,
5794
- perspective: {
5795
- aspect: void 0,
5796
- fov: 50
5797
- },
5798
- orthographic: {
5799
- left: void 0,
5800
- right: void 0,
5801
- top: void 0,
5802
- bottom: void 0
5803
- },
5804
- position: new import_three18.Vector3(50, 50, 50),
5805
- lookingAt: new import_three18.Vector3(0, 0, 0)
5806
- },
5807
- render: {
5808
- fpsLimit: 60,
5809
- stats: false,
5810
- antialias: true,
5811
- shade: true,
5812
- autoResize: true,
5813
- renderAlways: false
5814
- },
5815
- composer: {
5816
- enabled: true
5817
- },
5818
- debug: {
5819
- grid: false,
5820
- axes: false
5821
- }
5822
- });
5823
- var Renderer = _Renderer;
5824
-
5825
- // src/skin/Skins.ts
5826
- var Skins = class {
5827
- //<editor-fold desc="Skins">
5828
- static async fromUuidOrUsername(uuidOrUsername) {
5829
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5830
- return this.fromUuid(uuidOrUsername);
5831
- }
5832
- return this.fromUsername(uuidOrUsername);
5833
- }
5834
- static async fromUuid(uuid) {
5835
- return this.getSkinProxySkinUrl(uuid);
5836
- }
5837
- static async fromUsername(username) {
5838
- return this.usernameToUuid(username).then((uuid) => {
5839
- if (uuid) {
5840
- return this.fromUuid(uuid);
5841
- }
5842
- return void 0;
5843
- });
5844
- }
5845
- static async fromMineSkin(mineskinId) {
5846
- return this.getMineSkin(mineskinId).then((mineskin) => {
5847
- if (mineskin) {
5848
- return mineskin["data"]["texture"]["value"]["urls"]["skins"];
5849
- }
5850
- return void 0;
5851
- });
5852
- }
5853
- //</editor-fold>
5854
- //<editor-fold desc="Capes">
5855
- static async capeFromUuidOrUsername(uuidOrUsername) {
5856
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5857
- return this.capeFromUuid(uuidOrUsername);
5858
- }
5859
- return this.capeFromUsername(uuidOrUsername);
5860
- }
5861
- static async capeFromUuid(uuid) {
5862
- return this.getSkinProxyCapeUrl(uuid);
5863
- }
5864
- static async capeFromUsername(username) {
5865
- return this.usernameToUuid(username).then((uuid) => {
5866
- if (uuid) {
5867
- return this.capeFromUuid(uuid);
5868
- }
5869
- return void 0;
5870
- });
5871
- }
5872
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
5873
- return this.getCapesDev(uuid, capeType).then((cape) => {
5874
- if (cape) {
5875
- return cape == null ? void 0 : cape.stillImageUrl;
5876
- }
5877
- return void 0;
5878
- });
5879
- }
5880
- //</editor-fold>
5881
- //<editor-fold desc="Helpers">
5882
- static async usernameToUuid(username) {
5883
- return this.usernameToUuidSkinProxy(username);
5884
- }
5885
- static async usernameToUuidSkinProxy(username) {
5886
- return Requests.genericRequest({
5887
- baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
5888
- url: "/uuid/" + username
5889
- }).then((res) => {
5890
- if (res.status === 200) {
5891
- return res.data["id"];
5892
- }
5893
- return void 0;
5894
- }).catch((err) => {
5895
- console.warn(err);
5896
- return void 0;
5897
- });
5898
- }
5899
- static async usernameToUuidMineTools(username) {
5900
- return Requests.genericRequest({
5901
- baseURL: "https://api.minetools.eu",
5902
- url: "/uuid/" + username
5903
- }).then((res) => {
5904
- if (res.status === 200) {
5905
- return res.data["id"];
5906
- }
5907
- return void 0;
5908
- }).catch((err) => {
5909
- console.warn(err);
5910
- return void 0;
5911
- });
5912
- }
5913
- static async getProfileFromMinetools(uuid) {
5914
- return Requests.genericRequest({
5915
- baseURL: "https://api.minetools.eu",
5916
- url: "/profile/" + uuid
5917
- }).then((res) => {
5918
- if (res.status === 200) {
5919
- return res.data;
5920
- }
5921
- });
5922
- }
5923
- static async getMineSkin(mineskinId) {
5924
- return Requests.genericRequest({
5925
- baseURL: "https://api.mineskin.org",
5926
- url: "/get/uuid/" + mineskinId
5927
- }).then((res) => {
5928
- if (res.status === 200) {
5929
- return res.data;
5930
- }
5931
- return void 0;
5932
- }).catch((err) => {
5933
- console.warn(err);
5934
- return void 0;
5935
- });
5936
- }
5937
- static async getCapesDev(uuid, type = "all") {
5938
- return Requests.genericRequest({
5939
- baseURL: "https://api.capes.dev",
5940
- url: "/load/" + uuid + "/" + type
5941
- }).then((res) => {
5942
- if (res.status === 200) {
5943
- return res.data;
5944
- }
5945
- return void 0;
5946
- }).catch((err) => {
5947
- console.warn(err);
5948
- return void 0;
5949
- });
5950
- }
5951
- static getCrafatarSkinUrl(uuid) {
5952
- return "https://crafatar.com/skins/" + uuid;
5953
- }
5954
- static getCrafatarCapeUrl(uuid) {
5955
- return "https://crafatar.com/capes/" + uuid;
5956
- }
5957
- static getMcHeadsSkinUrl(uuid) {
5958
- return "https://mc-heads.net/skin/" + uuid;
5959
- }
5960
- static getMineSkinPlayerSkinUrl(uuid) {
5961
- return "https://mineskin.org/skin/player/" + uuid;
5962
- }
5963
- static getSkinProxySkinUrl(uuid) {
5964
- return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
5965
- }
5966
- static getSkinProxyCapeUrl(uuid) {
5967
- return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
5968
- }
5969
- //</editor-fold>
5970
- };
5971
-
5972
- // src/three/OrbitControls.js
5973
- var import_three20 = require("three");
5974
- var _changeEvent = { type: "change" };
5975
- var _startEvent = { type: "start" };
5976
- var _endEvent = { type: "end" };
5977
- var OrbitControls = class extends import_three20.EventDispatcher {
5978
- constructor(object, domElement) {
5979
- super();
5980
- if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5981
- if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5982
- this.object = object;
5983
- this.domElement = domElement;
5984
- this.domElement.style.touchAction = "none";
5985
- this.enabled = true;
5986
- this.target = new import_three20.Vector3();
5987
- this.minDistance = 0;
5988
- this.maxDistance = Infinity;
5989
- this.minZoom = 0;
5990
- this.maxZoom = Infinity;
5991
- this.minPolarAngle = 0;
5992
- this.maxPolarAngle = Math.PI;
5993
- this.minAzimuthAngle = -Infinity;
5994
- this.maxAzimuthAngle = Infinity;
5995
- this.enableDamping = false;
5996
- this.dampingFactor = 0.05;
5997
- this.enableZoom = true;
5998
- this.zoomSpeed = 1;
5999
- this.enableRotate = true;
6000
- this.rotateSpeed = 1;
6001
- this.enablePan = true;
6002
- this.panSpeed = 1;
6003
- this.screenSpacePanning = true;
6004
- this.keyPanSpeed = 7;
6005
- this.autoRotate = false;
6006
- this.autoRotateSpeed = 2;
6007
- this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
6008
- this.mouseButtons = { LEFT: import_three20.MOUSE.ROTATE, MIDDLE: import_three20.MOUSE.DOLLY, RIGHT: import_three20.MOUSE.PAN };
6009
- this.touches = { ONE: import_three20.TOUCH.ROTATE, TWO: import_three20.TOUCH.DOLLY_PAN };
6010
- this.target0 = this.target.clone();
6011
- this.position0 = this.object.position.clone();
6012
- this.zoom0 = this.object.zoom;
6013
- this._domElementKeyEvents = null;
6014
- this.getPolarAngle = function() {
6015
- return spherical.phi;
6016
- };
6017
- this.getAzimuthalAngle = function() {
6018
- return spherical.theta;
6019
- };
6020
- this.getDistance = function() {
6021
- return this.object.position.distanceTo(this.target);
6022
- };
6023
- this.saveState = function() {
6024
- scope.target0.copy(scope.target);
6025
- scope.position0.copy(scope.object.position);
6026
- scope.zoom0 = scope.object.zoom;
6027
- };
6028
- this.reset = function() {
6029
- scope.target.copy(scope.target0);
6030
- scope.object.position.copy(scope.position0);
6031
- scope.object.zoom = scope.zoom0;
6032
- scope.object.updateProjectionMatrix();
6033
- scope.dispatchEvent(_changeEvent);
6034
- scope.update();
6035
- state = STATE.NONE;
6036
- };
6037
- this.update = function() {
6038
- const offset = new import_three20.Vector3();
6039
- const quat = new import_three20.Quaternion().setFromUnitVectors(object.up, new import_three20.Vector3(0, 1, 0));
6040
- const quatInverse = quat.clone().invert();
6041
- const lastPosition = new import_three20.Vector3();
6042
- const lastQuaternion = new import_three20.Quaternion();
6043
- const twoPI = 2 * Math.PI;
6044
- return function update() {
6045
- const position = scope.object.position;
6046
- offset.copy(position).sub(scope.target);
6047
- offset.applyQuaternion(quat);
6048
- spherical.setFromVector3(offset);
6049
- if (scope.autoRotate && state === STATE.NONE) {
6050
- rotateLeft(getAutoRotationAngle());
6051
- }
6052
- if (scope.enableDamping) {
6053
- spherical.theta += sphericalDelta.theta * scope.dampingFactor;
6054
- spherical.phi += sphericalDelta.phi * scope.dampingFactor;
6055
- } else {
6056
- spherical.theta += sphericalDelta.theta;
6057
- spherical.phi += sphericalDelta.phi;
6058
- }
6059
- let min = scope.minAzimuthAngle;
6060
- let max = scope.maxAzimuthAngle;
6061
- if (isFinite(min) && isFinite(max)) {
6062
- if (min < -Math.PI) min += twoPI;
6063
- else if (min > Math.PI) min -= twoPI;
6064
- if (max < -Math.PI) max += twoPI;
6065
- else if (max > Math.PI) max -= twoPI;
6066
- if (min <= max) {
6067
- spherical.theta = Math.max(min, Math.min(max, spherical.theta));
6068
- } else {
6069
- spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
6070
- }
6071
- }
6072
- spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
6073
- spherical.makeSafe();
6074
- spherical.radius *= scale;
6075
- spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
6076
- if (scope.enableDamping === true) {
6077
- scope.target.addScaledVector(panOffset, scope.dampingFactor);
6078
- } else {
6079
- scope.target.add(panOffset);
6080
- }
6081
- offset.setFromSpherical(spherical);
6082
- offset.applyQuaternion(quatInverse);
6083
- position.copy(scope.target).add(offset);
6084
- scope.object.lookAt(scope.target);
6085
- if (scope.enableDamping === true) {
6086
- sphericalDelta.theta *= 1 - scope.dampingFactor;
6087
- sphericalDelta.phi *= 1 - scope.dampingFactor;
6088
- panOffset.multiplyScalar(1 - scope.dampingFactor);
6089
- } else {
6090
- sphericalDelta.set(0, 0, 0);
6091
- panOffset.set(0, 0, 0);
6092
- }
6093
- scale = 1;
6094
- if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
6095
- scope.dispatchEvent(_changeEvent);
6096
- lastPosition.copy(scope.object.position);
6097
- lastQuaternion.copy(scope.object.quaternion);
6098
- zoomChanged = false;
6099
- return true;
6100
- }
6101
- return false;
6102
- };
6103
- }();
6104
- this.dispose = function() {
6105
- scope.domElement.removeEventListener("contextmenu", onContextMenu);
6106
- scope.domElement.removeEventListener("pointerdown", onPointerDown);
6107
- scope.domElement.removeEventListener("pointercancel", onPointerCancel);
6108
- scope.domElement.removeEventListener("wheel", onMouseWheel);
6109
- scope.domElement.removeEventListener("pointermove", onPointerMove);
6110
- scope.domElement.removeEventListener("pointerup", onPointerUp);
6111
- if (scope._domElementKeyEvents !== null) {
6112
- scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
6113
- }
6114
- };
6115
- const scope = this;
6116
- const STATE = {
6117
- NONE: -1,
6118
- ROTATE: 0,
6119
- DOLLY: 1,
6120
- PAN: 2,
6121
- TOUCH_ROTATE: 3,
6122
- TOUCH_PAN: 4,
6123
- TOUCH_DOLLY_PAN: 5,
6124
- TOUCH_DOLLY_ROTATE: 6
6125
- };
6126
- let state = STATE.NONE;
6127
- const EPS = 1e-6;
6128
- const spherical = new import_three20.Spherical();
6129
- const sphericalDelta = new import_three20.Spherical();
6130
- let scale = 1;
6131
- const panOffset = new import_three20.Vector3();
6132
- let zoomChanged = false;
6133
- const rotateStart = new import_three20.Vector2();
6134
- const rotateEnd = new import_three20.Vector2();
6135
- const rotateDelta = new import_three20.Vector2();
6136
- const panStart = new import_three20.Vector2();
6137
- const panEnd = new import_three20.Vector2();
6138
- const panDelta = new import_three20.Vector2();
6139
- const dollyStart = new import_three20.Vector2();
6140
- const dollyEnd = new import_three20.Vector2();
6141
- const dollyDelta = new import_three20.Vector2();
6142
- const pointers = [];
6143
- const pointerPositions = {};
6144
- function getAutoRotationAngle() {
6145
- return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
6146
- }
6147
- function getZoomScale() {
6148
- return Math.pow(0.95, scope.zoomSpeed);
6149
- }
6150
- function rotateLeft(angle) {
6151
- sphericalDelta.theta -= angle;
6152
- }
6153
- function rotateUp(angle) {
6154
- sphericalDelta.phi -= angle;
6155
- }
6156
- const panLeft = function() {
6157
- const v = new import_three20.Vector3();
6158
- return function panLeft2(distance, objectMatrix) {
6159
- v.setFromMatrixColumn(objectMatrix, 0);
6160
- v.multiplyScalar(-distance);
6161
- panOffset.add(v);
6162
- };
6163
- }();
6164
- const panUp = function() {
6165
- const v = new import_three20.Vector3();
6166
- return function panUp2(distance, objectMatrix) {
6167
- if (scope.screenSpacePanning === true) {
6168
- v.setFromMatrixColumn(objectMatrix, 1);
6169
- } else {
6170
- v.setFromMatrixColumn(objectMatrix, 0);
6171
- v.crossVectors(scope.object.up, v);
6172
- }
6173
- v.multiplyScalar(distance);
6174
- panOffset.add(v);
6175
- };
6176
- }();
6177
- const pan = function() {
6178
- const offset = new import_three20.Vector3();
6179
- return function pan2(deltaX, deltaY) {
6180
- const element = scope.domElement;
6181
- if (scope.object.isPerspectiveCamera) {
6182
- const position = scope.object.position;
6183
- offset.copy(position).sub(scope.target);
6184
- let targetDistance = offset.length();
6185
- targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
6186
- panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
6187
- panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
6188
- } else if (scope.object.isOrthographicCamera) {
6189
- panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
6190
- panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
6191
- } else {
6192
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
6193
- scope.enablePan = false;
6194
- }
6195
- };
6196
- }();
6197
- function dollyOut(dollyScale) {
6198
- if (scope.object.isPerspectiveCamera) {
6199
- scale /= dollyScale;
6200
- } else if (scope.object.isOrthographicCamera) {
6201
- scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
6202
- scope.object.updateProjectionMatrix();
6203
- zoomChanged = true;
6204
- } else {
6205
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6206
- scope.enableZoom = false;
6207
- }
6208
- }
6209
- function dollyIn(dollyScale) {
6210
- if (scope.object.isPerspectiveCamera) {
6211
- scale *= dollyScale;
6212
- } else if (scope.object.isOrthographicCamera) {
6213
- scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
6214
- scope.object.updateProjectionMatrix();
6215
- zoomChanged = true;
6216
- } else {
6217
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6218
- scope.enableZoom = false;
6219
- }
6220
- }
6221
- function handleMouseDownRotate(event) {
6222
- rotateStart.set(event.clientX, event.clientY);
6223
- }
6224
- function handleMouseDownDolly(event) {
6225
- dollyStart.set(event.clientX, event.clientY);
6226
- }
6227
- function handleMouseDownPan(event) {
6228
- panStart.set(event.clientX, event.clientY);
6229
- }
6230
- function handleMouseMoveRotate(event) {
6231
- rotateEnd.set(event.clientX, event.clientY);
6232
- rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6233
- const element = scope.domElement;
6234
- rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6235
- rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6236
- rotateStart.copy(rotateEnd);
6237
- scope.update();
6238
- }
6239
- function handleMouseMoveDolly(event) {
6240
- dollyEnd.set(event.clientX, event.clientY);
6241
- dollyDelta.subVectors(dollyEnd, dollyStart);
6242
- if (dollyDelta.y > 0) {
6243
- dollyOut(getZoomScale());
6244
- } else if (dollyDelta.y < 0) {
6245
- dollyIn(getZoomScale());
6246
- }
6247
- dollyStart.copy(dollyEnd);
6248
- scope.update();
6249
- }
6250
- function handleMouseMovePan(event) {
6251
- panEnd.set(event.clientX, event.clientY);
6252
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6253
- pan(panDelta.x, panDelta.y);
6254
- panStart.copy(panEnd);
6255
- scope.update();
6256
- }
6257
- function handleMouseUp() {
6258
- }
6259
- function handleMouseWheel(event) {
6260
- if (event.deltaY < 0) {
6261
- dollyIn(getZoomScale());
6262
- } else if (event.deltaY > 0) {
6263
- dollyOut(getZoomScale());
6264
- }
6265
- scope.update();
6075
+ scope.update();
6266
6076
  }
6267
6077
  function handleKeyDown(event) {
6268
6078
  let needsUpdate = false;
@@ -6424,12 +6234,12 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6424
6234
  mouseAction = -1;
6425
6235
  }
6426
6236
  switch (mouseAction) {
6427
- case import_three20.MOUSE.DOLLY:
6237
+ case import_three18.MOUSE.DOLLY:
6428
6238
  if (scope.enableZoom === false) return;
6429
6239
  handleMouseDownDolly(event);
6430
6240
  state = STATE.DOLLY;
6431
6241
  break;
6432
- case import_three20.MOUSE.ROTATE:
6242
+ case import_three18.MOUSE.ROTATE:
6433
6243
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6434
6244
  if (scope.enablePan === false) return;
6435
6245
  handleMouseDownPan(event);
@@ -6440,7 +6250,7 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6440
6250
  state = STATE.ROTATE;
6441
6251
  }
6442
6252
  break;
6443
- case import_three20.MOUSE.PAN:
6253
+ case import_three18.MOUSE.PAN:
6444
6254
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6445
6255
  if (scope.enableRotate === false) return;
6446
6256
  handleMouseDownRotate(event);
@@ -6496,12 +6306,12 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6496
6306
  switch (pointers.length) {
6497
6307
  case 1:
6498
6308
  switch (scope.touches.ONE) {
6499
- case import_three20.TOUCH.ROTATE:
6309
+ case import_three18.TOUCH.ROTATE:
6500
6310
  if (scope.enableRotate === false) return;
6501
6311
  handleTouchStartRotate();
6502
6312
  state = STATE.TOUCH_ROTATE;
6503
6313
  break;
6504
- case import_three20.TOUCH.PAN:
6314
+ case import_three18.TOUCH.PAN:
6505
6315
  if (scope.enablePan === false) return;
6506
6316
  handleTouchStartPan();
6507
6317
  state = STATE.TOUCH_PAN;
@@ -6512,12 +6322,12 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6512
6322
  break;
6513
6323
  case 2:
6514
6324
  switch (scope.touches.TWO) {
6515
- case import_three20.TOUCH.DOLLY_PAN:
6325
+ case import_three18.TOUCH.DOLLY_PAN:
6516
6326
  if (scope.enableZoom === false && scope.enablePan === false) return;
6517
6327
  handleTouchStartDollyPan();
6518
6328
  state = STATE.TOUCH_DOLLY_PAN;
6519
6329
  break;
6520
- case import_three20.TOUCH.DOLLY_ROTATE:
6330
+ case import_three18.TOUCH.DOLLY_ROTATE:
6521
6331
  if (scope.enableZoom === false && scope.enableRotate === false) return;
6522
6332
  handleTouchStartDollyRotate();
6523
6333
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -6560,55 +6370,561 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6560
6370
  state = STATE.NONE;
6561
6371
  }
6562
6372
  }
6563
- function onTouchEnd(event) {
6564
- handleTouchEnd(event);
6565
- scope.dispatchEvent(_endEvent);
6566
- state = STATE.NONE;
6373
+ function onTouchEnd(event) {
6374
+ handleTouchEnd(event);
6375
+ scope.dispatchEvent(_endEvent);
6376
+ state = STATE.NONE;
6377
+ }
6378
+ function onContextMenu(event) {
6379
+ if (scope.enabled === false) return;
6380
+ event.preventDefault();
6381
+ }
6382
+ function addPointer(event) {
6383
+ pointers.push(event);
6384
+ }
6385
+ function removePointer(event) {
6386
+ delete pointerPositions[event.pointerId];
6387
+ for (let i = 0; i < pointers.length; i++) {
6388
+ if (pointers[i].pointerId == event.pointerId) {
6389
+ pointers.splice(i, 1);
6390
+ return;
6391
+ }
6392
+ }
6393
+ }
6394
+ function trackPointer(event) {
6395
+ let position = pointerPositions[event.pointerId];
6396
+ if (position === void 0) {
6397
+ position = new import_three18.Vector2();
6398
+ pointerPositions[event.pointerId] = position;
6399
+ }
6400
+ position.set(event.pageX, event.pageY);
6401
+ }
6402
+ function getSecondPointerPosition(event) {
6403
+ const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6404
+ return pointerPositions[pointer.pointerId];
6405
+ }
6406
+ scope.domElement.addEventListener("contextmenu", onContextMenu);
6407
+ scope.domElement.addEventListener("pointerdown", onPointerDown);
6408
+ scope.domElement.addEventListener("pointercancel", onPointerCancel);
6409
+ scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6410
+ this.update();
6411
+ }
6412
+ };
6413
+ var MapControls = class extends OrbitControls {
6414
+ constructor(object, domElement) {
6415
+ super(object, domElement);
6416
+ this.screenSpacePanning = false;
6417
+ this.mouseButtons.LEFT = import_three18.MOUSE.PAN;
6418
+ this.mouseButtons.RIGHT = import_three18.MOUSE.ROTATE;
6419
+ this.touches.ONE = import_three18.TOUCH.PAN;
6420
+ this.touches.TWO = import_three18.TOUCH.DOLLY_ROTATE;
6421
+ }
6422
+ };
6423
+
6424
+ // src/renderer/Renderer.ts
6425
+ var Renderer = class _Renderer {
6426
+ constructor(options) {
6427
+ this._dirty = true;
6428
+ this._resizeListener = void 0;
6429
+ this._disposed = false;
6430
+ this._debugHelpers = [];
6431
+ this._eventDispatchers = /* @__PURE__ */ new Map();
6432
+ this._changeListener = () => {
6433
+ this._dirty = true;
6434
+ };
6435
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6436
+ this._animationLoop = this.animate.bind(this);
6437
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6438
+ this._scene = this.createScene();
6439
+ this._camera = this.createCamera();
6440
+ this._renderer = this.createRenderer();
6441
+ this._composer = this.createComposer();
6442
+ if (this.options.render.stats) {
6443
+ this._stats = new import_stats.default();
6444
+ document.body.appendChild(this._stats.dom);
6445
+ }
6446
+ this.init();
6447
+ this._controls = this.createControls();
6448
+ }
6449
+ static {
6450
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6451
+ camera: {
6452
+ type: "perspective",
6453
+ near: 1,
6454
+ far: 5e3,
6455
+ perspective: {
6456
+ aspect: void 0,
6457
+ fov: 50
6458
+ },
6459
+ orthographic: {
6460
+ left: void 0,
6461
+ right: void 0,
6462
+ top: void 0,
6463
+ bottom: void 0
6464
+ },
6465
+ position: new import_three19.Vector3(50, 50, 50),
6466
+ lookingAt: new import_three19.Vector3(0, 0, 0)
6467
+ },
6468
+ render: {
6469
+ fpsLimit: 60,
6470
+ stats: false,
6471
+ antialias: true,
6472
+ shade: true,
6473
+ autoResize: true,
6474
+ renderAlways: false
6475
+ },
6476
+ composer: {
6477
+ enabled: true
6478
+ },
6479
+ controls: {
6480
+ enabled: false
6481
+ },
6482
+ debug: {
6483
+ grid: false,
6484
+ axes: false
6485
+ }
6486
+ });
6487
+ }
6488
+ //<editor-fold desc="INIT">
6489
+ createScene() {
6490
+ return new MineRenderScene();
6491
+ }
6492
+ createCamera() {
6493
+ switch (this.options.camera.type) {
6494
+ case "perspective":
6495
+ default:
6496
+ return new import_three19.PerspectiveCamera(
6497
+ this.options.camera.perspective.fov,
6498
+ this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6499
+ this.options.camera.near,
6500
+ this.options.camera.far
6501
+ );
6502
+ case "orthographic":
6503
+ return new import_three19.OrthographicCamera(
6504
+ this.options.camera.orthographic.left ?? this.viewWidth / -2,
6505
+ this.options.camera.orthographic.right ?? this.viewWidth / 2,
6506
+ this.options.camera.orthographic.top ?? this.viewHeight / 2,
6507
+ this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
6508
+ this.options.camera.near,
6509
+ this.options.camera.far
6510
+ );
6511
+ }
6512
+ }
6513
+ createRenderer() {
6514
+ const renderer = new import_three19.WebGLRenderer({
6515
+ antialias: this.options.render.antialias,
6516
+ alpha: true,
6517
+ powerPreference: "high-performance",
6518
+ depth: true
6519
+ });
6520
+ renderer.setClearColor(0, 0);
6521
+ renderer.shadowMap.enabled = true;
6522
+ renderer.shadowMap.type = import_three19.PCFSoftShadowMap;
6523
+ renderer.outputColorSpace = import_three19.SRGBColorSpace;
6524
+ renderer.setSize(this.viewWidth, this.viewHeight);
6525
+ return renderer;
6526
+ }
6527
+ createComposer() {
6528
+ if (!this.options.composer.enabled) return void 0;
6529
+ const composer = new import_postprocessing.EffectComposer(this.renderer);
6530
+ composer.setSize(this.viewWidth, this.viewHeight);
6531
+ composer.addPass(new import_postprocessing.RenderPass(this.scene, this.camera));
6532
+ return composer;
6533
+ }
6534
+ createControls() {
6535
+ if (!this.options.controls?.enabled) return void 0;
6536
+ const position = this.camera.position.clone();
6537
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
6538
+ this.camera.position.copy(position);
6539
+ const target = this.options.camera.lookingAt;
6540
+ if (isVector3(target)) {
6541
+ controls.target.copy(target);
6542
+ } else if (isTripleArray(target)) {
6543
+ controls.target.set(target[0], target[1], target[2]);
6544
+ }
6545
+ controls.update();
6546
+ controls.saveState();
6547
+ this.registerEventDispatcher(controls);
6548
+ return controls;
6549
+ }
6550
+ //</editor-fold>
6551
+ init() {
6552
+ if (this._disposed) return;
6553
+ if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
6554
+ window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6555
+ }
6556
+ if (this.options.debug.grid) {
6557
+ const gridHelper = new import_three19.GridHelper(128, 16);
6558
+ this._debugHelpers.push(gridHelper);
6559
+ this.scene.add(gridHelper);
6560
+ const gridHelper2 = new import_three19.GridHelper(128, 16);
6561
+ this._debugHelpers.push(gridHelper2);
6562
+ gridHelper2.rotation.x = 90 * (Math.PI / 180);
6563
+ this.scene.add(gridHelper2);
6564
+ const gridHelper3 = new import_three19.GridHelper(128, 16);
6565
+ this._debugHelpers.push(gridHelper3);
6566
+ gridHelper3.rotation.z = 90 * (Math.PI / 180);
6567
+ this.scene.add(gridHelper3);
6568
+ }
6569
+ if (this.options.debug.axes) {
6570
+ const axesHelper = new import_three19.AxesHelper(64);
6571
+ this._debugHelpers.push(axesHelper);
6572
+ this.scene.add(axesHelper);
6573
+ }
6574
+ if (this.options.camera.position) {
6575
+ if (isVector3(this.options.camera.position)) {
6576
+ this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
6577
+ } else if (isTripleArray(this.options.camera.position)) {
6578
+ this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
6579
+ }
6580
+ }
6581
+ if (this.options.camera.lookingAt) {
6582
+ if (isVector3(this.options.camera.lookingAt)) {
6583
+ this.camera.lookAt(this.options.camera.lookingAt);
6584
+ } else if (isTripleArray(this.options.camera.lookingAt)) {
6585
+ this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6586
+ }
6587
+ }
6588
+ if (this.options.render.autoResize && !this._resizeListener) {
6589
+ this._resizeListener = () => {
6590
+ this.resize(this.viewWidth, this.viewHeight);
6591
+ };
6592
+ window.addEventListener("resize", this._resizeListener);
6593
+ }
6594
+ }
6595
+ get element() {
6596
+ return this._element;
6597
+ }
6598
+ appendTo(element) {
6599
+ if (this._disposed) return;
6600
+ this._element = element;
6601
+ this._element.appendChild(this.renderer.domElement);
6602
+ if (this.viewWidth == 0) {
6603
+ console.warn("0 element width");
6604
+ }
6605
+ if (this.viewHeight == 0) {
6606
+ console.warn("0 element height");
6607
+ }
6608
+ this.resize(this.viewWidth, this.viewHeight);
6609
+ }
6610
+ /**
6611
+ * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
6612
+ * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
6613
+ */
6614
+ registerEventDispatcher(dispatcher, changeEvent2 = "change") {
6615
+ if (this._disposed) return;
6616
+ let events = this._eventDispatchers.get(dispatcher);
6617
+ if (!events) {
6618
+ events = /* @__PURE__ */ new Set();
6619
+ this._eventDispatchers.set(dispatcher, events);
6620
+ }
6621
+ if (events.has(changeEvent2)) return;
6622
+ events.add(changeEvent2);
6623
+ dispatcher.addEventListener(changeEvent2, this._changeListener);
6624
+ }
6625
+ resize(width, height) {
6626
+ if (this._disposed) return;
6627
+ if (isPerspectiveCamera(this.camera)) {
6628
+ this.camera.aspect = width / height;
6629
+ this.camera.updateProjectionMatrix();
6630
+ } else if (isOrthographicCamera(this.camera)) {
6631
+ this.camera.left = width / -2;
6632
+ this.camera.right = width / 2;
6633
+ this.camera.top = height / 2;
6634
+ this.camera.bottom = height / -2;
6635
+ this.camera.updateProjectionMatrix();
6636
+ }
6637
+ this.renderer.setSize(width, height);
6638
+ this.composer?.setSize(width, height);
6639
+ this._dirty = true;
6640
+ }
6641
+ //<editor-fold desc="RENDER">
6642
+ get dirty() {
6643
+ return this._dirty || this.scene.dirty;
6644
+ }
6645
+ set dirty(dirty) {
6646
+ this._dirty = dirty;
6647
+ this.scene.dirty = dirty;
6648
+ }
6649
+ start() {
6650
+ if (this._disposed) return;
6651
+ this.stop();
6652
+ this.renderer.setAnimationLoop(this._animationLoop);
6653
+ }
6654
+ stop() {
6655
+ if (this._disposed) return;
6656
+ this.renderer.setAnimationLoop(null);
6657
+ this._nextFrameTime = void 0;
6658
+ }
6659
+ /**
6660
+ * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
6661
+ * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
6662
+ * controls must be managed by their owners.
6663
+ */
6664
+ dispose() {
6665
+ if (this._disposed) return;
6666
+ this.stop();
6667
+ this._disposed = true;
6668
+ if (this._resizeListener) {
6669
+ window.removeEventListener("resize", this._resizeListener);
6670
+ this._resizeListener = void 0;
6671
+ }
6672
+ for (const [dispatcher, events] of this._eventDispatchers) {
6673
+ for (const event of events) {
6674
+ dispatcher.removeEventListener(event, this._changeListener);
6675
+ }
6676
+ }
6677
+ this._eventDispatchers.clear();
6678
+ this._stats?.dom.remove();
6679
+ this._stats = void 0;
6680
+ this.renderer.domElement.remove();
6681
+ this._element = void 0;
6682
+ if (this._controls) {
6683
+ const controls = this._controls;
6684
+ this._controls = void 0;
6685
+ controls.enabled = false;
6686
+ controls.dispose();
6567
6687
  }
6568
- function onContextMenu(event) {
6569
- if (scope.enabled === false) return;
6570
- event.preventDefault();
6688
+ this.scene.clear();
6689
+ for (const helper of this._debugHelpers) {
6690
+ helper.geometry.dispose();
6691
+ const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
6692
+ for (const material of materials) {
6693
+ material.dispose();
6694
+ }
6571
6695
  }
6572
- function addPointer(event) {
6573
- pointers.push(event);
6696
+ this._debugHelpers.length = 0;
6697
+ this.composer?.dispose();
6698
+ this.renderer.dispose();
6699
+ this.renderer.forceContextLoss();
6700
+ }
6701
+ animate(t = performance.now()) {
6702
+ if (this._disposed) return;
6703
+ if (this._controls?.enabled) {
6704
+ this._controls.update();
6574
6705
  }
6575
- function removePointer(event) {
6576
- delete pointerPositions[event.pointerId];
6577
- for (let i = 0; i < pointers.length; i++) {
6578
- if (pointers[i].pointerId == event.pointerId) {
6579
- pointers.splice(i, 1);
6580
- return;
6581
- }
6582
- }
6706
+ if (this._disposed) return;
6707
+ if (!this.dirty && !this.options.render.renderAlways) return;
6708
+ const interval = this._frameInterval;
6709
+ if (interval) {
6710
+ const next = this._nextFrameTime;
6711
+ if (next !== void 0 && t + 0.1 < next) return;
6712
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6583
6713
  }
6584
- function trackPointer(event) {
6585
- let position = pointerPositions[event.pointerId];
6586
- if (position === void 0) {
6587
- position = new import_three20.Vector2();
6588
- pointerPositions[event.pointerId] = position;
6589
- }
6590
- position.set(event.pageX, event.pageY);
6714
+ if (this._stats) {
6715
+ this._stats.begin();
6591
6716
  }
6592
- function getSecondPointerPosition(event) {
6593
- const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6594
- return pointerPositions[pointer.pointerId];
6717
+ if (this.options.composer.enabled && this.composer) {
6718
+ this.composer.render();
6719
+ } else {
6720
+ this.renderer.render(this.scene, this.camera);
6595
6721
  }
6596
- scope.domElement.addEventListener("contextmenu", onContextMenu);
6597
- scope.domElement.addEventListener("pointerdown", onPointerDown);
6598
- scope.domElement.addEventListener("pointercancel", onPointerCancel);
6599
- scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6600
- this.update();
6722
+ this.dirty = false;
6723
+ if (this._stats) {
6724
+ this._stats.end();
6725
+ }
6726
+ }
6727
+ //</editor-fold>
6728
+ toImage() {
6729
+ return this.renderer.domElement.toDataURL();
6730
+ }
6731
+ ///
6732
+ get attachedToBody() {
6733
+ return this.element === document.body;
6734
+ }
6735
+ get viewWidth() {
6736
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6737
+ }
6738
+ get viewHeight() {
6739
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6740
+ }
6741
+ get scene() {
6742
+ return this._scene;
6743
+ }
6744
+ get camera() {
6745
+ return this._camera;
6746
+ }
6747
+ get renderer() {
6748
+ return this._renderer;
6749
+ }
6750
+ get composer() {
6751
+ return this._composer;
6601
6752
  }
6753
+ /** Renderer-owned controls, or undefined when disabled at construction or after disposal. */
6754
+ get controls() {
6755
+ return this._controls;
6756
+ }
6757
+ ///
6602
6758
  };
6603
- var MapControls = class extends OrbitControls {
6604
- constructor(object, domElement) {
6605
- super(object, domElement);
6606
- this.screenSpacePanning = false;
6607
- this.mouseButtons.LEFT = import_three20.MOUSE.PAN;
6608
- this.mouseButtons.RIGHT = import_three20.MOUSE.ROTATE;
6609
- this.touches.ONE = import_three20.TOUCH.PAN;
6610
- this.touches.TWO = import_three20.TOUCH.DOLLY_ROTATE;
6759
+
6760
+ // src/skin/Skins.ts
6761
+ var Skins = class {
6762
+ //<editor-fold desc="Skins">
6763
+ static async fromUuidOrUsername(uuidOrUsername) {
6764
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6765
+ return this.fromUuid(uuidOrUsername);
6766
+ }
6767
+ return this.fromUsername(uuidOrUsername);
6768
+ }
6769
+ static async fromUuid(uuid) {
6770
+ return this.getMcProxySkinUrl(uuid);
6771
+ }
6772
+ static async fromUsername(username) {
6773
+ return this.usernameToUuid(username).then((uuid) => {
6774
+ if (uuid) {
6775
+ return this.fromUuid(uuid);
6776
+ }
6777
+ return void 0;
6778
+ });
6779
+ }
6780
+ static async fromMineSkin(mineskinId) {
6781
+ return this.getMineSkin(mineskinId).then((mineskin) => {
6782
+ if (mineskin) {
6783
+ return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6784
+ }
6785
+ return void 0;
6786
+ });
6787
+ }
6788
+ //</editor-fold>
6789
+ //<editor-fold desc="Capes">
6790
+ static async capeFromUuidOrUsername(uuidOrUsername) {
6791
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6792
+ return this.capeFromUuid(uuidOrUsername);
6793
+ }
6794
+ return this.capeFromUsername(uuidOrUsername);
6795
+ }
6796
+ static async capeFromUuid(uuid) {
6797
+ return this.getMcProxyCapeUrl(uuid);
6798
+ }
6799
+ static async capeFromUsername(username) {
6800
+ return this.usernameToUuid(username).then((uuid) => {
6801
+ if (uuid) {
6802
+ return this.capeFromUuid(uuid);
6803
+ }
6804
+ return void 0;
6805
+ });
6806
+ }
6807
+ static async capeFromCapesDev(uuid, capeType = "minecraft") {
6808
+ return this.getCapesDev(uuid, capeType).then((cape) => {
6809
+ if (cape) {
6810
+ return cape?.stillImageUrl;
6811
+ }
6812
+ return void 0;
6813
+ });
6814
+ }
6815
+ //</editor-fold>
6816
+ //<editor-fold desc="Helpers">
6817
+ static async usernameToUuid(username) {
6818
+ return this.usernameToUuidMcProxy(username);
6819
+ }
6820
+ static async usernameToUuidMcProxy(username) {
6821
+ return Requests.genericRequest({
6822
+ baseURL: "https://mcproxy.dev",
6823
+ url: "/uuid/" + username
6824
+ }).then((res) => {
6825
+ if (res.status === 200) {
6826
+ return res.data["data"]["id"];
6827
+ }
6828
+ return void 0;
6829
+ }).catch((err) => {
6830
+ console.warn(err);
6831
+ return void 0;
6832
+ });
6833
+ }
6834
+ /** @deprecated **/
6835
+ static async usernameToUuidSkinProxy(username) {
6836
+ return Requests.genericRequest({
6837
+ baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
6838
+ url: "/uuid/" + username
6839
+ }).then((res) => {
6840
+ if (res.status === 200) {
6841
+ return res.data["id"];
6842
+ }
6843
+ return void 0;
6844
+ }).catch((err) => {
6845
+ console.warn(err);
6846
+ return void 0;
6847
+ });
6848
+ }
6849
+ static async usernameToUuidMineTools(username) {
6850
+ return Requests.genericRequest({
6851
+ baseURL: "https://api.minetools.eu",
6852
+ url: "/uuid/" + username
6853
+ }).then((res) => {
6854
+ if (res.status === 200) {
6855
+ return res.data["id"];
6856
+ }
6857
+ return void 0;
6858
+ }).catch((err) => {
6859
+ console.warn(err);
6860
+ return void 0;
6861
+ });
6862
+ }
6863
+ static async getProfileFromMinetools(uuid) {
6864
+ return Requests.genericRequest({
6865
+ baseURL: "https://api.minetools.eu",
6866
+ url: "/profile/" + uuid
6867
+ }).then((res) => {
6868
+ if (res.status === 200) {
6869
+ return res.data;
6870
+ }
6871
+ });
6872
+ }
6873
+ static async getMineSkin(mineskinId) {
6874
+ return Requests.genericRequest({
6875
+ baseURL: "https://api.mineskin.org",
6876
+ url: "/get/uuid/" + mineskinId
6877
+ }).then((res) => {
6878
+ if (res.status === 200) {
6879
+ return res.data;
6880
+ }
6881
+ return void 0;
6882
+ }).catch((err) => {
6883
+ console.warn(err);
6884
+ return void 0;
6885
+ });
6886
+ }
6887
+ static async getCapesDev(uuid, type = "all") {
6888
+ return Requests.genericRequest({
6889
+ baseURL: "https://api.capes.dev",
6890
+ url: "/load/" + uuid + "/" + type
6891
+ }).then((res) => {
6892
+ if (res.status === 200) {
6893
+ return res.data;
6894
+ }
6895
+ return void 0;
6896
+ }).catch((err) => {
6897
+ console.warn(err);
6898
+ return void 0;
6899
+ });
6900
+ }
6901
+ static getCrafatarSkinUrl(uuid) {
6902
+ return "https://crafatar.com/skins/" + uuid;
6903
+ }
6904
+ static getCrafatarCapeUrl(uuid) {
6905
+ return "https://crafatar.com/capes/" + uuid;
6906
+ }
6907
+ static getMcHeadsSkinUrl(uuid) {
6908
+ return "https://mc-heads.net/skin/" + uuid;
6909
+ }
6910
+ static getMineSkinPlayerSkinUrl(uuid) {
6911
+ return "https://mineskin.org/skin/player/" + uuid;
6912
+ }
6913
+ /** @deprecated **/
6914
+ static getSkinProxySkinUrl(uuid) {
6915
+ return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6916
+ }
6917
+ /** @deprecated **/
6918
+ static getSkinProxyCapeUrl(uuid) {
6919
+ return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6920
+ }
6921
+ static getMcProxySkinUrl(uuid) {
6922
+ return "https://mcproxy.dev/skin/" + uuid;
6611
6923
  }
6924
+ static getMcProxyCapeUrl(uuid) {
6925
+ return "https://mcproxy.dev/cape/" + uuid;
6926
+ }
6927
+ //</editor-fold>
6612
6928
  };
6613
6929
 
6614
6930
  // src/world/Chunk.ts
@@ -6671,7 +6987,7 @@ var MineRenderWorld = class {
6671
6987
  console.log("CHUNKS", this._chunks);
6672
6988
  for (let chunk of this._chunks.values()) {
6673
6989
  console.log("dispose chunk", chunk);
6674
- await (chunk == null ? void 0 : chunk.dispose());
6990
+ await chunk?.dispose();
6675
6991
  }
6676
6992
  this._chunks.clear();
6677
6993
  }
@@ -6725,7 +7041,7 @@ var MineRenderWorld = class {
6725
7041
  };
6726
7042
 
6727
7043
  // src/world/Chunk.ts
6728
- var p12 = prefix("Chunk");
7044
+ var p11 = prefix("Chunk");
6729
7045
  var Chunk = class _Chunk {
6730
7046
  constructor(scene, x, y, z) {
6731
7047
  this._blocks = [];
@@ -6777,7 +7093,7 @@ var Chunk = class _Chunk {
6777
7093
  const index = _Chunk.chunkPosToBlockIndex(pos);
6778
7094
  const current = this._blocks[index];
6779
7095
  if (typeof current !== "undefined") {
6780
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
7096
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6781
7097
  current.object.removeFromScene();
6782
7098
  delete this._blocks[index];
6783
7099
  }
@@ -6844,6 +7160,7 @@ var Chunk = class _Chunk {
6844
7160
  AXES,
6845
7161
  ArchiveAssetSource,
6846
7162
  AssetKey,
7163
+ AssetLoadError,
6847
7164
  AssetLoader,
6848
7165
  AssetParser,
6849
7166
  AssetSource,
@@ -6901,6 +7218,7 @@ var Chunk = class _Chunk {
6901
7218
  OrbitControls,
6902
7219
  PersistentCache,
6903
7220
  Renderer,
7221
+ RequestError,
6904
7222
  Requests,
6905
7223
  SKIN_PARTS,
6906
7224
  SceneInspector,