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.d.mts
CHANGED
|
@@ -4068,7 +4068,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4068
4068
|
private ambientOcclusionCells?;
|
|
4069
4069
|
private readonly blockChanges;
|
|
4070
4070
|
private biomeChange?;
|
|
4071
|
-
constructor(scene: MineRenderScene, x: number, y: number, z: number, onBlocksChanged?: ((positions: Vector3[]) => Promise<void>) | undefined, sectionModels?: SectionModels | undefined, neighborCell?: ((x: number, y: number, z: number) => number) | undefined, biomeAt?: ((x: number, y: number, z: number) => Maybe<string>) | undefined, onBiomesChanged?: ((biomes?: readonly string[]) => Promise<void>) | undefined, lightAt?: ((x: number, y: number, z: number) => number) | undefined, onLightCleared?: (() => Promise<void>) | undefined, ambientLight?: number, biomeBlend?: (() => BiomeBlend | undefined) | undefined);
|
|
4071
|
+
constructor(scene: MineRenderScene, x: number, y: number, z: number, onBlocksChanged?: ((positions: Vector3[], deferCulling?: boolean) => Promise<void>) | undefined, sectionModels?: SectionModels | undefined, neighborCell?: ((x: number, y: number, z: number) => number) | undefined, biomeAt?: ((x: number, y: number, z: number) => Maybe<string>) | undefined, onBiomesChanged?: ((biomes?: readonly string[]) => Promise<void>) | undefined, lightAt?: ((x: number, y: number, z: number) => number) | undefined, onLightCleared?: (() => Promise<void>) | undefined, ambientLight?: number, biomeBlend?: (() => BiomeBlend | undefined) | undefined);
|
|
4072
4072
|
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
4073
4073
|
static raycast<SectionMeshing extends boolean>(chunks: Iterable<Chunk<SectionMeshing>>, raycaster: Raycaster): WorldBlockIntersection | undefined;
|
|
4074
4074
|
getBlockAt(x: number, y: number, z: number): Maybe<BlockInfo<SectionMeshing>>;
|
|
@@ -4080,11 +4080,14 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4080
4080
|
getBiomeAt(pos: TripleArray): Maybe<string>;
|
|
4081
4081
|
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
4082
4082
|
setBiomes(biomes?: readonly string[]): Promise<void>;
|
|
4083
|
-
/**
|
|
4083
|
+
/**
|
|
4084
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
4085
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
4086
|
+
*/
|
|
4084
4087
|
refreshBiomes(columns?: readonly {
|
|
4085
4088
|
x: number;
|
|
4086
4089
|
z: number;
|
|
4087
|
-
}[]): Promise<void>;
|
|
4090
|
+
}[], deferCulling?: boolean): Promise<void>;
|
|
4088
4091
|
private refreshBiomeBlocks;
|
|
4089
4092
|
/**
|
|
4090
4093
|
* Places a block at integer world block coordinates. Pass `undefined` to remove it.
|
|
@@ -4095,7 +4098,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4095
4098
|
/**
|
|
4096
4099
|
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
4097
4100
|
*/
|
|
4098
|
-
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[]) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4101
|
+
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[], deferCulling?: boolean) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4099
4102
|
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
4100
4103
|
placeBlocks(blocks: readonly {
|
|
4101
4104
|
index: number;
|
|
@@ -4260,6 +4263,14 @@ declare class MineRenderWorld<SectionMeshing extends boolean = false> {
|
|
|
4260
4263
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
4261
4264
|
*/
|
|
4262
4265
|
unloadChunkColumn(x: number, z: number): Promise<void>;
|
|
4266
|
+
/**
|
|
4267
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
4268
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
4269
|
+
*/
|
|
4270
|
+
unloadChunkColumns(positions: readonly {
|
|
4271
|
+
x: number;
|
|
4272
|
+
z: number;
|
|
4273
|
+
}[]): Promise<void>;
|
|
4263
4274
|
private clearChunkColumn;
|
|
4264
4275
|
private markSectionChanged;
|
|
4265
4276
|
/** Removes all chunks and releases their blocks, section meshes, and owned entities. */
|
|
@@ -4337,7 +4348,7 @@ declare class WorldStreamer {
|
|
|
4337
4348
|
private running?;
|
|
4338
4349
|
private disposal?;
|
|
4339
4350
|
private disposed;
|
|
4340
|
-
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "
|
|
4351
|
+
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "unloadChunkColumns">, source: WorldChunkSource, options?: WorldStreamerOptions);
|
|
4341
4352
|
/** Returns absolute coordinates of successfully placed columns, including retained columns. */
|
|
4342
4353
|
get loadedChunks(): readonly {
|
|
4343
4354
|
x: number;
|
|
@@ -4371,7 +4382,7 @@ declare class WorldStreamer {
|
|
|
4371
4382
|
dispose(): Promise<void>;
|
|
4372
4383
|
private drain;
|
|
4373
4384
|
private needsLoad;
|
|
4374
|
-
private
|
|
4385
|
+
private unloadMany;
|
|
4375
4386
|
private validateChunk;
|
|
4376
4387
|
private within;
|
|
4377
4388
|
private key;
|
package/dist/node/index.d.ts
CHANGED
|
@@ -4068,7 +4068,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4068
4068
|
private ambientOcclusionCells?;
|
|
4069
4069
|
private readonly blockChanges;
|
|
4070
4070
|
private biomeChange?;
|
|
4071
|
-
constructor(scene: MineRenderScene, x: number, y: number, z: number, onBlocksChanged?: ((positions: Vector3[]) => Promise<void>) | undefined, sectionModels?: SectionModels | undefined, neighborCell?: ((x: number, y: number, z: number) => number) | undefined, biomeAt?: ((x: number, y: number, z: number) => Maybe<string>) | undefined, onBiomesChanged?: ((biomes?: readonly string[]) => Promise<void>) | undefined, lightAt?: ((x: number, y: number, z: number) => number) | undefined, onLightCleared?: (() => Promise<void>) | undefined, ambientLight?: number, biomeBlend?: (() => BiomeBlend | undefined) | undefined);
|
|
4071
|
+
constructor(scene: MineRenderScene, x: number, y: number, z: number, onBlocksChanged?: ((positions: Vector3[], deferCulling?: boolean) => Promise<void>) | undefined, sectionModels?: SectionModels | undefined, neighborCell?: ((x: number, y: number, z: number) => number) | undefined, biomeAt?: ((x: number, y: number, z: number) => Maybe<string>) | undefined, onBiomesChanged?: ((biomes?: readonly string[]) => Promise<void>) | undefined, lightAt?: ((x: number, y: number, z: number) => number) | undefined, onLightCleared?: (() => Promise<void>) | undefined, ambientLight?: number, biomeBlend?: (() => BiomeBlend | undefined) | undefined);
|
|
4072
4072
|
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
4073
4073
|
static raycast<SectionMeshing extends boolean>(chunks: Iterable<Chunk<SectionMeshing>>, raycaster: Raycaster): WorldBlockIntersection | undefined;
|
|
4074
4074
|
getBlockAt(x: number, y: number, z: number): Maybe<BlockInfo<SectionMeshing>>;
|
|
@@ -4080,11 +4080,14 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4080
4080
|
getBiomeAt(pos: TripleArray): Maybe<string>;
|
|
4081
4081
|
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
4082
4082
|
setBiomes(biomes?: readonly string[]): Promise<void>;
|
|
4083
|
-
/**
|
|
4083
|
+
/**
|
|
4084
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
4085
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
4086
|
+
*/
|
|
4084
4087
|
refreshBiomes(columns?: readonly {
|
|
4085
4088
|
x: number;
|
|
4086
4089
|
z: number;
|
|
4087
|
-
}[]): Promise<void>;
|
|
4090
|
+
}[], deferCulling?: boolean): Promise<void>;
|
|
4088
4091
|
private refreshBiomeBlocks;
|
|
4089
4092
|
/**
|
|
4090
4093
|
* Places a block at integer world block coordinates. Pass `undefined` to remove it.
|
|
@@ -4095,7 +4098,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4095
4098
|
/**
|
|
4096
4099
|
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
4097
4100
|
*/
|
|
4098
|
-
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[]) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4101
|
+
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[], deferCulling?: boolean) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4099
4102
|
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
4100
4103
|
placeBlocks(blocks: readonly {
|
|
4101
4104
|
index: number;
|
|
@@ -4260,6 +4263,14 @@ declare class MineRenderWorld<SectionMeshing extends boolean = false> {
|
|
|
4260
4263
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
4261
4264
|
*/
|
|
4262
4265
|
unloadChunkColumn(x: number, z: number): Promise<void>;
|
|
4266
|
+
/**
|
|
4267
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
4268
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
4269
|
+
*/
|
|
4270
|
+
unloadChunkColumns(positions: readonly {
|
|
4271
|
+
x: number;
|
|
4272
|
+
z: number;
|
|
4273
|
+
}[]): Promise<void>;
|
|
4263
4274
|
private clearChunkColumn;
|
|
4264
4275
|
private markSectionChanged;
|
|
4265
4276
|
/** Removes all chunks and releases their blocks, section meshes, and owned entities. */
|
|
@@ -4337,7 +4348,7 @@ declare class WorldStreamer {
|
|
|
4337
4348
|
private running?;
|
|
4338
4349
|
private disposal?;
|
|
4339
4350
|
private disposed;
|
|
4340
|
-
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "
|
|
4351
|
+
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "unloadChunkColumns">, source: WorldChunkSource, options?: WorldStreamerOptions);
|
|
4341
4352
|
/** Returns absolute coordinates of successfully placed columns, including retained columns. */
|
|
4342
4353
|
get loadedChunks(): readonly {
|
|
4343
4354
|
x: number;
|
|
@@ -4371,7 +4382,7 @@ declare class WorldStreamer {
|
|
|
4371
4382
|
dispose(): Promise<void>;
|
|
4372
4383
|
private drain;
|
|
4373
4384
|
private needsLoad;
|
|
4374
|
-
private
|
|
4385
|
+
private unloadMany;
|
|
4375
4386
|
private validateChunk;
|
|
4376
4387
|
private within;
|
|
4377
4388
|
private key;
|
package/dist/node/index.js
CHANGED
|
@@ -18711,8 +18711,14 @@ var MineRenderWorld = class {
|
|
|
18711
18711
|
}
|
|
18712
18712
|
return queued;
|
|
18713
18713
|
}
|
|
18714
|
-
async refreshBiomes() {
|
|
18715
|
-
if (this.biomeRefreshing)
|
|
18714
|
+
async refreshBiomes(deferCulling = false) {
|
|
18715
|
+
if (this.biomeRefreshing) {
|
|
18716
|
+
await this.biomeRefreshing;
|
|
18717
|
+
if (!deferCulling) {
|
|
18718
|
+
if (this.pendingCulling.size) await this.updateCulling([]);
|
|
18719
|
+
else await this.culling;
|
|
18720
|
+
}
|
|
18721
|
+
}
|
|
18716
18722
|
if (!this.pendingBiomes.size) return /* @__PURE__ */ new Map();
|
|
18717
18723
|
return this.biomeRefreshing ??= Promise.resolve().then(async () => {
|
|
18718
18724
|
const failures = /* @__PURE__ */ new Map();
|
|
@@ -18724,7 +18730,7 @@ var MineRenderWorld = class {
|
|
|
18724
18730
|
this.pendingBiomes.delete(chunk);
|
|
18725
18731
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) !== chunk) continue;
|
|
18726
18732
|
try {
|
|
18727
|
-
await chunk.refreshBiomes(columns);
|
|
18733
|
+
await chunk.refreshBiomes(columns, deferCulling);
|
|
18728
18734
|
} catch (error) {
|
|
18729
18735
|
failures.set(chunk, error);
|
|
18730
18736
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
|
|
@@ -18986,15 +18992,35 @@ var MineRenderWorld = class {
|
|
|
18986
18992
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
18987
18993
|
*/
|
|
18988
18994
|
async unloadChunkColumn(x, z) {
|
|
18989
|
-
|
|
18990
|
-
|
|
18995
|
+
return this.unloadChunkColumns([{ x, z }]);
|
|
18996
|
+
}
|
|
18997
|
+
/**
|
|
18998
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
18999
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
19000
|
+
*/
|
|
19001
|
+
async unloadChunkColumns(positions) {
|
|
19002
|
+
const columns = /* @__PURE__ */ new Map();
|
|
19003
|
+
for (const position of positions) {
|
|
19004
|
+
const { x, z } = position ?? {};
|
|
19005
|
+
if (!Number.isInteger(x) || !Number.isInteger(z)) {
|
|
19006
|
+
throw new RangeError("Chunk column coordinates must be integers");
|
|
19007
|
+
}
|
|
19008
|
+
columns.set(`${x}_${z}`, { x, z });
|
|
18991
19009
|
}
|
|
18992
|
-
|
|
19010
|
+
if (!columns.size) return;
|
|
18993
19011
|
await this.culling;
|
|
19012
|
+
let sliceStart = performance.now();
|
|
18994
19013
|
try {
|
|
18995
|
-
|
|
19014
|
+
for (const { x, z } of columns.values()) {
|
|
19015
|
+
this.entities?.clearColumn(x, z);
|
|
19016
|
+
await this.clearChunkColumn(x, z);
|
|
19017
|
+
if (performance.now() - sliceStart > 8) {
|
|
19018
|
+
await yieldToEventLoop();
|
|
19019
|
+
sliceStart = performance.now();
|
|
19020
|
+
}
|
|
19021
|
+
}
|
|
18996
19022
|
} finally {
|
|
18997
|
-
const failures = await this.refreshBiomes();
|
|
19023
|
+
const failures = await this.refreshBiomes(true);
|
|
18998
19024
|
if (failures.size) log18.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
18999
19025
|
await this.updateCulling([]);
|
|
19000
19026
|
}
|
|
@@ -19057,7 +19083,7 @@ var MineRenderWorld = class {
|
|
|
19057
19083
|
}
|
|
19058
19084
|
this.sectionModels?.clear();
|
|
19059
19085
|
}
|
|
19060
|
-
updateCulling(positions) {
|
|
19086
|
+
updateCulling(positions, defer = false) {
|
|
19061
19087
|
const neighbor = new import_three45.Vector3();
|
|
19062
19088
|
for (const pos of positions) {
|
|
19063
19089
|
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
@@ -19079,58 +19105,72 @@ var MineRenderWorld = class {
|
|
|
19079
19105
|
}
|
|
19080
19106
|
}
|
|
19081
19107
|
}
|
|
19108
|
+
if (defer) return Promise.resolve();
|
|
19082
19109
|
return this.culling ??= Promise.resolve().then(async () => {
|
|
19083
19110
|
let sliceStart = performance.now();
|
|
19084
19111
|
try {
|
|
19085
19112
|
const culling = await loadBlockCulling();
|
|
19086
19113
|
while (this.pendingCulling.size) {
|
|
19087
|
-
const batch =
|
|
19114
|
+
const batch = new Map(this.pendingCulling);
|
|
19088
19115
|
this.pendingCulling.clear();
|
|
19089
|
-
|
|
19090
|
-
const
|
|
19091
|
-
|
|
19092
|
-
const
|
|
19093
|
-
|
|
19094
|
-
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
const
|
|
19098
|
-
|
|
19099
|
-
|
|
19100
|
-
|
|
19101
|
-
|
|
19102
|
-
|
|
19103
|
-
|
|
19104
|
-
|
|
19105
|
-
|
|
19106
|
-
|
|
19107
|
-
|
|
19108
|
-
|
|
19109
|
-
|
|
19110
|
-
|
|
19111
|
-
|
|
19112
|
-
|
|
19113
|
-
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
|
|
19117
|
-
|
|
19118
|
-
|
|
19119
|
-
|
|
19120
|
-
|
|
19121
|
-
|
|
19122
|
-
|
|
19116
|
+
try {
|
|
19117
|
+
for (const [chunk, indices] of batch) {
|
|
19118
|
+
const neighbors = CUBE_FACE_OFFSETS.map(([x, y, z]) => this._chunks.get(`${chunk.x + x}_${chunk.y + y}_${chunk.z + z}`));
|
|
19119
|
+
const neighborAt = (x, y, z) => {
|
|
19120
|
+
const lx = x - chunk.x * 16, ly = y - chunk.y * 16, lz = z - chunk.z * 16;
|
|
19121
|
+
const section = neighbors[lx >= 16 ? 0 : lx < 0 ? 1 : ly >= 16 ? 2 : ly < 0 ? 3 : lz >= 16 ? 4 : 5];
|
|
19122
|
+
return [section, (ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)];
|
|
19123
|
+
};
|
|
19124
|
+
const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x, y, z) => {
|
|
19125
|
+
const [section, i] = neighborAt(x, y, z);
|
|
19126
|
+
return section?.isOccludingIndex(i) ?? false;
|
|
19127
|
+
}, culling, (x, y, z) => {
|
|
19128
|
+
const [section, i] = neighborAt(x, y, z);
|
|
19129
|
+
return section?.visibleBlockIndex(i);
|
|
19130
|
+
});
|
|
19131
|
+
const fluidIndices = indices === "all" ? function* () {
|
|
19132
|
+
for (let index = 0; index < 4096; index++) yield index;
|
|
19133
|
+
}() : indices;
|
|
19134
|
+
for (const index of fluidIndices) {
|
|
19135
|
+
if (!chunk.fluidByteIndex(index) || !chunk.isBlockVisibleIndex(index)) continue;
|
|
19136
|
+
const lx = index % 16, ly = Math.floor(index / 256), lz = Math.floor(index / 16) % 16;
|
|
19137
|
+
const wx = chunk.x * 16 + lx, wy = chunk.y * 16 + ly, wz = chunk.z * 16 + lz;
|
|
19138
|
+
const block = chunk.getBlockAt(neighbor.set(wx, wy, wz));
|
|
19139
|
+
if (block.object?.fluidKind) {
|
|
19140
|
+
await block.object.updateFluid((x, y, z) => {
|
|
19141
|
+
const nx = lx + x, ny = ly + y, nz = lz + z;
|
|
19142
|
+
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)}`);
|
|
19143
|
+
const neighborIndex = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
19144
|
+
const byte = section?.fluidByteIndex(neighborIndex) ?? 0;
|
|
19145
|
+
return {
|
|
19146
|
+
fluid: fluidKindOf(byte),
|
|
19147
|
+
level: byte & 15,
|
|
19148
|
+
solid: section?.isOccludingIndex(neighborIndex) ?? false
|
|
19149
|
+
};
|
|
19150
|
+
});
|
|
19151
|
+
}
|
|
19152
|
+
}
|
|
19153
|
+
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
19154
|
+
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
19155
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
19156
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
19157
|
+
await yieldToEventLoop();
|
|
19158
|
+
sliceStart = performance.now();
|
|
19123
19159
|
}
|
|
19124
19160
|
}
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
|
|
19161
|
+
const builds = await Promise.allSettled([...batch.keys()].map(async (chunk) => {
|
|
19162
|
+
await chunk.rebuildSectionMesh();
|
|
19163
|
+
batch.delete(chunk);
|
|
19164
|
+
}));
|
|
19165
|
+
const failure = builds.find((result) => result.status === "rejected");
|
|
19166
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
19167
|
+
} catch (error) {
|
|
19168
|
+
for (const [chunk, indices] of batch) {
|
|
19169
|
+
const pending = this.pendingCulling.get(chunk);
|
|
19170
|
+
this.pendingCulling.set(chunk, indices === "all" || pending === "all" ? "all" : /* @__PURE__ */ new Set([...indices, ...pending ?? []]));
|
|
19131
19171
|
}
|
|
19172
|
+
throw error;
|
|
19132
19173
|
}
|
|
19133
|
-
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
19134
19174
|
}
|
|
19135
19175
|
} finally {
|
|
19136
19176
|
this.culling = void 0;
|
|
@@ -19147,7 +19187,7 @@ var MineRenderWorld = class {
|
|
|
19147
19187
|
x,
|
|
19148
19188
|
y,
|
|
19149
19189
|
z,
|
|
19150
|
-
(positions) => this.updateCulling(positions),
|
|
19190
|
+
(positions, defer) => this.updateCulling(positions, defer),
|
|
19151
19191
|
this.sectionModels,
|
|
19152
19192
|
(x2, y2, z2) => {
|
|
19153
19193
|
const cx = Math.floor(x2 / 16), cy = Math.floor(y2 / 16), cz = Math.floor(z2 / 16);
|
|
@@ -19882,11 +19922,14 @@ var Chunk = class _Chunk {
|
|
|
19882
19922
|
this.biomes = copy;
|
|
19883
19923
|
return this.refreshBiomes();
|
|
19884
19924
|
}
|
|
19885
|
-
/**
|
|
19886
|
-
|
|
19887
|
-
|
|
19925
|
+
/**
|
|
19926
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
19927
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
19928
|
+
*/
|
|
19929
|
+
refreshBiomes(columns, deferCulling = false) {
|
|
19930
|
+
return this.changeBlocks(() => this.refreshBiomeBlocks(columns, deferCulling), true);
|
|
19888
19931
|
}
|
|
19889
|
-
async refreshBiomeBlocks(columns) {
|
|
19932
|
+
async refreshBiomeBlocks(columns, deferCulling = false) {
|
|
19890
19933
|
const blend = columns && this.biomeBlend?.();
|
|
19891
19934
|
const ownColumn = columns?.some((column) => column.x === this.x && column.z === this.z);
|
|
19892
19935
|
const affected = /* @__PURE__ */ new Map();
|
|
@@ -19943,7 +19986,7 @@ var Chunk = class _Chunk {
|
|
|
19943
19986
|
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
19944
19987
|
}
|
|
19945
19988
|
const positions = blocks.map(({ index }) => new import_three47.Vector3(...this.positionAt(index)));
|
|
19946
|
-
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
19989
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions, deferCulling);
|
|
19947
19990
|
else await this.rebuildSectionMesh();
|
|
19948
19991
|
}
|
|
19949
19992
|
}
|
|
@@ -20597,19 +20640,12 @@ var WorldStreamer = class {
|
|
|
20597
20640
|
this.loading?.controller.abort();
|
|
20598
20641
|
return this.disposal ??= Promise.resolve().then(async () => {
|
|
20599
20642
|
await this.running?.catch(() => void 0);
|
|
20600
|
-
|
|
20601
|
-
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20605
|
-
} catch (error) {
|
|
20606
|
-
failed = true;
|
|
20607
|
-
failure ??= error;
|
|
20608
|
-
}
|
|
20643
|
+
try {
|
|
20644
|
+
await this.unloadMany([...this.owned.values()]);
|
|
20645
|
+
} finally {
|
|
20646
|
+
this.missing.clear();
|
|
20647
|
+
this.failed.clear();
|
|
20609
20648
|
}
|
|
20610
|
-
this.missing.clear();
|
|
20611
|
-
this.failed.clear();
|
|
20612
|
-
if (failed) throw failure;
|
|
20613
20649
|
}).catch((error) => {
|
|
20614
20650
|
this.disposal = void 0;
|
|
20615
20651
|
throw error;
|
|
@@ -20624,9 +20660,9 @@ var WorldStreamer = class {
|
|
|
20624
20660
|
for (const [key, position2] of this.failed) {
|
|
20625
20661
|
if (!this.within(position2, this.unloadRadius)) this.failed.delete(key);
|
|
20626
20662
|
}
|
|
20627
|
-
const obsolete = [...this.owned.values()].
|
|
20628
|
-
if (obsolete) {
|
|
20629
|
-
await this.
|
|
20663
|
+
const obsolete = [...this.owned.values()].filter((position2) => !this.loaded.has(this.key(position2)) || !this.within(position2, this.unloadRadius));
|
|
20664
|
+
if (obsolete.length) {
|
|
20665
|
+
await this.unloadMany(obsolete);
|
|
20630
20666
|
continue;
|
|
20631
20667
|
}
|
|
20632
20668
|
const position = this.desired.find((position2) => this.needsLoad(position2));
|
|
@@ -20656,7 +20692,7 @@ var WorldStreamer = class {
|
|
|
20656
20692
|
this.loaded.set(this.key(position), position);
|
|
20657
20693
|
} catch (error) {
|
|
20658
20694
|
try {
|
|
20659
|
-
await this.
|
|
20695
|
+
await this.unloadMany([position]);
|
|
20660
20696
|
} catch (cleanupError) {
|
|
20661
20697
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
20662
20698
|
try {
|
|
@@ -20677,10 +20713,18 @@ var WorldStreamer = class {
|
|
|
20677
20713
|
const key = this.key(position);
|
|
20678
20714
|
return !this.loaded.has(key) && !this.missing.has(key) && !this.failed.has(key);
|
|
20679
20715
|
}
|
|
20680
|
-
async
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20716
|
+
async unloadMany(positions) {
|
|
20717
|
+
if (!positions.length) return;
|
|
20718
|
+
try {
|
|
20719
|
+
await this.world.unloadChunkColumns(positions.map(({ x, z }) => ({ x, z })));
|
|
20720
|
+
} catch (error) {
|
|
20721
|
+
for (const position of positions) this.loaded.delete(this.key(position));
|
|
20722
|
+
throw error;
|
|
20723
|
+
}
|
|
20724
|
+
for (const position of positions) {
|
|
20725
|
+
this.owned.delete(this.key(position));
|
|
20726
|
+
this.loaded.delete(this.key(position));
|
|
20727
|
+
}
|
|
20684
20728
|
}
|
|
20685
20729
|
validateChunk(chunk, position) {
|
|
20686
20730
|
if (chunk.x !== position.x || chunk.z !== position.z) {
|