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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,10 @@ 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.entityModelsCache
414
416
  ];
415
417
  }
416
418
  static clear() {
@@ -421,8 +423,8 @@ var Caching = class {
421
423
  /**
422
424
  * Clears every cache and stops its expiry timer.
423
425
  *
424
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
425
- * this is called - see {@link shutdown}.
426
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
427
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
426
428
  */
427
429
  static end() {
428
430
  for (const cache of this.all) {
@@ -436,20 +438,24 @@ var Caching = class {
436
438
  };
437
439
  }
438
440
  };
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();
441
+ _Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
442
+ _Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
443
+ _Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
444
+ _Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
445
+ _Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
446
+ _Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
447
+ _Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
448
+ _Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
449
+ _Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
450
+ _Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
451
+ _Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
452
+ _Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
453
+ _Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
454
+ _Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
455
+ _Caching.listAssetCache = _Caching.createAssetCache();
456
+ _Caching.defaultBlockStatesCache = _Caching.createAssetCache();
457
+ _Caching.entityModelsCache = _Caching.createAssetCache();
458
+ var Caching = _Caching;
453
459
 
454
460
  // src/Geometries.ts
455
461
  var Geometries = class _Geometries {
@@ -477,6 +483,7 @@ import { CanvasTexture, Texture as Texture2 } from "three";
477
483
 
478
484
  // src/texture/TextureLoader.ts
479
485
  import { RGBAFormat, Texture } from "three";
486
+ import * as THREE from "three";
480
487
 
481
488
  // src/canvas/CanvasCompat.ts
482
489
  function createImage(width, height) {
@@ -487,9 +494,7 @@ function createCanvas(width, height) {
487
494
  }
488
495
 
489
496
  // src/request/Requests.ts
490
- import axios from "axios";
491
- import { JobQueue } from "jobqu";
492
- import { Time as Time2 } from "@inventivetalent/time";
497
+ import { JobCancelledError, JobQueue } from "jobqu";
493
498
 
494
499
  // src/util/log.ts
495
500
  var Reset = "\x1B[0m";
@@ -499,198 +504,170 @@ function prefix(prefix2) {
499
504
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
500
505
  }
501
506
 
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();
507
+ // src/request/Requests.ts
508
+ var p = prefix("Requests");
509
+ var RequestError = class extends Error {
510
+ constructor(message, response, cause) {
511
+ super(message);
512
+ this.response = response;
513
+ this.cause = cause;
514
+ this.name = "RequestError";
521
515
  }
522
516
  };
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);
517
+ async function fetchRequest(config, defaultBaseURL) {
518
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
519
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
520
+ const headers = new Headers(options.headers);
521
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
522
+ headers.set("User-Agent", "MineRender");
523
+ }
524
+ const attemptSignal = AbortSignal.any([
525
+ ...signal ? [signal] : [],
526
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
527
+ ]);
528
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
529
+ attemptSignal.throwIfAborted();
530
+ try {
531
+ const response = await fetch(request);
532
+ const result = {
533
+ data: void 0,
534
+ status: response.status,
535
+ statusText: response.statusText,
536
+ headers: response.headers,
537
+ url: response.url
538
+ };
539
+ if (!response.ok) {
540
+ await response.body?.cancel().catch(() => {
541
+ });
542
+ throw new RequestError(`Request failed with status ${response.status}`, result);
543
+ }
544
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
545
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
546
+ return { ...result, data };
547
+ } catch (error) {
548
+ attemptSignal.throwIfAborted();
549
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
550
+ throw new RequestError("Network request failed", void 0, error);
547
551
  }
552
+ throw error;
548
553
  }
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
554
  }
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;
555
+ async function abortable(promise, signal) {
556
+ if (!signal) return promise;
557
+ let abort;
558
+ const cancelled = new Promise((_, reject) => {
559
+ abort = () => reject(signal.reason);
560
+ signal.addEventListener("abort", abort, { once: true });
561
+ if (signal.aborted) abort();
562
+ });
563
+ try {
564
+ return await Promise.race([promise, cancelled]);
565
+ } finally {
566
+ signal.removeEventListener("abort", abort);
570
567
  }
571
568
  }
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
- });
569
+ var RequestQueue = class {
570
+ constructor() {
571
+ this.pendingRequests = 0;
572
+ this.stopped = new AbortController();
573
+ this.queue = new JobQueue(
574
+ (request) => fetchRequest(request, this.baseURL),
575
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
576
+ );
650
577
  }
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;
578
+ async request(request) {
579
+ this.pendingRequests++;
580
+ const signal = request.signal;
581
+ try {
582
+ for (let retries = 0; ; retries++) {
583
+ signal?.throwIfAborted();
584
+ try {
585
+ return await abortable(this.queue.add(request), signal);
586
+ } catch (error) {
587
+ console.debug(p, "Request failed", error);
588
+ const delay = this.retryDelay(error, request, retries);
589
+ if (delay === void 0) {
590
+ throw error;
658
591
  }
659
- } else {
660
- request["minerenderRetry"] = 3;
661
- return true;
592
+ await this.waitForRetry(delay, signal);
662
593
  }
663
594
  }
595
+ } finally {
596
+ if (signal?.aborted) {
597
+ this.queue.remove(request);
598
+ }
599
+ this.pendingRequests--;
664
600
  }
665
- return false;
601
+ }
602
+ retryDelay(error, request, retries) {
603
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
604
+ return void 0;
605
+ }
606
+ if (error instanceof RequestError) {
607
+ const status = error.response?.status;
608
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
609
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
610
+ return void 0;
611
+ }
612
+ let delay = 100 * 2 ** retries;
613
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
614
+ if (retryAfter !== void 0 && retryAfter !== null) {
615
+ const seconds = Number(retryAfter);
616
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
617
+ return void 0;
618
+ }
619
+ delay = Math.max(delay, seconds * 1e3);
620
+ }
621
+ return delay;
622
+ }
623
+ async waitForRetry(delay, signal) {
624
+ let timer;
625
+ const waiting = new Promise((resolve) => {
626
+ timer = setTimeout(resolve, delay);
627
+ });
628
+ try {
629
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
630
+ } finally {
631
+ clearTimeout(timer);
632
+ }
633
+ }
634
+ get pendingSize() {
635
+ return this.pendingRequests;
636
+ }
637
+ end() {
638
+ this.queue.end();
639
+ this.stopped.abort(new JobCancelledError("ended"));
640
+ }
641
+ };
642
+ var Requests = class {
643
+ static genericRequest(request) {
644
+ return this.genericQueue.request(request);
645
+ }
646
+ static mcAssetRequest(request) {
647
+ return this.mcAssetRequestQueue.request(request);
666
648
  }
667
649
  static setMcAssetRoot(root) {
668
- this.mcAssetInstance.defaults.baseURL = root;
650
+ this.mcAssetRequestQueue.baseURL = root;
669
651
  }
652
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
670
653
  static get queueSizes() {
671
654
  return {
672
- generic: this.genericQueue.size,
673
- mcAsset: this.mcAssetRequestQueue.size
655
+ generic: this.genericQueue.pendingSize,
656
+ mcAsset: this.mcAssetRequestQueue.pendingSize
674
657
  };
675
658
  }
676
659
  /**
677
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
678
- * exit until this is called - see {@link shutdown}.
660
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
661
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
662
+ * this cleanup. See {@link shutdown}.
679
663
  */
680
664
  static end() {
681
665
  this.genericQueue.end();
682
666
  this.mcAssetRequestQueue.end();
683
667
  }
684
668
  };
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;
669
+ Requests.genericQueue = new RequestQueue();
670
+ Requests.mcAssetRequestQueue = new RequestQueue();
694
671
 
695
672
  // src/WrappedImage.ts
696
673
  var WrappedImage = class {
@@ -728,10 +705,10 @@ var WrappedImage = class {
728
705
  return this.animated ? this.width : this.height;
729
706
  }
730
707
  get frameCount() {
731
- return this.height / this.width;
708
+ return this.height / this.frameHeight;
732
709
  }
733
710
  getFrameY(frame) {
734
- return this.height / this.frameCount * Math.max(0, Math.min(this.frameCount, frame));
711
+ return this.frameHeight * Math.max(0, Math.min(this.frameCount - 1, frame));
735
712
  }
736
713
  getSectionData(sx, sy, sw, sh) {
737
714
  return this.dta.data.getImageData(sx, sy, sw, sh);
@@ -741,7 +718,7 @@ var WrappedImage = class {
741
718
  }
742
719
  getFrameSectionData(frame) {
743
720
  const y = this.getFrameY(frame);
744
- return this.getSectionData(0, y, this.width, this.width + y);
721
+ return this.getSectionData(0, y, this.frameWidth, this.frameHeight);
745
722
  }
746
723
  };
747
724
 
@@ -755,29 +732,41 @@ var ImageLoader = class _ImageLoader {
755
732
  static async loadAsync(src) {
756
733
  return new Promise((resolve, reject) => {
757
734
  const image = this._createImage();
758
- image.src = src;
759
735
  image.onload = () => resolve(image);
760
- image.onerror = (err) => reject(err);
736
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
737
+ image.src = src;
761
738
  });
762
739
  }
763
740
  static loadElement(src, onload, onerr) {
764
741
  const image = this._createImage();
765
- image.src = src;
766
742
  if (onload)
767
743
  image.onload = onload;
768
744
  if (onerr)
769
745
  image.onerror = onerr;
746
+ image.src = src;
770
747
  return image;
771
748
  }
772
749
  static async loadData(src) {
773
750
  console.debug(p2, "loadData", src);
774
- return await this.infoToData(await this.getInfo(src));
751
+ const image = await this.loadCanvasData(src);
752
+ return image.data.getImageData(0, 0, image.width, image.height);
775
753
  }
776
754
  static async loadCanvasData(src) {
777
- return await this.infoToCanvasData(await this.getInfo(src));
755
+ const keyStr = serializeImageKey({ src });
756
+ const info = this.getInfo(src);
757
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
758
+ try {
759
+ return await this.infoToCanvasData(await info);
760
+ } catch (err) {
761
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
762
+ Caching.rawImageCache.invalidate(keyStr);
763
+ }
764
+ throw err;
765
+ }
778
766
  }
779
767
  static async infoToCanvasData(info) {
780
- const image = await _ImageLoader.loadAsync(info.src);
768
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
769
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
781
770
  const canvas = createCanvas(info.width, info.height);
782
771
  const context = canvas.getContext("2d");
783
772
  context.drawImage(image, 0, 0);
@@ -788,11 +777,8 @@ var ImageLoader = class _ImageLoader {
788
777
  };
789
778
  }
790
779
  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);
780
+ const image = await this.infoToCanvasData(info);
781
+ return image.data.getImageData(0, 0, image.width, image.height);
796
782
  }
797
783
  static async getData(src) {
798
784
  const keyStr = serializeImageKey({ src });
@@ -807,38 +793,25 @@ var ImageLoader = class _ImageLoader {
807
793
  });
808
794
  }
809
795
  static async processResponse(response) {
810
- const src = response.config.url;
796
+ const src = response.url;
811
797
  const data = Buffer2.from(response.data);
812
798
  const { width, height, type } = Env.provider.imageSize(data);
799
+ if (!width || !height) {
800
+ throw new Error("Invalid or unsupported image dimensions");
801
+ }
813
802
  return {
814
803
  src,
815
- width: width || 0,
816
- height: height || 0,
804
+ width,
805
+ height,
817
806
  type,
818
807
  data
819
808
  };
820
809
  }
821
810
  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
811
  return Requests.genericRequest({
831
812
  url: src,
832
813
  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
- });
814
+ }).then(this.processResponse);
842
815
  }
