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/browser/index.js
CHANGED
|
@@ -65,6 +65,7 @@ var init_PersistentCache = __esm({
|
|
|
65
65
|
constructor(backing) {
|
|
66
66
|
this.backing = backing;
|
|
67
67
|
}
|
|
68
|
+
/** Opens a named store in the active environment using the current cache schema version. */
|
|
68
69
|
static open(name) {
|
|
69
70
|
return Env.provider.openCache(name, _PersistentCache.VERSION);
|
|
70
71
|
}
|
|
@@ -263,6 +264,7 @@ var init_Caching = __esm({
|
|
|
263
264
|
this.fontCache
|
|
264
265
|
];
|
|
265
266
|
}
|
|
267
|
+
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
266
268
|
static clear() {
|
|
267
269
|
for (const cache of this.all) {
|
|
268
270
|
cache.invalidateAll();
|
|
@@ -328,6 +330,7 @@ var init_Geometries = __esm({
|
|
|
328
330
|
}
|
|
329
331
|
return geometry;
|
|
330
332
|
}
|
|
333
|
+
/** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
|
|
331
334
|
static getBox(key) {
|
|
332
335
|
const keyStr = serializeBoxGeometryKey(key);
|
|
333
336
|
return Caching.boxGeometryCache.get(keyStr, (k) => {
|
|
@@ -505,12 +508,15 @@ var init_Requests = __esm({
|
|
|
505
508
|
}
|
|
506
509
|
};
|
|
507
510
|
Requests = class {
|
|
511
|
+
/** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
|
|
508
512
|
static genericRequest(request) {
|
|
509
513
|
return this.genericQueue.request(request);
|
|
510
514
|
}
|
|
515
|
+
/** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
|
|
511
516
|
static mcAssetRequest(request) {
|
|
512
517
|
return this.mcAssetRequestQueue.request(request);
|
|
513
518
|
}
|
|
519
|
+
/** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
|
|
514
520
|
static setMcAssetRoot(root) {
|
|
515
521
|
this.mcAssetRequestQueue.baseURL = root;
|
|
516
522
|
}
|
|
@@ -565,6 +571,7 @@ var init_WrappedImage = __esm({
|
|
|
565
571
|
}
|
|
566
572
|
return false;
|
|
567
573
|
}
|
|
574
|
+
/** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
|
|
568
575
|
get animated() {
|
|
569
576
|
return this.height > this.width && this.height % this.width === 0;
|
|
570
577
|
}
|
|
@@ -611,6 +618,7 @@ var init_ImageLoader = __esm({
|
|
|
611
618
|
static _createImage() {
|
|
612
619
|
return createImage();
|
|
613
620
|
}
|
|
621
|
+
/** Resolves when an image URL has decoded, or rejects if decoding fails. */
|
|
614
622
|
static async loadAsync(src) {
|
|
615
623
|
return new Promise((resolve, reject) => {
|
|
616
624
|
const image = this._createImage();
|
|
@@ -619,6 +627,7 @@ var init_ImageLoader = __esm({
|
|
|
619
627
|
image.src = src;
|
|
620
628
|
});
|
|
621
629
|
}
|
|
630
|
+
/** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
|
|
622
631
|
static loadElement(src, onload, onerr) {
|
|
623
632
|
const image = this._createImage();
|
|
624
633
|
if (onload)
|
|
@@ -646,6 +655,7 @@ var init_ImageLoader = __esm({
|
|
|
646
655
|
throw err;
|
|
647
656
|
}
|
|
648
657
|
}
|
|
658
|
+
/** Decodes the supplied bytes into a canvas without fetching the source URL again. */
|
|
649
659
|
static async infoToCanvasData(info) {
|
|
650
660
|
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
651
661
|
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
@@ -662,12 +672,14 @@ var init_ImageLoader = __esm({
|
|
|
662
672
|
const image = await this.infoToCanvasData(info);
|
|
663
673
|
return image.data.getImageData(0, 0, image.width, image.height);
|
|
664
674
|
}
|
|
675
|
+
/** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
|
|
665
676
|
static async getData(src) {
|
|
666
677
|
const keyStr = serializeImageKey({ src });
|
|
667
678
|
return await Caching.imageDataCache.get(keyStr, (k) => {
|
|
668
679
|
return _ImageLoader.loadData(src);
|
|
669
680
|
});
|
|
670
681
|
}
|
|
682
|
+
/** Returns a cached canvas context and dimensions for an image URL or data URL. */
|
|
671
683
|
static async getCanvasData(src) {
|
|
672
684
|
const keyStr = serializeImageKey({ src });
|
|
673
685
|
return await Caching.canvasImageDataCache.get(keyStr, (k) => {
|
|
@@ -764,6 +776,7 @@ var init_TextureLoader = __esm({
|
|
|
764
776
|
texture.rotation = rotation;
|
|
765
777
|
return Textures.initTextureProps(texture);
|
|
766
778
|
}
|
|
779
|
+
/** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
|
|
767
780
|
static load(src, format2 = import_three3.RGBAFormat, rotation = 0) {
|
|
768
781
|
const texture = new import_three3.Texture();
|
|
769
782
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
@@ -801,8 +814,8 @@ var init_Textures = __esm({
|
|
|
801
814
|
for (let y = 0; y < size; y++) {
|
|
802
815
|
for (let x = 0; x < size; x++) {
|
|
803
816
|
const offset = (y * size + x) * 4;
|
|
804
|
-
const
|
|
805
|
-
data[offset] = data[offset + 2] =
|
|
817
|
+
const color2 = (x + y) % 2 === 0 ? 255 : 0;
|
|
818
|
+
data[offset] = data[offset + 2] = color2;
|
|
806
819
|
data[offset + 3] = 255;
|
|
807
820
|
}
|
|
808
821
|
}
|
|
@@ -813,6 +826,7 @@ var init_Textures = __esm({
|
|
|
813
826
|
return this.initTextureProps(texture);
|
|
814
827
|
});
|
|
815
828
|
}
|
|
829
|
+
/** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
|
|
816
830
|
static initTextureProps(texture) {
|
|
817
831
|
texture.magFilter = THREE2.NearestFilter;
|
|
818
832
|
texture.minFilter = THREE2.NearestFilter;
|
|
@@ -825,11 +839,13 @@ var init_Textures = __esm({
|
|
|
825
839
|
static createAsset(key) {
|
|
826
840
|
return new import_three4.Texture();
|
|
827
841
|
}
|
|
842
|
+
/** Creates an sRGB color texture from a canvas. */
|
|
828
843
|
static createCanvasTexture(canvas) {
|
|
829
844
|
const texture = new import_three4.CanvasTexture(canvas);
|
|
830
845
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
831
846
|
return this.initTextureProps(texture);
|
|
832
847
|
}
|
|
848
|
+
/** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
|
|
833
849
|
static getImage(key) {
|
|
834
850
|
const keyStr = serializeTextureKey(key);
|
|
835
851
|
const cached2 = Caching.textureCache.peek(keyStr);
|
|
@@ -854,6 +870,7 @@ var init_Materials = __esm({
|
|
|
854
870
|
init_TextureLoader();
|
|
855
871
|
init_Caching();
|
|
856
872
|
Materials = class _Materials {
|
|
873
|
+
/** Shared checkerboard material, created on first access. */
|
|
857
874
|
static get MISSING_TEXTURE() {
|
|
858
875
|
return Caching.materialCache.get("builtin:missing-texture", () => new import_three5.MeshBasicMaterial({
|
|
859
876
|
map: Textures.getMissing(),
|
|
@@ -957,6 +974,7 @@ var init_Materials = __esm({
|
|
|
957
974
|
if (tint !== void 0) material.color.multiply(new import_three5.Color(tint));
|
|
958
975
|
return material;
|
|
959
976
|
}
|
|
977
|
+
/** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
|
|
960
978
|
static createGuiCanvasMaterial(canvas) {
|
|
961
979
|
const material = new import_three5.MeshBasicMaterial({
|
|
962
980
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -1123,6 +1141,7 @@ var init_Materials = __esm({
|
|
|
1123
1141
|
}
|
|
1124
1142
|
return this.createBasicCanvasMaterial(canvas, transparent, shade);
|
|
1125
1143
|
}
|
|
1144
|
+
/** Returns a shared image material. Use {@link createImage} for a separate material instance. */
|
|
1126
1145
|
static getImage(key) {
|
|
1127
1146
|
const keyStr = serializeMaterialKey(key);
|
|
1128
1147
|
const map = Caching.materialCache.peek(keyStr)?.map;
|
|
@@ -1297,6 +1316,14 @@ var init_AssetKey = __esm({
|
|
|
1297
1316
|
}
|
|
1298
1317
|
};
|
|
1299
1318
|
AssetKey = class _AssetKey extends BasicAssetKey {
|
|
1319
|
+
/**
|
|
1320
|
+
* Creates a key from separate path components. Use {@link parse} for a combined reference.
|
|
1321
|
+
*
|
|
1322
|
+
* @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
|
|
1323
|
+
* @param type - Subdirectory, such as `block` or `item`.
|
|
1324
|
+
* @param rootType - Top-level directory, usually `assets` or `data`.
|
|
1325
|
+
* @param root - Base URL override for hosted asset sources.
|
|
1326
|
+
*/
|
|
1300
1327
|
constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
|
|
1301
1328
|
super(namespace, path);
|
|
1302
1329
|
this.namespace = namespace;
|
|
@@ -1308,6 +1335,16 @@ var init_AssetKey = __esm({
|
|
|
1308
1335
|
this.root = root;
|
|
1309
1336
|
this.isAssetKey = true;
|
|
1310
1337
|
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Parses an asset reference such as `minecraft:block/stone`.
|
|
1340
|
+
* A missing namespace defaults to the origin's namespace or `minecraft`.
|
|
1341
|
+
*
|
|
1342
|
+
* @param assetType - Asset category, such as `models` or `textures`.
|
|
1343
|
+
* @param str - Path with an optional namespace and file extension.
|
|
1344
|
+
* @param origin - Supplies the asset root, default namespace, and non-texture extension.
|
|
1345
|
+
* @returns A key with the matching extension removed from its path. Textures use `.png`;
|
|
1346
|
+
* other assets use the origin's extension or `.json`.
|
|
1347
|
+
*/
|
|
1311
1348
|
static parse(assetType, str, origin) {
|
|
1312
1349
|
let namespace = origin?.namespace || DEFAULT_NAMESPACE;
|
|
1313
1350
|
if (str.includes(":")) {
|
|
@@ -1339,6 +1376,7 @@ var init_AssetKey = __esm({
|
|
|
1339
1376
|
];
|
|
1340
1377
|
return a.join("/");
|
|
1341
1378
|
}
|
|
1379
|
+
/** Joins the type subdirectory and path without adding a namespace or file extension. */
|
|
1342
1380
|
getFullPath() {
|
|
1343
1381
|
let p10 = [];
|
|
1344
1382
|
if (this.type) {
|
|
@@ -1350,6 +1388,7 @@ var init_AssetKey = __esm({
|
|
|
1350
1388
|
toNamespacedString() {
|
|
1351
1389
|
return this.namespace + ":" + this.getFullPath();
|
|
1352
1390
|
}
|
|
1391
|
+
/** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
|
|
1353
1392
|
serialize() {
|
|
1354
1393
|
return this.toString();
|
|
1355
1394
|
}
|
|
@@ -1361,17 +1400,17 @@ var init_AssetKey = __esm({
|
|
|
1361
1400
|
var DisplayPosition, DISPLAY_POSITIONS;
|
|
1362
1401
|
var init_DisplayPosition = __esm({
|
|
1363
1402
|
"src/model/DisplayPosition.ts"() {
|
|
1364
|
-
DisplayPosition = /* @__PURE__ */ ((
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
return
|
|
1403
|
+
DisplayPosition = /* @__PURE__ */ ((DisplayPosition3) => {
|
|
1404
|
+
DisplayPosition3["THIRDPERSON_RIGHTHAND"] = "thirdperson_righthand";
|
|
1405
|
+
DisplayPosition3["THIRDPERSON_LEFTHAND"] = "thirdperson_lefthand";
|
|
1406
|
+
DisplayPosition3["FIRSTPERSON_RIGHTHAND"] = "firstperson_righthand";
|
|
1407
|
+
DisplayPosition3["FIRSTPERSON_LEFTHAND"] = "firstperson_lefthand";
|
|
1408
|
+
DisplayPosition3["GUI"] = "gui";
|
|
1409
|
+
DisplayPosition3["HEAD"] = "head";
|
|
1410
|
+
DisplayPosition3["GROUND"] = "ground";
|
|
1411
|
+
DisplayPosition3["FIXED"] = "fixed";
|
|
1412
|
+
DisplayPosition3["ON_SHELF"] = "on_shelf";
|
|
1413
|
+
return DisplayPosition3;
|
|
1375
1414
|
})(DisplayPosition || {});
|
|
1376
1415
|
DISPLAY_POSITIONS = Object.values(DisplayPosition);
|
|
1377
1416
|
}
|
|
@@ -1409,6 +1448,7 @@ var init_DisplayTransforms = __esm({
|
|
|
1409
1448
|
const scale = new import_three7.Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
|
|
1410
1449
|
return new import_three7.Matrix4().compose(translation, rotation, scale);
|
|
1411
1450
|
}
|
|
1451
|
+
/** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
|
|
1412
1452
|
static apply(geometry, matrix) {
|
|
1413
1453
|
geometry.applyMatrix4(matrix);
|
|
1414
1454
|
if (matrix.determinant() < 0) {
|
|
@@ -1436,6 +1476,7 @@ var init_ModelMerger = __esm({
|
|
|
1436
1476
|
init_AssetKey();
|
|
1437
1477
|
init_DisplayTransforms();
|
|
1438
1478
|
ModelMerger = class {
|
|
1479
|
+
/** Loads the parent chain and returns a merged model without modifying the supplied definition. */
|
|
1439
1480
|
static async mergeWithParents(model) {
|
|
1440
1481
|
const models = await this.collectAllParents(model);
|
|
1441
1482
|
let merged = {};
|
|
@@ -1503,6 +1544,7 @@ var init_Models = __esm({
|
|
|
1503
1544
|
static get PERSISTENT_CACHE() {
|
|
1504
1545
|
return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
|
|
1505
1546
|
}
|
|
1547
|
+
/** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
|
|
1506
1548
|
static async getItemList() {
|
|
1507
1549
|
const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
|
|
1508
1550
|
const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
|
|
@@ -1573,6 +1615,7 @@ var init_Models = __esm({
|
|
|
1573
1615
|
}
|
|
1574
1616
|
throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
|
|
1575
1617
|
}
|
|
1618
|
+
/** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
|
|
1576
1619
|
static async getRaw(key) {
|
|
1577
1620
|
if (!key.assetType) {
|
|
1578
1621
|
key.assetType = "models";
|
|
@@ -1585,13 +1628,19 @@ var init_Models = __esm({
|
|
|
1585
1628
|
return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
1586
1629
|
return AssetLoader.get(key, "model" /* MODEL */);
|
|
1587
1630
|
});
|
|
1588
|
-
}).then((
|
|
1589
|
-
if (
|
|
1590
|
-
|
|
1631
|
+
}).then((asset2) => {
|
|
1632
|
+
if (asset2) {
|
|
1633
|
+
asset2.key = key;
|
|
1591
1634
|
}
|
|
1592
|
-
return
|
|
1635
|
+
return asset2;
|
|
1593
1636
|
});
|
|
1594
1637
|
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
|
|
1640
|
+
* Item keys use GUI context, false conditions, and zero numeric properties.
|
|
1641
|
+
*
|
|
1642
|
+
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
1643
|
+
*/
|
|
1595
1644
|
static async getMerged(key) {
|
|
1596
1645
|
if (!key.assetType) {
|
|
1597
1646
|
key.assetType = "models";
|
|
@@ -1604,9 +1653,11 @@ var init_Models = __esm({
|
|
|
1604
1653
|
return _Models.loadAndMerge(key);
|
|
1605
1654
|
});
|
|
1606
1655
|
}
|
|
1656
|
+
/** Alias for {@link getMerged}. */
|
|
1607
1657
|
static async get(key) {
|
|
1608
1658
|
return this.getMerged(key);
|
|
1609
1659
|
}
|
|
1660
|
+
/** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1610
1661
|
static async clearCache() {
|
|
1611
1662
|
return this.PERSISTENT_CACHE.clear();
|
|
1612
1663
|
}
|
|
@@ -1629,6 +1680,7 @@ var init_BlockStates = __esm({
|
|
|
1629
1680
|
return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
|
|
1630
1681
|
}
|
|
1631
1682
|
// BlockState names are hardcoded
|
|
1683
|
+
/** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
|
|
1632
1684
|
static async getList() {
|
|
1633
1685
|
const key = new AssetKey(
|
|
1634
1686
|
DEFAULT_NAMESPACE,
|
|
@@ -1649,6 +1701,7 @@ var init_BlockStates = __esm({
|
|
|
1649
1701
|
return AssetLoader.get(key, "json" /* JSON */);
|
|
1650
1702
|
});
|
|
1651
1703
|
}
|
|
1704
|
+
/** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
|
|
1652
1705
|
static async getDefaultState(key) {
|
|
1653
1706
|
const defaultStates = await this.getDefaultStates();
|
|
1654
1707
|
if (!defaultStates) {
|
|
@@ -1656,6 +1709,7 @@ var init_BlockStates = __esm({
|
|
|
1656
1709
|
}
|
|
1657
1710
|
return defaultStates["minecraft:" + key.path];
|
|
1658
1711
|
}
|
|
1712
|
+
/** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
|
|
1659
1713
|
static async get(key) {
|
|
1660
1714
|
if (!key.assetType) {
|
|
1661
1715
|
key.assetType = "blockstates";
|
|
@@ -1668,11 +1722,11 @@ var init_BlockStates = __esm({
|
|
|
1668
1722
|
return this.PERSISTENT_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
1669
1723
|
return AssetLoader.get(key, "blockstate" /* BLOCKSTATE */);
|
|
1670
1724
|
});
|
|
1671
|
-
}).then((
|
|
1672
|
-
if (
|
|
1673
|
-
|
|
1725
|
+
}).then((asset2) => {
|
|
1726
|
+
if (asset2) {
|
|
1727
|
+
asset2.key = key;
|
|
1674
1728
|
}
|
|
1675
|
-
return
|
|
1729
|
+
return asset2;
|
|
1676
1730
|
});
|
|
1677
1731
|
}
|
|
1678
1732
|
static getAll(keys) {
|
|
@@ -1682,6 +1736,7 @@ var init_BlockStates = __esm({
|
|
|
1682
1736
|
}
|
|
1683
1737
|
return Promise.all(promises);
|
|
1684
1738
|
}
|
|
1739
|
+
/** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1685
1740
|
static async clearCache() {
|
|
1686
1741
|
await this.PERSISTENT_CACHE.clear();
|
|
1687
1742
|
}
|
|
@@ -1707,9 +1762,11 @@ var init_Assets = __esm({
|
|
|
1707
1762
|
static parseAssetKey(assetType, str, origin) {
|
|
1708
1763
|
return AssetKey.parse(assetType, str, origin);
|
|
1709
1764
|
}
|
|
1765
|
+
/** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
|
|
1710
1766
|
static async getModel(key) {
|
|
1711
1767
|
return Models.getMerged(key);
|
|
1712
1768
|
}
|
|
1769
|
+
/** Loads a blockstate definition. See {@link BlockStates.get}. */
|
|
1713
1770
|
static async getBlockState(key) {
|
|
1714
1771
|
return BlockStates.get(key);
|
|
1715
1772
|
}
|
|
@@ -1756,6 +1813,10 @@ var init_BatchedExecutor = __esm({
|
|
|
1756
1813
|
"src/util/BatchedExecutor.ts"() {
|
|
1757
1814
|
import_jobqu2 = require("jobqu");
|
|
1758
1815
|
BatchedExecutor = class {
|
|
1816
|
+
/**
|
|
1817
|
+
* @param interval - Delay between queue runs, in milliseconds.
|
|
1818
|
+
* @param batch - Maximum tasks started per run and maximum tasks active at once.
|
|
1819
|
+
*/
|
|
1759
1820
|
constructor(interval = 1, batch = 30) {
|
|
1760
1821
|
if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
|
|
1761
1822
|
if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
|
|
@@ -1763,9 +1824,11 @@ var init_BatchedExecutor = __esm({
|
|
|
1763
1824
|
this.batch = batch;
|
|
1764
1825
|
this.queue = new import_jobqu2.JobQueue(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
|
|
1765
1826
|
}
|
|
1827
|
+
/** Queues a task and resolves with its result, or rejects with its error. */
|
|
1766
1828
|
submit(task) {
|
|
1767
1829
|
return this.queue.add(() => task());
|
|
1768
1830
|
}
|
|
1831
|
+
/** Rejects queued and future tasks. Tasks already running are allowed to finish. */
|
|
1769
1832
|
stop() {
|
|
1770
1833
|
this.queue.end();
|
|
1771
1834
|
}
|
|
@@ -1812,29 +1875,29 @@ function applyGenericRotation(axis, rotation, obj) {
|
|
|
1812
1875
|
break;
|
|
1813
1876
|
}
|
|
1814
1877
|
}
|
|
1815
|
-
function addBox3WireframeToObject(box, obj,
|
|
1878
|
+
function addBox3WireframeToObject(box, obj, color2 = 16777215, w = 2) {
|
|
1816
1879
|
let size = new import_three8.Vector3();
|
|
1817
1880
|
box.getSize(size);
|
|
1818
1881
|
let boxGeo = new import_three8.BoxGeometry(size.x, size.y, size.z, 1, 1, 1);
|
|
1819
1882
|
let wireGeo = new import_three8.EdgesGeometry(boxGeo);
|
|
1820
|
-
let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
|
|
1883
|
+
let wireMat = new import_three8.LineBasicMaterial({ color: color2, linewidth: w });
|
|
1821
1884
|
let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
|
|
1822
1885
|
obj.add(wireframe);
|
|
1823
1886
|
let axes = new import_three8.AxesHelper(1);
|
|
1824
1887
|
obj.add(axes);
|
|
1825
1888
|
}
|
|
1826
|
-
function addWireframeToObject(obj,
|
|
1889
|
+
function addWireframeToObject(obj, color2 = 16777215, w = 2) {
|
|
1827
1890
|
let boxGeo = new import_three8.BoxGeometry(16, 16, 16, 1, 1, 1);
|
|
1828
1891
|
let wireGeo = new import_three8.EdgesGeometry(boxGeo);
|
|
1829
|
-
let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
|
|
1892
|
+
let wireMat = new import_three8.LineBasicMaterial({ color: color2, linewidth: w });
|
|
1830
1893
|
let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
|
|
1831
1894
|
obj.add(wireframe);
|
|
1832
1895
|
let axes = new import_three8.AxesHelper(1);
|
|
1833
1896
|
obj.add(axes);
|
|
1834
1897
|
}
|
|
1835
|
-
function addWireframeToMesh(geo, mesh,
|
|
1898
|
+
function addWireframeToMesh(geo, mesh, color2 = 16777215, w = 2) {
|
|
1836
1899
|
let wireGeo = new import_three8.EdgesGeometry(geo);
|
|
1837
|
-
let wireMat = new import_three8.LineBasicMaterial({ color, linewidth: w });
|
|
1900
|
+
let wireMat = new import_three8.LineBasicMaterial({ color: color2, linewidth: w });
|
|
1838
1901
|
let wireframe = new import_three8.LineSegments(wireGeo, wireMat);
|
|
1839
1902
|
mesh.add(wireframe);
|
|
1840
1903
|
let axes = new import_three8.AxesHelper(1);
|
|
@@ -1908,6 +1971,7 @@ var init_NBTHelper = __esm({
|
|
|
1908
1971
|
"src/nbt/NBTHelper.ts"() {
|
|
1909
1972
|
import_buffer2 = require("buffer");
|
|
1910
1973
|
NBTHelper = class {
|
|
1974
|
+
/** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
|
|
1911
1975
|
static async fromBuffer(data, format2) {
|
|
1912
1976
|
const buffer = import_buffer2.Buffer.from(data instanceof Uint8Array ? data : new Uint8Array(data));
|
|
1913
1977
|
const prismarineNbt = await import("prismarine-nbt");
|
|
@@ -1976,6 +2040,7 @@ var init_HostedAssetSource = __esm({
|
|
|
1976
2040
|
retryDefaults: true
|
|
1977
2041
|
};
|
|
1978
2042
|
_HostedAssetSource = class _HostedAssetSource extends AssetSource {
|
|
2043
|
+
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
1979
2044
|
async loadOrRetryWithDefaults(key, parser) {
|
|
1980
2045
|
const direct = await this.load(key, parser);
|
|
1981
2046
|
if (typeof direct !== "undefined") {
|
|
@@ -2033,6 +2098,10 @@ var init_HostedAssetSource = __esm({
|
|
|
2033
2098
|
assetBasePath(key) {
|
|
2034
2099
|
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 + "/" : ""}`;
|
|
2035
2100
|
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Creates a hosted source for {@link AssetLoader.addSource}.
|
|
2103
|
+
* Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
|
|
2104
|
+
*/
|
|
2036
2105
|
constructor(root, options) {
|
|
2037
2106
|
super();
|
|
2038
2107
|
this._root = root;
|
|
@@ -2125,6 +2194,11 @@ var init_BrowserArchiveProxy = __esm({
|
|
|
2125
2194
|
"src/assets/source/archive/BrowserArchiveProxy.ts"() {
|
|
2126
2195
|
import_zip = require("@zip.js/zip.js");
|
|
2127
2196
|
BrowserArchiveProxy = class {
|
|
2197
|
+
/**
|
|
2198
|
+
* Opens a ZIP for asset lookup.
|
|
2199
|
+
* @param id - Cache identity for this content. Change it when the pack changes.
|
|
2200
|
+
* A File supplies an identity from its name, size, and modification time when omitted.
|
|
2201
|
+
*/
|
|
2128
2202
|
constructor(blob, id) {
|
|
2129
2203
|
this._blob = blob;
|
|
2130
2204
|
this._reader = new import_zip.ZipReader(new import_zip.BlobReader(this._blob));
|
|
@@ -2254,27 +2328,27 @@ var init_PackFormats = __esm({
|
|
|
2254
2328
|
init_Requests();
|
|
2255
2329
|
PackFormats = class {
|
|
2256
2330
|
/** Resolves pack formats from Mojang's client metadata hosted on assets.mcasset.cloud. */
|
|
2257
|
-
static async get(
|
|
2258
|
-
let pending = this.versions.get(
|
|
2331
|
+
static async get(version2, type) {
|
|
2332
|
+
let pending = this.versions.get(version2);
|
|
2259
2333
|
if (!pending || pending.expires <= Date.now()) {
|
|
2260
2334
|
pending = {
|
|
2261
|
-
formats: this.load(
|
|
2262
|
-
expires: ["latest", "release", "snapshot"].includes(
|
|
2335
|
+
formats: this.load(version2),
|
|
2336
|
+
expires: ["latest", "release", "snapshot"].includes(version2) ? Date.now() + 3e5 : Infinity
|
|
2263
2337
|
};
|
|
2264
|
-
this.versions.set(
|
|
2338
|
+
this.versions.set(version2, pending);
|
|
2265
2339
|
}
|
|
2266
2340
|
try {
|
|
2267
2341
|
return (await pending.formats)[type];
|
|
2268
2342
|
} catch (cause) {
|
|
2269
|
-
if (this.versions.get(
|
|
2343
|
+
if (this.versions.get(version2) === pending) this.versions.delete(version2);
|
|
2270
2344
|
const option = type === "assets" ? "resourcePackFormat" : "dataPackFormat";
|
|
2271
2345
|
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
2272
|
-
throw new Error(`Could not resolve the pack format for Minecraft ${
|
|
2346
|
+
throw new Error(`Could not resolve the pack format for Minecraft ${version2}. Set ArchiveAssetSource ${option} explicitly. ${reason}`);
|
|
2273
2347
|
}
|
|
2274
2348
|
}
|
|
2275
|
-
static async load(
|
|
2349
|
+
static async load(version2) {
|
|
2276
2350
|
const response = await Requests.genericRequest({
|
|
2277
|
-
url: `https://assets.mcasset.cloud/${encodeURIComponent(
|
|
2351
|
+
url: `https://assets.mcasset.cloud/${encodeURIComponent(version2)}/game-version.json`,
|
|
2278
2352
|
responseType: "json"
|
|
2279
2353
|
});
|
|
2280
2354
|
const data = response.data;
|
|
@@ -2322,6 +2396,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2322
2396
|
dataPackFormat: copyFormat(options.dataPackFormat)
|
|
2323
2397
|
};
|
|
2324
2398
|
}
|
|
2399
|
+
/** Creates a browser ZIP source from a Blob or File. */
|
|
2325
2400
|
static blob(blob, options) {
|
|
2326
2401
|
return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
|
|
2327
2402
|
}
|
|
@@ -2362,7 +2437,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2362
2437
|
}
|
|
2363
2438
|
async load(key, parser) {
|
|
2364
2439
|
const path = `${this.assetBasePath(key)}${key.type !== void 0 ? key.type + "/" : ""}${key.path}${key.extension}`;
|
|
2365
|
-
const
|
|
2440
|
+
const version2 = AssetLoader.version;
|
|
2366
2441
|
let selectedPath = path;
|
|
2367
2442
|
let url;
|
|
2368
2443
|
try {
|
|
@@ -2370,7 +2445,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2370
2445
|
if (key.rootType === "assets" || key.rootType === "data") {
|
|
2371
2446
|
const metadata = await this.getMetadata(key);
|
|
2372
2447
|
if (metadata.hasOverlays) {
|
|
2373
|
-
const format2 = (key.rootType === "assets" ? this.options.resourcePackFormat : this.options.dataPackFormat) ?? await PackFormats.get(
|
|
2448
|
+
const format2 = (key.rootType === "assets" ? this.options.resourcePackFormat : this.options.dataPackFormat) ?? await PackFormats.get(version2, key.rootType);
|
|
2374
2449
|
directories = metadata.overlayDirectories(format2);
|
|
2375
2450
|
}
|
|
2376
2451
|
}
|
|
@@ -2456,8 +2531,9 @@ var init_AssetLoader = __esm({
|
|
|
2456
2531
|
static get version() {
|
|
2457
2532
|
return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
|
|
2458
2533
|
}
|
|
2459
|
-
|
|
2460
|
-
|
|
2534
|
+
/** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
|
|
2535
|
+
static setVersion(version2) {
|
|
2536
|
+
this.ROOT = `https://assets.mcasset.cloud/${version2}`;
|
|
2461
2537
|
const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
|
|
2462
2538
|
const index = this._SOURCES.findIndex((s) => s.key === "mcassets");
|
|
2463
2539
|
if (index !== -1) {
|
|
@@ -2489,6 +2565,13 @@ var init_AssetLoader = __esm({
|
|
|
2489
2565
|
return scope ? `${scope}
|
|
2490
2566
|
${key}` : key;
|
|
2491
2567
|
}
|
|
2568
|
+
/**
|
|
2569
|
+
* Registers a source at the highest priority.
|
|
2570
|
+
* Call {@link Caching.clear} after changing sources to discard previously loaded assets.
|
|
2571
|
+
*
|
|
2572
|
+
* @param key - Name used to replace or remove this source.
|
|
2573
|
+
* @param override - Removes the first source with this name before adding the new one.
|
|
2574
|
+
*/
|
|
2492
2575
|
static addSource(key, source, override = true) {
|
|
2493
2576
|
if (override) {
|
|
2494
2577
|
const existing = this.removeSource(key);
|
|
@@ -2499,6 +2582,7 @@ ${key}` : key;
|
|
|
2499
2582
|
this._SOURCES.unshift({ key, source });
|
|
2500
2583
|
console.log(p4, "Added AssetSource", key);
|
|
2501
2584
|
}
|
|
2585
|
+
/** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
|
|
2502
2586
|
static removeSource(key) {
|
|
2503
2587
|
const index = this._SOURCES.findIndex((s) => s.key === key);
|
|
2504
2588
|
if (index != -1) {
|
|
@@ -2509,12 +2593,13 @@ ${key}` : key;
|
|
|
2509
2593
|
}
|
|
2510
2594
|
return void 0;
|
|
2511
2595
|
}
|
|
2596
|
+
/** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
|
|
2512
2597
|
static async getAll(key, parser) {
|
|
2513
2598
|
const sources = [...this._SOURCES];
|
|
2514
2599
|
const results = [];
|
|
2515
2600
|
for (const { source } of sources) {
|
|
2516
|
-
const
|
|
2517
|
-
if (
|
|
2601
|
+
const asset2 = await source.get(key, parser);
|
|
2602
|
+
if (asset2 != void 0) results.push(asset2);
|
|
2518
2603
|
if (await source.blocks(key)) break;
|
|
2519
2604
|
}
|
|
2520
2605
|
return results;
|
|
@@ -2553,6 +2638,7 @@ ${key}` : key;
|
|
|
2553
2638
|
return void 0;
|
|
2554
2639
|
}
|
|
2555
2640
|
};
|
|
2641
|
+
/** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
|
|
2556
2642
|
_AssetLoader.ROOT = DEFAULT_ROOT;
|
|
2557
2643
|
_AssetLoader._SOURCES = [];
|
|
2558
2644
|
/** Used when a registered source cannot identify its content, so nothing persists past this session. */
|
|
@@ -2577,14 +2663,15 @@ var init_ModelTextures = __esm({
|
|
|
2577
2663
|
static get PERSISTENT_META_CACHE() {
|
|
2578
2664
|
return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
|
|
2579
2665
|
}
|
|
2666
|
+
/** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
|
|
2580
2667
|
static async get(key) {
|
|
2581
2668
|
const keyStr = key.serialize();
|
|
2582
2669
|
const pending = this.preload(key);
|
|
2583
2670
|
const cached2 = Caching.textureAssetCache.getIfPresent(keyStr);
|
|
2584
2671
|
try {
|
|
2585
|
-
const
|
|
2586
|
-
if (
|
|
2587
|
-
return await ImageLoader.infoToCanvasData(
|
|
2672
|
+
const asset2 = await pending;
|
|
2673
|
+
if (asset2) {
|
|
2674
|
+
return await ImageLoader.infoToCanvasData(asset2);
|
|
2588
2675
|
}
|
|
2589
2676
|
return void 0;
|
|
2590
2677
|
} catch (err) {
|
|
@@ -2594,16 +2681,18 @@ var init_ModelTextures = __esm({
|
|
|
2594
2681
|
throw err;
|
|
2595
2682
|
}
|
|
2596
2683
|
}
|
|
2684
|
+
/** Fetches and caches encoded texture bytes without decoding the pixels. */
|
|
2597
2685
|
static async preload(key) {
|
|
2598
2686
|
const keyStr = key.serialize();
|
|
2599
2687
|
return Caching.textureAssetCache.get(keyStr, (k) => {
|
|
2600
|
-
return AssetLoader.get(key, "image" /* IMAGE */).then((
|
|
2601
|
-
if (
|
|
2602
|
-
|
|
2603
|
-
return
|
|
2688
|
+
return AssetLoader.get(key, "image" /* IMAGE */).then((asset2) => {
|
|
2689
|
+
if (asset2)
|
|
2690
|
+
asset2.key = key;
|
|
2691
|
+
return asset2;
|
|
2604
2692
|
});
|
|
2605
2693
|
});
|
|
2606
2694
|
}
|
|
2695
|
+
/** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
|
|
2607
2696
|
static async getMeta(key) {
|
|
2608
2697
|
if (!key.extension || !key.extension.endsWith(".mcmeta")) {
|
|
2609
2698
|
key = Object.assign(new AssetKey("", ""), key);
|
|
@@ -2612,14 +2701,15 @@ var init_ModelTextures = __esm({
|
|
|
2612
2701
|
const keyStr = key.serialize();
|
|
2613
2702
|
return Caching.textureMetaCache.get(keyStr, (k) => {
|
|
2614
2703
|
return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
2615
|
-
return AssetLoader.get(key, "meta" /* META */).then((
|
|
2616
|
-
if (
|
|
2617
|
-
|
|
2618
|
-
return
|
|
2704
|
+
return AssetLoader.get(key, "meta" /* META */).then((asset2) => {
|
|
2705
|
+
if (asset2)
|
|
2706
|
+
asset2.key = key;
|
|
2707
|
+
return asset2;
|
|
2619
2708
|
});
|
|
2620
2709
|
});
|
|
2621
2710
|
});
|
|
2622
2711
|
}
|
|
2712
|
+
/** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
|
|
2623
2713
|
static async clearCache() {
|
|
2624
2714
|
await this.PERSISTENT_META_CACHE.clear();
|
|
2625
2715
|
}
|
|
@@ -2686,6 +2776,7 @@ var init_Ticker = __esm({
|
|
|
2686
2776
|
}
|
|
2687
2777
|
return handle;
|
|
2688
2778
|
}
|
|
2779
|
+
/** Starts or resumes the shared tick loop. Repeated calls have no effect. */
|
|
2689
2780
|
static start() {
|
|
2690
2781
|
if (this.interval) return;
|
|
2691
2782
|
this.interval = this.schedule(() => {
|
|
@@ -2708,6 +2799,7 @@ var init_Ticker = __esm({
|
|
|
2708
2799
|
_Ticker.fiveSecondTicks = 0;
|
|
2709
2800
|
}, 1e3 * 5);
|
|
2710
2801
|
}
|
|
2802
|
+
/** Pauses the loop while retaining callbacks for a later {@link start}. */
|
|
2711
2803
|
static stop() {
|
|
2712
2804
|
if (this.interval) clearInterval(this.interval);
|
|
2713
2805
|
if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
|
|
@@ -2716,12 +2808,14 @@ var init_Ticker = __esm({
|
|
|
2716
2808
|
this.oneSecondTicksTracker = void 0;
|
|
2717
2809
|
this.fiveSecondTicksTracker = void 0;
|
|
2718
2810
|
}
|
|
2811
|
+
/** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
|
|
2719
2812
|
static add(tick) {
|
|
2720
2813
|
this.start();
|
|
2721
2814
|
const c = this.counter++;
|
|
2722
2815
|
this._tickers.set(c, tick);
|
|
2723
2816
|
return c;
|
|
2724
2817
|
}
|
|
2818
|
+
/** Removes a callback by ID and stops the timers when no callbacks remain. */
|
|
2725
2819
|
static remove(c) {
|
|
2726
2820
|
if (typeof c === "number") this._tickers.delete(c);
|
|
2727
2821
|
if (!this._tickers.size) this.stop();
|
|
@@ -2735,6 +2829,7 @@ var init_Ticker = __esm({
|
|
|
2735
2829
|
static get tpsFiveSeconds() {
|
|
2736
2830
|
return this.fiveSecondTps;
|
|
2737
2831
|
}
|
|
2832
|
+
/** Stops the loop and removes all registered callbacks. */
|
|
2738
2833
|
static dispose() {
|
|
2739
2834
|
this.stop();
|
|
2740
2835
|
this._tickers.clear();
|
|
@@ -2789,6 +2884,7 @@ var init_TextureAtlas = __esm({
|
|
|
2789
2884
|
}
|
|
2790
2885
|
};
|
|
2791
2886
|
}
|
|
2887
|
+
/** Copies pixels for a texture variable from its current atlas rectangle. */
|
|
2792
2888
|
getData(texture) {
|
|
2793
2889
|
const pos = this.positions[texture];
|
|
2794
2890
|
const size = this.sizes[texture];
|
|
@@ -3066,6 +3162,7 @@ var init_UVMapper = __esm({
|
|
|
3066
3162
|
}
|
|
3067
3163
|
uv.needsUpdate = true;
|
|
3068
3164
|
}
|
|
3165
|
+
/** Returns the shared atlas for a keyed, merged model, creating it on first use. */
|
|
3069
3166
|
static async getAtlas(model) {
|
|
3070
3167
|
const keyStr = model.key.serialize();
|
|
3071
3168
|
return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
|
|
@@ -3136,6 +3233,11 @@ var init_UVMapper = __esm({
|
|
|
3136
3233
|
}
|
|
3137
3234
|
return [tl, tr, bl, br];
|
|
3138
3235
|
}
|
|
3236
|
+
/**
|
|
3237
|
+
* Combines model textures and animation metadata into an atlas.
|
|
3238
|
+
* Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
|
|
3239
|
+
* Returns `undefined` for models without a texture map.
|
|
3240
|
+
*/
|
|
3139
3241
|
static async createAtlas(originalModel) {
|
|
3140
3242
|
const textureMap = {};
|
|
3141
3243
|
const metaMap = {};
|
|
@@ -3156,12 +3258,12 @@ var init_UVMapper = __esm({
|
|
|
3156
3258
|
} else {
|
|
3157
3259
|
uniqueTextureNames.push(textureKey);
|
|
3158
3260
|
const assetKey = AssetKey.parse("textures", textureValue, model.key);
|
|
3159
|
-
promises.push(ModelTextures.get(assetKey).then((
|
|
3160
|
-
if (!
|
|
3261
|
+
promises.push(ModelTextures.get(assetKey).then((asset2) => {
|
|
3262
|
+
if (!asset2) {
|
|
3161
3263
|
console.warn(p5, "Missing texture", assetKey);
|
|
3162
3264
|
return;
|
|
3163
3265
|
}
|
|
3164
|
-
textureMap[textureKey] = new WrappedImage(
|
|
3266
|
+
textureMap[textureKey] = new WrappedImage(asset2);
|
|
3165
3267
|
}));
|
|
3166
3268
|
promises.push(ModelTextures.getMeta(assetKey).then((meta) => {
|
|
3167
3269
|
metaMap[textureKey] = meta;
|
|
@@ -3500,14 +3602,15 @@ var init_Entities = __esm({
|
|
|
3500
3602
|
init_MineRenderError();
|
|
3501
3603
|
init_ModelTextures();
|
|
3502
3604
|
Entities = class {
|
|
3605
|
+
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
3503
3606
|
static async getEntityList() {
|
|
3504
3607
|
const collect = async (path) => {
|
|
3505
3608
|
const prefix2 = path ? `${path}/` : "";
|
|
3506
3609
|
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
|
|
3507
|
-
const
|
|
3508
|
-
if (!
|
|
3509
|
-
const files =
|
|
3510
|
-
const children = await Promise.all(
|
|
3610
|
+
const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
|
|
3611
|
+
if (!list2) return [];
|
|
3612
|
+
const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
|
|
3613
|
+
const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
|
|
3511
3614
|
return [...files, ...children.flat()];
|
|
3512
3615
|
};
|
|
3513
3616
|
return collect("");
|
|
@@ -3517,6 +3620,7 @@ var init_Entities = __esm({
|
|
|
3517
3620
|
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
3518
3621
|
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3519
3622
|
}
|
|
3623
|
+
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
3520
3624
|
static async getLayerList(modelKey) {
|
|
3521
3625
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
3522
3626
|
}
|
|
@@ -3524,6 +3628,15 @@ var init_Entities = __esm({
|
|
|
3524
3628
|
static async getPassList(modelKey) {
|
|
3525
3629
|
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
3526
3630
|
}
|
|
3631
|
+
/**
|
|
3632
|
+
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
3633
|
+
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
3634
|
+
*
|
|
3635
|
+
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
3636
|
+
* @param textureKey - Texture override for the first selected layer.
|
|
3637
|
+
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
3638
|
+
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
3639
|
+
*/
|
|
3527
3640
|
static async getEntity(modelKey, textureKey, options) {
|
|
3528
3641
|
const model = await this.getModelFile(modelKey);
|
|
3529
3642
|
if (!model) return void 0;
|
|
@@ -3569,6 +3682,7 @@ var init_Entities = __esm({
|
|
|
3569
3682
|
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3570
3683
|
return file?.animations;
|
|
3571
3684
|
}
|
|
3685
|
+
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
3572
3686
|
static async resolveTexture(modelKey) {
|
|
3573
3687
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3574
3688
|
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
@@ -3580,8 +3694,8 @@ var init_Entities = __esm({
|
|
|
3580
3694
|
if (await ModelTextures.get(texture2)) return texture2;
|
|
3581
3695
|
}
|
|
3582
3696
|
const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
|
|
3583
|
-
const
|
|
3584
|
-
const files =
|
|
3697
|
+
const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
|
|
3698
|
+
const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
|
|
3585
3699
|
const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
|
|
3586
3700
|
if (!file) return void 0;
|
|
3587
3701
|
const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
|
|
@@ -3686,27 +3800,27 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3686
3800
|
for (const layer of layers) {
|
|
3687
3801
|
const objects = [];
|
|
3688
3802
|
if (poses) {
|
|
3689
|
-
layer.traverse((
|
|
3690
|
-
if (poses.has(
|
|
3803
|
+
layer.traverse((object3) => {
|
|
3804
|
+
if (poses.has(object3)) objects.push(object3);
|
|
3691
3805
|
});
|
|
3692
3806
|
} else {
|
|
3693
3807
|
for (const bone of Object.keys(animation.bones)) {
|
|
3694
|
-
const
|
|
3695
|
-
if (
|
|
3808
|
+
const object3 = layer.getObjectByName(`group:${bone}`);
|
|
3809
|
+
if (object3) objects.push(object3);
|
|
3696
3810
|
}
|
|
3697
3811
|
}
|
|
3698
|
-
for (const
|
|
3699
|
-
const bone =
|
|
3700
|
-
const pose = poses?.get(
|
|
3812
|
+
for (const object3 of objects) {
|
|
3813
|
+
const bone = object3.name.slice("group:".length);
|
|
3814
|
+
const pose = poses?.get(object3);
|
|
3701
3815
|
this.parts.push({
|
|
3702
3816
|
bone,
|
|
3703
|
-
object:
|
|
3704
|
-
position:
|
|
3705
|
-
rotation:
|
|
3706
|
-
scale:
|
|
3707
|
-
basePosition: pose ? new import_three11.Vector3(...pose.offset) :
|
|
3708
|
-
baseRotation: pose ? new import_three11.Euler(...pose.rotation, "ZYX") :
|
|
3709
|
-
baseScale: pose ? new import_three11.Vector3(...pose.scale ?? [1, 1, 1]) :
|
|
3817
|
+
object: object3,
|
|
3818
|
+
position: object3.position.clone(),
|
|
3819
|
+
rotation: object3.rotation.clone(),
|
|
3820
|
+
scale: object3.scale.clone(),
|
|
3821
|
+
basePosition: pose ? new import_three11.Vector3(...pose.offset) : object3.position.clone(),
|
|
3822
|
+
baseRotation: pose ? new import_three11.Euler(...pose.rotation, "ZYX") : object3.rotation.clone(),
|
|
3823
|
+
baseScale: pose ? new import_three11.Vector3(...pose.scale ?? [1, 1, 1]) : object3.scale.clone()
|
|
3710
3824
|
});
|
|
3711
3825
|
}
|
|
3712
3826
|
}
|
|
@@ -3729,12 +3843,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3729
3843
|
this._animation = void 0;
|
|
3730
3844
|
this._time = 0;
|
|
3731
3845
|
}
|
|
3846
|
+
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
3732
3847
|
setTime(seconds) {
|
|
3733
3848
|
if (!this._animation) return false;
|
|
3734
3849
|
this._time = seconds;
|
|
3735
3850
|
this.apply();
|
|
3736
3851
|
return true;
|
|
3737
3852
|
}
|
|
3853
|
+
/** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
|
|
3738
3854
|
advance(deltaSeconds) {
|
|
3739
3855
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
3740
3856
|
}
|
|
@@ -3772,6 +3888,7 @@ var init_InstanceReference = __esm({
|
|
|
3772
3888
|
if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
|
|
3773
3889
|
return this.instanceable;
|
|
3774
3890
|
}
|
|
3891
|
+
/** Releases this placement's slot for reuse. Repeated calls have no effect. */
|
|
3775
3892
|
removeFromScene() {
|
|
3776
3893
|
if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
|
|
3777
3894
|
}
|
|
@@ -3784,9 +3901,11 @@ var init_InstanceReference = __esm({
|
|
|
3784
3901
|
setMatrix(matrix) {
|
|
3785
3902
|
this.activeInstanceable.setMatrixAt(this.index, matrix);
|
|
3786
3903
|
}
|
|
3904
|
+
/** Hides or restores this placement while preserving its transform and allocated slot. */
|
|
3787
3905
|
setVisible(visible) {
|
|
3788
3906
|
this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
|
|
3789
3907
|
}
|
|
3908
|
+
/** Updates the supplied transform components. Positions use scene units and rotations use radians. */
|
|
3790
3909
|
setPositionRotationScale(position, rotation, scale) {
|
|
3791
3910
|
this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
|
|
3792
3911
|
}
|
|
@@ -3855,6 +3974,7 @@ var init_SceneObject = __esm({
|
|
|
3855
3974
|
}
|
|
3856
3975
|
async init() {
|
|
3857
3976
|
}
|
|
3977
|
+
/** Marks ancestor scenes for redraw and emits a `change` event. */
|
|
3858
3978
|
notifyDirty() {
|
|
3859
3979
|
this.traverseAncestors((parent) => {
|
|
3860
3980
|
const scene = parent;
|
|
@@ -3890,15 +4010,17 @@ var init_SceneObject = __esm({
|
|
|
3890
4010
|
return obj;
|
|
3891
4011
|
}
|
|
3892
4012
|
/**
|
|
3893
|
-
*
|
|
4013
|
+
* Finds a named part, such as `head`, without the internal `group:` prefix.
|
|
4014
|
+
* Returns `undefined` when the group does not exist.
|
|
3894
4015
|
*/
|
|
3895
4016
|
getGroupByName(name) {
|
|
3896
4017
|
return this.getObjectByName(`group:${name}`);
|
|
3897
4018
|
}
|
|
3898
4019
|
/**
|
|
3899
|
-
*
|
|
3900
|
-
* @param name name
|
|
3901
|
-
* @param visible
|
|
4020
|
+
* Changes a named group's visibility and requests a redraw.
|
|
4021
|
+
* @param name - Part name without the `group:` prefix.
|
|
4022
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4023
|
+
* @returns The resulting visibility, or `false` if the group does not exist.
|
|
3902
4024
|
*/
|
|
3903
4025
|
toggleGroupVisibility(name, visible) {
|
|
3904
4026
|
return this.toggleObjectVisibility(this.getGroupByName(name), visible);
|
|
@@ -3949,15 +4071,16 @@ var init_SceneObject = __esm({
|
|
|
3949
4071
|
return mesh;
|
|
3950
4072
|
}
|
|
3951
4073
|
/**
|
|
3952
|
-
*
|
|
4074
|
+
* Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
|
|
3953
4075
|
*/
|
|
3954
4076
|
getMeshByName(name) {
|
|
3955
4077
|
return this.getObjectByName(`mesh:${name}`);
|
|
3956
4078
|
}
|
|
3957
4079
|
/**
|
|
3958
|
-
*
|
|
3959
|
-
* @param name name
|
|
3960
|
-
* @param visible
|
|
4080
|
+
* Changes a named mesh's visibility and requests a redraw.
|
|
4081
|
+
* @param name - Mesh name without the `mesh:` prefix.
|
|
4082
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4083
|
+
* @returns The resulting visibility, or `false` if the mesh does not exist.
|
|
3961
4084
|
*/
|
|
3962
4085
|
toggleMeshVisibility(name, visible) {
|
|
3963
4086
|
return this.toggleObjectVisibility(this.getMeshByName(name), visible);
|
|
@@ -4003,12 +4126,14 @@ var init_SceneObject = __esm({
|
|
|
4003
4126
|
get isInstanced() {
|
|
4004
4127
|
return this._isInstanced;
|
|
4005
4128
|
}
|
|
4129
|
+
/** Number of live placements, excluding released instance slots. */
|
|
4006
4130
|
get instanceCounter() {
|
|
4007
4131
|
return this._instanceCounter;
|
|
4008
4132
|
}
|
|
4009
4133
|
constructInstanceReference(i) {
|
|
4010
4134
|
return new InstanceReference(this, i);
|
|
4011
4135
|
}
|
|
4136
|
+
/** Allocates a placement of this instanced object, reusing a released slot when available. */
|
|
4012
4137
|
nextInstance() {
|
|
4013
4138
|
const mesh = this.instanceMesh;
|
|
4014
4139
|
if (!mesh) throw new MineRenderError("Object is not instanced");
|
|
@@ -4053,10 +4178,10 @@ var init_SceneObject = __esm({
|
|
|
4053
4178
|
return new import_three12.InstancedBufferAttribute(array, attribute.itemSize, attribute.normalized, attribute.meshPerAttribute).setUsage(attribute.usage);
|
|
4054
4179
|
};
|
|
4055
4180
|
const matrix = grow(mesh.instanceMatrix, 0);
|
|
4056
|
-
const
|
|
4181
|
+
const color2 = mesh.instanceColor ? grow(mesh.instanceColor, 1) : null;
|
|
4057
4182
|
mesh.dispose();
|
|
4058
4183
|
mesh.instanceMatrix = matrix;
|
|
4059
|
-
mesh.instanceColor =
|
|
4184
|
+
mesh.instanceColor = color2;
|
|
4060
4185
|
}
|
|
4061
4186
|
*activeInstanceIndices() {
|
|
4062
4187
|
if (this.instanceMesh) {
|
|
@@ -4155,6 +4280,7 @@ var init_SceneObject = __esm({
|
|
|
4155
4280
|
vector.setFromMatrixScale(matrix);
|
|
4156
4281
|
return vector;
|
|
4157
4282
|
}
|
|
4283
|
+
/** Updates supplied transform components. For a shared model, affects every live instance. */
|
|
4158
4284
|
setPositionRotationScale(position, rotation, scale) {
|
|
4159
4285
|
if (this.isInstanced) {
|
|
4160
4286
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4173,6 +4299,7 @@ var init_SceneObject = __esm({
|
|
|
4173
4299
|
}
|
|
4174
4300
|
this.notifyDirty();
|
|
4175
4301
|
}
|
|
4302
|
+
/** Sets position in scene units. For a shared model, updates every live instance. */
|
|
4176
4303
|
setPosition(position) {
|
|
4177
4304
|
if (this.isInstanced) {
|
|
4178
4305
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4190,6 +4317,7 @@ var init_SceneObject = __esm({
|
|
|
4190
4317
|
return this.position;
|
|
4191
4318
|
}
|
|
4192
4319
|
}
|
|
4320
|
+
/** Sets rotation in radians. For a shared model, updates every live instance. */
|
|
4193
4321
|
setRotation(rotation) {
|
|
4194
4322
|
if (this.isInstanced) {
|
|
4195
4323
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4207,6 +4335,7 @@ var init_SceneObject = __esm({
|
|
|
4207
4335
|
return this.rotation;
|
|
4208
4336
|
}
|
|
4209
4337
|
}
|
|
4338
|
+
/** Sets scale factors. For a shared model, updates every live instance. */
|
|
4210
4339
|
setScale(scale) {
|
|
4211
4340
|
if (this.isInstanced) {
|
|
4212
4341
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4225,15 +4354,15 @@ var init_SceneObject = __esm({
|
|
|
4225
4354
|
}
|
|
4226
4355
|
}
|
|
4227
4356
|
//</editor-fold>
|
|
4228
|
-
toggleObjectVisibility(
|
|
4229
|
-
if (
|
|
4357
|
+
toggleObjectVisibility(object3, visible) {
|
|
4358
|
+
if (object3) {
|
|
4230
4359
|
if (typeof visible !== "undefined") {
|
|
4231
|
-
|
|
4360
|
+
object3.visible = visible;
|
|
4232
4361
|
} else {
|
|
4233
|
-
|
|
4362
|
+
object3.visible = !object3.visible;
|
|
4234
4363
|
}
|
|
4235
4364
|
this.notifyDirty();
|
|
4236
|
-
return
|
|
4365
|
+
return object3.visible;
|
|
4237
4366
|
}
|
|
4238
4367
|
this.notifyDirty();
|
|
4239
4368
|
return false;
|
|
@@ -4244,6 +4373,7 @@ var init_SceneObject = __esm({
|
|
|
4244
4373
|
this.notifyDirty();
|
|
4245
4374
|
super.dispose();
|
|
4246
4375
|
}
|
|
4376
|
+
/** Releases instance slots and removes children, disposing children that implement Disposable. */
|
|
4247
4377
|
disposeAndRemoveAllChildren() {
|
|
4248
4378
|
if (this.instanceMesh) {
|
|
4249
4379
|
if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
|
|
@@ -4266,6 +4396,7 @@ var init_SceneObject = __esm({
|
|
|
4266
4396
|
}
|
|
4267
4397
|
this.notifyDirty();
|
|
4268
4398
|
}
|
|
4399
|
+
/** Detaches the object from its parent and requests a redraw. */
|
|
4269
4400
|
removeFromScene() {
|
|
4270
4401
|
this.notifyDirty();
|
|
4271
4402
|
this.removeFromParent();
|
|
@@ -4421,12 +4552,15 @@ var init_EntityObject = __esm({
|
|
|
4421
4552
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
4422
4553
|
}
|
|
4423
4554
|
//</editor-fold>
|
|
4555
|
+
/** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
|
|
4424
4556
|
getLayerGroup(name) {
|
|
4425
4557
|
return super.getGroupByName(`layer:${name}`);
|
|
4426
4558
|
}
|
|
4559
|
+
/** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
|
|
4427
4560
|
getGroupByName(name, layerName) {
|
|
4428
4561
|
return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
|
|
4429
4562
|
}
|
|
4563
|
+
/** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
|
|
4430
4564
|
getMeshByName(name, layerName) {
|
|
4431
4565
|
return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
|
|
4432
4566
|
}
|
|
@@ -4528,8 +4662,8 @@ var init_EntityObject = __esm({
|
|
|
4528
4662
|
this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
|
|
4529
4663
|
}
|
|
4530
4664
|
}
|
|
4531
|
-
this.getLayerGroup(name)?.traverse((
|
|
4532
|
-
if (isMesh(
|
|
4665
|
+
this.getLayerGroup(name)?.traverse((object3) => {
|
|
4666
|
+
if (isMesh(object3)) object3.material = mat;
|
|
4533
4667
|
});
|
|
4534
4668
|
}));
|
|
4535
4669
|
if (!this.children.length) {
|
|
@@ -4859,8 +4993,8 @@ function toTrianglesDrawMode(geometry, drawMode) {
|
|
|
4859
4993
|
return geometry;
|
|
4860
4994
|
}
|
|
4861
4995
|
}
|
|
4862
|
-
function computeMorphedAttributes(
|
|
4863
|
-
if (
|
|
4996
|
+
function computeMorphedAttributes(object3) {
|
|
4997
|
+
if (object3.geometry.isBufferGeometry !== true) {
|
|
4864
4998
|
console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
|
|
4865
4999
|
return null;
|
|
4866
5000
|
}
|
|
@@ -4873,11 +5007,11 @@ function computeMorphedAttributes(object2) {
|
|
|
4873
5007
|
const _morphA = new import_three22.Vector3();
|
|
4874
5008
|
const _morphB = new import_three22.Vector3();
|
|
4875
5009
|
const _morphC = new import_three22.Vector3();
|
|
4876
|
-
function _calculateMorphedAttributeData(
|
|
5010
|
+
function _calculateMorphedAttributeData(object4, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
|
|
4877
5011
|
_vA.fromBufferAttribute(attribute, a2);
|
|
4878
5012
|
_vB.fromBufferAttribute(attribute, b2);
|
|
4879
5013
|
_vC.fromBufferAttribute(attribute, c2);
|
|
4880
|
-
const morphInfluences =
|
|
5014
|
+
const morphInfluences = object4.morphTargetInfluences;
|
|
4881
5015
|
if (material2.morphTargets && morphAttribute && morphInfluences) {
|
|
4882
5016
|
_morphA.set(0, 0, 0);
|
|
4883
5017
|
_morphB.set(0, 0, 0);
|
|
@@ -4903,10 +5037,10 @@ function computeMorphedAttributes(object2) {
|
|
|
4903
5037
|
_vB.add(_morphB);
|
|
4904
5038
|
_vC.add(_morphC);
|
|
4905
5039
|
}
|
|
4906
|
-
if (
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
5040
|
+
if (object4.isSkinnedMesh) {
|
|
5041
|
+
object4.boneTransform(a2, _vA);
|
|
5042
|
+
object4.boneTransform(b2, _vB);
|
|
5043
|
+
object4.boneTransform(c2, _vC);
|
|
4910
5044
|
}
|
|
4911
5045
|
modifiedAttributeArray[a2 * 3 + 0] = _vA.x;
|
|
4912
5046
|
modifiedAttributeArray[a2 * 3 + 1] = _vA.y;
|
|
@@ -4918,8 +5052,8 @@ function computeMorphedAttributes(object2) {
|
|
|
4918
5052
|
modifiedAttributeArray[c2 * 3 + 1] = _vC.y;
|
|
4919
5053
|
modifiedAttributeArray[c2 * 3 + 2] = _vC.z;
|
|
4920
5054
|
}
|
|
4921
|
-
const geometry =
|
|
4922
|
-
const material =
|
|
5055
|
+
const geometry = object3.geometry;
|
|
5056
|
+
const material = object3.material;
|
|
4923
5057
|
let a, b, c;
|
|
4924
5058
|
const index = geometry.index;
|
|
4925
5059
|
const positionAttribute = geometry.attributes.position;
|
|
@@ -4946,7 +5080,7 @@ function computeMorphedAttributes(object2) {
|
|
|
4946
5080
|
b = index.getX(j + 1);
|
|
4947
5081
|
c = index.getX(j + 2);
|
|
4948
5082
|
_calculateMorphedAttributeData(
|
|
4949
|
-
|
|
5083
|
+
object3,
|
|
4950
5084
|
groupMaterial,
|
|
4951
5085
|
positionAttribute,
|
|
4952
5086
|
morphPosition,
|
|
@@ -4957,7 +5091,7 @@ function computeMorphedAttributes(object2) {
|
|
|
4957
5091
|
modifiedPosition
|
|
4958
5092
|
);
|
|
4959
5093
|
_calculateMorphedAttributeData(
|
|
4960
|
-
|
|
5094
|
+
object3,
|
|
4961
5095
|
groupMaterial,
|
|
4962
5096
|
normalAttribute,
|
|
4963
5097
|
morphNormal,
|
|
@@ -4977,7 +5111,7 @@ function computeMorphedAttributes(object2) {
|
|
|
4977
5111
|
b = index.getX(i + 1);
|
|
4978
5112
|
c = index.getX(i + 2);
|
|
4979
5113
|
_calculateMorphedAttributeData(
|
|
4980
|
-
|
|
5114
|
+
object3,
|
|
4981
5115
|
material,
|
|
4982
5116
|
positionAttribute,
|
|
4983
5117
|
morphPosition,
|
|
@@ -4988,7 +5122,7 @@ function computeMorphedAttributes(object2) {
|
|
|
4988
5122
|
modifiedPosition
|
|
4989
5123
|
);
|
|
4990
5124
|
_calculateMorphedAttributeData(
|
|
4991
|
-
|
|
5125
|
+
object3,
|
|
4992
5126
|
material,
|
|
4993
5127
|
normalAttribute,
|
|
4994
5128
|
morphNormal,
|
|
@@ -5012,7 +5146,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5012
5146
|
b = j + 1;
|
|
5013
5147
|
c = j + 2;
|
|
5014
5148
|
_calculateMorphedAttributeData(
|
|
5015
|
-
|
|
5149
|
+
object3,
|
|
5016
5150
|
groupMaterial,
|
|
5017
5151
|
positionAttribute,
|
|
5018
5152
|
morphPosition,
|
|
@@ -5023,7 +5157,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5023
5157
|
modifiedPosition
|
|
5024
5158
|
);
|
|
5025
5159
|
_calculateMorphedAttributeData(
|
|
5026
|
-
|
|
5160
|
+
object3,
|
|
5027
5161
|
groupMaterial,
|
|
5028
5162
|
normalAttribute,
|
|
5029
5163
|
morphNormal,
|
|
@@ -5043,7 +5177,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5043
5177
|
b = i + 1;
|
|
5044
5178
|
c = i + 2;
|
|
5045
5179
|
_calculateMorphedAttributeData(
|
|
5046
|
-
|
|
5180
|
+
object3,
|
|
5047
5181
|
material,
|
|
5048
5182
|
positionAttribute,
|
|
5049
5183
|
morphPosition,
|
|
@@ -5054,7 +5188,7 @@ function computeMorphedAttributes(object2) {
|
|
|
5054
5188
|
modifiedPosition
|
|
5055
5189
|
);
|
|
5056
5190
|
_calculateMorphedAttributeData(
|
|
5057
|
-
|
|
5191
|
+
object3,
|
|
5058
5192
|
material,
|
|
5059
5193
|
normalAttribute,
|
|
5060
5194
|
morphNormal,
|
|
@@ -5090,6 +5224,7 @@ var init_ModelCulling = __esm({
|
|
|
5090
5224
|
import_three23 = require("three");
|
|
5091
5225
|
init_CubeFace();
|
|
5092
5226
|
ModelCulling = class {
|
|
5227
|
+
/** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
|
|
5093
5228
|
static toLocalMask(worldMask, rotation) {
|
|
5094
5229
|
let localMask = 0;
|
|
5095
5230
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
@@ -5100,6 +5235,7 @@ var init_ModelCulling = __esm({
|
|
|
5100
5235
|
}
|
|
5101
5236
|
return localMask;
|
|
5102
5237
|
}
|
|
5238
|
+
/** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
|
|
5103
5239
|
static isOpaqueFullCube(atlas) {
|
|
5104
5240
|
if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
|
|
5105
5241
|
const element = atlas.model.elements[0];
|
|
@@ -5310,9 +5446,9 @@ var init_ItemTints = __esm({
|
|
|
5310
5446
|
}));
|
|
5311
5447
|
return colors;
|
|
5312
5448
|
}
|
|
5313
|
-
static rgb(
|
|
5314
|
-
if (!Array.isArray(
|
|
5315
|
-
const [red, green, blue] =
|
|
5449
|
+
static rgb(color2) {
|
|
5450
|
+
if (!Array.isArray(color2)) return color2 & 16777215;
|
|
5451
|
+
const [red, green, blue] = color2.map((channel) => Math.floor(Math.fround(Math.fround(channel) * 255)));
|
|
5316
5452
|
return red << 16 | green << 8 | blue;
|
|
5317
5453
|
}
|
|
5318
5454
|
};
|
|
@@ -5365,13 +5501,13 @@ var init_ModelObject = __esm({
|
|
|
5365
5501
|
transform.multiply(new import_three25.Matrix4().makeTranslation(-8, -8, -8));
|
|
5366
5502
|
try {
|
|
5367
5503
|
for (const part of parts) {
|
|
5368
|
-
const
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
this.add(
|
|
5373
|
-
await
|
|
5374
|
-
|
|
5504
|
+
const object3 = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
|
|
5505
|
+
object3.matrix.copy(transform).multiply(part.transform);
|
|
5506
|
+
object3.matrixWorldNeedsUpdate = true;
|
|
5507
|
+
object3.matrixAutoUpdate = false;
|
|
5508
|
+
this.add(object3);
|
|
5509
|
+
await object3.init();
|
|
5510
|
+
object3.iterateAllMeshes((mesh) => {
|
|
5375
5511
|
const source = mesh.material;
|
|
5376
5512
|
let material = this.specialMaterials.get(source);
|
|
5377
5513
|
if (!material) {
|
|
@@ -5382,7 +5518,7 @@ var init_ModelObject = __esm({
|
|
|
5382
5518
|
mesh.material = material;
|
|
5383
5519
|
});
|
|
5384
5520
|
for (const [name, rotation] of Object.entries(part.rotations)) {
|
|
5385
|
-
|
|
5521
|
+
object3.getGroupByName(name)?.rotation.set(...rotation, "ZYX");
|
|
5386
5522
|
}
|
|
5387
5523
|
}
|
|
5388
5524
|
} catch (error) {
|
|
@@ -5435,9 +5571,9 @@ var init_ModelObject = __esm({
|
|
|
5435
5571
|
if (tintIndex === void 0 || tintIndex < 0) continue;
|
|
5436
5572
|
const tint = this.options.tints[tintIndex];
|
|
5437
5573
|
if (tint === void 0) continue;
|
|
5438
|
-
const
|
|
5574
|
+
const color2 = new import_three25.Color(tint);
|
|
5439
5575
|
for (let vertex = 0; vertex < 4; vertex++) {
|
|
5440
|
-
|
|
5576
|
+
color2.toArray(colors, (faceIndex * 4 + vertex) * 3);
|
|
5441
5577
|
}
|
|
5442
5578
|
}
|
|
5443
5579
|
elGeo.setAttribute("color", new import_three25.BufferAttribute(colors, 3));
|
|
@@ -5754,9 +5890,9 @@ var init_FluidModelObject = __esm({
|
|
|
5754
5890
|
}
|
|
5755
5891
|
}
|
|
5756
5892
|
geometry.clearGroups();
|
|
5757
|
-
const
|
|
5893
|
+
const color2 = new import_three31.Color(this.options.tints?.[0] ?? (this.kind === "water" ? 4159204 : 16777215));
|
|
5758
5894
|
const colors = new Float32Array(geometry.getAttribute("position").count * 3);
|
|
5759
|
-
for (let i = 0; i < colors.length; i += 3)
|
|
5895
|
+
for (let i = 0; i < colors.length; i += 3) color2.toArray(colors, i);
|
|
5760
5896
|
geometry.setAttribute("color", new import_three31.BufferAttribute(colors, 3));
|
|
5761
5897
|
geometry.computeBoundingBox();
|
|
5762
5898
|
geometry.computeBoundingSphere();
|
|
@@ -5867,6 +6003,7 @@ __export(index_browser_exports, {
|
|
|
5867
6003
|
RequestError: () => RequestError,
|
|
5868
6004
|
Requests: () => Requests,
|
|
5869
6005
|
SKIN_PARTS: () => SKIN_PARTS,
|
|
6006
|
+
SceneDocumentLoader: () => SceneDocumentLoader,
|
|
5870
6007
|
SceneExporter: () => SceneExporter,
|
|
5871
6008
|
SceneInspector: () => SceneInspector,
|
|
5872
6009
|
SceneObject: () => SceneObject,
|
|
@@ -5942,6 +6079,7 @@ __export(index_browser_exports, {
|
|
|
5942
6079
|
mergeBufferAttributes: () => mergeBufferAttributes,
|
|
5943
6080
|
mergeBufferGeometries: () => mergeBufferGeometries,
|
|
5944
6081
|
mergeVertices: () => mergeVertices,
|
|
6082
|
+
parseSceneDocument: () => parseSceneDocument,
|
|
5945
6083
|
prefix: () => prefix,
|
|
5946
6084
|
probeImageSize: () => probeImageSize,
|
|
5947
6085
|
registerBrowserEnv: () => registerBrowserEnv,
|
|
@@ -6070,11 +6208,11 @@ var BrowserEnv = class {
|
|
|
6070
6208
|
imageSize(data) {
|
|
6071
6209
|
return probeImageSize(data);
|
|
6072
6210
|
}
|
|
6073
|
-
openCache(name,
|
|
6211
|
+
openCache(name, version2) {
|
|
6074
6212
|
return new BrowserCache(import_localforage.default.createInstance({
|
|
6075
6213
|
// IndexedDB schema upgrades retain records; each cache generation needs its own database.
|
|
6076
|
-
name: name +
|
|
6077
|
-
version
|
|
6214
|
+
name: name + version2,
|
|
6215
|
+
version: version2
|
|
6078
6216
|
}));
|
|
6079
6217
|
}
|
|
6080
6218
|
};
|
|
@@ -6105,6 +6243,7 @@ var Meshes = class _Meshes {
|
|
|
6105
6243
|
static createBox(key) {
|
|
6106
6244
|
return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
|
|
6107
6245
|
}
|
|
6246
|
+
/** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
|
|
6108
6247
|
static getBox(key) {
|
|
6109
6248
|
const keyStr = serializeMeshKey(key);
|
|
6110
6249
|
return Caching.boxMeshCache.get(keyStr, (k) => {
|
|
@@ -6217,6 +6356,7 @@ init_AssetParsers();
|
|
|
6217
6356
|
init_ModelTextures();
|
|
6218
6357
|
init_Caching();
|
|
6219
6358
|
var Fonts = class {
|
|
6359
|
+
/** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
|
|
6220
6360
|
static async get(key = "minecraft:default") {
|
|
6221
6361
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
6222
6362
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -6232,8 +6372,8 @@ var Fonts = class {
|
|
|
6232
6372
|
const stack = await AssetLoader.getAll(key, "json" /* JSON */);
|
|
6233
6373
|
if (stack.length === 0) throw new Error(`Could not load font ${key.toNamespacedString()}`);
|
|
6234
6374
|
const glyphs = /* @__PURE__ */ new Map();
|
|
6235
|
-
for (const
|
|
6236
|
-
for (const provider of
|
|
6375
|
+
for (const asset2 of stack) {
|
|
6376
|
+
for (const provider of asset2.providers) {
|
|
6237
6377
|
if (provider.filter?.uniform || provider.filter?.jp) continue;
|
|
6238
6378
|
let provided;
|
|
6239
6379
|
switch (provider.type) {
|
|
@@ -6372,13 +6512,13 @@ var OBJExporter = class {
|
|
|
6372
6512
|
* @param {Object3D} object - The 3D object to export.
|
|
6373
6513
|
* @return {string} The exported OBJ.
|
|
6374
6514
|
*/
|
|
6375
|
-
parse(
|
|
6515
|
+
parse(object3) {
|
|
6376
6516
|
let output = "";
|
|
6377
6517
|
let indexVertex = 0;
|
|
6378
6518
|
let indexVertexUvs = 0;
|
|
6379
6519
|
let indexNormals = 0;
|
|
6380
6520
|
const vertex = new import_three16.Vector3();
|
|
6381
|
-
const
|
|
6521
|
+
const color2 = new import_three16.Color();
|
|
6382
6522
|
const normal = new import_three16.Vector3();
|
|
6383
6523
|
const uv = new import_three16.Vector2();
|
|
6384
6524
|
const face = [];
|
|
@@ -6477,9 +6617,9 @@ var OBJExporter = class {
|
|
|
6477
6617
|
vertex.applyMatrix4(points.matrixWorld);
|
|
6478
6618
|
output += "v " + vertex.x + " " + vertex.y + " " + vertex.z;
|
|
6479
6619
|
if (colors !== void 0) {
|
|
6480
|
-
|
|
6481
|
-
import_three16.ColorManagement.workingToColorSpace(
|
|
6482
|
-
output += " " +
|
|
6620
|
+
color2.fromBufferAttribute(colors, i);
|
|
6621
|
+
import_three16.ColorManagement.workingToColorSpace(color2, import_three16.SRGBColorSpace);
|
|
6622
|
+
output += " " + color2.r + " " + color2.g + " " + color2.b;
|
|
6483
6623
|
}
|
|
6484
6624
|
output += "\n";
|
|
6485
6625
|
}
|
|
@@ -6491,7 +6631,7 @@ var OBJExporter = class {
|
|
|
6491
6631
|
}
|
|
6492
6632
|
indexVertex += nbVertex;
|
|
6493
6633
|
}
|
|
6494
|
-
|
|
6634
|
+
object3.traverse(function(child) {
|
|
6495
6635
|
if (child.isMesh === true) {
|
|
6496
6636
|
parseMesh(child);
|
|
6497
6637
|
}
|
|
@@ -6519,9 +6659,9 @@ var PLYExporter = class {
|
|
|
6519
6659
|
* @param {PLYExporter~Options} options - The export options.
|
|
6520
6660
|
* @return {?(string|ArrayBuffer)} The exported PLY.
|
|
6521
6661
|
*/
|
|
6522
|
-
parse(
|
|
6662
|
+
parse(object3, onDone, options = {}) {
|
|
6523
6663
|
function traverseMeshes(cb) {
|
|
6524
|
-
|
|
6664
|
+
object3.traverse(function(child) {
|
|
6525
6665
|
if (child.isMesh === true || child.isPoints) {
|
|
6526
6666
|
const mesh = child;
|
|
6527
6667
|
const geometry = mesh.geometry;
|
|
@@ -6554,7 +6694,7 @@ var PLYExporter = class {
|
|
|
6554
6694
|
for (const name of customAttributeNames) customTypes[name] = "float";
|
|
6555
6695
|
let vertexCount = 0;
|
|
6556
6696
|
let faceCount = 0;
|
|
6557
|
-
|
|
6697
|
+
object3.traverse(function(child) {
|
|
6558
6698
|
if (child.isMesh === true) {
|
|
6559
6699
|
const mesh = child;
|
|
6560
6700
|
const geometry = mesh.geometry;
|
|
@@ -7148,8 +7288,8 @@ function equalArray(array1, array2) {
|
|
|
7148
7288
|
return element === array2[index];
|
|
7149
7289
|
});
|
|
7150
7290
|
}
|
|
7151
|
-
function stringToArrayBuffer(
|
|
7152
|
-
return new TextEncoder().encode(
|
|
7291
|
+
function stringToArrayBuffer(text2) {
|
|
7292
|
+
return new TextEncoder().encode(text2).buffer;
|
|
7153
7293
|
}
|
|
7154
7294
|
function isIdentityMatrix(matrix) {
|
|
7155
7295
|
return equalArray(matrix.elements, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
@@ -7342,12 +7482,12 @@ var GLTFWriter = class {
|
|
|
7342
7482
|
* @param {THREE.Object3D|THREE.Material|THREE.BufferGeometry|THREE.AnimationClip} object
|
|
7343
7483
|
* @param {Object} objectDef
|
|
7344
7484
|
*/
|
|
7345
|
-
serializeUserData(
|
|
7346
|
-
if (Object.keys(
|
|
7485
|
+
serializeUserData(object3, objectDef) {
|
|
7486
|
+
if (Object.keys(object3.userData).length === 0) return;
|
|
7347
7487
|
const options = this.options;
|
|
7348
7488
|
const extensionsUsed = this.extensionsUsed;
|
|
7349
7489
|
try {
|
|
7350
|
-
const json = JSON.parse(JSON.stringify(
|
|
7490
|
+
const json = JSON.parse(JSON.stringify(object3.userData));
|
|
7351
7491
|
if (options.includeCustomExtensions && json.gltfExtensions) {
|
|
7352
7492
|
if (objectDef.extensions === void 0) objectDef.extensions = {};
|
|
7353
7493
|
for (const extensionName in json.gltfExtensions) {
|
|
@@ -7358,7 +7498,7 @@ var GLTFWriter = class {
|
|
|
7358
7498
|
}
|
|
7359
7499
|
if (Object.keys(json).length > 0) objectDef.extras = json;
|
|
7360
7500
|
} catch (error) {
|
|
7361
|
-
console.warn("THREE.GLTFExporter: userData of '" +
|
|
7501
|
+
console.warn("THREE.GLTFExporter: userData of '" + object3.name + "' won't be serialized because of JSON.stringify error - " + error.message);
|
|
7362
7502
|
}
|
|
7363
7503
|
}
|
|
7364
7504
|
/**
|
|
@@ -7867,9 +8007,9 @@ var GLTFWriter = class {
|
|
|
7867
8007
|
if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) {
|
|
7868
8008
|
console.warn("GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.");
|
|
7869
8009
|
}
|
|
7870
|
-
const
|
|
7871
|
-
if (!equalArray(
|
|
7872
|
-
materialDef.pbrMetallicRoughness.baseColorFactor =
|
|
8010
|
+
const color2 = material.color.toArray().concat([material.opacity]);
|
|
8011
|
+
if (!equalArray(color2, [1, 1, 1, 1])) {
|
|
8012
|
+
materialDef.pbrMetallicRoughness.baseColorFactor = color2;
|
|
7873
8013
|
}
|
|
7874
8014
|
if (material.isMeshStandardMaterial) {
|
|
7875
8015
|
materialDef.pbrMetallicRoughness.metallicFactor = material.metalness;
|
|
@@ -8284,13 +8424,13 @@ var GLTFWriter = class {
|
|
|
8284
8424
|
* @param {THREE.Object3D} object
|
|
8285
8425
|
* @return {?number}
|
|
8286
8426
|
*/
|
|
8287
|
-
processSkin(
|
|
8427
|
+
processSkin(object3) {
|
|
8288
8428
|
const json = this.json;
|
|
8289
8429
|
const nodeMap = this.nodeMap;
|
|
8290
|
-
const node = json.nodes[nodeMap.get(
|
|
8291
|
-
const skeleton =
|
|
8430
|
+
const node = json.nodes[nodeMap.get(object3)];
|
|
8431
|
+
const skeleton = object3.skeleton;
|
|
8292
8432
|
if (skeleton === void 0) return null;
|
|
8293
|
-
const rootJoint =
|
|
8433
|
+
const rootJoint = object3.skeleton.bones[0];
|
|
8294
8434
|
if (rootJoint === void 0) return null;
|
|
8295
8435
|
const joints = [];
|
|
8296
8436
|
const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16);
|
|
@@ -8298,7 +8438,7 @@ var GLTFWriter = class {
|
|
|
8298
8438
|
for (let i = 0; i < skeleton.bones.length; ++i) {
|
|
8299
8439
|
joints.push(nodeMap.get(skeleton.bones[i]));
|
|
8300
8440
|
temporaryBoneInverse.copy(skeleton.boneInverses[i]);
|
|
8301
|
-
temporaryBoneInverse.multiply(
|
|
8441
|
+
temporaryBoneInverse.multiply(object3.bindMatrix).toArray(inverseBindMatrices, i * 16);
|
|
8302
8442
|
}
|
|
8303
8443
|
if (json.skins === void 0) json.skins = [];
|
|
8304
8444
|
json.skins.push({
|
|
@@ -8314,19 +8454,19 @@ var GLTFWriter = class {
|
|
|
8314
8454
|
* @param {THREE.Object3D} object Object3D to processNodeAsync
|
|
8315
8455
|
* @return {Promise<number>} Index of the node in the nodes list
|
|
8316
8456
|
*/
|
|
8317
|
-
async processNodeAsync(
|
|
8457
|
+
async processNodeAsync(object3) {
|
|
8318
8458
|
const json = this.json;
|
|
8319
8459
|
const options = this.options;
|
|
8320
8460
|
const nodeMap = this.nodeMap;
|
|
8321
8461
|
if (!json.nodes) json.nodes = [];
|
|
8322
|
-
if (
|
|
8323
|
-
return await this._processNodeWithPivotAsync(
|
|
8462
|
+
if (object3.pivot !== null) {
|
|
8463
|
+
return await this._processNodeWithPivotAsync(object3);
|
|
8324
8464
|
}
|
|
8325
8465
|
const nodeDef = {};
|
|
8326
8466
|
if (options.trs) {
|
|
8327
|
-
const rotation =
|
|
8328
|
-
const position =
|
|
8329
|
-
const scale =
|
|
8467
|
+
const rotation = object3.quaternion.toArray();
|
|
8468
|
+
const position = object3.position.toArray();
|
|
8469
|
+
const scale = object3.scale.toArray();
|
|
8330
8470
|
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
8331
8471
|
nodeDef.rotation = rotation;
|
|
8332
8472
|
}
|
|
@@ -8337,28 +8477,28 @@ var GLTFWriter = class {
|
|
|
8337
8477
|
nodeDef.scale = scale;
|
|
8338
8478
|
}
|
|
8339
8479
|
} else {
|
|
8340
|
-
if (
|
|
8341
|
-
|
|
8480
|
+
if (object3.matrixAutoUpdate) {
|
|
8481
|
+
object3.updateMatrix();
|
|
8342
8482
|
}
|
|
8343
|
-
if (isIdentityMatrix(
|
|
8344
|
-
nodeDef.matrix =
|
|
8483
|
+
if (isIdentityMatrix(object3.matrix) === false) {
|
|
8484
|
+
nodeDef.matrix = object3.matrix.elements;
|
|
8345
8485
|
}
|
|
8346
8486
|
}
|
|
8347
|
-
if (
|
|
8348
|
-
this.serializeUserData(
|
|
8349
|
-
if (
|
|
8350
|
-
const meshIndex = await this.processMeshAsync(
|
|
8487
|
+
if (object3.name !== "") nodeDef.name = String(object3.name);
|
|
8488
|
+
this.serializeUserData(object3, nodeDef);
|
|
8489
|
+
if (object3.isMesh || object3.isLine || object3.isPoints) {
|
|
8490
|
+
const meshIndex = await this.processMeshAsync(object3);
|
|
8351
8491
|
if (meshIndex !== null) nodeDef.mesh = meshIndex;
|
|
8352
|
-
} else if (
|
|
8353
|
-
nodeDef.camera = this.processCamera(
|
|
8492
|
+
} else if (object3.isCamera) {
|
|
8493
|
+
nodeDef.camera = this.processCamera(object3);
|
|
8354
8494
|
}
|
|
8355
|
-
if (
|
|
8495
|
+
if (object3.isSkinnedMesh) this.skins.push(object3);
|
|
8356
8496
|
const nodeIndex = json.nodes.push(nodeDef) - 1;
|
|
8357
|
-
nodeMap.set(
|
|
8358
|
-
if (
|
|
8497
|
+
nodeMap.set(object3, nodeIndex);
|
|
8498
|
+
if (object3.children.length > 0) {
|
|
8359
8499
|
const children = [];
|
|
8360
|
-
for (let i = 0, l =
|
|
8361
|
-
const child =
|
|
8500
|
+
for (let i = 0, l = object3.children.length; i < l; i++) {
|
|
8501
|
+
const child = object3.children[i];
|
|
8362
8502
|
if (child.visible || options.onlyVisible === false) {
|
|
8363
8503
|
const childNodeIndex = await this.processNodeAsync(child);
|
|
8364
8504
|
if (childNodeIndex !== null) children.push(childNodeIndex);
|
|
@@ -8367,7 +8507,7 @@ var GLTFWriter = class {
|
|
|
8367
8507
|
if (children.length > 0) nodeDef.children = children;
|
|
8368
8508
|
}
|
|
8369
8509
|
await this._invokeAllAsync(function(ext) {
|
|
8370
|
-
ext.writeNode && ext.writeNode(
|
|
8510
|
+
ext.writeNode && ext.writeNode(object3, nodeDef);
|
|
8371
8511
|
});
|
|
8372
8512
|
return nodeIndex;
|
|
8373
8513
|
}
|
|
@@ -8376,19 +8516,19 @@ var GLTFWriter = class {
|
|
|
8376
8516
|
* @param {THREE.Object3D} object Object3D with pivot
|
|
8377
8517
|
* @return {Promise<number>} Index of the container node
|
|
8378
8518
|
*/
|
|
8379
|
-
async _processNodeWithPivotAsync(
|
|
8519
|
+
async _processNodeWithPivotAsync(object3) {
|
|
8380
8520
|
const json = this.json;
|
|
8381
8521
|
const options = this.options;
|
|
8382
8522
|
const nodeMap = this.nodeMap;
|
|
8383
|
-
const pivot =
|
|
8523
|
+
const pivot = object3.pivot;
|
|
8384
8524
|
const containerDef = {};
|
|
8385
|
-
const rotation =
|
|
8525
|
+
const rotation = object3.quaternion.toArray();
|
|
8386
8526
|
const position = [
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8527
|
+
object3.position.x + pivot.x,
|
|
8528
|
+
object3.position.y + pivot.y,
|
|
8529
|
+
object3.position.z + pivot.z
|
|
8390
8530
|
];
|
|
8391
|
-
const scale =
|
|
8531
|
+
const scale = object3.scale.toArray();
|
|
8392
8532
|
if (!equalArray(rotation, [0, 0, 0, 1])) {
|
|
8393
8533
|
containerDef.rotation = rotation;
|
|
8394
8534
|
}
|
|
@@ -8399,28 +8539,28 @@ var GLTFWriter = class {
|
|
|
8399
8539
|
containerDef.scale = scale;
|
|
8400
8540
|
}
|
|
8401
8541
|
containerDef.extras = { pivot: pivot.toArray() };
|
|
8402
|
-
if (
|
|
8403
|
-
this.serializeUserData(
|
|
8542
|
+
if (object3.name !== "") containerDef.name = String(object3.name);
|
|
8543
|
+
this.serializeUserData(object3, containerDef);
|
|
8404
8544
|
const containerIndex = json.nodes.push(containerDef) - 1;
|
|
8405
|
-
nodeMap.set(
|
|
8545
|
+
nodeMap.set(object3, containerIndex);
|
|
8406
8546
|
const childDef = {};
|
|
8407
8547
|
const childPosition = [-pivot.x, -pivot.y, -pivot.z];
|
|
8408
8548
|
if (!equalArray(childPosition, [0, 0, 0])) {
|
|
8409
8549
|
childDef.translation = childPosition;
|
|
8410
8550
|
}
|
|
8411
|
-
if (
|
|
8412
|
-
const meshIndex = await this.processMeshAsync(
|
|
8551
|
+
if (object3.isMesh || object3.isLine || object3.isPoints) {
|
|
8552
|
+
const meshIndex = await this.processMeshAsync(object3);
|
|
8413
8553
|
if (meshIndex !== null) childDef.mesh = meshIndex;
|
|
8414
|
-
} else if (
|
|
8415
|
-
childDef.camera = this.processCamera(
|
|
8554
|
+
} else if (object3.isCamera) {
|
|
8555
|
+
childDef.camera = this.processCamera(object3);
|
|
8416
8556
|
}
|
|
8417
|
-
if (
|
|
8557
|
+
if (object3.isSkinnedMesh) this.skins.push(object3);
|
|
8418
8558
|
const childIndex = json.nodes.push(childDef) - 1;
|
|
8419
8559
|
const containerChildren = [childIndex];
|
|
8420
|
-
if (
|
|
8560
|
+
if (object3.children.length > 0) {
|
|
8421
8561
|
const grandchildren = [];
|
|
8422
|
-
for (let i = 0, l =
|
|
8423
|
-
const child =
|
|
8562
|
+
for (let i = 0, l = object3.children.length; i < l; i++) {
|
|
8563
|
+
const child = object3.children[i];
|
|
8424
8564
|
if (child.visible || options.onlyVisible === false) {
|
|
8425
8565
|
const childNodeIndex = await this.processNodeAsync(child);
|
|
8426
8566
|
if (childNodeIndex !== null) grandchildren.push(childNodeIndex);
|
|
@@ -8430,7 +8570,7 @@ var GLTFWriter = class {
|
|
|
8430
8570
|
}
|
|
8431
8571
|
containerDef.children = containerChildren;
|
|
8432
8572
|
await this._invokeAllAsync(function(ext) {
|
|
8433
|
-
ext.writeNode && ext.writeNode(
|
|
8573
|
+
ext.writeNode && ext.writeNode(object3, containerDef);
|
|
8434
8574
|
});
|
|
8435
8575
|
return containerIndex;
|
|
8436
8576
|
}
|
|
@@ -8873,10 +9013,10 @@ var GLTFMeshGpuInstancing = class {
|
|
|
8873
9013
|
this.writer = writer;
|
|
8874
9014
|
this.name = "EXT_mesh_gpu_instancing";
|
|
8875
9015
|
}
|
|
8876
|
-
writeNode(
|
|
8877
|
-
if (!
|
|
9016
|
+
writeNode(object3, nodeDef) {
|
|
9017
|
+
if (!object3.isInstancedMesh) return;
|
|
8878
9018
|
const writer = this.writer;
|
|
8879
|
-
const mesh =
|
|
9019
|
+
const mesh = object3;
|
|
8880
9020
|
const translationAttr = new Float32Array(mesh.count * 3);
|
|
8881
9021
|
const rotationAttr = new Float32Array(mesh.count * 4);
|
|
8882
9022
|
const scaleAttr = new Float32Array(mesh.count * 3);
|
|
@@ -9066,8 +9206,8 @@ var SceneExporter = class {
|
|
|
9066
9206
|
}
|
|
9067
9207
|
}
|
|
9068
9208
|
};
|
|
9069
|
-
function localMatrix(
|
|
9070
|
-
return
|
|
9209
|
+
function localMatrix(object3) {
|
|
9210
|
+
return object3.matrixAutoUpdate ? new import_three19.Matrix4().compose(object3.position, object3.quaternion, object3.scale) : object3.matrix.clone();
|
|
9071
9211
|
}
|
|
9072
9212
|
function createSnapshot(root, gltf, bakeColors = false) {
|
|
9073
9213
|
const scene = new import_three19.Scene();
|
|
@@ -9171,24 +9311,24 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
9171
9311
|
scene.add(copy);
|
|
9172
9312
|
}
|
|
9173
9313
|
};
|
|
9174
|
-
const visit = (
|
|
9175
|
-
if (!
|
|
9176
|
-
const world = parentWorld.clone().multiply(localMatrix(
|
|
9177
|
-
const mesh =
|
|
9314
|
+
const visit = (object3, parentWorld) => {
|
|
9315
|
+
if (!object3.visible) return;
|
|
9316
|
+
const world = parentWorld.clone().multiply(localMatrix(object3));
|
|
9317
|
+
const mesh = object3;
|
|
9178
9318
|
if (mesh.isMesh) {
|
|
9179
9319
|
const instanced = mesh;
|
|
9180
9320
|
if (instanced.isInstancedMesh) {
|
|
9181
9321
|
for (let i = 0; i < instanced.count; i++) {
|
|
9182
9322
|
const matrix = new import_three19.Matrix4();
|
|
9183
9323
|
instanced.getMatrixAt(i, matrix);
|
|
9184
|
-
const
|
|
9185
|
-
addMesh(mesh, world.clone().multiply(matrix),
|
|
9324
|
+
const color2 = instanced.instanceColor ? new import_three19.Color().fromBufferAttribute(instanced.instanceColor, i) : void 0;
|
|
9325
|
+
addMesh(mesh, world.clone().multiply(matrix), color2);
|
|
9186
9326
|
}
|
|
9187
9327
|
} else {
|
|
9188
9328
|
addMesh(mesh, world);
|
|
9189
9329
|
}
|
|
9190
9330
|
}
|
|
9191
|
-
for (const child of
|
|
9331
|
+
for (const child of object3.children) visit(child, world);
|
|
9192
9332
|
};
|
|
9193
9333
|
try {
|
|
9194
9334
|
const ancestors = [];
|
|
@@ -9264,13 +9404,13 @@ init_AssetKey();
|
|
|
9264
9404
|
|
|
9265
9405
|
// src/gui/GuiText.ts
|
|
9266
9406
|
var import_three20 = require("three");
|
|
9267
|
-
async function layoutGuiText(
|
|
9407
|
+
async function layoutGuiText(text2, options = {}) {
|
|
9268
9408
|
const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
|
|
9269
9409
|
if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
|
|
9270
9410
|
throw new Error("Text wrap width and line height must be positive");
|
|
9271
9411
|
}
|
|
9272
9412
|
const font = await Fonts.get(options.font);
|
|
9273
|
-
const runs = typeof
|
|
9413
|
+
const runs = typeof text2 === "string" ? [{ text: text2 }] : text2;
|
|
9274
9414
|
const glyphs = [], lineWidths = [];
|
|
9275
9415
|
let line = [], width = 0;
|
|
9276
9416
|
let trailingNewline = false;
|
|
@@ -9324,7 +9464,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
9324
9464
|
batch = { image: glyph?.image, positions: [], uvs: [], colors: [], indices: [] };
|
|
9325
9465
|
batches.push(batch);
|
|
9326
9466
|
}
|
|
9327
|
-
const
|
|
9467
|
+
const color2 = new import_three20.Color(isShadow ? (style.color & 16579836) >> 2 : style.color);
|
|
9328
9468
|
const offset = isShadow ? 1 : 0;
|
|
9329
9469
|
const top = glyph ? 7 - glyph.ascent : 0;
|
|
9330
9470
|
const height = glyph ? glyph.height * glyph.scale : 8;
|
|
@@ -9352,7 +9492,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
9352
9492
|
const v0 = glyph ? 1 - glyph.y / glyph.image.height : 1;
|
|
9353
9493
|
const v1 = glyph ? 1 - (glyph.y + glyph.height) / glyph.image.height : 0;
|
|
9354
9494
|
batch.uvs.push(u0, v0, u1, v0, u0, v1, u1, v1);
|
|
9355
|
-
for (let i = 0; i < 4; i++) batch.colors.push(
|
|
9495
|
+
for (let i = 0; i < 4; i++) batch.colors.push(color2.r, color2.g, color2.b);
|
|
9356
9496
|
batch.indices.push(base, base + 2, base + 1, base + 2, base + 3, base + 1);
|
|
9357
9497
|
};
|
|
9358
9498
|
for (const boldOffset of style.bold ? [0, 1] : [0]) {
|
|
@@ -9386,12 +9526,19 @@ var GuiHelper = class {
|
|
|
9386
9526
|
size: [width + 24, height + 24]
|
|
9387
9527
|
}));
|
|
9388
9528
|
let y = position[1];
|
|
9389
|
-
lines.forEach((
|
|
9390
|
-
layers.push({ ...textOptions, name: `tooltip-line-${index}`, text, position: [position[0], y] });
|
|
9529
|
+
lines.forEach((text2, index) => {
|
|
9530
|
+
layers.push({ ...textOptions, name: `tooltip-line-${index}`, text: text2, position: [position[0], y] });
|
|
9391
9531
|
y += layouts[index].height + (index === 0 ? titleGap : 0);
|
|
9392
9532
|
});
|
|
9393
9533
|
return layers;
|
|
9394
9534
|
}
|
|
9535
|
+
/**
|
|
9536
|
+
* Calculates a slot's top-left position in GUI pixels.
|
|
9537
|
+
* @param slot - Zero-based slot index, or `[column, row]`.
|
|
9538
|
+
* @param origin - Position of the first slot.
|
|
9539
|
+
* @param offset - Horizontal and vertical spacing between slot origins, in pixels.
|
|
9540
|
+
* @param rowSize - Slots per row when `slot` is an index.
|
|
9541
|
+
*/
|
|
9395
9542
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
9396
9543
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
9397
9544
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
@@ -9836,29 +9983,29 @@ var SceneInspector = class {
|
|
|
9836
9983
|
this.objectControlsContainer.innerHTML = "";
|
|
9837
9984
|
this.addControls(targetObject, targetIntersection, instance);
|
|
9838
9985
|
}
|
|
9839
|
-
addControls(
|
|
9986
|
+
addControls(object3, intersection, instance) {
|
|
9840
9987
|
const container = document.createElement("div");
|
|
9841
9988
|
container.append(this.separator("Select Parent/Child"));
|
|
9842
|
-
if (
|
|
9843
|
-
container.append(this.buttonControl("Select Parent " +
|
|
9844
|
-
this.selectObject(
|
|
9989
|
+
if (object3.parent) {
|
|
9990
|
+
container.append(this.buttonControl("Select Parent " + object3.parent.constructor.name + " " + object3.parent.name, "P", () => {
|
|
9991
|
+
this.selectObject(object3.parent, intersection, instance);
|
|
9845
9992
|
}));
|
|
9846
9993
|
}
|
|
9847
|
-
if (
|
|
9994
|
+
if (object3.children.length > 0) {
|
|
9848
9995
|
let i = 1;
|
|
9849
|
-
for (let child of
|
|
9996
|
+
for (let child of object3.children) {
|
|
9850
9997
|
container.append(this.buttonControl("Select Child " + child.constructor.name + " " + child.name, "C" + i++, () => {
|
|
9851
9998
|
this.selectObject(child, intersection, instance);
|
|
9852
9999
|
}));
|
|
9853
10000
|
}
|
|
9854
10001
|
}
|
|
9855
10002
|
container.append(this.separator());
|
|
9856
|
-
const selectedInstance = instance && (
|
|
10003
|
+
const selectedInstance = instance && (object3 === instance.instanceable || object3 === intersection?.object) ? instance : void 0;
|
|
9857
10004
|
if (!selectedInstance) {
|
|
9858
|
-
container.append(this.toggleControl("Visibility", "V",
|
|
10005
|
+
container.append(this.toggleControl("Visibility", "V", object3.visible, (v) => object3.visible = v));
|
|
9859
10006
|
}
|
|
9860
10007
|
container.append(this.separator("Mesh"));
|
|
9861
|
-
this.addObjectControls(
|
|
10008
|
+
this.addObjectControls(object3, intersection, container, selectedInstance);
|
|
9862
10009
|
container.append(this.separator());
|
|
9863
10010
|
this.objectControlsContainer.append(container);
|
|
9864
10011
|
}
|
|
@@ -10049,6 +10196,7 @@ var SceneStatsDisplay = class {
|
|
|
10049
10196
|
appendTo(el) {
|
|
10050
10197
|
el.append(this.statsContainer);
|
|
10051
10198
|
}
|
|
10199
|
+
/** Stops the refresh timer and removes the panel from the page. */
|
|
10052
10200
|
dispose() {
|
|
10053
10201
|
clearInterval(this.interval);
|
|
10054
10202
|
this.interval = void 0;
|
|
@@ -10073,6 +10221,7 @@ var InstanceManager = class {
|
|
|
10073
10221
|
this.isInstanceManager = true;
|
|
10074
10222
|
this.instanceCache = {};
|
|
10075
10223
|
}
|
|
10224
|
+
/** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
|
|
10076
10225
|
async get(key) {
|
|
10077
10226
|
if (key in this.instanceCache) {
|
|
10078
10227
|
console.debug(p9, "key in cache", key);
|
|
@@ -10080,6 +10229,7 @@ var InstanceManager = class {
|
|
|
10080
10229
|
}
|
|
10081
10230
|
return void 0;
|
|
10082
10231
|
}
|
|
10232
|
+
/** Allocates a placement, calling the supplier once when the shared model is first needed. */
|
|
10083
10233
|
async getOrCreate(key, supplier) {
|
|
10084
10234
|
if (key in this.instanceCache) {
|
|
10085
10235
|
return await this.get(key);
|
|
@@ -10096,6 +10246,7 @@ var InstanceManager = class {
|
|
|
10096
10246
|
throw error;
|
|
10097
10247
|
}
|
|
10098
10248
|
}
|
|
10249
|
+
/** Forgets cached models without disposing them or releasing their existing placements. */
|
|
10099
10250
|
reset() {
|
|
10100
10251
|
for (let instanceCacheKey in this.instanceCache) {
|
|
10101
10252
|
delete this.instanceCache[instanceCacheKey];
|
|
@@ -10141,6 +10292,7 @@ function matchesCondition(condition, state) {
|
|
|
10141
10292
|
});
|
|
10142
10293
|
}
|
|
10143
10294
|
var BlockStateResolver = class {
|
|
10295
|
+
/** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
|
|
10144
10296
|
static async defaults(blockState) {
|
|
10145
10297
|
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
10146
10298
|
const state = {};
|
|
@@ -10160,9 +10312,11 @@ var BlockStateResolver = class {
|
|
|
10160
10312
|
}
|
|
10161
10313
|
return state;
|
|
10162
10314
|
}
|
|
10315
|
+
/** Selects matching models. Supply `choose` to control selection within each alternatives array. */
|
|
10163
10316
|
static select(blockState, state, choose = this.choose) {
|
|
10164
10317
|
return this.matching(blockState, state).map(choose);
|
|
10165
10318
|
}
|
|
10319
|
+
/** Returns matching model groups before choosing weighted alternatives. */
|
|
10166
10320
|
static matching(blockState, state) {
|
|
10167
10321
|
const out = [];
|
|
10168
10322
|
if (blockState.variants) {
|
|
@@ -10186,6 +10340,7 @@ var BlockStateResolver = class {
|
|
|
10186
10340
|
}
|
|
10187
10341
|
return out;
|
|
10188
10342
|
}
|
|
10343
|
+
/** Selects a random alternative using positive integer weights, each defaulting to 1. */
|
|
10189
10344
|
static choose(variants) {
|
|
10190
10345
|
if (!Array.isArray(variants)) return variants;
|
|
10191
10346
|
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
@@ -10203,6 +10358,7 @@ var BlockStateResolver = class {
|
|
|
10203
10358
|
}
|
|
10204
10359
|
return variants[variants.length - 1];
|
|
10205
10360
|
}
|
|
10361
|
+
/** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
|
|
10206
10362
|
static rotation(variant) {
|
|
10207
10363
|
const rotation = new import_three29.Euler();
|
|
10208
10364
|
if (typeof variant.x !== "undefined") {
|
|
@@ -10265,29 +10421,29 @@ var BlockTints = class {
|
|
|
10265
10421
|
}
|
|
10266
10422
|
}
|
|
10267
10423
|
if (!indices.size) return tints;
|
|
10268
|
-
let
|
|
10424
|
+
let color2;
|
|
10269
10425
|
switch (rule.source) {
|
|
10270
10426
|
case "constant":
|
|
10271
|
-
|
|
10427
|
+
color2 = rule.color;
|
|
10272
10428
|
break;
|
|
10273
10429
|
case "grass":
|
|
10274
|
-
|
|
10430
|
+
color2 = await Colormaps.grassColor(key);
|
|
10275
10431
|
break;
|
|
10276
10432
|
case "redstone": {
|
|
10277
10433
|
const power = Number(state.power ?? 0) / 15;
|
|
10278
10434
|
const red = power * 0.6 + (power > 0 ? 0.4 : 0.3);
|
|
10279
10435
|
const green = Math.max(0, power * power * 0.7 - 0.5);
|
|
10280
10436
|
const blue = Math.max(0, power * power * 0.6 - 0.7);
|
|
10281
|
-
|
|
10437
|
+
color2 = Math.floor(red * 255) << 16 | Math.floor(green * 255) << 8 | Math.floor(blue * 255);
|
|
10282
10438
|
break;
|
|
10283
10439
|
}
|
|
10284
10440
|
case "stem": {
|
|
10285
10441
|
const age = Number(state.age ?? 0);
|
|
10286
|
-
|
|
10442
|
+
color2 = age * 32 << 16 | 255 - age * 8 << 8 | age * 4;
|
|
10287
10443
|
break;
|
|
10288
10444
|
}
|
|
10289
10445
|
}
|
|
10290
|
-
return { ...Object.fromEntries([...indices].map((index) => [index,
|
|
10446
|
+
return { ...Object.fromEntries([...indices].map((index) => [index, color2])), ...tints };
|
|
10291
10447
|
}
|
|
10292
10448
|
};
|
|
10293
10449
|
|
|
@@ -10424,8 +10580,8 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10424
10580
|
return false;
|
|
10425
10581
|
}
|
|
10426
10582
|
return this._models.some((model) => {
|
|
10427
|
-
const
|
|
10428
|
-
return
|
|
10583
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10584
|
+
return object3.isOpaqueFullCube && this.getModelCullMask(model, 63) === 63;
|
|
10429
10585
|
});
|
|
10430
10586
|
}
|
|
10431
10587
|
getModelMatrix(model) {
|
|
@@ -10434,8 +10590,8 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10434
10590
|
return model.matrix.clone();
|
|
10435
10591
|
}
|
|
10436
10592
|
getModelCullMask(model, worldMask) {
|
|
10437
|
-
const
|
|
10438
|
-
if (
|
|
10593
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10594
|
+
if (object3.options.displayPosition) return 0;
|
|
10439
10595
|
const position = new import_three32.Vector3();
|
|
10440
10596
|
const rotation = new import_three32.Quaternion();
|
|
10441
10597
|
const scale = new import_three32.Vector3();
|
|
@@ -10452,14 +10608,14 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10452
10608
|
replacements.push(model);
|
|
10453
10609
|
continue;
|
|
10454
10610
|
}
|
|
10455
|
-
const
|
|
10611
|
+
const object3 = isInstanceReference(model) ? model.instanceable : model;
|
|
10456
10612
|
const cullMask = this.getModelCullMask(model, worldMask);
|
|
10457
|
-
if (cullMask === (
|
|
10613
|
+
if (cullMask === (object3.options.cullMask ?? 0)) {
|
|
10458
10614
|
replacements.push(model);
|
|
10459
10615
|
continue;
|
|
10460
10616
|
}
|
|
10461
10617
|
const matrix = this.getModelMatrix(model);
|
|
10462
|
-
const replacement = await this.scene.addModel(
|
|
10618
|
+
const replacement = await this.scene.addModel(object3.originalModel, { ...object3.options, cullMask });
|
|
10463
10619
|
replacements.push(replacement);
|
|
10464
10620
|
if (isInstanceReference(replacement)) {
|
|
10465
10621
|
replacement.setMatrix(matrix);
|
|
@@ -10467,8 +10623,8 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10467
10623
|
replacement.matrix.copy(matrix);
|
|
10468
10624
|
replacement.matrixWorldNeedsUpdate = true;
|
|
10469
10625
|
matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
|
|
10470
|
-
replacement.matrixAutoUpdate =
|
|
10471
|
-
replacement.visible =
|
|
10626
|
+
replacement.matrixAutoUpdate = object3.matrixAutoUpdate;
|
|
10627
|
+
replacement.visible = object3.visible;
|
|
10472
10628
|
}
|
|
10473
10629
|
}
|
|
10474
10630
|
} catch (error) {
|
|
@@ -10484,6 +10640,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10484
10640
|
}
|
|
10485
10641
|
this.notifyDirty();
|
|
10486
10642
|
}
|
|
10643
|
+
/** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
|
|
10487
10644
|
get state() {
|
|
10488
10645
|
return this._state;
|
|
10489
10646
|
}
|
|
@@ -10583,6 +10740,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10583
10740
|
obj.setPosition(this.position);
|
|
10584
10741
|
return obj;
|
|
10585
10742
|
}
|
|
10743
|
+
/** Clears selected properties and rebuilds models without reapplying property defaults. */
|
|
10586
10744
|
async resetState() {
|
|
10587
10745
|
this._previousState = this._state;
|
|
10588
10746
|
this._state = {};
|
|
@@ -12486,6 +12644,11 @@ function compoundList(tags, name) {
|
|
|
12486
12644
|
// src/model/multiblock/StructureParser.ts
|
|
12487
12645
|
init_MineRenderError();
|
|
12488
12646
|
var StructureParser = class {
|
|
12647
|
+
/**
|
|
12648
|
+
* Parses decoded NBT, omitting air blocks.
|
|
12649
|
+
* @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
|
|
12650
|
+
* @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
|
|
12651
|
+
*/
|
|
12489
12652
|
static async parse(_nbt, paletteIndex) {
|
|
12490
12653
|
const nbt = _nbt.value;
|
|
12491
12654
|
let palette;
|
|
@@ -13320,6 +13483,7 @@ var SkinImage = class {
|
|
|
13320
13483
|
// src/skin/SkinTextures.ts
|
|
13321
13484
|
init_Textures();
|
|
13322
13485
|
var SkinTextures = class {
|
|
13486
|
+
/** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
|
|
13323
13487
|
static async get(src, legacy) {
|
|
13324
13488
|
const image = await SkinImage.getData(src);
|
|
13325
13489
|
const scale = image.width / 64;
|
|
@@ -13493,6 +13657,14 @@ var SkinObject = class extends SceneObject {
|
|
|
13493
13657
|
}
|
|
13494
13658
|
}
|
|
13495
13659
|
}
|
|
13660
|
+
/**
|
|
13661
|
+
* Loads a skin texture, detecting slim arms and legacy layouts by default.
|
|
13662
|
+
* To override detection, set `slim` or `legacy` in the options passed to
|
|
13663
|
+
* `new SkinObject(options)` or `scene.addSkin(src, options)`.
|
|
13664
|
+
* Use {@link setSlim} or {@link setLegacy} to change these settings later.
|
|
13665
|
+
*
|
|
13666
|
+
* @param src - URL of the skin texture.
|
|
13667
|
+
*/
|
|
13496
13668
|
async setSkinTexture(src) {
|
|
13497
13669
|
if (typeof src === "undefined") return;
|
|
13498
13670
|
this.skinTextureSrc = src;
|
|
@@ -13600,59 +13772,60 @@ var _MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13600
13772
|
this.options = (0, import_ts_deepmerge8.default)({}, _MineRenderScene.DEFAULT_OPTIONS, options ?? {});
|
|
13601
13773
|
}
|
|
13602
13774
|
add(...objects) {
|
|
13603
|
-
for (const
|
|
13775
|
+
for (const object3 of objects) {
|
|
13604
13776
|
this.dirty = true;
|
|
13605
13777
|
try {
|
|
13606
|
-
super.add(
|
|
13778
|
+
super.add(object3);
|
|
13607
13779
|
} finally {
|
|
13608
|
-
if (
|
|
13609
|
-
this.updateObjectRegistration(
|
|
13780
|
+
if (object3?.isObject3D && object3 !== this) {
|
|
13781
|
+
this.updateObjectRegistration(object3, object3.parent === this);
|
|
13610
13782
|
}
|
|
13611
13783
|
}
|
|
13612
13784
|
}
|
|
13613
13785
|
return this;
|
|
13614
13786
|
}
|
|
13615
13787
|
remove(...objects) {
|
|
13616
|
-
for (const
|
|
13617
|
-
if (!this.children.includes(
|
|
13788
|
+
for (const object3 of objects) {
|
|
13789
|
+
if (!this.children.includes(object3)) continue;
|
|
13618
13790
|
this.dirty = true;
|
|
13619
|
-
this.updateObjectRegistration(
|
|
13791
|
+
this.updateObjectRegistration(object3, false);
|
|
13620
13792
|
try {
|
|
13621
|
-
super.remove(
|
|
13793
|
+
super.remove(object3);
|
|
13622
13794
|
} finally {
|
|
13623
|
-
this.updateObjectRegistration(
|
|
13795
|
+
this.updateObjectRegistration(object3, object3.parent === this);
|
|
13624
13796
|
}
|
|
13625
13797
|
}
|
|
13626
13798
|
return this;
|
|
13627
13799
|
}
|
|
13628
|
-
updateObjectRegistration(
|
|
13629
|
-
if (this.observedObjects.has(
|
|
13630
|
-
const observable =
|
|
13800
|
+
updateObjectRegistration(object3, attached) {
|
|
13801
|
+
if (this.observedObjects.has(object3) === attached) return;
|
|
13802
|
+
const observable = object3;
|
|
13631
13803
|
if (attached) {
|
|
13632
|
-
this.observedObjects.add(
|
|
13804
|
+
this.observedObjects.add(object3);
|
|
13633
13805
|
observable.addEventListener("change", this.onObjectChange);
|
|
13634
13806
|
} else {
|
|
13635
|
-
this.observedObjects.delete(
|
|
13807
|
+
this.observedObjects.delete(object3);
|
|
13636
13808
|
observable.removeEventListener("change", this.onObjectChange);
|
|
13637
13809
|
}
|
|
13638
13810
|
const change = attached ? 1 : -1;
|
|
13639
13811
|
this.stats.objectCount += change;
|
|
13640
|
-
if (isSceneObject(
|
|
13812
|
+
if (isSceneObject(object3)) {
|
|
13641
13813
|
this.stats.sceneObjectCount += change;
|
|
13642
13814
|
}
|
|
13643
13815
|
}
|
|
13644
|
-
|
|
13816
|
+
/** Initializes each object before attaching it to the scene. */
|
|
13817
|
+
async initAndAdd(...object3) {
|
|
13645
13818
|
this.dirty = true;
|
|
13646
|
-
for (let obj of
|
|
13819
|
+
for (let obj of object3) {
|
|
13647
13820
|
await obj.init();
|
|
13648
13821
|
}
|
|
13649
|
-
return this.add(...
|
|
13822
|
+
return this.add(...object3);
|
|
13650
13823
|
}
|
|
13651
|
-
async addSceneObject(
|
|
13824
|
+
async addSceneObject(asset2, objectSupplier, _options, parent = this) {
|
|
13652
13825
|
this.dirty = true;
|
|
13653
13826
|
const obj = await objectSupplier();
|
|
13654
|
-
if (obj?.options?.instanceMeshes &&
|
|
13655
|
-
let key =
|
|
13827
|
+
if (obj?.options?.instanceMeshes && asset2.key && asset2.key?.assetType === "models") {
|
|
13828
|
+
let key = asset2.key.serialize();
|
|
13656
13829
|
if (isModelObject(obj)) {
|
|
13657
13830
|
const { displayPosition, uvLockRotation, tints, cullMask } = obj.options;
|
|
13658
13831
|
if (displayPosition) key += `|display:${displayPosition}`;
|
|
@@ -13676,13 +13849,33 @@ var _MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13676
13849
|
return obj;
|
|
13677
13850
|
}
|
|
13678
13851
|
}
|
|
13852
|
+
/**
|
|
13853
|
+
* Adds a model loaded with {@link Models.getMerged}.
|
|
13854
|
+
* Set `options.instanceMeshes` to `false` to create a separate ModelObject.
|
|
13855
|
+
*
|
|
13856
|
+
* @param parent - Object to attach the model to. Defaults to this scene.
|
|
13857
|
+
* @returns The model, or a reference to one placement of a shared model.
|
|
13858
|
+
*/
|
|
13679
13859
|
async addModel(model, options, parent = this) {
|
|
13680
13860
|
options = { ...options, tints: await ItemTints.get(model, options?.tints) };
|
|
13681
13861
|
return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
|
|
13682
13862
|
}
|
|
13863
|
+
/**
|
|
13864
|
+
* Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
|
|
13865
|
+
* Set `options.initialState` to choose block properties such as `facing` or `axis`.
|
|
13866
|
+
* Use the returned object's `setPosition` method to move all of its model parts.
|
|
13867
|
+
*/
|
|
13683
13868
|
async addBlock(blockState, options, parent = this) {
|
|
13684
13869
|
return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
|
|
13685
13870
|
}
|
|
13871
|
+
/**
|
|
13872
|
+
* Loads a skin and adds an initialized player model.
|
|
13873
|
+
*
|
|
13874
|
+
* @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
|
|
13875
|
+
* Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
|
|
13876
|
+
* @param options - Player settings, including `slim` and `legacy` detection overrides.
|
|
13877
|
+
* @param parent - Object to attach the player to. Defaults to this scene.
|
|
13878
|
+
*/
|
|
13686
13879
|
async addSkin(skin, options, parent = this) {
|
|
13687
13880
|
this.dirty = true;
|
|
13688
13881
|
const obj = new SkinObject(options);
|
|
@@ -13694,9 +13887,14 @@ var _MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13694
13887
|
parent.add(obj);
|
|
13695
13888
|
return obj;
|
|
13696
13889
|
}
|
|
13890
|
+
/** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
|
|
13697
13891
|
async addEntity(entity, options, parent = this) {
|
|
13698
13892
|
return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
|
|
13699
13893
|
}
|
|
13894
|
+
/**
|
|
13895
|
+
* Adds GUI layers in draw order. One GUI pixel equals one scene unit.
|
|
13896
|
+
* Layer positions start at the top left, with positive GUI y pointing down.
|
|
13897
|
+
*/
|
|
13700
13898
|
async addGui(layers, options, parent = this) {
|
|
13701
13899
|
const obj = new GuiObject(layers, options);
|
|
13702
13900
|
obj.scene = this;
|
|
@@ -13727,11 +13925,11 @@ var _changeEvent = { type: "change" };
|
|
|
13727
13925
|
var _startEvent = { type: "start" };
|
|
13728
13926
|
var _endEvent = { type: "end" };
|
|
13729
13927
|
var OrbitControls = class extends import_three35.EventDispatcher {
|
|
13730
|
-
constructor(
|
|
13928
|
+
constructor(object3, domElement) {
|
|
13731
13929
|
super();
|
|
13732
13930
|
if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
|
|
13733
13931
|
if (domElement === document) console.error('THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
|
|
13734
|
-
this.object =
|
|
13932
|
+
this.object = object3;
|
|
13735
13933
|
this.domElement = domElement;
|
|
13736
13934
|
this.domElement.style.touchAction = "none";
|
|
13737
13935
|
this.enabled = true;
|
|
@@ -13788,7 +13986,7 @@ var OrbitControls = class extends import_three35.EventDispatcher {
|
|
|
13788
13986
|
};
|
|
13789
13987
|
this.update = function() {
|
|
13790
13988
|
const offset = new import_three35.Vector3();
|
|
13791
|
-
const quat = new import_three35.Quaternion().setFromUnitVectors(
|
|
13989
|
+
const quat = new import_three35.Quaternion().setFromUnitVectors(object3.up, new import_three35.Vector3(0, 1, 0));
|
|
13792
13990
|
const quatInverse = quat.clone().invert();
|
|
13793
13991
|
const lastPosition = new import_three35.Vector3();
|
|
13794
13992
|
const lastQuaternion = new import_three35.Quaternion();
|
|
@@ -14353,8 +14551,8 @@ var OrbitControls = class extends import_three35.EventDispatcher {
|
|
|
14353
14551
|
}
|
|
14354
14552
|
};
|
|
14355
14553
|
var MapControls = class extends OrbitControls {
|
|
14356
|
-
constructor(
|
|
14357
|
-
super(
|
|
14554
|
+
constructor(object3, domElement) {
|
|
14555
|
+
super(object3, domElement);
|
|
14358
14556
|
this.screenSpacePanning = false;
|
|
14359
14557
|
this.mouseButtons.LEFT = import_three35.MOUSE.PAN;
|
|
14360
14558
|
this.mouseButtons.RIGHT = import_three35.MOUSE.ROTATE;
|
|
@@ -14513,6 +14711,7 @@ var _Renderer = class _Renderer {
|
|
|
14513
14711
|
get element() {
|
|
14514
14712
|
return this._element;
|
|
14515
14713
|
}
|
|
14714
|
+
/** Attaches the canvas to an element and sizes it to that element's dimensions. */
|
|
14516
14715
|
appendTo(element) {
|
|
14517
14716
|
if (this._disposed) return;
|
|
14518
14717
|
this._element = element;
|
|
@@ -14540,6 +14739,7 @@ var _Renderer = class _Renderer {
|
|
|
14540
14739
|
events.add(changeEvent2);
|
|
14541
14740
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
14542
14741
|
}
|
|
14742
|
+
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
14543
14743
|
resize(width, height) {
|
|
14544
14744
|
if (this._disposed) return;
|
|
14545
14745
|
if (isPerspectiveCamera(this.camera)) {
|
|
@@ -14578,12 +14778,14 @@ var _Renderer = class _Renderer {
|
|
|
14578
14778
|
if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
|
|
14579
14779
|
};
|
|
14580
14780
|
}
|
|
14781
|
+
/** Starts or resumes the animation loop and registered frame callbacks. */
|
|
14581
14782
|
start() {
|
|
14582
14783
|
if (this._disposed) return;
|
|
14583
14784
|
this.stop();
|
|
14584
14785
|
this._running = true;
|
|
14585
14786
|
if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
|
|
14586
14787
|
}
|
|
14788
|
+
/** Pauses rendering and frame callbacks. Call {@link start} to resume. */
|
|
14587
14789
|
stop() {
|
|
14588
14790
|
if (this._disposed) return;
|
|
14589
14791
|
this._running = false;
|
|
@@ -14692,12 +14894,15 @@ var _Renderer = class _Renderer {
|
|
|
14692
14894
|
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
14693
14895
|
return canvas.toDataURL(mime, quality);
|
|
14694
14896
|
}
|
|
14897
|
+
/** Exports visible scene meshes as OBJ text, without texture images. */
|
|
14695
14898
|
toObj() {
|
|
14696
14899
|
return SceneExporter.toObj(this.scene);
|
|
14697
14900
|
}
|
|
14901
|
+
/** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
|
|
14698
14902
|
toPLY(options) {
|
|
14699
14903
|
return SceneExporter.toPLY(this.scene, options);
|
|
14700
14904
|
}
|
|
14905
|
+
/** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
|
|
14701
14906
|
toGLTF(options) {
|
|
14702
14907
|
return SceneExporter.toGLTF(this.scene, options);
|
|
14703
14908
|
}
|
|
@@ -14775,16 +14980,244 @@ init_SceneObject();
|
|
|
14775
14980
|
// src/index.ts
|
|
14776
14981
|
init_request();
|
|
14777
14982
|
|
|
14983
|
+
// src/scene/SceneDocument.ts
|
|
14984
|
+
init_DisplayPosition();
|
|
14985
|
+
function fail(path, message) {
|
|
14986
|
+
throw new Error(`${path}: ${message}`);
|
|
14987
|
+
}
|
|
14988
|
+
function object2(value, path) {
|
|
14989
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) fail(path, "expected a JSON object");
|
|
14990
|
+
for (const key of Object.keys(value)) {
|
|
14991
|
+
if (["__proto__", "prototype", "constructor"].includes(key)) fail(`${path}.${key}`, "unsupported property");
|
|
14992
|
+
}
|
|
14993
|
+
return value;
|
|
14994
|
+
}
|
|
14995
|
+
function fields(value, path, allowed, required = []) {
|
|
14996
|
+
const input = object2(value, path);
|
|
14997
|
+
for (const key of required) if (input[key] === void 0) fail(`${path}.${key}`, "required");
|
|
14998
|
+
for (const [key, entry] of Object.entries(input)) {
|
|
14999
|
+
if (!Object.prototype.hasOwnProperty.call(allowed, key)) fail(`${path}.${key}`, "unsupported property");
|
|
15000
|
+
if (entry !== void 0) allowed[key](entry, `${path}.${key}`);
|
|
15001
|
+
}
|
|
15002
|
+
return input;
|
|
15003
|
+
}
|
|
15004
|
+
var text = (value, path) => {
|
|
15005
|
+
if (typeof value !== "string" || !value.trim()) fail(path, "expected a nonempty string");
|
|
15006
|
+
};
|
|
15007
|
+
var literalText = (value, path) => {
|
|
15008
|
+
if (typeof value !== "string") fail(path, "expected a string");
|
|
15009
|
+
};
|
|
15010
|
+
var boolean = (value, path) => {
|
|
15011
|
+
if (typeof value !== "boolean") fail(path, "expected a boolean");
|
|
15012
|
+
};
|
|
15013
|
+
var number = (value, path) => {
|
|
15014
|
+
if (typeof value !== "number" || !Number.isFinite(value)) fail(path, "expected a finite number");
|
|
15015
|
+
};
|
|
15016
|
+
var positive = (value, path) => {
|
|
15017
|
+
number(value, path);
|
|
15018
|
+
if (value <= 0) fail(path, "expected a positive number");
|
|
15019
|
+
};
|
|
15020
|
+
var nonnegative = (value, path) => {
|
|
15021
|
+
number(value, path);
|
|
15022
|
+
if (value < 0) fail(path, "expected a nonnegative number");
|
|
15023
|
+
};
|
|
15024
|
+
var color = (value, path) => {
|
|
15025
|
+
number(value, path);
|
|
15026
|
+
if (!Number.isInteger(value) || value < 0 || value > 16777215) {
|
|
15027
|
+
fail(path, "expected an RGB integer from 0 to 16777215");
|
|
15028
|
+
}
|
|
15029
|
+
};
|
|
15030
|
+
var asset = (value, path) => {
|
|
15031
|
+
text(value, path);
|
|
15032
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(value) || value.split(/[:/]/).some((part) => !part || part === "." || part === "..")) {
|
|
15033
|
+
fail(path, "expected a resource ID such as minecraft:stone");
|
|
15034
|
+
}
|
|
15035
|
+
};
|
|
15036
|
+
var version = (value, path) => {
|
|
15037
|
+
text(value, path);
|
|
15038
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(value)) fail(path, "expected a Minecraft version without slashes");
|
|
15039
|
+
};
|
|
15040
|
+
var tuple = (size, item = number) => (value, path) => {
|
|
15041
|
+
if (!Array.isArray(value) || value.length !== size) fail(path, `expected ${size} numbers`);
|
|
15042
|
+
for (let index = 0; index < size; index++) item(value[index], `${path}[${index}]`);
|
|
15043
|
+
};
|
|
15044
|
+
var list = (item) => (value, path) => {
|
|
15045
|
+
if (!Array.isArray(value)) fail(path, "expected an array");
|
|
15046
|
+
for (let index = 0; index < value.length; index++) item(value[index], `${path}[${index}]`);
|
|
15047
|
+
};
|
|
15048
|
+
var dictionary = (item, numericKeys = false) => (value, path) => {
|
|
15049
|
+
for (const [key, entry] of Object.entries(object2(value, path))) {
|
|
15050
|
+
if (numericKeys && !/^\d+$/.test(key)) fail(`${path}.${key}`, "expected a nonnegative tint index");
|
|
15051
|
+
item(entry, `${path}.${key}`);
|
|
15052
|
+
}
|
|
15053
|
+
};
|
|
15054
|
+
var enumeration = (values) => (value, path) => {
|
|
15055
|
+
if (!values.includes(value)) fail(path, `expected one of: ${values.join(", ")}`);
|
|
15056
|
+
};
|
|
15057
|
+
var textStyle = { color, bold: boolean, italic: boolean };
|
|
15058
|
+
function guiLayer(value, path) {
|
|
15059
|
+
const layer = object2(value, path);
|
|
15060
|
+
if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
|
|
15061
|
+
fail(path, "expected exactly one of texture, item, or text");
|
|
15062
|
+
}
|
|
15063
|
+
const layout = { name: text, position: tuple(2), size: tuple(2, positive) };
|
|
15064
|
+
if (layer.texture !== void 0) {
|
|
15065
|
+
fields(value, path, { ...layout, texture: asset, crop: (value2, path2) => {
|
|
15066
|
+
tuple(4)(value2, path2);
|
|
15067
|
+
const [x, y, width, height] = value2;
|
|
15068
|
+
nonnegative(x, `${path2}[0]`);
|
|
15069
|
+
nonnegative(y, `${path2}[1]`);
|
|
15070
|
+
positive(width, `${path2}[2]`);
|
|
15071
|
+
positive(height, `${path2}[3]`);
|
|
15072
|
+
} });
|
|
15073
|
+
} else if (layer.item !== void 0) {
|
|
15074
|
+
fields(value, path, { ...layout, item: asset, tints: dictionary(color, true) });
|
|
15075
|
+
} else {
|
|
15076
|
+
fields(value, path, {
|
|
15077
|
+
...layout,
|
|
15078
|
+
...textStyle,
|
|
15079
|
+
font: asset,
|
|
15080
|
+
shadow: boolean,
|
|
15081
|
+
maxWidth: positive,
|
|
15082
|
+
lineHeight: positive,
|
|
15083
|
+
text: (value2, path2) => {
|
|
15084
|
+
if (typeof value2 === "string") return;
|
|
15085
|
+
list((run, path3) => {
|
|
15086
|
+
fields(run, path3, { text: literalText, ...textStyle }, ["text"]);
|
|
15087
|
+
})(value2, path2);
|
|
15088
|
+
}
|
|
15089
|
+
});
|
|
15090
|
+
}
|
|
15091
|
+
}
|
|
15092
|
+
function validateObject(value, path) {
|
|
15093
|
+
const input = object2(value, path);
|
|
15094
|
+
const common = { id: text, name: text, type: text, position: tuple(3), rotation: tuple(3), scale: tuple(3), visible: boolean };
|
|
15095
|
+
const required = ["id", "type"];
|
|
15096
|
+
const renderOptions = { wireframe: boolean };
|
|
15097
|
+
switch (input.type) {
|
|
15098
|
+
case "skin":
|
|
15099
|
+
fields(value, path, {
|
|
15100
|
+
...common,
|
|
15101
|
+
skin: text,
|
|
15102
|
+
cape: (value2, path2) => {
|
|
15103
|
+
fields(value2, path2, { texture: text, layout: enumeration(["minecraft", "optifine", "labymod"]) }, ["texture"]);
|
|
15104
|
+
},
|
|
15105
|
+
hiddenParts: list(enumeration(SKIN_PARTS)),
|
|
15106
|
+
pose: (value2, path2) => {
|
|
15107
|
+
fields(value2, path2, {
|
|
15108
|
+
head: tuple(3),
|
|
15109
|
+
body: tuple(3),
|
|
15110
|
+
rightArm: tuple(3),
|
|
15111
|
+
leftArm: tuple(3),
|
|
15112
|
+
rightLeg: tuple(3),
|
|
15113
|
+
leftLeg: tuple(3),
|
|
15114
|
+
cape: tuple(3)
|
|
15115
|
+
});
|
|
15116
|
+
},
|
|
15117
|
+
options: (value2, path2) => {
|
|
15118
|
+
fields(value2, path2, { slim: boolean, legacy: boolean });
|
|
15119
|
+
}
|
|
15120
|
+
}, required);
|
|
15121
|
+
break;
|
|
15122
|
+
case "block":
|
|
15123
|
+
fields(value, path, {
|
|
15124
|
+
...common,
|
|
15125
|
+
asset,
|
|
15126
|
+
state: dictionary(text),
|
|
15127
|
+
options: (value2, path2) => {
|
|
15128
|
+
fields(value2, path2, { ...renderOptions, tints: dictionary(color, true) });
|
|
15129
|
+
}
|
|
15130
|
+
}, [...required, "asset"]);
|
|
15131
|
+
break;
|
|
15132
|
+
case "item":
|
|
15133
|
+
case "model":
|
|
15134
|
+
fields(value, path, {
|
|
15135
|
+
...common,
|
|
15136
|
+
asset,
|
|
15137
|
+
options: (value2, path2) => {
|
|
15138
|
+
fields(value2, path2, { ...renderOptions, displayPosition: enumeration(DISPLAY_POSITIONS), tints: dictionary(color, true) });
|
|
15139
|
+
}
|
|
15140
|
+
}, [...required, "asset"]);
|
|
15141
|
+
break;
|
|
15142
|
+
case "entity":
|
|
15143
|
+
fields(value, path, {
|
|
15144
|
+
...common,
|
|
15145
|
+
asset,
|
|
15146
|
+
texture: asset,
|
|
15147
|
+
layers: list(text),
|
|
15148
|
+
when: list(text),
|
|
15149
|
+
textures: dictionary(asset),
|
|
15150
|
+
options: (value2, path2) => {
|
|
15151
|
+
fields(value2, path2, {
|
|
15152
|
+
...renderOptions,
|
|
15153
|
+
flip: boolean,
|
|
15154
|
+
tints: dictionary((value3, path3) => {
|
|
15155
|
+
typeof value3 === "string" ? text(value3, path3) : color(value3, path3);
|
|
15156
|
+
})
|
|
15157
|
+
});
|
|
15158
|
+
},
|
|
15159
|
+
animation: (value2, path2) => {
|
|
15160
|
+
fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
|
|
15161
|
+
}
|
|
15162
|
+
}, [...required, "asset"]);
|
|
15163
|
+
if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
|
|
15164
|
+
break;
|
|
15165
|
+
case "gui":
|
|
15166
|
+
fields(value, path, { ...common, layers: list(guiLayer) }, [...required, "layers"]);
|
|
15167
|
+
break;
|
|
15168
|
+
default:
|
|
15169
|
+
fail(`${path}.type`, "expected skin, block, item, entity, model, or gui");
|
|
15170
|
+
}
|
|
15171
|
+
}
|
|
15172
|
+
function parseSceneDocument(value) {
|
|
15173
|
+
if (typeof value === "string") {
|
|
15174
|
+
try {
|
|
15175
|
+
value = JSON.parse(value);
|
|
15176
|
+
} catch {
|
|
15177
|
+
fail("scene", "invalid JSON");
|
|
15178
|
+
}
|
|
15179
|
+
}
|
|
15180
|
+
const input = fields(value, "scene", {
|
|
15181
|
+
format: enumeration(["minerender-scene"]),
|
|
15182
|
+
version: (value2, path) => {
|
|
15183
|
+
if (value2 !== 1) fail(path, "only scene document version 1 is supported");
|
|
15184
|
+
},
|
|
15185
|
+
minecraftVersion: version,
|
|
15186
|
+
camera: (value2, path) => {
|
|
15187
|
+
fields(value2, path, { position: tuple(3), target: tuple(3) }, ["position", "target"]);
|
|
15188
|
+
},
|
|
15189
|
+
objects: list(validateObject)
|
|
15190
|
+
}, ["format", "version", "objects"]);
|
|
15191
|
+
const ids = /* @__PURE__ */ new Set();
|
|
15192
|
+
for (const [index, entry] of input.objects.entries()) {
|
|
15193
|
+
if (ids.has(entry.id)) fail(`scene.objects[${index}].id`, `duplicate object ID "${entry.id}"`);
|
|
15194
|
+
ids.add(entry.id);
|
|
15195
|
+
}
|
|
15196
|
+
return JSON.parse(JSON.stringify(input));
|
|
15197
|
+
}
|
|
15198
|
+
|
|
15199
|
+
// src/scene/SceneDocumentLoader.ts
|
|
15200
|
+
var import_three38 = require("three");
|
|
15201
|
+
init_AssetKey();
|
|
15202
|
+
init_AssetLoader();
|
|
15203
|
+
init_BlockStates();
|
|
15204
|
+
init_Entities();
|
|
15205
|
+
init_Models();
|
|
15206
|
+
init_DisplayPosition();
|
|
15207
|
+
init_SceneObject();
|
|
15208
|
+
|
|
14778
15209
|
// src/skin/Skins.ts
|
|
14779
15210
|
init_Requests();
|
|
14780
15211
|
var Skins = class {
|
|
14781
15212
|
//<editor-fold desc="Skins">
|
|
15213
|
+
/** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
|
|
14782
15214
|
static async fromUuidOrUsername(uuidOrUsername) {
|
|
14783
15215
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14784
15216
|
return this.fromUuid(uuidOrUsername);
|
|
14785
15217
|
}
|
|
14786
15218
|
return this.fromUsername(uuidOrUsername);
|
|
14787
15219
|
}
|
|
15220
|
+
/** Builds a proxy URL for a UUID without downloading or checking the skin. */
|
|
14788
15221
|
static async fromUuid(uuid) {
|
|
14789
15222
|
return this.getMcProxySkinUrl(uuid);
|
|
14790
15223
|
}
|
|
@@ -14796,6 +15229,7 @@ var Skins = class {
|
|
|
14796
15229
|
return void 0;
|
|
14797
15230
|
});
|
|
14798
15231
|
}
|
|
15232
|
+
/** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
|
|
14799
15233
|
static async fromMineSkin(mineskinId) {
|
|
14800
15234
|
return this.getMineSkin(mineskinId).then((mineskin) => {
|
|
14801
15235
|
if (mineskin) {
|
|
@@ -14806,12 +15240,14 @@ var Skins = class {
|
|
|
14806
15240
|
}
|
|
14807
15241
|
//</editor-fold>
|
|
14808
15242
|
//<editor-fold desc="Capes">
|
|
15243
|
+
/** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
|
|
14809
15244
|
static async capeFromUuidOrUsername(uuidOrUsername) {
|
|
14810
15245
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14811
15246
|
return this.capeFromUuid(uuidOrUsername);
|
|
14812
15247
|
}
|
|
14813
15248
|
return this.capeFromUsername(uuidOrUsername);
|
|
14814
15249
|
}
|
|
15250
|
+
/** Builds a proxy URL without checking whether the player has a cape. */
|
|
14815
15251
|
static async capeFromUuid(uuid) {
|
|
14816
15252
|
return this.getMcProxyCapeUrl(uuid);
|
|
14817
15253
|
}
|
|
@@ -14940,6 +15376,195 @@ var Skins = class {
|
|
|
14940
15376
|
//</editor-fold>
|
|
14941
15377
|
};
|
|
14942
15378
|
|
|
15379
|
+
// src/scene/SceneDocumentLoader.ts
|
|
15380
|
+
var DocumentObjectScene = class extends MineRenderScene {
|
|
15381
|
+
async addSceneObject(_asset, supplier, _options, parent = this) {
|
|
15382
|
+
const object3 = await supplier();
|
|
15383
|
+
return this.initialize(object3, parent);
|
|
15384
|
+
}
|
|
15385
|
+
async initialize(object3, parent = this) {
|
|
15386
|
+
object3.scene = this;
|
|
15387
|
+
try {
|
|
15388
|
+
await object3.init();
|
|
15389
|
+
parent.add(object3);
|
|
15390
|
+
return object3;
|
|
15391
|
+
} catch (error) {
|
|
15392
|
+
object3.dispose();
|
|
15393
|
+
object3.removeFromParent();
|
|
15394
|
+
throw error;
|
|
15395
|
+
}
|
|
15396
|
+
}
|
|
15397
|
+
dispose() {
|
|
15398
|
+
for (const child of [...this.children]) {
|
|
15399
|
+
if (child.parent !== this) continue;
|
|
15400
|
+
if (isSceneObject(child)) child.dispose();
|
|
15401
|
+
child.removeFromParent();
|
|
15402
|
+
}
|
|
15403
|
+
}
|
|
15404
|
+
};
|
|
15405
|
+
async function skinTexture(value, cape = false) {
|
|
15406
|
+
if (!/^[a-zA-Z0-9_-]{1,36}$/.test(value)) return value;
|
|
15407
|
+
const texture = await (cape ? Skins.capeFromUuidOrUsername(value) : Skins.fromUuidOrUsername(value));
|
|
15408
|
+
if (!texture) throw new Error(`Could not find ${cape ? "cape" : "skin"} for "${value}"`);
|
|
15409
|
+
return texture;
|
|
15410
|
+
}
|
|
15411
|
+
var SceneDocumentLoader = class {
|
|
15412
|
+
static parse(value) {
|
|
15413
|
+
return parseSceneDocument(value);
|
|
15414
|
+
}
|
|
15415
|
+
/**
|
|
15416
|
+
* Loads objects concurrently and attaches them in document order after every load succeeds.
|
|
15417
|
+
* A failure waits for all loads, disposes staged objects, and reports the first error in document order.
|
|
15418
|
+
*/
|
|
15419
|
+
static async load(scene, value, parent = scene) {
|
|
15420
|
+
const definition = this.parse(value);
|
|
15421
|
+
if (definition.minecraftVersion !== void 0 && definition.minecraftVersion !== AssetLoader.version) {
|
|
15422
|
+
throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion("${definition.minecraftVersion}") before loading it`);
|
|
15423
|
+
}
|
|
15424
|
+
const root = new import_three38.Group();
|
|
15425
|
+
root.name = "MineRender scene document";
|
|
15426
|
+
const objects = [];
|
|
15427
|
+
let disposed = false;
|
|
15428
|
+
const loaded = {
|
|
15429
|
+
root,
|
|
15430
|
+
objects,
|
|
15431
|
+
definition,
|
|
15432
|
+
advanceAnimations: (delta) => {
|
|
15433
|
+
if (!disposed) for (const object3 of objects) object3.advanceAnimation(delta);
|
|
15434
|
+
},
|
|
15435
|
+
dispose: () => {
|
|
15436
|
+
if (disposed) return;
|
|
15437
|
+
disposed = true;
|
|
15438
|
+
root.removeFromParent();
|
|
15439
|
+
for (const object3 of objects) object3.dispose();
|
|
15440
|
+
root.clear();
|
|
15441
|
+
scene.dirty = true;
|
|
15442
|
+
}
|
|
15443
|
+
};
|
|
15444
|
+
try {
|
|
15445
|
+
const results = await Promise.allSettled(definition.objects.map((object3) => this.loadValidatedObject(scene, object3)));
|
|
15446
|
+
for (const result of results) if (result.status === "fulfilled") objects.push(result.value);
|
|
15447
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
15448
|
+
if (failure) throw failure.reason;
|
|
15449
|
+
for (const object3 of objects) root.add(object3.root);
|
|
15450
|
+
parent.add(root);
|
|
15451
|
+
scene.dirty = true;
|
|
15452
|
+
return loaded;
|
|
15453
|
+
} catch (error) {
|
|
15454
|
+
loaded.dispose();
|
|
15455
|
+
throw error;
|
|
15456
|
+
}
|
|
15457
|
+
}
|
|
15458
|
+
/** Loads an independently editable object. Its root owns the document's position, rotation, and scale. */
|
|
15459
|
+
static async loadObject(scene, value, parent = scene) {
|
|
15460
|
+
const definition = this.parse({ format: "minerender-scene", version: 1, objects: [value] }).objects[0];
|
|
15461
|
+
return this.loadValidatedObject(scene, definition, parent);
|
|
15462
|
+
}
|
|
15463
|
+
static async loadValidatedObject(scene, definition, parent) {
|
|
15464
|
+
const root = new import_three38.Group();
|
|
15465
|
+
root.name = definition.name ?? definition.id;
|
|
15466
|
+
root.userData.sceneObjectId = definition.id;
|
|
15467
|
+
root.position.fromArray(definition.position ?? [0, 0, 0]);
|
|
15468
|
+
root.rotation.set(...definition.rotation ?? [0, 0, 0]);
|
|
15469
|
+
root.scale.fromArray(definition.scale ?? [1, 1, 1]);
|
|
15470
|
+
root.visible = definition.visible ?? true;
|
|
15471
|
+
const content = new DocumentObjectScene();
|
|
15472
|
+
root.add(content);
|
|
15473
|
+
let object3;
|
|
15474
|
+
try {
|
|
15475
|
+
switch (definition.type) {
|
|
15476
|
+
case "skin": {
|
|
15477
|
+
const skin = new SkinObject({ ...definition.options, instanceMeshes: false });
|
|
15478
|
+
object3 = skin;
|
|
15479
|
+
const texture = definition.skin ? await skinTexture(definition.skin) : `${AssetLoader.ROOT}/assets/minecraft/textures/entity/player/${definition.options?.slim ? "slim/alex" : "wide/steve"}.png`;
|
|
15480
|
+
await skin.setSkinTexture(texture);
|
|
15481
|
+
await content.initialize(skin);
|
|
15482
|
+
if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);
|
|
15483
|
+
for (const [part, rotation] of Object.entries(definition.pose ?? {})) {
|
|
15484
|
+
skin.getGroupByName(part)?.rotation.set(...rotation, "XYZ");
|
|
15485
|
+
}
|
|
15486
|
+
for (const part of definition.hiddenParts ?? []) {
|
|
15487
|
+
const mesh = skin.getMeshByName(part);
|
|
15488
|
+
if (mesh) mesh.visible = false;
|
|
15489
|
+
}
|
|
15490
|
+
break;
|
|
15491
|
+
}
|
|
15492
|
+
case "block": {
|
|
15493
|
+
const state = await BlockStates.get(AssetKey.parse("blockstates", definition.asset));
|
|
15494
|
+
if (!state) throw new Error(`Could not load block ${definition.asset}`);
|
|
15495
|
+
object3 = await content.addBlock(state, { ...definition.options, initialState: definition.state, instanceMeshes: false });
|
|
15496
|
+
break;
|
|
15497
|
+
}
|
|
15498
|
+
case "item":
|
|
15499
|
+
case "model": {
|
|
15500
|
+
let key = AssetKey.parse("models", definition.asset);
|
|
15501
|
+
if (definition.type === "item" && key.type !== "item") {
|
|
15502
|
+
key = new AssetKey(key.namespace, key.getFullPath(), "models", "item");
|
|
15503
|
+
}
|
|
15504
|
+
const model = await Models.getMerged(key);
|
|
15505
|
+
if (!model) throw new Error(`Could not load ${definition.type} ${definition.asset}`);
|
|
15506
|
+
object3 = await content.addModel(model, {
|
|
15507
|
+
...definition.type === "item" ? { displayPosition: "gui" /* GUI */ } : {},
|
|
15508
|
+
...definition.options,
|
|
15509
|
+
instanceMeshes: false
|
|
15510
|
+
});
|
|
15511
|
+
break;
|
|
15512
|
+
}
|
|
15513
|
+
case "entity": {
|
|
15514
|
+
const key = AssetKey.parse("entity-models", definition.asset);
|
|
15515
|
+
const model = await Entities.getEntity(key, definition.texture ? AssetKey.parse("textures", definition.texture) : void 0, {
|
|
15516
|
+
layers: definition.layers,
|
|
15517
|
+
when: definition.when,
|
|
15518
|
+
textures: definition.textures && Object.fromEntries(Object.entries(definition.textures).map(([name, texture]) => [name, AssetKey.parse("textures", texture)]))
|
|
15519
|
+
});
|
|
15520
|
+
if (!model) throw new Error(`Could not load entity ${definition.asset}`);
|
|
15521
|
+
const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
|
|
15522
|
+
object3 = entity;
|
|
15523
|
+
if (definition.animation) {
|
|
15524
|
+
const animations = await Entities.getAnimations(key);
|
|
15525
|
+
const clip = animations?.[definition.animation.name];
|
|
15526
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${definition.animation.name}"`);
|
|
15527
|
+
entity.playAnimation(clip, definition.animation);
|
|
15528
|
+
}
|
|
15529
|
+
break;
|
|
15530
|
+
}
|
|
15531
|
+
case "gui":
|
|
15532
|
+
object3 = await content.initialize(new GuiObject(definition.layers));
|
|
15533
|
+
break;
|
|
15534
|
+
}
|
|
15535
|
+
let disposed = false;
|
|
15536
|
+
const loaded = {
|
|
15537
|
+
root,
|
|
15538
|
+
object: object3,
|
|
15539
|
+
definition,
|
|
15540
|
+
advanceAnimation: (delta) => {
|
|
15541
|
+
if (!disposed && definition.type === "entity" && !definition.animation?.paused) object3.advanceAnimation(delta);
|
|
15542
|
+
},
|
|
15543
|
+
dispose: () => {
|
|
15544
|
+
if (disposed) return;
|
|
15545
|
+
disposed = true;
|
|
15546
|
+
root.removeFromParent();
|
|
15547
|
+
object3.dispose();
|
|
15548
|
+
object3.removeFromParent();
|
|
15549
|
+
content.dispose();
|
|
15550
|
+
root.clear();
|
|
15551
|
+
scene.dirty = true;
|
|
15552
|
+
}
|
|
15553
|
+
};
|
|
15554
|
+
parent?.add(root);
|
|
15555
|
+
scene.dirty = true;
|
|
15556
|
+
return loaded;
|
|
15557
|
+
} catch (error) {
|
|
15558
|
+
object3?.dispose();
|
|
15559
|
+
object3?.removeFromParent();
|
|
15560
|
+
content.dispose();
|
|
15561
|
+
root.removeFromParent();
|
|
15562
|
+
root.clear();
|
|
15563
|
+
throw new Error(`Scene object "${definition.name ?? definition.id}": ${error instanceof Error ? error.message : String(error)}`);
|
|
15564
|
+
}
|
|
15565
|
+
}
|
|
15566
|
+
};
|
|
15567
|
+
|
|
14943
15568
|
// src/texture/index.ts
|
|
14944
15569
|
init_Colormaps();
|
|
14945
15570
|
init_TextureAtlas();
|
|
@@ -14966,16 +15591,19 @@ var ChunkData = class _ChunkData {
|
|
|
14966
15591
|
this.freeIds = [];
|
|
14967
15592
|
this.nbt = /* @__PURE__ */ new Map();
|
|
14968
15593
|
}
|
|
15594
|
+
/** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
|
|
14969
15595
|
get(index) {
|
|
14970
15596
|
_ChunkData.validateIndex(index);
|
|
14971
15597
|
const entry = this.palette[this.indices[index]];
|
|
14972
15598
|
return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
|
|
14973
15599
|
}
|
|
15600
|
+
/** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
|
|
14974
15601
|
snapshot(index) {
|
|
14975
15602
|
_ChunkData.validateIndex(index);
|
|
14976
15603
|
const entry = this.palette[this.indices[index]];
|
|
14977
15604
|
return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
|
|
14978
15605
|
}
|
|
15606
|
+
/** Copies block data into a cell. An omitted block or an air block clears the cell. */
|
|
14979
15607
|
set(index, block) {
|
|
14980
15608
|
_ChunkData.validateIndex(index);
|
|
14981
15609
|
let state;
|
|
@@ -15040,15 +15668,23 @@ var ChunkData = class _ChunkData {
|
|
|
15040
15668
|
|
|
15041
15669
|
// src/world/AnvilParser.ts
|
|
15042
15670
|
var AnvilParser = class {
|
|
15671
|
+
/** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
|
|
15043
15672
|
static getChunkList(data) {
|
|
15044
15673
|
return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
|
|
15045
15674
|
}
|
|
15675
|
+
/** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
|
|
15046
15676
|
static async parse(data) {
|
|
15047
15677
|
const bytes = this.bytes(data);
|
|
15048
15678
|
const chunks = [];
|
|
15049
15679
|
for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
|
|
15050
15680
|
return { chunks };
|
|
15051
15681
|
}
|
|
15682
|
+
/**
|
|
15683
|
+
* Decodes one chunk for {@link MineRenderWorld.placeChunk}.
|
|
15684
|
+
* @param localX - Chunk x within the region, from 0 to 31.
|
|
15685
|
+
* @param localZ - Chunk z within the region, from 0 to 31.
|
|
15686
|
+
* @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
|
|
15687
|
+
*/
|
|
15052
15688
|
static async parseChunk(data, localX, localZ) {
|
|
15053
15689
|
if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
|
|
15054
15690
|
throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
|
|
@@ -15210,12 +15846,12 @@ var AnvilParser = class {
|
|
|
15210
15846
|
};
|
|
15211
15847
|
|
|
15212
15848
|
// src/world/Chunk.ts
|
|
15213
|
-
var
|
|
15849
|
+
var import_three42 = require("three");
|
|
15214
15850
|
init_BlockStates();
|
|
15215
15851
|
init_AssetKey();
|
|
15216
15852
|
|
|
15217
15853
|
// src/world/MineRenderWorld.ts
|
|
15218
|
-
var
|
|
15854
|
+
var import_three40 = require("three");
|
|
15219
15855
|
init_Model();
|
|
15220
15856
|
init_BatchedExecutor();
|
|
15221
15857
|
init_AssetKey();
|
|
@@ -15223,7 +15859,7 @@ init_BlockStates();
|
|
|
15223
15859
|
init_CubeFace();
|
|
15224
15860
|
|
|
15225
15861
|
// src/world/SectionModels.ts
|
|
15226
|
-
var
|
|
15862
|
+
var import_three39 = require("three");
|
|
15227
15863
|
init_AssetKey();
|
|
15228
15864
|
init_Models();
|
|
15229
15865
|
init_CubeFace();
|
|
@@ -15253,6 +15889,7 @@ var SectionModels = class {
|
|
|
15253
15889
|
this.templates = /* @__PURE__ */ new Set();
|
|
15254
15890
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
15255
15891
|
}
|
|
15892
|
+
/** Returns a cube template, or `undefined` when the block requires an individual render object. */
|
|
15256
15893
|
async get(blockState, properties = {}) {
|
|
15257
15894
|
if (!blockState.variants || blockState.multipart) return void 0;
|
|
15258
15895
|
let states = this.states.get(blockState);
|
|
@@ -15281,20 +15918,20 @@ var SectionModels = class {
|
|
|
15281
15918
|
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
15282
15919
|
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
15283
15920
|
const template = await cached(models, key, async () => {
|
|
15284
|
-
const
|
|
15921
|
+
const object3 = new SectionModel(model, {
|
|
15285
15922
|
instanceMeshes: false,
|
|
15286
15923
|
mergeMeshes: false,
|
|
15287
15924
|
tints,
|
|
15288
15925
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
15289
15926
|
});
|
|
15290
|
-
await
|
|
15291
|
-
const geometry =
|
|
15292
|
-
geometry.applyMatrix4(new
|
|
15293
|
-
|
|
15927
|
+
await object3.init();
|
|
15928
|
+
const geometry = object3.children[0].geometry;
|
|
15929
|
+
geometry.applyMatrix4(new import_three39.Matrix4().makeRotationFromEuler(rotation));
|
|
15930
|
+
object3.clear();
|
|
15294
15931
|
const cullFaces = CUBE_FACES.map((face) => {
|
|
15295
15932
|
const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
|
|
15296
15933
|
if (local < 0) return 0;
|
|
15297
|
-
const normal = new
|
|
15934
|
+
const normal = new import_three39.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
15298
15935
|
const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
15299
15936
|
return 1 << world;
|
|
15300
15937
|
});
|
|
@@ -15306,6 +15943,7 @@ var SectionModels = class {
|
|
|
15306
15943
|
}
|
|
15307
15944
|
return { variants, templates };
|
|
15308
15945
|
}
|
|
15946
|
+
/** Disposes prepared geometry and clears this world's template caches. */
|
|
15309
15947
|
clear() {
|
|
15310
15948
|
for (const template of this.templates) template.geometry.dispose();
|
|
15311
15949
|
this.templates.clear();
|
|
@@ -15324,20 +15962,20 @@ var MineRenderWorld = class {
|
|
|
15324
15962
|
}
|
|
15325
15963
|
getBlockAt(posOrX, y, z) {
|
|
15326
15964
|
if (typeof posOrX == "number") {
|
|
15327
|
-
return this.getBlockAt(new
|
|
15965
|
+
return this.getBlockAt(new import_three40.Vector3(posOrX, y, z));
|
|
15328
15966
|
}
|
|
15329
15967
|
if (isTripleArray(posOrX)) {
|
|
15330
|
-
return this.getBlockAt(new
|
|
15968
|
+
return this.getBlockAt(new import_three40.Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
15331
15969
|
}
|
|
15332
15970
|
this.validatePosBounds(posOrX);
|
|
15333
15971
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
15334
15972
|
}
|
|
15335
15973
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
15336
15974
|
if (typeof posOrX == "number") {
|
|
15337
|
-
return this.setBlockAt(new
|
|
15975
|
+
return this.setBlockAt(new import_three40.Vector3(posOrX, yOrBlock, z), block);
|
|
15338
15976
|
}
|
|
15339
15977
|
if (isTripleArray(posOrX)) {
|
|
15340
|
-
return this.setBlockAt(new
|
|
15978
|
+
return this.setBlockAt(new import_three40.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
15341
15979
|
}
|
|
15342
15980
|
return this.placeBlock(posOrX, yOrBlock);
|
|
15343
15981
|
}
|
|
@@ -15348,14 +15986,21 @@ var MineRenderWorld = class {
|
|
|
15348
15986
|
}
|
|
15349
15987
|
async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
|
|
15350
15988
|
if (typeof posOrX === "number") {
|
|
15351
|
-
return this.setBlockVisibleAt(new
|
|
15989
|
+
return this.setBlockVisibleAt(new import_three40.Vector3(posOrX, yOrVisible, z), visible);
|
|
15352
15990
|
}
|
|
15353
15991
|
if (isTripleArray(posOrX)) {
|
|
15354
|
-
return this.setBlockVisibleAt(new
|
|
15992
|
+
return this.setBlockVisibleAt(new import_three40.Vector3(...posOrX), yOrVisible);
|
|
15355
15993
|
}
|
|
15356
15994
|
this.validatePosBounds(posOrX);
|
|
15357
15995
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
15358
15996
|
}
|
|
15997
|
+
/**
|
|
15998
|
+
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
15999
|
+
* Entity NBT is retained by the structure but is not rendered.
|
|
16000
|
+
*
|
|
16001
|
+
* @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
|
|
16002
|
+
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
16003
|
+
*/
|
|
15359
16004
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
15360
16005
|
const changes = /* @__PURE__ */ new Map();
|
|
15361
16006
|
try {
|
|
@@ -15368,7 +16013,7 @@ var MineRenderWorld = class {
|
|
|
15368
16013
|
const collect = async (positions2) => {
|
|
15369
16014
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
15370
16015
|
};
|
|
15371
|
-
const place = (block) => this.placeBlock(new
|
|
16016
|
+
const place = (block) => this.placeBlock(new import_three40.Vector3(...block.position), block, collect);
|
|
15372
16017
|
const keys = /* @__PURE__ */ new Map();
|
|
15373
16018
|
for (const block of multiblock.blocks) {
|
|
15374
16019
|
if (Chunk.isAir(block)) continue;
|
|
@@ -15452,6 +16097,7 @@ var MineRenderWorld = class {
|
|
|
15452
16097
|
});
|
|
15453
16098
|
}
|
|
15454
16099
|
}
|
|
16100
|
+
/** Removes all chunks and releases their block placements and section meshes. */
|
|
15455
16101
|
async clear() {
|
|
15456
16102
|
await this.culling;
|
|
15457
16103
|
const chunks = [...this._chunks.values()];
|
|
@@ -15465,13 +16111,13 @@ var MineRenderWorld = class {
|
|
|
15465
16111
|
for (const pos of positions) {
|
|
15466
16112
|
this.pendingCulling.set(pos.toArray().join(","), pos.clone());
|
|
15467
16113
|
for (const offset of CUBE_FACE_OFFSETS) {
|
|
15468
|
-
const neighbor = pos.clone().add(new
|
|
16114
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(...offset));
|
|
15469
16115
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
15470
16116
|
}
|
|
15471
16117
|
for (let y = -1; y <= 1; y++) {
|
|
15472
16118
|
for (let z = -1; z <= 1; z++) {
|
|
15473
16119
|
for (let x = -1; x <= 1; x++) {
|
|
15474
|
-
const neighbor = pos.clone().add(new
|
|
16120
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(x, y, z));
|
|
15475
16121
|
if (this.getBlockAt(neighbor)?.object?.fluidKind) {
|
|
15476
16122
|
this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
|
|
15477
16123
|
}
|
|
@@ -15495,19 +16141,19 @@ var MineRenderWorld = class {
|
|
|
15495
16141
|
}
|
|
15496
16142
|
if (block.object?.fluidKind) {
|
|
15497
16143
|
await block.object.updateFluid((x, y, z) => {
|
|
15498
|
-
const neighbor = pos.clone().add(new
|
|
16144
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(x, y, z));
|
|
15499
16145
|
const section = this.getChunkAt(neighbor);
|
|
15500
|
-
const
|
|
16146
|
+
const object3 = section?.isBlockVisibleAt(neighbor) ? section.getBlockAt(neighbor)?.object : void 0;
|
|
15501
16147
|
return {
|
|
15502
|
-
fluid:
|
|
15503
|
-
level:
|
|
16148
|
+
fluid: object3?.fluidKind,
|
|
16149
|
+
level: object3?.fluidLevel,
|
|
15504
16150
|
solid: section?.isOccludingAt(neighbor) ?? false
|
|
15505
16151
|
};
|
|
15506
16152
|
});
|
|
15507
16153
|
}
|
|
15508
16154
|
let mask = 0;
|
|
15509
16155
|
for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
15510
|
-
const neighbor = pos.clone().add(new
|
|
16156
|
+
const neighbor = pos.clone().add(new import_three40.Vector3(...offset));
|
|
15511
16157
|
if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
|
|
15512
16158
|
mask |= 1 << face;
|
|
15513
16159
|
}
|
|
@@ -15537,18 +16183,21 @@ var MineRenderWorld = class {
|
|
|
15537
16183
|
}
|
|
15538
16184
|
return chunk;
|
|
15539
16185
|
}
|
|
16186
|
+
/** Returns the loaded chunk containing a world block position, without creating a chunk. */
|
|
15540
16187
|
getChunkAt(pos) {
|
|
15541
16188
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
15542
16189
|
}
|
|
16190
|
+
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
15543
16191
|
static worldToScenePosition(pos) {
|
|
15544
|
-
return new
|
|
16192
|
+
return new import_three40.Vector3(
|
|
15545
16193
|
pos.x * 16,
|
|
15546
16194
|
pos.y * 16,
|
|
15547
16195
|
pos.z * 16
|
|
15548
16196
|
);
|
|
15549
16197
|
}
|
|
16198
|
+
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
15550
16199
|
static sceneToWorldPosition(pos) {
|
|
15551
|
-
return new
|
|
16200
|
+
return new import_three40.Vector3(
|
|
15552
16201
|
pos.x / 16,
|
|
15553
16202
|
pos.y / 16,
|
|
15554
16203
|
pos.z / 16
|
|
@@ -15571,14 +16220,15 @@ var MineRenderWorld = class {
|
|
|
15571
16220
|
init_Model();
|
|
15572
16221
|
|
|
15573
16222
|
// src/world/SectionMesh.ts
|
|
15574
|
-
var
|
|
16223
|
+
var import_three41 = require("three");
|
|
15575
16224
|
init_CanvasCompat();
|
|
15576
16225
|
init_Materials();
|
|
15577
|
-
var SectionMesh = class _SectionMesh extends
|
|
16226
|
+
var SectionMesh = class _SectionMesh extends import_three41.Group {
|
|
15578
16227
|
constructor() {
|
|
15579
16228
|
super(...arguments);
|
|
15580
16229
|
this.ownedMeshes = [];
|
|
15581
16230
|
}
|
|
16231
|
+
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
15582
16232
|
static build(entries, maxAtlasSize = 2048) {
|
|
15583
16233
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
15584
16234
|
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
@@ -15626,7 +16276,7 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
|
|
|
15626
16276
|
const normal = template.geometry.getAttribute("normal");
|
|
15627
16277
|
const uv = template.geometry.getAttribute("uv");
|
|
15628
16278
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
15629
|
-
const
|
|
16279
|
+
const color2 = template.geometry.getAttribute("color");
|
|
15630
16280
|
const sourceIndices = template.geometry.getIndex();
|
|
15631
16281
|
const placement = locations.get(template.atlas).placement;
|
|
15632
16282
|
const mapU = (u) => (placement.x + u * template.atlas.image.width) / page.width;
|
|
@@ -15648,24 +16298,24 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
|
|
|
15648
16298
|
mapU(bounds?.getZ(vertex) ?? 1),
|
|
15649
16299
|
mapV(bounds?.getW(vertex) ?? 1)
|
|
15650
16300
|
);
|
|
15651
|
-
colors.push(
|
|
16301
|
+
colors.push(color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1);
|
|
15652
16302
|
}
|
|
15653
16303
|
for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
|
|
15654
16304
|
}
|
|
15655
16305
|
}
|
|
15656
|
-
const geometry = new
|
|
15657
|
-
geometry.setAttribute("position", new
|
|
15658
|
-
geometry.setAttribute("normal", new
|
|
15659
|
-
geometry.setAttribute("uv", new
|
|
15660
|
-
geometry.setAttribute("uvBounds", new
|
|
15661
|
-
geometry.setAttribute("color", new
|
|
16306
|
+
const geometry = new import_three41.BufferGeometry();
|
|
16307
|
+
geometry.setAttribute("position", new import_three41.Float32BufferAttribute(positions, 3));
|
|
16308
|
+
geometry.setAttribute("normal", new import_three41.Float32BufferAttribute(normals, 3));
|
|
16309
|
+
geometry.setAttribute("uv", new import_three41.Float32BufferAttribute(uvs, 2));
|
|
16310
|
+
geometry.setAttribute("uvBounds", new import_three41.Float32BufferAttribute(uvBounds, 4));
|
|
16311
|
+
geometry.setAttribute("color", new import_three41.Float32BufferAttribute(colors, 3));
|
|
15662
16312
|
geometry.setIndex(indices);
|
|
15663
16313
|
geometry.computeBoundingBox();
|
|
15664
16314
|
geometry.computeBoundingSphere();
|
|
15665
16315
|
const material = Materials.createShadedCanvasMaterial(canvas, false, false, true);
|
|
15666
16316
|
material.vertexColors = true;
|
|
15667
16317
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
15668
|
-
const mesh = new
|
|
16318
|
+
const mesh = new import_three41.Mesh(geometry, material);
|
|
15669
16319
|
section.add(mesh);
|
|
15670
16320
|
section.ownedMeshes.push({ mesh, texture });
|
|
15671
16321
|
}
|
|
@@ -15701,10 +16351,10 @@ var Chunk = class _Chunk {
|
|
|
15701
16351
|
}
|
|
15702
16352
|
getBlockAt(posOrX, y, z) {
|
|
15703
16353
|
if (typeof posOrX == "number") {
|
|
15704
|
-
return this.getBlockAt(new
|
|
16354
|
+
return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
|
|
15705
16355
|
}
|
|
15706
16356
|
if (isTripleArray(posOrX)) {
|
|
15707
|
-
return this.getBlockAt(new
|
|
16357
|
+
return this.getBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
15708
16358
|
}
|
|
15709
16359
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
15710
16360
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
@@ -15712,10 +16362,10 @@ var Chunk = class _Chunk {
|
|
|
15712
16362
|
}
|
|
15713
16363
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
15714
16364
|
if (typeof posOrX == "number") {
|
|
15715
|
-
return this.setBlockAt(new
|
|
16365
|
+
return this.setBlockAt(new import_three42.Vector3(posOrX, yOrBlock, z), block);
|
|
15716
16366
|
}
|
|
15717
16367
|
if (isTripleArray(posOrX)) {
|
|
15718
|
-
return this.setBlockAt(new
|
|
16368
|
+
return this.setBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
15719
16369
|
}
|
|
15720
16370
|
const worldPos = posOrX;
|
|
15721
16371
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -15723,7 +16373,7 @@ var Chunk = class _Chunk {
|
|
|
15723
16373
|
return this.setBlockInChunkAt(pos, block, worldPos);
|
|
15724
16374
|
}
|
|
15725
16375
|
/**
|
|
15726
|
-
*
|
|
16376
|
+
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
15727
16377
|
*/
|
|
15728
16378
|
async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
|
|
15729
16379
|
if (typeof worldPos === "undefined") {
|
|
@@ -15736,7 +16386,7 @@ var Chunk = class _Chunk {
|
|
|
15736
16386
|
this.renderedBlocks.get(index)?.object?.removeFromScene();
|
|
15737
16387
|
if (this.sectionBlocks.delete(index)) this.meshDirty = true;
|
|
15738
16388
|
this.renderedBlocks.delete(index);
|
|
15739
|
-
let
|
|
16389
|
+
let object3;
|
|
15740
16390
|
try {
|
|
15741
16391
|
if (!readBlock) return void 0;
|
|
15742
16392
|
const stored = readBlock();
|
|
@@ -15751,27 +16401,28 @@ var Chunk = class _Chunk {
|
|
|
15751
16401
|
this.sectionBlocks.set(index, { index, template, cullMask: 0 });
|
|
15752
16402
|
this.meshDirty = true;
|
|
15753
16403
|
} else {
|
|
15754
|
-
|
|
16404
|
+
object3 = await this.scene.addBlock(blockState, {
|
|
15755
16405
|
mergeMeshes: true,
|
|
15756
16406
|
instanceMeshes: true,
|
|
15757
16407
|
maxInstanceCount: 2e3,
|
|
15758
16408
|
initialState: stored.properties
|
|
15759
16409
|
});
|
|
15760
|
-
|
|
16410
|
+
object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
15761
16411
|
}
|
|
15762
16412
|
const info = { get block() {
|
|
15763
16413
|
return readBlock();
|
|
15764
|
-
}, object:
|
|
16414
|
+
}, object: object3 };
|
|
15765
16415
|
this.renderedBlocks.set(index, info);
|
|
15766
16416
|
return info;
|
|
15767
16417
|
} catch (error) {
|
|
15768
16418
|
this.data.set(index, void 0);
|
|
15769
|
-
|
|
16419
|
+
object3?.removeFromScene();
|
|
15770
16420
|
throw error;
|
|
15771
16421
|
} finally {
|
|
15772
16422
|
await onBlocksChanged?.([worldPos]);
|
|
15773
16423
|
}
|
|
15774
16424
|
}
|
|
16425
|
+
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
15775
16426
|
async setBlockVisibleAt(pos, visible) {
|
|
15776
16427
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
15777
16428
|
const block = this.renderedBlocks.get(index);
|
|
@@ -15825,9 +16476,10 @@ var Chunk = class _Chunk {
|
|
|
15825
16476
|
this.scene.dirty = true;
|
|
15826
16477
|
this.meshDirty = false;
|
|
15827
16478
|
}
|
|
16479
|
+
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
15828
16480
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
15829
16481
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
15830
|
-
new
|
|
16482
|
+
new import_three42.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
15831
16483
|
));
|
|
15832
16484
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
15833
16485
|
this.sectionBlocks.clear();
|
|
@@ -15845,6 +16497,7 @@ var Chunk = class _Chunk {
|
|
|
15845
16497
|
static isAir(block) {
|
|
15846
16498
|
return ChunkData.isAir(block);
|
|
15847
16499
|
}
|
|
16500
|
+
/** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
|
|
15848
16501
|
static chunkPosToBlockIndex(pos) {
|
|
15849
16502
|
if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
|
|
15850
16503
|
throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");
|
|
@@ -15852,14 +16505,14 @@ var Chunk = class _Chunk {
|
|
|
15852
16505
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
15853
16506
|
}
|
|
15854
16507
|
worldPosToChunkPos(pos) {
|
|
15855
|
-
return new
|
|
16508
|
+
return new import_three42.Vector3(
|
|
15856
16509
|
pos.x - this.x * 16,
|
|
15857
16510
|
pos.y - this.y * 16,
|
|
15858
16511
|
pos.z - this.z * 16
|
|
15859
16512
|
);
|
|
15860
16513
|
}
|
|
15861
16514
|
chunkPosToWorldPos(pos) {
|
|
15862
|
-
return new
|
|
16515
|
+
return new import_three42.Vector3(
|
|
15863
16516
|
this.x * 16 + pos.x,
|
|
15864
16517
|
this.y * 16 + pos.y,
|
|
15865
16518
|
this.z * 16 + pos.z
|