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.
@@ -23,14 +23,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
24
  mod
25
25
  ));
26
- var __decorateClass = (decorators, target, key, kind) => {
27
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
28
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
29
- if (decorator = decorators[i])
30
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
31
- if (kind && result) __defProp(target, key, result);
32
- return result;
33
- };
34
26
 
35
27
  // ../../node_modules/ts-deepmerge/dist/index.js
36
28
  var require_dist = __commonJS({
@@ -40,8 +32,8 @@ var require_dist = __commonJS({
40
32
  __assign = Object.assign || function(t) {
41
33
  for (var s, i = 1, n = arguments.length; i < n; i++) {
42
34
  s = arguments[i];
43
- for (var p13 in s) if (Object.prototype.hasOwnProperty.call(s, p13))
44
- t[p13] = s[p13];
35
+ for (var p12 in s) if (Object.prototype.hasOwnProperty.call(s, p12))
36
+ t[p12] = s[p12];
45
37
  }
46
38
  return t;
47
39
  };
@@ -85,7 +77,7 @@ var require_dist = __commonJS({
85
77
  return false;
86
78
  };
87
79
  var PROTECTED_KEYS = ["__proto__"];
88
- var merge11 = function() {
80
+ var merge10 = function() {
89
81
  var objects = [];
90
82
  for (var _i = 0; _i < arguments.length; _i++) {
91
83
  objects[_i] = arguments[_i];
@@ -96,9 +88,9 @@ var require_dist = __commonJS({
96
88
  return;
97
89
  }
98
90
  if (Array.isArray(result[key]) && Array.isArray(current[key])) {
99
- result[key] = merge11.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
91
+ result[key] = merge10.options.mergeArrays ? Array.from(new Set(result[key].concat(current[key]))) : current[key];
100
92
  } else if (isObject(result[key]) && isObject(current[key])) {
101
- result[key] = merge11(result[key], current[key]);
93
+ result[key] = merge10(result[key], current[key]);
102
94
  } else {
103
95
  result[key] = current[key];
104
96
  }
@@ -109,18 +101,18 @@ var require_dist = __commonJS({
109
101
  var defaultOptions = {
110
102
  mergeArrays: true
111
103
  };
112
- merge11.options = defaultOptions;
113
- merge11.withOptions = function(options) {
104
+ merge10.options = defaultOptions;
105
+ merge10.withOptions = function(options) {
114
106
  var objects = [];
115
107
  for (var _i = 1; _i < arguments.length; _i++) {
116
108
  objects[_i - 1] = arguments[_i];
117
109
  }
118
- merge11.options = __assign({ mergeArrays: true }, options);
119
- var result = merge11.apply(void 0, __spreadArray([], __read(objects), false));
120
- merge11.options = defaultOptions;
110
+ merge10.options = __assign({ mergeArrays: true }, options);
111
+ var result = merge10.apply(void 0, __spreadArray([], __read(objects), false));
112
+ merge10.options = defaultOptions;
121
113
  return result;
122
114
  };
123
- exports.default = merge11;
115
+ exports.default = merge10;
124
116
  }
125
117
  });
126
118
 
@@ -154,17 +146,20 @@ var _PersistentCache = class _PersistentCache {
154
146
  static open(name) {
155
147
  return Env.provider.openCache(name, _PersistentCache.VERSION);
156
148
  }
149
+ /** Loads a missing entry and stores only non-nullish results. */
157
150
  async getOrLoad(key, loader) {
158
151
  let v = await this.get(key);
159
152
  if (typeof v === "undefined" || v === null) {
160
153
  v = await loader(key);
161
- await this.put(key, v);
154
+ if (typeof v !== "undefined" && v !== null) {
155
+ await this.put(key, v);
156
+ }
162
157
  }
163
158
  return v;
164
159
  }
165
160
  };
166
161
  /** Bump to invalidate every persisted entry. */
167
- _PersistentCache.VERSION = 1;
162
+ _PersistentCache.VERSION = 2;
168
163
  var PersistentCache = _PersistentCache;
169
164
 
170
165
  // src/env/browser/BrowserCache.ts
@@ -265,7 +260,8 @@ var BrowserEnv = class {
265
260
  }
266
261
  openCache(name, version) {
267
262
  return new BrowserCache(localforage.createInstance({
268
- name,
263
+ // IndexedDB schema upgrades retain records; each cache generation needs its own database.
264
+ name: name + version,
269
265
  version
270
266
  }));
271
267
  }
@@ -282,7 +278,7 @@ registerBrowserEnv();
282
278
  // src/Axis.ts
283
279
  import { Vector3 } from "three";
284
280
  var Axis = /* @__PURE__ */ ((Axis3) => {
285
- Axis3["X"] = "X";
281
+ Axis3["X"] = "x";
286
282
  Axis3["Y"] = "y";
287
283
  Axis3["Z"] = "z";
288
284
  return Axis3;
@@ -290,7 +286,7 @@ var Axis = /* @__PURE__ */ ((Axis3) => {
290
286
  var AXES = Object.values(Axis);
291
287
  function axisToVec3(axis) {
292
288
  switch (axis) {
293
- case "X" /* X */:
289
+ case "x" /* X */:
294
290
  return new Vector3(1, 0, 0);
295
291
  case "y" /* Y */:
296
292
  return new Vector3(0, 1, 0);
@@ -393,7 +389,10 @@ function serializeMeshKey(key) {
393
389
  // src/cache/Caching.ts
394
390
  import { Caches } from "@inventivetalent/loading-cache";
395
391
  import { Time } from "@inventivetalent/time";
396
- var Caching = class {
392
+ var _Caching = class _Caching {
393
+ static createAssetCache() {
394
+ return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
395
+ }
397
396
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
398
397
  static get all() {
399
398
  return [
@@ -410,7 +409,11 @@ var Caching = class {
410
409
  this.rawModelCache,
411
410
  this.mergedModelCache,
412
411
  this.modelTextureAtlasCache,
413
- this.blockStateCache
412
+ this.blockStateCache,
413
+ this.listAssetCache,
414
+ this.defaultBlockStatesCache,
415
+ this.blockTintCache,
416
+ this.entityModelsCache
414
417
  ];
415
418
  }
416
419
  static clear() {
@@ -421,8 +424,8 @@ var Caching = class {
421
424
  /**
422
425
  * Clears every cache and stops its expiry timer.
423
426
  *
424
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
425
- * this is called - see {@link shutdown}.
427
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
428
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
426
429
  */
427
430
  static end() {
428
431
  for (const cache of this.all) {
@@ -436,20 +439,25 @@ var Caching = class {
436
439
  };
437
440
  }
438
441
  };
439
- Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
440
- Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
441
- Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
442
- Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
443
- Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
444
- Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
445
- Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
446
- Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
447
- Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
448
- Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
449
- Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
450
- Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
451
- Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
452
- Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
442
+ _Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
443
+ _Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
444
+ _Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
445
+ _Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
446
+ _Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
447
+ _Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
448
+ _Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
449
+ _Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
450
+ _Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
451
+ _Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
452
+ _Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
453
+ _Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
454
+ _Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
455
+ _Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
456
+ _Caching.listAssetCache = _Caching.createAssetCache();
457
+ _Caching.defaultBlockStatesCache = _Caching.createAssetCache();
458
+ _Caching.blockTintCache = _Caching.createAssetCache();
459
+ _Caching.entityModelsCache = _Caching.createAssetCache();
460
+ var Caching = _Caching;
453
461
 
454
462
  // src/Geometries.ts
455
463
  var Geometries = class _Geometries {
@@ -477,6 +485,7 @@ import { CanvasTexture, Texture as Texture2 } from "three";
477
485
 
478
486
  // src/texture/TextureLoader.ts
479
487
  import { RGBAFormat, Texture } from "three";
488
+ import * as THREE from "three";
480
489
 
481
490
  // src/canvas/CanvasCompat.ts
482
491
  function createImage(width, height) {
@@ -487,9 +496,7 @@ function createCanvas(width, height) {
487
496
  }
488
497
 
489
498
  // src/request/Requests.ts
490
- import axios from "axios";
491
- import { JobQueue } from "jobqu";
492
- import { Time as Time2 } from "@inventivetalent/time";
499
+ import { JobCancelledError, JobQueue } from "jobqu";
493
500
 
494
501
  // src/util/log.ts
495
502
  var Reset = "\x1B[0m";
@@ -499,198 +506,170 @@ function prefix(prefix2) {
499
506
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
500
507
  }
501
508
 
502
- // src/util/BatchedExecutor.ts
503
- var BatchedExecutor = class {
504
- constructor(interval = 1, batch = 30) {
505
- this.interval = interval;
506
- this.batch = batch;
507
- this.queue = [];
508
- this.task = setInterval(() => this.run());
509
- }
510
- submit(task) {
511
- this.queue.push(task);
512
- }
513
- run() {
514
- for (let i = 0; i < this.batch; i++) {
515
- this.runNext();
516
- }
517
- }
518
- runNext() {
519
- let next = this.queue.shift();
520
- if (next) next();
509
+ // src/request/Requests.ts
510
+ var p = prefix("Requests");
511
+ var RequestError = class extends Error {
512
+ constructor(message, response, cause) {
513
+ super(message);
514
+ this.response = response;
515
+ this.cause = cause;
516
+ this.name = "RequestError";
521
517
  }
522
518
  };
523
-
524
- // src/util/model.ts
525
- import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
526
- function applyElementRotation(rotation, geometry) {
527
- const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
528
- geometry.translate(-origin.x, -origin.y, -origin.z);
529
- switch (rotation.axis) {
530
- case "X" /* X */:
531
- geometry.rotateX(toRadians(rotation.angle));
532
- break;
533
- case "y" /* Y */:
534
- geometry.rotateY(toRadians(rotation.angle));
535
- break;
536
- case "z" /* Z */:
537
- geometry.rotateZ(toRadians(rotation.angle));
538
- break;
539
- }
540
- if (rotation.rescale) {
541
- if (Math.abs(rotation.angle) === 22.5) {
542
- const s = 1 / Math.cos(0.39269909262657166);
543
- geometry.scale(s, 1, s);
544
- } else {
545
- const s = 1 / Math.cos(0.7853981852531433);
546
- geometry.scale(s, 1, s);
519
+ async function fetchRequest(config, defaultBaseURL) {
520
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
521
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
522
+ const headers = new Headers(options.headers);
523
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
524
+ headers.set("User-Agent", "MineRender");
525
+ }
526
+ const attemptSignal = AbortSignal.any([
527
+ ...signal ? [signal] : [],
528
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
529
+ ]);
530
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
531
+ attemptSignal.throwIfAborted();
532
+ try {
533
+ const response = await fetch(request);
534
+ const result = {
535
+ data: void 0,
536
+ status: response.status,
537
+ statusText: response.statusText,
538
+ headers: response.headers,
539
+ url: response.url
540
+ };
541
+ if (!response.ok) {
542
+ await response.body?.cancel().catch(() => {
543
+ });
544
+ throw new RequestError(`Request failed with status ${response.status}`, result);
545
+ }
546
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
547
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
548
+ return { ...result, data };
549
+ } catch (error) {
550
+ attemptSignal.throwIfAborted();
551
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
552
+ throw new RequestError("Network request failed", void 0, error);
547
553
  }
554
+ throw error;
548
555
  }
549
- geometry.translate(origin.x, origin.y, origin.z);
550
- }
551
- function applyModelPartRotation(modelPart, geometry) {
552
- const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
553
- geometry.translate(-origin.x, -origin.y, -origin.z);
554
- geometry.rotateX(toRadians(modelPart.pitch));
555
- geometry.rotateY(toRadians(modelPart.yaw));
556
- geometry.rotateZ(toRadians(modelPart.roll));
557
- geometry.translate(origin.x, origin.y, origin.z);
558
556
  }
559
- function applyGenericRotation(axis, rotation, obj) {
560
- switch (axis) {
561
- case "X" /* X */:
562
- obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
563
- break;
564
- case "y" /* Y */:
565
- obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
566
- break;
567
- case "z" /* Z */:
568
- obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
569
- break;
557
+ async function abortable(promise, signal) {
558
+ if (!signal) return promise;
559
+ let abort;
560
+ const cancelled = new Promise((_, reject) => {
561
+ abort = () => reject(signal.reason);
562
+ signal.addEventListener("abort", abort, { once: true });
563
+ if (signal.aborted) abort();
564
+ });
565
+ try {
566
+ return await Promise.race([promise, cancelled]);
567
+ } finally {
568
+ signal.removeEventListener("abort", abort);
570
569
  }
571
570
  }
572
- function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
573
- let size = new Vector32();
574
- box.getSize(size);
575
- let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
576
- let wireGeo = new EdgesGeometry(boxGeo);
577
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
578
- let wireframe = new LineSegments(wireGeo, wireMat);
579
- obj.add(wireframe);
580
- let axes = new AxesHelper(1);
581
- obj.add(axes);
582
- }
583
- function addWireframeToObject(obj, color = 16777215, w = 2) {
584
- let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
585
- let wireGeo = new EdgesGeometry(boxGeo);
586
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
587
- let wireframe = new LineSegments(wireGeo, wireMat);
588
- obj.add(wireframe);
589
- let axes = new AxesHelper(1);
590
- obj.add(axes);
591
- }
592
- function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
593
- let wireGeo = new EdgesGeometry(geo);
594
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
595
- let wireframe = new LineSegments(wireGeo, wireMat);
596
- mesh.add(wireframe);
597
- let axes = new AxesHelper(1);
598
- mesh.add(axes);
599
- }
600
-
601
- // src/util/performance.ts
602
- function captureException(e, ...extra) {
603
- console.error(e, extra);
604
- }
605
- function timingStart(marker) {
606
- console.time(marker);
607
- }
608
- function timingEnd(marker) {
609
- console.timeEnd(marker);
610
- }
611
-
612
- // src/util/three.ts
613
- function isObject3D(obj) {
614
- return obj.isObject3D;
615
- }
616
- function isMesh(obj) {
617
- return obj.isMesh;
618
- }
619
- function isInstancedMesh(obj) {
620
- return obj.isInstancedMesh;
621
- }
622
- function isPerspectiveCamera(obj) {
623
- return obj.isPerspectiveCamera;
624
- }
625
- function isOrthographicCamera(obj) {
626
- return obj.isOrthographicCamera;
627
- }
628
-
629
- // src/request/Requests.ts
630
- var p = prefix("Requests");
631
- if (typeof window === "undefined") {
632
- axios.defaults.headers["User-Agent"] = "MineRender";
633
- }
634
- var _Requests = class _Requests {
635
- static genericRequest(request) {
636
- return this.genericQueue.add(request).catch(async (e) => {
637
- console.debug(p, "generic catch", e.code, e);
638
- if (this.shouldRetry(e, request)) {
639
- await sleep(100);
640
- return this.genericRequest(request);
641
- }
642
- throw e;
643
- });
644
- }
645
- static mcAssetRequest(request) {
646
- return this.mcAssetRequestQueue.add(request).catch((e) => {
647
- console.debug(p, "mcAssetRequest catch", e.code, e);
648
- throw e;
649
- });
571
+ var RequestQueue = class {
572
+ constructor() {
573
+ this.pendingRequests = 0;
574
+ this.stopped = new AbortController();
575
+ this.queue = new JobQueue(
576
+ (request) => fetchRequest(request, this.baseURL),
577
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
578
+ );
650
579
  }
651
- static shouldRetry(e, request) {
652
- if ("code" in e) {
653
- if ("ECONNABORTED" === e.code) {
654
- if ("minerenderRetry" in request) {
655
- if (request["minerenderRetry"] > 0) {
656
- request["minerenderRetry"]--;
657
- return true;
580
+ async request(request) {
581
+ this.pendingRequests++;
582
+ const signal = request.signal;
583
+ try {
584
+ for (let retries = 0; ; retries++) {
585
+ signal?.throwIfAborted();
586
+ try {
587
+ return await abortable(this.queue.add(request), signal);
588
+ } catch (error) {
589
+ console.debug(p, "Request failed", error);
590
+ const delay = this.retryDelay(error, request, retries);
591
+ if (delay === void 0) {
592
+ throw error;
658
593
  }
659
- } else {
660
- request["minerenderRetry"] = 3;
661
- return true;
594
+ await this.waitForRetry(delay, signal);
662
595
  }
663
596
  }
597
+ } finally {
598
+ if (signal?.aborted) {
599
+ this.queue.remove(request);
600
+ }
601
+ this.pendingRequests--;
664
602
  }
665
- return false;
603
+ }
604
+ retryDelay(error, request, retries) {
605
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
606
+ return void 0;
607
+ }
608
+ if (error instanceof RequestError) {
609
+ const status = error.response?.status;
610
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
611
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
612
+ return void 0;
613
+ }
614
+ let delay = 100 * 2 ** retries;
615
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
616
+ if (retryAfter !== void 0 && retryAfter !== null) {
617
+ const seconds = Number(retryAfter);
618
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
619
+ return void 0;
620
+ }
621
+ delay = Math.max(delay, seconds * 1e3);
622
+ }
623
+ return delay;
624
+ }
625
+ async waitForRetry(delay, signal) {
626
+ let timer;
627
+ const waiting = new Promise((resolve) => {
628
+ timer = setTimeout(resolve, delay);
629
+ });
630
+ try {
631
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
632
+ } finally {
633
+ clearTimeout(timer);
634
+ }
635
+ }
636
+ get pendingSize() {
637
+ return this.pendingRequests;
638
+ }
639
+ end() {
640
+ this.queue.end();
641
+ this.stopped.abort(new JobCancelledError("ended"));
642
+ }
643
+ };
644
+ var Requests = class {
645
+ static genericRequest(request) {
646
+ return this.genericQueue.request(request);
647
+ }
648
+ static mcAssetRequest(request) {
649
+ return this.mcAssetRequestQueue.request(request);
666
650
  }
667
651
  static setMcAssetRoot(root) {
668
- this.mcAssetInstance.defaults.baseURL = root;
652
+ this.mcAssetRequestQueue.baseURL = root;
669
653
  }
654
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
670
655
  static get queueSizes() {
671
656
  return {
672
- generic: this.genericQueue.size,
673
- mcAsset: this.mcAssetRequestQueue.size
657
+ generic: this.genericQueue.pendingSize,
658
+ mcAsset: this.mcAssetRequestQueue.pendingSize
674
659
  };
675
660
  }
676
661
  /**
677
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
678
- * exit until this is called - see {@link shutdown}.
662
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
663
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
664
+ * this cleanup. See {@link shutdown}.
679
665
  */
680
666
  static end() {
681
667
  this.genericQueue.end();
682
668
  this.mcAssetRequestQueue.end();
683
669
  }
684
670
  };
685
- _Requests.axiosInstance = axios.create({
686
- timeout: 5e3
687
- });
688
- _Requests.mcAssetInstance = axios.create({
689
- timeout: 5e3
690
- });
691
- _Requests.genericQueue = new JobQueue((request) => _Requests.axiosInstance.request(request), Time2.millis(10), 1);
692
- _Requests.mcAssetRequestQueue = new JobQueue((request) => _Requests.mcAssetInstance.request(request), Time2.millis(10), 1);
693
- var Requests = _Requests;
671
+ Requests.genericQueue = new RequestQueue();
672
+ Requests.mcAssetRequestQueue = new RequestQueue();
694
673
 
695
674
  // src/WrappedImage.ts
696
675
  var WrappedImage = class {
@@ -728,10 +707,10 @@ var WrappedImage = class {
728
707
  return this.animated ? this.width : this.height;
729
708
  }
730
709
  get frameCount() {
731
- return this.height / this.width;
710
+ return this.height / this.frameHeight;
732
711
  }
733
712
  getFrameY(frame) {
734
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
713
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
735
714
  }
736
715
  getSectionData(sx, sy, sw, sh) {
737
716
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -741,7 +720,7 @@ var WrappedImage = class {
741
720
  }
742
721
  getFrameSectionData(frame) {
743
722
  const y = this.getFrameY(frame);
744
- return this.getSectionData(0, y, this.width, this.width + y);
723
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
745
724
  }
746
725
  };
747
726
 
@@ -755,29 +734,41 @@ var ImageLoader = class _ImageLoader {
755
734
  static async loadAsync(src) {
756
735
  return new Promise((resolve, reject) => {
757
736
  const image = this._createImage();
758
- image.src = src;
759
737
  image.onload = () => resolve(image);
760
- image.onerror = (err) => reject(err);
738
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
739
+ image.src = src;
761
740
  });
762
741
  }
763
742
  static loadElement(src, onload, onerr) {
764
743
  const image = this._createImage();
765
- image.src = src;
766
744
  if (onload)
767
745
  image.onload = onload;
768
746
  if (onerr)
769
747
  image.onerror = onerr;
748
+ image.src = src;
770
749
  return image;
771
750
  }
772
751
  static async loadData(src) {
773
752
  console.debug(p2, "loadData", src);
774
- return await this.infoToData(await this.getInfo(src));
753
+ const image = await this.loadCanvasData(src);
754
+ return image.data.getImageData(0, 0, image.width, image.height);
775
755
  }
776
756
  static async loadCanvasData(src) {
777
- return await this.infoToCanvasData(await this.getInfo(src));
757
+ const keyStr = serializeImageKey({ src });
758
+ const info = this.getInfo(src);
759
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
760
+ try {
761
+ return await this.infoToCanvasData(await info);
762
+ } catch (err) {
763
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
764
+ Caching.rawImageCache.invalidate(keyStr);
765
+ }
766
+ throw err;
767
+ }
778
768
  }
779
769
  static async infoToCanvasData(info) {
780
- const image = await _ImageLoader.loadAsync(info.src);
770
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
771
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
781
772
  const canvas = createCanvas(info.width, info.height);
782
773
  const context = canvas.getContext("2d");
783
774
  context.drawImage(image, 0, 0);
@@ -788,11 +779,8 @@ var ImageLoader = class _ImageLoader {
788
779
  };
789
780
  }
790
781
  static async infoToData(info) {
791
- const image = await _ImageLoader.loadAsync(info.src);
792
- const canvas = createCanvas(info.width, info.height);
793
- const context = canvas.getContext("2d");
794
- context.drawImage(image, 0, 0);
795
- return context.getImageData(0, 0, canvas.width, canvas.height);
782
+ const image = await this.infoToCanvasData(info);
783
+ return image.data.getImageData(0, 0, image.width, image.height);
796
784
  }
797
785
  static async getData(src) {
798
786
  const keyStr = serializeImageKey({ src });
@@ -807,38 +795,25 @@ var ImageLoader = class _ImageLoader {
807
795
  });
808
796
  }
809
797
  static async processResponse(response) {
810
- const src = response.config.url;
798
+ const src = response.url;
811
799
  const data = Buffer2.from(response.data);
812
800
  const { width, height, type } = Env.provider.imageSize(data);
801
+ if (!width || !height) {
802
+ throw new Error("Invalid or unsupported image dimensions");
803
+ }
813
804
  return {
814
805
  src,
815
- width: width || 0,
816
- height: height || 0,
806
+ width,
807
+ height,
817
808
  type,
818
809
  data
819
810
  };
820
811
  }
821
812
  static async loadInfo(src) {
822
- if (src.startsWith("data:image/png;base64")) {
823
- return this.processResponse({
824
- config: {
825
- url: src
826
- },
827
- data: Buffer2.from(src.substr("data:image/png;base64,".length), "base64")
828
- });
829
- }
830
813
  return Requests.genericRequest({
831
814
  url: src,
832
815
  responseType: "arraybuffer"
833
- }).then(this.processResponse).catch((err) => {
834
- return {
835
- src,
836
- width: 0,
837
- height: 0,
838
- type: void 0,
839
- data: Buffer2.from([0])
840
- };
841
- });
816
+ }).then(this.processResponse);
842
817
  }
843
818
  static async getInfo(src) {
844
819
  const keyStr = serializeImageKey({ src });
@@ -860,15 +835,22 @@ var ImageLoader = class _ImageLoader {
860
835
 
861
836
  // src/texture/TextureLoader.ts
862
837
  var TextureLoader = class {
838
+ /** Reports whether image loading failed, so cached textures can be retried. */
839
+ static hasFailed(texture) {
840
+ return this.failedTextures.has(texture);
841
+ }
863
842
  static createTexture() {
864
843
  return new Texture();
865
844
  }
866
845
  static loadInBackground(src, format = RGBAFormat, rotation = 0) {
867
846
  const texture = this.createTexture();
868
- const image = ImageLoader.loadElement(src);
869
- image.onload = function() {
847
+ texture.colorSpace = THREE.SRGBColorSpace;
848
+ const image = ImageLoader.loadElement(src, () => {
870
849
  texture.needsUpdate = true;
871
- };
850
+ }, (error) => {
851
+ this.failedTextures.add(texture);
852
+ console.warn("Failed to load texture", src, error);
853
+ });
872
854
  texture.image = image;
873
855
  texture.format = format;
874
856
  texture.rotation = rotation;
@@ -876,22 +858,27 @@ var TextureLoader = class {
876
858
  }
877
859
  static load(src, format = RGBAFormat, rotation = 0) {
878
860
  const texture = new Texture();
861
+ texture.colorSpace = THREE.SRGBColorSpace;
879
862
  ImageLoader.getData(src).then((image) => {
880
- texture.needsUpdate = true;
881
863
  texture.image = image;
864
+ texture.needsUpdate = true;
865
+ }).catch((error) => {
866
+ this.failedTextures.add(texture);
867
+ console.warn("Failed to load texture", src, error);
882
868
  });
883
869
  texture.format = format;
884
870
  texture.rotation = rotation;
885
871
  return Textures.initTextureProps(texture);
886
872
  }
887
873
  };
874
+ TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
888
875
 
889
876
  // src/texture/Textures.ts
890
- import * as THREE from "three";
877
+ import * as THREE2 from "three";
891
878
  var Textures = class _Textures {
892
879
  static initTextureProps(texture) {
893
- texture.magFilter = THREE.NearestFilter;
894
- texture.minFilter = THREE.NearestFilter;
880
+ texture.magFilter = THREE2.NearestFilter;
881
+ texture.minFilter = THREE2.NearestFilter;
895
882
  texture.anisotropy = 0;
896
883
  return texture;
897
884
  }
@@ -902,10 +889,16 @@ var Textures = class _Textures {
902
889
  return new Texture2();
903
890
  }
904
891
  static createCanvasTexture(canvas) {
905
- return this.initTextureProps(new CanvasTexture(canvas));
892
+ const texture = new CanvasTexture(canvas);
893
+ texture.colorSpace = THREE2.SRGBColorSpace;
894
+ return this.initTextureProps(texture);
906
895
  }
907
896
  static getImage(key) {
908
897
  const keyStr = serializeTextureKey(key);
898
+ const cached = Caching.textureCache.peek(keyStr);
899
+ if (cached && TextureLoader.hasFailed(cached)) {
900
+ Caching.textureCache.invalidate(keyStr);
901
+ }
909
902
  return Caching.textureCache.get(keyStr, (k) => {
910
903
  return _Textures.createImage(key);
911
904
  });
@@ -949,6 +942,7 @@ var _Materials = class _Materials {
949
942
  uniform bool SHADE;
950
943
 
951
944
  varying vec2 vUv;
945
+ varying vec3 vTint;
952
946
  varying float light;
953
947
  varying float lift;
954
948
 
@@ -961,7 +955,11 @@ var _Materials = class _Materials {
961
955
 
962
956
  if (SHADE) {
963
957
 
964
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
958
+ #ifdef USE_INSTANCING
959
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
960
+ #else
961
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
962
+ #endif
965
963
 
966
964
  float yLight = (1.0+N.y) * 0.5;
967
965
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -979,6 +977,7 @@ var _Materials = class _Materials {
979
977
  }
980
978
 
981
979
  vUv = uv;
980
+ vTint = color;
982
981
 
983
982
  #ifdef USE_INSTANCING
984
983
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -1000,12 +999,14 @@ var _Materials = class _Materials {
1000
999
  uniform float BRIGHTNESS;
1001
1000
 
1002
1001
  varying vec2 vUv;
1002
+ varying vec3 vTint;
1003
1003
  varying float light;
1004
1004
  varying float lift;
1005
1005
 
1006
1006
  void main(void)
1007
1007
  {
1008
1008
  vec4 color = texture2D(map, vUv);
1009
+ color.rgb *= vTint;
1009
1010
 
1010
1011
  if (color.a < 0.01) discard;
1011
1012
 
@@ -1019,6 +1020,9 @@ var _Materials = class _Materials {
1019
1020
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1020
1021
 
1021
1022
  }
1023
+
1024
+ #include <tonemapping_fragment>
1025
+ #include <colorspace_fragment>
1022
1026
  }
1023
1027
  `;
1024
1028
  try {
@@ -1047,6 +1051,10 @@ var _Materials = class _Materials {
1047
1051
  }
1048
1052
  static getImage(key) {
1049
1053
  const keyStr = serializeMaterialKey(key);
1054
+ const map = Caching.materialCache.peek(keyStr)?.map;
1055
+ if (map && TextureLoader.hasFailed(map)) {
1056
+ Caching.materialCache.invalidate(keyStr);
1057
+ }
1050
1058
  return Caching.materialCache.get(keyStr, (k) => {
1051
1059
  return _Materials.createImage(key);
1052
1060
  });
@@ -1071,10 +1079,10 @@ _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA
1071
1079
  var Materials = _Materials;
1072
1080
 
1073
1081
  // src/Meshes.ts
1074
- import { Mesh as Mesh2 } from "three";
1082
+ import { Mesh } from "three";
1075
1083
  var Meshes = class _Meshes {
1076
1084
  static createBox(key) {
1077
- return new Mesh2(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1085
+ return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1078
1086
  }
1079
1087
  static getBox(key) {
1080
1088
  const keyStr = serializeMeshKey(key);
@@ -1085,7 +1093,7 @@ var Meshes = class _Meshes {
1085
1093
  };
1086
1094
 
1087
1095
  // src/UVMapper.ts
1088
- import { Float32BufferAttribute as Float32BufferAttribute2, Vector2 } from "three";
1096
+ import { Float32BufferAttribute as Float32BufferAttribute2, Vector2, Vector3 as Vector33 } from "three";
1089
1097
 
1090
1098
  // src/model/ModelMerger.ts
1091
1099
  var import_ts_deepmerge = __toESM(require_dist());
@@ -1121,6 +1129,7 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1121
1129
  this.rootType = rootType;
1122
1130
  this.extension = extension;
1123
1131
  this.root = root;
1132
+ this.isAssetKey = true;
1124
1133
  }
1125
1134
  static parse(assetType, str, origin) {
1126
1135
  let namespace = origin?.namespace || DEFAULT_NAMESPACE;
@@ -1136,12 +1145,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1136
1145
  split.shift();
1137
1146
  }
1138
1147
  let path = split.join("/");
1139
- let extension = assetType === "textures" ? ".png" : origin?.assetType || ".json";
1148
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1149
+ if (extension && path.endsWith(extension)) {
1150
+ path = path.slice(0, -extension.length);
1151
+ }
1140
1152
  return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1141
1153
  }
1142
1154
  toString() {
1143
1155
  let a = [
1144
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1156
+ this.root ?? AssetLoader.ROOT,
1145
1157
  this.rootType ?? "__rootType__",
1146
1158
  this.assetType ?? "__assetType__",
1147
1159
  this.type ?? "__type__",
@@ -1151,12 +1163,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1151
1163
  return a.join("/");
1152
1164
  }
1153
1165
  getFullPath() {
1154
- let p13 = [];
1166
+ let p12 = [];
1155
1167
  if (this.type) {
1156
- p13.push(this.type);
1168
+ p12.push(this.type);
1157
1169
  }
1158
- p13.push(this.path);
1159
- return p13.join("/");
1170
+ p12.push(this.path);
1171
+ return p12.join("/");
1160
1172
  }
1161
1173
  toNamespacedString() {
1162
1174
  return this.namespace + ":" + this.getFullPath();
@@ -1166,10 +1178,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1166
1178
  }
1167
1179
  };
1168
1180
  function isBasicAssetKey(obj) {
1169
- return "namespace" in obj && "path" in obj;
1181
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1170
1182
  }
1171
1183
  function isAssetKey(obj) {
1172
- return isBasicAssetKey(obj) && "parse" in obj;
1184
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1173
1185
  }
1174
1186
 
1175
1187
  // src/model/ModelMerger.ts
@@ -1178,10 +1190,10 @@ var ModelMerger = class {
1178
1190
  const models = await this.collectAllParents(model);
1179
1191
  let merged = {};
1180
1192
  for (let parentModel of models) {
1181
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1193
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, parentModel);
1182
1194
  }
1183
- merged = (0, import_ts_deepmerge.default)(merged, model);
1184
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1195
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, model);
1196
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1185
1197
  merged.hierarchy.push(`${merged.parent}`);
1186
1198
  return merged;
1187
1199
  }
@@ -1191,6 +1203,7 @@ var ModelMerger = class {
1191
1203
  }
1192
1204
  const models = [];
1193
1205
  const parentKey = AssetKey.parse("models", model.parent);
1206
+ parentKey.root = model.key?.root;
1194
1207
  const parentModel = await Models.getRaw(parentKey);
1195
1208
  if (parentModel) {
1196
1209
  models.unshift(parentModel);
@@ -1200,9 +1213,6 @@ var ModelMerger = class {
1200
1213
  }
1201
1214
  };
1202
1215
 
1203
- // src/assets/Models.ts
1204
- import { Memoize } from "typescript-memoize";
1205
-
1206
1216
  // src/assets/source/parser/AssetParsers.ts
1207
1217
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1208
1218
  AssetParser2["MODEL"] = "model";
@@ -1216,30 +1226,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1216
1226
  })(AssetParser || {});
1217
1227
 
1218
1228
  // src/assets/Models.ts
1219
- var _Models = class _Models {
1229
+ var Models = class _Models {
1220
1230
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1221
1231
  // the library, and would require an EnvProvider before any entry has had a chance to register
1222
1232
  static get PERSISTENT_CACHE() {
1223
1233
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1224
1234
  }
1225
1235
  static async getItemList() {
1226
- return AssetLoader.get(new AssetKey(
1227
- DEFAULT_NAMESPACE,
1228
- "_list",
1229
- "models",
1230
- "item",
1231
- "assets",
1232
- ".json",
1233
- DEFAULT_ROOT
1234
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1236
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1237
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1238
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1239
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1240
+ }).then((r) => r?.files ?? []);
1235
1241
  }
1236
1242
  static async loadAndMerge(key) {
1237
- const model = await this.getRaw(key);
1243
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1238
1244
  if (!model) {
1239
1245
  return void 0;
1240
1246
  }
1241
1247
  return ModelMerger.mergeWithParents(model);
1242
1248
  }
1249
+ static async getItemModel(key) {
1250
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1251
+ const model = await this.PERSISTENT_CACHE.getOrLoad(itemKey.serialize(), async () => {
1252
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1253
+ if (!result) return void 0;
1254
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1255
+ const reference = this.defaultItemModel(result.asset.model, key);
1256
+ const modelKey = AssetKey.parse("models", reference);
1257
+ modelKey.root = key.root;
1258
+ const model2 = await this.getRaw(modelKey);
1259
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1260
+ return model2;
1261
+ });
1262
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1263
+ }
1264
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1265
+ static defaultItemModel(node, key) {
1266
+ if (!node || typeof node.type !== "string") {
1267
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1268
+ }
1269
+ switch (node.type.replace(/^minecraft:/, "")) {
1270
+ case "model":
1271
+ if (typeof node.model === "string" && node.model) return node.model;
1272
+ break;
1273
+ case "condition":
1274
+ return this.defaultItemModel(node.on_false, key);
1275
+ case "select": {
1276
+ 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;
1277
+ return this.defaultItemModel(selected ?? node.fallback, key);
1278
+ }
1279
+ case "range_dispatch": {
1280
+ const selected = node.entries?.reduce((match, entry) => {
1281
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1282
+ }, void 0);
1283
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1284
+ }
1285
+ }
1286
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1287
+ }
1243
1288
  static async getRaw(key) {
1244
1289
  if (!key.assetType) {
1245
1290
  key.assetType = "models";
@@ -1278,19 +1323,15 @@ var _Models = class _Models {
1278
1323
  return this.PERSISTENT_CACHE.clear();
1279
1324
  }
1280
1325
  };
1281
- __decorateClass([
1282
- Memoize()
1283
- ], _Models, "getItemList", 1);
1284
- var Models = _Models;
1285
1326
 
1286
1327
  // src/assets/BlockStates.ts
1287
- import { Memoize as Memoize2 } from "typescript-memoize";
1288
1328
  var BlockStates = class {
1289
1329
  static get PERSISTENT_CACHE() {
1290
1330
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1291
1331
  }
1332
+ // BlockState names are hardcoded
1292
1333
  static async getList() {
1293
- return AssetLoader.get(new AssetKey(
1334
+ const key = new AssetKey(
1294
1335
  DEFAULT_NAMESPACE,
1295
1336
  "_list",
1296
1337
  "blockstates",
@@ -1298,11 +1339,16 @@ var BlockStates = class {
1298
1339
  "assets",
1299
1340
  ".json",
1300
1341
  DEFAULT_ROOT
1301
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1342
+ );
1343
+ return Caching.listAssetCache.get(key.serialize(), () => {
1344
+ return AssetLoader.get(key, "list" /* LIST */);
1345
+ }).then((r) => r?.files ?? []);
1302
1346
  }
1303
1347
  static async getDefaultStates() {
1304
1348
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1305
- return AssetLoader.get(key, "json" /* JSON */);
1349
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1350
+ return AssetLoader.get(key, "json" /* JSON */);
1351
+ });
1306
1352
  }
1307
1353
  static async getDefaultState(key) {
1308
1354
  const defaultStates = await this.getDefaultStates();
@@ -1341,17 +1387,11 @@ var BlockStates = class {
1341
1387
  await this.PERSISTENT_CACHE.clear();
1342
1388
  }
1343
1389
  };
1344
- __decorateClass([
1345
- Memoize2()
1346
- ], BlockStates, "getList", 1);
1347
- __decorateClass([
1348
- Memoize2()
1349
- ], BlockStates, "getDefaultStates", 1);
1350
1390
  var DefaultBlockStates = class {
1351
1391
  };
1352
1392
 
1353
1393
  // src/assets/Assets.ts
1354
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1394
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1355
1395
  var DEFAULT_NAMESPACE = "minecraft";
1356
1396
  var Assets = class {
1357
1397
  /**
@@ -1373,37 +1413,174 @@ var AssetSource = class {
1373
1413
  constructor() {
1374
1414
  }
1375
1415
  };
1376
-
1377
- // src/nbt/NBTHelper.ts
1378
- var NBTHelper = class {
1379
- static async fromBuffer(buffer) {
1380
- const prismarineNbt = await import("prismarine-nbt");
1381
- const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1382
- return parsed;
1416
+ var AssetLoadError = class extends Error {
1417
+ constructor(source, key, path, cause) {
1418
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1419
+ this.source = source;
1420
+ this.key = key;
1421
+ this.path = path;
1422
+ this.cause = cause;
1423
+ this.name = "AssetLoadError";
1383
1424
  }
1384
1425
  };
1385
1426
 
1386
- // src/assets/source/HostedAssetSource.ts
1387
- var import_ts_deepmerge2 = __toESM(require_dist());
1388
- var p3 = prefix("HostedAssetSource");
1389
- var DEFAULT_OPTIONS = {
1390
- retryDefaults: true
1391
- };
1392
- var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1393
- async loadOrRetryWithDefaults(key, parser) {
1394
- const direct = await this.load(key, parser);
1395
- if (typeof direct !== "undefined") {
1396
- return direct;
1427
+ // src/util/BatchedExecutor.ts
1428
+ var BatchedExecutor = class {
1429
+ constructor(interval = 1, batch = 30) {
1430
+ this.interval = interval;
1431
+ this.batch = batch;
1432
+ this.queue = [];
1433
+ this.task = setInterval(() => this.run());
1434
+ }
1435
+ submit(task) {
1436
+ this.queue.push(task);
1437
+ }
1438
+ run() {
1439
+ for (let i = 0; i < this.batch; i++) {
1440
+ this.runNext();
1397
1441
  }
1398
- if (key.namespace !== DEFAULT_NAMESPACE) {
1399
- console.info(p3, "Retrying", key, "with default namespace");
1400
- const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
1401
- const namespaced = await this.load(namespaceKey, parser);
1402
- if (typeof namespaced !== "undefined") {
1403
- return namespaced;
1404
- }
1405
- if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1406
- console.info(p3, "Retrying", key, "with default root+namespace");
1442
+ }
1443
+ runNext() {
1444
+ let next = this.queue.shift();
1445
+ if (next) next();
1446
+ }
1447
+ };
1448
+
1449
+ // src/util/model.ts
1450
+ import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
1451
+ function applyElementRotation(rotation, geometry) {
1452
+ const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1453
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1454
+ switch (rotation.axis) {
1455
+ case "x" /* X */:
1456
+ geometry.rotateX(toRadians(rotation.angle));
1457
+ break;
1458
+ case "y" /* Y */:
1459
+ geometry.rotateY(toRadians(rotation.angle));
1460
+ break;
1461
+ case "z" /* Z */:
1462
+ geometry.rotateZ(toRadians(rotation.angle));
1463
+ break;
1464
+ }
1465
+ if (rotation.rescale) {
1466
+ if (Math.abs(rotation.angle) === 22.5) {
1467
+ const s = 1 / Math.cos(0.39269909262657166);
1468
+ geometry.scale(s, 1, s);
1469
+ } else {
1470
+ const s = 1 / Math.cos(0.7853981852531433);
1471
+ geometry.scale(s, 1, s);
1472
+ }
1473
+ }
1474
+ geometry.translate(origin.x, origin.y, origin.z);
1475
+ }
1476
+ function applyModelPartRotation(modelPart, geometry) {
1477
+ const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
1478
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1479
+ geometry.rotateX(toRadians(modelPart.pitch));
1480
+ geometry.rotateY(toRadians(modelPart.yaw));
1481
+ geometry.rotateZ(toRadians(modelPart.roll));
1482
+ geometry.translate(origin.x, origin.y, origin.z);
1483
+ }
1484
+ function applyGenericRotation(axis, rotation, obj) {
1485
+ switch (axis) {
1486
+ case "x" /* X */:
1487
+ obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
1488
+ break;
1489
+ case "y" /* Y */:
1490
+ obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
1491
+ break;
1492
+ case "z" /* Z */:
1493
+ obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
1494
+ break;
1495
+ }
1496
+ }
1497
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1498
+ let size = new Vector32();
1499
+ box.getSize(size);
1500
+ let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
1501
+ let wireGeo = new EdgesGeometry(boxGeo);
1502
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1503
+ let wireframe = new LineSegments(wireGeo, wireMat);
1504
+ obj.add(wireframe);
1505
+ let axes = new AxesHelper(1);
1506
+ obj.add(axes);
1507
+ }
1508
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1509
+ let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
1510
+ let wireGeo = new EdgesGeometry(boxGeo);
1511
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1512
+ let wireframe = new LineSegments(wireGeo, wireMat);
1513
+ obj.add(wireframe);
1514
+ let axes = new AxesHelper(1);
1515
+ obj.add(axes);
1516
+ }
1517
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1518
+ let wireGeo = new EdgesGeometry(geo);
1519
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1520
+ let wireframe = new LineSegments(wireGeo, wireMat);
1521
+ mesh.add(wireframe);
1522
+ let axes = new AxesHelper(1);
1523
+ mesh.add(axes);
1524
+ }
1525
+
1526
+ // src/util/performance.ts
1527
+ function captureException(e, ...extra) {
1528
+ console.error(e, extra);
1529
+ }
1530
+ function timingStart(marker) {
1531
+ console.time(marker);
1532
+ }
1533
+ function timingEnd(marker) {
1534
+ console.timeEnd(marker);
1535
+ }
1536
+
1537
+ // src/util/three.ts
1538
+ function isObject3D(obj) {
1539
+ return obj.isObject3D;
1540
+ }
1541
+ function isMesh(obj) {
1542
+ return obj.isMesh;
1543
+ }
1544
+ function isInstancedMesh(obj) {
1545
+ return obj.isInstancedMesh;
1546
+ }
1547
+ function isPerspectiveCamera(obj) {
1548
+ return obj.isPerspectiveCamera;
1549
+ }
1550
+ function isOrthographicCamera(obj) {
1551
+ return obj.isOrthographicCamera;
1552
+ }
1553
+
1554
+ // src/nbt/NBTHelper.ts
1555
+ var NBTHelper = class {
1556
+ static async fromBuffer(buffer) {
1557
+ const prismarineNbt = await import("prismarine-nbt");
1558
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1559
+ return parsed;
1560
+ }
1561
+ };
1562
+
1563
+ // src/assets/source/HostedAssetSource.ts
1564
+ var import_ts_deepmerge2 = __toESM(require_dist());
1565
+ var p3 = prefix("HostedAssetSource");
1566
+ var DEFAULT_OPTIONS = {
1567
+ retryDefaults: true
1568
+ };
1569
+ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1570
+ async loadOrRetryWithDefaults(key, parser) {
1571
+ const direct = await this.load(key, parser);
1572
+ if (typeof direct !== "undefined") {
1573
+ return direct;
1574
+ }
1575
+ if (key.namespace !== DEFAULT_NAMESPACE) {
1576
+ console.info(p3, "Retrying", key, "with default namespace");
1577
+ const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
1578
+ const namespaced = await this.load(namespaceKey, parser);
1579
+ if (typeof namespaced !== "undefined") {
1580
+ return namespaced;
1581
+ }
1582
+ if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1583
+ console.info(p3, "Retrying", key, "with default root+namespace");
1407
1584
  const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1408
1585
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
1409
1586
  if (typeof namespacedRooted !== "undefined") {
@@ -1424,31 +1601,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1424
1601
  console.info(p3, "Loading", key);
1425
1602
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1426
1603
  console.debug(p3, url);
1427
- let req = {
1428
- url
1429
- };
1430
- parser.config(req);
1431
- return await Requests.mcAssetRequest(req).then((response) => {
1432
- if (response && response.data) {
1433
- try {
1434
- return parser.parse(response);
1435
- } catch (e) {
1436
- console.warn("Parser failed to process response", response, e);
1437
- throw e;
1438
- }
1439
- }
1440
- return void 0;
1441
- }).catch((err) => {
1442
- if (err.response) {
1443
- let response = err.response;
1444
- if (response.status === 404) {
1445
- console.debug(p3, key, "not found");
1604
+ const request = { url };
1605
+ try {
1606
+ parser.config(request);
1607
+ let response;
1608
+ try {
1609
+ response = await Requests.mcAssetRequest(request);
1610
+ } catch (cause) {
1611
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1446
1612
  return void 0;
1447
1613
  }
1614
+ throw cause;
1448
1615
  }
1449
- console.debug(p3, "Failed to load", key, err?.message);
1450
- return void 0;
1451
- });
1616
+ if (response.data === void 0) {
1617
+ throw new Error("Asset response has no data");
1618
+ }
1619
+ return await parser.parse(response);
1620
+ } catch (cause) {
1621
+ throw new AssetLoadError(this, key, request.url, cause);
1622
+ }
1452
1623
  }
1453
1624
  assetBasePath(key) {
1454
1625
  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 + "/" : ""}`;
@@ -1555,7 +1726,6 @@ var BrowserArchiveProxy = class {
1555
1726
  };
1556
1727
 
1557
1728
  // src/assets/source/archive/ArchiveAssetSource.ts
1558
- var p4 = prefix("ArchiveAssetSource");
1559
1729
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1560
1730
  constructor(archiveProxy) {
1561
1731
  super();
@@ -1574,74 +1744,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1574
1744
  }
1575
1745
  async get(key, parser) {
1576
1746
  const responseParser = HostedAssetSource.PARSER_MAP.get(parser);
1577
- console.log("ArchiveAssetSource.get", key, parser);
1578
- let entries = await this.getEntries();
1579
- const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1580
- console.log(path);
1581
- const entry = await this.getEntry(path);
1582
- console.log(entry);
1583
- if (!entry) {
1584
- return void 0;
1585
- }
1586
- let blob = await entry.getData();
1587
- const url = URL.createObjectURL(blob);
1588
- console.log(url);
1589
- let req = {
1590
- url
1591
- };
1592
- responseParser.config(req);
1593
- return Requests.genericRequest(req).then((response) => {
1594
- if (response && response.data) {
1595
- try {
1596
- return responseParser.parse(response);
1597
- } catch (e) {
1598
- console.warn("Parser failed to process response", response, e);
1599
- throw e;
1600
- }
1601
- }
1602
- return void 0;
1603
- }).catch((err) => {
1604
- if (err.response) {
1605
- let response = err.response;
1606
- if (response.status === 404) {
1607
- console.debug(p4, key, "not found");
1608
- return void 0;
1609
- }
1610
- }
1611
- console.debug(p4, "Failed to load", key, err?.message);
1612
- return void 0;
1613
- });
1747
+ return this.load(key, responseParser);
1614
1748
  }
1615
- //TODO: abstract this
1616
1749
  async load(key, parser) {
1617
- console.info(p4, "Loading", key);
1618
- const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1619
- console.debug(p4, url);
1620
- let req = {
1621
- url
1622
- };
1623
- parser.config(req);
1624
- return await Requests.genericRequest(req).then((response) => {
1625
- if (response && response.data) {
1626
- try {
1627
- return parser.parse(response);
1628
- } catch (e) {
1629
- console.warn("Parser failed to process response", response, e);
1630
- throw e;
1631
- }
1750
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1751
+ let url;
1752
+ try {
1753
+ const entry = await this.getEntry(path);
1754
+ if (!entry) {
1755
+ return void 0;
1632
1756
  }
1633
- return void 0;
1634
- }).catch((err) => {
1635
- if (err.response) {
1636
- let response = err.response;
1637
- if (response.status === 404) {
1638
- console.debug(p4, key, "not found");
1639
- return void 0;
1640
- }
1757
+ url = URL.createObjectURL(await entry.getData());
1758
+ const request = { url };
1759
+ parser.config(request);
1760
+ const response = await Requests.genericRequest(request);
1761
+ if (response.data === void 0) {
1762
+ throw new Error("Asset response has no data");
1641
1763
  }
1642
- console.debug(p4, "Failed to load", key, err?.message);
1643
- return void 0;
1644
- });
1764
+ return await parser.parse(response);
1765
+ } catch (cause) {
1766
+ throw new AssetLoadError(this, key, path, cause);
1767
+ } finally {
1768
+ if (url !== void 0) {
1769
+ URL.revokeObjectURL(url);
1770
+ }
1771
+ }
1645
1772
  }
1646
1773
  assetBasePath(key) {
1647
1774
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1649,18 +1776,17 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1649
1776
  };
1650
1777
 
1651
1778
  // src/assets/AssetLoader.ts
1652
- var import_ts_deepmerge3 = __toESM(require_dist());
1653
- var p5 = prefix("AssetLoader");
1779
+ var p4 = prefix("AssetLoader");
1654
1780
  var _AssetLoader = class _AssetLoader {
1655
1781
  static addSource(key, source, override = true) {
1656
1782
  if (override) {
1657
1783
  const existing = this.removeSource(key);
1658
1784
  if (existing) {
1659
- console.log(p5, "Removed existing AssetSource", key);
1785
+ console.log(p4, "Removed existing AssetSource", key);
1660
1786
  }
1661
1787
  }
1662
1788
  this._SOURCES.unshift({ key, source });
1663
- console.log(p5, "Added AssetSource", key);
1789
+ console.log(p4, "Added AssetSource", key);
1664
1790
  }
1665
1791
  static removeSource(key) {
1666
1792
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1673,7 +1799,6 @@ var _AssetLoader = class _AssetLoader {
1673
1799
  return void 0;
1674
1800
  }
1675
1801
  static async getAll(key, parser) {
1676
- console.log(this._SOURCES);
1677
1802
  let promises = [];
1678
1803
  for (const source of this._SOURCES) {
1679
1804
  promises.push(source.source.get(key, parser));
@@ -1682,24 +1807,34 @@ var _AssetLoader = class _AssetLoader {
1682
1807
  return results.filter((r) => r != void 0);
1683
1808
  });
1684
1809
  }
1810
+ /** Returns the first defined result in source-priority order, without merging assets. */
1685
1811
  static async get(key, parser) {
1686
- console.log(this._SOURCES);
1687
- let promises = [];
1688
- for (const source of this._SOURCES) {
1689
- promises.push(source.source.get(key, parser));
1690
- }
1691
- return Promise.all(promises).then((results) => {
1692
- const fallback = results[results.length - 1];
1693
- for (const result of results) {
1694
- if (result) {
1695
- if (fallback) {
1696
- return (0, import_ts_deepmerge3.default)({}, fallback, result);
1697
- }
1698
- return result;
1812
+ const keys = [key];
1813
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
1814
+ keys.push(new AssetKey(
1815
+ key.namespace,
1816
+ key.path,
1817
+ key.assetType === "structure" ? "structures" : "structure",
1818
+ key.type,
1819
+ key.rootType,
1820
+ key.extension,
1821
+ key.root
1822
+ ));
1823
+ }
1824
+ return (await this.getFirst(keys, parser))?.asset;
1825
+ }
1826
+ /** Tries each path within a source before considering lower-priority sources. */
1827
+ static async getFirst(keys, parser) {
1828
+ const sources = [...this._SOURCES];
1829
+ for (const source of sources) {
1830
+ for (const key of keys) {
1831
+ const result = await source.source.get(key, parser);
1832
+ if (result !== void 0) {
1833
+ return { key, asset: result };
1699
1834
  }
1700
1835
  }
1701
- return void 0;
1702
- });
1836
+ }
1837
+ return void 0;
1703
1838
  }
1704
1839
  };
1705
1840
  _AssetLoader.ROOT = DEFAULT_ROOT;
@@ -1714,11 +1849,21 @@ var ModelTextures = class {
1714
1849
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
1715
1850
  }
1716
1851
  static async get(key) {
1717
- const asset = await this.preload(key);
1718
- if (asset) {
1719
- return ImageLoader.infoToCanvasData(asset);
1852
+ const keyStr = key.serialize();
1853
+ const pending = this.preload(key);
1854
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1855
+ try {
1856
+ const asset = await pending;
1857
+ if (asset) {
1858
+ return await ImageLoader.infoToCanvasData(asset);
1859
+ }
1860
+ return void 0;
1861
+ } catch (err) {
1862
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
1863
+ Caching.textureAssetCache.invalidate(keyStr);
1864
+ }
1865
+ throw err;
1720
1866
  }
1721
- return void 0;
1722
1867
  }
1723
1868
  static async preload(key) {
1724
1869
  const keyStr = key.serialize();
@@ -1888,17 +2033,20 @@ var TextureAtlas = class {
1888
2033
  // src/model/ModelGenerator.ts
1889
2034
  var ModelGenerator = class {
1890
2035
  static generateItemModel(imageData, layer) {
2036
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
1891
2037
  const mainElement = {
1892
2038
  from: [0, 0, 7.5],
1893
2039
  to: [16, 16, 8.5],
1894
2040
  faces: {
1895
2041
  "south": {
1896
2042
  uv: [0, 0, 16, 16],
1897
- texture: `#${layer}`
2043
+ texture: `#${layer}`,
2044
+ tintindex
1898
2045
  },
1899
2046
  "north": {
1900
2047
  uv: [16, 0, 0, 16],
1901
- texture: `#${layer}`
2048
+ texture: `#${layer}`,
2049
+ tintindex
1902
2050
  }
1903
2051
  },
1904
2052
  shade: true
@@ -1909,11 +2057,19 @@ var ModelGenerator = class {
1909
2057
  ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
1910
2058
 
1911
2059
  // src/UVMapper.ts
1912
- var p6 = prefix("UVMapper");
2060
+ var p5 = prefix("UVMapper");
1913
2061
  var DEFAULT_UV = [0, 0, 16, 16];
1914
2062
  var X = 0;
1915
2063
  var Y = 1;
1916
2064
  var Z = 2;
2065
+ var FACE_UV_AXES = {
2066
+ east: [new Vector33(0, 0, -1), new Vector33(0, -1, 0)],
2067
+ west: [new Vector33(0, 0, 1), new Vector33(0, -1, 0)],
2068
+ up: [new Vector33(1, 0, 0), new Vector33(0, 0, 1)],
2069
+ down: [new Vector33(1, 0, 0), new Vector33(0, 0, -1)],
2070
+ south: [new Vector33(1, 0, 0), new Vector33(0, -1, 0)],
2071
+ north: [new Vector33(-1, 0, 0), new Vector33(0, -1, 0)]
2072
+ };
1917
2073
  var UVMapper = class {
1918
2074
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
1919
2075
  if (uvCoord === 0) return 0;
@@ -2011,6 +2167,42 @@ var UVMapper = class {
2011
2167
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2012
2168
  return new Float32BufferAttribute2(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2013
2169
  }
2170
+ static lockUvs(geometry, faces, atlas, rotation) {
2171
+ const uv = geometry.getAttribute("uv");
2172
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2173
+ const faceName = CUBE_FACES[faceIndex];
2174
+ const texture = faces[faceName]?.texture?.substring(1);
2175
+ const position = texture && atlas.positions[texture];
2176
+ const size = texture && atlas.sizes[texture];
2177
+ if (!position || !size) continue;
2178
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2179
+ const uAxis = sourceU.clone().applyEuler(rotation);
2180
+ const vAxis = sourceV.clone().applyEuler(rotation);
2181
+ const normal = vAxis.clone().cross(uAxis);
2182
+ const targetFace = CUBE_FACES.find((name) => {
2183
+ const [u, v] = FACE_UV_AXES[name];
2184
+ return v.clone().cross(u).dot(normal) > 0.5;
2185
+ });
2186
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2187
+ const uu = Math.round(targetU.dot(uAxis));
2188
+ const uvCross = Math.round(targetU.dot(vAxis));
2189
+ const vu = Math.round(targetV.dot(uAxis));
2190
+ const vv = Math.round(targetV.dot(vAxis));
2191
+ for (let corner = 0; corner < 4; corner++) {
2192
+ const index = faceIndex * 4 + corner;
2193
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2194
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2195
+ const lockedU = uu * u + uvCross * v + 0.5;
2196
+ const lockedV = vu * u + vv * v + 0.5;
2197
+ uv.setXY(
2198
+ index,
2199
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2200
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2201
+ );
2202
+ }
2203
+ }
2204
+ uv.needsUpdate = true;
2205
+ }
2014
2206
  static async getAtlas(model) {
2015
2207
  const keyStr = model.key.serialize();
2016
2208
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -2086,7 +2278,7 @@ var UVMapper = class {
2086
2278
  const metaMap = {};
2087
2279
  const model = { ...originalModel };
2088
2280
  const isItemModel = !("elements" in model);
2089
- console.debug(p6, "Creating Atlas for", model.key);
2281
+ console.debug(p5, "Creating Atlas for", model.key);
2090
2282
  if (model.textures) {
2091
2283
  const promises = [];
2092
2284
  const uniqueTextureNames = [];
@@ -2100,7 +2292,7 @@ var UVMapper = class {
2100
2292
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2101
2293
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2102
2294
  if (!asset) {
2103
- console.warn(p6, "Missing texture", assetKey);
2295
+ console.warn(p5, "Missing texture", assetKey);
2104
2296
  return;
2105
2297
  }
2106
2298
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2112,7 +2304,7 @@ var UVMapper = class {
2112
2304
  }
2113
2305
  await Promise.all(promises);
2114
2306
  const textureCount = uniqueTextureNames.length;
2115
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2307
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2116
2308
  this.fillMissingTextureKeys(model.textures, textureMap);
2117
2309
  this.fillMissingTextureKeys(model.textures, metaMap);
2118
2310
  const sizes = {};
@@ -2132,7 +2324,7 @@ var UVMapper = class {
2132
2324
  this.fillMissingTextureKeys(model.textures, sizes);
2133
2325
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2134
2326
  const size = Math.ceil(s * maxWidth);
2135
- console.debug(p6, "Atlas size:", size);
2327
+ console.debug(p5, "Atlas size:", size);
2136
2328
  const squaredSize = size * size;
2137
2329
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2138
2330
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2187,10 +2379,10 @@ var UVMapper = class {
2187
2379
  }
2188
2380
  }
2189
2381
  const atlasImageData = image.toDataURL();
2190
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2382
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2191
2383
  this.fillMissingTextureKeys(model.textures, positions);
2192
2384
  if (isItemModel) {
2193
- console.debug(p6, "Generating item model for", model);
2385
+ console.debug(p5, "Generating item model for", model);
2194
2386
  model.elements = [];
2195
2387
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2196
2388
  const textureImage = textureMap[layerName];
@@ -2198,7 +2390,7 @@ var UVMapper = class {
2198
2390
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2199
2391
  }
2200
2392
  }
2201
- console.debug(p6, "Item model elements", model.elements);
2393
+ console.debug(p5, "Item model elements", model.elements);
2202
2394
  }
2203
2395
  if (!model.elements) {
2204
2396
  }
@@ -2216,17 +2408,13 @@ var UVMapper = class {
2216
2408
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2217
2409
  continue;
2218
2410
  }
2411
+ if (!face.texture) continue;
2219
2412
  if (!face.uv) {
2220
2413
  face.uv = this.getFallbackUv(element, faceName);
2221
2414
  }
2222
- let faceTexture = face.texture;
2223
- let texPosition;
2224
- let texSize;
2225
- if (faceTexture) {
2226
- faceTexture = faceTexture.substr(1);
2227
- texPosition = positions[faceTexture] || [0, 0];
2228
- texSize = sizes[faceTexture] || [16, 16];
2229
- }
2415
+ const faceTexture = face.texture.substr(1);
2416
+ const texPosition = positions[faceTexture] || [0, 0];
2417
+ const texSize = sizes[faceTexture] || [16, 16];
2230
2418
  let texPosV = new Vector2(texPosition[0], texPosition[1]);
2231
2419
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2232
2420
  tl.add(texPosV);
@@ -2258,7 +2446,7 @@ var UVMapper = class {
2258
2446
  hasTransparency
2259
2447
  );
2260
2448
  } else {
2261
- console.warn(p6, "Model does not have any textures", model);
2449
+ console.warn(p5, "Model does not have any textures", model);
2262
2450
  }
2263
2451
  return void 0;
2264
2452
  }
@@ -2396,17 +2584,20 @@ function shutdown() {
2396
2584
  }
2397
2585
 
2398
2586
  // src/assets/Entities.ts
2399
- import { Memoize as Memoize3 } from "typescript-memoize";
2400
2587
  var Entities = class {
2401
2588
  static async getBlockEntityModels() {
2402
2589
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2403
2590
  console.log(key);
2404
- return AssetLoader.get(key, "json" /* JSON */);
2591
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2592
+ return AssetLoader.get(key, "json" /* JSON */);
2593
+ });
2405
2594
  }
2406
2595
  static async getEntityModels() {
2407
2596
  const key = AssetKey.parse("models", "minerender:entityModels");
2408
2597
  console.log(key);
2409
- return AssetLoader.get(key, "json" /* JSON */);
2598
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2599
+ return AssetLoader.get(key, "json" /* JSON */);
2600
+ });
2410
2601
  }
2411
2602
  // BlockEntity names are hardcoded
2412
2603
  static async getBlockList() {
@@ -2452,19 +2643,13 @@ var Entities = class {
2452
2643
  };
2453
2644
  }
2454
2645
  };
2455
- __decorateClass([
2456
- Memoize3()
2457
- ], Entities, "getBlockEntityModels", 1);
2458
- __decorateClass([
2459
- Memoize3()
2460
- ], Entities, "getEntityModels", 1);
2461
2646
  var EntityModels = class {
2462
2647
  };
2463
2648
  var BlockEntityModels = class {
2464
2649
  };
2465
2650
 
2466
2651
  // src/renderer/SceneObject.ts
2467
- import { Euler, InstancedMesh, MathUtils, Matrix4 as Matrix42, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion2, Vector3 as Vector33 } from "three";
2652
+ import { Euler as Euler2, InstancedMesh, MathUtils, Matrix4 as Matrix42, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion2, Vector3 as Vector34 } from "three";
2468
2653
 
2469
2654
  // src/instance/InstanceReference.ts
2470
2655
  var InstanceReference = class {
@@ -2521,8 +2706,8 @@ var MineRenderError = class _MineRenderError extends Error {
2521
2706
  };
2522
2707
 
2523
2708
  // src/renderer/SceneObject.ts
2524
- var import_ts_deepmerge4 = __toESM(require_dist());
2525
- var p7 = prefix("SceneObject");
2709
+ var import_ts_deepmerge3 = __toESM(require_dist());
2710
+ var p6 = prefix("SceneObject");
2526
2711
  var _SceneObject = class _SceneObject extends Object3D2 {
2527
2712
  constructor(options) {
2528
2713
  super();
@@ -2530,7 +2715,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2530
2715
  this.materialCallbacks = {};
2531
2716
  this._isInstanced = false;
2532
2717
  this._instanceCounter = 0;
2533
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2718
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2534
2719
  console.log("SceneObject options", this.options);
2535
2720
  }
2536
2721
  set scene(scene) {
@@ -2624,6 +2809,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2624
2809
  }
2625
2810
  createInstancedMesh(name, geometry, material, count) {
2626
2811
  const mesh = new InstancedMesh(geometry, material, count);
2812
+ mesh.count = 0;
2627
2813
  if (name) {
2628
2814
  mesh.name = `mesh:${name}`;
2629
2815
  }
@@ -2701,9 +2887,13 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2701
2887
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2702
2888
  const i = this._instanceCounter++;
2703
2889
  this.setMatrixAt(i, new Matrix42());
2704
- console.debug(p7, "nextInstance " + i);
2890
+ const mesh = this.children[0];
2891
+ if (mesh && isInstancedMesh(mesh)) {
2892
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
2893
+ }
2894
+ console.debug(p6, "nextInstance " + i);
2705
2895
  if (i === this.options.maxInstanceCount) {
2706
- console.warn(p7, "Max instance count reached for " + this);
2896
+ console.warn(p6, "Max instance count reached for " + this);
2707
2897
  }
2708
2898
  if (this.scene) {
2709
2899
  this.scene.stats.instanceCount++;
@@ -2732,9 +2922,9 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2732
2922
  }
2733
2923
  setPositionRotationScaleAt(index, position, rotation, scale) {
2734
2924
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2735
- const oldPosition = new Vector33();
2925
+ const oldPosition = new Vector34();
2736
2926
  const oldRotation = new Quaternion2();
2737
- const oldScale = new Vector33();
2927
+ const oldScale = new Vector34();
2738
2928
  const matrix = new Matrix42();
2739
2929
  if (!scale || !rotation || !position) {
2740
2930
  this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
@@ -2750,7 +2940,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2750
2940
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2751
2941
  this.setPositionRotationScaleAt(index, position);
2752
2942
  }
2753
- getPositionAt(index, vector = new Vector33()) {
2943
+ getPositionAt(index, vector = new Vector34()) {
2754
2944
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2755
2945
  const matrix = this.getMatrixAt(index);
2756
2946
  vector.setFromMatrixPosition(matrix);
@@ -2760,7 +2950,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2760
2950
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2761
2951
  this.setPositionRotationScaleAt(index, void 0, rotation, void 0);
2762
2952
  }
2763
- getRotationAt(index, euler = new Euler()) {
2953
+ getRotationAt(index, euler = new Euler2()) {
2764
2954
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2765
2955
  const matrix = this.getMatrixAt(index);
2766
2956
  euler.setFromRotationMatrix(matrix);
@@ -2770,7 +2960,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2770
2960
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2771
2961
  this.setPositionRotationScaleAt(index, void 0, void 0, scale);
2772
2962
  }
2773
- getScaleAt(index, vector = new Vector33()) {
2963
+ getScaleAt(index, vector = new Vector34()) {
2774
2964
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2775
2965
  const matrix = this.getMatrixAt(index);
2776
2966
  vector.setFromMatrixScale(matrix);
@@ -2879,7 +3069,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2879
3069
  }
2880
3070
  //</editor-fold>
2881
3071
  };
2882
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
3072
+ _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2883
3073
  instanceMeshes: true,
2884
3074
  maxInstanceCount: 50,
2885
3075
  mergeMeshes: true,
@@ -2891,16 +3081,16 @@ function isSceneObject(obj) {
2891
3081
  }
2892
3082
 
2893
3083
  // src/entity/scene/EntityObject.ts
2894
- var import_ts_deepmerge5 = __toESM(require_dist());
3084
+ var import_ts_deepmerge4 = __toESM(require_dist());
2895
3085
  import { Object3D as Object3D3 } from "three";
2896
- import * as THREE2 from "three";
3086
+ import * as THREE3 from "three";
2897
3087
  var EntityObject = class extends SceneObject {
2898
3088
  constructor(entity, options) {
2899
3089
  super();
2900
3090
  this.entity = entity;
2901
3091
  this.isEntityObject = true;
2902
3092
  this.meshesCreated = false;
2903
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3093
+ this.options = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
2904
3094
  }
2905
3095
  async init() {
2906
3096
  this.createMeshes();
@@ -2909,8 +3099,8 @@ var EntityObject = class extends SceneObject {
2909
3099
  dispose() {
2910
3100
  super.dispose();
2911
3101
  }
2912
- async loadTextures() {
2913
- this.imageData = await ModelTextures.get(new AssetKey(
3102
+ get textureKey() {
3103
+ return new AssetKey(
2914
3104
  this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2915
3105
  this.entity.key.path,
2916
3106
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
@@ -2918,7 +3108,10 @@ var EntityObject = class extends SceneObject {
2918
3108
  "entity",
2919
3109
  "assets",
2920
3110
  ".png"
2921
- ));
3111
+ );
3112
+ }
3113
+ async loadTextures() {
3114
+ this.imageData = await ModelTextures.get(this.textureKey);
2922
3115
  }
2923
3116
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2924
3117
  createMeshes(force = false) {
@@ -2937,8 +3130,8 @@ var EntityObject = class extends SceneObject {
2937
3130
  const l = cube.maxZ - cube.minZ;
2938
3131
  const uv = texture.toUvArray(w, h, l);
2939
3132
  const cubeGeo = this._getBoxGeometryForDimensionsAndUv(w, h, l, uv).clone();
2940
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
2941
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
3133
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3134
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
2942
3135
  applyModelPartRotation(part, cubeGeo);
2943
3136
  const mesh = this.createMesh(partName, cubeGeo, mat);
2944
3137
  partAnchor.add(mesh);
@@ -2951,23 +3144,26 @@ var EntityObject = class extends SceneObject {
2951
3144
  this.meshesCreated = true;
2952
3145
  }
2953
3146
  async applyTextures() {
2954
- const textureAsset = await ModelTextures.preload(new AssetKey(
2955
- this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2956
- this.entity.key.path,
2957
- "textures",
2958
- "entity",
2959
- "assets",
2960
- ".png"
2961
- ));
2962
- if (textureAsset) {
2963
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
2964
- this.iterateAllMeshes((mesh) => {
2965
- mesh.material = mat;
2966
- });
2967
- }
3147
+ const assetKeyStr = this.textureKey.serialize();
3148
+ const keyStr = `entity:${assetKeyStr}`;
3149
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3150
+ if (!mat) {
3151
+ const pending = this.loadTextures();
3152
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3153
+ await pending;
3154
+ if (!this.imageData) return;
3155
+ const canvas = this.imageData.data.canvas;
3156
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3157
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3158
+ this.imageData = void 0;
3159
+ }
3160
+ this.iterateAllMeshes((mesh) => {
3161
+ mesh.material = mat;
3162
+ });
3163
+ this.notifyDirty();
2968
3164
  }
2969
3165
  };
2970
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3166
+ EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
2971
3167
  function isEntityObject(obj) {
2972
3168
  return obj.isEntityObject;
2973
3169
  }
@@ -2979,7 +3175,7 @@ var GuiObject = class extends SceneObject {
2979
3175
 
2980
3176
  // src/inspector/SceneInspector.ts
2981
3177
  import { Raycaster, Vector2 as Vector22 } from "three";
2982
- var p8 = prefix("SceneInspector");
3178
+ var p7 = prefix("SceneInspector");
2983
3179
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
2984
3180
  var SceneInspector = class {
2985
3181
  constructor(renderer) {
@@ -3048,7 +3244,7 @@ var SceneInspector = class {
3048
3244
  }
3049
3245
  selectObject(targetObject, targetIntersection) {
3050
3246
  this.selectedObject = targetObject;
3051
- console.log(p8, "selected", targetObject);
3247
+ console.log(p7, "selected", targetObject);
3052
3248
  this.redraw(targetObject, targetIntersection);
3053
3249
  }
3054
3250
  redraw(targetObject, targetIntersection) {
@@ -3346,7 +3542,7 @@ var SceneStatsDisplay = class {
3346
3542
  };
3347
3543
 
3348
3544
  // src/instance/InstanceManager.ts
3349
- var p9 = prefix("InstanceManager");
3545
+ var p8 = prefix("InstanceManager");
3350
3546
  var InstanceManager = class {
3351
3547
  constructor() {
3352
3548
  this.isInstanceManager = true;
@@ -3354,7 +3550,7 @@ var InstanceManager = class {
3354
3550
  }
3355
3551
  async get(key) {
3356
3552
  if (key in this.instanceCache) {
3357
- console.debug(p9, "key in cache", key);
3553
+ console.debug(p8, "key in cache", key);
3358
3554
  return (await this.instanceCache[key]).nextInstance();
3359
3555
  }
3360
3556
  return void 0;
@@ -3363,13 +3559,17 @@ var InstanceManager = class {
3363
3559
  if (key in this.instanceCache) {
3364
3560
  return await this.get(key);
3365
3561
  }
3366
- console.debug(p9, "key not in cache", key);
3367
- this.instanceCache[key] = new Promise(async (resolve) => {
3368
- const obj = await supplier();
3369
- const instance = obj.nextInstance();
3370
- resolve(instance);
3371
- });
3372
- return await this.instanceCache[key];
3562
+ console.debug(p8, "key not in cache", key);
3563
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3564
+ this.instanceCache[key] = pending;
3565
+ try {
3566
+ return await pending;
3567
+ } catch (error) {
3568
+ if (this.instanceCache[key] === pending) {
3569
+ delete this.instanceCache[key];
3570
+ }
3571
+ throw error;
3572
+ }
3373
3573
  }
3374
3574
  reset() {
3375
3575
  for (let instanceCacheKey in this.instanceCache) {
@@ -3422,8 +3622,93 @@ function isQuadArray(obj) {
3422
3622
  return Array.isArray(obj) && obj.length === 4;
3423
3623
  }
3424
3624
 
3625
+ // src/model/block/blockTints.json
3626
+ var blockTints_default = {
3627
+ "minecraft:large_fern": { source: "grass" },
3628
+ "minecraft:tall_grass": { source: "grass" },
3629
+ "minecraft:grass_block": { source: "grass" },
3630
+ "minecraft:fern": { source: "grass" },
3631
+ "minecraft:grass": { source: "grass" },
3632
+ "minecraft:short_grass": { source: "grass" },
3633
+ "minecraft:potted_fern": { source: "grass" },
3634
+ "minecraft:bush": { source: "grass" },
3635
+ "minecraft:pink_petals": { source: "grass", untinted: [0] },
3636
+ "minecraft:wildflowers": { source: "grass", untinted: [0] },
3637
+ "minecraft:spruce_leaves": { source: "constant", color: 6396257 },
3638
+ "minecraft:birch_leaves": { source: "constant", color: 8431445 },
3639
+ "minecraft:oak_leaves": { source: "constant", color: 4764952 },
3640
+ "minecraft:jungle_leaves": { source: "constant", color: 4764952 },
3641
+ "minecraft:acacia_leaves": { source: "constant", color: 4764952 },
3642
+ "minecraft:dark_oak_leaves": { source: "constant", color: 4764952 },
3643
+ "minecraft:vine": { source: "constant", color: 4764952 },
3644
+ "minecraft:mangrove_leaves": { source: "constant", color: 4764952 },
3645
+ "minecraft:leaf_litter": { source: "constant", color: 6044722 },
3646
+ "minecraft:water_cauldron": { source: "constant", color: 4159204 },
3647
+ "minecraft:redstone_wire": { source: "redstone" },
3648
+ "minecraft:attached_melon_stem": { source: "constant", color: 14731036 },
3649
+ "minecraft:attached_pumpkin_stem": { source: "constant", color: 14731036 },
3650
+ "minecraft:melon_stem": { source: "stem" },
3651
+ "minecraft:pumpkin_stem": { source: "stem" },
3652
+ "minecraft:lily_pad": { source: "constant", color: 7455580 }
3653
+ };
3654
+
3655
+ // src/model/block/BlockTints.ts
3656
+ var rules = blockTints_default;
3657
+ var BlockTints = class {
3658
+ /** Resolves block preview colors without biome context; explicit tints take precedence. */
3659
+ static async get(key, state, model, tints) {
3660
+ const rule = key && rules[key.toNamespacedString()];
3661
+ if (!key || !rule) return tints;
3662
+ const indices = /* @__PURE__ */ new Set();
3663
+ for (const element of model.elements ?? []) {
3664
+ for (const face of Object.values(element.faces)) {
3665
+ const index = face?.tintindex;
3666
+ if (index !== void 0 && index >= 0 && tints?.[index] === void 0 && !rule.untinted?.includes(index)) {
3667
+ indices.add(index);
3668
+ }
3669
+ }
3670
+ }
3671
+ if (!indices.size) return tints;
3672
+ let color;
3673
+ switch (rule.source) {
3674
+ case "constant":
3675
+ color = rule.color;
3676
+ break;
3677
+ case "grass":
3678
+ color = await this.grassColor(key);
3679
+ break;
3680
+ case "redstone": {
3681
+ const power = Number(state.power ?? 0) / 15;
3682
+ const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
3683
+ const green = Math.max(0, power * power * 0.7 - 0.5);
3684
+ const blue = Math.max(0, power * power * 0.6 - 0.7);
3685
+ color = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
3686
+ break;
3687
+ }
3688
+ case "stem": {
3689
+ const age = Number(state.age ?? 0);
3690
+ color = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
3691
+ break;
3692
+ }
3693
+ }
3694
+ return { ...Object.fromEntries([...indices].map((index) => [index, color])), ...tints };
3695
+ }
3696
+ static async grassColor(origin) {
3697
+ const key = AssetKey.parse("textures", "minecraft:colormap/grass", origin);
3698
+ return await Caching.blockTintCache.get(key.serialize(), async () => {
3699
+ const image = await ModelTextures.get(key);
3700
+ if (!image) throw new MineRenderError(`Missing grass colormap: ${key.toNamespacedString()}`);
3701
+ if (image.width !== 256 || image.height !== 256) {
3702
+ throw new MineRenderError("Grass colormaps must be 256 \xD7 256 pixels");
3703
+ }
3704
+ const [red, green, blue] = image.data.getImageData(127, 127, 1, 1).data;
3705
+ return red << 16 | green << 8 | blue;
3706
+ });
3707
+ }
3708
+ };
3709
+
3425
3710
  // src/model/scene/ModelObject.ts
3426
- import { BoxGeometry as BoxGeometry5, Matrix4 as Matrix45 } from "three";
3711
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler4, Matrix4 as Matrix45 } from "three";
3427
3712
 
3428
3713
  // src/three/BufferGeometryUtils.js
3429
3714
  import {
@@ -3435,7 +3720,7 @@ import {
3435
3720
  TriangleFanDrawMode,
3436
3721
  TriangleStripDrawMode,
3437
3722
  TrianglesDrawMode,
3438
- Vector3 as Vector35
3723
+ Vector3 as Vector36
3439
3724
  } from "three";
3440
3725
  function computeTangents(geometry) {
3441
3726
  geometry.computeTangents();
@@ -3754,15 +4039,15 @@ function computeMorphedAttributes(object) {
3754
4039
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3755
4040
  return null;
3756
4041
  }
3757
- const _vA = new Vector35();
3758
- const _vB = new Vector35();
3759
- const _vC = new Vector35();
3760
- const _tempA = new Vector35();
3761
- const _tempB = new Vector35();
3762
- const _tempC = new Vector35();
3763
- const _morphA = new Vector35();
3764
- const _morphB = new Vector35();
3765
- const _morphC = new Vector35();
4042
+ const _vA = new Vector36();
4043
+ const _vB = new Vector36();
4044
+ const _vC = new Vector36();
4045
+ const _tempA = new Vector36();
4046
+ const _tempB = new Vector36();
4047
+ const _tempC = new Vector36();
4048
+ const _morphA = new Vector36();
4049
+ const _morphB = new Vector36();
4050
+ const _morphC = new Vector36();
3766
4051
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3767
4052
  _vA.fromBufferAttribute(attribute, a2);
3768
4053
  _vB.fromBufferAttribute(attribute, b2);
@@ -3968,15 +4253,16 @@ function computeMorphedAttributes(object) {
3968
4253
  }
3969
4254
 
3970
4255
  // src/model/scene/ModelObject.ts
3971
- var import_ts_deepmerge6 = __toESM(require_dist());
3972
- var p10 = prefix("ModelObject");
4256
+ var import_ts_deepmerge5 = __toESM(require_dist());
4257
+ var p9 = prefix("ModelObject");
3973
4258
  var _ModelObject = class _ModelObject extends SceneObject {
3974
4259
  constructor(originalModel, options) {
3975
4260
  super(options);
3976
4261
  this.originalModel = originalModel;
3977
4262
  this.isModelObject = true;
3978
4263
  this.meshesCreated = false;
3979
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4264
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4265
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
3980
4266
  console.log("ModelObject options", this.options);
3981
4267
  }
3982
4268
  async init() {
@@ -4003,6 +4289,23 @@ var _ModelObject = class _ModelObject extends SceneObject {
4003
4289
  if (this.atlas.model.elements) {
4004
4290
  this.atlas.model.elements?.forEach((el) => {
4005
4291
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4292
+ if (this.options.uvLockRotation) {
4293
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler4(...this.options.uvLockRotation));
4294
+ }
4295
+ if (this.options.tints) {
4296
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4297
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4298
+ const tintIndex = el.faces[faceName]?.tintindex;
4299
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4300
+ const tint = this.options.tints[tintIndex];
4301
+ if (tint === void 0) continue;
4302
+ const color = new Color3(tint);
4303
+ for (let vertex = 0; vertex < 4; vertex++) {
4304
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4305
+ }
4306
+ }
4307
+ elGeo.setAttribute("color", new BufferAttribute4(colors, 3));
4308
+ }
4006
4309
  elGeo.applyMatrix4(new Matrix45().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4007
4310
  elGeo.applyMatrix4(new Matrix45().makeTranslation(el.from[0], el.from[1], el.from[2]));
4008
4311
  if (el.rotation) {
@@ -4019,10 +4322,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
4019
4322
  }
4020
4323
  });
4021
4324
  } else {
4022
- console.debug(p10, this.atlas.model, "has no elements");
4325
+ console.debug(p9, this.atlas.model, "has no elements");
4023
4326
  }
4024
4327
  } else {
4025
- console.debug(p10, "Missing atlas for", this);
4328
+ console.debug(p9, "Missing atlas for", this);
4026
4329
  }
4027
4330
  if (this.options.mergeMeshes) {
4028
4331
  let combinedGeo;
@@ -4059,6 +4362,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4059
4362
  /*TODO: get this from render options*/
4060
4363
  );
4061
4364
  this.iterateAllMeshes((mesh) => {
4365
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4062
4366
  mesh.material = mat;
4063
4367
  });
4064
4368
  if (this.atlas.hasAnimation) {
@@ -4074,16 +4378,26 @@ var _ModelObject = class _ModelObject extends SceneObject {
4074
4378
  }
4075
4379
  }
4076
4380
  };
4077
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4381
+ _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4078
4382
  var ModelObject = _ModelObject;
4079
4383
  function isModelObject(obj) {
4080
4384
  return obj.isModelObject;
4081
4385
  }
4082
4386
 
4083
4387
  // src/model/block/scene/BlockObject.ts
4084
- var import_ts_deepmerge7 = __toESM(require_dist());
4085
- import { Euler as Euler3, Matrix4 as Matrix46, Vector3 as Vector36 } from "three";
4086
- var p11 = prefix("BlockObject");
4388
+ var import_ts_deepmerge6 = __toESM(require_dist());
4389
+ import { Euler as Euler5, Matrix4 as Matrix46, Vector3 as Vector37 } from "three";
4390
+ var p10 = prefix("BlockObject");
4391
+ function matchesCondition(condition, state) {
4392
+ return Object.entries(condition).every(([key, value]) => {
4393
+ if (Array.isArray(value)) {
4394
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4395
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4396
+ return false;
4397
+ }
4398
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4399
+ });
4400
+ }
4087
4401
  var _BlockObject = class _BlockObject extends SceneObject {
4088
4402
  constructor(blockState, options) {
4089
4403
  super(options);
@@ -4097,11 +4411,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4097
4411
  this._instanceModel = [];
4098
4412
  this._variants = [];
4099
4413
  this._models = [];
4100
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4414
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4101
4415
  }
4102
4416
  async init() {
4103
4417
  if (this.options.applyDefaultState) {
4104
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4418
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4105
4419
  if (defaultState && Object.keys(defaultState).length > 0) {
4106
4420
  const state = {};
4107
4421
  for (let k in defaultState) {
@@ -4112,15 +4426,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4112
4426
  if (this.blockState.variants) {
4113
4427
  await this.setState(Object.keys(this.blockState.variants)[0]);
4114
4428
  } else if (this.blockState.multipart) {
4115
- for (let part of this.blockState.multipart) {
4116
- if (part.when && !("OR" in part.when)) {
4117
- const k = Object.keys(part.when)[0];
4118
- if (k) {
4119
- await this.setState(k, part.when[k].split("|")[0]);
4120
- break;
4121
- }
4122
- }
4123
- }
4429
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4430
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4431
+ await this.setState(state);
4124
4432
  }
4125
4433
  }
4126
4434
  } else {
@@ -4135,7 +4443,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4135
4443
  if (isModelObject(model)) {
4136
4444
  model.removeFromScene();
4137
4445
  } else if (isInstanceReference(model)) {
4138
- model.setScale(new Vector36(0, 0, 0));
4446
+ model.setScale(new Vector37(0, 0, 0));
4139
4447
  }
4140
4448
  }
4141
4449
  super.removeFromScene();
@@ -4177,55 +4485,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4177
4485
  } else if (this.blockState.multipart) {
4178
4486
  for (let part of this.blockState.multipart) {
4179
4487
  if (!part.apply) {
4180
- console.debug(p11, "Missing apply for blockState part", part);
4488
+ console.debug(p10, "Missing apply for blockState part", part);
4181
4489
  continue;
4182
4490
  }
4183
- if (!part.when) {
4491
+ if (!part.when || matchesCondition(part.when, state)) {
4184
4492
  out.push(this.getSingleVariant(part.apply));
4185
- } else {
4186
- let matches = true;
4187
- if ("OR" in part.when) {
4188
- const or = part.when.OR;
4189
- let anyMatch = false;
4190
- for (let o of or) {
4191
- for (let k in o) {
4192
- const split = o[k].split("|");
4193
- let m = false;
4194
- for (let s of split) {
4195
- if (`${state[k]}` === `${s}`) {
4196
- m = true;
4197
- break;
4198
- }
4199
- }
4200
- if (m) {
4201
- anyMatch = true;
4202
- break;
4203
- }
4204
- }
4205
- }
4206
- if (!anyMatch) {
4207
- matches = false;
4208
- }
4209
- } else {
4210
- for (let k in part.when) {
4211
- const split = part.when[k].split("|");
4212
- let m = false;
4213
- for (let s of split) {
4214
- if (`${state[k]}` === `${s}`) {
4215
- m = true;
4216
- break;
4217
- }
4218
- }
4219
- if (!m) {
4220
- matches = false;
4221
- break;
4222
- }
4223
- }
4224
- }
4225
- if (matches) {
4226
- const variants = part.apply;
4227
- out.push(this.getSingleVariant(variants));
4228
- }
4229
4493
  }
4230
4494
  }
4231
4495
  }
@@ -4240,7 +4504,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4240
4504
  }
4241
4505
  for (let model of this._models) {
4242
4506
  if (isInstanceReference(model)) {
4243
- model.setScale(new Vector36(0, 0, 0));
4507
+ model.setScale(new Vector37(0, 0, 0));
4244
4508
  } else {
4245
4509
  model.dispose();
4246
4510
  }
@@ -4255,11 +4519,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4255
4519
  }
4256
4520
  }
4257
4521
  getSingleVariant(variants) {
4258
- if (Array.isArray(variants)) {
4259
- return variants[0];
4260
- } else {
4261
- return variants;
4262
- }
4522
+ if (!Array.isArray(variants)) return variants;
4523
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4524
+ const total = variants.reduce((sum, variant) => {
4525
+ const weight = variant.weight ?? 1;
4526
+ if (!Number.isInteger(weight) || weight < 1) {
4527
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4528
+ }
4529
+ return sum + weight;
4530
+ }, 0);
4531
+ let choice = Math.random() * total;
4532
+ for (const variant of variants) {
4533
+ choice -= variant.weight ?? 1;
4534
+ if (choice < 0) return variant;
4535
+ }
4536
+ return variants[variants.length - 1];
4263
4537
  }
4264
4538
  // @deprecated
4265
4539
  async createAVariant(variants, instanceInfo) {
@@ -4267,28 +4541,25 @@ var _BlockObject = class _BlockObject extends SceneObject {
4267
4541
  await this.createVariant(variant);
4268
4542
  }
4269
4543
  async createVariant(variant) {
4270
- const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4271
- const obj = await this.scene.addModel(model, this.options);
4272
- if (isInstanceReference(obj) || obj.isInstanced) {
4273
- this._isInstanced = true;
4274
- this._instanceCounter = 1;
4275
- }
4276
- let rotation = new Euler3(0, 0, 0);
4544
+ const rotation = new Euler5();
4277
4545
  if (typeof variant.x !== "undefined") {
4278
4546
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4279
4547
  }
4280
4548
  if (typeof variant.y !== "undefined") {
4281
- if (typeof variant.x !== "undefined") {
4282
- rotation.y = toRadians(clampRotationDegrees(variant.y));
4283
- } else {
4284
- rotation.y = toRadians(clampRotationDegrees(360 - variant.y));
4285
- }
4549
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4550
+ }
4551
+ const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4552
+ const options = {
4553
+ ...this.options,
4554
+ tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
4555
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4556
+ };
4557
+ const obj = await this.scene.addModel(model, options);
4558
+ if (isInstanceReference(obj) || obj.isInstanced) {
4559
+ this._isInstanced = true;
4560
+ this._instanceCounter = 1;
4286
4561
  }
4287
4562
  obj.setRotation(rotation);
4288
- setTimeout(() => {
4289
- obj.setRotation(rotation);
4290
- }, 150);
4291
- console.log(obj);
4292
4563
  return obj;
4293
4564
  }
4294
4565
  async resetState() {
@@ -4378,15 +4649,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4378
4649
  }
4379
4650
  }
4380
4651
  setPosition(position) {
4381
- super.setPosition(position);
4652
+ this.position.copy(position);
4382
4653
  for (let model of this._models) {
4383
4654
  model.setPosition(position);
4384
4655
  }
4656
+ this.notifyDirty();
4385
4657
  }
4386
4658
  //TODO: should override rotation + scale methods
4387
4659
  //TODO
4388
4660
  };
4389
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4661
+ _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4390
4662
  applyDefaultState: true
4391
4663
  });
4392
4664
  var BlockObject = _BlockObject;
@@ -4436,7 +4708,7 @@ var StructureParser = class {
4436
4708
 
4437
4709
  // src/renderer/MineRenderScene.ts
4438
4710
  import { Scene as Scene2 } from "three";
4439
- var import_ts_deepmerge9 = __toESM(require_dist());
4711
+ var import_ts_deepmerge8 = __toESM(require_dist());
4440
4712
 
4441
4713
  // src/skin/SkinPart.ts
4442
4714
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5167,7 +5439,7 @@ var slimSkinGeometries = {
5167
5439
  };
5168
5440
 
5169
5441
  // src/skin/scene/SkinObject.ts
5170
- var import_ts_deepmerge8 = __toESM(require_dist());
5442
+ var import_ts_deepmerge7 = __toESM(require_dist());
5171
5443
  var SkinObject = class extends SceneObject {
5172
5444
  constructor(options) {
5173
5445
  super();
@@ -5175,7 +5447,7 @@ var SkinObject = class extends SceneObject {
5175
5447
  this.legacy = false;
5176
5448
  this.skinTextureWidth = 64;
5177
5449
  this.skinTextureHeight = 64;
5178
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5450
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5179
5451
  }
5180
5452
  async init() {
5181
5453
  this.createMeshes();
@@ -5292,7 +5564,7 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5292
5564
  this.dirty = true;
5293
5565
  }
5294
5566
  };
5295
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5567
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5296
5568
  }
5297
5569
  add(...objects) {
5298
5570
  for (const object of objects) {
@@ -5350,7 +5622,13 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5350
5622
  const obj = await objectSupplier();
5351
5623
  if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5352
5624
  console.log("instanceMeshes + key");
5353
- const key = asset.key.serialize();
5625
+ let key = asset.key.serialize();
5626
+ if (isModelObject(obj)) {
5627
+ const { uvLockRotation, tints } = obj.options;
5628
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
5629
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
5630
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
5631
+ }
5354
5632
  return this.instanceManager.getOrCreate(key, async () => {
5355
5633
  obj.scene = this;
5356
5634
  await obj.init();
@@ -5388,1121 +5666,1178 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5388
5666
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5389
5667
  }
5390
5668
  };
5391
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5669
+ _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5392
5670
  var MineRenderScene = _MineRenderScene;
5393
5671
  function isMineRenderScene(obj) {
5394
5672
  return obj.isMineRenderScene;
5395
5673
  }
5396
5674
 
5397
5675
  // src/renderer/Renderer.ts
5398
- import { AxesHelper as AxesHelper3, GridHelper, LinearEncoding, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, Vector3 as Vector37, WebGLRenderer } from "three";
5399
- var import_ts_deepmerge10 = __toESM(require_dist());
5676
+ import { AxesHelper as AxesHelper3, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector39, WebGLRenderer } from "three";
5677
+ var import_ts_deepmerge9 = __toESM(require_dist());
5400
5678
  import Stats from "stats.js";
5401
5679
  import { EffectComposer, RenderPass } from "postprocessing";
5402
- var _Renderer = class _Renderer {
5403
- constructor(options) {
5404
- this._dirty = true;
5405
- this._animationTimer = void 0;
5406
- this._animationFrame = void 0;
5407
- this._resizeListener = void 0;
5408
- this._disposed = false;
5409
- this._debugHelpers = [];
5410
- this._eventDispatchers = /* @__PURE__ */ new Map();
5411
- this._changeListener = () => {
5412
- this._dirty = true;
5680
+
5681
+ // src/three/OrbitControls.js
5682
+ import {
5683
+ EventDispatcher,
5684
+ MOUSE,
5685
+ Quaternion as Quaternion3,
5686
+ Spherical,
5687
+ TOUCH,
5688
+ Vector2 as Vector23,
5689
+ Vector3 as Vector38
5690
+ } from "three";
5691
+ var _changeEvent = { type: "change" };
5692
+ var _startEvent = { type: "start" };
5693
+ var _endEvent = { type: "end" };
5694
+ var OrbitControls = class extends EventDispatcher {
5695
+ constructor(object, domElement) {
5696
+ super();
5697
+ if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5698
+ if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5699
+ this.object = object;
5700
+ this.domElement = domElement;
5701
+ this.domElement.style.touchAction = "none";
5702
+ this.enabled = true;
5703
+ this.target = new Vector38();
5704
+ this.minDistance = 0;
5705
+ this.maxDistance = Infinity;
5706
+ this.minZoom = 0;
5707
+ this.maxZoom = Infinity;
5708
+ this.minPolarAngle = 0;
5709
+ this.maxPolarAngle = Math.PI;
5710
+ this.minAzimuthAngle = -Infinity;
5711
+ this.maxAzimuthAngle = Infinity;
5712
+ this.enableDamping = false;
5713
+ this.dampingFactor = 0.05;
5714
+ this.enableZoom = true;
5715
+ this.zoomSpeed = 1;
5716
+ this.enableRotate = true;
5717
+ this.rotateSpeed = 1;
5718
+ this.enablePan = true;
5719
+ this.panSpeed = 1;
5720
+ this.screenSpacePanning = true;
5721
+ this.keyPanSpeed = 7;
5722
+ this.autoRotate = false;
5723
+ this.autoRotateSpeed = 2;
5724
+ this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5725
+ this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
5726
+ this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
5727
+ this.target0 = this.target.clone();
5728
+ this.position0 = this.object.position.clone();
5729
+ this.zoom0 = this.object.zoom;
5730
+ this._domElementKeyEvents = null;
5731
+ this.getPolarAngle = function() {
5732
+ return spherical.phi;
5413
5733
  };
5414
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
5415
- this._animationLoop = this.animate.bind(this);
5416
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
5417
- this._scene = this.createScene();
5418
- this._camera = this.createCamera();
5419
- this._renderer = this.createRenderer();
5420
- this._composer = this.createComposer();
5421
- if (this.options.render.stats) {
5422
- this._stats = new Stats();
5423
- document.body.appendChild(this._stats.dom);
5734
+ this.getAzimuthalAngle = function() {
5735
+ return spherical.theta;
5736
+ };
5737
+ this.getDistance = function() {
5738
+ return this.object.position.distanceTo(this.target);
5739
+ };
5740
+ this.saveState = function() {
5741
+ scope.target0.copy(scope.target);
5742
+ scope.position0.copy(scope.object.position);
5743
+ scope.zoom0 = scope.object.zoom;
5744
+ };
5745
+ this.reset = function() {
5746
+ scope.target.copy(scope.target0);
5747
+ scope.object.position.copy(scope.position0);
5748
+ scope.object.zoom = scope.zoom0;
5749
+ scope.object.updateProjectionMatrix();
5750
+ scope.dispatchEvent(_changeEvent);
5751
+ scope.update();
5752
+ state = STATE.NONE;
5753
+ };
5754
+ this.update = function() {
5755
+ const offset = new Vector38();
5756
+ const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector38(0, 1, 0));
5757
+ const quatInverse = quat.clone().invert();
5758
+ const lastPosition = new Vector38();
5759
+ const lastQuaternion = new Quaternion3();
5760
+ const twoPI = 2 * Math.PI;
5761
+ return function update() {
5762
+ const position = scope.object.position;
5763
+ offset.copy(position).sub(scope.target);
5764
+ offset.applyQuaternion(quat);
5765
+ spherical.setFromVector3(offset);
5766
+ if (scope.autoRotate && state === STATE.NONE) {
5767
+ rotateLeft(getAutoRotationAngle());
5768
+ }
5769
+ if (scope.enableDamping) {
5770
+ spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5771
+ spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5772
+ } else {
5773
+ spherical.theta += sphericalDelta.theta;
5774
+ spherical.phi += sphericalDelta.phi;
5775
+ }
5776
+ let min = scope.minAzimuthAngle;
5777
+ let max = scope.maxAzimuthAngle;
5778
+ if (isFinite(min) && isFinite(max)) {
5779
+ if (min < -Math.PI) min += twoPI;
5780
+ else if (min > Math.PI) min -= twoPI;
5781
+ if (max < -Math.PI) max += twoPI;
5782
+ else if (max > Math.PI) max -= twoPI;
5783
+ if (min <= max) {
5784
+ spherical.theta = Math.max(min, Math.min(max, spherical.theta));
5785
+ } else {
5786
+ spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
5787
+ }
5788
+ }
5789
+ spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5790
+ spherical.makeSafe();
5791
+ spherical.radius *= scale;
5792
+ spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5793
+ if (scope.enableDamping === true) {
5794
+ scope.target.addScaledVector(panOffset, scope.dampingFactor);
5795
+ } else {
5796
+ scope.target.add(panOffset);
5797
+ }
5798
+ offset.setFromSpherical(spherical);
5799
+ offset.applyQuaternion(quatInverse);
5800
+ position.copy(scope.target).add(offset);
5801
+ scope.object.lookAt(scope.target);
5802
+ if (scope.enableDamping === true) {
5803
+ sphericalDelta.theta *= 1 - scope.dampingFactor;
5804
+ sphericalDelta.phi *= 1 - scope.dampingFactor;
5805
+ panOffset.multiplyScalar(1 - scope.dampingFactor);
5806
+ } else {
5807
+ sphericalDelta.set(0, 0, 0);
5808
+ panOffset.set(0, 0, 0);
5809
+ }
5810
+ scale = 1;
5811
+ if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5812
+ scope.dispatchEvent(_changeEvent);
5813
+ lastPosition.copy(scope.object.position);
5814
+ lastQuaternion.copy(scope.object.quaternion);
5815
+ zoomChanged = false;
5816
+ return true;
5817
+ }
5818
+ return false;
5819
+ };
5820
+ }();
5821
+ this.dispose = function() {
5822
+ scope.domElement.removeEventListener("contextmenu", onContextMenu);
5823
+ scope.domElement.removeEventListener("pointerdown", onPointerDown);
5824
+ scope.domElement.removeEventListener("pointercancel", onPointerCancel);
5825
+ scope.domElement.removeEventListener("wheel", onMouseWheel);
5826
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
5827
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5828
+ if (scope._domElementKeyEvents !== null) {
5829
+ scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
5830
+ }
5831
+ };
5832
+ const scope = this;
5833
+ const STATE = {
5834
+ NONE: -1,
5835
+ ROTATE: 0,
5836
+ DOLLY: 1,
5837
+ PAN: 2,
5838
+ TOUCH_ROTATE: 3,
5839
+ TOUCH_PAN: 4,
5840
+ TOUCH_DOLLY_PAN: 5,
5841
+ TOUCH_DOLLY_ROTATE: 6
5842
+ };
5843
+ let state = STATE.NONE;
5844
+ const EPS = 1e-6;
5845
+ const spherical = new Spherical();
5846
+ const sphericalDelta = new Spherical();
5847
+ let scale = 1;
5848
+ const panOffset = new Vector38();
5849
+ let zoomChanged = false;
5850
+ const rotateStart = new Vector23();
5851
+ const rotateEnd = new Vector23();
5852
+ const rotateDelta = new Vector23();
5853
+ const panStart = new Vector23();
5854
+ const panEnd = new Vector23();
5855
+ const panDelta = new Vector23();
5856
+ const dollyStart = new Vector23();
5857
+ const dollyEnd = new Vector23();
5858
+ const dollyDelta = new Vector23();
5859
+ const pointers = [];
5860
+ const pointerPositions = {};
5861
+ function getAutoRotationAngle() {
5862
+ return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
5424
5863
  }
5425
- this.init();
5426
- }
5427
- //<editor-fold desc="INIT">
5428
- createScene() {
5429
- return new MineRenderScene();
5430
- }
5431
- createCamera() {
5432
- switch (this.options.camera.type) {
5433
- case "perspective":
5434
- default:
5435
- return new PerspectiveCamera(
5436
- this.options.camera.perspective.fov,
5437
- this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
5438
- this.options.camera.near,
5439
- this.options.camera.far
5440
- );
5441
- case "orthographic":
5442
- return new OrthographicCamera(
5443
- this.options.camera.orthographic.left ?? this.viewWidth / -2,
5444
- this.options.camera.orthographic.right ?? this.viewWidth / 2,
5445
- this.options.camera.orthographic.top ?? this.viewHeight / 2,
5446
- this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
5447
- this.options.camera.near,
5448
- this.options.camera.far
5449
- );
5450
- }
5451
- }
5452
- createRenderer() {
5453
- const renderer = new WebGLRenderer({
5454
- antialias: this.options.render.antialias,
5455
- alpha: true,
5456
- powerPreference: "high-performance",
5457
- depth: true
5458
- });
5459
- renderer.setClearColor(0, 0);
5460
- renderer.shadowMap.enabled = true;
5461
- renderer.shadowMap.type = PCFSoftShadowMap;
5462
- renderer.outputEncoding = LinearEncoding;
5463
- renderer.setSize(this.viewWidth, this.viewHeight);
5464
- return renderer;
5465
- }
5466
- createComposer() {
5467
- const composer = new EffectComposer(this.renderer);
5468
- if (!this.options.composer.enabled) return composer;
5469
- composer.setSize(this.viewWidth, this.viewHeight);
5470
- composer.addPass(new RenderPass(this.scene, this.camera));
5471
- return composer;
5472
- }
5473
- //</editor-fold>
5474
- init() {
5475
- if (this._disposed) return;
5476
- if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
5477
- window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
5864
+ function getZoomScale() {
5865
+ return Math.pow(0.95, scope.zoomSpeed);
5478
5866
  }
5479
- if (this.options.debug.grid) {
5480
- const gridHelper = new GridHelper(128, 16);
5481
- this._debugHelpers.push(gridHelper);
5482
- this.scene.add(gridHelper);
5483
- const gridHelper2 = new GridHelper(128, 16);
5484
- this._debugHelpers.push(gridHelper2);
5485
- gridHelper2.rotation.x = 90 * (Math.PI / 180);
5486
- this.scene.add(gridHelper2);
5487
- const gridHelper3 = new GridHelper(128, 16);
5488
- this._debugHelpers.push(gridHelper3);
5489
- gridHelper3.rotation.z = 90 * (Math.PI / 180);
5490
- this.scene.add(gridHelper3);
5867
+ function rotateLeft(angle) {
5868
+ sphericalDelta.theta -= angle;
5491
5869
  }
5492
- if (this.options.debug.axes) {
5493
- const axesHelper = new AxesHelper3(64);
5494
- this._debugHelpers.push(axesHelper);
5495
- this.scene.add(axesHelper);
5870
+ function rotateUp(angle) {
5871
+ sphericalDelta.phi -= angle;
5496
5872
  }
5497
- if (this.options.camera.position) {
5498
- if (isVector3(this.options.camera.position)) {
5499
- this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
5500
- } else if (isTripleArray(this.options.camera.position)) {
5501
- this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
5873
+ const panLeft = function() {
5874
+ const v = new Vector38();
5875
+ return function panLeft2(distance, objectMatrix) {
5876
+ v.setFromMatrixColumn(objectMatrix, 0);
5877
+ v.multiplyScalar(-distance);
5878
+ panOffset.add(v);
5879
+ };
5880
+ }();
5881
+ const panUp = function() {
5882
+ const v = new Vector38();
5883
+ return function panUp2(distance, objectMatrix) {
5884
+ if (scope.screenSpacePanning === true) {
5885
+ v.setFromMatrixColumn(objectMatrix, 1);
5886
+ } else {
5887
+ v.setFromMatrixColumn(objectMatrix, 0);
5888
+ v.crossVectors(scope.object.up, v);
5889
+ }
5890
+ v.multiplyScalar(distance);
5891
+ panOffset.add(v);
5892
+ };
5893
+ }();
5894
+ const pan = function() {
5895
+ const offset = new Vector38();
5896
+ return function pan2(deltaX, deltaY) {
5897
+ const element = scope.domElement;
5898
+ if (scope.object.isPerspectiveCamera) {
5899
+ const position = scope.object.position;
5900
+ offset.copy(position).sub(scope.target);
5901
+ let targetDistance = offset.length();
5902
+ targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
5903
+ panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
5904
+ panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
5905
+ } else if (scope.object.isOrthographicCamera) {
5906
+ panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
5907
+ panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
5908
+ } else {
5909
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
5910
+ scope.enablePan = false;
5911
+ }
5912
+ };
5913
+ }();
5914
+ function dollyOut(dollyScale) {
5915
+ if (scope.object.isPerspectiveCamera) {
5916
+ scale /= dollyScale;
5917
+ } else if (scope.object.isOrthographicCamera) {
5918
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
5919
+ scope.object.updateProjectionMatrix();
5920
+ zoomChanged = true;
5921
+ } else {
5922
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
5923
+ scope.enableZoom = false;
5502
5924
  }
5503
5925
  }
5504
- if (this.options.camera.lookingAt) {
5505
- if (isVector3(this.options.camera.lookingAt)) {
5506
- this.camera.lookAt(this.options.camera.lookingAt);
5507
- } else if (isTripleArray(this.options.camera.lookingAt)) {
5508
- this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
5926
+ function dollyIn(dollyScale) {
5927
+ if (scope.object.isPerspectiveCamera) {
5928
+ scale *= dollyScale;
5929
+ } else if (scope.object.isOrthographicCamera) {
5930
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
5931
+ scope.object.updateProjectionMatrix();
5932
+ zoomChanged = true;
5933
+ } else {
5934
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
5935
+ scope.enableZoom = false;
5509
5936
  }
5510
5937
  }
5511
- if (this.options.render.autoResize && !this._resizeListener) {
5512
- this._resizeListener = () => {
5513
- this.resize(this.viewWidth, this.viewHeight);
5514
- };
5515
- window.addEventListener("resize", this._resizeListener);
5938
+ function handleMouseDownRotate(event) {
5939
+ rotateStart.set(event.clientX, event.clientY);
5516
5940
  }
5517
- }
5518
- get element() {
5519
- return this._element;
5520
- }
5521
- appendTo(element) {
5522
- if (this._disposed) return;
5523
- this._element = element;
5524
- this._element.appendChild(this.renderer.domElement);
5525
- if (this.viewWidth == 0) {
5526
- console.warn("0 element width");
5941
+ function handleMouseDownDolly(event) {
5942
+ dollyStart.set(event.clientX, event.clientY);
5527
5943
  }
5528
- if (this.viewHeight == 0) {
5529
- console.warn("0 element height");
5944
+ function handleMouseDownPan(event) {
5945
+ panStart.set(event.clientX, event.clientY);
5530
5946
  }
5531
- this.resize(this.viewWidth, this.viewHeight);
5532
- }
5533
- /**
5534
- * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
5535
- * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
5536
- */
5537
- registerEventDispatcher(dispatcher, changeEvent2 = "change") {
5538
- if (this._disposed) return;
5539
- let events = this._eventDispatchers.get(dispatcher);
5540
- if (!events) {
5541
- events = /* @__PURE__ */ new Set();
5542
- this._eventDispatchers.set(dispatcher, events);
5947
+ function handleMouseMoveRotate(event) {
5948
+ rotateEnd.set(event.clientX, event.clientY);
5949
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
5950
+ const element = scope.domElement;
5951
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
5952
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
5953
+ rotateStart.copy(rotateEnd);
5954
+ scope.update();
5543
5955
  }
5544
- if (events.has(changeEvent2)) return;
5545
- events.add(changeEvent2);
5546
- dispatcher.addEventListener(changeEvent2, this._changeListener);
5547
- }
5548
- resize(width, height) {
5549
- if (this._disposed) return;
5550
- if (isPerspectiveCamera(this.camera)) {
5551
- this.camera.aspect = width / height;
5552
- this.camera.updateProjectionMatrix();
5553
- } else if (isOrthographicCamera(this.camera)) {
5554
- this.camera.left = width / -2;
5555
- this.camera.right = width / 2;
5556
- this.camera.top = height / 2;
5557
- this.camera.bottom = height / -2;
5558
- this.camera.updateProjectionMatrix();
5956
+ function handleMouseMoveDolly(event) {
5957
+ dollyEnd.set(event.clientX, event.clientY);
5958
+ dollyDelta.subVectors(dollyEnd, dollyStart);
5959
+ if (dollyDelta.y > 0) {
5960
+ dollyOut(getZoomScale());
5961
+ } else if (dollyDelta.y < 0) {
5962
+ dollyIn(getZoomScale());
5963
+ }
5964
+ dollyStart.copy(dollyEnd);
5965
+ scope.update();
5559
5966
  }
5560
- this.renderer.setSize(width, height);
5561
- this.composer.setSize(width, height);
5562
- this._dirty = true;
5563
- }
5564
- //<editor-fold desc="RENDER">
5565
- get dirty() {
5566
- return this._dirty || this.scene.dirty;
5567
- }
5568
- set dirty(dirty) {
5569
- this._dirty = dirty;
5570
- this.scene.dirty = dirty;
5571
- }
5572
- start() {
5573
- if (this._disposed) return;
5574
- this.stop();
5575
- this.renderer.setAnimationLoop(this._animationLoop);
5576
- }
5577
- stop() {
5578
- if (this._disposed) return;
5579
- this.renderer.setAnimationLoop(null);
5580
- if (this._animationTimer)
5581
- clearTimeout(this._animationTimer);
5582
- this._animationTimer = void 0;
5583
- if (this._animationFrame)
5584
- cancelAnimationFrame(this._animationFrame);
5585
- this._animationFrame = void 0;
5586
- }
5587
- /**
5588
- * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
5589
- * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
5590
- * controls must be managed by their owners.
5591
- */
5592
- dispose() {
5593
- if (this._disposed) return;
5594
- this.stop();
5595
- this._disposed = true;
5596
- if (this._resizeListener) {
5597
- window.removeEventListener("resize", this._resizeListener);
5598
- this._resizeListener = void 0;
5967
+ function handleMouseMovePan(event) {
5968
+ panEnd.set(event.clientX, event.clientY);
5969
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
5970
+ pan(panDelta.x, panDelta.y);
5971
+ panStart.copy(panEnd);
5972
+ scope.update();
5599
5973
  }
5600
- for (const [dispatcher, events] of this._eventDispatchers) {
5601
- for (const event of events) {
5602
- dispatcher.removeEventListener(event, this._changeListener);
5603
- }
5974
+ function handleMouseUp() {
5604
5975
  }
5605
- this._eventDispatchers.clear();
5606
- this._stats?.dom.remove();
5607
- this._stats = void 0;
5608
- this.renderer.domElement.remove();
5609
- this._element = void 0;
5610
- this.scene.clear();
5611
- for (const helper of this._debugHelpers) {
5612
- helper.geometry.dispose();
5613
- const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
5614
- for (const material of materials) {
5615
- material.dispose();
5976
+ function handleMouseWheel(event) {
5977
+ if (event.deltaY < 0) {
5978
+ dollyIn(getZoomScale());
5979
+ } else if (event.deltaY > 0) {
5980
+ dollyOut(getZoomScale());
5616
5981
  }
5982
+ scope.update();
5617
5983
  }
5618
- this._debugHelpers.length = 0;
5619
- this.composer.dispose();
5620
- this.renderer.dispose();
5621
- this.renderer.forceContextLoss();
5622
- }
5623
- animate(t) {
5624
- if (this._disposed) return;
5625
- if (this._stats) {
5626
- this._stats.begin();
5984
+ function handleKeyDown(event) {
5985
+ let needsUpdate = false;
5986
+ switch (event.code) {
5987
+ case scope.keys.UP:
5988
+ pan(0, scope.keyPanSpeed);
5989
+ needsUpdate = true;
5990
+ break;
5991
+ case scope.keys.BOTTOM:
5992
+ pan(0, -scope.keyPanSpeed);
5993
+ needsUpdate = true;
5994
+ break;
5995
+ case scope.keys.LEFT:
5996
+ pan(scope.keyPanSpeed, 0);
5997
+ needsUpdate = true;
5998
+ break;
5999
+ case scope.keys.RIGHT:
6000
+ pan(-scope.keyPanSpeed, 0);
6001
+ needsUpdate = true;
6002
+ break;
6003
+ }
6004
+ if (needsUpdate) {
6005
+ event.preventDefault();
6006
+ scope.update();
6007
+ }
5627
6008
  }
5628
- if (this.dirty || this.options.render.renderAlways) {
5629
- if (this.options.composer.enabled) {
5630
- this.composer.render();
6009
+ function handleTouchStartRotate() {
6010
+ if (pointers.length === 1) {
6011
+ rotateStart.set(pointers[0].pageX, pointers[0].pageY);
5631
6012
  } else {
5632
- this.renderer.render(this.scene, this.camera);
6013
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6014
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6015
+ rotateStart.set(x, y);
5633
6016
  }
5634
6017
  }
5635
- this.dirty = false;
5636
- if (this._stats) {
5637
- this._stats.end();
6018
+ function handleTouchStartPan() {
6019
+ if (pointers.length === 1) {
6020
+ panStart.set(pointers[0].pageX, pointers[0].pageY);
6021
+ } else {
6022
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6023
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6024
+ panStart.set(x, y);
6025
+ }
5638
6026
  }
5639
- }
5640
- //</editor-fold>
5641
- toImage() {
5642
- return this.renderer.domElement.toDataURL();
5643
- }
5644
- ///
5645
- get attachedToBody() {
5646
- return this.element === document.body;
5647
- }
5648
- get viewWidth() {
5649
- return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
5650
- }
5651
- get viewHeight() {
5652
- return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
5653
- }
5654
- get scene() {
5655
- return this._scene;
5656
- }
5657
- get camera() {
5658
- return this._camera;
5659
- }
5660
- get renderer() {
5661
- return this._renderer;
5662
- }
5663
- get composer() {
5664
- return this._composer;
5665
- }
5666
- ///
5667
- };
5668
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
5669
- camera: {
5670
- type: "perspective",
5671
- near: 1,
5672
- far: 5e3,
5673
- perspective: {
5674
- aspect: void 0,
5675
- fov: 50
5676
- },
5677
- orthographic: {
5678
- left: void 0,
5679
- right: void 0,
5680
- top: void 0,
5681
- bottom: void 0
5682
- },
5683
- position: new Vector37(50, 50, 50),
5684
- lookingAt: new Vector37(0, 0, 0)
5685
- },
5686
- render: {
5687
- fpsLimit: 60,
5688
- stats: false,
5689
- antialias: true,
5690
- shade: true,
5691
- autoResize: true,
5692
- renderAlways: false
5693
- },
5694
- composer: {
5695
- enabled: true
5696
- },
5697
- debug: {
5698
- grid: false,
5699
- axes: false
5700
- }
5701
- });
5702
- var Renderer = _Renderer;
5703
-
5704
- // src/skin/Skins.ts
5705
- var Skins = class {
5706
- //<editor-fold desc="Skins">
5707
- static async fromUuidOrUsername(uuidOrUsername) {
5708
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5709
- return this.fromUuid(uuidOrUsername);
6027
+ function handleTouchStartDolly() {
6028
+ const dx = pointers[0].pageX - pointers[1].pageX;
6029
+ const dy = pointers[0].pageY - pointers[1].pageY;
6030
+ const distance = Math.sqrt(dx * dx + dy * dy);
6031
+ dollyStart.set(0, distance);
5710
6032
  }
5711
- return this.fromUsername(uuidOrUsername);
5712
- }
5713
- static async fromUuid(uuid) {
5714
- return this.getSkinProxySkinUrl(uuid);
5715
- }
5716
- static async fromUsername(username) {
5717
- return this.usernameToUuid(username).then((uuid) => {
5718
- if (uuid) {
5719
- return this.fromUuid(uuid);
5720
- }
5721
- return void 0;
5722
- });
5723
- }
5724
- static async fromMineSkin(mineskinId) {
5725
- return this.getMineSkin(mineskinId).then((mineskin) => {
5726
- if (mineskin) {
5727
- return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6033
+ function handleTouchStartDollyPan() {
6034
+ if (scope.enableZoom) handleTouchStartDolly();
6035
+ if (scope.enablePan) handleTouchStartPan();
6036
+ }
6037
+ function handleTouchStartDollyRotate() {
6038
+ if (scope.enableZoom) handleTouchStartDolly();
6039
+ if (scope.enableRotate) handleTouchStartRotate();
6040
+ }
6041
+ function handleTouchMoveRotate(event) {
6042
+ if (pointers.length == 1) {
6043
+ rotateEnd.set(event.pageX, event.pageY);
6044
+ } else {
6045
+ const position = getSecondPointerPosition(event);
6046
+ const x = 0.5 * (event.pageX + position.x);
6047
+ const y = 0.5 * (event.pageY + position.y);
6048
+ rotateEnd.set(x, y);
5728
6049
  }
5729
- return void 0;
5730
- });
5731
- }
5732
- //</editor-fold>
5733
- //<editor-fold desc="Capes">
5734
- static async capeFromUuidOrUsername(uuidOrUsername) {
5735
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5736
- return this.capeFromUuid(uuidOrUsername);
6050
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6051
+ const element = scope.domElement;
6052
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6053
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6054
+ rotateStart.copy(rotateEnd);
5737
6055
  }
5738
- return this.capeFromUsername(uuidOrUsername);
5739
- }
5740
- static async capeFromUuid(uuid) {
5741
- return this.getSkinProxyCapeUrl(uuid);
5742
- }
5743
- static async capeFromUsername(username) {
5744
- return this.usernameToUuid(username).then((uuid) => {
5745
- if (uuid) {
5746
- return this.capeFromUuid(uuid);
6056
+ function handleTouchMovePan(event) {
6057
+ if (pointers.length === 1) {
6058
+ panEnd.set(event.pageX, event.pageY);
6059
+ } else {
6060
+ const position = getSecondPointerPosition(event);
6061
+ const x = 0.5 * (event.pageX + position.x);
6062
+ const y = 0.5 * (event.pageY + position.y);
6063
+ panEnd.set(x, y);
5747
6064
  }
5748
- return void 0;
5749
- });
5750
- }
5751
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
5752
- return this.getCapesDev(uuid, capeType).then((cape) => {
5753
- if (cape) {
5754
- return cape?.stillImageUrl;
6065
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6066
+ pan(panDelta.x, panDelta.y);
6067
+ panStart.copy(panEnd);
6068
+ }
6069
+ function handleTouchMoveDolly(event) {
6070
+ const position = getSecondPointerPosition(event);
6071
+ const dx = event.pageX - position.x;
6072
+ const dy = event.pageY - position.y;
6073
+ const distance = Math.sqrt(dx * dx + dy * dy);
6074
+ dollyEnd.set(0, distance);
6075
+ dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
6076
+ dollyOut(dollyDelta.y);
6077
+ dollyStart.copy(dollyEnd);
6078
+ }
6079
+ function handleTouchMoveDollyPan(event) {
6080
+ if (scope.enableZoom) handleTouchMoveDolly(event);
6081
+ if (scope.enablePan) handleTouchMovePan(event);
6082
+ }
6083
+ function handleTouchMoveDollyRotate(event) {
6084
+ if (scope.enableZoom) handleTouchMoveDolly(event);
6085
+ if (scope.enableRotate) handleTouchMoveRotate(event);
6086
+ }
6087
+ function handleTouchEnd() {
6088
+ }
6089
+ function onPointerDown(event) {
6090
+ if (scope.enabled === false) return;
6091
+ if (pointers.length === 0) {
6092
+ scope.domElement.setPointerCapture(event.pointerId);
6093
+ scope.domElement.addEventListener("pointermove", onPointerMove);
6094
+ scope.domElement.addEventListener("pointerup", onPointerUp);
5755
6095
  }
5756
- return void 0;
5757
- });
5758
- }
5759
- //</editor-fold>
5760
- //<editor-fold desc="Helpers">
5761
- static async usernameToUuid(username) {
5762
- return this.usernameToUuidSkinProxy(username);
5763
- }
5764
- static async usernameToUuidSkinProxy(username) {
5765
- return Requests.genericRequest({
5766
- baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
5767
- url: "/uuid/" + username
5768
- }).then((res) => {
5769
- if (res.status === 200) {
5770
- return res.data["id"];
6096
+ addPointer(event);
6097
+ if (event.pointerType === "touch") {
6098
+ onTouchStart(event);
6099
+ } else {
6100
+ onMouseDown(event);
5771
6101
  }
5772
- return void 0;
5773
- }).catch((err) => {
5774
- console.warn(err);
5775
- return void 0;
5776
- });
5777
- }
5778
- static async usernameToUuidMineTools(username) {
5779
- return Requests.genericRequest({
5780
- baseURL: "https://api.minetools.eu",
5781
- url: "/uuid/" + username
5782
- }).then((res) => {
5783
- if (res.status === 200) {
5784
- return res.data["id"];
6102
+ }
6103
+ function onPointerMove(event) {
6104
+ if (scope.enabled === false) return;
6105
+ if (event.pointerType === "touch") {
6106
+ onTouchMove(event);
6107
+ } else {
6108
+ onMouseMove(event);
5785
6109
  }
5786
- return void 0;
5787
- }).catch((err) => {
5788
- console.warn(err);
5789
- return void 0;
5790
- });
5791
- }
5792
- static async getProfileFromMinetools(uuid) {
5793
- return Requests.genericRequest({
5794
- baseURL: "https://api.minetools.eu",
5795
- url: "/profile/" + uuid
5796
- }).then((res) => {
5797
- if (res.status === 200) {
5798
- return res.data;
6110
+ }
6111
+ function onPointerUp(event) {
6112
+ if (scope.enabled === false) return;
6113
+ if (event.pointerType === "touch") {
6114
+ onTouchEnd();
6115
+ } else {
6116
+ onMouseUp(event);
5799
6117
  }
5800
- });
5801
- }
5802
- static async getMineSkin(mineskinId) {
5803
- return Requests.genericRequest({
5804
- baseURL: "https://api.mineskin.org",
5805
- url: "/get/uuid/" + mineskinId
5806
- }).then((res) => {
5807
- if (res.status === 200) {
5808
- return res.data;
6118
+ removePointer(event);
6119
+ if (pointers.length === 0) {
6120
+ scope.domElement.releasePointerCapture(event.pointerId);
6121
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
6122
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5809
6123
  }
5810
- return void 0;
5811
- }).catch((err) => {
5812
- console.warn(err);
5813
- return void 0;
5814
- });
5815
- }
5816
- static async getCapesDev(uuid, type = "all") {
5817
- return Requests.genericRequest({
5818
- baseURL: "https://api.capes.dev",
5819
- url: "/load/" + uuid + "/" + type
5820
- }).then((res) => {
5821
- if (res.status === 200) {
5822
- return res.data;
6124
+ }
6125
+ function onPointerCancel(event) {
6126
+ removePointer(event);
6127
+ }
6128
+ function onMouseDown(event) {
6129
+ let mouseAction;
6130
+ switch (event.button) {
6131
+ case 0:
6132
+ mouseAction = scope.mouseButtons.LEFT;
6133
+ break;
6134
+ case 1:
6135
+ mouseAction = scope.mouseButtons.MIDDLE;
6136
+ break;
6137
+ case 2:
6138
+ mouseAction = scope.mouseButtons.RIGHT;
6139
+ break;
6140
+ default:
6141
+ mouseAction = -1;
5823
6142
  }
5824
- return void 0;
5825
- }).catch((err) => {
5826
- console.warn(err);
5827
- return void 0;
5828
- });
5829
- }
5830
- static getCrafatarSkinUrl(uuid) {
5831
- return "https://crafatar.com/skins/" + uuid;
5832
- }
5833
- static getCrafatarCapeUrl(uuid) {
5834
- return "https://crafatar.com/capes/" + uuid;
5835
- }
5836
- static getMcHeadsSkinUrl(uuid) {
5837
- return "https://mc-heads.net/skin/" + uuid;
5838
- }
5839
- static getMineSkinPlayerSkinUrl(uuid) {
5840
- return "https://mineskin.org/skin/player/" + uuid;
5841
- }
5842
- static getSkinProxySkinUrl(uuid) {
5843
- return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
5844
- }
5845
- static getSkinProxyCapeUrl(uuid) {
5846
- return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
5847
- }
5848
- //</editor-fold>
5849
- };
5850
-
5851
- // src/three/OrbitControls.js
5852
- import {
5853
- EventDispatcher as EventDispatcher2,
5854
- MOUSE,
5855
- Quaternion as Quaternion3,
5856
- Spherical,
5857
- TOUCH,
5858
- Vector2 as Vector23,
5859
- Vector3 as Vector38
5860
- } from "three";
5861
- var _changeEvent = { type: "change" };
5862
- var _startEvent = { type: "start" };
5863
- var _endEvent = { type: "end" };
5864
- var OrbitControls = class extends EventDispatcher2 {
5865
- constructor(object, domElement) {
5866
- super();
5867
- if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5868
- if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5869
- this.object = object;
5870
- this.domElement = domElement;
5871
- this.domElement.style.touchAction = "none";
5872
- this.enabled = true;
5873
- this.target = new Vector38();
5874
- this.minDistance = 0;
5875
- this.maxDistance = Infinity;
5876
- this.minZoom = 0;
5877
- this.maxZoom = Infinity;
5878
- this.minPolarAngle = 0;
5879
- this.maxPolarAngle = Math.PI;
5880
- this.minAzimuthAngle = -Infinity;
5881
- this.maxAzimuthAngle = Infinity;
5882
- this.enableDamping = false;
5883
- this.dampingFactor = 0.05;
5884
- this.enableZoom = true;
5885
- this.zoomSpeed = 1;
5886
- this.enableRotate = true;
5887
- this.rotateSpeed = 1;
5888
- this.enablePan = true;
5889
- this.panSpeed = 1;
5890
- this.screenSpacePanning = true;
5891
- this.keyPanSpeed = 7;
5892
- this.autoRotate = false;
5893
- this.autoRotateSpeed = 2;
5894
- this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5895
- this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
5896
- this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
5897
- this.target0 = this.target.clone();
5898
- this.position0 = this.object.position.clone();
5899
- this.zoom0 = this.object.zoom;
5900
- this._domElementKeyEvents = null;
5901
- this.getPolarAngle = function() {
5902
- return spherical.phi;
5903
- };
5904
- this.getAzimuthalAngle = function() {
5905
- return spherical.theta;
5906
- };
5907
- this.getDistance = function() {
5908
- return this.object.position.distanceTo(this.target);
5909
- };
5910
- this.saveState = function() {
5911
- scope.target0.copy(scope.target);
5912
- scope.position0.copy(scope.object.position);
5913
- scope.zoom0 = scope.object.zoom;
5914
- };
5915
- this.reset = function() {
5916
- scope.target.copy(scope.target0);
5917
- scope.object.position.copy(scope.position0);
5918
- scope.object.zoom = scope.zoom0;
5919
- scope.object.updateProjectionMatrix();
5920
- scope.dispatchEvent(_changeEvent);
5921
- scope.update();
5922
- state = STATE.NONE;
5923
- };
5924
- this.update = function() {
5925
- const offset = new Vector38();
5926
- const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector38(0, 1, 0));
5927
- const quatInverse = quat.clone().invert();
5928
- const lastPosition = new Vector38();
5929
- const lastQuaternion = new Quaternion3();
5930
- const twoPI = 2 * Math.PI;
5931
- return function update() {
5932
- const position = scope.object.position;
5933
- offset.copy(position).sub(scope.target);
5934
- offset.applyQuaternion(quat);
5935
- spherical.setFromVector3(offset);
5936
- if (scope.autoRotate && state === STATE.NONE) {
5937
- rotateLeft(getAutoRotationAngle());
5938
- }
5939
- if (scope.enableDamping) {
5940
- spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5941
- spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5942
- } else {
5943
- spherical.theta += sphericalDelta.theta;
5944
- spherical.phi += sphericalDelta.phi;
5945
- }
5946
- let min = scope.minAzimuthAngle;
5947
- let max = scope.maxAzimuthAngle;
5948
- if (isFinite(min) && isFinite(max)) {
5949
- if (min < -Math.PI) min += twoPI;
5950
- else if (min > Math.PI) min -= twoPI;
5951
- if (max < -Math.PI) max += twoPI;
5952
- else if (max > Math.PI) max -= twoPI;
5953
- if (min <= max) {
5954
- spherical.theta = Math.max(min, Math.min(max, spherical.theta));
6143
+ switch (mouseAction) {
6144
+ case MOUSE.DOLLY:
6145
+ if (scope.enableZoom === false) return;
6146
+ handleMouseDownDolly(event);
6147
+ state = STATE.DOLLY;
6148
+ break;
6149
+ case MOUSE.ROTATE:
6150
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
6151
+ if (scope.enablePan === false) return;
6152
+ handleMouseDownPan(event);
6153
+ state = STATE.PAN;
5955
6154
  } else {
5956
- spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
6155
+ if (scope.enableRotate === false) return;
6156
+ handleMouseDownRotate(event);
6157
+ state = STATE.ROTATE;
6158
+ }
6159
+ break;
6160
+ case MOUSE.PAN:
6161
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
6162
+ if (scope.enableRotate === false) return;
6163
+ handleMouseDownRotate(event);
6164
+ state = STATE.ROTATE;
6165
+ } else {
6166
+ if (scope.enablePan === false) return;
6167
+ handleMouseDownPan(event);
6168
+ state = STATE.PAN;
6169
+ }
6170
+ break;
6171
+ default:
6172
+ state = STATE.NONE;
6173
+ }
6174
+ if (state !== STATE.NONE) {
6175
+ scope.dispatchEvent(_startEvent);
6176
+ }
6177
+ }
6178
+ function onMouseMove(event) {
6179
+ if (scope.enabled === false) return;
6180
+ switch (state) {
6181
+ case STATE.ROTATE:
6182
+ if (scope.enableRotate === false) return;
6183
+ handleMouseMoveRotate(event);
6184
+ break;
6185
+ case STATE.DOLLY:
6186
+ if (scope.enableZoom === false) return;
6187
+ handleMouseMoveDolly(event);
6188
+ break;
6189
+ case STATE.PAN:
6190
+ if (scope.enablePan === false) return;
6191
+ handleMouseMovePan(event);
6192
+ break;
6193
+ }
6194
+ }
6195
+ function onMouseUp(event) {
6196
+ handleMouseUp(event);
6197
+ scope.dispatchEvent(_endEvent);
6198
+ state = STATE.NONE;
6199
+ }
6200
+ function onMouseWheel(event) {
6201
+ if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE) return;
6202
+ event.preventDefault();
6203
+ scope.dispatchEvent(_startEvent);
6204
+ handleMouseWheel(event);
6205
+ scope.dispatchEvent(_endEvent);
6206
+ }
6207
+ function onKeyDown(event) {
6208
+ if (scope.enabled === false || scope.enablePan === false) return;
6209
+ handleKeyDown(event);
6210
+ }
6211
+ function onTouchStart(event) {
6212
+ trackPointer(event);
6213
+ switch (pointers.length) {
6214
+ case 1:
6215
+ switch (scope.touches.ONE) {
6216
+ case TOUCH.ROTATE:
6217
+ if (scope.enableRotate === false) return;
6218
+ handleTouchStartRotate();
6219
+ state = STATE.TOUCH_ROTATE;
6220
+ break;
6221
+ case TOUCH.PAN:
6222
+ if (scope.enablePan === false) return;
6223
+ handleTouchStartPan();
6224
+ state = STATE.TOUCH_PAN;
6225
+ break;
6226
+ default:
6227
+ state = STATE.NONE;
5957
6228
  }
5958
- }
5959
- spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5960
- spherical.makeSafe();
5961
- spherical.radius *= scale;
5962
- spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5963
- if (scope.enableDamping === true) {
5964
- scope.target.addScaledVector(panOffset, scope.dampingFactor);
5965
- } else {
5966
- scope.target.add(panOffset);
5967
- }
5968
- offset.setFromSpherical(spherical);
5969
- offset.applyQuaternion(quatInverse);
5970
- position.copy(scope.target).add(offset);
5971
- scope.object.lookAt(scope.target);
5972
- if (scope.enableDamping === true) {
5973
- sphericalDelta.theta *= 1 - scope.dampingFactor;
5974
- sphericalDelta.phi *= 1 - scope.dampingFactor;
5975
- panOffset.multiplyScalar(1 - scope.dampingFactor);
5976
- } else {
5977
- sphericalDelta.set(0, 0, 0);
5978
- panOffset.set(0, 0, 0);
5979
- }
5980
- scale = 1;
5981
- if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5982
- scope.dispatchEvent(_changeEvent);
5983
- lastPosition.copy(scope.object.position);
5984
- lastQuaternion.copy(scope.object.quaternion);
5985
- zoomChanged = false;
5986
- return true;
5987
- }
5988
- return false;
5989
- };
5990
- }();
5991
- this.dispose = function() {
5992
- scope.domElement.removeEventListener("contextmenu", onContextMenu);
5993
- scope.domElement.removeEventListener("pointerdown", onPointerDown);
5994
- scope.domElement.removeEventListener("pointercancel", onPointerCancel);
5995
- scope.domElement.removeEventListener("wheel", onMouseWheel);
5996
- scope.domElement.removeEventListener("pointermove", onPointerMove);
5997
- scope.domElement.removeEventListener("pointerup", onPointerUp);
5998
- if (scope._domElementKeyEvents !== null) {
5999
- scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
6229
+ break;
6230
+ case 2:
6231
+ switch (scope.touches.TWO) {
6232
+ case TOUCH.DOLLY_PAN:
6233
+ if (scope.enableZoom === false && scope.enablePan === false) return;
6234
+ handleTouchStartDollyPan();
6235
+ state = STATE.TOUCH_DOLLY_PAN;
6236
+ break;
6237
+ case TOUCH.DOLLY_ROTATE:
6238
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
6239
+ handleTouchStartDollyRotate();
6240
+ state = STATE.TOUCH_DOLLY_ROTATE;
6241
+ break;
6242
+ default:
6243
+ state = STATE.NONE;
6244
+ }
6245
+ break;
6246
+ default:
6247
+ state = STATE.NONE;
6248
+ }
6249
+ if (state !== STATE.NONE) {
6250
+ scope.dispatchEvent(_startEvent);
6000
6251
  }
6001
- };
6002
- const scope = this;
6003
- const STATE = {
6004
- NONE: -1,
6005
- ROTATE: 0,
6006
- DOLLY: 1,
6007
- PAN: 2,
6008
- TOUCH_ROTATE: 3,
6009
- TOUCH_PAN: 4,
6010
- TOUCH_DOLLY_PAN: 5,
6011
- TOUCH_DOLLY_ROTATE: 6
6012
- };
6013
- let state = STATE.NONE;
6014
- const EPS = 1e-6;
6015
- const spherical = new Spherical();
6016
- const sphericalDelta = new Spherical();
6017
- let scale = 1;
6018
- const panOffset = new Vector38();
6019
- let zoomChanged = false;
6020
- const rotateStart = new Vector23();
6021
- const rotateEnd = new Vector23();
6022
- const rotateDelta = new Vector23();
6023
- const panStart = new Vector23();
6024
- const panEnd = new Vector23();
6025
- const panDelta = new Vector23();
6026
- const dollyStart = new Vector23();
6027
- const dollyEnd = new Vector23();
6028
- const dollyDelta = new Vector23();
6029
- const pointers = [];
6030
- const pointerPositions = {};
6031
- function getAutoRotationAngle() {
6032
- return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
6033
6252
  }
6034
- function getZoomScale() {
6035
- return Math.pow(0.95, scope.zoomSpeed);
6253
+ function onTouchMove(event) {
6254
+ trackPointer(event);
6255
+ switch (state) {
6256
+ case STATE.TOUCH_ROTATE:
6257
+ if (scope.enableRotate === false) return;
6258
+ handleTouchMoveRotate(event);
6259
+ scope.update();
6260
+ break;
6261
+ case STATE.TOUCH_PAN:
6262
+ if (scope.enablePan === false) return;
6263
+ handleTouchMovePan(event);
6264
+ scope.update();
6265
+ break;
6266
+ case STATE.TOUCH_DOLLY_PAN:
6267
+ if (scope.enableZoom === false && scope.enablePan === false) return;
6268
+ handleTouchMoveDollyPan(event);
6269
+ scope.update();
6270
+ break;
6271
+ case STATE.TOUCH_DOLLY_ROTATE:
6272
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
6273
+ handleTouchMoveDollyRotate(event);
6274
+ scope.update();
6275
+ break;
6276
+ default:
6277
+ state = STATE.NONE;
6278
+ }
6036
6279
  }
6037
- function rotateLeft(angle) {
6038
- sphericalDelta.theta -= angle;
6280
+ function onTouchEnd(event) {
6281
+ handleTouchEnd(event);
6282
+ scope.dispatchEvent(_endEvent);
6283
+ state = STATE.NONE;
6039
6284
  }
6040
- function rotateUp(angle) {
6041
- sphericalDelta.phi -= angle;
6285
+ function onContextMenu(event) {
6286
+ if (scope.enabled === false) return;
6287
+ event.preventDefault();
6042
6288
  }
6043
- const panLeft = function() {
6044
- const v = new Vector38();
6045
- return function panLeft2(distance, objectMatrix) {
6046
- v.setFromMatrixColumn(objectMatrix, 0);
6047
- v.multiplyScalar(-distance);
6048
- panOffset.add(v);
6049
- };
6050
- }();
6051
- const panUp = function() {
6052
- const v = new Vector38();
6053
- return function panUp2(distance, objectMatrix) {
6054
- if (scope.screenSpacePanning === true) {
6055
- v.setFromMatrixColumn(objectMatrix, 1);
6056
- } else {
6057
- v.setFromMatrixColumn(objectMatrix, 0);
6058
- v.crossVectors(scope.object.up, v);
6059
- }
6060
- v.multiplyScalar(distance);
6061
- panOffset.add(v);
6062
- };
6063
- }();
6064
- const pan = function() {
6065
- const offset = new Vector38();
6066
- return function pan2(deltaX, deltaY) {
6067
- const element = scope.domElement;
6068
- if (scope.object.isPerspectiveCamera) {
6069
- const position = scope.object.position;
6070
- offset.copy(position).sub(scope.target);
6071
- let targetDistance = offset.length();
6072
- targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
6073
- panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
6074
- panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
6075
- } else if (scope.object.isOrthographicCamera) {
6076
- panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
6077
- panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
6078
- } else {
6079
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
6080
- scope.enablePan = false;
6289
+ function addPointer(event) {
6290
+ pointers.push(event);
6291
+ }
6292
+ function removePointer(event) {
6293
+ delete pointerPositions[event.pointerId];
6294
+ for (let i = 0; i < pointers.length; i++) {
6295
+ if (pointers[i].pointerId == event.pointerId) {
6296
+ pointers.splice(i, 1);
6297
+ return;
6081
6298
  }
6082
- };
6083
- }();
6084
- function dollyOut(dollyScale) {
6085
- if (scope.object.isPerspectiveCamera) {
6086
- scale /= dollyScale;
6087
- } else if (scope.object.isOrthographicCamera) {
6088
- scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
6089
- scope.object.updateProjectionMatrix();
6090
- zoomChanged = true;
6091
- } else {
6092
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6093
- scope.enableZoom = false;
6094
6299
  }
6095
6300
  }
6096
- function dollyIn(dollyScale) {
6097
- if (scope.object.isPerspectiveCamera) {
6098
- scale *= dollyScale;
6099
- } else if (scope.object.isOrthographicCamera) {
6100
- scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
6101
- scope.object.updateProjectionMatrix();
6102
- zoomChanged = true;
6103
- } else {
6104
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6105
- scope.enableZoom = false;
6301
+ function trackPointer(event) {
6302
+ let position = pointerPositions[event.pointerId];
6303
+ if (position === void 0) {
6304
+ position = new Vector23();
6305
+ pointerPositions[event.pointerId] = position;
6106
6306
  }
6307
+ position.set(event.pageX, event.pageY);
6308
+ }
6309
+ function getSecondPointerPosition(event) {
6310
+ const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6311
+ return pointerPositions[pointer.pointerId];
6312
+ }
6313
+ scope.domElement.addEventListener("contextmenu", onContextMenu);
6314
+ scope.domElement.addEventListener("pointerdown", onPointerDown);
6315
+ scope.domElement.addEventListener("pointercancel", onPointerCancel);
6316
+ scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6317
+ this.update();
6318
+ }
6319
+ };
6320
+ var MapControls = class extends OrbitControls {
6321
+ constructor(object, domElement) {
6322
+ super(object, domElement);
6323
+ this.screenSpacePanning = false;
6324
+ this.mouseButtons.LEFT = MOUSE.PAN;
6325
+ this.mouseButtons.RIGHT = MOUSE.ROTATE;
6326
+ this.touches.ONE = TOUCH.PAN;
6327
+ this.touches.TWO = TOUCH.DOLLY_ROTATE;
6328
+ }
6329
+ };
6330
+
6331
+ // src/renderer/Renderer.ts
6332
+ var _Renderer = class _Renderer {
6333
+ constructor(options) {
6334
+ this._dirty = true;
6335
+ this._resizeListener = void 0;
6336
+ this._disposed = false;
6337
+ this._debugHelpers = [];
6338
+ this._eventDispatchers = /* @__PURE__ */ new Map();
6339
+ this._changeListener = () => {
6340
+ this._dirty = true;
6341
+ };
6342
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6343
+ this._animationLoop = this.animate.bind(this);
6344
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6345
+ this._scene = this.createScene();
6346
+ this._camera = this.createCamera();
6347
+ this._renderer = this.createRenderer();
6348
+ this._composer = this.createComposer();
6349
+ if (this.options.render.stats) {
6350
+ this._stats = new Stats();
6351
+ document.body.appendChild(this._stats.dom);
6107
6352
  }
6108
- function handleMouseDownRotate(event) {
6109
- rotateStart.set(event.clientX, event.clientY);
6353
+ this.init();
6354
+ this._controls = this.createControls();
6355
+ }
6356
+ //<editor-fold desc="INIT">
6357
+ createScene() {
6358
+ return new MineRenderScene();
6359
+ }
6360
+ createCamera() {
6361
+ switch (this.options.camera.type) {
6362
+ case "perspective":
6363
+ default:
6364
+ return new PerspectiveCamera(
6365
+ this.options.camera.perspective.fov,
6366
+ this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6367
+ this.options.camera.near,
6368
+ this.options.camera.far
6369
+ );
6370
+ case "orthographic":
6371
+ return new OrthographicCamera(
6372
+ this.options.camera.orthographic.left ?? this.viewWidth / -2,
6373
+ this.options.camera.orthographic.right ?? this.viewWidth / 2,
6374
+ this.options.camera.orthographic.top ?? this.viewHeight / 2,
6375
+ this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
6376
+ this.options.camera.near,
6377
+ this.options.camera.far
6378
+ );
6110
6379
  }
6111
- function handleMouseDownDolly(event) {
6112
- dollyStart.set(event.clientX, event.clientY);
6380
+ }
6381
+ createRenderer() {
6382
+ const renderer = new WebGLRenderer({
6383
+ antialias: this.options.render.antialias,
6384
+ alpha: true,
6385
+ powerPreference: "high-performance",
6386
+ depth: true
6387
+ });
6388
+ renderer.setClearColor(0, 0);
6389
+ renderer.shadowMap.enabled = true;
6390
+ renderer.shadowMap.type = PCFSoftShadowMap;
6391
+ renderer.outputColorSpace = SRGBColorSpace3;
6392
+ renderer.setSize(this.viewWidth, this.viewHeight);
6393
+ return renderer;
6394
+ }
6395
+ createComposer() {
6396
+ if (!this.options.composer.enabled) return void 0;
6397
+ const composer = new EffectComposer(this.renderer);
6398
+ composer.setSize(this.viewWidth, this.viewHeight);
6399
+ composer.addPass(new RenderPass(this.scene, this.camera));
6400
+ return composer;
6401
+ }
6402
+ createControls() {
6403
+ if (!this.options.controls?.enabled) return void 0;
6404
+ const position = this.camera.position.clone();
6405
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
6406
+ this.camera.position.copy(position);
6407
+ const target = this.options.camera.lookingAt;
6408
+ if (isVector3(target)) {
6409
+ controls.target.copy(target);
6410
+ } else if (isTripleArray(target)) {
6411
+ controls.target.set(target[0], target[1], target[2]);
6412
+ }
6413
+ controls.update();
6414
+ controls.saveState();
6415
+ this.registerEventDispatcher(controls);
6416
+ return controls;
6417
+ }
6418
+ //</editor-fold>
6419
+ init() {
6420
+ if (this._disposed) return;
6421
+ if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
6422
+ window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6113
6423
  }
6114
- function handleMouseDownPan(event) {
6115
- panStart.set(event.clientX, event.clientY);
6424
+ if (this.options.debug.grid) {
6425
+ const gridHelper = new GridHelper(128, 16);
6426
+ this._debugHelpers.push(gridHelper);
6427
+ this.scene.add(gridHelper);
6428
+ const gridHelper2 = new GridHelper(128, 16);
6429
+ this._debugHelpers.push(gridHelper2);
6430
+ gridHelper2.rotation.x = 90 * (Math.PI / 180);
6431
+ this.scene.add(gridHelper2);
6432
+ const gridHelper3 = new GridHelper(128, 16);
6433
+ this._debugHelpers.push(gridHelper3);
6434
+ gridHelper3.rotation.z = 90 * (Math.PI / 180);
6435
+ this.scene.add(gridHelper3);
6116
6436
  }
6117
- function handleMouseMoveRotate(event) {
6118
- rotateEnd.set(event.clientX, event.clientY);
6119
- rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6120
- const element = scope.domElement;
6121
- rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6122
- rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6123
- rotateStart.copy(rotateEnd);
6124
- scope.update();
6437
+ if (this.options.debug.axes) {
6438
+ const axesHelper = new AxesHelper3(64);
6439
+ this._debugHelpers.push(axesHelper);
6440
+ this.scene.add(axesHelper);
6125
6441
  }
6126
- function handleMouseMoveDolly(event) {
6127
- dollyEnd.set(event.clientX, event.clientY);
6128
- dollyDelta.subVectors(dollyEnd, dollyStart);
6129
- if (dollyDelta.y > 0) {
6130
- dollyOut(getZoomScale());
6131
- } else if (dollyDelta.y < 0) {
6132
- dollyIn(getZoomScale());
6442
+ if (this.options.camera.position) {
6443
+ if (isVector3(this.options.camera.position)) {
6444
+ this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
6445
+ } else if (isTripleArray(this.options.camera.position)) {
6446
+ this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
6133
6447
  }
6134
- dollyStart.copy(dollyEnd);
6135
- scope.update();
6136
6448
  }
6137
- function handleMouseMovePan(event) {
6138
- panEnd.set(event.clientX, event.clientY);
6139
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6140
- pan(panDelta.x, panDelta.y);
6141
- panStart.copy(panEnd);
6142
- scope.update();
6143
- }
6144
- function handleMouseUp() {
6145
- }
6146
- function handleMouseWheel(event) {
6147
- if (event.deltaY < 0) {
6148
- dollyIn(getZoomScale());
6149
- } else if (event.deltaY > 0) {
6150
- dollyOut(getZoomScale());
6449
+ if (this.options.camera.lookingAt) {
6450
+ if (isVector3(this.options.camera.lookingAt)) {
6451
+ this.camera.lookAt(this.options.camera.lookingAt);
6452
+ } else if (isTripleArray(this.options.camera.lookingAt)) {
6453
+ this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6151
6454
  }
6152
- scope.update();
6153
6455
  }
6154
- function handleKeyDown(event) {
6155
- let needsUpdate = false;
6156
- switch (event.code) {
6157
- case scope.keys.UP:
6158
- pan(0, scope.keyPanSpeed);
6159
- needsUpdate = true;
6160
- break;
6161
- case scope.keys.BOTTOM:
6162
- pan(0, -scope.keyPanSpeed);
6163
- needsUpdate = true;
6164
- break;
6165
- case scope.keys.LEFT:
6166
- pan(scope.keyPanSpeed, 0);
6167
- needsUpdate = true;
6168
- break;
6169
- case scope.keys.RIGHT:
6170
- pan(-scope.keyPanSpeed, 0);
6171
- needsUpdate = true;
6172
- break;
6173
- }
6174
- if (needsUpdate) {
6175
- event.preventDefault();
6176
- scope.update();
6177
- }
6456
+ if (this.options.render.autoResize && !this._resizeListener) {
6457
+ this._resizeListener = () => {
6458
+ this.resize(this.viewWidth, this.viewHeight);
6459
+ };
6460
+ window.addEventListener("resize", this._resizeListener);
6178
6461
  }
6179
- function handleTouchStartRotate() {
6180
- if (pointers.length === 1) {
6181
- rotateStart.set(pointers[0].pageX, pointers[0].pageY);
6182
- } else {
6183
- const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6184
- const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6185
- rotateStart.set(x, y);
6186
- }
6462
+ }
6463
+ get element() {
6464
+ return this._element;
6465
+ }
6466
+ appendTo(element) {
6467
+ if (this._disposed) return;
6468
+ this._element = element;
6469
+ this._element.appendChild(this.renderer.domElement);
6470
+ if (this.viewWidth == 0) {
6471
+ console.warn("0 element width");
6187
6472
  }
6188
- function handleTouchStartPan() {
6189
- if (pointers.length === 1) {
6190
- panStart.set(pointers[0].pageX, pointers[0].pageY);
6191
- } else {
6192
- const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6193
- const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6194
- panStart.set(x, y);
6195
- }
6473
+ if (this.viewHeight == 0) {
6474
+ console.warn("0 element height");
6196
6475
  }
6197
- function handleTouchStartDolly() {
6198
- const dx = pointers[0].pageX - pointers[1].pageX;
6199
- const dy = pointers[0].pageY - pointers[1].pageY;
6200
- const distance = Math.sqrt(dx * dx + dy * dy);
6201
- dollyStart.set(0, distance);
6476
+ this.resize(this.viewWidth, this.viewHeight);
6477
+ }
6478
+ /**
6479
+ * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
6480
+ * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
6481
+ */
6482
+ registerEventDispatcher(dispatcher, changeEvent2 = "change") {
6483
+ if (this._disposed) return;
6484
+ let events = this._eventDispatchers.get(dispatcher);
6485
+ if (!events) {
6486
+ events = /* @__PURE__ */ new Set();
6487
+ this._eventDispatchers.set(dispatcher, events);
6202
6488
  }
6203
- function handleTouchStartDollyPan() {
6204
- if (scope.enableZoom) handleTouchStartDolly();
6205
- if (scope.enablePan) handleTouchStartPan();
6489
+ if (events.has(changeEvent2)) return;
6490
+ events.add(changeEvent2);
6491
+ dispatcher.addEventListener(changeEvent2, this._changeListener);
6492
+ }
6493
+ resize(width, height) {
6494
+ if (this._disposed) return;
6495
+ if (isPerspectiveCamera(this.camera)) {
6496
+ this.camera.aspect = width / height;
6497
+ this.camera.updateProjectionMatrix();
6498
+ } else if (isOrthographicCamera(this.camera)) {
6499
+ this.camera.left = width / -2;
6500
+ this.camera.right = width / 2;
6501
+ this.camera.top = height / 2;
6502
+ this.camera.bottom = height / -2;
6503
+ this.camera.updateProjectionMatrix();
6206
6504
  }
6207
- function handleTouchStartDollyRotate() {
6208
- if (scope.enableZoom) handleTouchStartDolly();
6209
- if (scope.enableRotate) handleTouchStartRotate();
6505
+ this.renderer.setSize(width, height);
6506
+ this.composer?.setSize(width, height);
6507
+ this._dirty = true;
6508
+ }
6509
+ //<editor-fold desc="RENDER">
6510
+ get dirty() {
6511
+ return this._dirty || this.scene.dirty;
6512
+ }
6513
+ set dirty(dirty) {
6514
+ this._dirty = dirty;
6515
+ this.scene.dirty = dirty;
6516
+ }
6517
+ start() {
6518
+ if (this._disposed) return;
6519
+ this.stop();
6520
+ this.renderer.setAnimationLoop(this._animationLoop);
6521
+ }
6522
+ stop() {
6523
+ if (this._disposed) return;
6524
+ this.renderer.setAnimationLoop(null);
6525
+ this._nextFrameTime = void 0;
6526
+ }
6527
+ /**
6528
+ * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
6529
+ * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
6530
+ * controls must be managed by their owners.
6531
+ */
6532
+ dispose() {
6533
+ if (this._disposed) return;
6534
+ this.stop();
6535
+ this._disposed = true;
6536
+ if (this._resizeListener) {
6537
+ window.removeEventListener("resize", this._resizeListener);
6538
+ this._resizeListener = void 0;
6210
6539
  }
6211
- function handleTouchMoveRotate(event) {
6212
- if (pointers.length == 1) {
6213
- rotateEnd.set(event.pageX, event.pageY);
6214
- } else {
6215
- const position = getSecondPointerPosition(event);
6216
- const x = 0.5 * (event.pageX + position.x);
6217
- const y = 0.5 * (event.pageY + position.y);
6218
- rotateEnd.set(x, y);
6540
+ for (const [dispatcher, events] of this._eventDispatchers) {
6541
+ for (const event of events) {
6542
+ dispatcher.removeEventListener(event, this._changeListener);
6219
6543
  }
6220
- rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6221
- const element = scope.domElement;
6222
- rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6223
- rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6224
- rotateStart.copy(rotateEnd);
6225
6544
  }
6226
- function handleTouchMovePan(event) {
6227
- if (pointers.length === 1) {
6228
- panEnd.set(event.pageX, event.pageY);
6229
- } else {
6230
- const position = getSecondPointerPosition(event);
6231
- const x = 0.5 * (event.pageX + position.x);
6232
- const y = 0.5 * (event.pageY + position.y);
6233
- panEnd.set(x, y);
6545
+ this._eventDispatchers.clear();
6546
+ this._stats?.dom.remove();
6547
+ this._stats = void 0;
6548
+ this.renderer.domElement.remove();
6549
+ this._element = void 0;
6550
+ if (this._controls) {
6551
+ const controls = this._controls;
6552
+ this._controls = void 0;
6553
+ controls.enabled = false;
6554
+ controls.dispose();
6555
+ }
6556
+ this.scene.clear();
6557
+ for (const helper of this._debugHelpers) {
6558
+ helper.geometry.dispose();
6559
+ const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
6560
+ for (const material of materials) {
6561
+ material.dispose();
6234
6562
  }
6235
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6236
- pan(panDelta.x, panDelta.y);
6237
- panStart.copy(panEnd);
6238
6563
  }
6239
- function handleTouchMoveDolly(event) {
6240
- const position = getSecondPointerPosition(event);
6241
- const dx = event.pageX - position.x;
6242
- const dy = event.pageY - position.y;
6243
- const distance = Math.sqrt(dx * dx + dy * dy);
6244
- dollyEnd.set(0, distance);
6245
- dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
6246
- dollyOut(dollyDelta.y);
6247
- dollyStart.copy(dollyEnd);
6564
+ this._debugHelpers.length = 0;
6565
+ this.composer?.dispose();
6566
+ this.renderer.dispose();
6567
+ this.renderer.forceContextLoss();
6568
+ }
6569
+ animate(t = performance.now()) {
6570
+ if (this._disposed) return;
6571
+ if (this._controls?.enabled) {
6572
+ this._controls.update();
6248
6573
  }
6249
- function handleTouchMoveDollyPan(event) {
6250
- if (scope.enableZoom) handleTouchMoveDolly(event);
6251
- if (scope.enablePan) handleTouchMovePan(event);
6574
+ if (this._disposed) return;
6575
+ if (!this.dirty && !this.options.render.renderAlways) return;
6576
+ const interval = this._frameInterval;
6577
+ if (interval) {
6578
+ const next = this._nextFrameTime;
6579
+ if (next !== void 0 && t + 0.1 < next) return;
6580
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6252
6581
  }
6253
- function handleTouchMoveDollyRotate(event) {
6254
- if (scope.enableZoom) handleTouchMoveDolly(event);
6255
- if (scope.enableRotate) handleTouchMoveRotate(event);
6582
+ if (this._stats) {
6583
+ this._stats.begin();
6256
6584
  }
6257
- function handleTouchEnd() {
6585
+ if (this.options.composer.enabled && this.composer) {
6586
+ this.composer.render();
6587
+ } else {
6588
+ this.renderer.render(this.scene, this.camera);
6258
6589
  }
6259
- function onPointerDown(event) {
6260
- if (scope.enabled === false) return;
6261
- if (pointers.length === 0) {
6262
- scope.domElement.setPointerCapture(event.pointerId);
6263
- scope.domElement.addEventListener("pointermove", onPointerMove);
6264
- scope.domElement.addEventListener("pointerup", onPointerUp);
6265
- }
6266
- addPointer(event);
6267
- if (event.pointerType === "touch") {
6268
- onTouchStart(event);
6269
- } else {
6270
- onMouseDown(event);
6271
- }
6590
+ this.dirty = false;
6591
+ if (this._stats) {
6592
+ this._stats.end();
6272
6593
  }
6273
- function onPointerMove(event) {
6274
- if (scope.enabled === false) return;
6275
- if (event.pointerType === "touch") {
6276
- onTouchMove(event);
6277
- } else {
6278
- onMouseMove(event);
6279
- }
6594
+ }
6595
+ //</editor-fold>
6596
+ toImage() {
6597
+ return this.renderer.domElement.toDataURL();
6598
+ }
6599
+ ///
6600
+ get attachedToBody() {
6601
+ return this.element === document.body;
6602
+ }
6603
+ get viewWidth() {
6604
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6605
+ }
6606
+ get viewHeight() {
6607
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6608
+ }
6609
+ get scene() {
6610
+ return this._scene;
6611
+ }
6612
+ get camera() {
6613
+ return this._camera;
6614
+ }
6615
+ get renderer() {
6616
+ return this._renderer;
6617
+ }
6618
+ get composer() {
6619
+ return this._composer;
6620
+ }
6621
+ /** Renderer-owned controls, or undefined when disabled at construction or after disposal. */
6622
+ get controls() {
6623
+ return this._controls;
6624
+ }
6625
+ ///
6626
+ };
6627
+ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6628
+ camera: {
6629
+ type: "perspective",
6630
+ near: 1,
6631
+ far: 5e3,
6632
+ perspective: {
6633
+ aspect: void 0,
6634
+ fov: 50
6635
+ },
6636
+ orthographic: {
6637
+ left: void 0,
6638
+ right: void 0,
6639
+ top: void 0,
6640
+ bottom: void 0
6641
+ },
6642
+ position: new Vector39(50, 50, 50),
6643
+ lookingAt: new Vector39(0, 0, 0)
6644
+ },
6645
+ render: {
6646
+ fpsLimit: 60,
6647
+ stats: false,
6648
+ antialias: true,
6649
+ shade: true,
6650
+ autoResize: true,
6651
+ renderAlways: false
6652
+ },
6653
+ composer: {
6654
+ enabled: true
6655
+ },
6656
+ controls: {
6657
+ enabled: false
6658
+ },
6659
+ debug: {
6660
+ grid: false,
6661
+ axes: false
6662
+ }
6663
+ });
6664
+ var Renderer = _Renderer;
6665
+
6666
+ // src/skin/Skins.ts
6667
+ var Skins = class {
6668
+ //<editor-fold desc="Skins">
6669
+ static async fromUuidOrUsername(uuidOrUsername) {
6670
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6671
+ return this.fromUuid(uuidOrUsername);
6280
6672
  }
6281
- function onPointerUp(event) {
6282
- if (scope.enabled === false) return;
6283
- if (event.pointerType === "touch") {
6284
- onTouchEnd();
6285
- } else {
6286
- onMouseUp(event);
6673
+ return this.fromUsername(uuidOrUsername);
6674
+ }
6675
+ static async fromUuid(uuid) {
6676
+ return this.getMcProxySkinUrl(uuid);
6677
+ }
6678
+ static async fromUsername(username) {
6679
+ return this.usernameToUuid(username).then((uuid) => {
6680
+ if (uuid) {
6681
+ return this.fromUuid(uuid);
6287
6682
  }
6288
- removePointer(event);
6289
- if (pointers.length === 0) {
6290
- scope.domElement.releasePointerCapture(event.pointerId);
6291
- scope.domElement.removeEventListener("pointermove", onPointerMove);
6292
- scope.domElement.removeEventListener("pointerup", onPointerUp);
6683
+ return void 0;
6684
+ });
6685
+ }
6686
+ static async fromMineSkin(mineskinId) {
6687
+ return this.getMineSkin(mineskinId).then((mineskin) => {
6688
+ if (mineskin) {
6689
+ return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6293
6690
  }
6691
+ return void 0;
6692
+ });
6693
+ }
6694
+ //</editor-fold>
6695
+ //<editor-fold desc="Capes">
6696
+ static async capeFromUuidOrUsername(uuidOrUsername) {
6697
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6698
+ return this.capeFromUuid(uuidOrUsername);
6294
6699
  }
6295
- function onPointerCancel(event) {
6296
- removePointer(event);
6297
- }
6298
- function onMouseDown(event) {
6299
- let mouseAction;
6300
- switch (event.button) {
6301
- case 0:
6302
- mouseAction = scope.mouseButtons.LEFT;
6303
- break;
6304
- case 1:
6305
- mouseAction = scope.mouseButtons.MIDDLE;
6306
- break;
6307
- case 2:
6308
- mouseAction = scope.mouseButtons.RIGHT;
6309
- break;
6310
- default:
6311
- mouseAction = -1;
6312
- }
6313
- switch (mouseAction) {
6314
- case MOUSE.DOLLY:
6315
- if (scope.enableZoom === false) return;
6316
- handleMouseDownDolly(event);
6317
- state = STATE.DOLLY;
6318
- break;
6319
- case MOUSE.ROTATE:
6320
- if (event.ctrlKey || event.metaKey || event.shiftKey) {
6321
- if (scope.enablePan === false) return;
6322
- handleMouseDownPan(event);
6323
- state = STATE.PAN;
6324
- } else {
6325
- if (scope.enableRotate === false) return;
6326
- handleMouseDownRotate(event);
6327
- state = STATE.ROTATE;
6328
- }
6329
- break;
6330
- case MOUSE.PAN:
6331
- if (event.ctrlKey || event.metaKey || event.shiftKey) {
6332
- if (scope.enableRotate === false) return;
6333
- handleMouseDownRotate(event);
6334
- state = STATE.ROTATE;
6335
- } else {
6336
- if (scope.enablePan === false) return;
6337
- handleMouseDownPan(event);
6338
- state = STATE.PAN;
6339
- }
6340
- break;
6341
- default:
6342
- state = STATE.NONE;
6700
+ return this.capeFromUsername(uuidOrUsername);
6701
+ }
6702
+ static async capeFromUuid(uuid) {
6703
+ return this.getMcProxyCapeUrl(uuid);
6704
+ }
6705
+ static async capeFromUsername(username) {
6706
+ return this.usernameToUuid(username).then((uuid) => {
6707
+ if (uuid) {
6708
+ return this.capeFromUuid(uuid);
6343
6709
  }
6344
- if (state !== STATE.NONE) {
6345
- scope.dispatchEvent(_startEvent);
6710
+ return void 0;
6711
+ });
6712
+ }
6713
+ static async capeFromCapesDev(uuid, capeType = "minecraft") {
6714
+ return this.getCapesDev(uuid, capeType).then((cape) => {
6715
+ if (cape) {
6716
+ return cape?.stillImageUrl;
6346
6717
  }
6347
- }
6348
- function onMouseMove(event) {
6349
- if (scope.enabled === false) return;
6350
- switch (state) {
6351
- case STATE.ROTATE:
6352
- if (scope.enableRotate === false) return;
6353
- handleMouseMoveRotate(event);
6354
- break;
6355
- case STATE.DOLLY:
6356
- if (scope.enableZoom === false) return;
6357
- handleMouseMoveDolly(event);
6358
- break;
6359
- case STATE.PAN:
6360
- if (scope.enablePan === false) return;
6361
- handleMouseMovePan(event);
6362
- break;
6718
+ return void 0;
6719
+ });
6720
+ }
6721
+ //</editor-fold>
6722
+ //<editor-fold desc="Helpers">
6723
+ static async usernameToUuid(username) {
6724
+ return this.usernameToUuidMcProxy(username);
6725
+ }
6726
+ static async usernameToUuidMcProxy(username) {
6727
+ return Requests.genericRequest({
6728
+ baseURL: "https://mcproxy.dev",
6729
+ url: "/uuid/" + username
6730
+ }).then((res) => {
6731
+ if (res.status === 200) {
6732
+ return res.data["data"]["id"];
6363
6733
  }
6364
- }
6365
- function onMouseUp(event) {
6366
- handleMouseUp(event);
6367
- scope.dispatchEvent(_endEvent);
6368
- state = STATE.NONE;
6369
- }
6370
- function onMouseWheel(event) {
6371
- if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE) return;
6372
- event.preventDefault();
6373
- scope.dispatchEvent(_startEvent);
6374
- handleMouseWheel(event);
6375
- scope.dispatchEvent(_endEvent);
6376
- }
6377
- function onKeyDown(event) {
6378
- if (scope.enabled === false || scope.enablePan === false) return;
6379
- handleKeyDown(event);
6380
- }
6381
- function onTouchStart(event) {
6382
- trackPointer(event);
6383
- switch (pointers.length) {
6384
- case 1:
6385
- switch (scope.touches.ONE) {
6386
- case TOUCH.ROTATE:
6387
- if (scope.enableRotate === false) return;
6388
- handleTouchStartRotate();
6389
- state = STATE.TOUCH_ROTATE;
6390
- break;
6391
- case TOUCH.PAN:
6392
- if (scope.enablePan === false) return;
6393
- handleTouchStartPan();
6394
- state = STATE.TOUCH_PAN;
6395
- break;
6396
- default:
6397
- state = STATE.NONE;
6398
- }
6399
- break;
6400
- case 2:
6401
- switch (scope.touches.TWO) {
6402
- case TOUCH.DOLLY_PAN:
6403
- if (scope.enableZoom === false && scope.enablePan === false) return;
6404
- handleTouchStartDollyPan();
6405
- state = STATE.TOUCH_DOLLY_PAN;
6406
- break;
6407
- case TOUCH.DOLLY_ROTATE:
6408
- if (scope.enableZoom === false && scope.enableRotate === false) return;
6409
- handleTouchStartDollyRotate();
6410
- state = STATE.TOUCH_DOLLY_ROTATE;
6411
- break;
6412
- default:
6413
- state = STATE.NONE;
6414
- }
6415
- break;
6416
- default:
6417
- state = STATE.NONE;
6734
+ return void 0;
6735
+ }).catch((err) => {
6736
+ console.warn(err);
6737
+ return void 0;
6738
+ });
6739
+ }
6740
+ /** @deprecated **/
6741
+ static async usernameToUuidSkinProxy(username) {
6742
+ return Requests.genericRequest({
6743
+ baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
6744
+ url: "/uuid/" + username
6745
+ }).then((res) => {
6746
+ if (res.status === 200) {
6747
+ return res.data["id"];
6418
6748
  }
6419
- if (state !== STATE.NONE) {
6420
- scope.dispatchEvent(_startEvent);
6749
+ return void 0;
6750
+ }).catch((err) => {
6751
+ console.warn(err);
6752
+ return void 0;
6753
+ });
6754
+ }
6755
+ static async usernameToUuidMineTools(username) {
6756
+ return Requests.genericRequest({
6757
+ baseURL: "https://api.minetools.eu",
6758
+ url: "/uuid/" + username
6759
+ }).then((res) => {
6760
+ if (res.status === 200) {
6761
+ return res.data["id"];
6421
6762
  }
6422
- }
6423
- function onTouchMove(event) {
6424
- trackPointer(event);
6425
- switch (state) {
6426
- case STATE.TOUCH_ROTATE:
6427
- if (scope.enableRotate === false) return;
6428
- handleTouchMoveRotate(event);
6429
- scope.update();
6430
- break;
6431
- case STATE.TOUCH_PAN:
6432
- if (scope.enablePan === false) return;
6433
- handleTouchMovePan(event);
6434
- scope.update();
6435
- break;
6436
- case STATE.TOUCH_DOLLY_PAN:
6437
- if (scope.enableZoom === false && scope.enablePan === false) return;
6438
- handleTouchMoveDollyPan(event);
6439
- scope.update();
6440
- break;
6441
- case STATE.TOUCH_DOLLY_ROTATE:
6442
- if (scope.enableZoom === false && scope.enableRotate === false) return;
6443
- handleTouchMoveDollyRotate(event);
6444
- scope.update();
6445
- break;
6446
- default:
6447
- state = STATE.NONE;
6763
+ return void 0;
6764
+ }).catch((err) => {
6765
+ console.warn(err);
6766
+ return void 0;
6767
+ });
6768
+ }
6769
+ static async getProfileFromMinetools(uuid) {
6770
+ return Requests.genericRequest({
6771
+ baseURL: "https://api.minetools.eu",
6772
+ url: "/profile/" + uuid
6773
+ }).then((res) => {
6774
+ if (res.status === 200) {
6775
+ return res.data;
6448
6776
  }
6449
- }
6450
- function onTouchEnd(event) {
6451
- handleTouchEnd(event);
6452
- scope.dispatchEvent(_endEvent);
6453
- state = STATE.NONE;
6454
- }
6455
- function onContextMenu(event) {
6456
- if (scope.enabled === false) return;
6457
- event.preventDefault();
6458
- }
6459
- function addPointer(event) {
6460
- pointers.push(event);
6461
- }
6462
- function removePointer(event) {
6463
- delete pointerPositions[event.pointerId];
6464
- for (let i = 0; i < pointers.length; i++) {
6465
- if (pointers[i].pointerId == event.pointerId) {
6466
- pointers.splice(i, 1);
6467
- return;
6468
- }
6777
+ });
6778
+ }
6779
+ static async getMineSkin(mineskinId) {
6780
+ return Requests.genericRequest({
6781
+ baseURL: "https://api.mineskin.org",
6782
+ url: "/get/uuid/" + mineskinId
6783
+ }).then((res) => {
6784
+ if (res.status === 200) {
6785
+ return res.data;
6469
6786
  }
6470
- }
6471
- function trackPointer(event) {
6472
- let position = pointerPositions[event.pointerId];
6473
- if (position === void 0) {
6474
- position = new Vector23();
6475
- pointerPositions[event.pointerId] = position;
6787
+ return void 0;
6788
+ }).catch((err) => {
6789
+ console.warn(err);
6790
+ return void 0;
6791
+ });
6792
+ }
6793
+ static async getCapesDev(uuid, type = "all") {
6794
+ return Requests.genericRequest({
6795
+ baseURL: "https://api.capes.dev",
6796
+ url: "/load/" + uuid + "/" + type
6797
+ }).then((res) => {
6798
+ if (res.status === 200) {
6799
+ return res.data;
6476
6800
  }
6477
- position.set(event.pageX, event.pageY);
6478
- }
6479
- function getSecondPointerPosition(event) {
6480
- const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6481
- return pointerPositions[pointer.pointerId];
6482
- }
6483
- scope.domElement.addEventListener("contextmenu", onContextMenu);
6484
- scope.domElement.addEventListener("pointerdown", onPointerDown);
6485
- scope.domElement.addEventListener("pointercancel", onPointerCancel);
6486
- scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6487
- this.update();
6801
+ return void 0;
6802
+ }).catch((err) => {
6803
+ console.warn(err);
6804
+ return void 0;
6805
+ });
6488
6806
  }
6489
- };
6490
- var MapControls = class extends OrbitControls {
6491
- constructor(object, domElement) {
6492
- super(object, domElement);
6493
- this.screenSpacePanning = false;
6494
- this.mouseButtons.LEFT = MOUSE.PAN;
6495
- this.mouseButtons.RIGHT = MOUSE.ROTATE;
6496
- this.touches.ONE = TOUCH.PAN;
6497
- this.touches.TWO = TOUCH.DOLLY_ROTATE;
6807
+ static getCrafatarSkinUrl(uuid) {
6808
+ return "https://crafatar.com/skins/" + uuid;
6809
+ }
6810
+ static getCrafatarCapeUrl(uuid) {
6811
+ return "https://crafatar.com/capes/" + uuid;
6812
+ }
6813
+ static getMcHeadsSkinUrl(uuid) {
6814
+ return "https://mc-heads.net/skin/" + uuid;
6815
+ }
6816
+ static getMineSkinPlayerSkinUrl(uuid) {
6817
+ return "https://mineskin.org/skin/player/" + uuid;
6818
+ }
6819
+ /** @deprecated **/
6820
+ static getSkinProxySkinUrl(uuid) {
6821
+ return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6822
+ }
6823
+ /** @deprecated **/
6824
+ static getSkinProxyCapeUrl(uuid) {
6825
+ return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6826
+ }
6827
+ static getMcProxySkinUrl(uuid) {
6828
+ return "https://mcproxy.dev/skin/" + uuid;
6498
6829
  }
6830
+ static getMcProxyCapeUrl(uuid) {
6831
+ return "https://mcproxy.dev/cape/" + uuid;
6832
+ }
6833
+ //</editor-fold>
6499
6834
  };
6500
6835
 
6501
6836
  // src/world/Chunk.ts
6502
- import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector310 } from "three";
6837
+ import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector311 } from "three";
6503
6838
 
6504
6839
  // src/world/MineRenderWorld.ts
6505
- import { Vector3 as Vector39 } from "three";
6840
+ import { Vector3 as Vector310 } from "three";
6506
6841
  var MineRenderWorld = class {
6507
6842
  constructor(scene) {
6508
6843
  this._size = 4;
@@ -6513,10 +6848,10 @@ var MineRenderWorld = class {
6513
6848
  }
6514
6849
  getBlockAt(posOrX, y, z) {
6515
6850
  if (typeof posOrX == "number") {
6516
- return this.getBlockAt(new Vector39(posOrX, y, z));
6851
+ return this.getBlockAt(new Vector310(posOrX, y, z));
6517
6852
  }
6518
6853
  if (isTripleArray(posOrX)) {
6519
- return this.getBlockAt(new Vector39(posOrX[0], posOrX[1], posOrX[2]));
6854
+ return this.getBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]));
6520
6855
  }
6521
6856
  const chunk = this.getChunkAt(posOrX);
6522
6857
  if (typeof chunk === "undefined") {
@@ -6527,10 +6862,10 @@ var MineRenderWorld = class {
6527
6862
  }
6528
6863
  async setBlockAt(posOrX, yOrBlock, z, block) {
6529
6864
  if (typeof posOrX == "number") {
6530
- return this.setBlockAt(new Vector39(posOrX, yOrBlock, z), block);
6865
+ return this.setBlockAt(new Vector310(posOrX, yOrBlock, z), block);
6531
6866
  }
6532
6867
  if (isTripleArray(posOrX)) {
6533
- return this.setBlockAt(new Vector39(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6868
+ return this.setBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6534
6869
  }
6535
6870
  this.validatePosBounds(posOrX);
6536
6871
  const chunk = this.getOrCreateChunkAt(posOrX);
@@ -6576,14 +6911,14 @@ var MineRenderWorld = class {
6576
6911
  return this._chunks[index];
6577
6912
  }
6578
6913
  static worldToScenePosition(pos) {
6579
- return new Vector39(
6914
+ return new Vector310(
6580
6915
  pos.x * 16,
6581
6916
  pos.y * 16,
6582
6917
  pos.z * 16
6583
6918
  );
6584
6919
  }
6585
6920
  static sceneToWorldPosition(pos) {
6586
- return new Vector39(
6921
+ return new Vector310(
6587
6922
  pos.x / 16,
6588
6923
  pos.y / 16,
6589
6924
  pos.z / 16
@@ -6612,7 +6947,7 @@ var MineRenderWorld = class {
6612
6947
  };
6613
6948
 
6614
6949
  // src/world/Chunk.ts
6615
- var p12 = prefix("Chunk");
6950
+ var p11 = prefix("Chunk");
6616
6951
  var Chunk = class _Chunk {
6617
6952
  constructor(scene, x, y, z) {
6618
6953
  this._blocks = [];
@@ -6625,7 +6960,7 @@ var Chunk = class _Chunk {
6625
6960
  scene.add(anchor);
6626
6961
  anchor.position.set(this.x * 256 + 128 - 8, this.y * 256 + 128 - 8, this.z * 256 + 128 - 8);
6627
6962
  addBox3WireframeToObject(
6628
- new Box32(new Vector310(0, 0, 0), new Vector310(256, 256, 256)),
6963
+ new Box32(new Vector311(0, 0, 0), new Vector311(256, 256, 256)),
6629
6964
  anchor,
6630
6965
  16776960,
6631
6966
  4
@@ -6633,10 +6968,10 @@ var Chunk = class _Chunk {
6633
6968
  }
6634
6969
  getBlockAt(posOrX, y, z) {
6635
6970
  if (typeof posOrX == "number") {
6636
- return this.getBlockAt(new Vector310(posOrX, y, z));
6971
+ return this.getBlockAt(new Vector311(posOrX, y, z));
6637
6972
  }
6638
6973
  if (isTripleArray(posOrX)) {
6639
- return this.getBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]));
6974
+ return this.getBlockAt(new Vector311(posOrX[0], posOrX[1], posOrX[2]));
6640
6975
  }
6641
6976
  const pos = this.worldPosToChunkPos(posOrX);
6642
6977
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -6644,10 +6979,10 @@ var Chunk = class _Chunk {
6644
6979
  }
6645
6980
  async setBlockAt(posOrX, yOrBlock, z, block) {
6646
6981
  if (typeof posOrX == "number") {
6647
- return this.setBlockAt(new Vector310(posOrX, yOrBlock, z), block);
6982
+ return this.setBlockAt(new Vector311(posOrX, yOrBlock, z), block);
6648
6983
  }
6649
6984
  if (isTripleArray(posOrX)) {
6650
- return this.setBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6985
+ return this.setBlockAt(new Vector311(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6651
6986
  }
6652
6987
  const worldPos = posOrX;
6653
6988
  const pos = this.worldPosToChunkPos(worldPos);
@@ -6664,7 +6999,7 @@ var Chunk = class _Chunk {
6664
6999
  const index = _Chunk.chunkPosToBlockIndex(pos);
6665
7000
  const current = this._blocks[index];
6666
7001
  if (typeof current !== "undefined") {
6667
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
7002
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6668
7003
  current.object.removeFromScene();
6669
7004
  delete this._blocks[index];
6670
7005
  }
@@ -6693,7 +7028,7 @@ var Chunk = class _Chunk {
6693
7028
  }
6694
7029
  async clear() {
6695
7030
  let promises = [];
6696
- let pos = new Vector310();
7031
+ let pos = new Vector311();
6697
7032
  for (let x = 0; x < 16; x++) {
6698
7033
  for (let z = 0; z < 16; z++) {
6699
7034
  for (let y = 0; y < 16; y++) {
@@ -6712,14 +7047,14 @@ var Chunk = class _Chunk {
6712
7047
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
6713
7048
  }
6714
7049
  worldPosToChunkPos(pos) {
6715
- return new Vector310(
7050
+ return new Vector311(
6716
7051
  pos.x - this.x * 16,
6717
7052
  pos.y - this.y * 16,
6718
7053
  pos.z - this.z * 16
6719
7054
  );
6720
7055
  }
6721
7056
  chunkPosToWorldPos(pos) {
6722
- return new Vector310(
7057
+ return new Vector311(
6723
7058
  this.x * 16 + pos.x,
6724
7059
  this.y * 16 + pos.y,
6725
7060
  this.z * 16 + pos.z
@@ -6730,6 +7065,7 @@ export {
6730
7065
  AXES,
6731
7066
  ArchiveAssetSource,
6732
7067
  AssetKey,
7068
+ AssetLoadError,
6733
7069
  AssetLoader,
6734
7070
  AssetParser,
6735
7071
  AssetSource,
@@ -6742,6 +7078,7 @@ export {
6742
7078
  BlockEntityModels,
6743
7079
  BlockObject,
6744
7080
  BlockStates,
7081
+ BlockTints,
6745
7082
  BrowserArchiveProxy,
6746
7083
  BrowserCache,
6747
7084
  BrowserEnv,
@@ -6787,6 +7124,7 @@ export {
6787
7124
  OrbitControls,
6788
7125
  PersistentCache,
6789
7126
  Renderer,
7127
+ RequestError,
6790
7128
  Requests,
6791
7129
  SKIN_PARTS,
6792
7130
  SceneInspector,