843
816
  static async getInfo(src) {
844
817
  const keyStr = serializeImageKey({ src });
@@ -860,15 +833,22 @@ var ImageLoader = class _ImageLoader {
860
833
 
861
834
  // src/texture/TextureLoader.ts
862
835
  var TextureLoader = class {
836
+ /** Reports whether image loading failed, so cached textures can be retried. */
837
+ static hasFailed(texture) {
838
+ return this.failedTextures.has(texture);
839
+ }
863
840
  static createTexture() {
864
841
  return new Texture();
865
842
  }
866
843
  static loadInBackground(src, format = RGBAFormat, rotation = 0) {
867
844
  const texture = this.createTexture();
868
- const image = ImageLoader.loadElement(src);
869
- image.onload = function() {
845
+ texture.colorSpace = THREE.SRGBColorSpace;
846
+ const image = ImageLoader.loadElement(src, () => {
870
847
  texture.needsUpdate = true;
871
- };
848
+ }, (error) => {
849
+ this.failedTextures.add(texture);
850
+ console.warn("Failed to load texture", src, error);
851
+ });
872
852
  texture.image = image;
873
853
  texture.format = format;
874
854
  texture.rotation = rotation;
@@ -876,22 +856,27 @@ var TextureLoader = class {
876
856
  }
877
857
  static load(src, format = RGBAFormat, rotation = 0) {
878
858
  const texture = new Texture();
859
+ texture.colorSpace = THREE.SRGBColorSpace;
879
860
  ImageLoader.getData(src).then((image) => {
880
- texture.needsUpdate = true;
881
861
  texture.image = image;
862
+ texture.needsUpdate = true;
863
+ }).catch((error) => {
864
+ this.failedTextures.add(texture);
865
+ console.warn("Failed to load texture", src, error);
882
866
  });
883
867
  texture.format = format;
884
868
  texture.rotation = rotation;
885
869
  return Textures.initTextureProps(texture);
886
870
  }
887
871
  };
872
+ TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
888
873
 
889
874
  // src/texture/Textures.ts
890
- import * as THREE from "three";
875
+ import * as THREE2 from "three";
891
876
  var Textures = class _Textures {
892
877
  static initTextureProps(texture) {
893
- texture.magFilter = THREE.NearestFilter;
894
- texture.minFilter = THREE.NearestFilter;
878
+ texture.magFilter = THREE2.NearestFilter;
879
+ texture.minFilter = THREE2.NearestFilter;
895
880
  texture.anisotropy = 0;
896
881
  return texture;
897
882
  }
@@ -902,10 +887,16 @@ var Textures = class _Textures {
902
887
  return new Texture2();
903
888
  }
904
889
  static createCanvasTexture(canvas) {
905
- return this.initTextureProps(new CanvasTexture(canvas));
890
+ const texture = new CanvasTexture(canvas);
891
+ texture.colorSpace = THREE2.SRGBColorSpace;
892
+ return this.initTextureProps(texture);
906
893
  }
907
894
  static getImage(key) {
908
895
  const keyStr = serializeTextureKey(key);
896
+ const cached = Caching.textureCache.peek(keyStr);
897
+ if (cached && TextureLoader.hasFailed(cached)) {
898
+ Caching.textureCache.invalidate(keyStr);
899
+ }
909
900
  return Caching.textureCache.get(keyStr, (k) => {
910
901
  return _Textures.createImage(key);
911
902
  });
@@ -949,6 +940,7 @@ var _Materials = class _Materials {
949
940
  uniform bool SHADE;
950
941
 
951
942
  varying vec2 vUv;
943
+ varying vec3 vTint;
952
944
  varying float light;
953
945
  varying float lift;
954
946
 
@@ -961,7 +953,11 @@ var _Materials = class _Materials {
961
953
 
962
954
  if (SHADE) {
963
955
 
964
- vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
956
+ #ifdef USE_INSTANCING
957
+ vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );
958
+ #else
959
+ vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );
960
+ #endif
965
961
 
966
962
  float yLight = (1.0+N.y) * 0.5;
967
963
  light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;
@@ -979,6 +975,7 @@ var _Materials = class _Materials {
979
975
  }
980
976
 
981
977
  vUv = uv;
978
+ vTint = color;
982
979
 
983
980
  #ifdef USE_INSTANCING
984
981
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * instanceMatrix * vec4(position, 1.0);
@@ -1000,12 +997,14 @@ var _Materials = class _Materials {
1000
997
  uniform float BRIGHTNESS;
1001
998
 
1002
999
  varying vec2 vUv;
1000
+ varying vec3 vTint;
1003
1001
  varying float light;
1004
1002
  varying float lift;
1005
1003
 
1006
1004
  void main(void)
1007
1005
  {
1008
1006
  vec4 color = texture2D(map, vUv);
1007
+ color.rgb *= vTint;
1009
1008
 
1010
1009
  if (color.a < 0.01) discard;
1011
1010
 
@@ -1019,6 +1018,9 @@ var _Materials = class _Materials {
1019
1018
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1020
1019
 
1021
1020
  }
1021
+
1022
+ #include <tonemapping_fragment>
1023
+ #include <colorspace_fragment>
1022
1024
  }
1023
1025
  `;
1024
1026
  try {
@@ -1047,6 +1049,10 @@ var _Materials = class _Materials {
1047
1049
  }
1048
1050
  static getImage(key) {
1049
1051
  const keyStr = serializeMaterialKey(key);
1052
+ const map = Caching.materialCache.peek(keyStr)?.map;
1053
+ if (map && TextureLoader.hasFailed(map)) {
1054
+ Caching.materialCache.invalidate(keyStr);
1055
+ }
1050
1056
  return Caching.materialCache.get(keyStr, (k) => {
1051
1057
  return _Materials.createImage(key);
1052
1058
  });
@@ -1071,10 +1077,10 @@ _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA
1071
1077
  var Materials = _Materials;
1072
1078
 
1073
1079
  // src/Meshes.ts
1074
- import { Mesh as Mesh2 } from "three";
1080
+ import { Mesh } from "three";
1075
1081
  var Meshes = class _Meshes {
1076
1082
  static createBox(key) {
1077
- return new Mesh2(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1083
+ return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1078
1084
  }
1079
1085
  static getBox(key) {
1080
1086
  const keyStr = serializeMeshKey(key);
@@ -1085,7 +1091,7 @@ var Meshes = class _Meshes {
1085
1091
  };
1086
1092
 
1087
1093
  // src/UVMapper.ts
1088
- import { Float32BufferAttribute as Float32BufferAttribute2, Vector2 } from "three";
1094
+ import { Float32BufferAttribute as Float32BufferAttribute2, Vector2, Vector3 as Vector33 } from "three";
1089
1095
 
1090
1096
  // src/model/ModelMerger.ts
1091
1097
  var import_ts_deepmerge = __toESM(require_dist());
@@ -1121,6 +1127,7 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1121
1127
  this.rootType = rootType;
1122
1128
  this.extension = extension;
1123
1129
  this.root = root;
1130
+ this.isAssetKey = true;
1124
1131
  }
1125
1132
  static parse(assetType, str, origin) {
1126
1133
  let namespace = origin?.namespace || DEFAULT_NAMESPACE;
@@ -1136,12 +1143,15 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1136
1143
  split.shift();
1137
1144
  }
1138
1145
  let path = split.join("/");
1139
- let extension = assetType === "textures" ? ".png" : origin?.assetType || ".json";
1146
+ const extension = assetType === "textures" ? ".png" : origin?.extension ?? ".json";
1147
+ if (extension && path.endsWith(extension)) {
1148
+ path = path.slice(0, -extension.length);
1149
+ }
1140
1150
  return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1141
1151
  }
1142
1152
  toString() {
1143
1153
  let a = [
1144
- typeof this.root !== "undefined" || AssetLoader.ROOT !== DEFAULT_ROOT ? this.root ?? AssetLoader.ROOT : "__root__",
1154
+ this.root ?? AssetLoader.ROOT,
1145
1155
  this.rootType ?? "__rootType__",
1146
1156
  this.assetType ?? "__assetType__",
1147
1157
  this.type ?? "__type__",
@@ -1151,12 +1161,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1151
1161
  return a.join("/");
1152
1162
  }
1153
1163
  getFullPath() {
1154
- let p13 = [];
1164
+ let p12 = [];
1155
1165
  if (this.type) {
1156
- p13.push(this.type);
1166
+ p12.push(this.type);
1157
1167
  }
1158
- p13.push(this.path);
1159
- return p13.join("/");
1168
+ p12.push(this.path);
1169
+ return p12.join("/");
1160
1170
  }
1161
1171
  toNamespacedString() {
1162
1172
  return this.namespace + ":" + this.getFullPath();
@@ -1166,10 +1176,10 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1166
1176
  }
1167
1177
  };
1168
1178
  function isBasicAssetKey(obj) {
1169
- return "namespace" in obj && "path" in obj;
1179
+ return obj !== null && typeof obj === "object" && typeof obj.namespace === "string" && typeof obj.path === "string";
1170
1180
  }
1171
1181
  function isAssetKey(obj) {
1172
- return isBasicAssetKey(obj) && "parse" in obj;
1182
+ return isBasicAssetKey(obj) && obj.isAssetKey === true;
1173
1183
  }
1174
1184
 
1175
1185
  // src/model/ModelMerger.ts
@@ -1178,10 +1188,10 @@ var ModelMerger = class {
1178
1188
  const models = await this.collectAllParents(model);
1179
1189
  let merged = {};
1180
1190
  for (let parentModel of models) {
1181
- merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1191
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, parentModel);
1182
1192
  }
1183
- merged = (0, import_ts_deepmerge.default)(merged, model);
1184
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1193
+ merged = import_ts_deepmerge.default.withOptions({ mergeArrays: false }, merged, model);
1194
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1185
1195
  merged.hierarchy.push(`${merged.parent}`);
1186
1196
  return merged;
1187
1197
  }
@@ -1191,6 +1201,7 @@ var ModelMerger = class {
1191
1201
  }
1192
1202
  const models = [];
1193
1203
  const parentKey = AssetKey.parse("models", model.parent);
1204
+ parentKey.root = model.key?.root;
1194
1205
  const parentModel = await Models.getRaw(parentKey);
1195
1206
  if (parentModel) {
1196
1207
  models.unshift(parentModel);
@@ -1200,9 +1211,6 @@ var ModelMerger = class {
1200
1211
  }
1201
1212
  };
1202
1213
 
1203
- // src/assets/Models.ts
1204
- import { Memoize } from "typescript-memoize";
1205
-
1206
1214
  // src/assets/source/parser/AssetParsers.ts
1207
1215
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1208
1216
  AssetParser2["MODEL"] = "model";
@@ -1216,30 +1224,65 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1216
1224
  })(AssetParser || {});
1217
1225
 
1218
1226
  // src/assets/Models.ts
1219
- var _Models = class _Models {
1227
+ var Models = class _Models {
1220
1228
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1221
1229
  // the library, and would require an EnvProvider before any entry has had a chance to register
1222
1230
  static get PERSISTENT_CACHE() {
1223
1231
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1224
1232
  }
1225
1233
  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 ?? []);
1234
+ const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
1235
+ const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
1236
+ return Caching.listAssetCache.get(key.serialize(), async () => {
1237
+ return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
1238
+ }).then((r) => r?.files ?? []);
1235
1239
  }
1236
1240
  static async loadAndMerge(key) {
1237
- const model = await this.getRaw(key);
1241
+ const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
1238
1242
  if (!model) {
1239
1243
  return void 0;
1240
1244
  }
1241
1245
  return ModelMerger.mergeWithParents(model);
1242
1246
  }
1247
+ static async getItemModel(key) {
1248
+ const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
1249
+ const model = await this.PERSISTENT_CACHE.getOrLoad(itemKey.serialize(), async () => {
1250
+ const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1251
+ if (!result) return void 0;
1252
+ if (result.key.assetType !== "items") return { ...result.asset, key };
1253
+ const reference = this.defaultItemModel(result.asset.model, key);
1254
+ const modelKey = AssetKey.parse("models", reference);
1255
+ modelKey.root = key.root;
1256
+ const model2 = await this.getRaw(modelKey);
1257
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1258
+ return model2;
1259
+ });
1260
+ return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1261
+ }
1262
+ // Item previews use the GUI context, false conditions, and zero numeric properties.
1263
+ static defaultItemModel(node, key) {
1264
+ if (!node || typeof node.type !== "string") {
1265
+ throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
1266
+ }
1267
+ switch (node.type.replace(/^minecraft:/, "")) {
1268
+ case "model":
1269
+ if (typeof node.model === "string" && node.model) return node.model;
1270
+ break;
1271
+ case "condition":
1272
+ return this.defaultItemModel(node.on_false, key);
1273
+ case "select": {
1274
+ 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;
1275
+ return this.defaultItemModel(selected ?? node.fallback, key);
1276
+ }
1277
+ case "range_dispatch": {
1278
+ const selected = node.entries?.reduce((match, entry) => {
1279
+ return entry.threshold <= 0 && (!match || entry.threshold >= match.threshold) ? entry : match;
1280
+ }, void 0);
1281
+ return this.defaultItemModel(selected?.model ?? node.fallback, key);
1282
+ }
1283
+ }
1284
+ throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
1285
+ }
1243
1286
  static async getRaw(key) {
1244
1287
  if (!key.assetType) {
1245
1288
  key.assetType = "models";
@@ -1278,19 +1321,15 @@ var _Models = class _Models {
1278
1321
  return this.PERSISTENT_CACHE.clear();
1279
1322
  }
1280
1323
  };
1281
- __decorateClass([
1282
- Memoize()
1283
- ], _Models, "getItemList", 1);
1284
- var Models = _Models;
1285
1324
 
1286
1325
  // src/assets/BlockStates.ts
1287
- import { Memoize as Memoize2 } from "typescript-memoize";
1288
1326
  var BlockStates = class {
1289
1327
  static get PERSISTENT_CACHE() {
1290
1328
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1291
1329
  }
1330
+ // BlockState names are hardcoded
1292
1331
  static async getList() {
1293
- return AssetLoader.get(new AssetKey(
1332
+ const key = new AssetKey(
1294
1333
  DEFAULT_NAMESPACE,
1295
1334
  "_list",
1296
1335
  "blockstates",
@@ -1298,11 +1337,16 @@ var BlockStates = class {
1298
1337
  "assets",
1299
1338
  ".json",
1300
1339
  DEFAULT_ROOT
1301
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1340
+ );
1341
+ return Caching.listAssetCache.get(key.serialize(), () => {
1342
+ return AssetLoader.get(key, "list" /* LIST */);
1343
+ }).then((r) => r?.files ?? []);
1302
1344
  }
1303
1345
  static async getDefaultStates() {
1304
1346
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1305
- return AssetLoader.get(key, "json" /* JSON */);
1347
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1348
+ return AssetLoader.get(key, "json" /* JSON */);
1349
+ });
1306
1350
  }
1307
1351
  static async getDefaultState(key) {
1308
1352
  const defaultStates = await this.getDefaultStates();
@@ -1341,17 +1385,11 @@ var BlockStates = class {
1341
1385
  await this.PERSISTENT_CACHE.clear();
1342
1386
  }
1343
1387
  };
1344
- __decorateClass([
1345
- Memoize2()
1346
- ], BlockStates, "getList", 1);
1347
- __decorateClass([
1348
- Memoize2()
1349
- ], BlockStates, "getDefaultStates", 1);
1350
1388
  var DefaultBlockStates = class {
1351
1389
  };
1352
1390
 
1353
1391
  // src/assets/Assets.ts
1354
- var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.17.1";
1392
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
1355
1393
  var DEFAULT_NAMESPACE = "minecraft";
1356
1394
  var Assets = class {
1357
1395
  /**
@@ -1373,37 +1411,174 @@ var AssetSource = class {
1373
1411
  constructor() {
1374
1412
  }
1375
1413
  };
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;
1414
+ var AssetLoadError = class extends Error {
1415
+ constructor(source, key, path, cause) {
1416
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1417
+ this.source = source;
1418
+ this.key = key;
1419
+ this.path = path;
1420
+ this.cause = cause;
1421
+ this.name = "AssetLoadError";
1383
1422
  }
1384
1423
  };
1385
1424
 
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;
1425
+ // src/util/BatchedExecutor.ts
1426
+ var BatchedExecutor = class {
1427
+ constructor(interval = 1, batch = 30) {
1428
+ this.interval = interval;
1429
+ this.batch = batch;
1430
+ this.queue = [];
1431
+ this.task = setInterval(() => this.run());
1432
+ }
1433
+ submit(task) {
1434
+ this.queue.push(task);
1435
+ }
1436
+ run() {
1437
+ for (let i = 0; i < this.batch; i++) {
1438
+ this.runNext();
1397
1439
  }
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");
1440
+ }
1441
+ runNext() {
1442
+ let next = this.queue.shift();
1443
+ if (next) next();
1444
+ }
1445
+ };
1446
+
1447
+ // src/util/model.ts
1448
+ import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
1449
+ function applyElementRotation(rotation, geometry) {
1450
+ const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1451
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1452
+ switch (rotation.axis) {
1453
+ case "x" /* X */:
1454
+ geometry.rotateX(toRadians(rotation.angle));
1455
+ break;
1456
+ case "y" /* Y */:
1457
+ geometry.rotateY(toRadians(rotation.angle));
1458
+ break;
1459
+ case "z" /* Z */:
1460
+ geometry.rotateZ(toRadians(rotation.angle));
1461
+ break;
1462
+ }
1463
+ if (rotation.rescale) {
1464
+ if (Math.abs(rotation.angle) === 22.5) {
1465
+ const s = 1 / Math.cos(0.39269909262657166);
1466
+ geometry.scale(s, 1, s);
1467
+ } else {
1468
+ const s = 1 / Math.cos(0.7853981852531433);
1469
+ geometry.scale(s, 1, s);
1470
+ }
1471
+ }
1472
+ geometry.translate(origin.x, origin.y, origin.z);
1473
+ }
1474
+ function applyModelPartRotation(modelPart, geometry) {
1475
+ const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
1476
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1477
+ geometry.rotateX(toRadians(modelPart.pitch));
1478
+ geometry.rotateY(toRadians(modelPart.yaw));
1479
+ geometry.rotateZ(toRadians(modelPart.roll));
1480
+ geometry.translate(origin.x, origin.y, origin.z);
1481
+ }
1482
+ function applyGenericRotation(axis, rotation, obj) {
1483
+ switch (axis) {
1484
+ case "x" /* X */:
1485
+ obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
1486
+ break;
1487
+ case "y" /* Y */:
1488
+ obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
1489
+ break;
1490
+ case "z" /* Z */:
1491
+ obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
1492
+ break;
1493
+ }
1494
+ }
1495
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1496
+ let size = new Vector32();
1497
+ box.getSize(size);
1498
+ let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
1499
+ let wireGeo = new EdgesGeometry(boxGeo);
1500
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1501
+ let wireframe = new LineSegments(wireGeo, wireMat);
1502
+ obj.add(wireframe);
1503
+ let axes = new AxesHelper(1);
1504
+ obj.add(axes);
1505
+ }
1506
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1507
+ let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
1508
+ let wireGeo = new EdgesGeometry(boxGeo);
1509
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1510
+ let wireframe = new LineSegments(wireGeo, wireMat);
1511
+ obj.add(wireframe);
1512
+ let axes = new AxesHelper(1);
1513
+ obj.add(axes);
1514
+ }
1515
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1516
+ let wireGeo = new EdgesGeometry(geo);
1517
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1518
+ let wireframe = new LineSegments(wireGeo, wireMat);
1519
+ mesh.add(wireframe);
1520
+ let axes = new AxesHelper(1);
1521
+ mesh.add(axes);
1522
+ }
1523
+
1524
+ // src/util/performance.ts
1525
+ function captureException(e, ...extra) {
1526
+ console.error(e, extra);
1527
+ }
1528
+ function timingStart(marker) {
1529
+ console.time(marker);
1530
+ }
1531
+ function timingEnd(marker) {
1532
+ console.timeEnd(marker);
1533
+ }
1534
+
1535
+ // src/util/three.ts
1536
+ function isObject3D(obj) {
1537
+ return obj.isObject3D;
1538
+ }
1539
+ function isMesh(obj) {
1540
+ return obj.isMesh;
1541
+ }
1542
+ function isInstancedMesh(obj) {
1543
+ return obj.isInstancedMesh;
1544
+ }
1545
+ function isPerspectiveCamera(obj) {
1546
+ return obj.isPerspectiveCamera;
1547
+ }
1548
+ function isOrthographicCamera(obj) {
1549
+ return obj.isOrthographicCamera;
1550
+ }
1551
+
1552
+ // src/nbt/NBTHelper.ts
1553
+ var NBTHelper = class {
1554
+ static async fromBuffer(buffer) {
1555
+ const prismarineNbt = await import("prismarine-nbt");
1556
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1557
+ return parsed;
1558
+ }
1559
+ };
1560
+
1561
+ // src/assets/source/HostedAssetSource.ts
1562
+ var import_ts_deepmerge2 = __toESM(require_dist());
1563
+ var p3 = prefix("HostedAssetSource");
1564
+ var DEFAULT_OPTIONS = {
1565
+ retryDefaults: true
1566
+ };
1567
+ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1568
+ async loadOrRetryWithDefaults(key, parser) {
1569
+ const direct = await this.load(key, parser);
1570
+ if (typeof direct !== "undefined") {
1571
+ return direct;
1572
+ }
1573
+ if (key.namespace !== DEFAULT_NAMESPACE) {
1574
+ console.info(p3, "Retrying", key, "with default namespace");
1575
+ const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
1576
+ const namespaced = await this.load(namespaceKey, parser);
1577
+ if (typeof namespaced !== "undefined") {
1578
+ return namespaced;
1579
+ }
1580
+ if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1581
+ console.info(p3, "Retrying", key, "with default root+namespace");
1407
1582
  const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1408
1583
  const namespacedRooted = await this.load(namespacedRootedKey, parser);
1409
1584
  if (typeof namespacedRooted !== "undefined") {
@@ -1424,31 +1599,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1424
1599
  console.info(p3, "Loading", key);
1425
1600
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1426
1601
  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");
1602
+ const request = { url };
1603
+ try {
1604
+ parser.config(request);
1605
+ let response;
1606
+ try {
1607
+ response = await Requests.mcAssetRequest(request);
1608
+ } catch (cause) {
1609
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1446
1610
  return void 0;
1447
1611
  }
1612
+ throw cause;
1448
1613
  }
1449
- console.debug(p3, "Failed to load", key, err?.message);
1450
- return void 0;
1451
- });
1614
+ if (response.data === void 0) {
1615
+ throw new Error("Asset response has no data");
1616
+ }
1617
+ return await parser.parse(response);
1618
+ } catch (cause) {
1619
+ throw new AssetLoadError(this, key, request.url, cause);
1620
+ }
1452
1621
  }
1453
1622
  assetBasePath(key) {
1454
1623
  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 +1724,6 @@ var BrowserArchiveProxy = class {
1555
1724
  };
1556
1725
 
1557
1726
  // src/assets/source/archive/ArchiveAssetSource.ts
1558
- var p4 = prefix("ArchiveAssetSource");
1559
1727
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1560
1728
  constructor(archiveProxy) {
1561
1729
  super();
@@ -1574,74 +1742,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1574
1742
  }
1575
1743
  async get(key, parser) {
1576
1744
  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
- });
1745
+ return this.load(key, responseParser);
1614
1746
  }
1615
- //TODO: abstract this
1616
1747
  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
- }
1748
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1749
+ let url;
1750
+ try {
1751
+ const entry = await this.getEntry(path);
1752
+ if (!entry) {
1753
+ return void 0;
1632
1754
  }
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
- }
1755
+ url = URL.createObjectURL(await entry.getData());
1756
+ const request = { url };
1757
+ parser.config(request);
1758
+ const response = await Requests.genericRequest(request);
1759
+ if (response.data === void 0) {
1760
+ throw new Error("Asset response has no data");
1641
1761
  }
1642
- console.debug(p4, "Failed to load", key, err?.message);
1643
- return void 0;
1644
- });
1762
+ return await parser.parse(response);
1763
+ } catch (cause) {
1764
+ throw new AssetLoadError(this, key, path, cause);
1765
+ } finally {
1766
+ if (url !== void 0) {
1767
+ URL.revokeObjectURL(url);
1768
+ }
1769
+ }
1645
1770
  }
1646
1771
  assetBasePath(key) {
1647
1772
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1649,18 +1774,17 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1649
1774
  };
1650
1775
 
1651
1776
  // src/assets/AssetLoader.ts
1652
- var import_ts_deepmerge3 = __toESM(require_dist());
1653
- var p5 = prefix("AssetLoader");
1777
+ var p4 = prefix("AssetLoader");
1654
1778
  var _AssetLoader = class _AssetLoader {
1655
1779
  static addSource(key, source, override = true) {
1656
1780
  if (override) {
1657
1781
  const existing = this.removeSource(key);
1658
1782
  if (existing) {
1659
- console.log(p5, "Removed existing AssetSource", key);
1783
+ console.log(p4, "Removed existing AssetSource", key);
1660
1784
  }
1661
1785
  }
1662
1786
  this._SOURCES.unshift({ key, source });
1663
- console.log(p5, "Added AssetSource", key);
1787
+ console.log(p4, "Added AssetSource", key);
1664
1788
  }
1665
1789
  static removeSource(key) {
1666
1790
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1673,7 +1797,6 @@ var _AssetLoader = class _AssetLoader {
1673
1797
  return void 0;
1674
1798
  }
1675
1799
  static async getAll(key, parser) {
1676
- console.log(this._SOURCES);
1677
1800
  let promises = [];
1678
1801
  for (const source of this._SOURCES) {
1679
1802
  promises.push(source.source.get(key, parser));
@@ -1682,24 +1805,34 @@ var _AssetLoader = class _AssetLoader {
1682
1805
  return results.filter((r) => r != void 0);
1683
1806
  });
1684
1807
  }
1808
+ /** Returns the first defined result in source-priority order, without merging assets. */
1685
1809
  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;
1810
+ const keys = [key];
1811
+ if (key.rootType === "data" && (key.assetType === "structure" || key.assetType === "structures")) {
1812
+ keys.push(new AssetKey(
1813
+ key.namespace,
1814
+ key.path,
1815
+ key.assetType === "structure" ? "structures" : "structure",
1816
+ key.type,
1817
+ key.rootType,
1818
+ key.extension,
1819
+ key.root
1820
+ ));
1821
+ }
1822
+ return (await this.getFirst(keys, parser))?.asset;
1823
+ }
1824
+ /** Tries each path within a source before considering lower-priority sources. */
1825
+ static async getFirst(keys, parser) {
1826
+ const sources = [...this._SOURCES];
1827
+ for (const source of sources) {
1828
+ for (const key of keys) {
1829
+ const result = await source.source.get(key, parser);
1830
+ if (result !== void 0) {
1831
+ return { key, asset: result };
1699
1832
  }
1700
1833
  }
1701
- return void 0;
1702
- });
1834
+ }
1835
+ return void 0;
1703
1836
  }
1704
1837
  };
1705
1838
  _AssetLoader.ROOT = DEFAULT_ROOT;
@@ -1714,11 +1847,21 @@ var ModelTextures = class {
1714
1847
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
1715
1848
  }
1716
1849
  static async get(key) {
1717
- const asset = await this.preload(key);
1718
- if (asset) {
1719
- return ImageLoader.infoToCanvasData(asset);
1850
+ const keyStr = key.serialize();
1851
+ const pending = this.preload(key);
1852
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1853
+ try {
1854
+ const asset = await pending;
1855
+ if (asset) {
1856
+ return await ImageLoader.infoToCanvasData(asset);
1857
+ }
1858
+ return void 0;
1859
+ } catch (err) {
1860
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
1861
+ Caching.textureAssetCache.invalidate(keyStr);
1862
+ }
1863
+ throw err;
1720
1864
  }
1721
- return void 0;
1722
1865
  }
1723
1866
  static async preload(key) {
1724
1867
  const keyStr = key.serialize();
@@ -1888,17 +2031,20 @@ var TextureAtlas = class {
1888
2031
  // src/model/ModelGenerator.ts
1889
2032
  var ModelGenerator = class {
1890
2033
  static generateItemModel(imageData, layer) {
2034
+ const tintindex = this.ITEM_LAYERS.indexOf(layer);
1891
2035
  const mainElement = {
1892
2036
  from: [0, 0, 7.5],
1893
2037
  to: [16, 16, 8.5],
1894
2038
  faces: {
1895
2039
  "south": {
1896
2040
  uv: [0, 0, 16, 16],
1897
- texture: `#${layer}`
2041
+ texture: `#${layer}`,
2042
+ tintindex
1898
2043
  },
1899
2044
  "north": {
1900
2045
  uv: [16, 0, 0, 16],
1901
- texture: `#${layer}`
2046
+ texture: `#${layer}`,
2047
+ tintindex
1902
2048
  }
1903
2049
  },
1904
2050
  shade: true
@@ -1909,11 +2055,19 @@ var ModelGenerator = class {
1909
2055
  ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
1910
2056
 
1911
2057
  // src/UVMapper.ts
1912
- var p6 = prefix("UVMapper");
2058
+ var p5 = prefix("UVMapper");
1913
2059
  var DEFAULT_UV = [0, 0, 16, 16];
1914
2060
  var X = 0;
1915
2061
  var Y = 1;
1916
2062
  var Z = 2;
2063
+ var FACE_UV_AXES = {
2064
+ east: [new Vector33(0, 0, -1), new Vector33(0, -1, 0)],
2065
+ west: [new Vector33(0, 0, 1), new Vector33(0, -1, 0)],
2066
+ up: [new Vector33(1, 0, 0), new Vector33(0, 0, 1)],
2067
+ down: [new Vector33(1, 0, 0), new Vector33(0, 0, -1)],
2068
+ south: [new Vector33(1, 0, 0), new Vector33(0, -1, 0)],
2069
+ north: [new Vector33(-1, 0, 0), new Vector33(0, -1, 0)]
2070
+ };
1917
2071
  var UVMapper = class {
1918
2072
  static makeUv(uvCoord, originalTextureSize, actualTextureSize) {
1919
2073
  if (uvCoord === 0) return 0;
@@ -2011,6 +2165,42 @@ var UVMapper = class {
2011
2165
  static facesToUv(faces, originalTextureSize, actualTextureSize) {
2012
2166
  return new Float32BufferAttribute2(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);
2013
2167
  }
2168
+ static lockUvs(geometry, faces, atlas, rotation) {
2169
+ const uv = geometry.getAttribute("uv");
2170
+ for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {
2171
+ const faceName = CUBE_FACES[faceIndex];
2172
+ const texture = faces[faceName]?.texture?.substring(1);
2173
+ const position = texture && atlas.positions[texture];
2174
+ const size = texture && atlas.sizes[texture];
2175
+ if (!position || !size) continue;
2176
+ const [sourceU, sourceV] = FACE_UV_AXES[faceName];
2177
+ const uAxis = sourceU.clone().applyEuler(rotation);
2178
+ const vAxis = sourceV.clone().applyEuler(rotation);
2179
+ const normal = vAxis.clone().cross(uAxis);
2180
+ const targetFace = CUBE_FACES.find((name) => {
2181
+ const [u, v] = FACE_UV_AXES[name];
2182
+ return v.clone().cross(u).dot(normal) > 0.5;
2183
+ });
2184
+ const [targetU, targetV] = FACE_UV_AXES[targetFace];
2185
+ const uu = Math.round(targetU.dot(uAxis));
2186
+ const uvCross = Math.round(targetU.dot(vAxis));
2187
+ const vu = Math.round(targetV.dot(uAxis));
2188
+ const vv = Math.round(targetV.dot(vAxis));
2189
+ for (let corner = 0; corner < 4; corner++) {
2190
+ const index = faceIndex * 4 + corner;
2191
+ const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;
2192
+ const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;
2193
+ const lockedU = uu * u + uvCross * v + 0.5;
2194
+ const lockedV = vu * u + vv * v + 0.5;
2195
+ uv.setXY(
2196
+ index,
2197
+ (position[0] + lockedU * size[0]) / atlas.image.width,
2198
+ 1 - (position[1] + lockedV * size[1]) / atlas.image.height
2199
+ );
2200
+ }
2201
+ }
2202
+ uv.needsUpdate = true;
2203
+ }
2014
2204
  static async getAtlas(model) {
2015
2205
  const keyStr = model.key.serialize();
2016
2206
  return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
@@ -2086,7 +2276,7 @@ var UVMapper = class {
2086
2276
  const metaMap = {};
2087
2277
  const model = { ...originalModel };
2088
2278
  const isItemModel = !("elements" in model);
2089
- console.debug(p6, "Creating Atlas for", model.key);
2279
+ console.debug(p5, "Creating Atlas for", model.key);
2090
2280
  if (model.textures) {
2091
2281
  const promises = [];
2092
2282
  const uniqueTextureNames = [];
@@ -2100,7 +2290,7 @@ var UVMapper = class {
2100
2290
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2101
2291
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2102
2292
  if (!asset) {
2103
- console.warn(p6, "Missing texture", assetKey);
2293
+ console.warn(p5, "Missing texture", assetKey);
2104
2294
  return;
2105
2295
  }
2106
2296
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2112,7 +2302,7 @@ var UVMapper = class {
2112
2302
  }
2113
2303
  await Promise.all(promises);
2114
2304
  const textureCount = uniqueTextureNames.length;
2115
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2305
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2116
2306
  this.fillMissingTextureKeys(model.textures, textureMap);
2117
2307
  this.fillMissingTextureKeys(model.textures, metaMap);
2118
2308
  const sizes = {};
@@ -2132,7 +2322,7 @@ var UVMapper = class {
2132
2322
  this.fillMissingTextureKeys(model.textures, sizes);
2133
2323
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2134
2324
  const size = Math.ceil(s * maxWidth);
2135
- console.debug(p6, "Atlas size:", size);
2325
+ console.debug(p5, "Atlas size:", size);
2136
2326
  const squaredSize = size * size;
2137
2327
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2138
2328
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2187,10 +2377,10 @@ var UVMapper = class {
2187
2377
  }
2188
2378
  }
2189
2379
  const atlasImageData = image.toDataURL();
2190
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2380
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2191
2381
  this.fillMissingTextureKeys(model.textures, positions);
2192
2382
  if (isItemModel) {
2193
- console.debug(p6, "Generating item model for", model);
2383
+ console.debug(p5, "Generating item model for", model);
2194
2384
  model.elements = [];
2195
2385
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2196
2386
  const textureImage = textureMap[layerName];
@@ -2198,7 +2388,7 @@ var UVMapper = class {
2198
2388
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2199
2389
  }
2200
2390
  }
2201
- console.debug(p6, "Item model elements", model.elements);
2391
+ console.debug(p5, "Item model elements", model.elements);
2202
2392
  }
2203
2393
  if (!model.elements) {
2204
2394
  }
@@ -2216,17 +2406,13 @@ var UVMapper = class {
2216
2406
  this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size]);
2217
2407
  continue;
2218
2408
  }
2409
+ if (!face.texture) continue;
2219
2410
  if (!face.uv) {
2220
2411
  face.uv = this.getFallbackUv(element, faceName);
2221
2412
  }
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
- }
2413
+ const faceTexture = face.texture.substr(1);
2414
+ const texPosition = positions[faceTexture] || [0, 0];
2415
+ const texSize = sizes[faceTexture] || [16, 16];
2230
2416
  let texPosV = new Vector2(texPosition[0], texPosition[1]);
2231
2417
  const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);
2232
2418
  tl.add(texPosV);
@@ -2258,7 +2444,7 @@ var UVMapper = class {
2258
2444
  hasTransparency
2259
2445
  );
2260
2446
  } else {
2261
- console.warn(p6, "Model does not have any textures", model);
2447
+ console.warn(p5, "Model does not have any textures", model);
2262
2448
  }
2263
2449
  return void 0;
2264
2450
  }
@@ -2396,17 +2582,20 @@ function shutdown() {
2396
2582
  }
2397
2583
 
2398
2584
  // src/assets/Entities.ts
2399
- import { Memoize as Memoize3 } from "typescript-memoize";
2400
2585
  var Entities = class {
2401
2586
  static async getBlockEntityModels() {
2402
2587
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2403
2588
  console.log(key);
2404
- return AssetLoader.get(key, "json" /* JSON */);
2589
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2590
+ return AssetLoader.get(key, "json" /* JSON */);
2591
+ });
2405
2592
  }
2406
2593
  static async getEntityModels() {
2407
2594
  const key = AssetKey.parse("models", "minerender:entityModels");
2408
2595
  console.log(key);
2409
- return AssetLoader.get(key, "json" /* JSON */);
2596
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2597
+ return AssetLoader.get(key, "json" /* JSON */);
2598
+ });
2410
2599
  }
2411
2600
  // BlockEntity names are hardcoded
2412
2601
  static async getBlockList() {
@@ -2452,19 +2641,13 @@ var Entities = class {
2452
2641
  };
2453
2642
  }
2454
2643
  };
2455
- __decorateClass([
2456
- Memoize3()
2457
- ], Entities, "getBlockEntityModels", 1);
2458
- __decorateClass([
2459
- Memoize3()
2460
- ], Entities, "getEntityModels", 1);
2461
2644
  var EntityModels = class {
2462
2645
  };
2463
2646
  var BlockEntityModels = class {
2464
2647
  };
2465
2648
 
2466
2649
  // 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";
2650
+ import { Euler as Euler2, InstancedMesh, MathUtils, Matrix4 as Matrix42, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion2, Vector3 as Vector34 } from "three";
2468
2651
 
2469
2652
  // src/instance/InstanceReference.ts
2470
2653
  var InstanceReference = class {
@@ -2521,8 +2704,8 @@ var MineRenderError = class _MineRenderError extends Error {
2521
2704
  };
2522
2705
 
2523
2706
  // src/renderer/SceneObject.ts
2524
- var import_ts_deepmerge4 = __toESM(require_dist());
2525
- var p7 = prefix("SceneObject");
2707
+ var import_ts_deepmerge3 = __toESM(require_dist());
2708
+ var p6 = prefix("SceneObject");
2526
2709
  var _SceneObject = class _SceneObject extends Object3D2 {
2527
2710
  constructor(options) {
2528
2711
  super();
@@ -2530,7 +2713,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2530
2713
  this.materialCallbacks = {};
2531
2714
  this._isInstanced = false;
2532
2715
  this._instanceCounter = 0;
2533
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2716
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2534
2717
  console.log("SceneObject options", this.options);
2535
2718
  }
2536
2719
  set scene(scene) {
@@ -2624,6 +2807,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2624
2807
  }
2625
2808
  createInstancedMesh(name, geometry, material, count) {
2626
2809
  const mesh = new InstancedMesh(geometry, material, count);
2810
+ mesh.count = 0;
2627
2811
  if (name) {
2628
2812
  mesh.name = `mesh:${name}`;
2629
2813
  }
@@ -2701,9 +2885,13 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2701
2885
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2702
2886
  const i = this._instanceCounter++;
2703
2887
  this.setMatrixAt(i, new Matrix42());
2704
- console.debug(p7, "nextInstance " + i);
2888
+ const mesh = this.children[0];
2889
+ if (mesh && isInstancedMesh(mesh)) {
2890
+ mesh.count = Math.min(this._instanceCounter, mesh.instanceMatrix.count);
2891
+ }
2892
+ console.debug(p6, "nextInstance " + i);
2705
2893
  if (i === this.options.maxInstanceCount) {
2706
- console.warn(p7, "Max instance count reached for " + this);
2894
+ console.warn(p6, "Max instance count reached for " + this);
2707
2895
  }
2708
2896
  if (this.scene) {
2709
2897
  this.scene.stats.instanceCount++;
@@ -2732,9 +2920,9 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2732
2920
  }
2733
2921
  setPositionRotationScaleAt(index, position, rotation, scale) {
2734
2922
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2735
- const oldPosition = new Vector33();
2923
+ const oldPosition = new Vector34();
2736
2924
  const oldRotation = new Quaternion2();
2737
- const oldScale = new Vector33();
2925
+ const oldScale = new Vector34();
2738
2926
  const matrix = new Matrix42();
2739
2927
  if (!scale || !rotation || !position) {
2740
2928
  this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
@@ -2750,7 +2938,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2750
2938
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2751
2939
  this.setPositionRotationScaleAt(index, position);
2752
2940
  }
2753
- getPositionAt(index, vector = new Vector33()) {
2941
+ getPositionAt(index, vector = new Vector34()) {
2754
2942
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2755
2943
  const matrix = this.getMatrixAt(index);
2756
2944
  vector.setFromMatrixPosition(matrix);
@@ -2760,7 +2948,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2760
2948
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2761
2949
  this.setPositionRotationScaleAt(index, void 0, rotation, void 0);
2762
2950
  }
2763
- getRotationAt(index, euler = new Euler()) {
2951
+ getRotationAt(index, euler = new Euler2()) {
2764
2952
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2765
2953
  const matrix = this.getMatrixAt(index);
2766
2954
  euler.setFromRotationMatrix(matrix);
@@ -2770,7 +2958,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2770
2958
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2771
2959
  this.setPositionRotationScaleAt(index, void 0, void 0, scale);
2772
2960
  }
2773
- getScaleAt(index, vector = new Vector33()) {
2961
+ getScaleAt(index, vector = new Vector34()) {
2774
2962
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2775
2963
  const matrix = this.getMatrixAt(index);
2776
2964
  vector.setFromMatrixScale(matrix);
@@ -2879,7 +3067,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2879
3067
  }
2880
3068
  //</editor-fold>
2881
3069
  };
2882
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
3070
+ _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2883
3071
  instanceMeshes: true,
2884
3072
  maxInstanceCount: 50,
2885
3073
  mergeMeshes: true,
@@ -2891,16 +3079,16 @@ function isSceneObject(obj) {
2891
3079
  }
2892
3080
 
2893
3081
  // src/entity/scene/EntityObject.ts
2894
- var import_ts_deepmerge5 = __toESM(require_dist());
3082
+ var import_ts_deepmerge4 = __toESM(require_dist());
2895
3083
  import { Object3D as Object3D3 } from "three";
2896
- import * as THREE2 from "three";
3084
+ import * as THREE3 from "three";
2897
3085
  var EntityObject = class extends SceneObject {
2898
3086
  constructor(entity, options) {
2899
3087
  super();
2900
3088
  this.entity = entity;
2901
3089
  this.isEntityObject = true;
2902
3090
  this.meshesCreated = false;
2903
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3091
+ this.options = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
2904
3092
  }
2905
3093
  async init() {
2906
3094
  this.createMeshes();
@@ -2909,8 +3097,8 @@ var EntityObject = class extends SceneObject {
2909
3097
  dispose() {
2910
3098
  super.dispose();
2911
3099
  }
2912
- async loadTextures() {
2913
- this.imageData = await ModelTextures.get(new AssetKey(
3100
+ get textureKey() {
3101
+ return new AssetKey(
2914
3102
  this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2915
3103
  this.entity.key.path,
2916
3104
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
@@ -2918,7 +3106,10 @@ var EntityObject = class extends SceneObject {
2918
3106
  "entity",
2919
3107
  "assets",
2920
3108
  ".png"
2921
- ));
3109
+ );
3110
+ }
3111
+ async loadTextures() {
3112
+ this.imageData = await ModelTextures.get(this.textureKey);
2922
3113
  }
2923
3114
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2924
3115
  createMeshes(force = false) {
@@ -2937,8 +3128,8 @@ var EntityObject = class extends SceneObject {
2937
3128
  const l = cube.maxZ - cube.minZ;
2938
3129
  const uv = texture.toUvArray(w, h, l);
2939
3130
  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));
3131
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3132
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
2942
3133
  applyModelPartRotation(part, cubeGeo);
2943
3134
  const mesh = this.createMesh(partName, cubeGeo, mat);
2944
3135
  partAnchor.add(mesh);
@@ -2951,23 +3142,26 @@ var EntityObject = class extends SceneObject {
2951
3142
  this.meshesCreated = true;
2952
3143
  }
2953
3144
  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
- }
3145
+ const assetKeyStr = this.textureKey.serialize();
3146
+ const keyStr = `entity:${assetKeyStr}`;
3147
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3148
+ if (!mat) {
3149
+ const pending = this.loadTextures();
3150
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3151
+ await pending;
3152
+ if (!this.imageData) return;
3153
+ const canvas = this.imageData.data.canvas;
3154
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3155
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3156
+ this.imageData = void 0;
3157
+ }
3158
+ this.iterateAllMeshes((mesh) => {
3159
+ mesh.material = mat;
3160
+ });
3161
+ this.notifyDirty();
2968
3162
  }
2969
3163
  };
2970
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3164
+ EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
2971
3165
  function isEntityObject(obj) {
2972
3166
  return obj.isEntityObject;
2973
3167
  }
@@ -2979,7 +3173,7 @@ var GuiObject = class extends SceneObject {
2979
3173
 
2980
3174
  // src/inspector/SceneInspector.ts
2981
3175
  import { Raycaster, Vector2 as Vector22 } from "three";
2982
- var p8 = prefix("SceneInspector");
3176
+ var p7 = prefix("SceneInspector");
2983
3177
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
2984
3178
  var SceneInspector = class {
2985
3179
  constructor(renderer) {
@@ -3048,7 +3242,7 @@ var SceneInspector = class {
3048
3242
  }
3049
3243
  selectObject(targetObject, targetIntersection) {
3050
3244
  this.selectedObject = targetObject;
3051
- console.log(p8, "selected", targetObject);
3245
+ console.log(p7, "selected", targetObject);
3052
3246
  this.redraw(targetObject, targetIntersection);
3053
3247
  }
3054
3248
  redraw(targetObject, targetIntersection) {
@@ -3346,7 +3540,7 @@ var SceneStatsDisplay = class {
3346
3540
  };
3347
3541
 
3348
3542
  // src/instance/InstanceManager.ts
3349
- var p9 = prefix("InstanceManager");
3543
+ var p8 = prefix("InstanceManager");
3350
3544
  var InstanceManager = class {
3351
3545
  constructor() {
3352
3546
  this.isInstanceManager = true;
@@ -3354,7 +3548,7 @@ var InstanceManager = class {
3354
3548
  }
3355
3549
  async get(key) {
3356
3550
  if (key in this.instanceCache) {
3357
- console.debug(p9, "key in cache", key);
3551
+ console.debug(p8, "key in cache", key);
3358
3552
  return (await this.instanceCache[key]).nextInstance();
3359
3553
  }
3360
3554
  return void 0;
@@ -3363,13 +3557,17 @@ var InstanceManager = class {
3363
3557
  if (key in this.instanceCache) {
3364
3558
  return await this.get(key);
3365
3559
  }
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];
3560
+ console.debug(p8, "key not in cache", key);
3561
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3562
+ this.instanceCache[key] = pending;
3563
+ try {
3564
+ return await pending;
3565
+ } catch (error) {
3566
+ if (this.instanceCache[key] === pending) {
3567
+ delete this.instanceCache[key];
3568
+ }
3569
+ throw error;
3570
+ }
3373
3571
  }
3374
3572
  reset() {
3375
3573
  for (let instanceCacheKey in this.instanceCache) {
@@ -3423,7 +3621,7 @@ function isQuadArray(obj) {
3423
3621
  }
3424
3622
 
3425
3623
  // src/model/scene/ModelObject.ts
3426
- import { BoxGeometry as BoxGeometry5, Matrix4 as Matrix45 } from "three";
3624
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute4, Color as Color3, Euler as Euler4, Matrix4 as Matrix45 } from "three";
3427
3625
 
3428
3626
  // src/three/BufferGeometryUtils.js
3429
3627
  import {
@@ -3435,7 +3633,7 @@ import {
3435
3633
  TriangleFanDrawMode,
3436
3634
  TriangleStripDrawMode,
3437
3635
  TrianglesDrawMode,
3438
- Vector3 as Vector35
3636
+ Vector3 as Vector36
3439
3637
  } from "three";
3440
3638
  function computeTangents(geometry) {
3441
3639
  geometry.computeTangents();
@@ -3754,15 +3952,15 @@ function computeMorphedAttributes(object) {
3754
3952
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
3755
3953
  return null;
3756
3954
  }
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();
3955
+ const _vA = new Vector36();
3956
+ const _vB = new Vector36();
3957
+ const _vC = new Vector36();
3958
+ const _tempA = new Vector36();
3959
+ const _tempB = new Vector36();
3960
+ const _tempC = new Vector36();
3961
+ const _morphA = new Vector36();
3962
+ const _morphB = new Vector36();
3963
+ const _morphC = new Vector36();
3766
3964
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
3767
3965
  _vA.fromBufferAttribute(attribute, a2);
3768
3966
  _vB.fromBufferAttribute(attribute, b2);
@@ -3968,15 +4166,16 @@ function computeMorphedAttributes(object) {
3968
4166
  }
3969
4167
 
3970
4168
  // src/model/scene/ModelObject.ts
3971
- var import_ts_deepmerge6 = __toESM(require_dist());
3972
- var p10 = prefix("ModelObject");
4169
+ var import_ts_deepmerge5 = __toESM(require_dist());
4170
+ var p9 = prefix("ModelObject");
3973
4171
  var _ModelObject = class _ModelObject extends SceneObject {
3974
4172
  constructor(originalModel, options) {
3975
4173
  super(options);
3976
4174
  this.originalModel = originalModel;
3977
4175
  this.isModelObject = true;
3978
4176
  this.meshesCreated = false;
3979
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4177
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4178
+ if (this.options.tints) this.options.tints = { ...this.options.tints };
3980
4179
  console.log("ModelObject options", this.options);
3981
4180
  }
3982
4181
  async init() {
@@ -4003,6 +4202,23 @@ var _ModelObject = class _ModelObject extends SceneObject {
4003
4202
  if (this.atlas.model.elements) {
4004
4203
  this.atlas.model.elements?.forEach((el) => {
4005
4204
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4205
+ if (this.options.uvLockRotation) {
4206
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler4(...this.options.uvLockRotation));
4207
+ }
4208
+ if (this.options.tints) {
4209
+ const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
4210
+ for (const [faceIndex, faceName] of CUBE_FACES.entries()) {
4211
+ const tintIndex = el.faces[faceName]?.tintindex;
4212
+ if (tintIndex === void 0 || tintIndex < 0) continue;
4213
+ const tint = this.options.tints[tintIndex];
4214
+ if (tint === void 0) continue;
4215
+ const color = new Color3(tint);
4216
+ for (let vertex = 0; vertex < 4; vertex++) {
4217
+ color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4218
+ }
4219
+ }
4220
+ elGeo.setAttribute("color", new BufferAttribute4(colors, 3));
4221
+ }
4006
4222
  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
4223
  elGeo.applyMatrix4(new Matrix45().makeTranslation(el.from[0], el.from[1], el.from[2]));
4008
4224
  if (el.rotation) {
@@ -4019,10 +4235,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
4019
4235
  }
4020
4236
  });
4021
4237
  } else {
4022
- console.debug(p10, this.atlas.model, "has no elements");
4238
+ console.debug(p9, this.atlas.model, "has no elements");
4023
4239
  }
4024
4240
  } else {
4025
- console.debug(p10, "Missing atlas for", this);
4241
+ console.debug(p9, "Missing atlas for", this);
4026
4242
  }
4027
4243
  if (this.options.mergeMeshes) {
4028
4244
  let combinedGeo;
@@ -4059,6 +4275,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4059
4275
  /*TODO: get this from render options*/
4060
4276
  );
4061
4277
  this.iterateAllMeshes((mesh) => {
4278
+ if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
4062
4279
  mesh.material = mat;
4063
4280
  });
4064
4281
  if (this.atlas.hasAnimation) {
@@ -4074,16 +4291,26 @@ var _ModelObject = class _ModelObject extends SceneObject {
4074
4291
  }
4075
4292
  }
4076
4293
  };
4077
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4294
+ _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4078
4295
  var ModelObject = _ModelObject;
4079
4296
  function isModelObject(obj) {
4080
4297
  return obj.isModelObject;
4081
4298
  }
4082
4299
 
4083
4300
  // 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");
4301
+ var import_ts_deepmerge6 = __toESM(require_dist());
4302
+ import { Euler as Euler5, Matrix4 as Matrix46, Vector3 as Vector37 } from "three";
4303
+ var p10 = prefix("BlockObject");
4304
+ function matchesCondition(condition, state) {
4305
+ return Object.entries(condition).every(([key, value]) => {
4306
+ if (Array.isArray(value)) {
4307
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4308
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4309
+ return false;
4310
+ }
4311
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4312
+ });
4313
+ }
4087
4314
  var _BlockObject = class _BlockObject extends SceneObject {
4088
4315
  constructor(blockState, options) {
4089
4316
  super(options);
@@ -4097,11 +4324,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4097
4324
  this._instanceModel = [];
4098
4325
  this._variants = [];
4099
4326
  this._models = [];
4100
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4327
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4101
4328
  }
4102
4329
  async init() {
4103
4330
  if (this.options.applyDefaultState) {
4104
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4331
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4105
4332
  if (defaultState && Object.keys(defaultState).length > 0) {
4106
4333
  const state = {};
4107
4334
  for (let k in defaultState) {
@@ -4112,15 +4339,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
4112
4339
  if (this.blockState.variants) {
4113
4340
  await this.setState(Object.keys(this.blockState.variants)[0]);
4114
4341
  } 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
- }
4342
+ const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4343
+ const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4344
+ await this.setState(state);
4124
4345
  }
4125
4346
  }
4126
4347
  } else {
@@ -4135,7 +4356,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4135
4356
  if (isModelObject(model)) {
4136
4357
  model.removeFromScene();
4137
4358
  } else if (isInstanceReference(model)) {
4138
- model.setScale(new Vector36(0, 0, 0));
4359
+ model.setScale(new Vector37(0, 0, 0));
4139
4360
  }
4140
4361
  }
4141
4362
  super.removeFromScene();
@@ -4177,55 +4398,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4177
4398
  } else if (this.blockState.multipart) {
4178
4399
  for (let part of this.blockState.multipart) {
4179
4400
  if (!part.apply) {
4180
- console.debug(p11, "Missing apply for blockState part", part);
4401
+ console.debug(p10, "Missing apply for blockState part", part);
4181
4402
  continue;
4182
4403
  }
4183
- if (!part.when) {
4404
+ if (!part.when || matchesCondition(part.when, state)) {
4184
4405
  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
4406
  }
4230
4407
  }
4231
4408
  }
@@ -4240,7 +4417,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4240
4417
  }
4241
4418
  for (let model of this._models) {
4242
4419
  if (isInstanceReference(model)) {
4243
- model.setScale(new Vector36(0, 0, 0));
4420
+ model.setScale(new Vector37(0, 0, 0));
4244
4421
  } else {
4245
4422
  model.dispose();
4246
4423
  }
@@ -4255,11 +4432,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
4255
4432
  }
4256
4433
  }
4257
4434
  getSingleVariant(variants) {
4258
- if (Array.isArray(variants)) {
4259
- return variants[0];
4260
- } else {
4261
- return variants;
4262
- }
4435
+ if (!Array.isArray(variants)) return variants;
4436
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4437
+ const total = variants.reduce((sum, variant) => {
4438
+ const weight = variant.weight ?? 1;
4439
+ if (!Number.isInteger(weight) || weight < 1) {
4440
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4441
+ }
4442
+ return sum + weight;
4443
+ }, 0);
4444
+ let choice = Math.random() * total;
4445
+ for (const variant of variants) {
4446
+ choice -= variant.weight ?? 1;
4447
+ if (choice < 0) return variant;
4448
+ }
4449
+ return variants[variants.length - 1];
4263
4450
  }
4264
4451
  // @deprecated
4265
4452
  async createAVariant(variants, instanceInfo) {
@@ -4267,28 +4454,24 @@ var _BlockObject = class _BlockObject extends SceneObject {
4267
4454
  await this.createVariant(variant);
4268
4455
  }
4269
4456
  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);
4457
+ const rotation = new Euler5();
4277
4458
  if (typeof variant.x !== "undefined") {
4278
4459
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4279
4460
  }
4280
4461
  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
- }
4462
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4463
+ }
4464
+ const model = await Models.getMerged(AssetKey.parse("models", variant.model));
4465
+ const options = {
4466
+ ...this.options,
4467
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4468
+ };
4469
+ const obj = await this.scene.addModel(model, options);
4470
+ if (isInstanceReference(obj) || obj.isInstanced) {
4471
+ this._isInstanced = true;
4472
+ this._instanceCounter = 1;
4286
4473
  }
4287
4474
  obj.setRotation(rotation);
4288
- setTimeout(() => {
4289
- obj.setRotation(rotation);
4290
- }, 150);
4291
- console.log(obj);
4292
4475
  return obj;
4293
4476
  }
4294
4477
  async resetState() {
@@ -4378,15 +4561,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4378
4561
  }
4379
4562
  }
4380
4563
  setPosition(position) {
4381
- super.setPosition(position);
4564
+ this.position.copy(position);
4382
4565
  for (let model of this._models) {
4383
4566
  model.setPosition(position);
4384
4567
  }
4568
+ this.notifyDirty();
4385
4569
  }
4386
4570
  //TODO: should override rotation + scale methods
4387
4571
  //TODO
4388
4572
  };
4389
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4573
+ _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4390
4574
  applyDefaultState: true
4391
4575
  });
4392
4576
  var BlockObject = _BlockObject;
@@ -4436,7 +4620,7 @@ var StructureParser = class {
4436
4620
 
4437
4621
  // src/renderer/MineRenderScene.ts
4438
4622
  import { Scene as Scene2 } from "three";
4439
- var import_ts_deepmerge9 = __toESM(require_dist());
4623
+ var import_ts_deepmerge8 = __toESM(require_dist());
4440
4624
 
4441
4625
  // src/skin/SkinPart.ts
4442
4626
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5167,7 +5351,7 @@ var slimSkinGeometries = {
5167
5351
  };
5168
5352
 
5169
5353
  // src/skin/scene/SkinObject.ts
5170
- var import_ts_deepmerge8 = __toESM(require_dist());
5354
+ var import_ts_deepmerge7 = __toESM(require_dist());
5171
5355
  var SkinObject = class extends SceneObject {
5172
5356
  constructor(options) {
5173
5357
  super();
@@ -5175,7 +5359,7 @@ var SkinObject = class extends SceneObject {
5175
5359
  this.legacy = false;
5176
5360
  this.skinTextureWidth = 64;
5177
5361
  this.skinTextureHeight = 64;
5178
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5362
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5179
5363
  }
5180
5364
  async init() {
5181
5365
  this.createMeshes();
@@ -5292,7 +5476,7 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5292
5476
  this.dirty = true;
5293
5477
  }
5294
5478
  };
5295
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5479
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5296
5480
  }
5297
5481
  add(...objects) {
5298
5482
  for (const object of objects) {
@@ -5350,7 +5534,13 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5350
5534
  const obj = await objectSupplier();
5351
5535
  if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5352
5536
  console.log("instanceMeshes + key");
5353
- const key = asset.key.serialize();
5537
+ let key = asset.key.serialize();
5538
+ if (isModelObject(obj)) {
5539
+ const { uvLockRotation, tints } = obj.options;
5540
+ if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
5541
+ const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
5542
+ if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
5543
+ }
5354
5544
  return this.instanceManager.getOrCreate(key, async () => {
5355
5545
  obj.scene = this;
5356
5546
  await obj.init();
@@ -5388,1121 +5578,1178 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5388
5578
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5389
5579
  }
5390
5580
  };
5391
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5581
+ _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5392
5582
  var MineRenderScene = _MineRenderScene;
5393
5583
  function isMineRenderScene(obj) {
5394
5584
  return obj.isMineRenderScene;
5395
5585
  }
5396
5586
 
5397
5587
  // 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());
5588
+ import { AxesHelper as AxesHelper3, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector39, WebGLRenderer } from "three";
5589
+ var import_ts_deepmerge9 = __toESM(require_dist());
5400
5590
  import Stats from "stats.js";
5401
5591
  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;
5592
+
5593
+ // src/three/OrbitControls.js
5594
+ import {
5595
+ EventDispatcher,
5596
+ MOUSE,
5597
+ Quaternion as Quaternion3,
5598
+ Spherical,
5599
+ TOUCH,
5600
+ Vector2 as Vector23,
5601
+ Vector3 as Vector38
5602
+ } from "three";
5603
+ var _changeEvent = { type: "change" };
5604
+ var _startEvent = { type: "start" };
5605
+ var _endEvent = { type: "end" };
5606
+ var OrbitControls = class extends EventDispatcher {
5607
+ constructor(object, domElement) {
5608
+ super();
5609
+ if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5610
+ if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5611
+ this.object = object;
5612
+ this.domElement = domElement;
5613
+ this.domElement.style.touchAction = "none";
5614
+ this.enabled = true;
5615
+ this.target = new Vector38();
5616
+ this.minDistance = 0;
5617
+ this.maxDistance = Infinity;
5618
+ this.minZoom = 0;
5619
+ this.maxZoom = Infinity;
5620
+ this.minPolarAngle = 0;
5621
+ this.maxPolarAngle = Math.PI;
5622
+ this.minAzimuthAngle = -Infinity;
5623
+ this.maxAzimuthAngle = Infinity;
5624
+ this.enableDamping = false;
5625
+ this.dampingFactor = 0.05;
5626
+ this.enableZoom = true;
5627
+ this.zoomSpeed = 1;
5628
+ this.enableRotate = true;
5629
+ this.rotateSpeed = 1;
5630
+ this.enablePan = true;
5631
+ this.panSpeed = 1;
5632
+ this.screenSpacePanning = true;
5633
+ this.keyPanSpeed = 7;
5634
+ this.autoRotate = false;
5635
+ this.autoRotateSpeed = 2;
5636
+ this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5637
+ this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
5638
+ this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
5639
+ this.target0 = this.target.clone();
5640
+ this.position0 = this.object.position.clone();
5641
+ this.zoom0 = this.object.zoom;
5642
+ this._domElementKeyEvents = null;
5643
+ this.getPolarAngle = function() {
5644
+ return spherical.phi;
5413
5645
  };
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);
5646
+ this.getAzimuthalAngle = function() {
5647
+ return spherical.theta;
5648
+ };
5649
+ this.getDistance = function() {
5650
+ return this.object.position.distanceTo(this.target);
5651
+ };
5652
+ this.saveState = function() {
5653
+ scope.target0.copy(scope.target);
5654
+ scope.position0.copy(scope.object.position);
5655
+ scope.zoom0 = scope.object.zoom;
5656
+ };
5657
+ this.reset = function() {
5658
+ scope.target.copy(scope.target0);
5659
+ scope.object.position.copy(scope.position0);
5660
+ scope.object.zoom = scope.zoom0;
5661
+ scope.object.updateProjectionMatrix();
5662
+ scope.dispatchEvent(_changeEvent);
5663
+ scope.update();
5664
+ state = STATE.NONE;
5665
+ };
5666
+ this.update = function() {
5667
+ const offset = new Vector38();
5668
+ const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector38(0, 1, 0));
5669
+ const quatInverse = quat.clone().invert();
5670
+ const lastPosition = new Vector38();
5671
+ const lastQuaternion = new Quaternion3();
5672
+ const twoPI = 2 * Math.PI;
5673
+ return function update() {
5674
+ const position = scope.object.position;
5675
+ offset.copy(position).sub(scope.target);
5676
+ offset.applyQuaternion(quat);
5677
+ spherical.setFromVector3(offset);
5678
+ if (scope.autoRotate && state === STATE.NONE) {
5679
+ rotateLeft(getAutoRotationAngle());
5680
+ }
5681
+ if (scope.enableDamping) {
5682
+ spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5683
+ spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5684
+ } else {
5685
+ spherical.theta += sphericalDelta.theta;
5686
+ spherical.phi += sphericalDelta.phi;
5687
+ }
5688
+ let min = scope.minAzimuthAngle;
5689
+ let max = scope.maxAzimuthAngle;
5690
+ if (isFinite(min) && isFinite(max)) {
5691
+ if (min < -Math.PI) min += twoPI;
5692
+ else if (min > Math.PI) min -= twoPI;
5693
+ if (max < -Math.PI) max += twoPI;
5694
+ else if (max > Math.PI) max -= twoPI;
5695
+ if (min <= max) {
5696
+ spherical.theta = Math.max(min, Math.min(max, spherical.theta));
5697
+ } else {
5698
+ spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
5699
+ }
5700
+ }
5701
+ spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5702
+ spherical.makeSafe();
5703
+ spherical.radius *= scale;
5704
+ spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5705
+ if (scope.enableDamping === true) {
5706
+ scope.target.addScaledVector(panOffset, scope.dampingFactor);
5707
+ } else {
5708
+ scope.target.add(panOffset);
5709
+ }
5710
+ offset.setFromSpherical(spherical);
5711
+ offset.applyQuaternion(quatInverse);
5712
+ position.copy(scope.target).add(offset);
5713
+ scope.object.lookAt(scope.target);
5714
+ if (scope.enableDamping === true) {
5715
+ sphericalDelta.theta *= 1 - scope.dampingFactor;
5716
+ sphericalDelta.phi *= 1 - scope.dampingFactor;
5717
+ panOffset.multiplyScalar(1 - scope.dampingFactor);
5718
+ } else {
5719
+ sphericalDelta.set(0, 0, 0);
5720
+ panOffset.set(0, 0, 0);
5721
+ }
5722
+ scale = 1;
5723
+ if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5724
+ scope.dispatchEvent(_changeEvent);
5725
+ lastPosition.copy(scope.object.position);
5726
+ lastQuaternion.copy(scope.object.quaternion);
5727
+ zoomChanged = false;
5728
+ return true;
5729
+ }
5730
+ return false;
5731
+ };
5732
+ }();
5733
+ this.dispose = function() {
5734
+ scope.domElement.removeEventListener("contextmenu", onContextMenu);
5735
+ scope.domElement.removeEventListener("pointerdown", onPointerDown);
5736
+ scope.domElement.removeEventListener("pointercancel", onPointerCancel);
5737
+ scope.domElement.removeEventListener("wheel", onMouseWheel);
5738
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
5739
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5740
+ if (scope._domElementKeyEvents !== null) {
5741
+ scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
5742
+ }
5743
+ };
5744
+ const scope = this;
5745
+ const STATE = {
5746
+ NONE: -1,
5747
+ ROTATE: 0,
5748
+ DOLLY: 1,
5749
+ PAN: 2,
5750
+ TOUCH_ROTATE: 3,
5751
+ TOUCH_PAN: 4,
5752
+ TOUCH_DOLLY_PAN: 5,
5753
+ TOUCH_DOLLY_ROTATE: 6
5754
+ };
5755
+ let state = STATE.NONE;
5756
+ const EPS = 1e-6;
5757
+ const spherical = new Spherical();
5758
+ const sphericalDelta = new Spherical();
5759
+ let scale = 1;
5760
+ const panOffset = new Vector38();
5761
+ let zoomChanged = false;
5762
+ const rotateStart = new Vector23();
5763
+ const rotateEnd = new Vector23();
5764
+ const rotateDelta = new Vector23();
5765
+ const panStart = new Vector23();
5766
+ const panEnd = new Vector23();
5767
+ const panDelta = new Vector23();
5768
+ const dollyStart = new Vector23();
5769
+ const dollyEnd = new Vector23();
5770
+ const dollyDelta = new Vector23();
5771
+ const pointers = [];
5772
+ const pointerPositions = {};
5773
+ function getAutoRotationAngle() {
5774
+ return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
5424
5775
  }
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 }));
5776
+ function getZoomScale() {
5777
+ return Math.pow(0.95, scope.zoomSpeed);
5478
5778
  }
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);
5779
+ function rotateLeft(angle) {
5780
+ sphericalDelta.theta -= angle;
5491
5781
  }
5492
- if (this.options.debug.axes) {
5493
- const axesHelper = new AxesHelper3(64);
5494
- this._debugHelpers.push(axesHelper);
5495
- this.scene.add(axesHelper);
5782
+ function rotateUp(angle) {
5783
+ sphericalDelta.phi -= angle;
5496
5784
  }
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]);
5785
+ const panLeft = function() {
5786
+ const v = new Vector38();
5787
+ return function panLeft2(distance, objectMatrix) {
5788
+ v.setFromMatrixColumn(objectMatrix, 0);
5789
+ v.multiplyScalar(-distance);
5790
+ panOffset.add(v);
5791
+ };
5792
+ }();
5793
+ const panUp = function() {
5794
+ const v = new Vector38();
5795
+ return function panUp2(distance, objectMatrix) {
5796
+ if (scope.screenSpacePanning === true) {
5797
+ v.setFromMatrixColumn(objectMatrix, 1);
5798
+ } else {
5799
+ v.setFromMatrixColumn(objectMatrix, 0);
5800
+ v.crossVectors(scope.object.up, v);
5801
+ }
5802
+ v.multiplyScalar(distance);
5803
+ panOffset.add(v);
5804
+ };
5805
+ }();
5806
+ const pan = function() {
5807
+ const offset = new Vector38();
5808
+ return function pan2(deltaX, deltaY) {
5809
+ const element = scope.domElement;
5810
+ if (scope.object.isPerspectiveCamera) {
5811
+ const position = scope.object.position;
5812
+ offset.copy(position).sub(scope.target);
5813
+ let targetDistance = offset.length();
5814
+ targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
5815
+ panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
5816
+ panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
5817
+ } else if (scope.object.isOrthographicCamera) {
5818
+ panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
5819
+ panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
5820
+ } else {
5821
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
5822
+ scope.enablePan = false;
5823
+ }
5824
+ };
5825
+ }();
5826
+ function dollyOut(dollyScale) {
5827
+ if (scope.object.isPerspectiveCamera) {
5828
+ scale /= dollyScale;
5829
+ } else if (scope.object.isOrthographicCamera) {
5830
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
5831
+ scope.object.updateProjectionMatrix();
5832
+ zoomChanged = true;
5833
+ } else {
5834
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
5835
+ scope.enableZoom = false;
5502
5836
  }
5503
5837
  }
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]);
5838
+ function dollyIn(dollyScale) {
5839
+ if (scope.object.isPerspectiveCamera) {
5840
+ scale *= dollyScale;
5841
+ } else if (scope.object.isOrthographicCamera) {
5842
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
5843
+ scope.object.updateProjectionMatrix();
5844
+ zoomChanged = true;
5845
+ } else {
5846
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
5847
+ scope.enableZoom = false;
5509
5848
  }
5510
5849
  }
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);
5850
+ function handleMouseDownRotate(event) {
5851
+ rotateStart.set(event.clientX, event.clientY);
5516
5852
  }
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");
5853
+ function handleMouseDownDolly(event) {
5854
+ dollyStart.set(event.clientX, event.clientY);
5527
5855
  }
5528
- if (this.viewHeight == 0) {
5529
- console.warn("0 element height");
5856
+ function handleMouseDownPan(event) {
5857
+ panStart.set(event.clientX, event.clientY);
5530
5858
  }
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);
5859
+ function handleMouseMoveRotate(event) {
5860
+ rotateEnd.set(event.clientX, event.clientY);
5861
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
5862
+ const element = scope.domElement;
5863
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
5864
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
5865
+ rotateStart.copy(rotateEnd);
5866
+ scope.update();
5543
5867
  }
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();
5868
+ function handleMouseMoveDolly(event) {
5869
+ dollyEnd.set(event.clientX, event.clientY);
5870
+ dollyDelta.subVectors(dollyEnd, dollyStart);
5871
+ if (dollyDelta.y > 0) {
5872
+ dollyOut(getZoomScale());
5873
+ } else if (dollyDelta.y < 0) {
5874
+ dollyIn(getZoomScale());
5875
+ }
5876
+ dollyStart.copy(dollyEnd);
5877
+ scope.update();
5559
5878
  }
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;
5879
+ function handleMouseMovePan(event) {
5880
+ panEnd.set(event.clientX, event.clientY);
5881
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
5882
+ pan(panDelta.x, panDelta.y);
5883
+ panStart.copy(panEnd);
5884
+ scope.update();
5599
5885
  }
5600
- for (const [dispatcher, events] of this._eventDispatchers) {
5601
- for (const event of events) {
5602
- dispatcher.removeEventListener(event, this._changeListener);
5603
- }
5886
+ function handleMouseUp() {
5604
5887
  }
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();
5888
+ function handleMouseWheel(event) {
5889
+ if (event.deltaY < 0) {
5890
+ dollyIn(getZoomScale());
5891
+ } else if (event.deltaY > 0) {
5892
+ dollyOut(getZoomScale());
5616
5893
  }
5894
+ scope.update();
5617
5895
  }
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();
5896
+ function handleKeyDown(event) {
5897
+ let needsUpdate = false;
5898
+ switch (event.code) {
5899
+ case scope.keys.UP:
5900
+ pan(0, scope.keyPanSpeed);
5901
+ needsUpdate = true;
5902
+ break;
5903
+ case scope.keys.BOTTOM:
5904
+ pan(0, -scope.keyPanSpeed);
5905
+ needsUpdate = true;
5906
+ break;
5907
+ case scope.keys.LEFT:
5908
+ pan(scope.keyPanSpeed, 0);
5909
+ needsUpdate = true;
5910
+ break;
5911
+ case scope.keys.RIGHT:
5912
+ pan(-scope.keyPanSpeed, 0);
5913
+ needsUpdate = true;
5914
+ break;
5915
+ }
5916
+ if (needsUpdate) {
5917
+ event.preventDefault();
5918
+ scope.update();
5919
+ }
5627
5920
  }
5628
- if (this.dirty || this.options.render.renderAlways) {
5629
- if (this.options.composer.enabled) {
5630
- this.composer.render();
5921
+ function handleTouchStartRotate() {
5922
+ if (pointers.length === 1) {
5923
+ rotateStart.set(pointers[0].pageX, pointers[0].pageY);
5631
5924
  } else {
5632
- this.renderer.render(this.scene, this.camera);
5925
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
5926
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
5927
+ rotateStart.set(x, y);
5633
5928
  }
5634
5929
  }
5635
- this.dirty = false;
5636
- if (this._stats) {
5637
- this._stats.end();
5930
+ function handleTouchStartPan() {
5931
+ if (pointers.length === 1) {
5932
+ panStart.set(pointers[0].pageX, pointers[0].pageY);
5933
+ } else {
5934
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
5935
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
5936
+ panStart.set(x, y);
5937
+ }
5638
5938
  }
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);
5939
+ function handleTouchStartDolly() {
5940
+ const dx = pointers[0].pageX - pointers[1].pageX;
5941
+ const dy = pointers[0].pageY - pointers[1].pageY;
5942
+ const distance = Math.sqrt(dx * dx + dy * dy);
5943
+ dollyStart.set(0, distance);
5710
5944
  }
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"];
5945
+ function handleTouchStartDollyPan() {
5946
+ if (scope.enableZoom) handleTouchStartDolly();
5947
+ if (scope.enablePan) handleTouchStartPan();
5948
+ }
5949
+ function handleTouchStartDollyRotate() {
5950
+ if (scope.enableZoom) handleTouchStartDolly();
5951
+ if (scope.enableRotate) handleTouchStartRotate();
5952
+ }
5953
+ function handleTouchMoveRotate(event) {
5954
+ if (pointers.length == 1) {
5955
+ rotateEnd.set(event.pageX, event.pageY);
5956
+ } else {
5957
+ const position = getSecondPointerPosition(event);
5958
+ const x = 0.5 * (event.pageX + position.x);
5959
+ const y = 0.5 * (event.pageY + position.y);
5960
+ rotateEnd.set(x, y);
5728
5961
  }
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);
5962
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
5963
+ const element = scope.domElement;
5964
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
5965
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
5966
+ rotateStart.copy(rotateEnd);
5737
5967
  }
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);
5968
+ function handleTouchMovePan(event) {
5969
+ if (pointers.length === 1) {
5970
+ panEnd.set(event.pageX, event.pageY);
5971
+ } else {
5972
+ const position = getSecondPointerPosition(event);
5973
+ const x = 0.5 * (event.pageX + position.x);
5974
+ const y = 0.5 * (event.pageY + position.y);
5975
+ panEnd.set(x, y);
5747
5976
  }
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;
5977
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
5978
+ pan(panDelta.x, panDelta.y);
5979
+ panStart.copy(panEnd);
5980
+ }
5981
+ function handleTouchMoveDolly(event) {
5982
+ const position = getSecondPointerPosition(event);
5983
+ const dx = event.pageX - position.x;
5984
+ const dy = event.pageY - position.y;
5985
+ const distance = Math.sqrt(dx * dx + dy * dy);
5986
+ dollyEnd.set(0, distance);
5987
+ dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
5988
+ dollyOut(dollyDelta.y);
5989
+ dollyStart.copy(dollyEnd);
5990
+ }
5991
+ function handleTouchMoveDollyPan(event) {
5992
+ if (scope.enableZoom) handleTouchMoveDolly(event);
5993
+ if (scope.enablePan) handleTouchMovePan(event);
5994
+ }
5995
+ function handleTouchMoveDollyRotate(event) {
5996
+ if (scope.enableZoom) handleTouchMoveDolly(event);
5997
+ if (scope.enableRotate) handleTouchMoveRotate(event);
5998
+ }
5999
+ function handleTouchEnd() {
6000
+ }
6001
+ function onPointerDown(event) {
6002
+ if (scope.enabled === false) return;
6003
+ if (pointers.length === 0) {
6004
+ scope.domElement.setPointerCapture(event.pointerId);
6005
+ scope.domElement.addEventListener("pointermove", onPointerMove);
6006
+ scope.domElement.addEventListener("pointerup", onPointerUp);
5755
6007
  }
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"];
6008
+ addPointer(event);
6009
+ if (event.pointerType === "touch") {
6010
+ onTouchStart(event);
6011
+ } else {
6012
+ onMouseDown(event);
5771
6013
  }
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"];
6014
+ }
6015
+ function onPointerMove(event) {
6016
+ if (scope.enabled === false) return;
6017
+ if (event.pointerType === "touch") {
6018
+ onTouchMove(event);
6019
+ } else {
6020
+ onMouseMove(event);
5785
6021
  }
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;
6022
+ }
6023
+ function onPointerUp(event) {
6024
+ if (scope.enabled === false) return;
6025
+ if (event.pointerType === "touch") {
6026
+ onTouchEnd();
6027
+ } else {
6028
+ onMouseUp(event);
5799
6029
  }
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;
6030
+ removePointer(event);
6031
+ if (pointers.length === 0) {
6032
+ scope.domElement.releasePointerCapture(event.pointerId);
6033
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
6034
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5809
6035
  }
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;
6036
+ }
6037
+ function onPointerCancel(event) {
6038
+ removePointer(event);
6039
+ }
6040
+ function onMouseDown(event) {
6041
+ let mouseAction;
6042
+ switch (event.button) {
6043
+ case 0:
6044
+ mouseAction = scope.mouseButtons.LEFT;
6045
+ break;
6046
+ case 1:
6047
+ mouseAction = scope.mouseButtons.MIDDLE;
6048
+ break;
6049
+ case 2:
6050
+ mouseAction = scope.mouseButtons.RIGHT;
6051
+ break;
6052
+ default:
6053
+ mouseAction = -1;
5823
6054
  }
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));
6055
+ switch (mouseAction) {
6056
+ case MOUSE.DOLLY:
6057
+ if (scope.enableZoom === false) return;
6058
+ handleMouseDownDolly(event);
6059
+ state = STATE.DOLLY;
6060
+ break;
6061
+ case MOUSE.ROTATE:
6062
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
6063
+ if (scope.enablePan === false) return;
6064
+ handleMouseDownPan(event);
6065
+ state = STATE.PAN;
5955
6066
  } else {
5956
- spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
6067
+ if (scope.enableRotate === false) return;
6068
+ handleMouseDownRotate(event);
6069
+ state = STATE.ROTATE;
5957
6070
  }
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);
6071
+ break;
6072
+ case MOUSE.PAN:
6073
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
6074
+ if (scope.enableRotate === false) return;
6075
+ handleMouseDownRotate(event);
6076
+ state = STATE.ROTATE;
6077
+ } else {
6078
+ if (scope.enablePan === false) return;
6079
+ handleMouseDownPan(event);
6080
+ state = STATE.PAN;
6081
+ }
6082
+ break;
6083
+ default:
6084
+ state = STATE.NONE;
6085
+ }
6086
+ if (state !== STATE.NONE) {
6087
+ scope.dispatchEvent(_startEvent);
6000
6088
  }
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
6089
  }
6034
- function getZoomScale() {
6035
- return Math.pow(0.95, scope.zoomSpeed);
6090
+ function onMouseMove(event) {
6091
+ if (scope.enabled === false) return;
6092
+ switch (state) {
6093
+ case STATE.ROTATE:
6094
+ if (scope.enableRotate === false) return;
6095
+ handleMouseMoveRotate(event);
6096
+ break;
6097
+ case STATE.DOLLY:
6098
+ if (scope.enableZoom === false) return;
6099
+ handleMouseMoveDolly(event);
6100
+ break;
6101
+ case STATE.PAN:
6102
+ if (scope.enablePan === false) return;
6103
+ handleMouseMovePan(event);
6104
+ break;
6105
+ }
6036
6106
  }
6037
- function rotateLeft(angle) {
6038
- sphericalDelta.theta -= angle;
6107
+ function onMouseUp(event) {
6108
+ handleMouseUp(event);
6109
+ scope.dispatchEvent(_endEvent);
6110
+ state = STATE.NONE;
6039
6111
  }
6040
- function rotateUp(angle) {
6041
- sphericalDelta.phi -= angle;
6112
+ function onMouseWheel(event) {
6113
+ if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE) return;
6114
+ event.preventDefault();
6115
+ scope.dispatchEvent(_startEvent);
6116
+ handleMouseWheel(event);
6117
+ scope.dispatchEvent(_endEvent);
6042
6118
  }
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;
6119
+ function onKeyDown(event) {
6120
+ if (scope.enabled === false || scope.enablePan === false) return;
6121
+ handleKeyDown(event);
6122
+ }
6123
+ function onTouchStart(event) {
6124
+ trackPointer(event);
6125
+ switch (pointers.length) {
6126
+ case 1:
6127
+ switch (scope.touches.ONE) {
6128
+ case TOUCH.ROTATE:
6129
+ if (scope.enableRotate === false) return;
6130
+ handleTouchStartRotate();
6131
+ state = STATE.TOUCH_ROTATE;
6132
+ break;
6133
+ case TOUCH.PAN:
6134
+ if (scope.enablePan === false) return;
6135
+ handleTouchStartPan();
6136
+ state = STATE.TOUCH_PAN;
6137
+ break;
6138
+ default:
6139
+ state = STATE.NONE;
6140
+ }
6141
+ break;
6142
+ case 2:
6143
+ switch (scope.touches.TWO) {
6144
+ case TOUCH.DOLLY_PAN:
6145
+ if (scope.enableZoom === false && scope.enablePan === false) return;
6146
+ handleTouchStartDollyPan();
6147
+ state = STATE.TOUCH_DOLLY_PAN;
6148
+ break;
6149
+ case TOUCH.DOLLY_ROTATE:
6150
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
6151
+ handleTouchStartDollyRotate();
6152
+ state = STATE.TOUCH_DOLLY_ROTATE;
6153
+ break;
6154
+ default:
6155
+ state = STATE.NONE;
6156
+ }
6157
+ break;
6158
+ default:
6159
+ state = STATE.NONE;
6160
+ }
6161
+ if (state !== STATE.NONE) {
6162
+ scope.dispatchEvent(_startEvent);
6163
+ }
6164
+ }
6165
+ function onTouchMove(event) {
6166
+ trackPointer(event);
6167
+ switch (state) {
6168
+ case STATE.TOUCH_ROTATE:
6169
+ if (scope.enableRotate === false) return;
6170
+ handleTouchMoveRotate(event);
6171
+ scope.update();
6172
+ break;
6173
+ case STATE.TOUCH_PAN:
6174
+ if (scope.enablePan === false) return;
6175
+ handleTouchMovePan(event);
6176
+ scope.update();
6177
+ break;
6178
+ case STATE.TOUCH_DOLLY_PAN:
6179
+ if (scope.enableZoom === false && scope.enablePan === false) return;
6180
+ handleTouchMoveDollyPan(event);
6181
+ scope.update();
6182
+ break;
6183
+ case STATE.TOUCH_DOLLY_ROTATE:
6184
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
6185
+ handleTouchMoveDollyRotate(event);
6186
+ scope.update();
6187
+ break;
6188
+ default:
6189
+ state = STATE.NONE;
6190
+ }
6191
+ }
6192
+ function onTouchEnd(event) {
6193
+ handleTouchEnd(event);
6194
+ scope.dispatchEvent(_endEvent);
6195
+ state = STATE.NONE;
6196
+ }
6197
+ function onContextMenu(event) {
6198
+ if (scope.enabled === false) return;
6199
+ event.preventDefault();
6200
+ }
6201
+ function addPointer(event) {
6202
+ pointers.push(event);
6203
+ }
6204
+ function removePointer(event) {
6205
+ delete pointerPositions[event.pointerId];
6206
+ for (let i = 0; i < pointers.length; i++) {
6207
+ if (pointers[i].pointerId == event.pointerId) {
6208
+ pointers.splice(i, 1);
6209
+ return;
6081
6210
  }
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
6211
  }
6095
6212
  }
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;
6213
+ function trackPointer(event) {
6214
+ let position = pointerPositions[event.pointerId];
6215
+ if (position === void 0) {
6216
+ position = new Vector23();
6217
+ pointerPositions[event.pointerId] = position;
6106
6218
  }
6219
+ position.set(event.pageX, event.pageY);
6220
+ }
6221
+ function getSecondPointerPosition(event) {
6222
+ const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6223
+ return pointerPositions[pointer.pointerId];
6224
+ }
6225
+ scope.domElement.addEventListener("contextmenu", onContextMenu);
6226
+ scope.domElement.addEventListener("pointerdown", onPointerDown);
6227
+ scope.domElement.addEventListener("pointercancel", onPointerCancel);
6228
+ scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6229
+ this.update();
6230
+ }
6231
+ };
6232
+ var MapControls = class extends OrbitControls {
6233
+ constructor(object, domElement) {
6234
+ super(object, domElement);
6235
+ this.screenSpacePanning = false;
6236
+ this.mouseButtons.LEFT = MOUSE.PAN;
6237
+ this.mouseButtons.RIGHT = MOUSE.ROTATE;
6238
+ this.touches.ONE = TOUCH.PAN;
6239
+ this.touches.TWO = TOUCH.DOLLY_ROTATE;
6240
+ }
6241
+ };
6242
+
6243
+ // src/renderer/Renderer.ts
6244
+ var _Renderer = class _Renderer {
6245
+ constructor(options) {
6246
+ this._dirty = true;
6247
+ this._resizeListener = void 0;
6248
+ this._disposed = false;
6249
+ this._debugHelpers = [];
6250
+ this._eventDispatchers = /* @__PURE__ */ new Map();
6251
+ this._changeListener = () => {
6252
+ this._dirty = true;
6253
+ };
6254
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6255
+ this._animationLoop = this.animate.bind(this);
6256
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6257
+ this._scene = this.createScene();
6258
+ this._camera = this.createCamera();
6259
+ this._renderer = this.createRenderer();
6260
+ this._composer = this.createComposer();
6261
+ if (this.options.render.stats) {
6262
+ this._stats = new Stats();
6263
+ document.body.appendChild(this._stats.dom);
6107
6264
  }
6108
- function handleMouseDownRotate(event) {
6109
- rotateStart.set(event.clientX, event.clientY);
6265
+ this.init();
6266
+ this._controls = this.createControls();
6267
+ }
6268
+ //<editor-fold desc="INIT">
6269
+ createScene() {
6270
+ return new MineRenderScene();
6271
+ }
6272
+ createCamera() {
6273
+ switch (this.options.camera.type) {
6274
+ case "perspective":
6275
+ default:
6276
+ return new PerspectiveCamera(
6277
+ this.options.camera.perspective.fov,
6278
+ this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6279
+ this.options.camera.near,
6280
+ this.options.camera.far
6281
+ );
6282
+ case "orthographic":
6283
+ return new OrthographicCamera(
6284
+ this.options.camera.orthographic.left ?? this.viewWidth / -2,
6285
+ this.options.camera.orthographic.right ?? this.viewWidth / 2,
6286
+ this.options.camera.orthographic.top ?? this.viewHeight / 2,
6287
+ this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
6288
+ this.options.camera.near,
6289
+ this.options.camera.far
6290
+ );
6110
6291
  }
6111
- function handleMouseDownDolly(event) {
6112
- dollyStart.set(event.clientX, event.clientY);
6292
+ }
6293
+ createRenderer() {
6294
+ const renderer = new WebGLRenderer({
6295
+ antialias: this.options.render.antialias,
6296
+ alpha: true,
6297
+ powerPreference: "high-performance",
6298
+ depth: true
6299
+ });
6300
+ renderer.setClearColor(0, 0);
6301
+ renderer.shadowMap.enabled = true;
6302
+ renderer.shadowMap.type = PCFSoftShadowMap;
6303
+ renderer.outputColorSpace = SRGBColorSpace3;
6304
+ renderer.setSize(this.viewWidth, this.viewHeight);
6305
+ return renderer;
6306
+ }
6307
+ createComposer() {
6308
+ if (!this.options.composer.enabled) return void 0;
6309
+ const composer = new EffectComposer(this.renderer);
6310
+ composer.setSize(this.viewWidth, this.viewHeight);
6311
+ composer.addPass(new RenderPass(this.scene, this.camera));
6312
+ return composer;
6313
+ }
6314
+ createControls() {
6315
+ if (!this.options.controls?.enabled) return void 0;
6316
+ const position = this.camera.position.clone();
6317
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
6318
+ this.camera.position.copy(position);
6319
+ const target = this.options.camera.lookingAt;
6320
+ if (isVector3(target)) {
6321
+ controls.target.copy(target);
6322
+ } else if (isTripleArray(target)) {
6323
+ controls.target.set(target[0], target[1], target[2]);
6324
+ }
6325
+ controls.update();
6326
+ controls.saveState();
6327
+ this.registerEventDispatcher(controls);
6328
+ return controls;
6329
+ }
6330
+ //</editor-fold>
6331
+ init() {
6332
+ if (this._disposed) return;
6333
+ if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
6334
+ window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6113
6335
  }
6114
- function handleMouseDownPan(event) {
6115
- panStart.set(event.clientX, event.clientY);
6336
+ if (this.options.debug.grid) {
6337
+ const gridHelper = new GridHelper(128, 16);
6338
+ this._debugHelpers.push(gridHelper);
6339
+ this.scene.add(gridHelper);
6340
+ const gridHelper2 = new GridHelper(128, 16);
6341
+ this._debugHelpers.push(gridHelper2);
6342
+ gridHelper2.rotation.x = 90 * (Math.PI / 180);
6343
+ this.scene.add(gridHelper2);
6344
+ const gridHelper3 = new GridHelper(128, 16);
6345
+ this._debugHelpers.push(gridHelper3);
6346
+ gridHelper3.rotation.z = 90 * (Math.PI / 180);
6347
+ this.scene.add(gridHelper3);
6116
6348
  }
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();
6349
+ if (this.options.debug.axes) {
6350
+ const axesHelper = new AxesHelper3(64);
6351
+ this._debugHelpers.push(axesHelper);
6352
+ this.scene.add(axesHelper);
6125
6353
  }
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());
6354
+ if (this.options.camera.position) {
6355
+ if (isVector3(this.options.camera.position)) {
6356
+ this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
6357
+ } else if (isTripleArray(this.options.camera.position)) {
6358
+ this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
6133
6359
  }
6134
- dollyStart.copy(dollyEnd);
6135
- scope.update();
6136
6360
  }
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());
6361
+ if (this.options.camera.lookingAt) {
6362
+ if (isVector3(this.options.camera.lookingAt)) {
6363
+ this.camera.lookAt(this.options.camera.lookingAt);
6364
+ } else if (isTripleArray(this.options.camera.lookingAt)) {
6365
+ this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6151
6366
  }
6152
- scope.update();
6153
6367
  }
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
- }
6368
+ if (this.options.render.autoResize && !this._resizeListener) {
6369
+ this._resizeListener = () => {
6370
+ this.resize(this.viewWidth, this.viewHeight);
6371
+ };
6372
+ window.addEventListener("resize", this._resizeListener);
6178
6373
  }
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
- }
6374
+ }
6375
+ get element() {
6376
+ return this._element;
6377
+ }
6378
+ appendTo(element) {
6379
+ if (this._disposed) return;
6380
+ this._element = element;
6381
+ this._element.appendChild(this.renderer.domElement);
6382
+ if (this.viewWidth == 0) {
6383
+ console.warn("0 element width");
6187
6384
  }
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
- }
6385
+ if (this.viewHeight == 0) {
6386
+ console.warn("0 element height");
6196
6387
  }
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);
6388
+ this.resize(this.viewWidth, this.viewHeight);
6389
+ }
6390
+ /**
6391
+ * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
6392
+ * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
6393
+ */
6394
+ registerEventDispatcher(dispatcher, changeEvent2 = "change") {
6395
+ if (this._disposed) return;
6396
+ let events = this._eventDispatchers.get(dispatcher);
6397
+ if (!events) {
6398
+ events = /* @__PURE__ */ new Set();
6399
+ this._eventDispatchers.set(dispatcher, events);
6202
6400
  }
6203
- function handleTouchStartDollyPan() {
6204
- if (scope.enableZoom) handleTouchStartDolly();
6205
- if (scope.enablePan) handleTouchStartPan();
6401
+ if (events.has(changeEvent2)) return;
6402
+ events.add(changeEvent2);
6403
+ dispatcher.addEventListener(changeEvent2, this._changeListener);
6404
+ }
6405
+ resize(width, height) {
6406
+ if (this._disposed) return;
6407
+ if (isPerspectiveCamera(this.camera)) {
6408
+ this.camera.aspect = width / height;
6409
+ this.camera.updateProjectionMatrix();
6410
+ } else if (isOrthographicCamera(this.camera)) {
6411
+ this.camera.left = width / -2;
6412
+ this.camera.right = width / 2;
6413
+ this.camera.top = height / 2;
6414
+ this.camera.bottom = height / -2;
6415
+ this.camera.updateProjectionMatrix();
6206
6416
  }
6207
- function handleTouchStartDollyRotate() {
6208
- if (scope.enableZoom) handleTouchStartDolly();
6209
- if (scope.enableRotate) handleTouchStartRotate();
6417
+ this.renderer.setSize(width, height);
6418
+ this.composer?.setSize(width, height);
6419
+ this._dirty = true;
6420
+ }
6421
+ //<editor-fold desc="RENDER">
6422
+ get dirty() {
6423
+ return this._dirty || this.scene.dirty;
6424
+ }
6425
+ set dirty(dirty) {
6426
+ this._dirty = dirty;
6427
+ this.scene.dirty = dirty;
6428
+ }
6429
+ start() {
6430
+ if (this._disposed) return;
6431
+ this.stop();
6432
+ this.renderer.setAnimationLoop(this._animationLoop);
6433
+ }
6434
+ stop() {
6435
+ if (this._disposed) return;
6436
+ this.renderer.setAnimationLoop(null);
6437
+ this._nextFrameTime = void 0;
6438
+ }
6439
+ /**
6440
+ * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
6441
+ * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
6442
+ * controls must be managed by their owners.
6443
+ */
6444
+ dispose() {
6445
+ if (this._disposed) return;
6446
+ this.stop();
6447
+ this._disposed = true;
6448
+ if (this._resizeListener) {
6449
+ window.removeEventListener("resize", this._resizeListener);
6450
+ this._resizeListener = void 0;
6210
6451
  }
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);
6452
+ for (const [dispatcher, events] of this._eventDispatchers) {
6453
+ for (const event of events) {
6454
+ dispatcher.removeEventListener(event, this._changeListener);
6219
6455
  }
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
6456
  }
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);
6457
+ this._eventDispatchers.clear();
6458
+ this._stats?.dom.remove();
6459
+ this._stats = void 0;
6460
+ this.renderer.domElement.remove();
6461
+ this._element = void 0;
6462
+ if (this._controls) {
6463
+ const controls = this._controls;
6464
+ this._controls = void 0;
6465
+ controls.enabled = false;
6466
+ controls.dispose();
6467
+ }
6468
+ this.scene.clear();
6469
+ for (const helper of this._debugHelpers) {
6470
+ helper.geometry.dispose();
6471
+ const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
6472
+ for (const material of materials) {
6473
+ material.dispose();
6234
6474
  }
6235
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6236
- pan(panDelta.x, panDelta.y);
6237
- panStart.copy(panEnd);
6238
6475
  }
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);
6476
+ this._debugHelpers.length = 0;
6477
+ this.composer?.dispose();
6478
+ this.renderer.dispose();
6479
+ this.renderer.forceContextLoss();
6480
+ }
6481
+ animate(t = performance.now()) {
6482
+ if (this._disposed) return;
6483
+ if (this._controls?.enabled) {
6484
+ this._controls.update();
6248
6485
  }
6249
- function handleTouchMoveDollyPan(event) {
6250
- if (scope.enableZoom) handleTouchMoveDolly(event);
6251
- if (scope.enablePan) handleTouchMovePan(event);
6486
+ if (this._disposed) return;
6487
+ if (!this.dirty && !this.options.render.renderAlways) return;
6488
+ const interval = this._frameInterval;
6489
+ if (interval) {
6490
+ const next = this._nextFrameTime;
6491
+ if (next !== void 0 && t + 0.1 < next) return;
6492
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6252
6493
  }
6253
- function handleTouchMoveDollyRotate(event) {
6254
- if (scope.enableZoom) handleTouchMoveDolly(event);
6255
- if (scope.enableRotate) handleTouchMoveRotate(event);
6494
+ if (this._stats) {
6495
+ this._stats.begin();
6256
6496
  }
6257
- function handleTouchEnd() {
6497
+ if (this.options.composer.enabled && this.composer) {
6498
+ this.composer.render();
6499
+ } else {
6500
+ this.renderer.render(this.scene, this.camera);
6258
6501
  }
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
- }
6502
+ this.dirty = false;
6503
+ if (this._stats) {
6504
+ this._stats.end();
6272
6505
  }
6273
- function onPointerMove(event) {
6274
- if (scope.enabled === false) return;
6275
- if (event.pointerType === "touch") {
6276
- onTouchMove(event);
6277
- } else {
6278
- onMouseMove(event);
6279
- }
6506
+ }
6507
+ //</editor-fold>
6508
+ toImage() {
6509
+ return this.renderer.domElement.toDataURL();
6510
+ }
6511
+ ///
6512
+ get attachedToBody() {
6513
+ return this.element === document.body;
6514
+ }
6515
+ get viewWidth() {
6516
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6517
+ }
6518
+ get viewHeight() {
6519
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6520
+ }
6521
+ get scene() {
6522
+ return this._scene;
6523
+ }
6524
+ get camera() {
6525
+ return this._camera;
6526
+ }
6527
+ get renderer() {
6528
+ return this._renderer;
6529
+ }
6530
+ get composer() {
6531
+ return this._composer;
6532
+ }
6533
+ /** Renderer-owned controls, or undefined when disabled at construction or after disposal. */
6534
+ get controls() {
6535
+ return this._controls;
6536
+ }
6537
+ ///
6538
+ };
6539
+ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6540
+ camera: {
6541
+ type: "perspective",
6542
+ near: 1,
6543
+ far: 5e3,
6544
+ perspective: {
6545
+ aspect: void 0,
6546
+ fov: 50
6547
+ },
6548
+ orthographic: {
6549
+ left: void 0,
6550
+ right: void 0,
6551
+ top: void 0,
6552
+ bottom: void 0
6553
+ },
6554
+ position: new Vector39(50, 50, 50),
6555
+ lookingAt: new Vector39(0, 0, 0)
6556
+ },
6557
+ render: {
6558
+ fpsLimit: 60,
6559
+ stats: false,
6560
+ antialias: true,
6561
+ shade: true,
6562
+ autoResize: true,
6563
+ renderAlways: false
6564
+ },
6565
+ composer: {
6566
+ enabled: true
6567
+ },
6568
+ controls: {
6569
+ enabled: false
6570
+ },
6571
+ debug: {
6572
+ grid: false,
6573
+ axes: false
6574
+ }
6575
+ });
6576
+ var Renderer = _Renderer;
6577
+
6578
+ // src/skin/Skins.ts
6579
+ var Skins = class {
6580
+ //<editor-fold desc="Skins">
6581
+ static async fromUuidOrUsername(uuidOrUsername) {
6582
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6583
+ return this.fromUuid(uuidOrUsername);
6280
6584
  }
6281
- function onPointerUp(event) {
6282
- if (scope.enabled === false) return;
6283
- if (event.pointerType === "touch") {
6284
- onTouchEnd();
6285
- } else {
6286
- onMouseUp(event);
6585
+ return this.fromUsername(uuidOrUsername);
6586
+ }
6587
+ static async fromUuid(uuid) {
6588
+ return this.getMcProxySkinUrl(uuid);
6589
+ }
6590
+ static async fromUsername(username) {
6591
+ return this.usernameToUuid(username).then((uuid) => {
6592
+ if (uuid) {
6593
+ return this.fromUuid(uuid);
6287
6594
  }
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);
6595
+ return void 0;
6596
+ });
6597
+ }
6598
+ static async fromMineSkin(mineskinId) {
6599
+ return this.getMineSkin(mineskinId).then((mineskin) => {
6600
+ if (mineskin) {
6601
+ return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6293
6602
  }
6603
+ return void 0;
6604
+ });
6605
+ }
6606
+ //</editor-fold>
6607
+ //<editor-fold desc="Capes">
6608
+ static async capeFromUuidOrUsername(uuidOrUsername) {
6609
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6610
+ return this.capeFromUuid(uuidOrUsername);
6294
6611
  }
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;
6612
+ return this.capeFromUsername(uuidOrUsername);
6613
+ }
6614
+ static async capeFromUuid(uuid) {
6615
+ return this.getMcProxyCapeUrl(uuid);
6616
+ }
6617
+ static async capeFromUsername(username) {
6618
+ return this.usernameToUuid(username).then((uuid) => {
6619
+ if (uuid) {
6620
+ return this.capeFromUuid(uuid);
6343
6621
  }
6344
- if (state !== STATE.NONE) {
6345
- scope.dispatchEvent(_startEvent);
6622
+ return void 0;
6623
+ });
6624
+ }
6625
+ static async capeFromCapesDev(uuid, capeType = "minecraft") {
6626
+ return this.getCapesDev(uuid, capeType).then((cape) => {
6627
+ if (cape) {
6628
+ return cape?.stillImageUrl;
6346
6629
  }
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;
6630
+ return void 0;
6631
+ });
6632
+ }
6633
+ //</editor-fold>
6634
+ //<editor-fold desc="Helpers">
6635
+ static async usernameToUuid(username) {
6636
+ return this.usernameToUuidMcProxy(username);
6637
+ }
6638
+ static async usernameToUuidMcProxy(username) {
6639
+ return Requests.genericRequest({
6640
+ baseURL: "https://mcproxy.dev",
6641
+ url: "/uuid/" + username
6642
+ }).then((res) => {
6643
+ if (res.status === 200) {
6644
+ return res.data["data"]["id"];
6363
6645
  }
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;
6646
+ return void 0;
6647
+ }).catch((err) => {
6648
+ console.warn(err);
6649
+ return void 0;
6650
+ });
6651
+ }
6652
+ /** @deprecated **/
6653
+ static async usernameToUuidSkinProxy(username) {
6654
+ return Requests.genericRequest({
6655
+ baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
6656
+ url: "/uuid/" + username
6657
+ }).then((res) => {
6658
+ if (res.status === 200) {
6659
+ return res.data["id"];
6418
6660
  }
6419
- if (state !== STATE.NONE) {
6420
- scope.dispatchEvent(_startEvent);
6661
+ return void 0;
6662
+ }).catch((err) => {
6663
+ console.warn(err);
6664
+ return void 0;
6665
+ });
6666
+ }
6667
+ static async usernameToUuidMineTools(username) {
6668
+ return Requests.genericRequest({
6669
+ baseURL: "https://api.minetools.eu",
6670
+ url: "/uuid/" + username
6671
+ }).then((res) => {
6672
+ if (res.status === 200) {
6673
+ return res.data["id"];
6421
6674
  }
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;
6675
+ return void 0;
6676
+ }).catch((err) => {
6677
+ console.warn(err);
6678
+ return void 0;
6679
+ });
6680
+ }
6681
+ static async getProfileFromMinetools(uuid) {
6682
+ return Requests.genericRequest({
6683
+ baseURL: "https://api.minetools.eu",
6684
+ url: "/profile/" + uuid
6685
+ }).then((res) => {
6686
+ if (res.status === 200) {
6687
+ return res.data;
6448
6688
  }
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
- }
6689
+ });
6690
+ }
6691
+ static async getMineSkin(mineskinId) {
6692
+ return Requests.genericRequest({
6693
+ baseURL: "https://api.mineskin.org",
6694
+ url: "/get/uuid/" + mineskinId
6695
+ }).then((res) => {
6696
+ if (res.status === 200) {
6697
+ return res.data;
6469
6698
  }
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;
6699
+ return void 0;
6700
+ }).catch((err) => {
6701
+ console.warn(err);
6702
+ return void 0;
6703
+ });
6704
+ }
6705
+ static async getCapesDev(uuid, type = "all") {
6706
+ return Requests.genericRequest({
6707
+ baseURL: "https://api.capes.dev",
6708
+ url: "/load/" + uuid + "/" + type
6709
+ }).then((res) => {
6710
+ if (res.status === 200) {
6711
+ return res.data;
6476
6712
  }
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();
6713
+ return void 0;
6714
+ }).catch((err) => {
6715
+ console.warn(err);
6716
+ return void 0;
6717
+ });
6488
6718
  }
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;
6719
+ static getCrafatarSkinUrl(uuid) {
6720
+ return "https://crafatar.com/skins/" + uuid;
6721
+ }
6722
+ static getCrafatarCapeUrl(uuid) {
6723
+ return "https://crafatar.com/capes/" + uuid;
6724
+ }
6725
+ static getMcHeadsSkinUrl(uuid) {
6726
+ return "https://mc-heads.net/skin/" + uuid;
6727
+ }
6728
+ static getMineSkinPlayerSkinUrl(uuid) {
6729
+ return "https://mineskin.org/skin/player/" + uuid;
6730
+ }
6731
+ /** @deprecated **/
6732
+ static getSkinProxySkinUrl(uuid) {
6733
+ return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6734
+ }
6735
+ /** @deprecated **/
6736
+ static getSkinProxyCapeUrl(uuid) {
6737
+ return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6738
+ }
6739
+ static getMcProxySkinUrl(uuid) {
6740
+ return "https://mcproxy.dev/skin/" + uuid;
6498
6741
  }
6742
+ static getMcProxyCapeUrl(uuid) {
6743
+ return "https://mcproxy.dev/cape/" + uuid;
6744
+ }
6745
+ //</editor-fold>
6499
6746
  };
