minerender 2.1.0-alpha.7 → 2.1.0-alpha.9

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({
@@ -154,11 +146,14 @@ var _PersistentCache = class _PersistentCache {
154
146
  static open(name) {
155
147
  return Env.provider.openCache(name, _PersistentCache.VERSION);
156
148
  }
149
+ /** Loads a missing entry and stores only non-nullish results. */
157
150
  async getOrLoad(key, loader) {
158
151
  let v = await this.get(key);
159
152
  if (typeof v === "undefined" || v === null) {
160
153
  v = await loader(key);
161
- await this.put(key, v);
154
+ if (typeof v !== "undefined" && v !== null) {
155
+ await this.put(key, v);
156
+ }
162
157
  }
163
158
  return v;
164
159
  }
@@ -394,7 +389,10 @@ function serializeMeshKey(key) {
394
389
  // src/cache/Caching.ts
395
390
  import { Caches } from "@inventivetalent/loading-cache";
396
391
  import { Time } from "@inventivetalent/time";
397
- var Caching = class {
392
+ var _Caching = class _Caching {
393
+ static createAssetCache() {
394
+ return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
395
+ }
398
396
  /** Every cache above, so clear()/end() can never fall out of sync with the field list again. */
399
397
  static get all() {
400
398
  return [
@@ -411,7 +409,10 @@ var Caching = class {
411
409
  this.rawModelCache,
412
410
  this.mergedModelCache,
413
411
  this.modelTextureAtlasCache,
414
- this.blockStateCache
412
+ this.blockStateCache,
413
+ this.listAssetCache,
414
+ this.defaultBlockStatesCache,
415
+ this.entityModelsCache
415
416
  ];
416
417
  }
417
418
  static clear() {
@@ -437,20 +438,24 @@ var Caching = class {
437
438
  };
438
439
  }
439
440
  };
440
- Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
441
- Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
442
- Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
443
- Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
444
- Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
445
- Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
446
- Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
447
- Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
448
- Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
449
- Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
450
- Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
451
- Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
452
- Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
453
- Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
441
+ _Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
442
+ _Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
443
+ _Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
444
+ _Caching.wrappedImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
445
+ _Caching.boxGeometryCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(20)).build();
446
+ _Caching.textureCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
447
+ _Caching.materialCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
448
+ _Caching.boxMeshCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).build();
449
+ _Caching.textureAssetCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
450
+ _Caching.textureMetaCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
451
+ _Caching.rawModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
452
+ _Caching.mergedModelCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
453
+ _Caching.modelTextureAtlasCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
454
+ _Caching.blockStateCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
455
+ _Caching.listAssetCache = _Caching.createAssetCache();
456
+ _Caching.defaultBlockStatesCache = _Caching.createAssetCache();
457
+ _Caching.entityModelsCache = _Caching.createAssetCache();
458
+ var Caching = _Caching;
454
459
 
455
460
  // src/Geometries.ts
456
461
  var Geometries = class _Geometries {
@@ -758,29 +763,41 @@ var ImageLoader = class _ImageLoader {
758
763
  static async loadAsync(src) {
759
764
  return new Promise((resolve, reject) => {
760
765
  const image = this._createImage();
761
- image.src = src;
762
766
  image.onload = () => resolve(image);
763
- image.onerror = (err) => reject(err);
767
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
768
+ image.src = src;
764
769
  });
765
770
  }
766
771
  static loadElement(src, onload, onerr) {
767
772
  const image = this._createImage();
768
- image.src = src;
769
773
  if (onload)
770
774
  image.onload = onload;
771
775
  if (onerr)
772
776
  image.onerror = onerr;
777
+ image.src = src;
773
778
  return image;
774
779
  }
775
780
  static async loadData(src) {
776
781
  console.debug(p2, "loadData", src);
777
- return await this.infoToData(await this.getInfo(src));
782
+ const image = await this.loadCanvasData(src);
783
+ return image.data.getImageData(0, 0, image.width, image.height);
778
784
  }
779
785
  static async loadCanvasData(src) {
780
- return await this.infoToCanvasData(await this.getInfo(src));
786
+ const keyStr = serializeImageKey({ src });
787
+ const info = this.getInfo(src);
788
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
789
+ try {
790
+ return await this.infoToCanvasData(await info);
791
+ } catch (err) {
792
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
793
+ Caching.rawImageCache.invalidate(keyStr);
794
+ }
795
+ throw err;
796
+ }
781
797
  }
782
798
  static async infoToCanvasData(info) {
783
- const image = await _ImageLoader.loadAsync(info.src);
799
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
800
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
784
801
  const canvas = createCanvas(info.width, info.height);
785
802
  const context = canvas.getContext("2d");
786
803
  context.drawImage(image, 0, 0);
@@ -791,11 +808,8 @@ var ImageLoader = class _ImageLoader {
791
808
  };
792
809
  }
793
810
  static async infoToData(info) {
794
- const image = await _ImageLoader.loadAsync(info.src);
795
- const canvas = createCanvas(info.width, info.height);
796
- const context = canvas.getContext("2d");
797
- context.drawImage(image, 0, 0);
798
- return context.getImageData(0, 0, canvas.width, canvas.height);
811
+ const image = await this.infoToCanvasData(info);
812
+ return image.data.getImageData(0, 0, image.width, image.height);
799
813
  }
800
814
  static async getData(src) {
801
815
  const keyStr = serializeImageKey({ src });
@@ -810,13 +824,16 @@ var ImageLoader = class _ImageLoader {
810
824
  });
811
825
  }
812
826
  static async processResponse(response) {
813
- const src = response.config.url;
827
+ const src = response.config?.url;
814
828
  const data = Buffer2.from(response.data);
815
829
  const { width, height, type } = Env.provider.imageSize(data);
830
+ if (!width || !height) {
831
+ throw new Error("Invalid or unsupported image dimensions");
832
+ }
816
833
  return {
817
834
  src,
818
- width: width || 0,
819
- height: height || 0,
835
+ width,
836
+ height,
820
837
  type,
821
838
  data
822
839
  };
@@ -833,15 +850,7 @@ var ImageLoader = class _ImageLoader {
833
850
  return Requests.genericRequest({
834
851
  url: src,
835
852
  responseType: "arraybuffer"
836
- }).then(this.processResponse).catch((err) => {
837
- return {
838
- src,
839
- width: 0,
840
- height: 0,
841
- type: void 0,
842
- data: Buffer2.from([0])
843
- };
844
- });
853
+ }).then(this.processResponse);
845
854
  }
846
855
  static async getInfo(src) {
847
856
  const keyStr = serializeImageKey({ src });
@@ -863,16 +872,22 @@ var ImageLoader = class _ImageLoader {
863
872
 
864
873
  // src/texture/TextureLoader.ts
865
874
  var TextureLoader = class {
875
+ /** Reports whether image loading failed, so cached textures can be retried. */
876
+ static hasFailed(texture) {
877
+ return this.failedTextures.has(texture);
878
+ }
866
879
  static createTexture() {
867
880
  return new Texture();
868
881
  }
869
882
  static loadInBackground(src, format = RGBAFormat, rotation = 0) {
870
883
  const texture = this.createTexture();
871
884
  texture.colorSpace = THREE.SRGBColorSpace;
872
- const image = ImageLoader.loadElement(src);
873
- image.onload = function() {
885
+ const image = ImageLoader.loadElement(src, () => {
874
886
  texture.needsUpdate = true;
875
- };
887
+ }, (error) => {
888
+ this.failedTextures.add(texture);
889
+ console.warn("Failed to load texture", src, error);
890
+ });
876
891
  texture.image = image;
877
892
  texture.format = format;
878
893
  texture.rotation = rotation;
@@ -882,14 +897,18 @@ var TextureLoader = class {
882
897
  const texture = new Texture();
883
898
  texture.colorSpace = THREE.SRGBColorSpace;
884
899
  ImageLoader.getData(src).then((image) => {
885
- texture.needsUpdate = true;
886
900
  texture.image = image;
901
+ texture.needsUpdate = true;
902
+ }).catch((error) => {
903
+ this.failedTextures.add(texture);
904
+ console.warn("Failed to load texture", src, error);
887
905
  });
888
906
  texture.format = format;
889
907
  texture.rotation = rotation;
890
908
  return Textures.initTextureProps(texture);
891
909
  }
892
910
  };
911
+ TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
893
912
 
894
913
  // src/texture/Textures.ts
895
914
  import * as THREE2 from "three";
@@ -913,6 +932,10 @@ var Textures = class _Textures {
913
932
  }
914
933
  static getImage(key) {
915
934
  const keyStr = serializeTextureKey(key);
935
+ const cached = Caching.textureCache.peek(keyStr);
936
+ if (cached && TextureLoader.hasFailed(cached)) {
937
+ Caching.textureCache.invalidate(keyStr);
938
+ }
916
939
  return Caching.textureCache.get(keyStr, (k) => {
917
940
  return _Textures.createImage(key);
918
941
  });
@@ -1057,6 +1080,10 @@ var _Materials = class _Materials {
1057
1080
  }
1058
1081
  static getImage(key) {
1059
1082
  const keyStr = serializeMaterialKey(key);
1083
+ const map = Caching.materialCache.peek(keyStr)?.map;
1084
+ if (map && TextureLoader.hasFailed(map)) {
1085
+ Caching.materialCache.invalidate(keyStr);
1086
+ }
1060
1087
  return Caching.materialCache.get(keyStr, (k) => {
1061
1088
  return _Materials.createImage(key);
1062
1089
  });
@@ -1210,9 +1237,6 @@ var ModelMerger = class {
1210
1237
  }
1211
1238
  };
1212
1239
 
1213
- // src/assets/Models.ts
1214
- import { Memoize } from "typescript-memoize";
1215
-
1216
1240
  // src/assets/source/parser/AssetParsers.ts
1217
1241
  var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1218
1242
  AssetParser2["MODEL"] = "model";
@@ -1226,14 +1250,14 @@ var AssetParser = /* @__PURE__ */ ((AssetParser2) => {
1226
1250
  })(AssetParser || {});
1227
1251
 
1228
1252
  // src/assets/Models.ts
1229
- var _Models = class _Models {
1253
+ var Models = class _Models {
1230
1254
  // opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
1231
1255
  // the library, and would require an EnvProvider before any entry has had a chance to register
1232
1256
  static get PERSISTENT_CACHE() {
1233
1257
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
1234
1258
  }
1235
1259
  static async getItemList() {
1236
- return AssetLoader.get(new AssetKey(
1260
+ const key = new AssetKey(
1237
1261
  DEFAULT_NAMESPACE,
1238
1262
  "_list",
1239
1263
  "models",
@@ -1241,7 +1265,10 @@ var _Models = class _Models {
1241
1265
  "assets",
1242
1266
  ".json",
1243
1267
  DEFAULT_ROOT
1244
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1268
+ );
1269
+ return Caching.listAssetCache.get(key.serialize(), () => {
1270
+ return AssetLoader.get(key, "list" /* LIST */);
1271
+ }).then((r) => r?.files ?? []);
1245
1272
  }
1246
1273
  static async loadAndMerge(key) {
1247
1274
  const model = await this.getRaw(key);
@@ -1288,19 +1315,15 @@ var _Models = class _Models {
1288
1315
  return this.PERSISTENT_CACHE.clear();
1289
1316
  }
1290
1317
  };
1291
- __decorateClass([
1292
- Memoize()
1293
- ], _Models, "getItemList", 1);
1294
- var Models = _Models;
1295
1318
 
1296
1319
  // src/assets/BlockStates.ts
1297
- import { Memoize as Memoize2 } from "typescript-memoize";
1298
1320
  var BlockStates = class {
1299
1321
  static get PERSISTENT_CACHE() {
1300
1322
  return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
1301
1323
  }
1324
+ // BlockState names are hardcoded
1302
1325
  static async getList() {
1303
- return AssetLoader.get(new AssetKey(
1326
+ const key = new AssetKey(
1304
1327
  DEFAULT_NAMESPACE,
1305
1328
  "_list",
1306
1329
  "blockstates",
@@ -1308,11 +1331,16 @@ var BlockStates = class {
1308
1331
  "assets",
1309
1332
  ".json",
1310
1333
  DEFAULT_ROOT
1311
- ), "list" /* LIST */).then((r) => r?.files ?? []);
1334
+ );
1335
+ return Caching.listAssetCache.get(key.serialize(), () => {
1336
+ return AssetLoader.get(key, "list" /* LIST */);
1337
+ }).then((r) => r?.files ?? []);
1312
1338
  }
1313
1339
  static async getDefaultStates() {
1314
1340
  const key = AssetKey.parse("blockstates", "minerender:defaultBlockStates");
1315
- return AssetLoader.get(key, "json" /* JSON */);
1341
+ return Caching.defaultBlockStatesCache.get(key.serialize(), () => {
1342
+ return AssetLoader.get(key, "json" /* JSON */);
1343
+ });
1316
1344
  }
1317
1345
  static async getDefaultState(key) {
1318
1346
  const defaultStates = await this.getDefaultStates();
@@ -1351,12 +1379,6 @@ var BlockStates = class {
1351
1379
  await this.PERSISTENT_CACHE.clear();
1352
1380
  }
1353
1381
  };
1354
- __decorateClass([
1355
- Memoize2()
1356
- ], BlockStates, "getList", 1);
1357
- __decorateClass([
1358
- Memoize2()
1359
- ], BlockStates, "getDefaultStates", 1);
1360
1382
  var DefaultBlockStates = class {
1361
1383
  };
1362
1384
 
@@ -1714,11 +1736,21 @@ var ModelTextures = class {
1714
1736
  return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
1715
1737
  }
1716
1738
  static async get(key) {
1717
- const asset = await this.preload(key);
1718
- if (asset) {
1719
- return ImageLoader.infoToCanvasData(asset);
1739
+ const keyStr = key.serialize();
1740
+ const pending = this.preload(key);
1741
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1742
+ try {
1743
+ const asset = await pending;
1744
+ if (asset) {
1745
+ return await ImageLoader.infoToCanvasData(asset);
1746
+ }
1747
+ return void 0;
1748
+ } catch (err) {
1749
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
1750
+ Caching.textureAssetCache.invalidate(keyStr);
1751
+ }
1752
+ throw err;
1720
1753
  }
1721
- return void 0;
1722
1754
  }
1723
1755
  static async preload(key) {
1724
1756
  const keyStr = key.serialize();
@@ -2396,17 +2428,20 @@ function shutdown() {
2396
2428
  }
2397
2429
 
2398
2430
  // src/assets/Entities.ts
2399
- import { Memoize as Memoize3 } from "typescript-memoize";
2400
2431
  var Entities = class {
2401
2432
  static async getBlockEntityModels() {
2402
2433
  const key = AssetKey.parse("models", "minerender:blockEntityModels");
2403
2434
  console.log(key);
2404
- return AssetLoader.get(key, "json" /* JSON */);
2435
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2436
+ return AssetLoader.get(key, "json" /* JSON */);
2437
+ });
2405
2438
  }
2406
2439
  static async getEntityModels() {
2407
2440
  const key = AssetKey.parse("models", "minerender:entityModels");
2408
2441
  console.log(key);
2409
- return AssetLoader.get(key, "json" /* JSON */);
2442
+ return Caching.entityModelsCache.get(key.serialize(), () => {
2443
+ return AssetLoader.get(key, "json" /* JSON */);
2444
+ });
2410
2445
  }
2411
2446
  // BlockEntity names are hardcoded
2412
2447
  static async getBlockList() {
@@ -2452,12 +2487,6 @@ var Entities = class {
2452
2487
  };
2453
2488
  }
2454
2489
  };
2455
- __decorateClass([
2456
- Memoize3()
2457
- ], Entities, "getBlockEntityModels", 1);
2458
- __decorateClass([
2459
- Memoize3()
2460
- ], Entities, "getEntityModels", 1);
2461
2490
  var EntityModels = class {
2462
2491
  };
2463
2492
  var BlockEntityModels = class {
@@ -2909,8 +2938,8 @@ var EntityObject = class extends SceneObject {
2909
2938
  dispose() {
2910
2939
  super.dispose();
2911
2940
  }
2912
- async loadTextures() {
2913
- this.imageData = await ModelTextures.get(new AssetKey(
2941
+ get textureKey() {
2942
+ return new AssetKey(
2914
2943
  this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2915
2944
  this.entity.key.path,
2916
2945
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
@@ -2918,7 +2947,10 @@ var EntityObject = class extends SceneObject {
2918
2947
  "entity",
2919
2948
  "assets",
2920
2949
  ".png"
2921
- ));
2950
+ );
2951
+ }
2952
+ async loadTextures() {
2953
+ this.imageData = await ModelTextures.get(this.textureKey);
2922
2954
  }
2923
2955
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2924
2956
  createMeshes(force = false) {
@@ -2951,20 +2983,23 @@ var EntityObject = class extends SceneObject {
2951
2983
  this.meshesCreated = true;
2952
2984
  }
2953
2985
  async applyTextures() {
2954
- const textureAsset = await ModelTextures.preload(new AssetKey(
2955
- this.entity.key?.namespace ?? DEFAULT_NAMESPACE,
2956
- this.entity.key.path,
2957
- "textures",
2958
- "entity",
2959
- "assets",
2960
- ".png"
2961
- ));
2962
- if (textureAsset) {
2963
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
2964
- this.iterateAllMeshes((mesh) => {
2965
- mesh.material = mat;
2966
- });
2967
- }
2986
+ const assetKeyStr = this.textureKey.serialize();
2987
+ const keyStr = `entity:${assetKeyStr}`;
2988
+ let mat = Caching.materialCache.getIfPresent(keyStr);
2989
+ if (!mat) {
2990
+ const pending = this.loadTextures();
2991
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
2992
+ await pending;
2993
+ if (!this.imageData) return;
2994
+ const canvas = this.imageData.data.canvas;
2995
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
2996
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
2997
+ this.imageData = void 0;
2998
+ }
2999
+ this.iterateAllMeshes((mesh) => {
3000
+ mesh.material = mat;
3001
+ });
3002
+ this.notifyDirty();
2968
3003
  }
2969
3004
  };
2970
3005
  EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});