minerender 2.1.0-alpha.7 → 2.1.0-alpha.8

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.
@@ -721,29 +721,41 @@ var ImageLoader = class _ImageLoader {
721
721
  static async loadAsync(src) {
722
722
  return new Promise((resolve, reject) => {
723
723
  const image = this._createImage();
724
- image.src = src;
725
724
  image.onload = () => resolve(image);
726
- image.onerror = (err) => reject(err);
725
+ image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
726
+ image.src = src;
727
727
  });
728
728
  }
729
729
  static loadElement(src, onload, onerr) {
730
730
  const image = this._createImage();
731
- image.src = src;
732
731
  if (onload)
733
732
  image.onload = onload;
734
733
  if (onerr)
735
734
  image.onerror = onerr;
735
+ image.src = src;
736
736
  return image;
737
737
  }
738
738
  static async loadData(src) {
739
739
  console.debug(p2, "loadData", src);
740
- return await this.infoToData(await this.getInfo(src));
740
+ const image = await this.loadCanvasData(src);
741
+ return image.data.getImageData(0, 0, image.width, image.height);
741
742
  }
742
743
  static async loadCanvasData(src) {
743
- return await this.infoToCanvasData(await this.getInfo(src));
744
+ const keyStr = serializeImageKey({ src });
745
+ const info = this.getInfo(src);
746
+ const cached = Caching.rawImageCache.getIfPresent(keyStr);
747
+ try {
748
+ return await this.infoToCanvasData(await info);
749
+ } catch (err) {
750
+ if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
751
+ Caching.rawImageCache.invalidate(keyStr);
752
+ }
753
+ throw err;
754
+ }
744
755
  }
745
756
  static async infoToCanvasData(info) {
746
- const image = await _ImageLoader.loadAsync(info.src);
757
+ const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
758
+ const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
747
759
  const canvas = createCanvas2(info.width, info.height);
748
760
  const context = canvas.getContext("2d");
749
761
  context.drawImage(image, 0, 0);
@@ -754,11 +766,8 @@ var ImageLoader = class _ImageLoader {
754
766
  };
755
767
  }
756
768
  static async infoToData(info) {
757
- const image = await _ImageLoader.loadAsync(info.src);
758
- const canvas = createCanvas2(info.width, info.height);
759
- const context = canvas.getContext("2d");
760
- context.drawImage(image, 0, 0);
761
- return context.getImageData(0, 0, canvas.width, canvas.height);
769
+ const image = await this.infoToCanvasData(info);
770
+ return image.data.getImageData(0, 0, image.width, image.height);
762
771
  }
763
772
  static async getData(src) {
764
773
  const keyStr = serializeImageKey({ src });
@@ -773,13 +782,17 @@ var ImageLoader = class _ImageLoader {
773
782
  });
774
783
  }
775
784
  static async processResponse(response) {
776
- const src = response.config.url;
785
+ var _a;
786
+ const src = (_a = response.config) == null ? void 0 : _a.url;
777
787
  const data = Buffer2.from(response.data);
778
788
  const { width, height, type } = Env.provider.imageSize(data);
789
+ if (!width || !height) {
790
+ throw new Error("Invalid or unsupported image dimensions");
791
+ }
779
792
  return {
780
793
  src,
781
- width: width || 0,
782
- height: height || 0,
794
+ width,
795
+ height,
783
796
  type,
784
797
  data
785
798
  };
@@ -796,15 +809,7 @@ var ImageLoader = class _ImageLoader {
796
809
  return Requests.genericRequest({
797
810
  url: src,
798
811
  responseType: "arraybuffer"
799
- }).then(this.processResponse).catch((err) => {
800
- return {
801
- src,
802
- width: 0,
803
- height: 0,
804
- type: void 0,
805
- data: Buffer2.from([0])
806
- };
807
- });
812
+ }).then(this.processResponse);
808
813
  }