6500
6747
 
6501
6748
  // src/world/Chunk.ts
6502
- import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector310 } from "three";
6749
+ import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector311 } from "three";
6503
6750
 
6504
6751
  // src/world/MineRenderWorld.ts
6505
- import { Vector3 as Vector39 } from "three";
6752
+ import { Vector3 as Vector310 } from "three";
6506
6753
  var MineRenderWorld = class {
6507
6754
  constructor(scene) {
6508
6755
  this._size = 4;
@@ -6513,10 +6760,10 @@ var MineRenderWorld = class {
6513
6760
  }
6514
6761
  getBlockAt(posOrX, y, z) {
6515
6762
  if (typeof posOrX == "number") {
6516
- return this.getBlockAt(new Vector39(posOrX, y, z));
6763
+ return this.getBlockAt(new Vector310(posOrX, y, z));
6517
6764
  }
6518
6765
  if (isTripleArray(posOrX)) {
6519
- return this.getBlockAt(new Vector39(posOrX[0], posOrX[1], posOrX[2]));
6766
+ return this.getBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]));
6520
6767
  }
6521
6768
  const chunk = this.getChunkAt(posOrX);
6522
6769
  if (typeof chunk === "undefined") {
@@ -6527,10 +6774,10 @@ var MineRenderWorld = class {
6527
6774
  }
6528
6775
  async setBlockAt(posOrX, yOrBlock, z, block) {
6529
6776
  if (typeof posOrX == "number") {
6530
- return this.setBlockAt(new Vector39(posOrX, yOrBlock, z), block);
6777
+ return this.setBlockAt(new Vector310(posOrX, yOrBlock, z), block);
6531
6778
  }
6532
6779
  if (isTripleArray(posOrX)) {
6533
- return this.setBlockAt(new Vector39(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6780
+ return this.setBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6534
6781
  }
6535
6782
  this.validatePosBounds(posOrX);
6536
6783
  const chunk = this.getOrCreateChunkAt(posOrX);
@@ -6576,14 +6823,14 @@ var MineRenderWorld = class {
6576
6823
  return this._chunks[index];
6577
6824
  }
6578
6825
  static worldToScenePosition(pos) {
6579
- return new Vector39(
6826
+ return new Vector310(
6580
6827
  pos.x * 16,
6581
6828
  pos.y * 16,
6582
6829
  pos.z * 16
6583
6830
  );
6584
6831
  }
6585
6832
  static sceneToWorldPosition(pos) {
6586
- return new Vector39(
6833
+ return new Vector310(
6587
6834
  pos.x / 16,
6588
6835
  pos.y / 16,
6589
6836
  pos.z / 16
@@ -6612,7 +6859,7 @@ var MineRenderWorld = class {
6612
6859
  };
6613
6860
 
6614
6861
  // src/world/Chunk.ts
6615
- var p12 = prefix("Chunk");
6862
+ var p11 = prefix("Chunk");
6616
6863
  var Chunk = class _Chunk {
6617
6864
  constructor(scene, x, y, z) {
6618
6865
  this._blocks = [];
@@ -6625,7 +6872,7 @@ var Chunk = class _Chunk {
6625
6872
  scene.add(anchor);
6626
6873
  anchor.position.set(this.x * 256 + 128 - 8, this.y * 256 + 128 - 8, this.z * 256 + 128 - 8);
6627
6874
  addBox3WireframeToObject(
6628
- new Box32(new Vector310(0, 0, 0), new Vector310(256, 256, 256)),
6875
+ new Box32(new Vector311(0, 0, 0), new Vector311(256, 256, 256)),
6629
6876
  anchor,
6630
6877
  16776960,
6631
6878
  4
@@ -6633,10 +6880,10 @@ var Chunk = class _Chunk {
6633
6880
  }
6634
6881
  getBlockAt(posOrX, y, z) {
6635
6882
  if (typeof posOrX == "number") {
6636
- return this.getBlockAt(new Vector310(posOrX, y, z));
6883
+ return this.getBlockAt(new Vector311(posOrX, y, z));
6637
6884
  }
6638
6885
  if (isTripleArray(posOrX)) {
6639
- return this.getBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]));
6886
+ return this.getBlockAt(new Vector311(posOrX[0], posOrX[1], posOrX[2]));
6640
6887
  }
6641
6888
  const pos = this.worldPosToChunkPos(posOrX);
6642
6889
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -6644,10 +6891,10 @@ var Chunk = class _Chunk {
6644
6891
  }
6645
6892
  async setBlockAt(posOrX, yOrBlock, z, block) {
6646
6893
  if (typeof posOrX == "number") {
6647
- return this.setBlockAt(new Vector310(posOrX, yOrBlock, z), block);
6894
+ return this.setBlockAt(new Vector311(posOrX, yOrBlock, z), block);
6648
6895
  }
6649
6896
  if (isTripleArray(posOrX)) {
6650
- return this.setBlockAt(new Vector310(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6897
+ return this.setBlockAt(new Vector311(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
6651
6898
  }
6652
6899
  const worldPos = posOrX;
6653
6900
  const pos = this.worldPosToChunkPos(worldPos);
@@ -6664,7 +6911,7 @@ var Chunk = class _Chunk {
6664
6911
  const index = _Chunk.chunkPosToBlockIndex(pos);
6665
6912
  const current = this._blocks[index];
6666
6913
  if (typeof current !== "undefined") {
6667
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
6914
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6668
6915
  current.object.removeFromScene();
6669
6916
  delete this._blocks[index];
6670
6917
  }
@@ -6693,7 +6940,7 @@ var Chunk = class _Chunk {
6693
6940
  }
6694
6941
  async clear() {
6695
6942
  let promises = [];
6696
- let pos = new Vector310();
6943
+ let pos = new Vector311();
6697
6944
  for (let x = 0; x < 16; x++) {
6698
6945
  for (let z = 0; z < 16; z++) {
6699
6946
  for (let y = 0; y < 16; y++) {
@@ -6712,14 +6959,14 @@ var Chunk = class _Chunk {
6712
6959
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
6713
6960
  }
6714
6961
  worldPosToChunkPos(pos) {
6715
- return new Vector310(
6962
+ return new Vector311(
6716
6963
  pos.x - this.x * 16,
6717
6964
  pos.y - this.y * 16,
6718
6965
  pos.z - this.z * 16
6719
6966
  );
6720
6967
  }
6721
6968
  chunkPosToWorldPos(pos) {
6722
- return new Vector310(
6969
+ return new Vector311(
6723
6970
  this.x * 16 + pos.x,
6724
6971
  this.y * 16 + pos.y,
6725
6972
  this.z * 16 + pos.z
@@ -6730,6 +6977,7 @@ export {
6730
6977
  AXES,
6731
6978
  ArchiveAssetSource,
6732
6979
  AssetKey,
6980
+ AssetLoadError,
6733
6981
  AssetLoader,
6734
6982
  AssetParser,
6735
6983
  AssetSource,
@@ -6787,6 +7035,7 @@ export {
6787
7035
  OrbitControls,
6788
7036
  PersistentCache,
6789
7037
  Renderer,
7038
+ RequestError,
6790
7039
  Requests,
6791
7040
  SKIN_PARTS,
6792
7041
  SceneInspector,