minerender 2.1.0-alpha.137 → 2.1.0-alpha.138
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/esm/index.browser.d.mts +17 -6
- package/dist/browser/esm/world/Chunk.mjs +8 -5
- package/dist/browser/esm/world/Chunk.mjs.map +1 -1
- package/dist/browser/esm/world/MineRenderWorld.mjs +92 -52
- package/dist/browser/esm/world/MineRenderWorld.mjs.map +1 -1
- package/dist/browser/esm/world/WorldStreamer.mjs +21 -20
- package/dist/browser/esm/world/WorldStreamer.mjs.map +1 -1
- package/dist/browser/index.d.ts +17 -6
- package/dist/browser/index.js +121 -77
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +121 -77
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +17 -6
- package/dist/node/index.d.ts +17 -6
- package/dist/node/index.js +121 -77
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +121 -77
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.mjs
CHANGED
|
@@ -18543,8 +18543,14 @@ var MineRenderWorld = class {
|
|
|
18543
18543
|
}
|
|
18544
18544
|
return queued;
|
|
18545
18545
|
}
|
|
18546
|
-
async refreshBiomes() {
|
|
18547
|
-
if (this.biomeRefreshing)
|
|
18546
|
+
async refreshBiomes(deferCulling = false) {
|
|
18547
|
+
if (this.biomeRefreshing) {
|
|
18548
|
+
await this.biomeRefreshing;
|
|
18549
|
+
if (!deferCulling) {
|
|
18550
|
+
if (this.pendingCulling.size) await this.updateCulling([]);
|
|
18551
|
+
else await this.culling;
|
|
18552
|
+
}
|
|
18553
|
+
}
|
|
18548
18554
|
if (!this.pendingBiomes.size) return /* @__PURE__ */ new Map();
|
|
18549
18555
|
return this.biomeRefreshing ??= Promise.resolve().then(async () => {
|
|
18550
18556
|
const failures = /* @__PURE__ */ new Map();
|
|
@@ -18556,7 +18562,7 @@ var MineRenderWorld = class {
|
|
|
18556
18562
|
this.pendingBiomes.delete(chunk);
|
|
18557
18563
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) !== chunk) continue;
|
|
18558
18564
|
try {
|
|
18559
|
-
await chunk.refreshBiomes(columns);
|
|
18565
|
+
await chunk.refreshBiomes(columns, deferCulling);
|
|
18560
18566
|
} catch (error) {
|
|
18561
18567
|
failures.set(chunk, error);
|
|
18562
18568
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
|
|
@@ -18818,15 +18824,35 @@ var MineRenderWorld = class {
|
|
|
18818
18824
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
18819
18825
|
*/
|
|
18820
18826
|
async unloadChunkColumn(x, z) {
|
|
18821
|
-
|
|
18822
|
-
|
|
18827
|
+
return this.unloadChunkColumns([{ x, z }]);
|
|
18828
|
+
}
|
|
18829
|
+
/**
|
|
18830
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
18831
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
18832
|
+
*/
|
|
18833
|
+
async unloadChunkColumns(positions) {
|
|
18834
|
+
const columns = /* @__PURE__ */ new Map();
|
|
18835
|
+
for (const position of positions) {
|
|
18836
|
+
const { x, z } = position ?? {};
|
|
18837
|
+
if (!Number.isInteger(x) || !Number.isInteger(z)) {
|
|
18838
|
+
throw new RangeError("Chunk column coordinates must be integers");
|
|
18839
|
+
}
|
|
18840
|
+
columns.set(`${x}_${z}`, { x, z });
|
|
18823
18841
|
}
|
|
18824
|
-
|
|
18842
|
+
if (!columns.size) return;
|
|
18825
18843
|
await this.culling;
|
|
18844
|
+
let sliceStart = performance.now();
|
|
18826
18845
|
try {
|
|
18827
|
-
|
|
18846
|
+
for (const { x, z } of columns.values()) {
|
|
18847
|
+
this.entities?.clearColumn(x, z);
|
|
18848
|
+
await this.clearChunkColumn(x, z);
|
|
18849
|
+
if (performance.now() - sliceStart > 8) {
|
|
18850
|
+
await yieldToEventLoop();
|
|
18851
|
+
sliceStart = performance.now();
|
|
18852
|
+
}
|
|
18853
|
+
}
|
|
18828
18854
|
} finally {
|
|
18829
|
-
const failures = await this.refreshBiomes();
|
|
18855
|
+
const failures = await this.refreshBiomes(true);
|
|
18830
18856
|
if (failures.size) log18.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
18831
18857
|
await this.updateCulling([]);
|
|
18832
18858
|
}
|
|
@@ -18889,7 +18915,7 @@ var MineRenderWorld = class {
|
|
|
18889
18915
|
}
|
|
18890
18916
|
this.sectionModels?.clear();
|
|
18891
18917
|
}
|
|
18892
|
-
updateCulling(positions) {
|
|
18918
|
+
updateCulling(positions, defer = false) {
|
|
18893
18919
|
const neighbor = new Vector319();
|
|
18894
18920
|
for (const pos of positions) {
|
|
18895
18921
|
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
@@ -18911,58 +18937,72 @@ var MineRenderWorld = class {
|
|
|
18911
18937
|
}
|
|
18912
18938
|
}
|
|
18913
18939
|
}
|
|
18940
|
+
if (defer) return Promise.resolve();
|
|
18914
18941
|
return this.culling ??= Promise.resolve().then(async () => {
|
|
18915
18942
|
let sliceStart = performance.now();
|
|
18916
18943
|
try {
|
|
18917
18944
|
const culling = await loadBlockCulling();
|
|
18918
18945
|
while (this.pendingCulling.size) {
|
|
18919
|
-
const batch =
|
|
18946
|
+
const batch = new Map(this.pendingCulling);
|
|
18920
18947
|
this.pendingCulling.clear();
|
|
18921
|
-
|
|
18922
|
-
const
|
|
18923
|
-
|
|
18924
|
-
const
|
|
18925
|
-
|
|
18926
|
-
|
|
18927
|
-
|
|
18928
|
-
|
|
18929
|
-
const
|
|
18930
|
-
|
|
18931
|
-
|
|
18932
|
-
|
|
18933
|
-
|
|
18934
|
-
|
|
18935
|
-
|
|
18936
|
-
|
|
18937
|
-
|
|
18938
|
-
|
|
18939
|
-
|
|
18940
|
-
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
18945
|
-
|
|
18946
|
-
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
|
|
18950
|
-
|
|
18951
|
-
|
|
18952
|
-
|
|
18953
|
-
|
|
18954
|
-
|
|
18948
|
+
try {
|
|
18949
|
+
for (const [chunk, indices] of batch) {
|
|
18950
|
+
const neighbors = CUBE_FACE_OFFSETS.map(([x, y, z]) => this._chunks.get(`${chunk.x + x}_${chunk.y + y}_${chunk.z + z}`));
|
|
18951
|
+
const neighborAt = (x, y, z) => {
|
|
18952
|
+
const lx = x - chunk.x * 16, ly = y - chunk.y * 16, lz = z - chunk.z * 16;
|
|
18953
|
+
const section = neighbors[lx >= 16 ? 0 : lx < 0 ? 1 : ly >= 16 ? 2 : ly < 0 ? 3 : lz >= 16 ? 4 : 5];
|
|
18954
|
+
return [section, (ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)];
|
|
18955
|
+
};
|
|
18956
|
+
const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x, y, z) => {
|
|
18957
|
+
const [section, i] = neighborAt(x, y, z);
|
|
18958
|
+
return section?.isOccludingIndex(i) ?? false;
|
|
18959
|
+
}, culling, (x, y, z) => {
|
|
18960
|
+
const [section, i] = neighborAt(x, y, z);
|
|
18961
|
+
return section?.visibleBlockIndex(i);
|
|
18962
|
+
});
|
|
18963
|
+
const fluidIndices = indices === "all" ? function* () {
|
|
18964
|
+
for (let index = 0; index < 4096; index++) yield index;
|
|
18965
|
+
}() : indices;
|
|
18966
|
+
for (const index of fluidIndices) {
|
|
18967
|
+
if (!chunk.fluidByteIndex(index) || !chunk.isBlockVisibleIndex(index)) continue;
|
|
18968
|
+
const lx = index % 16, ly = Math.floor(index / 256), lz = Math.floor(index / 16) % 16;
|
|
18969
|
+
const wx = chunk.x * 16 + lx, wy = chunk.y * 16 + ly, wz = chunk.z * 16 + lz;
|
|
18970
|
+
const block = chunk.getBlockAt(neighbor.set(wx, wy, wz));
|
|
18971
|
+
if (block.object?.fluidKind) {
|
|
18972
|
+
await block.object.updateFluid((x, y, z) => {
|
|
18973
|
+
const nx = lx + x, ny = ly + y, nz = lz + z;
|
|
18974
|
+
const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${chunk.x + Math.floor(nx / 16)}_${chunk.y + Math.floor(ny / 16)}_${chunk.z + Math.floor(nz / 16)}`);
|
|
18975
|
+
const neighborIndex = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
18976
|
+
const byte = section?.fluidByteIndex(neighborIndex) ?? 0;
|
|
18977
|
+
return {
|
|
18978
|
+
fluid: fluidKindOf(byte),
|
|
18979
|
+
level: byte & 15,
|
|
18980
|
+
solid: section?.isOccludingIndex(neighborIndex) ?? false
|
|
18981
|
+
};
|
|
18982
|
+
});
|
|
18983
|
+
}
|
|
18984
|
+
}
|
|
18985
|
+
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
18986
|
+
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
18987
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
18988
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
18989
|
+
await yieldToEventLoop();
|
|
18990
|
+
sliceStart = performance.now();
|
|
18955
18991
|
}
|
|
18956
18992
|
}
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
|
|
18961
|
-
|
|
18962
|
-
|
|
18993
|
+
const builds = await Promise.allSettled([...batch.keys()].map(async (chunk) => {
|
|
18994
|
+
await chunk.rebuildSectionMesh();
|
|
18995
|
+
batch.delete(chunk);
|
|
18996
|
+
}));
|
|
18997
|
+
const failure = builds.find((result) => result.status === "rejected");
|
|
18998
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
18999
|
+
} catch (error) {
|
|
19000
|
+
for (const [chunk, indices] of batch) {
|
|
19001
|
+
const pending = this.pendingCulling.get(chunk);
|
|
19002
|
+
this.pendingCulling.set(chunk, indices === "all" || pending === "all" ? "all" : /* @__PURE__ */ new Set([...indices, ...pending ?? []]));
|
|
18963
19003
|
}
|
|
19004
|
+
throw error;
|
|
18964
19005
|
}
|
|
18965
|
-
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
18966
19006
|
}
|
|
18967
19007
|
} finally {
|
|
18968
19008
|
this.culling = void 0;
|
|
@@ -18979,7 +19019,7 @@ var MineRenderWorld = class {
|
|
|
18979
19019
|
x,
|
|
18980
19020
|
y,
|
|
18981
19021
|
z,
|
|
18982
|
-
(positions) => this.updateCulling(positions),
|
|
19022
|
+
(positions, defer) => this.updateCulling(positions, defer),
|
|
18983
19023
|
this.sectionModels,
|
|
18984
19024
|
(x2, y2, z2) => {
|
|
18985
19025
|
const cx = Math.floor(x2 / 16), cy = Math.floor(y2 / 16), cz = Math.floor(z2 / 16);
|
|
@@ -19714,11 +19754,14 @@ var Chunk = class _Chunk {
|
|
|
19714
19754
|
this.biomes = copy;
|
|
19715
19755
|
return this.refreshBiomes();
|
|
19716
19756
|
}
|
|
19717
|
-
/**
|
|
19718
|
-
|
|
19719
|
-
|
|
19757
|
+
/**
|
|
19758
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
19759
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
19760
|
+
*/
|
|
19761
|
+
refreshBiomes(columns, deferCulling = false) {
|
|
19762
|
+
return this.changeBlocks(() => this.refreshBiomeBlocks(columns, deferCulling), true);
|
|
19720
19763
|
}
|
|
19721
|
-
async refreshBiomeBlocks(columns) {
|
|
19764
|
+
async refreshBiomeBlocks(columns, deferCulling = false) {
|
|
19722
19765
|
const blend = columns && this.biomeBlend?.();
|
|
19723
19766
|
const ownColumn = columns?.some((column) => column.x === this.x && column.z === this.z);
|
|
19724
19767
|
const affected = /* @__PURE__ */ new Map();
|
|
@@ -19775,7 +19818,7 @@ var Chunk = class _Chunk {
|
|
|
19775
19818
|
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
19776
19819
|
}
|
|
19777
19820
|
const positions = blocks.map(({ index }) => new Vector320(...this.positionAt(index)));
|
|
19778
|
-
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
19821
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions, deferCulling);
|
|
19779
19822
|
else await this.rebuildSectionMesh();
|
|
19780
19823
|
}
|
|
19781
19824
|
}
|
|
@@ -20429,19 +20472,12 @@ var WorldStreamer = class {
|
|
|
20429
20472
|
this.loading?.controller.abort();
|
|
20430
20473
|
return this.disposal ??= Promise.resolve().then(async () => {
|
|
20431
20474
|
await this.running?.catch(() => void 0);
|
|
20432
|
-
|
|
20433
|
-
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
|
|
20437
|
-
} catch (error) {
|
|
20438
|
-
failed = true;
|
|
20439
|
-
failure ??= error;
|
|
20440
|
-
}
|
|
20475
|
+
try {
|
|
20476
|
+
await this.unloadMany([...this.owned.values()]);
|
|
20477
|
+
} finally {
|
|
20478
|
+
this.missing.clear();
|
|
20479
|
+
this.failed.clear();
|
|
20441
20480
|
}
|
|
20442
|
-
this.missing.clear();
|
|
20443
|
-
this.failed.clear();
|
|
20444
|
-
if (failed) throw failure;
|
|
20445
20481
|
}).catch((error) => {
|
|
20446
20482
|
this.disposal = void 0;
|
|
20447
20483
|
throw error;
|
|
@@ -20456,9 +20492,9 @@ var WorldStreamer = class {
|
|
|
20456
20492
|
for (const [key, position2] of this.failed) {
|
|
20457
20493
|
if (!this.within(position2, this.unloadRadius)) this.failed.delete(key);
|
|
20458
20494
|
}
|
|
20459
|
-
const obsolete = [...this.owned.values()].
|
|
20460
|
-
if (obsolete) {
|
|
20461
|
-
await this.
|
|
20495
|
+
const obsolete = [...this.owned.values()].filter((position2) => !this.loaded.has(this.key(position2)) || !this.within(position2, this.unloadRadius));
|
|
20496
|
+
if (obsolete.length) {
|
|
20497
|
+
await this.unloadMany(obsolete);
|
|
20462
20498
|
continue;
|
|
20463
20499
|
}
|
|
20464
20500
|
const position = this.desired.find((position2) => this.needsLoad(position2));
|
|
@@ -20488,7 +20524,7 @@ var WorldStreamer = class {
|
|
|
20488
20524
|
this.loaded.set(this.key(position), position);
|
|
20489
20525
|
} catch (error) {
|
|
20490
20526
|
try {
|
|
20491
|
-
await this.
|
|
20527
|
+
await this.unloadMany([position]);
|
|
20492
20528
|
} catch (cleanupError) {
|
|
20493
20529
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
20494
20530
|
try {
|
|
@@ -20509,10 +20545,18 @@ var WorldStreamer = class {
|
|
|
20509
20545
|
const key = this.key(position);
|
|
20510
20546
|
return !this.loaded.has(key) && !this.missing.has(key) && !this.failed.has(key);
|
|
20511
20547
|
}
|
|
20512
|
-
async
|
|
20513
|
-
|
|
20514
|
-
|
|
20515
|
-
|
|
20548
|
+
async unloadMany(positions) {
|
|
20549
|
+
if (!positions.length) return;
|
|
20550
|
+
try {
|
|
20551
|
+
await this.world.unloadChunkColumns(positions.map(({ x, z }) => ({ x, z })));
|
|
20552
|
+
} catch (error) {
|
|
20553
|
+
for (const position of positions) this.loaded.delete(this.key(position));
|
|
20554
|
+
throw error;
|
|
20555
|
+
}
|
|
20556
|
+
for (const position of positions) {
|
|
20557
|
+
this.owned.delete(this.key(position));
|
|
20558
|
+
this.loaded.delete(this.key(position));
|
|
20559
|
+
}
|
|
20516
20560
|
}
|
|
20517
20561
|
validateChunk(chunk, position) {
|
|
20518
20562
|
if (chunk.x !== position.x || chunk.z !== position.z) {
|