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.mjs
CHANGED
|
@@ -68,6 +68,7 @@ var init_PersistentCache = __esm({
|
|
|
68
68
|
/** Bump to invalidate every persisted entry. */
|
|
69
69
|
this.VERSION = 2;
|
|
70
70
|
}
|
|
71
|
+
/** Opens a named store in the active environment using the current cache schema version. */
|
|
71
72
|
static open(name) {
|
|
72
73
|
return Env.provider.openCache(name, _PersistentCache.VERSION);
|
|
73
74
|
}
|
|
@@ -329,6 +330,7 @@ var init_Caching = __esm({
|
|
|
329
330
|
this.fontCache
|
|
330
331
|
];
|
|
331
332
|
}
|
|
333
|
+
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
332
334
|
static clear() {
|
|
333
335
|
for (const cache of this.all) {
|
|
334
336
|
cache.invalidateAll();
|
|
@@ -371,6 +373,7 @@ var init_Geometries = __esm({
|
|
|
371
373
|
}
|
|
372
374
|
return geometry;
|
|
373
375
|
}
|
|
376
|
+
/** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
|
|
374
377
|
static getBox(key) {
|
|
375
378
|
const keyStr = serializeBoxGeometryKey(key);
|
|
376
379
|
return Caching.boxGeometryCache.get(keyStr, (k) => {
|
|
@@ -554,12 +557,15 @@ var init_Requests = __esm({
|
|
|
554
557
|
static {
|
|
555
558
|
this.mcAssetRequestQueue = new RequestQueue();
|
|
556
559
|
}
|
|
560
|
+
/** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
|
|
557
561
|
static genericRequest(request) {
|
|
558
562
|
return this.genericQueue.request(request);
|
|
559
563
|
}
|
|
564
|
+
/** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
|
|
560
565
|
static mcAssetRequest(request) {
|
|
561
566
|
return this.mcAssetRequestQueue.request(request);
|
|
562
567
|
}
|
|
568
|
+
/** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
|
|
563
569
|
static setMcAssetRoot(root) {
|
|
564
570
|
this.mcAssetRequestQueue.baseURL = root;
|
|
565
571
|
}
|
|
@@ -612,6 +618,7 @@ var init_WrappedImage = __esm({
|
|
|
612
618
|
}
|
|
613
619
|
return false;
|
|
614
620
|
}
|
|
621
|
+
/** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
|
|
615
622
|
get animated() {
|
|
616
623
|
return this.height > this.width && this.height % this.width === 0;
|
|
617
624
|
}
|
|
@@ -658,6 +665,7 @@ var init_ImageLoader = __esm({
|
|
|
658
665
|
static _createImage() {
|
|
659
666
|
return createImage();
|
|
660
667
|
}
|
|
668
|
+
/** Resolves when an image URL has decoded, or rejects if decoding fails. */
|
|
661
669
|
static async loadAsync(src) {
|
|
662
670
|
return new Promise((resolve, reject) => {
|
|
663
671
|
const image = this._createImage();
|
|
@@ -666,6 +674,7 @@ var init_ImageLoader = __esm({
|
|
|
666
674
|
image.src = src;
|
|
667
675
|
});
|
|
668
676
|
}
|
|
677
|
+
/** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
|
|
669
678
|
static loadElement(src, onload, onerr) {
|
|
670
679
|
const image = this._createImage();
|
|
671
680
|
if (onload)
|
|
@@ -693,6 +702,7 @@ var init_ImageLoader = __esm({
|
|
|
693
702
|
throw err;
|
|
694
703
|
}
|
|
695
704
|
}
|
|
705
|
+
/** Decodes the supplied bytes into a canvas without fetching the source URL again. */
|
|
696
706
|
static async infoToCanvasData(info) {
|
|
697
707
|
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
698
708
|
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
@@ -709,12 +719,14 @@ var init_ImageLoader = __esm({
|
|
|
709
719
|
const image = await this.infoToCanvasData(info);
|
|
710
720
|
return image.data.getImageData(0, 0, image.width, image.height);
|
|
711
721
|
}
|
|
722
|
+
/** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
|
|
712
723
|
static async getData(src) {
|
|
713
724
|
const keyStr = serializeImageKey({ src });
|
|
714
725
|
return await Caching.imageDataCache.get(keyStr, (k) => {
|
|
715
726
|
return _ImageLoader.loadData(src);
|
|
716
727
|
});
|
|
717
728
|
}
|
|
729
|
+
/** Returns a cached canvas context and dimensions for an image URL or data URL. */
|
|
718
730
|
static async getCanvasData(src) {
|
|
719
731
|
const keyStr = serializeImageKey({ src });
|
|
720
732
|
return await Caching.canvasImageDataCache.get(keyStr, (k) => {
|
|
@@ -814,6 +826,7 @@ var init_TextureLoader = __esm({
|
|
|
814
826
|
texture.rotation = rotation;
|
|
815
827
|
return Textures.initTextureProps(texture);
|
|
816
828
|
}
|
|
829
|
+
/** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
|
|
817
830
|
static load(src, format2 = RGBAFormat, rotation = 0) {
|
|
818
831
|
const texture = new Texture();
|
|
819
832
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
@@ -850,8 +863,8 @@ var init_Textures = __esm({
|
|
|
850
863
|
for (let y = 0; y < size; y++) {
|
|
851
864
|
for (let x = 0; x < size; x++) {
|
|
852
865
|
const offset = (y * size + x) * 4;
|
|
853
|
-
const
|
|
854
|
-
data[offset] = data[offset + 2] =
|
|
866
|
+
const color2 = (x + y) % 2 === 0 ? 255 : 0;
|
|
867
|
+
data[offset] = data[offset + 2] = color2;
|
|
855
868
|
data[offset + 3] = 255;
|
|
856
869
|
}
|
|
857
870
|
}
|
|
@@ -862,6 +875,7 @@ var init_Textures = __esm({
|
|
|
862
875
|
return this.initTextureProps(texture);
|
|
863
876
|
});
|
|
864
877
|
}
|
|
878
|
+
/** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
|
|
865
879
|
static initTextureProps(texture) {
|
|
866
880
|
texture.magFilter = THREE2.NearestFilter;
|
|
867
881
|
texture.minFilter = THREE2.NearestFilter;
|
|
@@ -874,11 +888,13 @@ var init_Textures = __esm({
|
|
|
874
888
|
static createAsset(key) {
|
|
875
889
|
return new Texture2();
|
|
876
890
|
}
|
|
891
|
+
/** Creates an sRGB color texture from a canvas. */
|
|
877
892
|
static createCanvasTexture(canvas) {
|
|
878
893
|
const texture = new CanvasTexture(canvas);
|
|
879
894
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
880
895
|
return this.initTextureProps(texture);
|
|
881
896
|
}
|
|
897
|
+
/** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
|
|
882
898
|
static getImage(key) {
|
|
883
899
|
const keyStr = serializeTextureKey(key);
|
|
884
900
|
const cached2 = Caching.textureCache.peek(keyStr);
|
|
@@ -903,6 +919,7 @@ var init_Materials = __esm({
|
|
|
903
919
|
init_TextureLoader();
|
|
904
920
|
init_Caching();
|
|
905
921
|
Materials = class _Materials {
|
|
922
|
+
/** Shared checkerboard material, created on first access. */
|
|
906
923
|
static get MISSING_TEXTURE() {
|
|
907
924
|
return Caching.materialCache.get("builtin:missing-texture", () => new MeshBasicMaterial({
|
|
908
925
|
map: Textures.getMissing(),
|
|
@@ -1006,6 +1023,7 @@ var init_Materials = __esm({
|
|
|
1006
1023
|
if (tint !== void 0) material.color.multiply(new Color(tint));
|
|
1007
1024
|
return material;
|
|
1008
1025
|
}
|
|
1026
|
+
/** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
|
|
1009
1027
|
static createGuiCanvasMaterial(canvas) {
|
|
1010
1028
|
const material = new MeshBasicMaterial({
|
|
1011
1029
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -1172,6 +1190,7 @@ var init_Materials = __esm({
|
|
|
1172
1190
|
}
|
|
1173
1191
|
return this.createBasicCanvasMaterial(canvas, transparent, shade);
|
|
1174
1192
|
}
|
|
1193
|
+
/** Returns a shared image material. Use {@link createImage} for a separate material instance. */
|
|
1175
1194
|
static getImage(key) {
|
|
1176
1195
|
const keyStr = serializeMaterialKey(key);
|
|
1177
1196
|
const map = Caching.materialCache.peek(keyStr)?.map;
|
|
@@ -1346,6 +1365,14 @@ var init_AssetKey = __esm({
|
|
|
1346
1365
|
}
|
|
1347
1366
|
};
|
|
1348
1367
|
AssetKey = class _AssetKey extends BasicAssetKey {
|
|
1368
|
+
/**
|
|
1369
|
+
* Creates a key from separate path components. Use {@link parse} for a combined reference.
|
|
1370
|
+
*
|
|
1371
|
+
* @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
|
|
1372
|
+
* @param type - Subdirectory, such as `block` or `item`.
|
|
1373
|
+
* @param rootType - Top-level directory, usually `assets` or `data`.
|
|
1374
|
+
* @param root - Base URL override for hosted asset sources.
|
|
1375
|
+
*/
|
|
1349
1376
|
constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
|
|
1350
1377
|
super(namespace, path);
|
|
1351
1378
|
this.namespace = namespace;
|
|
@@ -1357,6 +1384,16 @@ var init_AssetKey = __esm({
|
|
|
1357
1384
|
this.root = root;
|
|
1358
1385
|
this.isAssetKey = true;
|
|
1359
1386
|
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Parses an asset reference such as `minecraft:block/stone`.
|
|
1389
|
+
* A missing namespace defaults to the origin's namespace or `minecraft`.
|
|
1390
|
+
*
|
|
1391
|
+
* @param assetType - Asset category, such as `models` or `textures`.
|
|
1392
|
+
* @param str - Path with an optional namespace and file extension.
|
|
1393
|
+
* @param origin - Supplies the asset root, default namespace, and non-texture extension.
|
|
1394
|
+
* @returns A key with the matching extension removed from its path. Textures use `.png`;
|
|
1395
|
+
* other assets use the origin's extension or `.json`.
|
|
1396
|
+
*/
|
|
1360
1397
|
static parse(assetType, str, origin) {
|
|
1361
1398
|
let namespace = origin?.namespace || DEFAULT_NAMESPACE;
|
|
1362
1399
|
if (str.includes(":")) {
|
|
@@ -1388,6 +1425,7 @@ var init_AssetKey = __esm({
|
|
|
1388
1425
|
];
|
|
1389
1426
|
return a.join("/");
|
|
1390
1427
|
}
|
|
1428
|
+
/** Joins the type subdirectory and path without adding a namespace or file extension. */
|
|
1391
1429
|
getFullPath() {
|
|
1392
1430
|
let p10 = [];
|
|
1393
1431
|
if (this.type) {
|
|
@@ -1399,6 +1437,7 @@ var init_AssetKey = __esm({
|
|
|
1399
1437
|
toNamespacedString() {
|
|
1400
1438
|
return this.namespace + ":" + this.getFullPath();
|
|
1401
1439
|
}
|
|
1440
|
+
/** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
|
|
1402
1441
|
serialize() {
|
|
1403
1442
|
return this.toString();
|
|
1404
1443
|
}
|
|
@@ -1410,17 +1449,17 @@ var init_AssetKey = __esm({
|
|
|
1410
1449
|
var DisplayPosition, DISPLAY_POSITIONS;
|
|
1411
1450
|
var init_DisplayPosition = __esm({
|
|
1412
1451
|
"src/model/DisplayPosition.ts"() {
|
|
1413
|
-
DisplayPosition = /* @__PURE__ */ ((
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
return
|
|
1452
|
+
DisplayPosition = /* @__PURE__ */ ((DisplayPosition3) => {
|
|
1453
|
+
DisplayPosition3["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
|
|
1454
|
+
DisplayPosition3["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
|
|
1455
|
+
DisplayPosition3["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
|
|
1456
|
+
DisplayPosition3["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
|
|
1457
|
+
DisplayPosition3["GUI"] = "gui";
|
|
1458
|
+
DisplayPosition3["HEAD"] = "head";
|
|
1459
|
+
DisplayPosition3["GROUND"] = "ground";
|
|
1460
|
+
DisplayPosition3["FIXED"] = "fixed";
|
|
1461
|
+
DisplayPosition3["ON_SHELF"] = "on_shelf";
|
|
1462
|
+
return DisplayPosition3;
|
|
1424
1463
|
})(DisplayPosition || {});
|
|
1425
1464
|
DISPLAY_POSITIONS = Object.values(DisplayPosition);
|
|
1426
1465
|
}
|
|
@@ -1458,6 +1497,7 @@ var init_DisplayTransforms = __esm({
|
|
|
1458
1497
|
const scale = new Vector32(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
|
|
1459
1498
|
return new Matrix4().compose(translation, rotation, scale);
|
|
1460
1499
|
}
|
|
1500
|
+
/** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
|
|
1461
1501
|
static apply(geometry, matrix) {
|
|
1462
1502
|
geometry.applyMatrix4(matrix);
|
|
1463
1503
|
if (matrix.determinant() < 0) {
|
|
@@ -1485,6 +1525,7 @@ var init_ModelMerger = __esm({
|
|
|
1485
1525
|
init_AssetKey();
|
|
1486
1526
|
init_DisplayTransforms();
|
|
1487
1527
|
ModelMerger = class {
|
|
1528
|
+
/** Loads the parent chain and returns a merged model without modifying the supplied definition. */
|
|
1488
1529
|
static async mergeWithParents(model) {
|
|
1489
1530
|
const models = await this.collectAllParents(model);
|
|
1490
1531
|
let merged = {};
|
|
@@ -1552,6 +1593,7 @@ var init_Models = __esm({
|
|
|
1552
1593
|
static get PERSISTENT_CACHE() {
|
|
1553
1594
|
return this._persistentCache ??= PersistentCache.open("minerender-models");
|
|
1554
1595
|
}
|
|
1596
|
+
/** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
|
|
1555
1597
|
static async getItemList() {
|
|
1556
1598
|
const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
|
|
1557
1599
|
const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
|
|
@@ -1622,6 +1664,7 @@ var init_Models = __esm({
|
|
|
1622
1664
|
}
|
|
1623
1665
|
throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
|
|
1624
1666
|
}
|
|
1667
|
+
/** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
|
|
1625
1668
|
static async getRaw(key) {
|
|
1626
1669
|
if (!key.assetType) {
|
|
1627
1670
|
key.assetType = "models";
|
|
@@ -1634,13 +1677,19 @@ var init_Models = __esm({
|
|
|
1634
1677
|
return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
1635
1678
|
return AssetLoader.get(key, "model" /* MODEL */);
|
|
1636
1679
|
});
|
|
1637
|
-
}).then((
|
|
1638
|
-
if (
|
|
1639
|
-
|
|
1680
|
+
}).then((asset2) => {
|
|
1681
|
+
if (asset2) {
|
|
1682
|
+
asset2.key = key;
|
|
1640
1683
|
}
|
|
1641
|
-
return
|
|
1684
|
+
return asset2;
|
|
1642
1685
|
});
|
|
1643
1686
|
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
|
|
1689
|
+
* Item keys use GUI context, false conditions, and zero numeric properties.
|
|
1690
|
+
*
|
|
1691
|
+
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
1692
|
+
*/
|
|
1644
1693
|
static async getMerged(key) {
|
|
1645
1694
|
if (!key.assetType) {
|
|
1646
1695
|
key.assetType = "models";
|
|
@@ -1653,9 +1702,11 @@ var init_Models = __esm({
|
|
|
1653
1702
|
return _Models.loadAndMerge(key);
|
|
1654
1703
|
});
|
|
1655
1704
|
}
|
|
1705
|
+
/** Alias for {@link getMerged}. */
|
|
1656
1706
|
static async get(key) {
|
|
1657
1707
|
return this.getMerged(key);
|
|
1658
1708
|
}
|
|
1709
|
+
/** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1659
1710
|
static async clearCache() {
|
|
1660
1711
|
return this.PERSISTENT_CACHE.clear();
|
|
1661
1712
|
}
|
|
@@ -1678,6 +1729,7 @@ var init_BlockStates = __esm({
|
|
|
1678
1729
|
return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
|
|
1679
1730
|
}
|
|
1680
1731
|
// BlockState names are hardcoded
|
|
1732
|
+
/** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
|
|
1681
1733
|
static async getList() {
|
|
1682
1734
|
const key = new AssetKey(
|
|
1683
1735
|
DEFAULT_NAMESPACE,
|
|
@@ -1698,6 +1750,7 @@ var init_BlockStates = __esm({
|
|
|
1698
1750
|
return AssetLoader.get(key, "json" /* JSON */);
|
|
1699
1751
|
});
|
|
1700
1752
|
}
|
|
1753
|
+
/** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
|
|
1701
1754
|
static async getDefaultState(key) {
|
|
1702
1755
|
const defaultStates = await this.getDefaultStates();
|
|
1703
1756
|
if (!defaultStates) {
|
|
@@ -1705,6 +1758,7 @@ var init_BlockStates = __esm({
|
|
|
1705
1758
|
}
|
|
1706
1759
|
return defaultStates["minecraft:" + key.path];
|
|
1707
1760
|
}
|
|
1761
|
+
/** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
|
|
1708
1762
|
static async get(key) {
|
|
1709
1763
|
if (!key.assetType) {
|
|
1710
1764
|
key.assetType = "blockstates";
|
|
@@ -1717,11 +1771,11 @@ var init_BlockStates = __esm({
|
|
|
1717
1771
|
return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
1718
1772
|
return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
|
|
1719
1773
|
});
|
|
1720
|
-
}).then((
|
|
1721
|
-
if (
|
|
1722
|
-
|
|
1774
|
+
}).then((asset2) => {
|
|
1775
|
+
if (asset2) {
|
|
1776
|
+
asset2.key = key;
|
|
1723
1777
|
}
|
|
1724
|
-
return
|
|
1778
|
+
return asset2;
|
|
1725
1779
|
});
|
|
1726
1780
|
}
|
|
1727
1781
|
static getAll(keys) {
|
|
@@ -1731,6 +1785,7 @@ var init_BlockStates = __esm({
|
|
|
1731
1785
|
}
|
|
1732
1786
|
return Promise.all(promises);
|
|
1733
1787
|
}
|
|
1788
|
+
/** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1734
1789
|
static async clearCache() {
|
|
1735
1790
|
await this.PERSISTENT_CACHE.clear();
|
|
1736
1791
|
}
|
|
@@ -1756,9 +1811,11 @@ var init_Assets = __esm({
|
|
|
1756
1811
|
static parseAssetKey(assetType, str, origin) {
|
|
1757
1812
|
return AssetKey.parse(assetType, str, origin);
|
|
1758
1813
|
}
|
|
1814
|
+
/** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
|
|
1759
1815
|
static async getModel(key) {
|
|
1760
1816
|
return Models.getMerged(key);
|
|
1761
1817
|
}
|
|
1818
|
+
/** Loads a blockstate definition. See {@link BlockStates.get}. */
|
|
1762
1819
|
static async getBlockState(key) {
|
|
1763
1820
|
return BlockStates.get(key);
|
|
1764
1821
|
}
|
|
@@ -1805,6 +1862,10 @@ var BatchedExecutor;
|
|
|
1805
1862
|
var init_BatchedExecutor = __esm({
|
|
1806
1863
|
"src/util/BatchedExecutor.ts"() {
|
|
1807
1864
|
BatchedExecutor = class {
|
|
1865
|
+
/**
|
|
1866
|
+
* @param interval - Delay between queue runs, in milliseconds.
|
|
1867
|
+
* @param batch - Maximum tasks started per run and maximum tasks active at once.
|
|
1868
|
+
*/
|
|
1808
1869
|
constructor(interval = 1, batch = 30) {
|
|
1809
1870
|
if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
|
|
1810
1871
|
if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
|
|
@@ -1812,9 +1873,11 @@ var init_BatchedExecutor = __esm({
|
|
|
1812
1873
|
this.batch = batch;
|
|
1813
1874
|
this.queue = new JobQueue2(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
|
|
1814
1875
|
}
|
|
1876
|
+
/** Queues a task and resolves with its result, or rejects with its error. */
|
|
1815
1877
|
submit(task) {
|
|
1816
1878
|
return this.queue.add(() => task());
|
|
1817
1879
|
}
|
|
1880
|
+
/** Rejects queued and future tasks. Tasks already running are allowed to finish. */
|
|
1818
1881
|
stop() {
|
|
1819
1882
|
this.queue.end();
|
|
1820
1883
|
}
|
|
@@ -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 Vector33();
|
|
1867
1930
|
box.getSize(size);
|
|
1868
1931
|
let boxGeo = new BoxGeometry2(size.x, size.y, size.z, 1, 1, 1);
|
|
1869
1932
|
let wireGeo = new EdgesGeometry(boxGeo);
|
|
1870
|
-
let wireMat = new LineBasicMaterial({ color, linewidth: w });
|
|
1933
|
+
let wireMat = new LineBasicMaterial({ color: color2, linewidth: w });
|
|
1871
1934
|
let wireframe = new LineSegments(wireGeo, wireMat);
|
|
1872
1935
|
obj.add(wireframe);
|
|
1873
1936
|
let axes = new 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 BoxGeometry2(16, 16, 16, 1, 1, 1);
|
|
1878
1941
|
let wireGeo = new EdgesGeometry(boxGeo);
|
|
1879
|
-
let wireMat = new LineBasicMaterial({ color, linewidth: w });
|
|
1942
|
+
let wireMat = new LineBasicMaterial({ color: color2, linewidth: w });
|
|
1880
1943
|
let wireframe = new LineSegments(wireGeo, wireMat);
|
|
1881
1944
|
obj.add(wireframe);
|
|
1882
1945
|
let axes = new 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 EdgesGeometry(geo);
|
|
1887
|
-
let wireMat = new LineBasicMaterial({ color, linewidth: w });
|
|
1950
|
+
let wireMat = new LineBasicMaterial({ color: color2, linewidth: w });
|
|
1888
1951
|
let wireframe = new LineSegments(wireGeo, wireMat);
|
|
1889
1952
|
mesh.add(wireframe);
|
|
1890
1953
|
let axes = new AxesHelper(1);
|
|
@@ -1956,6 +2019,7 @@ var NBTHelper;
|
|
|
1956
2019
|
var init_NBTHelper = __esm({
|
|
1957
2020
|
"src/nbt/NBTHelper.ts"() {
|
|
1958
2021
|
NBTHelper = class {
|
|
2022
|
+
/** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
|
|
1959
2023
|
static async fromBuffer(data, format2) {
|
|
1960
2024
|
const buffer = Buffer3.from(data instanceof Uint8Array ? data : new Uint8Array(data));
|
|
1961
2025
|
const prismarineNbt = await import("prismarine-nbt");
|
|
@@ -2100,6 +2164,7 @@ var init_HostedAssetSource = __esm({
|
|
|
2100
2164
|
["json" /* JSON */, _HostedAssetSource.JSON]
|
|
2101
2165
|
]);
|
|
2102
2166
|
}
|
|
2167
|
+
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
2103
2168
|
async loadOrRetryWithDefaults(key, parser) {
|
|
2104
2169
|
const direct = await this.load(key, parser);
|
|
2105
2170
|
if (typeof direct !== "undefined") {
|
|
@@ -2157,6 +2222,10 @@ var init_HostedAssetSource = __esm({
|
|
|
2157
2222
|
assetBasePath(key) {
|
|
2158
2223
|
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 + "/" : ""}`;
|
|
2159
2224
|
}
|
|
2225
|
+
/**
|
|
2226
|
+
* Creates a hosted source for {@link AssetLoader.addSource}.
|
|
2227
|
+
* Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
|
|
2228
|
+
*/
|
|
2160
2229
|
constructor(root, options) {
|
|
2161
2230
|
super();
|
|
2162
2231
|
this._root = root;
|
|
@@ -2188,6 +2257,11 @@ var BrowserArchiveProxy;
|
|
|
2188
2257
|
var init_BrowserArchiveProxy = __esm({
|
|
2189
2258
|
"src/assets/source/archive/BrowserArchiveProxy.ts"() {
|
|
2190
2259
|
BrowserArchiveProxy = class {
|
|
2260
|
+
/**
|
|
2261
|
+
* Opens a ZIP for asset lookup.
|
|
2262
|
+
* @param id - Cache identity for this content. Change it when the pack changes.
|
|
2263
|
+
* A File supplies an identity from its name, size, and modification time when omitted.
|
|
2264
|
+
*/
|
|
2191
2265
|
constructor(blob, id) {
|
|
2192
2266
|
this._blob = blob;
|
|
2193
2267
|
this._reader = new ZipReader(new BlobReader(this._blob));
|
|
@@ -2320,27 +2394,27 @@ var init_PackFormats = __esm({
|
|
|
2320
2394
|
this.versions = /* @__PURE__ */ new Map();
|
|
2321
2395
|
}
|
|
2322
2396
|
/** Resolves pack formats from Mojang's client metadata hosted on assets.mcasset.cloud. */
|
|
2323
|
-
static async get(
|
|
2324
|
-
let pending = this.versions.get(
|
|
2397
|
+
static async get(version2, type) {
|
|
2398
|
+
let pending = this.versions.get(version2);
|
|
2325
2399
|
if (!pending || pending.expires <= Date.now()) {
|
|
2326
2400
|
pending = {
|
|
2327
|
-
formats: this.load(
|
|
2328
|
-
expires: ["latest", "release", "snapshot"].includes(
|
|
2401
|
+
formats: this.load(version2),
|
|
2402
|
+
expires: ["latest", "release", "snapshot"].includes(version2) ? Date.now() + 3e5 : Infinity
|
|
2329
2403
|
};
|
|
2330
|
-
this.versions.set(
|
|
2404
|
+
this.versions.set(version2, pending);
|
|
2331
2405
|
}
|
|
2332
2406
|
try {
|
|
2333
2407
|
return (await pending.formats)[type];
|
|
2334
2408
|
} catch (cause) {
|
|
2335
|
-
if (this.versions.get(
|
|
2409
|
+
if (this.versions.get(version2) === pending) this.versions.delete(version2);
|
|
2336
2410
|
const option = type === "assets" ? "resourcePackFormat" : "dataPackFormat";
|
|
2337
2411
|
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
2338
|
-
throw new Error(`Could not resolve the pack format for Minecraft ${
|
|
2412
|
+
throw new Error(`Could not resolve the pack format for Minecraft ${version2}. Set ArchiveAssetSource ${option} explicitly. ${reason}`);
|
|
2339
2413
|
}
|
|
2340
2414
|
}
|
|
2341
|
-
static async load(
|
|
2415
|
+
static async load(version2) {
|
|
2342
2416
|
const response = await Requests.genericRequest({
|
|
2343
|
-
url: `https://assets.mcasset.cloud/${encodeURIComponent(
|
|
2417
|
+
url: `https://assets.mcasset.cloud/${encodeURIComponent(version2)}/game-version.json`,
|
|
2344
2418
|
responseType: "json"
|
|
2345
2419
|
});
|
|
2346
2420
|
const data = response.data;
|
|
@@ -2387,6 +2461,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2387
2461
|
dataPackFormat: copyFormat(options.dataPackFormat)
|
|
2388
2462
|
};
|
|
2389
2463
|
}
|
|
2464
|
+
/** Creates a browser ZIP source from a Blob or File. */
|
|
2390
2465
|
static blob(blob, options) {
|
|
2391
2466
|
return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
|
|
2392
2467
|
}
|
|
@@ -2427,7 +2502,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2427
2502
|
}
|
|
2428
2503
|
async load(key, parser) {
|
|
2429
2504
|
const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
|
|
2430
|
-
const
|
|
2505
|
+
const version2 = AssetLoader.version;
|
|
2431
2506
|
let selectedPath = path;
|
|
2432
2507
|
let url;
|
|
2433
2508
|
try {
|
|
@@ -2435,7 +2510,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2435
2510
|
if (key.rootType === "assets" || key.rootType === "data") {
|
|
2436
2511
|
const metadata = await this.getMetadata(key);
|
|
2437
2512
|
if (metadata.hasOverlays) {
|
|
2438
|
-
const format2 = (key.rootType === "assets" ? this.options.resourcePackFormat : this.options.dataPackFormat) ?? await PackFormats.get(
|
|
2513
|
+
const format2 = (key.rootType === "assets" ? this.options.resourcePackFormat : this.options.dataPackFormat) ?? await PackFormats.get(version2, key.rootType);
|
|
2439
2514
|
directories = metadata.overlayDirectories(format2);
|
|
2440
2515
|
}
|
|
2441
2516
|
}
|
|
@@ -2519,6 +2594,7 @@ var init_AssetLoader = __esm({
|
|
|
2519
2594
|
FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
|
|
2520
2595
|
AssetLoader = class {
|
|
2521
2596
|
static {
|
|
2597
|
+
/** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
|
|
2522
2598
|
this.ROOT = DEFAULT_ROOT;
|
|
2523
2599
|
}
|
|
2524
2600
|
static {
|
|
@@ -2531,8 +2607,9 @@ var init_AssetLoader = __esm({
|
|
|
2531
2607
|
static get version() {
|
|
2532
2608
|
return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
|
|
2533
2609
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2610
|
+
/** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
|
|
2611
|
+
static setVersion(version2) {
|
|
2612
|
+
this.ROOT = `https://assets.mcasset.cloud/${version2}`;
|
|
2536
2613
|
const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
|
|
2537
2614
|
const index = this._SOURCES.findIndex((s) => s.key === "mcassets");
|
|
2538
2615
|
if (index !== -1) {
|
|
@@ -2564,6 +2641,13 @@ var init_AssetLoader = __esm({
|
|
|
2564
2641
|
return scope ? `${scope}
|
|
2565
2642
|
${key}` : key;
|
|
2566
2643
|
}
|
|
2644
|
+
/**
|
|
2645
|
+
* Registers a source at the highest priority.
|
|
2646
|
+
* Call {@link Caching.clear} after changing sources to discard previously loaded assets.
|
|
2647
|
+
*
|
|
2648
|
+
* @param key - Name used to replace or remove this source.
|
|
2649
|
+
* @param override - Removes the first source with this name before adding the new one.
|
|
2650
|
+
*/
|
|
2567
2651
|
static addSource(key, source, override = true) {
|
|
2568
2652
|
if (override) {
|
|
2569
2653
|
const existing = this.removeSource(key);
|
|
@@ -2574,6 +2658,7 @@ ${key}` : key;
|
|
|
2574
2658
|
this._SOURCES.unshift({ key, source });
|
|
2575
2659
|
console.log(p4, "Added AssetSource", key);
|
|
2576
2660
|
}
|
|
2661
|
+
/** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
|
|
2577
2662
|
static removeSource(key) {
|
|
2578
2663
|
const index = this._SOURCES.findIndex((s) => s.key === key);
|
|
2579
2664
|
if (index != -1) {
|
|
@@ -2588,12 +2673,13 @@ ${key}` : key;
|
|
|
2588
2673
|
this.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
|
|
2589
2674
|
this.addSource("mcassets", new HostedAssetSource(this.ROOT, { retryDefaults: false }));
|
|
2590
2675
|
}
|
|
2676
|
+
/** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
|
|
2591
2677
|
static async getAll(key, parser) {
|
|
2592
2678
|
const sources = [...this._SOURCES];
|
|
2593
2679
|
const results = [];
|
|
2594
2680
|
for (const { source } of sources) {
|
|
2595
|
-
const
|
|
2596
|
-
if (
|
|
2681
|
+
const asset2 = await source.get(key, parser);
|
|
2682
|
+
if (asset2 != void 0) results.push(asset2);
|
|
2597
2683
|
if (await source.blocks(key)) break;
|
|
2598
2684
|
}
|
|
2599
2685
|
return results;
|
|
@@ -2649,14 +2735,15 @@ var init_ModelTextures = __esm({
|
|
|
2649
2735
|
static get PERSISTENT_META_CACHE() {
|
|
2650
2736
|
return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
|
|
2651
2737
|
}
|
|
2738
|
+
/** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
|
|
2652
2739
|
static async get(key) {
|
|
2653
2740
|
const keyStr = key.serialize();
|
|
2654
2741
|
const pending = this.preload(key);
|
|
2655
2742
|
const cached2 = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
2656
2743
|
try {
|
|
2657
|
-
const
|
|
2658
|
-
if (
|
|
2659
|
-
return await ImageLoader.infoToCanvasData(
|
|
2744
|
+
const asset2 = await pending;
|
|
2745
|
+
if (asset2) {
|
|
2746
|
+
return await ImageLoader.infoToCanvasData(asset2);
|
|
2660
2747
|
}
|
|
2661
2748
|
return void 0;
|
|
2662
2749
|
} catch (err) {
|
|
@@ -2666,16 +2753,18 @@ var init_ModelTextures = __esm({
|
|
|
2666
2753
|
throw err;
|
|
2667
2754
|
}
|
|
2668
2755
|
}
|
|
2756
|
+
/** Fetches and caches encoded texture bytes without decoding the pixels. */
|
|
2669
2757
|
static async preload(key) {
|
|
2670
2758
|
const keyStr = key.serialize();
|
|
2671
2759
|
return Caching.textureAssetCache.get(keyStr, (k) => {
|
|
2672
|
-
return AssetLoader.get(key, "image" /* IMAGE */).then((
|
|
2673
|
-
if (
|
|
2674
|
-
|
|
2675
|
-
return
|
|
2760
|
+
return AssetLoader.get(key, "image" /* IMAGE */).then((asset2) => {
|
|
2761
|
+
if (asset2)
|
|
2762
|
+
asset2.key = key;
|
|
2763
|
+
return asset2;
|
|
2676
2764
|
});
|
|
2677
2765
|
});
|
|
2678
2766
|
}
|
|
2767
|
+
/** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
|
|
2679
2768
|
static async getMeta(key) {
|
|
2680
2769
|
if (!key.extension || !key.extension.endsWith(".mcmeta")) {
|
|
2681
2770
|
key = Object.assign(new AssetKey("", ""), key);
|
|
@@ -2684,14 +2773,15 @@ var init_ModelTextures = __esm({
|
|
|
2684
2773
|
const keyStr = key.serialize();
|
|
2685
2774
|
return Caching.textureMetaCache.get(keyStr, (k) => {
|
|
2686
2775
|
return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
2687
|
-
return AssetLoader.get(key, "meta" /* META */).then((
|
|
2688
|
-
if (
|
|
2689
|
-
|
|
2690
|
-
return
|
|
2776
|
+
return AssetLoader.get(key, "meta" /* META */).then((asset2) => {
|
|
2777
|
+
if (asset2)
|
|
2778
|
+
asset2.key = key;
|
|
2779
|
+
return asset2;
|
|
2691
2780
|
});
|
|
2692
2781
|
});
|
|
2693
2782
|
});
|
|
2694
2783
|
}
|
|
2784
|
+
/** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
|
|
2695
2785
|
static async clearCache() {
|
|
2696
2786
|
await this.PERSISTENT_META_CACHE.clear();
|
|
2697
2787
|
}
|
|
@@ -2779,6 +2869,7 @@ var init_Ticker = __esm({
|
|
|
2779
2869
|
}
|
|
2780
2870
|
return handle;
|
|
2781
2871
|
}
|
|
2872
|
+
/** Starts or resumes the shared tick loop. Repeated calls have no effect. */
|
|
2782
2873
|
static start() {
|
|
2783
2874
|
if (this.interval) return;
|
|
2784
2875
|
this.interval = this.schedule(() => {
|
|
@@ -2801,6 +2892,7 @@ var init_Ticker = __esm({
|
|
|
2801
2892
|
_Ticker.fiveSecondTicks = 0;
|
|
2802
2893
|
}, 1e3 * 5);
|
|
2803
2894
|
}
|
|
2895
|
+
/** Pauses the loop while retaining callbacks for a later {@link start}. */
|
|
2804
2896
|
static stop() {
|
|
2805
2897
|
if (this.interval) clearInterval(this.interval);
|
|
2806
2898
|
if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
|
|
@@ -2809,12 +2901,14 @@ var init_Ticker = __esm({
|
|
|
2809
2901
|
this.oneSecondTicksTracker = void 0;
|
|
2810
2902
|
this.fiveSecondTicksTracker = void 0;
|
|
2811
2903
|
}
|
|
2904
|
+
/** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
|
|
2812
2905
|
static add(tick) {
|
|
2813
2906
|
this.start();
|
|
2814
2907
|
const c = this.counter++;
|
|
2815
2908
|
this._tickers.set(c, tick);
|
|
2816
2909
|
return c;
|
|
2817
2910
|
}
|
|
2911
|
+
/** Removes a callback by ID and stops the timers when no callbacks remain. */
|
|
2818
2912
|
static remove(c) {
|
|
2819
2913
|
if (typeof c === "number") this._tickers.delete(c);
|
|
2820
2914
|
if (!this._tickers.size) this.stop();
|
|
@@ -2828,6 +2922,7 @@ var init_Ticker = __esm({
|
|
|
2828
2922
|
static get tpsFiveSeconds() {
|
|
2829
2923
|
return this.fiveSecondTps;
|
|
2830
2924
|
}
|
|
2925
|
+
/** Stops the loop and removes all registered callbacks. */
|
|
2831
2926
|
static dispose() {
|
|
2832
2927
|
this.stop();
|
|
2833
2928
|
this._tickers.clear();
|
|
@@ -2874,6 +2969,7 @@ var init_TextureAtlas = __esm({
|
|
|
2874
2969
|
}
|
|
2875
2970
|
};
|
|
2876
2971
|
}
|
|
2972
|
+
/** Copies pixels for a texture variable from its current atlas rectangle. */
|
|
2877
2973
|
getData(texture) {
|
|
2878
2974
|
const pos = this.positions[texture];
|
|
2879
2975
|
const size = this.sizes[texture];
|
|
@@ -3153,6 +3249,7 @@ var init_UVMapper = __esm({
|
|
|
3153
3249
|
}
|
|
3154
3250
|
uv.needsUpdate = true;
|
|
3155
3251
|
}
|
|
3252
|
+
/** Returns the shared atlas for a keyed, merged model, creating it on first use. */
|
|
3156
3253
|
static async getAtlas(model) {
|
|
3157
3254
|
const keyStr = model.key.serialize();
|
|
3158
3255
|
return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
|
|
@@ -3223,6 +3320,11 @@ var init_UVMapper = __esm({
|
|
|
3223
3320
|
}
|
|
3224
3321
|
return [tl, tr, bl, br];
|
|
3225
3322
|
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Combines model textures and animation metadata into an atlas.
|
|
3325
|
+
* Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
|
|
3326
|
+
* Returns `undefined` for models without a texture map.
|
|
3327
|
+
*/
|
|
3226
3328
|
static async createAtlas(originalModel) {
|
|
3227
3329
|
const textureMap = {};
|
|
3228
3330
|
const metaMap = {};
|
|
@@ -3243,12 +3345,12 @@ var init_UVMapper = __esm({
|
|
|
3243
3345
|
} else {
|
|
3244
3346
|
uniqueTextureNames.push(textureKey);
|
|
3245
3347
|
const assetKey = AssetKey.parse("textures", textureValue, model.key);
|
|
3246
|
-
promises.push(ModelTextures.get(assetKey).then((
|
|
3247
|
-
if (!
|
|
3348
|
+
promises.push(ModelTextures.get(assetKey).then((asset2) => {
|
|
3349
|
+
if (!asset2) {
|
|
3248
3350
|
console.warn(p5, "Missing texture", assetKey);
|
|
3249
3351
|
return;
|
|
3250
3352
|
}
|
|
3251
|
-
textureMap[textureKey] = new WrappedImage(
|
|
3353
|
+
textureMap[textureKey] = new WrappedImage(asset2);
|
|
3252
3354
|
}));
|
|
3253
3355
|
promises.push(ModelTextures.getMeta(assetKey).then((meta) => {
|
|
3254
3356
|
metaMap[textureKey] = meta;
|
|
@@ -3587,14 +3689,15 @@ var init_Entities = __esm({
|
|
|
3587
3689
|
init_MineRenderError();
|
|
3588
3690
|
init_ModelTextures();
|
|
3589
3691
|
Entities = class {
|
|
3692
|
+
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
3590
3693
|
static async getEntityList() {
|
|
3591
3694
|
const collect = async (path) => {
|
|
3592
3695
|
const prefix2 = path ? `${path}/` : "";
|
|
3593
3696
|
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
|
|
3594
|
-
const
|
|
3595
|
-
if (!
|
|
3596
|
-
const files =
|
|
3597
|
-
const children = await Promise.all(
|
|
3697
|
+
const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
|
|
3698
|
+
if (!list2) return [];
|
|
3699
|
+
const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
|
|
3700
|
+
const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
|
|
3598
3701
|
return [...files, ...children.flat()];
|
|
3599
3702
|
};
|
|
3600
3703
|
return collect("");
|
|
@@ -3604,6 +3707,7 @@ var init_Entities = __esm({
|
|
|
3604
3707
|
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
3605
3708
|
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3606
3709
|
}
|
|
3710
|
+
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
3607
3711
|
static async getLayerList(modelKey) {
|
|
3608
3712
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
3609
3713
|
}
|
|
@@ -3611,6 +3715,15 @@ var init_Entities = __esm({
|
|
|
3611
3715
|
static async getPassList(modelKey) {
|
|
3612
3716
|
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
3613
3717
|
}
|
|
3718
|
+
/**
|
|
3719
|
+
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
3720
|
+
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
3721
|
+
*
|
|
3722
|
+
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
3723
|
+
* @param textureKey - Texture override for the first selected layer.
|
|
3724
|
+
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
3725
|
+
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
3726
|
+
*/
|
|
3614
3727
|
static async getEntity(modelKey, textureKey, options) {
|
|
3615
3728
|
const model = await this.getModelFile(modelKey);
|
|
3616
3729
|
if (!model) return void 0;
|
|
@@ -3656,6 +3769,7 @@ var init_Entities = __esm({
|
|
|
3656
3769
|
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3657
3770
|
return file?.animations;
|
|
3658
3771
|
}
|
|
3772
|
+
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
3659
3773
|
static async resolveTexture(modelKey) {
|
|
3660
3774
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3661
3775
|
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
@@ -3667,8 +3781,8 @@ var init_Entities = __esm({
|
|
|
3667
3781
|
if (await ModelTextures.get(texture2)) return texture2;
|
|
3668
3782
|
}
|
|
3669
3783
|
const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
|
|
3670
|
-
const
|
|
3671
|
-
const files =
|
|
3784
|
+
const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
|
|
3785
|
+
const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
|
|
3672
3786
|
const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
|
|
3673
3787
|
if (!file) return void 0;
|
|
3674
3788
|
const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
|
|
@@ -3773,27 +3887,27 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3773
3887
|
for (const layer of layers) {
|
|
3774
3888
|
const objects = [];
|
|
3775
3889
|
if (poses) {
|
|
3776
|
-
layer.traverse((
|
|
3777
|
-
if (poses.has(
|
|
3890
|
+
layer.traverse((object3) => {
|
|
3891
|
+
if (poses.has(object3)) objects.push(object3);
|
|
3778
3892
|
});
|
|
3779
3893
|
} else {
|
|
3780
3894
|
for (const bone of Object.keys(animation.bones)) {
|
|
3781
|
-
const
|
|
3782
|
-
if (
|
|
3895
|
+
const object3 = layer.getObjectByName(`group:${bone}`);
|
|
3896
|
+
if (object3) objects.push(object3);
|
|
3783
3897
|
}
|
|
3784
3898
|
}
|
|
3785
|
-
for (const
|
|
3786
|
-
const bone =
|
|
3787
|
-
const pose = poses?.get(
|
|
3899
|
+
for (const object3 of objects) {
|
|
3900
|
+
const bone = object3.name.slice("group:".length);
|
|
3901
|
+
const pose = poses?.get(object3);
|
|
3788
3902
|
this.parts.push({
|
|
3789
3903
|
bone,
|
|
3790
|
-
object:
|
|
3791
|
-
position:
|
|
3792
|
-
rotation:
|
|
3793
|
-
scale:
|
|
3794
|
-
basePosition: pose ? new Vector35(...pose.offset) :
|
|
3795
|
-
baseRotation: pose ? new Euler3(...pose.rotation, "ZYX") :
|
|
3796
|
-
baseScale: pose ? new Vector35(...pose.scale ?? [1, 1, 1]) :
|
|
3904
|
+
object: object3,
|
|
3905
|
+
position: object3.position.clone(),
|
|
3906
|
+
rotation: object3.rotation.clone(),
|
|
3907
|
+
scale: object3.scale.clone(),
|
|
3908
|
+
basePosition: pose ? new Vector35(...pose.offset) : object3.position.clone(),
|
|
3909
|
+
baseRotation: pose ? new Euler3(...pose.rotation, "ZYX") : object3.rotation.clone(),
|
|
3910
|
+
baseScale: pose ? new Vector35(...pose.scale ?? [1, 1, 1]) : object3.scale.clone()
|
|
3797
3911
|
});
|
|
3798
3912
|
}
|
|
3799
3913
|
}
|
|
@@ -3816,12 +3930,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3816
3930
|
this._animation = void 0;
|
|
3817
3931
|
this._time = 0;
|
|
3818
3932
|
}
|
|
3933
|
+
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
3819
3934
|
setTime(seconds) {
|
|
3820
3935
|
if (!this._animation) return false;
|
|
3821
3936
|
this._time = seconds;
|
|
3822
3937
|
this.apply();
|
|
3823
3938
|
return true;
|
|
3824
3939
|
}
|
|
3940
|
+
/** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
|
|
3825
3941
|
advance(deltaSeconds) {
|
|
3826
3942
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
3827
3943
|
}
|
|
@@ -3859,6 +3975,7 @@ var init_InstanceReference = __esm({
|
|
|
3859
3975
|
if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
|
|
3860
3976
|
return this.instanceable;
|
|
3861
3977
|
}
|
|
3978
|
+
/** Releases this placement's slot for reuse. Repeated calls have no effect. */
|
|
3862
3979
|
removeFromScene() {
|
|
3863
3980
|
if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
|
|
3864
3981
|
}
|
|
@@ -3871,9 +3988,11 @@ var init_InstanceReference = __esm({
|
|
|
3871
3988
|
setMatrix(matrix) {
|
|
3872
3989
|
this.activeInstanceable.setMatrixAt(this.index, matrix);
|
|
3873
3990
|
}
|
|
3991
|
+
/** Hides or restores this placement while preserving its transform and allocated slot. */
|
|
3874
3992
|
setVisible(visible) {
|
|
3875
3993
|
this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
|
|
3876
3994
|
}
|
|
3995
|
+
/** Updates the supplied transform components. Positions use scene units and rotations use radians. */
|
|
3877
3996
|
setPositionRotationScale(position, rotation, scale) {
|
|
3878
3997
|
this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
|
|
3879
3998
|
}
|
|
@@ -3950,6 +4069,7 @@ var init_SceneObject = __esm({
|
|
|
3950
4069
|
}
|
|
3951
4070
|
async init() {
|
|
3952
4071
|
}
|
|
4072
|
+
/** Marks ancestor scenes for redraw and emits a `change` event. */
|
|
3953
4073
|
notifyDirty() {
|
|
3954
4074
|
this.traverseAncestors((parent) => {
|
|
3955
4075
|
const scene = parent;
|
|
@@ -3985,15 +4105,17 @@ var init_SceneObject = __esm({
|
|
|
3985
4105
|
return obj;
|
|
3986
4106
|
}
|
|
3987
4107
|
/**
|
|
3988
|
-
*
|
|
4108
|
+
* Finds a named part, such as `head`, without the internal `group:` prefix.
|
|
4109
|
+
* Returns `undefined` when the group does not exist.
|
|
3989
4110
|
*/
|
|
3990
4111
|
getGroupByName(name) {
|
|
3991
4112
|
return this.getObjectByName(`group:${name}`);
|
|
3992
4113
|
}
|
|
3993
4114
|
/**
|
|
3994
|
-
*
|
|
3995
|
-
* @param name name
|
|
3996
|
-
* @param visible
|
|
4115
|
+
* Changes a named group's visibility and requests a redraw.
|
|
4116
|
+
* @param name - Part name without the `group:` prefix.
|
|
4117
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4118
|
+
* @returns The resulting visibility, or `false` if the group does not exist.
|
|
3997
4119
|
*/
|
|
3998
4120
|
toggleGroupVisibility(name, visible) {
|
|
3999
4121
|
return this.toggleObjectVisibility(this.getGroupByName(name), visible);
|
|
@@ -4044,15 +4166,16 @@ var init_SceneObject = __esm({
|
|
|
4044
4166
|
return mesh;
|
|
4045
4167
|
}
|
|
4046
4168
|
/**
|
|
4047
|
-
*
|
|
4169
|
+
* Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
|
|
4048
4170
|
*/
|
|
4049
4171
|
getMeshByName(name) {
|
|
4050
4172
|
return this.getObjectByName(`mesh:${name}`);
|
|
4051
4173
|
}
|
|
4052
4174
|
/**
|
|
4053
|
-
*
|
|
4054
|
-
* @param name name
|
|
4055
|
-
* @param visible
|
|
4175
|
+
* Changes a named mesh's visibility and requests a redraw.
|
|
4176
|
+
* @param name - Mesh name without the `mesh:` prefix.
|
|
4177
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4178
|
+
* @returns The resulting visibility, or `false` if the mesh does not exist.
|
|
4056
4179
|
*/
|
|
4057
4180
|
toggleMeshVisibility(name, visible) {
|
|
4058
4181
|
return this.toggleObjectVisibility(this.getMeshByName(name), visible);
|
|
@@ -4098,12 +4221,14 @@ var init_SceneObject = __esm({
|
|
|
4098
4221
|
get isInstanced() {
|
|
4099
4222
|
return this._isInstanced;
|
|
4100
4223
|
}
|
|
4224
|
+
/** Number of live placements, excluding released instance slots. */
|
|
4101
4225
|
get instanceCounter() {
|
|
4102
4226
|
return this._instanceCounter;
|
|
4103
4227
|
}
|
|
4104
4228
|
constructInstanceReference(i) {
|
|
4105
4229
|
return new InstanceReference(this, i);
|
|
4106
4230
|
}
|
|
4231
|
+
/** Allocates a placement of this instanced object, reusing a released slot when available. */
|
|
4107
4232
|
nextInstance() {
|
|
4108
4233
|
const mesh = this.instanceMesh;
|
|
4109
4234
|
if (!mesh) throw new MineRenderError("Object is not instanced");
|
|
@@ -4148,10 +4273,10 @@ var init_SceneObject = __esm({
|
|
|
4148
4273
|
return new InstancedBufferAttribute(array, attribute.itemSize, attribute.normalized, attribute.meshPerAttribute).setUsage(attribute.usage);
|
|
4149
4274
|
};
|
|
4150
4275
|
const matrix = grow(mesh.instanceMatrix, 0);
|
|
4151
|
-
const
|
|
4276
|
+
const color2 = mesh.instanceColor ? grow(mesh.instanceColor, 1) : null;
|
|
4152
4277
|
mesh.dispose();
|
|
4153
4278
|
mesh.instanceMatrix = matrix;
|
|
4154
|
-
mesh.instanceColor =
|
|
4279
|
+
mesh.instanceColor = color2;
|
|
4155
4280
|
}
|
|
4156
4281
|
*activeInstanceIndices() {
|
|
4157
4282
|
if (this.instanceMesh) {
|
|
@@ -4250,6 +4375,7 @@ var init_SceneObject = __esm({
|
|
|
4250
4375
|
vector.setFromMatrixScale(matrix);
|
|
4251
4376
|
return vector;
|
|
4252
4377
|
}
|
|
4378
|
+
/** Updates supplied transform components. For a shared model, affects every live instance. */
|
|
4253
4379
|
setPositionRotationScale(position, rotation, scale) {
|
|
4254
4380
|
if (this.isInstanced) {
|
|
4255
4381
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4268,6 +4394,7 @@ var init_SceneObject = __esm({
|
|
|
4268
4394
|
}
|
|
4269
4395
|
this.notifyDirty();
|
|
4270
4396
|
}
|
|
4397
|
+
/** Sets position in scene units. For a shared model, updates every live instance. */
|
|
4271
4398
|
setPosition(position) {
|
|
4272
4399
|
if (this.isInstanced) {
|
|
4273
4400
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4285,6 +4412,7 @@ var init_SceneObject = __esm({
|
|
|
4285
4412
|
return this.position;
|
|
4286
4413
|
}
|
|
4287
4414
|
}
|
|
4415
|
+
/** Sets rotation in radians. For a shared model, updates every live instance. */
|
|
4288
4416
|
setRotation(rotation) {
|
|
4289
4417
|
if (this.isInstanced) {
|
|
4290
4418
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4302,6 +4430,7 @@ var init_SceneObject = __esm({
|
|
|
4302
4430
|
return this.rotation;
|
|
4303
4431
|
}
|
|
4304
4432
|
}
|
|
4433
|
+
/** Sets scale factors. For a shared model, updates every live instance. */
|
|
4305
4434
|
setScale(scale) {
|
|
4306
4435
|
if (this.isInstanced) {
|
|
4307
4436
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4320,15 +4449,15 @@ var init_SceneObject = __esm({
|
|
|
4320
4449
|
}
|
|
4321
4450
|
}
|
|
4322
4451
|
//</editor-fold>
|
|
4323
|
-
toggleObjectVisibility(
|
|
4324
|
-
if (
|
|
4452
|
+
toggleObjectVisibility(object3, visible) {
|
|
4453
|
+
if (object3) {
|
|
4325
4454
|
if (typeof visible !== "undefined") {
|
|
4326
|
-
|
|
4455
|
+
object3.visible = visible;
|
|
4327
4456
|
} else {
|
|
4328
|
-
|
|
4457
|
+
object3.visible = !object3.visible;
|
|
4329
4458
|
}
|
|
4330
4459
|
this.notifyDirty();
|
|
4331
|
-
return
|
|
4460
|
+
return object3.visible;
|
|
4332
4461
|
}
|
|
4333
4462
|
this.notifyDirty();
|
|
4334
4463
|
return false;
|
|
@@ -4339,6 +4468,7 @@ var init_SceneObject = __esm({
|
|
|
4339
4468
|
this.notifyDirty();
|
|
4340
4469
|
super.dispose();
|
|
4341
4470
|
}
|
|
4471
|
+
/** Releases instance slots and removes children, disposing children that implement Disposable. */
|
|
4342
4472
|
disposeAndRemoveAllChildren() {
|
|
4343
4473
|
if (this.instanceMesh) {
|
|
4344
4474
|
if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
|
|
@@ -4361,6 +4491,7 @@ var init_SceneObject = __esm({
|
|
|
4361
4491
|
}
|
|
4362
4492
|
this.notifyDirty();
|
|
4363
4493
|
}
|
|
4494
|
+
/** Detaches the object from its parent and requests a redraw. */
|
|
4364
4495
|
removeFromScene() {
|
|
4365
4496
|
this.notifyDirty();
|
|
4366
4497
|
this.removeFromParent();
|
|
@@ -4512,12 +4643,15 @@ var init_EntityObject = __esm({
|
|
|
4512
4643
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
4513
4644
|
}
|
|
4514
4645
|
//</editor-fold>
|
|
4646
|
+
/** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
|
|
4515
4647
|
getLayerGroup(name) {
|
|
4516
4648
|
return super.getGroupByName(`layer:${name}`);
|
|
4517
4649
|
}
|
|
4650
|
+
/** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
|
|
4518
4651
|
getGroupByName(name, layerName) {
|
|
4519
4652
|
return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
|
|
4520
4653
|
}
|
|
4654
|
+
/** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
|
|
4521
4655
|
getMeshByName(name, layerName) {
|
|
4522
4656
|
return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
|
|
4523
4657
|
}
|
|
@@ -4619,8 +4753,8 @@ var init_EntityObject = __esm({
|
|
|
4619
4753
|
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
4620
4754
|
}
|
|
4621
4755
|
}
|
|
4622
|
-
this.getLayerGroup(name)?.traverse((
|
|
4623
|
-
if (isMesh(
|
|
4756
|
+
this.getLayerGroup(name)?.traverse((object3) => {
|
|
4757
|
+
if (isMesh(object3)) object3.material = mat;
|
|
4624
4758
|
});
|
|
4625
4759
|
}));
|
|
4626
4760
|
if (!this.children.length) {
|
|
@@ -4959,8 +5093,8 @@ function toTrianglesDrawMode(geometry, drawMode) {
|
|
|
4959
5093
|
return geometry;
|
|
4960
5094
|
}
|
|
4961
5095
|
}
|
|
4962
|
-
function computeMorphedAttributes(
|
|
4963
|
-
if (
|
|
5096
|
+
function computeMorphedAttributes(object3) {
|
|
5097
|
+
if (object3.geometry.isBufferGeometry !== true) {
|
|
4964
5098
|
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
|
|
4965
5099
|
return null;
|
|
4966
5100
|
}
|
|
@@ -4973,11 +5107,11 @@ function computeMorphedAttributes(object2) {
|
|
|
4973
5107
|
const _morphA = new Vector310();
|
|
4974
5108
|
const _morphB = new Vector310();
|
|
4975
5109
|
const _morphC = new Vector310();
|
|
4976
|
-
function _calculateMorphedAttributeData(
|
|
5110
|
+
function _calculateMorphedAttributeData(object4, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
|
|
4977
5111
|
_vA.fromBufferAttribute(attribute, a2);
|
|
4978
5112
|
_vB.fromBufferAttribute(attribute, b2);
|
|
4979
5113
|
_vC.fromBufferAttribute(attribute, c2);
|
|
4980
|
-
const morphInfluences =
|
|
5114
|
+
const morphInfluences = object4.morphTargetInfluences;
|
|
4981
5115
|
if (material2.morphTargets && morphAttribute && morphInfluences) {
|
|
4982
5116
|
_morphA.set(0, 0, 0);
|
|
4983
5117
|
_morphB.set(0, 0, 0);
|
|
@@ -5003,10 +5137,10 @@ function computeMorphedAttributes(object2) {
|
|
|
5003
5137
|
_vB.add(_morphB);
|
|
5004
5138
|
_vC.add(_morphC);
|
|
5005
5139
|
}
|
|
5006
|
-
if (
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5140
|
+
if (object4.isSkinnedMesh) {
|
|
5141
|
+
object4.boneTransform(a2, _vA);
|
|
5142
|
+
object4.boneTransform(b2, _vB);
|
|
5143
|
+
object4.boneTransform(c2, _vC);
|
|
5010
5144
|
}
|
|
5011
5145
|
modifiedAttributeArray[a2 * 3 + 0] = _vA.x;
|
|
5012
5146
|
modifiedAttributeArray[a2 * 3 + 1] = _vA.y;
|
|
@@ -5018,8 +5152,8 @@ function computeMorphedAttributes(object2) {
|
|
|
5018
5152
|
modifiedAttributeArray[c2 * 3 + 1] = _vC.y;
|
|
5019
5153
|
modifiedAttributeArray[c2 * 3 + 2] = _vC.z;
|
|
5020
5154
|
}
|
|
5021
|
-
const geometry =
|
|
5022
|
-
const material =
|
|
5155
|
+
const geometry = object3.geometry;
|
|
5156
|
+
const material = object3.material;
|
|
5023
5157
|
let a, b, c;
|
|
5024
5158
|
const index = geometry.index;
|
|
5025
5159
|
const positionAttribute = geometry.attributes.position;
|
|
@@ -5046,7 +5180,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5046
5180
|
b = index.getX(j + 1);
|
|
5047
5181
|
c = index.getX(j + 2);
|
|
5048
5182
|
_calculateMorphedAttributeData(
|
|
5049
|
-
|
|
5183
|
+
object3,
|
|
5050
5184
|
groupMaterial,
|
|
5051
5185
|
positionAttribute,
|
|
5052
5186
|
morphPosition,
|
|
@@ -5057,7 +5191,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5057
5191
|
modifiedPosition
|
|
5058
5192
|
);
|
|
5059
5193
|
_calculateMorphedAttributeData(
|
|
5060
|
-
|
|
5194
|
+
object3,
|
|
5061
5195
|
groupMaterial,
|
|
5062
5196
|
normalAttribute,
|
|
5063
5197
|
morphNormal,
|
|
@@ -5077,7 +5211,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5077
5211
|
b = index.getX(i + 1);
|
|
5078
5212
|
c = index.getX(i + 2);
|
|
5079
5213
|
_calculateMorphedAttributeData(
|
|
5080
|
-
|
|
5214
|
+
object3,
|
|
5081
5215
|
material,
|
|
5082
5216
|
positionAttribute,
|
|
5083
5217
|
morphPosition,
|
|
@@ -5088,7 +5222,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5088
5222
|
modifiedPosition
|
|
5089
5223
|
);
|
|
5090
5224
|
_calculateMorphedAttributeData(
|
|
5091
|
-
|
|
5225
|
+
object3,
|
|
5092
5226
|
material,
|
|
5093
5227
|
normalAttribute,
|
|
5094
5228
|
morphNormal,
|
|
@@ -5112,7 +5246,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5112
5246
|
b = j + 1;
|
|
5113
5247
|
c = j + 2;
|
|
5114
5248
|
_calculateMorphedAttributeData(
|
|
5115
|
-
|
|
5249
|
+
object3,
|
|
5116
5250
|
groupMaterial,
|
|
5117
5251
|
positionAttribute,
|
|
5118
5252
|
morphPosition,
|
|
@@ -5123,7 +5257,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5123
5257
|
modifiedPosition
|
|
5124
5258
|
);
|
|
5125
5259
|
_calculateMorphedAttributeData(
|
|
5126
|
-
|
|
5260
|
+
object3,
|
|
5127
5261
|
groupMaterial,
|
|
5128
5262
|
normalAttribute,
|
|
5129
5263
|
morphNormal,
|
|
@@ -5143,7 +5277,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5143
5277
|
b = i + 1;
|
|
5144
5278
|
c = i + 2;
|
|
5145
5279
|
_calculateMorphedAttributeData(
|
|
5146
|
-
|
|
5280
|
+
object3,
|
|
5147
5281
|
material,
|
|
5148
5282
|
positionAttribute,
|
|
5149
5283
|
morphPosition,
|
|
@@ -5154,7 +5288,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5154
5288
|
modifiedPosition
|
|
5155
5289
|
);
|
|
5156
5290
|
_calculateMorphedAttributeData(
|
|
5157
|
-
|
|
5291
|
+
object3,
|
|
5158
5292
|
material,
|
|
5159
5293
|
normalAttribute,
|
|
5160
5294
|
morphNormal,
|
|
@@ -5188,6 +5322,7 @@ var init_ModelCulling = __esm({
|
|
|
5188
5322
|
"src/model/ModelCulling.ts"() {
|
|
5189
5323
|
init_CubeFace();
|
|
5190
5324
|
ModelCulling = class {
|
|
5325
|
+
/** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
|
|
5191
5326
|
static toLocalMask(worldMask, rotation) {
|
|
5192
5327
|
let localMask = 0;
|
|
5193
5328
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
@@ -5198,6 +5333,7 @@ var init_ModelCulling = __esm({
|
|
|
5198
5333
|
}
|
|
5199
5334
|
return localMask;
|
|
5200
5335
|
}
|
|
5336
|
+
/** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
|
|
5201
5337
|
static isOpaqueFullCube(atlas) {
|
|
5202
5338
|
if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
|
|
5203
5339
|
const element = atlas.model.elements[0];
|
|
@@ -5408,9 +5544,9 @@ var init_ItemTints = __esm({
|
|
|
5408
5544
|
}));
|
|
5409
5545
|
return colors;
|
|
5410
5546
|
}
|
|
5411
|
-
static rgb(
|
|
5412
|
-
if (!Array.isArray(
|
|
5413
|
-
const [red, green, blue] =
|
|
5547
|
+
static rgb(color2) {
|
|
5548
|
+
if (!Array.isArray(color2)) return color2 & 16777215;
|
|
5549
|
+
const [red, green, blue] = color2.map((channel) => Math.floor(Math.fround(Math.fround(channel) * 255)));
|
|
5414
5550
|
return red << 16 | green << 8 | blue;
|
|
5415
5551
|
}
|
|
5416
5552
|
};
|
|
@@ -5466,13 +5602,13 @@ var init_ModelObject = __esm({
|
|
|
5466
5602
|
transform.multiply(new Matrix49().makeTranslation(-8, -8, -8));
|
|
5467
5603
|
try {
|
|
5468
5604
|
for (const part of parts) {
|
|
5469
|
-
const
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
this.add(
|
|
5474
|
-
await
|
|
5475
|
-
|
|
5605
|
+
const object3 = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
|
|
5606
|
+
object3.matrix.copy(transform).multiply(part.transform);
|
|
5607
|
+
object3.matrixWorldNeedsUpdate = true;
|
|
5608
|
+
object3.matrixAutoUpdate = false;
|
|
5609
|
+
this.add(object3);
|
|
5610
|
+
await object3.init();
|
|
5611
|
+
object3.iterateAllMeshes((mesh) => {
|
|
5476
5612
|
const source = mesh.material;
|
|
5477
5613
|
let material = this.specialMaterials.get(source);
|
|
5478
5614
|
if (!material) {
|
|
@@ -5483,7 +5619,7 @@ var init_ModelObject = __esm({
|
|
|
5483
5619
|
mesh.material = material;
|
|
5484
5620
|
});
|
|
5485
5621
|
for (const [name, rotation] of Object.entries(part.rotations)) {
|
|
5486
|
-
|
|
5622
|
+
object3.getGroupByName(name)?.rotation.set(...rotation, "ZYX");
|
|
5487
5623
|
}
|
|
5488
5624
|
}
|
|
5489
5625
|
} catch (error) {
|
|
@@ -5536,9 +5672,9 @@ var init_ModelObject = __esm({
|
|
|
5536
5672
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
5537
5673
|
const tint = this.options.tints[tintIndex];
|
|
5538
5674
|
if (tint === void 0) continue;
|
|
5539
|
-
const
|
|
5675
|
+
const color2 = new Color9(tint);
|
|
5540
5676
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
5541
|
-
|
|
5677
|
+
color2.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
5542
5678
|
}
|
|
5543
5679
|
}
|
|
5544
5680
|
elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
|
|
@@ -5853,9 +5989,9 @@ var init_FluidModelObject = __esm({
|
|
|
5853
5989
|
}
|
|
5854
5990
|
}
|
|
5855
5991
|
geometry.clearGroups();
|
|
5856
|
-
const
|
|
5992
|
+
const color2 = new Color10(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
5857
5993
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
5858
|
-
for (let i = 0; i < colors.length; i += 3)
|
|
5994
|
+
for (let i = 0; i < colors.length; i += 3) color2.toArray(colors, i);
|
|
5859
5995
|
geometry.setAttribute("color", new BufferAttribute6(colors, 3));
|
|
5860
5996
|
geometry.computeBoundingBox();
|
|
5861
5997
|
geometry.computeBoundingSphere();
|
|
@@ -5948,9 +6084,9 @@ var NodeEnv = class {
|
|
|
5948
6084
|
imageSize(data) {
|
|
5949
6085
|
return imageSize(Buffer.isBuffer(data) ? data : Buffer.from(data));
|
|
5950
6086
|
}
|
|
5951
|
-
openCache(name,
|
|
6087
|
+
openCache(name, version2) {
|
|
5952
6088
|
return new NodeCache(NodePersist.create({
|
|
5953
|
-
dir: name +
|
|
6089
|
+
dir: name + version2,
|
|
5954
6090
|
encoding: "utf8"
|
|
5955
6091
|
}));
|
|
5956
6092
|
}
|
|
@@ -5982,6 +6118,7 @@ var Meshes = class _Meshes {
|
|
|
5982
6118
|
static createBox(key) {
|
|
5983
6119
|
return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
|
|
5984
6120
|
}
|
|
6121
|
+
/** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
|
|
5985
6122
|
static getBox(key) {
|
|
5986
6123
|
const keyStr = serializeMeshKey(key);
|
|
5987
6124
|
return Caching.boxMeshCache.get(keyStr, (k) => {
|
|
@@ -6094,6 +6231,7 @@ init_AssetParsers();
|
|
|
6094
6231
|
init_ModelTextures();
|
|
6095
6232
|
init_Caching();
|
|
6096
6233
|
var Fonts = class {
|
|
6234
|
+
/** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
|
|
6097
6235
|
static async get(key = "minecraft:default") {
|
|
6098
6236
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
6099
6237
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -6109,8 +6247,8 @@ var Fonts = class {
|
|
|
6109
6247
|
const stack = await AssetLoader.getAll(key, "json" /* JSON */);
|
|
6110
6248
|
if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
|
|
6111
6249
|
const glyphs = /* @__PURE__ */ new Map();
|
|
6112
|
-
for (const
|
|
6113
|
-
for (const provider of
|
|
6250
|
+
for (const asset2 of stack) {
|
|
6251
|
+
for (const provider of asset2.providers) {
|
|
6114
6252
|
if (provider.filter?.uniform || provider.filter?.jp) continue;
|
|
6115
6253
|
let provided;
|
|
6116
6254
|
switch (provider.type) {
|
|
@@ -6256,13 +6394,13 @@ var OBJExporter = class {
|
|
|
6256
6394
|
* @param {Object3D} object - The 3D object to export.
|
|
6257
6395
|
* @return {string} The exported OBJ.
|
|
6258
6396
|
*/
|
|
6259
|
-
parse(
|
|
6397
|
+
parse(object3) {
|
|
6260
6398
|
let output = "";
|
|
6261
6399
|
let indexVertex = 0;
|
|
6262
6400
|
let indexVertexUvs = 0;
|
|
6263
6401
|
let indexNormals = 0;
|
|
6264
6402
|
const vertex = new Vector37();
|
|
6265
|
-
const
|
|
6403
|
+
const color2 = new Color4();
|
|
6266
6404
|
const normal = new Vector37();
|
|
6267
6405
|
const uv = new Vector22();
|
|
6268
6406
|
const face = [];
|
|
@@ -6361,9 +6499,9 @@ var OBJExporter = class {
|
|
|
6361
6499
|
vertex.applyMatrix4(points.matrixWorld);
|
|
6362
6500
|
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
6363
6501
|
if (colors !== void 0) {
|
|
6364
|
-
|
|
6365
|
-
ColorManagement.workingToColorSpace(
|
|
6366
|
-
output += " " +
|
|
6502
|
+
color2.fromBufferAttribute(colors, i);
|
|
6503
|
+
ColorManagement.workingToColorSpace(color2, SRGBColorSpace3);
|
|
6504
|
+
output += " " + color2.r + " " + color2.g + " " + color2.b;
|
|
6367
6505
|
}
|
|
6368
6506
|
output += "\n";
|
|
6369
6507
|
}
|
|
@@ -6375,7 +6513,7 @@ var OBJExporter = class {
|
|
|
6375
6513
|
}
|
|
6376
6514
|
indexVertex += nbVertex;
|
|
6377
6515
|
}
|
|
6378
|
-
|
|
6516
|
+
object3.traverse(function(child) {
|
|
6379
6517
|
if (child.isMesh === true) {
|
|
6380
6518
|
parseMesh(child);
|
|
6381
6519
|
}
|
|
@@ -6409,9 +6547,9 @@ var PLYExporter = class {
|
|
|
6409
6547
|
* @param {PLYExporter~Options} options - The export options.
|
|
6410
6548
|
* @return {?(string|ArrayBuffer)} The exported PLY.
|
|
6411
6549
|
*/
|
|
6412
|
-
parse(
|
|
6550
|
+
parse(object3, onDone, options = {}) {
|
|
6413
6551
|
function traverseMeshes(cb) {
|
|
6414
|
-
|
|
6552
|
+
object3.traverse(function(child) {
|
|
6415
6553
|
if (child.isMesh === true || child.isPoints) {
|
|
6416
6554
|
const mesh = child;
|
|
6417
6555
|
const geometry = mesh.geometry;
|
|
@@ -6444,7 +6582,7 @@ var PLYExporter = class {
|
|
|
6444
6582
|
for (const name of customAttributeNames) customTypes[name] = "float";
|
|
6445
6583
|
let vertexCount = 0;
|
|
6446
6584
|
let faceCount = 0;
|
|
6447
|
-
|
|
6585
|
+
object3.traverse(function(child) {
|
|
6448
6586
|
if (child.isMesh === true) {
|
|
6449
6587
|
const mesh = child;
|
|
6450
6588
|
const geometry = mesh.geometry;
|
|
@@ -7066,8 +7204,8 @@ function equalArray(array1, array2) {
|
|
|
7066
7204
|
return element === array2[index];
|
|
7067
7205
|
});
|
|
7068
7206
|
}
|
|
7069
|
-
function stringToArrayBuffer(
|
|
7070
|
-
return new TextEncoder().encode(
|
|
7207
|
+
function stringToArrayBuffer(text2) {
|
|
7208
|
+
return new TextEncoder().encode(text2).buffer;
|
|
7071
7209
|
}
|
|
7072
7210
|
function isIdentityMatrix(matrix) {
|
|
7073
7211
|
return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
@@ -7260,12 +7398,12 @@ var GLTFWriter = class {
|
|
|
7260
7398
|
* @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry|THREE.AnimationClip} object
|
|
7261
7399
|
* @param {Object} objectDef
|
|
7262
7400
|
*/
|
|
7263
|
-
serializeUserData(
|
|
7264
|
-
if (Object.keys(
|
|
7401
|
+
serializeUserData(object3, objectDef) {
|
|
7402
|
+
if (Object.keys(object3.userData).length === 0) return;
|
|
7265
7403
|
const options = this.options;
|
|
7266
7404
|
const extensionsUsed = this.extensionsUsed;
|
|
7267
7405
|
try {
|
|
7268
|
-
const json = JSON.parse(JSON.stringify(
|
|
7406
|
+
const json = JSON.parse(JSON.stringify(object3.userData));
|
|
7269
7407
|
if (options.includeCustomExtensions && json.gltfExtensions) {
|
|
7270
7408
|
if (objectDef.extensions === void 0) objectDef.extensions = {};
|
|
7271
7409
|
for (const extensionName in json.gltfExtensions) {
|
|
@@ -7276,7 +7414,7 @@ var GLTFWriter = class {
|
|
|
7276
7414
|
}
|
|
7277
7415
|
if (Object.keys(json).length > 0) objectDef.extras = json;
|
|
7278
7416
|
} catch (error) {
|
|
7279
|
-
console.warn("THREE.GLTFExporter: userData of '" +
|
|
7417
|
+
console.warn("THREE.GLTFExporter: userData of '" + object3.name + "' won't be serialized because of JSON.stringify error - " + error.message);
|
|
7280
7418
|
}
|
|
7281
7419
|
}
|
|
7282
7420
|
/**
|
|
@@ -7785,9 +7923,9 @@ var GLTFWriter = class {
|
|
|
7785
7923
|
if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
|
|
7786
7924
|
console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
|
|
7787
7925
|
}
|
|
7788
|
-
const
|
|
7789
|
-
if (!equalArray(
|
|
7790
|
-
materialDef.pbrMetallicRoughness.baseColorFactor =
|
|
7926
|
+
const color2 = material.color.toArray().concat([material.opacity]);
|
|
7927
|
+
if (!equalArray(color2, [1, 1, 1, 1])) {
|
|
7928
|
+
materialDef.pbrMetallicRoughness.baseColorFactor = color2;
|
|
7791
7929
|
}
|
|
7792
7930
|
if (material.isMeshStandardMaterial) {
|
|
7793
7931
|
materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
|
|
@@ -8202,13 +8340,13 @@ var GLTFWriter = class {
|
|
|
8202
8340
|
* @param {THREE.Object3D} object
|
|
8203
8341
|
* @return {?number}
|
|
8204
8342
|
*/
|
|
8205
|
-
processSkin(
|
|
8343
|
+
processSkin(object3) {
|
|
8206
8344
|
const json = this.json;
|
|
8207
8345
|
const nodeMap = this.nodeMap;
|
|
8208
|
-
const node = json.nodes[nodeMap.get(
|
|
8209
|
-
const skeleton =
|
|
8346
|
+
const node = json.nodes[nodeMap.get(object3)];
|
|
8347
|
+
const skeleton = object3.skeleton;
|
|
8210
8348
|
if (skeleton === void 0) return null;
|
|
8211
|
-
const rootJoint =
|
|
8349
|
+
const rootJoint = object3.skeleton.bones[0];
|
|
8212
8350
|
if (rootJoint === void 0) return null;
|
|
8213
8351
|
const joints = [];
|
|
8214
8352
|
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
@@ -8216,7 +8354,7 @@ var GLTFWriter = class {
|
|
|
8216
8354
|
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
8217
8355
|
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
8218
8356
|
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
8219
|
-
temporaryBoneInverse.multiply(
|
|
8357
|
+
temporaryBoneInverse.multiply(object3.bindMatrix).toArray(inverseBindMatrices, i * 16);
|
|
8220
8358
|
}
|
|
8221
8359
|
if (json.skins === void 0) json.skins = [];
|
|
8222
8360
|
json.skins.push({
|
|
@@ -8232,19 +8370,19 @@ var GLTFWriter = class {
|
|
|
8232
8370
|
* @param {THREE.Object3D} object Object3D to processNodeAsync
|
|
8233
8371
|
* @return {Promise<number>} Index of the node in the nodes list
|
|
8234
8372
|
*/
|
|
8235
|
-
async processNodeAsync(
|
|
8373
|
+
async processNodeAsync(object3) {
|
|
8236
8374
|
const json = this.json;
|
|
8237
8375
|
const options = this.options;
|
|
8238
8376
|
const nodeMap = this.nodeMap;
|
|
8239
8377
|
if (!json.nodes) json.nodes = [];
|
|
8240
|
-
if (
|
|
8241
|
-
return await this._processNodeWithPivotAsync(
|
|
8378
|
+
if (object3.pivot !== null) {
|
|
8379
|
+
return await this._processNodeWithPivotAsync(object3);
|
|
8242
8380
|
}
|
|
8243
8381
|
const nodeDef = {};
|
|
8244
8382
|
if (options.trs) {
|
|
8245
|
-
const rotation =
|
|
8246
|
-
const position =
|
|
8247
|
-
const scale =
|
|
8383
|
+
const rotation = object3.quaternion.toArray();
|
|
8384
|
+
const position = object3.position.toArray();
|
|
8385
|
+
const scale = object3.scale.toArray();
|
|
8248
8386
|
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
8249
8387
|
nodeDef.rotation = rotation;
|
|
8250
8388
|
}
|
|
@@ -8255,28 +8393,28 @@ var GLTFWriter = class {
|
|
|
8255
8393
|
nodeDef.scale = scale;
|
|
8256
8394
|
}
|
|
8257
8395
|
} else {
|
|
8258
|
-
if (
|
|
8259
|
-
|
|
8396
|
+
if (object3.matrixAutoUpdate) {
|
|
8397
|
+
object3.updateMatrix();
|
|
8260
8398
|
}
|
|
8261
|
-
if (isIdentityMatrix(
|
|
8262
|
-
nodeDef.matrix =
|
|
8399
|
+
if (isIdentityMatrix(object3.matrix) === false) {
|
|
8400
|
+
nodeDef.matrix = object3.matrix.elements;
|
|
8263
8401
|
}
|
|
8264
8402
|
}
|
|
8265
|
-
if (
|
|
8266
|
-
this.serializeUserData(
|
|
8267
|
-
if (
|
|
8268
|
-
const meshIndex = await this.processMeshAsync(
|
|
8403
|
+
if (object3.name !== "") nodeDef.name = String(object3.name);
|
|
8404
|
+
this.serializeUserData(object3, nodeDef);
|
|
8405
|
+
if (object3.isMesh || object3.isLine || object3.isPoints) {
|
|
8406
|
+
const meshIndex = await this.processMeshAsync(object3);
|
|
8269
8407
|
if (meshIndex !== null) nodeDef.mesh = meshIndex;
|
|
8270
|
-
} else if (
|
|
8271
|
-
nodeDef.camera = this.processCamera(
|
|
8408
|
+
} else if (object3.isCamera) {
|
|
8409
|
+
nodeDef.camera = this.processCamera(object3);
|
|
8272
8410
|
}
|
|
8273
|
-
if (
|
|
8411
|
+
if (object3.isSkinnedMesh) this.skins.push(object3);
|
|
8274
8412
|
const nodeIndex = json.nodes.push(nodeDef) - 1;
|
|
8275
|
-
nodeMap.set(
|
|
8276
|
-
if (
|
|
8413
|
+
nodeMap.set(object3, nodeIndex);
|
|
8414
|
+
if (object3.children.length > 0) {
|
|
8277
8415
|
const children = [];
|
|
8278
|
-
for (let i = 0, l =
|
|
8279
|
-
const child =
|
|
8416
|
+
for (let i = 0, l = object3.children.length; i < l; i++) {
|
|
8417
|
+
const child = object3.children[i];
|
|
8280
8418
|
if (child.visible || options.onlyVisible === false) {
|
|
8281
8419
|
const childNodeIndex = await this.processNodeAsync(child);
|
|
8282
8420
|
if (childNodeIndex !== null) children.push(childNodeIndex);
|
|
@@ -8285,7 +8423,7 @@ var GLTFWriter = class {
|
|
|
8285
8423
|
if (children.length > 0) nodeDef.children = children;
|
|
8286
8424
|
}
|
|
8287
8425
|
await this._invokeAllAsync(function(ext) {
|
|
8288
|
-
ext.writeNode && ext.writeNode(
|
|
8426
|
+
ext.writeNode && ext.writeNode(object3, nodeDef);
|
|
8289
8427
|
});
|
|
8290
8428
|
return nodeIndex;
|
|
8291
8429
|
}
|
|
@@ -8294,19 +8432,19 @@ var GLTFWriter = class {
|
|
|
8294
8432
|
* @param {THREE.Object3D} object Object3D with pivot
|
|
8295
8433
|
* @return {Promise<number>} Index of the container node
|
|
8296
8434
|
*/
|
|
8297
|
-
async _processNodeWithPivotAsync(
|
|
8435
|
+
async _processNodeWithPivotAsync(object3) {
|
|
8298
8436
|
const json = this.json;
|
|
8299
8437
|
const options = this.options;
|
|
8300
8438
|
const nodeMap = this.nodeMap;
|
|
8301
|
-
const pivot =
|
|
8439
|
+
const pivot = object3.pivot;
|
|
8302
8440
|
const containerDef = {};
|
|
8303
|
-
const rotation =
|
|
8441
|
+
const rotation = object3.quaternion.toArray();
|
|
8304
8442
|
const position = [
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8443
|
+
object3.position.x + pivot.x,
|
|
8444
|
+
object3.position.y + pivot.y,
|
|
8445
|
+
object3.position.z + pivot.z
|
|
8308
8446
|
];
|
|
8309
|
-
const scale =
|
|
8447
|
+
const scale = object3.scale.toArray();
|
|
8310
8448
|
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
8311
8449
|
containerDef.rotation = rotation;
|
|
8312
8450
|
}
|
|
@@ -8317,28 +8455,28 @@ var GLTFWriter = class {
|
|
|
8317
8455
|
containerDef.scale = scale;
|
|
8318
8456
|
}
|
|
8319
8457
|
containerDef.extras = { pivot: pivot.toArray() };
|
|
8320
|
-
if (
|
|
8321
|
-
this.serializeUserData(
|
|
8458
|
+
if (object3.name !== "") containerDef.name = String(object3.name);
|
|
8459
|
+
this.serializeUserData(object3, containerDef);
|
|
8322
8460
|
const containerIndex = json.nodes.push(containerDef) - 1;
|
|
8323
|
-
nodeMap.set(
|
|
8461
|
+
nodeMap.set(object3, containerIndex);
|
|
8324
8462
|
const childDef = {};
|
|
8325
8463
|
const childPosition = [-pivot.x, -pivot.y, -pivot.z];
|
|
8326
8464
|
if (!equalArray(childPosition, [0, 0, 0])) {
|
|
8327
8465
|
childDef.translation = childPosition;
|
|
8328
8466
|
}
|
|
8329
|
-
if (
|
|
8330
|
-
const meshIndex = await this.processMeshAsync(
|
|
8467
|
+
if (object3.isMesh || object3.isLine || object3.isPoints) {
|
|
8468
|
+
const meshIndex = await this.processMeshAsync(object3);
|
|
8331
8469
|
if (meshIndex !== null) childDef.mesh = meshIndex;
|
|
8332
|
-
} else if (
|
|
8333
|
-
childDef.camera = this.processCamera(
|
|
8470
|
+
} else if (object3.isCamera) {
|
|
8471
|
+
childDef.camera = this.processCamera(object3);
|
|
8334
8472
|
}
|
|
8335
|
-
if (
|
|
8473
|
+
if (object3.isSkinnedMesh) this.skins.push(object3);
|
|
8336
8474
|
const childIndex = json.nodes.push(childDef) - 1;
|
|
8337
8475
|
const containerChildren = [childIndex];
|
|
8338
|
-
if (
|
|
8476
|
+
if (object3.children.length > 0) {
|
|
8339
8477
|
const grandchildren = [];
|
|
8340
|
-
for (let i = 0, l =
|
|
8341
|
-
const child =
|
|
8478
|
+
for (let i = 0, l = object3.children.length; i < l; i++) {
|
|
8479
|
+
const child = object3.children[i];
|
|
8342
8480
|
if (child.visible || options.onlyVisible === false) {
|
|
8343
8481
|
const childNodeIndex = await this.processNodeAsync(child);
|
|
8344
8482
|
if (childNodeIndex !== null) grandchildren.push(childNodeIndex);
|
|
@@ -8348,7 +8486,7 @@ var GLTFWriter = class {
|
|
|
8348
8486
|
}
|
|
8349
8487
|
containerDef.children = containerChildren;
|
|
8350
8488
|
await this._invokeAllAsync(function(ext) {
|
|
8351
|
-
ext.writeNode && ext.writeNode(
|
|
8489
|
+
ext.writeNode && ext.writeNode(object3, containerDef);
|
|
8352
8490
|
});
|
|
8353
8491
|
return containerIndex;
|
|
8354
8492
|
}
|
|
@@ -8791,10 +8929,10 @@ var GLTFMeshGpuInstancing = class {
|
|
|
8791
8929
|
this.writer = writer;
|
|
8792
8930
|
this.name = "EXT_mesh_gpu_instancing";
|
|
8793
8931
|
}
|
|
8794
|
-
writeNode(
|
|
8795
|
-
if (!
|
|
8932
|
+
writeNode(object3, nodeDef) {
|
|
8933
|
+
if (!object3.isInstancedMesh) return;
|
|
8796
8934
|
const writer = this.writer;
|
|
8797
|
-
const mesh =
|
|
8935
|
+
const mesh = object3;
|
|
8798
8936
|
const translationAttr = new Float32Array(mesh.count * 3);
|
|
8799
8937
|
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
8800
8938
|
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
@@ -8984,8 +9122,8 @@ var SceneExporter = class {
|
|
|
8984
9122
|
}
|
|
8985
9123
|
}
|
|
8986
9124
|
};
|
|
8987
|
-
function localMatrix(
|
|
8988
|
-
return
|
|
9125
|
+
function localMatrix(object3) {
|
|
9126
|
+
return object3.matrixAutoUpdate ? new Matrix47().compose(object3.position, object3.quaternion, object3.scale) : object3.matrix.clone();
|
|
8989
9127
|
}
|
|
8990
9128
|
function createSnapshot(root, gltf, bakeColors = false) {
|
|
8991
9129
|
const scene = new Scene3();
|
|
@@ -9089,24 +9227,24 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
9089
9227
|
scene.add(copy);
|
|
9090
9228
|
}
|
|
9091
9229
|
};
|
|
9092
|
-
const visit = (
|
|
9093
|
-
if (!
|
|
9094
|
-
const world = parentWorld.clone().multiply(localMatrix(
|
|
9095
|
-
const mesh =
|
|
9230
|
+
const visit = (object3, parentWorld) => {
|
|
9231
|
+
if (!object3.visible) return;
|
|
9232
|
+
const world = parentWorld.clone().multiply(localMatrix(object3));
|
|
9233
|
+
const mesh = object3;
|
|
9096
9234
|
if (mesh.isMesh) {
|
|
9097
9235
|
const instanced = mesh;
|
|
9098
9236
|
if (instanced.isInstancedMesh) {
|
|
9099
9237
|
for (let i = 0; i < instanced.count; i++) {
|
|
9100
9238
|
const matrix = new Matrix47();
|
|
9101
9239
|
instanced.getMatrixAt(i, matrix);
|
|
9102
|
-
const
|
|
9103
|
-
addMesh(mesh, world.clone().multiply(matrix),
|
|
9240
|
+
const color2 = instanced.instanceColor ? new Color7().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
9241
|
+
addMesh(mesh, world.clone().multiply(matrix), color2);
|
|
9104
9242
|
}
|
|
9105
9243
|
} else {
|
|
9106
9244
|
addMesh(mesh, world);
|
|
9107
9245
|
}
|
|
9108
9246
|
}
|
|
9109
|
-
for (const child of
|
|
9247
|
+
for (const child of object3.children) visit(child, world);
|
|
9110
9248
|
};
|
|
9111
9249
|
try {
|
|
9112
9250
|
const ancestors = [];
|
|
@@ -9182,13 +9320,13 @@ init_AssetKey();
|
|
|
9182
9320
|
|
|
9183
9321
|
// src/gui/GuiText.ts
|
|
9184
9322
|
import { BufferGeometry as BufferGeometry2, Color as Color8, Float32BufferAttribute as Float32BufferAttribute4 } from "three";
|
|
9185
|
-
async function layoutGuiText(
|
|
9323
|
+
async function layoutGuiText(text2, options = {}) {
|
|
9186
9324
|
const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
|
|
9187
9325
|
if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
|
|
9188
9326
|
throw new Error("Text wrap width and line height must be positive");
|
|
9189
9327
|
}
|
|
9190
9328
|
const font = await Fonts.get(options.font);
|
|
9191
|
-
const runs = typeof
|
|
9329
|
+
const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
|
|
9192
9330
|
const glyphs = [], lineWidths = [];
|
|
9193
9331
|
let line = [], width = 0;
|
|
9194
9332
|
let trailingNewline = false;
|
|
@@ -9242,7 +9380,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
9242
9380
|
batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
|
|
9243
9381
|
batches.push(batch);
|
|
9244
9382
|
}
|
|
9245
|
-
const
|
|
9383
|
+
const color2 = new Color8(isShadow ? (style.color & 16579836) >> 2 : style.color);
|
|
9246
9384
|
const offset = isShadow ? 1 : 0;
|
|
9247
9385
|
const top = glyph ? 7 - glyph.ascent : 0;
|
|
9248
9386
|
const height = glyph ? glyph.height * glyph.scale : 8;
|
|
@@ -9270,7 +9408,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
9270
9408
|
const v0 = glyph ? 1 - glyph.y / glyph.image.height : 1;
|
|
9271
9409
|
const v1 = glyph ? 1 - (glyph.y + glyph.height) / glyph.image.height : 0;
|
|
9272
9410
|
batch.uvs.push(u0, v0, u1, v0, u0, v1, u1, v1);
|
|
9273
|
-
for (let i = 0; i < 4; i++) batch.colors.push(
|
|
9411
|
+
for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
|
|
9274
9412
|
batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
|
|
9275
9413
|
};
|
|
9276
9414
|
for (const boldOffset of style.bold ? [0, 1] : [0]) {
|
|
@@ -9304,12 +9442,19 @@ var GuiHelper = class {
|
|
|
9304
9442
|
size: [width + 24, height + 24]
|
|
9305
9443
|
}));
|
|
9306
9444
|
let y = position[1];
|
|
9307
|
-
lines.forEach((
|
|
9308
|
-
layers.push({ ...textOptions, name: `tooltip-line-${index}`, text, position: [position[0], y] });
|
|
9445
|
+
lines.forEach((text2, index) => {
|
|
9446
|
+
layers.push({ ...textOptions, name: `tooltip-line-${index}`, text: text2, position: [position[0], y] });
|
|
9309
9447
|
y += layouts[index].height + (index === 0 ? titleGap : 0);
|
|
9310
9448
|
});
|
|
9311
9449
|
return layers;
|
|
9312
9450
|
}
|
|
9451
|
+
/**
|
|
9452
|
+
* Calculates a slot's top-left position in GUI pixels.
|
|
9453
|
+
* @param slot - Zero-based slot index, or `[column, row]`.
|
|
9454
|
+
* @param origin - Position of the first slot.
|
|
9455
|
+
* @param offset - Horizontal and vertical spacing between slot origins, in pixels.
|
|
9456
|
+
* @param rowSize - Slots per row when `slot` is an index.
|
|
9457
|
+
*/
|
|
9313
9458
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
9314
9459
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
9315
9460
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
@@ -9754,29 +9899,29 @@ var SceneInspector = class {
|
|
|
9754
9899
|
this.objectControlsContainer.innerHTML = "";
|
|
9755
9900
|
this.addControls(targetObject, targetIntersection, instance);
|
|
9756
9901
|
}
|
|
9757
|
-
addControls(
|
|
9902
|
+
addControls(object3, intersection, instance) {
|
|
9758
9903
|
const container = document.createElement("div");
|
|
9759
9904
|
container.append(this.separator("Select Parent/Child"));
|
|
9760
|
-
if (
|
|
9761
|
-
container.append(this.buttonControl("Select Parent " +
|
|
9762
|
-
this.selectObject(
|
|
9905
|
+
if (object3.parent) {
|
|
9906
|
+
container.append(this.buttonControl("Select Parent " + object3.parent.constructor.name + " " + object3.parent.name, "P", () => {
|
|
9907
|
+
this.selectObject(object3.parent, intersection, instance);
|
|
9763
9908
|
}));
|
|
9764
9909
|
}
|
|
9765
|
-
if (
|
|
9910
|
+
if (object3.children.length > 0) {
|
|
9766
9911
|
let i = 1;
|
|
9767
|
-
for (let child of
|
|
9912
|
+
for (let child of object3.children) {
|
|
9768
9913
|
container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
|
|
9769
9914
|
this.selectObject(child, intersection, instance);
|
|
9770
9915
|
}));
|
|
9771
9916
|
}
|
|
9772
9917
|
}
|
|
9773
9918
|
container.append(this.separator());
|
|
9774
|
-
const selectedInstance = instance && (
|
|
9919
|
+
const selectedInstance = instance && (object3 === instance.instanceable || object3 === intersection?.object) ? instance : void 0;
|
|
9775
9920
|
if (!selectedInstance) {
|
|
9776
|
-
container.append(this.toggleControl("Visibility", "V",
|
|
9921
|
+
container.append(this.toggleControl("Visibility", "V", object3.visible, (v) => object3.visible = v));
|
|
9777
9922
|
}
|
|
9778
9923
|
container.append(this.separator("Mesh"));
|
|
9779
|
-
this.addObjectControls(
|
|
9924
|
+
this.addObjectControls(object3, intersection, container, selectedInstance);
|
|
9780
9925
|
container.append(this.separator());
|
|
9781
9926
|
this.objectControlsContainer.append(container);
|
|
9782
9927
|
}
|
|
@@ -9967,6 +10112,7 @@ var SceneStatsDisplay = class {
|
|
|
9967
10112
|
appendTo(el) {
|
|
9968
10113
|
el.append(this.statsContainer);
|
|
9969
10114
|
}
|
|
10115
|
+
/** Stops the refresh timer and removes the panel from the page. */
|
|
9970
10116
|
dispose() {
|
|
9971
10117
|
clearInterval(this.interval);
|
|
9972
10118
|
this.interval = void 0;
|
|
@@ -9991,6 +10137,7 @@ var InstanceManager = class {
|
|
|
9991
10137
|
this.isInstanceManager = true;
|
|
9992
10138
|
this.instanceCache = {};
|
|
9993
10139
|
}
|
|
10140
|
+
/** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
|
|
9994
10141
|
async get(key) {
|
|
9995
10142
|
if (key in this.instanceCache) {
|
|
9996
10143
|
console.debug(p9, "key in cache", key);
|
|
@@ -9998,6 +10145,7 @@ var InstanceManager = class {
|
|
|
9998
10145
|
}
|
|
9999
10146
|
return void 0;
|
|
10000
10147
|
}
|
|
10148
|
+
/** Allocates a placement, calling the supplier once when the shared model is first needed. */
|
|
10001
10149
|
async getOrCreate(key, supplier) {
|
|
10002
10150
|
if (key in this.instanceCache) {
|
|
10003
10151
|
return await this.get(key);
|
|
@@ -10014,6 +10162,7 @@ var InstanceManager = class {
|
|
|
10014
10162
|
throw error;
|
|
10015
10163
|
}
|
|
10016
10164
|
}
|
|
10165
|
+
/** Forgets cached models without disposing them or releasing their existing placements. */
|
|
10017
10166
|
reset() {
|
|
10018
10167
|
for (let instanceCacheKey in this.instanceCache) {
|
|
10019
10168
|
delete this.instanceCache[instanceCacheKey];
|
|
@@ -10059,6 +10208,7 @@ function matchesCondition(condition, state) {
|
|
|
10059
10208
|
});
|
|
10060
10209
|
}
|
|
10061
10210
|
var BlockStateResolver = class {
|
|
10211
|
+
/** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
|
|
10062
10212
|
static async defaults(blockState) {
|
|
10063
10213
|
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
10064
10214
|
const state = {};
|
|
@@ -10078,9 +10228,11 @@ var BlockStateResolver = class {
|
|
|
10078
10228
|
}
|
|
10079
10229
|
return state;
|
|
10080
10230
|
}
|
|
10231
|
+
/** Selects matching models. Supply `choose` to control selection within each alternatives array. */
|
|
10081
10232
|
static select(blockState, state, choose = this.choose) {
|
|
10082
10233
|
return this.matching(blockState, state).map(choose);
|
|
10083
10234
|
}
|
|
10235
|
+
/** Returns matching model groups before choosing weighted alternatives. */
|
|
10084
10236
|
static matching(blockState, state) {
|
|
10085
10237
|
const out = [];
|
|
10086
10238
|
if (blockState.variants) {
|
|
@@ -10104,6 +10256,7 @@ var BlockStateResolver = class {
|
|
|
10104
10256
|
}
|
|
10105
10257
|
return out;
|
|
10106
10258
|
}
|
|
10259
|
+
/** Selects a random alternative using positive integer weights, each defaulting to 1. */
|
|
10107
10260
|
static choose(variants) {
|
|
10108
10261
|
if (!Array.isArray(variants)) return variants;
|
|
10109
10262
|
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
@@ -10121,6 +10274,7 @@ var BlockStateResolver = class {
|
|
|
10121
10274
|
}
|
|
10122
10275
|
return variants[variants.length - 1];
|
|
10123
10276
|
}
|
|
10277
|
+
/** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
|
|
10124
10278
|
static rotation(variant) {
|
|
10125
10279
|
const rotation = new Euler8();
|
|
10126
10280
|
if (typeof variant.x !== "undefined") {
|
|
@@ -10183,29 +10337,29 @@ var BlockTints = class {
|
|
|
10183
10337
|
}
|
|
10184
10338
|
}
|
|
10185
10339
|
if (!indices.size) return tints;
|
|
10186
|
-
let
|
|
10340
|
+
let color2;
|
|
10187
10341
|
switch (rule.source) {
|
|
10188
10342
|
case "constant":
|
|
10189
|
-
|
|
10343
|
+
color2 = rule.color;
|
|
10190
10344
|
break;
|
|
10191
10345
|
case "grass":
|
|
10192
|
-
|
|
10346
|
+
color2 = await Colormaps.grassColor(key);
|
|
10193
10347
|
break;
|
|
10194
10348
|
case "redstone": {
|
|
10195
10349
|
const power = Number(state.power ?? 0) / 15;
|
|
10196
10350
|
const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
|
|
10197
10351
|
const green = Math.max(0, power * power * 0.7 - 0.5);
|
|
10198
10352
|
const blue = Math.max(0, power * power * 0.6 - 0.7);
|
|
10199
|
-
|
|
10353
|
+
color2 = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
|
|
10200
10354
|
break;
|
|
10201
10355
|
}
|
|
10202
10356
|
case "stem": {
|
|
10203
10357
|
const age = Number(state.age ?? 0);
|
|
10204
|
-
|
|
10358
|
+
color2 = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
|
|
10205
10359
|
break;
|
|
10206
10360
|
}
|
|
10207
10361
|
}
|
|
10208
|
-
return { ...Object.fromEntries([...indices].map((index) => [index,
|
|
10362
|
+
return { ...Object.fromEntries([...indices].map((index) => [index, color2])), ...tints };
|
|
10209
10363
|
}
|
|
10210
10364
|
};
|
|
10211
10365
|
|
|
@@ -10347,8 +10501,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10347
10501
|
return false;
|
|
10348
10502
|
}
|
|
10349
10503
|
return this._models.some((model) => {
|
|
10350
|
-
const
|
|
10351
|
-
return
|
|
10504
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10505
|
+
return object3.isOpaqueFullCube && this.getModelCullMask(model, 63) === 63;
|
|
10352
10506
|
});
|
|
10353
10507
|
}
|
|
10354
10508
|
getModelMatrix(model) {
|
|
@@ -10357,8 +10511,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10357
10511
|
return model.matrix.clone();
|
|
10358
10512
|
}
|
|
10359
10513
|
getModelCullMask(model, worldMask) {
|
|
10360
|
-
const
|
|
10361
|
-
if (
|
|
10514
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10515
|
+
if (object3.options.displayPosition) return 0;
|
|
10362
10516
|
const position = new Vector312();
|
|
10363
10517
|
const rotation = new Quaternion5();
|
|
10364
10518
|
const scale = new Vector312();
|
|
@@ -10375,14 +10529,14 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10375
10529
|
replacements.push(model);
|
|
10376
10530
|
continue;
|
|
10377
10531
|
}
|
|
10378
|
-
const
|
|
10532
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10379
10533
|
const cullMask = this.getModelCullMask(model, worldMask);
|
|
10380
|
-
if (cullMask === (
|
|
10534
|
+
if (cullMask === (object3.options.cullMask ?? 0)) {
|
|
10381
10535
|
replacements.push(model);
|
|
10382
10536
|
continue;
|
|
10383
10537
|
}
|
|
10384
10538
|
const matrix = this.getModelMatrix(model);
|
|
10385
|
-
const replacement = await this.scene.addModel(
|
|
10539
|
+
const replacement = await this.scene.addModel(object3.originalModel, { ...object3.options, cullMask });
|
|
10386
10540
|
replacements.push(replacement);
|
|
10387
10541
|
if (isInstanceReference(replacement)) {
|
|
10388
10542
|
replacement.setMatrix(matrix);
|
|
@@ -10390,8 +10544,8 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10390
10544
|
replacement.matrix.copy(matrix);
|
|
10391
10545
|
replacement.matrixWorldNeedsUpdate = true;
|
|
10392
10546
|
matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
10393
|
-
replacement.matrixAutoUpdate =
|
|
10394
|
-
replacement.visible =
|
|
10547
|
+
replacement.matrixAutoUpdate = object3.matrixAutoUpdate;
|
|
10548
|
+
replacement.visible = object3.visible;
|
|
10395
10549
|
}
|
|
10396
10550
|
}
|
|
10397
10551
|
} catch (error) {
|
|
@@ -10407,6 +10561,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10407
10561
|
}
|
|
10408
10562
|
this.notifyDirty();
|
|
10409
10563
|
}
|
|
10564
|
+
/** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
|
|
10410
10565
|
get state() {
|
|
10411
10566
|
return this._state;
|
|
10412
10567
|
}
|
|
@@ -10506,6 +10661,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10506
10661
|
obj.setPosition(this.position);
|
|
10507
10662
|
return obj;
|
|
10508
10663
|
}
|
|
10664
|
+
/** Clears selected properties and rebuilds models without reapplying property defaults. */
|
|
10509
10665
|
async resetState() {
|
|
10510
10666
|
this._previousState = this._state;
|
|
10511
10667
|
this._state = {};
|
|
@@ -12405,6 +12561,11 @@ function compoundList(tags, name) {
|
|
|
12405
12561
|
// src/model/multiblock/StructureParser.ts
|
|
12406
12562
|
init_MineRenderError();
|
|
12407
12563
|
var StructureParser = class {
|
|
12564
|
+
/**
|
|
12565
|
+
* Parses decoded NBT, omitting air blocks.
|
|
12566
|
+
* @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
|
|
12567
|
+
* @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
|
|
12568
|
+
*/
|
|
12408
12569
|
static async parse(_nbt, paletteIndex) {
|
|
12409
12570
|
const nbt = _nbt.value;
|
|
12410
12571
|
let palette;
|
|
@@ -13239,6 +13400,7 @@ var SkinImage = class {
|
|
|
13239
13400
|
// src/skin/SkinTextures.ts
|
|
13240
13401
|
init_Textures();
|
|
13241
13402
|
var SkinTextures = class {
|
|
13403
|
+
/** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
|
|
13242
13404
|
static async get(src, legacy) {
|
|
13243
13405
|
const image = await SkinImage.getData(src);
|
|
13244
13406
|
const scale = image.width / 64;
|
|
@@ -13412,6 +13574,14 @@ var SkinObject = class extends SceneObject {
|
|
|
13412
13574
|
}
|
|
13413
13575
|
}
|
|
13414
13576
|
}
|
|
13577
|
+
/**
|
|
13578
|
+
* Loads a skin texture, detecting slim arms and legacy layouts by default.
|
|
13579
|
+
* To override detection, set `slim` or `legacy` in the options passed to
|
|
13580
|
+
* `new SkinObject(options)` or `scene.addSkin(src, options)`.
|
|
13581
|
+
* Use {@link setSlim} or {@link setLegacy} to change these settings later.
|
|
13582
|
+
*
|
|
13583
|
+
* @param src - URL of the skin texture.
|
|
13584
|
+
*/
|
|
13415
13585
|
async setSkinTexture(src) {
|
|
13416
13586
|
if (typeof src === "undefined") return;
|
|
13417
13587
|
this.skinTextureSrc = src;
|
|
@@ -13522,59 +13692,60 @@ var MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
13522
13692
|
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge8.default)({}, {});
|
|
13523
13693
|
}
|
|
13524
13694
|
add(...objects) {
|
|
13525
|
-
for (const
|
|
13695
|
+
for (const object3 of objects) {
|
|
13526
13696
|
this.dirty = true;
|
|
13527
13697
|
try {
|
|
13528
|
-
super.add(
|
|
13698
|
+
super.add(object3);
|
|
13529
13699
|
} finally {
|
|
13530
|
-
if (
|
|
13531
|
-
this.updateObjectRegistration(
|
|
13700
|
+
if (object3?.isObject3D && object3 !== this) {
|
|
13701
|
+
this.updateObjectRegistration(object3, object3.parent === this);
|
|
13532
13702
|
}
|
|
13533
13703
|
}
|
|
13534
13704
|
}
|
|
13535
13705
|
return this;
|
|
13536
13706
|
}
|
|
13537
13707
|
remove(...objects) {
|
|
13538
|
-
for (const
|
|
13539
|
-
if (!this.children.includes(
|
|
13708
|
+
for (const object3 of objects) {
|
|
13709
|
+
if (!this.children.includes(object3)) continue;
|
|
13540
13710
|
this.dirty = true;
|
|
13541
|
-
this.updateObjectRegistration(
|
|
13711
|
+
this.updateObjectRegistration(object3, false);
|
|
13542
13712
|
try {
|
|
13543
|
-
super.remove(
|
|
13713
|
+
super.remove(object3);
|
|
13544
13714
|
} finally {
|
|
13545
|
-
this.updateObjectRegistration(
|
|
13715
|
+
this.updateObjectRegistration(object3, object3.parent === this);
|
|
13546
13716
|
}
|
|
13547
13717
|
}
|
|
13548
13718
|
return this;
|
|
13549
13719
|
}
|
|
13550
|
-
updateObjectRegistration(
|
|
13551
|
-
if (this.observedObjects.has(
|
|
13552
|
-
const observable =
|
|
13720
|
+
updateObjectRegistration(object3, attached) {
|
|
13721
|
+
if (this.observedObjects.has(object3) === attached) return;
|
|
13722
|
+
const observable = object3;
|
|
13553
13723
|
if (attached) {
|
|
13554
|
-
this.observedObjects.add(
|
|
13724
|
+
this.observedObjects.add(object3);
|
|
13555
13725
|
observable.addEventListener("change", this.onObjectChange);
|
|
13556
13726
|
} else {
|
|
13557
|
-
this.observedObjects.delete(
|
|
13727
|
+
this.observedObjects.delete(object3);
|
|
13558
13728
|
observable.removeEventListener("change", this.onObjectChange);
|
|
13559
13729
|
}
|
|
13560
13730
|
const change = attached ? 1 : -1;
|
|
13561
13731
|
this.stats.objectCount += change;
|
|
13562
|
-
if (isSceneObject(
|
|
13732
|
+
if (isSceneObject(object3)) {
|
|
13563
13733
|
this.stats.sceneObjectCount += change;
|
|
13564
13734
|
}
|
|
13565
13735
|
}
|
|
13566
|
-
|
|
13736
|
+
/** Initializes each object before attaching it to the scene. */
|
|
13737
|
+
async initAndAdd(...object3) {
|
|
13567
13738
|
this.dirty = true;
|
|
13568
|
-
for (let obj of
|
|
13739
|
+
for (let obj of object3) {
|
|
13569
13740
|
await obj.init();
|
|
13570
13741
|
}
|
|
13571
|
-
return this.add(...
|
|
13742
|
+
return this.add(...object3);
|
|
13572
13743
|
}
|
|
13573
|
-
async addSceneObject(
|
|
13744
|
+
async addSceneObject(asset2, objectSupplier, _options, parent = this) {
|
|
13574
13745
|
this.dirty = true;
|
|
13575
13746
|
const obj = await objectSupplier();
|
|
13576
|
-
if (obj?.options?.instanceMeshes &&
|
|
13577
|
-
let key =
|
|
13747
|
+
if (obj?.options?.instanceMeshes && asset2.key && asset2.key?.assetType === "models") {
|
|
13748
|
+
let key = asset2.key.serialize();
|
|
13578
13749
|
if (isModelObject(obj)) {
|
|
13579
13750
|
const { displayPosition, uvLockRotation, tints, cullMask } = obj.options;
|
|
13580
13751
|
if (displayPosition) key += `|display:${displayPosition}`;
|
|
@@ -13598,13 +13769,33 @@ var MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
13598
13769
|
return obj;
|
|
13599
13770
|
}
|
|
13600
13771
|
}
|
|
13772
|
+
/**
|
|
13773
|
+
* Adds a model loaded with {@link Models.getMerged}.
|
|
13774
|
+
* Set `options.instanceMeshes` to `false` to create a separate ModelObject.
|
|
13775
|
+
*
|
|
13776
|
+
* @param parent - Object to attach the model to. Defaults to this scene.
|
|
13777
|
+
* @returns The model, or a reference to one placement of a shared model.
|
|
13778
|
+
*/
|
|
13601
13779
|
async addModel(model, options, parent = this) {
|
|
13602
13780
|
options = { ...options, tints: await ItemTints.get(model, options?.tints) };
|
|
13603
13781
|
return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
|
|
13604
13782
|
}
|
|
13783
|
+
/**
|
|
13784
|
+
* Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
|
|
13785
|
+
* Set `options.initialState` to choose block properties such as `facing` or `axis`.
|
|
13786
|
+
* Use the returned object's `setPosition` method to move all of its model parts.
|
|
13787
|
+
*/
|
|
13605
13788
|
async addBlock(blockState, options, parent = this) {
|
|
13606
13789
|
return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
|
|
13607
13790
|
}
|
|
13791
|
+
/**
|
|
13792
|
+
* Loads a skin and adds an initialized player model.
|
|
13793
|
+
*
|
|
13794
|
+
* @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
|
|
13795
|
+
* Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
|
|
13796
|
+
* @param options - Player settings, including `slim` and `legacy` detection overrides.
|
|
13797
|
+
* @param parent - Object to attach the player to. Defaults to this scene.
|
|
13798
|
+
*/
|
|
13608
13799
|
async addSkin(skin, options, parent = this) {
|
|
13609
13800
|
this.dirty = true;
|
|
13610
13801
|
const obj = new SkinObject(options);
|
|
@@ -13616,9 +13807,14 @@ var MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
13616
13807
|
parent.add(obj);
|
|
13617
13808
|
return obj;
|
|
13618
13809
|
}
|
|
13810
|
+
/** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
|
|
13619
13811
|
async addEntity(entity, options, parent = this) {
|
|
13620
13812
|
return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
|
|
13621
13813
|
}
|
|
13814
|
+
/**
|
|
13815
|
+
* Adds GUI layers in draw order. One GUI pixel equals one scene unit.
|
|
13816
|
+
* Layer positions start at the top left, with positive GUI y pointing down.
|
|
13817
|
+
*/
|
|
13622
13818
|
async addGui(layers, options, parent = this) {
|
|
13623
13819
|
const obj = new GuiObject(layers, options);
|
|
13624
13820
|
obj.scene = this;
|
|
@@ -13655,11 +13851,11 @@ var _changeEvent = { type: "change" };
|
|
|
13655
13851
|
var _startEvent = { type: "start" };
|
|
13656
13852
|
var _endEvent = { type: "end" };
|
|
13657
13853
|
var OrbitControls = class extends EventDispatcher {
|
|
13658
|
-
constructor(
|
|
13854
|
+
constructor(object3, domElement) {
|
|
13659
13855
|
super();
|
|
13660
13856
|
if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
|
|
13661
13857
|
if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
|
|
13662
|
-
this.object =
|
|
13858
|
+
this.object = object3;
|
|
13663
13859
|
this.domElement = domElement;
|
|
13664
13860
|
this.domElement.style.touchAction = "none";
|
|
13665
13861
|
this.enabled = true;
|
|
@@ -13716,7 +13912,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
13716
13912
|
};
|
|
13717
13913
|
this.update = function() {
|
|
13718
13914
|
const offset = new Vector313();
|
|
13719
|
-
const quat = new Quaternion6().setFromUnitVectors(
|
|
13915
|
+
const quat = new Quaternion6().setFromUnitVectors(object3.up, new Vector313(0, 1, 0));
|
|
13720
13916
|
const quatInverse = quat.clone().invert();
|
|
13721
13917
|
const lastPosition = new Vector313();
|
|
13722
13918
|
const lastQuaternion = new Quaternion6();
|
|
@@ -14281,8 +14477,8 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14281
14477
|
}
|
|
14282
14478
|
};
|
|
14283
14479
|
var MapControls = class extends OrbitControls {
|
|
14284
|
-
constructor(
|
|
14285
|
-
super(
|
|
14480
|
+
constructor(object3, domElement) {
|
|
14481
|
+
super(object3, domElement);
|
|
14286
14482
|
this.screenSpacePanning = false;
|
|
14287
14483
|
this.mouseButtons.LEFT = MOUSE.PAN;
|
|
14288
14484
|
this.mouseButtons.RIGHT = MOUSE.ROTATE;
|
|
@@ -14481,6 +14677,7 @@ var Renderer = class _Renderer {
|
|
|
14481
14677
|
get element() {
|
|
14482
14678
|
return this._element;
|
|
14483
14679
|
}
|
|
14680
|
+
/** Attaches the canvas to an element and sizes it to that element's dimensions. */
|
|
14484
14681
|
appendTo(element) {
|
|
14485
14682
|
if (this._disposed) return;
|
|
14486
14683
|
this._element = element;
|
|
@@ -14508,6 +14705,7 @@ var Renderer = class _Renderer {
|
|
|
14508
14705
|
events.add(changeEvent2);
|
|
14509
14706
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
14510
14707
|
}
|
|
14708
|
+
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
14511
14709
|
resize(width, height) {
|
|
14512
14710
|
if (this._disposed) return;
|
|
14513
14711
|
if (isPerspectiveCamera(this.camera)) {
|
|
@@ -14546,12 +14744,14 @@ var Renderer = class _Renderer {
|
|
|
14546
14744
|
if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
|
|
14547
14745
|
};
|
|
14548
14746
|
}
|
|
14747
|
+
/** Starts or resumes the animation loop and registered frame callbacks. */
|
|
14549
14748
|
start() {
|
|
14550
14749
|
if (this._disposed) return;
|
|
14551
14750
|
this.stop();
|
|
14552
14751
|
this._running = true;
|
|
14553
14752
|
if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
|
|
14554
14753
|
}
|
|
14754
|
+
/** Pauses rendering and frame callbacks. Call {@link start} to resume. */
|
|
14555
14755
|
stop() {
|
|
14556
14756
|
if (this._disposed) return;
|
|
14557
14757
|
this._running = false;
|
|
@@ -14660,12 +14860,15 @@ var Renderer = class _Renderer {
|
|
|
14660
14860
|
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
14661
14861
|
return canvas.toDataURL(mime, quality);
|
|
14662
14862
|
}
|
|
14863
|
+
/** Exports visible scene meshes as OBJ text, without texture images. */
|
|
14663
14864
|
toObj() {
|
|
14664
14865
|
return SceneExporter.toObj(this.scene);
|
|
14665
14866
|
}
|
|
14867
|
+
/** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
|
|
14666
14868
|
toPLY(options) {
|
|
14667
14869
|
return SceneExporter.toPLY(this.scene, options);
|
|
14668
14870
|
}
|
|
14871
|
+
/** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
|
|
14669
14872
|
toGLTF(options) {
|
|
14670
14873
|
return SceneExporter.toGLTF(this.scene, options);
|
|
14671
14874
|
}
|
|
@@ -14704,16 +14907,244 @@ init_SceneObject();
|
|
|
14704
14907
|
// src/index.ts
|
|
14705
14908
|
init_request();
|
|
14706
14909
|
|
|
14910
|
+
// src/scene/SceneDocument.ts
|
|
14911
|
+
init_DisplayPosition();
|
|
14912
|
+
function fail(path, message) {
|
|
14913
|
+
throw new Error(`${path}: ${message}`);
|
|
14914
|
+
}
|
|
14915
|
+
function object2(value, path) {
|
|
14916
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail(path, "expected a JSON object");
|
|
14917
|
+
for (const key of Object.keys(value)) {
|
|
14918
|
+
if (["__proto__", "prototype", "constructor"].includes(key)) fail(`${path}.${key}`, "unsupported property");
|
|
14919
|
+
}
|
|
14920
|
+
return value;
|
|
14921
|
+
}
|
|
14922
|
+
function fields(value, path, allowed, required = []) {
|
|
14923
|
+
const input = object2(value, path);
|
|
14924
|
+
for (const key of required) if (input[key] === void 0) fail(`${path}.${key}`, "required");
|
|
14925
|
+
for (const [key, entry] of Object.entries(input)) {
|
|
14926
|
+
if (!Object.prototype.hasOwnProperty.call(allowed, key)) fail(`${path}.${key}`, "unsupported property");
|
|
14927
|
+
if (entry !== void 0) allowed[key](entry, `${path}.${key}`);
|
|
14928
|
+
}
|
|
14929
|
+
return input;
|
|
14930
|
+
}
|
|
14931
|
+
var text = (value, path) => {
|
|
14932
|
+
if (typeof value !== "string" || !value.trim()) fail(path, "expected a nonempty string");
|
|
14933
|
+
};
|
|
14934
|
+
var literalText = (value, path) => {
|
|
14935
|
+
if (typeof value !== "string") fail(path, "expected a string");
|
|
14936
|
+
};
|
|
14937
|
+
var boolean = (value, path) => {
|
|
14938
|
+
if (typeof value !== "boolean") fail(path, "expected a boolean");
|
|
14939
|
+
};
|
|
14940
|
+
var number = (value, path) => {
|
|
14941
|
+
if (typeof value !== "number" || !Number.isFinite(value)) fail(path, "expected a finite number");
|
|
14942
|
+
};
|
|
14943
|
+
var positive = (value, path) => {
|
|
14944
|
+
number(value, path);
|
|
14945
|
+
if (value <= 0) fail(path, "expected a positive number");
|
|
14946
|
+
};
|
|
14947
|
+
var nonnegative = (value, path) => {
|
|
14948
|
+
number(value, path);
|
|
14949
|
+
if (value < 0) fail(path, "expected a nonnegative number");
|
|
14950
|
+
};
|
|
14951
|
+
var color = (value, path) => {
|
|
14952
|
+
number(value, path);
|
|
14953
|
+
if (!Number.isInteger(value) || value < 0 || value > 16777215) {
|
|
14954
|
+
fail(path, "expected an RGB integer from 0 to 16777215");
|
|
14955
|
+
}
|
|
14956
|
+
};
|
|
14957
|
+
var asset = (value, path) => {
|
|
14958
|
+
text(value, path);
|
|
14959
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(value) || value.split(/[:/]/).some((part) => !part || part === "." || part === "..")) {
|
|
14960
|
+
fail(path, "expected a resource ID such as minecraft:stone");
|
|
14961
|
+
}
|
|
14962
|
+
};
|
|
14963
|
+
var version = (value, path) => {
|
|
14964
|
+
text(value, path);
|
|
14965
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(value)) fail(path, "expected a Minecraft version without slashes");
|
|
14966
|
+
};
|
|
14967
|
+
var tuple = (size, item = number) => (value, path) => {
|
|
14968
|
+
if (!Array.isArray(value) || value.length !== size) fail(path, `expected ${size} numbers`);
|
|
14969
|
+
for (let index = 0; index < size; index++) item(value[index], `${path}[${index}]`);
|
|
14970
|
+
};
|
|
14971
|
+
var list = (item) => (value, path) => {
|
|
14972
|
+
if (!Array.isArray(value)) fail(path, "expected an array");
|
|
14973
|
+
for (let index = 0; index < value.length; index++) item(value[index], `${path}[${index}]`);
|
|
14974
|
+
};
|
|
14975
|
+
var dictionary = (item, numericKeys = false) => (value, path) => {
|
|
14976
|
+
for (const [key, entry] of Object.entries(object2(value, path))) {
|
|
14977
|
+
if (numericKeys && !/^\d+$/.test(key)) fail(`${path}.${key}`, "expected a nonnegative tint index");
|
|
14978
|
+
item(entry, `${path}.${key}`);
|
|
14979
|
+
}
|
|
14980
|
+
};
|
|
14981
|
+
var enumeration = (values) => (value, path) => {
|
|
14982
|
+
if (!values.includes(value)) fail(path, `expected one of: ${values.join(", ")}`);
|
|
14983
|
+
};
|
|
14984
|
+
var textStyle = { color, bold: boolean, italic: boolean };
|
|
14985
|
+
function guiLayer(value, path) {
|
|
14986
|
+
const layer = object2(value, path);
|
|
14987
|
+
if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
|
|
14988
|
+
fail(path, "expected exactly one of texture, item, or text");
|
|
14989
|
+
}
|
|
14990
|
+
const layout = { name: text, position: tuple(2), size: tuple(2, positive) };
|
|
14991
|
+
if (layer.texture !== void 0) {
|
|
14992
|
+
fields(value, path, { ...layout, texture: asset, crop: (value2, path2) => {
|
|
14993
|
+
tuple(4)(value2, path2);
|
|
14994
|
+
const [x, y, width, height] = value2;
|
|
14995
|
+
nonnegative(x, `${path2}[0]`);
|
|
14996
|
+
nonnegative(y, `${path2}[1]`);
|
|
14997
|
+
positive(width, `${path2}[2]`);
|
|
14998
|
+
positive(height, `${path2}[3]`);
|
|
14999
|
+
} });
|
|
15000
|
+
} else if (layer.item !== void 0) {
|
|
15001
|
+
fields(value, path, { ...layout, item: asset, tints: dictionary(color, true) });
|
|
15002
|
+
} else {
|
|
15003
|
+
fields(value, path, {
|
|
15004
|
+
...layout,
|
|
15005
|
+
...textStyle,
|
|
15006
|
+
font: asset,
|
|
15007
|
+
shadow: boolean,
|
|
15008
|
+
maxWidth: positive,
|
|
15009
|
+
lineHeight: positive,
|
|
15010
|
+
text: (value2, path2) => {
|
|
15011
|
+
if (typeof value2 === "string") return;
|
|
15012
|
+
list((run, path3) => {
|
|
15013
|
+
fields(run, path3, { text: literalText, ...textStyle }, ["text"]);
|
|
15014
|
+
})(value2, path2);
|
|
15015
|
+
}
|
|
15016
|
+
});
|
|
15017
|
+
}
|
|
15018
|
+
}
|
|
15019
|
+
function validateObject(value, path) {
|
|
15020
|
+
const input = object2(value, path);
|
|
15021
|
+
const common = { id: text, name: text, type: text, position: tuple(3), rotation: tuple(3), scale: tuple(3), visible: boolean };
|
|
15022
|
+
const required = ["id", "type"];
|
|
15023
|
+
const renderOptions = { wireframe: boolean };
|
|
15024
|
+
switch (input.type) {
|
|
15025
|
+
case "skin":
|
|
15026
|
+
fields(value, path, {
|
|
15027
|
+
...common,
|
|
15028
|
+
skin: text,
|
|
15029
|
+
cape: (value2, path2) => {
|
|
15030
|
+
fields(value2, path2, { texture: text, layout: enumeration(["minecraft", "optifine", "labymod"]) }, ["texture"]);
|
|
15031
|
+
},
|
|
15032
|
+
hiddenParts: list(enumeration(SKIN_PARTS)),
|
|
15033
|
+
pose: (value2, path2) => {
|
|
15034
|
+
fields(value2, path2, {
|
|
15035
|
+
head: tuple(3),
|
|
15036
|
+
body: tuple(3),
|
|
15037
|
+
rightArm: tuple(3),
|
|
15038
|
+
leftArm: tuple(3),
|
|
15039
|
+
rightLeg: tuple(3),
|
|
15040
|
+
leftLeg: tuple(3),
|
|
15041
|
+
cape: tuple(3)
|
|
15042
|
+
});
|
|
15043
|
+
},
|
|
15044
|
+
options: (value2, path2) => {
|
|
15045
|
+
fields(value2, path2, { slim: boolean, legacy: boolean });
|
|
15046
|
+
}
|
|
15047
|
+
}, required);
|
|
15048
|
+
break;
|
|
15049
|
+
case "block":
|
|
15050
|
+
fields(value, path, {
|
|
15051
|
+
...common,
|
|
15052
|
+
asset,
|
|
15053
|
+
state: dictionary(text),
|
|
15054
|
+
options: (value2, path2) => {
|
|
15055
|
+
fields(value2, path2, { ...renderOptions, tints: dictionary(color, true) });
|
|
15056
|
+
}
|
|
15057
|
+
}, [...required, "asset"]);
|
|
15058
|
+
break;
|
|
15059
|
+
case "item":
|
|
15060
|
+
case "model":
|
|
15061
|
+
fields(value, path, {
|
|
15062
|
+
...common,
|
|
15063
|
+
asset,
|
|
15064
|
+
options: (value2, path2) => {
|
|
15065
|
+
fields(value2, path2, { ...renderOptions, displayPosition: enumeration(DISPLAY_POSITIONS), tints: dictionary(color, true) });
|
|
15066
|
+
}
|
|
15067
|
+
}, [...required, "asset"]);
|
|
15068
|
+
break;
|
|
15069
|
+
case "entity":
|
|
15070
|
+
fields(value, path, {
|
|
15071
|
+
...common,
|
|
15072
|
+
asset,
|
|
15073
|
+
texture: asset,
|
|
15074
|
+
layers: list(text),
|
|
15075
|
+
when: list(text),
|
|
15076
|
+
textures: dictionary(asset),
|
|
15077
|
+
options: (value2, path2) => {
|
|
15078
|
+
fields(value2, path2, {
|
|
15079
|
+
...renderOptions,
|
|
15080
|
+
flip: boolean,
|
|
15081
|
+
tints: dictionary((value3, path3) => {
|
|
15082
|
+
typeof value3 === "string" ? text(value3, path3) : color(value3, path3);
|
|
15083
|
+
})
|
|
15084
|
+
});
|
|
15085
|
+
},
|
|
15086
|
+
animation: (value2, path2) => {
|
|
15087
|
+
fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
|
|
15088
|
+
}
|
|
15089
|
+
}, [...required, "asset"]);
|
|
15090
|
+
if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
|
|
15091
|
+
break;
|
|
15092
|
+
case "gui":
|
|
15093
|
+
fields(value, path, { ...common, layers: list(guiLayer) }, [...required, "layers"]);
|
|
15094
|
+
break;
|
|
15095
|
+
default:
|
|
15096
|
+
fail(`${path}.type`, "expected skin, block, item, entity, model, or gui");
|
|
15097
|
+
}
|
|
15098
|
+
}
|
|
15099
|
+
function parseSceneDocument(value) {
|
|
15100
|
+
if (typeof value === "string") {
|
|
15101
|
+
try {
|
|
15102
|
+
value = JSON.parse(value);
|
|
15103
|
+
} catch {
|
|
15104
|
+
fail("scene", "invalid JSON");
|
|
15105
|
+
}
|
|
15106
|
+
}
|
|
15107
|
+
const input = fields(value, "scene", {
|
|
15108
|
+
format: enumeration(["minerender-scene"]),
|
|
15109
|
+
version: (value2, path) => {
|
|
15110
|
+
if (value2 !== 1) fail(path, "only scene document version 1 is supported");
|
|
15111
|
+
},
|
|
15112
|
+
minecraftVersion: version,
|
|
15113
|
+
camera: (value2, path) => {
|
|
15114
|
+
fields(value2, path, { position: tuple(3), target: tuple(3) }, ["position", "target"]);
|
|
15115
|
+
},
|
|
15116
|
+
objects: list(validateObject)
|
|
15117
|
+
}, ["format", "version", "objects"]);
|
|
15118
|
+
const ids = /* @__PURE__ */ new Set();
|
|
15119
|
+
for (const [index, entry] of input.objects.entries()) {
|
|
15120
|
+
if (ids.has(entry.id)) fail(`scene.objects[${index}].id`, `duplicate object ID "${entry.id}"`);
|
|
15121
|
+
ids.add(entry.id);
|
|
15122
|
+
}
|
|
15123
|
+
return JSON.parse(JSON.stringify(input));
|
|
15124
|
+
}
|
|
15125
|
+
|
|
15126
|
+
// src/scene/SceneDocumentLoader.ts
|
|
15127
|
+
init_AssetKey();
|
|
15128
|
+
init_AssetLoader();
|
|
15129
|
+
init_BlockStates();
|
|
15130
|
+
init_Entities();
|
|
15131
|
+
init_Models();
|
|
15132
|
+
init_DisplayPosition();
|
|
15133
|
+
import { Group as Group2 } from "three";
|
|
15134
|
+
init_SceneObject();
|
|
15135
|
+
|
|
14707
15136
|
// src/skin/Skins.ts
|
|
14708
15137
|
init_Requests();
|
|
14709
15138
|
var Skins = class {
|
|
14710
15139
|
//<editor-fold desc="Skins">
|
|
15140
|
+
/** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
|
|
14711
15141
|
static async fromUuidOrUsername(uuidOrUsername) {
|
|
14712
15142
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14713
15143
|
return this.fromUuid(uuidOrUsername);
|
|
14714
15144
|
}
|
|
14715
15145
|
return this.fromUsername(uuidOrUsername);
|
|
14716
15146
|
}
|
|
15147
|
+
/** Builds a proxy URL for a UUID without downloading or checking the skin. */
|
|
14717
15148
|
static async fromUuid(uuid) {
|
|
14718
15149
|
return this.getMcProxySkinUrl(uuid);
|
|
14719
15150
|
}
|
|
@@ -14725,6 +15156,7 @@ var Skins = class {
|
|
|
14725
15156
|
return void 0;
|
|
14726
15157
|
});
|
|
14727
15158
|
}
|
|
15159
|
+
/** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
|
|
14728
15160
|
static async fromMineSkin(mineskinId) {
|
|
14729
15161
|
return this.getMineSkin(mineskinId).then((mineskin) => {
|
|
14730
15162
|
if (mineskin) {
|
|
@@ -14735,12 +15167,14 @@ var Skins = class {
|
|
|
14735
15167
|
}
|
|
14736
15168
|
//</editor-fold>
|
|
14737
15169
|
//<editor-fold desc="Capes">
|
|
15170
|
+
/** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
|
|
14738
15171
|
static async capeFromUuidOrUsername(uuidOrUsername) {
|
|
14739
15172
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14740
15173
|
return this.capeFromUuid(uuidOrUsername);
|
|
14741
15174
|
}
|
|
14742
15175
|
return this.capeFromUsername(uuidOrUsername);
|
|
14743
15176
|
}
|
|
15177
|
+
/** Builds a proxy URL without checking whether the player has a cape. */
|
|
14744
15178
|
static async capeFromUuid(uuid) {
|
|
14745
15179
|
return this.getMcProxyCapeUrl(uuid);
|
|
14746
15180
|
}
|
|
@@ -14869,6 +15303,195 @@ var Skins = class {
|
|
|
14869
15303
|
//</editor-fold>
|
|
14870
15304
|
};
|
|
14871
15305
|
|
|
15306
|
+
// src/scene/SceneDocumentLoader.ts
|
|
15307
|
+
var DocumentObjectScene = class extends MineRenderScene {
|
|
15308
|
+
async addSceneObject(_asset, supplier, _options, parent = this) {
|
|
15309
|
+
const object3 = await supplier();
|
|
15310
|
+
return this.initialize(object3, parent);
|
|
15311
|
+
}
|
|
15312
|
+
async initialize(object3, parent = this) {
|
|
15313
|
+
object3.scene = this;
|
|
15314
|
+
try {
|
|
15315
|
+
await object3.init();
|
|
15316
|
+
parent.add(object3);
|
|
15317
|
+
return object3;
|
|
15318
|
+
} catch (error) {
|
|
15319
|
+
object3.dispose();
|
|
15320
|
+
object3.removeFromParent();
|
|
15321
|
+
throw error;
|
|
15322
|
+
}
|
|
15323
|
+
}
|
|
15324
|
+
dispose() {
|
|
15325
|
+
for (const child of [...this.children]) {
|
|
15326
|
+
if (child.parent !== this) continue;
|
|
15327
|
+
if (isSceneObject(child)) child.dispose();
|
|
15328
|
+
child.removeFromParent();
|
|
15329
|
+
}
|
|
15330
|
+
}
|
|
15331
|
+
};
|
|
15332
|
+
async function skinTexture(value, cape = false) {
|
|
15333
|
+
if (!/^[a-zA-Z0-9_-]{1,36}$/.test(value)) return value;
|
|
15334
|
+
const texture = await (cape ? Skins.capeFromUuidOrUsername(value) : Skins.fromUuidOrUsername(value));
|
|
15335
|
+
if (!texture) throw new Error(`Could not find ${cape ? "cape" : "skin"} for "${value}"`);
|
|
15336
|
+
return texture;
|
|
15337
|
+
}
|
|
15338
|
+
var SceneDocumentLoader = class {
|
|
15339
|
+
static parse(value) {
|
|
15340
|
+
return parseSceneDocument(value);
|
|
15341
|
+
}
|
|
15342
|
+
/**
|
|
15343
|
+
* Loads objects concurrently and attaches them in document order after every load succeeds.
|
|
15344
|
+
* A failure waits for all loads, disposes staged objects, and reports the first error in document order.
|
|
15345
|
+
*/
|
|
15346
|
+
static async load(scene, value, parent = scene) {
|
|
15347
|
+
const definition = this.parse(value);
|
|
15348
|
+
if (definition.minecraftVersion !== void 0 && definition.minecraftVersion !== AssetLoader.version) {
|
|
15349
|
+
throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion("${definition.minecraftVersion}") before loading it`);
|
|
15350
|
+
}
|
|
15351
|
+
const root = new Group2();
|
|
15352
|
+
root.name = "MineRender scene document";
|
|
15353
|
+
const objects = [];
|
|
15354
|
+
let disposed = false;
|
|
15355
|
+
const loaded = {
|
|
15356
|
+
root,
|
|
15357
|
+
objects,
|
|
15358
|
+
definition,
|
|
15359
|
+
advanceAnimations: (delta) => {
|
|
15360
|
+
if (!disposed) for (const object3 of objects) object3.advanceAnimation(delta);
|
|
15361
|
+
},
|
|
15362
|
+
dispose: () => {
|
|
15363
|
+
if (disposed) return;
|
|
15364
|
+
disposed = true;
|
|
15365
|
+
root.removeFromParent();
|
|
15366
|
+
for (const object3 of objects) object3.dispose();
|
|
15367
|
+
root.clear();
|
|
15368
|
+
scene.dirty = true;
|
|
15369
|
+
}
|
|
15370
|
+
};
|
|
15371
|
+
try {
|
|
15372
|
+
const results = await Promise.allSettled(definition.objects.map((object3) => this.loadValidatedObject(scene, object3)));
|
|
15373
|
+
for (const result of results) if (result.status === "fulfilled") objects.push(result.value);
|
|
15374
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
15375
|
+
if (failure) throw failure.reason;
|
|
15376
|
+
for (const object3 of objects) root.add(object3.root);
|
|
15377
|
+
parent.add(root);
|
|
15378
|
+
scene.dirty = true;
|
|
15379
|
+
return loaded;
|
|
15380
|
+
} catch (error) {
|
|
15381
|
+
loaded.dispose();
|
|
15382
|
+
throw error;
|
|
15383
|
+
}
|
|
15384
|
+
}
|
|
15385
|
+
/** Loads an independently editable object. Its root owns the document's position, rotation, and scale. */
|
|
15386
|
+
static async loadObject(scene, value, parent = scene) {
|
|
15387
|
+
const definition = this.parse({ format: "minerender-scene", version: 1, objects: [value] }).objects[0];
|
|
15388
|
+
return this.loadValidatedObject(scene, definition, parent);
|
|
15389
|
+
}
|
|
15390
|
+
static async loadValidatedObject(scene, definition, parent) {
|
|
15391
|
+
const root = new Group2();
|
|
15392
|
+
root.name = definition.name ?? definition.id;
|
|
15393
|
+
root.userData.sceneObjectId = definition.id;
|
|
15394
|
+
root.position.fromArray(definition.position ?? [0, 0, 0]);
|
|
15395
|
+
root.rotation.set(...definition.rotation ?? [0, 0, 0]);
|
|
15396
|
+
root.scale.fromArray(definition.scale ?? [1, 1, 1]);
|
|
15397
|
+
root.visible = definition.visible ?? true;
|
|
15398
|
+
const content = new DocumentObjectScene();
|
|
15399
|
+
root.add(content);
|
|
15400
|
+
let object3;
|
|
15401
|
+
try {
|
|
15402
|
+
switch (definition.type) {
|
|
15403
|
+
case "skin": {
|
|
15404
|
+
const skin = new SkinObject({ ...definition.options, instanceMeshes: false });
|
|
15405
|
+
object3 = skin;
|
|
15406
|
+
const texture = definition.skin ? await skinTexture(definition.skin) : `${AssetLoader.ROOT}/assets/minecraft/textures/entity/player/${definition.options?.slim ? "slim/alex" : "wide/steve"}.png`;
|
|
15407
|
+
await skin.setSkinTexture(texture);
|
|
15408
|
+
await content.initialize(skin);
|
|
15409
|
+
if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);
|
|
15410
|
+
for (const [part, rotation] of Object.entries(definition.pose ?? {})) {
|
|
15411
|
+
skin.getGroupByName(part)?.rotation.set(...rotation, "XYZ");
|
|
15412
|
+
}
|
|
15413
|
+
for (const part of definition.hiddenParts ?? []) {
|
|
15414
|
+
const mesh = skin.getMeshByName(part);
|
|
15415
|
+
if (mesh) mesh.visible = false;
|
|
15416
|
+
}
|
|
15417
|
+
break;
|
|
15418
|
+
}
|
|
15419
|
+
case "block": {
|
|
15420
|
+
const state = await BlockStates.get(AssetKey.parse("blockstates", definition.asset));
|
|
15421
|
+
if (!state) throw new Error(`Could not load block ${definition.asset}`);
|
|
15422
|
+
object3 = await content.addBlock(state, { ...definition.options, initialState: definition.state, instanceMeshes: false });
|
|
15423
|
+
break;
|
|
15424
|
+
}
|
|
15425
|
+
case "item":
|
|
15426
|
+
case "model": {
|
|
15427
|
+
let key = AssetKey.parse("models", definition.asset);
|
|
15428
|
+
if (definition.type === "item" && key.type !== "item") {
|
|
15429
|
+
key = new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
15430
|
+
}
|
|
15431
|
+
const model = await Models.getMerged(key);
|
|
15432
|
+
if (!model) throw new Error(`Could not load ${definition.type} ${definition.asset}`);
|
|
15433
|
+
object3 = await content.addModel(model, {
|
|
15434
|
+
...definition.type === "item" ? { displayPosition: "gui" /* GUI */ } : {},
|
|
15435
|
+
...definition.options,
|
|
15436
|
+
instanceMeshes: false
|
|
15437
|
+
});
|
|
15438
|
+
break;
|
|
15439
|
+
}
|
|
15440
|
+
case "entity": {
|
|
15441
|
+
const key = AssetKey.parse("entity-models", definition.asset);
|
|
15442
|
+
const model = await Entities.getEntity(key, definition.texture ? AssetKey.parse("textures", definition.texture) : void 0, {
|
|
15443
|
+
layers: definition.layers,
|
|
15444
|
+
when: definition.when,
|
|
15445
|
+
textures: definition.textures && Object.fromEntries(Object.entries(definition.textures).map(([name, texture]) => [name, AssetKey.parse("textures", texture)]))
|
|
15446
|
+
});
|
|
15447
|
+
if (!model) throw new Error(`Could not load entity ${definition.asset}`);
|
|
15448
|
+
const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
|
|
15449
|
+
object3 = entity;
|
|
15450
|
+
if (definition.animation) {
|
|
15451
|
+
const animations = await Entities.getAnimations(key);
|
|
15452
|
+
const clip = animations?.[definition.animation.name];
|
|
15453
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${definition.animation.name}"`);
|
|
15454
|
+
entity.playAnimation(clip, definition.animation);
|
|
15455
|
+
}
|
|
15456
|
+
break;
|
|
15457
|
+
}
|
|
15458
|
+
case "gui":
|
|
15459
|
+
object3 = await content.initialize(new GuiObject(definition.layers));
|
|
15460
|
+
break;
|
|
15461
|
+
}
|
|
15462
|
+
let disposed = false;
|
|
15463
|
+
const loaded = {
|
|
15464
|
+
root,
|
|
15465
|
+
object: object3,
|
|
15466
|
+
definition,
|
|
15467
|
+
advanceAnimation: (delta) => {
|
|
15468
|
+
if (!disposed && definition.type === "entity" && !definition.animation?.paused) object3.advanceAnimation(delta);
|
|
15469
|
+
},
|
|
15470
|
+
dispose: () => {
|
|
15471
|
+
if (disposed) return;
|
|
15472
|
+
disposed = true;
|
|
15473
|
+
root.removeFromParent();
|
|
15474
|
+
object3.dispose();
|
|
15475
|
+
object3.removeFromParent();
|
|
15476
|
+
content.dispose();
|
|
15477
|
+
root.clear();
|
|
15478
|
+
scene.dirty = true;
|
|
15479
|
+
}
|
|
15480
|
+
};
|
|
15481
|
+
parent?.add(root);
|
|
15482
|
+
scene.dirty = true;
|
|
15483
|
+
return loaded;
|
|
15484
|
+
} catch (error) {
|
|
15485
|
+
object3?.dispose();
|
|
15486
|
+
object3?.removeFromParent();
|
|
15487
|
+
content.dispose();
|
|
15488
|
+
root.removeFromParent();
|
|
15489
|
+
root.clear();
|
|
15490
|
+
throw new Error(`Scene object "${definition.name ?? definition.id}": ${error instanceof Error ? error.message : String(error)}`);
|
|
15491
|
+
}
|
|
15492
|
+
}
|
|
15493
|
+
};
|
|
15494
|
+
|
|
14872
15495
|
// src/texture/index.ts
|
|
14873
15496
|
init_Colormaps();
|
|
14874
15497
|
init_TextureAtlas();
|
|
@@ -14895,16 +15518,19 @@ var ChunkData = class _ChunkData {
|
|
|
14895
15518
|
this.freeIds = [];
|
|
14896
15519
|
this.nbt = /* @__PURE__ */ new Map();
|
|
14897
15520
|
}
|
|
15521
|
+
/** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
|
|
14898
15522
|
get(index) {
|
|
14899
15523
|
_ChunkData.validateIndex(index);
|
|
14900
15524
|
const entry = this.palette[this.indices[index]];
|
|
14901
15525
|
return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
|
|
14902
15526
|
}
|
|
15527
|
+
/** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
|
|
14903
15528
|
snapshot(index) {
|
|
14904
15529
|
_ChunkData.validateIndex(index);
|
|
14905
15530
|
const entry = this.palette[this.indices[index]];
|
|
14906
15531
|
return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
|
|
14907
15532
|
}
|
|
15533
|
+
/** Copies block data into a cell. An omitted block or an air block clears the cell. */
|
|
14908
15534
|
set(index, block) {
|
|
14909
15535
|
_ChunkData.validateIndex(index);
|
|
14910
15536
|
let state;
|
|
@@ -14969,15 +15595,23 @@ var ChunkData = class _ChunkData {
|
|
|
14969
15595
|
|
|
14970
15596
|
// src/world/AnvilParser.ts
|
|
14971
15597
|
var AnvilParser = class {
|
|
15598
|
+
/** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
|
|
14972
15599
|
static getChunkList(data) {
|
|
14973
15600
|
return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
|
|
14974
15601
|
}
|
|
15602
|
+
/** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
|
|
14975
15603
|
static async parse(data) {
|
|
14976
15604
|
const bytes = this.bytes(data);
|
|
14977
15605
|
const chunks = [];
|
|
14978
15606
|
for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
|
|
14979
15607
|
return { chunks };
|
|
14980
15608
|
}
|
|
15609
|
+
/**
|
|
15610
|
+
* Decodes one chunk for {@link MineRenderWorld.placeChunk}.
|
|
15611
|
+
* @param localX - Chunk x within the region, from 0 to 31.
|
|
15612
|
+
* @param localZ - Chunk z within the region, from 0 to 31.
|
|
15613
|
+
* @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
|
|
15614
|
+
*/
|
|
14981
15615
|
static async parseChunk(data, localX, localZ) {
|
|
14982
15616
|
if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
|
|
14983
15617
|
throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
|
|
@@ -15182,6 +15816,7 @@ var SectionModels = class {
|
|
|
15182
15816
|
this.templates = /* @__PURE__ */ new Set();
|
|
15183
15817
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
15184
15818
|
}
|
|
15819
|
+
/** Returns a cube template, or `undefined` when the block requires an individual render object. */
|
|
15185
15820
|
async get(blockState, properties = {}) {
|
|
15186
15821
|
if (!blockState.variants || blockState.multipart) return void 0;
|
|
15187
15822
|
let states = this.states.get(blockState);
|
|
@@ -15210,16 +15845,16 @@ var SectionModels = class {
|
|
|
15210
15845
|
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
15211
15846
|
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
15212
15847
|
const template = await cached(models, key, async () => {
|
|
15213
|
-
const
|
|
15848
|
+
const object3 = new SectionModel(model, {
|
|
15214
15849
|
instanceMeshes: false,
|
|
15215
15850
|
mergeMeshes: false,
|
|
15216
15851
|
tints,
|
|
15217
15852
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
15218
15853
|
});
|
|
15219
|
-
await
|
|
15220
|
-
const geometry =
|
|
15854
|
+
await object3.init();
|
|
15855
|
+
const geometry = object3.children[0].geometry;
|
|
15221
15856
|
geometry.applyMatrix4(new Matrix412().makeRotationFromEuler(rotation));
|
|
15222
|
-
|
|
15857
|
+
object3.clear();
|
|
15223
15858
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
15224
15859
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
15225
15860
|
if (local < 0) return 0;
|
|
@@ -15235,6 +15870,7 @@ var SectionModels = class {
|
|
|
15235
15870
|
}
|
|
15236
15871
|
return { variants, templates };
|
|
15237
15872
|
}
|
|
15873
|
+
/** Disposes prepared geometry and clears this world's template caches. */
|
|
15238
15874
|
clear() {
|
|
15239
15875
|
for (const template of this.templates) template.geometry.dispose();
|
|
15240
15876
|
this.templates.clear();
|
|
@@ -15285,6 +15921,13 @@ var MineRenderWorld = class {
|
|
|
15285
15921
|
this.validatePosBounds(posOrX);
|
|
15286
15922
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
15287
15923
|
}
|
|
15924
|
+
/**
|
|
15925
|
+
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
15926
|
+
* Entity NBT is retained by the structure but is not rendered.
|
|
15927
|
+
*
|
|
15928
|
+
* @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
|
|
15929
|
+
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
15930
|
+
*/
|
|
15288
15931
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
15289
15932
|
const changes = /* @__PURE__ */ new Map();
|
|
15290
15933
|
try {
|
|
@@ -15381,6 +16024,7 @@ var MineRenderWorld = class {
|
|
|
15381
16024
|
});
|
|
15382
16025
|
}
|
|
15383
16026
|
}
|
|
16027
|
+
/** Removes all chunks and releases their block placements and section meshes. */
|
|
15384
16028
|
async clear() {
|
|
15385
16029
|
await this.culling;
|
|
15386
16030
|
const chunks = [...this._chunks.values()];
|
|
@@ -15426,10 +16070,10 @@ var MineRenderWorld = class {
|
|
|
15426
16070
|
await block.object.updateFluid((x, y, z) => {
|
|
15427
16071
|
const neighbor = pos.clone().add(new Vector316(x, y, z));
|
|
15428
16072
|
const section = this.getChunkAt(neighbor);
|
|
15429
|
-
const
|
|
16073
|
+
const object3 = section?.isBlockVisibleAt(neighbor) ? section.getBlockAt(neighbor)?.object : void 0;
|
|
15430
16074
|
return {
|
|
15431
|
-
fluid:
|
|
15432
|
-
level:
|
|
16075
|
+
fluid: object3?.fluidKind,
|
|
16076
|
+
level: object3?.fluidLevel,
|
|
15433
16077
|
solid: section?.isOccludingAt(neighbor) ?? false
|
|
15434
16078
|
};
|
|
15435
16079
|
});
|
|
@@ -15466,9 +16110,11 @@ var MineRenderWorld = class {
|
|
|
15466
16110
|
}
|
|
15467
16111
|
return chunk;
|
|
15468
16112
|
}
|
|
16113
|
+
/** Returns the loaded chunk containing a world block position, without creating a chunk. */
|
|
15469
16114
|
getChunkAt(pos) {
|
|
15470
16115
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
15471
16116
|
}
|
|
16117
|
+
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
15472
16118
|
static worldToScenePosition(pos) {
|
|
15473
16119
|
return new Vector316(
|
|
15474
16120
|
pos.x * 16,
|
|
@@ -15476,6 +16122,7 @@ var MineRenderWorld = class {
|
|
|
15476
16122
|
pos.z * 16
|
|
15477
16123
|
);
|
|
15478
16124
|
}
|
|
16125
|
+
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
15479
16126
|
static sceneToWorldPosition(pos) {
|
|
15480
16127
|
return new Vector316(
|
|
15481
16128
|
pos.x / 16,
|
|
@@ -15502,12 +16149,13 @@ init_Model();
|
|
|
15502
16149
|
// src/world/SectionMesh.ts
|
|
15503
16150
|
init_CanvasCompat();
|
|
15504
16151
|
init_Materials();
|
|
15505
|
-
import { BufferGeometry as BufferGeometry8, Float32BufferAttribute as Float32BufferAttribute8, Group as
|
|
15506
|
-
var SectionMesh = class _SectionMesh extends
|
|
16152
|
+
import { BufferGeometry as BufferGeometry8, Float32BufferAttribute as Float32BufferAttribute8, Group as Group3, Mesh as Mesh9 } from "three";
|
|
16153
|
+
var SectionMesh = class _SectionMesh extends Group3 {
|
|
15507
16154
|
constructor() {
|
|
15508
16155
|
super(...arguments);
|
|
15509
16156
|
this.ownedMeshes = [];
|
|
15510
16157
|
}
|
|
16158
|
+
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
15511
16159
|
static build(entries, maxAtlasSize = 2048) {
|
|
15512
16160
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
15513
16161
|
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
@@ -15555,7 +16203,7 @@ var SectionMesh = class _SectionMesh extends Group2 {
|
|
|
15555
16203
|
const normal = template.geometry.getAttribute("normal");
|
|
15556
16204
|
const uv = template.geometry.getAttribute("uv");
|
|
15557
16205
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
15558
|
-
const
|
|
16206
|
+
const color2 = template.geometry.getAttribute("color");
|
|
15559
16207
|
const sourceIndices = template.geometry.getIndex();
|
|
15560
16208
|
const placement = locations.get(template.atlas).placement;
|
|
15561
16209
|
const mapU = (u) => (placement.x + u * template.atlas.image.width) / page.width;
|
|
@@ -15577,7 +16225,7 @@ var SectionMesh = class _SectionMesh extends Group2 {
|
|
|
15577
16225
|
mapU(bounds?.getZ(vertex) ?? 1),
|
|
15578
16226
|
mapV(bounds?.getW(vertex) ?? 1)
|
|
15579
16227
|
);
|
|
15580
|
-
colors.push(
|
|
16228
|
+
colors.push(color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1);
|
|
15581
16229
|
}
|
|
15582
16230
|
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
15583
16231
|
}
|
|
@@ -15652,7 +16300,7 @@ var Chunk = class _Chunk {
|
|
|
15652
16300
|
return this.setBlockInChunkAt(pos, block, worldPos);
|
|
15653
16301
|
}
|
|
15654
16302
|
/**
|
|
15655
|
-
*
|
|
16303
|
+
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
15656
16304
|
*/
|
|
15657
16305
|
async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
|
|
15658
16306
|
if (typeof worldPos === "undefined") {
|
|
@@ -15665,7 +16313,7 @@ var Chunk = class _Chunk {
|
|
|
15665
16313
|
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
15666
16314
|
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
15667
16315
|
this.renderedBlocks.delete(index);
|
|
15668
|
-
let
|
|
16316
|
+
let object3;
|
|
15669
16317
|
try {
|
|
15670
16318
|
if (!readBlock) return void 0;
|
|
15671
16319
|
const stored = readBlock();
|
|
@@ -15680,27 +16328,28 @@ var Chunk = class _Chunk {
|
|
|
15680
16328
|
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
15681
16329
|
this.meshDirty = true;
|
|
15682
16330
|
} else {
|
|
15683
|
-
|
|
16331
|
+
object3 = await this.scene.addBlock(blockState, {
|
|
15684
16332
|
mergeMeshes: true,
|
|
15685
16333
|
instanceMeshes: true,
|
|
15686
16334
|
maxInstanceCount: 2e3,
|
|
15687
16335
|
initialState: stored.properties
|
|
15688
16336
|
});
|
|
15689
|
-
|
|
16337
|
+
object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
15690
16338
|
}
|
|
15691
16339
|
const info = { get block() {
|
|
15692
16340
|
return readBlock();
|
|
15693
|
-
}, object:
|
|
16341
|
+
}, object: object3 };
|
|
15694
16342
|
this.renderedBlocks.set(index, info);
|
|
15695
16343
|
return info;
|
|
15696
16344
|
} catch (error) {
|
|
15697
16345
|
this.data.set(index, void 0);
|
|
15698
|
-
|
|
16346
|
+
object3?.removeFromScene();
|
|
15699
16347
|
throw error;
|
|
15700
16348
|
} finally {
|
|
15701
16349
|
await onBlocksChanged?.([worldPos]);
|
|
15702
16350
|
}
|
|
15703
16351
|
}
|
|
16352
|
+
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
15704
16353
|
async setBlockVisibleAt(pos, visible) {
|
|
15705
16354
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
15706
16355
|
const block = this.renderedBlocks.get(index);
|
|
@@ -15754,6 +16403,7 @@ var Chunk = class _Chunk {
|
|
|
15754
16403
|
this.scene.dirty = true;
|
|
15755
16404
|
this.meshDirty = false;
|
|
15756
16405
|
}
|
|
16406
|
+
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
15757
16407
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
15758
16408
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
15759
16409
|
new Vector317(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
@@ -15774,6 +16424,7 @@ var Chunk = class _Chunk {
|
|
|
15774
16424
|
static isAir(block) {
|
|
15775
16425
|
return ChunkData.isAir(block);
|
|
15776
16426
|
}
|
|
16427
|
+
/** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
|
|
15777
16428
|
static chunkPosToBlockIndex(pos) {
|
|
15778
16429
|
if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
|
|
15779
16430
|
throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");
|
|
@@ -15875,6 +16526,7 @@ export {
|
|
|
15875
16526
|
RequestError,
|
|
15876
16527
|
Requests,
|
|
15877
16528
|
SKIN_PARTS,
|
|
16529
|
+
SceneDocumentLoader,
|
|
15878
16530
|
SceneExporter,
|
|
15879
16531
|
SceneInspector,
|
|
15880
16532
|
SceneObject,
|
|
@@ -15950,6 +16602,7 @@ export {
|
|
|
15950
16602
|
mergeBufferAttributes,
|
|
15951
16603
|
mergeBufferGeometries,
|
|
15952
16604
|
mergeVertices,
|
|
16605
|
+
parseSceneDocument,
|
|
15953
16606
|
prefix,
|
|
15954
16607
|
registerNodeEnv,
|
|
15955
16608
|
sampleEntityAnimation,
|