minerender 2.1.0-alpha.137 → 2.1.0-alpha.139
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 +29 -8
- package/dist/browser/esm/model/multiblock/StructureParser.mjs +7 -4
- package/dist/browser/esm/model/multiblock/StructureParser.mjs.map +1 -1
- 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 +29 -8
- package/dist/browser/index.js +128 -81
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +128 -81
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +29 -8
- package/dist/node/index.d.ts +29 -8
- package/dist/node/index.js +128 -81
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +128 -81
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.d.mts
CHANGED
|
@@ -2493,11 +2493,21 @@ interface Palette {
|
|
|
2493
2493
|
};
|
|
2494
2494
|
}
|
|
2495
2495
|
interface PaletteEntry {
|
|
2496
|
-
Name
|
|
2496
|
+
Name?: {
|
|
2497
2497
|
type: "string";
|
|
2498
2498
|
value: string;
|
|
2499
2499
|
};
|
|
2500
|
-
|
|
2500
|
+
id?: {
|
|
2501
|
+
type: "string";
|
|
2502
|
+
value: string;
|
|
2503
|
+
};
|
|
2504
|
+
Properties?: {
|
|
2505
|
+
type: "compound";
|
|
2506
|
+
value: {
|
|
2507
|
+
[property: string]: PalettePropertyValue;
|
|
2508
|
+
};
|
|
2509
|
+
};
|
|
2510
|
+
properties?: {
|
|
2501
2511
|
type: "compound";
|
|
2502
2512
|
value: {
|
|
2503
2513
|
[property: string]: PalettePropertyValue;
|
|
@@ -4068,7 +4078,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4068
4078
|
private ambientOcclusionCells?;
|
|
4069
4079
|
private readonly blockChanges;
|
|
4070
4080
|
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);
|
|
4081
|
+
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
4082
|
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
4073
4083
|
static raycast<SectionMeshing extends boolean>(chunks: Iterable<Chunk<SectionMeshing>>, raycaster: Raycaster): WorldBlockIntersection | undefined;
|
|
4074
4084
|
getBlockAt(x: number, y: number, z: number): Maybe<BlockInfo<SectionMeshing>>;
|
|
@@ -4080,11 +4090,14 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4080
4090
|
getBiomeAt(pos: TripleArray): Maybe<string>;
|
|
4081
4091
|
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
4082
4092
|
setBiomes(biomes?: readonly string[]): Promise<void>;
|
|
4083
|
-
/**
|
|
4093
|
+
/**
|
|
4094
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
4095
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
4096
|
+
*/
|
|
4084
4097
|
refreshBiomes(columns?: readonly {
|
|
4085
4098
|
x: number;
|
|
4086
4099
|
z: number;
|
|
4087
|
-
}[]): Promise<void>;
|
|
4100
|
+
}[], deferCulling?: boolean): Promise<void>;
|
|
4088
4101
|
private refreshBiomeBlocks;
|
|
4089
4102
|
/**
|
|
4090
4103
|
* Places a block at integer world block coordinates. Pass `undefined` to remove it.
|
|
@@ -4095,7 +4108,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4095
4108
|
/**
|
|
4096
4109
|
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
4097
4110
|
*/
|
|
4098
|
-
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[]) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4111
|
+
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[], deferCulling?: boolean) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4099
4112
|
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
4100
4113
|
placeBlocks(blocks: readonly {
|
|
4101
4114
|
index: number;
|
|
@@ -4260,6 +4273,14 @@ declare class MineRenderWorld<SectionMeshing extends boolean = false> {
|
|
|
4260
4273
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
4261
4274
|
*/
|
|
4262
4275
|
unloadChunkColumn(x: number, z: number): Promise<void>;
|
|
4276
|
+
/**
|
|
4277
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
4278
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
4279
|
+
*/
|
|
4280
|
+
unloadChunkColumns(positions: readonly {
|
|
4281
|
+
x: number;
|
|
4282
|
+
z: number;
|
|
4283
|
+
}[]): Promise<void>;
|
|
4263
4284
|
private clearChunkColumn;
|
|
4264
4285
|
private markSectionChanged;
|
|
4265
4286
|
/** Removes all chunks and releases their blocks, section meshes, and owned entities. */
|
|
@@ -4337,7 +4358,7 @@ declare class WorldStreamer {
|
|
|
4337
4358
|
private running?;
|
|
4338
4359
|
private disposal?;
|
|
4339
4360
|
private disposed;
|
|
4340
|
-
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "
|
|
4361
|
+
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "unloadChunkColumns">, source: WorldChunkSource, options?: WorldStreamerOptions);
|
|
4341
4362
|
/** Returns absolute coordinates of successfully placed columns, including retained columns. */
|
|
4342
4363
|
get loadedChunks(): readonly {
|
|
4343
4364
|
x: number;
|
|
@@ -4371,7 +4392,7 @@ declare class WorldStreamer {
|
|
|
4371
4392
|
dispose(): Promise<void>;
|
|
4372
4393
|
private drain;
|
|
4373
4394
|
private needsLoad;
|
|
4374
|
-
private
|
|
4395
|
+
private unloadMany;
|
|
4375
4396
|
private validateChunk;
|
|
4376
4397
|
private within;
|
|
4377
4398
|
private key;
|
package/dist/node/index.d.ts
CHANGED
|
@@ -2493,11 +2493,21 @@ interface Palette {
|
|
|
2493
2493
|
};
|
|
2494
2494
|
}
|
|
2495
2495
|
interface PaletteEntry {
|
|
2496
|
-
Name
|
|
2496
|
+
Name?: {
|
|
2497
2497
|
type: "string";
|
|
2498
2498
|
value: string;
|
|
2499
2499
|
};
|
|
2500
|
-
|
|
2500
|
+
id?: {
|
|
2501
|
+
type: "string";
|
|
2502
|
+
value: string;
|
|
2503
|
+
};
|
|
2504
|
+
Properties?: {
|
|
2505
|
+
type: "compound";
|
|
2506
|
+
value: {
|
|
2507
|
+
[property: string]: PalettePropertyValue;
|
|
2508
|
+
};
|
|
2509
|
+
};
|
|
2510
|
+
properties?: {
|
|
2501
2511
|
type: "compound";
|
|
2502
2512
|
value: {
|
|
2503
2513
|
[property: string]: PalettePropertyValue;
|
|
@@ -4068,7 +4078,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4068
4078
|
private ambientOcclusionCells?;
|
|
4069
4079
|
private readonly blockChanges;
|
|
4070
4080
|
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);
|
|
4081
|
+
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
4082
|
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
4073
4083
|
static raycast<SectionMeshing extends boolean>(chunks: Iterable<Chunk<SectionMeshing>>, raycaster: Raycaster): WorldBlockIntersection | undefined;
|
|
4074
4084
|
getBlockAt(x: number, y: number, z: number): Maybe<BlockInfo<SectionMeshing>>;
|
|
@@ -4080,11 +4090,14 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4080
4090
|
getBiomeAt(pos: TripleArray): Maybe<string>;
|
|
4081
4091
|
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
4082
4092
|
setBiomes(biomes?: readonly string[]): Promise<void>;
|
|
4083
|
-
/**
|
|
4093
|
+
/**
|
|
4094
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
4095
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
4096
|
+
*/
|
|
4084
4097
|
refreshBiomes(columns?: readonly {
|
|
4085
4098
|
x: number;
|
|
4086
4099
|
z: number;
|
|
4087
|
-
}[]): Promise<void>;
|
|
4100
|
+
}[], deferCulling?: boolean): Promise<void>;
|
|
4088
4101
|
private refreshBiomeBlocks;
|
|
4089
4102
|
/**
|
|
4090
4103
|
* Places a block at integer world block coordinates. Pass `undefined` to remove it.
|
|
@@ -4095,7 +4108,7 @@ declare class Chunk<SectionMeshing extends boolean = false> {
|
|
|
4095
4108
|
/**
|
|
4096
4109
|
* Places a block at integer chunk-local coordinates from 0 to 15.
|
|
4097
4110
|
*/
|
|
4098
|
-
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[]) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4111
|
+
setBlockInChunkAt(pos: Vector3, block?: Block, worldPos?: Vector3, onBlocksChanged?: ((positions: Vector3[], deferCulling?: boolean) => Promise<void>) | undefined): Promise<Maybe<BlockInfo<SectionMeshing>>>;
|
|
4099
4112
|
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
4100
4113
|
placeBlocks(blocks: readonly {
|
|
4101
4114
|
index: number;
|
|
@@ -4260,6 +4273,14 @@ declare class MineRenderWorld<SectionMeshing extends boolean = false> {
|
|
|
4260
4273
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
4261
4274
|
*/
|
|
4262
4275
|
unloadChunkColumn(x: number, z: number): Promise<void>;
|
|
4276
|
+
/**
|
|
4277
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
4278
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
4279
|
+
*/
|
|
4280
|
+
unloadChunkColumns(positions: readonly {
|
|
4281
|
+
x: number;
|
|
4282
|
+
z: number;
|
|
4283
|
+
}[]): Promise<void>;
|
|
4263
4284
|
private clearChunkColumn;
|
|
4264
4285
|
private markSectionChanged;
|
|
4265
4286
|
/** Removes all chunks and releases their blocks, section meshes, and owned entities. */
|
|
@@ -4337,7 +4358,7 @@ declare class WorldStreamer {
|
|
|
4337
4358
|
private running?;
|
|
4338
4359
|
private disposal?;
|
|
4339
4360
|
private disposed;
|
|
4340
|
-
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "
|
|
4361
|
+
constructor(world: Pick<MineRenderWorld<boolean>, "placeChunk" | "unloadChunkColumns">, source: WorldChunkSource, options?: WorldStreamerOptions);
|
|
4341
4362
|
/** Returns absolute coordinates of successfully placed columns, including retained columns. */
|
|
4342
4363
|
get loadedChunks(): readonly {
|
|
4343
4364
|
x: number;
|
|
@@ -4371,7 +4392,7 @@ declare class WorldStreamer {
|
|
|
4371
4392
|
dispose(): Promise<void>;
|
|
4372
4393
|
private drain;
|
|
4373
4394
|
private needsLoad;
|
|
4374
|
-
private
|
|
4395
|
+
private unloadMany;
|
|
4375
4396
|
private validateChunk;
|
|
4376
4397
|
private within;
|
|
4377
4398
|
private key;
|
package/dist/node/index.js
CHANGED
|
@@ -13974,13 +13974,16 @@ var StructureParser = class {
|
|
|
13974
13974
|
const blocks = nbt.blocks.value.value.map((block) => {
|
|
13975
13975
|
const state = palette.value.value[block.state.value];
|
|
13976
13976
|
if (!state) throw new MineRenderError(`Structure palette index ${block.state.value} does not exist`);
|
|
13977
|
-
|
|
13977
|
+
const name = (state.Name ?? state.id)?.value;
|
|
13978
|
+
if (!name) throw new MineRenderError(`Structure palette entry ${block.state.value} has no block name`);
|
|
13979
|
+
if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(name)) return void 0;
|
|
13978
13980
|
const props = {};
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
+
const properties = (state.Properties ?? state.properties)?.value;
|
|
13982
|
+
for (let k in properties) {
|
|
13983
|
+
props[k] = properties[k].value;
|
|
13981
13984
|
}
|
|
13982
13985
|
return {
|
|
13983
|
-
type:
|
|
13986
|
+
type: name,
|
|
13984
13987
|
properties: props,
|
|
13985
13988
|
position: block.pos.value.value,
|
|
13986
13989
|
nbt: block.nbt
|
|
@@ -18711,8 +18714,14 @@ var MineRenderWorld = class {
|
|
|
18711
18714
|
}
|
|
18712
18715
|
return queued;
|
|
18713
18716
|
}
|
|
18714
|
-
async refreshBiomes() {
|
|
18715
|
-
if (this.biomeRefreshing)
|
|
18717
|
+
async refreshBiomes(deferCulling = false) {
|
|
18718
|
+
if (this.biomeRefreshing) {
|
|
18719
|
+
await this.biomeRefreshing;
|
|
18720
|
+
if (!deferCulling) {
|
|
18721
|
+
if (this.pendingCulling.size) await this.updateCulling([]);
|
|
18722
|
+
else await this.culling;
|
|
18723
|
+
}
|
|
18724
|
+
}
|
|
18716
18725
|
if (!this.pendingBiomes.size) return /* @__PURE__ */ new Map();
|
|
18717
18726
|
return this.biomeRefreshing ??= Promise.resolve().then(async () => {
|
|
18718
18727
|
const failures = /* @__PURE__ */ new Map();
|
|
@@ -18724,7 +18733,7 @@ var MineRenderWorld = class {
|
|
|
18724
18733
|
this.pendingBiomes.delete(chunk);
|
|
18725
18734
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) !== chunk) continue;
|
|
18726
18735
|
try {
|
|
18727
|
-
await chunk.refreshBiomes(columns);
|
|
18736
|
+
await chunk.refreshBiomes(columns, deferCulling);
|
|
18728
18737
|
} catch (error) {
|
|
18729
18738
|
failures.set(chunk, error);
|
|
18730
18739
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
|
|
@@ -18986,15 +18995,35 @@ var MineRenderWorld = class {
|
|
|
18986
18995
|
* Coordinates match AnvilChunk.x/z, not block positions. Missing columns are ignored.
|
|
18987
18996
|
*/
|
|
18988
18997
|
async unloadChunkColumn(x, z) {
|
|
18989
|
-
|
|
18990
|
-
|
|
18998
|
+
return this.unloadChunkColumns([{ x, z }]);
|
|
18999
|
+
}
|
|
19000
|
+
/**
|
|
19001
|
+
* Removes chunk columns together and refreshes surviving neighbors once.
|
|
19002
|
+
* Coordinates are absolute chunk columns. Duplicate and missing columns are ignored.
|
|
19003
|
+
*/
|
|
19004
|
+
async unloadChunkColumns(positions) {
|
|
19005
|
+
const columns = /* @__PURE__ */ new Map();
|
|
19006
|
+
for (const position of positions) {
|
|
19007
|
+
const { x, z } = position ?? {};
|
|
19008
|
+
if (!Number.isInteger(x) || !Number.isInteger(z)) {
|
|
19009
|
+
throw new RangeError("Chunk column coordinates must be integers");
|
|
19010
|
+
}
|
|
19011
|
+
columns.set(`${x}_${z}`, { x, z });
|
|
18991
19012
|
}
|
|
18992
|
-
|
|
19013
|
+
if (!columns.size) return;
|
|
18993
19014
|
await this.culling;
|
|
19015
|
+
let sliceStart = performance.now();
|
|
18994
19016
|
try {
|
|
18995
|
-
|
|
19017
|
+
for (const { x, z } of columns.values()) {
|
|
19018
|
+
this.entities?.clearColumn(x, z);
|
|
19019
|
+
await this.clearChunkColumn(x, z);
|
|
19020
|
+
if (performance.now() - sliceStart > 8) {
|
|
19021
|
+
await yieldToEventLoop();
|
|
19022
|
+
sliceStart = performance.now();
|
|
19023
|
+
}
|
|
19024
|
+
}
|
|
18996
19025
|
} finally {
|
|
18997
|
-
const failures = await this.refreshBiomes();
|
|
19026
|
+
const failures = await this.refreshBiomes(true);
|
|
18998
19027
|
if (failures.size) log18.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
18999
19028
|
await this.updateCulling([]);
|
|
19000
19029
|
}
|
|
@@ -19057,7 +19086,7 @@ var MineRenderWorld = class {
|
|
|
19057
19086
|
}
|
|
19058
19087
|
this.sectionModels?.clear();
|
|
19059
19088
|
}
|
|
19060
|
-
updateCulling(positions) {
|
|
19089
|
+
updateCulling(positions, defer = false) {
|
|
19061
19090
|
const neighbor = new import_three45.Vector3();
|
|
19062
19091
|
for (const pos of positions) {
|
|
19063
19092
|
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
@@ -19079,58 +19108,72 @@ var MineRenderWorld = class {
|
|
|
19079
19108
|
}
|
|
19080
19109
|
}
|
|
19081
19110
|
}
|
|
19111
|
+
if (defer) return Promise.resolve();
|
|
19082
19112
|
return this.culling ??= Promise.resolve().then(async () => {
|
|
19083
19113
|
let sliceStart = performance.now();
|
|
19084
19114
|
try {
|
|
19085
19115
|
const culling = await loadBlockCulling();
|
|
19086
19116
|
while (this.pendingCulling.size) {
|
|
19087
|
-
const batch =
|
|
19117
|
+
const batch = new Map(this.pendingCulling);
|
|
19088
19118
|
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
|
-
|
|
19119
|
+
try {
|
|
19120
|
+
for (const [chunk, indices] of batch) {
|
|
19121
|
+
const neighbors = CUBE_FACE_OFFSETS.map(([x, y, z]) => this._chunks.get(`${chunk.x + x}_${chunk.y + y}_${chunk.z + z}`));
|
|
19122
|
+
const neighborAt = (x, y, z) => {
|
|
19123
|
+
const lx = x - chunk.x * 16, ly = y - chunk.y * 16, lz = z - chunk.z * 16;
|
|
19124
|
+
const section = neighbors[lx >= 16 ? 0 : lx < 0 ? 1 : ly >= 16 ? 2 : ly < 0 ? 3 : lz >= 16 ? 4 : 5];
|
|
19125
|
+
return [section, (ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)];
|
|
19126
|
+
};
|
|
19127
|
+
const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x, y, z) => {
|
|
19128
|
+
const [section, i] = neighborAt(x, y, z);
|
|
19129
|
+
return section?.isOccludingIndex(i) ?? false;
|
|
19130
|
+
}, culling, (x, y, z) => {
|
|
19131
|
+
const [section, i] = neighborAt(x, y, z);
|
|
19132
|
+
return section?.visibleBlockIndex(i);
|
|
19133
|
+
});
|
|
19134
|
+
const fluidIndices = indices === "all" ? function* () {
|
|
19135
|
+
for (let index = 0; index < 4096; index++) yield index;
|
|
19136
|
+
}() : indices;
|
|
19137
|
+
for (const index of fluidIndices) {
|
|
19138
|
+
if (!chunk.fluidByteIndex(index) || !chunk.isBlockVisibleIndex(index)) continue;
|
|
19139
|
+
const lx = index % 16, ly = Math.floor(index / 256), lz = Math.floor(index / 16) % 16;
|
|
19140
|
+
const wx = chunk.x * 16 + lx, wy = chunk.y * 16 + ly, wz = chunk.z * 16 + lz;
|
|
19141
|
+
const block = chunk.getBlockAt(neighbor.set(wx, wy, wz));
|
|
19142
|
+
if (block.object?.fluidKind) {
|
|
19143
|
+
await block.object.updateFluid((x, y, z) => {
|
|
19144
|
+
const nx = lx + x, ny = ly + y, nz = lz + z;
|
|
19145
|
+
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)}`);
|
|
19146
|
+
const neighborIndex = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
19147
|
+
const byte = section?.fluidByteIndex(neighborIndex) ?? 0;
|
|
19148
|
+
return {
|
|
19149
|
+
fluid: fluidKindOf(byte),
|
|
19150
|
+
level: byte & 15,
|
|
19151
|
+
solid: section?.isOccludingIndex(neighborIndex) ?? false
|
|
19152
|
+
};
|
|
19153
|
+
});
|
|
19154
|
+
}
|
|
19155
|
+
}
|
|
19156
|
+
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
19157
|
+
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
19158
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
19159
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
19160
|
+
await yieldToEventLoop();
|
|
19161
|
+
sliceStart = performance.now();
|
|
19123
19162
|
}
|
|
19124
19163
|
}
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
|
|
19164
|
+
const builds = await Promise.allSettled([...batch.keys()].map(async (chunk) => {
|
|
19165
|
+
await chunk.rebuildSectionMesh();
|
|
19166
|
+
batch.delete(chunk);
|
|
19167
|
+
}));
|
|
19168
|
+
const failure = builds.find((result) => result.status === "rejected");
|
|
19169
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
19170
|
+
} catch (error) {
|
|
19171
|
+
for (const [chunk, indices] of batch) {
|
|
19172
|
+
const pending = this.pendingCulling.get(chunk);
|
|
19173
|
+
this.pendingCulling.set(chunk, indices === "all" || pending === "all" ? "all" : /* @__PURE__ */ new Set([...indices, ...pending ?? []]));
|
|
19131
19174
|
}
|
|
19175
|
+
throw error;
|
|
19132
19176
|
}
|
|
19133
|
-
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
19134
19177
|
}
|
|
19135
19178
|
} finally {
|
|
19136
19179
|
this.culling = void 0;
|
|
@@ -19147,7 +19190,7 @@ var MineRenderWorld = class {
|
|
|
19147
19190
|
x,
|
|
19148
19191
|
y,
|
|
19149
19192
|
z,
|
|
19150
|
-
(positions) => this.updateCulling(positions),
|
|
19193
|
+
(positions, defer) => this.updateCulling(positions, defer),
|
|
19151
19194
|
this.sectionModels,
|
|
19152
19195
|
(x2, y2, z2) => {
|
|
19153
19196
|
const cx = Math.floor(x2 / 16), cy = Math.floor(y2 / 16), cz = Math.floor(z2 / 16);
|
|
@@ -19882,11 +19925,14 @@ var Chunk = class _Chunk {
|
|
|
19882
19925
|
this.biomes = copy;
|
|
19883
19926
|
return this.refreshBiomes();
|
|
19884
19927
|
}
|
|
19885
|
-
/**
|
|
19886
|
-
|
|
19887
|
-
|
|
19928
|
+
/**
|
|
19929
|
+
* Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects.
|
|
19930
|
+
* The owning world can defer neighbor culling until all affected chunks are refreshed.
|
|
19931
|
+
*/
|
|
19932
|
+
refreshBiomes(columns, deferCulling = false) {
|
|
19933
|
+
return this.changeBlocks(() => this.refreshBiomeBlocks(columns, deferCulling), true);
|
|
19888
19934
|
}
|
|
19889
|
-
async refreshBiomeBlocks(columns) {
|
|
19935
|
+
async refreshBiomeBlocks(columns, deferCulling = false) {
|
|
19890
19936
|
const blend = columns && this.biomeBlend?.();
|
|
19891
19937
|
const ownColumn = columns?.some((column) => column.x === this.x && column.z === this.z);
|
|
19892
19938
|
const affected = /* @__PURE__ */ new Map();
|
|
@@ -19943,7 +19989,7 @@ var Chunk = class _Chunk {
|
|
|
19943
19989
|
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
19944
19990
|
}
|
|
19945
19991
|
const positions = blocks.map(({ index }) => new import_three47.Vector3(...this.positionAt(index)));
|
|
19946
|
-
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
19992
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions, deferCulling);
|
|
19947
19993
|
else await this.rebuildSectionMesh();
|
|
19948
19994
|
}
|
|
19949
19995
|
}
|
|
@@ -20597,19 +20643,12 @@ var WorldStreamer = class {
|
|
|
20597
20643
|
this.loading?.controller.abort();
|
|
20598
20644
|
return this.disposal ??= Promise.resolve().then(async () => {
|
|
20599
20645
|
await this.running?.catch(() => void 0);
|
|
20600
|
-
|
|
20601
|
-
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20605
|
-
} catch (error) {
|
|
20606
|
-
failed = true;
|
|
20607
|
-
failure ??= error;
|
|
20608
|
-
}
|
|
20646
|
+
try {
|
|
20647
|
+
await this.unloadMany([...this.owned.values()]);
|
|
20648
|
+
} finally {
|
|
20649
|
+
this.missing.clear();
|
|
20650
|
+
this.failed.clear();
|
|
20609
20651
|
}
|
|
20610
|
-
this.missing.clear();
|
|
20611
|
-
this.failed.clear();
|
|
20612
|
-
if (failed) throw failure;
|
|
20613
20652
|
}).catch((error) => {
|
|
20614
20653
|
this.disposal = void 0;
|
|
20615
20654
|
throw error;
|
|
@@ -20624,9 +20663,9 @@ var WorldStreamer = class {
|
|
|
20624
20663
|
for (const [key, position2] of this.failed) {
|
|
20625
20664
|
if (!this.within(position2, this.unloadRadius)) this.failed.delete(key);
|
|
20626
20665
|
}
|
|
20627
|
-
const obsolete = [...this.owned.values()].
|
|
20628
|
-
if (obsolete) {
|
|
20629
|
-
await this.
|
|
20666
|
+
const obsolete = [...this.owned.values()].filter((position2) => !this.loaded.has(this.key(position2)) || !this.within(position2, this.unloadRadius));
|
|
20667
|
+
if (obsolete.length) {
|
|
20668
|
+
await this.unloadMany(obsolete);
|
|
20630
20669
|
continue;
|
|
20631
20670
|
}
|
|
20632
20671
|
const position = this.desired.find((position2) => this.needsLoad(position2));
|
|
@@ -20656,7 +20695,7 @@ var WorldStreamer = class {
|
|
|
20656
20695
|
this.loaded.set(this.key(position), position);
|
|
20657
20696
|
} catch (error) {
|
|
20658
20697
|
try {
|
|
20659
|
-
await this.
|
|
20698
|
+
await this.unloadMany([position]);
|
|
20660
20699
|
} catch (cleanupError) {
|
|
20661
20700
|
const failure = error instanceof Error ? error : new Error(String(error));
|
|
20662
20701
|
try {
|
|
@@ -20677,10 +20716,18 @@ var WorldStreamer = class {
|
|
|
20677
20716
|
const key = this.key(position);
|
|
20678
20717
|
return !this.loaded.has(key) && !this.missing.has(key) && !this.failed.has(key);
|
|
20679
20718
|
}
|
|
20680
|
-
async
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20719
|
+
async unloadMany(positions) {
|
|
20720
|
+
if (!positions.length) return;
|
|
20721
|
+
try {
|
|
20722
|
+
await this.world.unloadChunkColumns(positions.map(({ x, z }) => ({ x, z })));
|
|
20723
|
+
} catch (error) {
|
|
20724
|
+
for (const position of positions) this.loaded.delete(this.key(position));
|
|
20725
|
+
throw error;
|
|
20726
|
+
}
|
|
20727
|
+
for (const position of positions) {
|
|
20728
|
+
this.owned.delete(this.key(position));
|
|
20729
|
+
this.loaded.delete(this.key(position));
|
|
20730
|
+
}
|
|
20684
20731
|
}
|
|
20685
20732
|
validateChunk(chunk, position) {
|
|
20686
20733
|
if (chunk.x !== position.x || chunk.z !== position.z) {
|