minerender 2.1.0-alpha.1 → 2.1.0-alpha.11

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
  }
@@ -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);
547
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);
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 {
@@ -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
  });
@@ -1019,6 +1010,9 @@ var _Materials = class _Materials {
1019
1010
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
1020
1011
 
1021
1012
  }
1013
+
1014
+ #include <tonemapping_fragment>
1015
+ #include <colorspace_fragment>
1022
1016
  }
1023
1017
  `;
1024
1018
  try {
@@ -1047,6 +1041,10 @@ var _Materials = class _Materials {
1047
1041
  }
1048
1042
  static getImage(key) {
1049
1043
  const keyStr = serializeMaterialKey(key);
1044
+ const map = Caching.materialCache.peek(keyStr)?.map;
1045
+ if (map && TextureLoader.hasFailed(map)) {
1046
+ Caching.materialCache.invalidate(keyStr);
1047
+ }
1050
1048
  return Caching.materialCache.get(keyStr, (k) => {
1051
1049
  return _Materials.createImage(key);
1052
1050
  });
@@ -1071,10 +1069,10 @@ _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA
1071
1069
  var Materials = _Materials;
1072
1070
 
1073
1071
  // src/Meshes.ts
1074
- import { Mesh as Mesh2 } from "three";
1072
+ import { Mesh } from "three";
1075
1073
  var Meshes = class _Meshes {
1076
1074
  static createBox(key) {
1077
- return new Mesh2(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1075
+ return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1078
1076
  }
1079
1077
  static getBox(key) {
1080
1078
  const keyStr = serializeMeshKey(key);
@@ -1151,12 +1149,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1151
1149
  return a.join("/");
1152
1150
  }
1153
1151
  getFullPath() {
1154
- let p13 = [];
1152
+ let p12 = [];
1155
1153
  if (this.type) {
1156
- p13.push(this.type);
1154
+ p12.push(this.type);
1157
1155
  }
1158
- p13.push(this.path);
1159
- return p13.join("/");
1156
+ p12.push(this.path);
1157
+ return p12.join("/");
1160
1158
  }
1161
1159
  toNamespacedString() {
1162
1160
  return this.namespace + ":" + this.getFullPath();
@@ -1181,7 +1179,7 @@ var ModelMerger = class {
1181
1179
  merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1182
1180
  }
1183
1181
  merged = (0, import_ts_deepmerge.default)(merged, model);
1184
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1182
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1185
1183
  merged.hierarchy.push(`${merged.parent}`);
1186
1184
  return merged;
1187
1185
  }
@@ -1200,9 +1198,6 @@ var ModelMerger = class {
1200
1198
  }
1201
1199
  };
1202
1200
 
1203
- // src/assets/Models.ts
1204
- import { Memoize } from "typescript-memoize";
1205
-
1206
1201
  // src/assets/source/parser/AssetParsers.ts
1207
1202
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1208
1203
  AssetParser2["MODEL"] = "model";
@@ -1216,14 +1211,14 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1216
1211
  })(AssetParser || {});
1217
1212
 
1218
1213
  // src/assets/Models.ts
1219
- var _Models = class _Models {
1214
+ var Models = class _Models {
1220
1215
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1221
1216
  // the library, and would require an EnvProvider before any entry has had a chance to register
1222
1217
  static get PERSISTENT_CACHE() {
1223
1218
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1224
1219
  }
1225
1220
  static async getItemList() {
1226
- return AssetLoader.get(new AssetKey(
1221
+ const key = new AssetKey(
1227
1222
  DEFAULT_NAMESPACE,
1228
1223
  "_list",
1229
1224
  "models",
@@ -1231,7 +1226,10 @@ var _Models = class _Models {
1231
1226
  "assets",
1232
1227
  ".json",
1233
1228
  DEFAULT_ROOT
1234
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1229
+ );
1230
+ return Caching.listAssetCache.get(key.serialize(), () => {
1231
+ return AssetLoader.get(key, "list" /* LIST */);
1232
+ }).then((r) => r?.files ?? []);
1235
1233
  }
1236
1234
  static async loadAndMerge(key) {
1237
1235
  const model = await this.getRaw(key);
@@ -1278,19 +1276,15 @@ var _Models = class _Models {
1278
1276
  return this.PERSISTENT_CACHE.clear();
1279
1277
  }
1280
1278
  };
1281
- __decorateClass([
1282
- Memoize()
1283
- ], _Models, "getItemList", 1);
1284
- var Models = _Models;
1285
1279
 
1286
1280
  // src/assets/BlockStates.ts
1287
- import { Memoize as Memoize2 } from "typescript-memoize";
1288
1281
  var BlockStates = class {
1289
1282
  static get PERSISTENT_CACHE() {
1290
1283
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1291
1284
  }
1285
+ // BlockState names are hardcoded
1292
1286
  static async getList() {
1293
- return AssetLoader.get(new AssetKey(
1287
+ const key = new AssetKey(
1294
1288
  DEFAULT_NAMESPACE,
1295
1289
  "_list",
1296
1290
  "blockstates",
@@ -1298,11 +1292,16 @@ var BlockStates = class {
1298
1292
  "assets",
1299
1293
  ".json",
1300
1294
  DEFAULT_ROOT
1301
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1295
+ );
1296
+ return Caching.listAssetCache.get(key.serialize(), () => {
1297
+ return AssetLoader.get(key, "list" /* LIST */);
1298
+ }).then((r) => r?.files ?? []);
1302
1299
  }
1303
1300
  static async getDefaultStates() {
1304
1301
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1305
- return AssetLoader.get(key, "json" /* JSON */);
1302
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1303
+ return AssetLoader.get(key, "json" /* JSON */);
1304
+ });
1306
1305
  }
1307
1306
  static async getDefaultState(key) {
1308
1307
  const defaultStates = await this.getDefaultStates();
@@ -1341,12 +1340,6 @@ var BlockStates = class {
1341
1340
  await this.PERSISTENT_CACHE.clear();
1342
1341
  }
1343
1342
  };
1344
- __decorateClass([
1345
- Memoize2()
1346
- ], BlockStates, "getList", 1);
1347
- __decorateClass([
1348
- Memoize2()
1349
- ], BlockStates, "getDefaultStates", 1);
1350
1343
  var DefaultBlockStates = class {
1351
1344
  };
1352
1345
 
@@ -1373,82 +1366,213 @@ var AssetSource = class {
1373
1366
  constructor() {
1374
1367
  }
1375
1368
  };
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;
1369
+ var AssetLoadError = class extends Error {
1370
+ constructor(source, key, path, cause) {
1371
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1372
+ this.source = source;
1373
+ this.key = key;
1374
+ this.path = path;
1375
+ this.cause = cause;
1376
+ this.name = "AssetLoadError";
1383
1377
  }
1384
1378
  };
1385
1379
 
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;
1397
- }
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");
1407
- const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1408
- const namespacedRooted = await this.load(namespacedRootedKey, parser);
1409
- if (typeof namespacedRooted !== "undefined") {
1410
- return namespacedRooted;
1411
- }
1412
- }
1413
- } else if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1414
- console.info(p3, "Retrying", key, "with default root");
1415
- const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1416
- const rooted = await this.load(rootKey, parser);
1417
- if (typeof rooted !== "undefined") {
1418
- return rooted;
1419
- }
1420
- }
1421
- return void 0;
1380
+ // src/util/BatchedExecutor.ts
1381
+ var BatchedExecutor = class {
1382
+ constructor(interval = 1, batch = 30) {
1383
+ this.interval = interval;
1384
+ this.batch = batch;
1385
+ this.queue = [];
1386
+ this.task = setInterval(() => this.run());
1422
1387
  }
1423
- async load(key, parser) {
1424
- console.info(p3, "Loading", key);
1425
- const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1426
- 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;
1388
+ submit(task) {
1389
+ this.queue.push(task);
1390
+ }
1391
+ run() {
1392
+ for (let i = 0; i < this.batch; i++) {
1393
+ this.runNext();
1394
+ }
1395
+ }
1396
+ runNext() {
1397
+ let next = this.queue.shift();
1398
+ if (next) next();
1399
+ }
1400
+ };
1401
+
1402
+ // src/util/model.ts
1403
+ import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
1404
+ function applyElementRotation(rotation, geometry) {
1405
+ const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1406
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1407
+ switch (rotation.axis) {
1408
+ case "X" /* X */:
1409
+ geometry.rotateX(toRadians(rotation.angle));
1410
+ break;
1411
+ case "y" /* Y */:
1412
+ geometry.rotateY(toRadians(rotation.angle));
1413
+ break;
1414
+ case "z" /* Z */:
1415
+ geometry.rotateZ(toRadians(rotation.angle));
1416
+ break;
1417
+ }
1418
+ if (rotation.rescale) {
1419
+ if (Math.abs(rotation.angle) === 22.5) {
1420
+ const s = 1 / Math.cos(0.39269909262657166);
1421
+ geometry.scale(s, 1, s);
1422
+ } else {
1423
+ const s = 1 / Math.cos(0.7853981852531433);
1424
+ geometry.scale(s, 1, s);
1425
+ }
1426
+ }
1427
+ geometry.translate(origin.x, origin.y, origin.z);
1428
+ }
1429
+ function applyModelPartRotation(modelPart, geometry) {
1430
+ const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
1431
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1432
+ geometry.rotateX(toRadians(modelPart.pitch));
1433
+ geometry.rotateY(toRadians(modelPart.yaw));
1434
+ geometry.rotateZ(toRadians(modelPart.roll));
1435
+ geometry.translate(origin.x, origin.y, origin.z);
1436
+ }
1437
+ function applyGenericRotation(axis, rotation, obj) {
1438
+ switch (axis) {
1439
+ case "X" /* X */:
1440
+ obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
1441
+ break;
1442
+ case "y" /* Y */:
1443
+ obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
1444
+ break;
1445
+ case "z" /* Z */:
1446
+ obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
1447
+ break;
1448
+ }
1449
+ }
1450
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1451
+ let size = new Vector32();
1452
+ box.getSize(size);
1453
+ let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
1454
+ let wireGeo = new EdgesGeometry(boxGeo);
1455
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1456
+ let wireframe = new LineSegments(wireGeo, wireMat);
1457
+ obj.add(wireframe);
1458
+ let axes = new AxesHelper(1);
1459
+ obj.add(axes);
1460
+ }
1461
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1462
+ let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
1463
+ let wireGeo = new EdgesGeometry(boxGeo);
1464
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1465
+ let wireframe = new LineSegments(wireGeo, wireMat);
1466
+ obj.add(wireframe);
1467
+ let axes = new AxesHelper(1);
1468
+ obj.add(axes);
1469
+ }
1470
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1471
+ let wireGeo = new EdgesGeometry(geo);
1472
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1473
+ let wireframe = new LineSegments(wireGeo, wireMat);
1474
+ mesh.add(wireframe);
1475
+ let axes = new AxesHelper(1);
1476
+ mesh.add(axes);
1477
+ }
1478
+
1479
+ // src/util/performance.ts
1480
+ function captureException(e, ...extra) {
1481
+ console.error(e, extra);
1482
+ }
1483
+ function timingStart(marker) {
1484
+ console.time(marker);
1485
+ }
1486
+ function timingEnd(marker) {
1487
+ console.timeEnd(marker);
1488
+ }
1489
+
1490
+ // src/util/three.ts
1491
+ function isObject3D(obj) {
1492
+ return obj.isObject3D;
1493
+ }
1494
+ function isMesh(obj) {
1495
+ return obj.isMesh;
1496
+ }
1497
+ function isInstancedMesh(obj) {
1498
+ return obj.isInstancedMesh;
1499
+ }
1500
+ function isPerspectiveCamera(obj) {
1501
+ return obj.isPerspectiveCamera;
1502
+ }
1503
+ function isOrthographicCamera(obj) {
1504
+ return obj.isOrthographicCamera;
1505
+ }
1506
+
1507
+ // src/nbt/NBTHelper.ts
1508
+ var NBTHelper = class {
1509
+ static async fromBuffer(buffer) {
1510
+ const prismarineNbt = await import("prismarine-nbt");
1511
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1512
+ return parsed;
1513
+ }
1514
+ };
1515
+
1516
+ // src/assets/source/HostedAssetSource.ts
1517
+ var import_ts_deepmerge2 = __toESM(require_dist());
1518
+ var p3 = prefix("HostedAssetSource");
1519
+ var DEFAULT_OPTIONS = {
1520
+ retryDefaults: true
1521
+ };
1522
+ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1523
+ async loadOrRetryWithDefaults(key, parser) {
1524
+ const direct = await this.load(key, parser);
1525
+ if (typeof direct !== "undefined") {
1526
+ return direct;
1527
+ }
1528
+ if (key.namespace !== DEFAULT_NAMESPACE) {
1529
+ console.info(p3, "Retrying", key, "with default namespace");
1530
+ const namespaceKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, key.root);
1531
+ const namespaced = await this.load(namespaceKey, parser);
1532
+ if (typeof namespaced !== "undefined") {
1533
+ return namespaced;
1534
+ }
1535
+ if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1536
+ console.info(p3, "Retrying", key, "with default root+namespace");
1537
+ const namespacedRootedKey = new AssetKey(DEFAULT_NAMESPACE, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1538
+ const namespacedRooted = await this.load(namespacedRootedKey, parser);
1539
+ if (typeof namespacedRooted !== "undefined") {
1540
+ return namespacedRooted;
1438
1541
  }
1439
1542
  }
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");
1543
+ } else if (typeof key.root !== "undefined" && key.root !== DEFAULT_ROOT || typeof this.root !== "undefined" && this.root !== DEFAULT_ROOT) {
1544
+ console.info(p3, "Retrying", key, "with default root");
1545
+ const rootKey = new AssetKey(key.namespace, key.path, key.assetType, key.type, key.rootType, key.extension, DEFAULT_ROOT);
1546
+ const rooted = await this.load(rootKey, parser);
1547
+ if (typeof rooted !== "undefined") {
1548
+ return rooted;
1549
+ }
1550
+ }
1551
+ return void 0;
1552
+ }
1553
+ async load(key, parser) {
1554
+ console.info(p3, "Loading", key);
1555
+ const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1556
+ console.debug(p3, url);
1557
+ const request = { url };
1558
+ try {
1559
+ parser.config(request);
1560
+ let response;
1561
+ try {
1562
+ response = await Requests.mcAssetRequest(request);
1563
+ } catch (cause) {
1564
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1446
1565
  return void 0;
1447
1566
  }
1567
+ throw cause;
1448
1568
  }
1449
- console.debug(p3, "Failed to load", key, err?.message);
1450
- return void 0;
1451
- });
1569
+ if (response.data === void 0) {
1570
+ throw new Error("Asset response has no data");
1571
+ }
1572
+ return await parser.parse(response);
1573
+ } catch (cause) {
1574
+ throw new AssetLoadError(this, key, request.url, cause);
1575
+ }
1452
1576
  }
1453
1577
  assetBasePath(key) {
1454
1578
  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 +1679,6 @@ var BrowserArchiveProxy = class {
1555
1679
  };
1556
1680
 
1557
1681
  // src/assets/source/archive/ArchiveAssetSource.ts
1558
- var p4 = prefix("ArchiveAssetSource");
1559
1682
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1560
1683
  constructor(archiveProxy) {
1561
1684
  super();
@@ -1574,74 +1697,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1574
1697
  }
1575
1698
  async get(key, parser) {
1576
1699
  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
- });
1700
+ return this.load(key, responseParser);
1614
1701
  }
1615
- //TODO: abstract this
1616
1702
  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
- }
1703
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1704
+ let url;
1705
+ try {
1706
+ const entry = await this.getEntry(path);
1707
+ if (!entry) {
1708
+ return void 0;
1632
1709
  }
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
- }
1710
+ url = URL.createObjectURL(await entry.getData());
1711
+ const request = { url };
1712
+ parser.config(request);
1713
+ const response = await Requests.genericRequest(request);
1714
+ if (response.data === void 0) {
1715
+ throw new Error("Asset response has no data");
1641
1716
  }
1642
- console.debug(p4, "Failed to load", key, err?.message);
1643
- return void 0;
1644
- });
1717
+ return await parser.parse(response);
1718
+ } catch (cause) {
1719
+ throw new AssetLoadError(this, key, path, cause);
1720
+ } finally {
1721
+ if (url !== void 0) {
1722
+ URL.revokeObjectURL(url);
1723
+ }
1724
+ }
1645
1725
  }
1646
1726
  assetBasePath(key) {
1647
1727
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1649,18 +1729,17 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1649
1729
  };
1650
1730
 
1651
1731
  // src/assets/AssetLoader.ts
1652
- var import_ts_deepmerge3 = __toESM(require_dist());
1653
- var p5 = prefix("AssetLoader");
1732
+ var p4 = prefix("AssetLoader");
1654
1733
  var _AssetLoader = class _AssetLoader {
1655
1734
  static addSource(key, source, override = true) {
1656
1735
  if (override) {
1657
1736
  const existing = this.removeSource(key);
1658
1737
  if (existing) {
1659
- console.log(p5, "Removed existing AssetSource", key);
1738
+ console.log(p4, "Removed existing AssetSource", key);
1660
1739
  }
1661
1740
  }
1662
1741
  this._SOURCES.unshift({ key, source });
1663
- console.log(p5, "Added AssetSource", key);
1742
+ console.log(p4, "Added AssetSource", key);
1664
1743
  }
1665
1744
  static removeSource(key) {
1666
1745
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1673,7 +1752,6 @@ var _AssetLoader = class _AssetLoader {
1673
1752
  return void 0;
1674
1753
  }
1675
1754
  static async getAll(key, parser) {
1676
- console.log(this._SOURCES);
1677
1755
  let promises = [];
1678
1756
  for (const source of this._SOURCES) {
1679
1757
  promises.push(source.source.get(key, parser));
@@ -1682,24 +1760,16 @@ var _AssetLoader = class _AssetLoader {
1682
1760
  return results.filter((r) => r != void 0);
1683
1761
  });
1684
1762
  }
1763
+ /** Returns the first defined result in source-priority order, without merging assets. */
1685
1764
  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;
1699
- }
1765
+ const sources = [...this._SOURCES];
1766
+ for (const source of sources) {
1767
+ const result = await source.source.get(key, parser);
1768
+ if (result !== void 0) {
1769
+ return result;
1700
1770
  }
1701
- return void 0;
1702
- });
1771
+ }
1772
+ return void 0;
1703
1773
  }
1704
1774
  };
1705
1775
  _AssetLoader.ROOT = DEFAULT_ROOT;
@@ -1714,11 +1784,21 @@ var ModelTextures = class {
1714
1784
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
1715
1785
  }
1716
1786
  static async get(key) {
1717
- const asset = await this.preload(key);
1718
- if (asset) {
1719
- return ImageLoader.infoToCanvasData(asset);
1787
+ const keyStr = key.serialize();
1788
+ const pending = this.preload(key);
1789
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1790
+ try {
1791
+ const asset = await pending;
1792
+ if (asset) {
1793
+ return await ImageLoader.infoToCanvasData(asset);
1794
+ }
1795
+ return void 0;
1796
+ } catch (err) {
1797
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
1798
+ Caching.textureAssetCache.invalidate(keyStr);
1799
+ }
1800
+ throw err;
1720
1801
  }
1721
- return void 0;
1722
1802
  }
1723
1803
  static async preload(key) {
1724
1804
  const keyStr = key.serialize();
@@ -1909,7 +1989,7 @@ var ModelGenerator = class {
1909
1989
  ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
1910
1990
 
1911
1991
  // src/UVMapper.ts
1912
- var p6 = prefix("UVMapper");
1992
+ var p5 = prefix("UVMapper");
1913
1993
  var DEFAULT_UV = [0, 0, 16, 16];
1914
1994
  var X = 0;
1915
1995
  var Y = 1;
@@ -2086,7 +2166,7 @@ var UVMapper = class {
2086
2166
  const metaMap = {};
2087
2167
  const model = { ...originalModel };
2088
2168
  const isItemModel = !("elements" in model);
2089
- console.debug(p6, "Creating Atlas for", model.key);
2169
+ console.debug(p5, "Creating Atlas for", model.key);
2090
2170
  if (model.textures) {
2091
2171
  const promises = [];
2092
2172
  const uniqueTextureNames = [];
@@ -2100,7 +2180,7 @@ var UVMapper = class {
2100
2180
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2101
2181
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2102
2182
  if (!asset) {
2103
- console.warn(p6, "Missing texture", assetKey);
2183
+ console.warn(p5, "Missing texture", assetKey);
2104
2184
  return;
2105
2185
  }
2106
2186
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2112,7 +2192,7 @@ var UVMapper = class {
2112
2192
  }
2113
2193
  await Promise.all(promises);
2114
2194
  const textureCount = uniqueTextureNames.length;
2115
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2195
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2116
2196
  this.fillMissingTextureKeys(model.textures, textureMap);
2117
2197
  this.fillMissingTextureKeys(model.textures, metaMap);
2118
2198
  const sizes = {};
@@ -2132,7 +2212,7 @@ var UVMapper = class {
2132
2212
  this.fillMissingTextureKeys(model.textures, sizes);
2133
2213
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2134
2214
  const size = Math.ceil(s * maxWidth);
2135
- console.debug(p6, "Atlas size:", size);
2215
+ console.debug(p5, "Atlas size:", size);
2136
2216
  const squaredSize = size * size;
2137
2217
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2138
2218
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2187,10 +2267,10 @@ var UVMapper = class {
2187
2267
  }
2188
2268
  }
2189
2269
  const atlasImageData = image.toDataURL();
2190
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2270
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2191
2271
  this.fillMissingTextureKeys(model.textures, positions);
2192
2272
  if (isItemModel) {
2193
- console.debug(p6, "Generating item model for", model);
2273
+ console.debug(p5, "Generating item model for", model);
2194
2274
  model.elements = [];
2195
2275
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2196
2276
  const textureImage = textureMap[layerName];
@@ -2198,7 +2278,7 @@ var UVMapper = class {
2198
2278
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2199
2279
  }
2200
2280
  }
2201
- console.debug(p6, "Item model elements", model.elements);
2281
+ console.debug(p5, "Item model elements", model.elements);
2202
2282
  }
2203
2283
  if (!model.elements) {
2204
2284
  }
@@ -2258,7 +2338,7 @@ var UVMapper = class {
2258
2338
  hasTransparency
2259
2339
  );
2260
2340
  } else {
2261
- console.warn(p6, "Model does not have any textures", model);
2341
+ console.warn(p5, "Model does not have any textures", model);
2262
2342
  }
2263
2343
  return void 0;
2264
2344
  }
@@ -2396,17 +2476,20 @@ function shutdown() {
2396
2476
  }
2397
2477
 
2398
2478
  // src/assets/Entities.ts
2399
- import { Memoize as Memoize3 } from "typescript-memoize";
2400
2479
  var Entities = class {
2401
2480
  static async getBlockEntityModels() {
2402
2481
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2403
2482
  console.log(key);
2404
- return AssetLoader.get(key, "json" /* JSON */);
2483
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2484
+ return AssetLoader.get(key, "json" /* JSON */);
2485
+ });
2405
2486
  }
2406
2487
  static async getEntityModels() {
2407
2488
  const key = AssetKey.parse("models", "minerender:entityModels");
2408
2489
  console.log(key);
2409
- return AssetLoader.get(key, "json" /* JSON */);
2490
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2491
+ return AssetLoader.get(key, "json" /* JSON */);
2492
+ });
2410
2493
  }
2411
2494
  // BlockEntity names are hardcoded
2412
2495
  static async getBlockList() {
@@ -2452,12 +2535,6 @@ var Entities = class {
2452
2535
  };
2453
2536
  }
2454
2537
  };
2455
- __decorateClass([
2456
- Memoize3()
2457
- ], Entities, "getBlockEntityModels", 1);
2458
- __decorateClass([
2459
- Memoize3()
2460
- ], Entities, "getEntityModels", 1);
2461
2538
  var EntityModels = class {
2462
2539
  };
2463
2540
  var BlockEntityModels = class {
@@ -2521,8 +2598,8 @@ var MineRenderError = class _MineRenderError extends Error {
2521
2598
  };
2522
2599
 
2523
2600
  // src/renderer/SceneObject.ts
2524
- var import_ts_deepmerge4 = __toESM(require_dist());
2525
- var p7 = prefix("SceneObject");
2601
+ var import_ts_deepmerge3 = __toESM(require_dist());
2602
+ var p6 = prefix("SceneObject");
2526
2603
  var _SceneObject = class _SceneObject extends Object3D2 {
2527
2604
  constructor(options) {
2528
2605
  super();
@@ -2530,7 +2607,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2530
2607
  this.materialCallbacks = {};
2531
2608
  this._isInstanced = false;
2532
2609
  this._instanceCounter = 0;
2533
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2610
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2534
2611
  console.log("SceneObject options", this.options);
2535
2612
  }
2536
2613
  set scene(scene) {
@@ -2701,9 +2778,9 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2701
2778
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2702
2779
  const i = this._instanceCounter++;
2703
2780
  this.setMatrixAt(i, new Matrix42());
2704
- console.debug(p7, "nextInstance " + i);
2781
+ console.debug(p6, "nextInstance " + i);
2705
2782
  if (i === this.options.maxInstanceCount) {
2706
- console.warn(p7, "Max instance count reached for " + this);
2783
+ console.warn(p6, "Max instance count reached for " + this);
2707
2784
  }
2708
2785
  if (this.scene) {
2709
2786
  this.scene.stats.instanceCount++;
@@ -2879,7 +2956,7 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2879
2956
  }
2880
2957
  //</editor-fold>
2881
2958
  };
2882
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
2959
+ _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2883
2960
  instanceMeshes: true,
2884
2961
  maxInstanceCount: 50,
2885
2962
  mergeMeshes: true,
@@ -2891,16 +2968,16 @@ function isSceneObject(obj) {
2891
2968
  }
2892
2969
 
2893
2970
  // src/entity/scene/EntityObject.ts
2894
- var import_ts_deepmerge5 = __toESM(require_dist());
2971
+ var import_ts_deepmerge4 = __toESM(require_dist());
2895
2972
  import { Object3D as Object3D3 } from "three";
2896
- import * as THREE2 from "three";
2973
+ import * as THREE3 from "three";
2897
2974
  var EntityObject = class extends SceneObject {
2898
2975
  constructor(entity, options) {
2899
2976
  super();
2900
2977
  this.entity = entity;
2901
2978
  this.isEntityObject = true;
2902
2979
  this.meshesCreated = false;
2903
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
2980
+ this.options = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
2904
2981
  }
2905
2982
  async init() {
2906
2983
  this.createMeshes();
@@ -2909,8 +2986,8 @@ var EntityObject = class extends SceneObject {
2909
2986
  dispose() {
2910
2987
  super.dispose();
2911
2988
  }
2912
- async loadTextures() {
2913
- this.imageData = await ModelTextures.get(new AssetKey(
2989
+ get textureKey() {
2990
+ return new AssetKey(
2914
2991
  this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2915
2992
  this.entity.key.path,
2916
2993
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
@@ -2918,7 +2995,10 @@ var EntityObject = class extends SceneObject {
2918
2995
  "entity",
2919
2996
  "assets",
2920
2997
  ".png"
2921
- ));
2998
+ );
2999
+ }
3000
+ async loadTextures() {
3001
+ this.imageData = await ModelTextures.get(this.textureKey);
2922
3002
  }
2923
3003
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2924
3004
  createMeshes(force = false) {
@@ -2937,8 +3017,8 @@ var EntityObject = class extends SceneObject {
2937
3017
  const l = cube.maxZ - cube.minZ;
2938
3018
  const uv = texture.toUvArray(w, h, l);
2939
3019
  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));
3020
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3021
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
2942
3022
  applyModelPartRotation(part, cubeGeo);
2943
3023
  const mesh = this.createMesh(partName, cubeGeo, mat);
2944
3024
  partAnchor.add(mesh);
@@ -2951,23 +3031,26 @@ var EntityObject = class extends SceneObject {
2951
3031
  this.meshesCreated = true;
2952
3032
  }
2953
3033
  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
- }
3034
+ const assetKeyStr = this.textureKey.serialize();
3035
+ const keyStr = `entity:${assetKeyStr}`;
3036
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3037
+ if (!mat) {
3038
+ const pending = this.loadTextures();
3039
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3040
+ await pending;
3041
+ if (!this.imageData) return;
3042
+ const canvas = this.imageData.data.canvas;
3043
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3044
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3045
+ this.imageData = void 0;
3046
+ }
3047
+ this.iterateAllMeshes((mesh) => {
3048
+ mesh.material = mat;
3049
+ });
3050
+ this.notifyDirty();
2968
3051
  }
2969
3052
  };
2970
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
3053
+ EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
2971
3054
  function isEntityObject(obj) {
2972
3055
  return obj.isEntityObject;
2973
3056
  }
@@ -2979,7 +3062,7 @@ var GuiObject = class extends SceneObject {
2979
3062
 
2980
3063
  // src/inspector/SceneInspector.ts
2981
3064
  import { Raycaster, Vector2 as Vector22 } from "three";
2982
- var p8 = prefix("SceneInspector");
3065
+ var p7 = prefix("SceneInspector");
2983
3066
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
2984
3067
  var SceneInspector = class {
2985
3068
  constructor(renderer) {
@@ -3048,7 +3131,7 @@ var SceneInspector = class {
3048
3131
  }
3049
3132
  selectObject(targetObject, targetIntersection) {
3050
3133
  this.selectedObject = targetObject;
3051
- console.log(p8, "selected", targetObject);
3134
+ console.log(p7, "selected", targetObject);
3052
3135
  this.redraw(targetObject, targetIntersection);
3053
3136
  }
3054
3137
  redraw(targetObject, targetIntersection) {
@@ -3346,7 +3429,7 @@ var SceneStatsDisplay = class {
3346
3429
  };
3347
3430
 
3348
3431
  // src/instance/InstanceManager.ts
3349
- var p9 = prefix("InstanceManager");
3432
+ var p8 = prefix("InstanceManager");
3350
3433
  var InstanceManager = class {
3351
3434
  constructor() {
3352
3435
  this.isInstanceManager = true;
@@ -3354,7 +3437,7 @@ var InstanceManager = class {
3354
3437
  }
3355
3438
  async get(key) {
3356
3439
  if (key in this.instanceCache) {
3357
- console.debug(p9, "key in cache", key);
3440
+ console.debug(p8, "key in cache", key);
3358
3441
  return (await this.instanceCache[key]).nextInstance();
3359
3442
  }
3360
3443
  return void 0;
@@ -3363,14 +3446,18 @@ var InstanceManager = class {
3363
3446
  if (key in this.instanceCache) {
3364
3447
  return await this.get(key);
3365
3448
  }
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];
3373
- }
3449
+ console.debug(p8, "key not in cache", key);
3450
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3451
+ this.instanceCache[key] = pending;
3452
+ try {
3453
+ return await pending;
3454
+ } catch (error) {
3455
+ if (this.instanceCache[key] === pending) {
3456
+ delete this.instanceCache[key];
3457
+ }
3458
+ throw error;
3459
+ }
3460
+ }
3374
3461
  reset() {
3375
3462
  for (let instanceCacheKey in this.instanceCache) {
3376
3463
  delete this.instanceCache[instanceCacheKey];
@@ -3968,15 +4055,15 @@ function computeMorphedAttributes(object) {
3968
4055
  }
3969
4056
 
3970
4057
  // src/model/scene/ModelObject.ts
3971
- var import_ts_deepmerge6 = __toESM(require_dist());
3972
- var p10 = prefix("ModelObject");
4058
+ var import_ts_deepmerge5 = __toESM(require_dist());
4059
+ var p9 = prefix("ModelObject");
3973
4060
  var _ModelObject = class _ModelObject extends SceneObject {
3974
4061
  constructor(originalModel, options) {
3975
4062
  super(options);
3976
4063
  this.originalModel = originalModel;
3977
4064
  this.isModelObject = true;
3978
4065
  this.meshesCreated = false;
3979
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4066
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
3980
4067
  console.log("ModelObject options", this.options);
3981
4068
  }
3982
4069
  async init() {
@@ -4019,10 +4106,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
4019
4106
  }
4020
4107
  });
4021
4108
  } else {
4022
- console.debug(p10, this.atlas.model, "has no elements");
4109
+ console.debug(p9, this.atlas.model, "has no elements");
4023
4110
  }
4024
4111
  } else {
4025
- console.debug(p10, "Missing atlas for", this);
4112
+ console.debug(p9, "Missing atlas for", this);
4026
4113
  }
4027
4114
  if (this.options.mergeMeshes) {
4028
4115
  let combinedGeo;
@@ -4074,16 +4161,16 @@ var _ModelObject = class _ModelObject extends SceneObject {
4074
4161
  }
4075
4162
  }
4076
4163
  };
4077
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4164
+ _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4078
4165
  var ModelObject = _ModelObject;
4079
4166
  function isModelObject(obj) {
4080
4167
  return obj.isModelObject;
4081
4168
  }
4082
4169
 
4083
4170
  // src/model/block/scene/BlockObject.ts
4084
- var import_ts_deepmerge7 = __toESM(require_dist());
4171
+ var import_ts_deepmerge6 = __toESM(require_dist());
4085
4172
  import { Euler as Euler3, Matrix4 as Matrix46, Vector3 as Vector36 } from "three";
4086
- var p11 = prefix("BlockObject");
4173
+ var p10 = prefix("BlockObject");
4087
4174
  var _BlockObject = class _BlockObject extends SceneObject {
4088
4175
  constructor(blockState, options) {
4089
4176
  super(options);
@@ -4097,11 +4184,11 @@ var _BlockObject = class _BlockObject extends SceneObject {
4097
4184
  this._instanceModel = [];
4098
4185
  this._variants = [];
4099
4186
  this._models = [];
4100
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4187
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4101
4188
  }
4102
4189
  async init() {
4103
4190
  if (this.options.applyDefaultState) {
4104
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4191
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4105
4192
  if (defaultState && Object.keys(defaultState).length > 0) {
4106
4193
  const state = {};
4107
4194
  for (let k in defaultState) {
@@ -4177,7 +4264,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4177
4264
  } else if (this.blockState.multipart) {
4178
4265
  for (let part of this.blockState.multipart) {
4179
4266
  if (!part.apply) {
4180
- console.debug(p11, "Missing apply for blockState part", part);
4267
+ console.debug(p10, "Missing apply for blockState part", part);
4181
4268
  continue;
4182
4269
  }
4183
4270
  if (!part.when) {
@@ -4386,7 +4473,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4386
4473
  //TODO: should override rotation + scale methods
4387
4474
  //TODO
4388
4475
  };
4389
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4476
+ _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4390
4477
  applyDefaultState: true
4391
4478
  });
4392
4479
  var BlockObject = _BlockObject;
@@ -4436,7 +4523,7 @@ var StructureParser = class {
4436
4523
 
4437
4524
  // src/renderer/MineRenderScene.ts
4438
4525
  import { Scene as Scene2 } from "three";
4439
- var import_ts_deepmerge9 = __toESM(require_dist());
4526
+ var import_ts_deepmerge8 = __toESM(require_dist());
4440
4527
 
4441
4528
  // src/skin/SkinPart.ts
4442
4529
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5167,7 +5254,7 @@ var slimSkinGeometries = {
5167
5254
  };
5168
5255
 
5169
5256
  // src/skin/scene/SkinObject.ts
5170
- var import_ts_deepmerge8 = __toESM(require_dist());
5257
+ var import_ts_deepmerge7 = __toESM(require_dist());
5171
5258
  var SkinObject = class extends SceneObject {
5172
5259
  constructor(options) {
5173
5260
  super();
@@ -5175,7 +5262,7 @@ var SkinObject = class extends SceneObject {
5175
5262
  this.legacy = false;
5176
5263
  this.skinTextureWidth = 64;
5177
5264
  this.skinTextureHeight = 64;
5178
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5265
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5179
5266
  }
5180
5267
  async init() {
5181
5268
  this.createMeshes();
@@ -5286,24 +5373,54 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5286
5373
  this.stats = new SceneStats();
5287
5374
  this.instanceManager = new InstanceManager();
5288
5375
  this.dirty = true;
5289
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5376
+ this.observedObjects = /* @__PURE__ */ new Set();
5377
+ this.onObjectChange = (event) => {
5378
+ if (event.target?.parent === this) {
5379
+ this.dirty = true;
5380
+ }
5381
+ };
5382
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5290
5383
  }
5291
- add(...object) {
5292
- this.dirty = true;
5293
- this.stats.objectCount += object.length;
5294
- for (let obj of object) {
5295
- if (isSceneObject(obj)) {
5296
- this.stats.sceneObjectCount++;
5384
+ add(...objects) {
5385
+ for (const object of objects) {
5386
+ this.dirty = true;
5387
+ try {
5388
+ super.add(object);
5389
+ } finally {
5390
+ if (object?.isObject3D && object !== this) {
5391
+ this.updateObjectRegistration(object, object.parent === this);
5392
+ }
5297
5393
  }
5298
- obj.addEventListener("change", (event) => {
5299
- this.dirty = true;
5300
- });
5301
5394
  }
5302
- return super.add(...object);
5395
+ return this;
5303
5396
  }
5304
- remove(...object) {
5305
- this.dirty = true;
5306
- return super.remove(...object);
5397
+ remove(...objects) {
5398
+ for (const object of objects) {
5399
+ if (!this.children.includes(object)) continue;
5400
+ this.dirty = true;
5401
+ this.updateObjectRegistration(object, false);
5402
+ try {
5403
+ super.remove(object);
5404
+ } finally {
5405
+ this.updateObjectRegistration(object, object.parent === this);
5406
+ }
5407
+ }
5408
+ return this;
5409
+ }
5410
+ updateObjectRegistration(object, attached) {
5411
+ if (this.observedObjects.has(object) === attached) return;
5412
+ if (attached) {
5413
+ this.observedObjects.add(object);
5414
+ object.addEventListener("change", this.onObjectChange);
5415
+ } else {
5416
+ this.observedObjects.delete(object);
5417
+ object.removeEventListener("change", this.onObjectChange);
5418
+ }
5419
+ const change = attached ? 1 : -1;
5420
+ this.stats.objectCount += change;
5421
+ if (isSceneObject(object)) {
5422
+ this.stats.sceneObjectCount += change;
5423
+ }
5307
5424
  }
5308
5425
  async initAndAdd(...object) {
5309
5426
  this.dirty = true;
@@ -5358,1054 +5475,1148 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5358
5475
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5359
5476
  }
5360
5477
  };
5361
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5478
+ _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5362
5479
  var MineRenderScene = _MineRenderScene;
5363
5480
  function isMineRenderScene(obj) {
5364
5481
  return obj.isMineRenderScene;
5365
5482
  }
5366
5483
 
5367
5484
  // src/renderer/Renderer.ts
5368
- import { AxesHelper as AxesHelper3, GridHelper, LinearEncoding, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, Vector3 as Vector37, WebGLRenderer } from "three";
5369
- var import_ts_deepmerge10 = __toESM(require_dist());
5485
+ import { AxesHelper as AxesHelper3, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector38, WebGLRenderer } from "three";
5486
+ var import_ts_deepmerge9 = __toESM(require_dist());
5370
5487
  import Stats from "stats.js";
5371
5488
  import { EffectComposer, RenderPass } from "postprocessing";
5372
- var _Renderer = class _Renderer {
5373
- constructor(options) {
5374
- this._dirty = true;
5375
- this._animationTimer = void 0;
5376
- this._animationFrame = void 0;
5377
- this._resizeListener = void 0;
5378
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
5379
- this._animationLoop = this.animate.bind(this);
5380
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
5381
- this._scene = this.createScene();
5382
- this._camera = this.createCamera();
5383
- this._renderer = this.createRenderer();
5384
- this._composer = this.createComposer();
5385
- if (this.options.render.stats) {
5386
- this._stats = new Stats();
5387
- document.body.appendChild(this._stats.dom);
5489
+
5490
+ // src/three/OrbitControls.js
5491
+ import {
5492
+ EventDispatcher,
5493
+ MOUSE,
5494
+ Quaternion as Quaternion3,
5495
+ Spherical,
5496
+ TOUCH,
5497
+ Vector2 as Vector23,
5498
+ Vector3 as Vector37
5499
+ } from "three";
5500
+ var _changeEvent = { type: "change" };
5501
+ var _startEvent = { type: "start" };
5502
+ var _endEvent = { type: "end" };
5503
+ var OrbitControls = class extends EventDispatcher {
5504
+ constructor(object, domElement) {
5505
+ super();
5506
+ if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5507
+ if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5508
+ this.object = object;
5509
+ this.domElement = domElement;
5510
+ this.domElement.style.touchAction = "none";
5511
+ this.enabled = true;
5512
+ this.target = new Vector37();
5513
+ this.minDistance = 0;
5514
+ this.maxDistance = Infinity;
5515
+ this.minZoom = 0;
5516
+ this.maxZoom = Infinity;
5517
+ this.minPolarAngle = 0;
5518
+ this.maxPolarAngle = Math.PI;
5519
+ this.minAzimuthAngle = -Infinity;
5520
+ this.maxAzimuthAngle = Infinity;
5521
+ this.enableDamping = false;
5522
+ this.dampingFactor = 0.05;
5523
+ this.enableZoom = true;
5524
+ this.zoomSpeed = 1;
5525
+ this.enableRotate = true;
5526
+ this.rotateSpeed = 1;
5527
+ this.enablePan = true;
5528
+ this.panSpeed = 1;
5529
+ this.screenSpacePanning = true;
5530
+ this.keyPanSpeed = 7;
5531
+ this.autoRotate = false;
5532
+ this.autoRotateSpeed = 2;
5533
+ this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5534
+ this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
5535
+ this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
5536
+ this.target0 = this.target.clone();
5537
+ this.position0 = this.object.position.clone();
5538
+ this.zoom0 = this.object.zoom;
5539
+ this._domElementKeyEvents = null;
5540
+ this.getPolarAngle = function() {
5541
+ return spherical.phi;
5542
+ };
5543
+ this.getAzimuthalAngle = function() {
5544
+ return spherical.theta;
5545
+ };
5546
+ this.getDistance = function() {
5547
+ return this.object.position.distanceTo(this.target);
5548
+ };
5549
+ this.saveState = function() {
5550
+ scope.target0.copy(scope.target);
5551
+ scope.position0.copy(scope.object.position);
5552
+ scope.zoom0 = scope.object.zoom;
5553
+ };
5554
+ this.reset = function() {
5555
+ scope.target.copy(scope.target0);
5556
+ scope.object.position.copy(scope.position0);
5557
+ scope.object.zoom = scope.zoom0;
5558
+ scope.object.updateProjectionMatrix();
5559
+ scope.dispatchEvent(_changeEvent);
5560
+ scope.update();
5561
+ state = STATE.NONE;
5562
+ };
5563
+ this.update = function() {
5564
+ const offset = new Vector37();
5565
+ const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector37(0, 1, 0));
5566
+ const quatInverse = quat.clone().invert();
5567
+ const lastPosition = new Vector37();
5568
+ const lastQuaternion = new Quaternion3();
5569
+ const twoPI = 2 * Math.PI;
5570
+ return function update() {
5571
+ const position = scope.object.position;
5572
+ offset.copy(position).sub(scope.target);
5573
+ offset.applyQuaternion(quat);
5574
+ spherical.setFromVector3(offset);
5575
+ if (scope.autoRotate && state === STATE.NONE) {
5576
+ rotateLeft(getAutoRotationAngle());
5577
+ }
5578
+ if (scope.enableDamping) {
5579
+ spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5580
+ spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5581
+ } else {
5582
+ spherical.theta += sphericalDelta.theta;
5583
+ spherical.phi += sphericalDelta.phi;
5584
+ }
5585
+ let min = scope.minAzimuthAngle;
5586
+ let max = scope.maxAzimuthAngle;
5587
+ if (isFinite(min) && isFinite(max)) {
5588
+ if (min < -Math.PI) min += twoPI;
5589
+ else if (min > Math.PI) min -= twoPI;
5590
+ if (max < -Math.PI) max += twoPI;
5591
+ else if (max > Math.PI) max -= twoPI;
5592
+ if (min <= max) {
5593
+ spherical.theta = Math.max(min, Math.min(max, spherical.theta));
5594
+ } else {
5595
+ spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
5596
+ }
5597
+ }
5598
+ spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5599
+ spherical.makeSafe();
5600
+ spherical.radius *= scale;
5601
+ spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5602
+ if (scope.enableDamping === true) {
5603
+ scope.target.addScaledVector(panOffset, scope.dampingFactor);
5604
+ } else {
5605
+ scope.target.add(panOffset);
5606
+ }
5607
+ offset.setFromSpherical(spherical);
5608
+ offset.applyQuaternion(quatInverse);
5609
+ position.copy(scope.target).add(offset);
5610
+ scope.object.lookAt(scope.target);
5611
+ if (scope.enableDamping === true) {
5612
+ sphericalDelta.theta *= 1 - scope.dampingFactor;
5613
+ sphericalDelta.phi *= 1 - scope.dampingFactor;
5614
+ panOffset.multiplyScalar(1 - scope.dampingFactor);
5615
+ } else {
5616
+ sphericalDelta.set(0, 0, 0);
5617
+ panOffset.set(0, 0, 0);
5618
+ }
5619
+ scale = 1;
5620
+ if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5621
+ scope.dispatchEvent(_changeEvent);
5622
+ lastPosition.copy(scope.object.position);
5623
+ lastQuaternion.copy(scope.object.quaternion);
5624
+ zoomChanged = false;
5625
+ return true;
5626
+ }
5627
+ return false;
5628
+ };
5629
+ }();
5630
+ this.dispose = function() {
5631
+ scope.domElement.removeEventListener("contextmenu", onContextMenu);
5632
+ scope.domElement.removeEventListener("pointerdown", onPointerDown);
5633
+ scope.domElement.removeEventListener("pointercancel", onPointerCancel);
5634
+ scope.domElement.removeEventListener("wheel", onMouseWheel);
5635
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
5636
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5637
+ if (scope._domElementKeyEvents !== null) {
5638
+ scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
5639
+ }
5640
+ };
5641
+ const scope = this;
5642
+ const STATE = {
5643
+ NONE: -1,
5644
+ ROTATE: 0,
5645
+ DOLLY: 1,
5646
+ PAN: 2,
5647
+ TOUCH_ROTATE: 3,
5648
+ TOUCH_PAN: 4,
5649
+ TOUCH_DOLLY_PAN: 5,
5650
+ TOUCH_DOLLY_ROTATE: 6
5651
+ };
5652
+ let state = STATE.NONE;
5653
+ const EPS = 1e-6;
5654
+ const spherical = new Spherical();
5655
+ const sphericalDelta = new Spherical();
5656
+ let scale = 1;
5657
+ const panOffset = new Vector37();
5658
+ let zoomChanged = false;
5659
+ const rotateStart = new Vector23();
5660
+ const rotateEnd = new Vector23();
5661
+ const rotateDelta = new Vector23();
5662
+ const panStart = new Vector23();
5663
+ const panEnd = new Vector23();
5664
+ const panDelta = new Vector23();
5665
+ const dollyStart = new Vector23();
5666
+ const dollyEnd = new Vector23();
5667
+ const dollyDelta = new Vector23();
5668
+ const pointers = [];
5669
+ const pointerPositions = {};
5670
+ function getAutoRotationAngle() {
5671
+ return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
5388
5672
  }
5389
- this.init();
5390
- }
5391
- //<editor-fold desc="INIT">
5392
- createScene() {
5393
- return new MineRenderScene();
5394
- }
5395
- createCamera() {
5396
- switch (this.options.camera.type) {
5397
- case "perspective":
5398
- default:
5399
- return new PerspectiveCamera(
5400
- this.options.camera.perspective.fov,
5401
- this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
5402
- this.options.camera.near,
5403
- this.options.camera.far
5404
- );
5405
- case "orthographic":
5406
- return new OrthographicCamera(
5407
- this.options.camera.orthographic.left ?? this.viewWidth / -2,
5408
- this.options.camera.orthographic.right ?? this.viewWidth / 2,
5409
- this.options.camera.orthographic.top ?? this.viewHeight / 2,
5410
- this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
5411
- this.options.camera.near,
5412
- this.options.camera.far
5413
- );
5673
+ function getZoomScale() {
5674
+ return Math.pow(0.95, scope.zoomSpeed);
5414
5675
  }
5415
- }
5416
- createRenderer() {
5417
- const renderer = new WebGLRenderer({
5418
- antialias: this.options.render.antialias,
5419
- alpha: true,
5420
- powerPreference: "high-performance",
5421
- depth: true
5422
- });
5423
- renderer.setClearColor(0, 0);
5424
- renderer.shadowMap.enabled = true;
5425
- renderer.shadowMap.type = PCFSoftShadowMap;
5426
- renderer.outputEncoding = LinearEncoding;
5427
- renderer.setSize(this.viewWidth, this.viewHeight);
5428
- return renderer;
5429
- }
5430
- createComposer() {
5431
- const composer = new EffectComposer(this.renderer);
5432
- if (!this.options.composer.enabled) return composer;
5433
- composer.setSize(this.viewWidth, this.viewHeight);
5434
- composer.addPass(new RenderPass(this.scene, this.camera));
5435
- return composer;
5436
- }
5437
- //</editor-fold>
5438
- init() {
5439
- if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
5440
- window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
5676
+ function rotateLeft(angle) {
5677
+ sphericalDelta.theta -= angle;
5441
5678
  }
5442
- if (this.options.debug.grid) {
5443
- const gridHelper = new GridHelper(128, 16);
5444
- this.scene.add(gridHelper);
5445
- const gridHelper2 = new GridHelper(128, 16);
5446
- gridHelper2.rotation.x = 90 * (Math.PI / 180);
5447
- this.scene.add(gridHelper2);
5448
- const gridHelper3 = new GridHelper(128, 16);
5449
- gridHelper3.rotation.z = 90 * (Math.PI / 180);
5450
- this.scene.add(gridHelper3);
5679
+ function rotateUp(angle) {
5680
+ sphericalDelta.phi -= angle;
5451
5681
  }
5452
- if (this.options.debug.axes) {
5453
- const axesHelper = new AxesHelper3(64);
5454
- this.scene.add(axesHelper);
5682
+ const panLeft = function() {
5683
+ const v = new Vector37();
5684
+ return function panLeft2(distance, objectMatrix) {
5685
+ v.setFromMatrixColumn(objectMatrix, 0);
5686
+ v.multiplyScalar(-distance);
5687
+ panOffset.add(v);
5688
+ };
5689
+ }();
5690
+ const panUp = function() {
5691
+ const v = new Vector37();
5692
+ return function panUp2(distance, objectMatrix) {
5693
+ if (scope.screenSpacePanning === true) {
5694
+ v.setFromMatrixColumn(objectMatrix, 1);
5695
+ } else {
5696
+ v.setFromMatrixColumn(objectMatrix, 0);
5697
+ v.crossVectors(scope.object.up, v);
5698
+ }
5699
+ v.multiplyScalar(distance);
5700
+ panOffset.add(v);
5701
+ };
5702
+ }();
5703
+ const pan = function() {
5704
+ const offset = new Vector37();
5705
+ return function pan2(deltaX, deltaY) {
5706
+ const element = scope.domElement;
5707
+ if (scope.object.isPerspectiveCamera) {
5708
+ const position = scope.object.position;
5709
+ offset.copy(position).sub(scope.target);
5710
+ let targetDistance = offset.length();
5711
+ targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
5712
+ panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
5713
+ panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
5714
+ } else if (scope.object.isOrthographicCamera) {
5715
+ panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
5716
+ panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
5717
+ } else {
5718
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
5719
+ scope.enablePan = false;
5720
+ }
5721
+ };
5722
+ }();
5723
+ function dollyOut(dollyScale) {
5724
+ if (scope.object.isPerspectiveCamera) {
5725
+ scale /= dollyScale;
5726
+ } else if (scope.object.isOrthographicCamera) {
5727
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
5728
+ scope.object.updateProjectionMatrix();
5729
+ zoomChanged = true;
5730
+ } else {
5731
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
5732
+ scope.enableZoom = false;
5733
+ }
5455
5734
  }
5456
- if (this.options.camera.position) {
5457
- if (isVector3(this.options.camera.position)) {
5458
- this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
5459
- } else if (isTripleArray(this.options.camera.position)) {
5460
- this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
5735
+ function dollyIn(dollyScale) {
5736
+ if (scope.object.isPerspectiveCamera) {
5737
+ scale *= dollyScale;
5738
+ } else if (scope.object.isOrthographicCamera) {
5739
+ scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
5740
+ scope.object.updateProjectionMatrix();
5741
+ zoomChanged = true;
5742
+ } else {
5743
+ console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
5744
+ scope.enableZoom = false;
5461
5745
  }
5462
5746
  }
5463
- if (this.options.camera.lookingAt) {
5464
- if (isVector3(this.options.camera.lookingAt)) {
5465
- this.camera.lookAt(this.options.camera.lookingAt);
5466
- } else if (isTripleArray(this.options.camera.lookingAt)) {
5467
- this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
5747
+ function handleMouseDownRotate(event) {
5748
+ rotateStart.set(event.clientX, event.clientY);
5749
+ }
5750
+ function handleMouseDownDolly(event) {
5751
+ dollyStart.set(event.clientX, event.clientY);
5752
+ }
5753
+ function handleMouseDownPan(event) {
5754
+ panStart.set(event.clientX, event.clientY);
5755
+ }
5756
+ function handleMouseMoveRotate(event) {
5757
+ rotateEnd.set(event.clientX, event.clientY);
5758
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
5759
+ const element = scope.domElement;
5760
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
5761
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
5762
+ rotateStart.copy(rotateEnd);
5763
+ scope.update();
5764
+ }
5765
+ function handleMouseMoveDolly(event) {
5766
+ dollyEnd.set(event.clientX, event.clientY);
5767
+ dollyDelta.subVectors(dollyEnd, dollyStart);
5768
+ if (dollyDelta.y > 0) {
5769
+ dollyOut(getZoomScale());
5770
+ } else if (dollyDelta.y < 0) {
5771
+ dollyIn(getZoomScale());
5468
5772
  }
5773
+ dollyStart.copy(dollyEnd);
5774
+ scope.update();
5469
5775
  }
5470
- if (this.options.render.autoResize) {
5471
- this._resizeListener = () => {
5472
- this.resize(this.viewWidth, this.viewHeight);
5473
- };
5474
- window.addEventListener("resize", this._resizeListener);
5776
+ function handleMouseMovePan(event) {
5777
+ panEnd.set(event.clientX, event.clientY);
5778
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
5779
+ pan(panDelta.x, panDelta.y);
5780
+ panStart.copy(panEnd);
5781
+ scope.update();
5475
5782
  }
5476
- }
5477
- get element() {
5478
- return this._element;
5479
- }
5480
- appendTo(element) {
5481
- this._element = element;
5482
- this._element.appendChild(this.renderer.domElement);
5483
- if (this.viewWidth == 0) {
5484
- console.warn("0 element width");
5783
+ function handleMouseUp() {
5485
5784
  }
5486
- if (this.viewHeight == 0) {
5487
- console.warn("0 element height");
5785
+ function handleMouseWheel(event) {
5786
+ if (event.deltaY < 0) {
5787
+ dollyIn(getZoomScale());
5788
+ } else if (event.deltaY > 0) {
5789
+ dollyOut(getZoomScale());
5790
+ }
5791
+ scope.update();
5488
5792
  }
5489
- this.resize(this.viewWidth, this.viewHeight);
5490
- }
5491
- /**
5492
- * Register an EventDispatcher which may update the scene or renderer in order to redraw the scene
5493
- */
5494
- registerEventDispatcher(dispatcher, changeEvent2 = "change") {
5495
- dispatcher.addEventListener(changeEvent2, (event) => {
5496
- this._dirty = true;
5497
- });
5498
- }
5499
- resize(width, height) {
5500
- if (isPerspectiveCamera(this.camera)) {
5501
- this.camera.aspect = width / height;
5502
- this.camera.updateProjectionMatrix();
5503
- } else if (isOrthographicCamera(this.camera)) {
5504
- this.camera.left = width / -2;
5505
- this.camera.right = width / 2;
5506
- this.camera.top = height / 2;
5507
- this.camera.bottom = height / -2;
5508
- this.camera.updateProjectionMatrix();
5793
+ function handleKeyDown(event) {
5794
+ let needsUpdate = false;
5795
+ switch (event.code) {
5796
+ case scope.keys.UP:
5797
+ pan(0, scope.keyPanSpeed);
5798
+ needsUpdate = true;
5799
+ break;
5800
+ case scope.keys.BOTTOM:
5801
+ pan(0, -scope.keyPanSpeed);
5802
+ needsUpdate = true;
5803
+ break;
5804
+ case scope.keys.LEFT:
5805
+ pan(scope.keyPanSpeed, 0);
5806
+ needsUpdate = true;
5807
+ break;
5808
+ case scope.keys.RIGHT:
5809
+ pan(-scope.keyPanSpeed, 0);
5810
+ needsUpdate = true;
5811
+ break;
5812
+ }
5813
+ if (needsUpdate) {
5814
+ event.preventDefault();
5815
+ scope.update();
5816
+ }
5509
5817
  }
5510
- this.renderer.setSize(width, height);
5511
- this.composer.setSize(width, height);
5512
- }
5513
- //<editor-fold desc="RENDER">
5514
- get dirty() {
5515
- return this._dirty || this.scene.dirty;
5516
- }
5517
- set dirty(dirty) {
5518
- this._dirty = dirty;
5519
- this.scene.dirty = dirty;
5520
- }
5521
- start() {
5522
- stop();
5523
- this.renderer.setAnimationLoop(this._animationLoop);
5524
- }
5525
- stop() {
5526
- this.renderer.setAnimationLoop(null);
5527
- if (this._animationTimer)
5528
- clearTimeout(this._animationTimer);
5529
- this._animationTimer = void 0;
5530
- if (this._animationFrame)
5531
- cancelAnimationFrame(this._animationFrame);
5532
- this._animationFrame = void 0;
5533
- }
5534
- animate(t) {
5535
- if (this._stats) {
5536
- this._stats.begin();
5818
+ function handleTouchStartRotate() {
5819
+ if (pointers.length === 1) {
5820
+ rotateStart.set(pointers[0].pageX, pointers[0].pageY);
5821
+ } else {
5822
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
5823
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
5824
+ rotateStart.set(x, y);
5825
+ }
5537
5826
  }
5538
- if (this.dirty || this.options.render.renderAlways) {
5539
- if (this.options.composer.enabled) {
5540
- this.composer.render();
5827
+ function handleTouchStartPan() {
5828
+ if (pointers.length === 1) {
5829
+ panStart.set(pointers[0].pageX, pointers[0].pageY);
5541
5830
  } else {
5542
- this.renderer.render(this.scene, this.camera);
5831
+ const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
5832
+ const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
5833
+ panStart.set(x, y);
5543
5834
  }
5544
5835
  }
5545
- this.dirty = false;
5546
- if (this._stats) {
5547
- this._stats.end();
5836
+ function handleTouchStartDolly() {
5837
+ const dx = pointers[0].pageX - pointers[1].pageX;
5838
+ const dy = pointers[0].pageY - pointers[1].pageY;
5839
+ const distance = Math.sqrt(dx * dx + dy * dy);
5840
+ dollyStart.set(0, distance);
5548
5841
  }
5549
- }
5550
- //</editor-fold>
5551
- toImage() {
5552
- return this.renderer.domElement.toDataURL();
5553
- }
5554
- ///
5555
- get attachedToBody() {
5556
- return this.element === document.body;
5557
- }
5558
- get viewWidth() {
5559
- return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
5560
- }
5561
- get viewHeight() {
5562
- return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
5563
- }
5564
- get scene() {
5565
- return this._scene;
5566
- }
5567
- get camera() {
5568
- return this._camera;
5569
- }
5570
- get renderer() {
5571
- return this._renderer;
5572
- }
5573
- get composer() {
5574
- return this._composer;
5575
- }
5576
- ///
5577
- };
5578
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
5579
- camera: {
5580
- type: "perspective",
5581
- near: 1,
5582
- far: 5e3,
5583
- perspective: {
5584
- aspect: void 0,
5585
- fov: 50
5586
- },
5587
- orthographic: {
5588
- left: void 0,
5589
- right: void 0,
5590
- top: void 0,
5591
- bottom: void 0
5592
- },
5593
- position: new Vector37(50, 50, 50),
5594
- lookingAt: new Vector37(0, 0, 0)
5595
- },
5596
- render: {
5597
- fpsLimit: 60,
5598
- stats: false,
5599
- antialias: true,
5600
- shade: true,
5601
- autoResize: true,
5602
- renderAlways: false
5603
- },
5604
- composer: {
5605
- enabled: true
5606
- },
5607
- debug: {
5608
- grid: false,
5609
- axes: false
5610
- }
5611
- });
5612
- var Renderer = _Renderer;
5613
-
5614
- // src/skin/Skins.ts
5615
- var Skins = class {
5616
- //<editor-fold desc="Skins">
5617
- static async fromUuidOrUsername(uuidOrUsername) {
5618
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5619
- return this.fromUuid(uuidOrUsername);
5620
- }
5621
- return this.fromUsername(uuidOrUsername);
5622
- }
5623
- static async fromUuid(uuid) {
5624
- return this.getSkinProxySkinUrl(uuid);
5625
- }
5626
- static async fromUsername(username) {
5627
- return this.usernameToUuid(username).then((uuid) => {
5628
- if (uuid) {
5629
- return this.fromUuid(uuid);
5630
- }
5631
- return void 0;
5632
- });
5633
- }
5634
- static async fromMineSkin(mineskinId) {
5635
- return this.getMineSkin(mineskinId).then((mineskin) => {
5636
- if (mineskin) {
5637
- return mineskin["data"]["texture"]["value"]["urls"]["skins"];
5638
- }
5639
- return void 0;
5640
- });
5641
- }
5642
- //</editor-fold>
5643
- //<editor-fold desc="Capes">
5644
- static async capeFromUuidOrUsername(uuidOrUsername) {
5645
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5646
- return this.capeFromUuid(uuidOrUsername);
5842
+ function handleTouchStartDollyPan() {
5843
+ if (scope.enableZoom) handleTouchStartDolly();
5844
+ if (scope.enablePan) handleTouchStartPan();
5647
5845
  }
5648
- return this.capeFromUsername(uuidOrUsername);
5649
- }
5650
- static async capeFromUuid(uuid) {
5651
- return this.getSkinProxyCapeUrl(uuid);
5652
- }
5653
- static async capeFromUsername(username) {
5654
- return this.usernameToUuid(username).then((uuid) => {
5655
- if (uuid) {
5656
- return this.capeFromUuid(uuid);
5657
- }
5658
- return void 0;
5659
- });
5660
- }
5661
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
5662
- return this.getCapesDev(uuid, capeType).then((cape) => {
5663
- if (cape) {
5664
- return cape?.stillImageUrl;
5665
- }
5666
- return void 0;
5667
- });
5668
- }
5669
- //</editor-fold>
5670
- //<editor-fold desc="Helpers">
5671
- static async usernameToUuid(username) {
5672
- return this.usernameToUuidSkinProxy(username);
5673
- }
5674
- static async usernameToUuidSkinProxy(username) {
5675
- return Requests.genericRequest({
5676
- baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
5677
- url: "/uuid/" + username
5678
- }).then((res) => {
5679
- if (res.status === 200) {
5680
- return res.data["id"];
5681
- }
5682
- return void 0;
5683
- }).catch((err) => {
5684
- console.warn(err);
5685
- return void 0;
5686
- });
5687
- }
5688
- static async usernameToUuidMineTools(username) {
5689
- return Requests.genericRequest({
5690
- baseURL: "https://api.minetools.eu",
5691
- url: "/uuid/" + username
5692
- }).then((res) => {
5693
- if (res.status === 200) {
5694
- return res.data["id"];
5695
- }
5696
- return void 0;
5697
- }).catch((err) => {
5698
- console.warn(err);
5699
- return void 0;
5700
- });
5701
- }
5702
- static async getProfileFromMinetools(uuid) {
5703
- return Requests.genericRequest({
5704
- baseURL: "https://api.minetools.eu",
5705
- url: "/profile/" + uuid
5706
- }).then((res) => {
5707
- if (res.status === 200) {
5708
- return res.data;
5709
- }
5710
- });
5711
- }
5712
- static async getMineSkin(mineskinId) {
5713
- return Requests.genericRequest({
5714
- baseURL: "https://api.mineskin.org",
5715
- url: "/get/uuid/" + mineskinId
5716
- }).then((res) => {
5717
- if (res.status === 200) {
5718
- return res.data;
5719
- }
5720
- return void 0;
5721
- }).catch((err) => {
5722
- console.warn(err);
5723
- return void 0;
5724
- });
5725
- }
5726
- static async getCapesDev(uuid, type = "all") {
5727
- return Requests.genericRequest({
5728
- baseURL: "https://api.capes.dev",
5729
- url: "/load/" + uuid + "/" + type
5730
- }).then((res) => {
5731
- if (res.status === 200) {
5732
- return res.data;
5733
- }
5734
- return void 0;
5735
- }).catch((err) => {
5736
- console.warn(err);
5737
- return void 0;
5738
- });
5739
- }
5740
- static getCrafatarSkinUrl(uuid) {
5741
- return "https://crafatar.com/skins/" + uuid;
5742
- }
5743
- static getCrafatarCapeUrl(uuid) {
5744
- return "https://crafatar.com/capes/" + uuid;
5745
- }
5746
- static getMcHeadsSkinUrl(uuid) {
5747
- return "https://mc-heads.net/skin/" + uuid;
5748
- }
5749
- static getMineSkinPlayerSkinUrl(uuid) {
5750
- return "https://mineskin.org/skin/player/" + uuid;
5751
- }
5752
- static getSkinProxySkinUrl(uuid) {
5753
- return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
5754
- }
5755
- static getSkinProxyCapeUrl(uuid) {
5756
- return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
5757
- }
5758
- //</editor-fold>
5759
- };
5760
-
5761
- // src/three/OrbitControls.js
5762
- import {
5763
- EventDispatcher as EventDispatcher2,
5764
- MOUSE,
5765
- Quaternion as Quaternion3,
5766
- Spherical,
5767
- TOUCH,
5768
- Vector2 as Vector23,
5769
- Vector3 as Vector38
5770
- } from "three";
5771
- var _changeEvent = { type: "change" };
5772
- var _startEvent = { type: "start" };
5773
- var _endEvent = { type: "end" };
5774
- var OrbitControls = class extends EventDispatcher2 {
5775
- constructor(object, domElement) {
5776
- super();
5777
- if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
5778
- if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
5779
- this.object = object;
5780
- this.domElement = domElement;
5781
- this.domElement.style.touchAction = "none";
5782
- this.enabled = true;
5783
- this.target = new Vector38();
5784
- this.minDistance = 0;
5785
- this.maxDistance = Infinity;
5786
- this.minZoom = 0;
5787
- this.maxZoom = Infinity;
5788
- this.minPolarAngle = 0;
5789
- this.maxPolarAngle = Math.PI;
5790
- this.minAzimuthAngle = -Infinity;
5791
- this.maxAzimuthAngle = Infinity;
5792
- this.enableDamping = false;
5793
- this.dampingFactor = 0.05;
5794
- this.enableZoom = true;
5795
- this.zoomSpeed = 1;
5796
- this.enableRotate = true;
5797
- this.rotateSpeed = 1;
5798
- this.enablePan = true;
5799
- this.panSpeed = 1;
5800
- this.screenSpacePanning = true;
5801
- this.keyPanSpeed = 7;
5802
- this.autoRotate = false;
5803
- this.autoRotateSpeed = 2;
5804
- this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
5805
- this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
5806
- this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
5807
- this.target0 = this.target.clone();
5808
- this.position0 = this.object.position.clone();
5809
- this.zoom0 = this.object.zoom;
5810
- this._domElementKeyEvents = null;
5811
- this.getPolarAngle = function() {
5812
- return spherical.phi;
5813
- };
5814
- this.getAzimuthalAngle = function() {
5815
- return spherical.theta;
5816
- };
5817
- this.getDistance = function() {
5818
- return this.object.position.distanceTo(this.target);
5819
- };
5820
- this.saveState = function() {
5821
- scope.target0.copy(scope.target);
5822
- scope.position0.copy(scope.object.position);
5823
- scope.zoom0 = scope.object.zoom;
5824
- };
5825
- this.reset = function() {
5826
- scope.target.copy(scope.target0);
5827
- scope.object.position.copy(scope.position0);
5828
- scope.object.zoom = scope.zoom0;
5829
- scope.object.updateProjectionMatrix();
5830
- scope.dispatchEvent(_changeEvent);
5831
- scope.update();
5832
- state = STATE.NONE;
5833
- };
5834
- this.update = function() {
5835
- const offset = new Vector38();
5836
- const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector38(0, 1, 0));
5837
- const quatInverse = quat.clone().invert();
5838
- const lastPosition = new Vector38();
5839
- const lastQuaternion = new Quaternion3();
5840
- const twoPI = 2 * Math.PI;
5841
- return function update() {
5842
- const position = scope.object.position;
5843
- offset.copy(position).sub(scope.target);
5844
- offset.applyQuaternion(quat);
5845
- spherical.setFromVector3(offset);
5846
- if (scope.autoRotate && state === STATE.NONE) {
5847
- rotateLeft(getAutoRotationAngle());
5848
- }
5849
- if (scope.enableDamping) {
5850
- spherical.theta += sphericalDelta.theta * scope.dampingFactor;
5851
- spherical.phi += sphericalDelta.phi * scope.dampingFactor;
5852
- } else {
5853
- spherical.theta += sphericalDelta.theta;
5854
- spherical.phi += sphericalDelta.phi;
5855
- }
5856
- let min = scope.minAzimuthAngle;
5857
- let max = scope.maxAzimuthAngle;
5858
- if (isFinite(min) && isFinite(max)) {
5859
- if (min < -Math.PI) min += twoPI;
5860
- else if (min > Math.PI) min -= twoPI;
5861
- if (max < -Math.PI) max += twoPI;
5862
- else if (max > Math.PI) max -= twoPI;
5863
- if (min <= max) {
5864
- spherical.theta = Math.max(min, Math.min(max, spherical.theta));
5865
- } else {
5866
- spherical.theta = spherical.theta > (min + max) / 2 ? Math.max(min, spherical.theta) : Math.min(max, spherical.theta);
5867
- }
5868
- }
5869
- spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
5870
- spherical.makeSafe();
5871
- spherical.radius *= scale;
5872
- spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
5873
- if (scope.enableDamping === true) {
5874
- scope.target.addScaledVector(panOffset, scope.dampingFactor);
5875
- } else {
5876
- scope.target.add(panOffset);
5877
- }
5878
- offset.setFromSpherical(spherical);
5879
- offset.applyQuaternion(quatInverse);
5880
- position.copy(scope.target).add(offset);
5881
- scope.object.lookAt(scope.target);
5882
- if (scope.enableDamping === true) {
5883
- sphericalDelta.theta *= 1 - scope.dampingFactor;
5884
- sphericalDelta.phi *= 1 - scope.dampingFactor;
5885
- panOffset.multiplyScalar(1 - scope.dampingFactor);
5886
- } else {
5887
- sphericalDelta.set(0, 0, 0);
5888
- panOffset.set(0, 0, 0);
5889
- }
5890
- scale = 1;
5891
- if (zoomChanged || lastPosition.distanceToSquared(scope.object.position) > EPS || 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
5892
- scope.dispatchEvent(_changeEvent);
5893
- lastPosition.copy(scope.object.position);
5894
- lastQuaternion.copy(scope.object.quaternion);
5895
- zoomChanged = false;
5896
- return true;
5897
- }
5898
- return false;
5899
- };
5900
- }();
5901
- this.dispose = function() {
5902
- scope.domElement.removeEventListener("contextmenu", onContextMenu);
5903
- scope.domElement.removeEventListener("pointerdown", onPointerDown);
5904
- scope.domElement.removeEventListener("pointercancel", onPointerCancel);
5905
- scope.domElement.removeEventListener("wheel", onMouseWheel);
5906
- scope.domElement.removeEventListener("pointermove", onPointerMove);
5907
- scope.domElement.removeEventListener("pointerup", onPointerUp);
5908
- if (scope._domElementKeyEvents !== null) {
5909
- scope._domElementKeyEvents.removeEventListener("keydown", onKeyDown);
5910
- }
5911
- };
5912
- const scope = this;
5913
- const STATE = {
5914
- NONE: -1,
5915
- ROTATE: 0,
5916
- DOLLY: 1,
5917
- PAN: 2,
5918
- TOUCH_ROTATE: 3,
5919
- TOUCH_PAN: 4,
5920
- TOUCH_DOLLY_PAN: 5,
5921
- TOUCH_DOLLY_ROTATE: 6
5922
- };
5923
- let state = STATE.NONE;
5924
- const EPS = 1e-6;
5925
- const spherical = new Spherical();
5926
- const sphericalDelta = new Spherical();
5927
- let scale = 1;
5928
- const panOffset = new Vector38();
5929
- let zoomChanged = false;
5930
- const rotateStart = new Vector23();
5931
- const rotateEnd = new Vector23();
5932
- const rotateDelta = new Vector23();
5933
- const panStart = new Vector23();
5934
- const panEnd = new Vector23();
5935
- const panDelta = new Vector23();
5936
- const dollyStart = new Vector23();
5937
- const dollyEnd = new Vector23();
5938
- const dollyDelta = new Vector23();
5939
- const pointers = [];
5940
- const pointerPositions = {};
5941
- function getAutoRotationAngle() {
5942
- return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
5846
+ function handleTouchStartDollyRotate() {
5847
+ if (scope.enableZoom) handleTouchStartDolly();
5848
+ if (scope.enableRotate) handleTouchStartRotate();
5943
5849
  }
5944
- function getZoomScale() {
5945
- return Math.pow(0.95, scope.zoomSpeed);
5850
+ function handleTouchMoveRotate(event) {
5851
+ if (pointers.length == 1) {
5852
+ rotateEnd.set(event.pageX, event.pageY);
5853
+ } else {
5854
+ const position = getSecondPointerPosition(event);
5855
+ const x = 0.5 * (event.pageX + position.x);
5856
+ const y = 0.5 * (event.pageY + position.y);
5857
+ rotateEnd.set(x, y);
5858
+ }
5859
+ rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
5860
+ const element = scope.domElement;
5861
+ rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
5862
+ rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
5863
+ rotateStart.copy(rotateEnd);
5946
5864
  }
5947
- function rotateLeft(angle) {
5948
- sphericalDelta.theta -= angle;
5865
+ function handleTouchMovePan(event) {
5866
+ if (pointers.length === 1) {
5867
+ panEnd.set(event.pageX, event.pageY);
5868
+ } else {
5869
+ const position = getSecondPointerPosition(event);
5870
+ const x = 0.5 * (event.pageX + position.x);
5871
+ const y = 0.5 * (event.pageY + position.y);
5872
+ panEnd.set(x, y);
5873
+ }
5874
+ panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
5875
+ pan(panDelta.x, panDelta.y);
5876
+ panStart.copy(panEnd);
5949
5877
  }
5950
- function rotateUp(angle) {
5951
- sphericalDelta.phi -= angle;
5878
+ function handleTouchMoveDolly(event) {
5879
+ const position = getSecondPointerPosition(event);
5880
+ const dx = event.pageX - position.x;
5881
+ const dy = event.pageY - position.y;
5882
+ const distance = Math.sqrt(dx * dx + dy * dy);
5883
+ dollyEnd.set(0, distance);
5884
+ dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
5885
+ dollyOut(dollyDelta.y);
5886
+ dollyStart.copy(dollyEnd);
5952
5887
  }
5953
- const panLeft = function() {
5954
- const v = new Vector38();
5955
- return function panLeft2(distance, objectMatrix) {
5956
- v.setFromMatrixColumn(objectMatrix, 0);
5957
- v.multiplyScalar(-distance);
5958
- panOffset.add(v);
5959
- };
5960
- }();
5961
- const panUp = function() {
5962
- const v = new Vector38();
5963
- return function panUp2(distance, objectMatrix) {
5964
- if (scope.screenSpacePanning === true) {
5965
- v.setFromMatrixColumn(objectMatrix, 1);
5966
- } else {
5967
- v.setFromMatrixColumn(objectMatrix, 0);
5968
- v.crossVectors(scope.object.up, v);
5969
- }
5970
- v.multiplyScalar(distance);
5971
- panOffset.add(v);
5972
- };
5973
- }();
5974
- const pan = function() {
5975
- const offset = new Vector38();
5976
- return function pan2(deltaX, deltaY) {
5977
- const element = scope.domElement;
5978
- if (scope.object.isPerspectiveCamera) {
5979
- const position = scope.object.position;
5980
- offset.copy(position).sub(scope.target);
5981
- let targetDistance = offset.length();
5982
- targetDistance *= Math.tan(scope.object.fov / 2 * Math.PI / 180);
5983
- panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
5984
- panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
5985
- } else if (scope.object.isOrthographicCamera) {
5986
- panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
5987
- panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
5988
- } else {
5989
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.");
5990
- scope.enablePan = false;
5991
- }
5992
- };
5993
- }();
5994
- function dollyOut(dollyScale) {
5995
- if (scope.object.isPerspectiveCamera) {
5996
- scale /= dollyScale;
5997
- } else if (scope.object.isOrthographicCamera) {
5998
- scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
5999
- scope.object.updateProjectionMatrix();
6000
- zoomChanged = true;
5888
+ function handleTouchMoveDollyPan(event) {
5889
+ if (scope.enableZoom) handleTouchMoveDolly(event);
5890
+ if (scope.enablePan) handleTouchMovePan(event);
5891
+ }
5892
+ function handleTouchMoveDollyRotate(event) {
5893
+ if (scope.enableZoom) handleTouchMoveDolly(event);
5894
+ if (scope.enableRotate) handleTouchMoveRotate(event);
5895
+ }
5896
+ function handleTouchEnd() {
5897
+ }
5898
+ function onPointerDown(event) {
5899
+ if (scope.enabled === false) return;
5900
+ if (pointers.length === 0) {
5901
+ scope.domElement.setPointerCapture(event.pointerId);
5902
+ scope.domElement.addEventListener("pointermove", onPointerMove);
5903
+ scope.domElement.addEventListener("pointerup", onPointerUp);
5904
+ }
5905
+ addPointer(event);
5906
+ if (event.pointerType === "touch") {
5907
+ onTouchStart(event);
6001
5908
  } else {
6002
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6003
- scope.enableZoom = false;
5909
+ onMouseDown(event);
6004
5910
  }
6005
5911
  }
6006
- function dollyIn(dollyScale) {
6007
- if (scope.object.isPerspectiveCamera) {
6008
- scale *= dollyScale;
6009
- } else if (scope.object.isOrthographicCamera) {
6010
- scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
6011
- scope.object.updateProjectionMatrix();
6012
- zoomChanged = true;
5912
+ function onPointerMove(event) {
5913
+ if (scope.enabled === false) return;
5914
+ if (event.pointerType === "touch") {
5915
+ onTouchMove(event);
6013
5916
  } else {
6014
- console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.");
6015
- scope.enableZoom = false;
5917
+ onMouseMove(event);
6016
5918
  }
6017
5919
  }
6018
- function handleMouseDownRotate(event) {
6019
- rotateStart.set(event.clientX, event.clientY);
5920
+ function onPointerUp(event) {
5921
+ if (scope.enabled === false) return;
5922
+ if (event.pointerType === "touch") {
5923
+ onTouchEnd();
5924
+ } else {
5925
+ onMouseUp(event);
5926
+ }
5927
+ removePointer(event);
5928
+ if (pointers.length === 0) {
5929
+ scope.domElement.releasePointerCapture(event.pointerId);
5930
+ scope.domElement.removeEventListener("pointermove", onPointerMove);
5931
+ scope.domElement.removeEventListener("pointerup", onPointerUp);
5932
+ }
6020
5933
  }
6021
- function handleMouseDownDolly(event) {
6022
- dollyStart.set(event.clientX, event.clientY);
5934
+ function onPointerCancel(event) {
5935
+ removePointer(event);
6023
5936
  }
6024
- function handleMouseDownPan(event) {
6025
- panStart.set(event.clientX, event.clientY);
5937
+ function onMouseDown(event) {
5938
+ let mouseAction;
5939
+ switch (event.button) {
5940
+ case 0:
5941
+ mouseAction = scope.mouseButtons.LEFT;
5942
+ break;
5943
+ case 1:
5944
+ mouseAction = scope.mouseButtons.MIDDLE;
5945
+ break;
5946
+ case 2:
5947
+ mouseAction = scope.mouseButtons.RIGHT;
5948
+ break;
5949
+ default:
5950
+ mouseAction = -1;
5951
+ }
5952
+ switch (mouseAction) {
5953
+ case MOUSE.DOLLY:
5954
+ if (scope.enableZoom === false) return;
5955
+ handleMouseDownDolly(event);
5956
+ state = STATE.DOLLY;
5957
+ break;
5958
+ case MOUSE.ROTATE:
5959
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
5960
+ if (scope.enablePan === false) return;
5961
+ handleMouseDownPan(event);
5962
+ state = STATE.PAN;
5963
+ } else {
5964
+ if (scope.enableRotate === false) return;
5965
+ handleMouseDownRotate(event);
5966
+ state = STATE.ROTATE;
5967
+ }
5968
+ break;
5969
+ case MOUSE.PAN:
5970
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
5971
+ if (scope.enableRotate === false) return;
5972
+ handleMouseDownRotate(event);
5973
+ state = STATE.ROTATE;
5974
+ } else {
5975
+ if (scope.enablePan === false) return;
5976
+ handleMouseDownPan(event);
5977
+ state = STATE.PAN;
5978
+ }
5979
+ break;
5980
+ default:
5981
+ state = STATE.NONE;
5982
+ }
5983
+ if (state !== STATE.NONE) {
5984
+ scope.dispatchEvent(_startEvent);
5985
+ }
6026
5986
  }
6027
- function handleMouseMoveRotate(event) {
6028
- rotateEnd.set(event.clientX, event.clientY);
6029
- rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6030
- const element = scope.domElement;
6031
- rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6032
- rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6033
- rotateStart.copy(rotateEnd);
6034
- scope.update();
5987
+ function onMouseMove(event) {
5988
+ if (scope.enabled === false) return;
5989
+ switch (state) {
5990
+ case STATE.ROTATE:
5991
+ if (scope.enableRotate === false) return;
5992
+ handleMouseMoveRotate(event);
5993
+ break;
5994
+ case STATE.DOLLY:
5995
+ if (scope.enableZoom === false) return;
5996
+ handleMouseMoveDolly(event);
5997
+ break;
5998
+ case STATE.PAN:
5999
+ if (scope.enablePan === false) return;
6000
+ handleMouseMovePan(event);
6001
+ break;
6002
+ }
6035
6003
  }
6036
- function handleMouseMoveDolly(event) {
6037
- dollyEnd.set(event.clientX, event.clientY);
6038
- dollyDelta.subVectors(dollyEnd, dollyStart);
6039
- if (dollyDelta.y > 0) {
6040
- dollyOut(getZoomScale());
6041
- } else if (dollyDelta.y < 0) {
6042
- dollyIn(getZoomScale());
6004
+ function onMouseUp(event) {
6005
+ handleMouseUp(event);
6006
+ scope.dispatchEvent(_endEvent);
6007
+ state = STATE.NONE;
6008
+ }
6009
+ function onMouseWheel(event) {
6010
+ if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE) return;
6011
+ event.preventDefault();
6012
+ scope.dispatchEvent(_startEvent);
6013
+ handleMouseWheel(event);
6014
+ scope.dispatchEvent(_endEvent);
6015
+ }
6016
+ function onKeyDown(event) {
6017
+ if (scope.enabled === false || scope.enablePan === false) return;
6018
+ handleKeyDown(event);
6019
+ }
6020
+ function onTouchStart(event) {
6021
+ trackPointer(event);
6022
+ switch (pointers.length) {
6023
+ case 1:
6024
+ switch (scope.touches.ONE) {
6025
+ case TOUCH.ROTATE:
6026
+ if (scope.enableRotate === false) return;
6027
+ handleTouchStartRotate();
6028
+ state = STATE.TOUCH_ROTATE;
6029
+ break;
6030
+ case TOUCH.PAN:
6031
+ if (scope.enablePan === false) return;
6032
+ handleTouchStartPan();
6033
+ state = STATE.TOUCH_PAN;
6034
+ break;
6035
+ default:
6036
+ state = STATE.NONE;
6037
+ }
6038
+ break;
6039
+ case 2:
6040
+ switch (scope.touches.TWO) {
6041
+ case TOUCH.DOLLY_PAN:
6042
+ if (scope.enableZoom === false && scope.enablePan === false) return;
6043
+ handleTouchStartDollyPan();
6044
+ state = STATE.TOUCH_DOLLY_PAN;
6045
+ break;
6046
+ case TOUCH.DOLLY_ROTATE:
6047
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
6048
+ handleTouchStartDollyRotate();
6049
+ state = STATE.TOUCH_DOLLY_ROTATE;
6050
+ break;
6051
+ default:
6052
+ state = STATE.NONE;
6053
+ }
6054
+ break;
6055
+ default:
6056
+ state = STATE.NONE;
6043
6057
  }
6044
- dollyStart.copy(dollyEnd);
6045
- scope.update();
6046
- }
6047
- function handleMouseMovePan(event) {
6048
- panEnd.set(event.clientX, event.clientY);
6049
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6050
- pan(panDelta.x, panDelta.y);
6051
- panStart.copy(panEnd);
6052
- scope.update();
6053
- }
6054
- function handleMouseUp() {
6055
- }
6056
- function handleMouseWheel(event) {
6057
- if (event.deltaY < 0) {
6058
- dollyIn(getZoomScale());
6059
- } else if (event.deltaY > 0) {
6060
- dollyOut(getZoomScale());
6058
+ if (state !== STATE.NONE) {
6059
+ scope.dispatchEvent(_startEvent);
6061
6060
  }
6062
- scope.update();
6063
6061
  }
6064
- function handleKeyDown(event) {
6065
- let needsUpdate = false;
6066
- switch (event.code) {
6067
- case scope.keys.UP:
6068
- pan(0, scope.keyPanSpeed);
6069
- needsUpdate = true;
6062
+ function onTouchMove(event) {
6063
+ trackPointer(event);
6064
+ switch (state) {
6065
+ case STATE.TOUCH_ROTATE:
6066
+ if (scope.enableRotate === false) return;
6067
+ handleTouchMoveRotate(event);
6068
+ scope.update();
6070
6069
  break;
6071
- case scope.keys.BOTTOM:
6072
- pan(0, -scope.keyPanSpeed);
6073
- needsUpdate = true;
6070
+ case STATE.TOUCH_PAN:
6071
+ if (scope.enablePan === false) return;
6072
+ handleTouchMovePan(event);
6073
+ scope.update();
6074
6074
  break;
6075
- case scope.keys.LEFT:
6076
- pan(scope.keyPanSpeed, 0);
6077
- needsUpdate = true;
6075
+ case STATE.TOUCH_DOLLY_PAN:
6076
+ if (scope.enableZoom === false && scope.enablePan === false) return;
6077
+ handleTouchMoveDollyPan(event);
6078
+ scope.update();
6078
6079
  break;
6079
- case scope.keys.RIGHT:
6080
- pan(-scope.keyPanSpeed, 0);
6081
- needsUpdate = true;
6080
+ case STATE.TOUCH_DOLLY_ROTATE:
6081
+ if (scope.enableZoom === false && scope.enableRotate === false) return;
6082
+ handleTouchMoveDollyRotate(event);
6083
+ scope.update();
6082
6084
  break;
6083
- }
6084
- if (needsUpdate) {
6085
- event.preventDefault();
6086
- scope.update();
6085
+ default:
6086
+ state = STATE.NONE;
6087
6087
  }
6088
6088
  }
6089
- function handleTouchStartRotate() {
6090
- if (pointers.length === 1) {
6091
- rotateStart.set(pointers[0].pageX, pointers[0].pageY);
6092
- } else {
6093
- const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6094
- const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6095
- rotateStart.set(x, y);
6089
+ function onTouchEnd(event) {
6090
+ handleTouchEnd(event);
6091
+ scope.dispatchEvent(_endEvent);
6092
+ state = STATE.NONE;
6093
+ }
6094
+ function onContextMenu(event) {
6095
+ if (scope.enabled === false) return;
6096
+ event.preventDefault();
6097
+ }
6098
+ function addPointer(event) {
6099
+ pointers.push(event);
6100
+ }
6101
+ function removePointer(event) {
6102
+ delete pointerPositions[event.pointerId];
6103
+ for (let i = 0; i < pointers.length; i++) {
6104
+ if (pointers[i].pointerId == event.pointerId) {
6105
+ pointers.splice(i, 1);
6106
+ return;
6107
+ }
6096
6108
  }
6097
6109
  }
6098
- function handleTouchStartPan() {
6099
- if (pointers.length === 1) {
6100
- panStart.set(pointers[0].pageX, pointers[0].pageY);
6101
- } else {
6102
- const x = 0.5 * (pointers[0].pageX + pointers[1].pageX);
6103
- const y = 0.5 * (pointers[0].pageY + pointers[1].pageY);
6104
- panStart.set(x, y);
6110
+ function trackPointer(event) {
6111
+ let position = pointerPositions[event.pointerId];
6112
+ if (position === void 0) {
6113
+ position = new Vector23();
6114
+ pointerPositions[event.pointerId] = position;
6105
6115
  }
6116
+ position.set(event.pageX, event.pageY);
6106
6117
  }
6107
- function handleTouchStartDolly() {
6108
- const dx = pointers[0].pageX - pointers[1].pageX;
6109
- const dy = pointers[0].pageY - pointers[1].pageY;
6110
- const distance = Math.sqrt(dx * dx + dy * dy);
6111
- dollyStart.set(0, distance);
6118
+ function getSecondPointerPosition(event) {
6119
+ const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6120
+ return pointerPositions[pointer.pointerId];
6112
6121
  }
6113
- function handleTouchStartDollyPan() {
6114
- if (scope.enableZoom) handleTouchStartDolly();
6115
- if (scope.enablePan) handleTouchStartPan();
6122
+ scope.domElement.addEventListener("contextmenu", onContextMenu);
6123
+ scope.domElement.addEventListener("pointerdown", onPointerDown);
6124
+ scope.domElement.addEventListener("pointercancel", onPointerCancel);
6125
+ scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6126
+ this.update();
6127
+ }
6128
+ };
6129
+ var MapControls = class extends OrbitControls {
6130
+ constructor(object, domElement) {
6131
+ super(object, domElement);
6132
+ this.screenSpacePanning = false;
6133
+ this.mouseButtons.LEFT = MOUSE.PAN;
6134
+ this.mouseButtons.RIGHT = MOUSE.ROTATE;
6135
+ this.touches.ONE = TOUCH.PAN;
6136
+ this.touches.TWO = TOUCH.DOLLY_ROTATE;
6137
+ }
6138
+ };
6139
+
6140
+ // src/renderer/Renderer.ts
6141
+ var _Renderer = class _Renderer {
6142
+ constructor(options) {
6143
+ this._dirty = true;
6144
+ this._resizeListener = void 0;
6145
+ this._disposed = false;
6146
+ this._debugHelpers = [];
6147
+ this._eventDispatchers = /* @__PURE__ */ new Map();
6148
+ this._changeListener = () => {
6149
+ this._dirty = true;
6150
+ };
6151
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6152
+ this._animationLoop = this.animate.bind(this);
6153
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6154
+ this._scene = this.createScene();
6155
+ this._camera = this.createCamera();
6156
+ this._renderer = this.createRenderer();
6157
+ this._composer = this.createComposer();
6158
+ if (this.options.render.stats) {
6159
+ this._stats = new Stats();
6160
+ document.body.appendChild(this._stats.dom);
6116
6161
  }
6117
- function handleTouchStartDollyRotate() {
6118
- if (scope.enableZoom) handleTouchStartDolly();
6119
- if (scope.enableRotate) handleTouchStartRotate();
6162
+ this.init();
6163
+ this._controls = this.createControls();
6164
+ }
6165
+ //<editor-fold desc="INIT">
6166
+ createScene() {
6167
+ return new MineRenderScene();
6168
+ }
6169
+ createCamera() {
6170
+ switch (this.options.camera.type) {
6171
+ case "perspective":
6172
+ default:
6173
+ return new PerspectiveCamera(
6174
+ this.options.camera.perspective.fov,
6175
+ this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6176
+ this.options.camera.near,
6177
+ this.options.camera.far
6178
+ );
6179
+ case "orthographic":
6180
+ return new OrthographicCamera(
6181
+ this.options.camera.orthographic.left ?? this.viewWidth / -2,
6182
+ this.options.camera.orthographic.right ?? this.viewWidth / 2,
6183
+ this.options.camera.orthographic.top ?? this.viewHeight / 2,
6184
+ this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
6185
+ this.options.camera.near,
6186
+ this.options.camera.far
6187
+ );
6120
6188
  }
6121
- function handleTouchMoveRotate(event) {
6122
- if (pointers.length == 1) {
6123
- rotateEnd.set(event.pageX, event.pageY);
6124
- } else {
6125
- const position = getSecondPointerPosition(event);
6126
- const x = 0.5 * (event.pageX + position.x);
6127
- const y = 0.5 * (event.pageY + position.y);
6128
- rotateEnd.set(x, y);
6129
- }
6130
- rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
6131
- const element = scope.domElement;
6132
- rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight);
6133
- rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
6134
- rotateStart.copy(rotateEnd);
6189
+ }
6190
+ createRenderer() {
6191
+ const renderer = new WebGLRenderer({
6192
+ antialias: this.options.render.antialias,
6193
+ alpha: true,
6194
+ powerPreference: "high-performance",
6195
+ depth: true
6196
+ });
6197
+ renderer.setClearColor(0, 0);
6198
+ renderer.shadowMap.enabled = true;
6199
+ renderer.shadowMap.type = PCFSoftShadowMap;
6200
+ renderer.outputColorSpace = SRGBColorSpace3;
6201
+ renderer.setSize(this.viewWidth, this.viewHeight);
6202
+ return renderer;
6203
+ }
6204
+ createComposer() {
6205
+ if (!this.options.composer.enabled) return void 0;
6206
+ const composer = new EffectComposer(this.renderer);
6207
+ composer.setSize(this.viewWidth, this.viewHeight);
6208
+ composer.addPass(new RenderPass(this.scene, this.camera));
6209
+ return composer;
6210
+ }
6211
+ createControls() {
6212
+ if (!this.options.controls?.enabled) return void 0;
6213
+ const position = this.camera.position.clone();
6214
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
6215
+ this.camera.position.copy(position);
6216
+ const target = this.options.camera.lookingAt;
6217
+ if (isVector3(target)) {
6218
+ controls.target.copy(target);
6219
+ } else if (isTripleArray(target)) {
6220
+ controls.target.set(target[0], target[1], target[2]);
6221
+ }
6222
+ controls.update();
6223
+ controls.saveState();
6224
+ this.registerEventDispatcher(controls);
6225
+ return controls;
6226
+ }
6227
+ //</editor-fold>
6228
+ init() {
6229
+ if (this._disposed) return;
6230
+ if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
6231
+ window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6135
6232
  }
6136
- function handleTouchMovePan(event) {
6137
- if (pointers.length === 1) {
6138
- panEnd.set(event.pageX, event.pageY);
6139
- } else {
6140
- const position = getSecondPointerPosition(event);
6141
- const x = 0.5 * (event.pageX + position.x);
6142
- const y = 0.5 * (event.pageY + position.y);
6143
- panEnd.set(x, y);
6233
+ if (this.options.debug.grid) {
6234
+ const gridHelper = new GridHelper(128, 16);
6235
+ this._debugHelpers.push(gridHelper);
6236
+ this.scene.add(gridHelper);
6237
+ const gridHelper2 = new GridHelper(128, 16);
6238
+ this._debugHelpers.push(gridHelper2);
6239
+ gridHelper2.rotation.x = 90 * (Math.PI / 180);
6240
+ this.scene.add(gridHelper2);
6241
+ const gridHelper3 = new GridHelper(128, 16);
6242
+ this._debugHelpers.push(gridHelper3);
6243
+ gridHelper3.rotation.z = 90 * (Math.PI / 180);
6244
+ this.scene.add(gridHelper3);
6245
+ }
6246
+ if (this.options.debug.axes) {
6247
+ const axesHelper = new AxesHelper3(64);
6248
+ this._debugHelpers.push(axesHelper);
6249
+ this.scene.add(axesHelper);
6250
+ }
6251
+ if (this.options.camera.position) {
6252
+ if (isVector3(this.options.camera.position)) {
6253
+ this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
6254
+ } else if (isTripleArray(this.options.camera.position)) {
6255
+ this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
6144
6256
  }
6145
- panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
6146
- pan(panDelta.x, panDelta.y);
6147
- panStart.copy(panEnd);
6148
6257
  }
6149
- function handleTouchMoveDolly(event) {
6150
- const position = getSecondPointerPosition(event);
6151
- const dx = event.pageX - position.x;
6152
- const dy = event.pageY - position.y;
6153
- const distance = Math.sqrt(dx * dx + dy * dy);
6154
- dollyEnd.set(0, distance);
6155
- dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
6156
- dollyOut(dollyDelta.y);
6157
- dollyStart.copy(dollyEnd);
6258
+ if (this.options.camera.lookingAt) {
6259
+ if (isVector3(this.options.camera.lookingAt)) {
6260
+ this.camera.lookAt(this.options.camera.lookingAt);
6261
+ } else if (isTripleArray(this.options.camera.lookingAt)) {
6262
+ this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6263
+ }
6158
6264
  }
6159
- function handleTouchMoveDollyPan(event) {
6160
- if (scope.enableZoom) handleTouchMoveDolly(event);
6161
- if (scope.enablePan) handleTouchMovePan(event);
6265
+ if (this.options.render.autoResize && !this._resizeListener) {
6266
+ this._resizeListener = () => {
6267
+ this.resize(this.viewWidth, this.viewHeight);
6268
+ };
6269
+ window.addEventListener("resize", this._resizeListener);
6162
6270
  }
6163
- function handleTouchMoveDollyRotate(event) {
6164
- if (scope.enableZoom) handleTouchMoveDolly(event);
6165
- if (scope.enableRotate) handleTouchMoveRotate(event);
6271
+ }
6272
+ get element() {
6273
+ return this._element;
6274
+ }
6275
+ appendTo(element) {
6276
+ if (this._disposed) return;
6277
+ this._element = element;
6278
+ this._element.appendChild(this.renderer.domElement);
6279
+ if (this.viewWidth == 0) {
6280
+ console.warn("0 element width");
6166
6281
  }
6167
- function handleTouchEnd() {
6282
+ if (this.viewHeight == 0) {
6283
+ console.warn("0 element height");
6168
6284
  }
6169
- function onPointerDown(event) {
6170
- if (scope.enabled === false) return;
6171
- if (pointers.length === 0) {
6172
- scope.domElement.setPointerCapture(event.pointerId);
6173
- scope.domElement.addEventListener("pointermove", onPointerMove);
6174
- scope.domElement.addEventListener("pointerup", onPointerUp);
6175
- }
6176
- addPointer(event);
6177
- if (event.pointerType === "touch") {
6178
- onTouchStart(event);
6179
- } else {
6180
- onMouseDown(event);
6181
- }
6285
+ this.resize(this.viewWidth, this.viewHeight);
6286
+ }
6287
+ /**
6288
+ * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
6289
+ * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
6290
+ */
6291
+ registerEventDispatcher(dispatcher, changeEvent2 = "change") {
6292
+ if (this._disposed) return;
6293
+ let events = this._eventDispatchers.get(dispatcher);
6294
+ if (!events) {
6295
+ events = /* @__PURE__ */ new Set();
6296
+ this._eventDispatchers.set(dispatcher, events);
6182
6297
  }
6183
- function onPointerMove(event) {
6184
- if (scope.enabled === false) return;
6185
- if (event.pointerType === "touch") {
6186
- onTouchMove(event);
6187
- } else {
6188
- onMouseMove(event);
6189
- }
6298
+ if (events.has(changeEvent2)) return;
6299
+ events.add(changeEvent2);
6300
+ dispatcher.addEventListener(changeEvent2, this._changeListener);
6301
+ }
6302
+ resize(width, height) {
6303
+ if (this._disposed) return;
6304
+ if (isPerspectiveCamera(this.camera)) {
6305
+ this.camera.aspect = width / height;
6306
+ this.camera.updateProjectionMatrix();
6307
+ } else if (isOrthographicCamera(this.camera)) {
6308
+ this.camera.left = width / -2;
6309
+ this.camera.right = width / 2;
6310
+ this.camera.top = height / 2;
6311
+ this.camera.bottom = height / -2;
6312
+ this.camera.updateProjectionMatrix();
6190
6313
  }
6191
- function onPointerUp(event) {
6192
- if (scope.enabled === false) return;
6193
- if (event.pointerType === "touch") {
6194
- onTouchEnd();
6195
- } else {
6196
- onMouseUp(event);
6197
- }
6198
- removePointer(event);
6199
- if (pointers.length === 0) {
6200
- scope.domElement.releasePointerCapture(event.pointerId);
6201
- scope.domElement.removeEventListener("pointermove", onPointerMove);
6202
- scope.domElement.removeEventListener("pointerup", onPointerUp);
6203
- }
6314
+ this.renderer.setSize(width, height);
6315
+ this.composer?.setSize(width, height);
6316
+ this._dirty = true;
6317
+ }
6318
+ //<editor-fold desc="RENDER">
6319
+ get dirty() {
6320
+ return this._dirty || this.scene.dirty;
6321
+ }
6322
+ set dirty(dirty) {
6323
+ this._dirty = dirty;
6324
+ this.scene.dirty = dirty;
6325
+ }
6326
+ start() {
6327
+ if (this._disposed) return;
6328
+ this.stop();
6329
+ this.renderer.setAnimationLoop(this._animationLoop);
6330
+ }
6331
+ stop() {
6332
+ if (this._disposed) return;
6333
+ this.renderer.setAnimationLoop(null);
6334
+ this._nextFrameTime = void 0;
6335
+ }
6336
+ /**
6337
+ * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
6338
+ * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
6339
+ * controls must be managed by their owners.
6340
+ */
6341
+ dispose() {
6342
+ if (this._disposed) return;
6343
+ this.stop();
6344
+ this._disposed = true;
6345
+ if (this._resizeListener) {
6346
+ window.removeEventListener("resize", this._resizeListener);
6347
+ this._resizeListener = void 0;
6348
+ }
6349
+ for (const [dispatcher, events] of this._eventDispatchers) {
6350
+ for (const event of events) {
6351
+ dispatcher.removeEventListener(event, this._changeListener);
6352
+ }
6353
+ }
6354
+ this._eventDispatchers.clear();
6355
+ this._stats?.dom.remove();
6356
+ this._stats = void 0;
6357
+ this.renderer.domElement.remove();
6358
+ this._element = void 0;
6359
+ if (this._controls) {
6360
+ const controls = this._controls;
6361
+ this._controls = void 0;
6362
+ controls.enabled = false;
6363
+ controls.dispose();
6364
+ }
6365
+ this.scene.clear();
6366
+ for (const helper of this._debugHelpers) {
6367
+ helper.geometry.dispose();
6368
+ const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
6369
+ for (const material of materials) {
6370
+ material.dispose();
6371
+ }
6372
+ }
6373
+ this._debugHelpers.length = 0;
6374
+ this.composer?.dispose();
6375
+ this.renderer.dispose();
6376
+ this.renderer.forceContextLoss();
6377
+ }
6378
+ animate(t = performance.now()) {
6379
+ if (this._disposed) return;
6380
+ if (this._controls?.enabled) {
6381
+ this._controls.update();
6382
+ }
6383
+ if (this._disposed) return;
6384
+ if (!this.dirty && !this.options.render.renderAlways) return;
6385
+ const interval = this._frameInterval;
6386
+ if (interval) {
6387
+ const next = this._nextFrameTime;
6388
+ if (next !== void 0 && t + 0.1 < next) return;
6389
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6204
6390
  }
6205
- function onPointerCancel(event) {
6206
- removePointer(event);
6391
+ if (this._stats) {
6392
+ this._stats.begin();
6207
6393
  }
6208
- function onMouseDown(event) {
6209
- let mouseAction;
6210
- switch (event.button) {
6211
- case 0:
6212
- mouseAction = scope.mouseButtons.LEFT;
6213
- break;
6214
- case 1:
6215
- mouseAction = scope.mouseButtons.MIDDLE;
6216
- break;
6217
- case 2:
6218
- mouseAction = scope.mouseButtons.RIGHT;
6219
- break;
6220
- default:
6221
- mouseAction = -1;
6222
- }
6223
- switch (mouseAction) {
6224
- case MOUSE.DOLLY:
6225
- if (scope.enableZoom === false) return;
6226
- handleMouseDownDolly(event);
6227
- state = STATE.DOLLY;
6228
- break;
6229
- case MOUSE.ROTATE:
6230
- if (event.ctrlKey || event.metaKey || event.shiftKey) {
6231
- if (scope.enablePan === false) return;
6232
- handleMouseDownPan(event);
6233
- state = STATE.PAN;
6234
- } else {
6235
- if (scope.enableRotate === false) return;
6236
- handleMouseDownRotate(event);
6237
- state = STATE.ROTATE;
6238
- }
6239
- break;
6240
- case MOUSE.PAN:
6241
- if (event.ctrlKey || event.metaKey || event.shiftKey) {
6242
- if (scope.enableRotate === false) return;
6243
- handleMouseDownRotate(event);
6244
- state = STATE.ROTATE;
6245
- } else {
6246
- if (scope.enablePan === false) return;
6247
- handleMouseDownPan(event);
6248
- state = STATE.PAN;
6249
- }
6250
- break;
6251
- default:
6252
- state = STATE.NONE;
6394
+ if (this.options.composer.enabled && this.composer) {
6395
+ this.composer.render();
6396
+ } else {
6397
+ this.renderer.render(this.scene, this.camera);
6398
+ }
6399
+ this.dirty = false;
6400
+ if (this._stats) {
6401
+ this._stats.end();
6402
+ }
6403
+ }
6404
+ //</editor-fold>
6405
+ toImage() {
6406
+ return this.renderer.domElement.toDataURL();
6407
+ }
6408
+ ///
6409
+ get attachedToBody() {
6410
+ return this.element === document.body;
6411
+ }
6412
+ get viewWidth() {
6413
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6414
+ }
6415
+ get viewHeight() {
6416
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6417
+ }
6418
+ get scene() {
6419
+ return this._scene;
6420
+ }
6421
+ get camera() {
6422
+ return this._camera;
6423
+ }
6424
+ get renderer() {
6425
+ return this._renderer;
6426
+ }
6427
+ get composer() {
6428
+ return this._composer;
6429
+ }
6430
+ /** Renderer-owned controls, or undefined when disabled at construction or after disposal. */
6431
+ get controls() {
6432
+ return this._controls;
6433
+ }
6434
+ ///
6435
+ };
6436
+ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6437
+ camera: {
6438
+ type: "perspective",
6439
+ near: 1,
6440
+ far: 5e3,
6441
+ perspective: {
6442
+ aspect: void 0,
6443
+ fov: 50
6444
+ },
6445
+ orthographic: {
6446
+ left: void 0,
6447
+ right: void 0,
6448
+ top: void 0,
6449
+ bottom: void 0
6450
+ },
6451
+ position: new Vector38(50, 50, 50),
6452
+ lookingAt: new Vector38(0, 0, 0)
6453
+ },
6454
+ render: {
6455
+ fpsLimit: 60,
6456
+ stats: false,
6457
+ antialias: true,
6458
+ shade: true,
6459
+ autoResize: true,
6460
+ renderAlways: false
6461
+ },
6462
+ composer: {
6463
+ enabled: true
6464
+ },
6465
+ controls: {
6466
+ enabled: false
6467
+ },
6468
+ debug: {
6469
+ grid: false,
6470
+ axes: false
6471
+ }
6472
+ });
6473
+ var Renderer = _Renderer;
6474
+
6475
+ // src/skin/Skins.ts
6476
+ var Skins = class {
6477
+ //<editor-fold desc="Skins">
6478
+ static async fromUuidOrUsername(uuidOrUsername) {
6479
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6480
+ return this.fromUuid(uuidOrUsername);
6481
+ }
6482
+ return this.fromUsername(uuidOrUsername);
6483
+ }
6484
+ static async fromUuid(uuid) {
6485
+ return this.getSkinProxySkinUrl(uuid);
6486
+ }
6487
+ static async fromUsername(username) {
6488
+ return this.usernameToUuid(username).then((uuid) => {
6489
+ if (uuid) {
6490
+ return this.fromUuid(uuid);
6253
6491
  }
6254
- if (state !== STATE.NONE) {
6255
- scope.dispatchEvent(_startEvent);
6492
+ return void 0;
6493
+ });
6494
+ }
6495
+ static async fromMineSkin(mineskinId) {
6496
+ return this.getMineSkin(mineskinId).then((mineskin) => {
6497
+ if (mineskin) {
6498
+ return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6256
6499
  }
6500
+ return void 0;
6501
+ });
6502
+ }
6503
+ //</editor-fold>
6504
+ //<editor-fold desc="Capes">
6505
+ static async capeFromUuidOrUsername(uuidOrUsername) {
6506
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6507
+ return this.capeFromUuid(uuidOrUsername);
6257
6508
  }
6258
- function onMouseMove(event) {
6259
- if (scope.enabled === false) return;
6260
- switch (state) {
6261
- case STATE.ROTATE:
6262
- if (scope.enableRotate === false) return;
6263
- handleMouseMoveRotate(event);
6264
- break;
6265
- case STATE.DOLLY:
6266
- if (scope.enableZoom === false) return;
6267
- handleMouseMoveDolly(event);
6268
- break;
6269
- case STATE.PAN:
6270
- if (scope.enablePan === false) return;
6271
- handleMouseMovePan(event);
6272
- break;
6509
+ return this.capeFromUsername(uuidOrUsername);
6510
+ }
6511
+ static async capeFromUuid(uuid) {
6512
+ return this.getSkinProxyCapeUrl(uuid);
6513
+ }
6514
+ static async capeFromUsername(username) {
6515
+ return this.usernameToUuid(username).then((uuid) => {
6516
+ if (uuid) {
6517
+ return this.capeFromUuid(uuid);
6273
6518
  }
6274
- }
6275
- function onMouseUp(event) {
6276
- handleMouseUp(event);
6277
- scope.dispatchEvent(_endEvent);
6278
- state = STATE.NONE;
6279
- }
6280
- function onMouseWheel(event) {
6281
- if (scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE) return;
6282
- event.preventDefault();
6283
- scope.dispatchEvent(_startEvent);
6284
- handleMouseWheel(event);
6285
- scope.dispatchEvent(_endEvent);
6286
- }
6287
- function onKeyDown(event) {
6288
- if (scope.enabled === false || scope.enablePan === false) return;
6289
- handleKeyDown(event);
6290
- }
6291
- function onTouchStart(event) {
6292
- trackPointer(event);
6293
- switch (pointers.length) {
6294
- case 1:
6295
- switch (scope.touches.ONE) {
6296
- case TOUCH.ROTATE:
6297
- if (scope.enableRotate === false) return;
6298
- handleTouchStartRotate();
6299
- state = STATE.TOUCH_ROTATE;
6300
- break;
6301
- case TOUCH.PAN:
6302
- if (scope.enablePan === false) return;
6303
- handleTouchStartPan();
6304
- state = STATE.TOUCH_PAN;
6305
- break;
6306
- default:
6307
- state = STATE.NONE;
6308
- }
6309
- break;
6310
- case 2:
6311
- switch (scope.touches.TWO) {
6312
- case TOUCH.DOLLY_PAN:
6313
- if (scope.enableZoom === false && scope.enablePan === false) return;
6314
- handleTouchStartDollyPan();
6315
- state = STATE.TOUCH_DOLLY_PAN;
6316
- break;
6317
- case TOUCH.DOLLY_ROTATE:
6318
- if (scope.enableZoom === false && scope.enableRotate === false) return;
6319
- handleTouchStartDollyRotate();
6320
- state = STATE.TOUCH_DOLLY_ROTATE;
6321
- break;
6322
- default:
6323
- state = STATE.NONE;
6324
- }
6325
- break;
6326
- default:
6327
- state = STATE.NONE;
6519
+ return void 0;
6520
+ });
6521
+ }
6522
+ static async capeFromCapesDev(uuid, capeType = "minecraft") {
6523
+ return this.getCapesDev(uuid, capeType).then((cape) => {
6524
+ if (cape) {
6525
+ return cape?.stillImageUrl;
6328
6526
  }
6329
- if (state !== STATE.NONE) {
6330
- scope.dispatchEvent(_startEvent);
6527
+ return void 0;
6528
+ });
6529
+ }
6530
+ //</editor-fold>
6531
+ //<editor-fold desc="Helpers">
6532
+ static async usernameToUuid(username) {
6533
+ return this.usernameToUuidSkinProxy(username);
6534
+ }
6535
+ static async usernameToUuidSkinProxy(username) {
6536
+ return Requests.genericRequest({
6537
+ baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
6538
+ url: "/uuid/" + username
6539
+ }).then((res) => {
6540
+ if (res.status === 200) {
6541
+ return res.data["id"];
6331
6542
  }
6332
- }
6333
- function onTouchMove(event) {
6334
- trackPointer(event);
6335
- switch (state) {
6336
- case STATE.TOUCH_ROTATE:
6337
- if (scope.enableRotate === false) return;
6338
- handleTouchMoveRotate(event);
6339
- scope.update();
6340
- break;
6341
- case STATE.TOUCH_PAN:
6342
- if (scope.enablePan === false) return;
6343
- handleTouchMovePan(event);
6344
- scope.update();
6345
- break;
6346
- case STATE.TOUCH_DOLLY_PAN:
6347
- if (scope.enableZoom === false && scope.enablePan === false) return;
6348
- handleTouchMoveDollyPan(event);
6349
- scope.update();
6350
- break;
6351
- case STATE.TOUCH_DOLLY_ROTATE:
6352
- if (scope.enableZoom === false && scope.enableRotate === false) return;
6353
- handleTouchMoveDollyRotate(event);
6354
- scope.update();
6355
- break;
6356
- default:
6357
- state = STATE.NONE;
6543
+ return void 0;
6544
+ }).catch((err) => {
6545
+ console.warn(err);
6546
+ return void 0;
6547
+ });
6548
+ }
6549
+ static async usernameToUuidMineTools(username) {
6550
+ return Requests.genericRequest({
6551
+ baseURL: "https://api.minetools.eu",
6552
+ url: "/uuid/" + username
6553
+ }).then((res) => {
6554
+ if (res.status === 200) {
6555
+ return res.data["id"];
6358
6556
  }
6359
- }
6360
- function onTouchEnd(event) {
6361
- handleTouchEnd(event);
6362
- scope.dispatchEvent(_endEvent);
6363
- state = STATE.NONE;
6364
- }
6365
- function onContextMenu(event) {
6366
- if (scope.enabled === false) return;
6367
- event.preventDefault();
6368
- }
6369
- function addPointer(event) {
6370
- pointers.push(event);
6371
- }
6372
- function removePointer(event) {
6373
- delete pointerPositions[event.pointerId];
6374
- for (let i = 0; i < pointers.length; i++) {
6375
- if (pointers[i].pointerId == event.pointerId) {
6376
- pointers.splice(i, 1);
6377
- return;
6378
- }
6557
+ return void 0;
6558
+ }).catch((err) => {
6559
+ console.warn(err);
6560
+ return void 0;
6561
+ });
6562
+ }
6563
+ static async getProfileFromMinetools(uuid) {
6564
+ return Requests.genericRequest({
6565
+ baseURL: "https://api.minetools.eu",
6566
+ url: "/profile/" + uuid
6567
+ }).then((res) => {
6568
+ if (res.status === 200) {
6569
+ return res.data;
6379
6570
  }
6380
- }
6381
- function trackPointer(event) {
6382
- let position = pointerPositions[event.pointerId];
6383
- if (position === void 0) {
6384
- position = new Vector23();
6385
- pointerPositions[event.pointerId] = position;
6571
+ });
6572
+ }
6573
+ static async getMineSkin(mineskinId) {
6574
+ return Requests.genericRequest({
6575
+ baseURL: "https://api.mineskin.org",
6576
+ url: "/get/uuid/" + mineskinId
6577
+ }).then((res) => {
6578
+ if (res.status === 200) {
6579
+ return res.data;
6386
6580
  }
6387
- position.set(event.pageX, event.pageY);
6388
- }
6389
- function getSecondPointerPosition(event) {
6390
- const pointer = event.pointerId === pointers[0].pointerId ? pointers[1] : pointers[0];
6391
- return pointerPositions[pointer.pointerId];
6392
- }
6393
- scope.domElement.addEventListener("contextmenu", onContextMenu);
6394
- scope.domElement.addEventListener("pointerdown", onPointerDown);
6395
- scope.domElement.addEventListener("pointercancel", onPointerCancel);
6396
- scope.domElement.addEventListener("wheel", onMouseWheel, { passive: false });
6397
- this.update();
6581
+ return void 0;
6582
+ }).catch((err) => {
6583
+ console.warn(err);
6584
+ return void 0;
6585
+ });
6398
6586
  }
6399
- };
6400
- var MapControls = class extends OrbitControls {
6401
- constructor(object, domElement) {
6402
- super(object, domElement);
6403
- this.screenSpacePanning = false;
6404
- this.mouseButtons.LEFT = MOUSE.PAN;
6405
- this.mouseButtons.RIGHT = MOUSE.ROTATE;
6406
- this.touches.ONE = TOUCH.PAN;
6407
- this.touches.TWO = TOUCH.DOLLY_ROTATE;
6587
+ static async getCapesDev(uuid, type = "all") {
6588
+ return Requests.genericRequest({
6589
+ baseURL: "https://api.capes.dev",
6590
+ url: "/load/" + uuid + "/" + type
6591
+ }).then((res) => {
6592
+ if (res.status === 200) {
6593
+ return res.data;
6594
+ }
6595
+ return void 0;
6596
+ }).catch((err) => {
6597
+ console.warn(err);
6598
+ return void 0;
6599
+ });
6600
+ }
6601
+ static getCrafatarSkinUrl(uuid) {
6602
+ return "https://crafatar.com/skins/" + uuid;
6408
6603
  }
6604
+ static getCrafatarCapeUrl(uuid) {
6605
+ return "https://crafatar.com/capes/" + uuid;
6606
+ }
6607
+ static getMcHeadsSkinUrl(uuid) {
6608
+ return "https://mc-heads.net/skin/" + uuid;
6609
+ }
6610
+ static getMineSkinPlayerSkinUrl(uuid) {
6611
+ return "https://mineskin.org/skin/player/" + uuid;
6612
+ }
6613
+ static getSkinProxySkinUrl(uuid) {
6614
+ return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6615
+ }
6616
+ static getSkinProxyCapeUrl(uuid) {
6617
+ return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6618
+ }
6619
+ //</editor-fold>
6409
6620
  };
6410
6621
 
6411
6622
  // src/world/Chunk.ts
@@ -6522,7 +6733,7 @@ var MineRenderWorld = class {
6522
6733
  };
6523
6734
 
6524
6735
  // src/world/Chunk.ts
6525
- var p12 = prefix("Chunk");
6736
+ var p11 = prefix("Chunk");
6526
6737
  var Chunk = class _Chunk {
6527
6738
  constructor(scene, x, y, z) {
6528
6739
  this._blocks = [];
@@ -6574,7 +6785,7 @@ var Chunk = class _Chunk {
6574
6785
  const index = _Chunk.chunkPosToBlockIndex(pos);
6575
6786
  const current = this._blocks[index];
6576
6787
  if (typeof current !== "undefined") {
6577
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
6788
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6578
6789
  current.object.removeFromScene();
6579
6790
  delete this._blocks[index];
6580
6791
  }
@@ -6640,6 +6851,7 @@ export {
6640
6851
  AXES,
6641
6852
  ArchiveAssetSource,
6642
6853
  AssetKey,
6854
+ AssetLoadError,
6643
6855
  AssetLoader,
6644
6856
  AssetParser,
6645
6857
  AssetSource,
@@ -6697,6 +6909,7 @@ export {
6697
6909
  OrbitControls,
6698
6910
  PersistentCache,
6699
6911
  Renderer,
6912
+ RequestError,
6700
6913
  Requests,
6701
6914
  SKIN_PARTS,
6702
6915
  SceneInspector,