809
814
  static async getInfo(src) {
810
815
  const keyStr = serializeImageKey({ src });
@@ -826,16 +831,22 @@ var ImageLoader = class _ImageLoader {
826
831
 
827
832
  // src/texture/TextureLoader.ts
828
833
  var TextureLoader = class {
834
+ /** Reports whether image loading failed, so cached textures can be retried. */
835
+ static hasFailed(texture) {
836
+ return this.failedTextures.has(texture);
837
+ }
829
838
  static createTexture() {
830
839
  return new Texture();
831
840
  }
832
841
  static loadInBackground(src, format = RGBAFormat, rotation = 0) {
833
842
  const texture = this.createTexture();
834
843
  texture.colorSpace = THREE.SRGBColorSpace;
835
- const image = ImageLoader.loadElement(src);
836
- image.onload = function() {
844
+ const image = ImageLoader.loadElement(src, () => {
837
845
  texture.needsUpdate = true;
838
- };
846
+ }, (error) => {
847
+ this.failedTextures.add(texture);
848
+ console.warn("Failed to load texture", src, error);
849
+ });
839
850
  texture.image = image;
840
851
  texture.format = format;
841
852
  texture.rotation = rotation;
@@ -845,14 +856,18 @@ var TextureLoader = class {
845
856
  const texture = new Texture();
846
857
  texture.colorSpace = THREE.SRGBColorSpace;
847
858
  ImageLoader.getData(src).then((image) => {
848
- texture.needsUpdate = true;
849
859
  texture.image = image;
860
+ texture.needsUpdate = true;
861
+ }).catch((error) => {
862
+ this.failedTextures.add(texture);
863
+ console.warn("Failed to load texture", src, error);
850
864
  });
851
865
  texture.format = format;
852
866
  texture.rotation = rotation;
853
867
  return Textures.initTextureProps(texture);
854
868
  }
855
869
  };
870
+ TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
856
871
 
857
872
  // src/texture/Textures.ts
858
873
  import * as THREE2 from "three";
@@ -876,6 +891,10 @@ var Textures = class _Textures {
876
891
  }
877
892
  static getImage(key) {
878
893
  const keyStr = serializeTextureKey(key);
894
+ const cached = Caching.textureCache.peek(keyStr);
895
+ if (cached && TextureLoader.hasFailed(cached)) {
896
+ Caching.textureCache.invalidate(keyStr);
897
+ }
879
898
  return Caching.textureCache.get(keyStr, (k) => {
880
899
  return _Textures.createImage(key);
881
900
  });
@@ -1019,7 +1038,12 @@ var _Materials = class _Materials {
1019
1038
  return this.createBasicCanvasMaterial(canvas, transparent, shade);
1020
1039
  }
1021
1040
  static getImage(key) {
1041
+ var _a;
1022
1042
  const keyStr = serializeMaterialKey(key);
1043
+ const map = (_a = Caching.materialCache.peek(keyStr)) == null ? void 0 : _a.map;
1044
+ if (map && TextureLoader.hasFailed(map)) {
1045
+ Caching.materialCache.invalidate(keyStr);
1046
+ }
1023
1047
  return Caching.materialCache.get(keyStr, (k) => {
1024
1048
  return _Materials.createImage(key);
1025
1049
  });
@@ -1677,11 +1701,21 @@ var ModelTextures = class {
1677
1701
  return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
1678
1702
  }
1679
1703
  static async get(key) {
1680
- const asset = await this.preload(key);
1681
- if (asset) {
1682
- return ImageLoader.infoToCanvasData(asset);
1704
+ const keyStr = key.serialize();
1705
+ const pending = this.preload(key);
1706
+ const cached = Caching.textureAssetCache.getIfPresent(keyStr);
1707
+ try {
1708
+ const asset = await pending;
1709
+ if (asset) {
1710
+ return await ImageLoader.infoToCanvasData(asset);
1711
+ }
1712
+ return void 0;
1713
+ } catch (err) {
1714
+ if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
1715
+ Caching.textureAssetCache.invalidate(keyStr);
1716
+ }
1717
+ throw err;
1683
1718
  }
1684
- return void 0;
1685
1719
  }
1686
1720
  static async preload(key) {
1687
1721
  const keyStr = key.serialize();
@@ -2875,9 +2909,9 @@ var EntityObject = class extends SceneObject {
2875
2909
  dispose() {
2876
2910
  super.dispose();
2877
2911
  }
2878
- async loadTextures() {
2912
+ get textureKey() {
2879
2913
  var _a;
2880
- this.imageData = await ModelTextures.get(new AssetKey(
2914
+ return new AssetKey(
2881
2915
  ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
2882
2916
  this.entity.key.path,
2883
2917
  //TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
@@ -2885,7 +2919,10 @@ var EntityObject = class extends SceneObject {
2885
2919
  "entity",
2886
2920
  "assets",
2887
2921
  ".png"
2888
- ));
2922
+ );
2923
+ }
2924
+ async loadTextures() {
2925
+ this.imageData = await ModelTextures.get(this.textureKey);
2889
2926
  }
2890
2927
  //TODO: abstract this, since extracted model data can be used for entities, blocks, players
2891
2928
  createMeshes(force = false) {
@@ -2918,21 +2955,23 @@ var EntityObject = class extends SceneObject {
2918
2955
  this.meshesCreated = true;
2919
2956
  }
2920
2957
  async applyTextures() {
2921
- var _a;
2922
- const textureAsset = await ModelTextures.preload(new AssetKey(
2923
- ((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
2924
- this.entity.key.path,
2925
- "textures",
2926
- "entity",
2927
- "assets",
2928
- ".png"
2929
- ));
2930
- if (textureAsset) {
2931
- let mat = Materials.getImage({ texture: { src: textureAsset.src } });
2932
- this.iterateAllMeshes((mesh) => {
2933
- mesh.material = mat;
2934
- });
2935
- }
2958
+ const assetKeyStr = this.textureKey.serialize();
2959
+ const keyStr = `entity:${assetKeyStr}`;
2960
+ let mat = Caching.materialCache.getIfPresent(keyStr);
2961
+ if (!mat) {
2962
+ const pending = this.loadTextures();
2963
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
2964
+ await pending;
2965
+ if (!this.imageData) return;
2966
+ const canvas = this.imageData.data.canvas;
2967
+ const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
2968
+ mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
2969
+ this.imageData = void 0;
2970
+ }
2971
+ this.iterateAllMeshes((mesh) => {
2972
+ mesh.material = mat;
2973
+ });
2974
+ this.notifyDirty();
2936
2975
  }
2937
2976
  };
2938
2977
  EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});