minerender 2.1.0-alpha.74 → 2.1.0-alpha.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.mts +479 -12
- package/dist/browser/index.d.ts +479 -12
- package/dist/browser/index.js +271 -16
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +271 -16
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +271 -16
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +479 -12
- package/dist/node/index.d.ts +479 -12
- package/dist/node/index.js +271 -16
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +271 -16
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -69,6 +69,7 @@ var init_PersistentCache = __esm({
|
|
|
69
69
|
/** Bump to invalidate every persisted entry. */
|
|
70
70
|
this.VERSION = 2;
|
|
71
71
|
}
|
|
72
|
+
/** Opens a named store in the active environment using the current cache schema version. */
|
|
72
73
|
static open(name) {
|
|
73
74
|
return Env.provider.openCache(name, _PersistentCache.VERSION);
|
|
74
75
|
}
|
|
@@ -330,6 +331,7 @@ var init_Caching = __esm({
|
|
|
330
331
|
this.fontCache
|
|
331
332
|
];
|
|
332
333
|
}
|
|
334
|
+
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
333
335
|
static clear() {
|
|
334
336
|
for (const cache of this.all) {
|
|
335
337
|
cache.invalidateAll();
|
|
@@ -372,6 +374,7 @@ var init_Geometries = __esm({
|
|
|
372
374
|
}
|
|
373
375
|
return geometry;
|
|
374
376
|
}
|
|
377
|
+
/** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
|
|
375
378
|
static getBox(key) {
|
|
376
379
|
const keyStr = serializeBoxGeometryKey(key);
|
|
377
380
|
return Caching.boxGeometryCache.get(keyStr, (k) => {
|
|
@@ -555,12 +558,15 @@ var init_Requests = __esm({
|
|
|
555
558
|
static {
|
|
556
559
|
this.mcAssetRequestQueue = new RequestQueue();
|
|
557
560
|
}
|
|
561
|
+
/** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
|
|
558
562
|
static genericRequest(request) {
|
|
559
563
|
return this.genericQueue.request(request);
|
|
560
564
|
}
|
|
565
|
+
/** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
|
|
561
566
|
static mcAssetRequest(request) {
|
|
562
567
|
return this.mcAssetRequestQueue.request(request);
|
|
563
568
|
}
|
|
569
|
+
/** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
|
|
564
570
|
static setMcAssetRoot(root) {
|
|
565
571
|
this.mcAssetRequestQueue.baseURL = root;
|
|
566
572
|
}
|
|
@@ -613,6 +619,7 @@ var init_WrappedImage = __esm({
|
|
|
613
619
|
}
|
|
614
620
|
return false;
|
|
615
621
|
}
|
|
622
|
+
/** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
|
|
616
623
|
get animated() {
|
|
617
624
|
return this.height > this.width && this.height % this.width === 0;
|
|
618
625
|
}
|
|
@@ -659,6 +666,7 @@ var init_ImageLoader = __esm({
|
|
|
659
666
|
static _createImage() {
|
|
660
667
|
return createImage();
|
|
661
668
|
}
|
|
669
|
+
/** Resolves when an image URL has decoded, or rejects if decoding fails. */
|
|
662
670
|
static async loadAsync(src) {
|
|
663
671
|
return new Promise((resolve, reject) => {
|
|
664
672
|
const image = this._createImage();
|
|
@@ -667,6 +675,7 @@ var init_ImageLoader = __esm({
|
|
|
667
675
|
image.src = src;
|
|
668
676
|
});
|
|
669
677
|
}
|
|
678
|
+
/** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
|
|
670
679
|
static loadElement(src, onload, onerr) {
|
|
671
680
|
const image = this._createImage();
|
|
672
681
|
if (onload)
|
|
@@ -694,6 +703,7 @@ var init_ImageLoader = __esm({
|
|
|
694
703
|
throw err;
|
|
695
704
|
}
|
|
696
705
|
}
|
|
706
|
+
/** Decodes the supplied bytes into a canvas without fetching the source URL again. */
|
|
697
707
|
static async infoToCanvasData(info) {
|
|
698
708
|
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
699
709
|
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
@@ -710,12 +720,14 @@ var init_ImageLoader = __esm({
|
|
|
710
720
|
const image = await this.infoToCanvasData(info);
|
|
711
721
|
return image.data.getImageData(0, 0, image.width, image.height);
|
|
712
722
|
}
|
|
723
|
+
/** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
|
|
713
724
|
static async getData(src) {
|
|
714
725
|
const keyStr = serializeImageKey({ src });
|
|
715
726
|
return await Caching.imageDataCache.get(keyStr, (k) => {
|
|
716
727
|
return _ImageLoader.loadData(src);
|
|
717
728
|
});
|
|
718
729
|
}
|
|
730
|
+
/** Returns a cached canvas context and dimensions for an image URL or data URL. */
|
|
719
731
|
static async getCanvasData(src) {
|
|
720
732
|
const keyStr = serializeImageKey({ src });
|
|
721
733
|
return await Caching.canvasImageDataCache.get(keyStr, (k) => {
|
|
@@ -815,6 +827,7 @@ var init_TextureLoader = __esm({
|
|
|
815
827
|
texture.rotation = rotation;
|
|
816
828
|
return Textures.initTextureProps(texture);
|
|
817
829
|
}
|
|
830
|
+
/** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
|
|
818
831
|
static load(src, format2 = import_three3.RGBAFormat, rotation = 0) {
|
|
819
832
|
const texture = new import_three3.Texture();
|
|
820
833
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
@@ -863,6 +876,7 @@ var init_Textures = __esm({
|
|
|
863
876
|
return this.initTextureProps(texture);
|
|
864
877
|
});
|
|
865
878
|
}
|
|
879
|
+
/** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
|
|
866
880
|
static initTextureProps(texture) {
|
|
867
881
|
texture.magFilter = THREE2.NearestFilter;
|
|
868
882
|
texture.minFilter = THREE2.NearestFilter;
|
|
@@ -875,11 +889,13 @@ var init_Textures = __esm({
|
|
|
875
889
|
static createAsset(key) {
|
|
876
890
|
return new import_three4.Texture();
|
|
877
891
|
}
|
|
892
|
+
/** Creates an sRGB color texture from a canvas. */
|
|
878
893
|
static createCanvasTexture(canvas) {
|
|
879
894
|
const texture = new import_three4.CanvasTexture(canvas);
|
|
880
895
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
881
896
|
return this.initTextureProps(texture);
|
|
882
897
|
}
|
|
898
|
+
/** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
|
|
883
899
|
static getImage(key) {
|
|
884
900
|
const keyStr = serializeTextureKey(key);
|
|
885
901
|
const cached2 = Caching.textureCache.peek(keyStr);
|
|
@@ -904,6 +920,7 @@ var init_Materials = __esm({
|
|
|
904
920
|
init_TextureLoader();
|
|
905
921
|
init_Caching();
|
|
906
922
|
Materials = class _Materials {
|
|
923
|
+
/** Shared checkerboard material, created on first access. */
|
|
907
924
|
static get MISSING_TEXTURE() {
|
|
908
925
|
return Caching.materialCache.get("builtin:missing-texture", () => new import_three5.MeshBasicMaterial({
|
|
909
926
|
map: Textures.getMissing(),
|
|
@@ -1007,6 +1024,7 @@ var init_Materials = __esm({
|
|
|
1007
1024
|
if (tint !== void 0) material.color.multiply(new import_three5.Color(tint));
|
|
1008
1025
|
return material;
|
|
1009
1026
|
}
|
|
1027
|
+
/** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
|
|
1010
1028
|
static createGuiCanvasMaterial(canvas) {
|
|
1011
1029
|
const material = new import_three5.MeshBasicMaterial({
|
|
1012
1030
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -1173,6 +1191,7 @@ var init_Materials = __esm({
|
|
|
1173
1191
|
}
|
|
1174
1192
|
return this.createBasicCanvasMaterial(canvas, transparent, shade);
|
|
1175
1193
|
}
|
|
1194
|
+
/** Returns a shared image material. Use {@link createImage} for a separate material instance. */
|
|
1176
1195
|
static getImage(key) {
|
|
1177
1196
|
const keyStr = serializeMaterialKey(key);
|
|
1178
1197
|
const map = Caching.materialCache.peek(keyStr)?.map;
|
|
@@ -1347,6 +1366,14 @@ var init_AssetKey = __esm({
|
|
|
1347
1366
|
}
|
|
1348
1367
|
};
|
|
1349
1368
|
AssetKey = class _AssetKey extends BasicAssetKey {
|
|
1369
|
+
/**
|
|
1370
|
+
* Creates a key from separate path components. Use {@link parse} for a combined reference.
|
|
1371
|
+
*
|
|
1372
|
+
* @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
|
|
1373
|
+
* @param type - Subdirectory, such as `block` or `item`.
|
|
1374
|
+
* @param rootType - Top-level directory, usually `assets` or `data`.
|
|
1375
|
+
* @param root - Base URL override for hosted asset sources.
|
|
1376
|
+
*/
|
|
1350
1377
|
constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
|
|
1351
1378
|
super(namespace, path);
|
|
1352
1379
|
this.namespace = namespace;
|
|
@@ -1358,6 +1385,16 @@ var init_AssetKey = __esm({
|
|
|
1358
1385
|
this.root = root;
|
|
1359
1386
|
this.isAssetKey = true;
|
|
1360
1387
|
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Parses an asset reference such as `minecraft:block/stone`.
|
|
1390
|
+
* A missing namespace defaults to the origin's namespace or `minecraft`.
|
|
1391
|
+
*
|
|
1392
|
+
* @param assetType - Asset category, such as `models` or `textures`.
|
|
1393
|
+
* @param str - Path with an optional namespace and file extension.
|
|
1394
|
+
* @param origin - Supplies the asset root, default namespace, and non-texture extension.
|
|
1395
|
+
* @returns A key with the matching extension removed from its path. Textures use `.png`;
|
|
1396
|
+
* other assets use the origin's extension or `.json`.
|
|
1397
|
+
*/
|
|
1361
1398
|
static parse(assetType, str, origin) {
|
|
1362
1399
|
let namespace = origin?.namespace || DEFAULT_NAMESPACE;
|
|
1363
1400
|
if (str.includes(":")) {
|
|
@@ -1389,6 +1426,7 @@ var init_AssetKey = __esm({
|
|
|
1389
1426
|
];
|
|
1390
1427
|
return a.join("/");
|
|
1391
1428
|
}
|
|
1429
|
+
/** Joins the type subdirectory and path without adding a namespace or file extension. */
|
|
1392
1430
|
getFullPath() {
|
|
1393
1431
|
let p10 = [];
|
|
1394
1432
|
if (this.type) {
|
|
@@ -1400,6 +1438,7 @@ var init_AssetKey = __esm({
|
|
|
1400
1438
|
toNamespacedString() {
|
|
1401
1439
|
return this.namespace + ":" + this.getFullPath();
|
|
1402
1440
|
}
|
|
1441
|
+
/** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
|
|
1403
1442
|
serialize() {
|
|
1404
1443
|
return this.toString();
|
|
1405
1444
|
}
|
|
@@ -1459,6 +1498,7 @@ var init_DisplayTransforms = __esm({
|
|
|
1459
1498
|
const scale = new import_three7.Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
|
|
1460
1499
|
return new import_three7.Matrix4().compose(translation, rotation, scale);
|
|
1461
1500
|
}
|
|
1501
|
+
/** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
|
|
1462
1502
|
static apply(geometry, matrix) {
|
|
1463
1503
|
geometry.applyMatrix4(matrix);
|
|
1464
1504
|
if (matrix.determinant() < 0) {
|
|
@@ -1486,6 +1526,7 @@ var init_ModelMerger = __esm({
|
|
|
1486
1526
|
init_AssetKey();
|
|
1487
1527
|
init_DisplayTransforms();
|
|
1488
1528
|
ModelMerger = class {
|
|
1529
|
+
/** Loads the parent chain and returns a merged model without modifying the supplied definition. */
|
|
1489
1530
|
static async mergeWithParents(model) {
|
|
1490
1531
|
const models = await this.collectAllParents(model);
|
|
1491
1532
|
let merged = {};
|
|
@@ -1553,6 +1594,7 @@ var init_Models = __esm({
|
|
|
1553
1594
|
static get PERSISTENT_CACHE() {
|
|
1554
1595
|
return this._persistentCache ??= PersistentCache.open("minerender-models");
|
|
1555
1596
|
}
|
|
1597
|
+
/** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
|
|
1556
1598
|
static async getItemList() {
|
|
1557
1599
|
const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
|
|
1558
1600
|
const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
|
|
@@ -1623,6 +1665,7 @@ var init_Models = __esm({
|
|
|
1623
1665
|
}
|
|
1624
1666
|
throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
|
|
1625
1667
|
}
|
|
1668
|
+
/** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
|
|
1626
1669
|
static async getRaw(key) {
|
|
1627
1670
|
if (!key.assetType) {
|
|
1628
1671
|
key.assetType = "models";
|
|
@@ -1642,6 +1685,12 @@ var init_Models = __esm({
|
|
|
1642
1685
|
return asset;
|
|
1643
1686
|
});
|
|
1644
1687
|
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
|
|
1690
|
+
* Item keys use GUI context, false conditions, and zero numeric properties.
|
|
1691
|
+
*
|
|
1692
|
+
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
1693
|
+
*/
|
|
1645
1694
|
static async getMerged(key) {
|
|
1646
1695
|
if (!key.assetType) {
|
|
1647
1696
|
key.assetType = "models";
|
|
@@ -1654,9 +1703,11 @@ var init_Models = __esm({
|
|
|
1654
1703
|
return _Models.loadAndMerge(key);
|
|
1655
1704
|
});
|
|
1656
1705
|
}
|
|
1706
|
+
/** Alias for {@link getMerged}. */
|
|
1657
1707
|
static async get(key) {
|
|
1658
1708
|
return this.getMerged(key);
|
|
1659
1709
|
}
|
|
1710
|
+
/** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1660
1711
|
static async clearCache() {
|
|
1661
1712
|
return this.PERSISTENT_CACHE.clear();
|
|
1662
1713
|
}
|
|
@@ -1679,6 +1730,7 @@ var init_BlockStates = __esm({
|
|
|
1679
1730
|
return this._persistentCache ??= PersistentCache.open("minerender-blockstates");
|
|
1680
1731
|
}
|
|
1681
1732
|
// BlockState names are hardcoded
|
|
1733
|
+
/** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
|
|
1682
1734
|
static async getList() {
|
|
1683
1735
|
const key = new AssetKey(
|
|
1684
1736
|
DEFAULT_NAMESPACE,
|
|
@@ -1699,6 +1751,7 @@ var init_BlockStates = __esm({
|
|
|
1699
1751
|
return AssetLoader.get(key, "json" /* JSON */);
|
|
1700
1752
|
});
|
|
1701
1753
|
}
|
|
1754
|
+
/** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
|
|
1702
1755
|
static async getDefaultState(key) {
|
|
1703
1756
|
const defaultStates = await this.getDefaultStates();
|
|
1704
1757
|
if (!defaultStates) {
|
|
@@ -1706,6 +1759,7 @@ var init_BlockStates = __esm({
|
|
|
1706
1759
|
}
|
|
1707
1760
|
return defaultStates["minecraft:" + key.path];
|
|
1708
1761
|
}
|
|
1762
|
+
/** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
|
|
1709
1763
|
static async get(key) {
|
|
1710
1764
|
if (!key.assetType) {
|
|
1711
1765
|
key.assetType = "blockstates";
|
|
@@ -1732,6 +1786,7 @@ var init_BlockStates = __esm({
|
|
|
1732
1786
|
}
|
|
1733
1787
|
return Promise.all(promises);
|
|
1734
1788
|
}
|
|
1789
|
+
/** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1735
1790
|
static async clearCache() {
|
|
1736
1791
|
await this.PERSISTENT_CACHE.clear();
|
|
1737
1792
|
}
|
|
@@ -1757,9 +1812,11 @@ var init_Assets = __esm({
|
|
|
1757
1812
|
static parseAssetKey(assetType, str, origin) {
|
|
1758
1813
|
return AssetKey.parse(assetType, str, origin);
|
|
1759
1814
|
}
|
|
1815
|
+
/** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
|
|
1760
1816
|
static async getModel(key) {
|
|
1761
1817
|
return Models.getMerged(key);
|
|
1762
1818
|
}
|
|
1819
|
+
/** Loads a blockstate definition. See {@link BlockStates.get}. */
|
|
1763
1820
|
static async getBlockState(key) {
|
|
1764
1821
|
return BlockStates.get(key);
|
|
1765
1822
|
}
|
|
@@ -1806,6 +1863,10 @@ var init_BatchedExecutor = __esm({
|
|
|
1806
1863
|
"src/util/BatchedExecutor.ts"() {
|
|
1807
1864
|
import_jobqu2 = require("jobqu");
|
|
1808
1865
|
BatchedExecutor = class {
|
|
1866
|
+
/**
|
|
1867
|
+
* @param interval - Delay between queue runs, in milliseconds.
|
|
1868
|
+
* @param batch - Maximum tasks started per run and maximum tasks active at once.
|
|
1869
|
+
*/
|
|
1809
1870
|
constructor(interval = 1, batch = 30) {
|
|
1810
1871
|
if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
|
|
1811
1872
|
if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
|
|
@@ -1813,9 +1874,11 @@ var init_BatchedExecutor = __esm({
|
|
|
1813
1874
|
this.batch = batch;
|
|
1814
1875
|
this.queue = new import_jobqu2.JobQueue(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
|
|
1815
1876
|
}
|
|
1877
|
+
/** Queues a task and resolves with its result, or rejects with its error. */
|
|
1816
1878
|
submit(task) {
|
|
1817
1879
|
return this.queue.add(() => task());
|
|
1818
1880
|
}
|
|
1881
|
+
/** Rejects queued and future tasks. Tasks already running are allowed to finish. */
|
|
1819
1882
|
stop() {
|
|
1820
1883
|
this.queue.end();
|
|
1821
1884
|
}
|
|
@@ -1958,6 +2021,7 @@ var init_NBTHelper = __esm({
|
|
|
1958
2021
|
"src/nbt/NBTHelper.ts"() {
|
|
1959
2022
|
import_buffer2 = require("buffer");
|
|
1960
2023
|
NBTHelper = class {
|
|
2024
|
+
/** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
|
|
1961
2025
|
static async fromBuffer(data, format2) {
|
|
1962
2026
|
const buffer = import_buffer2.Buffer.from(data instanceof Uint8Array ? data : new Uint8Array(data));
|
|
1963
2027
|
const prismarineNbt = await import("prismarine-nbt");
|
|
@@ -2102,6 +2166,7 @@ var init_HostedAssetSource = __esm({
|
|
|
2102
2166
|
["json" /* JSON */, _HostedAssetSource.JSON]
|
|
2103
2167
|
]);
|
|
2104
2168
|
}
|
|
2169
|
+
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
2105
2170
|
async loadOrRetryWithDefaults(key, parser) {
|
|
2106
2171
|
const direct = await this.load(key, parser);
|
|
2107
2172
|
if (typeof direct !== "undefined") {
|
|
@@ -2159,6 +2224,10 @@ var init_HostedAssetSource = __esm({
|
|
|
2159
2224
|
assetBasePath(key) {
|
|
2160
2225
|
return `${key.root ?? this.root ?? AssetLoader.ROOT}/${key.rootType !== void 0 ? key.rootType + "/" : ""}${key.namespace !== void 0 ? key.namespace + "/" : ""}${key.assetType !== void 0 ? key.assetType + "/" : ""}`;
|
|
2161
2226
|
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Creates a hosted source for {@link AssetLoader.addSource}.
|
|
2229
|
+
* Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
|
|
2230
|
+
*/
|
|
2162
2231
|
constructor(root, options) {
|
|
2163
2232
|
super();
|
|
2164
2233
|
this._root = root;
|
|
@@ -2190,6 +2259,11 @@ var init_BrowserArchiveProxy = __esm({
|
|
|
2190
2259
|
"src/assets/source/archive/BrowserArchiveProxy.ts"() {
|
|
2191
2260
|
import_zip = require("@zip.js/zip.js");
|
|
2192
2261
|
BrowserArchiveProxy = class {
|
|
2262
|
+
/**
|
|
2263
|
+
* Opens a ZIP for asset lookup.
|
|
2264
|
+
* @param id - Cache identity for this content. Change it when the pack changes.
|
|
2265
|
+
* A File supplies an identity from its name, size, and modification time when omitted.
|
|
2266
|
+
*/
|
|
2193
2267
|
constructor(blob, id) {
|
|
2194
2268
|
this._blob = blob;
|
|
2195
2269
|
this._reader = new import_zip.ZipReader(new import_zip.BlobReader(this._blob));
|
|
@@ -2389,6 +2463,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2389
2463
|
dataPackFormat: copyFormat(options.dataPackFormat)
|
|
2390
2464
|
};
|
|
2391
2465
|
}
|
|
2466
|
+
/** Creates a browser ZIP source from a Blob or File. */
|
|
2392
2467
|
static blob(blob, options) {
|
|
2393
2468
|
return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
|
|
2394
2469
|
}
|
|
@@ -2521,6 +2596,7 @@ var init_AssetLoader = __esm({
|
|
|
2521
2596
|
FALLBACK_ROOT = "https://raw.githubusercontent.com/InventivetalentDev/minerender-fallback-assets/master";
|
|
2522
2597
|
AssetLoader = class {
|
|
2523
2598
|
static {
|
|
2599
|
+
/** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
|
|
2524
2600
|
this.ROOT = DEFAULT_ROOT;
|
|
2525
2601
|
}
|
|
2526
2602
|
static {
|
|
@@ -2533,6 +2609,7 @@ var init_AssetLoader = __esm({
|
|
|
2533
2609
|
static get version() {
|
|
2534
2610
|
return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
|
|
2535
2611
|
}
|
|
2612
|
+
/** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
|
|
2536
2613
|
static setVersion(version) {
|
|
2537
2614
|
this.ROOT = `https://assets.mcasset.cloud/${version}`;
|
|
2538
2615
|
const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
|
|
@@ -2566,6 +2643,13 @@ var init_AssetLoader = __esm({
|
|
|
2566
2643
|
return scope ? `${scope}
|
|
2567
2644
|
${key}` : key;
|
|
2568
2645
|
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Registers a source at the highest priority.
|
|
2648
|
+
* Call {@link Caching.clear} after changing sources to discard previously loaded assets.
|
|
2649
|
+
*
|
|
2650
|
+
* @param key - Name used to replace or remove this source.
|
|
2651
|
+
* @param override - Removes the first source with this name before adding the new one.
|
|
2652
|
+
*/
|
|
2569
2653
|
static addSource(key, source, override = true) {
|
|
2570
2654
|
if (override) {
|
|
2571
2655
|
const existing = this.removeSource(key);
|
|
@@ -2576,6 +2660,7 @@ ${key}` : key;
|
|
|
2576
2660
|
this._SOURCES.unshift({ key, source });
|
|
2577
2661
|
console.log(p4, "Added AssetSource", key);
|
|
2578
2662
|
}
|
|
2663
|
+
/** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
|
|
2579
2664
|
static removeSource(key) {
|
|
2580
2665
|
const index = this._SOURCES.findIndex((s) => s.key === key);
|
|
2581
2666
|
if (index != -1) {
|
|
@@ -2590,6 +2675,7 @@ ${key}` : key;
|
|
|
2590
2675
|
this.addSource("mcassets-fallback", new HostedAssetSource(FALLBACK_ROOT, { retryDefaults: false }));
|
|
2591
2676
|
this.addSource("mcassets", new HostedAssetSource(this.ROOT, { retryDefaults: false }));
|
|
2592
2677
|
}
|
|
2678
|
+
/** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
|
|
2593
2679
|
static async getAll(key, parser) {
|
|
2594
2680
|
const sources = [...this._SOURCES];
|
|
2595
2681
|
const results = [];
|
|
@@ -2651,6 +2737,7 @@ var init_ModelTextures = __esm({
|
|
|
2651
2737
|
static get PERSISTENT_META_CACHE() {
|
|
2652
2738
|
return this._persistentMetaCache ??= PersistentCache.open("minerender-texturemeta");
|
|
2653
2739
|
}
|
|
2740
|
+
/** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
|
|
2654
2741
|
static async get(key) {
|
|
2655
2742
|
const keyStr = key.serialize();
|
|
2656
2743
|
const pending = this.preload(key);
|
|
@@ -2668,6 +2755,7 @@ var init_ModelTextures = __esm({
|
|
|
2668
2755
|
throw err;
|
|
2669
2756
|
}
|
|
2670
2757
|
}
|
|
2758
|
+
/** Fetches and caches encoded texture bytes without decoding the pixels. */
|
|
2671
2759
|
static async preload(key) {
|
|
2672
2760
|
const keyStr = key.serialize();
|
|
2673
2761
|
return Caching.textureAssetCache.get(keyStr, (k) => {
|
|
@@ -2678,6 +2766,7 @@ var init_ModelTextures = __esm({
|
|
|
2678
2766
|
});
|
|
2679
2767
|
});
|
|
2680
2768
|
}
|
|
2769
|
+
/** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
|
|
2681
2770
|
static async getMeta(key) {
|
|
2682
2771
|
if (!key.extension || !key.extension.endsWith(".mcmeta")) {
|
|
2683
2772
|
key = Object.assign(new AssetKey("", ""), key);
|
|
@@ -2694,6 +2783,7 @@ var init_ModelTextures = __esm({
|
|
|
2694
2783
|
});
|
|
2695
2784
|
});
|
|
2696
2785
|
}
|
|
2786
|
+
/** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
|
|
2697
2787
|
static async clearCache() {
|
|
2698
2788
|
await this.PERSISTENT_META_CACHE.clear();
|
|
2699
2789
|
}
|
|
@@ -2781,6 +2871,7 @@ var init_Ticker = __esm({
|
|
|
2781
2871
|
}
|
|
2782
2872
|
return handle;
|
|
2783
2873
|
}
|
|
2874
|
+
/** Starts or resumes the shared tick loop. Repeated calls have no effect. */
|
|
2784
2875
|
static start() {
|
|
2785
2876
|
if (this.interval) return;
|
|
2786
2877
|
this.interval = this.schedule(() => {
|
|
@@ -2803,6 +2894,7 @@ var init_Ticker = __esm({
|
|
|
2803
2894
|
_Ticker.fiveSecondTicks = 0;
|
|
2804
2895
|
}, 1e3 * 5);
|
|
2805
2896
|
}
|
|
2897
|
+
/** Pauses the loop while retaining callbacks for a later {@link start}. */
|
|
2806
2898
|
static stop() {
|
|
2807
2899
|
if (this.interval) clearInterval(this.interval);
|
|
2808
2900
|
if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
|
|
@@ -2811,12 +2903,14 @@ var init_Ticker = __esm({
|
|
|
2811
2903
|
this.oneSecondTicksTracker = void 0;
|
|
2812
2904
|
this.fiveSecondTicksTracker = void 0;
|
|
2813
2905
|
}
|
|
2906
|
+
/** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
|
|
2814
2907
|
static add(tick) {
|
|
2815
2908
|
this.start();
|
|
2816
2909
|
const c = this.counter++;
|
|
2817
2910
|
this._tickers.set(c, tick);
|
|
2818
2911
|
return c;
|
|
2819
2912
|
}
|
|
2913
|
+
/** Removes a callback by ID and stops the timers when no callbacks remain. */
|
|
2820
2914
|
static remove(c) {
|
|
2821
2915
|
if (typeof c === "number") this._tickers.delete(c);
|
|
2822
2916
|
if (!this._tickers.size) this.stop();
|
|
@@ -2830,6 +2924,7 @@ var init_Ticker = __esm({
|
|
|
2830
2924
|
static get tpsFiveSeconds() {
|
|
2831
2925
|
return this.fiveSecondTps;
|
|
2832
2926
|
}
|
|
2927
|
+
/** Stops the loop and removes all registered callbacks. */
|
|
2833
2928
|
static dispose() {
|
|
2834
2929
|
this.stop();
|
|
2835
2930
|
this._tickers.clear();
|
|
@@ -2876,6 +2971,7 @@ var init_TextureAtlas = __esm({
|
|
|
2876
2971
|
}
|
|
2877
2972
|
};
|
|
2878
2973
|
}
|
|
2974
|
+
/** Copies pixels for a texture variable from its current atlas rectangle. */
|
|
2879
2975
|
getData(texture) {
|
|
2880
2976
|
const pos = this.positions[texture];
|
|
2881
2977
|
const size = this.sizes[texture];
|
|
@@ -3155,6 +3251,7 @@ var init_UVMapper = __esm({
|
|
|
3155
3251
|
}
|
|
3156
3252
|
uv.needsUpdate = true;
|
|
3157
3253
|
}
|
|
3254
|
+
/** Returns the shared atlas for a keyed, merged model, creating it on first use. */
|
|
3158
3255
|
static async getAtlas(model) {
|
|
3159
3256
|
const keyStr = model.key.serialize();
|
|
3160
3257
|
return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
|
|
@@ -3225,6 +3322,11 @@ var init_UVMapper = __esm({
|
|
|
3225
3322
|
}
|
|
3226
3323
|
return [tl, tr, bl, br];
|
|
3227
3324
|
}
|
|
3325
|
+
/**
|
|
3326
|
+
* Combines model textures and animation metadata into an atlas.
|
|
3327
|
+
* Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
|
|
3328
|
+
* Returns `undefined` for models without a texture map.
|
|
3329
|
+
*/
|
|
3228
3330
|
static async createAtlas(originalModel) {
|
|
3229
3331
|
const textureMap = {};
|
|
3230
3332
|
const metaMap = {};
|
|
@@ -3589,6 +3691,7 @@ var init_Entities = __esm({
|
|
|
3589
3691
|
init_MineRenderError();
|
|
3590
3692
|
init_ModelTextures();
|
|
3591
3693
|
Entities = class {
|
|
3694
|
+
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
3592
3695
|
static async getEntityList() {
|
|
3593
3696
|
const collect = async (path) => {
|
|
3594
3697
|
const prefix2 = path ? `${path}/` : "";
|
|
@@ -3606,6 +3709,7 @@ var init_Entities = __esm({
|
|
|
3606
3709
|
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
3607
3710
|
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3608
3711
|
}
|
|
3712
|
+
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
3609
3713
|
static async getLayerList(modelKey) {
|
|
3610
3714
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
3611
3715
|
}
|
|
@@ -3613,6 +3717,15 @@ var init_Entities = __esm({
|
|
|
3613
3717
|
static async getPassList(modelKey) {
|
|
3614
3718
|
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
3615
3719
|
}
|
|
3720
|
+
/**
|
|
3721
|
+
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
3722
|
+
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
3723
|
+
*
|
|
3724
|
+
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
3725
|
+
* @param textureKey - Texture override for the first selected layer.
|
|
3726
|
+
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
3727
|
+
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
3728
|
+
*/
|
|
3616
3729
|
static async getEntity(modelKey, textureKey, options) {
|
|
3617
3730
|
const model = await this.getModelFile(modelKey);
|
|
3618
3731
|
if (!model) return void 0;
|
|
@@ -3658,6 +3771,7 @@ var init_Entities = __esm({
|
|
|
3658
3771
|
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3659
3772
|
return file?.animations;
|
|
3660
3773
|
}
|
|
3774
|
+
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
3661
3775
|
static async resolveTexture(modelKey) {
|
|
3662
3776
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3663
3777
|
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
@@ -3818,12 +3932,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3818
3932
|
this._animation = void 0;
|
|
3819
3933
|
this._time = 0;
|
|
3820
3934
|
}
|
|
3935
|
+
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
3821
3936
|
setTime(seconds) {
|
|
3822
3937
|
if (!this._animation) return false;
|
|
3823
3938
|
this._time = seconds;
|
|
3824
3939
|
this.apply();
|
|
3825
3940
|
return true;
|
|
3826
3941
|
}
|
|
3942
|
+
/** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
|
|
3827
3943
|
advance(deltaSeconds) {
|
|
3828
3944
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
3829
3945
|
}
|
|
@@ -3861,6 +3977,7 @@ var init_InstanceReference = __esm({
|
|
|
3861
3977
|
if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
|
|
3862
3978
|
return this.instanceable;
|
|
3863
3979
|
}
|
|
3980
|
+
/** Releases this placement's slot for reuse. Repeated calls have no effect. */
|
|
3864
3981
|
removeFromScene() {
|
|
3865
3982
|
if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
|
|
3866
3983
|
}
|
|
@@ -3873,9 +3990,11 @@ var init_InstanceReference = __esm({
|
|
|
3873
3990
|
setMatrix(matrix) {
|
|
3874
3991
|
this.activeInstanceable.setMatrixAt(this.index, matrix);
|
|
3875
3992
|
}
|
|
3993
|
+
/** Hides or restores this placement while preserving its transform and allocated slot. */
|
|
3876
3994
|
setVisible(visible) {
|
|
3877
3995
|
this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
|
|
3878
3996
|
}
|
|
3997
|
+
/** Updates the supplied transform components. Positions use scene units and rotations use radians. */
|
|
3879
3998
|
setPositionRotationScale(position, rotation, scale) {
|
|
3880
3999
|
this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
|
|
3881
4000
|
}
|
|
@@ -3952,6 +4071,7 @@ var init_SceneObject = __esm({
|
|
|
3952
4071
|
}
|
|
3953
4072
|
async init() {
|
|
3954
4073
|
}
|
|
4074
|
+
/** Marks ancestor scenes for redraw and emits a `change` event. */
|
|
3955
4075
|
notifyDirty() {
|
|
3956
4076
|
this.traverseAncestors((parent) => {
|
|
3957
4077
|
const scene = parent;
|
|
@@ -3987,15 +4107,17 @@ var init_SceneObject = __esm({
|
|
|
3987
4107
|
return obj;
|
|
3988
4108
|
}
|
|
3989
4109
|
/**
|
|
3990
|
-
*
|
|
4110
|
+
* Finds a named part, such as `head`, without the internal `group:` prefix.
|
|
4111
|
+
* Returns `undefined` when the group does not exist.
|
|
3991
4112
|
*/
|
|
3992
4113
|
getGroupByName(name) {
|
|
3993
4114
|
return this.getObjectByName(`group:${name}`);
|
|
3994
4115
|
}
|
|
3995
4116
|
/**
|
|
3996
|
-
*
|
|
3997
|
-
* @param name name
|
|
3998
|
-
* @param visible
|
|
4117
|
+
* Changes a named group's visibility and requests a redraw.
|
|
4118
|
+
* @param name - Part name without the `group:` prefix.
|
|
4119
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4120
|
+
* @returns The resulting visibility, or `false` if the group does not exist.
|
|
3999
4121
|
*/
|
|
4000
4122
|
toggleGroupVisibility(name, visible) {
|
|
4001
4123
|
return this.toggleObjectVisibility(this.getGroupByName(name), visible);
|
|
@@ -4046,15 +4168,16 @@ var init_SceneObject = __esm({
|
|
|
4046
4168
|
return mesh;
|
|
4047
4169
|
}
|
|
4048
4170
|
/**
|
|
4049
|
-
*
|
|
4171
|
+
* Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
|
|
4050
4172
|
*/
|
|
4051
4173
|
getMeshByName(name) {
|
|
4052
4174
|
return this.getObjectByName(`mesh:${name}`);
|
|
4053
4175
|
}
|
|
4054
4176
|
/**
|
|
4055
|
-
*
|
|
4056
|
-
* @param name name
|
|
4057
|
-
* @param visible
|
|
4177
|
+
* Changes a named mesh's visibility and requests a redraw.
|
|
4178
|
+
* @param name - Mesh name without the `mesh:` prefix.
|
|
4179
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4180
|
+
* @returns The resulting visibility, or `false` if the mesh does not exist.
|
|
4058
4181
|
*/
|
|
4059
4182
|
toggleMeshVisibility(name, visible) {
|
|
4060
4183
|
return this.toggleObjectVisibility(this.getMeshByName(name), visible);
|
|
@@ -4100,12 +4223,14 @@ var init_SceneObject = __esm({
|
|
|
4100
4223
|
get isInstanced() {
|
|
4101
4224
|
return this._isInstanced;
|
|
4102
4225
|
}
|
|
4226
|
+
/** Number of live placements, excluding released instance slots. */
|
|
4103
4227
|
get instanceCounter() {
|
|
4104
4228
|
return this._instanceCounter;
|
|
4105
4229
|
}
|
|
4106
4230
|
constructInstanceReference(i) {
|
|
4107
4231
|
return new InstanceReference(this, i);
|
|
4108
4232
|
}
|
|
4233
|
+
/** Allocates a placement of this instanced object, reusing a released slot when available. */
|
|
4109
4234
|
nextInstance() {
|
|
4110
4235
|
const mesh = this.instanceMesh;
|
|
4111
4236
|
if (!mesh) throw new MineRenderError("Object is not instanced");
|
|
@@ -4252,6 +4377,7 @@ var init_SceneObject = __esm({
|
|
|
4252
4377
|
vector.setFromMatrixScale(matrix);
|
|
4253
4378
|
return vector;
|
|
4254
4379
|
}
|
|
4380
|
+
/** Updates supplied transform components. For a shared model, affects every live instance. */
|
|
4255
4381
|
setPositionRotationScale(position, rotation, scale) {
|
|
4256
4382
|
if (this.isInstanced) {
|
|
4257
4383
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4270,6 +4396,7 @@ var init_SceneObject = __esm({
|
|
|
4270
4396
|
}
|
|
4271
4397
|
this.notifyDirty();
|
|
4272
4398
|
}
|
|
4399
|
+
/** Sets position in scene units. For a shared model, updates every live instance. */
|
|
4273
4400
|
setPosition(position) {
|
|
4274
4401
|
if (this.isInstanced) {
|
|
4275
4402
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4287,6 +4414,7 @@ var init_SceneObject = __esm({
|
|
|
4287
4414
|
return this.position;
|
|
4288
4415
|
}
|
|
4289
4416
|
}
|
|
4417
|
+
/** Sets rotation in radians. For a shared model, updates every live instance. */
|
|
4290
4418
|
setRotation(rotation) {
|
|
4291
4419
|
if (this.isInstanced) {
|
|
4292
4420
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4304,6 +4432,7 @@ var init_SceneObject = __esm({
|
|
|
4304
4432
|
return this.rotation;
|
|
4305
4433
|
}
|
|
4306
4434
|
}
|
|
4435
|
+
/** Sets scale factors. For a shared model, updates every live instance. */
|
|
4307
4436
|
setScale(scale) {
|
|
4308
4437
|
if (this.isInstanced) {
|
|
4309
4438
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4341,6 +4470,7 @@ var init_SceneObject = __esm({
|
|
|
4341
4470
|
this.notifyDirty();
|
|
4342
4471
|
super.dispose();
|
|
4343
4472
|
}
|
|
4473
|
+
/** Releases instance slots and removes children, disposing children that implement Disposable. */
|
|
4344
4474
|
disposeAndRemoveAllChildren() {
|
|
4345
4475
|
if (this.instanceMesh) {
|
|
4346
4476
|
if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
|
|
@@ -4363,6 +4493,7 @@ var init_SceneObject = __esm({
|
|
|
4363
4493
|
}
|
|
4364
4494
|
this.notifyDirty();
|
|
4365
4495
|
}
|
|
4496
|
+
/** Detaches the object from its parent and requests a redraw. */
|
|
4366
4497
|
removeFromScene() {
|
|
4367
4498
|
this.notifyDirty();
|
|
4368
4499
|
this.removeFromParent();
|
|
@@ -4514,12 +4645,15 @@ var init_EntityObject = __esm({
|
|
|
4514
4645
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
4515
4646
|
}
|
|
4516
4647
|
//</editor-fold>
|
|
4648
|
+
/** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
|
|
4517
4649
|
getLayerGroup(name) {
|
|
4518
4650
|
return super.getGroupByName(`layer:${name}`);
|
|
4519
4651
|
}
|
|
4652
|
+
/** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
|
|
4520
4653
|
getGroupByName(name, layerName) {
|
|
4521
4654
|
return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
|
|
4522
4655
|
}
|
|
4656
|
+
/** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
|
|
4523
4657
|
getMeshByName(name, layerName) {
|
|
4524
4658
|
return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
|
|
4525
4659
|
}
|
|
@@ -5181,6 +5315,7 @@ var init_ModelCulling = __esm({
|
|
|
5181
5315
|
import_three23 = require("three");
|
|
5182
5316
|
init_CubeFace();
|
|
5183
5317
|
ModelCulling = class {
|
|
5318
|
+
/** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
|
|
5184
5319
|
static toLocalMask(worldMask, rotation) {
|
|
5185
5320
|
let localMask = 0;
|
|
5186
5321
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
@@ -5191,6 +5326,7 @@ var init_ModelCulling = __esm({
|
|
|
5191
5326
|
}
|
|
5192
5327
|
return localMask;
|
|
5193
5328
|
}
|
|
5329
|
+
/** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
|
|
5194
5330
|
static isOpaqueFullCube(atlas) {
|
|
5195
5331
|
if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
|
|
5196
5332
|
const element = atlas.model.elements[0];
|
|
@@ -6158,6 +6294,7 @@ var Meshes = class _Meshes {
|
|
|
6158
6294
|
static createBox(key) {
|
|
6159
6295
|
return new import_three6.Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
|
|
6160
6296
|
}
|
|
6297
|
+
/** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
|
|
6161
6298
|
static getBox(key) {
|
|
6162
6299
|
const keyStr = serializeMeshKey(key);
|
|
6163
6300
|
return Caching.boxMeshCache.get(keyStr, (k) => {
|
|
@@ -6270,6 +6407,7 @@ init_AssetParsers();
|
|
|
6270
6407
|
init_ModelTextures();
|
|
6271
6408
|
init_Caching();
|
|
6272
6409
|
var Fonts = class {
|
|
6410
|
+
/** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
|
|
6273
6411
|
static async get(key = "minecraft:default") {
|
|
6274
6412
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
6275
6413
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -9445,6 +9583,13 @@ var GuiHelper = class {
|
|
|
9445
9583
|
});
|
|
9446
9584
|
return layers;
|
|
9447
9585
|
}
|
|
9586
|
+
/**
|
|
9587
|
+
* Calculates a slot's top-left position in GUI pixels.
|
|
9588
|
+
* @param slot - Zero-based slot index, or `[column, row]`.
|
|
9589
|
+
* @param origin - Position of the first slot.
|
|
9590
|
+
* @param offset - Horizontal and vertical spacing between slot origins, in pixels.
|
|
9591
|
+
* @param rowSize - Slots per row when `slot` is an index.
|
|
9592
|
+
*/
|
|
9448
9593
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
9449
9594
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
9450
9595
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
@@ -10102,6 +10247,7 @@ var SceneStatsDisplay = class {
|
|
|
10102
10247
|
appendTo(el) {
|
|
10103
10248
|
el.append(this.statsContainer);
|
|
10104
10249
|
}
|
|
10250
|
+
/** Stops the refresh timer and removes the panel from the page. */
|
|
10105
10251
|
dispose() {
|
|
10106
10252
|
clearInterval(this.interval);
|
|
10107
10253
|
this.interval = void 0;
|
|
@@ -10126,6 +10272,7 @@ var InstanceManager = class {
|
|
|
10126
10272
|
this.isInstanceManager = true;
|
|
10127
10273
|
this.instanceCache = {};
|
|
10128
10274
|
}
|
|
10275
|
+
/** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
|
|
10129
10276
|
async get(key) {
|
|
10130
10277
|
if (key in this.instanceCache) {
|
|
10131
10278
|
console.debug(p9, "key in cache", key);
|
|
@@ -10133,6 +10280,7 @@ var InstanceManager = class {
|
|
|
10133
10280
|
}
|
|
10134
10281
|
return void 0;
|
|
10135
10282
|
}
|
|
10283
|
+
/** Allocates a placement, calling the supplier once when the shared model is first needed. */
|
|
10136
10284
|
async getOrCreate(key, supplier) {
|
|
10137
10285
|
if (key in this.instanceCache) {
|
|
10138
10286
|
return await this.get(key);
|
|
@@ -10149,6 +10297,7 @@ var InstanceManager = class {
|
|
|
10149
10297
|
throw error;
|
|
10150
10298
|
}
|
|
10151
10299
|
}
|
|
10300
|
+
/** Forgets cached models without disposing them or releasing their existing placements. */
|
|
10152
10301
|
reset() {
|
|
10153
10302
|
for (let instanceCacheKey in this.instanceCache) {
|
|
10154
10303
|
delete this.instanceCache[instanceCacheKey];
|
|
@@ -10194,6 +10343,7 @@ function matchesCondition(condition, state) {
|
|
|
10194
10343
|
});
|
|
10195
10344
|
}
|
|
10196
10345
|
var BlockStateResolver = class {
|
|
10346
|
+
/** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
|
|
10197
10347
|
static async defaults(blockState) {
|
|
10198
10348
|
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
10199
10349
|
const state = {};
|
|
@@ -10213,9 +10363,11 @@ var BlockStateResolver = class {
|
|
|
10213
10363
|
}
|
|
10214
10364
|
return state;
|
|
10215
10365
|
}
|
|
10366
|
+
/** Selects matching models. Supply `choose` to control selection within each alternatives array. */
|
|
10216
10367
|
static select(blockState, state, choose = this.choose) {
|
|
10217
10368
|
return this.matching(blockState, state).map(choose);
|
|
10218
10369
|
}
|
|
10370
|
+
/** Returns matching model groups before choosing weighted alternatives. */
|
|
10219
10371
|
static matching(blockState, state) {
|
|
10220
10372
|
const out = [];
|
|
10221
10373
|
if (blockState.variants) {
|
|
@@ -10239,6 +10391,7 @@ var BlockStateResolver = class {
|
|
|
10239
10391
|
}
|
|
10240
10392
|
return out;
|
|
10241
10393
|
}
|
|
10394
|
+
/** Selects a random alternative using positive integer weights, each defaulting to 1. */
|
|
10242
10395
|
static choose(variants) {
|
|
10243
10396
|
if (!Array.isArray(variants)) return variants;
|
|
10244
10397
|
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
@@ -10256,6 +10409,7 @@ var BlockStateResolver = class {
|
|
|
10256
10409
|
}
|
|
10257
10410
|
return variants[variants.length - 1];
|
|
10258
10411
|
}
|
|
10412
|
+
/** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
|
|
10259
10413
|
static rotation(variant) {
|
|
10260
10414
|
const rotation = new import_three29.Euler();
|
|
10261
10415
|
if (typeof variant.x !== "undefined") {
|
|
@@ -10542,6 +10696,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10542
10696
|
}
|
|
10543
10697
|
this.notifyDirty();
|
|
10544
10698
|
}
|
|
10699
|
+
/** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
|
|
10545
10700
|
get state() {
|
|
10546
10701
|
return this._state;
|
|
10547
10702
|
}
|
|
@@ -10641,6 +10796,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
10641
10796
|
obj.setPosition(this.position);
|
|
10642
10797
|
return obj;
|
|
10643
10798
|
}
|
|
10799
|
+
/** Clears selected properties and rebuilds models without reapplying property defaults. */
|
|
10644
10800
|
async resetState() {
|
|
10645
10801
|
this._previousState = this._state;
|
|
10646
10802
|
this._state = {};
|
|
@@ -12540,6 +12696,11 @@ function compoundList(tags, name) {
|
|
|
12540
12696
|
// src/model/multiblock/StructureParser.ts
|
|
12541
12697
|
init_MineRenderError();
|
|
12542
12698
|
var StructureParser = class {
|
|
12699
|
+
/**
|
|
12700
|
+
* Parses decoded NBT, omitting air blocks.
|
|
12701
|
+
* @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
|
|
12702
|
+
* @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
|
|
12703
|
+
*/
|
|
12543
12704
|
static async parse(_nbt, paletteIndex) {
|
|
12544
12705
|
const nbt = _nbt.value;
|
|
12545
12706
|
let palette;
|
|
@@ -13374,6 +13535,7 @@ var SkinImage = class {
|
|
|
13374
13535
|
// src/skin/SkinTextures.ts
|
|
13375
13536
|
init_Textures();
|
|
13376
13537
|
var SkinTextures = class {
|
|
13538
|
+
/** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
|
|
13377
13539
|
static async get(src, legacy) {
|
|
13378
13540
|
const image = await SkinImage.getData(src);
|
|
13379
13541
|
const scale = image.width / 64;
|
|
@@ -13547,6 +13709,14 @@ var SkinObject = class extends SceneObject {
|
|
|
13547
13709
|
}
|
|
13548
13710
|
}
|
|
13549
13711
|
}
|
|
13712
|
+
/**
|
|
13713
|
+
* Loads a skin texture, detecting slim arms and legacy layouts by default.
|
|
13714
|
+
* To override detection, set `slim` or `legacy` in the options passed to
|
|
13715
|
+
* `new SkinObject(options)` or `scene.addSkin(src, options)`.
|
|
13716
|
+
* Use {@link setSlim} or {@link setLegacy} to change these settings later.
|
|
13717
|
+
*
|
|
13718
|
+
* @param src - URL of the skin texture.
|
|
13719
|
+
*/
|
|
13550
13720
|
async setSkinTexture(src) {
|
|
13551
13721
|
if (typeof src === "undefined") return;
|
|
13552
13722
|
this.skinTextureSrc = src;
|
|
@@ -13698,6 +13868,7 @@ var MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13698
13868
|
this.stats.sceneObjectCount += change;
|
|
13699
13869
|
}
|
|
13700
13870
|
}
|
|
13871
|
+
/** Initializes each object before attaching it to the scene. */
|
|
13701
13872
|
async initAndAdd(...object2) {
|
|
13702
13873
|
this.dirty = true;
|
|
13703
13874
|
for (let obj of object2) {
|
|
@@ -13733,13 +13904,33 @@ var MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13733
13904
|
return obj;
|
|
13734
13905
|
}
|
|
13735
13906
|
}
|
|
13907
|
+
/**
|
|
13908
|
+
* Adds a model loaded with {@link Models.getMerged}.
|
|
13909
|
+
* Set `options.instanceMeshes` to `false` to create a separate ModelObject.
|
|
13910
|
+
*
|
|
13911
|
+
* @param parent - Object to attach the model to. Defaults to this scene.
|
|
13912
|
+
* @returns The model, or a reference to one placement of a shared model.
|
|
13913
|
+
*/
|
|
13736
13914
|
async addModel(model, options, parent = this) {
|
|
13737
13915
|
options = { ...options, tints: await ItemTints.get(model, options?.tints) };
|
|
13738
13916
|
return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
|
|
13739
13917
|
}
|
|
13918
|
+
/**
|
|
13919
|
+
* Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
|
|
13920
|
+
* Set `options.initialState` to choose block properties such as `facing` or `axis`.
|
|
13921
|
+
* Use the returned object's `setPosition` method to move all of its model parts.
|
|
13922
|
+
*/
|
|
13740
13923
|
async addBlock(blockState, options, parent = this) {
|
|
13741
13924
|
return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
|
|
13742
13925
|
}
|
|
13926
|
+
/**
|
|
13927
|
+
* Loads a skin and adds an initialized player model.
|
|
13928
|
+
*
|
|
13929
|
+
* @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
|
|
13930
|
+
* Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
|
|
13931
|
+
* @param options - Player settings, including `slim` and `legacy` detection overrides.
|
|
13932
|
+
* @param parent - Object to attach the player to. Defaults to this scene.
|
|
13933
|
+
*/
|
|
13743
13934
|
async addSkin(skin, options, parent = this) {
|
|
13744
13935
|
this.dirty = true;
|
|
13745
13936
|
const obj = new SkinObject(options);
|
|
@@ -13751,9 +13942,14 @@ var MineRenderScene = class _MineRenderScene extends import_three34.Scene {
|
|
|
13751
13942
|
parent.add(obj);
|
|
13752
13943
|
return obj;
|
|
13753
13944
|
}
|
|
13945
|
+
/** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
|
|
13754
13946
|
async addEntity(entity, options, parent = this) {
|
|
13755
13947
|
return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
|
|
13756
13948
|
}
|
|
13949
|
+
/**
|
|
13950
|
+
* Adds GUI layers in draw order. One GUI pixel equals one scene unit.
|
|
13951
|
+
* Layer positions start at the top left, with positive GUI y pointing down.
|
|
13952
|
+
*/
|
|
13757
13953
|
async addGui(layers, options, parent = this) {
|
|
13758
13954
|
const obj = new GuiObject(layers, options);
|
|
13759
13955
|
obj.scene = this;
|
|
@@ -14608,6 +14804,7 @@ var Renderer = class _Renderer {
|
|
|
14608
14804
|
get element() {
|
|
14609
14805
|
return this._element;
|
|
14610
14806
|
}
|
|
14807
|
+
/** Attaches the canvas to an element and sizes it to that element's dimensions. */
|
|
14611
14808
|
appendTo(element) {
|
|
14612
14809
|
if (this._disposed) return;
|
|
14613
14810
|
this._element = element;
|
|
@@ -14635,6 +14832,7 @@ var Renderer = class _Renderer {
|
|
|
14635
14832
|
events.add(changeEvent2);
|
|
14636
14833
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
14637
14834
|
}
|
|
14835
|
+
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
14638
14836
|
resize(width, height) {
|
|
14639
14837
|
if (this._disposed) return;
|
|
14640
14838
|
if (isPerspectiveCamera(this.camera)) {
|
|
@@ -14673,12 +14871,14 @@ var Renderer = class _Renderer {
|
|
|
14673
14871
|
if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
|
|
14674
14872
|
};
|
|
14675
14873
|
}
|
|
14874
|
+
/** Starts or resumes the animation loop and registered frame callbacks. */
|
|
14676
14875
|
start() {
|
|
14677
14876
|
if (this._disposed) return;
|
|
14678
14877
|
this.stop();
|
|
14679
14878
|
this._running = true;
|
|
14680
14879
|
if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
|
|
14681
14880
|
}
|
|
14881
|
+
/** Pauses rendering and frame callbacks. Call {@link start} to resume. */
|
|
14682
14882
|
stop() {
|
|
14683
14883
|
if (this._disposed) return;
|
|
14684
14884
|
this._running = false;
|
|
@@ -14787,12 +14987,15 @@ var Renderer = class _Renderer {
|
|
|
14787
14987
|
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
14788
14988
|
return canvas.toDataURL(mime, quality);
|
|
14789
14989
|
}
|
|
14990
|
+
/** Exports visible scene meshes as OBJ text, without texture images. */
|
|
14790
14991
|
toObj() {
|
|
14791
14992
|
return SceneExporter.toObj(this.scene);
|
|
14792
14993
|
}
|
|
14994
|
+
/** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
|
|
14793
14995
|
toPLY(options) {
|
|
14794
14996
|
return SceneExporter.toPLY(this.scene, options);
|
|
14795
14997
|
}
|
|
14998
|
+
/** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
|
|
14796
14999
|
toGLTF(options) {
|
|
14797
15000
|
return SceneExporter.toGLTF(this.scene, options);
|
|
14798
15001
|
}
|
|
@@ -14835,12 +15038,14 @@ init_request();
|
|
|
14835
15038
|
init_Requests();
|
|
14836
15039
|
var Skins = class {
|
|
14837
15040
|
//<editor-fold desc="Skins">
|
|
15041
|
+
/** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
|
|
14838
15042
|
static async fromUuidOrUsername(uuidOrUsername) {
|
|
14839
15043
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14840
15044
|
return this.fromUuid(uuidOrUsername);
|
|
14841
15045
|
}
|
|
14842
15046
|
return this.fromUsername(uuidOrUsername);
|
|
14843
15047
|
}
|
|
15048
|
+
/** Builds a proxy URL for a UUID without downloading or checking the skin. */
|
|
14844
15049
|
static async fromUuid(uuid) {
|
|
14845
15050
|
return this.getMcProxySkinUrl(uuid);
|
|
14846
15051
|
}
|
|
@@ -14852,6 +15057,7 @@ var Skins = class {
|
|
|
14852
15057
|
return void 0;
|
|
14853
15058
|
});
|
|
14854
15059
|
}
|
|
15060
|
+
/** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
|
|
14855
15061
|
static async fromMineSkin(mineskinId) {
|
|
14856
15062
|
return this.getMineSkin(mineskinId).then((mineskin) => {
|
|
14857
15063
|
if (mineskin) {
|
|
@@ -14862,12 +15068,14 @@ var Skins = class {
|
|
|
14862
15068
|
}
|
|
14863
15069
|
//</editor-fold>
|
|
14864
15070
|
//<editor-fold desc="Capes">
|
|
15071
|
+
/** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
|
|
14865
15072
|
static async capeFromUuidOrUsername(uuidOrUsername) {
|
|
14866
15073
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14867
15074
|
return this.capeFromUuid(uuidOrUsername);
|
|
14868
15075
|
}
|
|
14869
15076
|
return this.capeFromUsername(uuidOrUsername);
|
|
14870
15077
|
}
|
|
15078
|
+
/** Builds a proxy URL without checking whether the player has a cape. */
|
|
14871
15079
|
static async capeFromUuid(uuid) {
|
|
14872
15080
|
return this.getMcProxyCapeUrl(uuid);
|
|
14873
15081
|
}
|
|
@@ -15022,16 +15230,19 @@ var ChunkData = class _ChunkData {
|
|
|
15022
15230
|
this.freeIds = [];
|
|
15023
15231
|
this.nbt = /* @__PURE__ */ new Map();
|
|
15024
15232
|
}
|
|
15233
|
+
/** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
|
|
15025
15234
|
get(index) {
|
|
15026
15235
|
_ChunkData.validateIndex(index);
|
|
15027
15236
|
const entry = this.palette[this.indices[index]];
|
|
15028
15237
|
return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
|
|
15029
15238
|
}
|
|
15239
|
+
/** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
|
|
15030
15240
|
snapshot(index) {
|
|
15031
15241
|
_ChunkData.validateIndex(index);
|
|
15032
15242
|
const entry = this.palette[this.indices[index]];
|
|
15033
15243
|
return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
|
|
15034
15244
|
}
|
|
15245
|
+
/** Copies block data into a cell. An omitted block or an air block clears the cell. */
|
|
15035
15246
|
set(index, block) {
|
|
15036
15247
|
_ChunkData.validateIndex(index);
|
|
15037
15248
|
let state;
|
|
@@ -15096,15 +15307,23 @@ var ChunkData = class _ChunkData {
|
|
|
15096
15307
|
|
|
15097
15308
|
// src/world/AnvilParser.ts
|
|
15098
15309
|
var AnvilParser = class {
|
|
15310
|
+
/** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
|
|
15099
15311
|
static getChunkList(data) {
|
|
15100
15312
|
return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
|
|
15101
15313
|
}
|
|
15314
|
+
/** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
|
|
15102
15315
|
static async parse(data) {
|
|
15103
15316
|
const bytes = this.bytes(data);
|
|
15104
15317
|
const chunks = [];
|
|
15105
15318
|
for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
|
|
15106
15319
|
return { chunks };
|
|
15107
15320
|
}
|
|
15321
|
+
/**
|
|
15322
|
+
* Decodes one chunk for {@link MineRenderWorld.placeChunk}.
|
|
15323
|
+
* @param localX - Chunk x within the region, from 0 to 31.
|
|
15324
|
+
* @param localZ - Chunk z within the region, from 0 to 31.
|
|
15325
|
+
* @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
|
|
15326
|
+
*/
|
|
15108
15327
|
static async parseChunk(data, localX, localZ) {
|
|
15109
15328
|
if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
|
|
15110
15329
|
throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
|
|
@@ -15309,6 +15528,7 @@ var SectionModels = class {
|
|
|
15309
15528
|
this.templates = /* @__PURE__ */ new Set();
|
|
15310
15529
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
15311
15530
|
}
|
|
15531
|
+
/** Returns a cube template, or `undefined` when the block requires an individual render object. */
|
|
15312
15532
|
async get(blockState, properties = {}) {
|
|
15313
15533
|
if (!blockState.variants || blockState.multipart) return void 0;
|
|
15314
15534
|
let states = this.states.get(blockState);
|
|
@@ -15362,6 +15582,7 @@ var SectionModels = class {
|
|
|
15362
15582
|
}
|
|
15363
15583
|
return { variants, templates };
|
|
15364
15584
|
}
|
|
15585
|
+
/** Disposes prepared geometry and clears this world's template caches. */
|
|
15365
15586
|
clear() {
|
|
15366
15587
|
for (const template of this.templates) template.geometry.dispose();
|
|
15367
15588
|
this.templates.clear();
|
|
@@ -15412,6 +15633,13 @@ var MineRenderWorld = class {
|
|
|
15412
15633
|
this.validatePosBounds(posOrX);
|
|
15413
15634
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
15414
15635
|
}
|
|
15636
|
+
/**
|
|
15637
|
+
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
15638
|
+
* Entity NBT is retained by the structure but is not rendered.
|
|
15639
|
+
*
|
|
15640
|
+
* @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
|
|
15641
|
+
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
15642
|
+
*/
|
|
15415
15643
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
15416
15644
|
const changes = /* @__PURE__ */ new Map();
|
|
15417
15645
|
try {
|
|
@@ -15463,13 +15691,7 @@ var MineRenderWorld = class {
|
|
|
15463
15691
|
async placeChunk(chunk, executor) {
|
|
15464
15692
|
const changes = /* @__PURE__ */ new Map();
|
|
15465
15693
|
try {
|
|
15466
|
-
|
|
15467
|
-
for (const [key, section] of previous) {
|
|
15468
|
-
this._chunks.delete(key);
|
|
15469
|
-
await section.clear(async (positions) => {
|
|
15470
|
-
for (const pos of positions) changes.set(pos.toArray().join(","), pos);
|
|
15471
|
-
});
|
|
15472
|
-
}
|
|
15694
|
+
await this.clearChunkColumn(chunk.x, chunk.z, changes);
|
|
15473
15695
|
for (const section of chunk.sections) {
|
|
15474
15696
|
const blocks = [];
|
|
15475
15697
|
for (let index = 0; index < 4096; index++) {
|
|
@@ -15489,6 +15711,32 @@ var MineRenderWorld = class {
|
|
|
15489
15711
|
await this.updateCulling([...changes.values()]);
|
|
15490
15712
|
}
|
|
15491
15713
|
}
|
|
15714
|
+
/**
|
|
15715
|
+
* Removes all sections at integer chunk-column coordinates, then refreshes neighboring faces and fluids.
|
|
15716
|
+
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
15717
|
+
*/
|
|
15718
|
+
async unloadChunkColumn(x, z) {
|
|
15719
|
+
if (!Number.isInteger(x) || !Number.isInteger(z)) {
|
|
15720
|
+
throw new RangeError("Chunk column coordinates must be integers");
|
|
15721
|
+
}
|
|
15722
|
+
await this.culling;
|
|
15723
|
+
const changes = /* @__PURE__ */ new Map();
|
|
15724
|
+
try {
|
|
15725
|
+
await this.clearChunkColumn(x, z, changes);
|
|
15726
|
+
} finally {
|
|
15727
|
+
await this.updateCulling([...changes.values()]);
|
|
15728
|
+
}
|
|
15729
|
+
}
|
|
15730
|
+
async clearChunkColumn(x, z, changes) {
|
|
15731
|
+
const previous = [...this._chunks.entries()].filter(([, section]) => section.x === x && section.z === z);
|
|
15732
|
+
for (const [key, section] of previous) {
|
|
15733
|
+
this._chunks.delete(key);
|
|
15734
|
+
await section.clear(async (positions) => {
|
|
15735
|
+
for (const pos of positions) changes.set(pos.toArray().join(","), pos);
|
|
15736
|
+
});
|
|
15737
|
+
}
|
|
15738
|
+
}
|
|
15739
|
+
/** Removes all chunks and releases their block placements and section meshes. */
|
|
15492
15740
|
async clear() {
|
|
15493
15741
|
await this.culling;
|
|
15494
15742
|
const chunks = [...this._chunks.values()];
|
|
@@ -15574,9 +15822,11 @@ var MineRenderWorld = class {
|
|
|
15574
15822
|
}
|
|
15575
15823
|
return chunk;
|
|
15576
15824
|
}
|
|
15825
|
+
/** Returns the loaded chunk containing a world block position, without creating a chunk. */
|
|
15577
15826
|
getChunkAt(pos) {
|
|
15578
15827
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
15579
15828
|
}
|
|
15829
|
+
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
15580
15830
|
static worldToScenePosition(pos) {
|
|
15581
15831
|
return new import_three39.Vector3(
|
|
15582
15832
|
pos.x * 16,
|
|
@@ -15584,6 +15834,7 @@ var MineRenderWorld = class {
|
|
|
15584
15834
|
pos.z * 16
|
|
15585
15835
|
);
|
|
15586
15836
|
}
|
|
15837
|
+
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
15587
15838
|
static sceneToWorldPosition(pos) {
|
|
15588
15839
|
return new import_three39.Vector3(
|
|
15589
15840
|
pos.x / 16,
|
|
@@ -15616,6 +15867,7 @@ var SectionMesh = class _SectionMesh extends import_three40.Group {
|
|
|
15616
15867
|
super(...arguments);
|
|
15617
15868
|
this.ownedMeshes = [];
|
|
15618
15869
|
}
|
|
15870
|
+
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
15619
15871
|
static build(entries, maxAtlasSize = 2048) {
|
|
15620
15872
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
15621
15873
|
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
@@ -15760,7 +16012,7 @@ var Chunk = class _Chunk {
|
|
|
15760
16012
|
return this.setBlockInChunkAt(pos, block, worldPos);
|
|
15761
16013
|
}
|
|
15762
16014
|
/**
|
|
15763
|
-
*
|
|
16015
|
+
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
15764
16016
|
*/
|
|
15765
16017
|
async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
|
|
15766
16018
|
if (typeof worldPos === "undefined") {
|
|
@@ -15809,6 +16061,7 @@ var Chunk = class _Chunk {
|
|
|
15809
16061
|
await onBlocksChanged?.([worldPos]);
|
|
15810
16062
|
}
|
|
15811
16063
|
}
|
|
16064
|
+
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
15812
16065
|
async setBlockVisibleAt(pos, visible) {
|
|
15813
16066
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
15814
16067
|
const block = this.renderedBlocks.get(index);
|
|
@@ -15862,6 +16115,7 @@ var Chunk = class _Chunk {
|
|
|
15862
16115
|
this.scene.dirty = true;
|
|
15863
16116
|
this.meshDirty = false;
|
|
15864
16117
|
}
|
|
16118
|
+
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
15865
16119
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
15866
16120
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
15867
16121
|
new import_three41.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
@@ -15882,6 +16136,7 @@ var Chunk = class _Chunk {
|
|
|
15882
16136
|
static isAir(block) {
|
|
15883
16137
|
return ChunkData.isAir(block);
|
|
15884
16138
|
}
|
|
16139
|
+
/** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
|
|
15885
16140
|
static chunkPosToBlockIndex(pos) {
|
|
15886
16141
|
if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
|
|
15887
16142
|
throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");
|