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
 
@@ -149,25 +141,29 @@ var Env = class {
149
141
  };
150
142
 
151
143
  // src/cache/PersistentCache.ts
152
- var _PersistentCache = class _PersistentCache {
144
+ var PersistentCache = class _PersistentCache {
153
145
  constructor(backing) {
154
146
  this.backing = backing;
155
147
  }
148
+ static {
149
+ /** Bump to invalidate every persisted entry. */
150
+ this.VERSION = 2;
151
+ }
156
152
  static open(name) {
157
153
  return Env.provider.openCache(name, _PersistentCache.VERSION);
158
154
  }
155
+ /** Loads a missing entry and stores only non-nullish results. */
159
156
  async getOrLoad(key, loader) {
160
157
  let v = await this.get(key);
161
158
  if (typeof v === "undefined" || v === null) {
162
159
  v = await loader(key);
163
- await this.put(key, v);
160
+ if (typeof v !== "undefined" && v !== null) {
161
+ await this.put(key, v);
162
+ }
164
163
  }
165
164
  return v;
166
165
  }
167
166
  };
168
- /** Bump to invalidate every persisted entry. */
169
- _PersistentCache.VERSION = 1;
170
- var PersistentCache = _PersistentCache;
171
167
 
172
168
  // src/env/node/NodeCache.ts
173
169
  var NodeCache = class extends PersistentCache {
@@ -341,8 +337,7 @@ function serializeImageKey(key) {
341
337
  return md5(key.src);
342
338
  }
343
339
  function serializeBoxGeometryKey(key) {
344
- var _a;
345
- return md5([key.width, key.height, key.depth, (_a = key.uv) == null ? void 0 : _a.join(":")].join("_"));
340
+ return md5([key.width, key.height, key.depth, key.uv?.join(":")].join("_"));
346
341
  }
347
342
  function serializeTextureKey(key) {
348
343
  return md5([key.src, key.format, key.rotation].join("$"));
@@ -357,7 +352,61 @@ function serializeMeshKey(key) {
357
352
  // src/cache/Caching.ts
358
353
  import { Caches } from "@inventivetalent/loading-cache";
359
354
  import { Time } from "@inventivetalent/time";
360
- var Caching = class {
355
+ var Caching = class _Caching {
356
+ static {
357
+ this.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
358
+ }
359
+ static {
360
+ this.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
361
+ }
362
+ static {
363
+ this.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
364
+ }
365
+ static {
366
+ this.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
367
+ }
368
+ static {
369
+ this.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
370
+ }
371
+ static {
372
+ this.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
373
+ }
374
+ static {
375
+ this.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
376
+ }
377
+ static {
378
+ this.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
379
+ }
380
+ static {
381
+ this.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
382
+ }
383
+ static {
384
+ this.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
385
+ }
386
+ static {
387
+ this.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
388
+ }
389
+ static {
390
+ this.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
391
+ }
392
+ static {
393
+ this.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
394
+ }
395
+ static {
396
+ this.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
397
+ }
398
+ static {
399
+ this.listAssetCache = _Caching.createAssetCache();
400
+ }
401
+ static {
402
+ this.defaultBlockStatesCache = _Caching.createAssetCache();
403
+ }
404
+ static {
405
+ this.entityModelsCache = _Caching.createAssetCache();
406
+ }
407
+ static createAssetCache() {
408
+ return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
409
+ }
361
410
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
362
411
  static get all() {
363
412
  return [
@@ -374,7 +423,10 @@ var Caching = class {
374
423
  this.rawModelCache,
375
424
  this.mergedModelCache,
376
425
  this.modelTextureAtlasCache,
377
- this.blockStateCache
426
+ this.blockStateCache,
427
+ this.listAssetCache,
428
+ this.defaultBlockStatesCache,
429
+ this.entityModelsCache
378
430
  ];
379
431
  }
380
432
  static clear() {
@@ -385,8 +437,8 @@ var Caching = class {
385
437
  /**
386
438
  * Clears every cache and stops its expiry timer.
387
439
  *
388
- * loading-cache reschedules that timer indefinitely, so a Node process will not exit until
389
- * this is called - see {@link shutdown}.
440
+ * Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
441
+ * Use {@link shutdown} to also stop requests and the shared Ticker.
390
442
  */
391
443
  static end() {
392
444
  for (const cache of this.all) {
@@ -400,20 +452,6 @@ var Caching = class {
400
452
  };
401
453
  }
402
454
  };
403
- Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
404
- Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
405
- Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
406
- Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
407
- Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
408
- Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
409
- Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
410
- Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
411
- Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
412
- Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
413
- Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
414
- Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
415
- Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
416
- Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
417
455
 
418
456
  // src/Geometries.ts
419
457
  var Geometries = class _Geometries {
@@ -441,6 +479,7 @@ import { CanvasTexture, Texture as Texture2 } from "three";
441
479
 
442
480
  // src/texture/TextureLoader.ts
443
481
  import { RGBAFormat, Texture } from "three";
482
+ import * as THREE from "three";
444
483
 
445
484
  // src/canvas/CanvasCompat.ts
446
485
  function createImage(width, height) {
@@ -451,9 +490,7 @@ function createCanvas2(width, height) {
451
490
  }
452
491
 
453
492
  // src/request/Requests.ts
454
- import axios from "axios";
455
- import { JobQueue } from "jobqu";
456
- import { Time as Time2 } from "@inventivetalent/time";
493
+ import { JobCancelledError, JobQueue } from "jobqu";
457
494
 
458
495
  // src/util/log.ts
459
496
  var Reset = "\x1B[0m";
@@ -463,198 +500,174 @@ function prefix(prefix2) {
463
500
  return `${FgGreen}MR${BgBlack}${prefix2 ?? ""}${Reset}`;
464
501
  }
465
502
 
466
- // src/util/BatchedExecutor.ts
467
- var BatchedExecutor = class {
468
- constructor(interval = 1, batch = 30) {
469
- this.interval = interval;
470
- this.batch = batch;
471
- this.queue = [];
472
- this.task = setInterval(() => this.run());
473
- }
474
- submit(task) {
475
- this.queue.push(task);
476
- }
477
- run() {
478
- for (let i = 0; i < this.batch; i++) {
479
- this.runNext();
480
- }
481
- }
482
- runNext() {
483
- let next = this.queue.shift();
484
- if (next) next();
503
+ // src/request/Requests.ts
504
+ var p = prefix("Requests");
505
+ var RequestError = class extends Error {
506
+ constructor(message, response, cause) {
507
+ super(message);
508
+ this.response = response;
509
+ this.cause = cause;
510
+ this.name = "RequestError";
485
511
  }
486
512
  };
487
-
488
- // src/util/model.ts
489
- import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
490
- function applyElementRotation(rotation, geometry) {
491
- const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
492
- geometry.translate(-origin.x, -origin.y, -origin.z);
493
- switch (rotation.axis) {
494
- case "X" /* X */:
495
- geometry.rotateX(toRadians(rotation.angle));
496
- break;
497
- case "y" /* Y */:
498
- geometry.rotateY(toRadians(rotation.angle));
499
- break;
500
- case "z" /* Z */:
501
- geometry.rotateZ(toRadians(rotation.angle));
502
- break;
503
- }
504
- if (rotation.rescale) {
505
- if (Math.abs(rotation.angle) === 22.5) {
506
- const s = 1 / Math.cos(0.39269909262657166);
507
- geometry.scale(s, 1, s);
508
- } else {
509
- const s = 1 / Math.cos(0.7853981852531433);
510
- geometry.scale(s, 1, s);
513
+ async function fetchRequest(config, defaultBaseURL) {
514
+ const { url, baseURL = defaultBaseURL, timeout = 5e3, responseType = "json", signal, ...options } = config;
515
+ const target = baseURL && !/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url) ? `${baseURL.replace(/\/+$/, "")}/${url.replace(/^\/+/, "")}` : url;
516
+ const headers = new Headers(options.headers);
517
+ if (typeof window === "undefined" && !headers.has("User-Agent")) {
518
+ headers.set("User-Agent", "MineRender");
519
+ }
520
+ const attemptSignal = AbortSignal.any([
521
+ ...signal ? [signal] : [],
522
+ ...timeout === 0 ? [] : [AbortSignal.timeout(timeout)]
523
+ ]);
524
+ const request = new Request(target, { ...options, headers, signal: attemptSignal });
525
+ attemptSignal.throwIfAborted();
526
+ try {
527
+ const response = await fetch(request);
528
+ const result = {
529
+ data: void 0,
530
+ status: response.status,
531
+ statusText: response.statusText,
532
+ headers: response.headers,
533
+ url: response.url
534
+ };
535
+ if (!response.ok) {
536
+ await response.body?.cancel().catch(() => {
537
+ });
538
+ throw new RequestError(`Request failed with status ${response.status}`, result);
511
539
  }
540
+ const emptyBody = request.method === "HEAD" || response.status === 204 || response.status === 205;
541
+ const data = responseType === "arraybuffer" ? await response.arrayBuffer() : emptyBody || response.body === null ? void 0 : await response.json();
542
+ return { ...result, data };
543
+ } catch (error) {
544
+ attemptSignal.throwIfAborted();
545
+ if (/^https?:/.test(request.url) && request.redirect !== "error" && error instanceof TypeError) {
546
+ throw new RequestError("Network request failed", void 0, error);
547
+ }
548
+ throw error;
512
549
  }
513
- geometry.translate(origin.x, origin.y, origin.z);
514
- }
515
- function applyModelPartRotation(modelPart, geometry) {
516
- const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
517
- geometry.translate(-origin.x, -origin.y, -origin.z);
518
- geometry.rotateX(toRadians(modelPart.pitch));
519
- geometry.rotateY(toRadians(modelPart.yaw));
520
- geometry.rotateZ(toRadians(modelPart.roll));
521
- geometry.translate(origin.x, origin.y, origin.z);
522
550
  }
523
- function applyGenericRotation(axis, rotation, obj) {
524
- switch (axis) {
525
- case "X" /* X */:
526
- obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
527
- break;
528
- case "y" /* Y */:
529
- obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
530
- break;
531
- case "z" /* Z */:
532
- obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
533
- break;
551
+ async function abortable(promise, signal) {
552
+ if (!signal) return promise;
553
+ let abort;
554
+ const cancelled = new Promise((_, reject) => {
555
+ abort = () => reject(signal.reason);
556
+ signal.addEventListener("abort", abort, { once: true });
557
+ if (signal.aborted) abort();
558
+ });
559
+ try {
560
+ return await Promise.race([promise, cancelled]);
561
+ } finally {
562
+ signal.removeEventListener("abort", abort);
534
563
  }
535
564
  }
536
- function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
537
- let size = new Vector32();
538
- box.getSize(size);
539
- let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
540
- let wireGeo = new EdgesGeometry(boxGeo);
541
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
542
- let wireframe = new LineSegments(wireGeo, wireMat);
543
- obj.add(wireframe);
544
- let axes = new AxesHelper(1);
545
- obj.add(axes);
546
- }
547
- function addWireframeToObject(obj, color = 16777215, w = 2) {
548
- let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
549
- let wireGeo = new EdgesGeometry(boxGeo);
550
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
551
- let wireframe = new LineSegments(wireGeo, wireMat);
552
- obj.add(wireframe);
553
- let axes = new AxesHelper(1);
554
- obj.add(axes);
555
- }
556
- function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
557
- let wireGeo = new EdgesGeometry(geo);
558
- let wireMat = new LineBasicMaterial({ color, linewidth: w });
559
- let wireframe = new LineSegments(wireGeo, wireMat);
560
- mesh.add(wireframe);
561
- let axes = new AxesHelper(1);
562
- mesh.add(axes);
563
- }
564
-
565
- // src/util/performance.ts
566
- function captureException(e, ...extra) {
567
- console.error(e, extra);
568
- }
569
- function timingStart(marker) {
570
- console.time(marker);
571
- }
572
- function timingEnd(marker) {
573
- console.timeEnd(marker);
574
- }
575
-
576
- // src/util/three.ts
577
- function isObject3D(obj) {
578
- return obj.isObject3D;
579
- }
580
- function isMesh(obj) {
581
- return obj.isMesh;
582
- }
583
- function isInstancedMesh(obj) {
584
- return obj.isInstancedMesh;
585
- }
586
- function isPerspectiveCamera(obj) {
587
- return obj.isPerspectiveCamera;
588
- }
589
- function isOrthographicCamera(obj) {
590
- return obj.isOrthographicCamera;
591
- }
592
-
593
- // src/request/Requests.ts
594
- var p = prefix("Requests");
595
- if (typeof window === "undefined") {
596
- axios.defaults.headers["User-Agent"] = "MineRender";
597
- }
598
- var _Requests = class _Requests {
599
- static genericRequest(request) {
600
- return this.genericQueue.add(request).catch(async (e) => {
601
- console.debug(p, "generic catch", e.code, e);
602
- if (this.shouldRetry(e, request)) {
603
- await sleep(100);
604
- return this.genericRequest(request);
605
- }
606
- throw e;
607
- });
608
- }
609
- static mcAssetRequest(request) {
610
- return this.mcAssetRequestQueue.add(request).catch((e) => {
611
- console.debug(p, "mcAssetRequest catch", e.code, e);
612
- throw e;
613
- });
565
+ var RequestQueue = class {
566
+ constructor() {
567
+ this.pendingRequests = 0;
568
+ this.stopped = new AbortController();
569
+ this.queue = new JobQueue(
570
+ (request) => fetchRequest(request, this.baseURL),
571
+ { interval: 10, maxPerRun: 1, maxActive: 8 }
572
+ );
614
573
  }
615
- static shouldRetry(e, request) {
616
- if ("code" in e) {
617
- if ("ECONNABORTED" === e.code) {
618
- if ("minerenderRetry" in request) {
619
- if (request["minerenderRetry"] > 0) {
620
- request["minerenderRetry"]--;
621
- return true;
574
+ async request(request) {
575
+ this.pendingRequests++;
576
+ const signal = request.signal;
577
+ try {
578
+ for (let retries = 0; ; retries++) {
579
+ signal?.throwIfAborted();
580
+ try {
581
+ return await abortable(this.queue.add(request), signal);
582
+ } catch (error) {
583
+ console.debug(p, "Request failed", error);
584
+ const delay = this.retryDelay(error, request, retries);
585
+ if (delay === void 0) {
586
+ throw error;
622
587
  }
623
- } else {
624
- request["minerenderRetry"] = 3;
625
- return true;
588
+ await this.waitForRetry(delay, signal);
626
589
  }
627
590
  }
591
+ } finally {
592
+ if (signal?.aborted) {
593
+ this.queue.remove(request);
594
+ }
595
+ this.pendingRequests--;
628
596
  }
629
- return false;
597
+ }
598
+ retryDelay(error, request, retries) {
599
+ if (this.stopped.signal.aborted || retries >= 3 || (request.method ?? "get").toLowerCase() !== "get" || request.signal?.aborted) {
600
+ return void 0;
601
+ }
602
+ if (error instanceof RequestError) {
603
+ const status = error.response?.status;
604
+ if (status !== void 0 && status !== 408 && status !== 429 && !(status >= 500 && status < 600)) return void 0;
605
+ } else if (!(error instanceof DOMException && error.name === "TimeoutError")) {
606
+ return void 0;
607
+ }
608
+ let delay = 100 * 2 ** retries;
609
+ const retryAfter = error instanceof RequestError ? error.response?.headers.get("Retry-After") : void 0;
610
+ if (retryAfter !== void 0 && retryAfter !== null) {
611
+ const seconds = Number(retryAfter);
612
+ if (!retryAfter.trim() || !Number.isFinite(seconds) || seconds < 0) {
613
+ return void 0;
614
+ }
615
+ delay = Math.max(delay, seconds * 1e3);
616
+ }
617
+ return delay;
618
+ }
619
+ async waitForRetry(delay, signal) {
620
+ let timer;
621
+ const waiting = new Promise((resolve) => {
622
+ timer = setTimeout(resolve, delay);
623
+ });
624
+ try {
625
+ await abortable(waiting, AbortSignal.any([this.stopped.signal, ...signal ? [signal] : []]));
626
+ } finally {
627
+ clearTimeout(timer);
628
+ }
629
+ }
630
+ get pendingSize() {
631
+ return this.pendingRequests;
632
+ }
633
+ end() {
634
+ this.queue.end();
635
+ this.stopped.abort(new JobCancelledError("ended"));
636
+ }
637
+ };
638
+ var Requests = class {
639
+ static {
640
+ this.genericQueue = new RequestQueue();
641
+ }
642
+ static {
643
+ this.mcAssetRequestQueue = new RequestQueue();
644
+ }
645
+ static genericRequest(request) {
646
+ return this.genericQueue.request(request);
647
+ }
648
+ static mcAssetRequest(request) {
649
+ return this.mcAssetRequestQueue.request(request);
630
650
  }
631
651
  static setMcAssetRoot(root) {
632
- this.mcAssetInstance.defaults.baseURL = root;
652
+ this.mcAssetRequestQueue.baseURL = root;
633
653
  }
654
+ /** Counts unsettled calls, including retry delays and requests still running after shutdown. */
634
655
  static get queueSizes() {
635
656
  return {
636
- generic: this.genericQueue.size,
637
- mcAsset: this.mcAssetRequestQueue.size
657
+ generic: this.genericQueue.pendingSize,
658
+ mcAsset: this.mcAssetRequestQueue.pendingSize
638
659
  };
639
660
  }
640
661
  /**
641
- * Stops both queue timers. jobqu reschedules itself indefinitely, so a Node process will not
642
- * exit until this is called - see {@link shutdown}.
662
+ * Permanently stops both queues and rejects waiting, retrying, and future requests.
663
+ * Requests already running can finish. Idle queues hold no timer, so Node can exit without
664
+ * this cleanup. See {@link shutdown}.
643
665
  */
644
666
  static end() {
645
667
  this.genericQueue.end();
646
668
  this.mcAssetRequestQueue.end();
647
669
  }
648
670
  };
649
- _Requests.axiosInstance = axios.create({
650
- timeout: 5e3
651
- });
652
- _Requests.mcAssetInstance = axios.create({
653
- timeout: 5e3
654
- });
655
- _Requests.genericQueue = new JobQueue((request) => _Requests.axiosInstance.request(request), Time2.millis(10), 1);
656
- _Requests.mcAssetRequestQueue = new JobQueue((request) => _Requests.mcAssetInstance.request(request), Time2.millis(10), 1);
657
- var Requests = _Requests;
658
671
 
659
672
  // src/WrappedImage.ts
660
673
  var WrappedImage = class {
@@ -719,29 +732,41 @@ var ImageLoader = class _ImageLoader {
719
732
  static async loadAsync(src) {
720
733
  return new Promise((resolve, reject) => {
721
734
  const image = this._createImage();
722
- image.src = src;
723
735
  image.onload = () => resolve(image);
724
- image.onerror = (err) => reject(err);
736
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
737
+ image.src = src;
725
738
  });
726
739
  }
727
740
  static loadElement(src, onload, onerr) {
728
741
  const image = this._createImage();
729
- image.src = src;
730
742
  if (onload)
731
743
  image.onload = onload;
732
744
  if (onerr)
733
745
  image.onerror = onerr;
746
+ image.src = src;
734
747
  return image;
735
748
  }
736
749
  static async loadData(src) {
737
750
  console.debug(p2, "loadData", src);
738
- 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);
739
753
  }
740
754
  static async loadCanvasData(src) {
741
- 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
+ }
742
766
  }
743
767
  static async infoToCanvasData(info) {
744
- 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")}`);
745
770
  const canvas = createCanvas2(info.width, info.height);
746
771
  const context = canvas.getContext("2d");
747
772
  context.drawImage(image, 0, 0);
@@ -752,11 +777,8 @@ var ImageLoader = class _ImageLoader {
752
777
  };
753
778
  }
754
779
  static async infoToData(info) {
755
- const image = await _ImageLoader.loadAsync(info.src);
756
- const canvas = createCanvas2(info.width, info.height);
757
- const context = canvas.getContext("2d");
758
- context.drawImage(image, 0, 0);
759
- 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);
760
782
  }
761
783
  static async getData(src) {
762
784
  const keyStr = serializeImageKey({ src });
@@ -771,38 +793,25 @@ var ImageLoader = class _ImageLoader {
771
793
  });
772
794
  }
773
795
  static async processResponse(response) {
774
- const src = response.config.url;
796
+ const src = response.url;
775
797
  const data = Buffer2.from(response.data);
776
798
  const { width, height, type } = Env.provider.imageSize(data);
799
+ if (!width || !height) {
800
+ throw new Error("Invalid or unsupported image dimensions");
801
+ }
777
802
  return {
778
803
  src,
779
- width: width || 0,
780
- height: height || 0,
804
+ width,
805
+ height,
781
806
  type,
782
807
  data
783
808
  };
784
809
  }
785
810
  static async loadInfo(src) {
786
- if (src.startsWith("data:image/png;base64")) {
787
- return this.processResponse({
788
- config: {
789
- url: src
790
- },
791
- data: Buffer2.from(src.substr("data:image/png;base64,".length), "base64")
792
- });
793
- }
794
811
  return Requests.genericRequest({
795
812
  url: src,
796
813
  responseType: "arraybuffer"
797
- }).then(this.processResponse).catch((err) => {
798
- return {
799
- src,
800
- width: 0,
801
- height: 0,
802
- type: void 0,
803
- data: Buffer2.from([0])
804
- };
805
- });
814
+ }).then(this.processResponse);
806
815
  }
807
816
  static async getInfo(src) {
808
817
  const keyStr = serializeImageKey({ src });
@@ -824,15 +833,25 @@ var ImageLoader = class _ImageLoader {
824
833
 
825
834
  // src/texture/TextureLoader.ts
826
835
  var TextureLoader = class {
836
+ static {
837
+ this.failedTextures = /* @__PURE__ */ new WeakSet();
838
+ }
839
+ /** Reports whether image loading failed, so cached textures can be retried. */
840
+ static hasFailed(texture) {
841
+ return this.failedTextures.has(texture);
842
+ }
827
843
  static createTexture() {
828
844
  return new Texture();
829
845
  }
830
846
  static loadInBackground(src, format = RGBAFormat, rotation = 0) {
831
847
  const texture = this.createTexture();
832
- const image = ImageLoader.loadElement(src);
833
- image.onload = function() {
848
+ texture.colorSpace = THREE.SRGBColorSpace;
849
+ const image = ImageLoader.loadElement(src, () => {
834
850
  texture.needsUpdate = true;
835
- };
851
+ }, (error) => {
852
+ this.failedTextures.add(texture);
853
+ console.warn("Failed to load texture", src, error);
854
+ });
836
855
  texture.image = image;
837
856
  texture.format = format;
838
857
  texture.rotation = rotation;
@@ -840,9 +859,13 @@ var TextureLoader = class {
840
859
  }
841
860
  static load(src, format = RGBAFormat, rotation = 0) {
842
861
  const texture = new Texture();
862
+ texture.colorSpace = THREE.SRGBColorSpace;
843
863
  ImageLoader.getData(src).then((image) => {
844
- texture.needsUpdate = true;
845
864
  texture.image = image;
865
+ texture.needsUpdate = true;
866
+ }).catch((error) => {
867
+ this.failedTextures.add(texture);
868
+ console.warn("Failed to load texture", src, error);
846
869
  });
847
870
  texture.format = format;
848
871
  texture.rotation = rotation;
@@ -851,11 +874,11 @@ var TextureLoader = class {
851
874
  };
852
875
 
853
876
  // src/texture/Textures.ts
854
- import * as THREE from "three";
877
+ import * as THREE2 from "three";
855
878
  var Textures = class _Textures {
856
879
  static initTextureProps(texture) {
857
- texture.magFilter = THREE.NearestFilter;
858
- texture.minFilter = THREE.NearestFilter;
880
+ texture.magFilter = THREE2.NearestFilter;
881
+ texture.minFilter = THREE2.NearestFilter;
859
882
  texture.anisotropy = 0;
860
883
  return texture;
861
884
  }
@@ -866,10 +889,16 @@ var Textures = class _Textures {
866
889
  return new Texture2();
867
890
  }
868
891
  static createCanvasTexture(canvas) {
869
- return this.initTextureProps(new CanvasTexture(canvas));
892
+ const texture = new CanvasTexture(canvas);
893
+ texture.colorSpace = THREE2.SRGBColorSpace;
894
+ return this.initTextureProps(texture);
870
895
  }
871
896
  static getImage(key) {
872
897
  const keyStr = serializeTextureKey(key);
898
+ const cached = Caching.textureCache.peek(keyStr);
899
+ if (cached && TextureLoader.hasFailed(cached)) {
900
+ Caching.textureCache.invalidate(keyStr);
901
+ }
873
902
  return Caching.textureCache.get(keyStr, (k) => {
874
903
  return _Textures.createImage(key);
875
904
  });
@@ -877,7 +906,10 @@ var Textures = class _Textures {
877
906
  };
878
907
 
879
908
  // src/Materials.ts
880
- var _Materials = class _Materials {
909
+ var Materials = class _Materials {
910
+ static {
911
+ this.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
912
+ }
881
913
  // resolved lazily: as a static field this decoded an image the moment the library was
882
914
  // imported, which needs both a DOM and an EnvProvider to already be in place
883
915
  static get MISSING_TEXTURE() {
@@ -983,6 +1015,9 @@ var _Materials = class _Materials {
983
1015
  gl_FragColor = vec4(lift + color.rgb * light2, 1.0);
984
1016
 
985
1017
  }
1018
+
1019
+ #include <tonemapping_fragment>
1020
+ #include <colorspace_fragment>
986
1021
  }
987
1022
  `;
988
1023
  try {
@@ -1011,6 +1046,10 @@ var _Materials = class _Materials {
1011
1046
  }
1012
1047
  static getImage(key) {
1013
1048
  const keyStr = serializeMaterialKey(key);
1049
+ const map = Caching.materialCache.peek(keyStr)?.map;
1050
+ if (map && TextureLoader.hasFailed(map)) {
1051
+ Caching.materialCache.invalidate(keyStr);
1052
+ }
1014
1053
  return Caching.materialCache.get(keyStr, (k) => {
1015
1054
  return _Materials.createImage(key);
1016
1055
  });
@@ -1031,14 +1070,12 @@ var _Materials = class _Materials {
1031
1070
  }
1032
1071
  }
1033
1072
  };
1034
- _Materials.MISSING_TEXTURE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC";
1035
- var Materials = _Materials;
1036
1073
 
1037
1074
  // src/Meshes.ts
1038
- import { Mesh as Mesh2 } from "three";
1075
+ import { Mesh } from "three";
1039
1076
  var Meshes = class _Meshes {
1040
1077
  static createBox(key) {
1041
- return new Mesh2(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1078
+ return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
1042
1079
  }
1043
1080
  static getBox(key) {
1044
1081
  const keyStr = serializeMeshKey(key);
@@ -1087,7 +1124,7 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1087
1124
  this.root = root;
1088
1125
  }
1089
1126
  static parse(assetType, str, origin) {
1090
- let namespace = (origin == null ? void 0 : origin.namespace) || DEFAULT_NAMESPACE;
1127
+ let namespace = origin?.namespace || DEFAULT_NAMESPACE;
1091
1128
  if (str.includes(":")) {
1092
1129
  let split2 = str.split(":");
1093
1130
  namespace = split2[0];
@@ -1100,8 +1137,8 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1100
1137
  split.shift();
1101
1138
  }
1102
1139
  let path = split.join("/");
1103
- let extension = assetType === "textures" ? ".png" : (origin == null ? void 0 : origin.assetType) || ".json";
1104
- return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin == null ? void 0 : origin.root);
1140
+ let extension = assetType === "textures" ? ".png" : origin?.assetType || ".json";
1141
+ return new _AssetKey(namespace, path, assetType, type, "assets", extension, origin?.root);
1105
1142
  }
1106
1143
  toString() {
1107
1144
  let a = [
@@ -1115,12 +1152,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1115
1152
  return a.join("/");
1116
1153
  }
1117
1154
  getFullPath() {
1118
- let p13 = [];
1155
+ let p12 = [];
1119
1156
  if (this.type) {
1120
- p13.push(this.type);
1157
+ p12.push(this.type);
1121
1158
  }
1122
- p13.push(this.path);
1123
- return p13.join("/");
1159
+ p12.push(this.path);
1160
+ return p12.join("/");
1124
1161
  }
1125
1162
  toNamespacedString() {
1126
1163
  return this.namespace + ":" + this.getFullPath();
@@ -1145,7 +1182,7 @@ var ModelMerger = class {
1145
1182
  merged = (0, import_ts_deepmerge.default)(merged, parentModel);
1146
1183
  }
1147
1184
  merged = (0, import_ts_deepmerge.default)(merged, model);
1148
- merged.hierarchy = models.map((m) => m.parent).filter((p13) => `${p13}`);
1185
+ merged.hierarchy = models.map((m) => m.parent).filter((p12) => `${p12}`);
1149
1186
  merged.hierarchy.push(`${merged.parent}`);
1150
1187
  return merged;
1151
1188
  }
@@ -1164,9 +1201,6 @@ var ModelMerger = class {
1164
1201
  }
1165
1202
  };
1166
1203
 
1167
- // src/assets/Models.ts
1168
- import { Memoize } from "typescript-memoize";
1169
-
1170
1204
  // src/assets/source/parser/AssetParsers.ts
1171
1205
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1172
1206
  AssetParser2["MODEL"] = "model";
@@ -1180,14 +1214,14 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1180
1214
  })(AssetParser || {});
1181
1215
 
1182
1216
  // src/assets/Models.ts
1183
- var _Models = class _Models {
1217
+ var Models = class _Models {
1184
1218
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1185
1219
  // the library, and would require an EnvProvider before any entry has had a chance to register
1186
1220
  static get PERSISTENT_CACHE() {
1187
1221
  return this._persistentCache ??= PersistentCache.open("minerender-models");
1188
1222
  }
1189
1223
  static async getItemList() {
1190
- return AssetLoader.get(new AssetKey(
1224
+ const key = new AssetKey(
1191
1225
  DEFAULT_NAMESPACE,
1192
1226
  "_list",
1193
1227
  "models",
@@ -1195,7 +1229,10 @@ var _Models = class _Models {
1195
1229
  "assets",
1196
1230
  ".json",
1197
1231
  DEFAULT_ROOT
1198
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1232
+ );
1233
+ return Caching.listAssetCache.get(key.serialize(), () => {
1234
+ return AssetLoader.get(key, "list" /* LIST */);
1235
+ }).then((r) => r?.files ?? []);
1199
1236
  }
1200
1237
  static async loadAndMerge(key) {
1201
1238
  const model = await this.getRaw(key);
@@ -1242,19 +1279,15 @@ var _Models = class _Models {
1242
1279
  return this.PERSISTENT_CACHE.clear();
1243
1280
  }
1244
1281
  };
1245
- __decorateClass([
1246
- Memoize()
1247
- ], _Models, "getItemList", 1);
1248
- var Models = _Models;
1249
1282
 
1250
1283
  // src/assets/BlockStates.ts
1251
- import { Memoize as Memoize2 } from "typescript-memoize";
1252
1284
  var BlockStates = class {
1253
1285
  static get PERSISTENT_CACHE() {
1254
1286
  return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
1255
1287
  }
1288
+ // BlockState names are hardcoded
1256
1289
  static async getList() {
1257
- return AssetLoader.get(new AssetKey(
1290
+ const key = new AssetKey(
1258
1291
  DEFAULT_NAMESPACE,
1259
1292
  "_list",
1260
1293
  "blockstates",
@@ -1262,11 +1295,16 @@ var BlockStates = class {
1262
1295
  "assets",
1263
1296
  ".json",
1264
1297
  DEFAULT_ROOT
1265
- ), "list" /* LIST */).then((r) => (r == null ? void 0 : r.files) ?? []);
1298
+ );
1299
+ return Caching.listAssetCache.get(key.serialize(), () => {
1300
+ return AssetLoader.get(key, "list" /* LIST */);
1301
+ }).then((r) => r?.files ?? []);
1266
1302
  }
1267
1303
  static async getDefaultStates() {
1268
1304
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1269
- return AssetLoader.get(key, "json" /* JSON */);
1305
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1306
+ return AssetLoader.get(key, "json" /* JSON */);
1307
+ });
1270
1308
  }
1271
1309
  static async getDefaultState(key) {
1272
1310
  const defaultStates = await this.getDefaultStates();
@@ -1305,12 +1343,6 @@ var BlockStates = class {
1305
1343
  await this.PERSISTENT_CACHE.clear();
1306
1344
  }
1307
1345
  };
1308
- __decorateClass([
1309
- Memoize2()
1310
- ], BlockStates, "getList", 1);
1311
- __decorateClass([
1312
- Memoize2()
1313
- ], BlockStates, "getDefaultStates", 1);
1314
1346
  var DefaultBlockStates = class {
1315
1347
  };
1316
1348
 
@@ -1337,23 +1369,236 @@ var AssetSource = class {
1337
1369
  constructor() {
1338
1370
  }
1339
1371
  };
1372
+ var AssetLoadError = class extends Error {
1373
+ constructor(source, key, path, cause) {
1374
+ super(`Failed to load ${key.toNamespacedString()} from ${path}${cause instanceof Error ? `: ${cause.message}` : ""}`);
1375
+ this.source = source;
1376
+ this.key = key;
1377
+ this.path = path;
1378
+ this.cause = cause;
1379
+ this.name = "AssetLoadError";
1380
+ }
1381
+ };
1340
1382
 
1341
- // src/nbt/NBTHelper.ts
1342
- var NBTHelper = class {
1343
- static async fromBuffer(buffer) {
1344
- const prismarineNbt = await import("prismarine-nbt");
1345
- const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1346
- return parsed;
1383
+ // src/util/BatchedExecutor.ts
1384
+ var BatchedExecutor = class {
1385
+ constructor(interval = 1, batch = 30) {
1386
+ this.interval = interval;
1387
+ this.batch = batch;
1388
+ this.queue = [];
1389
+ this.task = setInterval(() => this.run());
1390
+ }
1391
+ submit(task) {
1392
+ this.queue.push(task);
1393
+ }
1394
+ run() {
1395
+ for (let i = 0; i < this.batch; i++) {
1396
+ this.runNext();
1397
+ }
1398
+ }
1399
+ runNext() {
1400
+ let next = this.queue.shift();
1401
+ if (next) next();
1347
1402
  }
1348
1403
  };
1349
1404
 
1350
- // src/assets/source/HostedAssetSource.ts
1351
- var import_ts_deepmerge2 = __toESM(require_dist());
1352
- var p3 = prefix("HostedAssetSource");
1405
+ // src/util/model.ts
1406
+ import { AxesHelper, BoxGeometry as BoxGeometry2, EdgesGeometry, LineBasicMaterial, LineSegments, Vector3 as Vector32 } from "three";
1407
+ function applyElementRotation(rotation, geometry) {
1408
+ const origin = new Vector32(rotation.origin[0], rotation.origin[1], rotation.origin[2]);
1409
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1410
+ switch (rotation.axis) {
1411
+ case "X" /* X */:
1412
+ geometry.rotateX(toRadians(rotation.angle));
1413
+ break;
1414
+ case "y" /* Y */:
1415
+ geometry.rotateY(toRadians(rotation.angle));
1416
+ break;
1417
+ case "z" /* Z */:
1418
+ geometry.rotateZ(toRadians(rotation.angle));
1419
+ break;
1420
+ }
1421
+ if (rotation.rescale) {
1422
+ if (Math.abs(rotation.angle) === 22.5) {
1423
+ const s = 1 / Math.cos(0.39269909262657166);
1424
+ geometry.scale(s, 1, s);
1425
+ } else {
1426
+ const s = 1 / Math.cos(0.7853981852531433);
1427
+ geometry.scale(s, 1, s);
1428
+ }
1429
+ }
1430
+ geometry.translate(origin.x, origin.y, origin.z);
1431
+ }
1432
+ function applyModelPartRotation(modelPart, geometry) {
1433
+ const origin = new Vector32(modelPart.pivotX, modelPart.pivotY, modelPart.pivotZ);
1434
+ geometry.translate(-origin.x, -origin.y, -origin.z);
1435
+ geometry.rotateX(toRadians(modelPart.pitch));
1436
+ geometry.rotateY(toRadians(modelPart.yaw));
1437
+ geometry.rotateZ(toRadians(modelPart.roll));
1438
+ geometry.translate(origin.x, origin.y, origin.z);
1439
+ }
1440
+ function applyGenericRotation(axis, rotation, obj) {
1441
+ switch (axis) {
1442
+ case "X" /* X */:
1443
+ obj.rotateOnAxis(new Vector32(1, 0, 0), toRadians(rotation));
1444
+ break;
1445
+ case "y" /* Y */:
1446
+ obj.rotateOnAxis(new Vector32(0, 1, 0), toRadians(rotation));
1447
+ break;
1448
+ case "z" /* Z */:
1449
+ obj.rotateOnAxis(new Vector32(0, 0, 1), toRadians(rotation));
1450
+ break;
1451
+ }
1452
+ }
1453
+ function addBox3WireframeToObject(box, obj, color = 16777215, w = 2) {
1454
+ let size = new Vector32();
1455
+ box.getSize(size);
1456
+ let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
1457
+ let wireGeo = new EdgesGeometry(boxGeo);
1458
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1459
+ let wireframe = new LineSegments(wireGeo, wireMat);
1460
+ obj.add(wireframe);
1461
+ let axes = new AxesHelper(1);
1462
+ obj.add(axes);
1463
+ }
1464
+ function addWireframeToObject(obj, color = 16777215, w = 2) {
1465
+ let boxGeo = new BoxGeometry2(16, 16, 16, 1, 1, 1);
1466
+ let wireGeo = new EdgesGeometry(boxGeo);
1467
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1468
+ let wireframe = new LineSegments(wireGeo, wireMat);
1469
+ obj.add(wireframe);
1470
+ let axes = new AxesHelper(1);
1471
+ obj.add(axes);
1472
+ }
1473
+ function addWireframeToMesh(geo, mesh, color = 16777215, w = 2) {
1474
+ let wireGeo = new EdgesGeometry(geo);
1475
+ let wireMat = new LineBasicMaterial({ color, linewidth: w });
1476
+ let wireframe = new LineSegments(wireGeo, wireMat);
1477
+ mesh.add(wireframe);
1478
+ let axes = new AxesHelper(1);
1479
+ mesh.add(axes);
1480
+ }
1481
+
1482
+ // src/util/performance.ts
1483
+ function captureException(e, ...extra) {
1484
+ console.error(e, extra);
1485
+ }
1486
+ function timingStart(marker) {
1487
+ console.time(marker);
1488
+ }
1489
+ function timingEnd(marker) {
1490
+ console.timeEnd(marker);
1491
+ }
1492
+
1493
+ // src/util/three.ts
1494
+ function isObject3D(obj) {
1495
+ return obj.isObject3D;
1496
+ }
1497
+ function isMesh(obj) {
1498
+ return obj.isMesh;
1499
+ }
1500
+ function isInstancedMesh(obj) {
1501
+ return obj.isInstancedMesh;
1502
+ }
1503
+ function isPerspectiveCamera(obj) {
1504
+ return obj.isPerspectiveCamera;
1505
+ }
1506
+ function isOrthographicCamera(obj) {
1507
+ return obj.isOrthographicCamera;
1508
+ }
1509
+
1510
+ // src/nbt/NBTHelper.ts
1511
+ var NBTHelper = class {
1512
+ static async fromBuffer(buffer) {
1513
+ const prismarineNbt = await import("prismarine-nbt");
1514
+ const { parsed, type, metadata } = await prismarineNbt.parse(buffer);
1515
+ return parsed;
1516
+ }
1517
+ };
1518
+
1519
+ // src/assets/source/HostedAssetSource.ts
1520
+ var import_ts_deepmerge2 = __toESM(require_dist());
1521
+ var p3 = prefix("HostedAssetSource");
1353
1522
  var DEFAULT_OPTIONS = {
1354
1523
  retryDefaults: true
1355
1524
  };
1356
- var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1525
+ var HostedAssetSource = class _HostedAssetSource extends AssetSource {
1526
+ static {
1527
+ this.MODEL = {
1528
+ config(request) {
1529
+ },
1530
+ parse(response) {
1531
+ return response.data;
1532
+ }
1533
+ };
1534
+ }
1535
+ static {
1536
+ this.BLOCKSTATE = {
1537
+ config(request) {
1538
+ },
1539
+ parse(response) {
1540
+ return response.data;
1541
+ }
1542
+ };
1543
+ }
1544
+ static {
1545
+ this.META = {
1546
+ config(request) {
1547
+ },
1548
+ parse(response) {
1549
+ return response.data;
1550
+ }
1551
+ };
1552
+ }
1553
+ static {
1554
+ this.NBT = {
1555
+ config(request) {
1556
+ request.responseType = "arraybuffer";
1557
+ },
1558
+ parse(response) {
1559
+ return NBTHelper.fromBuffer(Buffer.from(response.data));
1560
+ }
1561
+ };
1562
+ }
1563
+ static {
1564
+ this.IMAGE = {
1565
+ config(request) {
1566
+ request.responseType = "arraybuffer";
1567
+ },
1568
+ async parse(response) {
1569
+ return await ImageLoader.processResponse(response);
1570
+ }
1571
+ };
1572
+ }
1573
+ static {
1574
+ this.LIST = {
1575
+ config(request) {
1576
+ },
1577
+ parse(response) {
1578
+ return response.data;
1579
+ }
1580
+ };
1581
+ }
1582
+ static {
1583
+ this.JSON = {
1584
+ config(request) {
1585
+ },
1586
+ parse(response) {
1587
+ return response.data;
1588
+ }
1589
+ };
1590
+ }
1591
+ static {
1592
+ this.PARSER_MAP = /* @__PURE__ */ new Map([
1593
+ ["model" /* MODEL */, _HostedAssetSource.MODEL],
1594
+ ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1595
+ ["meta" /* META */, _HostedAssetSource.META],
1596
+ ["nbt" /* NBT */, _HostedAssetSource.NBT],
1597
+ ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1598
+ ["list" /* LIST */, _HostedAssetSource.LIST],
1599
+ ["json" /* JSON */, _HostedAssetSource.JSON]
1600
+ ]);
1601
+ }
1357
1602
  async loadOrRetryWithDefaults(key, parser) {
1358
1603
  const direct = await this.load(key, parser);
1359
1604
  if (typeof direct !== "undefined") {
@@ -1388,31 +1633,25 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1388
1633
  console.info(p3, "Loading", key);
1389
1634
  const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1390
1635
  console.debug(p3, url);
1391
- let req = {
1392
- url
1393
- };
1394
- parser.config(req);
1395
- return await Requests.mcAssetRequest(req).then((response) => {
1396
- if (response && response.data) {
1397
- try {
1398
- return parser.parse(response);
1399
- } catch (e) {
1400
- console.warn("Parser failed to process response", response, e);
1401
- throw e;
1402
- }
1403
- }
1404
- return void 0;
1405
- }).catch((err) => {
1406
- if (err.response) {
1407
- let response = err.response;
1408
- if (response.status === 404) {
1409
- console.debug(p3, key, "not found");
1636
+ const request = { url };
1637
+ try {
1638
+ parser.config(request);
1639
+ let response;
1640
+ try {
1641
+ response = await Requests.mcAssetRequest(request);
1642
+ } catch (cause) {
1643
+ if (cause instanceof RequestError && cause.response?.status === 404) {
1410
1644
  return void 0;
1411
1645
  }
1646
+ throw cause;
1412
1647
  }
1413
- console.debug(p3, "Failed to load", key, err == null ? void 0 : err.message);
1414
- return void 0;
1415
- });
1648
+ if (response.data === void 0) {
1649
+ throw new Error("Asset response has no data");
1650
+ }
1651
+ return await parser.parse(response);
1652
+ } catch (cause) {
1653
+ throw new AssetLoadError(this, key, request.url, cause);
1654
+ }
1416
1655
  }
1417
1656
  assetBasePath(key) {
1418
1657
  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 + "/" : ""}`;
@@ -1436,67 +1675,6 @@ var _HostedAssetSource = class _HostedAssetSource extends AssetSource {
1436
1675
  return this.load(key, responseParser);
1437
1676
  }
1438
1677
  };
1439
- _HostedAssetSource.MODEL = {
1440
- config(request) {
1441
- },
1442
- parse(response) {
1443
- return response.data;
1444
- }
1445
- };
1446
- _HostedAssetSource.BLOCKSTATE = {
1447
- config(request) {
1448
- },
1449
- parse(response) {
1450
- return response.data;
1451
- }
1452
- };
1453
- _HostedAssetSource.META = {
1454
- config(request) {
1455
- },
1456
- parse(response) {
1457
- return response.data;
1458
- }
1459
- };
1460
- _HostedAssetSource.NBT = {
1461
- config(request) {
1462
- request.responseType = "arraybuffer";
1463
- },
1464
- parse(response) {
1465
- return NBTHelper.fromBuffer(Buffer.from(response.data));
1466
- }
1467
- };
1468
- _HostedAssetSource.IMAGE = {
1469
- config(request) {
1470
- request.responseType = "arraybuffer";
1471
- },
1472
- async parse(response) {
1473
- return await ImageLoader.processResponse(response);
1474
- }
1475
- };
1476
- _HostedAssetSource.LIST = {
1477
- config(request) {
1478
- },
1479
- parse(response) {
1480
- return response.data;
1481
- }
1482
- };
1483
- _HostedAssetSource.JSON = {
1484
- config(request) {
1485
- },
1486
- parse(response) {
1487
- return response.data;
1488
- }
1489
- };
1490
- _HostedAssetSource.PARSER_MAP = /* @__PURE__ */ new Map([
1491
- ["model" /* MODEL */, _HostedAssetSource.MODEL],
1492
- ["blockstate" /* BLOCKSTATE */, _HostedAssetSource.BLOCKSTATE],
1493
- ["meta" /* META */, _HostedAssetSource.META],
1494
- ["nbt" /* NBT */, _HostedAssetSource.NBT],
1495
- ["image" /* IMAGE */, _HostedAssetSource.IMAGE],
1496
- ["list" /* LIST */, _HostedAssetSource.LIST],
1497
- ["json" /* JSON */, _HostedAssetSource.JSON]
1498
- ]);
1499
- var HostedAssetSource = _HostedAssetSource;
1500
1678
 
1501
1679
  // src/assets/source/archive/BrowserArchiveProxy.ts
1502
1680
  import { BlobReader, BlobWriter, ZipReader } from "@zip.js/zip.js";
@@ -1519,7 +1697,6 @@ var BrowserArchiveProxy = class {
1519
1697
  };
1520
1698
 
1521
1699
  // src/assets/source/archive/ArchiveAssetSource.ts
1522
- var p4 = prefix("ArchiveAssetSource");
1523
1700
  var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1524
1701
  constructor(archiveProxy) {
1525
1702
  super();
@@ -1538,74 +1715,31 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1538
1715
  }
1539
1716
  async get(key, parser) {
1540
1717
  const responseParser = HostedAssetSource.PARSER_MAP.get(parser);
1541
- console.log("ArchiveAssetSource.get", key, parser);
1542
- let entries = await this.getEntries();
1543
- const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1544
- console.log(path);
1545
- const entry = await this.getEntry(path);
1546
- console.log(entry);
1547
- if (!entry) {
1548
- return void 0;
1549
- }
1550
- let blob = await entry.getData();
1551
- const url = URL.createObjectURL(blob);
1552
- console.log(url);
1553
- let req = {
1554
- url
1555
- };
1556
- responseParser.config(req);
1557
- return Requests.genericRequest(req).then((response) => {
1558
- if (response && response.data) {
1559
- try {
1560
- return responseParser.parse(response);
1561
- } catch (e) {
1562
- console.warn("Parser failed to process response", response, e);
1563
- throw e;
1564
- }
1565
- }
1566
- return void 0;
1567
- }).catch((err) => {
1568
- if (err.response) {
1569
- let response = err.response;
1570
- if (response.status === 404) {
1571
- console.debug(p4, key, "not found");
1572
- return void 0;
1573
- }
1574
- }
1575
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1576
- return void 0;
1577
- });
1718
+ return this.load(key, responseParser);
1578
1719
  }
1579
- //TODO: abstract this
1580
1720
  async load(key, parser) {
1581
- console.info(p4, "Loading", key);
1582
- const url = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1583
- console.debug(p4, url);
1584
- let req = {
1585
- url
1586
- };
1587
- parser.config(req);
1588
- return await Requests.genericRequest(req).then((response) => {
1589
- if (response && response.data) {
1590
- try {
1591
- return parser.parse(response);
1592
- } catch (e) {
1593
- console.warn("Parser failed to process response", response, e);
1594
- throw e;
1595
- }
1721
+ const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
1722
+ let url;
1723
+ try {
1724
+ const entry = await this.getEntry(path);
1725
+ if (!entry) {
1726
+ return void 0;
1596
1727
  }
1597
- return void 0;
1598
- }).catch((err) => {
1599
- if (err.response) {
1600
- let response = err.response;
1601
- if (response.status === 404) {
1602
- console.debug(p4, key, "not found");
1603
- return void 0;
1604
- }
1728
+ url = URL.createObjectURL(await entry.getData());
1729
+ const request = { url };
1730
+ parser.config(request);
1731
+ const response = await Requests.genericRequest(request);
1732
+ if (response.data === void 0) {
1733
+ throw new Error("Asset response has no data");
1605
1734
  }
1606
- console.debug(p4, "Failed to load", key, err == null ? void 0 : err.message);
1607
- return void 0;
1608
- });
1735
+ return await parser.parse(response);
1736
+ } catch (cause) {
1737
+ throw new AssetLoadError(this, key, path, cause);
1738
+ } finally {
1739
+ if (url !== void 0) {
1740
+ URL.revokeObjectURL(url);
1741
+ }
1742
+ }
1609
1743
  }
1610
1744
  assetBasePath(key) {
1611
1745
  return `${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
@@ -1613,18 +1747,23 @@ var ArchiveAssetSource = class _ArchiveAssetSource extends AssetSource {
1613
1747
  };
1614
1748
 
1615
1749
  // src/assets/AssetLoader.ts
1616
- var import_ts_deepmerge3 = __toESM(require_dist());
1617
- var p5 = prefix("AssetLoader");
1618
- var _AssetLoader = class _AssetLoader {
1750
+ var p4 = prefix("AssetLoader");
1751
+ var AssetLoader = class {
1752
+ static {
1753
+ this.ROOT = DEFAULT_ROOT;
1754
+ }
1755
+ static {
1756
+ this._SOURCES = [];
1757
+ }
1619
1758
  static addSource(key, source, override = true) {
1620
1759
  if (override) {
1621
1760
  const existing = this.removeSource(key);
1622
1761
  if (existing) {
1623
- console.log(p5, "Removed existing AssetSource", key);
1762
+ console.log(p4, "Removed existing AssetSource", key);
1624
1763
  }
1625
1764
  }
1626
1765
  this._SOURCES.unshift({ key, source });
1627
- console.log(p5, "Added AssetSource", key);
1766
+ console.log(p4, "Added AssetSource", key);
1628
1767
  }
1629
1768
  static removeSource(key) {
1630
1769
  const index = this._SOURCES.findIndex((s) => s.key === key);
@@ -1636,8 +1775,11 @@ var _AssetLoader = class _AssetLoader {
1636
1775
  }
1637
1776
  return void 0;
1638
1777
  }
1778
+ static {
1779
+ this.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1780
+ this.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
1781
+ }
1639
1782
  static async getAll(key, parser) {
1640
- console.log(this._SOURCES);
1641
1783
  let promises = [];
1642
1784
  for (const source of this._SOURCES) {
1643
1785
  promises.push(source.source.get(key, parser));
@@ -1646,31 +1788,18 @@ var _AssetLoader = class _AssetLoader {
1646
1788
  return results.filter((r) => r != void 0);
1647
1789
  });
1648
1790
  }
1791
+ /** Returns the first defined result in source-priority order, without merging assets. */
1649
1792
  static async get(key, parser) {
1650
- console.log(this._SOURCES);
1651
- let promises = [];
1652
- for (const source of this._SOURCES) {
1653
- promises.push(source.source.get(key, parser));
1654
- }
1655
- return Promise.all(promises).then((results) => {
1656
- const fallback = results[results.length - 1];
1657
- for (const result of results) {
1658
- if (result) {
1659
- if (fallback) {
1660
- return (0, import_ts_deepmerge3.default)({}, fallback, result);
1661
- }
1662
- return result;
1663
- }
1793
+ const sources = [...this._SOURCES];
1794
+ for (const source of sources) {
1795
+ const result = await source.source.get(key, parser);
1796
+ if (result !== void 0) {
1797
+ return result;
1664
1798
  }
1665
- return void 0;
1666
- });
1799
+ }
1800
+ return void 0;
1667
1801
  }
1668
1802
  };
1669
- _AssetLoader.ROOT = DEFAULT_ROOT;
1670
- _AssetLoader._SOURCES = [];
1671
- _AssetLoader.addSource("mcassets-fallback", new HostedAssetSource("https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master", { retryDefaults: false }));
1672
- _AssetLoader.addSource("mcassets", new HostedAssetSource(DEFAULT_ROOT, { retryDefaults: false }));
1673
- var AssetLoader = _AssetLoader;
1674
1803
 
1675
1804
  // src/assets/ModelTextures.ts
1676
1805
  var ModelTextures = class {
@@ -1678,11 +1807,21 @@ var ModelTextures = class {
1678
1807
  return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
1679
1808
  }
1680
1809
  static async get(key) {
1681
- const asset = await this.preload(key);
1682
- if (asset) {
1683
- return ImageLoader.infoToCanvasData(asset);
1810
+ const keyStr = key.serialize();
1811
+ const pending = this.preload(key);
1812
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1813
+ try {
1814
+ const asset = await pending;
1815
+ if (asset) {
1816
+ return await ImageLoader.infoToCanvasData(asset);
1817
+ }
1818
+ return void 0;
1819
+ } catch (err) {
1820
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
1821
+ Caching.textureAssetCache.invalidate(keyStr);
1822
+ }
1823
+ throw err;
1684
1824
  }
1685
- return void 0;
1686
1825
  }
1687
1826
  static async preload(key) {
1688
1827
  const keyStr = key.serialize();
@@ -1756,7 +1895,28 @@ var CanvasImage = class {
1756
1895
  };
1757
1896
 
1758
1897
  // src/Ticker.ts
1759
- var _Ticker = class _Ticker {
1898
+ var Ticker = class _Ticker {
1899
+ static {
1900
+ this.TPS = 20;
1901
+ }
1902
+ static {
1903
+ this.counter = 0;
1904
+ }
1905
+ static {
1906
+ this._tickers = /* @__PURE__ */ new Map();
1907
+ }
1908
+ static {
1909
+ this.oneSecondTps = 0;
1910
+ }
1911
+ static {
1912
+ this.oneSecondTicks = 0;
1913
+ }
1914
+ static {
1915
+ this.fiveSecondTps = 0;
1916
+ }
1917
+ static {
1918
+ this.fiveSecondTicks = 0;
1919
+ }
1760
1920
  static schedule(fn, ms) {
1761
1921
  const handle = setInterval(fn, ms);
1762
1922
  const unref = handle.unref;
@@ -1818,14 +1978,6 @@ var _Ticker = class _Ticker {
1818
1978
  this._tickers.clear();
1819
1979
  }
1820
1980
  };
1821
- _Ticker.TPS = 20;
1822
- _Ticker.counter = 0;
1823
- _Ticker._tickers = /* @__PURE__ */ new Map();
1824
- _Ticker.oneSecondTps = 0;
1825
- _Ticker.oneSecondTicks = 0;
1826
- _Ticker.fiveSecondTps = 0;
1827
- _Ticker.fiveSecondTicks = 0;
1828
- var Ticker = _Ticker;
1829
1981
 
1830
1982
  // src/texture/TextureAtlas.ts
1831
1983
  var TextureAtlas = class {
@@ -1851,6 +2003,9 @@ var TextureAtlas = class {
1851
2003
 
1852
2004
  // src/model/ModelGenerator.ts
1853
2005
  var ModelGenerator = class {
2006
+ static {
2007
+ this.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
2008
+ }
1854
2009
  static generateItemModel(imageData, layer) {
1855
2010
  const mainElement = {
1856
2011
  from: [0, 0, 7.5],
@@ -1870,10 +2025,9 @@ var ModelGenerator = class {
1870
2025
  return [mainElement];
1871
2026
  }
1872
2027
  };
1873
- ModelGenerator.ITEM_LAYERS = ["layer0", "layer1", "layer2", "layer3", "layer4"];
1874
2028
 
1875
2029
  // src/UVMapper.ts
1876
- var p6 = prefix("UVMapper");
2030
+ var p5 = prefix("UVMapper");
1877
2031
  var DEFAULT_UV = [0, 0, 16, 16];
1878
2032
  var X = 0;
1879
2033
  var Y = 1;
@@ -2046,12 +2200,11 @@ var UVMapper = class {
2046
2200
  return [tl, tr, bl, br];
2047
2201
  }
2048
2202
  static async createAtlas(originalModel) {
2049
- var _a;
2050
2203
  const textureMap = {};
2051
2204
  const metaMap = {};
2052
2205
  const model = { ...originalModel };
2053
2206
  const isItemModel = !("elements" in model);
2054
- console.debug(p6, "Creating Atlas for", model.key);
2207
+ console.debug(p5, "Creating Atlas for", model.key);
2055
2208
  if (model.textures) {
2056
2209
  const promises = [];
2057
2210
  const uniqueTextureNames = [];
@@ -2065,7 +2218,7 @@ var UVMapper = class {
2065
2218
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
2066
2219
  promises.push(ModelTextures.get(assetKey).then((asset) => {
2067
2220
  if (!asset) {
2068
- console.warn(p6, "Missing texture", assetKey);
2221
+ console.warn(p5, "Missing texture", assetKey);
2069
2222
  return;
2070
2223
  }
2071
2224
  textureMap[textureKey] = new WrappedImage(asset);
@@ -2077,7 +2230,7 @@ var UVMapper = class {
2077
2230
  }
2078
2231
  await Promise.all(promises);
2079
2232
  const textureCount = uniqueTextureNames.length;
2080
- console.debug(p6, "Creating Atlas for", textureCount, "textures");
2233
+ console.debug(p5, "Creating Atlas for", textureCount, "textures");
2081
2234
  this.fillMissingTextureKeys(model.textures, textureMap);
2082
2235
  this.fillMissingTextureKeys(model.textures, metaMap);
2083
2236
  const sizes = {};
@@ -2097,7 +2250,7 @@ var UVMapper = class {
2097
2250
  this.fillMissingTextureKeys(model.textures, sizes);
2098
2251
  const s = Math.ceil(Math.sqrt(textureCount + 1));
2099
2252
  const size = Math.ceil(s * maxWidth);
2100
- console.debug(p6, "Atlas size:", size);
2253
+ console.debug(p5, "Atlas size:", size);
2101
2254
  const squaredSize = size * size;
2102
2255
  const missing = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAABlBMVEX/AP8AAACfphTyAAAAFUlEQVQoz2MIhQKGVVAwKjIqQrwIAHRz/wFI17TEAAAAAElFTkSuQmCC");
2103
2256
  const empty = await ImageLoader.getData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQMAAACQp+OdAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAA5JREFUKM9jGAWjgAIAAAJAAAFSSwuTAAAAAElFTkSuQmCC");
@@ -2126,16 +2279,15 @@ var UVMapper = class {
2126
2279
  if (texture.animated) {
2127
2280
  hasAnimation = true;
2128
2281
  const meta = metaMap[textureKey];
2129
- const frameTime = ((_a = meta == null ? void 0 : meta.animation) == null ? void 0 : _a.frametime) ?? 1;
2282
+ const frameTime = meta?.animation?.frametime ?? 1;
2130
2283
  console.log(meta);
2131
2284
  console.log(frameTime);
2132
2285
  let t = 0;
2133
2286
  let f = 0;
2134
2287
  animatorFunctions[textureKey] = () => {
2135
- var _a2;
2136
2288
  if (t++ >= frameTime) {
2137
2289
  t = 0;
2138
- const frames = (_a2 = meta == null ? void 0 : meta.animation) == null ? void 0 : _a2.frames;
2290
+ const frames = meta?.animation?.frames;
2139
2291
  const frame = frames ? frames[f] : f;
2140
2292
  image.putData(texture.getFrameSectionData(frame), x, y, 0, 0, maxWidth, maxWidth);
2141
2293
  f++;
@@ -2153,10 +2305,10 @@ var UVMapper = class {
2153
2305
  }
2154
2306
  }
2155
2307
  const atlasImageData = image.toDataURL();
2156
- console.log(p6, "Atlas Image for", model.key, atlasImageData);
2308
+ console.log(p5, "Atlas Image for", model.key, atlasImageData);
2157
2309
  this.fillMissingTextureKeys(model.textures, positions);
2158
2310
  if (isItemModel) {
2159
- console.debug(p6, "Generating item model for", model);
2311
+ console.debug(p5, "Generating item model for", model);
2160
2312
  model.elements = [];
2161
2313
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
2162
2314
  const textureImage = textureMap[layerName];
@@ -2164,7 +2316,7 @@ var UVMapper = class {
2164
2316
  model.elements.push(...ModelGenerator.generateItemModel(textureImage.data, layerName));
2165
2317
  }
2166
2318
  }
2167
- console.debug(p6, "Item model elements", model.elements);
2319
+ console.debug(p5, "Item model elements", model.elements);
2168
2320
  }
2169
2321
  if (!model.elements) {
2170
2322
  }
@@ -2224,7 +2376,7 @@ var UVMapper = class {
2224
2376
  hasTransparency
2225
2377
  );
2226
2378
  } else {
2227
- console.warn(p6, "Model does not have any textures", model);
2379
+ console.warn(p5, "Model does not have any textures", model);
2228
2380
  }
2229
2381
  return void 0;
2230
2382
  }
@@ -2362,17 +2514,20 @@ function shutdown() {
2362
2514
  }
2363
2515
 
2364
2516
  // src/assets/Entities.ts
2365
- import { Memoize as Memoize3 } from "typescript-memoize";
2366
2517
  var Entities = class {
2367
2518
  static async getBlockEntityModels() {
2368
2519
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2369
2520
  console.log(key);
2370
- return AssetLoader.get(key, "json" /* JSON */);
2521
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2522
+ return AssetLoader.get(key, "json" /* JSON */);
2523
+ });
2371
2524
  }
2372
2525
  static async getEntityModels() {
2373
2526
  const key = AssetKey.parse("models", "minerender:entityModels");
2374
2527
  console.log(key);
2375
- return AssetLoader.get(key, "json" /* JSON */);
2528
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2529
+ return AssetLoader.get(key, "json" /* JSON */);
2530
+ });
2376
2531
  }
2377
2532
  // BlockEntity names are hardcoded
2378
2533
  static async getBlockList() {
@@ -2418,12 +2573,6 @@ var Entities = class {
2418
2573
  };
2419
2574
  }
2420
2575
  };
2421
- __decorateClass([
2422
- Memoize3()
2423
- ], Entities, "getBlockEntityModels", 1);
2424
- __decorateClass([
2425
- Memoize3()
2426
- ], Entities, "getEntityModels", 1);
2427
2576
  var EntityModels = class {
2428
2577
  };
2429
2578
  var BlockEntityModels = class {
@@ -2487,18 +2636,26 @@ var MineRenderError = class _MineRenderError extends Error {
2487
2636
  };
2488
2637
 
2489
2638
  // src/renderer/SceneObject.ts
2490
- var import_ts_deepmerge4 = __toESM(require_dist());
2491
- var p7 = prefix("SceneObject");
2492
- var _SceneObject = class _SceneObject extends Object3D2 {
2639
+ var import_ts_deepmerge3 = __toESM(require_dist());
2640
+ var p6 = prefix("SceneObject");
2641
+ var SceneObject = class _SceneObject extends Object3D2 {
2493
2642
  constructor(options) {
2494
2643
  super();
2495
2644
  this.isSceneObject = true;
2496
2645
  this.materialCallbacks = {};
2497
2646
  this._isInstanced = false;
2498
2647
  this._instanceCounter = 0;
2499
- this.options = (0, import_ts_deepmerge4.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2648
+ this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
2500
2649
  console.log("SceneObject options", this.options);
2501
2650
  }
2651
+ static {
2652
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge3.default)({}, {
2653
+ instanceMeshes: true,
2654
+ maxInstanceCount: 50,
2655
+ mergeMeshes: true,
2656
+ wireframe: false
2657
+ });
2658
+ }
2502
2659
  set scene(scene) {
2503
2660
  if (!!this._scene) throw new MineRenderError("Scene already set");
2504
2661
  this._scene = scene;
@@ -2667,9 +2824,9 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2667
2824
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
2668
2825
  const i = this._instanceCounter++;
2669
2826
  this.setMatrixAt(i, new Matrix42());
2670
- console.debug(p7, "nextInstance " + i);
2827
+ console.debug(p6, "nextInstance " + i);
2671
2828
  if (i === this.options.maxInstanceCount) {
2672
- console.warn(p7, "Max instance count reached for " + this);
2829
+ console.warn(p6, "Max instance count reached for " + this);
2673
2830
  }
2674
2831
  if (this.scene) {
2675
2832
  this.scene.stats.instanceCount++;
@@ -2840,34 +2997,29 @@ var _SceneObject = class _SceneObject extends Object3D2 {
2840
2997
  this.notifyDirty();
2841
2998
  }
2842
2999
  removeFromScene() {
2843
- var _a;
2844
- (_a = this._scene) == null ? void 0 : _a.remove(this);
3000
+ this._scene?.remove(this);
2845
3001
  this.notifyDirty();
2846
3002
  }
2847
3003
  //</editor-fold>
2848
3004
  };
2849
- _SceneObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, {
2850
- instanceMeshes: true,
2851
- maxInstanceCount: 50,
2852
- mergeMeshes: true,
2853
- wireframe: false
2854
- });
2855
- var SceneObject = _SceneObject;
2856
3005
  function isSceneObject(obj) {
2857
3006
  return obj.isSceneObject;
2858
3007
  }
2859
3008
 
2860
3009
  // src/entity/scene/EntityObject.ts
2861
- var import_ts_deepmerge5 = __toESM(require_dist());
3010
+ var import_ts_deepmerge4 = __toESM(require_dist());
2862
3011
  import { Object3D as Object3D3 } from "three";
2863
- import * as THREE2 from "three";
3012
+ import * as THREE3 from "three";
2864
3013
  var EntityObject = class extends SceneObject {
2865
3014
  constructor(entity, options) {
2866
3015
  super();
2867
3016
  this.entity = entity;
2868
3017
  this.isEntityObject = true;
2869
3018
  this.meshesCreated = false;
2870
- this.options = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3019
+ this.options = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
3020
+ }
3021
+ static {
3022
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
2871
3023
  }
2872
3024
  async init() {
2873
3025
  this.createMeshes();
@@ -2876,19 +3028,21 @@ var EntityObject = class extends SceneObject {
2876
3028
  dispose() {
2877
3029
  super.dispose();
2878
3030
  }
2879
- async loadTextures() {
2880
- var _a;
2881
- this.imageData = await ModelTextures.get(new AssetKey(
2882
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
3031
+ get textureKey() {
3032
+ return new AssetKey(
3033
+ this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2883
3034
  this.entity.key.path,
2884
3035
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
2885
3036
  "textures",
2886
3037
  "entity",
2887
3038
  "assets",
2888
3039
  ".png"
2889
- ));
3040
+ );
2890
3041
  }
2891
- //TODO: abstract this, since extracted model data can be used for entities, blocks, players
3042
+ async loadTextures() {
3043
+ this.imageData = await ModelTextures.get(this.textureKey);
3044
+ }
3045
+ //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2892
3046
  createMeshes(force = false) {
2893
3047
  if (this.meshesCreated && !force) return;
2894
3048
  const mat = Materials.MISSING_TEXTURE;
@@ -2905,8 +3059,8 @@ var EntityObject = class extends SceneObject {
2905
3059
  const l = cube.maxZ - cube.minZ;
2906
3060
  const uv = texture.toUvArray(w, h, l);
2907
3061
  const cubeGeo = this._getBoxGeometryForDimensionsAndUv(w, h, l, uv).clone();
2908
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
2909
- cubeGeo.applyMatrix4(new THREE2.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
3062
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(w / 2, h / 2, l / 2));
3063
+ cubeGeo.applyMatrix4(new THREE3.Matrix4().makeTranslation(cube.minX, cube.minY, cube.minZ));
2910
3064
  applyModelPartRotation(part, cubeGeo);
2911
3065
  const mesh = this.createMesh(partName, cubeGeo, mat);
2912
3066
  partAnchor.add(mesh);
@@ -2919,24 +3073,25 @@ var EntityObject = class extends SceneObject {
2919
3073
  this.meshesCreated = true;
2920
3074
  }
2921
3075
  async applyTextures() {
2922
- var _a;
2923
- const textureAsset = await ModelTextures.preload(new AssetKey(
2924
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
2925
- this.entity.key.path,
2926
- "textures",
2927
- "entity",
2928
- "assets",
2929
- ".png"
2930
- ));
2931
- if (textureAsset) {
2932
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
2933
- this.iterateAllMeshes((mesh) => {
2934
- mesh.material = mat;
2935
- });
2936
- }
3076
+ const assetKeyStr = this.textureKey.serialize();
3077
+ const keyStr = `entity:${assetKeyStr}`;
3078
+ let mat = Caching.materialCache.getIfPresent(keyStr);
3079
+ if (!mat) {
3080
+ const pending = this.loadTextures();
3081
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
3082
+ await pending;
3083
+ if (!this.imageData) return;
3084
+ const canvas = this.imageData.data.canvas;
3085
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
3086
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
3087
+ this.imageData = void 0;
3088
+ }
3089
+ this.iterateAllMeshes((mesh) => {
3090
+ mesh.material = mat;
3091
+ });
3092
+ this.notifyDirty();
2937
3093
  }
2938
3094
  };
2939
- EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
2940
3095
  function isEntityObject(obj) {
2941
3096
  return obj.isEntityObject;
2942
3097
  }
@@ -2948,7 +3103,7 @@ var GuiObject = class extends SceneObject {
2948
3103
 
2949
3104
  // src/inspector/SceneInspector.ts
2950
3105
  import { Raycaster, Vector2 as Vector22 } from "three";
2951
- var p8 = prefix("SceneInspector");
3106
+ var p7 = prefix("SceneInspector");
2952
3107
  var help = "<span>Ctrl+Click to Select<br/></span><br/>";
2953
3108
  var SceneInspector = class {
2954
3109
  constructor(renderer) {
@@ -2977,8 +3132,7 @@ var SceneInspector = class {
2977
3132
  return out;
2978
3133
  }
2979
3134
  onClick(event) {
2980
- var _a;
2981
- if (((_a = event.target) == null ? void 0 : _a.nodeName) !== "CANVAS") return;
3135
+ if (event.target?.nodeName !== "CANVAS") return;
2982
3136
  if (!event.ctrlKey) return;
2983
3137
  setTimeout(() => {
2984
3138
  this.mouse.x = event.clientX / window.innerWidth * 2 - 1;
@@ -3018,7 +3172,7 @@ var SceneInspector = class {
3018
3172
  }
3019
3173
  selectObject(targetObject, targetIntersection) {
3020
3174
  this.selectedObject = targetObject;
3021
- console.log(p8, "selected", targetObject);
3175
+ console.log(p7, "selected", targetObject);
3022
3176
  this.redraw(targetObject, targetIntersection);
3023
3177
  }
3024
3178
  redraw(targetObject, targetIntersection) {
@@ -3316,7 +3470,7 @@ var SceneStatsDisplay = class {
3316
3470
  };
3317
3471
 
3318
3472
  // src/instance/InstanceManager.ts
3319
- var p9 = prefix("InstanceManager");
3473
+ var p8 = prefix("InstanceManager");
3320
3474
  var InstanceManager = class {
3321
3475
  constructor() {
3322
3476
  this.isInstanceManager = true;
@@ -3324,7 +3478,7 @@ var InstanceManager = class {
3324
3478
  }
3325
3479
  async get(key) {
3326
3480
  if (key in this.instanceCache) {
3327
- console.debug(p9, "key in cache", key);
3481
+ console.debug(p8, "key in cache", key);
3328
3482
  return (await this.instanceCache[key]).nextInstance();
3329
3483
  }
3330
3484
  return void 0;
@@ -3333,13 +3487,17 @@ var InstanceManager = class {
3333
3487
  if (key in this.instanceCache) {
3334
3488
  return await this.get(key);
3335
3489
  }
3336
- console.debug(p9, "key not in cache", key);
3337
- this.instanceCache[key] = new Promise(async (resolve) => {
3338
- const obj = await supplier();
3339
- const instance = obj.nextInstance();
3340
- resolve(instance);
3341
- });
3342
- return await this.instanceCache[key];
3490
+ console.debug(p8, "key not in cache", key);
3491
+ const pending = Promise.resolve().then(supplier).then((obj) => obj.nextInstance());
3492
+ this.instanceCache[key] = pending;
3493
+ try {
3494
+ return await pending;
3495
+ } catch (error) {
3496
+ if (this.instanceCache[key] === pending) {
3497
+ delete this.instanceCache[key];
3498
+ }
3499
+ throw error;
3500
+ }
3343
3501
  }
3344
3502
  reset() {
3345
3503
  for (let instanceCacheKey in this.instanceCache) {
@@ -3938,26 +4096,28 @@ function computeMorphedAttributes(object) {
3938
4096
  }
3939
4097
 
3940
4098
  // src/model/scene/ModelObject.ts
3941
- var import_ts_deepmerge6 = __toESM(require_dist());
3942
- var p10 = prefix("ModelObject");
3943
- var _ModelObject = class _ModelObject extends SceneObject {
4099
+ var import_ts_deepmerge5 = __toESM(require_dist());
4100
+ var p9 = prefix("ModelObject");
4101
+ var ModelObject = class _ModelObject extends SceneObject {
3944
4102
  constructor(originalModel, options) {
3945
4103
  super(options);
3946
4104
  this.originalModel = originalModel;
3947
4105
  this.isModelObject = true;
3948
4106
  this.meshesCreated = false;
3949
- this.options = (0, import_ts_deepmerge6.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4107
+ this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
3950
4108
  console.log("ModelObject options", this.options);
3951
4109
  }
4110
+ static {
4111
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4112
+ }
3952
4113
  async init() {
3953
4114
  await this.loadTextures();
3954
4115
  this.createMeshes();
3955
4116
  this.applyTextures();
3956
4117
  }
3957
4118
  dispose() {
3958
- var _a;
3959
4119
  super.dispose();
3960
- (_a = this.atlas) == null ? void 0 : _a.dispose();
4120
+ this.atlas?.dispose();
3961
4121
  }
3962
4122
  get textureAtlas() {
3963
4123
  return this.atlas;
@@ -3967,13 +4127,12 @@ var _ModelObject = class _ModelObject extends SceneObject {
3967
4127
  this.atlas = await UVMapper.getAtlas(this.originalModel);
3968
4128
  }
3969
4129
  createMeshes(force = false) {
3970
- var _a;
3971
4130
  if (this.meshesCreated && !force) return;
3972
4131
  const mat = Materials.MISSING_TEXTURE;
3973
4132
  let allGeos = [];
3974
4133
  if (this.atlas) {
3975
4134
  if (this.atlas.model.elements) {
3976
- (_a = this.atlas.model.elements) == null ? void 0 : _a.forEach((el) => {
4135
+ this.atlas.model.elements?.forEach((el) => {
3977
4136
  const elGeo = this._getBoxGeometryFromElement(el).clone();
3978
4137
  elGeo.applyMatrix4(new Matrix45().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
3979
4138
  elGeo.applyMatrix4(new Matrix45().makeTranslation(el.from[0], el.from[1], el.from[2]));
@@ -3991,10 +4150,10 @@ var _ModelObject = class _ModelObject extends SceneObject {
3991
4150
  }
3992
4151
  });
3993
4152
  } else {
3994
- console.debug(p10, this.atlas.model, "has no elements");
4153
+ console.debug(p9, this.atlas.model, "has no elements");
3995
4154
  }
3996
4155
  } else {
3997
- console.debug(p10, "Missing atlas for", this);
4156
+ console.debug(p9, "Missing atlas for", this);
3998
4157
  }
3999
4158
  if (this.options.mergeMeshes) {
4000
4159
  let combinedGeo;
@@ -4046,17 +4205,15 @@ var _ModelObject = class _ModelObject extends SceneObject {
4046
4205
  }
4047
4206
  }
4048
4207
  };
4049
- _ModelObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4050
- var ModelObject = _ModelObject;
4051
4208
  function isModelObject(obj) {
4052
4209
  return obj.isModelObject;
4053
4210
  }
4054
4211
 
4055
4212
  // src/model/block/scene/BlockObject.ts
4056
- var import_ts_deepmerge7 = __toESM(require_dist());
4213
+ var import_ts_deepmerge6 = __toESM(require_dist());
4057
4214
  import { Euler as Euler3, Matrix4 as Matrix46, Vector3 as Vector36 } from "three";
4058
- var p11 = prefix("BlockObject");
4059
- var _BlockObject = class _BlockObject extends SceneObject {
4215
+ var p10 = prefix("BlockObject");
4216
+ var BlockObject = class _BlockObject extends SceneObject {
4060
4217
  constructor(blockState, options) {
4061
4218
  super(options);
4062
4219
  this.blockState = blockState;
@@ -4069,11 +4226,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
4069
4226
  this._instanceModel = [];
4070
4227
  this._variants = [];
4071
4228
  this._models = [];
4072
- this.options = (0, import_ts_deepmerge7.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4229
+ this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4230
+ }
4231
+ static {
4232
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
4233
+ applyDefaultState: true
4234
+ });
4073
4235
  }
4074
4236
  async init() {
4075
4237
  if (this.options.applyDefaultState) {
4076
- const defaultState = this.blockState.key ? BlockStates.getDefaultState(this.blockState.key) : void 0;
4238
+ const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4077
4239
  if (defaultState && Object.keys(defaultState).length > 0) {
4078
4240
  const state = {};
4079
4241
  for (let k in defaultState) {
@@ -4149,7 +4311,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4149
4311
  } else if (this.blockState.multipart) {
4150
4312
  for (let part of this.blockState.multipart) {
4151
4313
  if (!part.apply) {
4152
- console.debug(p11, "Missing apply for blockState part", part);
4314
+ console.debug(p10, "Missing apply for blockState part", part);
4153
4315
  continue;
4154
4316
  }
4155
4317
  if (!part.when) {
@@ -4358,10 +4520,6 @@ var _BlockObject = class _BlockObject extends SceneObject {
4358
4520
  //TODO: should override rotation + scale methods
4359
4521
  //TODO
4360
4522
  };
4361
- _BlockObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge7.default)({}, ModelObject.DEFAULT_OPTIONS, {
4362
- applyDefaultState: true
4363
- });
4364
- var BlockObject = _BlockObject;
4365
4523
  function isBlockObject(obj) {
4366
4524
  return obj.isBlockObject;
4367
4525
  }
@@ -4386,11 +4544,10 @@ var StructureParser = class {
4386
4544
  throw new MineRenderError("Structure does not have palette(s)");
4387
4545
  }
4388
4546
  const blocks = nbt.blocks.value.value.map((block) => {
4389
- var _a;
4390
4547
  const state = palette.value.value[block.state.value];
4391
4548
  if (state.Name.value === "minecraft:air") return void 0;
4392
4549
  const props = {};
4393
- for (let k in (_a = state.Properties) == null ? void 0 : _a.value) {
4550
+ for (let k in state.Properties?.value) {
4394
4551
  props[k] = state.Properties.value[k].value;
4395
4552
  }
4396
4553
  return {
@@ -4409,7 +4566,7 @@ var StructureParser = class {
4409
4566
 
4410
4567
  // src/renderer/MineRenderScene.ts
4411
4568
  import { Scene as Scene2 } from "three";
4412
- var import_ts_deepmerge9 = __toESM(require_dist());
4569
+ var import_ts_deepmerge8 = __toESM(require_dist());
4413
4570
 
4414
4571
  // src/skin/SkinPart.ts
4415
4572
  var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
@@ -5140,7 +5297,7 @@ var slimSkinGeometries = {
5140
5297
  };
5141
5298
 
5142
5299
  // src/skin/scene/SkinObject.ts
5143
- var import_ts_deepmerge8 = __toESM(require_dist());
5300
+ var import_ts_deepmerge7 = __toESM(require_dist());
5144
5301
  var SkinObject = class extends SceneObject {
5145
5302
  constructor(options) {
5146
5303
  super();
@@ -5148,7 +5305,7 @@ var SkinObject = class extends SceneObject {
5148
5305
  this.legacy = false;
5149
5306
  this.skinTextureWidth = 64;
5150
5307
  this.skinTextureHeight = 64;
5151
- this.options = (0, import_ts_deepmerge8.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5308
+ this.options = (0, import_ts_deepmerge7.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
5152
5309
  }
5153
5310
  async init() {
5154
5311
  this.createMeshes();
@@ -5252,31 +5409,64 @@ var SkinObject = class extends SceneObject {
5252
5409
  };
5253
5410
 
5254
5411
  // src/renderer/MineRenderScene.ts
5255
- var _MineRenderScene = class _MineRenderScene extends Scene2 {
5412
+ var MineRenderScene = class _MineRenderScene extends Scene2 {
5256
5413
  constructor(options) {
5257
5414
  super();
5258
5415
  this.isMineRenderScene = true;
5259
5416
  this.stats = new SceneStats();
5260
5417
  this.instanceManager = new InstanceManager();
5261
5418
  this.dirty = true;
5262
- this.options = (0, import_ts_deepmerge9.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5419
+ this.observedObjects = /* @__PURE__ */ new Set();
5420
+ this.onObjectChange = (event) => {
5421
+ if (event.target?.parent === this) {
5422
+ this.dirty = true;
5423
+ }
5424
+ };
5425
+ this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
5263
5426
  }
5264
- add(...object) {
5265
- this.dirty = true;
5266
- this.stats.objectCount += object.length;
5267
- for (let obj of object) {
5268
- if (isSceneObject(obj)) {
5269
- this.stats.sceneObjectCount++;
5427
+ static {
5428
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
5429
+ }
5430
+ add(...objects) {
5431
+ for (const object of objects) {
5432
+ this.dirty = true;
5433
+ try {
5434
+ super.add(object);
5435
+ } finally {
5436
+ if (object?.isObject3D && object !== this) {
5437
+ this.updateObjectRegistration(object, object.parent === this);
5438
+ }
5270
5439
  }
5271
- obj.addEventListener("change", (event) => {
5272
- this.dirty = true;
5273
- });
5274
5440
  }
5275
- return super.add(...object);
5441
+ return this;
5276
5442
  }
5277
- remove(...object) {
5278
- this.dirty = true;
5279
- return super.remove(...object);
5443
+ remove(...objects) {
5444
+ for (const object of objects) {
5445
+ if (!this.children.includes(object)) continue;
5446
+ this.dirty = true;
5447
+ this.updateObjectRegistration(object, false);
5448
+ try {
5449
+ super.remove(object);
5450
+ } finally {
5451
+ this.updateObjectRegistration(object, object.parent === this);
5452
+ }
5453
+ }
5454
+ return this;
5455
+ }
5456
+ updateObjectRegistration(object, attached) {
5457
+ if (this.observedObjects.has(object) === attached) return;
5458
+ if (attached) {
5459
+ this.observedObjects.add(object);
5460
+ object.addEventListener("change", this.onObjectChange);
5461
+ } else {
5462
+ this.observedObjects.delete(object);
5463
+ object.removeEventListener("change", this.onObjectChange);
5464
+ }
5465
+ const change = attached ? 1 : -1;
5466
+ this.stats.objectCount += change;
5467
+ if (isSceneObject(object)) {
5468
+ this.stats.sceneObjectCount += change;
5469
+ }
5280
5470
  }
5281
5471
  async initAndAdd(...object) {
5282
5472
  this.dirty = true;
@@ -5286,13 +5476,12 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5286
5476
  return this.add(...object);
5287
5477
  }
5288
5478
  async addSceneObject(asset, objectSupplier, _options, parent = this) {
5289
- var _a, _b;
5290
5479
  console.log("addSceneObject", asset);
5291
5480
  console.log("parent", parent);
5292
5481
  console.log(_options);
5293
5482
  this.dirty = true;
5294
5483
  const obj = await objectSupplier();
5295
- if (((_a = obj == null ? void 0 : obj.options) == null ? void 0 : _a.instanceMeshes) && asset.key && ((_b = asset.key) == null ? void 0 : _b.assetType) === "models") {
5484
+ if (obj?.options?.instanceMeshes && asset.key && asset.key?.assetType === "models") {
5296
5485
  console.log("instanceMeshes + key");
5297
5486
  const key = asset.key.serialize();
5298
5487
  return this.instanceManager.getOrCreate(key, async () => {
@@ -5332,422 +5521,30 @@ var _MineRenderScene = class _MineRenderScene extends Scene2 {
5332
5521
  return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
5333
5522
  }
5334
5523
  };
5335
- _MineRenderScene.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {});
5336
- var MineRenderScene = _MineRenderScene;
5337
5524
  function isMineRenderScene(obj) {
5338
5525
  return obj.isMineRenderScene;
5339
5526
  }
5340
5527
 
5341
5528
  // src/renderer/Renderer.ts
5342
- import { AxesHelper as AxesHelper3, GridHelper, LinearEncoding, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, Vector3 as Vector37, WebGLRenderer } from "three";
5343
- var import_ts_deepmerge10 = __toESM(require_dist());
5529
+ import { AxesHelper as AxesHelper3, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace3, Vector3 as Vector38, WebGLRenderer } from "three";
5530
+ var import_ts_deepmerge9 = __toESM(require_dist());
5344
5531
  import Stats from "stats.js";
5345
5532
  import { EffectComposer, RenderPass } from "postprocessing";
5346
- var _Renderer = class _Renderer {
5347
- constructor(options) {
5348
- this._dirty = true;
5349
- this._animationTimer = void 0;
5350
- this._animationFrame = void 0;
5351
- this._resizeListener = void 0;
5352
- this.options = (0, import_ts_deepmerge10.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
5353
- this._animationLoop = this.animate.bind(this);
5354
- this._fpsTimer = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
5355
- this._scene = this.createScene();
5356
- this._camera = this.createCamera();
5357
- this._renderer = this.createRenderer();
5358
- this._composer = this.createComposer();
5359
- if (this.options.render.stats) {
5360
- this._stats = new Stats();
5361
- document.body.appendChild(this._stats.dom);
5362
- }
5363
- this.init();
5364
- }
5365
- //<editor-fold desc="INIT">
5366
- createScene() {
5367
- return new MineRenderScene();
5368
- }
5369
- createCamera() {
5370
- switch (this.options.camera.type) {
5371
- case "perspective":
5372
- default:
5373
- return new PerspectiveCamera(
5374
- this.options.camera.perspective.fov,
5375
- this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
5376
- this.options.camera.near,
5377
- this.options.camera.far
5378
- );
5379
- case "orthographic":
5380
- return new OrthographicCamera(
5381
- this.options.camera.orthographic.left ?? this.viewWidth / -2,
5382
- this.options.camera.orthographic.right ?? this.viewWidth / 2,
5383
- this.options.camera.orthographic.top ?? this.viewHeight / 2,
5384
- this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
5385
- this.options.camera.near,
5386
- this.options.camera.far
5387
- );
5388
- }
5389
- }
5390
- createRenderer() {
5391
- const renderer = new WebGLRenderer({
5392
- antialias: this.options.render.antialias,
5393
- alpha: true,
5394
- powerPreference: "high-performance",
5395
- depth: true
5396
- });
5397
- renderer.setClearColor(0, 0);
5398
- renderer.shadowMap.enabled = true;
5399
- renderer.shadowMap.type = PCFSoftShadowMap;
5400
- renderer.outputEncoding = LinearEncoding;
5401
- renderer.setSize(this.viewWidth, this.viewHeight);
5402
- return renderer;
5403
- }
5404
- createComposer() {
5405
- const composer = new EffectComposer(this.renderer);
5406
- if (!this.options.composer.enabled) return composer;
5407
- composer.setSize(this.viewWidth, this.viewHeight);
5408
- composer.addPass(new RenderPass(this.scene, this.camera));
5409
- return composer;
5410
- }
5411
- //</editor-fold>
5412
- init() {
5413
- if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
5414
- window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
5415
- }
5416
- if (this.options.debug.grid) {
5417
- const gridHelper = new GridHelper(128, 16);
5418
- this.scene.add(gridHelper);
5419
- const gridHelper2 = new GridHelper(128, 16);
5420
- gridHelper2.rotation.x = 90 * (Math.PI / 180);
5421
- this.scene.add(gridHelper2);
5422
- const gridHelper3 = new GridHelper(128, 16);
5423
- gridHelper3.rotation.z = 90 * (Math.PI / 180);
5424
- this.scene.add(gridHelper3);
5425
- }
5426
- if (this.options.debug.axes) {
5427
- const axesHelper = new AxesHelper3(64);
5428
- this.scene.add(axesHelper);
5429
- }
5430
- if (this.options.camera.position) {
5431
- if (isVector3(this.options.camera.position)) {
5432
- this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
5433
- } else if (isTripleArray(this.options.camera.position)) {
5434
- this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
5435
- }
5436
- }
5437
- if (this.options.camera.lookingAt) {
5438
- if (isVector3(this.options.camera.lookingAt)) {
5439
- this.camera.lookAt(this.options.camera.lookingAt);
5440
- } else if (isTripleArray(this.options.camera.lookingAt)) {
5441
- this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
5442
- }
5443
- }
5444
- if (this.options.render.autoResize) {
5445
- this._resizeListener = () => {
5446
- this.resize(this.viewWidth, this.viewHeight);
5447
- };
5448
- window.addEventListener("resize", this._resizeListener);
5449
- }
5450
- }
5451
- get element() {
5452
- return this._element;
5453
- }
5454
- appendTo(element) {
5455
- this._element = element;
5456
- this._element.appendChild(this.renderer.domElement);
5457
- if (this.viewWidth == 0) {
5458
- console.warn("0 element width");
5459
- }
5460
- if (this.viewHeight == 0) {
5461
- console.warn("0 element height");
5462
- }
5463
- this.resize(this.viewWidth, this.viewHeight);
5464
- }
5465
- /**
5466
- * Register an EventDispatcher which may update the scene or renderer in order to redraw the scene
5467
- */
5468
- registerEventDispatcher(dispatcher, changeEvent2 = "change") {
5469
- dispatcher.addEventListener(changeEvent2, (event) => {
5470
- this._dirty = true;
5471
- });
5472
- }
5473
- resize(width, height) {
5474
- if (isPerspectiveCamera(this.camera)) {
5475
- this.camera.aspect = width / height;
5476
- this.camera.updateProjectionMatrix();
5477
- } else if (isOrthographicCamera(this.camera)) {
5478
- this.camera.left = width / -2;
5479
- this.camera.right = width / 2;
5480
- this.camera.top = height / 2;
5481
- this.camera.bottom = height / -2;
5482
- this.camera.updateProjectionMatrix();
5483
- }
5484
- this.renderer.setSize(width, height);
5485
- this.composer.setSize(width, height);
5486
- }
5487
- //<editor-fold desc="RENDER">
5488
- get dirty() {
5489
- return this._dirty || this.scene.dirty;
5490
- }
5491
- set dirty(dirty) {
5492
- this._dirty = dirty;
5493
- this.scene.dirty = dirty;
5494
- }
5495
- start() {
5496
- stop();
5497
- this.renderer.setAnimationLoop(this._animationLoop);
5498
- }
5499
- stop() {
5500
- this.renderer.setAnimationLoop(null);
5501
- if (this._animationTimer)
5502
- clearTimeout(this._animationTimer);
5503
- this._animationTimer = void 0;
5504
- if (this._animationFrame)
5505
- cancelAnimationFrame(this._animationFrame);
5506
- this._animationFrame = void 0;
5507
- }
5508
- animate(t) {
5509
- if (this._stats) {
5510
- this._stats.begin();
5511
- }
5512
- if (this.dirty || this.options.render.renderAlways) {
5513
- if (this.options.composer.enabled) {
5514
- this.composer.render();
5515
- } else {
5516
- this.renderer.render(this.scene, this.camera);
5517
- }
5518
- }
5519
- this.dirty = false;
5520
- if (this._stats) {
5521
- this._stats.end();
5522
- }
5523
- }
5524
- //</editor-fold>
5525
- toImage() {
5526
- return this.renderer.domElement.toDataURL();
5527
- }
5528
- ///
5529
- get attachedToBody() {
5530
- return this.element === document.body;
5531
- }
5532
- get viewWidth() {
5533
- var _a;
5534
- return this.attachedToBody ? window.innerWidth : ((_a = this.element) == null ? void 0 : _a.offsetWidth) || 0;
5535
- }
5536
- get viewHeight() {
5537
- var _a;
5538
- return this.attachedToBody ? window.innerHeight : ((_a = this.element) == null ? void 0 : _a.offsetHeight) || 0;
5539
- }
5540
- get scene() {
5541
- return this._scene;
5542
- }
5543
- get camera() {
5544
- return this._camera;
5545
- }
5546
- get renderer() {
5547
- return this._renderer;
5548
- }
5549
- get composer() {
5550
- return this._composer;
5551
- }
5552
- ///
5553
- };
5554
- _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge10.default)({}, {
5555
- camera: {
5556
- type: "perspective",
5557
- near: 1,
5558
- far: 5e3,
5559
- perspective: {
5560
- aspect: void 0,
5561
- fov: 50
5562
- },
5563
- orthographic: {
5564
- left: void 0,
5565
- right: void 0,
5566
- top: void 0,
5567
- bottom: void 0
5568
- },
5569
- position: new Vector37(50, 50, 50),
5570
- lookingAt: new Vector37(0, 0, 0)
5571
- },
5572
- render: {
5573
- fpsLimit: 60,
5574
- stats: false,
5575
- antialias: true,
5576
- shade: true,
5577
- autoResize: true,
5578
- renderAlways: false
5579
- },
5580
- composer: {
5581
- enabled: true
5582
- },
5583
- debug: {
5584
- grid: false,
5585
- axes: false
5586
- }
5587
- });
5588
- var Renderer = _Renderer;
5589
-
5590
- // src/skin/Skins.ts
5591
- var Skins = class {
5592
- //<editor-fold desc="Skins">
5593
- static async fromUuidOrUsername(uuidOrUsername) {
5594
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5595
- return this.fromUuid(uuidOrUsername);
5596
- }
5597
- return this.fromUsername(uuidOrUsername);
5598
- }
5599
- static async fromUuid(uuid) {
5600
- return this.getSkinProxySkinUrl(uuid);
5601
- }
5602
- static async fromUsername(username) {
5603
- return this.usernameToUuid(username).then((uuid) => {
5604
- if (uuid) {
5605
- return this.fromUuid(uuid);
5606
- }
5607
- return void 0;
5608
- });
5609
- }
5610
- static async fromMineSkin(mineskinId) {
5611
- return this.getMineSkin(mineskinId).then((mineskin) => {
5612
- if (mineskin) {
5613
- return mineskin["data"]["texture"]["value"]["urls"]["skins"];
5614
- }
5615
- return void 0;
5616
- });
5617
- }
5618
- //</editor-fold>
5619
- //<editor-fold desc="Capes">
5620
- static async capeFromUuidOrUsername(uuidOrUsername) {
5621
- if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
5622
- return this.capeFromUuid(uuidOrUsername);
5623
- }
5624
- return this.capeFromUsername(uuidOrUsername);
5625
- }
5626
- static async capeFromUuid(uuid) {
5627
- return this.getSkinProxyCapeUrl(uuid);
5628
- }
5629
- static async capeFromUsername(username) {
5630
- return this.usernameToUuid(username).then((uuid) => {
5631
- if (uuid) {
5632
- return this.capeFromUuid(uuid);
5633
- }
5634
- return void 0;
5635
- });
5636
- }
5637
- static async capeFromCapesDev(uuid, capeType = "minecraft") {
5638
- return this.getCapesDev(uuid, capeType).then((cape) => {
5639
- if (cape) {
5640
- return cape == null ? void 0 : cape.stillImageUrl;
5641
- }
5642
- return void 0;
5643
- });
5644
- }
5645
- //</editor-fold>
5646
- //<editor-fold desc="Helpers">
5647
- static async usernameToUuid(username) {
5648
- return this.usernameToUuidSkinProxy(username);
5649
- }
5650
- static async usernameToUuidSkinProxy(username) {
5651
- return Requests.genericRequest({
5652
- baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
5653
- url: "/uuid/" + username
5654
- }).then((res) => {
5655
- if (res.status === 200) {
5656
- return res.data["id"];
5657
- }
5658
- return void 0;
5659
- }).catch((err) => {
5660
- console.warn(err);
5661
- return void 0;
5662
- });
5663
- }
5664
- static async usernameToUuidMineTools(username) {
5665
- return Requests.genericRequest({
5666
- baseURL: "https://api.minetools.eu",
5667
- url: "/uuid/" + username
5668
- }).then((res) => {
5669
- if (res.status === 200) {
5670
- return res.data["id"];
5671
- }
5672
- return void 0;
5673
- }).catch((err) => {
5674
- console.warn(err);
5675
- return void 0;
5676
- });
5677
- }
5678
- static async getProfileFromMinetools(uuid) {
5679
- return Requests.genericRequest({
5680
- baseURL: "https://api.minetools.eu",
5681
- url: "/profile/" + uuid
5682
- }).then((res) => {
5683
- if (res.status === 200) {
5684
- return res.data;
5685
- }
5686
- });
5687
- }
5688
- static async getMineSkin(mineskinId) {
5689
- return Requests.genericRequest({
5690
- baseURL: "https://api.mineskin.org",
5691
- url: "/get/uuid/" + mineskinId
5692
- }).then((res) => {
5693
- if (res.status === 200) {
5694
- return res.data;
5695
- }
5696
- return void 0;
5697
- }).catch((err) => {
5698
- console.warn(err);
5699
- return void 0;
5700
- });
5701
- }
5702
- static async getCapesDev(uuid, type = "all") {
5703
- return Requests.genericRequest({
5704
- baseURL: "https://api.capes.dev",
5705
- url: "/load/" + uuid + "/" + type
5706
- }).then((res) => {
5707
- if (res.status === 200) {
5708
- return res.data;
5709
- }
5710
- return void 0;
5711
- }).catch((err) => {
5712
- console.warn(err);
5713
- return void 0;
5714
- });
5715
- }
5716
- static getCrafatarSkinUrl(uuid) {
5717
- return "https://crafatar.com/skins/" + uuid;
5718
- }
5719
- static getCrafatarCapeUrl(uuid) {
5720
- return "https://crafatar.com/capes/" + uuid;
5721
- }
5722
- static getMcHeadsSkinUrl(uuid) {
5723
- return "https://mc-heads.net/skin/" + uuid;
5724
- }
5725
- static getMineSkinPlayerSkinUrl(uuid) {
5726
- return "https://mineskin.org/skin/player/" + uuid;
5727
- }
5728
- static getSkinProxySkinUrl(uuid) {
5729
- return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
5730
- }
5731
- static getSkinProxyCapeUrl(uuid) {
5732
- return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
5733
- }
5734
- //</editor-fold>
5735
- };
5736
5533
 
5737
5534
  // src/three/OrbitControls.js
5738
5535
  import {
5739
- EventDispatcher as EventDispatcher2,
5536
+ EventDispatcher,
5740
5537
  MOUSE,
5741
5538
  Quaternion as Quaternion3,
5742
5539
  Spherical,
5743
5540
  TOUCH,
5744
5541
  Vector2 as Vector23,
5745
- Vector3 as Vector38
5542
+ Vector3 as Vector37
5746
5543
  } from "three";
5747
5544
  var _changeEvent = { type: "change" };
5748
5545
  var _startEvent = { type: "start" };
5749
5546
  var _endEvent = { type: "end" };
5750
- var OrbitControls = class extends EventDispatcher2 {
5547
+ var OrbitControls = class extends EventDispatcher {
5751
5548
  constructor(object, domElement) {
5752
5549
  super();
5753
5550
  if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
@@ -5756,7 +5553,7 @@ var OrbitControls = class extends EventDispatcher2 {
5756
5553
  this.domElement = domElement;
5757
5554
  this.domElement.style.touchAction = "none";
5758
5555
  this.enabled = true;
5759
- this.target = new Vector38();
5556
+ this.target = new Vector37();
5760
5557
  this.minDistance = 0;
5761
5558
  this.maxDistance = Infinity;
5762
5559
  this.minZoom = 0;
@@ -5808,10 +5605,10 @@ var OrbitControls = class extends EventDispatcher2 {
5808
5605
  state = STATE.NONE;
5809
5606
  };
5810
5607
  this.update = function() {
5811
- const offset = new Vector38();
5812
- const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector38(0, 1, 0));
5608
+ const offset = new Vector37();
5609
+ const quat = new Quaternion3().setFromUnitVectors(object.up, new Vector37(0, 1, 0));
5813
5610
  const quatInverse = quat.clone().invert();
5814
- const lastPosition = new Vector38();
5611
+ const lastPosition = new Vector37();
5815
5612
  const lastQuaternion = new Quaternion3();
5816
5613
  const twoPI = 2 * Math.PI;
5817
5614
  return function update() {
@@ -5901,7 +5698,7 @@ var OrbitControls = class extends EventDispatcher2 {
5901
5698
  const spherical = new Spherical();
5902
5699
  const sphericalDelta = new Spherical();
5903
5700
  let scale = 1;
5904
- const panOffset = new Vector38();
5701
+ const panOffset = new Vector37();
5905
5702
  let zoomChanged = false;
5906
5703
  const rotateStart = new Vector23();
5907
5704
  const rotateEnd = new Vector23();
@@ -5927,7 +5724,7 @@ var OrbitControls = class extends EventDispatcher2 {
5927
5724
  sphericalDelta.phi -= angle;
5928
5725
  }
5929
5726
  const panLeft = function() {
5930
- const v = new Vector38();
5727
+ const v = new Vector37();
5931
5728
  return function panLeft2(distance, objectMatrix) {
5932
5729
  v.setFromMatrixColumn(objectMatrix, 0);
5933
5730
  v.multiplyScalar(-distance);
@@ -5935,7 +5732,7 @@ var OrbitControls = class extends EventDispatcher2 {
5935
5732
  };
5936
5733
  }();
5937
5734
  const panUp = function() {
5938
- const v = new Vector38();
5735
+ const v = new Vector37();
5939
5736
  return function panUp2(distance, objectMatrix) {
5940
5737
  if (scope.screenSpacePanning === true) {
5941
5738
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -5948,7 +5745,7 @@ var OrbitControls = class extends EventDispatcher2 {
5948
5745
  };
5949
5746
  }();
5950
5747
  const pan = function() {
5951
- const offset = new Vector38();
5748
+ const offset = new Vector37();
5952
5749
  return function pan2(deltaX, deltaY) {
5953
5750
  const element = scope.domElement;
5954
5751
  if (scope.object.isPerspectiveCamera) {
@@ -6384,6 +6181,489 @@ var MapControls = class extends OrbitControls {
6384
6181
  }
6385
6182
  };
6386
6183
 
6184
+ // src/renderer/Renderer.ts
6185
+ var Renderer = class _Renderer {
6186
+ constructor(options) {
6187
+ this._dirty = true;
6188
+ this._resizeListener = void 0;
6189
+ this._disposed = false;
6190
+ this._debugHelpers = [];
6191
+ this._eventDispatchers = /* @__PURE__ */ new Map();
6192
+ this._changeListener = () => {
6193
+ this._dirty = true;
6194
+ };
6195
+ this.options = (0, import_ts_deepmerge9.default)({}, _Renderer.DEFAULT_OPTIONS, options ?? {});
6196
+ this._animationLoop = this.animate.bind(this);
6197
+ this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
6198
+ this._scene = this.createScene();
6199
+ this._camera = this.createCamera();
6200
+ this._renderer = this.createRenderer();
6201
+ this._composer = this.createComposer();
6202
+ if (this.options.render.stats) {
6203
+ this._stats = new Stats();
6204
+ document.body.appendChild(this._stats.dom);
6205
+ }
6206
+ this.init();
6207
+ this._controls = this.createControls();
6208
+ }
6209
+ static {
6210
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
6211
+ camera: {
6212
+ type: "perspective",
6213
+ near: 1,
6214
+ far: 5e3,
6215
+ perspective: {
6216
+ aspect: void 0,
6217
+ fov: 50
6218
+ },
6219
+ orthographic: {
6220
+ left: void 0,
6221
+ right: void 0,
6222
+ top: void 0,
6223
+ bottom: void 0
6224
+ },
6225
+ position: new Vector38(50, 50, 50),
6226
+ lookingAt: new Vector38(0, 0, 0)
6227
+ },
6228
+ render: {
6229
+ fpsLimit: 60,
6230
+ stats: false,
6231
+ antialias: true,
6232
+ shade: true,
6233
+ autoResize: true,
6234
+ renderAlways: false
6235
+ },
6236
+ composer: {
6237
+ enabled: true
6238
+ },
6239
+ controls: {
6240
+ enabled: false
6241
+ },
6242
+ debug: {
6243
+ grid: false,
6244
+ axes: false
6245
+ }
6246
+ });
6247
+ }
6248
+ //<editor-fold desc="INIT">
6249
+ createScene() {
6250
+ return new MineRenderScene();
6251
+ }
6252
+ createCamera() {
6253
+ switch (this.options.camera.type) {
6254
+ case "perspective":
6255
+ default:
6256
+ return new PerspectiveCamera(
6257
+ this.options.camera.perspective.fov,
6258
+ this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6259
+ this.options.camera.near,
6260
+ this.options.camera.far
6261
+ );
6262
+ case "orthographic":
6263
+ return new OrthographicCamera(
6264
+ this.options.camera.orthographic.left ?? this.viewWidth / -2,
6265
+ this.options.camera.orthographic.right ?? this.viewWidth / 2,
6266
+ this.options.camera.orthographic.top ?? this.viewHeight / 2,
6267
+ this.options.camera.orthographic.bottom ?? this.viewHeight / -2,
6268
+ this.options.camera.near,
6269
+ this.options.camera.far
6270
+ );
6271
+ }
6272
+ }
6273
+ createRenderer() {
6274
+ const renderer = new WebGLRenderer({
6275
+ antialias: this.options.render.antialias,
6276
+ alpha: true,
6277
+ powerPreference: "high-performance",
6278
+ depth: true
6279
+ });
6280
+ renderer.setClearColor(0, 0);
6281
+ renderer.shadowMap.enabled = true;
6282
+ renderer.shadowMap.type = PCFSoftShadowMap;
6283
+ renderer.outputColorSpace = SRGBColorSpace3;
6284
+ renderer.setSize(this.viewWidth, this.viewHeight);
6285
+ return renderer;
6286
+ }
6287
+ createComposer() {
6288
+ if (!this.options.composer.enabled) return void 0;
6289
+ const composer = new EffectComposer(this.renderer);
6290
+ composer.setSize(this.viewWidth, this.viewHeight);
6291
+ composer.addPass(new RenderPass(this.scene, this.camera));
6292
+ return composer;
6293
+ }
6294
+ createControls() {
6295
+ if (!this.options.controls?.enabled) return void 0;
6296
+ const position = this.camera.position.clone();
6297
+ const controls = new OrbitControls(this.camera, this.renderer.domElement);
6298
+ this.camera.position.copy(position);
6299
+ const target = this.options.camera.lookingAt;
6300
+ if (isVector3(target)) {
6301
+ controls.target.copy(target);
6302
+ } else if (isTripleArray(target)) {
6303
+ controls.target.set(target[0], target[1], target[2]);
6304
+ }
6305
+ controls.update();
6306
+ controls.saveState();
6307
+ this.registerEventDispatcher(controls);
6308
+ return controls;
6309
+ }
6310
+ //</editor-fold>
6311
+ init() {
6312
+ if (this._disposed) return;
6313
+ if (typeof window["__THREE_DEVTOOLS__"] !== "undefined") {
6314
+ window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6315
+ }
6316
+ if (this.options.debug.grid) {
6317
+ const gridHelper = new GridHelper(128, 16);
6318
+ this._debugHelpers.push(gridHelper);
6319
+ this.scene.add(gridHelper);
6320
+ const gridHelper2 = new GridHelper(128, 16);
6321
+ this._debugHelpers.push(gridHelper2);
6322
+ gridHelper2.rotation.x = 90 * (Math.PI / 180);
6323
+ this.scene.add(gridHelper2);
6324
+ const gridHelper3 = new GridHelper(128, 16);
6325
+ this._debugHelpers.push(gridHelper3);
6326
+ gridHelper3.rotation.z = 90 * (Math.PI / 180);
6327
+ this.scene.add(gridHelper3);
6328
+ }
6329
+ if (this.options.debug.axes) {
6330
+ const axesHelper = new AxesHelper3(64);
6331
+ this._debugHelpers.push(axesHelper);
6332
+ this.scene.add(axesHelper);
6333
+ }
6334
+ if (this.options.camera.position) {
6335
+ if (isVector3(this.options.camera.position)) {
6336
+ this.camera.position.set(this.options.camera.position.x, this.options.camera.position.y, this.options.camera.position.z);
6337
+ } else if (isTripleArray(this.options.camera.position)) {
6338
+ this.camera.position.set(this.options.camera.position[0], this.options.camera.position[1], this.options.camera.position[2]);
6339
+ }
6340
+ }
6341
+ if (this.options.camera.lookingAt) {
6342
+ if (isVector3(this.options.camera.lookingAt)) {
6343
+ this.camera.lookAt(this.options.camera.lookingAt);
6344
+ } else if (isTripleArray(this.options.camera.lookingAt)) {
6345
+ this.camera.lookAt(this.options.camera.lookingAt[0], this.options.camera.lookingAt[1], this.options.camera.lookingAt[2]);
6346
+ }
6347
+ }
6348
+ if (this.options.render.autoResize && !this._resizeListener) {
6349
+ this._resizeListener = () => {
6350
+ this.resize(this.viewWidth, this.viewHeight);
6351
+ };
6352
+ window.addEventListener("resize", this._resizeListener);
6353
+ }
6354
+ }
6355
+ get element() {
6356
+ return this._element;
6357
+ }
6358
+ appendTo(element) {
6359
+ if (this._disposed) return;
6360
+ this._element = element;
6361
+ this._element.appendChild(this.renderer.domElement);
6362
+ if (this.viewWidth == 0) {
6363
+ console.warn("0 element width");
6364
+ }
6365
+ if (this.viewHeight == 0) {
6366
+ console.warn("0 element height");
6367
+ }
6368
+ this.resize(this.viewWidth, this.viewHeight);
6369
+ }
6370
+ /**
6371
+ * Redraws when the dispatcher emits the selected event. Registering the same pair twice has no effect.
6372
+ * The renderer removes its listener on disposal; the caller retains ownership of the dispatcher.
6373
+ */
6374
+ registerEventDispatcher(dispatcher, changeEvent2 = "change") {
6375
+ if (this._disposed) return;
6376
+ let events = this._eventDispatchers.get(dispatcher);
6377
+ if (!events) {
6378
+ events = /* @__PURE__ */ new Set();
6379
+ this._eventDispatchers.set(dispatcher, events);
6380
+ }
6381
+ if (events.has(changeEvent2)) return;
6382
+ events.add(changeEvent2);
6383
+ dispatcher.addEventListener(changeEvent2, this._changeListener);
6384
+ }
6385
+ resize(width, height) {
6386
+ if (this._disposed) return;
6387
+ if (isPerspectiveCamera(this.camera)) {
6388
+ this.camera.aspect = width / height;
6389
+ this.camera.updateProjectionMatrix();
6390
+ } else if (isOrthographicCamera(this.camera)) {
6391
+ this.camera.left = width / -2;
6392
+ this.camera.right = width / 2;
6393
+ this.camera.top = height / 2;
6394
+ this.camera.bottom = height / -2;
6395
+ this.camera.updateProjectionMatrix();
6396
+ }
6397
+ this.renderer.setSize(width, height);
6398
+ this.composer?.setSize(width, height);
6399
+ this._dirty = true;
6400
+ }
6401
+ //<editor-fold desc="RENDER">
6402
+ get dirty() {
6403
+ return this._dirty || this.scene.dirty;
6404
+ }
6405
+ set dirty(dirty) {
6406
+ this._dirty = dirty;
6407
+ this.scene.dirty = dirty;
6408
+ }
6409
+ start() {
6410
+ if (this._disposed) return;
6411
+ this.stop();
6412
+ this.renderer.setAnimationLoop(this._animationLoop);
6413
+ }
6414
+ stop() {
6415
+ if (this._disposed) return;
6416
+ this.renderer.setAnimationLoop(null);
6417
+ this._nextFrameTime = void 0;
6418
+ }
6419
+ /**
6420
+ * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
6421
+ * renderer cannot be restarted. Scene objects are detached; shared assets and caller-owned
6422
+ * controls must be managed by their owners.
6423
+ */
6424
+ dispose() {
6425
+ if (this._disposed) return;
6426
+ this.stop();
6427
+ this._disposed = true;
6428
+ if (this._resizeListener) {
6429
+ window.removeEventListener("resize", this._resizeListener);
6430
+ this._resizeListener = void 0;
6431
+ }
6432
+ for (const [dispatcher, events] of this._eventDispatchers) {
6433
+ for (const event of events) {
6434
+ dispatcher.removeEventListener(event, this._changeListener);
6435
+ }
6436
+ }
6437
+ this._eventDispatchers.clear();
6438
+ this._stats?.dom.remove();
6439
+ this._stats = void 0;
6440
+ this.renderer.domElement.remove();
6441
+ this._element = void 0;
6442
+ if (this._controls) {
6443
+ const controls = this._controls;
6444
+ this._controls = void 0;
6445
+ controls.enabled = false;
6446
+ controls.dispose();
6447
+ }
6448
+ this.scene.clear();
6449
+ for (const helper of this._debugHelpers) {
6450
+ helper.geometry.dispose();
6451
+ const materials = Array.isArray(helper.material) ? helper.material : [helper.material];
6452
+ for (const material of materials) {
6453
+ material.dispose();
6454
+ }
6455
+ }
6456
+ this._debugHelpers.length = 0;
6457
+ this.composer?.dispose();
6458
+ this.renderer.dispose();
6459
+ this.renderer.forceContextLoss();
6460
+ }
6461
+ animate(t = performance.now()) {
6462
+ if (this._disposed) return;
6463
+ if (this._controls?.enabled) {
6464
+ this._controls.update();
6465
+ }
6466
+ if (this._disposed) return;
6467
+ if (!this.dirty && !this.options.render.renderAlways) return;
6468
+ const interval = this._frameInterval;
6469
+ if (interval) {
6470
+ const next = this._nextFrameTime;
6471
+ if (next !== void 0 && t + 0.1 < next) return;
6472
+ this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
6473
+ }
6474
+ if (this._stats) {
6475
+ this._stats.begin();
6476
+ }
6477
+ if (this.options.composer.enabled && this.composer) {
6478
+ this.composer.render();
6479
+ } else {
6480
+ this.renderer.render(this.scene, this.camera);
6481
+ }
6482
+ this.dirty = false;
6483
+ if (this._stats) {
6484
+ this._stats.end();
6485
+ }
6486
+ }
6487
+ //</editor-fold>
6488
+ toImage() {
6489
+ return this.renderer.domElement.toDataURL();
6490
+ }
6491
+ ///
6492
+ get attachedToBody() {
6493
+ return this.element === document.body;
6494
+ }
6495
+ get viewWidth() {
6496
+ return this.attachedToBody ? window.innerWidth : this.element?.offsetWidth || 0;
6497
+ }
6498
+ get viewHeight() {
6499
+ return this.attachedToBody ? window.innerHeight : this.element?.offsetHeight || 0;
6500
+ }
6501
+ get scene() {
6502
+ return this._scene;
6503
+ }
6504
+ get camera() {
6505
+ return this._camera;
6506
+ }
6507
+ get renderer() {
6508
+ return this._renderer;
6509
+ }
6510
+ get composer() {
6511
+ return this._composer;
6512
+ }
6513
+ /** Renderer-owned controls, or undefined when disabled at construction or after disposal. */
6514
+ get controls() {
6515
+ return this._controls;
6516
+ }
6517
+ ///
6518
+ };
6519
+
6520
+ // src/skin/Skins.ts
6521
+ var Skins = class {
6522
+ //<editor-fold desc="Skins">
6523
+ static async fromUuidOrUsername(uuidOrUsername) {
6524
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6525
+ return this.fromUuid(uuidOrUsername);
6526
+ }
6527
+ return this.fromUsername(uuidOrUsername);
6528
+ }
6529
+ static async fromUuid(uuid) {
6530
+ return this.getSkinProxySkinUrl(uuid);
6531
+ }
6532
+ static async fromUsername(username) {
6533
+ return this.usernameToUuid(username).then((uuid) => {
6534
+ if (uuid) {
6535
+ return this.fromUuid(uuid);
6536
+ }
6537
+ return void 0;
6538
+ });
6539
+ }
6540
+ static async fromMineSkin(mineskinId) {
6541
+ return this.getMineSkin(mineskinId).then((mineskin) => {
6542
+ if (mineskin) {
6543
+ return mineskin["data"]["texture"]["value"]["urls"]["skins"];
6544
+ }
6545
+ return void 0;
6546
+ });
6547
+ }
6548
+ //</editor-fold>
6549
+ //<editor-fold desc="Capes">
6550
+ static async capeFromUuidOrUsername(uuidOrUsername) {
6551
+ if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
6552
+ return this.capeFromUuid(uuidOrUsername);
6553
+ }
6554
+ return this.capeFromUsername(uuidOrUsername);
6555
+ }
6556
+ static async capeFromUuid(uuid) {
6557
+ return this.getSkinProxyCapeUrl(uuid);
6558
+ }
6559
+ static async capeFromUsername(username) {
6560
+ return this.usernameToUuid(username).then((uuid) => {
6561
+ if (uuid) {
6562
+ return this.capeFromUuid(uuid);
6563
+ }
6564
+ return void 0;
6565
+ });
6566
+ }
6567
+ static async capeFromCapesDev(uuid, capeType = "minecraft") {
6568
+ return this.getCapesDev(uuid, capeType).then((cape) => {
6569
+ if (cape) {
6570
+ return cape?.stillImageUrl;
6571
+ }
6572
+ return void 0;
6573
+ });
6574
+ }
6575
+ //</editor-fold>
6576
+ //<editor-fold desc="Helpers">
6577
+ static async usernameToUuid(username) {
6578
+ return this.usernameToUuidSkinProxy(username);
6579
+ }
6580
+ static async usernameToUuidSkinProxy(username) {
6581
+ return Requests.genericRequest({
6582
+ baseURL: "https://minecraft-skin-proxy.inventive.workers.dev",
6583
+ url: "/uuid/" + username
6584
+ }).then((res) => {
6585
+ if (res.status === 200) {
6586
+ return res.data["id"];
6587
+ }
6588
+ return void 0;
6589
+ }).catch((err) => {
6590
+ console.warn(err);
6591
+ return void 0;
6592
+ });
6593
+ }
6594
+ static async usernameToUuidMineTools(username) {
6595
+ return Requests.genericRequest({
6596
+ baseURL: "https://api.minetools.eu",
6597
+ url: "/uuid/" + username
6598
+ }).then((res) => {
6599
+ if (res.status === 200) {
6600
+ return res.data["id"];
6601
+ }
6602
+ return void 0;
6603
+ }).catch((err) => {
6604
+ console.warn(err);
6605
+ return void 0;
6606
+ });
6607
+ }
6608
+ static async getProfileFromMinetools(uuid) {
6609
+ return Requests.genericRequest({
6610
+ baseURL: "https://api.minetools.eu",
6611
+ url: "/profile/" + uuid
6612
+ }).then((res) => {
6613
+ if (res.status === 200) {
6614
+ return res.data;
6615
+ }
6616
+ });
6617
+ }
6618
+ static async getMineSkin(mineskinId) {
6619
+ return Requests.genericRequest({
6620
+ baseURL: "https://api.mineskin.org",
6621
+ url: "/get/uuid/" + mineskinId
6622
+ }).then((res) => {
6623
+ if (res.status === 200) {
6624
+ return res.data;
6625
+ }
6626
+ return void 0;
6627
+ }).catch((err) => {
6628
+ console.warn(err);
6629
+ return void 0;
6630
+ });
6631
+ }
6632
+ static async getCapesDev(uuid, type = "all") {
6633
+ return Requests.genericRequest({
6634
+ baseURL: "https://api.capes.dev",
6635
+ url: "/load/" + uuid + "/" + type
6636
+ }).then((res) => {
6637
+ if (res.status === 200) {
6638
+ return res.data;
6639
+ }
6640
+ return void 0;
6641
+ }).catch((err) => {
6642
+ console.warn(err);
6643
+ return void 0;
6644
+ });
6645
+ }
6646
+ static getCrafatarSkinUrl(uuid) {
6647
+ return "https://crafatar.com/skins/" + uuid;
6648
+ }
6649
+ static getCrafatarCapeUrl(uuid) {
6650
+ return "https://crafatar.com/capes/" + uuid;
6651
+ }
6652
+ static getMcHeadsSkinUrl(uuid) {
6653
+ return "https://mc-heads.net/skin/" + uuid;
6654
+ }
6655
+ static getMineSkinPlayerSkinUrl(uuid) {
6656
+ return "https://mineskin.org/skin/player/" + uuid;
6657
+ }
6658
+ static getSkinProxySkinUrl(uuid) {
6659
+ return "https://minecraft-skin-proxy.inventive.workers.dev/skin/" + uuid;
6660
+ }
6661
+ static getSkinProxyCapeUrl(uuid) {
6662
+ return "https://minecraft-skin-proxy.inventive.workers.dev/cape/" + uuid;
6663
+ }
6664
+ //</editor-fold>
6665
+ };
6666
+
6387
6667
  // src/world/Chunk.ts
6388
6668
  import { Box3 as Box32, Object3D as Object3D6, Vector3 as Vector310 } from "three";
6389
6669
 
@@ -6444,7 +6724,7 @@ var MineRenderWorld = class {
6444
6724
  console.log("CHUNKS", this._chunks);
6445
6725
  for (let chunk of this._chunks.values()) {
6446
6726
  console.log("dispose chunk", chunk);
6447
- await (chunk == null ? void 0 : chunk.dispose());
6727
+ await chunk?.dispose();
6448
6728
  }
6449
6729
  this._chunks.clear();
6450
6730
  }
@@ -6498,7 +6778,7 @@ var MineRenderWorld = class {
6498
6778
  };
6499
6779
 
6500
6780
  // src/world/Chunk.ts
6501
- var p12 = prefix("Chunk");
6781
+ var p11 = prefix("Chunk");
6502
6782
  var Chunk = class _Chunk {
6503
6783
  constructor(scene, x, y, z) {
6504
6784
  this._blocks = [];
@@ -6550,7 +6830,7 @@ var Chunk = class _Chunk {
6550
6830
  const index = _Chunk.chunkPosToBlockIndex(pos);
6551
6831
  const current = this._blocks[index];
6552
6832
  if (typeof current !== "undefined") {
6553
- console.debug(p12, "deleting existing block at", pos, worldPos, index);
6833
+ console.debug(p11, "deleting existing block at", pos, worldPos, index);
6554
6834
  current.object.removeFromScene();
6555
6835
  delete this._blocks[index];
6556
6836
  }
@@ -6616,6 +6896,7 @@ export {
6616
6896
  AXES,
6617
6897
  ArchiveAssetSource,
6618
6898
  AssetKey,
6899
+ AssetLoadError,
6619
6900
  AssetLoader,
6620
6901
  AssetParser,
6621
6902
  AssetSource,
@@ -6673,6 +6954,7 @@ export {
6673
6954
  OrbitControls,
6674
6955
  PersistentCache,
6675
6956
  Renderer,
6957
+ RequestError,
6676
6958
  Requests,
6677
6959
  SKIN_PARTS,
6678
6960
  SceneInspector,