minerender 2.1.0-alpha.6 → 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.
- package/dist/browser/index.d.mts +15 -11
- package/dist/browser/index.d.ts +15 -11
- package/dist/browser/index.js +93 -54
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +93 -54
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +1340 -1088
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +14 -10
- package/dist/node/index.d.ts +14 -10
- package/dist/node/index.js +95 -55
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +95 -55
- package/dist/node/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/node/index.d.mts
CHANGED
|
@@ -535,14 +535,13 @@ declare class MinecraftFaceUV {
|
|
|
535
535
|
}
|
|
536
536
|
|
|
537
537
|
/**
|
|
538
|
-
*
|
|
538
|
+
* Stops the shared Ticker and request queues, and clears the in-memory caches.
|
|
539
539
|
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* the library is loaded. Browsers don't care, but anything headless - a render server, a CLI, a
|
|
543
|
-
* test run - has to call this when it's done.
|
|
540
|
+
* Idle Node processes can exit without calling this: cache and Ticker timers are unref'd,
|
|
541
|
+
* and idle request queues hold no timer. Pending requests keep their normal timer references.
|
|
544
542
|
*
|
|
545
|
-
*
|
|
543
|
+
* Call this only when finished with MineRender. Waiting and future requests reject; requests
|
|
544
|
+
* already running can finish. Queue shutdown is permanent, and cache expiry timers do not restart.
|
|
546
545
|
*/
|
|
547
546
|
declare function shutdown(): void;
|
|
548
547
|
|
|
@@ -854,6 +853,7 @@ declare class EntityObject extends SceneObject {
|
|
|
854
853
|
constructor(entity: EntityModel, options?: Partial<EntityObjectOptions>);
|
|
855
854
|
init(): Promise<void>;
|
|
856
855
|
dispose(): void;
|
|
856
|
+
private get textureKey();
|
|
857
857
|
protected loadTextures(): Promise<void>;
|
|
858
858
|
protected createMeshes(force?: boolean): void;
|
|
859
859
|
protected applyTextures(): Promise<void>;
|
|
@@ -1220,8 +1220,8 @@ declare class Caching {
|
|
|
1220
1220
|
/**
|
|
1221
1221
|
* Clears every cache and stops its expiry timer.
|
|
1222
1222
|
*
|
|
1223
|
-
*
|
|
1224
|
-
*
|
|
1223
|
+
* Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
|
|
1224
|
+
* Use {@link shutdown} to also stop requests and the shared Ticker.
|
|
1225
1225
|
*/
|
|
1226
1226
|
static end(): void;
|
|
1227
1227
|
static get cacheSizes(): {};
|
|
@@ -1474,8 +1474,9 @@ declare class Requests {
|
|
|
1474
1474
|
mcAsset: number;
|
|
1475
1475
|
};
|
|
1476
1476
|
/**
|
|
1477
|
-
*
|
|
1478
|
-
*
|
|
1477
|
+
* Permanently stops both queues and rejects waiting and future requests.
|
|
1478
|
+
* Requests already running can finish. Idle queues hold no timer, so Node can exit without
|
|
1479
|
+
* this cleanup. See {@link shutdown}.
|
|
1479
1480
|
*/
|
|
1480
1481
|
static end(): void;
|
|
1481
1482
|
}
|
|
@@ -1512,6 +1513,9 @@ declare class Skins {
|
|
|
1512
1513
|
}
|
|
1513
1514
|
|
|
1514
1515
|
declare class TextureLoader {
|
|
1516
|
+
private static readonly failedTextures;
|
|
1517
|
+
/** Reports whether image loading failed, so cached textures can be retried. */
|
|
1518
|
+
static hasFailed(texture: Texture): boolean;
|
|
1515
1519
|
protected static createTexture(): Texture;
|
|
1516
1520
|
static loadInBackground(src: string, format?: PixelFormat, rotation?: number): Texture;
|
|
1517
1521
|
static load(src: string, format?: PixelFormat, rotation?: number): Texture;
|
package/dist/node/index.d.ts
CHANGED
|
@@ -535,14 +535,13 @@ declare class MinecraftFaceUV {
|
|
|
535
535
|
}
|
|
536
536
|
|
|
537
537
|
/**
|
|
538
|
-
*
|
|
538
|
+
* Stops the shared Ticker and request queues, and clears the in-memory caches.
|
|
539
539
|
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* the library is loaded. Browsers don't care, but anything headless - a render server, a CLI, a
|
|
543
|
-
* test run - has to call this when it's done.
|
|
540
|
+
* Idle Node processes can exit without calling this: cache and Ticker timers are unref'd,
|
|
541
|
+
* and idle request queues hold no timer. Pending requests keep their normal timer references.
|
|
544
542
|
*
|
|
545
|
-
*
|
|
543
|
+
* Call this only when finished with MineRender. Waiting and future requests reject; requests
|
|
544
|
+
* already running can finish. Queue shutdown is permanent, and cache expiry timers do not restart.
|
|
546
545
|
*/
|
|
547
546
|
declare function shutdown(): void;
|
|
548
547
|
|
|
@@ -854,6 +853,7 @@ declare class EntityObject extends SceneObject {
|
|
|
854
853
|
constructor(entity: EntityModel, options?: Partial<EntityObjectOptions>);
|
|
855
854
|
init(): Promise<void>;
|
|
856
855
|
dispose(): void;
|
|
856
|
+
private get textureKey();
|
|
857
857
|
protected loadTextures(): Promise<void>;
|
|
858
858
|
protected createMeshes(force?: boolean): void;
|
|
859
859
|
protected applyTextures(): Promise<void>;
|
|
@@ -1220,8 +1220,8 @@ declare class Caching {
|
|
|
1220
1220
|
/**
|
|
1221
1221
|
* Clears every cache and stops its expiry timer.
|
|
1222
1222
|
*
|
|
1223
|
-
*
|
|
1224
|
-
*
|
|
1223
|
+
* Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
|
|
1224
|
+
* Use {@link shutdown} to also stop requests and the shared Ticker.
|
|
1225
1225
|
*/
|
|
1226
1226
|
static end(): void;
|
|
1227
1227
|
static get cacheSizes(): {};
|
|
@@ -1474,8 +1474,9 @@ declare class Requests {
|
|
|
1474
1474
|
mcAsset: number;
|
|
1475
1475
|
};
|
|
1476
1476
|
/**
|
|
1477
|
-
*
|
|
1478
|
-
*
|
|
1477
|
+
* Permanently stops both queues and rejects waiting and future requests.
|
|
1478
|
+
* Requests already running can finish. Idle queues hold no timer, so Node can exit without
|
|
1479
|
+
* this cleanup. See {@link shutdown}.
|
|
1479
1480
|
*/
|
|
1480
1481
|
static end(): void;
|
|
1481
1482
|
}
|
|
@@ -1512,6 +1513,9 @@ declare class Skins {
|
|
|
1512
1513
|
}
|
|
1513
1514
|
|
|
1514
1515
|
declare class TextureLoader {
|
|
1516
|
+
private static readonly failedTextures;
|
|
1517
|
+
/** Reports whether image loading failed, so cached textures can be retried. */
|
|
1518
|
+
static hasFailed(texture: Texture): boolean;
|
|
1515
1519
|
protected static createTexture(): Texture;
|
|
1516
1520
|
static loadInBackground(src: string, format?: PixelFormat, rotation?: number): Texture;
|
|
1517
1521
|
static load(src: string, format?: PixelFormat, rotation?: number): Texture;
|
package/dist/node/index.js
CHANGED
|
@@ -538,8 +538,8 @@ var Caching = class {
|
|
|
538
538
|
/**
|
|
539
539
|
* Clears every cache and stops its expiry timer.
|
|
540
540
|
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
541
|
+
* Expiry timers are unref'd in Node, so idle processes can exit without this cleanup.
|
|
542
|
+
* Use {@link shutdown} to also stop requests and the shared Ticker.
|
|
543
543
|
*/
|
|
544
544
|
static end() {
|
|
545
545
|
for (const cache of this.all) {
|
|
@@ -787,13 +787,14 @@ var _Requests = class _Requests {
|
|
|
787
787
|
}
|
|
788
788
|
static get queueSizes() {
|
|
789
789
|
return {
|
|
790
|
-
generic: this.genericQueue.size,
|
|
791
|
-
mcAsset: this.mcAssetRequestQueue.size
|
|
790
|
+
generic: this.genericQueue.size + this.genericQueue.activeSize,
|
|
791
|
+
mcAsset: this.mcAssetRequestQueue.size + this.mcAssetRequestQueue.activeSize
|
|
792
792
|
};
|
|
793
793
|
}
|
|
794
794
|
/**
|
|
795
|
-
*
|
|
796
|
-
*
|
|
795
|
+
* Permanently stops both queues and rejects waiting and future requests.
|
|
796
|
+
* Requests already running can finish. Idle queues hold no timer, so Node can exit without
|
|
797
|
+
* this cleanup. See {@link shutdown}.
|
|
797
798
|
*/
|
|
798
799
|
static end() {
|
|
799
800
|
this.genericQueue.end();
|
|
@@ -873,29 +874,41 @@ var ImageLoader = class _ImageLoader {
|
|
|
873
874
|
static async loadAsync(src) {
|
|
874
875
|
return new Promise((resolve, reject) => {
|
|
875
876
|
const image = this._createImage();
|
|
876
|
-
image.src = src;
|
|
877
877
|
image.onload = () => resolve(image);
|
|
878
|
-
image.onerror = (err) => reject(err);
|
|
878
|
+
image.onerror = (err) => reject(err instanceof Error ? err : new Error("Failed to decode image"));
|
|
879
|
+
image.src = src;
|
|
879
880
|
});
|
|
880
881
|
}
|
|
881
882
|
static loadElement(src, onload, onerr) {
|
|
882
883
|
const image = this._createImage();
|
|
883
|
-
image.src = src;
|
|
884
884
|
if (onload)
|
|
885
885
|
image.onload = onload;
|
|
886
886
|
if (onerr)
|
|
887
887
|
image.onerror = onerr;
|
|
888
|
+
image.src = src;
|
|
888
889
|
return image;
|
|
889
890
|
}
|
|
890
891
|
static async loadData(src) {
|
|
891
892
|
console.debug(p2, "loadData", src);
|
|
892
|
-
|
|
893
|
+
const image = await this.loadCanvasData(src);
|
|
894
|
+
return image.data.getImageData(0, 0, image.width, image.height);
|
|
893
895
|
}
|
|
894
896
|
static async loadCanvasData(src) {
|
|
895
|
-
|
|
897
|
+
const keyStr = serializeImageKey({ src });
|
|
898
|
+
const info = this.getInfo(src);
|
|
899
|
+
const cached = Caching.rawImageCache.getIfPresent(keyStr);
|
|
900
|
+
try {
|
|
901
|
+
return await this.infoToCanvasData(await info);
|
|
902
|
+
} catch (err) {
|
|
903
|
+
if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
|
|
904
|
+
Caching.rawImageCache.invalidate(keyStr);
|
|
905
|
+
}
|
|
906
|
+
throw err;
|
|
907
|
+
}
|
|
896
908
|
}
|
|
897
909
|
static async infoToCanvasData(info) {
|
|
898
|
-
const
|
|
910
|
+
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
911
|
+
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
899
912
|
const canvas = createCanvas2(info.width, info.height);
|
|
900
913
|
const context = canvas.getContext("2d");
|
|
901
914
|
context.drawImage(image, 0, 0);
|
|
@@ -906,11 +919,8 @@ var ImageLoader = class _ImageLoader {
|
|
|
906
919
|
};
|
|
907
920
|
}
|
|
908
921
|
static async infoToData(info) {
|
|
909
|
-
const image = await
|
|
910
|
-
|
|
911
|
-
const context = canvas.getContext("2d");
|
|
912
|
-
context.drawImage(image, 0, 0);
|
|
913
|
-
return context.getImageData(0, 0, canvas.width, canvas.height);
|
|
922
|
+
const image = await this.infoToCanvasData(info);
|
|
923
|
+
return image.data.getImageData(0, 0, image.width, image.height);
|
|
914
924
|
}
|
|
915
925
|
static async getData(src) {
|
|
916
926
|
const keyStr = serializeImageKey({ src });
|
|
@@ -925,13 +935,17 @@ var ImageLoader = class _ImageLoader {
|
|
|
925
935
|
});
|
|
926
936
|
}
|
|
927
937
|
static async processResponse(response) {
|
|
928
|
-
|
|
938
|
+
var _a;
|
|
939
|
+
const src = (_a = response.config) == null ? void 0 : _a.url;
|
|
929
940
|
const data = import_buffer.Buffer.from(response.data);
|
|
930
941
|
const { width, height, type } = Env.provider.imageSize(data);
|
|
942
|
+
if (!width || !height) {
|
|
943
|
+
throw new Error("Invalid or unsupported image dimensions");
|
|
944
|
+
}
|
|
931
945
|
return {
|
|
932
946
|
src,
|
|
933
|
-
width
|
|
934
|
-
height
|
|
947
|
+
width,
|
|
948
|
+
height,
|
|
935
949
|
type,
|
|
936
950
|
data
|
|
937
951
|
};
|
|
@@ -948,15 +962,7 @@ var ImageLoader = class _ImageLoader {
|
|
|
948
962
|
return Requests.genericRequest({
|
|
949
963
|
url: src,
|
|
950
964
|
responseType: "arraybuffer"
|
|
951
|
-
}).then(this.processResponse)
|
|
952
|
-
return {
|
|
953
|
-
src,
|
|
954
|
-
width: 0,
|
|
955
|
-
height: 0,
|
|
956
|
-
type: void 0,
|
|
957
|
-
data: import_buffer.Buffer.from([0])
|
|
958
|
-
};
|
|
959
|
-
});
|
|
965
|
+
}).then(this.processResponse);
|
|
960
966
|
}
|
|
961
967
|
static async getInfo(src) {
|
|
962
968
|
const keyStr = serializeImageKey({ src });
|
|
@@ -978,16 +984,22 @@ var ImageLoader = class _ImageLoader {
|
|
|
978
984
|
|
|
979
985
|
// src/texture/TextureLoader.ts
|
|
980
986
|
var TextureLoader = class {
|
|
987
|
+
/** Reports whether image loading failed, so cached textures can be retried. */
|
|
988
|
+
static hasFailed(texture) {
|
|
989
|
+
return this.failedTextures.has(texture);
|
|
990
|
+
}
|
|
981
991
|
static createTexture() {
|
|
982
992
|
return new import_three4.Texture();
|
|
983
993
|
}
|
|
984
994
|
static loadInBackground(src, format = import_three4.RGBAFormat, rotation = 0) {
|
|
985
995
|
const texture = this.createTexture();
|
|
986
996
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
987
|
-
const image = ImageLoader.loadElement(src)
|
|
988
|
-
image.onload = function() {
|
|
997
|
+
const image = ImageLoader.loadElement(src, () => {
|
|
989
998
|
texture.needsUpdate = true;
|
|
990
|
-
}
|
|
999
|
+
}, (error) => {
|
|
1000
|
+
this.failedTextures.add(texture);
|
|
1001
|
+
console.warn("Failed to load texture", src, error);
|
|
1002
|
+
});
|
|
991
1003
|
texture.image = image;
|
|
992
1004
|
texture.format = format;
|
|
993
1005
|
texture.rotation = rotation;
|
|
@@ -997,14 +1009,18 @@ var TextureLoader = class {
|
|
|
997
1009
|
const texture = new import_three4.Texture();
|
|
998
1010
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
999
1011
|
ImageLoader.getData(src).then((image) => {
|
|
1000
|
-
texture.needsUpdate = true;
|
|
1001
1012
|
texture.image = image;
|
|
1013
|
+
texture.needsUpdate = true;
|
|
1014
|
+
}).catch((error) => {
|
|
1015
|
+
this.failedTextures.add(texture);
|
|
1016
|
+
console.warn("Failed to load texture", src, error);
|
|
1002
1017
|
});
|
|
1003
1018
|
texture.format = format;
|
|
1004
1019
|
texture.rotation = rotation;
|
|
1005
1020
|
return Textures.initTextureProps(texture);
|
|
1006
1021
|
}
|
|
1007
1022
|
};
|
|
1023
|
+
TextureLoader.failedTextures = /* @__PURE__ */ new WeakSet();
|
|
1008
1024
|
|
|
1009
1025
|
// src/texture/Textures.ts
|
|
1010
1026
|
var THREE2 = __toESM(require("three"));
|
|
@@ -1028,6 +1044,10 @@ var Textures = class _Textures {
|
|
|
1028
1044
|
}
|
|
1029
1045
|
static getImage(key) {
|
|
1030
1046
|
const keyStr = serializeTextureKey(key);
|
|
1047
|
+
const cached = Caching.textureCache.peek(keyStr);
|
|
1048
|
+
if (cached && TextureLoader.hasFailed(cached)) {
|
|
1049
|
+
Caching.textureCache.invalidate(keyStr);
|
|
1050
|
+
}
|
|
1031
1051
|
return Caching.textureCache.get(keyStr, (k) => {
|
|
1032
1052
|
return _Textures.createImage(key);
|
|
1033
1053
|
});
|
|
@@ -1171,7 +1191,12 @@ var _Materials = class _Materials {
|
|
|
1171
1191
|
return this.createBasicCanvasMaterial(canvas, transparent, shade);
|
|
1172
1192
|
}
|
|
1173
1193
|
static getImage(key) {
|
|
1194
|
+
var _a;
|
|
1174
1195
|
const keyStr = serializeMaterialKey(key);
|
|
1196
|
+
const map = (_a = Caching.materialCache.peek(keyStr)) == null ? void 0 : _a.map;
|
|
1197
|
+
if (map && TextureLoader.hasFailed(map)) {
|
|
1198
|
+
Caching.materialCache.invalidate(keyStr);
|
|
1199
|
+
}
|
|
1175
1200
|
return Caching.materialCache.get(keyStr, (k) => {
|
|
1176
1201
|
return _Materials.createImage(key);
|
|
1177
1202
|
});
|
|
@@ -1829,11 +1854,21 @@ var ModelTextures = class {
|
|
|
1829
1854
|
return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
|
|
1830
1855
|
}
|
|
1831
1856
|
static async get(key) {
|
|
1832
|
-
const
|
|
1833
|
-
|
|
1834
|
-
|
|
1857
|
+
const keyStr = key.serialize();
|
|
1858
|
+
const pending = this.preload(key);
|
|
1859
|
+
const cached = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
1860
|
+
try {
|
|
1861
|
+
const asset = await pending;
|
|
1862
|
+
if (asset) {
|
|
1863
|
+
return await ImageLoader.infoToCanvasData(asset);
|
|
1864
|
+
}
|
|
1865
|
+
return void 0;
|
|
1866
|
+
} catch (err) {
|
|
1867
|
+
if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
|
|
1868
|
+
Caching.textureAssetCache.invalidate(keyStr);
|
|
1869
|
+
}
|
|
1870
|
+
throw err;
|
|
1835
1871
|
}
|
|
1836
|
-
return void 0;
|
|
1837
1872
|
}
|
|
1838
1873
|
static async preload(key) {
|
|
1839
1874
|
const keyStr = key.serialize();
|
|
@@ -3027,9 +3062,9 @@ var EntityObject = class extends SceneObject {
|
|
|
3027
3062
|
dispose() {
|
|
3028
3063
|
super.dispose();
|
|
3029
3064
|
}
|
|
3030
|
-
|
|
3065
|
+
get textureKey() {
|
|
3031
3066
|
var _a;
|
|
3032
|
-
|
|
3067
|
+
return new AssetKey(
|
|
3033
3068
|
((_a = this.entity.key) == null ? void 0 : _a.namespace) ?? DEFAULT_NAMESPACE,
|
|
3034
3069
|
this.entity.key.path,
|
|
3035
3070
|
//TODO: texture may differ from entity name; most of them are in subdirectories for multiple variants etc.
|
|
@@ -3037,7 +3072,10 @@ var EntityObject = class extends SceneObject {
|
|
|
3037
3072
|
"entity",
|
|
3038
3073
|
"assets",
|
|
3039
3074
|
".png"
|
|
3040
|
-
)
|
|
3075
|
+
);
|
|
3076
|
+
}
|
|
3077
|
+
async loadTextures() {
|
|
3078
|
+
this.imageData = await ModelTextures.get(this.textureKey);
|
|
3041
3079
|
}
|
|
3042
3080
|
//TODO: abstract this, since extracted model data can be used for entities, blocks, players
|
|
3043
3081
|
createMeshes(force = false) {
|
|
@@ -3070,21 +3108,23 @@ var EntityObject = class extends SceneObject {
|
|
|
3070
3108
|
this.meshesCreated = true;
|
|
3071
3109
|
}
|
|
3072
3110
|
async applyTextures() {
|
|
3073
|
-
|
|
3074
|
-
const
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
this.
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3111
|
+
const assetKeyStr = this.textureKey.serialize();
|
|
3112
|
+
const keyStr = `entity:${assetKeyStr}`;
|
|
3113
|
+
let mat = Caching.materialCache.getIfPresent(keyStr);
|
|
3114
|
+
if (!mat) {
|
|
3115
|
+
const pending = this.loadTextures();
|
|
3116
|
+
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
3117
|
+
await pending;
|
|
3118
|
+
if (!this.imageData) return;
|
|
3119
|
+
const canvas = this.imageData.data.canvas;
|
|
3120
|
+
const createMaterial = () => Materials.createBasicCanvasMaterial(canvas);
|
|
3121
|
+
mat = cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
|
|
3122
|
+
this.imageData = void 0;
|
|
3123
|
+
}
|
|
3124
|
+
this.iterateAllMeshes((mesh) => {
|
|
3125
|
+
mesh.material = mat;
|
|
3126
|
+
});
|
|
3127
|
+
this.notifyDirty();
|
|
3088
3128
|
}
|
|
3089
3129
|
};
|
|
3090
3130
|
EntityObject.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS, {});
|