minerender 2.1.0-alpha.2 → 2.1.0-alpha.21

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,
@@ -147,6 +140,7 @@ __export(index_node_exports, {
147
140
  BlockEntityModels: () => BlockEntityModels,
148
141
  BlockObject: () => BlockObject,
149
142
  BlockStates: () => BlockStates,
143
+ BlockTints: () => BlockTints,
150
144
  BrowserArchiveProxy: () => BrowserArchiveProxy,
151
145
  CUBE_FACES: () => CUBE_FACES,
152
146
  Caching: () => Caching,
@@ -192,6 +186,7 @@ __export(index_node_exports, {
192
186
  OrbitControls: () => OrbitControls,
193
187
  PersistentCache: () => PersistentCache,
194
188
  Renderer: () => Renderer,
189
+ RequestError: () => RequestError,
195
190
  Requests: () => Requests,
196
191
  SKIN_PARTS: () => SKIN_PARTS,
197
192
  SceneInspector: () => SceneInspector,
@@ -302,25 +297,29 @@ var Env = class {
302
297
  };
303
298
 
304
299
  // src/cache/PersistentCache.ts
305
- var _PersistentCache = class _PersistentCache {
300
+ var PersistentCache = class _PersistentCache {
306
301
  constructor(backing) {
307
302
  this.backing = backing;
308
303
  }
304
+ static {
305
+ /** Bump to invalidate every persisted entry. */
306
+ this.VERSION = 2;
307
+ }
309
308
  static open(name) {
310
309
  return Env.provider.openCache(name, _PersistentCache.VERSION);
311
310
  }
311
+ /** Loads a missing entry and stores only non-nullish results. */
312
312
  async getOrLoad(key, loader) {
313
313
  let v = await this.get(key);
314
314
  if (typeof v === "undefined" || v === null) {
315
315
  v = await loader(key);
316
- await this.put(key, v);
316
+ if (typeof v !== "undefined" && v !== null) {
317
+ await this.put(key, v);
318
+ }
317
319
  }
318
320
  return v;
319
321
  }
320
322
  };
321
- /** Bump to invalidate every persisted entry. */
322
- _PersistentCache.VERSION = 1;
323
- var PersistentCache = _PersistentCache;
324
323
 
325
324
  // src/env/node/NodeCache.ts
326
325
  var NodeCache = class extends PersistentCache {
@@ -398,7 +397,7 @@ registerNodeEnv();
398
397
  // src/Axis.ts
399
398
  var import_three = require("three");
400
399
  var Axis = /* @__PURE__ */ ((Axis3) => {
401
- Axis3["X"] = "X";
400
+ Axis3["X"] = "x";
402
401
  Axis3["Y"] = "y";
403
402
  Axis3["Z"] = "z";
404
403
  return Axis3;
@@ -406,7 +405,7 @@ var Axis = /* @__PURE__ */ ((Axis3) => {
406
405
  var AXES = Object.values(Axis);
407
406
  function axisToVec3(axis) {
408
407
  switch (axis) {
409
- case "X" /* X */:
408
+ case "x" /* X */:
410
409
  return new import_three.Vector3(1, 0, 0);
411
410
  case "y" /* Y */:
412
411
  return new import_three.Vector3(0, 1, 0);
@@ -494,8 +493,7 @@ function serializeImageKey(key) {
494
493
  return md5(key.src);
495
494
  }
496
495
  function serializeBoxGeometryKey(key) {
497
- var _a;
498
- return md5([key.width, key.height, key.depth, (_a = key.uv) == null ? void 0 : _a.join(":")].join("_"));
496
+ return md5([key.width, key.height, key.depth, key.uv?.join(":")].join("_"));
499
497
  }
500
498
  function serializeTextureKey(key) {
501
499
  return md5([key.src, key.format, key.rotation].join("$"));
@@ -510,7 +508,64 @@ function serializeMeshKey(key) {
510
508
  // src/cache/Caching.ts
511
509
  var import_loading_cache = require("@inventivetalent/loading-cache");
512
510
  var import_time = require("@inventivetalent/time");
513
- var Caching = class {
511
+ var Caching = class _Caching {
512
+ static {
513
+ this.rawImageCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(5)).buildAsync();
514
+ }
515
+ static {
516
+ this.imageDataCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
517
+ }
518
+ static {
519
+ this.canvasImageDataCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
520
+ }
521
+ static {
522
+ this.wrappedImageCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(10)).buildAsync();
523
+ }
524
+ static {
525
+ this.boxGeometryCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(20)).build();
526
+ }
527
+ static {
528
+ this.textureCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
529
+ }
530
+ static {
531
+ this.materialCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
532
+ }
533
+ static {
534
+ this.boxMeshCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).build();
535
+ }
536
+ static {
537
+ this.textureAssetCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
538
+ }
539
+ static {
540
+ this.textureMetaCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
541
+ }
542
+ static {
543
+ this.rawModelCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
544
+ }
545
+ static {
546
+ this.mergedModelCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
547
+ }
548
+ static {
549
+ this.modelTextureAtlasCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
550
+ }
551
+ static {
552
+ this.blockStateCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
553
+ }
554
+ static {
555
+ this.listAssetCache = _Caching.createAssetCache();
556
+ }
557
+ static {
558
+ this.defaultBlockStatesCache = _Caching.createAssetCache();
559
+ }
560
+ static {
561
+ this.blockTintCache = _Caching.createAssetCache();
562
+ }
563
+ static {
564
+ this.entityModelsCache = _Caching.createAssetCache();
565
+ }
566
+ static createAssetCache() {
567
+ 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();
568
+ }
514
569
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
515
570
  static get all() {
516
571
  return [
@@ -527,7 +582,11 @@ var Caching = class {
527
582
  this.rawModelCache,
528
583
  this.mergedModelCache,
529
584
  this.modelTextureAtlasCache,
530
- this.blockStateCache
585
+ this.blockStateCache,
586
+ this.listAssetCache,
587
+ this.defaultBlockStatesCache,
588
+ this.blockTintCache,
589
+ this.entityModelsCache
531
590
  ];
532
591
  }
533
592
  static clear() {
@@ -538,8 +597,8 @@ var Caching = class {
538
597
  /**
539
598
  * Clears every cache and stops its expiry timer.
540
599
  *
541
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
542
- * this is called - see {@link shutdown}.
600
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
601
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
543
602
  */
544
603
  static end() {
545
604
  for (const cache of this.all) {
@@ -553,20 +612,6 @@ var Caching = class {
553
612
  };
554
613
  }
555
614
  };
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
615
 
571
616
  // src/Geometries.ts
572
617
  var Geometries = class _Geometries {
@@ -587,13 +632,14 @@ var Geometries = class _Geometries {
587
632
  };
588
633
 
589
634
  // src/Materials.ts
590
- var import_three6 = require("three");
635
+ var import_three5 = require("three");
591
636
 
592
637
  // src/texture/Textures.ts
593
- var import_three5 = require("three");
638
+ var import_three4 = require("three");
594
639
 
595
640
  // src/texture/TextureLoader.ts
596
- var import_three4 = require("three");
641
+ var import_three3 = require("three");
642
+ var THREE = __toESM(require("three"));
597
643
 
598
644
  // src/canvas/CanvasCompat.ts
599
645
  function createImage(width, height) {
@@ -604,9 +650,7 @@ function createCanvas2(width, height) {
604
650
  }
605
651
 
606
652
  // src/request/Requests.ts
607
- var import_axios = __toESM(require("axios"));
608
653
  var import_jobqu = require("jobqu");
609
- var import_time2 = require("@inventivetalent/time");
610
654
 
611
655
  // src/util/log.ts
612
656
  var Reset = "\x1B[0m";
@@ -616,198 +660,174 @@ function prefix(prefix2) {
616
660
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
617
661
  }
618
662
 
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();
663
+ // src/request/Requests.ts
664
+ var p = prefix("Requests");
665
+ var RequestError = class extends Error {
666
+ constructor(message, response, cause) {
667
+ super(message);
668
+ this.response = response;
669
+ this.cause = cause;
670
+ this.name = "RequestError";
638
671
  }
639
672
  };
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);
673
+ async function fetchRequest(config, defaultBaseURL) {
674
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
675
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
676
+ const headers = new Headers(options.headers);
677
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
678
+ headers.set("User-Agent", "MineRender");
679
+ }
680
+ const attemptSignal = AbortSignal.any([
681
+ ...signal ? [signal] : [],
682
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
683
+ ]);
684
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
685
+ attemptSignal.throwIfAborted();
686
+ try {
687
+ const response = await fetch(request);
688
+ const result = {
689
+ data: void 0,
690
+ status: response.status,
691
+ statusText: response.statusText,
692
+ headers: response.headers,
693
+ url: response.url
694
+ };
695
+ if (!response.ok) {
696
+ await response.body?.cancel().catch(() => {
697
+ });
698
+ throw new RequestError(`Request failed with status ${response.status}`, result);
699
+ }
700
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
701
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
702
+ return { ...result, data };
703
+ } catch (error) {
704
+ attemptSignal.throwIfAborted();
705
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
706
+ throw new RequestError("Network request failed", void 0, error);
664
707
  }
708
+ throw error;
665
709
  }
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
710
  }
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;
711
+ async function abortable(promise, signal) {
712
+ if (!signal) return promise;
713
+ let abort;
714
+ const cancelled = new Promise((_, reject) => {
715
+ abort = () => reject(signal.reason);
716
+ signal.addEventListener("abort", abort, { once: true });
717
+ if (signal.aborted) abort();
718
+ });
719
+ try {
720
+ return await Promise.race([promise, cancelled]);
721
+ } finally {
722
+ signal.removeEventListener("abort", abort);
687
723
  }
688
724
  }
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
- });
725
+ var RequestQueue = class {
726
+ constructor() {
727
+ this.pendingRequests = 0;
728
+ this.stopped = new AbortController();
729
+ this.queue = new import_jobqu.JobQueue(
730
+ (request) => fetchRequest(request, this.baseURL),
731
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
732
+ );
767
733
  }
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;
734
+ async request(request) {
735
+ this.pendingRequests++;
736
+ const signal = request.signal;
737
+ try {
738
+ for (let retries = 0; ; retries++) {
739
+ signal?.throwIfAborted();
740
+ try {
741
+ return await abortable(this.queue.add(request), signal);
742
+ } catch (error) {
743
+ console.debug(p, "Request failed", error);
744
+ const delay = this.retryDelay(error, request, retries);
745
+ if (delay === void 0) {
746
+ throw error;
775
747
  }
776
- } else {
777
- request["minerenderRetry"] = 3;
778
- return true;
748
+ await this.waitForRetry(delay, signal);
779
749
  }
780
750
  }
751
+ } finally {
752
+ if (signal?.aborted) {
753
+ this.queue.remove(request);
754
+ }
755
+ this.pendingRequests--;
781
756
  }
782
- return false;
757
+ }
758
+ retryDelay(error, request, retries) {
759
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
760
+ return void 0;
761
+ }
762
+ if (error instanceof RequestError) {
763
+ const status = error.response?.status;
764
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
765
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
766
+ return void 0;
767
+ }
768
+ let delay = 100 * 2 ** retries;
769
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
770
+ if (retryAfter !== void 0 && retryAfter !== null) {
771
+ const seconds = Number(retryAfter);
772
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
773
+ return void 0;
774
+ }
775
+ delay = Math.max(delay, seconds * 1e3);
776
+ }
777
+ return delay;
778
+ }
779
+ async waitForRetry(delay, signal) {
780
+ let timer;
781
+ const waiting = new Promise((resolve) => {
782
+ timer = setTimeout(resolve, delay);
783
+ });
784
+ try {
785
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
786
+ } finally {
787
+ clearTimeout(timer);
788
+ }
789
+ }
790
+ get pendingSize() {
791
+ return this.pendingRequests;
792
+ }
793
+ end() {
794
+ this.queue.end();
795
+ this.stopped.abort(new import_jobqu.JobCancelledError("ended"));
796
+ }
797
+ };
798
+ var Requests = class {
799
+ static {
800
+ this.genericQueue = new RequestQueue();
801
+ }
802
+ static {
803
+ this.mcAssetRequestQueue = new RequestQueue();
804
+ }
805
+ static genericRequest(request) {
806
+ return this.genericQueue.request(request);
807
+ }
808
+ static mcAssetRequest(request) {
809
+ return this.mcAssetRequestQueue.request(request);
783
810
  }
784
811
  static setMcAssetRoot(root) {
785
- this.mcAssetInstance.defaults.baseURL = root;
812
+ this.mcAssetRequestQueue.baseURL = root;
786
813
  }
814
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
787
815
  static get queueSizes() {
788
816
  return {
789
- generic: this.genericQueue.size,
790
- mcAsset: this.mcAssetRequestQueue.size
817
+ generic: this.genericQueue.pendingSize,
818
+ mcAsset: this.mcAssetRequestQueue.pendingSize
791
819
  };
792
820
  }
793
821
  /**
794
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
795
- * exit until this is called - see {@link shutdown}.
822
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
823
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
824
+ * this cleanup. See {@link shutdown}.
796
825
  */
797
826
  static end() {
798
827
  this.genericQueue.end();
799
828
  this.mcAssetRequestQueue.end();
800
829
  }
801
830
  };
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
831
 
812
832
  // src/WrappedImage.ts
813
833
  var WrappedImage = class {
@@ -845,10 +865,10 @@ var WrappedImage = class {
845
865
  return this.animated ? this.width : this.height;
846
866
  }
847
867
  get frameCount() {
848
- return this.height / this.width;
868
+ return this.height / this.frameHeight;
849
869
  }
850
870
  getFrameY(frame) {
851
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
871
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
852
872
  }
853
873
  getSectionData(sx, sy, sw, sh) {
854
874
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -858,7 +878,7 @@ var WrappedImage = class {
858
878
  }
859
879
  getFrameSectionData(frame) {
860
880
  const y = this.getFrameY(frame);
861
- return this.getSectionData(0, y, this.width, this.width + y);
881
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
862
882
  }
863
883
  };
864
884
 
@@ -872,29 +892,41 @@ var ImageLoader = class _ImageLoader {
872
892
  static async loadAsync(src) {
873
893
  return new Promise((resolve, reject) => {
874
894
  const image = this._createImage();
875
- image.src = src;
876
895
  image.onload = () => resolve(image);
877
- image.onerror = (err) => reject(err);
896
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
897
+ image.src = src;
878
898
  });
879
899
  }
880
900
  static loadElement(src, onload, onerr) {
881
901
  const image = this._createImage();
882
- image.src = src;
883
902
  if (onload)
884
903
  image.onload = onload;
885
904
  if (onerr)
886
905
  image.onerror = onerr;
906
+ image.src = src;
887
907
  return image;
888
908
  }
889
909
  static async loadData(src) {
890
910
  console.debug(p2, "loadData", src);
891
- return await this.infoToData(await this.getInfo(src));
911
+ const image = await this.loadCanvasData(src);
912
+ return image.data.getImageData(0, 0, image.width, image.height);
892
913
  }
893
914
  static async loadCanvasData(src) {
894
- return await this.infoToCanvasData(await this.getInfo(src));
915
+ const keyStr = serializeImageKey({ src });
916
+ const info = this.getInfo(src);
917
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
918
+ try {
919
+ return await this.infoToCanvasData(await info);
920
+ } catch (err) {
921
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
922
+ Caching.rawImageCache.invalidate(keyStr);
923
+ }
924
+ throw err;
925
+ }
895
926
  }
896
927
  static async infoToCanvasData(info) {
897
- const image = await _ImageLoader.loadAsync(info.src);
928
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
929
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
898
930
  const canvas = createCanvas2(info.width, info.height);
899
931
  const context = canvas.getContext("2d");
900
932
  context.drawImage(image, 0, 0);
@@ -905,11 +937,8 @@ var ImageLoader = class _ImageLoader {
905
937
  };
906
938
  }
907
939
  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);
940
+ const image = await this.infoToCanvasData(info);
941
+ return image.data.getImageData(0, 0, image.width, image.height);
913
942
  }
914
943
  static async getData(src) {
915
944
  const keyStr = serializeImageKey({ src });
@@ -924,38 +953,25 @@ var ImageLoader = class _ImageLoader {
924
953
  });
925
954
  }
926
955
  static async processResponse(response) {
927
- const src = response.config.url;
956
+ const src = response.url;
928
957
  const data = import_buffer.Buffer.from(response.data);
929
958
  const { width, height, type } = Env.provider.imageSize(data);
959
+ if (!width || !height) {
960
+ throw new Error("Invalid or unsupported image dimensions");
961
+ }
930
962
  return {
931
963
  src,
932
- width: width || 0,
933
- height: height || 0,
964
+ width,
965
+ height,
934
966
  type,
935
967
  data
936
968
  };
937
969
  }
938
970
  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
971
  return Requests.genericRequest({
948
972
  url: src,
949
973
  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
- });
974
+ }).then(this.processResponse);
959
975
  }
960
976
  static async getInfo(src) {
961
977
  const keyStr = serializeImageKey({ src });
@@ -977,25 +993,39 @@ var ImageLoader = class _ImageLoader {
977
993
 
978
994
  // src/texture/TextureLoader.ts
979
995
  var TextureLoader = class {
996
+ static {
997
+ this.failedTextures = /* @__PURE__ */ new WeakSet();
998
+ }
999
+ /** Reports whether image loading failed, so cached textures can be retried. */
1000
+ static hasFailed(texture) {
1001
+ return this.failedTextures.has(texture);
1002
+ }
980
1003
  static createTexture() {
981
- return new import_three4.Texture();
1004
+ return new import_three3.Texture();
982
1005
  }
983
- static loadInBackground(src, format = import_three4.RGBAFormat, rotation = 0) {
1006
+ static loadInBackground(src, format = import_three3.RGBAFormat, rotation = 0) {
984
1007
  const texture = this.createTexture();
985
- const image = ImageLoader.loadElement(src);
986
- image.onload = function() {
1008
+ texture.colorSpace = THREE.SRGBColorSpace;
1009
+ const image = ImageLoader.loadElement(src, () => {
987
1010
  texture.needsUpdate = true;
988
- };
1011
+ }, (error) => {
1012
+ this.failedTextures.add(texture);
1013
+ console.warn("Failed to load texture", src, error);
1014
+ });
989
1015
  texture.image = image;
990
1016
  texture.format = format;
991
1017
  texture.rotation = rotation;
992
1018
  return Textures.initTextureProps(texture);
993
1019
  }
994
- static load(src, format = import_three4.RGBAFormat, rotation = 0) {
995
- const texture = new import_three4.Texture();
1020
+ static load(src, format = import_three3.RGBAFormat, rotation = 0) {
1021
+ const texture = new import_three3.Texture();
1022
+ texture.colorSpace = THREE.SRGBColorSpace;
996
1023
  ImageLoader.getData(src).then((image) => {
997
- texture.needsUpdate = true;
998
1024
  texture.image = image;
1025
+ texture.needsUpdate = true;
1026
+ }).catch((error) => {
1027
+ this.failedTextures.add(texture);
1028
+ console.warn("Failed to load texture", src, error);
999
1029
  });
1000
1030
  texture.format = format;
1001
1031
  texture.rotation = rotation;
@@ -1004,11 +1034,11 @@ var TextureLoader = class {
1004
1034
  };
1005
1035
 
1006
1036
  // src/texture/Textures.ts
1007
- var THREE = __toESM(require("three"));
1037
+ var THREE2 = __toESM(require("three"));
1008
1038
  var Textures = class _Textures {
1009
1039
  static initTextureProps(texture) {
1010
- texture.magFilter = THREE.NearestFilter;
1011
- texture.minFilter = THREE.NearestFilter;
1040
+ texture.magFilter = THREE2.NearestFilter;
1041
+ texture.minFilter = THREE2.NearestFilter;
1012
1042
  texture.anisotropy = 0;
1013
1043
  return texture;
1014
1044
  }
@@ -1016,13 +1046,19 @@ var Textures = class _Textures {
1016
1046
  return TextureLoader.load(key.src, key.format, key.rotation);
1017
1047
  }
1018
1048
  static createAsset(key) {
1019
- return new import_three5.Texture();
1049
+ return new import_three4.Texture();
1020
1050
  }
1021
1051
  static createCanvasTexture(canvas) {
1022
- return this.initTextureProps(new import_three5.CanvasTexture(canvas));
1052
+ const texture = new import_three4.CanvasTexture(canvas);
1053
+ texture.colorSpace = THREE2.SRGBColorSpace;
1054
+ return this.initTextureProps(texture);
1023
1055
  }
1024
1056
  static getImage(key) {
1025
1057
  const keyStr = serializeTextureKey(key);
1058
+ const cached = Caching.textureCache.peek(keyStr);
1059
+ if (cached && TextureLoader.hasFailed(cached)) {
1060
+ Caching.textureCache.invalidate(keyStr);
1061
+ }
1026
1062
  return Caching.textureCache.get(keyStr, (k) => {
1027
1063
  return _Textures.createImage(key);
1028
1064
  });
@@ -1030,7 +1066,10 @@ var Textures = class _Textures {
1030
1066
  };
1031
1067
 
1032
1068
  // src/Materials.ts
1033
- var _Materials = class _Materials {
1069
+ var Materials = class _Materials {
1070
+ static {
1071
+ this.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1072
+ }
1034
1073
  // resolved lazily: as a static field this decoded an image the moment the library was
1035
1074
  // imported, which needs both a DOM and an EnvProvider to already be in place
1036
1075
  static get MISSING_TEXTURE() {
@@ -1038,26 +1077,26 @@ var _Materials = class _Materials {
1038
1077
  }
1039
1078
  static createImage(key) {
1040
1079
  const transparent = key.transparent || false;
1041
- return new import_three6.MeshBasicMaterial({
1080
+ return new import_three5.MeshBasicMaterial({
1042
1081
  map: Textures.getImage(key.texture),
1043
1082
  transparent,
1044
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1083
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1045
1084
  alphaTest: 0.5
1046
1085
  });
1047
1086
  }
1048
1087
  static createBasicCanvasMaterial(canvas, transparent = false, shade = false) {
1049
1088
  if (shade) {
1050
- return new import_three6.MeshStandardMaterial({
1089
+ return new import_three5.MeshStandardMaterial({
1051
1090
  map: Textures.createCanvasTexture(canvas),
1052
1091
  transparent,
1053
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1092
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1054
1093
  alphaTest: 0.5
1055
1094
  });
1056
1095
  }
1057
- return new import_three6.MeshBasicMaterial({
1096
+ return new import_three5.MeshBasicMaterial({
1058
1097
  map: Textures.createCanvasTexture(canvas),
1059
1098
  transparent,
1060
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1099
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1061
1100
  alphaTest: 0.5
1062
1101
  });
1063
1102
  }
@@ -1066,6 +1105,7 @@ var _Materials = class _Materials {
1066
1105
  uniform bool SHADE;
1067
1106
 
1068
1107
  varying vec2 vUv;
1108
+ varying vec3 vTint;
1069
1109
  varying float light;
1070
1110
  varying float lift;
1071
1111
 
@@ -1078,7 +1118,11 @@ var _Materials = class _Materials {
1078
1118
 
1079
1119
  if (SHADE) {
1080
1120
 
1081
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1121
+ #ifdef USE_INSTANCING
1122
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
1123
+ #else
1124
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
1125
+ #endif
1082
1126
 
1083
1127
  float yLight = (1.0+N.y) * 0.5;
1084
1128
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -1096,6 +1140,7 @@ var _Materials = class _Materials {
1096
1140
  }
1097
1141
 
1098
1142
  vUv = uv;
1143
+ vTint = color;
1099
1144
 
1100
1145
  #ifdef USE_INSTANCING
1101
1146
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -1117,12 +1162,14 @@ var _Materials = class _Materials {
1117
1162
  uniform float BRIGHTNESS;
1118
1163
 
1119
1164
  varying vec2 vUv;
1165
+ varying vec3 vTint;
1120
1166
  varying float light;
1121
1167
  varying float lift;
1122
1168
 
1123
1169
  void main(void)
1124
1170
  {
1125
1171
  vec4 color = texture2D(map, vUv);
1172
+ color.rgb *= vTint;
1126
1173
 
1127
1174
  if (color.a < 0.01) discard;
1128
1175
 
@@ -1136,16 +1183,19 @@ var _Materials = class _Materials {
1136
1183
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1137
1184
 
1138
1185
  }
1186
+
1187
+ #include <tonemapping_fragment>
1188
+ #include <colorspace_fragment>
1139
1189
  }
1140
1190
  `;
1141
1191
  try {
1142
- return new import_three6.ShaderMaterial({
1192
+ return new import_three5.ShaderMaterial({
1143
1193
  uniforms: {
1144
1194
  SHADE: { value: true },
1145
1195
  BRIGHTNESS: { value: 1 },
1146
1196
  EMISSIVE: { value: false },
1147
1197
  base: {
1148
- value: new import_three6.Color(12698049)
1198
+ value: new import_three5.Color(12698049)
1149
1199
  /*TODO*/
1150
1200
  },
1151
1201
  map: { value: Textures.createCanvasTexture(canvas) }
@@ -1154,7 +1204,7 @@ var _Materials = class _Materials {
1154
1204
  fragmentShader: fragShader,
1155
1205
  vertexColors: true,
1156
1206
  transparent,
1157
- side: transparent ? import_three6.DoubleSide : import_three6.FrontSide,
1207
+ side: transparent ? import_three5.DoubleSide : import_three5.FrontSide,
1158
1208
  alphaTest: 0.5
1159
1209
  });
1160
1210
  } catch (e) {
@@ -1164,6 +1214,10 @@ var _Materials = class _Materials {
1164
1214
  }
1165
1215
  static getImage(key) {
1166
1216
  const keyStr = serializeMaterialKey(key);
1217
+ const map = Caching.materialCache.peek(keyStr)?.map;
1218
+ if (map && TextureLoader.hasFailed(map)) {
1219
+ Caching.materialCache.invalidate(keyStr);
1220
+ }
1167
1221
  return Caching.materialCache.get(keyStr, (k) => {
1168
1222
  return _Materials.createImage(key);
1169
1223
  });
@@ -1184,14 +1238,12 @@ var _Materials = class _Materials {
1184
1238
  }
1185
1239
  }
1186
1240
  };
1187
- _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1188
- var Materials = _Materials;
1189
1241
 
1190
1242
  // src/Meshes.ts
1191
- var import_three7 = require("three");
1243
+ var import_three6 = require("three");
1192
1244
  var Meshes = class _Meshes {
1193
1245
  static createBox(key) {
1194
- return new import_three7.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1246
+ return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1195
1247
  }
1196
1248
  static getBox(key) {
1197
1249
  const keyStr = serializeMeshKey(key);
@@ -1238,9 +1290,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1238
1290
  this.rootType = rootType;
1239
1291
  this.extension = extension;
1240
1292
  this.root = root;
1293
+ this.isAssetKey = true;
1241
1294
  }
1242
1295
  static parse(assetType, str, origin) {
1243
- let namespace = (origin == null ? void 0 : origin.namespace) || DEFAULT_NAMESPACE;
1296
+ let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1244
1297
  if (str.includes(":")) {
1245
1298
  let split2 = str.split(":");
1246
1299
  namespace = split2[0];
@@ -1253,12 +1306,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1253
1306
  split.shift();
1254
1307
  }
1255
1308
  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);
1309
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1310
+ if (extension && path.endsWith(extension)) {
1311
+ path = path.slice(0, -extension.length);
1312
+ }
1313
+ return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1258
1314
  }
1259
1315
  toString() {
1260
1316
  let a = [
1261
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1317
+ this.root ?? AssetLoader.ROOT,
1262
1318
  this.rootType ?? "__rootType__",
1263
1319
  this.assetType ?? "__assetType__",
1264
1320
  this.type ?? "__type__",
@@ -1268,12 +1324,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1268
1324
  return a.join("/");
1269
1325
  }
1270
1326
  getFullPath() {
1271
- let p13 = [];
1327
+ let p12 = [];
1272
1328
  if (this.type) {
1273
- p13.push(this.type);
1329
+ p12.push(this.type);
1274
1330
  }
1275
- p13.push(this.path);
1276
- return p13.join("/");
1331
+ p12.push(this.path);
1332
+ return p12.join("/");
1277
1333
  }
1278
1334
  toNamespacedString() {
1279
1335
  return this.namespace + ":" + this.getFullPath();
@@ -1283,10 +1339,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1283
1339
  }
1284
1340
  };
1285
1341
  function isBasicAssetKey(obj) {
1286
- return "namespace" in obj && "path" in obj;
1342
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1287
1343
  }
1288
1344
  function isAssetKey(obj) {
1289
- return isBasicAssetKey(obj) && "parse" in obj;
1345
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1290
1346
  }
1291
1347
 
1292
1348
  // src/model/ModelMerger.ts
@@ -1295,10 +1351,10 @@ var ModelMerger = class {
1295
1351
  const models = await this.collectAllParents(model);
1296
1352
  let merged = {};
1297
1353
  for (let parentModel of models) {
1298
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1354
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, parentModel);
1299
1355
  }
1300
- merged = (0, import_ts_deepmerge.default)(merged, model);
1301
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1356
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, model);
1357
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1302
1358
  merged.hierarchy.push(`${merged.parent}`);
1303
1359
  return merged;
1304
1360
  }
@@ -1308,6 +1364,7 @@ var ModelMerger = class {
1308
1364
  }
1309
1365
  const models = [];
1310
1366
  const parentKey = AssetKey.parse("models", model.parent);
1367
+ parentKey.root = model.key?.root;
1311
1368
  const parentModel = await Models.getRaw(parentKey);
1312
1369
  if (parentModel) {
1313
1370
  models.unshift(parentModel);
@@ -1317,9 +1374,6 @@ var ModelMerger = class {
1317
1374
  }
1318
1375
  };
1319
1376
 
1320
- // src/assets/Models.ts
1321
- var import_typescript_memoize = require("typescript-memoize");
1322
-
1323
1377
  // src/assets/source/parser/AssetParsers.ts
1324
1378
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1325
1379
  AssetParser2["MODEL"] = "model";
@@ -1333,30 +1387,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1333
1387
  })(AssetParser || {});
1334
1388
 
1335
1389
  // src/assets/Models.ts
1336
- var _Models = class _Models {
1390
+ var Models = class _Models {
1337
1391
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1338
1392
  // the library, and would require an EnvProvider before any entry has had a chance to register
1339
1393
  static get PERSISTENT_CACHE() {
1340
1394
  return this._persistentCache ??= PersistentCache.open("minerender-models");
1341
1395
  }
1342
1396
  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) ?? []);
1397
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1398
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1399
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1400
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1401
+ }).then((r) => r?.files ?? []);
1352
1402
  }
1353
1403
  static async loadAndMerge(key) {
1354
- const model = await this.getRaw(key);
1404
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1355
1405
  if (!model) {
1356
1406
  return void 0;
1357
1407
  }
1358
1408
  return ModelMerger.mergeWithParents(model);
1359
1409
  }
1410
+ static async getItemModel(key) {
1411
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1412
+ const model = await this.PERSISTENT_CACHE.getOrLoad(itemKey.serialize(), async () => {
1413
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1414
+ if (!result) return void 0;
1415
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1416
+ const reference = this.defaultItemModel(result.asset.model, key);
1417
+ const modelKey = AssetKey.parse("models", reference);
1418
+ modelKey.root = key.root;
1419
+ const model2 = await this.getRaw(modelKey);
1420
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1421
+ return model2;
1422
+ });
1423
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1424
+ }
1425
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1426
+ static defaultItemModel(node, key) {
1427
+ if (!node || typeof node.type !== "string") {
1428
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1429
+ }
1430
+ switch (node.type.replace(/^minecraft:/, "")) {
1431
+ case "model":
1432
+ if (typeof node.model === "string" && node.model) return node.model;
1433
+ break;
1434
+ case "condition":
1435
+ return this.defaultItemModel(node.on_false, key);
1436
+ case "select": {
1437
+ 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;
1438
+ return this.defaultItemModel(selected ?? node.fallback, key);
1439
+ }
1440
+ case "range_dispatch": {
1441
+ const selected = node.entries?.reduce((match, entry) => {
1442
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1443
+ }, void 0);
1444
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1445
+ }
1446
+ }
1447
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1448
+ }
1360
1449
  static async getRaw(key) {
1361
1450
  if (!key.assetType) {
1362
1451
  key.assetType = "models";
@@ -1395,19 +1484,15 @@ var _Models = class _Models {
1395
1484
  return this.PERSISTENT_CACHE.clear();
1396
1485
  }
1397
1486
  };
1398
- __decorateClass([
1399
- (0, import_typescript_memoize.Memoize)()
1400
- ], _Models, "getItemList", 1);
1401
- var Models = _Models;
1402
1487
 
1403
1488
  // src/assets/BlockStates.ts
1404
- var import_typescript_memoize2 = require("typescript-memoize");
1405
1489
  var BlockStates = class {
1406
1490
  static get PERSISTENT_CACHE() {
1407
1491
  return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
1408
1492
  }
1493
+ // BlockState names are hardcoded
1409
1494
  static async getList() {
1410
- return AssetLoader.get(new AssetKey(
1495
+ const key = new AssetKey(
1411
1496
  DEFAULT_NAMESPACE,
1412
1497
  "_list",
1413
1498
  "blockstates",
@@ -1415,11 +1500,16 @@ var BlockStates = class {
1415
1500
  "assets",
1416
1501
  ".json",
1417
1502
  DEFAULT_ROOT
1418
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1503
+ );
1504
+ return Caching.listAssetCache.get(key.serialize(), () => {
1505
+ return AssetLoader.get(key, "list" /* LIST */);
1506
+ }).then((r) => r?.files ?? []);
1419
1507
  }
1420
1508
  static async getDefaultStates() {
1421
1509
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1422
- return AssetLoader.get(key, "json" /* JSON */);
1510
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1511
+ return AssetLoader.get(key, "json" /* JSON */);
1512
+ });
1423
1513
  }
1424
1514
  static async getDefaultState(key) {
1425
1515
  const defaultStates = await this.getDefaultStates();
@@ -1458,17 +1548,11 @@ var BlockStates = class {
1458
1548
  await this.PERSISTENT_CACHE.clear();
1459
1549
  }
1460
1550
  };
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
1551
  var DefaultBlockStates = class {
1468
1552
  };
1469
1553
 
1470
1554
  // src/assets/Assets.ts
1471
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1555
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1472
1556
  var DEFAULT_NAMESPACE = "minecraft";
1473
1557
  var Assets = class {
1474
1558
  /**
@@ -1490,23 +1574,236 @@ var AssetSource = class {
1490
1574
  constructor() {
1491
1575
  }
1492
1576
  };
1577
+ var AssetLoadError = class extends Error {
1578
+ constructor(source, key, path, cause) {
1579
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1580
+ this.source = source;
1581
+ this.key = key;
1582
+ this.path = path;
1583
+ this.cause = cause;
1584
+ this.name = "AssetLoadError";
1585
+ }
1586
+ };
1493
1587
 
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;
1588
+ // src/util/BatchedExecutor.ts
1589
+ var BatchedExecutor = class {
1590
+ constructor(interval = 1, batch = 30) {
1591
+ this.interval = interval;
1592
+ this.batch = batch;
1593
+ this.queue = [];
1594
+ this.task = setInterval(() => this.run());
1595
+ }
1596
+ submit(task) {
1597
+ this.queue.push(task);
1598
+ }
1599
+ run() {
1600
+ for (let i = 0; i < this.batch; i++) {
1601
+ this.runNext();
1602
+ }
1603
+ }
1604
+ runNext() {
1605
+ let next = this.queue.shift();
1606
+ if (next) next();
1500
1607
  }
1501
1608
  };
1502
1609
 
1503
- // src/assets/source/HostedAssetSource.ts
1610
+ // src/util/model.ts
1611
+ var import_three7 = require("three");
1612
+ function applyElementRotation(rotation, geometry) {
1613
+ const origin = new import_three7.Vector3(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1614
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1615
+ switch (rotation.axis) {
1616
+ case "x" /* X */:
1617
+ geometry.rotateX(toRadians(rotation.angle));
1618
+ break;
1619
+ case "y" /* Y */:
1620
+ geometry.rotateY(toRadians(rotation.angle));
1621
+ break;
1622
+ case "z" /* Z */:
1623
+ geometry.rotateZ(toRadians(rotation.angle));
1624
+ break;
1625
+ }
1626
+ if (rotation.rescale) {
1627
+ if (Math.abs(rotation.angle) === 22.5) {
1628
+ const s = 1 / Math.cos(0.39269909262657166);
1629
+ geometry.scale(s, 1, s);
1630
+ } else {
1631
+ const s = 1 / Math.cos(0.7853981852531433);
1632
+ geometry.scale(s, 1, s);
1633
+ }
1634
+ }
1635
+ geometry.translate(origin.x, origin.y, origin.z);
1636
+ }
1637
+ function applyModelPartRotation(modelPart, geometry) {
1638
+ const origin = new import_three7.Vector3(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
1639
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1640
+ geometry.rotateX(toRadians(modelPart.pitch));
1641
+ geometry.rotateY(toRadians(modelPart.yaw));
1642
+ geometry.rotateZ(toRadians(modelPart.roll));
1643
+ geometry.translate(origin.x, origin.y, origin.z);
1644
+ }
1645
+ function applyGenericRotation(axis, rotation, obj) {
1646
+ switch (axis) {
1647
+ case "x" /* X */:
1648
+ obj.rotateOnAxis(new import_three7.Vector3(1, 0, 0), toRadians(rotation));
1649
+ break;
1650
+ case "y" /* Y */:
1651
+ obj.rotateOnAxis(new import_three7.Vector3(0, 1, 0), toRadians(rotation));
1652
+ break;
1653
+ case "z" /* Z */:
1654
+ obj.rotateOnAxis(new import_three7.Vector3(0, 0, 1), toRadians(rotation));
1655
+ break;
1656
+ }
1657
+ }
1658
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1659
+ let size = new import_three7.Vector3();
1660
+ box.getSize(size);
1661
+ let boxGeo = new import_three7.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
1662
+ let wireGeo = new import_three7.EdgesGeometry(boxGeo);
1663
+ let wireMat = new import_three7.LineBasicMaterial({ color, linewidth: w });
1664
+ let wireframe = new import_three7.LineSegments(wireGeo, wireMat);
1665
+ obj.add(wireframe);
1666
+ let axes = new import_three7.AxesHelper(1);
1667
+ obj.add(axes);
1668
+ }
1669
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1670
+ let boxGeo = new import_three7.BoxGeometry(16, 16, 16, 1, 1, 1);
1671
+ let wireGeo = new import_three7.EdgesGeometry(boxGeo);
1672
+ let wireMat = new import_three7.LineBasicMaterial({ color, linewidth: w });
1673
+ let wireframe = new import_three7.LineSegments(wireGeo, wireMat);
1674
+ obj.add(wireframe);
1675
+ let axes = new import_three7.AxesHelper(1);
1676
+ obj.add(axes);
1677
+ }
1678
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1679
+ let wireGeo = new import_three7.EdgesGeometry(geo);
1680
+ let wireMat = new import_three7.LineBasicMaterial({ color, linewidth: w });
1681
+ let wireframe = new import_three7.LineSegments(wireGeo, wireMat);
1682
+ mesh.add(wireframe);
1683
+ let axes = new import_three7.AxesHelper(1);
1684
+ mesh.add(axes);
1685
+ }
1686
+
1687
+ // src/util/performance.ts
1688
+ function captureException(e, ...extra) {
1689
+ console.error(e, extra);
1690
+ }
1691
+ function timingStart(marker) {
1692
+ console.time(marker);
1693
+ }
1694
+ function timingEnd(marker) {
1695
+ console.timeEnd(marker);
1696
+ }
1697
+
1698
+ // src/util/three.ts
1699
+ function isObject3D(obj) {
1700
+ return obj.isObject3D;
1701
+ }
1702
+ function isMesh(obj) {
1703
+ return obj.isMesh;
1704
+ }
1705
+ function isInstancedMesh(obj) {
1706
+ return obj.isInstancedMesh;
1707
+ }
1708
+ function isPerspectiveCamera(obj) {
1709
+ return obj.isPerspectiveCamera;
1710
+ }
1711
+ function isOrthographicCamera(obj) {
1712
+ return obj.isOrthographicCamera;
1713
+ }
1714
+
1715
+ // src/nbt/NBTHelper.ts
1716
+ var NBTHelper = class {
1717
+ static async fromBuffer(buffer) {
1718
+ const prismarineNbt = await import("prismarine-nbt");
1719
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1720
+ return parsed;
1721
+ }
1722
+ };
1723
+
1724
+ // src/assets/source/HostedAssetSource.ts
1504
1725
  var import_ts_deepmerge2 = __toESM(require_dist());
1505
1726
  var p3 = prefix("HostedAssetSource");
1506
1727
  var DEFAULT_OPTIONS = {
1507
1728
  retryDefaults: true
1508
1729
  };
1509
- var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1730
+ var HostedAssetSource = class _HostedAssetSource extends AssetSource {
1731
+ static {
1732
+ this.MODEL = {
1733
+ config(request) {
1734
+ },
1735
+ parse(response) {
1736
+ return response.data;
1737
+ }
1738
+ };
1739
+ }
1740
+ static {
1741
+ this.BLOCKSTATE = {
1742
+ config(request) {
1743
+ },
1744
+ parse(response) {
1745
+ return response.data;
1746
+ }
1747
+ };
1748
+ }
1749
+ static {
1750
+ this.META = {
1751
+ config(request) {
1752
+ },
1753
+ parse(response) {
1754
+ return response.data;
1755
+ }
1756
+ };
1757
+ }
1758
+ static {
1759
+ this.NBT = {
1760
+ config(request) {
1761
+ request.responseType = "arraybuffer";
1762
+ },
1763
+ parse(response) {
1764
+ return NBTHelper.fromBuffer(Buffer.from(response.data));
1765
+ }
1766
+ };
1767
+ }
1768
+ static {
1769
+ this.IMAGE = {
1770
+ config(request) {
1771
+ request.responseType = "arraybuffer";
1772
+ },
1773
+ async parse(response) {
1774
+ return await ImageLoader.processResponse(response);
1775
+ }
1776
+ };
1777
+ }
1778
+ static {
1779
+ this.LIST = {
1780
+ config(request) {
1781
+ },
1782
+ parse(response) {
1783
+ return response.data;
1784
+ }
1785
+ };
1786
+ }
1787
+ static {
1788
+ this.JSON = {
1789
+ config(request) {
1790
+ },
1791
+ parse(response) {
1792
+ return response.data;
1793
+ }
1794
+ };
1795
+ }
1796
+ static {
1797
+ this.PARSER_MAP = /* @__PURE__ */ new Map([
1798
+ ["model" /* MODEL */, _HostedAssetSource.MODEL],
1799
+ ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1800
+ ["meta" /* META */, _HostedAssetSource.META],
1801
+ ["nbt" /* NBT */, _HostedAssetSource.NBT],
1802
+ ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1803
+ ["list" /* LIST */, _HostedAssetSource.LIST],
1804
+ ["json" /* JSON */, _HostedAssetSource.JSON]
1805
+ ]);
1806
+ }
1510
1807
  async loadOrRetryWithDefaults(key, parser) {
1511
1808
  const direct = await this.load(key, parser);
1512
1809
  if (typeof direct !== "undefined") {
@@ -1541,31 +1838,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1541
1838
  console.info(p3, "Loading", key);
1542
1839
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1543
1840
  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");
1841
+ const request = { url };
1842
+ try {
1843
+ parser.config(request);
1844
+ let response;
1845
+ try {
1846
+ response = await Requests.mcAssetRequest(request);
1847
+ } catch (cause) {
1848
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1563
1849
  return void 0;
1564
1850
  }
1851
+ throw cause;
1565
1852
  }
1566
- console.debug(p3, "Failed to load", key, err == null ? void 0 : err.message);
1567
- return void 0;
1568
- });
1853
+ if (response.data === void 0) {
1854
+ throw new Error("Asset response has no data");
1855
+ }
1856
+ return await parser.parse(response);
1857
+ } catch (cause) {
1858
+ throw new AssetLoadError(this, key, request.url, cause);
1859
+ }
1569
1860
  }
1570
1861
  assetBasePath(key) {
1571
1862
  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 +1880,6 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1589
1880
  return this.load(key, responseParser);
1590
1881
  }
1591
1882
  };
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
1883
 
1654
1884
  // src/assets/source/archive/BrowserArchiveProxy.ts
1655
1885
  var import_zip = require("@zip.js/zip.js");
@@ -1672,7 +1902,6 @@ var BrowserArchiveProxy = class {
1672
1902
  };
1673
1903
 
1674
1904
  // src/assets/source/archive/ArchiveAssetSource.ts
1675
- var p4 = prefix("ArchiveAssetSource");
1676
1905
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1677
1906
  constructor(archiveProxy) {
1678
1907
  super();
@@ -1691,74 +1920,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1691
1920
  }
1692
1921
  async get(key, parser) {
1693
1922
  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
- });
1923
+ return this.load(key, responseParser);
1731
1924
  }
1732
- //TODO: abstract this
1733
1925
  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
- }
1926
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1927
+ let url;
1928
+ try {
1929
+ const entry = await this.getEntry(path);
1930
+ if (!entry) {
1931
+ return void 0;
1749
1932
  }
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
- }
1933
+ url = URL.createObjectURL(await entry.getData());
1934
+ const request = { url };
1935
+ parser.config(request);
1936
+ const response = await Requests.genericRequest(request);
1937
+ if (response.data === void 0) {
1938
+ throw new Error("Asset response has no data");
1758
1939
  }
1759
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1760
- return void 0;
1761
- });
1940
+ return await parser.parse(response);
1941
+ } catch (cause) {
1942
+ throw new AssetLoadError(this, key, path, cause);
1943
+ } finally {
1944
+ if (url !== void 0) {
1945
+ URL.revokeObjectURL(url);
1946
+ }
1947
+ }
1762
1948
  }
1763
1949
  assetBasePath(key) {
1764
1950
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1766,18 +1952,23 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1766
1952
  };
1767
1953
 
1768
1954
  // src/assets/AssetLoader.ts
1769
- var import_ts_deepmerge3 = __toESM(require_dist());
1770
- var p5 = prefix("AssetLoader");
1771
- var _AssetLoader = class _AssetLoader {
1955
+ var p4 = prefix("AssetLoader");
1956
+ var AssetLoader = class {
1957
+ static {
1958
+ this.ROOT = DEFAULT_ROOT;
1959
+ }
1960
+ static {
1961
+ this._SOURCES = [];
1962
+ }
1772
1963
  static addSource(key, source, override = true) {
1773
1964
  if (override) {
1774
1965
  const existing = this.removeSource(key);
1775
1966
  if (existing) {
1776
- console.log(p5, "Removed existing AssetSource", key);
1967
+ console.log(p4, "Removed existing AssetSource", key);
1777
1968
  }
1778
1969
  }
1779
1970
  this._SOURCES.unshift({ key, source });
1780
- console.log(p5, "Added AssetSource", key);
1971
+ console.log(p4, "Added AssetSource", key);
1781
1972
  }
1782
1973
  static removeSource(key) {
1783
1974
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1789,8 +1980,11 @@ var _AssetLoader = class _AssetLoader {
1789
1980
  }
1790
1981
  return void 0;
1791
1982
  }
1983
+ static {
1984
+ this.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1985
+ this.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
1986
+ }
1792
1987
  static async getAll(key, parser) {
1793
- console.log(this._SOURCES);
1794
1988
  let promises = [];
1795
1989
  for (const source of this._SOURCES) {
1796
1990
  promises.push(source.source.get(key, parser));
@@ -1799,31 +1993,36 @@ var _AssetLoader = class _AssetLoader {
1799
1993
  return results.filter((r) => r != void 0);
1800
1994
  });
1801
1995
  }
1996
+ /** Returns the first defined result in source-priority order, without merging assets. */
1802
1997
  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;
1998
+ const keys = [key];
1999
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
2000
+ keys.push(new AssetKey(
2001
+ key.namespace,
2002
+ key.path,
2003
+ key.assetType === "structure" ? "structures" : "structure",
2004
+ key.type,
2005
+ key.rootType,
2006
+ key.extension,
2007
+ key.root
2008
+ ));
2009
+ }
2010
+ return (await this.getFirst(keys, parser))?.asset;
2011
+ }
2012
+ /** Tries each path within a source before considering lower-priority sources. */
2013
+ static async getFirst(keys, parser) {
2014
+ const sources = [...this._SOURCES];
2015
+ for (const source of sources) {
2016
+ for (const key of keys) {
2017
+ const result = await source.source.get(key, parser);
2018
+ if (result !== void 0) {
2019
+ return { key, asset: result };
1816
2020
  }
1817
2021
  }
1818
- return void 0;
1819
- });
2022
+ }
2023
+ return void 0;
1820
2024
  }
1821
2025
  };
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
2026
 
1828
2027
  // src/assets/ModelTextures.ts
1829
2028
  var ModelTextures = class {
@@ -1831,11 +2030,21 @@ var ModelTextures = class {
1831
2030
  return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
1832
2031
  }
1833
2032
  static async get(key) {
1834
- const asset = await this.preload(key);
1835
- if (asset) {
1836
- return ImageLoader.infoToCanvasData(asset);
2033
+ const keyStr = key.serialize();
2034
+ const pending = this.preload(key);
2035
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
2036
+ try {
2037
+ const asset = await pending;
2038
+ if (asset) {
2039
+ return await ImageLoader.infoToCanvasData(asset);
2040
+ }
2041
+ return void 0;
2042
+ } catch (err) {
2043
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
2044
+ Caching.textureAssetCache.invalidate(keyStr);
2045
+ }
2046
+ throw err;
1837
2047
  }
1838
- return void 0;
1839
2048
  }
1840
2049
  static async preload(key) {
1841
2050
  const keyStr = key.serialize();
@@ -1909,7 +2118,28 @@ var CanvasImage = class {
1909
2118
  };
1910
2119
 
1911
2120
  // src/Ticker.ts
1912
- var _Ticker = class _Ticker {
2121
+ var Ticker = class _Ticker {
2122
+ static {
2123
+ this.TPS = 20;
2124
+ }
2125
+ static {
2126
+ this.counter = 0;
2127
+ }
2128
+ static {
2129
+ this._tickers = /* @__PURE__ */ new Map();
2130
+ }
2131
+ static {
2132
+ this.oneSecondTps = 0;
2133
+ }
2134
+ static {
2135
+ this.oneSecondTicks = 0;
2136
+ }
2137
+ static {
2138
+ this.fiveSecondTps = 0;
2139
+ }
2140
+ static {
2141
+ this.fiveSecondTicks = 0;
2142
+ }
1913
2143
  static schedule(fn, ms) {
1914
2144
  const handle = setInterval(fn, ms);
1915
2145
  const unref = handle.unref;
@@ -1971,14 +2201,6 @@ var _Ticker = class _Ticker {
1971
2201
  this._tickers.clear();
1972
2202
  }
1973
2203
  };
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
2204
 
1983
2205
  // src/texture/TextureAtlas.ts
1984
2206
  var TextureAtlas = class {
@@ -2004,18 +2226,24 @@ var TextureAtlas = class {
2004
2226
 
2005
2227
  // src/model/ModelGenerator.ts
2006
2228
  var ModelGenerator = class {
2229
+ static {
2230
+ this.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2231
+ }
2007
2232
  static generateItemModel(imageData, layer) {
2233
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
2008
2234
  const mainElement = {
2009
2235
  from: [0, 0, 7.5],
2010
2236
  to: [16, 16, 8.5],
2011
2237
  faces: {
2012
2238
  "south": {
2013
2239
  uv: [0, 0, 16, 16],
2014
- texture: `#${layer}`
2240
+ texture: `#${layer}`,
2241
+ tintindex
2015
2242
  },
2016
2243
  "north": {
2017
2244
  uv: [16, 0, 0, 16],
2018
- texture: `#${layer}`
2245
+ texture: `#${layer}`,
2246
+ tintindex
2019
2247
  }
2020
2248
  },
2021
2249
  shade: true
@@ -2023,14 +2251,21 @@ var ModelGenerator = class {
2023
2251
  return [mainElement];
2024
2252
  }
2025
2253
  };
2026
- ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2027
2254
 
2028
2255
  // src/UVMapper.ts
2029
- var p6 = prefix("UVMapper");
2256
+ var p5 = prefix("UVMapper");
2030
2257
  var DEFAULT_UV = [0, 0, 16, 16];
2031
2258
  var X = 0;
2032
2259
  var Y = 1;
2033
2260
  var Z = 2;
2261
+ var FACE_UV_AXES = {
2262
+ east: [new import_three8.Vector3(0, 0, -1), new import_three8.Vector3(0, -1, 0)],
2263
+ west: [new import_three8.Vector3(0, 0, 1), new import_three8.Vector3(0, -1, 0)],
2264
+ up: [new import_three8.Vector3(1, 0, 0), new import_three8.Vector3(0, 0, 1)],
2265
+ down: [new import_three8.Vector3(1, 0, 0), new import_three8.Vector3(0, 0, -1)],
2266
+ south: [new import_three8.Vector3(1, 0, 0), new import_three8.Vector3(0, -1, 0)],
2267
+ north: [new import_three8.Vector3(-1, 0, 0), new import_three8.Vector3(0, -1, 0)]
2268
+ };
2034
2269
  var UVMapper = class {
2035
2270
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
2036
2271
  if (uvCoord === 0) return 0;
@@ -2128,6 +2363,42 @@ var UVMapper = class {
2128
2363
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2129
2364
  return new import_three8.Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2130
2365
  }
2366
+ static lockUvs(geometry, faces, atlas, rotation) {
2367
+ const uv = geometry.getAttribute("uv");
2368
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2369
+ const faceName = CUBE_FACES[faceIndex];
2370
+ const texture = faces[faceName]?.texture?.substring(1);
2371
+ const position = texture && atlas.positions[texture];
2372
+ const size = texture && atlas.sizes[texture];
2373
+ if (!position || !size) continue;
2374
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2375
+ const uAxis = sourceU.clone().applyEuler(rotation);
2376
+ const vAxis = sourceV.clone().applyEuler(rotation);
2377
+ const normal = vAxis.clone().cross(uAxis);
2378
+ const targetFace = CUBE_FACES.find((name) => {
2379
+ const [u, v] = FACE_UV_AXES[name];
2380
+ return v.clone().cross(u).dot(normal) > 0.5;
2381
+ });
2382
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2383
+ const uu = Math.round(targetU.dot(uAxis));
2384
+ const uvCross = Math.round(targetU.dot(vAxis));
2385
+ const vu = Math.round(targetV.dot(uAxis));
2386
+ const vv = Math.round(targetV.dot(vAxis));
2387
+ for (let corner = 0; corner < 4; corner++) {
2388
+ const index = faceIndex * 4 + corner;
2389
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2390
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2391
+ const lockedU = uu * u + uvCross * v + 0.5;
2392
+ const lockedV = vu * u + vv * v + 0.5;
2393
+ uv.setXY(
2394
+ index,
2395
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2396
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2397
+ );
2398
+ }
2399
+ }
2400
+ uv.needsUpdate = true;
2401
+ }
2131
2402
  static async getAtlas(model) {
2132
2403
  const keyStr = model.key.serialize();
2133
2404
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -2199,12 +2470,11 @@ var UVMapper = class {
2199
2470
  return [tl, tr, bl, br];
2200
2471
  }
2201
2472
  static async createAtlas(originalModel) {
2202
- var _a;
2203
2473
  const textureMap = {};
2204
2474
  const metaMap = {};
2205
2475
  const model = { ...originalModel };
2206
2476
  const isItemModel = !("elements" in model);
2207
- console.debug(p6, "Creating Atlas for", model.key);
2477
+ console.debug(p5, "Creating Atlas for", model.key);
2208
2478
  if (model.textures) {
2209
2479
  const promises = [];
2210
2480
  const uniqueTextureNames = [];
@@ -2218,7 +2488,7 @@ var UVMapper = class {
2218
2488
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2219
2489
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2220
2490
  if (!asset) {
2221
- console.warn(p6, "Missing texture", assetKey);
2491
+ console.warn(p5, "Missing texture", assetKey);
2222
2492
  return;
2223
2493
  }
2224
2494
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2230,7 +2500,7 @@ var UVMapper = class {
2230
2500
  }
2231
2501
  await Promise.all(promises);
2232
2502
  const textureCount = uniqueTextureNames.length;
2233
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2503
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2234
2504
  this.fillMissingTextureKeys(model.textures, textureMap);
2235
2505
  this.fillMissingTextureKeys(model.textures, metaMap);
2236
2506
  const sizes = {};
@@ -2250,7 +2520,7 @@ var UVMapper = class {
2250
2520
  this.fillMissingTextureKeys(model.textures, sizes);
2251
2521
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2252
2522
  const size = Math.ceil(s * maxWidth);
2253
- console.debug(p6, "Atlas size:", size);
2523
+ console.debug(p5, "Atlas size:", size);
2254
2524
  const squaredSize = size * size;
2255
2525
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2256
2526
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2279,16 +2549,15 @@ var UVMapper = class {
2279
2549
  if (texture.animated) {
2280
2550
  hasAnimation = true;
2281
2551
  const meta = metaMap[textureKey];
2282
- const frameTime = ((_a = meta == null ? void 0 : meta.animation) == null ? void 0 : _a.frametime) ?? 1;
2552
+ const frameTime = meta?.animation?.frametime ?? 1;
2283
2553
  console.log(meta);
2284
2554
  console.log(frameTime);
2285
2555
  let t = 0;
2286
2556
  let f = 0;
2287
2557
  animatorFunctions[textureKey] = () => {
2288
- var _a2;
2289
2558
  if (t++ >= frameTime) {
2290
2559
  t = 0;
2291
- const frames = (_a2 = meta == null ? void 0 : meta.animation) == null ? void 0 : _a2.frames;
2560
+ const frames = meta?.animation?.frames;
2292
2561
  const frame = frames ? frames[f] : f;
2293
2562
  image.putData(texture.getFrameSectionData(frame), x, y, 0, 0, maxWidth, maxWidth);
2294
2563
  f++;
@@ -2306,10 +2575,10 @@ var UVMapper = class {
2306
2575
  }
2307
2576
  }
2308
2577
  const atlasImageData = image.toDataURL();
2309
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2578
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2310
2579
  this.fillMissingTextureKeys(model.textures, positions);
2311
2580
  if (isItemModel) {
2312
- console.debug(p6, "Generating item model for", model);
2581
+ console.debug(p5, "Generating item model for", model);
2313
2582
  model.elements = [];
2314
2583
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2315
2584
  const textureImage = textureMap[layerName];
@@ -2317,7 +2586,7 @@ var UVMapper = class {
2317
2586
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2318
2587
  }
2319
2588
  }
2320
- console.debug(p6, "Item model elements", model.elements);
2589
+ console.debug(p5, "Item model elements", model.elements);
2321
2590
  }
2322
2591
  if (!model.elements) {
2323
2592
  }
@@ -2335,17 +2604,13 @@ var UVMapper = class {
2335
2604
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2336
2605
  continue;
2337
2606
  }
2607
+ if (!face.texture) continue;
2338
2608
  if (!face.uv) {
2339
2609
  face.uv = this.getFallbackUv(element, faceName);
2340
2610
  }
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
- }
2611
+ const faceTexture = face.texture.substr(1);
2612
+ const texPosition = positions[faceTexture] || [0, 0];
2613
+ const texSize = sizes[faceTexture] || [16, 16];
2349
2614
  let texPosV = new import_three8.Vector2(texPosition[0], texPosition[1]);
2350
2615
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2351
2616
  tl.add(texPosV);
@@ -2377,7 +2642,7 @@ var UVMapper = class {
2377
2642
  hasTransparency
2378
2643
  );
2379
2644
  } else {
2380
- console.warn(p6, "Model does not have any textures", model);
2645
+ console.warn(p5, "Model does not have any textures", model);
2381
2646
  }
2382
2647
  return void 0;
2383
2648
  }
@@ -2515,17 +2780,20 @@ function shutdown() {
2515
2780
  }
2516
2781
 
2517
2782
  // src/assets/Entities.ts
2518
- var import_typescript_memoize3 = require("typescript-memoize");
2519
2783
  var Entities = class {
2520
2784
  static async getBlockEntityModels() {
2521
2785
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2522
2786
  console.log(key);
2523
- return AssetLoader.get(key, "json" /* JSON */);
2787
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2788
+ return AssetLoader.get(key, "json" /* JSON */);
2789
+ });
2524
2790
  }
2525
2791
  static async getEntityModels() {
2526
2792
  const key = AssetKey.parse("models", "minerender:entityModels");
2527
2793
  console.log(key);
2528
- return AssetLoader.get(key, "json" /* JSON */);
2794
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2795
+ return AssetLoader.get(key, "json" /* JSON */);
2796
+ });
2529
2797
  }
2530
2798
  // BlockEntity names are hardcoded
2531
2799
  static async getBlockList() {
@@ -2571,12 +2839,6 @@ var Entities = class {
2571
2839
  };
2572
2840
  }
2573
2841
  };
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
2842
  var EntityModels = class {
2581
2843
  };
2582
2844
  var BlockEntityModels = class {
@@ -2640,18 +2902,26 @@ var MineRenderError = class _MineRenderError extends Error {
2640
2902
  };
2641
2903
 
2642
2904
  // 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 {
2905
+ var import_ts_deepmerge3 = __toESM(require_dist());
2906
+ var p6 = prefix("SceneObject");
2907
+ var SceneObject = class _SceneObject extends import_three9.Object3D {
2646
2908
  constructor(options) {
2647
2909
  super();
2648
2910
  this.isSceneObject = true;
2649
2911
  this.materialCallbacks = {};
2650
2912
  this._isInstanced = false;
2651
2913
  this._instanceCounter = 0;
2652
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2914
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2653
2915
  console.log("SceneObject options", this.options);
2654
2916
  }
2917
+ static {
2918
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2919
+ instanceMeshes: true,
2920
+ maxInstanceCount: 50,
2921
+ mergeMeshes: true,
2922
+ wireframe: false
2923
+ });
2924
+ }
2655
2925
  set scene(scene) {
2656
2926
  if (!!this._scene) throw new MineRenderError("Scene already set");
2657
2927
  this._scene = scene;
@@ -2743,6 +3013,7 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2743
3013
  }
2744
3014
  createInstancedMesh(name, geometry, material, count) {
2745
3015
  const mesh = new import_three9.InstancedMesh(geometry, material, count);
3016
+ mesh.count = 0;
2746
3017
  if (name) {
2747
3018
  mesh.name = `mesh:${name}`;
2748
3019
  }
@@ -2820,9 +3091,13 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2820
3091
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2821
3092
  const i = this._instanceCounter++;
2822
3093
  this.setMatrixAt(i, new import_three9.Matrix4());
2823
- console.debug(p7, "nextInstance " + i);
3094
+ const mesh = this.children[0];
3095
+ if (mesh && isInstancedMesh(mesh)) {
3096
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
3097
+ }
3098
+ console.debug(p6, "nextInstance " + i);
2824
3099
  if (i === this.options.maxInstanceCount) {
2825
- console.warn(p7, "Max instance count reached for " + this);
3100
+ console.warn(p6, "Max instance count reached for " + this);
2826
3101
  }
2827
3102
  if (this.scene) {
2828
3103
  this.scene.stats.instanceCount++;
@@ -2993,34 +3268,29 @@ var _SceneObject = class _SceneObject extends import_three9.Object3D {
2993
3268
  this.notifyDirty();
2994
3269
  }
2995
3270
  removeFromScene() {
2996
- var _a;
2997
- (_a = this._scene) == null ? void 0 : _a.remove(this);
3271
+ this._scene?.remove(this);
2998
3272
  this.notifyDirty();
2999
3273
  }
3000
3274
  //</editor-fold>
3001
3275
  };
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
3276
  function isSceneObject(obj) {
3010
3277
  return obj.isSceneObject;
3011
3278
  }
3012
3279
 
3013
3280
  // src/entity/scene/EntityObject.ts
3014
- var import_ts_deepmerge5 = __toESM(require_dist());
3281
+ var import_ts_deepmerge4 = __toESM(require_dist());
3015
3282
  var import_three11 = require("three");
3016
- var THREE2 = __toESM(require("three"));
3283
+ var THREE3 = __toESM(require("three"));
3017
3284
  var EntityObject = class extends SceneObject {
3018
3285
  constructor(entity, options) {
3019
3286
  super();
3020
3287
  this.entity = entity;
3021
3288
  this.isEntityObject = true;
3022
3289
  this.meshesCreated = false;
3023
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3290
+ this.options = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3291
+ }
3292
+ static {
3293
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3024
3294
  }
3025
3295
  async init() {
3026
3296
  this.createMeshes();
@@ -3029,17 +3299,19 @@ var EntityObject = class extends SceneObject {
3029
3299
  dispose() {
3030
3300
  super.dispose();
3031
3301
  }
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,
3302
+ get textureKey() {
3303
+ return new AssetKey(
3304
+ this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
3036
3305
  this.entity.key.path,
3037
3306
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
3038
3307
  "textures",
3039
3308
  "entity",
3040
3309
  "assets",
3041
3310
  ".png"
3042
- ));
3311
+ );
3312
+ }
3313
+ async loadTextures() {
3314
+ this.imageData = await ModelTextures.get(this.textureKey);
3043
3315
  }
3044
3316
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
3045
3317
  createMeshes(force = false) {
@@ -3058,8 +3330,8 @@ var EntityObject = class extends SceneObject {
3058
3330
  const l = cube.maxZ - cube.minZ;
3059
3331
  const uv = texture.toUvArray(w, h, l);
3060
3332
  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));
3333
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3334
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
3063
3335
  applyModelPartRotation(part, cubeGeo);
3064
3336
  const mesh = this.createMesh(partName, cubeGeo, mat);
3065
3337
  partAnchor.add(mesh);
@@ -3072,24 +3344,25 @@ var EntityObject = class extends SceneObject {
3072
3344
  this.meshesCreated = true;
3073
3345
  }
3074
3346
  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
- }
3347
+ const assetKeyStr = this.textureKey.serialize();
3348
+ const keyStr = `entity:${assetKeyStr}`;
3349
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3350
+ if (!mat) {
3351
+ const pending = this.loadTextures();
3352
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3353
+ await pending;
3354
+ if (!this.imageData) return;
3355
+ const canvas = this.imageData.data.canvas;
3356
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3357
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3358
+ this.imageData = void 0;
3359
+ }
3360
+ this.iterateAllMeshes((mesh) => {
3361
+ mesh.material = mat;
3362
+ });
3363
+ this.notifyDirty();
3090
3364
  }
3091
3365
  };
3092
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3093
3366
  function isEntityObject(obj) {
3094
3367
  return obj.isEntityObject;
3095
3368
  }
@@ -3101,7 +3374,7 @@ var GuiObject = class extends SceneObject {
3101
3374
 
3102
3375
  // src/inspector/SceneInspector.ts
3103
3376
  var import_three12 = require("three");
3104
- var p8 = prefix("SceneInspector");
3377
+ var p7 = prefix("SceneInspector");
3105
3378
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
3106
3379
  var SceneInspector = class {
3107
3380
  constructor(renderer) {
@@ -3130,8 +3403,7 @@ var SceneInspector = class {
3130
3403
  return out;
3131
3404
  }
3132
3405
  onClick(event) {
3133
- var _a;
3134
- if (((_a = event.target) == null ? void 0 : _a.nodeName) !== "CANVAS") return;
3406
+ if (event.target?.nodeName !== "CANVAS") return;
3135
3407
  if (!event.ctrlKey) return;
3136
3408
  setTimeout(() => {
3137
3409
  this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
@@ -3171,7 +3443,7 @@ var SceneInspector = class {
3171
3443
  }
3172
3444
  selectObject(targetObject, targetIntersection) {
3173
3445
  this.selectedObject = targetObject;
3174
- console.log(p8, "selected", targetObject);
3446
+ console.log(p7, "selected", targetObject);
3175
3447
  this.redraw(targetObject, targetIntersection);
3176
3448
  }
3177
3449
  redraw(targetObject, targetIntersection) {
@@ -3469,7 +3741,7 @@ var SceneStatsDisplay = class {
3469
3741
  };
3470
3742
 
3471
3743
  // src/instance/InstanceManager.ts
3472
- var p9 = prefix("InstanceManager");
3744
+ var p8 = prefix("InstanceManager");
3473
3745
  var InstanceManager = class {
3474
3746
  constructor() {
3475
3747
  this.isInstanceManager = true;
@@ -3477,7 +3749,7 @@ var InstanceManager = class {
3477
3749
  }
3478
3750
  async get(key) {
3479
3751
  if (key in this.instanceCache) {
3480
- console.debug(p9, "key in cache", key);
3752
+ console.debug(p8, "key in cache", key);
3481
3753
  return (await this.instanceCache[key]).nextInstance();
3482
3754
  }
3483
3755
  return void 0;
@@ -3486,13 +3758,17 @@ var InstanceManager = class {
3486
3758
  if (key in this.instanceCache) {
3487
3759
  return await this.get(key);
3488
3760
  }
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];
3761
+ console.debug(p8, "key not in cache", key);
3762
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3763
+ this.instanceCache[key] = pending;
3764
+ try {
3765
+ return await pending;
3766
+ } catch (error) {
3767
+ if (this.instanceCache[key] === pending) {
3768
+ delete this.instanceCache[key];
3769
+ }
3770
+ throw error;
3771
+ }
3496
3772
  }
3497
3773
  reset() {
3498
3774
  for (let instanceCacheKey in this.instanceCache) {
@@ -3545,7 +3821,92 @@ function isQuadArray(obj) {
3545
3821
  return Array.isArray(obj) && obj.length === 4;
3546
3822
  }
3547
3823
 
3548
- // src/model/scene/ModelObject.ts
3824
+ // src/model/block/blockTints.json
3825
+ var blockTints_default = {
3826
+ "minecraft:large_fern": { source: "grass" },
3827
+ "minecraft:tall_grass": { source: "grass" },
3828
+ "minecraft:grass_block": { source: "grass" },
3829
+ "minecraft:fern": { source: "grass" },
3830
+ "minecraft:grass": { source: "grass" },
3831
+ "minecraft:short_grass": { source: "grass" },
3832
+ "minecraft:potted_fern": { source: "grass" },
3833
+ "minecraft:bush": { source: "grass" },
3834
+ "minecraft:pink_petals": { source: "grass", untinted: [0] },
3835
+ "minecraft:wildflowers": { source: "grass", untinted: [0] },
3836
+ "minecraft:spruce_leaves": { source: "constant", color: 6396257 },
3837
+ "minecraft:birch_leaves": { source: "constant", color: 8431445 },
3838
+ "minecraft:oak_leaves": { source: "constant", color: 4764952 },
3839
+ "minecraft:jungle_leaves": { source: "constant", color: 4764952 },
3840
+ "minecraft:acacia_leaves": { source: "constant", color: 4764952 },
3841
+ "minecraft:dark_oak_leaves": { source: "constant", color: 4764952 },
3842
+ "minecraft:vine": { source: "constant", color: 4764952 },
3843
+ "minecraft:mangrove_leaves": { source: "constant", color: 4764952 },
3844
+ "minecraft:leaf_litter": { source: "constant", color: 6044722 },
3845
+ "minecraft:water_cauldron": { source: "constant", color: 4159204 },
3846
+ "minecraft:redstone_wire": { source: "redstone" },
3847
+ "minecraft:attached_melon_stem": { source: "constant", color: 14731036 },
3848
+ "minecraft:attached_pumpkin_stem": { source: "constant", color: 14731036 },
3849
+ "minecraft:melon_stem": { source: "stem" },
3850
+ "minecraft:pumpkin_stem": { source: "stem" },
3851
+ "minecraft:lily_pad": { source: "constant", color: 7455580 }
3852
+ };
3853
+
3854
+ // src/model/block/BlockTints.ts
3855
+ var rules = blockTints_default;
3856
+ var BlockTints = class {
3857
+ /** Resolves block preview colors without biome context; explicit tints take precedence. */
3858
+ static async get(key, state, model, tints) {
3859
+ const rule = key && rules[key.toNamespacedString()];
3860
+ if (!key || !rule) return tints;
3861
+ const indices = /* @__PURE__ */ new Set();
3862
+ for (const element of model.elements ?? []) {
3863
+ for (const face of Object.values(element.faces)) {
3864
+ const index = face?.tintindex;
3865
+ if (index !== void 0 && index >= 0 && tints?.[index] === void 0 && !rule.untinted?.includes(index)) {
3866
+ indices.add(index);
3867
+ }
3868
+ }
3869
+ }
3870
+ if (!indices.size) return tints;
3871
+ let color;
3872
+ switch (rule.source) {
3873
+ case "constant":
3874
+ color = rule.color;
3875
+ break;
3876
+ case "grass":
3877
+ color = await this.grassColor(key);
3878
+ break;
3879
+ case "redstone": {
3880
+ const power = Number(state.power ?? 0) / 15;
3881
+ const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
3882
+ const green = Math.max(0, power * power * 0.7 - 0.5);
3883
+ const blue = Math.max(0, power * power * 0.6 - 0.7);
3884
+ color = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
3885
+ break;
3886
+ }
3887
+ case "stem": {
3888
+ const age = Number(state.age ?? 0);
3889
+ color = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
3890
+ break;
3891
+ }
3892
+ }
3893
+ return { ...Object.fromEntries([...indices].map((index) => [index, color])), ...tints };
3894
+ }
3895
+ static async grassColor(origin) {
3896
+ const key = AssetKey.parse("textures", "minecraft:colormap/grass", origin);
3897
+ return await Caching.blockTintCache.get(key.serialize(), async () => {
3898
+ const image = await ModelTextures.get(key);
3899
+ if (!image) throw new MineRenderError(`Missing grass colormap: ${key.toNamespacedString()}`);
3900
+ if (image.width !== 256 || image.height !== 256) {
3901
+ throw new MineRenderError("Grass colormaps must be 256 \xD7 256 pixels");
3902
+ }
3903
+ const [red, green, blue] = image.data.getImageData(127, 127, 1, 1).data;
3904
+ return red << 16 | green << 8 | blue;
3905
+ });
3906
+ }
3907
+ };
3908
+
3909
+ // src/model/scene/ModelObject.ts
3549
3910
  var import_three15 = require("three");
3550
3911
 
3551
3912
  // src/three/BufferGeometryUtils.js
@@ -4081,26 +4442,29 @@ function computeMorphedAttributes(object) {
4081
4442
  }
4082
4443
 
4083
4444
  // 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 {
4445
+ var import_ts_deepmerge5 = __toESM(require_dist());
4446
+ var p9 = prefix("ModelObject");
4447
+ var ModelObject = class _ModelObject extends SceneObject {
4087
4448
  constructor(originalModel, options) {
4088
4449
  super(options);
4089
4450
  this.originalModel = originalModel;
4090
4451
  this.isModelObject = true;
4091
4452
  this.meshesCreated = false;
4092
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4453
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4454
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
4093
4455
  console.log("ModelObject options", this.options);
4094
4456
  }
4457
+ static {
4458
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4459
+ }
4095
4460
  async init() {
4096
4461
  await this.loadTextures();
4097
4462
  this.createMeshes();
4098
4463
  this.applyTextures();
4099
4464
  }
4100
4465
  dispose() {
4101
- var _a;
4102
4466
  super.dispose();
4103
- (_a = this.atlas) == null ? void 0 : _a.dispose();
4467
+ this.atlas?.dispose();
4104
4468
  }
4105
4469
  get textureAtlas() {
4106
4470
  return this.atlas;
@@ -4110,14 +4474,30 @@ var _ModelObject = class _ModelObject extends SceneObject {
4110
4474
  this.atlas = await UVMapper.getAtlas(this.originalModel);
4111
4475
  }
4112
4476
  createMeshes(force = false) {
4113
- var _a;
4114
4477
  if (this.meshesCreated && !force) return;
4115
4478
  const mat = Materials.MISSING_TEXTURE;
4116
4479
  let allGeos = [];
4117
4480
  if (this.atlas) {
4118
4481
  if (this.atlas.model.elements) {
4119
- (_a = this.atlas.model.elements) == null ? void 0 : _a.forEach((el) => {
4482
+ this.atlas.model.elements?.forEach((el) => {
4120
4483
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4484
+ if (this.options.uvLockRotation) {
4485
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three15.Euler(...this.options.uvLockRotation));
4486
+ }
4487
+ if (this.options.tints) {
4488
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4489
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4490
+ const tintIndex = el.faces[faceName]?.tintindex;
4491
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4492
+ const tint = this.options.tints[tintIndex];
4493
+ if (tint === void 0) continue;
4494
+ const color = new import_three15.Color(tint);
4495
+ for (let vertex = 0; vertex < 4; vertex++) {
4496
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4497
+ }
4498
+ }
4499
+ elGeo.setAttribute("color", new import_three15.BufferAttribute(colors, 3));
4500
+ }
4121
4501
  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
4502
  elGeo.applyMatrix4(new import_three15.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4123
4503
  if (el.rotation) {
@@ -4134,10 +4514,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
4134
4514
  }
4135
4515
  });
4136
4516
  } else {
4137
- console.debug(p10, this.atlas.model, "has no elements");
4517
+ console.debug(p9, this.atlas.model, "has no elements");
4138
4518
  }
4139
4519
  } else {
4140
- console.debug(p10, "Missing atlas for", this);
4520
+ console.debug(p9, "Missing atlas for", this);
4141
4521
  }
4142
4522
  if (this.options.mergeMeshes) {
4143
4523
  let combinedGeo;
@@ -4174,6 +4554,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4174
4554
  /*TODO: get this from render options*/
4175
4555
  );
4176
4556
  this.iterateAllMeshes((mesh) => {
4557
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4177
4558
  mesh.material = mat;
4178
4559
  });
4179
4560
  if (this.atlas.hasAnimation) {
@@ -4189,17 +4570,25 @@ var _ModelObject = class _ModelObject extends SceneObject {
4189
4570
  }
4190
4571
  }
4191
4572
  };
4192
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4193
- var ModelObject = _ModelObject;
4194
4573
  function isModelObject(obj) {
4195
4574
  return obj.isModelObject;
4196
4575
  }
4197
4576
 
4198
4577
  // src/model/block/scene/BlockObject.ts
4199
- var import_ts_deepmerge7 = __toESM(require_dist());
4578
+ var import_ts_deepmerge6 = __toESM(require_dist());
4200
4579
  var import_three16 = require("three");
4201
- var p11 = prefix("BlockObject");
4202
- var _BlockObject = class _BlockObject extends SceneObject {
4580
+ var p10 = prefix("BlockObject");
4581
+ function matchesCondition(condition, state) {
4582
+ return Object.entries(condition).every(([key, value]) => {
4583
+ if (Array.isArray(value)) {
4584
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4585
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4586
+ return false;
4587
+ }
4588
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4589
+ });
4590
+ }
4591
+ var BlockObject = class _BlockObject extends SceneObject {
4203
4592
  constructor(blockState, options) {
4204
4593
  super(options);
4205
4594
  this.blockState = blockState;
@@ -4212,11 +4601,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4212
4601
  this._instanceModel = [];
4213
4602
  this._variants = [];
4214
4603
  this._models = [];
4215
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4604
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4605
+ }
4606
+ static {
4607
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4608
+ applyDefaultState: true
4609
+ });
4216
4610
  }
4217
4611
  async init() {
4218
4612
  if (this.options.applyDefaultState) {
4219
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4613
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4220
4614
  if (defaultState && Object.keys(defaultState).length > 0) {
4221
4615
  const state = {};
4222
4616
  for (let k in defaultState) {
@@ -4227,15 +4621,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4227
4621
  if (this.blockState.variants) {
4228
4622
  await this.setState(Object.keys(this.blockState.variants)[0]);
4229
4623
  } 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
- }
4624
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4625
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4626
+ await this.setState(state);
4239
4627
  }
4240
4628
  }
4241
4629
  } else {
@@ -4292,55 +4680,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4292
4680
  } else if (this.blockState.multipart) {
4293
4681
  for (let part of this.blockState.multipart) {
4294
4682
  if (!part.apply) {
4295
- console.debug(p11, "Missing apply for blockState part", part);
4683
+ console.debug(p10, "Missing apply for blockState part", part);
4296
4684
  continue;
4297
4685
  }
4298
- if (!part.when) {
4686
+ if (!part.when || matchesCondition(part.when, state)) {
4299
4687
  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
4688
  }
4345
4689
  }
4346
4690
  }
@@ -4370,11 +4714,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4370
4714
  }
4371
4715
  }
4372
4716
  getSingleVariant(variants) {
4373
- if (Array.isArray(variants)) {
4374
- return variants[0];
4375
- } else {
4376
- return variants;
4377
- }
4717
+ if (!Array.isArray(variants)) return variants;
4718
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4719
+ const total = variants.reduce((sum, variant) => {
4720
+ const weight = variant.weight ?? 1;
4721
+ if (!Number.isInteger(weight) || weight < 1) {
4722
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4723
+ }
4724
+ return sum + weight;
4725
+ }, 0);
4726
+ let choice = Math.random() * total;
4727
+ for (const variant of variants) {
4728
+ choice -= variant.weight ?? 1;
4729
+ if (choice < 0) return variant;
4730
+ }
4731
+ return variants[variants.length - 1];
4378
4732
  }
4379
4733
  // @deprecated
4380
4734
  async createAVariant(variants, instanceInfo) {
@@ -4382,28 +4736,25 @@ var _BlockObject = class _BlockObject extends SceneObject {
4382
4736
  await this.createVariant(variant);
4383
4737
  }
4384
4738
  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);
4739
+ const rotation = new import_three16.Euler();
4392
4740
  if (typeof variant.x !== "undefined") {
4393
4741
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4394
4742
  }
4395
4743
  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
- }
4744
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4745
+ }
4746
+ const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4747
+ const options = {
4748
+ ...this.options,
4749
+ tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
4750
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4751
+ };
4752
+ const obj = await this.scene.addModel(model, options);
4753
+ if (isInstanceReference(obj) || obj.isInstanced) {
4754
+ this._isInstanced = true;
4755
+ this._instanceCounter = 1;
4401
4756
  }
4402
4757
  obj.setRotation(rotation);
4403
- setTimeout(() => {
4404
- obj.setRotation(rotation);
4405
- }, 150);
4406
- console.log(obj);
4407
4758
  return obj;
4408
4759
  }
4409
4760
  async resetState() {
@@ -4493,18 +4844,15 @@ var _BlockObject = class _BlockObject extends SceneObject {
4493
4844
  }
4494
4845
  }
4495
4846
  setPosition(position) {
4496
- super.setPosition(position);
4847
+ this.position.copy(position);
4497
4848
  for (let model of this._models) {
4498
4849
  model.setPosition(position);
4499
4850
  }
4851
+ this.notifyDirty();
4500
4852
  }
4501
4853
  //TODO: should override rotation + scale methods
4502
4854
  //TODO
4503
4855
  };
4504
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4505
- applyDefaultState: true
4506
- });
4507
- var BlockObject = _BlockObject;
4508
4856
  function isBlockObject(obj) {
4509
4857
  return obj.isBlockObject;
4510
4858
  }
@@ -4529,11 +4877,10 @@ var StructureParser = class {
4529
4877
  throw new MineRenderError("Structure does not have palette(s)");
4530
4878
  }
4531
4879
  const blocks = nbt.blocks.value.value.map((block) => {
4532
- var _a;
4533
4880
  const state = palette.value.value[block.state.value];
4534
4881
  if (state.Name.value === "minecraft:air") return void 0;
4535
4882
  const props = {};
4536
- for (let k in (_a = state.Properties) == null ? void 0 : _a.value) {
4883
+ for (let k in state.Properties?.value) {
4537
4884
  props[k] = state.Properties.value[k].value;
4538
4885
  }
4539
4886
  return {
@@ -4552,7 +4899,7 @@ var StructureParser = class {
4552
4899
 
4553
4900
  // src/renderer/MineRenderScene.ts
4554
4901
  var import_three17 = require("three");
4555
- var import_ts_deepmerge9 = __toESM(require_dist());
4902
+ var import_ts_deepmerge8 = __toESM(require_dist());
4556
4903
 
4557
4904
  // src/skin/SkinPart.ts
4558
4905
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5283,7 +5630,7 @@ var slimSkinGeometries = {
5283
5630
  };
5284
5631
 
5285
5632
  // src/skin/scene/SkinObject.ts
5286
- var import_ts_deepmerge8 = __toESM(require_dist());
5633
+ var import_ts_deepmerge7 = __toESM(require_dist());
5287
5634
  var SkinObject = class extends SceneObject {
5288
5635
  constructor(options) {
5289
5636
  super();
@@ -5291,7 +5638,7 @@ var SkinObject = class extends SceneObject {
5291
5638
  this.legacy = false;
5292
5639
  this.skinTextureWidth = 64;
5293
5640
  this.skinTextureHeight = 64;
5294
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5641
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5295
5642
  }
5296
5643
  async init() {
5297
5644
  this.createMeshes();
@@ -5395,7 +5742,7 @@ var SkinObject = class extends SceneObject {
5395
5742
  };
5396
5743
 
5397
5744
  // src/renderer/MineRenderScene.ts
5398
- var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5745
+ var MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5399
5746
  constructor(options) {
5400
5747
  super();
5401
5748
  this.isMineRenderScene = true;
@@ -5404,12 +5751,14 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5404
5751
  this.dirty = true;
5405
5752
  this.observedObjects = /* @__PURE__ */ new Set();
5406
5753
  this.onObjectChange = (event) => {
5407
- var _a;
5408
- if (((_a = event.target) == null ? void 0 : _a.parent) === this) {
5754
+ if (event.target?.parent === this) {
5409
5755
  this.dirty = true;
5410
5756
  }
5411
5757
  };
5412
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5758
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5759
+ }
5760
+ static {
5761
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5413
5762
  }
5414
5763
  add(...objects) {
5415
5764
  for (const object of objects) {
@@ -5417,7 +5766,7 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5417
5766
  try {
5418
5767
  super.add(object);
5419
5768
  } finally {
5420
- if ((object == null ? void 0 : object.isObject3D) && object !== this) {
5769
+ if (object?.isObject3D && object !== this) {
5421
5770
  this.updateObjectRegistration(object, object.parent === this);
5422
5771
  }
5423
5772
  }
@@ -5460,15 +5809,20 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5460
5809
  return this.add(...object);
5461
5810
  }
5462
5811
  async addSceneObject(asset, objectSupplier, _options, parent = this) {
5463
- var _a, _b;
5464
5812
  console.log("addSceneObject", asset);
5465
5813
  console.log("parent", parent);
5466
5814
  console.log(_options);
5467
5815
  this.dirty = true;
5468
5816
  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") {
5817
+ if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5470
5818
  console.log("instanceMeshes + key");
5471
- const key = asset.key.serialize();
5819
+ let key = asset.key.serialize();
5820
+ if (isModelObject(obj)) {
5821
+ const { uvLockRotation, tints } = obj.options;
5822
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
5823
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
5824
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
5825
+ }
5472
5826
  return this.instanceManager.getOrCreate(key, async () => {
5473
5827
  obj.scene = this;
5474
5828
  await obj.init();
@@ -5506,903 +5860,450 @@ var _MineRenderScene = class _MineRenderScene extends import_three17.Scene {
5506
5860
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5507
5861
  }
5508
5862
  };
5509
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5510
- var MineRenderScene = _MineRenderScene;
5511
5863
  function isMineRenderScene(obj) {
5512
5864
  return obj.isMineRenderScene;
5513
5865
  }
5514
5866
 
5515
5867
  // src/renderer/Renderer.ts
5516
- var import_three18 = require("three");
5517
- var import_ts_deepmerge10 = __toESM(require_dist());
5868
+ var import_three19 = require("three");
5869
+ var import_ts_deepmerge9 = __toESM(require_dist());
5518
5870
  var import_stats = __toESM(require("stats.js"));
5519
5871
  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;
5872
+
5873
+ // src/three/OrbitControls.js
5874
+ var import_three18 = require("three");
5875
+ var _changeEvent = { type: "change" };
5876
+ var _startEvent = { type: "start" };
5877
+ var _endEvent = { type: "end" };
5878
+ var OrbitControls = class extends import_three18.EventDispatcher {
5879
+ constructor(object, domElement) {
5880
+ super();
5881
+ if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5882
+ if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5883
+ this.object = object;
5884
+ this.domElement = domElement;
5885
+ this.domElement.style.touchAction = "none";
5886
+ this.enabled = true;
5887
+ this.target = new import_three18.Vector3();
5888
+ this.minDistance = 0;
5889
+ this.maxDistance = Infinity;
5890
+ this.minZoom = 0;
5891
+ this.maxZoom = Infinity;
5892
+ this.minPolarAngle = 0;
5893
+ this.maxPolarAngle = Math.PI;
5894
+ this.minAzimuthAngle = -Infinity;
5895
+ this.maxAzimuthAngle = Infinity;
5896
+ this.enableDamping = false;
5897
+ this.dampingFactor = 0.05;
5898
+ this.enableZoom = true;
5899
+ this.zoomSpeed = 1;
5900
+ this.enableRotate = true;
5901
+ this.rotateSpeed = 1;
5902
+ this.enablePan = true;
5903
+ this.panSpeed = 1;
5904
+ this.screenSpacePanning = true;
5905
+ this.keyPanSpeed = 7;
5906
+ this.autoRotate = false;
5907
+ this.autoRotateSpeed = 2;
5908
+ this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5909
+ this.mouseButtons = { LEFT: import_three18.MOUSE.ROTATE, MIDDLE: import_three18.MOUSE.DOLLY, RIGHT: import_three18.MOUSE.PAN };
5910
+ this.touches = { ONE: import_three18.TOUCH.ROTATE, TWO: import_three18.TOUCH.DOLLY_PAN };
5911
+ this.target0 = this.target.clone();
5912
+ this.position0 = this.object.position.clone();
5913
+ this.zoom0 = this.object.zoom;
5914
+ this._domElementKeyEvents = null;
5915
+ this.getPolarAngle = function() {
5916
+ return spherical.phi;
5531
5917
  };
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);
5918
+ this.getAzimuthalAngle = function() {
5919
+ return spherical.theta;
5920
+ };
5921
+ this.getDistance = function() {
5922
+ return this.object.position.distanceTo(this.target);
5923
+ };
5924
+ this.saveState = function() {
5925
+ scope.target0.copy(scope.target);
5926
+ scope.position0.copy(scope.object.position);
5927
+ scope.zoom0 = scope.object.zoom;
5928
+ };
5929
+ this.reset = function() {
5930
+ scope.target.copy(scope.target0);
5931
+ scope.object.position.copy(scope.position0);
5932
+ scope.object.zoom = scope.zoom0;
5933
+ scope.object.updateProjectionMatrix();
5934
+ scope.dispatchEvent(_changeEvent);
5935
+ scope.update();
5936
+ state = STATE.NONE;
5937
+ };
5938
+ this.update = function() {
5939
+ const offset = new import_three18.Vector3();
5940
+ const quat = new import_three18.Quaternion().setFromUnitVectors(object.up, new import_three18.Vector3(0, 1, 0));
5941
+ const quatInverse = quat.clone().invert();
5942
+ const lastPosition = new import_three18.Vector3();
5943
+ const lastQuaternion = new import_three18.Quaternion();
5944
+ const twoPI = 2 * Math.PI;
5945
+ return function update() {
5946
+ const position = scope.object.position;
5947
+ offset.copy(position).sub(scope.target);
5948
+ offset.applyQuaternion(quat);
5949
+ spherical.setFromVector3(offset);
5950
+ if (scope.autoRotate && state === STATE.NONE) {
5951
+ rotateLeft(getAutoRotationAngle());
5952
+ }
5953
+ if (scope.enableDamping) {
5954
+ spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5955
+ spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5956
+ } else {
5957
+ spherical.theta += sphericalDelta.theta;
5958
+ spherical.phi += sphericalDelta.phi;
5959
+ }
5960
+ let min = scope.minAzimuthAngle;
5961
+ let max = scope.maxAzimuthAngle;
5962
+ if (isFinite(min) && isFinite(max)) {
5963
+ if (min < -Math.PI) min += twoPI;
5964
+ else if (min > Math.PI) min -= twoPI;
5965
+ if (max < -Math.PI) max += twoPI;
5966
+ else if (max > Math.PI) max -= twoPI;
5967
+ if (min <= max) {
5968
+ spherical.theta = Math.max(min, Math.min(max, spherical.theta));
5969
+ } else {
5970
+ spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
5971
+ }
5972
+ }
5973
+ spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5974
+ spherical.makeSafe();
5975
+ spherical.radius *= scale;
5976
+ spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5977
+ if (scope.enableDamping === true) {
5978
+ scope.target.addScaledVector(panOffset, scope.dampingFactor);
5979
+ } else {
5980
+ scope.target.add(panOffset);
5981
+ }
5982
+ offset.setFromSpherical(spherical);
5983
+ offset.applyQuaternion(quatInverse);
5984
+ position.copy(scope.target).add(offset);
5985
+ scope.object.lookAt(scope.target);
5986
+ if (scope.enableDamping === true) {
5987
+ sphericalDelta.theta *= 1 - scope.dampingFactor;
5988
+ sphericalDelta.phi *= 1 - scope.dampingFactor;
5989
+ panOffset.multiplyScalar(1 - scope.dampingFactor);
5990
+ } else {
5991
+ sphericalDelta.set(0, 0, 0);
5992
+ panOffset.set(0, 0, 0);
5993
+ }
5994
+ scale = 1;
5995
+ if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5996
+ scope.dispatchEvent(_changeEvent);
5997
+ lastPosition.copy(scope.object.position);
5998
+ lastQuaternion.copy(scope.object.quaternion);
5999
+ zoomChanged = false;
6000
+ return true;
6001
+ }
6002
+ return false;
6003
+ };
6004
+ }();
6005
+ this.dispose = function() {
6006
+ scope.domElement.removeEventListener("contextmenu", onContextMenu);
6007
+ scope.domElement.removeEventListener("pointerdown", onPointerDown);
6008
+ scope.domElement.removeEventListener("pointercancel", onPointerCancel);
6009
+ scope.domElement.removeEventListener("wheel", onMouseWheel);
6010
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
6011
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
6012
+ if (scope._domElementKeyEvents !== null) {
6013
+ scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
6014
+ }
6015
+ };
6016
+ const scope = this;
6017
+ const STATE = {
6018
+ NONE: -1,
6019
+ ROTATE: 0,
6020
+ DOLLY: 1,
6021
+ PAN: 2,
6022
+ TOUCH_ROTATE: 3,
6023
+ TOUCH_PAN: 4,
6024
+ TOUCH_DOLLY_PAN: 5,
6025
+ TOUCH_DOLLY_ROTATE: 6
6026
+ };
6027
+ let state = STATE.NONE;
6028
+ const EPS = 1e-6;
6029
+ const spherical = new import_three18.Spherical();
6030
+ const sphericalDelta = new import_three18.Spherical();
6031
+ let scale = 1;
6032
+ const panOffset = new import_three18.Vector3();
6033
+ let zoomChanged = false;
6034
+ const rotateStart = new import_three18.Vector2();
6035
+ const rotateEnd = new import_three18.Vector2();
6036
+ const rotateDelta = new import_three18.Vector2();
6037
+ const panStart = new import_three18.Vector2();
6038
+ const panEnd = new import_three18.Vector2();
6039
+ const panDelta = new import_three18.Vector2();
6040
+ const dollyStart = new import_three18.Vector2();
6041
+ const dollyEnd = new import_three18.Vector2();
6042
+ const dollyDelta = new import_three18.Vector2();
6043
+ const pointers = [];
6044
+ const pointerPositions = {};
6045
+ function getAutoRotationAngle() {
6046
+ return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
5542
6047
  }
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
- );
5568
- }
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 }));
6048
+ function getZoomScale() {
6049
+ return Math.pow(0.95, scope.zoomSpeed);
5596
6050
  }
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);
6051
+ function rotateLeft(angle) {
6052
+ sphericalDelta.theta -= angle;
5609
6053
  }
5610
- if (this.options.debug.axes) {
5611
- const axesHelper = new import_three18.AxesHelper(64);
5612
- this._debugHelpers.push(axesHelper);
5613
- this.scene.add(axesHelper);
6054
+ function rotateUp(angle) {
6055
+ sphericalDelta.phi -= angle;
5614
6056
  }
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]);
6057
+ const panLeft = function() {
6058
+ const v = new import_three18.Vector3();
6059
+ return function panLeft2(distance, objectMatrix) {
6060
+ v.setFromMatrixColumn(objectMatrix, 0);
6061
+ v.multiplyScalar(-distance);
6062
+ panOffset.add(v);
6063
+ };
6064
+ }();
6065
+ const panUp = function() {
6066
+ const v = new import_three18.Vector3();
6067
+ return function panUp2(distance, objectMatrix) {
6068
+ if (scope.screenSpacePanning === true) {
6069
+ v.setFromMatrixColumn(objectMatrix, 1);
6070
+ } else {
6071
+ v.setFromMatrixColumn(objectMatrix, 0);
6072
+ v.crossVectors(scope.object.up, v);
6073
+ }
6074
+ v.multiplyScalar(distance);
6075
+ panOffset.add(v);
6076
+ };
6077
+ }();
6078
+ const pan = function() {
6079
+ const offset = new import_three18.Vector3();
6080
+ return function pan2(deltaX, deltaY) {
6081
+ const element = scope.domElement;
6082
+ if (scope.object.isPerspectiveCamera) {
6083
+ const position = scope.object.position;
6084
+ offset.copy(position).sub(scope.target);
6085
+ let targetDistance = offset.length();
6086
+ targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
6087
+ panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
6088
+ panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
6089
+ } else if (scope.object.isOrthographicCamera) {
6090
+ panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
6091
+ panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
6092
+ } else {
6093
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
6094
+ scope.enablePan = false;
6095
+ }
6096
+ };
6097
+ }();
6098
+ function dollyOut(dollyScale) {
6099
+ if (scope.object.isPerspectiveCamera) {
6100
+ scale /= dollyScale;
6101
+ } else if (scope.object.isOrthographicCamera) {
6102
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
6103
+ scope.object.updateProjectionMatrix();
6104
+ zoomChanged = true;
6105
+ } else {
6106
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6107
+ scope.enableZoom = false;
5620
6108
  }
5621
6109
  }
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]);
6110
+ function dollyIn(dollyScale) {
6111
+ if (scope.object.isPerspectiveCamera) {
6112
+ scale *= dollyScale;
6113
+ } else if (scope.object.isOrthographicCamera) {
6114
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
6115
+ scope.object.updateProjectionMatrix();
6116
+ zoomChanged = true;
6117
+ } else {
6118
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6119
+ scope.enableZoom = false;
5627
6120
  }
5628
6121
  }
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);
6122
+ function handleMouseDownRotate(event) {
6123
+ rotateStart.set(event.clientX, event.clientY);
5634
6124
  }
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");
6125
+ function handleMouseDownDolly(event) {
6126
+ dollyStart.set(event.clientX, event.clientY);
5645
6127
  }
5646
- if (this.viewHeight == 0) {
5647
- console.warn("0 element height");
6128
+ function handleMouseDownPan(event) {
6129
+ panStart.set(event.clientX, event.clientY);
5648
6130
  }
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);
6131
+ function handleMouseMoveRotate(event) {
6132
+ rotateEnd.set(event.clientX, event.clientY);
6133
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6134
+ const element = scope.domElement;
6135
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6136
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6137
+ rotateStart.copy(rotateEnd);
6138
+ scope.update();
5661
6139
  }
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();
6140
+ function handleMouseMoveDolly(event) {
6141
+ dollyEnd.set(event.clientX, event.clientY);
6142
+ dollyDelta.subVectors(dollyEnd, dollyStart);
6143
+ if (dollyDelta.y > 0) {
6144
+ dollyOut(getZoomScale());
6145
+ } else if (dollyDelta.y < 0) {
6146
+ dollyIn(getZoomScale());
6147
+ }
6148
+ dollyStart.copy(dollyEnd);
6149
+ scope.update();
5677
6150
  }
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;
6151
+ function handleMouseMovePan(event) {
6152
+ panEnd.set(event.clientX, event.clientY);
6153
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6154
+ pan(panDelta.x, panDelta.y);
6155
+ panStart.copy(panEnd);
6156
+ scope.update();
5718
6157
  }
5719
- for (const [dispatcher, events] of this._eventDispatchers) {
5720
- for (const event of events) {
5721
- dispatcher.removeEventListener(event, this._changeListener);
5722
- }
6158
+ function handleMouseUp() {
5723
6159
  }
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();
6160
+ function handleMouseWheel(event) {
6161
+ if (event.deltaY < 0) {
6162
+ dollyIn(getZoomScale());
6163
+ } else if (event.deltaY > 0) {
6164
+ dollyOut(getZoomScale());
5735
6165
  }
6166
+ scope.update();
5736
6167
  }
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();
6168
+ function handleKeyDown(event) {
6169
+ let needsUpdate = false;
6170
+ switch (event.code) {
6171
+ case scope.keys.UP:
6172
+ pan(0, scope.keyPanSpeed);
6173
+ needsUpdate = true;
6174
+ break;
6175
+ case scope.keys.BOTTOM:
6176
+ pan(0, -scope.keyPanSpeed);
6177
+ needsUpdate = true;
6178
+ break;
6179
+ case scope.keys.LEFT:
6180
+ pan(scope.keyPanSpeed, 0);
6181
+ needsUpdate = true;
6182
+ break;
6183
+ case scope.keys.RIGHT:
6184
+ pan(-scope.keyPanSpeed, 0);
6185
+ needsUpdate = true;
6186
+ break;
6187
+ }
6188
+ if (needsUpdate) {
6189
+ event.preventDefault();
6190
+ scope.update();
6191
+ }
5746
6192
  }
5747
- if (this.dirty || this.options.render.renderAlways) {
5748
- if (this.options.composer.enabled) {
5749
- this.composer.render();
6193
+ function handleTouchStartRotate() {
6194
+ if (pointers.length === 1) {
6195
+ rotateStart.set(pointers[0].pageX, pointers[0].pageY);
5750
6196
  } else {
5751
- this.renderer.render(this.scene, this.camera);
6197
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6198
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6199
+ rotateStart.set(x, y);
5752
6200
  }
5753
6201
  }
5754
- this.dirty = false;
5755
- if (this._stats) {
5756
- this._stats.end();
6202
+ function handleTouchStartPan() {
6203
+ if (pointers.length === 1) {
6204
+ panStart.set(pointers[0].pageX, pointers[0].pageY);
6205
+ } else {
6206
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6207
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6208
+ panStart.set(x, y);
6209
+ }
5757
6210
  }
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);
6211
+ function handleTouchStartDolly() {
6212
+ const dx = pointers[0].pageX - pointers[1].pageX;
6213
+ const dy = pointers[0].pageY - pointers[1].pageY;
6214
+ const distance = Math.sqrt(dx * dx + dy * dy);
6215
+ dollyStart.set(0, distance);
5831
6216
  }
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);
6217
+ function handleTouchStartDollyPan() {
6218
+ if (scope.enableZoom) handleTouchStartDolly();
6219
+ if (scope.enablePan) handleTouchStartPan();
6220
+ }
6221
+ function handleTouchStartDollyRotate() {
6222
+ if (scope.enableZoom) handleTouchStartDolly();
6223
+ if (scope.enableRotate) handleTouchStartRotate();
6224
+ }
6225
+ function handleTouchMoveRotate(event) {
6226
+ if (pointers.length == 1) {
6227
+ rotateEnd.set(event.pageX, event.pageY);
6228
+ } else {
6229
+ const position = getSecondPointerPosition(event);
6230
+ const x = 0.5 * (event.pageX + position.x);
6231
+ const y = 0.5 * (event.pageY + position.y);
6232
+ rotateEnd.set(x, y);
5841
6233
  }
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"];
6234
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6235
+ const element = scope.domElement;
6236
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6237
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6238
+ rotateStart.copy(rotateEnd);
6239
+ }
6240
+ function handleTouchMovePan(event) {
6241
+ if (pointers.length === 1) {
6242
+ panEnd.set(event.pageX, event.pageY);
6243
+ } else {
6244
+ const position = getSecondPointerPosition(event);
6245
+ const x = 0.5 * (event.pageX + position.x);
6246
+ const y = 0.5 * (event.pageY + position.y);
6247
+ panEnd.set(x, y);
5849
6248
  }
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);
6249
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6250
+ pan(panDelta.x, panDelta.y);
6251
+ panStart.copy(panEnd);
5858
6252
  }
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);
6253
+ function handleTouchMoveDolly(event) {
6254
+ const position = getSecondPointerPosition(event);
6255
+ const dx = event.pageX - position.x;
6256
+ const dy = event.pageY - position.y;
6257
+ const distance = Math.sqrt(dx * dx + dy * dy);
6258
+ dollyEnd.set(0, distance);
6259
+ dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
6260
+ dollyOut(dollyDelta.y);
6261
+ dollyStart.copy(dollyEnd);
6262
+ }
6263
+ function handleTouchMoveDollyPan(event) {
6264
+ if (scope.enableZoom) handleTouchMoveDolly(event);
6265
+ if (scope.enablePan) handleTouchMovePan(event);
6266
+ }
6267
+ function handleTouchMoveDollyRotate(event) {
6268
+ if (scope.enableZoom) handleTouchMoveDolly(event);
6269
+ if (scope.enableRotate) handleTouchMoveRotate(event);
6270
+ }
6271
+ function handleTouchEnd() {
6272
+ }
6273
+ function onPointerDown(event) {
6274
+ if (scope.enabled === false) return;
6275
+ if (pointers.length === 0) {
6276
+ scope.domElement.setPointerCapture(event.pointerId);
6277
+ scope.domElement.addEventListener("pointermove", onPointerMove);
6278
+ scope.domElement.addEventListener("pointerup", onPointerUp);
5868
6279
  }
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;
6280
+ addPointer(event);
6281
+ if (event.pointerType === "touch") {
6282
+ onTouchStart(event);
6283
+ } else {
6284
+ onMouseDown(event);
5876
6285
  }
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"];
6286
+ }
6287
+ function onPointerMove(event) {
6288
+ if (scope.enabled === false) return;
6289
+ if (event.pointerType === "touch") {
6290
+ onTouchMove(event);
6291
+ } else {
6292
+ onMouseMove(event);
5892
6293
  }
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"];
6294
+ }
6295
+ function onPointerUp(event) {
6296
+ if (scope.enabled === false) return;
6297
+ if (event.pointerType === "touch") {
6298
+ onTouchEnd();
6299
+ } else {
6300
+ onMouseUp(event);
5906
6301
  }
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();
6266
- }
6267
- function handleKeyDown(event) {
6268
- let needsUpdate = false;
6269
- switch (event.code) {
6270
- case scope.keys.UP:
6271
- pan(0, scope.keyPanSpeed);
6272
- needsUpdate = true;
6273
- break;
6274
- case scope.keys.BOTTOM:
6275
- pan(0, -scope.keyPanSpeed);
6276
- needsUpdate = true;
6277
- break;
6278
- case scope.keys.LEFT:
6279
- pan(scope.keyPanSpeed, 0);
6280
- needsUpdate = true;
6281
- break;
6282
- case scope.keys.RIGHT:
6283
- pan(-scope.keyPanSpeed, 0);
6284
- needsUpdate = true;
6285
- break;
6286
- }
6287
- if (needsUpdate) {
6288
- event.preventDefault();
6289
- scope.update();
6290
- }
6291
- }
6292
- function handleTouchStartRotate() {
6293
- if (pointers.length === 1) {
6294
- rotateStart.set(pointers[0].pageX, pointers[0].pageY);
6295
- } else {
6296
- const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6297
- const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6298
- rotateStart.set(x, y);
6299
- }
6300
- }
6301
- function handleTouchStartPan() {
6302
- if (pointers.length === 1) {
6303
- panStart.set(pointers[0].pageX, pointers[0].pageY);
6304
- } else {
6305
- const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6306
- const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6307
- panStart.set(x, y);
6308
- }
6309
- }
6310
- function handleTouchStartDolly() {
6311
- const dx = pointers[0].pageX - pointers[1].pageX;
6312
- const dy = pointers[0].pageY - pointers[1].pageY;
6313
- const distance = Math.sqrt(dx * dx + dy * dy);
6314
- dollyStart.set(0, distance);
6315
- }
6316
- function handleTouchStartDollyPan() {
6317
- if (scope.enableZoom) handleTouchStartDolly();
6318
- if (scope.enablePan) handleTouchStartPan();
6319
- }
6320
- function handleTouchStartDollyRotate() {
6321
- if (scope.enableZoom) handleTouchStartDolly();
6322
- if (scope.enableRotate) handleTouchStartRotate();
6323
- }
6324
- function handleTouchMoveRotate(event) {
6325
- if (pointers.length == 1) {
6326
- rotateEnd.set(event.pageX, event.pageY);
6327
- } else {
6328
- const position = getSecondPointerPosition(event);
6329
- const x = 0.5 * (event.pageX + position.x);
6330
- const y = 0.5 * (event.pageY + position.y);
6331
- rotateEnd.set(x, y);
6332
- }
6333
- rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6334
- const element = scope.domElement;
6335
- rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6336
- rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6337
- rotateStart.copy(rotateEnd);
6338
- }
6339
- function handleTouchMovePan(event) {
6340
- if (pointers.length === 1) {
6341
- panEnd.set(event.pageX, event.pageY);
6342
- } else {
6343
- const position = getSecondPointerPosition(event);
6344
- const x = 0.5 * (event.pageX + position.x);
6345
- const y = 0.5 * (event.pageY + position.y);
6346
- panEnd.set(x, y);
6347
- }
6348
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6349
- pan(panDelta.x, panDelta.y);
6350
- panStart.copy(panEnd);
6351
- }
6352
- function handleTouchMoveDolly(event) {
6353
- const position = getSecondPointerPosition(event);
6354
- const dx = event.pageX - position.x;
6355
- const dy = event.pageY - position.y;
6356
- const distance = Math.sqrt(dx * dx + dy * dy);
6357
- dollyEnd.set(0, distance);
6358
- dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
6359
- dollyOut(dollyDelta.y);
6360
- dollyStart.copy(dollyEnd);
6361
- }
6362
- function handleTouchMoveDollyPan(event) {
6363
- if (scope.enableZoom) handleTouchMoveDolly(event);
6364
- if (scope.enablePan) handleTouchMovePan(event);
6365
- }
6366
- function handleTouchMoveDollyRotate(event) {
6367
- if (scope.enableZoom) handleTouchMoveDolly(event);
6368
- if (scope.enableRotate) handleTouchMoveRotate(event);
6369
- }
6370
- function handleTouchEnd() {
6371
- }
6372
- function onPointerDown(event) {
6373
- if (scope.enabled === false) return;
6374
- if (pointers.length === 0) {
6375
- scope.domElement.setPointerCapture(event.pointerId);
6376
- scope.domElement.addEventListener("pointermove", onPointerMove);
6377
- scope.domElement.addEventListener("pointerup", onPointerUp);
6378
- }
6379
- addPointer(event);
6380
- if (event.pointerType === "touch") {
6381
- onTouchStart(event);
6382
- } else {
6383
- onMouseDown(event);
6384
- }
6385
- }
6386
- function onPointerMove(event) {
6387
- if (scope.enabled === false) return;
6388
- if (event.pointerType === "touch") {
6389
- onTouchMove(event);
6390
- } else {
6391
- onMouseMove(event);
6392
- }
6393
- }
6394
- function onPointerUp(event) {
6395
- if (scope.enabled === false) return;
6396
- if (event.pointerType === "touch") {
6397
- onTouchEnd();
6398
- } else {
6399
- onMouseUp(event);
6400
- }
6401
- removePointer(event);
6402
- if (pointers.length === 0) {
6403
- scope.domElement.releasePointerCapture(event.pointerId);
6404
- scope.domElement.removeEventListener("pointermove", onPointerMove);
6405
- scope.domElement.removeEventListener("pointerup", onPointerUp);
6302
+ removePointer(event);
6303
+ if (pointers.length === 0) {
6304
+ scope.domElement.releasePointerCapture(event.pointerId);
6305
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
6306
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
6406
6307
  }
6407
6308
  }
6408
6309
  function onPointerCancel(event) {
@@ -6424,12 +6325,12 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6424
6325
  mouseAction = -1;
6425
6326
  }
6426
6327
  switch (mouseAction) {
6427
- case import_three20.MOUSE.DOLLY:
6328
+ case import_three18.MOUSE.DOLLY:
6428
6329
  if (scope.enableZoom === false) return;
6429
6330
  handleMouseDownDolly(event);
6430
6331
  state = STATE.DOLLY;
6431
6332
  break;
6432
- case import_three20.MOUSE.ROTATE:
6333
+ case import_three18.MOUSE.ROTATE:
6433
6334
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6434
6335
  if (scope.enablePan === false) return;
6435
6336
  handleMouseDownPan(event);
@@ -6440,7 +6341,7 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6440
6341
  state = STATE.ROTATE;
6441
6342
  }
6442
6343
  break;
6443
- case import_three20.MOUSE.PAN:
6344
+ case import_three18.MOUSE.PAN:
6444
6345
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6445
6346
  if (scope.enableRotate === false) return;
6446
6347
  handleMouseDownRotate(event);
@@ -6496,12 +6397,12 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6496
6397
  switch (pointers.length) {
6497
6398
  case 1:
6498
6399
  switch (scope.touches.ONE) {
6499
- case import_three20.TOUCH.ROTATE:
6400
+ case import_three18.TOUCH.ROTATE:
6500
6401
  if (scope.enableRotate === false) return;
6501
6402
  handleTouchStartRotate();
6502
6403
  state = STATE.TOUCH_ROTATE;
6503
6404
  break;
6504
- case import_three20.TOUCH.PAN:
6405
+ case import_three18.TOUCH.PAN:
6505
6406
  if (scope.enablePan === false) return;
6506
6407
  handleTouchStartPan();
6507
6408
  state = STATE.TOUCH_PAN;
@@ -6512,12 +6413,12 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6512
6413
  break;
6513
6414
  case 2:
6514
6415
  switch (scope.touches.TWO) {
6515
- case import_three20.TOUCH.DOLLY_PAN:
6416
+ case import_three18.TOUCH.DOLLY_PAN:
6516
6417
  if (scope.enableZoom === false && scope.enablePan === false) return;
6517
6418
  handleTouchStartDollyPan();
6518
6419
  state = STATE.TOUCH_DOLLY_PAN;
6519
6420
  break;
6520
- case import_three20.TOUCH.DOLLY_ROTATE:
6421
+ case import_three18.TOUCH.DOLLY_ROTATE:
6521
6422
  if (scope.enableZoom === false && scope.enableRotate === false) return;
6522
6423
  handleTouchStartDollyRotate();
6523
6424
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -6560,55 +6461,561 @@ var OrbitControls = class extends import_three20.EventDispatcher {
6560
6461
  state = STATE.NONE;
6561
6462
  }
6562
6463
  }
6563
- function onTouchEnd(event) {
6564
- handleTouchEnd(event);
6565
- scope.dispatchEvent(_endEvent);
6566
- state = STATE.NONE;
6464
+ function onTouchEnd(event) {
6465
+ handleTouchEnd(event);
6466
+ scope.dispatchEvent(_endEvent);
6467
+ state = STATE.NONE;
6468
+ }
6469
+ function onContextMenu(event) {
6470
+ if (scope.enabled === false) return;
6471
+ event.preventDefault();
6472
+ }
6473
+ function addPointer(event) {
6474
+ pointers.push(event);
6475
+ }
6476
+ function removePointer(event) {
6477
+ delete pointerPositions[event.pointerId];
6478
+ for (let i = 0; i < pointers.length; i++) {
6479
+ if (pointers[i].pointerId == event.pointerId) {
6480
+ pointers.splice(i, 1);
6481
+ return;
6482
+ }
6483
+ }
6484
+ }
6485
+ function trackPointer(event) {
6486
+ let position = pointerPositions[event.pointerId];
6487
+ if (position === void 0) {
6488
+ position = new import_three18.Vector2();
6489
+ pointerPositions[event.pointerId] = position;
6490
+ }
6491
+ position.set(event.pageX, event.pageY);
6492
+ }
6493
+ function getSecondPointerPosition(event) {
6494
+ const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6495
+ return pointerPositions[pointer.pointerId];
6496
+ }
6497
+ scope.domElement.addEventListener("contextmenu", onContextMenu);
6498
+ scope.domElement.addEventListener("pointerdown", onPointerDown);
6499
+ scope.domElement.addEventListener("pointercancel", onPointerCancel);
6500
+ scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6501
+ this.update();
6502
+ }
6503
+ };
6504
+ var MapControls = class extends OrbitControls {
6505
+ constructor(object, domElement) {
6506
+ super(object, domElement);
6507
+ this.screenSpacePanning = false;
6508
+ this.mouseButtons.LEFT = import_three18.MOUSE.PAN;
6509
+ this.mouseButtons.RIGHT = import_three18.MOUSE.ROTATE;
6510
+ this.touches.ONE = import_three18.TOUCH.PAN;
6511
+ this.touches.TWO = import_three18.TOUCH.DOLLY_ROTATE;
6512
+ }
6513
+ };
6514
+
6515
+ // src/renderer/Renderer.ts
6516
+ var Renderer = class _Renderer {
6517
+ constructor(options) {
6518
+ this._dirty = true;
6519
+ this._resizeListener = void 0;
6520
+ this._disposed = false;
6521
+ this._debugHelpers = [];
6522
+ this._eventDispatchers = /* @__PURE__ */ new Map();
6523
+ this._changeListener = () => {
6524
+ this._dirty = true;
6525
+ };
6526
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6527
+ this._animationLoop = this.animate.bind(this);
6528
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6529
+ this._scene = this.createScene();
6530
+ this._camera = this.createCamera();
6531
+ this._renderer = this.createRenderer();
6532
+ this._composer = this.createComposer();
6533
+ if (this.options.render.stats) {
6534
+ this._stats = new import_stats.default();
6535
+ document.body.appendChild(this._stats.dom);
6536
+ }
6537
+ this.init();
6538
+ this._controls = this.createControls();
6539
+ }
6540
+ static {
6541
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6542
+ camera: {
6543
+ type: "perspective",
6544
+ near: 1,
6545
+ far: 5e3,
6546
+ perspective: {
6547
+ aspect: void 0,
6548
+ fov: 50
6549
+ },
6550
+ orthographic: {
6551
+ left: void 0,
6552
+ right: void 0,
6553
+ top: void 0,
6554
+ bottom: void 0
6555
+ },
6556
+ position: new import_three19.Vector3(50, 50, 50),
6557
+ lookingAt: new import_three19.Vector3(0, 0, 0)
6558
+ },
6559
+ render: {
6560
+ fpsLimit: 60,
6561
+ stats: false,
6562
+ antialias: true,
6563
+ shade: true,
6564
+ autoResize: true,
6565
+ renderAlways: false
6566
+ },
6567
+ composer: {
6568
+ enabled: true
6569
+ },
6570
+ controls: {
6571
+ enabled: false
6572
+ },
6573
+ debug: {
6574
+ grid: false,
6575
+ axes: false
6576
+ }
6577
+ });
6578
+ }
6579
+ //<editor-fold desc="INIT">
6580
+ createScene() {
6581
+ return new MineRenderScene();
6582
+ }
6583
+ createCamera() {
6584
+ switch (this.options.camera.type) {
6585
+ case "perspective":
6586
+ default:
6587
+ return new import_three19.PerspectiveCamera(
6588
+ this.options.camera.perspective.fov,
6589
+ this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6590
+ this.options.camera.near,
6591
+ this.options.camera.far
6592
+ );
6593
+ case "orthographic":
6594
+ return new import_three19.OrthographicCamera(
6595
+ this.options.camera.orthographic.left ?? this.viewWidth / -2,
6596
+ this.options.camera.orthographic.right ?? this.viewWidth / 2,
6597
+ this.options.camera.orthographic.top ?? this.viewHeight / 2,
6598
+ this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
6599
+ this.options.camera.near,
6600
+ this.options.camera.far
6601
+ );
6602
+ }
6603
+ }
6604
+ createRenderer() {
6605
+ const renderer = new import_three19.WebGLRenderer({
6606
+ antialias: this.options.render.antialias,
6607
+ alpha: true,
6608
+ powerPreference: "high-performance",
6609
+ depth: true
6610
+ });
6611
+ renderer.setClearColor(0, 0);
6612
+ renderer.shadowMap.enabled = true;
6613
+ renderer.shadowMap.type = import_three19.PCFSoftShadowMap;
6614
+ renderer.outputColorSpace = import_three19.SRGBColorSpace;
6615
+ renderer.setSize(this.viewWidth, this.viewHeight);
6616
+ return renderer;
6617
+ }
6618
+ createComposer() {
6619
+ if (!this.options.composer.enabled) return void 0;
6620
+ const composer = new import_postprocessing.EffectComposer(this.renderer);
6621
+ composer.setSize(this.viewWidth, this.viewHeight);
6622
+ composer.addPass(new import_postprocessing.RenderPass(this.scene, this.camera));
6623
+ return composer;
6624
+ }
6625
+ createControls() {
6626
+ if (!this.options.controls?.enabled) return void 0;
6627
+ const position = this.camera.position.clone();
6628
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
6629
+ this.camera.position.copy(position);
6630
+ const target = this.options.camera.lookingAt;
6631
+ if (isVector3(target)) {
6632
+ controls.target.copy(target);
6633
+ } else if (isTripleArray(target)) {
6634
+ controls.target.set(target[0], target[1], target[2]);
6635
+ }
6636
+ controls.update();
6637
+ controls.saveState();
6638
+ this.registerEventDispatcher(controls);
6639
+ return controls;
6640
+ }
6641
+ //</editor-fold>
6642
+ init() {
6643
+ if (this._disposed) return;
6644
+ if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
6645
+ window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6646
+ }
6647
+ if (this.options.debug.grid) {
6648
+ const gridHelper = new import_three19.GridHelper(128, 16);
6649
+ this._debugHelpers.push(gridHelper);
6650
+ this.scene.add(gridHelper);
6651
+ const gridHelper2 = new import_three19.GridHelper(128, 16);
6652
+ this._debugHelpers.push(gridHelper2);
6653
+ gridHelper2.rotation.x = 90 * (Math.PI / 180);
6654
+ this.scene.add(gridHelper2);
6655
+ const gridHelper3 = new import_three19.GridHelper(128, 16);
6656
+ this._debugHelpers.push(gridHelper3);
6657
+ gridHelper3.rotation.z = 90 * (Math.PI / 180);
6658
+ this.scene.add(gridHelper3);
6659
+ }
6660
+ if (this.options.debug.axes) {
6661
+ const axesHelper = new import_three19.AxesHelper(64);
6662
+ this._debugHelpers.push(axesHelper);
6663
+ this.scene.add(axesHelper);
6664
+ }
6665
+ if (this.options.camera.position) {
6666
+ if (isVector3(this.options.camera.position)) {
6667
+ this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
6668
+ } else if (isTripleArray(this.options.camera.position)) {
6669
+ this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
6670
+ }
6671
+ }
6672
+ if (this.options.camera.lookingAt) {
6673
+ if (isVector3(this.options.camera.lookingAt)) {
6674
+ this.camera.lookAt(this.options.camera.lookingAt);
6675
+ } else if (isTripleArray(this.options.camera.lookingAt)) {
6676
+ this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6677
+ }
6678
+ }
6679
+ if (this.options.render.autoResize && !this._resizeListener) {
6680
+ this._resizeListener = () => {
6681
+ this.resize(this.viewWidth, this.viewHeight);
6682
+ };
6683
+ window.addEventListener("resize", this._resizeListener);
6684
+ }
6685
+ }
6686
+ get element() {
6687
+ return this._element;
6688
+ }
6689
+ appendTo(element) {
6690
+ if (this._disposed) return;
6691
+ this._element = element;
6692
+ this._element.appendChild(this.renderer.domElement);
6693
+ if (this.viewWidth == 0) {
6694
+ console.warn("0 element width");
6695
+ }
6696
+ if (this.viewHeight == 0) {
6697
+ console.warn("0 element height");
6698
+ }
6699
+ this.resize(this.viewWidth, this.viewHeight);
6700
+ }
6701
+ /**
6702
+ * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
6703
+ * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
6704
+ */
6705
+ registerEventDispatcher(dispatcher, changeEvent2 = "change") {
6706
+ if (this._disposed) return;
6707
+ let events = this._eventDispatchers.get(dispatcher);
6708
+ if (!events) {
6709
+ events = /* @__PURE__ */ new Set();
6710
+ this._eventDispatchers.set(dispatcher, events);
6711
+ }
6712
+ if (events.has(changeEvent2)) return;
6713
+ events.add(changeEvent2);
6714
+ dispatcher.addEventListener(changeEvent2, this._changeListener);
6715
+ }
6716
+ resize(width, height) {
6717
+ if (this._disposed) return;
6718
+ if (isPerspectiveCamera(this.camera)) {
6719
+ this.camera.aspect = width / height;
6720
+ this.camera.updateProjectionMatrix();
6721
+ } else if (isOrthographicCamera(this.camera)) {
6722
+ this.camera.left = width / -2;
6723
+ this.camera.right = width / 2;
6724
+ this.camera.top = height / 2;
6725
+ this.camera.bottom = height / -2;
6726
+ this.camera.updateProjectionMatrix();
6727
+ }
6728
+ this.renderer.setSize(width, height);
6729
+ this.composer?.setSize(width, height);
6730
+ this._dirty = true;
6731
+ }
6732
+ //<editor-fold desc="RENDER">
6733
+ get dirty() {
6734
+ return this._dirty || this.scene.dirty;
6735
+ }
6736
+ set dirty(dirty) {
6737
+ this._dirty = dirty;
6738
+ this.scene.dirty = dirty;
6739
+ }
6740
+ start() {
6741
+ if (this._disposed) return;
6742
+ this.stop();
6743
+ this.renderer.setAnimationLoop(this._animationLoop);
6744
+ }
6745
+ stop() {
6746
+ if (this._disposed) return;
6747
+ this.renderer.setAnimationLoop(null);
6748
+ this._nextFrameTime = void 0;
6749
+ }
6750
+ /**
6751
+ * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
6752
+ * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
6753
+ * controls must be managed by their owners.
6754
+ */
6755
+ dispose() {
6756
+ if (this._disposed) return;
6757
+ this.stop();
6758
+ this._disposed = true;
6759
+ if (this._resizeListener) {
6760
+ window.removeEventListener("resize", this._resizeListener);
6761
+ this._resizeListener = void 0;
6762
+ }
6763
+ for (const [dispatcher, events] of this._eventDispatchers) {
6764
+ for (const event of events) {
6765
+ dispatcher.removeEventListener(event, this._changeListener);
6766
+ }
6767
+ }
6768
+ this._eventDispatchers.clear();
6769
+ this._stats?.dom.remove();
6770
+ this._stats = void 0;
6771
+ this.renderer.domElement.remove();
6772
+ this._element = void 0;
6773
+ if (this._controls) {
6774
+ const controls = this._controls;
6775
+ this._controls = void 0;
6776
+ controls.enabled = false;
6777
+ controls.dispose();
6567
6778
  }
6568
- function onContextMenu(event) {
6569
- if (scope.enabled === false) return;
6570
- event.preventDefault();
6779
+ this.scene.clear();
6780
+ for (const helper of this._debugHelpers) {
6781
+ helper.geometry.dispose();
6782
+ const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
6783
+ for (const material of materials) {
6784
+ material.dispose();
6785
+ }
6571
6786
  }
6572
- function addPointer(event) {
6573
- pointers.push(event);
6787
+ this._debugHelpers.length = 0;
6788
+ this.composer?.dispose();
6789
+ this.renderer.dispose();
6790
+ this.renderer.forceContextLoss();
6791
+ }
6792
+ animate(t = performance.now()) {
6793
+ if (this._disposed) return;
6794
+ if (this._controls?.enabled) {
6795
+ this._controls.update();
6574
6796
  }
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
- }
6797
+ if (this._disposed) return;
6798
+ if (!this.dirty && !this.options.render.renderAlways) return;
6799
+ const interval = this._frameInterval;
6800
+ if (interval) {
6801
+ const next = this._nextFrameTime;
6802
+ if (next !== void 0 && t + 0.1 < next) return;
6803
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6583
6804
  }
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);
6805
+ if (this._stats) {
6806
+ this._stats.begin();
6591
6807
  }
6592
- function getSecondPointerPosition(event) {
6593
- const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6594
- return pointerPositions[pointer.pointerId];
6808
+ if (this.options.composer.enabled && this.composer) {
6809
+ this.composer.render();
6810
+ } else {
6811
+ this.renderer.render(this.scene, this.camera);
6595
6812
  }
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();
6813
+ this.dirty = false;
6814
+ if (this._stats) {
6815
+ this._stats.end();
6816
+ }
6817
+ }
6818
+ //</editor-fold>
6819
+ toImage() {
6820
+ return this.renderer.domElement.toDataURL();
6821
+ }
6822
+ ///
6823
+ get attachedToBody() {
6824
+ return this.element === document.body;
6825
+ }
6826
+ get viewWidth() {
6827
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6828
+ }
6829
+ get viewHeight() {
6830
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6831
+ }
6832
+ get scene() {
6833
+ return this._scene;
6834
+ }
6835
+ get camera() {
6836
+ return this._camera;
6837
+ }
6838
+ get renderer() {
6839
+ return this._renderer;
6840
+ }
6841
+ get composer() {
6842
+ return this._composer;
6601
6843
  }
6844
+ /** Renderer-owned controls, or undefined when disabled at construction or after disposal. */
6845
+ get controls() {
6846
+ return this._controls;
6847
+ }
6848
+ ///
6602
6849
  };
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;
6850
+
6851
+ // src/skin/Skins.ts
6852
+ var Skins = class {
6853
+ //<editor-fold desc="Skins">
6854
+ static async fromUuidOrUsername(uuidOrUsername) {
6855
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6856
+ return this.fromUuid(uuidOrUsername);
6857
+ }
6858
+ return this.fromUsername(uuidOrUsername);
6859
+ }
6860
+ static async fromUuid(uuid) {
6861
+ return this.getMcProxySkinUrl(uuid);
6862
+ }
6863
+ static async fromUsername(username) {
6864
+ return this.usernameToUuid(username).then((uuid) => {
6865
+ if (uuid) {
6866
+ return this.fromUuid(uuid);
6867
+ }
6868
+ return void 0;
6869
+ });
6870
+ }
6871
+ static async fromMineSkin(mineskinId) {
6872
+ return this.getMineSkin(mineskinId).then((mineskin) => {
6873
+ if (mineskin) {
6874
+ return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6875
+ }
6876
+ return void 0;
6877
+ });
6878
+ }
6879
+ //</editor-fold>
6880
+ //<editor-fold desc="Capes">
6881
+ static async capeFromUuidOrUsername(uuidOrUsername) {
6882
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6883
+ return this.capeFromUuid(uuidOrUsername);
6884
+ }
6885
+ return this.capeFromUsername(uuidOrUsername);
6886
+ }
6887
+ static async capeFromUuid(uuid) {
6888
+ return this.getMcProxyCapeUrl(uuid);
6889
+ }
6890
+ static async capeFromUsername(username) {
6891
+ return this.usernameToUuid(username).then((uuid) => {
6892
+ if (uuid) {
6893
+ return this.capeFromUuid(uuid);
6894
+ }
6895
+ return void 0;
6896
+ });
6897
+ }
6898
+ static async capeFromCapesDev(uuid, capeType = "minecraft") {
6899
+ return this.getCapesDev(uuid, capeType).then((cape) => {
6900
+ if (cape) {
6901
+ return cape?.stillImageUrl;
6902
+ }
6903
+ return void 0;
6904
+ });
6905
+ }
6906
+ //</editor-fold>
6907
+ //<editor-fold desc="Helpers">
6908
+ static async usernameToUuid(username) {
6909
+ return this.usernameToUuidMcProxy(username);
6910
+ }
6911
+ static async usernameToUuidMcProxy(username) {
6912
+ return Requests.genericRequest({
6913
+ baseURL: "https://mcproxy.dev",
6914
+ url: "/uuid/" + username
6915
+ }).then((res) => {
6916
+ if (res.status === 200) {
6917
+ return res.data["data"]["id"];
6918
+ }
6919
+ return void 0;
6920
+ }).catch((err) => {
6921
+ console.warn(err);
6922
+ return void 0;
6923
+ });
6924
+ }
6925
+ /** @deprecated **/
6926
+ static async usernameToUuidSkinProxy(username) {
6927
+ return Requests.genericRequest({
6928
+ baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
6929
+ url: "/uuid/" + username
6930
+ }).then((res) => {
6931
+ if (res.status === 200) {
6932
+ return res.data["id"];
6933
+ }
6934
+ return void 0;
6935
+ }).catch((err) => {
6936
+ console.warn(err);
6937
+ return void 0;
6938
+ });
6939
+ }
6940
+ static async usernameToUuidMineTools(username) {
6941
+ return Requests.genericRequest({
6942
+ baseURL: "https://api.minetools.eu",
6943
+ url: "/uuid/" + username
6944
+ }).then((res) => {
6945
+ if (res.status === 200) {
6946
+ return res.data["id"];
6947
+ }
6948
+ return void 0;
6949
+ }).catch((err) => {
6950
+ console.warn(err);
6951
+ return void 0;
6952
+ });
6953
+ }
6954
+ static async getProfileFromMinetools(uuid) {
6955
+ return Requests.genericRequest({
6956
+ baseURL: "https://api.minetools.eu",
6957
+ url: "/profile/" + uuid
6958
+ }).then((res) => {
6959
+ if (res.status === 200) {
6960
+ return res.data;
6961
+ }
6962
+ });
6963
+ }
6964
+ static async getMineSkin(mineskinId) {
6965
+ return Requests.genericRequest({
6966
+ baseURL: "https://api.mineskin.org",
6967
+ url: "/get/uuid/" + mineskinId
6968
+ }).then((res) => {
6969
+ if (res.status === 200) {
6970
+ return res.data;
6971
+ }
6972
+ return void 0;
6973
+ }).catch((err) => {
6974
+ console.warn(err);
6975
+ return void 0;
6976
+ });
6977
+ }
6978
+ static async getCapesDev(uuid, type = "all") {
6979
+ return Requests.genericRequest({
6980
+ baseURL: "https://api.capes.dev",
6981
+ url: "/load/" + uuid + "/" + type
6982
+ }).then((res) => {
6983
+ if (res.status === 200) {
6984
+ return res.data;
6985
+ }
6986
+ return void 0;
6987
+ }).catch((err) => {
6988
+ console.warn(err);
6989
+ return void 0;
6990
+ });
6991
+ }
6992
+ static getCrafatarSkinUrl(uuid) {
6993
+ return "https://crafatar.com/skins/" + uuid;
6994
+ }
6995
+ static getCrafatarCapeUrl(uuid) {
6996
+ return "https://crafatar.com/capes/" + uuid;
6997
+ }
6998
+ static getMcHeadsSkinUrl(uuid) {
6999
+ return "https://mc-heads.net/skin/" + uuid;
7000
+ }
7001
+ static getMineSkinPlayerSkinUrl(uuid) {
7002
+ return "https://mineskin.org/skin/player/" + uuid;
7003
+ }
7004
+ /** @deprecated **/
7005
+ static getSkinProxySkinUrl(uuid) {
7006
+ return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
7007
+ }
7008
+ /** @deprecated **/
7009
+ static getSkinProxyCapeUrl(uuid) {
7010
+ return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
7011
+ }
7012
+ static getMcProxySkinUrl(uuid) {
7013
+ return "https://mcproxy.dev/skin/" + uuid;
6611
7014
  }
7015
+ static getMcProxyCapeUrl(uuid) {
7016
+ return "https://mcproxy.dev/cape/" + uuid;
7017
+ }
7018
+ //</editor-fold>
6612
7019
  };
6613
7020
 
6614
7021
  // src/world/Chunk.ts
@@ -6671,7 +7078,7 @@ var MineRenderWorld = class {
6671
7078
  console.log("CHUNKS", this._chunks);
6672
7079
  for (let chunk of this._chunks.values()) {
6673
7080
  console.log("dispose chunk", chunk);
6674
- await (chunk == null ? void 0 : chunk.dispose());
7081
+ await chunk?.dispose();
6675
7082
  }
6676
7083
  this._chunks.clear();
6677
7084
  }
@@ -6725,7 +7132,7 @@ var MineRenderWorld = class {
6725
7132
  };
6726
7133
 
6727
7134
  // src/world/Chunk.ts
6728
- var p12 = prefix("Chunk");
7135
+ var p11 = prefix("Chunk");
6729
7136
  var Chunk = class _Chunk {
6730
7137
  constructor(scene, x, y, z) {
6731
7138
  this._blocks = [];
@@ -6777,7 +7184,7 @@ var Chunk = class _Chunk {
6777
7184
  const index = _Chunk.chunkPosToBlockIndex(pos);
6778
7185
  const current = this._blocks[index];
6779
7186
  if (typeof current !== "undefined") {
6780
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
7187
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6781
7188
  current.object.removeFromScene();
6782
7189
  delete this._blocks[index];
6783
7190
  }
@@ -6844,6 +7251,7 @@ var Chunk = class _Chunk {
6844
7251
  AXES,
6845
7252
  ArchiveAssetSource,
6846
7253
  AssetKey,
7254
+ AssetLoadError,
6847
7255
  AssetLoader,
6848
7256
  AssetParser,
6849
7257
  AssetSource,
@@ -6856,6 +7264,7 @@ var Chunk = class _Chunk {
6856
7264
  BlockEntityModels,
6857
7265
  BlockObject,
6858
7266
  BlockStates,
7267
+ BlockTints,
6859
7268
  BrowserArchiveProxy,
6860
7269
  CUBE_FACES,
6861
7270
  Caching,
@@ -6901,6 +7310,7 @@ var Chunk = class _Chunk {
6901
7310
  OrbitControls,
6902
7311
  PersistentCache,
6903
7312
  Renderer,
7313
+ RequestError,
6904
7314
  Requests,
6905
7315
  SKIN_PARTS,
6906
7316
  SceneInspector,