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/browser/index.mjs
CHANGED
|
@@ -64,6 +64,7 @@ var init_PersistentCache = __esm({
|
|
|
64
64
|
constructor(backing) {
|
|
65
65
|
this.backing = backing;
|
|
66
66
|
}
|
|
67
|
+
/** Opens a named store in the active environment using the current cache schema version. */
|
|
67
68
|
static open(name) {
|
|
68
69
|
return Env.provider.openCache(name, _PersistentCache.VERSION);
|
|
69
70
|
}
|
|
@@ -262,6 +263,7 @@ var init_Caching = __esm({
|
|
|
262
263
|
this.fontCache
|
|
263
264
|
];
|
|
264
265
|
}
|
|
266
|
+
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
265
267
|
static clear() {
|
|
266
268
|
for (const cache of this.all) {
|
|
267
269
|
cache.invalidateAll();
|
|
@@ -327,6 +329,7 @@ var init_Geometries = __esm({
|
|
|
327
329
|
}
|
|
328
330
|
return geometry;
|
|
329
331
|
}
|
|
332
|
+
/** Returns shared geometry. Use {@link createBox} when the caller needs to modify or dispose it independently. */
|
|
330
333
|
static getBox(key) {
|
|
331
334
|
const keyStr = serializeBoxGeometryKey(key);
|
|
332
335
|
return Caching.boxGeometryCache.get(keyStr, (k) => {
|
|
@@ -504,12 +507,15 @@ var init_Requests = __esm({
|
|
|
504
507
|
}
|
|
505
508
|
};
|
|
506
509
|
Requests = class {
|
|
510
|
+
/** Queues a general request. Set `request.signal` to cancel it and `request.timeout` to limit each attempt. */
|
|
507
511
|
static genericRequest(request) {
|
|
508
512
|
return this.genericQueue.request(request);
|
|
509
513
|
}
|
|
514
|
+
/** Queues a request separately from general traffic, using the configured asset base URL for relative paths. */
|
|
510
515
|
static mcAssetRequest(request) {
|
|
511
516
|
return this.mcAssetRequestQueue.request(request);
|
|
512
517
|
}
|
|
518
|
+
/** Sets the base URL for relative asset requests. Use {@link AssetLoader.setVersion} to change Minecraft versions. */
|
|
513
519
|
static setMcAssetRoot(root) {
|
|
514
520
|
this.mcAssetRequestQueue.baseURL = root;
|
|
515
521
|
}
|
|
@@ -564,6 +570,7 @@ var init_WrappedImage = __esm({
|
|
|
564
570
|
}
|
|
565
571
|
return false;
|
|
566
572
|
}
|
|
573
|
+
/** Whether the dimensions form a vertical strip of square frames, without consulting `.mcmeta`. */
|
|
567
574
|
get animated() {
|
|
568
575
|
return this.height > this.width && this.height % this.width === 0;
|
|
569
576
|
}
|
|
@@ -610,6 +617,7 @@ var init_ImageLoader = __esm({
|
|
|
610
617
|
static _createImage() {
|
|
611
618
|
return createImage();
|
|
612
619
|
}
|
|
620
|
+
/** Resolves when an image URL has decoded, or rejects if decoding fails. */
|
|
613
621
|
static async loadAsync(src) {
|
|
614
622
|
return new Promise((resolve, reject) => {
|
|
615
623
|
const image = this._createImage();
|
|
@@ -618,6 +626,7 @@ var init_ImageLoader = __esm({
|
|
|
618
626
|
image.src = src;
|
|
619
627
|
});
|
|
620
628
|
}
|
|
629
|
+
/** Returns an image immediately. Use the callbacks to observe loading, or await {@link loadAsync}. */
|
|
621
630
|
static loadElement(src, onload, onerr) {
|
|
622
631
|
const image = this._createImage();
|
|
623
632
|
if (onload)
|
|
@@ -645,6 +654,7 @@ var init_ImageLoader = __esm({
|
|
|
645
654
|
throw err;
|
|
646
655
|
}
|
|
647
656
|
}
|
|
657
|
+
/** Decodes the supplied bytes into a canvas without fetching the source URL again. */
|
|
648
658
|
static async infoToCanvasData(info) {
|
|
649
659
|
const type = info.type === "jpg" ? "jpeg" : info.type ?? "png";
|
|
650
660
|
const image = await _ImageLoader.loadAsync(`data:image/${type};base64,${info.data.toString("base64")}`);
|
|
@@ -661,12 +671,14 @@ var init_ImageLoader = __esm({
|
|
|
661
671
|
const image = await this.infoToCanvasData(info);
|
|
662
672
|
return image.data.getImageData(0, 0, image.width, image.height);
|
|
663
673
|
}
|
|
674
|
+
/** Returns cached RGBA pixels for an image URL or data URL. Failed loads can be retried. */
|
|
664
675
|
static async getData(src) {
|
|
665
676
|
const keyStr = serializeImageKey({ src });
|
|
666
677
|
return await Caching.imageDataCache.get(keyStr, (k) => {
|
|
667
678
|
return _ImageLoader.loadData(src);
|
|
668
679
|
});
|
|
669
680
|
}
|
|
681
|
+
/** Returns a cached canvas context and dimensions for an image URL or data URL. */
|
|
670
682
|
static async getCanvasData(src) {
|
|
671
683
|
const keyStr = serializeImageKey({ src });
|
|
672
684
|
return await Caching.canvasImageDataCache.get(keyStr, (k) => {
|
|
@@ -763,6 +775,7 @@ var init_TextureLoader = __esm({
|
|
|
763
775
|
texture.rotation = rotation;
|
|
764
776
|
return Textures.initTextureProps(texture);
|
|
765
777
|
}
|
|
778
|
+
/** Loads image pixels in the background. `rotation` is in radians. Check {@link hasFailed} for load failures. */
|
|
766
779
|
static load(src, format2 = RGBAFormat, rotation = 0) {
|
|
767
780
|
const texture = new Texture();
|
|
768
781
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
@@ -812,6 +825,7 @@ var init_Textures = __esm({
|
|
|
812
825
|
return this.initTextureProps(texture);
|
|
813
826
|
});
|
|
814
827
|
}
|
|
828
|
+
/** Sets nearest-neighbor filters without changing the texture's color space. Returns the same texture. */
|
|
815
829
|
static initTextureProps(texture) {
|
|
816
830
|
texture.magFilter = THREE2.NearestFilter;
|
|
817
831
|
texture.minFilter = THREE2.NearestFilter;
|
|
@@ -824,11 +838,13 @@ var init_Textures = __esm({
|
|
|
824
838
|
static createAsset(key) {
|
|
825
839
|
return new Texture2();
|
|
826
840
|
}
|
|
841
|
+
/** Creates an sRGB color texture from a canvas. */
|
|
827
842
|
static createCanvasTexture(canvas) {
|
|
828
843
|
const texture = new CanvasTexture(canvas);
|
|
829
844
|
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
830
845
|
return this.initTextureProps(texture);
|
|
831
846
|
}
|
|
847
|
+
/** Returns a shared texture immediately and loads its image asynchronously. Failed cached loads are retried. */
|
|
832
848
|
static getImage(key) {
|
|
833
849
|
const keyStr = serializeTextureKey(key);
|
|
834
850
|
const cached2 = Caching.textureCache.peek(keyStr);
|
|
@@ -853,6 +869,7 @@ var init_Materials = __esm({
|
|
|
853
869
|
init_TextureLoader();
|
|
854
870
|
init_Caching();
|
|
855
871
|
Materials = class _Materials {
|
|
872
|
+
/** Shared checkerboard material, created on first access. */
|
|
856
873
|
static get MISSING_TEXTURE() {
|
|
857
874
|
return Caching.materialCache.get("builtin:missing-texture", () => new MeshBasicMaterial({
|
|
858
875
|
map: Textures.getMissing(),
|
|
@@ -956,6 +973,7 @@ var init_Materials = __esm({
|
|
|
956
973
|
if (tint !== void 0) material.color.multiply(new Color(tint));
|
|
957
974
|
return material;
|
|
958
975
|
}
|
|
976
|
+
/** Creates an unlit, transparent GUI material without depth writes or tone mapping. */
|
|
959
977
|
static createGuiCanvasMaterial(canvas) {
|
|
960
978
|
const material = new MeshBasicMaterial({
|
|
961
979
|
map: Textures.createCanvasTexture(canvas),
|
|
@@ -1122,6 +1140,7 @@ var init_Materials = __esm({
|
|
|
1122
1140
|
}
|
|
1123
1141
|
return this.createBasicCanvasMaterial(canvas, transparent, shade);
|
|
1124
1142
|
}
|
|
1143
|
+
/** Returns a shared image material. Use {@link createImage} for a separate material instance. */
|
|
1125
1144
|
static getImage(key) {
|
|
1126
1145
|
const keyStr = serializeMaterialKey(key);
|
|
1127
1146
|
const map = Caching.materialCache.peek(keyStr)?.map;
|
|
@@ -1296,6 +1315,14 @@ var init_AssetKey = __esm({
|
|
|
1296
1315
|
}
|
|
1297
1316
|
};
|
|
1298
1317
|
AssetKey = class _AssetKey extends BasicAssetKey {
|
|
1318
|
+
/**
|
|
1319
|
+
* Creates a key from separate path components. Use {@link parse} for a combined reference.
|
|
1320
|
+
*
|
|
1321
|
+
* @param assetType - Asset directory, such as `models`, `textures`, or `blockstates`.
|
|
1322
|
+
* @param type - Subdirectory, such as `block` or `item`.
|
|
1323
|
+
* @param rootType - Top-level directory, usually `assets` or `data`.
|
|
1324
|
+
* @param root - Base URL override for hosted asset sources.
|
|
1325
|
+
*/
|
|
1299
1326
|
constructor(namespace, path, assetType, type, rootType = "assets", extension = ".json", root) {
|
|
1300
1327
|
super(namespace, path);
|
|
1301
1328
|
this.namespace = namespace;
|
|
@@ -1307,6 +1334,16 @@ var init_AssetKey = __esm({
|
|
|
1307
1334
|
this.root = root;
|
|
1308
1335
|
this.isAssetKey = true;
|
|
1309
1336
|
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Parses an asset reference such as `minecraft:block/stone`.
|
|
1339
|
+
* A missing namespace defaults to the origin's namespace or `minecraft`.
|
|
1340
|
+
*
|
|
1341
|
+
* @param assetType - Asset category, such as `models` or `textures`.
|
|
1342
|
+
* @param str - Path with an optional namespace and file extension.
|
|
1343
|
+
* @param origin - Supplies the asset root, default namespace, and non-texture extension.
|
|
1344
|
+
* @returns A key with the matching extension removed from its path. Textures use `.png`;
|
|
1345
|
+
* other assets use the origin's extension or `.json`.
|
|
1346
|
+
*/
|
|
1310
1347
|
static parse(assetType, str, origin) {
|
|
1311
1348
|
let namespace = origin?.namespace || DEFAULT_NAMESPACE;
|
|
1312
1349
|
if (str.includes(":")) {
|
|
@@ -1338,6 +1375,7 @@ var init_AssetKey = __esm({
|
|
|
1338
1375
|
];
|
|
1339
1376
|
return a.join("/");
|
|
1340
1377
|
}
|
|
1378
|
+
/** Joins the type subdirectory and path without adding a namespace or file extension. */
|
|
1341
1379
|
getFullPath() {
|
|
1342
1380
|
let p10 = [];
|
|
1343
1381
|
if (this.type) {
|
|
@@ -1349,6 +1387,7 @@ var init_AssetKey = __esm({
|
|
|
1349
1387
|
toNamespacedString() {
|
|
1350
1388
|
return this.namespace + ":" + this.getFullPath();
|
|
1351
1389
|
}
|
|
1390
|
+
/** Returns a cache identifier that includes the explicit root or {@link AssetLoader.ROOT}. */
|
|
1352
1391
|
serialize() {
|
|
1353
1392
|
return this.toString();
|
|
1354
1393
|
}
|
|
@@ -1408,6 +1447,7 @@ var init_DisplayTransforms = __esm({
|
|
|
1408
1447
|
const scale = new Vector32(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
|
|
1409
1448
|
return new Matrix4().compose(translation, rotation, scale);
|
|
1410
1449
|
}
|
|
1450
|
+
/** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
|
|
1411
1451
|
static apply(geometry, matrix) {
|
|
1412
1452
|
geometry.applyMatrix4(matrix);
|
|
1413
1453
|
if (matrix.determinant() < 0) {
|
|
@@ -1435,6 +1475,7 @@ var init_ModelMerger = __esm({
|
|
|
1435
1475
|
init_AssetKey();
|
|
1436
1476
|
init_DisplayTransforms();
|
|
1437
1477
|
ModelMerger = class {
|
|
1478
|
+
/** Loads the parent chain and returns a merged model without modifying the supplied definition. */
|
|
1438
1479
|
static async mergeWithParents(model) {
|
|
1439
1480
|
const models = await this.collectAllParents(model);
|
|
1440
1481
|
let merged = {};
|
|
@@ -1502,6 +1543,7 @@ var init_Models = __esm({
|
|
|
1502
1543
|
static get PERSISTENT_CACHE() {
|
|
1503
1544
|
return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-models"));
|
|
1504
1545
|
}
|
|
1546
|
+
/** Lists item filenames from the asset source's `_list.json`, with a legacy model-directory fallback. */
|
|
1505
1547
|
static async getItemList() {
|
|
1506
1548
|
const key = new AssetKey(DEFAULT_NAMESPACE, "_list", "items");
|
|
1507
1549
|
const legacyKey = new AssetKey(DEFAULT_NAMESPACE, "_list", "models", "item");
|
|
@@ -1572,6 +1614,7 @@ var init_Models = __esm({
|
|
|
1572
1614
|
}
|
|
1573
1615
|
throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
|
|
1574
1616
|
}
|
|
1617
|
+
/** Loads one model file without resolving its parents. Returns `undefined` when the file is missing. */
|
|
1575
1618
|
static async getRaw(key) {
|
|
1576
1619
|
if (!key.assetType) {
|
|
1577
1620
|
key.assetType = "models";
|
|
@@ -1591,6 +1634,12 @@ var init_Models = __esm({
|
|
|
1591
1634
|
return asset;
|
|
1592
1635
|
});
|
|
1593
1636
|
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
|
|
1639
|
+
* Item keys use GUI context, false conditions, and zero numeric properties.
|
|
1640
|
+
*
|
|
1641
|
+
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
1642
|
+
*/
|
|
1594
1643
|
static async getMerged(key) {
|
|
1595
1644
|
if (!key.assetType) {
|
|
1596
1645
|
key.assetType = "models";
|
|
@@ -1603,9 +1652,11 @@ var init_Models = __esm({
|
|
|
1603
1652
|
return _Models.loadAndMerge(key);
|
|
1604
1653
|
});
|
|
1605
1654
|
}
|
|
1655
|
+
/** Alias for {@link getMerged}. */
|
|
1606
1656
|
static async get(key) {
|
|
1607
1657
|
return this.getMerged(key);
|
|
1608
1658
|
}
|
|
1659
|
+
/** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1609
1660
|
static async clearCache() {
|
|
1610
1661
|
return this.PERSISTENT_CACHE.clear();
|
|
1611
1662
|
}
|
|
@@ -1628,6 +1679,7 @@ var init_BlockStates = __esm({
|
|
|
1628
1679
|
return this._persistentCache ?? (this._persistentCache = PersistentCache.open("minerender-blockstates"));
|
|
1629
1680
|
}
|
|
1630
1681
|
// BlockState names are hardcoded
|
|
1682
|
+
/** Returns blockstate filenames from the selected version's `_list.json`, or an empty list. */
|
|
1631
1683
|
static async getList() {
|
|
1632
1684
|
const key = new AssetKey(
|
|
1633
1685
|
DEFAULT_NAMESPACE,
|
|
@@ -1648,6 +1700,7 @@ var init_BlockStates = __esm({
|
|
|
1648
1700
|
return AssetLoader.get(key, "json" /* JSON */);
|
|
1649
1701
|
});
|
|
1650
1702
|
}
|
|
1703
|
+
/** Looks up vanilla property definitions for the key's block path, or returns `undefined`. */
|
|
1651
1704
|
static async getDefaultState(key) {
|
|
1652
1705
|
const defaultStates = await this.getDefaultStates();
|
|
1653
1706
|
if (!defaultStates) {
|
|
@@ -1655,6 +1708,7 @@ var init_BlockStates = __esm({
|
|
|
1655
1708
|
}
|
|
1656
1709
|
return defaultStates["minecraft:" + key.path];
|
|
1657
1710
|
}
|
|
1711
|
+
/** Loads a cached blockstate definition for {@link MineRenderScene.addBlock}, or returns `undefined`. */
|
|
1658
1712
|
static async get(key) {
|
|
1659
1713
|
if (!key.assetType) {
|
|
1660
1714
|
key.assetType = "blockstates";
|
|
@@ -1681,6 +1735,7 @@ var init_BlockStates = __esm({
|
|
|
1681
1735
|
}
|
|
1682
1736
|
return Promise.all(promises);
|
|
1683
1737
|
}
|
|
1738
|
+
/** Clears persisted blockstates. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
1684
1739
|
static async clearCache() {
|
|
1685
1740
|
await this.PERSISTENT_CACHE.clear();
|
|
1686
1741
|
}
|
|
@@ -1706,9 +1761,11 @@ var init_Assets = __esm({
|
|
|
1706
1761
|
static parseAssetKey(assetType, str, origin) {
|
|
1707
1762
|
return AssetKey.parse(assetType, str, origin);
|
|
1708
1763
|
}
|
|
1764
|
+
/** Loads a model with its parent chain resolved. See {@link Models.getMerged}. */
|
|
1709
1765
|
static async getModel(key) {
|
|
1710
1766
|
return Models.getMerged(key);
|
|
1711
1767
|
}
|
|
1768
|
+
/** Loads a blockstate definition. See {@link BlockStates.get}. */
|
|
1712
1769
|
static async getBlockState(key) {
|
|
1713
1770
|
return BlockStates.get(key);
|
|
1714
1771
|
}
|
|
@@ -1755,6 +1812,10 @@ var BatchedExecutor;
|
|
|
1755
1812
|
var init_BatchedExecutor = __esm({
|
|
1756
1813
|
"src/util/BatchedExecutor.ts"() {
|
|
1757
1814
|
BatchedExecutor = class {
|
|
1815
|
+
/**
|
|
1816
|
+
* @param interval - Delay between queue runs, in milliseconds.
|
|
1817
|
+
* @param batch - Maximum tasks started per run and maximum tasks active at once.
|
|
1818
|
+
*/
|
|
1758
1819
|
constructor(interval = 1, batch = 30) {
|
|
1759
1820
|
if (!Number.isFinite(interval) || interval < 0) throw new RangeError("Batch interval must be finite and nonnegative");
|
|
1760
1821
|
if (!Number.isInteger(batch) || batch < 1) throw new RangeError("Batch size must be a positive integer");
|
|
@@ -1762,9 +1823,11 @@ var init_BatchedExecutor = __esm({
|
|
|
1762
1823
|
this.batch = batch;
|
|
1763
1824
|
this.queue = new JobQueue2(async (task) => task(), { interval, maxPerRun: batch, maxActive: batch });
|
|
1764
1825
|
}
|
|
1826
|
+
/** Queues a task and resolves with its result, or rejects with its error. */
|
|
1765
1827
|
submit(task) {
|
|
1766
1828
|
return this.queue.add(() => task());
|
|
1767
1829
|
}
|
|
1830
|
+
/** Rejects queued and future tasks. Tasks already running are allowed to finish. */
|
|
1768
1831
|
stop() {
|
|
1769
1832
|
this.queue.end();
|
|
1770
1833
|
}
|
|
@@ -1906,6 +1969,7 @@ var NBTHelper;
|
|
|
1906
1969
|
var init_NBTHelper = __esm({
|
|
1907
1970
|
"src/nbt/NBTHelper.ts"() {
|
|
1908
1971
|
NBTHelper = class {
|
|
1972
|
+
/** Parses NBT bytes and preserves format and compression metadata. Omit `format` for automatic detection. */
|
|
1909
1973
|
static async fromBuffer(data, format2) {
|
|
1910
1974
|
const buffer = Buffer3.from(data instanceof Uint8Array ? data : new Uint8Array(data));
|
|
1911
1975
|
const prismarineNbt = await import("prismarine-nbt");
|
|
@@ -1974,6 +2038,7 @@ var init_HostedAssetSource = __esm({
|
|
|
1974
2038
|
retryDefaults: true
|
|
1975
2039
|
};
|
|
1976
2040
|
_HostedAssetSource = class _HostedAssetSource extends AssetSource {
|
|
2041
|
+
/** Retries missing assets with the `minecraft` namespace and default root. Other failures reject. */
|
|
1977
2042
|
async loadOrRetryWithDefaults(key, parser) {
|
|
1978
2043
|
const direct = await this.load(key, parser);
|
|
1979
2044
|
if (typeof direct !== "undefined") {
|
|
@@ -2031,6 +2096,10 @@ var init_HostedAssetSource = __esm({
|
|
|
2031
2096
|
assetBasePath(key) {
|
|
2032
2097
|
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 + "/" : ""}`;
|
|
2033
2098
|
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Creates a hosted source for {@link AssetLoader.addSource}.
|
|
2101
|
+
* Set `options.retryDefaults` to `false` to restrict lookups to the requested namespace and root.
|
|
2102
|
+
*/
|
|
2034
2103
|
constructor(root, options) {
|
|
2035
2104
|
super();
|
|
2036
2105
|
this._root = root;
|
|
@@ -2123,6 +2192,11 @@ var BrowserArchiveProxy;
|
|
|
2123
2192
|
var init_BrowserArchiveProxy = __esm({
|
|
2124
2193
|
"src/assets/source/archive/BrowserArchiveProxy.ts"() {
|
|
2125
2194
|
BrowserArchiveProxy = class {
|
|
2195
|
+
/**
|
|
2196
|
+
* Opens a ZIP for asset lookup.
|
|
2197
|
+
* @param id - Cache identity for this content. Change it when the pack changes.
|
|
2198
|
+
* A File supplies an identity from its name, size, and modification time when omitted.
|
|
2199
|
+
*/
|
|
2126
2200
|
constructor(blob, id) {
|
|
2127
2201
|
this._blob = blob;
|
|
2128
2202
|
this._reader = new ZipReader(new BlobReader(this._blob));
|
|
@@ -2320,6 +2394,7 @@ var init_ArchiveAssetSource = __esm({
|
|
|
2320
2394
|
dataPackFormat: copyFormat(options.dataPackFormat)
|
|
2321
2395
|
};
|
|
2322
2396
|
}
|
|
2397
|
+
/** Creates a browser ZIP source from a Blob or File. */
|
|
2323
2398
|
static blob(blob, options) {
|
|
2324
2399
|
return new _ArchiveAssetSource(new BrowserArchiveProxy(blob), options);
|
|
2325
2400
|
}
|
|
@@ -2454,6 +2529,7 @@ var init_AssetLoader = __esm({
|
|
|
2454
2529
|
static get version() {
|
|
2455
2530
|
return this.ROOT.substring(this.ROOT.lastIndexOf("/") + 1);
|
|
2456
2531
|
}
|
|
2532
|
+
/** Selects an mcasset.cloud version, updates the vanilla source, and clears in-memory caches. */
|
|
2457
2533
|
static setVersion(version) {
|
|
2458
2534
|
this.ROOT = `https://assets.mcasset.cloud/${version}`;
|
|
2459
2535
|
const source = new HostedAssetSource(this.ROOT, { retryDefaults: false });
|
|
@@ -2487,6 +2563,13 @@ var init_AssetLoader = __esm({
|
|
|
2487
2563
|
return scope ? `${scope}
|
|
2488
2564
|
${key}` : key;
|
|
2489
2565
|
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Registers a source at the highest priority.
|
|
2568
|
+
* Call {@link Caching.clear} after changing sources to discard previously loaded assets.
|
|
2569
|
+
*
|
|
2570
|
+
* @param key - Name used to replace or remove this source.
|
|
2571
|
+
* @param override - Removes the first source with this name before adding the new one.
|
|
2572
|
+
*/
|
|
2490
2573
|
static addSource(key, source, override = true) {
|
|
2491
2574
|
if (override) {
|
|
2492
2575
|
const existing = this.removeSource(key);
|
|
@@ -2497,6 +2580,7 @@ ${key}` : key;
|
|
|
2497
2580
|
this._SOURCES.unshift({ key, source });
|
|
2498
2581
|
console.log(p4, "Added AssetSource", key);
|
|
2499
2582
|
}
|
|
2583
|
+
/** Removes and returns the first source with this name. Call {@link Caching.clear} to reload assets. */
|
|
2500
2584
|
static removeSource(key) {
|
|
2501
2585
|
const index = this._SOURCES.findIndex((s) => s.key === key);
|
|
2502
2586
|
if (index != -1) {
|
|
@@ -2507,6 +2591,7 @@ ${key}` : key;
|
|
|
2507
2591
|
}
|
|
2508
2592
|
return void 0;
|
|
2509
2593
|
}
|
|
2594
|
+
/** Loads from all sources and returns defined results in priority order. Any source failure rejects the call. */
|
|
2510
2595
|
static async getAll(key, parser) {
|
|
2511
2596
|
const sources = [...this._SOURCES];
|
|
2512
2597
|
const results = [];
|
|
@@ -2551,6 +2636,7 @@ ${key}` : key;
|
|
|
2551
2636
|
return void 0;
|
|
2552
2637
|
}
|
|
2553
2638
|
};
|
|
2639
|
+
/** Default asset base URL. Use {@link setVersion} to select a Minecraft version. */
|
|
2554
2640
|
_AssetLoader.ROOT = DEFAULT_ROOT;
|
|
2555
2641
|
_AssetLoader._SOURCES = [];
|
|
2556
2642
|
/** Used when a registered source cannot identify its content, so nothing persists past this session. */
|
|
@@ -2575,6 +2661,7 @@ var init_ModelTextures = __esm({
|
|
|
2575
2661
|
static get PERSISTENT_META_CACHE() {
|
|
2576
2662
|
return this._persistentMetaCache ?? (this._persistentMetaCache = PersistentCache.open("minerender-texturemeta"));
|
|
2577
2663
|
}
|
|
2664
|
+
/** Loads and decodes a texture into a readable canvas, or returns `undefined` when missing. */
|
|
2578
2665
|
static async get(key) {
|
|
2579
2666
|
const keyStr = key.serialize();
|
|
2580
2667
|
const pending = this.preload(key);
|
|
@@ -2592,6 +2679,7 @@ var init_ModelTextures = __esm({
|
|
|
2592
2679
|
throw err;
|
|
2593
2680
|
}
|
|
2594
2681
|
}
|
|
2682
|
+
/** Fetches and caches encoded texture bytes without decoding the pixels. */
|
|
2595
2683
|
static async preload(key) {
|
|
2596
2684
|
const keyStr = key.serialize();
|
|
2597
2685
|
return Caching.textureAssetCache.get(keyStr, (k) => {
|
|
@@ -2602,6 +2690,7 @@ var init_ModelTextures = __esm({
|
|
|
2602
2690
|
});
|
|
2603
2691
|
});
|
|
2604
2692
|
}
|
|
2693
|
+
/** Loads a texture's `.mcmeta` file, or returns `undefined` when no metadata file exists. */
|
|
2605
2694
|
static async getMeta(key) {
|
|
2606
2695
|
if (!key.extension || !key.extension.endsWith(".mcmeta")) {
|
|
2607
2696
|
key = Object.assign(new AssetKey("", ""), key);
|
|
@@ -2618,6 +2707,7 @@ var init_ModelTextures = __esm({
|
|
|
2618
2707
|
});
|
|
2619
2708
|
});
|
|
2620
2709
|
}
|
|
2710
|
+
/** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
|
|
2621
2711
|
static async clearCache() {
|
|
2622
2712
|
await this.PERSISTENT_META_CACHE.clear();
|
|
2623
2713
|
}
|
|
@@ -2684,6 +2774,7 @@ var init_Ticker = __esm({
|
|
|
2684
2774
|
}
|
|
2685
2775
|
return handle;
|
|
2686
2776
|
}
|
|
2777
|
+
/** Starts or resumes the shared tick loop. Repeated calls have no effect. */
|
|
2687
2778
|
static start() {
|
|
2688
2779
|
if (this.interval) return;
|
|
2689
2780
|
this.interval = this.schedule(() => {
|
|
@@ -2706,6 +2797,7 @@ var init_Ticker = __esm({
|
|
|
2706
2797
|
_Ticker.fiveSecondTicks = 0;
|
|
2707
2798
|
}, 1e3 * 5);
|
|
2708
2799
|
}
|
|
2800
|
+
/** Pauses the loop while retaining callbacks for a later {@link start}. */
|
|
2709
2801
|
static stop() {
|
|
2710
2802
|
if (this.interval) clearInterval(this.interval);
|
|
2711
2803
|
if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);
|
|
@@ -2714,12 +2806,14 @@ var init_Ticker = __esm({
|
|
|
2714
2806
|
this.oneSecondTicksTracker = void 0;
|
|
2715
2807
|
this.fiveSecondTicksTracker = void 0;
|
|
2716
2808
|
}
|
|
2809
|
+
/** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */
|
|
2717
2810
|
static add(tick) {
|
|
2718
2811
|
this.start();
|
|
2719
2812
|
const c = this.counter++;
|
|
2720
2813
|
this._tickers.set(c, tick);
|
|
2721
2814
|
return c;
|
|
2722
2815
|
}
|
|
2816
|
+
/** Removes a callback by ID and stops the timers when no callbacks remain. */
|
|
2723
2817
|
static remove(c) {
|
|
2724
2818
|
if (typeof c === "number") this._tickers.delete(c);
|
|
2725
2819
|
if (!this._tickers.size) this.stop();
|
|
@@ -2733,6 +2827,7 @@ var init_Ticker = __esm({
|
|
|
2733
2827
|
static get tpsFiveSeconds() {
|
|
2734
2828
|
return this.fiveSecondTps;
|
|
2735
2829
|
}
|
|
2830
|
+
/** Stops the loop and removes all registered callbacks. */
|
|
2736
2831
|
static dispose() {
|
|
2737
2832
|
this.stop();
|
|
2738
2833
|
this._tickers.clear();
|
|
@@ -2787,6 +2882,7 @@ var init_TextureAtlas = __esm({
|
|
|
2787
2882
|
}
|
|
2788
2883
|
};
|
|
2789
2884
|
}
|
|
2885
|
+
/** Copies pixels for a texture variable from its current atlas rectangle. */
|
|
2790
2886
|
getData(texture) {
|
|
2791
2887
|
const pos = this.positions[texture];
|
|
2792
2888
|
const size = this.sizes[texture];
|
|
@@ -3064,6 +3160,7 @@ var init_UVMapper = __esm({
|
|
|
3064
3160
|
}
|
|
3065
3161
|
uv.needsUpdate = true;
|
|
3066
3162
|
}
|
|
3163
|
+
/** Returns the shared atlas for a keyed, merged model, creating it on first use. */
|
|
3067
3164
|
static async getAtlas(model) {
|
|
3068
3165
|
const keyStr = model.key.serialize();
|
|
3069
3166
|
return Caching.modelTextureAtlasCache.get(keyStr, (k) => {
|
|
@@ -3134,6 +3231,11 @@ var init_UVMapper = __esm({
|
|
|
3134
3231
|
}
|
|
3135
3232
|
return [tl, tr, bl, br];
|
|
3136
3233
|
}
|
|
3234
|
+
/**
|
|
3235
|
+
* Combines model textures and animation metadata into an atlas.
|
|
3236
|
+
* Mapped UVs are stored on copies of the model's elements, available through the returned atlas.
|
|
3237
|
+
* Returns `undefined` for models without a texture map.
|
|
3238
|
+
*/
|
|
3137
3239
|
static async createAtlas(originalModel) {
|
|
3138
3240
|
const textureMap = {};
|
|
3139
3241
|
const metaMap = {};
|
|
@@ -3498,6 +3600,7 @@ var init_Entities = __esm({
|
|
|
3498
3600
|
init_MineRenderError();
|
|
3499
3601
|
init_ModelTextures();
|
|
3500
3602
|
Entities = class {
|
|
3603
|
+
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
3501
3604
|
static async getEntityList() {
|
|
3502
3605
|
const collect = async (path) => {
|
|
3503
3606
|
const prefix2 = path ? `${path}/` : "";
|
|
@@ -3515,6 +3618,7 @@ var init_Entities = __esm({
|
|
|
3515
3618
|
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
3516
3619
|
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3517
3620
|
}
|
|
3621
|
+
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
3518
3622
|
static async getLayerList(modelKey) {
|
|
3519
3623
|
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
3520
3624
|
}
|
|
@@ -3522,6 +3626,15 @@ var init_Entities = __esm({
|
|
|
3522
3626
|
static async getPassList(modelKey) {
|
|
3523
3627
|
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
3524
3628
|
}
|
|
3629
|
+
/**
|
|
3630
|
+
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
3631
|
+
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
3632
|
+
*
|
|
3633
|
+
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
3634
|
+
* @param textureKey - Texture override for the first selected layer.
|
|
3635
|
+
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
3636
|
+
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
3637
|
+
*/
|
|
3525
3638
|
static async getEntity(modelKey, textureKey, options) {
|
|
3526
3639
|
const model = await this.getModelFile(modelKey);
|
|
3527
3640
|
if (!model) return void 0;
|
|
@@ -3567,6 +3680,7 @@ var init_Entities = __esm({
|
|
|
3567
3680
|
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3568
3681
|
return file?.animations;
|
|
3569
3682
|
}
|
|
3683
|
+
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
3570
3684
|
static async resolveTexture(modelKey) {
|
|
3571
3685
|
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3572
3686
|
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
@@ -3727,12 +3841,14 @@ var init_EntityAnimationPlayer = __esm({
|
|
|
3727
3841
|
this._animation = void 0;
|
|
3728
3842
|
this._time = 0;
|
|
3729
3843
|
}
|
|
3844
|
+
/** Applies the pose at an absolute playback time. Returns `false` when no clip is active. */
|
|
3730
3845
|
setTime(seconds) {
|
|
3731
3846
|
if (!this._animation) return false;
|
|
3732
3847
|
this._time = seconds;
|
|
3733
3848
|
this.apply();
|
|
3734
3849
|
return true;
|
|
3735
3850
|
}
|
|
3851
|
+
/** Advances playback by elapsed seconds multiplied by the speed passed to {@link play}. */
|
|
3736
3852
|
advance(deltaSeconds) {
|
|
3737
3853
|
return this.setTime(this._time + deltaSeconds * this.speed);
|
|
3738
3854
|
}
|
|
@@ -3770,6 +3886,7 @@ var init_InstanceReference = __esm({
|
|
|
3770
3886
|
if (!this.instanceable.isInstanceActive(this.index, this)) throw new MineRenderError("Instance has been removed");
|
|
3771
3887
|
return this.instanceable;
|
|
3772
3888
|
}
|
|
3889
|
+
/** Releases this placement's slot for reuse. Repeated calls have no effect. */
|
|
3773
3890
|
removeFromScene() {
|
|
3774
3891
|
if (this.instanceable.isInstanceActive(this.index, this)) this.instanceable.removeInstanceAt(this.index);
|
|
3775
3892
|
}
|
|
@@ -3782,9 +3899,11 @@ var init_InstanceReference = __esm({
|
|
|
3782
3899
|
setMatrix(matrix) {
|
|
3783
3900
|
this.activeInstanceable.setMatrixAt(this.index, matrix);
|
|
3784
3901
|
}
|
|
3902
|
+
/** Hides or restores this placement while preserving its transform and allocated slot. */
|
|
3785
3903
|
setVisible(visible) {
|
|
3786
3904
|
this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
|
|
3787
3905
|
}
|
|
3906
|
+
/** Updates the supplied transform components. Positions use scene units and rotations use radians. */
|
|
3788
3907
|
setPositionRotationScale(position, rotation, scale) {
|
|
3789
3908
|
this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
|
|
3790
3909
|
}
|
|
@@ -3853,6 +3972,7 @@ var init_SceneObject = __esm({
|
|
|
3853
3972
|
}
|
|
3854
3973
|
async init() {
|
|
3855
3974
|
}
|
|
3975
|
+
/** Marks ancestor scenes for redraw and emits a `change` event. */
|
|
3856
3976
|
notifyDirty() {
|
|
3857
3977
|
this.traverseAncestors((parent) => {
|
|
3858
3978
|
const scene = parent;
|
|
@@ -3888,15 +4008,17 @@ var init_SceneObject = __esm({
|
|
|
3888
4008
|
return obj;
|
|
3889
4009
|
}
|
|
3890
4010
|
/**
|
|
3891
|
-
*
|
|
4011
|
+
* Finds a named part, such as `head`, without the internal `group:` prefix.
|
|
4012
|
+
* Returns `undefined` when the group does not exist.
|
|
3892
4013
|
*/
|
|
3893
4014
|
getGroupByName(name) {
|
|
3894
4015
|
return this.getObjectByName(`group:${name}`);
|
|
3895
4016
|
}
|
|
3896
4017
|
/**
|
|
3897
|
-
*
|
|
3898
|
-
* @param name name
|
|
3899
|
-
* @param visible
|
|
4018
|
+
* Changes a named group's visibility and requests a redraw.
|
|
4019
|
+
* @param name - Part name without the `group:` prefix.
|
|
4020
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4021
|
+
* @returns The resulting visibility, or `false` if the group does not exist.
|
|
3900
4022
|
*/
|
|
3901
4023
|
toggleGroupVisibility(name, visible) {
|
|
3902
4024
|
return this.toggleObjectVisibility(this.getGroupByName(name), visible);
|
|
@@ -3947,15 +4069,16 @@ var init_SceneObject = __esm({
|
|
|
3947
4069
|
return mesh;
|
|
3948
4070
|
}
|
|
3949
4071
|
/**
|
|
3950
|
-
*
|
|
4072
|
+
* Finds a named mesh without the internal `mesh:` prefix, or returns `undefined`.
|
|
3951
4073
|
*/
|
|
3952
4074
|
getMeshByName(name) {
|
|
3953
4075
|
return this.getObjectByName(`mesh:${name}`);
|
|
3954
4076
|
}
|
|
3955
4077
|
/**
|
|
3956
|
-
*
|
|
3957
|
-
* @param name name
|
|
3958
|
-
* @param visible
|
|
4078
|
+
* Changes a named mesh's visibility and requests a redraw.
|
|
4079
|
+
* @param name - Mesh name without the `mesh:` prefix.
|
|
4080
|
+
* @param visible - Visibility to assign. Omit it to toggle the current value.
|
|
4081
|
+
* @returns The resulting visibility, or `false` if the mesh does not exist.
|
|
3959
4082
|
*/
|
|
3960
4083
|
toggleMeshVisibility(name, visible) {
|
|
3961
4084
|
return this.toggleObjectVisibility(this.getMeshByName(name), visible);
|
|
@@ -4001,12 +4124,14 @@ var init_SceneObject = __esm({
|
|
|
4001
4124
|
get isInstanced() {
|
|
4002
4125
|
return this._isInstanced;
|
|
4003
4126
|
}
|
|
4127
|
+
/** Number of live placements, excluding released instance slots. */
|
|
4004
4128
|
get instanceCounter() {
|
|
4005
4129
|
return this._instanceCounter;
|
|
4006
4130
|
}
|
|
4007
4131
|
constructInstanceReference(i) {
|
|
4008
4132
|
return new InstanceReference(this, i);
|
|
4009
4133
|
}
|
|
4134
|
+
/** Allocates a placement of this instanced object, reusing a released slot when available. */
|
|
4010
4135
|
nextInstance() {
|
|
4011
4136
|
const mesh = this.instanceMesh;
|
|
4012
4137
|
if (!mesh) throw new MineRenderError("Object is not instanced");
|
|
@@ -4153,6 +4278,7 @@ var init_SceneObject = __esm({
|
|
|
4153
4278
|
vector.setFromMatrixScale(matrix);
|
|
4154
4279
|
return vector;
|
|
4155
4280
|
}
|
|
4281
|
+
/** Updates supplied transform components. For a shared model, affects every live instance. */
|
|
4156
4282
|
setPositionRotationScale(position, rotation, scale) {
|
|
4157
4283
|
if (this.isInstanced) {
|
|
4158
4284
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4171,6 +4297,7 @@ var init_SceneObject = __esm({
|
|
|
4171
4297
|
}
|
|
4172
4298
|
this.notifyDirty();
|
|
4173
4299
|
}
|
|
4300
|
+
/** Sets position in scene units. For a shared model, updates every live instance. */
|
|
4174
4301
|
setPosition(position) {
|
|
4175
4302
|
if (this.isInstanced) {
|
|
4176
4303
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4188,6 +4315,7 @@ var init_SceneObject = __esm({
|
|
|
4188
4315
|
return this.position;
|
|
4189
4316
|
}
|
|
4190
4317
|
}
|
|
4318
|
+
/** Sets rotation in radians. For a shared model, updates every live instance. */
|
|
4191
4319
|
setRotation(rotation) {
|
|
4192
4320
|
if (this.isInstanced) {
|
|
4193
4321
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4205,6 +4333,7 @@ var init_SceneObject = __esm({
|
|
|
4205
4333
|
return this.rotation;
|
|
4206
4334
|
}
|
|
4207
4335
|
}
|
|
4336
|
+
/** Sets scale factors. For a shared model, updates every live instance. */
|
|
4208
4337
|
setScale(scale) {
|
|
4209
4338
|
if (this.isInstanced) {
|
|
4210
4339
|
for (const i of this.activeInstanceIndices()) {
|
|
@@ -4242,6 +4371,7 @@ var init_SceneObject = __esm({
|
|
|
4242
4371
|
this.notifyDirty();
|
|
4243
4372
|
super.dispose();
|
|
4244
4373
|
}
|
|
4374
|
+
/** Releases instance slots and removes children, disposing children that implement Disposable. */
|
|
4245
4375
|
disposeAndRemoveAllChildren() {
|
|
4246
4376
|
if (this.instanceMesh) {
|
|
4247
4377
|
if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
|
|
@@ -4264,6 +4394,7 @@ var init_SceneObject = __esm({
|
|
|
4264
4394
|
}
|
|
4265
4395
|
this.notifyDirty();
|
|
4266
4396
|
}
|
|
4397
|
+
/** Detaches the object from its parent and requests a redraw. */
|
|
4267
4398
|
removeFromScene() {
|
|
4268
4399
|
this.notifyDirty();
|
|
4269
4400
|
this.removeFromParent();
|
|
@@ -4419,12 +4550,15 @@ var init_EntityObject = __esm({
|
|
|
4419
4550
|
if (this.animationPlayers.length) this.notifyDirty();
|
|
4420
4551
|
}
|
|
4421
4552
|
//</editor-fold>
|
|
4553
|
+
/** Finds a selected draw by its layer key, such as `main` or `main#2`, or returns `undefined`. */
|
|
4422
4554
|
getLayerGroup(name) {
|
|
4423
4555
|
return super.getGroupByName(`layer:${name}`);
|
|
4424
4556
|
}
|
|
4557
|
+
/** Finds a part name without `group:`. Supply `layerName` to restrict the search to one draw. */
|
|
4425
4558
|
getGroupByName(name, layerName) {
|
|
4426
4559
|
return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
|
|
4427
4560
|
}
|
|
4561
|
+
/** Finds a mesh name without `mesh:`. Supply `layerName` to restrict the search to one draw. */
|
|
4428
4562
|
getMeshByName(name, layerName) {
|
|
4429
4563
|
return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
|
|
4430
4564
|
}
|
|
@@ -5097,6 +5231,7 @@ var init_ModelCulling = __esm({
|
|
|
5097
5231
|
"src/model/ModelCulling.ts"() {
|
|
5098
5232
|
init_CubeFace();
|
|
5099
5233
|
ModelCulling = class {
|
|
5234
|
+
/** Rotates a world-direction bit mask into model space. Bits follow {@link CUBE_FACES}. */
|
|
5100
5235
|
static toLocalMask(worldMask, rotation) {
|
|
5101
5236
|
let localMask = 0;
|
|
5102
5237
|
for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
|
|
@@ -5107,6 +5242,7 @@ var init_ModelCulling = __esm({
|
|
|
5107
5242
|
}
|
|
5108
5243
|
return localMask;
|
|
5109
5244
|
}
|
|
5245
|
+
/** Whether a model fills one block with opaque faces and can hide adjacent block faces. */
|
|
5110
5246
|
static isOpaqueFullCube(atlas) {
|
|
5111
5247
|
if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
|
|
5112
5248
|
const element = atlas.model.elements[0];
|
|
@@ -5928,6 +6064,7 @@ var Meshes = class _Meshes {
|
|
|
5928
6064
|
static createBox(key) {
|
|
5929
6065
|
return new Mesh(Geometries.getBox(key.geometry), Materials.getImage(key.material));
|
|
5930
6066
|
}
|
|
6067
|
+
/** Returns a shared Mesh object. Use {@link createBox} for a mesh with its own transform and parent. */
|
|
5931
6068
|
static getBox(key) {
|
|
5932
6069
|
const keyStr = serializeMeshKey(key);
|
|
5933
6070
|
return Caching.boxMeshCache.get(keyStr, (k) => {
|
|
@@ -6040,6 +6177,7 @@ init_AssetParsers();
|
|
|
6040
6177
|
init_ModelTextures();
|
|
6041
6178
|
init_Caching();
|
|
6042
6179
|
var Fonts = class {
|
|
6180
|
+
/** Combines font definitions in source-priority order. Unsupported Unihex and TrueType providers are skipped. */
|
|
6043
6181
|
static async get(key = "minecraft:default") {
|
|
6044
6182
|
const fontKey = typeof key === "string" ? AssetKey.parse("font", key) : key;
|
|
6045
6183
|
return await Caching.fontCache.get(fontKey.serialize(), () => this.load(fontKey, []));
|
|
@@ -9256,6 +9394,13 @@ var GuiHelper = class {
|
|
|
9256
9394
|
});
|
|
9257
9395
|
return layers;
|
|
9258
9396
|
}
|
|
9397
|
+
/**
|
|
9398
|
+
* Calculates a slot's top-left position in GUI pixels.
|
|
9399
|
+
* @param slot - Zero-based slot index, or `[column, row]`.
|
|
9400
|
+
* @param origin - Position of the first slot.
|
|
9401
|
+
* @param offset - Horizontal and vertical spacing between slot origins, in pixels.
|
|
9402
|
+
* @param rowSize - Slots per row when `slot` is an index.
|
|
9403
|
+
*/
|
|
9259
9404
|
static inventorySlot(slot, origin = [0, 0], offset = [18, 18], rowSize = 9) {
|
|
9260
9405
|
const [column, row] = typeof slot === "number" ? [slot % rowSize, Math.floor(slot / rowSize)] : slot;
|
|
9261
9406
|
return [origin[0] + column * offset[0], origin[1] + row * offset[1]];
|
|
@@ -9913,6 +10058,7 @@ var SceneStatsDisplay = class {
|
|
|
9913
10058
|
appendTo(el) {
|
|
9914
10059
|
el.append(this.statsContainer);
|
|
9915
10060
|
}
|
|
10061
|
+
/** Stops the refresh timer and removes the panel from the page. */
|
|
9916
10062
|
dispose() {
|
|
9917
10063
|
clearInterval(this.interval);
|
|
9918
10064
|
this.interval = void 0;
|
|
@@ -9937,6 +10083,7 @@ var InstanceManager = class {
|
|
|
9937
10083
|
this.isInstanceManager = true;
|
|
9938
10084
|
this.instanceCache = {};
|
|
9939
10085
|
}
|
|
10086
|
+
/** Allocates a new placement of a cached model, or returns `undefined` if the key is unknown. */
|
|
9940
10087
|
async get(key) {
|
|
9941
10088
|
if (key in this.instanceCache) {
|
|
9942
10089
|
console.debug(p9, "key in cache", key);
|
|
@@ -9944,6 +10091,7 @@ var InstanceManager = class {
|
|
|
9944
10091
|
}
|
|
9945
10092
|
return void 0;
|
|
9946
10093
|
}
|
|
10094
|
+
/** Allocates a placement, calling the supplier once when the shared model is first needed. */
|
|
9947
10095
|
async getOrCreate(key, supplier) {
|
|
9948
10096
|
if (key in this.instanceCache) {
|
|
9949
10097
|
return await this.get(key);
|
|
@@ -9960,6 +10108,7 @@ var InstanceManager = class {
|
|
|
9960
10108
|
throw error;
|
|
9961
10109
|
}
|
|
9962
10110
|
}
|
|
10111
|
+
/** Forgets cached models without disposing them or releasing their existing placements. */
|
|
9963
10112
|
reset() {
|
|
9964
10113
|
for (let instanceCacheKey in this.instanceCache) {
|
|
9965
10114
|
delete this.instanceCache[instanceCacheKey];
|
|
@@ -10005,6 +10154,7 @@ function matchesCondition(condition, state) {
|
|
|
10005
10154
|
});
|
|
10006
10155
|
}
|
|
10007
10156
|
var BlockStateResolver = class {
|
|
10157
|
+
/** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
|
|
10008
10158
|
static async defaults(blockState) {
|
|
10009
10159
|
const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
|
|
10010
10160
|
const state = {};
|
|
@@ -10024,9 +10174,11 @@ var BlockStateResolver = class {
|
|
|
10024
10174
|
}
|
|
10025
10175
|
return state;
|
|
10026
10176
|
}
|
|
10177
|
+
/** Selects matching models. Supply `choose` to control selection within each alternatives array. */
|
|
10027
10178
|
static select(blockState, state, choose = this.choose) {
|
|
10028
10179
|
return this.matching(blockState, state).map(choose);
|
|
10029
10180
|
}
|
|
10181
|
+
/** Returns matching model groups before choosing weighted alternatives. */
|
|
10030
10182
|
static matching(blockState, state) {
|
|
10031
10183
|
const out = [];
|
|
10032
10184
|
if (blockState.variants) {
|
|
@@ -10050,6 +10202,7 @@ var BlockStateResolver = class {
|
|
|
10050
10202
|
}
|
|
10051
10203
|
return out;
|
|
10052
10204
|
}
|
|
10205
|
+
/** Selects a random alternative using positive integer weights, each defaulting to 1. */
|
|
10053
10206
|
static choose(variants) {
|
|
10054
10207
|
if (!Array.isArray(variants)) return variants;
|
|
10055
10208
|
if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
|
|
@@ -10067,6 +10220,7 @@ var BlockStateResolver = class {
|
|
|
10067
10220
|
}
|
|
10068
10221
|
return variants[variants.length - 1];
|
|
10069
10222
|
}
|
|
10223
|
+
/** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
|
|
10070
10224
|
static rotation(variant) {
|
|
10071
10225
|
const rotation = new Euler8();
|
|
10072
10226
|
if (typeof variant.x !== "undefined") {
|
|
@@ -10348,6 +10502,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10348
10502
|
}
|
|
10349
10503
|
this.notifyDirty();
|
|
10350
10504
|
}
|
|
10505
|
+
/** Selected property values. Use {@link setState} to change properties and rebuild the rendered models. */
|
|
10351
10506
|
get state() {
|
|
10352
10507
|
return this._state;
|
|
10353
10508
|
}
|
|
@@ -10447,6 +10602,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
10447
10602
|
obj.setPosition(this.position);
|
|
10448
10603
|
return obj;
|
|
10449
10604
|
}
|
|
10605
|
+
/** Clears selected properties and rebuilds models without reapplying property defaults. */
|
|
10450
10606
|
async resetState() {
|
|
10451
10607
|
this._previousState = this._state;
|
|
10452
10608
|
this._state = {};
|
|
@@ -12350,6 +12506,11 @@ function compoundList(tags, name) {
|
|
|
12350
12506
|
// src/model/multiblock/StructureParser.ts
|
|
12351
12507
|
init_MineRenderError();
|
|
12352
12508
|
var StructureParser = class {
|
|
12509
|
+
/**
|
|
12510
|
+
* Parses decoded NBT, omitting air blocks.
|
|
12511
|
+
* @param _nbt - Structure data decoded by {@link NBTHelper.fromBuffer}.
|
|
12512
|
+
* @param paletteIndex - Palette to select when the structure has several. Defaults to 0.
|
|
12513
|
+
*/
|
|
12353
12514
|
static async parse(_nbt, paletteIndex) {
|
|
12354
12515
|
const nbt = _nbt.value;
|
|
12355
12516
|
let palette;
|
|
@@ -13184,6 +13345,7 @@ var SkinImage = class {
|
|
|
13184
13345
|
// src/skin/SkinTextures.ts
|
|
13185
13346
|
init_Textures();
|
|
13186
13347
|
var SkinTextures = class {
|
|
13348
|
+
/** Loads a skin URL. Pass `legacy` to override layout detection from the image dimensions. */
|
|
13187
13349
|
static async get(src, legacy) {
|
|
13188
13350
|
const image = await SkinImage.getData(src);
|
|
13189
13351
|
const scale = image.width / 64;
|
|
@@ -13357,6 +13519,14 @@ var SkinObject = class extends SceneObject {
|
|
|
13357
13519
|
}
|
|
13358
13520
|
}
|
|
13359
13521
|
}
|
|
13522
|
+
/**
|
|
13523
|
+
* Loads a skin texture, detecting slim arms and legacy layouts by default.
|
|
13524
|
+
* To override detection, set `slim` or `legacy` in the options passed to
|
|
13525
|
+
* `new SkinObject(options)` or `scene.addSkin(src, options)`.
|
|
13526
|
+
* Use {@link setSlim} or {@link setLegacy} to change these settings later.
|
|
13527
|
+
*
|
|
13528
|
+
* @param src - URL of the skin texture.
|
|
13529
|
+
*/
|
|
13360
13530
|
async setSkinTexture(src) {
|
|
13361
13531
|
if (typeof src === "undefined") return;
|
|
13362
13532
|
this.skinTextureSrc = src;
|
|
@@ -13505,6 +13675,7 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
13505
13675
|
this.stats.sceneObjectCount += change;
|
|
13506
13676
|
}
|
|
13507
13677
|
}
|
|
13678
|
+
/** Initializes each object before attaching it to the scene. */
|
|
13508
13679
|
async initAndAdd(...object2) {
|
|
13509
13680
|
this.dirty = true;
|
|
13510
13681
|
for (let obj of object2) {
|
|
@@ -13540,13 +13711,33 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
13540
13711
|
return obj;
|
|
13541
13712
|
}
|
|
13542
13713
|
}
|
|
13714
|
+
/**
|
|
13715
|
+
* Adds a model loaded with {@link Models.getMerged}.
|
|
13716
|
+
* Set `options.instanceMeshes` to `false` to create a separate ModelObject.
|
|
13717
|
+
*
|
|
13718
|
+
* @param parent - Object to attach the model to. Defaults to this scene.
|
|
13719
|
+
* @returns The model, or a reference to one placement of a shared model.
|
|
13720
|
+
*/
|
|
13543
13721
|
async addModel(model, options, parent = this) {
|
|
13544
13722
|
options = { ...options, tints: await ItemTints.get(model, options?.tints) };
|
|
13545
13723
|
return this.addSceneObject(model, () => new ModelObject(model, options), options, parent);
|
|
13546
13724
|
}
|
|
13725
|
+
/**
|
|
13726
|
+
* Adds the models selected by a blockstate loaded with {@link BlockStates.get}.
|
|
13727
|
+
* Set `options.initialState` to choose block properties such as `facing` or `axis`.
|
|
13728
|
+
* Use the returned object's `setPosition` method to move all of its model parts.
|
|
13729
|
+
*/
|
|
13547
13730
|
async addBlock(blockState, options, parent = this) {
|
|
13548
13731
|
return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
|
|
13549
13732
|
}
|
|
13733
|
+
/**
|
|
13734
|
+
* Loads a skin and adds an initialized player model.
|
|
13735
|
+
*
|
|
13736
|
+
* @param skin - Texture URL, such as one returned by {@link Skins.fromUuidOrUsername}.
|
|
13737
|
+
* Omit it to assign a texture later with {@link SkinObject.setSkinTexture}.
|
|
13738
|
+
* @param options - Player settings, including `slim` and `legacy` detection overrides.
|
|
13739
|
+
* @param parent - Object to attach the player to. Defaults to this scene.
|
|
13740
|
+
*/
|
|
13550
13741
|
async addSkin(skin, options, parent = this) {
|
|
13551
13742
|
this.dirty = true;
|
|
13552
13743
|
const obj = new SkinObject(options);
|
|
@@ -13558,9 +13749,14 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
13558
13749
|
parent.add(obj);
|
|
13559
13750
|
return obj;
|
|
13560
13751
|
}
|
|
13752
|
+
/** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
|
|
13561
13753
|
async addEntity(entity, options, parent = this) {
|
|
13562
13754
|
return this.addSceneObject(entity, () => new EntityObject(entity, options), options, parent);
|
|
13563
13755
|
}
|
|
13756
|
+
/**
|
|
13757
|
+
* Adds GUI layers in draw order. One GUI pixel equals one scene unit.
|
|
13758
|
+
* Layer positions start at the top left, with positive GUI y pointing down.
|
|
13759
|
+
*/
|
|
13564
13760
|
async addGui(layers, options, parent = this) {
|
|
13565
13761
|
const obj = new GuiObject(layers, options);
|
|
13566
13762
|
obj.scene = this;
|
|
@@ -14385,6 +14581,7 @@ var _Renderer = class _Renderer {
|
|
|
14385
14581
|
get element() {
|
|
14386
14582
|
return this._element;
|
|
14387
14583
|
}
|
|
14584
|
+
/** Attaches the canvas to an element and sizes it to that element's dimensions. */
|
|
14388
14585
|
appendTo(element) {
|
|
14389
14586
|
if (this._disposed) return;
|
|
14390
14587
|
this._element = element;
|
|
@@ -14412,6 +14609,7 @@ var _Renderer = class _Renderer {
|
|
|
14412
14609
|
events.add(changeEvent2);
|
|
14413
14610
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
14414
14611
|
}
|
|
14612
|
+
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
14415
14613
|
resize(width, height) {
|
|
14416
14614
|
if (this._disposed) return;
|
|
14417
14615
|
if (isPerspectiveCamera(this.camera)) {
|
|
@@ -14450,12 +14648,14 @@ var _Renderer = class _Renderer {
|
|
|
14450
14648
|
if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
|
|
14451
14649
|
};
|
|
14452
14650
|
}
|
|
14651
|
+
/** Starts or resumes the animation loop and registered frame callbacks. */
|
|
14453
14652
|
start() {
|
|
14454
14653
|
if (this._disposed) return;
|
|
14455
14654
|
this.stop();
|
|
14456
14655
|
this._running = true;
|
|
14457
14656
|
if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
|
|
14458
14657
|
}
|
|
14658
|
+
/** Pauses rendering and frame callbacks. Call {@link start} to resume. */
|
|
14459
14659
|
stop() {
|
|
14460
14660
|
if (this._disposed) return;
|
|
14461
14661
|
this._running = false;
|
|
@@ -14564,12 +14764,15 @@ var _Renderer = class _Renderer {
|
|
|
14564
14764
|
const canvas = trim ? trimCanvas(this.renderer.domElement) : this.renderer.domElement;
|
|
14565
14765
|
return canvas.toDataURL(mime, quality);
|
|
14566
14766
|
}
|
|
14767
|
+
/** Exports visible scene meshes as OBJ text, without texture images. */
|
|
14567
14768
|
toObj() {
|
|
14568
14769
|
return SceneExporter.toObj(this.scene);
|
|
14569
14770
|
}
|
|
14771
|
+
/** Exports visible scene meshes as PLY. Set `options.binary` for an ArrayBuffer. */
|
|
14570
14772
|
toPLY(options) {
|
|
14571
14773
|
return SceneExporter.toPLY(this.scene, options);
|
|
14572
14774
|
}
|
|
14775
|
+
/** Exports a static textured scene in the browser. Set `options.binary` for GLB output. */
|
|
14573
14776
|
toGLTF(options) {
|
|
14574
14777
|
return SceneExporter.toGLTF(this.scene, options);
|
|
14575
14778
|
}
|
|
@@ -14651,12 +14854,14 @@ init_request();
|
|
|
14651
14854
|
init_Requests();
|
|
14652
14855
|
var Skins = class {
|
|
14653
14856
|
//<editor-fold desc="Skins">
|
|
14857
|
+
/** Returns a skin URL for {@link MineRenderScene.addSkin}, or `undefined` if name lookup fails. */
|
|
14654
14858
|
static async fromUuidOrUsername(uuidOrUsername) {
|
|
14655
14859
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14656
14860
|
return this.fromUuid(uuidOrUsername);
|
|
14657
14861
|
}
|
|
14658
14862
|
return this.fromUsername(uuidOrUsername);
|
|
14659
14863
|
}
|
|
14864
|
+
/** Builds a proxy URL for a UUID without downloading or checking the skin. */
|
|
14660
14865
|
static async fromUuid(uuid) {
|
|
14661
14866
|
return this.getMcProxySkinUrl(uuid);
|
|
14662
14867
|
}
|
|
@@ -14668,6 +14873,7 @@ var Skins = class {
|
|
|
14668
14873
|
return void 0;
|
|
14669
14874
|
});
|
|
14670
14875
|
}
|
|
14876
|
+
/** Looks up a saved MineSkin skin and returns its texture URL, or `undefined` on lookup failure. */
|
|
14671
14877
|
static async fromMineSkin(mineskinId) {
|
|
14672
14878
|
return this.getMineSkin(mineskinId).then((mineskin) => {
|
|
14673
14879
|
if (mineskin) {
|
|
@@ -14678,12 +14884,14 @@ var Skins = class {
|
|
|
14678
14884
|
}
|
|
14679
14885
|
//</editor-fold>
|
|
14680
14886
|
//<editor-fold desc="Capes">
|
|
14887
|
+
/** Resolves a player's Minecraft cape URL for {@link SkinObject.setCapeTexture}. */
|
|
14681
14888
|
static async capeFromUuidOrUsername(uuidOrUsername) {
|
|
14682
14889
|
if (uuidOrUsername.length === 32 || uuidOrUsername.length === 36) {
|
|
14683
14890
|
return this.capeFromUuid(uuidOrUsername);
|
|
14684
14891
|
}
|
|
14685
14892
|
return this.capeFromUsername(uuidOrUsername);
|
|
14686
14893
|
}
|
|
14894
|
+
/** Builds a proxy URL without checking whether the player has a cape. */
|
|
14687
14895
|
static async capeFromUuid(uuid) {
|
|
14688
14896
|
return this.getMcProxyCapeUrl(uuid);
|
|
14689
14897
|
}
|
|
@@ -14838,16 +15046,19 @@ var ChunkData = class _ChunkData {
|
|
|
14838
15046
|
this.freeIds = [];
|
|
14839
15047
|
this.nbt = /* @__PURE__ */ new Map();
|
|
14840
15048
|
}
|
|
15049
|
+
/** Returns a detached copy of a cell, or `undefined` for air. Indices range from 0 to 4095. */
|
|
14841
15050
|
get(index) {
|
|
14842
15051
|
_ChunkData.validateIndex(index);
|
|
14843
15052
|
const entry = this.palette[this.indices[index]];
|
|
14844
15053
|
return entry ? _ChunkData.copyBlock(entry.state, this.nbt.get(index)) : void 0;
|
|
14845
15054
|
}
|
|
15055
|
+
/** Captures a cell's data and returns a copy-producing reader that survives later cell changes. */
|
|
14846
15056
|
snapshot(index) {
|
|
14847
15057
|
_ChunkData.validateIndex(index);
|
|
14848
15058
|
const entry = this.palette[this.indices[index]];
|
|
14849
15059
|
return entry ? _ChunkData.copyBlock.bind(void 0, entry.state, this.nbt.get(index)) : void 0;
|
|
14850
15060
|
}
|
|
15061
|
+
/** Copies block data into a cell. An omitted block or an air block clears the cell. */
|
|
14851
15062
|
set(index, block) {
|
|
14852
15063
|
_ChunkData.validateIndex(index);
|
|
14853
15064
|
let state;
|
|
@@ -14912,15 +15123,23 @@ var ChunkData = class _ChunkData {
|
|
|
14912
15123
|
|
|
14913
15124
|
// src/world/AnvilParser.ts
|
|
14914
15125
|
var AnvilParser = class {
|
|
15126
|
+
/** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
|
|
14915
15127
|
static getChunkList(data) {
|
|
14916
15128
|
return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
|
|
14917
15129
|
}
|
|
15130
|
+
/** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
|
|
14918
15131
|
static async parse(data) {
|
|
14919
15132
|
const bytes = this.bytes(data);
|
|
14920
15133
|
const chunks = [];
|
|
14921
15134
|
for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
|
|
14922
15135
|
return { chunks };
|
|
14923
15136
|
}
|
|
15137
|
+
/**
|
|
15138
|
+
* Decodes one chunk for {@link MineRenderWorld.placeChunk}.
|
|
15139
|
+
* @param localX - Chunk x within the region, from 0 to 31.
|
|
15140
|
+
* @param localZ - Chunk z within the region, from 0 to 31.
|
|
15141
|
+
* @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
|
|
15142
|
+
*/
|
|
14924
15143
|
static async parseChunk(data, localX, localZ) {
|
|
14925
15144
|
if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
|
|
14926
15145
|
throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
|
|
@@ -15125,6 +15344,7 @@ var SectionModels = class {
|
|
|
15125
15344
|
this.templates = /* @__PURE__ */ new Set();
|
|
15126
15345
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
15127
15346
|
}
|
|
15347
|
+
/** Returns a cube template, or `undefined` when the block requires an individual render object. */
|
|
15128
15348
|
async get(blockState, properties = {}) {
|
|
15129
15349
|
if (!blockState.variants || blockState.multipart) return void 0;
|
|
15130
15350
|
let states = this.states.get(blockState);
|
|
@@ -15178,6 +15398,7 @@ var SectionModels = class {
|
|
|
15178
15398
|
}
|
|
15179
15399
|
return { variants, templates };
|
|
15180
15400
|
}
|
|
15401
|
+
/** Disposes prepared geometry and clears this world's template caches. */
|
|
15181
15402
|
clear() {
|
|
15182
15403
|
for (const template of this.templates) template.geometry.dispose();
|
|
15183
15404
|
this.templates.clear();
|
|
@@ -15228,6 +15449,13 @@ var MineRenderWorld = class {
|
|
|
15228
15449
|
this.validatePosBounds(posOrX);
|
|
15229
15450
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
15230
15451
|
}
|
|
15452
|
+
/**
|
|
15453
|
+
* Places a structure's blocks at their stored positions, then refreshes neighboring faces.
|
|
15454
|
+
* Entity NBT is retained by the structure but is not rendered.
|
|
15455
|
+
*
|
|
15456
|
+
* @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
|
|
15457
|
+
* @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
|
|
15458
|
+
*/
|
|
15231
15459
|
async placeMultiBlock(multiblock, useBatches = true, executor) {
|
|
15232
15460
|
const changes = /* @__PURE__ */ new Map();
|
|
15233
15461
|
try {
|
|
@@ -15279,13 +15507,7 @@ var MineRenderWorld = class {
|
|
|
15279
15507
|
async placeChunk(chunk, executor) {
|
|
15280
15508
|
const changes = /* @__PURE__ */ new Map();
|
|
15281
15509
|
try {
|
|
15282
|
-
|
|
15283
|
-
for (const [key, section] of previous) {
|
|
15284
|
-
this._chunks.delete(key);
|
|
15285
|
-
await section.clear(async (positions) => {
|
|
15286
|
-
for (const pos of positions) changes.set(pos.toArray().join(","), pos);
|
|
15287
|
-
});
|
|
15288
|
-
}
|
|
15510
|
+
await this.clearChunkColumn(chunk.x, chunk.z, changes);
|
|
15289
15511
|
for (const section of chunk.sections) {
|
|
15290
15512
|
const blocks = [];
|
|
15291
15513
|
for (let index = 0; index < 4096; index++) {
|
|
@@ -15305,6 +15527,32 @@ var MineRenderWorld = class {
|
|
|
15305
15527
|
await this.updateCulling([...changes.values()]);
|
|
15306
15528
|
}
|
|
15307
15529
|
}
|
|
15530
|
+
/**
|
|
15531
|
+
* Removes all sections at integer chunk-column coordinates, then refreshes neighboring faces and fluids.
|
|
15532
|
+
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
15533
|
+
*/
|
|
15534
|
+
async unloadChunkColumn(x, z) {
|
|
15535
|
+
if (!Number.isInteger(x) || !Number.isInteger(z)) {
|
|
15536
|
+
throw new RangeError("Chunk column coordinates must be integers");
|
|
15537
|
+
}
|
|
15538
|
+
await this.culling;
|
|
15539
|
+
const changes = /* @__PURE__ */ new Map();
|
|
15540
|
+
try {
|
|
15541
|
+
await this.clearChunkColumn(x, z, changes);
|
|
15542
|
+
} finally {
|
|
15543
|
+
await this.updateCulling([...changes.values()]);
|
|
15544
|
+
}
|
|
15545
|
+
}
|
|
15546
|
+
async clearChunkColumn(x, z, changes) {
|
|
15547
|
+
const previous = [...this._chunks.entries()].filter(([, section]) => section.x === x && section.z === z);
|
|
15548
|
+
for (const [key, section] of previous) {
|
|
15549
|
+
this._chunks.delete(key);
|
|
15550
|
+
await section.clear(async (positions) => {
|
|
15551
|
+
for (const pos of positions) changes.set(pos.toArray().join(","), pos);
|
|
15552
|
+
});
|
|
15553
|
+
}
|
|
15554
|
+
}
|
|
15555
|
+
/** Removes all chunks and releases their block placements and section meshes. */
|
|
15308
15556
|
async clear() {
|
|
15309
15557
|
await this.culling;
|
|
15310
15558
|
const chunks = [...this._chunks.values()];
|
|
@@ -15390,9 +15638,11 @@ var MineRenderWorld = class {
|
|
|
15390
15638
|
}
|
|
15391
15639
|
return chunk;
|
|
15392
15640
|
}
|
|
15641
|
+
/** Returns the loaded chunk containing a world block position, without creating a chunk. */
|
|
15393
15642
|
getChunkAt(pos) {
|
|
15394
15643
|
return this._chunks.get(this.worldPosToChunkKey(pos));
|
|
15395
15644
|
}
|
|
15645
|
+
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
15396
15646
|
static worldToScenePosition(pos) {
|
|
15397
15647
|
return new Vector316(
|
|
15398
15648
|
pos.x * 16,
|
|
@@ -15400,6 +15650,7 @@ var MineRenderWorld = class {
|
|
|
15400
15650
|
pos.z * 16
|
|
15401
15651
|
);
|
|
15402
15652
|
}
|
|
15653
|
+
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
15403
15654
|
static sceneToWorldPosition(pos) {
|
|
15404
15655
|
return new Vector316(
|
|
15405
15656
|
pos.x / 16,
|
|
@@ -15432,6 +15683,7 @@ var SectionMesh = class _SectionMesh extends Group2 {
|
|
|
15432
15683
|
super(...arguments);
|
|
15433
15684
|
this.ownedMeshes = [];
|
|
15434
15685
|
}
|
|
15686
|
+
/** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
15435
15687
|
static build(entries, maxAtlasSize = 2048) {
|
|
15436
15688
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
15437
15689
|
const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
|
|
@@ -15576,7 +15828,7 @@ var Chunk = class _Chunk {
|
|
|
15576
15828
|
return this.setBlockInChunkAt(pos, block, worldPos);
|
|
15577
15829
|
}
|
|
15578
15830
|
/**
|
|
15579
|
-
*
|
|
15831
|
+
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
15580
15832
|
*/
|
|
15581
15833
|
async setBlockInChunkAt(pos, block, worldPos, onBlocksChanged = this.onBlocksChanged) {
|
|
15582
15834
|
if (typeof worldPos === "undefined") {
|
|
@@ -15625,6 +15877,7 @@ var Chunk = class _Chunk {
|
|
|
15625
15877
|
await onBlocksChanged?.([worldPos]);
|
|
15626
15878
|
}
|
|
15627
15879
|
}
|
|
15880
|
+
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
15628
15881
|
async setBlockVisibleAt(pos, visible) {
|
|
15629
15882
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
15630
15883
|
const block = this.renderedBlocks.get(index);
|
|
@@ -15678,6 +15931,7 @@ var Chunk = class _Chunk {
|
|
|
15678
15931
|
this.scene.dirty = true;
|
|
15679
15932
|
this.meshDirty = false;
|
|
15680
15933
|
}
|
|
15934
|
+
/** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
|
|
15681
15935
|
async clear(onBlocksChanged = this.onBlocksChanged) {
|
|
15682
15936
|
const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
15683
15937
|
new Vector317(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
@@ -15698,6 +15952,7 @@ var Chunk = class _Chunk {
|
|
|
15698
15952
|
static isAir(block) {
|
|
15699
15953
|
return ChunkData.isAir(block);
|
|
15700
15954
|
}
|
|
15955
|
+
/** Maps chunk-local coordinates from 0 to 15 to a storage index, with x varying fastest, then z, then y. */
|
|
15701
15956
|
static chunkPosToBlockIndex(pos) {
|
|
15702
15957
|
if ([pos.x, pos.y, pos.z].some((value) => !Number.isInteger(value) || value < 0 || value >= 16)) {
|
|
15703
15958
|
throw new RangeError("Block coordinates must be integers from 0 to 15 within a chunk");
|