minerender 2.1.0-alpha.75 → 2.1.0-alpha.77
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/README.md +57 -0
- package/dist/browser/index.d.mts +594 -14
- package/dist/browser/index.d.ts +594 -14
- package/dist/browser/index.js +965 -312
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +933 -280
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +1708 -1044
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +594 -14
- package/dist/node/index.d.ts +594 -14
- package/dist/node/index.js +966 -311
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +932 -279
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -69,6 +69,7 @@ var init_PersistentCache = __esm({
|
|
|
69
69
|
/** Bump to invalidate every persisted entry. */
|
|
70
70
|
this.VERSION = 2;
|
|
71
71
|
}
|
|
72
|
+
/** Opens a named store in the active environment using the current cache schema version. */
|
|
72
73
|
static open(name) {
|
|
73
74
|
return Env.provider.openCache(name, _PersistentCache.VERSION);
|
|
74
75
|
}
|
|
@@ -330,6 +331,7 @@ var init_Caching = __esm({
|
|
|
330
331
|
this.fontCache
|
|
331
332
|
];
|
|
332
333
|
}
|
|
334
|
+
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
333
335
|
static clear() {
|
|
334
336
|
for (const cache of this.all) {
|
|
335
337
|
cache.invalidateAll();
|
|
@@ -372,6 +374,7 @@ var init_Geometries = __esm({
|
|
|
372
374
|
}
|
|
373
375
|
return geometry;
|
|
374
376
|
}
|
|
377
|
+
/** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
|
|
375
378
|
static getBox(key) {
|
|
376
379
|
const keyStr = serializeBoxGeometryKey(key);
|
|
377
380
|
return Caching.boxGeometryCache.get(keyStr, (k) => {
|
|
@@ -555,12 +558,15 @@ var init_Requests = __esm({
|
|
|
555
558
|
static {
|
|
556
559
|
this.mcAssetRequestQueue = new RequestQueue();
|
|
557
560
|
}
|
|
561
|
+
/** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
|
|
558
562
|
static genericRequest(request) {
|
|
559
563
|
return this.genericQueue.request(request);
|
|
560
564
|
}
|
|
565
|
+
/** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
|
|
561
566
|
static mcAssetRequest(request) {
|
|
562
567
|
return this.mcAssetRequestQueue.request(request);
|
|
563
568
|
}
|
|
569
|
+
/** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
|
|
564
570
|
static setMcAssetRoot(root) {
|
|
565
571
|
this.mcAssetRequestQueue.baseURL = root;
|
|
566
572
|
}
|
|
@@ -613,6 +619,7 @@ var init_WrappedImage = __esm({
|
|
|
613
619
|
}
|
|
614
620
|
return false;
|
|
615
621
|
}
|
|
622
|
+
/** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
|
|
616
623
|
get animated() {
|
|
617
624
|
return this.height > this.width && this.height % this.width === 0;
|
|
618
625
|
}
|
|
@@ -659,6 +666,7 @@ var init_ImageLoader = __esm({
|
|
|
659
666
|
static _createImage() {
|
|
660
667
|
return createImage();
|
|
661
668
|
}
|
|
669
|
+
/** Resolves when an image URL has decoded, or rejects if decoding fails. */
|
|
662
670
|
static async loadAsync(src) {
|
|
663
671
|
return new Promise((resolve, reject) => {
|
|
664
672
|
const image = this._createImage();
|
|
@@ -667,6 +675,7 @@ var init_ImageLoader = __esm({
|
|
|
667
675
|
image.src = src;
|
|
668
676
|
});
|
|
669
677
|
}
|
|
678
|
+
/** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
|
|
670
679
|
static loadElement(src, onload, onerr) {
|
|
671
680
|
const image = this._createImage();
|
|
672
681
|
if (onload)
|
|
@@ -694,6 +703,7 @@ var init_ImageLoader = __esm({
|
|
|
694
703
|
throw err;
|
|
695
704
|
}
|
|
696
705
|
}
|
|
706
|
+
/** Decodes the supplied bytes into a canvas without fetching the source URL again. */
|
|
697
707
|
static async infoToCanvasData(info) {
|
|
698
708
|
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
699
709
|
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
@@ -710,12 +720,14 @@ var init_ImageLoader = __esm({
|
|
|
710
720
|
const image = await this.infoToCanvasData(info);
|
|
711
721
|
return image.data.getImageData(0, 0, image.width, image.height);
|
|
712
722
|
}
|
|
723
|
+
/** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
|
|
713
724
|
static async getData(src) {
|
|
714
725
|
const keyStr = serializeImageKey({ src });
|
|
715
726
|
return await Caching.imageDataCache.get(keyStr, (k) => {
|
|
716
727
|
return _ImageLoader.loadData(src);
|
|
717
728
|
});
|
|
718
729
|
}
|
|
730
|
+
/** Returns a cached canvas context and dimensions for an image URL or data URL. */
|
|
719
731
|
static async getCanvasData(src) {
|
|
720
732
|
const keyStr = serializeImageKey({ src });
|
|
721
733
|
return await Caching.canvasImageDataCache.get(keyStr, (k) => {
|
|
@@ -815,6 +827,7 @@ var init_TextureLoader = __esm({
|
|
|
815
827
|
texture.rotation = rotation;
|
|
816
828
|
return Textures.initTextureProps(texture);
|
|
817
829
|
}
|
|
830
|
+
/** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
|
|
818
831
|
static load(src, format2 = import_three3.RGBAFormat, rotation = 0) {
|
|
819
832
|
const texture = new import_three3.Texture();
|
|
820
833
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
@@ -851,8 +864,8 @@ var init_Textures = __esm({
|
|
|
851
864
|
for (let y = 0; y < size; y++) {
|
|
852
865
|
for (let x = 0; x < size; x++) {
|
|
853
866
|
const offset = (y * size + x) * 4;
|
|
854
|
-
const
|
|
855
|
-
data[offset] = data[offset + 2] =
|
|
867
|
+
const color2 = (x + y) % 2 === 0 ? 255 : 0;
|
|
868
|
+
data[offset] = data[offset + 2] = color2;
|
|
856
869
|
data[offset + 3] = 255;
|
|
857
870
|
}
|
|
858
871
|
}
|
|
@@ -863,6 +876,7 @@ var init_Textures = __esm({
|
|
|
863
876
|
return this.initTextureProps(texture);
|
|
864
877
|
});
|
|
865
878
|
}
|
|
879
|
+
/** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
|
|
866
880
|
static initTextureProps(texture) {
|
|
867
881
|
texture.magFilter = THREE2.NearestFilter;
|
|
868
882
|
texture.minFilter = THREE2.NearestFilter;
|
|
@@ -875,11 +889,13 @@ var init_Textures = __esm({
|
|
|
875
889
|
static createAsset(key) {
|
|
876
890
|
return new import_three4.Texture();
|
|
877
891
|
}
|
|
892
|
+
/** Creates an sRGB color texture from a canvas. */
|
|
878
893
|
static createCanvasTexture(canvas) {
|
|
879
894
|
const texture = new import_three4.CanvasTexture(canvas);
|
|
880
895
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
881
896
|
return this.initTextureProps(texture);
|
|
882
897
|
}
|
|
898
|
+
/** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
|
|
883
899
|
static getImage(key) {
|
|
884
900
|
const keyStr = serializeTextureKey(key);
|
|
885
901
|
const cached2 = Caching.textureCache.peek(keyStr);
|
|
@@ -904,6 +920,7 @@ var init_Materials = __esm({
|
|
|
904
920
|
init_TextureLoader();
|
|
905
921
|
init_Caching();
|
|
906
922
|
Materials = class _Materials {
|
|
923
|
+
/** Shared checkerboard material, created on first access. */
|
|
907
924
|
static get MISSING_TEXTURE() {
|
|
908
925
|
return Caching.materialCache.get("builtin:missing-texture", () => new import_three5.MeshBasicMaterial({
|
|
909
926
|
map: Textures.getMissing(),
|
|
@@ -1007,6 +1024,7 @@ var init_Materials = __esm({
|
|
|
1007
1024
|
if (tint !== void 0) material.color.multiply(new import_three5.Color(tint));
|
|
1008
1025
|
return material;
|
|
1009
1026
|
}
|
|
1027
|
+
/** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
|
|
1010
1028
|
static createGuiCanvasMaterial(canvas) {
|
|
1011
1029
|
const material = new import_three5.MeshBasicMaterial({
|
|
1012
1030
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -1173,6 +1191,7 @@ var init_Materials = __esm({
|
|
|
1173
1191
|
}
|
|
1174
1192
|
return this.createBasicCanvasMaterial(canvas, transparent, shade);
|
|
1175
1193
|
}
|
|
1194
|
+
/** Returns a shared image material. Use {@link createImage} for a separate material instance. */
|
|
1176
1195
|
static getImage(key) {
|
|
1177
1196
|
const keyStr = serializeMaterialKey(key);
|
|
1178
1197
|
const map = Caching.materialCache.peek(keyStr)?.map;
|
|
@@ -1347,6 +1366,14 @@ var init_AssetKey = __esm({
|
|
|
1347
1366
|
}
|
|
1348
1367
|
};
|
|
1349
1368
|
AssetKey = class _AssetKey extends BasicAssetKey {
|
|
1369
|
+
/**
|
|
1370
|
+
* Creates a key from separate path components. Use {@link parse} for a combined reference.
|
|
1371
|
+
*
|
|
1372
|
+
* @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
|
|
1373
|
+
* @param type - Subdirectory, such as `block` or `item`.
|
|
1374
|
+
* @param rootType - Top-level directory, usually `assets` or `data`.
|
|
1375
|
+
* @param root - Base URL override for hosted asset sources.
|
|
1376
|
+
*/
|
|
1350
1377
|
constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
|
|
1351
1378
|
super(namespace, path);
|
|
1352
1379
|
this.namespace = namespace;
|
|
@@ -1358,6 +1385,16 @@ var init_AssetKey = __esm({
|
|
|
1358
1385
|
this.root = root;
|
|
1359
1386
|
this.isAssetKey = true;
|
|
1360
1387
|
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Parses an asset reference such as `minecraft:block/stone`.
|
|
1390
|
+
* A missing namespace defaults to the origin's namespace or `minecraft`.
|
|
1391
|
+
*
|
|
1392
|
+
* @param assetType - Asset category, such as `models` or `textures`.
|
|
1393
|
+
* @param str - Path with an optional namespace and file extension.
|
|
1394
|
+
* @param origin - Supplies the asset root, default namespace, and non-texture extension.
|
|
1395
|
+
* @returns A key with the matching extension removed from its path. Textures use `.png`;
|
|
1396
|
+
* other assets use the origin's extension or `.json`.
|
|
1397
|
+
*/
|
|
1361
1398
|
static parse(assetType, str, origin) {
|
|
1362
1399
|
let namespace = origin?.namespace || DEFAULT_NAMESPACE;
|
|
1363
1400
|
if (str.includes(":")) {
|
|
@@ -1389,6 +1426,7 @@ var init_AssetKey = __esm({
|
|
|
1389
1426
|
];
|
|
1390
1427
|
return a.join("/");
|
|
1391
1428
|
}
|
|
1429
|
+
/** Joins the type subdirectory and path without adding a namespace or file extension. */
|
|
1392
1430
|
getFullPath() {
|
|
1393
1431
|
let p10 = [];
|
|
1394
1432
|
if (this.type) {
|
|
@@ -1400,6 +1438,7 @@ var init_AssetKey = __esm({
|
|
|
1400
1438
|
toNamespacedString() {
|
|
1401
1439
|
return this.namespace + ":" + this.getFullPath();
|
|
1402
1440
|
}
|
|
1441
|
+
/** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
|
|
1403
1442
|
serialize() {
|
|
1404
1443
|
return this.toString();
|
|
1405
1444
|
}
|
|
@@ -1411,17 +1450,17 @@ var init_AssetKey = __esm({
|
|
|
1411
1450
|
var DisplayPosition, DISPLAY_POSITIONS;
|
|
1412
1451
|
var init_DisplayPosition = __esm({
|
|
1413
1452
|
"src/model/DisplayPosition.ts"() {
|
|
1414
|
-
DisplayPosition = /* @__PURE__ */ ((
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
return
|
|
1453
|
+
DisplayPosition = /* @__PURE__ */ ((DisplayPosition3) => {
|
|
1454
|
+
DisplayPosition3["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
|
|
1455
|
+
DisplayPosition3["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
|
|
1456
|
+
DisplayPosition3["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
|
|
1457
|
+
DisplayPosition3["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
|
|
1458
|
+
DisplayPosition3["GUI"] = "gui";
|
|
1459
|
+
DisplayPosition3["HEAD"] = "head";
|
|
1460
|
+
DisplayPosition3["GROUND"] = "ground";
|
|
1461
|
+
DisplayPosition3["FIXED"] = "fixed";
|
|
1462
|
+
DisplayPosition3["ON_SHELF"] = "on_shelf";
|
|
1463
|
+
return DisplayPosition3;
|
|
1425
1464
|
})(DisplayPosition || {});
|
|
1426
1465
|
DISPLAY_POSITIONS = Object.values(DisplayPosition);
|
|
1427
1466
|
}
|
|
@@ -1459,6 +1498,7 @@ var init_DisplayTransforms = __esm({
|
|
|
1459
1498
|
const scale = new import_three7.Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
|
|
1460
1499
|
return new import_three7.Matrix4().compose(translation, rotation, scale);
|
|
1461
1500
|
}
|
|
1501
|
+
/** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
|
|
1462
1502
|
static apply(geometry, matrix) {
|
|
1463
1503
|
geometry.applyMatrix4(matrix);
|
|
1464
1504
|
if (matrix.determinant() < 0) {
|
|
@@ -1486,6 +1526,7 @@ var init_ModelMerger = __esm({
|
|
|
1486
1526
|
init_AssetKey();
|
|
1487
1527
|
init_DisplayTransforms();
|
|
1488
1528
|
ModelMerger = class {
|
|
1529
|
+
/** Loads the parent chain and returns a merged model without modifying the supplied definition. */
|
|
1489
1530
|
static async mergeWithParents(model) {
|
|
1490
1531
|
const models = await this.collectAllParents(model);
|
|
1491
1532
|
let merged = {};
|
|
@@ -1553,6 +1594,7 @@ var init_Models = __esm({
|
|
|
1553
1594
|
static get PERSISTENT_CACHE() {
|
|
1554
1595
|
return this._persistentCache ??= PersistentCache.open("minerender-models");
|
|
1555
1596
|
}
|
|
1597
|
+
/** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
|
|
1556
1598
|
static async getItemList() {
|
|
1557
1599
|
const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
|
|
1558
1600
|
const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
|
|
@@ -1623,6 +1665,7 @@ var init_Models = __esm({
|
|
|
1623
1665
|
}
|
|
1624
1666
|
throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
|
|
1625
1667
|
}
|
|
1668
|
+
/** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
|
|
1626
1669
|
static async getRaw(key) {
|
|
1627
1670
|
if (!key.assetType) {
|
|
1628
1671
|
key.assetType = "models";
|
|
@@ -1635,13 +1678,19 @@ var init_Models = __esm({
|
|
|
1635
1678
|
return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
1636
1679
|
return AssetLoader.get(key, "model" /* MODEL */);
|
|
1637
1680
|
});
|
|
1638
|
-
}).then((
|
|
1639
|
-
if (
|
|
1640
|
-
|
|
1681
|
+
}).then((asset2) => {
|
|
1682
|
+
if (asset2) {
|
|
1683
|
+
asset2.key = key;
|
|
1641
1684
|
}
|
|
1642
|
-
return
|
|
1685
|
+
return asset2;
|
|
1643
1686
|
});
|
|
1644
1687
|
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
|
|
1690
|
+
* Item keys use GUI context, false conditions, and zero numeric properties.
|
|
1691
|
+
*
|
|
1692
|
+
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
1693
|
+
*/
|
|
1645
1694
|
static async getMerged(key) {
|
|
1646
1695
|
if (!key.assetType) {
|
|
1647
1696
|
key.assetType = "models";
|
|
@@ -1654,9 +1703,11 @@ var init_Models = __esm({
|
|
|
1654
1703
|
return _Models.loadAndMerge(key);
|
|
1655
1704
|
});
|
|
1656
1705
|
}
|
|
1706
|
+
/** Alias for {@link getMerged}. */
|
|
1657
1707
|
static async get(key) {
|
|
1658
1708
|
return this.getMerged(key);
|
|
1659
1709
|
}
|
|
1710
|
+
/** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1660
1711
|
static async clearCache() {
|
|
1661
1712
|
return this.PERSISTENT_CACHE.clear();
|
|
1662
1713
|
}
|
|
@@ -1679,6 +1730,7 @@ var init_BlockStates = __esm({
|
|
|
1679
1730
|
return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
|
|
1680
1731
|
}
|
|
1681
1732
|
// BlockState names are hardcoded
|
|
1733
|
+
/** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
|
|
1682
1734
|
static async getList() {
|
|
1683
1735
|
const key = new AssetKey(
|
|
1684
1736
|
DEFAULT_NAMESPACE,
|
|
@@ -1699,6 +1751,7 @@ var init_BlockStates = __esm({
|
|
|
1699
1751
|
return AssetLoader.get(key, "json" /* JSON */);
|
|
1700
1752
|
});
|
|
1701
1753
|
}
|
|
1754
|
+
/** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
|
|
1702
1755
|
static async getDefaultState(key) {
|
|
1703
1756
|
const defaultStates = await this.getDefaultStates();
|
|
1704
1757
|
if (!defaultStates) {
|
|
@@ -1706,6 +1759,7 @@ var init_BlockStates = __esm({
|
|
|
1706
1759
|
}
|
|
1707
1760
|
return defaultStates["minecraft:" + key.path];
|
|
1708
1761
|
}
|
|
1762
|
+
/** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
|
|
1709
1763
|
static async get(key) {
|
|
1710
1764
|
if (!key.assetType) {
|
|
1711
1765
|
key.assetType = "blockstates";
|
|
@@ -1718,11 +1772,11 @@ var init_BlockStates = __esm({
|
|
|
1718
1772
|
return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
1719
1773
|
return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
|
|
1720
1774
|
});
|
|
1721
|
-
}).then((
|
|
1722
|
-
if (
|
|
1723
|
-
|
|
1775
|
+
}).then((asset2) => {
|
|
1776
|
+
if (asset2) {
|
|
1777
|
+
asset2.key = key;
|
|
1724
1778
|
}
|
|
1725
|
-
return
|
|
1779
|
+
return asset2;
|
|
1726
1780
|
});
|
|
1727
1781
|
}
|
|
1728
1782
|
static getAll(keys) {
|
|
@@ -1732,6 +1786,7 @@ var init_BlockStates = __esm({
|
|
|
1732
1786
|
}
|
|
1733
1787
|
return Promise.all(promises);
|
|
1734
1788
|
}
|
|
1789
|
+
/** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1735
1790
|
static async clearCache() {
|
|
1736
1791
|
await this.PERSISTENT_CACHE.clear();
|
|
1737
1792
|
}
|
|
@@ -1757,9 +1812,11 @@ var init_Assets = __esm({
|
|
|
1757
1812
|
static parseAssetKey(assetType, str, origin) {
|
|
1758
1813
|
return AssetKey.parse(assetType, str, origin);
|
|
1759
1814
|
}
|
|
1815
|
+
/** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
|
|
1760
1816
|
static async getModel(key) {
|
|
1761
1817
|
return Models.getMerged(key);
|
|
1762
1818
|
}
|
|
1819
|
+
/** Loads a blockstate definition. See {@link BlockStates.get}. */
|
|
1763
1820
|
static async getBlockState(key) {
|
|
1764
1821
|
return BlockStates.get(key);
|
|
1765
1822
|
}
|
|
@@ -1806,6 +1863,10 @@ var init_BatchedExecutor = __esm({
|
|
|
1806
1863
|
"src/util/BatchedExecutor.ts"() {
|
|
1807
1864
|
import_jobqu2 = require("jobqu");
|
|
1808
1865
|
BatchedExecutor = class {
|
|
1866
|
+
/**
|
|
1867
|
+
* @param interval - Delay between queue runs, in milliseconds.
|
|
1868
|
+
* @param batch - Maximum tasks started per run and maximum tasks active at once.
|
|
1869
|
+
*/
|
|
1809
1870
|
constructor(interval = 1, batch = 30) {
|
|
1810
1871
|
if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
|
|
1811
1872
|
if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
|
|
@@ -1813,9 +1874,11 @@ var init_BatchedExecutor = __esm({
|
|
|
1813
1874
|
this.batch = batch;
|
|
1814
1875
|
this.queue = new import_jobqu2.JobQueue(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
|
|
1815
1876
|
}
|
|
1877
|
+
/** Queues a task and resolves with its result, or rejects with its error. */
|
|
1816
1878
|
submit(task) {
|
|
1817
1879
|
return this.queue.add(() => task());
|
|
1818
1880
|
}
|
|
1881
|
+
/** Rejects queued and future tasks. Tasks already running are allowed to finish. */
|
|
1819
1882
|
stop() {
|
|
1820
1883
|
this.queue.end();
|
|
1821
1884
|
}
|
|
@@ -1862,29 +1925,29 @@ function applyGenericRotation(axis, rotation, obj) {
|
|
|
1862
1925
|
break;
|
|
1863
1926
|
}
|
|
1864
1927
|
}
|
|
1865
|
-
function addBox3WireframeToObject(box, obj,
|
|
1928
|
+
function addBox3WireframeToObject(box, obj, color2 = 16777215, w = 2) {
|
|
1866
1929
|
let size = new import_three8.Vector3();
|
|
1867
1930
|
box.getSize(size);
|
|
1868
1931
|
let boxGeo = new import_three8.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
|
|
1869
1932
|
let wireGeo = new import_three8.EdgesGeometry(boxGeo);
|
|
1870
|
-
let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
|
|
1933
|
+
let wireMat = new import_three8.LineBasicMaterial({ color: color2, linewidth: w });
|
|
1871
1934
|
let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
|
|
1872
1935
|
obj.add(wireframe);
|
|
1873
1936
|
let axes = new import_three8.AxesHelper(1);
|
|
1874
1937
|
obj.add(axes);
|
|
1875
1938
|
}
|
|
1876
|
-
function addWireframeToObject(obj,
|
|
1939
|
+
function addWireframeToObject(obj, color2 = 16777215, w = 2) {
|
|
1877
1940
|
let boxGeo = new import_three8.BoxGeometry(16, 16, 16, 1, 1, 1);
|
|
1878
1941
|
let wireGeo = new import_three8.EdgesGeometry(boxGeo);
|
|
1879
|
-
let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
|
|
1942
|
+
let wireMat = new import_three8.LineBasicMaterial({ color: color2, linewidth: w });
|
|
1880
1943
|
let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
|
|
1881
1944
|
obj.add(wireframe);
|
|
1882
1945
|
let axes = new import_three8.AxesHelper(1);
|
|
1883
1946
|
obj.add(axes);
|
|
1884
1947
|
}
|
|
1885
|
-
function addWireframeToMesh(geo, mesh,
|
|
1948
|
+
function addWireframeToMesh(geo, mesh, color2 = 16777215, w = 2) {
|
|
1886
1949
|
let wireGeo = new import_three8.EdgesGeometry(geo);
|
|
1887
|
-
let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
|
|
1950
|
+
let wireMat = new import_three8.LineBasicMaterial({ color: color2, linewidth: w });
|
|
1888
1951
|
let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
|
|
1889
1952
|
mesh.add(wireframe);
|
|
1890
1953
|
let axes = new import_three8.AxesHelper(1);
|
|
@@ -1958,6 +2021,7 @@ var init_NBTHelper = __esm({
|
|
|
1958
2021
|
"src/nbt/NBTHelper.ts"() {
|
|
1959
2022
|
import_buffer2 = require("buffer");
|
|
1960
2023
|
NBTHelper = class {
|
|
2024
|
+
/** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
|
|
1961
2025
|
static async fromBuffer(data, format2) {
|
|
1962
2026
|
const buffer = import_buffer2.Buffer.from(data instanceof Uint8Array ? data : new Uint8Array(data));
|
|
1963
2027
|
const prismarineNbt = await import("prismarine-nbt");
|
|
@@ -2102,6 +2166,7 @@ var init_HostedAssetSource = __esm({
|
|
|
2102
2166
|
["json" /* JSON */, _HostedAssetSource.JSON]
|
|
2103
2167
|
]);
|
|
2104
2168
|
}
|
|
2169
|
+
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
2105
2170
|
async loadOrRetryWithDefaults(key, parser) {
|
|
2106
2171
|
const direct = await this.load(key, parser);
|
|
2107
2172
|
if (typeof direct !== "undefined") {
|
|
@@ -2159,6 +2224,10 @@ var init_HostedAssetSource = __esm({
|
|
|
2159
2224
|
assetBasePath(key) {
|
|
2160
2225
|
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 + "/" : ""}`;
|
|
2161
2226
|
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Creates a hosted source for {@link AssetLoader.addSource}.
|
|
2229
|
+
* Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
|
|
2230
|
+
*/
|
|
2162
2231
|
constructor(root, options) {
|
|
2163
2232
|
super();
|
|
2164
2233
|
this._root = root;
|
|
@@ -2190,6 +2259,11 @@ var init_BrowserArchiveProxy = __esm({
|
|
|
2190
2259
|
"src/assets/source/archive/BrowserArchiveProxy.ts"() {
|
|
2191
2260
|
import_zip = require("@zip.js/zip.js");
|
|
2192
2261
|
BrowserArchiveProxy = class {
|
|
2262
|
+
/**
|
|
2263
|
+
* Opens a ZIP for asset lookup.
|
|
2264
|
+
* @param id - Cache identity for this content. Change it when the pack changes.
|
|
2265
|
+
* A File supplies an identity from its name, size, and modification time when omitted.
|
|
2266
|
+
*/
|
|
2193
2267
|
constructor(blob, id) {
|
|
2194
2268
|
this._blob = blob;
|
|
2195
2269
|
this._reader = new import_zip.ZipReader(new import_zip.BlobReader(this._blob));
|
|
@@ -2322,27 +2396,27 @@ var init_PackFormats = __esm({
|
|
|
2322
2396
|
this.versions = /* @__PURE__ */ new Map();
|
|
2323
2397
|
}
|
|
2324
2398
|
/** Resolves pack formats from Mojang's client metadata hosted on assets.mcasset.cloud. */
|
|
2325
|
-
static async get(
|
|
2326
|
-
let pending = this.versions.get(
|
|
2399
|
+
static async get(version2, type) {
|
|
2400
|
+
let pending = this.versions.get(version2);
|
|
2327
2401
|
if (!pending || pending.expires <= Date.now()) {
|
|
2328
2402
|
pending = {
|
|
2329
|
-
formats: this.load(
|
|
2330
|
-
expires: ["latest", "release", "snapshot"].includes(
|
|
2403
|
+
formats: this.load(version2),
|
|
2404
|
+
expires: ["latest", "release", "snapshot"].includes(version2) ? Date.now() + 3e5 : Infinity
|
|
2331
2405
|
};
|
|
2332
|
-
this.versions.set(
|
|
2406
|
+
this.versions.set(version2, pending);
|
|
2333
2407
|
}
|
|
2334
2408
|
try {
|
|
2335
2409
|
return (await pending.formats)[type];
|
|
2336
2410
|
} catch (cause) {
|
|
2337
|
-
if (this.versions.get(
|
|
2411
|
+
if (this.versions.get(version2) === pending) this.versions.delete(version2);
|
|
2338
2412
|
const option = type === "assets" ? "resourcePackFormat" : "dataPackFormat";
|
|
2339
2413
|
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
2340
|
-
throw new Error(`Could not resolve the pack format for Minecraft ${
|
|
2414
|
+
throw new Error(`Could not resolve the pack format for Minecraft ${version2}. Set ArchiveAssetSource ${option} explicitly. ${reason}`);
|
|
2341
2415
|
}
|
|
2342
2416
|
}
|
|
2343
|
-
static async load(
|
|
2417
|
+
static async load(version2) {
|
|
2344
2418
|
const response = await Requests.genericRequest({
|
|
2345
|
-
url: `https://assets.mcasset.cloud/${encodeURIComponent(
|
|
2419
|
+
url: `https://assets.mcasset.cloud/${encodeURIComponent(version2)}/game-version.json`,
|
|
2346
2420
|
responseType: "json"
|
|
2347
2421
|
});
|
|
2348
2422
|
const data = response.data;
|
|
@@ -2389,6 +2463,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2389
2463
|
dataPackFormat: copyFormat(options.dataPackFormat)
|
|
2390
2464
|
};
|
|
2391
2465
|
}
|
|
2466
|
+
/** Creates a browser ZIP source from a Blob or File. */
|
|
2392
2467
|
static blob(blob, options) {
|
|
2393
2468
|
return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
|
|
2394
2469
|
}
|
|
@@ -2429,7 +2504,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2429
2504
|
}
|
|
2430
2505
|
async load(key, parser) {
|
|
2431
2506
|
const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
|
|
2432
|
-
const
|
|
2507
|
+
const version2 = AssetLoader.version;
|
|
2433
2508
|
let selectedPath = path;
|
|
2434
2509
|
let url;
|
|
2435
2510
|
try {
|
|
@@ -2437,7 +2512,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2437
2512
|
if (key.rootType === "assets" || key.rootType === "data") {
|
|
2438
2513
|
const metadata = await this.getMetadata(key);
|
|
2439
2514
|
if (metadata.hasOverlays) {
|
|
2440
|
-
const format2 = (key.rootType === "assets" ? this.options.resourcePackFormat : this.options.dataPackFormat) ?? await PackFormats.get(
|
|
2515
|
+
const format2 = (key.rootType === "assets" ? this.options.resourcePackFormat : this.options.dataPackFormat) ?? await PackFormats.get(version2, key.rootType);
|
|
2441
2516
|
directories = metadata.overlayDirectories(format2);
|
|
2442
2517
|
}
|
|
2443
2518
|
}
|
|
@@ -2521,6 +2596,7 @@ var init_AssetLoader = __esm({
|
|
|
2521
2596
|
FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
|
|
2522
2597
|
AssetLoader = class {
|
|
2523
2598
|
static {
|
|
2599
|
+
/** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
|
|
2524
2600
|
this.ROOT = DEFAULT_ROOT;
|
|
2525
2601
|
}
|
|
2526
2602
|
static {
|
|
@@ -2533,8 +2609,9 @@ var init_AssetLoader = __esm({
|
|
|
2533
2609
|
static get version() {
|
|
2534
2610
|
return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
|
|
2535
2611
|
}
|
|
2536
|
-
|
|
2537
|
-
|
|
2612
|
+
/** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
|
|
2613
|
+
static setVersion(version2) {
|
|
2614
|
+
this.ROOT = `https://assets.mcasset.cloud/${version2}`;
|
|
2538
2615
|
const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
|
|
2539
2616
|
const index = this._SOURCES.findIndex((s) => s.key === "mcassets");
|
|
2540
2617
|
if (index !== -1) {
|
|
@@ -2566,6 +2643,13 @@ var init_AssetLoader = __esm({
|
|
|
2566
2643
|
return scope ? `${scope}
|
|
2567
2644
|
${key}` : key;
|
|
2568
2645
|
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Registers a source at the highest priority.
|
|
2648
|
+
* Call {@link Caching.clear} after changing sources to discard previously loaded assets.
|
|
2649
|
+
*
|
|
2650
|
+
* @param key - Name used to replace or remove this source.
|
|
2651
|
+
* @param override - Removes the first source with this name before adding the new one.
|
|
2652
|
+
*/
|
|
2569
2653
|
static addSource(key, source, override = true) {
|
|
2570
2654
|
if (override) {
|
|
2571
2655
|
const existing = this.removeSource(key);
|
|
@@ -2576,6 +2660,7 @@ ${key}` : key;
|
|
|
2576
2660
|
this._SOURCES.unshift({ key, source });
|
|
2577
2661
|
console.log(p4, "Added AssetSource", key);
|
|
2578
2662
|
}
|
|
2663
|
+
/** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
|
|
2579
2664
|
static removeSource(key) {
|
|
2580
2665
|
const index = this._SOURCES.findIndex((s) => s.key === key);
|
|
2581
2666
|
if (index != -1) {
|
|
@@ -2590,12 +2675,13 @@ ${key}` : key;
|
|
|
2590
2675
|
this.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
|
|
2591
2676
|
this.addSource("mcassets", new HostedAssetSource(this.ROOT, { retryDefaults: false }));
|
|
2592
2677
|
}
|
|
2678
|
+
/** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
|
|
2593
2679
|
static async getAll(key, parser) {
|
|
2594
2680
|
const sources = [...this._SOURCES];
|
|
2595
2681
|
const results = [];
|
|
2596
2682
|
for (const { source } of sources) {
|
|
2597
|
-
const
|
|
2598
|
-
if (
|
|
2683
|
+
const asset2 = await source.get(key, parser);
|
|
2684
|
+
if (asset2 != void 0) results.push(asset2);
|
|
2599
2685
|
if (await source.blocks(key)) break;
|
|
2600
2686
|
}
|
|
2601
2687
|
return results;
|
|
@@ -2651,14 +2737,15 @@ var init_ModelTextures = __esm({
|
|
|
2651
2737
|
static get PERSISTENT_META_CACHE() {
|
|
2652
2738
|
return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
|
|
2653
2739
|
}
|
|
2740
|
+
/** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
|
|
2654
2741
|
static async get(key) {
|
|
2655
2742
|
const keyStr = key.serialize();
|
|
2656
2743
|
const pending = this.preload(key);
|
|
2657
2744
|
const cached2 = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
2658
2745
|
try {
|
|
2659
|
-
const
|
|
2660
|
-
if (
|
|
2661
|
-
return await ImageLoader.infoToCanvasData(
|
|
2746
|
+
const asset2 = await pending;
|
|
2747
|
+
if (asset2) {
|
|
2748
|
+
return await ImageLoader.infoToCanvasData(asset2);
|
|
2662
2749
|
}
|
|
2663
2750
|
return void 0;
|
|
2664
2751
|
} catch (err) {
|
|
@@ -2668,16 +2755,18 @@ var init_ModelTextures = __esm({
|
|
|
2668
2755
|
throw err;
|
|
2669
2756
|
}
|
|
2670
2757
|
}
|
|
2758
|
+
/** Fetches and caches encoded texture bytes without decoding the pixels. */
|
|
2671
2759
|
static async preload(key) {
|
|
2672
2760
|
const keyStr = key.serialize();
|
|
2673
2761
|
return Caching.textureAssetCache.get(keyStr, (k) => {
|
|
2674
|
-
return AssetLoader.get(key, "image" /* IMAGE */).then((
|
|
2675
|
-
if (
|
|
2676
|
-
|
|
2677
|
-
return
|
|
2762
|
+
return AssetLoader.get(key, "image" /* IMAGE */).then((asset2) => {
|
|
2763
|
+
if (asset2)
|
|
2764
|
+
asset2.key = key;
|
|
2765
|
+
return asset2;
|
|
2678
2766
|
});
|
|
2679
2767
|
});
|
|
2680
2768
|
}
|
|
2769
|
+
/** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
|
|
2681
2770
|
static async getMeta(key) {
|
|
2682
2771
|
if (!key.extension || !key.extension.endsWith(".mcmeta")) {
|
|
2683
2772
|
key = Object.assign(new AssetKey("", ""), key);
|
|
@@ -2686,14 +2775,15 @@ var init_ModelTextures = __esm({
|
|
|
2686
2775
|
const keyStr = key.serialize();
|
|
2687
2776
|
return Caching.textureMetaCache.get(keyStr, (k) => {
|
|
2688
2777
|
return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
2689
|
-
return AssetLoader.get(key, "meta" /* META */).then((
|
|
2690
|
-
if (
|
|
2691
|
-
|
|
2692
|
-
return
|
|
2778
|
+
return AssetLoader.get(key, "meta" /* META */).then((asset2) => {
|
|
2779
|
+
if (asset2)
|
|
2780
|
+
asset2.key = key;
|
|
2781
|
+
return asset2;
|
|
2693
2782
|
});
|
|
2694
2783
|
});
|
|
2695
2784
|
});
|
|
2696
2785
|
}
|
|
2786
|
+
/** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
|
|
2697
2787
|
static async clearCache() {
|
|
2698
2788
|
await this.PERSISTENT_META_CACHE.clear();
|
|
2699
2789
|
}
|
|
@@ -2781,6 +2871,7 @@ var init_Ticker = __esm({
|
|
|
2781
2871
|
}
|
|
2782
2872
|
return handle;
|
|
2783
2873
|
}
|
|
2874
|
+
/** Starts or resumes the shared tick loop. Repeated calls have no effect. */
|
|
2784
2875
|
static start() {
|
|
2785
2876
|
if (this.interval) return;
|
|
2786
2877
|
this.interval = this.schedule(() => {
|
|
@@ -2803,6 +2894,7 @@ var init_Ticker = __esm({
|
|
|
2803
2894
|
_Ticker.fiveSecondTicks = 0;
|
|
2804
2895
|
}, 1e3 * 5);
|
|
2805
2896
|
}
|
|
2897
|
+
/** Pauses the loop while retaining callbacks for a later {@link start}. */
|
|
2806
2898
|
static stop() {
|
|
2807
2899
|
if (this.interval) clearInterval(this.interval);
|
|
2808
2900
|
if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
|
|
@@ -2811,12 +2903,14 @@ var init_Ticker = __esm({
|
|
|
2811
2903
|
this.oneSecondTicksTracker = void 0;
|
|
2812
2904
|
this.fiveSecondTicksTracker = void 0;
|
|
2813
2905
|
}
|
|
2906
|
+
/** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
|
|
2814
2907
|
static add(tick) {
|
|
2815
2908
|
this.start();
|
|
2816
2909
|
const c = this.counter++;
|
|
2817
2910
|
this._tickers.set(c, tick);
|
|
2818
2911
|
return c;
|
|
2819
2912
|
}
|
|
2913
|
+
/** Removes a callback by ID and stops the timers when no callbacks remain. */
|
|
2820
2914
|
static remove(c) {
|
|
2821
2915
|
if (typeof c === "number") this._tickers.delete(c);
|
|
2822
2916
|
if (!this._tickers.size) this.stop();
|
|
@@ -2830,6 +2924,7 @@ var init_Ticker = __esm({
|
|
|
2830
2924
|
static get tpsFiveSeconds() {
|
|
2831
2925
|
return this.fiveSecondTps;
|
|
2832
2926
|
}
|
|
2927
|
+
/** Stops the loop and removes all registered callbacks. */
|
|
2833
2928
|
static dispose() {
|
|
2834
2929
|
this.stop();
|
|
2835
2930
|
this._tickers.clear();
|
|
@@ -2876,6 +2971,7 @@ var init_TextureAtlas = __esm({
|
|
|
2876
2971
|
}
|
|
2877
2972
|
};
|
|
2878
2973
|
}
|
|
2974
|
+
/** Copies pixels for a texture variable from its current atlas rectangle. */
|
|
2879
2975
|
getData(texture) {
|
|
2880
2976
|
const pos = this.positions[texture];
|
|
2881
2977
|
const size = this.sizes[texture];
|
|
@@ -3155,6 +3251,7 @@ var init_UVMapper = __esm({
|
|
|
3155
3251
|
}
|
|
3156
3252
|
uv.needsUpdate = true;
|
|
3157
3253
|
}
|
|
3254
|
+
/** Returns the shared atlas for a keyed, merged model, creating it on first use. */
|
|
3158
3255
|
static async getAtlas(model) {
|
|
3159
3256
|
const keyStr = model.key.serialize();
|
|
3160
3257
|
return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
|
|
@@ -3225,6 +3322,11 @@ var init_UVMapper = __esm({
|
|
|
3225
3322
|
}
|
|
3226
3323
|
return [tl, tr, bl, br];
|
|
3227
3324
|
}
|
|
3325
|
+
/**
|
|
3326
|
+
* Combines model textures and animation metadata into an atlas.
|
|
3327
|
+
* Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
|
|
3328
|
+
* Returns `undefined` for models without a texture map.
|
|
3329
|
+
*/
|
|
3228
3330
|
static async createAtlas(originalModel) {
|
|
3229
3331
|
const textureMap = {};
|
|
3230
3332
|
const metaMap = {};
|
|
@@ -3245,12 +3347,12 @@ var init_UVMapper = __esm({
|
|
|
3245
3347
|
} else {
|
|
3246
3348
|
uniqueTextureNames.push(textureKey);
|
|
3247
3349
|
const assetKey = AssetKey.parse("textures", textureValue, model.key);
|
|
3248
|
-
promises.push(ModelTextures.get(assetKey).then((
|
|
3249
|
-
if (!
|
|
3350
|
+
promises.push(ModelTextures.get(assetKey).then((asset2) => {
|
|
3351
|
+
if (!asset2) {
|
|
3250
3352
|
console.warn(p5, "Missing texture", assetKey);
|
|
3251
3353
|
return;
|
|
3252
3354
|
}
|
|
3253
|
-
textureMap[textureKey] = new WrappedImage(
|
|
3355
|
+
textureMap[textureKey] = new WrappedImage(asset2);
|
|
3254
3356
|
}));
|
|
3255
3357
|
promises.push(ModelTextures.getMeta(assetKey).then((meta) => {
|
|
3256
3358
|
metaMap[textureKey] = meta;
|
|
@@ -3589,14 +3691,15 @@ var init_Entities = __esm({
|
|
|
3589
3691
|
init_MineRenderError();
|
|
3590
3692
|
init_ModelTextures();
|
|
3591
3693
|
Entities = class {
|
|
3694
|
+
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
3592
3695
|
static async getEntityList() {
|
|
3593
3696
|
const collect = async (path) => {
|
|
3594
3697
|
const prefix2 = path ? `${path}/` : "";
|
|
3595
3698
|
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
|
|
3596
|
-
const
|
|
3597
|
-
if (!
|
|
3598
|
-
const files =
|
|
3599
|
-
const children = await Promise.all(
|
|
3699
|
+
const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
|
|
3700
|
+
if (!list2) return [];
|
|
3701
|
+
const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
|
|
3702
|
+
const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
|
|
3600
3703
|
return [...files, ...children.flat()];
|
|
3601
3704
|
};
|
|
3602
3705
|
return collect("");
|
|
@@ -3606,6 +3709,7 @@ var init_Entities = __esm({
|
|
|
3606
3709
|
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
3607
3710
|
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3608
3711
|
}
|
|
3712
|
+
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
3609
3713
|
static async getLayerList(modelKey) {
|
|
3610
3714
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
3611
3715
|
}
|
|
@@ -3613,6 +3717,15 @@ var init_Entities = __esm({
|
|
|
3613
3717
|
static async getPassList(modelKey) {
|
|
3614
3718
|
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
3615
3719
|
}
|
|
3720
|
+
/**
|
|
3721
|
+
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
3722
|
+
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
3723
|
+
*
|
|
3724
|
+
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
3725
|
+
* @param textureKey - Texture override for the first selected layer.
|
|
3726
|
+
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
3727
|
+
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
3728
|
+
*/
|
|
3616
3729
|
static async getEntity(modelKey, textureKey, options) {
|
|
3617
3730
|
const model = await this.getModelFile(modelKey);
|
|
3618
3731
|
if (!model) return void 0;
|
|
@@ -3658,6 +3771,7 @@ var init_Entities = __esm({
|
|
|
3658
3771
|
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3659
3772
|
return file?.animations;
|
|
3660
3773
|
}
|
|
3774
|
+
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
3661
3775
|
static async resolveTexture(modelKey) {
|
|
3662
3776
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3663
3777
|
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
@@ -3669,8 +3783,8 @@ var init_Entities = __esm({
|
|
|
3669
3783
|
if (await ModelTextures.get(texture2)) return texture2;
|
|
3670
3784
|
}
|
|
3671
3785
|
const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
|
|
3672
|
-
const
|
|
3673
|
-
const files =
|
|
3786
|
+
const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
|
|
3787
|
+
const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
|
|
3674
3788
|
const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
|
|
3675
3789
|
if (!file) return void 0;
|
|
3676
3790
|
const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
|
|
@@ -3775,27 +3889,27 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3775
3889
|
for (const layer of layers) {
|
|
3776
3890
|
const objects = [];
|
|
3777
3891
|
if (poses) {
|
|
3778
|
-
layer.traverse((
|
|
3779
|
-
if (poses.has(
|
|
3892
|
+
layer.traverse((object3) => {
|
|
3893
|
+
if (poses.has(object3)) objects.push(object3);
|
|
3780
3894
|
});
|
|
3781
3895
|
} else {
|
|
3782
3896
|
for (const bone of Object.keys(animation.bones)) {
|
|
3783
|
-
const
|
|
3784
|
-
if (
|
|
3897
|
+
const object3 = layer.getObjectByName(`group:${bone}`);
|
|
3898
|
+
if (object3) objects.push(object3);
|
|
3785
3899
|
}
|
|
3786
3900
|
}
|
|
3787
|
-
for (const
|
|
3788
|
-
const bone =
|
|
3789
|
-
const pose = poses?.get(
|
|
3901
|
+
for (const object3 of objects) {
|
|
3902
|
+
const bone = object3.name.slice("group:".length);
|
|
3903
|
+
const pose = poses?.get(object3);
|
|
3790
3904
|
this.parts.push({
|
|
3791
3905
|
bone,
|
|
3792
|
-
object:
|
|
3793
|
-
position:
|
|
3794
|
-
rotation:
|
|
3795
|
-
scale:
|
|
3796
|
-
basePosition: pose ? new import_three11.Vector3(...pose.offset) :
|
|
3797
|
-
baseRotation: pose ? new import_three11.Euler(...pose.rotation, "ZYX") :
|
|
3798
|
-
baseScale: pose ? new import_three11.Vector3(...pose.scale ?? [1, 1, 1]) :
|
|
3906
|
+
object: object3,
|
|
3907
|
+
position: object3.position.clone(),
|
|
3908
|
+
rotation: object3.rotation.clone(),
|
|
3909
|
+
scale: object3.scale.clone(),
|
|
3910
|
+
basePosition: pose ? new import_three11.Vector3(...pose.offset) : object3.position.clone(),
|
|
3911
|
+
baseRotation: pose ? new import_three11.Euler(...pose.rotation, "ZYX") : object3.rotation.clone(),
|
|
3912
|
+
baseScale: pose ? new import_three11.Vector3(...pose.scale ?? [1, 1, 1]) : object3.scale.clone()
|
|
3799
3913
|
});
|
|
3800
3914
|
}
|
|
3801
3915
|
}
|
|
@@ -3818,12 +3932,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3818
3932
|
this._animation = void 0;
|
|
3819
3933
|
this._time = 0;
|
|
3820
3934
|
}
|
|
3935
|
+
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
3821
3936
|
setTime(seconds) {
|
|
3822
3937
|
if (!this._animation) return false;
|
|
3823
3938
|
this._time = seconds;
|
|
3824
3939
|
this.apply();
|
|
3825
3940
|
return true;
|
|
3826
3941
|
}
|
|
3942
|
+
/** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
|
|
3827
3943
|
advance(deltaSeconds) {
|
|
3828
3944
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
3829
3945
|
}
|
|
@@ -3861,6 +3977,7 @@ var init_InstanceReference = __esm({
|
|
|
3861
3977
|
if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
|
|
3862
3978
|
return this.instanceable;
|
|
3863
3979
|
}
|
|
3980
|
+
/** Releases this placement's slot for reuse. Repeated calls have no effect. */
|
|
3864
3981
|
removeFromScene() {
|
|
3865
3982
|
if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
|
|
3866
3983
|
}
|
|
@@ -3873,9 +3990,11 @@ var init_InstanceReference = __esm({
|
|
|
3873
3990
|
setMatrix(matrix) {
|
|
3874
3991
|
this.activeInstanceable.setMatrixAt(this.index, matrix);
|
|
3875
3992
|
}
|
|
3993
|
+
/** Hides or restores this placement while preserving its transform and allocated slot. */
|
|
3876
3994
|
setVisible(visible) {
|
|
3877
3995
|
this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
|
|
3878
3996
|
}
|
|
3997
|
+
/** Updates the supplied transform components. Positions use scene units and rotations use radians. */
|
|
3879
3998
|
setPositionRotationScale(position, rotation, scale) {
|
|
3880
3999
|
this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
|
|
3881
4000
|
}
|
|
@@ -3952,6 +4071,7 @@ var init_SceneObject = __esm({
|
|
|
3952
4071
|
}
|
|
3953
4072
|
async init() {
|
|
3954
4073
|
}
|
|
4074
|
+
/** Marks ancestor scenes for redraw and emits a `change` event. */
|
|
3955
4075
|
notifyDirty() {
|
|
3956
4076
|
this.traverseAncestors((parent) => {
|
|
3957
4077
|
const scene = parent;
|
|
@@ -3987,15 +4107,17 @@ var init_SceneObject = __esm({
|
|
|
3987
4107
|
return obj;
|
|
3988
4108
|
}
|
|
3989
4109
|
/**
|
|
3990
|
-
*
|
|
4110
|
+
* Finds a named part, such as `head`, without the internal `group:` prefix.
|
|
4111
|
+
* Returns `undefined` when the group does not exist.
|
|
3991
4112
|
*/
|
|
3992
4113
|
getGroupByName(name) {
|
|
3993
4114
|
return this.getObjectByName(`group:${name}`);
|
|
3994
4115
|
}
|
|
3995
4116
|
/**
|
|
3996
|
-
*
|
|
3997
|
-
* @param name name
|
|
3998
|
-
* @param visible
|
|
4117
|
+
* Changes a named group's visibility and requests a redraw.
|
|
4118
|
+
* @param name - Part name without the `group:` prefix.
|
|
4119
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4120
|
+
* @returns The resulting visibility, or `false` if the group does not exist.
|
|
3999
4121
|
*/
|
|
4000
4122
|
toggleGroupVisibility(name, visible) {
|
|
4001
4123
|
return this.toggleObjectVisibility(this.getGroupByName(name), visible);
|
|
@@ -4046,15 +4168,16 @@ var init_SceneObject = __esm({
|
|
|
4046
4168
|
return mesh;
|
|
4047
4169
|
}
|
|
4048
4170
|
/**
|
|
4049
|
-
*
|
|
4171
|
+
* Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
|
|
4050
4172
|
*/
|
|
4051
4173
|
getMeshByName(name) {
|
|
4052
4174
|
return this.getObjectByName(`mesh:${name}`);
|
|
4053
4175
|
}
|
|
4054
4176
|
/**
|
|
4055
|
-
*
|
|
4056
|
-
* @param name name
|
|
4057
|
-
* @param visible
|
|
4177
|
+
* Changes a named mesh's visibility and requests a redraw.
|
|
4178
|
+
* @param name - Mesh name without the `mesh:` prefix.
|
|
4179
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4180
|
+
* @returns The resulting visibility, or `false` if the mesh does not exist.
|
|
4058
4181
|
*/
|
|
4059
4182
|
toggleMeshVisibility(name, visible) {
|
|
4060
4183
|
return this.toggleObjectVisibility(this.getMeshByName(name), visible);
|
|
@@ -4100,12 +4223,14 @@ var init_SceneObject = __esm({
|
|
|
4100
4223
|
get isInstanced() {
|
|
4101
4224
|
return this._isInstanced;
|
|
4102
4225
|
}
|
|
4226
|
+
/** Number of live placements, excluding released instance slots. */
|
|
4103
4227
|
get instanceCounter() {
|
|
4104
4228
|
return this._instanceCounter;
|
|
4105
4229
|
}
|
|
4106
4230
|
constructInstanceReference(i) {
|
|
4107
4231
|
return new InstanceReference(this, i);
|
|
4108
4232
|
}
|
|
4233
|
+
/** Allocates a placement of this instanced object, reusing a released slot when available. */
|
|
4109
4234
|
nextInstance() {
|
|
4110
4235
|
const mesh = this.instanceMesh;
|
|
4111
4236
|
if (!mesh) throw new MineRenderError("Object is not instanced");
|
|
@@ -4150,10 +4275,10 @@ var init_SceneObject = __esm({
|
|
|
4150
4275
|
return new import_three12.InstancedBufferAttribute(array, attribute.itemSize, attribute.normalized, attribute.meshPerAttribute).setUsage(attribute.usage);
|
|
4151
4276
|
};
|
|
4152
4277
|
const matrix = grow(mesh.instanceMatrix, 0);
|
|
4153
|
-
const
|
|
4278
|
+
const color2 = mesh.instanceColor ? grow(mesh.instanceColor, 1) : null;
|
|
4154
4279
|
mesh.dispose();
|
|
4155
4280
|
mesh.instanceMatrix = matrix;
|
|
4156
|
-
mesh.instanceColor =
|
|
4281
|
+
mesh.instanceColor = color2;
|
|
4157
4282
|
}
|
|
4158
4283
|
*activeInstanceIndices() {
|
|
4159
4284
|
if (this.instanceMesh) {
|
|
@@ -4252,6 +4377,7 @@ var init_SceneObject = __esm({
|
|
|
4252
4377
|
vector.setFromMatrixScale(matrix);
|
|
4253
4378
|
return vector;
|
|
4254
4379
|
}
|
|
4380
|
+
/** Updates supplied transform components. For a shared model, affects every live instance. */
|
|
4255
4381
|
setPositionRotationScale(position, rotation, scale) {
|
|
4256
4382
|
if (this.isInstanced) {
|
|
4257
4383
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4270,6 +4396,7 @@ var init_SceneObject = __esm({
|
|
|
4270
4396
|
}
|
|
4271
4397
|
this.notifyDirty();
|
|
4272
4398
|
}
|
|
4399
|
+
/** Sets position in scene units. For a shared model, updates every live instance. */
|
|
4273
4400
|
setPosition(position) {
|
|
4274
4401
|
if (this.isInstanced) {
|
|
4275
4402
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4287,6 +4414,7 @@ var init_SceneObject = __esm({
|
|
|
4287
4414
|
return this.position;
|
|
4288
4415
|
}
|
|
4289
4416
|
}
|
|
4417
|
+
/** Sets rotation in radians. For a shared model, updates every live instance. */
|
|
4290
4418
|
setRotation(rotation) {
|
|
4291
4419
|
if (this.isInstanced) {
|
|
4292
4420
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4304,6 +4432,7 @@ var init_SceneObject = __esm({
|
|
|
4304
4432
|
return this.rotation;
|
|
4305
4433
|
}
|
|
4306
4434
|
}
|
|
4435
|
+
/** Sets scale factors. For a shared model, updates every live instance. */
|
|
4307
4436
|
setScale(scale) {
|
|
4308
4437
|
if (this.isInstanced) {
|
|
4309
4438
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4322,15 +4451,15 @@ var init_SceneObject = __esm({
|
|
|
4322
4451
|
}
|
|
4323
4452
|
}
|
|
4324
4453
|
//</editor-fold>
|
|
4325
|
-
toggleObjectVisibility(
|
|
4326
|
-
if (
|
|
4454
|
+
toggleObjectVisibility(object3, visible) {
|
|
4455
|
+
if (object3) {
|
|
4327
4456
|
if (typeof visible !== "undefined") {
|
|
4328
|
-
|
|
4457
|
+
object3.visible = visible;
|
|
4329
4458
|
} else {
|
|
4330
|
-
|
|
4459
|
+
object3.visible = !object3.visible;
|
|
4331
4460
|
}
|
|
4332
4461
|
this.notifyDirty();
|
|
4333
|
-
return
|
|
4462
|
+
return object3.visible;
|
|
4334
4463
|
}
|
|
4335
4464
|
this.notifyDirty();
|
|
4336
4465
|
return false;
|
|
@@ -4341,6 +4470,7 @@ var init_SceneObject = __esm({
|
|
|
4341
4470
|
this.notifyDirty();
|
|
4342
4471
|
super.dispose();
|
|
4343
4472
|
}
|
|
4473
|
+
/** Releases instance slots and removes children, disposing children that implement Disposable. */
|
|
4344
4474
|
disposeAndRemoveAllChildren() {
|
|
4345
4475
|
if (this.instanceMesh) {
|
|
4346
4476
|
if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
|
|
@@ -4363,6 +4493,7 @@ var init_SceneObject = __esm({
|
|
|
4363
4493
|
}
|
|
4364
4494
|
this.notifyDirty();
|
|
4365
4495
|
}
|
|
4496
|
+
/** Detaches the object from its parent and requests a redraw. */
|
|
4366
4497
|
removeFromScene() {
|
|
4367
4498
|
this.notifyDirty();
|
|
4368
4499
|
this.removeFromParent();
|
|
@@ -4514,12 +4645,15 @@ var init_EntityObject = __esm({
|
|
|
4514
4645
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
4515
4646
|
}
|
|
4516
4647
|
//</editor-fold>
|
|
4648
|
+
/** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
|
|
4517
4649
|
getLayerGroup(name) {
|
|
4518
4650
|
return super.getGroupByName(`layer:${name}`);
|
|
4519
4651
|
}
|
|
4652
|
+
/** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
|
|
4520
4653
|
getGroupByName(name, layerName) {
|
|
4521
4654
|
return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
|
|
4522
4655
|
}
|
|
4656
|
+
/** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
|
|
4523
4657
|
getMeshByName(name, layerName) {
|
|
4524
4658
|
return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
|
|
4525
4659
|
}
|
|
@@ -4621,8 +4755,8 @@ var init_EntityObject = __esm({
|
|
|
4621
4755
|
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
4622
4756
|
}
|
|
4623
4757
|
}
|
|
4624
|
-
this.getLayerGroup(name)?.traverse((
|
|
4625
|
-
if (isMesh(
|
|
4758
|
+
this.getLayerGroup(name)?.traverse((object3) => {
|
|
4759
|
+
if (isMesh(object3)) object3.material = mat;
|
|
4626
4760
|
});
|
|
4627
4761
|
}));
|
|
4628
4762
|
if (!this.children.length) {
|
|
@@ -4950,8 +5084,8 @@ function toTrianglesDrawMode(geometry, drawMode) {
|
|
|
4950
5084
|
return geometry;
|
|
4951
5085
|
}
|
|
4952
5086
|
}
|
|
4953
|
-
function computeMorphedAttributes(
|
|
4954
|
-
if (
|
|
5087
|
+
function computeMorphedAttributes(object3) {
|
|
5088
|
+
if (object3.geometry.isBufferGeometry !== true) {
|
|
4955
5089
|
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
|
|
4956
5090
|
return null;
|
|
4957
5091
|
}
|
|
@@ -4964,11 +5098,11 @@ function computeMorphedAttributes(object2) {
|
|
|
4964
5098
|
const _morphA = new import_three22.Vector3();
|
|
4965
5099
|
const _morphB = new import_three22.Vector3();
|
|
4966
5100
|
const _morphC = new import_three22.Vector3();
|
|
4967
|
-
function _calculateMorphedAttributeData(
|
|
5101
|
+
function _calculateMorphedAttributeData(object4, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
|
|
4968
5102
|
_vA.fromBufferAttribute(attribute, a2);
|
|
4969
5103
|
_vB.fromBufferAttribute(attribute, b2);
|
|
4970
5104
|
_vC.fromBufferAttribute(attribute, c2);
|
|
4971
|
-
const morphInfluences =
|
|
5105
|
+
const morphInfluences = object4.morphTargetInfluences;
|
|
4972
5106
|
if (material2.morphTargets && morphAttribute && morphInfluences) {
|
|
4973
5107
|
_morphA.set(0, 0, 0);
|
|
4974
5108
|
_morphB.set(0, 0, 0);
|
|
@@ -4994,10 +5128,10 @@ function computeMorphedAttributes(object2) {
|
|
|
4994
5128
|
_vB.add(_morphB);
|
|
4995
5129
|
_vC.add(_morphC);
|
|
4996
5130
|
}
|
|
4997
|
-
if (
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5131
|
+
if (object4.isSkinnedMesh) {
|
|
5132
|
+
object4.boneTransform(a2, _vA);
|
|
5133
|
+
object4.boneTransform(b2, _vB);
|
|
5134
|
+
object4.boneTransform(c2, _vC);
|
|
5001
5135
|
}
|
|
5002
5136
|
modifiedAttributeArray[a2 * 3 + 0] = _vA.x;
|
|
5003
5137
|
modifiedAttributeArray[a2 * 3 + 1] = _vA.y;
|
|
@@ -5009,8 +5143,8 @@ function computeMorphedAttributes(object2) {
|
|
|
5009
5143
|
modifiedAttributeArray[c2 * 3 + 1] = _vC.y;
|
|
5010
5144
|
modifiedAttributeArray[c2 * 3 + 2] = _vC.z;
|
|
5011
5145
|
}
|
|
5012
|
-
const geometry =
|
|
5013
|
-
const material =
|
|
5146
|
+
const geometry = object3.geometry;
|
|
5147
|
+
const material = object3.material;
|
|
5014
5148
|
let a, b, c;
|
|
5015
5149
|
const index = geometry.index;
|
|
5016
5150
|
const positionAttribute = geometry.attributes.position;
|
|
@@ -5037,7 +5171,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5037
5171
|
b = index.getX(j + 1);
|
|
5038
5172
|
c = index.getX(j + 2);
|
|
5039
5173
|
_calculateMorphedAttributeData(
|
|
5040
|
-
|
|
5174
|
+
object3,
|
|
5041
5175
|
groupMaterial,
|
|
5042
5176
|
positionAttribute,
|
|
5043
5177
|
morphPosition,
|
|
@@ -5048,7 +5182,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5048
5182
|
modifiedPosition
|
|
5049
5183
|
);
|
|
5050
5184
|
_calculateMorphedAttributeData(
|
|
5051
|
-
|
|
5185
|
+
object3,
|
|
5052
5186
|
groupMaterial,
|
|
5053
5187
|
normalAttribute,
|
|
5054
5188
|
morphNormal,
|
|
@@ -5068,7 +5202,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5068
5202
|
b = index.getX(i + 1);
|
|
5069
5203
|
c = index.getX(i + 2);
|
|
5070
5204
|
_calculateMorphedAttributeData(
|
|
5071
|
-
|
|
5205
|
+
object3,
|
|
5072
5206
|
material,
|
|
5073
5207
|
positionAttribute,
|
|
5074
5208
|
morphPosition,
|
|
@@ -5079,7 +5213,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5079
5213
|
modifiedPosition
|
|
5080
5214
|
);
|
|
5081
5215
|
_calculateMorphedAttributeData(
|
|
5082
|
-
|
|
5216
|
+
object3,
|
|
5083
5217
|
material,
|
|
5084
5218
|
normalAttribute,
|
|
5085
5219
|
morphNormal,
|
|
@@ -5103,7 +5237,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5103
5237
|
b = j + 1;
|
|
5104
5238
|
c = j + 2;
|
|
5105
5239
|
_calculateMorphedAttributeData(
|
|
5106
|
-
|
|
5240
|
+
object3,
|
|
5107
5241
|
groupMaterial,
|
|
5108
5242
|
positionAttribute,
|
|
5109
5243
|
morphPosition,
|
|
@@ -5114,7 +5248,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5114
5248
|
modifiedPosition
|
|
5115
5249
|
);
|
|
5116
5250
|
_calculateMorphedAttributeData(
|
|
5117
|
-
|
|
5251
|
+
object3,
|
|
5118
5252
|
groupMaterial,
|
|
5119
5253
|
normalAttribute,
|
|
5120
5254
|
morphNormal,
|
|
@@ -5134,7 +5268,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5134
5268
|
b = i + 1;
|
|
5135
5269
|
c = i + 2;
|
|
5136
5270
|
_calculateMorphedAttributeData(
|
|
5137
|
-
|
|
5271
|
+
object3,
|
|
5138
5272
|
material,
|
|
5139
5273
|
positionAttribute,
|
|
5140
5274
|
morphPosition,
|
|
@@ -5145,7 +5279,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5145
5279
|
modifiedPosition
|
|
5146
5280
|
);
|
|
5147
5281
|
_calculateMorphedAttributeData(
|
|
5148
|
-
|
|
5282
|
+
object3,
|
|
5149
5283
|
material,
|
|
5150
5284
|
normalAttribute,
|
|
5151
5285
|
morphNormal,
|
|
@@ -5181,6 +5315,7 @@ var init_ModelCulling = __esm({
|
|
|
5181
5315
|
import_three23 = require("three");
|
|
5182
5316
|
init_CubeFace();
|
|
5183
5317
|
ModelCulling = class {
|
|
5318
|
+
/** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
|
|
5184
5319
|
static toLocalMask(worldMask, rotation) {
|
|
5185
5320
|
let localMask = 0;
|
|
5186
5321
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
@@ -5191,6 +5326,7 @@ var init_ModelCulling = __esm({
|
|
|
5191
5326
|
}
|
|
5192
5327
|
return localMask;
|
|
5193
5328
|
}
|
|
5329
|
+
/** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
|
|
5194
5330
|
static isOpaqueFullCube(atlas) {
|
|
5195
5331
|
if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
|
|
5196
5332
|
const element = atlas.model.elements[0];
|
|
@@ -5401,9 +5537,9 @@ var init_ItemTints = __esm({
|
|
|
5401
5537
|
}));
|
|
5402
5538
|
return colors;
|
|
5403
5539
|
}
|
|
5404
|
-
static rgb(
|
|
5405
|
-
if (!Array.isArray(
|
|
5406
|
-
const [red, green, blue] =
|
|
5540
|
+
static rgb(color2) {
|
|
5541
|
+
if (!Array.isArray(color2)) return color2 & 16777215;
|
|
5542
|
+
const [red, green, blue] = color2.map((channel) => Math.floor(Math.fround(Math.fround(channel) * 255)));
|
|
5407
5543
|
return red << 16 | green << 8 | blue;
|
|
5408
5544
|
}
|
|
5409
5545
|
};
|
|
@@ -5459,13 +5595,13 @@ var init_ModelObject = __esm({
|
|
|
5459
5595
|
transform.multiply(new import_three25.Matrix4().makeTranslation(-8, -8, -8));
|
|
5460
5596
|
try {
|
|
5461
5597
|
for (const part of parts) {
|
|
5462
|
-
const
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
this.add(
|
|
5467
|
-
await
|
|
5468
|
-
|
|
5598
|
+
const object3 = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
|
|
5599
|
+
object3.matrix.copy(transform).multiply(part.transform);
|
|
5600
|
+
object3.matrixWorldNeedsUpdate = true;
|
|
5601
|
+
object3.matrixAutoUpdate = false;
|
|
5602
|
+
this.add(object3);
|
|
5603
|
+
await object3.init();
|
|
5604
|
+
object3.iterateAllMeshes((mesh) => {
|
|
5469
5605
|
const source = mesh.material;
|
|
5470
5606
|
let material = this.specialMaterials.get(source);
|
|
5471
5607
|
if (!material) {
|
|
@@ -5476,7 +5612,7 @@ var init_ModelObject = __esm({
|
|
|
5476
5612
|
mesh.material = material;
|
|
5477
5613
|
});
|
|
5478
5614
|
for (const [name, rotation] of Object.entries(part.rotations)) {
|
|
5479
|
-
|
|
5615
|
+
object3.getGroupByName(name)?.rotation.set(...rotation, "ZYX");
|
|
5480
5616
|
}
|
|
5481
5617
|
}
|
|
5482
5618
|
} catch (error) {
|
|
@@ -5529,9 +5665,9 @@ var init_ModelObject = __esm({
|
|
|
5529
5665
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
5530
5666
|
const tint = this.options.tints[tintIndex];
|
|
5531
5667
|
if (tint === void 0) continue;
|
|
5532
|
-
const
|
|
5668
|
+
const color2 = new import_three25.Color(tint);
|
|
5533
5669
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
5534
|
-
|
|
5670
|
+
color2.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
5535
5671
|
}
|
|
5536
5672
|
}
|
|
5537
5673
|
elGeo.setAttribute("color", new import_three25.BufferAttribute(colors, 3));
|
|
@@ -5846,9 +5982,9 @@ var init_FluidModelObject = __esm({
|
|
|
5846
5982
|
}
|
|
5847
5983
|
}
|
|
5848
5984
|
geometry.clearGroups();
|
|
5849
|
-
const
|
|
5985
|
+
const color2 = new import_three31.Color(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
5850
5986
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
5851
|
-
for (let i = 0; i < colors.length; i += 3)
|
|
5987
|
+
for (let i = 0; i < colors.length; i += 3) color2.toArray(colors, i);
|
|
5852
5988
|
geometry.setAttribute("color", new import_three31.BufferAttribute(colors, 3));
|
|
5853
5989
|
geometry.computeBoundingBox();
|
|
5854
5990
|
geometry.computeBoundingSphere();
|
|
@@ -5959,6 +6095,7 @@ __export(index_node_exports, {
|
|
|
5959
6095
|
RequestError: () => RequestError,
|
|
5960
6096
|
Requests: () => Requests,
|
|
5961
6097
|
SKIN_PARTS: () => SKIN_PARTS,
|
|
6098
|
+
SceneDocumentLoader: () => SceneDocumentLoader,
|
|
5962
6099
|
SceneExporter: () => SceneExporter,
|
|
5963
6100
|
SceneInspector: () => SceneInspector,
|
|
5964
6101
|
SceneObject: () => SceneObject,
|
|
@@ -6034,6 +6171,7 @@ __export(index_node_exports, {
|
|
|
6034
6171
|
mergeBufferAttributes: () => mergeBufferAttributes,
|
|
6035
6172
|
mergeBufferGeometries: () => mergeBufferGeometries,
|
|
6036
6173
|
mergeVertices: () => mergeVertices,
|
|
6174
|
+
parseSceneDocument: () => parseSceneDocument,
|
|
6037
6175
|
prefix: () => prefix,
|
|
6038
6176
|
registerNodeEnv: () => registerNodeEnv,
|
|
6039
6177
|
sampleEntityAnimation: () => sampleEntityAnimation,
|
|
@@ -6124,9 +6262,9 @@ var NodeEnv = class {
|
|
|
6124
6262
|
imageSize(data) {
|
|
6125
6263
|
return (0, import_image_size.default)(Buffer.isBuffer(data) ? data : Buffer.from(data));
|
|
6126
6264
|
}
|
|
6127
|
-
openCache(name,
|
|
6265
|
+
openCache(name, version2) {
|
|
6128
6266
|
return new NodeCache(import_node_persist.default.create({
|
|
6129
|
-
dir: name +
|
|
6267
|
+
dir: name + version2,
|
|
6130
6268
|
encoding: "utf8"
|
|
6131
6269
|
}));
|
|
6132
6270
|
}
|
|
@@ -6158,6 +6296,7 @@ var Meshes = class _Meshes {
|
|
|
6158
6296
|
static createBox(key) {
|
|
6159
6297
|
return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
|
|
6160
6298
|
}
|
|
6299
|
+
/** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
|
|
6161
6300
|
static getBox(key) {
|
|
6162
6301
|
const keyStr = serializeMeshKey(key);
|
|
6163
6302
|
return Caching.boxMeshCache.get(keyStr, (k) => {
|
|
@@ -6270,6 +6409,7 @@ init_AssetParsers();
|
|
|
6270
6409
|
init_ModelTextures();
|
|
6271
6410
|
init_Caching();
|
|
6272
6411
|
var Fonts = class {
|
|
6412
|
+
/** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
|
|
6273
6413
|
static async get(key = "minecraft:default") {
|
|
6274
6414
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
6275
6415
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -6285,8 +6425,8 @@ var Fonts = class {
|
|
|
6285
6425
|
const stack = await AssetLoader.getAll(key, "json" /* JSON */);
|
|
6286
6426
|
if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
|
|
6287
6427
|
const glyphs = /* @__PURE__ */ new Map();
|
|
6288
|
-
for (const
|
|
6289
|
-
for (const provider of
|
|
6428
|
+
for (const asset2 of stack) {
|
|
6429
|
+
for (const provider of asset2.providers) {
|
|
6290
6430
|
if (provider.filter?.uniform || provider.filter?.jp) continue;
|
|
6291
6431
|
let provided;
|
|
6292
6432
|
switch (provider.type) {
|
|
@@ -6425,13 +6565,13 @@ var OBJExporter = class {
|
|
|
6425
6565
|
* @param {Object3D} object - The 3D object to export.
|
|
6426
6566
|
* @return {string} The exported OBJ.
|
|
6427
6567
|
*/
|
|
6428
|
-
parse(
|
|
6568
|
+
parse(object3) {
|
|
6429
6569
|
let output = "";
|
|
6430
6570
|
let indexVertex = 0;
|
|
6431
6571
|
let indexVertexUvs = 0;
|
|
6432
6572
|
let indexNormals = 0;
|
|
6433
6573
|
const vertex = new import_three16.Vector3();
|
|
6434
|
-
const
|
|
6574
|
+
const color2 = new import_three16.Color();
|
|
6435
6575
|
const normal = new import_three16.Vector3();
|
|
6436
6576
|
const uv = new import_three16.Vector2();
|
|
6437
6577
|
const face = [];
|
|
@@ -6530,9 +6670,9 @@ var OBJExporter = class {
|
|
|
6530
6670
|
vertex.applyMatrix4(points.matrixWorld);
|
|
6531
6671
|
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
6532
6672
|
if (colors !== void 0) {
|
|
6533
|
-
|
|
6534
|
-
import_three16.ColorManagement.workingToColorSpace(
|
|
6535
|
-
output += " " +
|
|
6673
|
+
color2.fromBufferAttribute(colors, i);
|
|
6674
|
+
import_three16.ColorManagement.workingToColorSpace(color2, import_three16.SRGBColorSpace);
|
|
6675
|
+
output += " " + color2.r + " " + color2.g + " " + color2.b;
|
|
6536
6676
|
}
|
|
6537
6677
|
output += "\n";
|
|
6538
6678
|
}
|
|
@@ -6544,7 +6684,7 @@ var OBJExporter = class {
|
|
|
6544
6684
|
}
|
|
6545
6685
|
indexVertex += nbVertex;
|
|
6546
6686
|
}
|
|
6547
|
-
|
|
6687
|
+
object3.traverse(function(child) {
|
|
6548
6688
|
if (child.isMesh === true) {
|
|
6549
6689
|
parseMesh(child);
|
|
6550
6690
|
}
|
|
@@ -6572,9 +6712,9 @@ var PLYExporter = class {
|
|
|
6572
6712
|
* @param {PLYExporter~Options} options - The export options.
|
|
6573
6713
|
* @return {?(string|ArrayBuffer)} The exported PLY.
|
|
6574
6714
|
*/
|
|
6575
|
-
parse(
|
|
6715
|
+
parse(object3, onDone, options = {}) {
|
|
6576
6716
|
function traverseMeshes(cb) {
|
|
6577
|
-
|
|
6717
|
+
object3.traverse(function(child) {
|
|
6578
6718
|
if (child.isMesh === true || child.isPoints) {
|
|
6579
6719
|
const mesh = child;
|
|
6580
6720
|
const geometry = mesh.geometry;
|
|
@@ -6607,7 +6747,7 @@ var PLYExporter = class {
|
|
|
6607
6747
|
for (const name of customAttributeNames) customTypes[name] = "float";
|
|
6608
6748
|
let vertexCount = 0;
|
|
6609
6749
|
let faceCount = 0;
|
|
6610
|
-
|
|
6750
|
+
object3.traverse(function(child) {
|
|
6611
6751
|
if (child.isMesh === true) {
|
|
6612
6752
|
const mesh = child;
|
|
6613
6753
|
const geometry = mesh.geometry;
|
|
@@ -7201,8 +7341,8 @@ function equalArray(array1, array2) {
|
|
|
7201
7341
|
return element === array2[index];
|
|
7202
7342
|
});
|
|
7203
7343
|
}
|
|
7204
|
-
function stringToArrayBuffer(
|
|
7205
|
-
return new TextEncoder().encode(
|
|
7344
|
+
function stringToArrayBuffer(text2) {
|
|
7345
|
+
return new TextEncoder().encode(text2).buffer;
|
|
7206
7346
|
}
|
|
7207
7347
|
function isIdentityMatrix(matrix) {
|
|
7208
7348
|
return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
@@ -7395,12 +7535,12 @@ var GLTFWriter = class {
|
|
|
7395
7535
|
* @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry|THREE.AnimationClip} object
|
|
7396
7536
|
* @param {Object} objectDef
|
|
7397
7537
|
*/
|
|
7398
|
-
serializeUserData(
|
|
7399
|
-
if (Object.keys(
|
|
7538
|
+
serializeUserData(object3, objectDef) {
|
|
7539
|
+
if (Object.keys(object3.userData).length === 0) return;
|
|
7400
7540
|
const options = this.options;
|
|
7401
7541
|
const extensionsUsed = this.extensionsUsed;
|
|
7402
7542
|
try {
|
|
7403
|
-
const json = JSON.parse(JSON.stringify(
|
|
7543
|
+
const json = JSON.parse(JSON.stringify(object3.userData));
|
|
7404
7544
|
if (options.includeCustomExtensions && json.gltfExtensions) {
|
|
7405
7545
|
if (objectDef.extensions === void 0) objectDef.extensions = {};
|
|
7406
7546
|
for (const extensionName in json.gltfExtensions) {
|
|
@@ -7411,7 +7551,7 @@ var GLTFWriter = class {
|
|
|
7411
7551
|
}
|
|
7412
7552
|
if (Object.keys(json).length > 0) objectDef.extras = json;
|
|
7413
7553
|
} catch (error) {
|
|
7414
|
-
console.warn("THREE.GLTFExporter: userData of '" +
|
|
7554
|
+
console.warn("THREE.GLTFExporter: userData of '" + object3.name + "' won't be serialized because of JSON.stringify error - " + error.message);
|
|
7415
7555
|
}
|
|
7416
7556
|
}
|
|
7417
7557
|
/**
|
|
@@ -7920,9 +8060,9 @@ var GLTFWriter = class {
|
|
|
7920
8060
|
if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
|
|
7921
8061
|
console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
|
|
7922
8062
|
}
|
|
7923
|
-
const
|
|
7924
|
-
if (!equalArray(
|
|
7925
|
-
materialDef.pbrMetallicRoughness.baseColorFactor =
|
|
8063
|
+
const color2 = material.color.toArray().concat([material.opacity]);
|
|
8064
|
+
if (!equalArray(color2, [1, 1, 1, 1])) {
|
|
8065
|
+
materialDef.pbrMetallicRoughness.baseColorFactor = color2;
|
|
7926
8066
|
}
|
|
7927
8067
|
if (material.isMeshStandardMaterial) {
|
|
7928
8068
|
materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
|
|
@@ -8337,13 +8477,13 @@ var GLTFWriter = class {
|
|
|
8337
8477
|
* @param {THREE.Object3D} object
|
|
8338
8478
|
* @return {?number}
|
|
8339
8479
|
*/
|
|
8340
|
-
processSkin(
|
|
8480
|
+
processSkin(object3) {
|
|
8341
8481
|
const json = this.json;
|
|
8342
8482
|
const nodeMap = this.nodeMap;
|
|
8343
|
-
const node = json.nodes[nodeMap.get(
|
|
8344
|
-
const skeleton =
|
|
8483
|
+
const node = json.nodes[nodeMap.get(object3)];
|
|
8484
|
+
const skeleton = object3.skeleton;
|
|
8345
8485
|
if (skeleton === void 0) return null;
|
|
8346
|
-
const rootJoint =
|
|
8486
|
+
const rootJoint = object3.skeleton.bones[0];
|
|
8347
8487
|
if (rootJoint === void 0) return null;
|
|
8348
8488
|
const joints = [];
|
|
8349
8489
|
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
@@ -8351,7 +8491,7 @@ var GLTFWriter = class {
|
|
|
8351
8491
|
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
8352
8492
|
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
8353
8493
|
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
8354
|
-
temporaryBoneInverse.multiply(
|
|
8494
|
+
temporaryBoneInverse.multiply(object3.bindMatrix).toArray(inverseBindMatrices, i * 16);
|
|
8355
8495
|
}
|
|
8356
8496
|
if (json.skins === void 0) json.skins = [];
|
|
8357
8497
|
json.skins.push({
|
|
@@ -8367,19 +8507,19 @@ var GLTFWriter = class {
|
|
|
8367
8507
|
* @param {THREE.Object3D} object Object3D to processNodeAsync
|
|
8368
8508
|
* @return {Promise<number>} Index of the node in the nodes list
|
|
8369
8509
|
*/
|
|
8370
|
-
async processNodeAsync(
|
|
8510
|
+
async processNodeAsync(object3) {
|
|
8371
8511
|
const json = this.json;
|
|
8372
8512
|
const options = this.options;
|
|
8373
8513
|
const nodeMap = this.nodeMap;
|
|
8374
8514
|
if (!json.nodes) json.nodes = [];
|
|
8375
|
-
if (
|
|
8376
|
-
return await this._processNodeWithPivotAsync(
|
|
8515
|
+
if (object3.pivot !== null) {
|
|
8516
|
+
return await this._processNodeWithPivotAsync(object3);
|
|
8377
8517
|
}
|
|
8378
8518
|
const nodeDef = {};
|
|
8379
8519
|
if (options.trs) {
|
|
8380
|
-
const rotation =
|
|
8381
|
-
const position =
|
|
8382
|
-
const scale =
|
|
8520
|
+
const rotation = object3.quaternion.toArray();
|
|
8521
|
+
const position = object3.position.toArray();
|
|
8522
|
+
const scale = object3.scale.toArray();
|
|
8383
8523
|
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
8384
8524
|
nodeDef.rotation = rotation;
|
|
8385
8525
|
}
|
|
@@ -8390,28 +8530,28 @@ var GLTFWriter = class {
|
|
|
8390
8530
|
nodeDef.scale = scale;
|
|
8391
8531
|
}
|
|
8392
8532
|
} else {
|
|
8393
|
-
if (
|
|
8394
|
-
|
|
8533
|
+
if (object3.matrixAutoUpdate) {
|
|
8534
|
+
object3.updateMatrix();
|
|
8395
8535
|
}
|
|
8396
|
-
if (isIdentityMatrix(
|
|
8397
|
-
nodeDef.matrix =
|
|
8536
|
+
if (isIdentityMatrix(object3.matrix) === false) {
|
|
8537
|
+
nodeDef.matrix = object3.matrix.elements;
|
|
8398
8538
|
}
|
|
8399
8539
|
}
|
|
8400
|
-
if (
|
|
8401
|
-
this.serializeUserData(
|
|
8402
|
-
if (
|
|
8403
|
-
const meshIndex = await this.processMeshAsync(
|
|
8540
|
+
if (object3.name !== "") nodeDef.name = String(object3.name);
|
|
8541
|
+
this.serializeUserData(object3, nodeDef);
|
|
8542
|
+
if (object3.isMesh || object3.isLine || object3.isPoints) {
|
|
8543
|
+
const meshIndex = await this.processMeshAsync(object3);
|
|
8404
8544
|
if (meshIndex !== null) nodeDef.mesh = meshIndex;
|
|
8405
|
-
} else if (
|
|
8406
|
-
nodeDef.camera = this.processCamera(
|
|
8545
|
+
} else if (object3.isCamera) {
|
|
8546
|
+
nodeDef.camera = this.processCamera(object3);
|
|
8407
8547
|
}
|
|
8408
|
-
if (
|
|
8548
|
+
if (object3.isSkinnedMesh) this.skins.push(object3);
|
|
8409
8549
|
const nodeIndex = json.nodes.push(nodeDef) - 1;
|
|
8410
|
-
nodeMap.set(
|
|
8411
|
-
if (
|
|
8550
|
+
nodeMap.set(object3, nodeIndex);
|
|
8551
|
+
if (object3.children.length > 0) {
|
|
8412
8552
|
const children = [];
|
|
8413
|
-
for (let i = 0, l =
|
|
8414
|
-
const child =
|
|
8553
|
+
for (let i = 0, l = object3.children.length; i < l; i++) {
|
|
8554
|
+
const child = object3.children[i];
|
|
8415
8555
|
if (child.visible || options.onlyVisible === false) {
|
|
8416
8556
|
const childNodeIndex = await this.processNodeAsync(child);
|
|
8417
8557
|
if (childNodeIndex !== null) children.push(childNodeIndex);
|
|
@@ -8420,7 +8560,7 @@ var GLTFWriter = class {
|
|
|
8420
8560
|
if (children.length > 0) nodeDef.children = children;
|
|
8421
8561
|
}
|
|
8422
8562
|
await this._invokeAllAsync(function(ext) {
|
|
8423
|
-
ext.writeNode && ext.writeNode(
|
|
8563
|
+
ext.writeNode && ext.writeNode(object3, nodeDef);
|
|
8424
8564
|
});
|
|
8425
8565
|
return nodeIndex;
|
|
8426
8566
|
}
|
|
@@ -8429,19 +8569,19 @@ var GLTFWriter = class {
|
|
|
8429
8569
|
* @param {THREE.Object3D} object Object3D with pivot
|
|
8430
8570
|
* @return {Promise<number>} Index of the container node
|
|
8431
8571
|
*/
|
|
8432
|
-
async _processNodeWithPivotAsync(
|
|
8572
|
+
async _processNodeWithPivotAsync(object3) {
|
|
8433
8573
|
const json = this.json;
|
|
8434
8574
|
const options = this.options;
|
|
8435
8575
|
const nodeMap = this.nodeMap;
|
|
8436
|
-
const pivot =
|
|
8576
|
+
const pivot = object3.pivot;
|
|
8437
8577
|
const containerDef = {};
|
|
8438
|
-
const rotation =
|
|
8578
|
+
const rotation = object3.quaternion.toArray();
|
|
8439
8579
|
const position = [
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8580
|
+
object3.position.x + pivot.x,
|
|
8581
|
+
object3.position.y + pivot.y,
|
|
8582
|
+
object3.position.z + pivot.z
|
|
8443
8583
|
];
|
|
8444
|
-
const scale =
|
|
8584
|
+
const scale = object3.scale.toArray();
|
|
8445
8585
|
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
8446
8586
|
containerDef.rotation = rotation;
|
|
8447
8587
|
}
|
|
@@ -8452,28 +8592,28 @@ var GLTFWriter = class {
|
|
|
8452
8592
|
containerDef.scale = scale;
|
|
8453
8593
|
}
|
|
8454
8594
|
containerDef.extras = { pivot: pivot.toArray() };
|
|
8455
|
-
if (
|
|
8456
|
-
this.serializeUserData(
|
|
8595
|
+
if (object3.name !== "") containerDef.name = String(object3.name);
|
|
8596
|
+
this.serializeUserData(object3, containerDef);
|
|
8457
8597
|
const containerIndex = json.nodes.push(containerDef) - 1;
|
|
8458
|
-
nodeMap.set(
|
|
8598
|
+
nodeMap.set(object3, containerIndex);
|
|
8459
8599
|
const childDef = {};
|
|
8460
8600
|
const childPosition = [-pivot.x, -pivot.y, -pivot.z];
|
|
8461
8601
|
if (!equalArray(childPosition, [0, 0, 0])) {
|
|
8462
8602
|
childDef.translation = childPosition;
|
|
8463
8603
|
}
|
|
8464
|
-
if (
|
|
8465
|
-
const meshIndex = await this.processMeshAsync(
|
|
8604
|
+
if (object3.isMesh || object3.isLine || object3.isPoints) {
|
|
8605
|
+
const meshIndex = await this.processMeshAsync(object3);
|
|
8466
8606
|
if (meshIndex !== null) childDef.mesh = meshIndex;
|
|
8467
|
-
} else if (
|
|
8468
|
-
childDef.camera = this.processCamera(
|
|
8607
|
+
} else if (object3.isCamera) {
|
|
8608
|
+
childDef.camera = this.processCamera(object3);
|
|
8469
8609
|
}
|
|
8470
|
-
if (
|
|
8610
|
+
if (object3.isSkinnedMesh) this.skins.push(object3);
|
|
8471
8611
|
const childIndex = json.nodes.push(childDef) - 1;
|
|
8472
8612
|
const containerChildren = [childIndex];
|
|
8473
|
-
if (
|
|
8613
|
+
if (object3.children.length > 0) {
|
|
8474
8614
|
const grandchildren = [];
|
|
8475
|
-
for (let i = 0, l =
|
|
8476
|
-
const child =
|
|
8615
|
+
for (let i = 0, l = object3.children.length; i < l; i++) {
|
|
8616
|
+
const child = object3.children[i];
|
|
8477
8617
|
if (child.visible || options.onlyVisible === false) {
|
|
8478
8618
|
const childNodeIndex = await this.processNodeAsync(child);
|
|
8479
8619
|
if (childNodeIndex !== null) grandchildren.push(childNodeIndex);
|
|
@@ -8483,7 +8623,7 @@ var GLTFWriter = class {
|
|
|
8483
8623
|
}
|
|
8484
8624
|
containerDef.children = containerChildren;
|
|
8485
8625
|
await this._invokeAllAsync(function(ext) {
|
|
8486
|
-
ext.writeNode && ext.writeNode(
|
|
8626
|
+
ext.writeNode && ext.writeNode(object3, containerDef);
|
|
8487
8627
|
});
|
|
8488
8628
|
return containerIndex;
|
|
8489
8629
|
}
|
|
@@ -8926,10 +9066,10 @@ var GLTFMeshGpuInstancing = class {
|
|
|
8926
9066
|
this.writer = writer;
|
|
8927
9067
|
this.name = "EXT_mesh_gpu_instancing";
|
|
8928
9068
|
}
|
|
8929
|
-
writeNode(
|
|
8930
|
-
if (!
|
|
9069
|
+
writeNode(object3, nodeDef) {
|
|
9070
|
+
if (!object3.isInstancedMesh) return;
|
|
8931
9071
|
const writer = this.writer;
|
|
8932
|
-
const mesh =
|
|
9072
|
+
const mesh = object3;
|
|
8933
9073
|
const translationAttr = new Float32Array(mesh.count * 3);
|
|
8934
9074
|
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
8935
9075
|
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
@@ -9119,8 +9259,8 @@ var SceneExporter = class {
|
|
|
9119
9259
|
}
|
|
9120
9260
|
}
|
|
9121
9261
|
};
|
|
9122
|
-
function localMatrix(
|
|
9123
|
-
return
|
|
9262
|
+
function localMatrix(object3) {
|
|
9263
|
+
return object3.matrixAutoUpdate ? new import_three19.Matrix4().compose(object3.position, object3.quaternion, object3.scale) : object3.matrix.clone();
|
|
9124
9264
|
}
|
|
9125
9265
|
function createSnapshot(root, gltf, bakeColors = false) {
|
|
9126
9266
|
const scene = new import_three19.Scene();
|
|
@@ -9224,24 +9364,24 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
9224
9364
|
scene.add(copy);
|
|
9225
9365
|
}
|
|
9226
9366
|
};
|
|
9227
|
-
const visit = (
|
|
9228
|
-
if (!
|
|
9229
|
-
const world = parentWorld.clone().multiply(localMatrix(
|
|
9230
|
-
const mesh =
|
|
9367
|
+
const visit = (object3, parentWorld) => {
|
|
9368
|
+
if (!object3.visible) return;
|
|
9369
|
+
const world = parentWorld.clone().multiply(localMatrix(object3));
|
|
9370
|
+
const mesh = object3;
|
|
9231
9371
|
if (mesh.isMesh) {
|
|
9232
9372
|
const instanced = mesh;
|
|
9233
9373
|
if (instanced.isInstancedMesh) {
|
|
9234
9374
|
for (let i = 0; i < instanced.count; i++) {
|
|
9235
9375
|
const matrix = new import_three19.Matrix4();
|
|
9236
9376
|
instanced.getMatrixAt(i, matrix);
|
|
9237
|
-
const
|
|
9238
|
-
addMesh(mesh, world.clone().multiply(matrix),
|
|
9377
|
+
const color2 = instanced.instanceColor ? new import_three19.Color().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
9378
|
+
addMesh(mesh, world.clone().multiply(matrix), color2);
|
|
9239
9379
|
}
|
|
9240
9380
|
} else {
|
|
9241
9381
|
addMesh(mesh, world);
|
|
9242
9382
|
}
|
|
9243
9383
|
}
|
|
9244
|
-
for (const child of
|
|
9384
|
+
for (const child of object3.children) visit(child, world);
|
|
9245
9385
|
};
|
|
9246
9386
|
try {
|
|
9247
9387
|
const ancestors = [];
|
|
@@ -9317,13 +9457,13 @@ init_AssetKey();
|
|
|
9317
9457
|
|
|
9318
9458
|
// src/gui/GuiText.ts
|
|
9319
9459
|
var import_three20 = require("three");
|
|
9320
|
-
async function layoutGuiText(
|
|
9460
|
+
async function layoutGuiText(text2, options = {}) {
|
|
9321
9461
|
const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
|
|
9322
9462
|
if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
|
|
9323
9463
|
throw new Error("Text wrap width and line height must be positive");
|
|
9324
9464
|
}
|
|
9325
9465
|
const font = await Fonts.get(options.font);
|
|
9326
|
-
const runs = typeof
|
|
9466
|
+
const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
|
|
9327
9467
|
const glyphs = [], lineWidths = [];
|
|
9328
9468
|
let line = [], width = 0;
|
|
9329
9469
|
let trailingNewline = false;
|
|
@@ -9377,7 +9517,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
9377
9517
|
batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
|
|
9378
9518
|
batches.push(batch);
|
|
9379
9519
|
}
|
|
9380
|
-
const
|
|
9520
|
+
const color2 = new import_three20.Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
|
|
9381
9521
|
const offset = isShadow ? 1 : 0;
|
|
9382
9522
|
const top = glyph ? 7 - glyph.ascent : 0;
|
|
9383
9523
|
const height = glyph ? glyph.height * glyph.scale : 8;
|
|
@@ -9405,7 +9545,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
9405
9545
|
const v0 = glyph ? 1 - glyph.y / glyph.image.height : 1;
|
|
9406
9546
|
const v1 = glyph ? 1 - (glyph.y + glyph.height) / glyph.image.height : 0;
|
|
9407
9547
|
batch.uvs.push(u0, v0, u1, v0, u0, v1, u1, v1);
|
|
9408
|
-
for (let i = 0; i < 4; i++) batch.colors.push(
|
|
9548
|
+
for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
|
|
9409
9549
|
batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
|
|
9410
9550
|
};
|
|
9411
9551
|
for (const boldOffset of style.bold ? [0, 1] : [0]) {
|
|
@@ -9439,12 +9579,19 @@ var GuiHelper = class {
|
|
|
9439
9579
|
size: [width + 24, height + 24]
|
|
9440
9580
|
}));
|
|
9441
9581
|
let y = position[1];
|
|
9442
|
-
lines.forEach((
|
|
9443
|
-
layers.push({ ...textOptions, name: `tooltip-line-${index}`, text, position: [position[0], y] });
|
|
9582
|
+
lines.forEach((text2, index) => {
|
|
9583
|
+
layers.push({ ...textOptions, name: `tooltip-line-${index}`, text: text2, position: [position[0], y] });
|
|
9444
9584
|
y += layouts[index].height + (index === 0 ? titleGap : 0);
|
|
9445
9585
|
});
|
|
9446
9586
|
return layers;
|
|
9447
9587
|
}
|
|
9588
|
+
/**
|
|
9589
|
+
* Calculates a slot's top-left position in GUI pixels.
|
|
9590
|
+
* @param slot - Zero-based slot index, or `[column, row]`.
|
|
9591
|
+
* @param origin - Position of the first slot.
|
|
9592
|
+
* @param offset - Horizontal and vertical spacing between slot origins, in pixels.
|
|
9593
|
+
* @param rowSize - Slots per row when `slot` is an index.
|
|
9594
|
+
*/
|
|
9448
9595
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
9449
9596
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
9450
9597
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
@@ -9889,29 +10036,29 @@ var SceneInspector = class {
|
|
|
9889
10036
|
this.objectControlsContainer.innerHTML = "";
|
|
9890
10037
|
this.addControls(targetObject, targetIntersection, instance);
|
|
9891
10038
|
}
|
|
9892
|
-
addControls(
|
|
10039
|
+
addControls(object3, intersection, instance) {
|
|
9893
10040
|
const container = document.createElement("div");
|
|
9894
10041
|
container.append(this.separator("Select Parent/Child"));
|
|
9895
|
-
if (
|
|
9896
|
-
container.append(this.buttonControl("Select Parent " +
|
|
9897
|
-
this.selectObject(
|
|
10042
|
+
if (object3.parent) {
|
|
10043
|
+
container.append(this.buttonControl("Select Parent " + object3.parent.constructor.name + " " + object3.parent.name, "P", () => {
|
|
10044
|
+
this.selectObject(object3.parent, intersection, instance);
|
|
9898
10045
|
}));
|
|
9899
10046
|
}
|
|
9900
|
-
if (
|
|
10047
|
+
if (object3.children.length > 0) {
|
|
9901
10048
|
let i = 1;
|
|
9902
|
-
for (let child of
|
|
10049
|
+
for (let child of object3.children) {
|
|
9903
10050
|
container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
|
|
9904
10051
|
this.selectObject(child, intersection, instance);
|
|
9905
10052
|
}));
|
|
9906
10053
|
}
|
|
9907
10054
|
}
|
|
9908
10055
|
container.append(this.separator());
|
|
9909
|
-
const selectedInstance = instance && (
|
|
10056
|
+
const selectedInstance = instance && (object3 === instance.instanceable || object3 === intersection?.object) ? instance : void 0;
|
|
9910
10057
|
if (!selectedInstance) {
|
|
9911
|
-
container.append(this.toggleControl("Visibility", "V",
|
|
10058
|
+
container.append(this.toggleControl("Visibility", "V", object3.visible, (v) => object3.visible = v));
|
|
9912
10059
|
}
|
|
9913
10060
|
container.append(this.separator("Mesh"));
|
|
9914
|
-
this.addObjectControls(
|
|
10061
|
+
this.addObjectControls(object3, intersection, container, selectedInstance);
|
|
9915
10062
|
container.append(this.separator());
|
|
9916
10063
|
this.objectControlsContainer.append(container);
|
|
9917
10064
|
}
|
|
@@ -10102,6 +10249,7 @@ var SceneStatsDisplay = class {
|
|
|
10102
10249
|
appendTo(el) {
|
|
10103
10250
|
el.append(this.statsContainer);
|
|
10104
10251
|
}
|
|
10252
|
+
/** Stops the refresh timer and removes the panel from the page. */
|
|
10105
10253
|
dispose() {
|
|
10106
10254
|
clearInterval(this.interval);
|
|
10107
10255
|
this.interval = void 0;
|
|
@@ -10126,6 +10274,7 @@ var InstanceManager = class {
|
|
|
10126
10274
|
this.isInstanceManager = true;
|
|
10127
10275
|
this.instanceCache = {};
|
|
10128
10276
|
}
|
|
10277
|
+
/** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
|
|
10129
10278
|
async get(key) {
|
|
10130
10279
|
if (key in this.instanceCache) {
|
|
10131
10280
|
console.debug(p9, "key in cache", key);
|
|
@@ -10133,6 +10282,7 @@ var InstanceManager = class {
|
|
|
10133
10282
|
}
|
|
10134
10283
|
return void 0;
|
|
10135
10284
|
}
|
|
10285
|
+
/** Allocates a placement, calling the supplier once when the shared model is first needed. */
|
|
10136
10286
|
async getOrCreate(key, supplier) {
|
|
10137
10287
|
if (key in this.instanceCache) {
|
|
10138
10288
|
return await this.get(key);
|
|
@@ -10149,6 +10299,7 @@ var InstanceManager = class {
|
|
|
10149
10299
|
throw error;
|
|
10150
10300
|
}
|
|
10151
10301
|
}
|
|
10302
|
+
/** Forgets cached models without disposing them or releasing their existing placements. */
|
|
10152
10303
|
reset() {
|
|
10153
10304
|
for (let instanceCacheKey in this.instanceCache) {
|
|
10154
10305
|
delete this.instanceCache[instanceCacheKey];
|
|
@@ -10194,6 +10345,7 @@ function matchesCondition(condition, state) {
|
|
|
10194
10345
|
});
|
|
10195
10346
|
}
|
|
10196
10347
|
var BlockStateResolver = class {
|
|
10348
|
+
/** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
|
|
10197
10349
|
static async defaults(blockState) {
|
|
10198
10350
|
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
10199
10351
|
const state = {};
|
|
@@ -10213,9 +10365,11 @@ var BlockStateResolver = class {
|
|
|
10213
10365
|
}
|
|
10214
10366
|
return state;
|
|
10215
10367
|
}
|
|
10368
|
+
/** Selects matching models. Supply `choose` to control selection within each alternatives array. */
|
|
10216
10369
|
static select(blockState, state, choose = this.choose) {
|
|
10217
10370
|
return this.matching(blockState, state).map(choose);
|
|
10218
10371
|
}
|
|
10372
|
+
/** Returns matching model groups before choosing weighted alternatives. */
|
|
10219
10373
|
static matching(blockState, state) {
|
|
10220
10374
|
const out = [];
|
|
10221
10375
|
if (blockState.variants) {
|
|
@@ -10239,6 +10393,7 @@ var BlockStateResolver = class {
|
|
|
10239
10393
|
}
|
|
10240
10394
|
return out;
|
|
10241
10395
|
}
|
|
10396
|
+
/** Selects a random alternative using positive integer weights, each defaulting to 1. */
|
|
10242
10397
|
static choose(variants) {
|
|
10243
10398
|
if (!Array.isArray(variants)) return variants;
|
|
10244
10399
|
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
@@ -10256,6 +10411,7 @@ var BlockStateResolver = class {
|
|
|
10256
10411
|
}
|
|
10257
10412
|
return variants[variants.length - 1];
|
|
10258
10413
|
}
|
|
10414
|
+
/** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
|
|
10259
10415
|
static rotation(variant) {
|
|
10260
10416
|
const rotation = new import_three29.Euler();
|
|
10261
10417
|
if (typeof variant.x !== "undefined") {
|
|
@@ -10318,29 +10474,29 @@ var BlockTints = class {
|
|
|
10318
10474
|
}
|
|
10319
10475
|
}
|
|
10320
10476
|
if (!indices.size) return tints;
|
|
10321
|
-
let
|
|
10477
|
+
let color2;
|
|
10322
10478
|
switch (rule.source) {
|
|
10323
10479
|
case "constant":
|
|
10324
|
-
|
|
10480
|
+
color2 = rule.color;
|
|
10325
10481
|
break;
|
|
10326
10482
|
case "grass":
|
|
10327
|
-
|
|
10483
|
+
color2 = await Colormaps.grassColor(key);
|
|
10328
10484
|
break;
|
|
10329
10485
|
case "redstone": {
|
|
10330
10486
|
const power = Number(state.power ?? 0) / 15;
|
|
10331
10487
|
const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
|
|
10332
10488
|
const green = Math.max(0, power * power * 0.7 - 0.5);
|
|
10333
10489
|
const blue = Math.max(0, power * power * 0.6 - 0.7);
|
|
10334
|
-
|
|
10490
|
+
color2 = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
|
|
10335
10491
|
break;
|
|
10336
10492
|
}
|
|
10337
10493
|
case "stem": {
|
|
10338
10494
|
const age = Number(state.age ?? 0);
|
|
10339
|
-
|
|
10495
|
+
color2 = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
|
|
10340
10496
|
break;
|
|
10341
10497
|
}
|
|
10342
10498
|
}
|
|
10343
|
-
return { ...Object.fromEntries([...indices].map((index) => [index,
|
|
10499
|
+
return { ...Object.fromEntries([...indices].map((index) => [index, color2])), ...tints };
|
|
10344
10500
|
}
|
|
10345
10501
|
};
|
|
10346
10502
|
|
|
@@ -10482,8 +10638,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10482
10638
|
return false;
|
|
10483
10639
|
}
|
|
10484
10640
|
return this._models.some((model) => {
|
|
10485
|
-
const
|
|
10486
|
-
return
|
|
10641
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10642
|
+
return object3.isOpaqueFullCube && this.getModelCullMask(model, 63) === 63;
|
|
10487
10643
|
});
|
|
10488
10644
|
}
|
|
10489
10645
|
getModelMatrix(model) {
|
|
@@ -10492,8 +10648,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10492
10648
|
return model.matrix.clone();
|
|
10493
10649
|
}
|
|
10494
10650
|
getModelCullMask(model, worldMask) {
|
|
10495
|
-
const
|
|
10496
|
-
if (
|
|
10651
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10652
|
+
if (object3.options.displayPosition) return 0;
|
|
10497
10653
|
const position = new import_three32.Vector3();
|
|
10498
10654
|
const rotation = new import_three32.Quaternion();
|
|
10499
10655
|
const scale = new import_three32.Vector3();
|
|
@@ -10510,14 +10666,14 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10510
10666
|
replacements.push(model);
|
|
10511
10667
|
continue;
|
|
10512
10668
|
}
|
|
10513
|
-
const
|
|
10669
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10514
10670
|
const cullMask = this.getModelCullMask(model, worldMask);
|
|
10515
|
-
if (cullMask === (
|
|
10671
|
+
if (cullMask === (object3.options.cullMask ?? 0)) {
|
|
10516
10672
|
replacements.push(model);
|
|
10517
10673
|
continue;
|
|
10518
10674
|
}
|
|
10519
10675
|
const matrix = this.getModelMatrix(model);
|
|
10520
|
-
const replacement = await this.scene.addModel(
|
|
10676
|
+
const replacement = await this.scene.addModel(object3.originalModel, { ...object3.options, cullMask });
|
|
10521
10677
|
replacements.push(replacement);
|
|
10522
10678
|
if (isInstanceReference(replacement)) {
|
|
10523
10679
|
replacement.setMatrix(matrix);
|
|
@@ -10525,8 +10681,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10525
10681
|
replacement.matrix.copy(matrix);
|
|
10526
10682
|
replacement.matrixWorldNeedsUpdate = true;
|
|
10527
10683
|
matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
10528
|
-
replacement.matrixAutoUpdate =
|
|
10529
|
-
replacement.visible =
|
|
10684
|
+
replacement.matrixAutoUpdate = object3.matrixAutoUpdate;
|
|
10685
|
+
replacement.visible = object3.visible;
|
|
10530
10686
|
}
|
|
10531
10687
|
}
|
|
10532
10688
|
} catch (error) {
|
|
@@ -10542,6 +10698,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10542
10698
|
}
|
|
10543
10699
|
this.notifyDirty();
|
|
10544
10700
|
}
|
|
10701
|
+
/** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
|
|
10545
10702
|
get state() {
|
|
10546
10703
|
return this._state;
|
|
10547
10704
|
}
|
|
@@ -10641,6 +10798,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10641
10798
|
obj.setPosition(this.position);
|
|
10642
10799
|
return obj;
|
|
10643
10800
|
}
|
|
10801
|
+
/** Clears selected properties and rebuilds models without reapplying property defaults. */
|
|
10644
10802
|
async resetState() {
|
|
10645
10803
|
this._previousState = this._state;
|
|
10646
10804
|
this._state = {};
|
|
@@ -12540,6 +12698,11 @@ function compoundList(tags, name) {
|
|
|
12540
12698
|
// src/model/multiblock/StructureParser.ts
|
|
12541
12699
|
init_MineRenderError();
|
|
12542
12700
|
var StructureParser = class {
|
|
12701
|
+
/**
|
|
12702
|
+
* Parses decoded NBT, omitting air blocks.
|
|
12703
|
+
* @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
|
|
12704
|
+
* @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
|
|
12705
|
+
*/
|
|
12543
12706
|
static async parse(_nbt, paletteIndex) {
|
|
12544
12707
|
const nbt = _nbt.value;
|
|
12545
12708
|
let palette;
|
|
@@ -13374,6 +13537,7 @@ var SkinImage = class {
|
|
|
13374
13537
|
// src/skin/SkinTextures.ts
|
|
13375
13538
|
init_Textures();
|
|
13376
13539
|
var SkinTextures = class {
|
|
13540
|
+
/** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
|
|
13377
13541
|
static async get(src, legacy) {
|
|
13378
13542
|
const image = await SkinImage.getData(src);
|
|
13379
13543
|
const scale = image.width / 64;
|
|
@@ -13547,6 +13711,14 @@ var SkinObject = class extends SceneObject {
|
|
|
13547
13711
|
}
|
|
13548
13712
|
}
|
|
13549
13713
|
}
|
|
13714
|
+
/**
|
|
13715
|
+
* Loads a skin texture, detecting slim arms and legacy layouts by default.
|
|
13716
|
+
* To override detection, set `slim` or `legacy` in the options passed to
|
|
13717
|
+
* `new SkinObject(options)` or `scene.addSkin(src, options)`.
|
|
13718
|
+
* Use {@link setSlim} or {@link setLegacy} to change these settings later.
|
|
13719
|
+
*
|
|
13720
|
+
* @param src - URL of the skin texture.
|
|
13721
|
+
*/
|
|
13550
13722
|
async setSkinTexture(src) {
|
|
13551
13723
|
if (typeof src === "undefined") return;
|
|
13552
13724
|
this.skinTextureSrc = src;
|
|
@@ -13657,59 +13829,60 @@ var MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13657
13829
|
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
|
|
13658
13830
|
}
|
|
13659
13831
|
add(...objects) {
|
|
13660
|
-
for (const
|
|
13832
|
+
for (const object3 of objects) {
|
|
13661
13833
|
this.dirty = true;
|
|
13662
13834
|
try {
|
|
13663
|
-
super.add(
|
|
13835
|
+
super.add(object3);
|
|
13664
13836
|
} finally {
|
|
13665
|
-
if (
|
|
13666
|
-
this.updateObjectRegistration(
|
|
13837
|
+
if (object3?.isObject3D && object3 !== this) {
|
|
13838
|
+
this.updateObjectRegistration(object3, object3.parent === this);
|
|
13667
13839
|
}
|
|
13668
13840
|
}
|
|
13669
13841
|
}
|
|
13670
13842
|
return this;
|
|
13671
13843
|
}
|
|
13672
13844
|
remove(...objects) {
|
|
13673
|
-
for (const
|
|
13674
|
-
if (!this.children.includes(
|
|
13845
|
+
for (const object3 of objects) {
|
|
13846
|
+
if (!this.children.includes(object3)) continue;
|
|
13675
13847
|
this.dirty = true;
|
|
13676
|
-
this.updateObjectRegistration(
|
|
13848
|
+
this.updateObjectRegistration(object3, false);
|
|
13677
13849
|
try {
|
|
13678
|
-
super.remove(
|
|
13850
|
+
super.remove(object3);
|
|
13679
13851
|
} finally {
|
|
13680
|
-
this.updateObjectRegistration(
|
|
13852
|
+
this.updateObjectRegistration(object3, object3.parent === this);
|
|
13681
13853
|
}
|
|
13682
13854
|
}
|
|
13683
13855
|
return this;
|
|
13684
13856
|
}
|
|
13685
|
-
updateObjectRegistration(
|
|
13686
|
-
if (this.observedObjects.has(
|
|
13687
|
-
const observable =
|
|
13857
|
+
updateObjectRegistration(object3, attached) {
|
|
13858
|
+
if (this.observedObjects.has(object3) === attached) return;
|
|
13859
|
+
const observable = object3;
|
|
13688
13860
|
if (attached) {
|
|
13689
|
-
this.observedObjects.add(
|
|
13861
|
+
this.observedObjects.add(object3);
|
|
13690
13862
|
observable.addEventListener("change", this.onObjectChange);
|
|
13691
13863
|
} else {
|
|
13692
|
-
this.observedObjects.delete(
|
|
13864
|
+
this.observedObjects.delete(object3);
|
|
13693
13865
|
observable.removeEventListener("change", this.onObjectChange);
|
|
13694
13866
|
}
|
|
13695
13867
|
const change = attached ? 1 : -1;
|
|
13696
13868
|
this.stats.objectCount += change;
|
|
13697
|
-
if (isSceneObject(
|
|
13869
|
+
if (isSceneObject(object3)) {
|
|
13698
13870
|
this.stats.sceneObjectCount += change;
|
|
13699
13871
|
}
|
|
13700
13872
|
}
|
|
13701
|
-
|
|
13873
|
+
/** Initializes each object before attaching it to the scene. */
|
|
13874
|
+
async initAndAdd(...object3) {
|
|
13702
13875
|
this.dirty = true;
|
|
13703
|
-
for (let obj of
|
|
13876
|
+
for (let obj of object3) {
|
|
13704
13877
|
await obj.init();
|
|
13705
13878
|
}
|
|
13706
|
-
return this.add(...
|
|
13879
|
+
return this.add(...object3);
|
|
13707
13880
|
}
|
|
13708
|
-
async addSceneObject(
|
|
13881
|
+
async addSceneObject(asset2, objectSupplier, _options, parent = this) {
|
|
13709
13882
|
this.dirty = true;
|
|
13710
13883
|
const obj = await objectSupplier();
|
|
13711
|
-
if (obj?.options?.instanceMeshes &&
|
|
13712
|
-
let key =
|
|
13884
|
+
if (obj?.options?.instanceMeshes && asset2.key && asset2.key?.assetType === "models") {
|
|
13885
|
+
let key = asset2.key.serialize();
|
|
13713
13886
|
if (isModelObject(obj)) {
|
|
13714
13887
|
const { displayPosition, uvLockRotation, tints, cullMask } = obj.options;
|
|
13715
13888
|
if (displayPosition) key += `|display:${displayPosition}`;
|
|
@@ -13733,13 +13906,33 @@ var MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13733
13906
|
return obj;
|
|
13734
13907
|
}
|
|
13735
13908
|
}
|
|
13909
|
+
/**
|
|
13910
|
+
* Adds a model loaded with {@link Models.getMerged}.
|
|
13911
|
+
* Set `options.instanceMeshes` to `false` to create a separate ModelObject.
|
|
13912
|
+
*
|
|
13913
|
+
* @param parent - Object to attach the model to. Defaults to this scene.
|
|
13914
|
+
* @returns The model, or a reference to one placement of a shared model.
|
|
13915
|
+
*/
|
|
13736
13916
|
async addModel(model, options, parent = this) {
|
|
13737
13917
|
options = { ...options, tints: await ItemTints.get(model, options?.tints) };
|
|
13738
13918
|
return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
|
|
13739
13919
|
}
|
|
13920
|
+
/**
|
|
13921
|
+
* Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
|
|
13922
|
+
* Set `options.initialState` to choose block properties such as `facing` or `axis`.
|
|
13923
|
+
* Use the returned object's `setPosition` method to move all of its model parts.
|
|
13924
|
+
*/
|
|
13740
13925
|
async addBlock(blockState, options, parent = this) {
|
|
13741
13926
|
return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
|
|
13742
13927
|
}
|
|
13928
|
+
/**
|
|
13929
|
+
* Loads a skin and adds an initialized player model.
|
|
13930
|
+
*
|
|
13931
|
+
* @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
|
|
13932
|
+
* Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
|
|
13933
|
+
* @param options - Player settings, including `slim` and `legacy` detection overrides.
|
|
13934
|
+
* @param parent - Object to attach the player to. Defaults to this scene.
|
|
13935
|
+
*/
|
|
13743
13936
|
async addSkin(skin, options, parent = this) {
|
|
13744
13937
|
this.dirty = true;
|
|
13745
13938
|
const obj = new SkinObject(options);
|
|
@@ -13751,9 +13944,14 @@ var MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13751
13944
|
parent.add(obj);
|
|
13752
13945
|
return obj;
|
|
13753
13946
|
}
|
|
13947
|
+
/** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
|
|
13754
13948
|
async addEntity(entity, options, parent = this) {
|
|
13755
13949
|
return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
|
|
13756
13950
|
}
|
|
13951
|
+
/**
|
|
13952
|
+
* Adds GUI layers in draw order. One GUI pixel equals one scene unit.
|
|
13953
|
+
* Layer positions start at the top left, with positive GUI y pointing down.
|
|
13954
|
+
*/
|
|
13757
13955
|
async addGui(layers, options, parent = this) {
|
|
13758
13956
|
const obj = new GuiObject(layers, options);
|
|
13759
13957
|
obj.scene = this;
|
|
@@ -13782,11 +13980,11 @@ var _changeEvent = { type: "change" };
|
|
|
13782
13980
|
var _startEvent = { type: "start" };
|
|
13783
13981
|
var _endEvent = { type: "end" };
|
|
13784
13982
|
var OrbitControls = class extends import_three35.EventDispatcher {
|
|
13785
|
-
constructor(
|
|
13983
|
+
constructor(object3, domElement) {
|
|
13786
13984
|
super();
|
|
13787
13985
|
if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
|
|
13788
13986
|
if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
|
|
13789
|
-
this.object =
|
|
13987
|
+
this.object = object3;
|
|
13790
13988
|
this.domElement = domElement;
|
|
13791
13989
|
this.domElement.style.touchAction = "none";
|
|
13792
13990
|
this.enabled = true;
|
|
@@ -13843,7 +14041,7 @@ var OrbitControls = class extends import_three35.EventDispatcher {
|
|
|
13843
14041
|
};
|
|
13844
14042
|
this.update = function() {
|
|
13845
14043
|
const offset = new import_three35.Vector3();
|
|
13846
|
-
const quat = new import_three35.Quaternion().setFromUnitVectors(
|
|
14044
|
+
const quat = new import_three35.Quaternion().setFromUnitVectors(object3.up, new import_three35.Vector3(0, 1, 0));
|
|
13847
14045
|
const quatInverse = quat.clone().invert();
|
|
13848
14046
|
const lastPosition = new import_three35.Vector3();
|
|
13849
14047
|
const lastQuaternion = new import_three35.Quaternion();
|
|
@@ -14408,8 +14606,8 @@ var OrbitControls = class extends import_three35.EventDispatcher {
|
|
|
14408
14606
|
}
|
|
14409
14607
|
};
|
|
14410
14608
|
var MapControls = class extends OrbitControls {
|
|
14411
|
-
constructor(
|
|
14412
|
-
super(
|
|
14609
|
+
constructor(object3, domElement) {
|
|
14610
|
+
super(object3, domElement);
|
|
14413
14611
|
this.screenSpacePanning = false;
|
|
14414
14612
|
this.mouseButtons.LEFT = import_three35.MOUSE.PAN;
|
|
14415
14613
|
this.mouseButtons.RIGHT = import_three35.MOUSE.ROTATE;
|
|
@@ -14608,6 +14806,7 @@ var Renderer = class _Renderer {
|
|
|
14608
14806
|
get element() {
|
|
14609
14807
|
return this._element;
|
|
14610
14808
|
}
|
|
14809
|
+
/** Attaches the canvas to an element and sizes it to that element's dimensions. */
|
|
14611
14810
|
appendTo(element) {
|
|
14612
14811
|
if (this._disposed) return;
|
|
14613
14812
|
this._element = element;
|
|
@@ -14635,6 +14834,7 @@ var Renderer = class _Renderer {
|
|
|
14635
14834
|
events.add(changeEvent2);
|
|
14636
14835
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
14637
14836
|
}
|
|
14837
|
+
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
14638
14838
|
resize(width, height) {
|
|
14639
14839
|
if (this._disposed) return;
|
|
14640
14840
|
if (isPerspectiveCamera(this.camera)) {
|
|
@@ -14673,12 +14873,14 @@ var Renderer = class _Renderer {
|
|
|
14673
14873
|
if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
|
|
14674
14874
|
};
|
|
14675
14875
|
}
|
|
14876
|
+
/** Starts or resumes the animation loop and registered frame callbacks. */
|
|
14676
14877
|
start() {
|
|
14677
14878
|
if (this._disposed) return;
|
|
14678
14879
|
this.stop();
|
|
14679
14880
|
this._running = true;
|
|
14680
14881
|
if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
|
|
14681
14882
|
}
|
|
14883
|
+
/** Pauses rendering and frame callbacks. Call {@link start} to resume. */
|
|
14682
14884
|
stop() {
|
|
14683
14885
|
if (this._disposed) return;
|
|
14684
14886
|
this._running = false;
|
|
@@ -14787,12 +14989,15 @@ var Renderer = class _Renderer {
|
|
|
14787
14989
|
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
14788
14990
|
return canvas.toDataURL(mime, quality);
|
|
14789
14991
|
}
|
|
14992
|
+
/** Exports visible scene meshes as OBJ text, without texture images. */
|
|
14790
14993
|
toObj() {
|
|
14791
14994
|
return SceneExporter.toObj(this.scene);
|
|
14792
14995
|
}
|
|
14996
|
+
/** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
|
|
14793
14997
|
toPLY(options) {
|
|
14794
14998
|
return SceneExporter.toPLY(this.scene, options);
|
|
14795
14999
|
}
|
|
15000
|
+
/** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
|
|
14796
15001
|
toGLTF(options) {
|
|
14797
15002
|
return SceneExporter.toGLTF(this.scene, options);
|
|
14798
15003
|
}
|
|
@@ -14831,16 +15036,244 @@ init_SceneObject();
|
|
|
14831
15036
|
// src/index.ts
|
|
14832
15037
|
init_request();
|
|
14833
15038
|
|
|
15039
|
+
// src/scene/SceneDocument.ts
|
|
15040
|
+
init_DisplayPosition();
|
|
15041
|
+
function fail(path, message) {
|
|
15042
|
+
throw new Error(`${path}: ${message}`);
|
|
15043
|
+
}
|
|
15044
|
+
function object2(value, path) {
|
|
15045
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail(path, "expected a JSON object");
|
|
15046
|
+
for (const key of Object.keys(value)) {
|
|
15047
|
+
if (["__proto__", "prototype", "constructor"].includes(key)) fail(`${path}.${key}`, "unsupported property");
|
|
15048
|
+
}
|
|
15049
|
+
return value;
|
|
15050
|
+
}
|
|
15051
|
+
function fields(value, path, allowed, required = []) {
|
|
15052
|
+
const input = object2(value, path);
|
|
15053
|
+
for (const key of required) if (input[key] === void 0) fail(`${path}.${key}`, "required");
|
|
15054
|
+
for (const [key, entry] of Object.entries(input)) {
|
|
15055
|
+
if (!Object.prototype.hasOwnProperty.call(allowed, key)) fail(`${path}.${key}`, "unsupported property");
|
|
15056
|
+
if (entry !== void 0) allowed[key](entry, `${path}.${key}`);
|
|
15057
|
+
}
|
|
15058
|
+
return input;
|
|
15059
|
+
}
|
|
15060
|
+
var text = (value, path) => {
|
|
15061
|
+
if (typeof value !== "string" || !value.trim()) fail(path, "expected a nonempty string");
|
|
15062
|
+
};
|
|
15063
|
+
var literalText = (value, path) => {
|
|
15064
|
+
if (typeof value !== "string") fail(path, "expected a string");
|
|
15065
|
+
};
|
|
15066
|
+
var boolean = (value, path) => {
|
|
15067
|
+
if (typeof value !== "boolean") fail(path, "expected a boolean");
|
|
15068
|
+
};
|
|
15069
|
+
var number = (value, path) => {
|
|
15070
|
+
if (typeof value !== "number" || !Number.isFinite(value)) fail(path, "expected a finite number");
|
|
15071
|
+
};
|
|
15072
|
+
var positive = (value, path) => {
|
|
15073
|
+
number(value, path);
|
|
15074
|
+
if (value <= 0) fail(path, "expected a positive number");
|
|
15075
|
+
};
|
|
15076
|
+
var nonnegative = (value, path) => {
|
|
15077
|
+
number(value, path);
|
|
15078
|
+
if (value < 0) fail(path, "expected a nonnegative number");
|
|
15079
|
+
};
|
|
15080
|
+
var color = (value, path) => {
|
|
15081
|
+
number(value, path);
|
|
15082
|
+
if (!Number.isInteger(value) || value < 0 || value > 16777215) {
|
|
15083
|
+
fail(path, "expected an RGB integer from 0 to 16777215");
|
|
15084
|
+
}
|
|
15085
|
+
};
|
|
15086
|
+
var asset = (value, path) => {
|
|
15087
|
+
text(value, path);
|
|
15088
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(value) || value.split(/[:/]/).some((part) => !part || part === "." || part === "..")) {
|
|
15089
|
+
fail(path, "expected a resource ID such as minecraft:stone");
|
|
15090
|
+
}
|
|
15091
|
+
};
|
|
15092
|
+
var version = (value, path) => {
|
|
15093
|
+
text(value, path);
|
|
15094
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(value)) fail(path, "expected a Minecraft version without slashes");
|
|
15095
|
+
};
|
|
15096
|
+
var tuple = (size, item = number) => (value, path) => {
|
|
15097
|
+
if (!Array.isArray(value) || value.length !== size) fail(path, `expected ${size} numbers`);
|
|
15098
|
+
for (let index = 0; index < size; index++) item(value[index], `${path}[${index}]`);
|
|
15099
|
+
};
|
|
15100
|
+
var list = (item) => (value, path) => {
|
|
15101
|
+
if (!Array.isArray(value)) fail(path, "expected an array");
|
|
15102
|
+
for (let index = 0; index < value.length; index++) item(value[index], `${path}[${index}]`);
|
|
15103
|
+
};
|
|
15104
|
+
var dictionary = (item, numericKeys = false) => (value, path) => {
|
|
15105
|
+
for (const [key, entry] of Object.entries(object2(value, path))) {
|
|
15106
|
+
if (numericKeys && !/^\d+$/.test(key)) fail(`${path}.${key}`, "expected a nonnegative tint index");
|
|
15107
|
+
item(entry, `${path}.${key}`);
|
|
15108
|
+
}
|
|
15109
|
+
};
|
|
15110
|
+
var enumeration = (values) => (value, path) => {
|
|
15111
|
+
if (!values.includes(value)) fail(path, `expected one of: ${values.join(", ")}`);
|
|
15112
|
+
};
|
|
15113
|
+
var textStyle = { color, bold: boolean, italic: boolean };
|
|
15114
|
+
function guiLayer(value, path) {
|
|
15115
|
+
const layer = object2(value, path);
|
|
15116
|
+
if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
|
|
15117
|
+
fail(path, "expected exactly one of texture, item, or text");
|
|
15118
|
+
}
|
|
15119
|
+
const layout = { name: text, position: tuple(2), size: tuple(2, positive) };
|
|
15120
|
+
if (layer.texture !== void 0) {
|
|
15121
|
+
fields(value, path, { ...layout, texture: asset, crop: (value2, path2) => {
|
|
15122
|
+
tuple(4)(value2, path2);
|
|
15123
|
+
const [x, y, width, height] = value2;
|
|
15124
|
+
nonnegative(x, `${path2}[0]`);
|
|
15125
|
+
nonnegative(y, `${path2}[1]`);
|
|
15126
|
+
positive(width, `${path2}[2]`);
|
|
15127
|
+
positive(height, `${path2}[3]`);
|
|
15128
|
+
} });
|
|
15129
|
+
} else if (layer.item !== void 0) {
|
|
15130
|
+
fields(value, path, { ...layout, item: asset, tints: dictionary(color, true) });
|
|
15131
|
+
} else {
|
|
15132
|
+
fields(value, path, {
|
|
15133
|
+
...layout,
|
|
15134
|
+
...textStyle,
|
|
15135
|
+
font: asset,
|
|
15136
|
+
shadow: boolean,
|
|
15137
|
+
maxWidth: positive,
|
|
15138
|
+
lineHeight: positive,
|
|
15139
|
+
text: (value2, path2) => {
|
|
15140
|
+
if (typeof value2 === "string") return;
|
|
15141
|
+
list((run, path3) => {
|
|
15142
|
+
fields(run, path3, { text: literalText, ...textStyle }, ["text"]);
|
|
15143
|
+
})(value2, path2);
|
|
15144
|
+
}
|
|
15145
|
+
});
|
|
15146
|
+
}
|
|
15147
|
+
}
|
|
15148
|
+
function validateObject(value, path) {
|
|
15149
|
+
const input = object2(value, path);
|
|
15150
|
+
const common = { id: text, name: text, type: text, position: tuple(3), rotation: tuple(3), scale: tuple(3), visible: boolean };
|
|
15151
|
+
const required = ["id", "type"];
|
|
15152
|
+
const renderOptions = { wireframe: boolean };
|
|
15153
|
+
switch (input.type) {
|
|
15154
|
+
case "skin":
|
|
15155
|
+
fields(value, path, {
|
|
15156
|
+
...common,
|
|
15157
|
+
skin: text,
|
|
15158
|
+
cape: (value2, path2) => {
|
|
15159
|
+
fields(value2, path2, { texture: text, layout: enumeration(["minecraft", "optifine", "labymod"]) }, ["texture"]);
|
|
15160
|
+
},
|
|
15161
|
+
hiddenParts: list(enumeration(SKIN_PARTS)),
|
|
15162
|
+
pose: (value2, path2) => {
|
|
15163
|
+
fields(value2, path2, {
|
|
15164
|
+
head: tuple(3),
|
|
15165
|
+
body: tuple(3),
|
|
15166
|
+
rightArm: tuple(3),
|
|
15167
|
+
leftArm: tuple(3),
|
|
15168
|
+
rightLeg: tuple(3),
|
|
15169
|
+
leftLeg: tuple(3),
|
|
15170
|
+
cape: tuple(3)
|
|
15171
|
+
});
|
|
15172
|
+
},
|
|
15173
|
+
options: (value2, path2) => {
|
|
15174
|
+
fields(value2, path2, { slim: boolean, legacy: boolean });
|
|
15175
|
+
}
|
|
15176
|
+
}, required);
|
|
15177
|
+
break;
|
|
15178
|
+
case "block":
|
|
15179
|
+
fields(value, path, {
|
|
15180
|
+
...common,
|
|
15181
|
+
asset,
|
|
15182
|
+
state: dictionary(text),
|
|
15183
|
+
options: (value2, path2) => {
|
|
15184
|
+
fields(value2, path2, { ...renderOptions, tints: dictionary(color, true) });
|
|
15185
|
+
}
|
|
15186
|
+
}, [...required, "asset"]);
|
|
15187
|
+
break;
|
|
15188
|
+
case "item":
|
|
15189
|
+
case "model":
|
|
15190
|
+
fields(value, path, {
|
|
15191
|
+
...common,
|
|
15192
|
+
asset,
|
|
15193
|
+
options: (value2, path2) => {
|
|
15194
|
+
fields(value2, path2, { ...renderOptions, displayPosition: enumeration(DISPLAY_POSITIONS), tints: dictionary(color, true) });
|
|
15195
|
+
}
|
|
15196
|
+
}, [...required, "asset"]);
|
|
15197
|
+
break;
|
|
15198
|
+
case "entity":
|
|
15199
|
+
fields(value, path, {
|
|
15200
|
+
...common,
|
|
15201
|
+
asset,
|
|
15202
|
+
texture: asset,
|
|
15203
|
+
layers: list(text),
|
|
15204
|
+
when: list(text),
|
|
15205
|
+
textures: dictionary(asset),
|
|
15206
|
+
options: (value2, path2) => {
|
|
15207
|
+
fields(value2, path2, {
|
|
15208
|
+
...renderOptions,
|
|
15209
|
+
flip: boolean,
|
|
15210
|
+
tints: dictionary((value3, path3) => {
|
|
15211
|
+
typeof value3 === "string" ? text(value3, path3) : color(value3, path3);
|
|
15212
|
+
})
|
|
15213
|
+
});
|
|
15214
|
+
},
|
|
15215
|
+
animation: (value2, path2) => {
|
|
15216
|
+
fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
|
|
15217
|
+
}
|
|
15218
|
+
}, [...required, "asset"]);
|
|
15219
|
+
if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
|
|
15220
|
+
break;
|
|
15221
|
+
case "gui":
|
|
15222
|
+
fields(value, path, { ...common, layers: list(guiLayer) }, [...required, "layers"]);
|
|
15223
|
+
break;
|
|
15224
|
+
default:
|
|
15225
|
+
fail(`${path}.type`, "expected skin, block, item, entity, model, or gui");
|
|
15226
|
+
}
|
|
15227
|
+
}
|
|
15228
|
+
function parseSceneDocument(value) {
|
|
15229
|
+
if (typeof value === "string") {
|
|
15230
|
+
try {
|
|
15231
|
+
value = JSON.parse(value);
|
|
15232
|
+
} catch {
|
|
15233
|
+
fail("scene", "invalid JSON");
|
|
15234
|
+
}
|
|
15235
|
+
}
|
|
15236
|
+
const input = fields(value, "scene", {
|
|
15237
|
+
format: enumeration(["minerender-scene"]),
|
|
15238
|
+
version: (value2, path) => {
|
|
15239
|
+
if (value2 !== 1) fail(path, "only scene document version 1 is supported");
|
|
15240
|
+
},
|
|
15241
|
+
minecraftVersion: version,
|
|
15242
|
+
camera: (value2, path) => {
|
|
15243
|
+
fields(value2, path, { position: tuple(3), target: tuple(3) }, ["position", "target"]);
|
|
15244
|
+
},
|
|
15245
|
+
objects: list(validateObject)
|
|
15246
|
+
}, ["format", "version", "objects"]);
|
|
15247
|
+
const ids = /* @__PURE__ */ new Set();
|
|
15248
|
+
for (const [index, entry] of input.objects.entries()) {
|
|
15249
|
+
if (ids.has(entry.id)) fail(`scene.objects[${index}].id`, `duplicate object ID "${entry.id}"`);
|
|
15250
|
+
ids.add(entry.id);
|
|
15251
|
+
}
|
|
15252
|
+
return JSON.parse(JSON.stringify(input));
|
|
15253
|
+
}
|
|
15254
|
+
|
|
15255
|
+
// src/scene/SceneDocumentLoader.ts
|
|
15256
|
+
var import_three38 = require("three");
|
|
15257
|
+
init_AssetKey();
|
|
15258
|
+
init_AssetLoader();
|
|
15259
|
+
init_BlockStates();
|
|
15260
|
+
init_Entities();
|
|
15261
|
+
init_Models();
|
|
15262
|
+
init_DisplayPosition();
|
|
15263
|
+
init_SceneObject();
|
|
15264
|
+
|
|
14834
15265
|
// src/skin/Skins.ts
|
|
14835
15266
|
init_Requests();
|
|
14836
15267
|
var Skins = class {
|
|
14837
15268
|
//<editor-fold desc="Skins">
|
|
15269
|
+
/** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
|
|
14838
15270
|
static async fromUuidOrUsername(uuidOrUsername) {
|
|
14839
15271
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14840
15272
|
return this.fromUuid(uuidOrUsername);
|
|
14841
15273
|
}
|
|
14842
15274
|
return this.fromUsername(uuidOrUsername);
|
|
14843
15275
|
}
|
|
15276
|
+
/** Builds a proxy URL for a UUID without downloading or checking the skin. */
|
|
14844
15277
|
static async fromUuid(uuid) {
|
|
14845
15278
|
return this.getMcProxySkinUrl(uuid);
|
|
14846
15279
|
}
|
|
@@ -14852,6 +15285,7 @@ var Skins = class {
|
|
|
14852
15285
|
return void 0;
|
|
14853
15286
|
});
|
|
14854
15287
|
}
|
|
15288
|
+
/** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
|
|
14855
15289
|
static async fromMineSkin(mineskinId) {
|
|
14856
15290
|
return this.getMineSkin(mineskinId).then((mineskin) => {
|
|
14857
15291
|
if (mineskin) {
|
|
@@ -14862,12 +15296,14 @@ var Skins = class {
|
|
|
14862
15296
|
}
|
|
14863
15297
|
//</editor-fold>
|
|
14864
15298
|
//<editor-fold desc="Capes">
|
|
15299
|
+
/** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
|
|
14865
15300
|
static async capeFromUuidOrUsername(uuidOrUsername) {
|
|
14866
15301
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14867
15302
|
return this.capeFromUuid(uuidOrUsername);
|
|
14868
15303
|
}
|
|
14869
15304
|
return this.capeFromUsername(uuidOrUsername);
|
|
14870
15305
|
}
|
|
15306
|
+
/** Builds a proxy URL without checking whether the player has a cape. */
|
|
14871
15307
|
static async capeFromUuid(uuid) {
|
|
14872
15308
|
return this.getMcProxyCapeUrl(uuid);
|
|
14873
15309
|
}
|
|
@@ -14996,6 +15432,195 @@ var Skins = class {
|
|
|
14996
15432
|
//</editor-fold>
|
|
14997
15433
|
};
|
|
14998
15434
|
|
|
15435
|
+
// src/scene/SceneDocumentLoader.ts
|
|
15436
|
+
var DocumentObjectScene = class extends MineRenderScene {
|
|
15437
|
+
async addSceneObject(_asset, supplier, _options, parent = this) {
|
|
15438
|
+
const object3 = await supplier();
|
|
15439
|
+
return this.initialize(object3, parent);
|
|
15440
|
+
}
|
|
15441
|
+
async initialize(object3, parent = this) {
|
|
15442
|
+
object3.scene = this;
|
|
15443
|
+
try {
|
|
15444
|
+
await object3.init();
|
|
15445
|
+
parent.add(object3);
|
|
15446
|
+
return object3;
|
|
15447
|
+
} catch (error) {
|
|
15448
|
+
object3.dispose();
|
|
15449
|
+
object3.removeFromParent();
|
|
15450
|
+
throw error;
|
|
15451
|
+
}
|
|
15452
|
+
}
|
|
15453
|
+
dispose() {
|
|
15454
|
+
for (const child of [...this.children]) {
|
|
15455
|
+
if (child.parent !== this) continue;
|
|
15456
|
+
if (isSceneObject(child)) child.dispose();
|
|
15457
|
+
child.removeFromParent();
|
|
15458
|
+
}
|
|
15459
|
+
}
|
|
15460
|
+
};
|
|
15461
|
+
async function skinTexture(value, cape = false) {
|
|
15462
|
+
if (!/^[a-zA-Z0-9_-]{1,36}$/.test(value)) return value;
|
|
15463
|
+
const texture = await (cape ? Skins.capeFromUuidOrUsername(value) : Skins.fromUuidOrUsername(value));
|
|
15464
|
+
if (!texture) throw new Error(`Could not find ${cape ? "cape" : "skin"} for "${value}"`);
|
|
15465
|
+
return texture;
|
|
15466
|
+
}
|
|
15467
|
+
var SceneDocumentLoader = class {
|
|
15468
|
+
static parse(value) {
|
|
15469
|
+
return parseSceneDocument(value);
|
|
15470
|
+
}
|
|
15471
|
+
/**
|
|
15472
|
+
* Loads objects concurrently and attaches them in document order after every load succeeds.
|
|
15473
|
+
* A failure waits for all loads, disposes staged objects, and reports the first error in document order.
|
|
15474
|
+
*/
|
|
15475
|
+
static async load(scene, value, parent = scene) {
|
|
15476
|
+
const definition = this.parse(value);
|
|
15477
|
+
if (definition.minecraftVersion !== void 0 && definition.minecraftVersion !== AssetLoader.version) {
|
|
15478
|
+
throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion("${definition.minecraftVersion}") before loading it`);
|
|
15479
|
+
}
|
|
15480
|
+
const root = new import_three38.Group();
|
|
15481
|
+
root.name = "MineRender scene document";
|
|
15482
|
+
const objects = [];
|
|
15483
|
+
let disposed = false;
|
|
15484
|
+
const loaded = {
|
|
15485
|
+
root,
|
|
15486
|
+
objects,
|
|
15487
|
+
definition,
|
|
15488
|
+
advanceAnimations: (delta) => {
|
|
15489
|
+
if (!disposed) for (const object3 of objects) object3.advanceAnimation(delta);
|
|
15490
|
+
},
|
|
15491
|
+
dispose: () => {
|
|
15492
|
+
if (disposed) return;
|
|
15493
|
+
disposed = true;
|
|
15494
|
+
root.removeFromParent();
|
|
15495
|
+
for (const object3 of objects) object3.dispose();
|
|
15496
|
+
root.clear();
|
|
15497
|
+
scene.dirty = true;
|
|
15498
|
+
}
|
|
15499
|
+
};
|
|
15500
|
+
try {
|
|
15501
|
+
const results = await Promise.allSettled(definition.objects.map((object3) => this.loadValidatedObject(scene, object3)));
|
|
15502
|
+
for (const result of results) if (result.status === "fulfilled") objects.push(result.value);
|
|
15503
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
15504
|
+
if (failure) throw failure.reason;
|
|
15505
|
+
for (const object3 of objects) root.add(object3.root);
|
|
15506
|
+
parent.add(root);
|
|
15507
|
+
scene.dirty = true;
|
|
15508
|
+
return loaded;
|
|
15509
|
+
} catch (error) {
|
|
15510
|
+
loaded.dispose();
|
|
15511
|
+
throw error;
|
|
15512
|
+
}
|
|
15513
|
+
}
|
|
15514
|
+
/** Loads an independently editable object. Its root owns the document's position, rotation, and scale. */
|
|
15515
|
+
static async loadObject(scene, value, parent = scene) {
|
|
15516
|
+
const definition = this.parse({ format: "minerender-scene", version: 1, objects: [value] }).objects[0];
|
|
15517
|
+
return this.loadValidatedObject(scene, definition, parent);
|
|
15518
|
+
}
|
|
15519
|
+
static async loadValidatedObject(scene, definition, parent) {
|
|
15520
|
+
const root = new import_three38.Group();
|
|
15521
|
+
root.name = definition.name ?? definition.id;
|
|
15522
|
+
root.userData.sceneObjectId = definition.id;
|
|
15523
|
+
root.position.fromArray(definition.position ?? [0, 0, 0]);
|
|
15524
|
+
root.rotation.set(...definition.rotation ?? [0, 0, 0]);
|
|
15525
|
+
root.scale.fromArray(definition.scale ?? [1, 1, 1]);
|
|
15526
|
+
root.visible = definition.visible ?? true;
|
|
15527
|
+
const content = new DocumentObjectScene();
|
|
15528
|
+
root.add(content);
|
|
15529
|
+
let object3;
|
|
15530
|
+
try {
|
|
15531
|
+
switch (definition.type) {
|
|
15532
|
+
case "skin": {
|
|
15533
|
+
const skin = new SkinObject({ ...definition.options, instanceMeshes: false });
|
|
15534
|
+
object3 = skin;
|
|
15535
|
+
const texture = definition.skin ? await skinTexture(definition.skin) : `${AssetLoader.ROOT}/assets/minecraft/textures/entity/player/${definition.options?.slim ? "slim/alex" : "wide/steve"}.png`;
|
|
15536
|
+
await skin.setSkinTexture(texture);
|
|
15537
|
+
await content.initialize(skin);
|
|
15538
|
+
if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);
|
|
15539
|
+
for (const [part, rotation] of Object.entries(definition.pose ?? {})) {
|
|
15540
|
+
skin.getGroupByName(part)?.rotation.set(...rotation, "XYZ");
|
|
15541
|
+
}
|
|
15542
|
+
for (const part of definition.hiddenParts ?? []) {
|
|
15543
|
+
const mesh = skin.getMeshByName(part);
|
|
15544
|
+
if (mesh) mesh.visible = false;
|
|
15545
|
+
}
|
|
15546
|
+
break;
|
|
15547
|
+
}
|
|
15548
|
+
case "block": {
|
|
15549
|
+
const state = await BlockStates.get(AssetKey.parse("blockstates", definition.asset));
|
|
15550
|
+
if (!state) throw new Error(`Could not load block ${definition.asset}`);
|
|
15551
|
+
object3 = await content.addBlock(state, { ...definition.options, initialState: definition.state, instanceMeshes: false });
|
|
15552
|
+
break;
|
|
15553
|
+
}
|
|
15554
|
+
case "item":
|
|
15555
|
+
case "model": {
|
|
15556
|
+
let key = AssetKey.parse("models", definition.asset);
|
|
15557
|
+
if (definition.type === "item" && key.type !== "item") {
|
|
15558
|
+
key = new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
15559
|
+
}
|
|
15560
|
+
const model = await Models.getMerged(key);
|
|
15561
|
+
if (!model) throw new Error(`Could not load ${definition.type} ${definition.asset}`);
|
|
15562
|
+
object3 = await content.addModel(model, {
|
|
15563
|
+
...definition.type === "item" ? { displayPosition: "gui" /* GUI */ } : {},
|
|
15564
|
+
...definition.options,
|
|
15565
|
+
instanceMeshes: false
|
|
15566
|
+
});
|
|
15567
|
+
break;
|
|
15568
|
+
}
|
|
15569
|
+
case "entity": {
|
|
15570
|
+
const key = AssetKey.parse("entity-models", definition.asset);
|
|
15571
|
+
const model = await Entities.getEntity(key, definition.texture ? AssetKey.parse("textures", definition.texture) : void 0, {
|
|
15572
|
+
layers: definition.layers,
|
|
15573
|
+
when: definition.when,
|
|
15574
|
+
textures: definition.textures && Object.fromEntries(Object.entries(definition.textures).map(([name, texture]) => [name, AssetKey.parse("textures", texture)]))
|
|
15575
|
+
});
|
|
15576
|
+
if (!model) throw new Error(`Could not load entity ${definition.asset}`);
|
|
15577
|
+
const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
|
|
15578
|
+
object3 = entity;
|
|
15579
|
+
if (definition.animation) {
|
|
15580
|
+
const animations = await Entities.getAnimations(key);
|
|
15581
|
+
const clip = animations?.[definition.animation.name];
|
|
15582
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${definition.animation.name}"`);
|
|
15583
|
+
entity.playAnimation(clip, definition.animation);
|
|
15584
|
+
}
|
|
15585
|
+
break;
|
|
15586
|
+
}
|
|
15587
|
+
case "gui":
|
|
15588
|
+
object3 = await content.initialize(new GuiObject(definition.layers));
|
|
15589
|
+
break;
|
|
15590
|
+
}
|
|
15591
|
+
let disposed = false;
|
|
15592
|
+
const loaded = {
|
|
15593
|
+
root,
|
|
15594
|
+
object: object3,
|
|
15595
|
+
definition,
|
|
15596
|
+
advanceAnimation: (delta) => {
|
|
15597
|
+
if (!disposed && definition.type === "entity" && !definition.animation?.paused) object3.advanceAnimation(delta);
|
|
15598
|
+
},
|
|
15599
|
+
dispose: () => {
|
|
15600
|
+
if (disposed) return;
|
|
15601
|
+
disposed = true;
|
|
15602
|
+
root.removeFromParent();
|
|
15603
|
+
object3.dispose();
|
|
15604
|
+
object3.removeFromParent();
|
|
15605
|
+
content.dispose();
|
|
15606
|
+
root.clear();
|
|
15607
|
+
scene.dirty = true;
|
|
15608
|
+
}
|
|
15609
|
+
};
|
|
15610
|
+
parent?.add(root);
|
|
15611
|
+
scene.dirty = true;
|
|
15612
|
+
return loaded;
|
|
15613
|
+
} catch (error) {
|
|
15614
|
+
object3?.dispose();
|
|
15615
|
+
object3?.removeFromParent();
|
|
15616
|
+
content.dispose();
|
|
15617
|
+
root.removeFromParent();
|
|
15618
|
+
root.clear();
|
|
15619
|
+
throw new Error(`Scene object "${definition.name ?? definition.id}": ${error instanceof Error ? error.message : String(error)}`);
|
|
15620
|
+
}
|
|
15621
|
+
}
|
|
15622
|
+
};
|
|
15623
|
+
|
|
14999
15624
|
// src/texture/index.ts
|
|
15000
15625
|
init_Colormaps();
|
|
15001
15626
|
init_TextureAtlas();
|
|
@@ -15022,16 +15647,19 @@ var ChunkData = class _ChunkData {
|
|
|
15022
15647
|
this.freeIds = [];
|
|
15023
15648
|
this.nbt = /* @__PURE__ */ new Map();
|
|
15024
15649
|
}
|
|
15650
|
+
/** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
|
|
15025
15651
|
get(index) {
|
|
15026
15652
|
_ChunkData.validateIndex(index);
|
|
15027
15653
|
const entry = this.palette[this.indices[index]];
|
|
15028
15654
|
return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
|
|
15029
15655
|
}
|
|
15656
|
+
/** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
|
|
15030
15657
|
snapshot(index) {
|
|
15031
15658
|
_ChunkData.validateIndex(index);
|
|
15032
15659
|
const entry = this.palette[this.indices[index]];
|
|
15033
15660
|
return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
|
|
15034
15661
|
}
|
|
15662
|
+
/** Copies block data into a cell. An omitted block or an air block clears the cell. */
|
|
15035
15663
|
set(index, block) {
|
|
15036
15664
|
_ChunkData.validateIndex(index);
|
|
15037
15665
|
let state;
|
|
@@ -15096,15 +15724,23 @@ var ChunkData = class _ChunkData {
|
|
|
15096
15724
|
|
|
15097
15725
|
// src/world/AnvilParser.ts
|
|
15098
15726
|
var AnvilParser = class {
|
|
15727
|
+
/** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
|
|
15099
15728
|
static getChunkList(data) {
|
|
15100
15729
|
return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
|
|
15101
15730
|
}
|
|
15731
|
+
/** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
|
|
15102
15732
|
static async parse(data) {
|
|
15103
15733
|
const bytes = this.bytes(data);
|
|
15104
15734
|
const chunks = [];
|
|
15105
15735
|
for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
|
|
15106
15736
|
return { chunks };
|
|
15107
15737
|
}
|
|
15738
|
+
/**
|
|
15739
|
+
* Decodes one chunk for {@link MineRenderWorld.placeChunk}.
|
|
15740
|
+
* @param localX - Chunk x within the region, from 0 to 31.
|
|
15741
|
+
* @param localZ - Chunk z within the region, from 0 to 31.
|
|
15742
|
+
* @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
|
|
15743
|
+
*/
|
|
15108
15744
|
static async parseChunk(data, localX, localZ) {
|
|
15109
15745
|
if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
|
|
15110
15746
|
throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
|
|
@@ -15266,12 +15902,12 @@ var AnvilParser = class {
|
|
|
15266
15902
|
};
|
|
15267
15903
|
|
|
15268
15904
|
// src/world/Chunk.ts
|
|
15269
|
-
var
|
|
15905
|
+
var import_three42 = require("three");
|
|
15270
15906
|
init_BlockStates();
|
|
15271
15907
|
init_AssetKey();
|
|
15272
15908
|
|
|
15273
15909
|
// src/world/MineRenderWorld.ts
|
|
15274
|
-
var
|
|
15910
|
+
var import_three40 = require("three");
|
|
15275
15911
|
init_Model();
|
|
15276
15912
|
init_BatchedExecutor();
|
|
15277
15913
|
init_AssetKey();
|
|
@@ -15279,7 +15915,7 @@ init_BlockStates();
|
|
|
15279
15915
|
init_CubeFace();
|
|
15280
15916
|
|
|
15281
15917
|
// src/world/SectionModels.ts
|
|
15282
|
-
var
|
|
15918
|
+
var import_three39 = require("three");
|
|
15283
15919
|
init_AssetKey();
|
|
15284
15920
|
init_Models();
|
|
15285
15921
|
init_CubeFace();
|
|
@@ -15309,6 +15945,7 @@ var SectionModels = class {
|
|
|
15309
15945
|
this.templates = /* @__PURE__ */ new Set();
|
|
15310
15946
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
15311
15947
|
}
|
|
15948
|
+
/** Returns a cube template, or `undefined` when the block requires an individual render object. */
|
|
15312
15949
|
async get(blockState, properties = {}) {
|
|
15313
15950
|
if (!blockState.variants || blockState.multipart) return void 0;
|
|
15314
15951
|
let states = this.states.get(blockState);
|
|
@@ -15337,20 +15974,20 @@ var SectionModels = class {
|
|
|
15337
15974
|
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
15338
15975
|
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
15339
15976
|
const template = await cached(models, key, async () => {
|
|
15340
|
-
const
|
|
15977
|
+
const object3 = new SectionModel(model, {
|
|
15341
15978
|
instanceMeshes: false,
|
|
15342
15979
|
mergeMeshes: false,
|
|
15343
15980
|
tints,
|
|
15344
15981
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
15345
15982
|
});
|
|
15346
|
-
await
|
|
15347
|
-
const geometry =
|
|
15348
|
-
geometry.applyMatrix4(new
|
|
15349
|
-
|
|
15983
|
+
await object3.init();
|
|
15984
|
+
const geometry = object3.children[0].geometry;
|
|
15985
|
+
geometry.applyMatrix4(new import_three39.Matrix4().makeRotationFromEuler(rotation));
|
|
15986
|
+
object3.clear();
|
|
15350
15987
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
15351
15988
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
15352
15989
|
if (local < 0) return 0;
|
|
15353
|
-
const normal = new
|
|
15990
|
+
const normal = new import_three39.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
15354
15991
|
const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
15355
15992
|
return 1 << world;
|
|
15356
15993
|
});
|
|
@@ -15362,6 +15999,7 @@ var SectionModels = class {
|
|
|
15362
15999
|
}
|
|
15363
16000
|
return { variants, templates };
|
|
15364
16001
|
}
|
|
16002
|
+
/** Disposes prepared geometry and clears this world's template caches. */
|
|
15365
16003
|
clear() {
|
|
15366
16004
|
for (const template of this.templates) template.geometry.dispose();
|
|
15367
16005
|
this.templates.clear();
|
|
@@ -15380,20 +16018,20 @@ var MineRenderWorld = class {
|
|
|
15380
16018
|
}
|
|
15381
16019
|
getBlockAt(posOrX, y, z) {
|
|
15382
16020
|
if (typeof posOrX == "number") {
|
|
15383
|
-
return this.getBlockAt(new
|
|
16021
|
+
return this.getBlockAt(new import_three40.Vector3(posOrX, y, z));
|
|
15384
16022
|
}
|
|
15385
16023
|
if (isTripleArray(posOrX)) {
|
|
15386
|
-
return this.getBlockAt(new
|
|
16024
|
+
return this.getBlockAt(new import_three40.Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
15387
16025
|
}
|
|
15388
16026
|
this.validatePosBounds(posOrX);
|
|
15389
16027
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
15390
16028
|
}
|
|
15391
16029
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
15392
16030
|
if (typeof posOrX == "number") {
|
|
15393
|
-
return this.setBlockAt(new
|
|
16031
|
+
return this.setBlockAt(new import_three40.Vector3(posOrX, yOrBlock, z), block);
|
|
15394
16032
|
}
|
|
15395
16033
|
if (isTripleArray(posOrX)) {
|
|
15396
|
-
return this.setBlockAt(new
|
|
16034
|
+
return this.setBlockAt(new import_three40.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
15397
16035
|
}
|
|
15398
16036
|
return this.placeBlock(posOrX, yOrBlock);
|
|
15399
16037
|
}
|
|
@@ -15404,14 +16042,21 @@ var MineRenderWorld = class {
|
|
|
15404
16042
|
}
|
|
15405
16043
|
async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
|
|
15406
16044
|
if (typeof posOrX === "number") {
|
|
15407
|
-
return this.setBlockVisibleAt(new
|
|
16045
|
+
return this.setBlockVisibleAt(new import_three40.Vector3(posOrX, yOrVisible, z), visible);
|
|
15408
16046
|
}
|
|
15409
16047
|
if (isTripleArray(posOrX)) {
|
|
15410
|
-
return this.setBlockVisibleAt(new
|
|
16048
|
+
return this.setBlockVisibleAt(new import_three40.Vector3(...posOrX), yOrVisible);
|
|
15411
16049
|
}
|
|
15412
16050
|
this.validatePosBounds(posOrX);
|
|
15413
16051
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
15414
16052
|
}
|
|
16053
|
+
/**
|
|
16054
|
+
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
16055
|
+
* Entity NBT is retained by the structure but is not rendered.
|
|
16056
|
+
*
|
|
16057
|
+
* @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
|
|
16058
|
+
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
16059
|
+
*/
|
|
15415
16060
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
15416
16061
|
const changes = /* @__PURE__ */ new Map();
|
|
15417
16062
|
try {
|
|
@@ -15424,7 +16069,7 @@ var MineRenderWorld = class {
|
|
|
15424
16069
|
const collect = async (positions2) => {
|
|
15425
16070
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
15426
16071
|
};
|
|
15427
|
-
const place = (block) => this.placeBlock(new
|
|
16072
|
+
const place = (block) => this.placeBlock(new import_three40.Vector3(...block.position), block, collect);
|
|
15428
16073
|
const keys = /* @__PURE__ */ new Map();
|
|
15429
16074
|
for (const block of multiblock.blocks) {
|
|
15430
16075
|
if (Chunk.isAir(block)) continue;
|
|
@@ -15508,6 +16153,7 @@ var MineRenderWorld = class {
|
|
|
15508
16153
|
});
|
|
15509
16154
|
}
|
|
15510
16155
|
}
|
|
16156
|
+
/** Removes all chunks and releases their block placements and section meshes. */
|
|
15511
16157
|
async clear() {
|
|
15512
16158
|
await this.culling;
|
|
15513
16159
|
const chunks = [...this._chunks.values()];
|
|
@@ -15521,13 +16167,13 @@ var MineRenderWorld = class {
|
|
|
15521
16167
|
for (const pos of positions) {
|
|
15522
16168
|
this.pendingCulling.set(pos.toArray().join(","), pos.clone());
|
|
15523
16169
|
for (const offset of CUBE_FACE_OFFSETS) {
|
|
15524
|
-
const neighbor = pos.clone().add(new
|
|
16170
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(...offset));
|
|
15525
16171
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
15526
16172
|
}
|
|
15527
16173
|
for (let y = -1; y <= 1; y++) {
|
|
15528
16174
|
for (let z = -1; z <= 1; z++) {
|
|
15529
16175
|
for (let x = -1; x <= 1; x++) {
|
|
15530
|
-
const neighbor = pos.clone().add(new
|
|
16176
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(x, y, z));
|
|
15531
16177
|
if (this.getBlockAt(neighbor)?.object?.fluidKind) {
|
|
15532
16178
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
15533
16179
|
}
|
|
@@ -15551,19 +16197,19 @@ var MineRenderWorld = class {
|
|
|
15551
16197
|
}
|
|
15552
16198
|
if (block.object?.fluidKind) {
|
|
15553
16199
|
await block.object.updateFluid((x, y, z) => {
|
|
15554
|
-
const neighbor = pos.clone().add(new
|
|
16200
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(x, y, z));
|
|
15555
16201
|
const section = this.getChunkAt(neighbor);
|
|
15556
|
-
const
|
|
16202
|
+
const object3 = section?.isBlockVisibleAt(neighbor) ? section.getBlockAt(neighbor)?.object : void 0;
|
|
15557
16203
|
return {
|
|
15558
|
-
fluid:
|
|
15559
|
-
level:
|
|
16204
|
+
fluid: object3?.fluidKind,
|
|
16205
|
+
level: object3?.fluidLevel,
|
|
15560
16206
|
solid: section?.isOccludingAt(neighbor) ?? false
|
|
15561
16207
|
};
|
|
15562
16208
|
});
|
|
15563
16209
|
}
|
|
15564
16210
|
let mask = 0;
|
|
15565
16211
|
for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
15566
|
-
const neighbor = pos.clone().add(new
|
|
16212
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(...offset));
|
|
15567
16213
|
if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
|
|
15568
16214
|
mask |= 1 << face;
|
|
15569
16215
|
}
|
|
@@ -15593,18 +16239,21 @@ var MineRenderWorld = class {
|
|
|
15593
16239
|
}
|
|
15594
16240
|
return chunk;
|
|
15595
16241
|
}
|
|
16242
|
+
/** Returns the loaded chunk containing a world block position, without creating a chunk. */
|
|
15596
16243
|
getChunkAt(pos) {
|
|
15597
16244
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
15598
16245
|
}
|
|
16246
|
+
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
15599
16247
|
static worldToScenePosition(pos) {
|
|
15600
|
-
return new
|
|
16248
|
+
return new import_three40.Vector3(
|
|
15601
16249
|
pos.x * 16,
|
|
15602
16250
|
pos.y * 16,
|
|
15603
16251
|
pos.z * 16
|
|
15604
16252
|
);
|
|
15605
16253
|
}
|
|
16254
|
+
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
15606
16255
|
static sceneToWorldPosition(pos) {
|
|
15607
|
-
return new
|
|
16256
|
+
return new import_three40.Vector3(
|
|
15608
16257
|
pos.x / 16,
|
|
15609
16258
|
pos.y / 16,
|
|
15610
16259
|
pos.z / 16
|
|
@@ -15627,14 +16276,15 @@ var MineRenderWorld = class {
|
|
|
15627
16276
|
init_Model();
|
|
15628
16277
|
|
|
15629
16278
|
// src/world/SectionMesh.ts
|
|
15630
|
-
var
|
|
16279
|
+
var import_three41 = require("three");
|
|
15631
16280
|
init_CanvasCompat();
|
|
15632
16281
|
init_Materials();
|
|
15633
|
-
var SectionMesh = class _SectionMesh extends
|
|
16282
|
+
var SectionMesh = class _SectionMesh extends import_three41.Group {
|
|
15634
16283
|
constructor() {
|
|
15635
16284
|
super(...arguments);
|
|
15636
16285
|
this.ownedMeshes = [];
|
|
15637
16286
|
}
|
|
16287
|
+
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
15638
16288
|
static build(entries, maxAtlasSize = 2048) {
|
|
15639
16289
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
15640
16290
|
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
@@ -15682,7 +16332,7 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
|
|
|
15682
16332
|
const normal = template.geometry.getAttribute("normal");
|
|
15683
16333
|
const uv = template.geometry.getAttribute("uv");
|
|
15684
16334
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
15685
|
-
const
|
|
16335
|
+
const color2 = template.geometry.getAttribute("color");
|
|
15686
16336
|
const sourceIndices = template.geometry.getIndex();
|
|
15687
16337
|
const placement = locations.get(template.atlas).placement;
|
|
15688
16338
|
const mapU = (u) => (placement.x + u * template.atlas.image.width) / page.width;
|
|
@@ -15704,24 +16354,24 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
|
|
|
15704
16354
|
mapU(bounds?.getZ(vertex) ?? 1),
|
|
15705
16355
|
mapV(bounds?.getW(vertex) ?? 1)
|
|
15706
16356
|
);
|
|
15707
|
-
colors.push(
|
|
16357
|
+
colors.push(color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1);
|
|
15708
16358
|
}
|
|
15709
16359
|
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
15710
16360
|
}
|
|
15711
16361
|
}
|
|
15712
|
-
const geometry = new
|
|
15713
|
-
geometry.setAttribute("position", new
|
|
15714
|
-
geometry.setAttribute("normal", new
|
|
15715
|
-
geometry.setAttribute("uv", new
|
|
15716
|
-
geometry.setAttribute("uvBounds", new
|
|
15717
|
-
geometry.setAttribute("color", new
|
|
16362
|
+
const geometry = new import_three41.BufferGeometry();
|
|
16363
|
+
geometry.setAttribute("position", new import_three41.Float32BufferAttribute(positions, 3));
|
|
16364
|
+
geometry.setAttribute("normal", new import_three41.Float32BufferAttribute(normals, 3));
|
|
16365
|
+
geometry.setAttribute("uv", new import_three41.Float32BufferAttribute(uvs, 2));
|
|
16366
|
+
geometry.setAttribute("uvBounds", new import_three41.Float32BufferAttribute(uvBounds, 4));
|
|
16367
|
+
geometry.setAttribute("color", new import_three41.Float32BufferAttribute(colors, 3));
|
|
15718
16368
|
geometry.setIndex(indices);
|
|
15719
16369
|
geometry.computeBoundingBox();
|
|
15720
16370
|
geometry.computeBoundingSphere();
|
|
15721
16371
|
const material = Materials.createShadedCanvasMaterial(canvas, false, false, true);
|
|
15722
16372
|
material.vertexColors = true;
|
|
15723
16373
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
15724
|
-
const mesh = new
|
|
16374
|
+
const mesh = new import_three41.Mesh(geometry, material);
|
|
15725
16375
|
section.add(mesh);
|
|
15726
16376
|
section.ownedMeshes.push({ mesh, texture });
|
|
15727
16377
|
}
|
|
@@ -15757,10 +16407,10 @@ var Chunk = class _Chunk {
|
|
|
15757
16407
|
}
|
|
15758
16408
|
getBlockAt(posOrX, y, z) {
|
|
15759
16409
|
if (typeof posOrX == "number") {
|
|
15760
|
-
return this.getBlockAt(new
|
|
16410
|
+
return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
|
|
15761
16411
|
}
|
|
15762
16412
|
if (isTripleArray(posOrX)) {
|
|
15763
|
-
return this.getBlockAt(new
|
|
16413
|
+
return this.getBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
15764
16414
|
}
|
|
15765
16415
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
15766
16416
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
@@ -15768,10 +16418,10 @@ var Chunk = class _Chunk {
|
|
|
15768
16418
|
}
|
|
15769
16419
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
15770
16420
|
if (typeof posOrX == "number") {
|
|
15771
|
-
return this.setBlockAt(new
|
|
16421
|
+
return this.setBlockAt(new import_three42.Vector3(posOrX, yOrBlock, z), block);
|
|
15772
16422
|
}
|
|
15773
16423
|
if (isTripleArray(posOrX)) {
|
|
15774
|
-
return this.setBlockAt(new
|
|
16424
|
+
return this.setBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
15775
16425
|
}
|
|
15776
16426
|
const worldPos = posOrX;
|
|
15777
16427
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -15779,7 +16429,7 @@ var Chunk = class _Chunk {
|
|
|
15779
16429
|
return this.setBlockInChunkAt(pos, block, worldPos);
|
|
15780
16430
|
}
|
|
15781
16431
|
/**
|
|
15782
|
-
*
|
|
16432
|
+
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
15783
16433
|
*/
|
|
15784
16434
|
async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
|
|
15785
16435
|
if (typeof worldPos === "undefined") {
|
|
@@ -15792,7 +16442,7 @@ var Chunk = class _Chunk {
|
|
|
15792
16442
|
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
15793
16443
|
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
15794
16444
|
this.renderedBlocks.delete(index);
|
|
15795
|
-
let
|
|
16445
|
+
let object3;
|
|
15796
16446
|
try {
|
|
15797
16447
|
if (!readBlock) return void 0;
|
|
15798
16448
|
const stored = readBlock();
|
|
@@ -15807,27 +16457,28 @@ var Chunk = class _Chunk {
|
|
|
15807
16457
|
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
15808
16458
|
this.meshDirty = true;
|
|
15809
16459
|
} else {
|
|
15810
|
-
|
|
16460
|
+
object3 = await this.scene.addBlock(blockState, {
|
|
15811
16461
|
mergeMeshes: true,
|
|
15812
16462
|
instanceMeshes: true,
|
|
15813
16463
|
maxInstanceCount: 2e3,
|
|
15814
16464
|
initialState: stored.properties
|
|
15815
16465
|
});
|
|
15816
|
-
|
|
16466
|
+
object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
15817
16467
|
}
|
|
15818
16468
|
const info = { get block() {
|
|
15819
16469
|
return readBlock();
|
|
15820
|
-
}, object:
|
|
16470
|
+
}, object: object3 };
|
|
15821
16471
|
this.renderedBlocks.set(index, info);
|
|
15822
16472
|
return info;
|
|
15823
16473
|
} catch (error) {
|
|
15824
16474
|
this.data.set(index, void 0);
|
|
15825
|
-
|
|
16475
|
+
object3?.removeFromScene();
|
|
15826
16476
|
throw error;
|
|
15827
16477
|
} finally {
|
|
15828
16478
|
await onBlocksChanged?.([worldPos]);
|
|
15829
16479
|
}
|
|
15830
16480
|
}
|
|
16481
|
+
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
15831
16482
|
async setBlockVisibleAt(pos, visible) {
|
|
15832
16483
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
15833
16484
|
const block = this.renderedBlocks.get(index);
|
|
@@ -15881,9 +16532,10 @@ var Chunk = class _Chunk {
|
|
|
15881
16532
|
this.scene.dirty = true;
|
|
15882
16533
|
this.meshDirty = false;
|
|
15883
16534
|
}
|
|
16535
|
+
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
15884
16536
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
15885
16537
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
15886
|
-
new
|
|
16538
|
+
new import_three42.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
15887
16539
|
));
|
|
15888
16540
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
15889
16541
|
this.sectionBlocks.clear();
|
|
@@ -15901,6 +16553,7 @@ var Chunk = class _Chunk {
|
|
|
15901
16553
|
static isAir(block) {
|
|
15902
16554
|
return ChunkData.isAir(block);
|
|
15903
16555
|
}
|
|
16556
|
+
/** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
|
|
15904
16557
|
static chunkPosToBlockIndex(pos) {
|
|
15905
16558
|
if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
|
|
15906
16559
|
throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");
|
|
@@ -15908,14 +16561,14 @@ var Chunk = class _Chunk {
|
|
|
15908
16561
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
15909
16562
|
}
|
|
15910
16563
|
worldPosToChunkPos(pos) {
|
|
15911
|
-
return new
|
|
16564
|
+
return new import_three42.Vector3(
|
|
15912
16565
|
pos.x - this.x * 16,
|
|
15913
16566
|
pos.y - this.y * 16,
|
|
15914
16567
|
pos.z - this.z * 16
|
|
15915
16568
|
);
|
|
15916
16569
|
}
|
|
15917
16570
|
chunkPosToWorldPos(pos) {
|
|
15918
|
-
return new
|
|
16571
|
+
return new import_three42.Vector3(
|
|
15919
16572
|
this.x * 16 + pos.x,
|
|
15920
16573
|
this.y * 16 + pos.y,
|
|
15921
16574
|
this.z * 16 + pos.z
|
|
@@ -16003,6 +16656,7 @@ var Chunk = class _Chunk {
|
|
|
16003
16656
|
RequestError,
|
|
16004
16657
|
Requests,
|
|
16005
16658
|
SKIN_PARTS,
|
|
16659
|
+
SceneDocumentLoader,
|
|
16006
16660
|
SceneExporter,
|
|
16007
16661
|
SceneInspector,
|
|
16008
16662
|
SceneObject,
|
|
@@ -16078,6 +16732,7 @@ var Chunk = class _Chunk {
|
|
|
16078
16732
|
mergeBufferAttributes,
|
|
16079
16733
|
mergeBufferGeometries,
|
|
16080
16734
|
mergeVertices,
|
|
16735
|
+
parseSceneDocument,
|
|
16081
16736
|
prefix,
|
|
16082
16737
|
registerNodeEnv,
|
|
16083
16738
|
sampleEntityAnimation,
|