minerender 2.1.0-alpha.128 → 2.1.0-alpha.129
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 +52 -4
- package/dist/browser/index.d.ts +52 -4
- package/dist/browser/index.js +339 -24
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +339 -24
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/section.worker.js +7 -5
- package/dist/browser/section.worker.js.map +1 -1
- package/dist/browser/section.worker.mjs +7 -5
- package/dist/browser/section.worker.mjs.map +1 -1
- package/dist/bundle.js +342 -24
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +52 -4
- package/dist/node/index.d.ts +52 -4
- package/dist/node/index.js +341 -24
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +341 -24
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -252,6 +252,13 @@ var init_Caching = __esm({
|
|
|
252
252
|
import_loading_cache = require("@inventivetalent/loading-cache");
|
|
253
253
|
import_time = require("@inventivetalent/time");
|
|
254
254
|
Caching = class _Caching {
|
|
255
|
+
static {
|
|
256
|
+
this._generation = 0;
|
|
257
|
+
}
|
|
258
|
+
/** Changes when shared assets are cleared, so derived caches can discard their old values. */
|
|
259
|
+
static get generation() {
|
|
260
|
+
return this._generation;
|
|
261
|
+
}
|
|
255
262
|
static {
|
|
256
263
|
this.rawImageCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(10)).expireAfterAccess(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(5)).buildAsync();
|
|
257
264
|
}
|
|
@@ -362,6 +369,7 @@ var init_Caching = __esm({
|
|
|
362
369
|
}
|
|
363
370
|
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
364
371
|
static clear() {
|
|
372
|
+
this._generation++;
|
|
365
373
|
for (const cache of this.all) {
|
|
366
374
|
cache.invalidateAll();
|
|
367
375
|
}
|
|
@@ -373,6 +381,7 @@ var init_Caching = __esm({
|
|
|
373
381
|
* Use {@link shutdown} to also stop requests and the shared Ticker.
|
|
374
382
|
*/
|
|
375
383
|
static end() {
|
|
384
|
+
this._generation++;
|
|
376
385
|
for (const cache of this.all) {
|
|
377
386
|
cache.invalidateAll();
|
|
378
387
|
cache.end();
|
|
@@ -17544,18 +17553,23 @@ var SectionModels = class {
|
|
|
17544
17553
|
return this.template(variant, choice, tints);
|
|
17545
17554
|
}));
|
|
17546
17555
|
}
|
|
17547
|
-
/** Resolves
|
|
17548
|
-
async prepareState(blockState3, properties = {}, biomeColor) {
|
|
17556
|
+
/** Resolves shared templates; dynamic biome tints are supplied on section placements instead of cached geometry. */
|
|
17557
|
+
async prepareState(blockState3, properties = {}, biomeColor, dynamicBiomeTint = false) {
|
|
17549
17558
|
const prepared = await this.state(blockState3, properties);
|
|
17550
17559
|
if (!prepared) return void 0;
|
|
17551
17560
|
let color2;
|
|
17552
17561
|
const resolveColor = typeof biomeColor === "function" ? () => color2 ??= biomeColor() : biomeColor;
|
|
17553
17562
|
const templates = /* @__PURE__ */ new Map();
|
|
17563
|
+
const source = dynamicBiomeTint && await BlockTints.biomeSource(blockState3.key);
|
|
17554
17564
|
await Promise.all([...prepared.choices].map(async ([variant, choice]) => {
|
|
17555
17565
|
const tints = await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, resolveColor);
|
|
17556
|
-
|
|
17566
|
+
const biomeTints = source ? await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, 16777215) : void 0;
|
|
17567
|
+
templates.set(variant, await this.template(variant, choice, tints, biomeTints));
|
|
17557
17568
|
}));
|
|
17558
|
-
return {
|
|
17569
|
+
return {
|
|
17570
|
+
pick: (position) => prepared.groups.map((group) => templates.get(BlockStateResolver.choose(group, position))),
|
|
17571
|
+
biomeTint: source ? [...templates.values()].some((template) => template.biomeTint?.some((value) => value === 1)) || void 0 : void 0
|
|
17572
|
+
};
|
|
17559
17573
|
}
|
|
17560
17574
|
async state(blockState3, properties) {
|
|
17561
17575
|
let states = this.states.get(blockState3);
|
|
@@ -17598,10 +17612,10 @@ var SectionModels = class {
|
|
|
17598
17612
|
}
|
|
17599
17613
|
return { state, groups, choices: prepared };
|
|
17600
17614
|
}
|
|
17601
|
-
async template(variant, { model, atlas, rotation }, tints) {
|
|
17615
|
+
async template(variant, { model, atlas, rotation }, tints, biomeTints) {
|
|
17602
17616
|
let models = this.models.get(model);
|
|
17603
17617
|
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
17604
|
-
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
17618
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints, biomeTints]);
|
|
17605
17619
|
return cached(models, key, async () => {
|
|
17606
17620
|
const object4 = new SectionModel(model, {
|
|
17607
17621
|
instanceMeshes: false,
|
|
@@ -17615,11 +17629,13 @@ var SectionModels = class {
|
|
|
17615
17629
|
object4.clear();
|
|
17616
17630
|
const keep = [];
|
|
17617
17631
|
const cullFaces = [];
|
|
17632
|
+
const biomeTint = biomeTints ? [] : void 0;
|
|
17618
17633
|
for (const element of atlas.model.elements) {
|
|
17619
17634
|
for (const face of CUBE_FACES) {
|
|
17620
17635
|
const data = element.faces[face];
|
|
17621
17636
|
keep.push(data !== void 0);
|
|
17622
17637
|
if (!data) continue;
|
|
17638
|
+
biomeTint?.push(Number(data.tintindex !== void 0 && biomeTints?.[data.tintindex] !== void 0));
|
|
17623
17639
|
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
17624
17640
|
if (local < 0) {
|
|
17625
17641
|
cullFaces.push(0);
|
|
@@ -17635,6 +17651,7 @@ var SectionModels = class {
|
|
|
17635
17651
|
geometry,
|
|
17636
17652
|
atlas,
|
|
17637
17653
|
cullFaces: new Uint8Array(cullFaces),
|
|
17654
|
+
biomeTint: biomeTint?.some(Boolean) ? new Uint8Array(biomeTint) : void 0,
|
|
17638
17655
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17639
17656
|
layer: atlas.hasTranslucency ? 1 : 0,
|
|
17640
17657
|
ambientOcclusion: model.ambientocclusion !== false
|
|
@@ -17864,6 +17881,132 @@ var WorldEntities = class {
|
|
|
17864
17881
|
// src/world/MineRenderWorld.ts
|
|
17865
17882
|
init_FluidQuads();
|
|
17866
17883
|
|
|
17884
|
+
// src/world/_biomes/BiomeBlend.ts
|
|
17885
|
+
init_AssetKey();
|
|
17886
|
+
init_AssetLoader();
|
|
17887
|
+
init_Caching();
|
|
17888
|
+
var MAX_TILES = 256;
|
|
17889
|
+
function validateBiomeBlendRadius(radius) {
|
|
17890
|
+
if (!Number.isInteger(radius) || radius < 0 || radius > 7) {
|
|
17891
|
+
throw new RangeError("biomeBlendRadius must be an integer from 0 to 7");
|
|
17892
|
+
}
|
|
17893
|
+
}
|
|
17894
|
+
var BiomeBlend = class {
|
|
17895
|
+
constructor(biomeAt, radius) {
|
|
17896
|
+
this.biomeAt = biomeAt;
|
|
17897
|
+
this.tiles = /* @__PURE__ */ new Map();
|
|
17898
|
+
this.generation = Caching.generation;
|
|
17899
|
+
validateBiomeBlendRadius(radius);
|
|
17900
|
+
this._radius = radius;
|
|
17901
|
+
}
|
|
17902
|
+
get radius() {
|
|
17903
|
+
return this._radius;
|
|
17904
|
+
}
|
|
17905
|
+
clear() {
|
|
17906
|
+
this.tiles.clear();
|
|
17907
|
+
}
|
|
17908
|
+
invalidateColumn(x, z) {
|
|
17909
|
+
for (const [key, tile] of this.tiles) {
|
|
17910
|
+
if (Math.abs(tile.x - x) <= 1 && Math.abs(tile.z - z) <= 1) this.tiles.delete(key);
|
|
17911
|
+
}
|
|
17912
|
+
}
|
|
17913
|
+
async getColor(kind, origin, position) {
|
|
17914
|
+
const [x, y, z] = position;
|
|
17915
|
+
const biome = this.biomeAt(x, y, z);
|
|
17916
|
+
if (biome === void 0) return void 0;
|
|
17917
|
+
if (this.generation !== Caching.generation) {
|
|
17918
|
+
this.clear();
|
|
17919
|
+
this.generation = Caching.generation;
|
|
17920
|
+
}
|
|
17921
|
+
const tileX = Math.floor(x / 16), tileZ = Math.floor(z / 16), quartY = Math.floor(y / 4);
|
|
17922
|
+
const root = origin?.root ?? AssetLoader.ROOT;
|
|
17923
|
+
const key = JSON.stringify([root, AssetLoader.persistentScope, kind, this._radius, tileX, quartY, tileZ]);
|
|
17924
|
+
let tile = this.tiles.get(key);
|
|
17925
|
+
if (tile) {
|
|
17926
|
+
this.tiles.delete(key);
|
|
17927
|
+
this.tiles.set(key, tile);
|
|
17928
|
+
} else {
|
|
17929
|
+
const snapshot = new AssetKey("minecraft", "", void 0, void 0, "assets", ".json", root);
|
|
17930
|
+
const colors = this.buildTile(kind, snapshot, tileX, quartY, tileZ, this._radius).then((result2) => {
|
|
17931
|
+
if (!result2.complete && this.tiles.get(key)?.colors === colors) this.tiles.delete(key);
|
|
17932
|
+
return result2;
|
|
17933
|
+
}, (error) => {
|
|
17934
|
+
if (this.tiles.get(key)?.colors === colors) this.tiles.delete(key);
|
|
17935
|
+
throw error;
|
|
17936
|
+
});
|
|
17937
|
+
tile = { x: tileX, z: tileZ, colors };
|
|
17938
|
+
this.tiles.set(key, tile);
|
|
17939
|
+
if (this.tiles.size > MAX_TILES) this.tiles.delete(this.tiles.keys().next().value);
|
|
17940
|
+
}
|
|
17941
|
+
const result = await tile.colors;
|
|
17942
|
+
if (result.failures.has(biome)) throw result.failures.get(biome);
|
|
17943
|
+
const color2 = result.colors[(z - tileZ * 16) * 16 + x - tileX * 16];
|
|
17944
|
+
return color2 === -1 ? void 0 : color2;
|
|
17945
|
+
}
|
|
17946
|
+
async buildTile(kind, origin, tileX, quartY, tileZ, radius) {
|
|
17947
|
+
const size = 16 + radius * 2, stride = size + 1;
|
|
17948
|
+
const startX = tileX * 16 - radius, startZ = tileZ * 16 - radius;
|
|
17949
|
+
const quartX = Math.floor(startX / 4), quartZ = Math.floor(startZ / 4);
|
|
17950
|
+
const quartSize = Math.floor((startX + size - 1) / 4) - quartX + 1;
|
|
17951
|
+
const ids = new Array(quartSize * quartSize);
|
|
17952
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
17953
|
+
for (let z = 0; z < quartSize; z++) {
|
|
17954
|
+
for (let x = 0; x < quartSize; x++) {
|
|
17955
|
+
const id = this.biomeAt((quartX + x) * 4, quartY * 4, (quartZ + z) * 4);
|
|
17956
|
+
ids[z * quartSize + x] = id;
|
|
17957
|
+
if (id !== void 0 && !biomes.has(id)) {
|
|
17958
|
+
biomes.set(id, (async () => {
|
|
17959
|
+
const swamp = kind === "grass" && (await Biomes.get(id, origin))?.effects.grass_color_modifier === "swamp";
|
|
17960
|
+
return { color: swamp ? void 0 : await Biomes.getColor(id, kind, origin), swamp };
|
|
17961
|
+
})());
|
|
17962
|
+
}
|
|
17963
|
+
}
|
|
17964
|
+
}
|
|
17965
|
+
const failures = /* @__PURE__ */ new Map();
|
|
17966
|
+
const loaded = new Map(await Promise.all([...biomes].map(async ([id, color2]) => {
|
|
17967
|
+
try {
|
|
17968
|
+
return [id, await color2];
|
|
17969
|
+
} catch (error) {
|
|
17970
|
+
failures.set(id, error);
|
|
17971
|
+
return [id, { color: void 0, swamp: false }];
|
|
17972
|
+
}
|
|
17973
|
+
})));
|
|
17974
|
+
const complete = [...loaded.values()].every((value) => value.swamp || value.color !== void 0);
|
|
17975
|
+
const samples = new Int32Array(size * size).fill(-1);
|
|
17976
|
+
const sums = Array.from({ length: 4 }, () => new Uint32Array(stride * stride));
|
|
17977
|
+
for (let z = 0; z < size; z++) {
|
|
17978
|
+
const row = [0, 0, 0, 0];
|
|
17979
|
+
for (let x = 0; x < size; x++) {
|
|
17980
|
+
const id = ids[(Math.floor((startZ + z) / 4) - quartZ) * quartSize + Math.floor((startX + x) / 4) - quartX];
|
|
17981
|
+
const value = id === void 0 ? void 0 : loaded.get(id);
|
|
17982
|
+
const color2 = value?.swamp ? swampGrassColor(startX + x, startZ + z) : value?.color;
|
|
17983
|
+
if (color2 !== void 0) {
|
|
17984
|
+
samples[z * size + x] = color2;
|
|
17985
|
+
row[0] += color2 >> 16 & 255;
|
|
17986
|
+
row[1] += color2 >> 8 & 255;
|
|
17987
|
+
row[2] += color2 & 255;
|
|
17988
|
+
row[3]++;
|
|
17989
|
+
}
|
|
17990
|
+
for (let channel = 0; channel < 4; channel++) {
|
|
17991
|
+
sums[channel][(z + 1) * stride + x + 1] = sums[channel][z * stride + x + 1] + row[channel];
|
|
17992
|
+
}
|
|
17993
|
+
}
|
|
17994
|
+
}
|
|
17995
|
+
const colors = new Int32Array(256).fill(-1), width = radius * 2 + 1;
|
|
17996
|
+
for (let z = 0; z < 16; z++) {
|
|
17997
|
+
for (let x = 0; x < 16; x++) {
|
|
17998
|
+
if (samples[(z + radius) * size + x + radius] === -1) continue;
|
|
17999
|
+
const topLeft = z * stride + x, topRight = topLeft + width;
|
|
18000
|
+
const bottomLeft = (z + width) * stride + x, bottomRight = bottomLeft + width;
|
|
18001
|
+
const sum = (values) => values[bottomRight] - values[bottomLeft] - values[topRight] + values[topLeft];
|
|
18002
|
+
const count = sum(sums[3]);
|
|
18003
|
+
if (count) colors[z * 16 + x] = Math.floor(sum(sums[0]) / count) << 16 | Math.floor(sum(sums[1]) / count) << 8 | Math.floor(sum(sums[2]) / count);
|
|
18004
|
+
}
|
|
18005
|
+
}
|
|
18006
|
+
return { colors, complete, failures };
|
|
18007
|
+
}
|
|
18008
|
+
};
|
|
18009
|
+
|
|
17867
18010
|
// src/world/WorldLight.ts
|
|
17868
18011
|
function copySectionLight(light) {
|
|
17869
18012
|
const copy = {};
|
|
@@ -17927,12 +18070,17 @@ var MineRenderWorld = class {
|
|
|
17927
18070
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
17928
18071
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
17929
18072
|
this.ambientOcclusionPending = false;
|
|
18073
|
+
this.pendingBiomes = /* @__PURE__ */ new Map();
|
|
17930
18074
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
17931
18075
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
17932
18076
|
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17933
18077
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
17934
18078
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
17935
18079
|
}
|
|
18080
|
+
this._biomeBlendRadius = options.biomeBlendRadius ?? 0;
|
|
18081
|
+
validateBiomeBlendRadius(this._biomeBlendRadius);
|
|
18082
|
+
if (this._biomeBlendRadius > 0 && !options.sectionMeshing) throw new TypeError("biomeBlendRadius requires sectionMeshing");
|
|
18083
|
+
if (this._biomeBlendRadius) this.biomeBlend = new BiomeBlend((x, y, z) => this.getBiomeAt(x, y, z), this._biomeBlendRadius);
|
|
17936
18084
|
this.scene = scene;
|
|
17937
18085
|
this.savedLighting = options.savedLighting ?? false;
|
|
17938
18086
|
this.ambientLight = options.ambientLight ?? 0;
|
|
@@ -17973,6 +18121,65 @@ var MineRenderWorld = class {
|
|
|
17973
18121
|
await this.updateCulling([]);
|
|
17974
18122
|
this.ambientOcclusionPending = false;
|
|
17975
18123
|
}
|
|
18124
|
+
/** Horizontal biome-color sampling radius, from 0 to 7 blocks. Zero disables blending. */
|
|
18125
|
+
get biomeBlendRadius() {
|
|
18126
|
+
return this._biomeBlendRadius;
|
|
18127
|
+
}
|
|
18128
|
+
/** Refreshes loaded grass, foliage, and water colors without reloading their source chunks. */
|
|
18129
|
+
async setBiomeBlendRadius(radius) {
|
|
18130
|
+
validateBiomeBlendRadius(radius);
|
|
18131
|
+
if (radius > 0 && !this.sectionModels) throw new TypeError("biomeBlendRadius requires sectionMeshing");
|
|
18132
|
+
if (radius !== this._biomeBlendRadius) {
|
|
18133
|
+
this._biomeBlendRadius = radius;
|
|
18134
|
+
this.biomeBlend?.clear();
|
|
18135
|
+
this.biomeBlend = radius ? new BiomeBlend((x, y, z) => this.getBiomeAt(x, y, z), radius) : void 0;
|
|
18136
|
+
for (const chunk of this._chunks.values()) this.pendingBiomes.set(chunk, void 0);
|
|
18137
|
+
}
|
|
18138
|
+
const failures = await this.refreshBiomes();
|
|
18139
|
+
if (failures.size) throw failures.values().next().value;
|
|
18140
|
+
}
|
|
18141
|
+
markBiomesChanged(x, z, y, includeColumn = true) {
|
|
18142
|
+
const queued = [];
|
|
18143
|
+
if (!this.biomeBlend) return queued;
|
|
18144
|
+
this.biomeBlend.invalidateColumn(x, z);
|
|
18145
|
+
for (const chunk of this._chunks.values()) {
|
|
18146
|
+
if (Math.abs(chunk.x - x) > 1 || Math.abs(chunk.z - z) > 1 || !includeColumn && chunk.x === x && chunk.z === z || y !== void 0 && chunk.y !== y && chunk.y !== y + 1) continue;
|
|
18147
|
+
queued.push(chunk);
|
|
18148
|
+
if (!this.pendingBiomes.has(chunk)) this.pendingBiomes.set(chunk, []);
|
|
18149
|
+
const columns = this.pendingBiomes.get(chunk);
|
|
18150
|
+
if (columns && !columns.some((column) => column.x === x && column.z === z)) columns.push({ x, z });
|
|
18151
|
+
}
|
|
18152
|
+
return queued;
|
|
18153
|
+
}
|
|
18154
|
+
async refreshBiomes() {
|
|
18155
|
+
if (this.biomeRefreshing) await this.biomeRefreshing;
|
|
18156
|
+
if (!this.pendingBiomes.size) return /* @__PURE__ */ new Map();
|
|
18157
|
+
return this.biomeRefreshing ??= Promise.resolve().then(async () => {
|
|
18158
|
+
const failures = /* @__PURE__ */ new Map();
|
|
18159
|
+
const batch = [...this.pendingBiomes.keys()];
|
|
18160
|
+
let sliceStart = performance.now();
|
|
18161
|
+
try {
|
|
18162
|
+
for (const chunk of batch) {
|
|
18163
|
+
const columns = this.pendingBiomes.get(chunk);
|
|
18164
|
+
this.pendingBiomes.delete(chunk);
|
|
18165
|
+
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) !== chunk) continue;
|
|
18166
|
+
try {
|
|
18167
|
+
await chunk.refreshBiomes(columns);
|
|
18168
|
+
} catch (error) {
|
|
18169
|
+
failures.set(chunk, error);
|
|
18170
|
+
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
|
|
18171
|
+
}
|
|
18172
|
+
if (performance.now() - sliceStart > 8) {
|
|
18173
|
+
await yieldToEventLoop();
|
|
18174
|
+
sliceStart = performance.now();
|
|
18175
|
+
}
|
|
18176
|
+
}
|
|
18177
|
+
return failures;
|
|
18178
|
+
} finally {
|
|
18179
|
+
this.biomeRefreshing = void 0;
|
|
18180
|
+
}
|
|
18181
|
+
});
|
|
18182
|
+
}
|
|
17976
18183
|
getBlockAt(posOrX, y, z) {
|
|
17977
18184
|
if (typeof posOrX == "number") {
|
|
17978
18185
|
return this.getBlockAt(new import_three45.Vector3(posOrX, y, z));
|
|
@@ -18208,6 +18415,9 @@ var MineRenderWorld = class {
|
|
|
18208
18415
|
}
|
|
18209
18416
|
await placeEntities?.();
|
|
18210
18417
|
} finally {
|
|
18418
|
+
this.markBiomesChanged(chunk.x, chunk.z, void 0, false);
|
|
18419
|
+
const failures = await this.refreshBiomes();
|
|
18420
|
+
if (failures.size) console.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
18211
18421
|
await this.updateCulling([...changes.values()]);
|
|
18212
18422
|
}
|
|
18213
18423
|
}
|
|
@@ -18224,11 +18434,14 @@ var MineRenderWorld = class {
|
|
|
18224
18434
|
try {
|
|
18225
18435
|
await this.clearChunkColumn(x, z);
|
|
18226
18436
|
} finally {
|
|
18437
|
+
const failures = await this.refreshBiomes();
|
|
18438
|
+
if (failures.size) console.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
18227
18439
|
await this.updateCulling([]);
|
|
18228
18440
|
}
|
|
18229
18441
|
}
|
|
18230
18442
|
async clearChunkColumn(x, z) {
|
|
18231
18443
|
this.biomes.delete(`${x}_${z}`);
|
|
18444
|
+
this.markBiomesChanged(x, z, void 0, false);
|
|
18232
18445
|
if (this.savedLighting) {
|
|
18233
18446
|
for (const y of this.light.get(`${x}_${z}`)?.keys() ?? []) this.markSectionChanged({ x, y, z });
|
|
18234
18447
|
}
|
|
@@ -18239,6 +18452,7 @@ var MineRenderWorld = class {
|
|
|
18239
18452
|
for (const [key, section] of previous) {
|
|
18240
18453
|
this._chunks.delete(key);
|
|
18241
18454
|
this.pendingCulling.delete(section);
|
|
18455
|
+
this.pendingBiomes.delete(section);
|
|
18242
18456
|
await section.clear(false);
|
|
18243
18457
|
this.markSectionChanged(section);
|
|
18244
18458
|
}
|
|
@@ -18273,6 +18487,8 @@ var MineRenderWorld = class {
|
|
|
18273
18487
|
const chunks = [...this._chunks.values()];
|
|
18274
18488
|
this._chunks.clear();
|
|
18275
18489
|
this.biomes.clear();
|
|
18490
|
+
this.biomeBlend?.clear();
|
|
18491
|
+
this.pendingBiomes.clear();
|
|
18276
18492
|
this.light.clear();
|
|
18277
18493
|
this.lightValidity.clear();
|
|
18278
18494
|
this.highestSkySection.clear();
|
|
@@ -18391,8 +18607,14 @@ var MineRenderWorld = class {
|
|
|
18391
18607
|
column?.delete(y);
|
|
18392
18608
|
if (!column?.size) this.biomes.delete(columnKey);
|
|
18393
18609
|
}
|
|
18394
|
-
|
|
18395
|
-
|
|
18610
|
+
if (this.biomeBlend) {
|
|
18611
|
+
const queued = this.markBiomesChanged(x, z, y);
|
|
18612
|
+
const failures = await this.refreshBiomes();
|
|
18613
|
+
for (const chunk2 of queued) if (failures.has(chunk2)) throw failures.get(chunk2);
|
|
18614
|
+
} else {
|
|
18615
|
+
await chunk.refreshBiomes();
|
|
18616
|
+
await this._chunks.get(`${x}_${y + 1}_${z}`)?.refreshBiomes();
|
|
18617
|
+
}
|
|
18396
18618
|
},
|
|
18397
18619
|
this.savedLighting ? (x2, y2, z2) => this.lightLevelAt(x2, y2, z2) : void 0,
|
|
18398
18620
|
async () => {
|
|
@@ -18409,7 +18631,8 @@ var MineRenderWorld = class {
|
|
|
18409
18631
|
await this.updateCulling([]);
|
|
18410
18632
|
}
|
|
18411
18633
|
},
|
|
18412
|
-
this.ambientLight
|
|
18634
|
+
this.ambientLight,
|
|
18635
|
+
() => this.biomeBlend
|
|
18413
18636
|
);
|
|
18414
18637
|
this._chunks.set(key, chunk);
|
|
18415
18638
|
}
|
|
@@ -18528,9 +18751,10 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18528
18751
|
|
|
18529
18752
|
// src/world/SectionGeometry.ts
|
|
18530
18753
|
function buildSectionGeometry(input) {
|
|
18531
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
18754
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
18532
18755
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18533
18756
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18757
|
+
if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
|
|
18534
18758
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
18535
18759
|
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
18536
18760
|
if (light && (light.length !== 5832 || light.some((level) => level > 15 && level !== 255))) {
|
|
@@ -18545,7 +18769,7 @@ function buildSectionGeometry(input) {
|
|
|
18545
18769
|
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18546
18770
|
for (const template of templateData) {
|
|
18547
18771
|
const { quads } = template;
|
|
18548
|
-
if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads) {
|
|
18772
|
+
if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads || template.biomeTint && template.biomeTint.length !== quads) {
|
|
18549
18773
|
throw new RangeError("Section template arrays do not match its quad count");
|
|
18550
18774
|
}
|
|
18551
18775
|
}
|
|
@@ -18655,6 +18879,7 @@ function buildSectionGeometry(input) {
|
|
|
18655
18879
|
blockIndices[indexOffset / 6] = indices[entry];
|
|
18656
18880
|
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
18657
18881
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
18882
|
+
const tint = biomeTints && template.biomeTint?.[quad] && !Number.isNaN(biomeTints[entry * 3]) ? entry * 3 : void 0;
|
|
18658
18883
|
const start = vertex;
|
|
18659
18884
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
18660
18885
|
const source = quad * 4 + corner;
|
|
@@ -18671,9 +18896,9 @@ function buildSectionGeometry(input) {
|
|
|
18671
18896
|
uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
18672
18897
|
uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
18673
18898
|
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
18674
|
-
colors[vertex * 3] = template.colors[source * 3] * factor;
|
|
18675
|
-
colors[vertex * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
18676
|
-
colors[vertex * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
18899
|
+
colors[vertex * 3] = (tint === void 0 ? template.colors[source * 3] : biomeTints[tint]) * factor;
|
|
18900
|
+
colors[vertex * 3 + 1] = (tint === void 0 ? template.colors[source * 3 + 1] : biomeTints[tint + 1]) * factor;
|
|
18901
|
+
colors[vertex * 3 + 2] = (tint === void 0 ? template.colors[source * 3 + 2] : biomeTints[tint + 2]) * factor;
|
|
18677
18902
|
}
|
|
18678
18903
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
18679
18904
|
}
|
|
@@ -18795,7 +19020,11 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
18795
19020
|
...lighting
|
|
18796
19021
|
};
|
|
18797
19022
|
for (let i = 0; i < entries.length; i++) {
|
|
18798
|
-
const { index, template, cullMask } = entries[i];
|
|
19023
|
+
const { index, template, cullMask, biomeTint } = entries[i];
|
|
19024
|
+
if (biomeTint) {
|
|
19025
|
+
input.biomeTints ??= new Float32Array(entries.length * 3).fill(NaN);
|
|
19026
|
+
input.biomeTints.set(biomeTint, i * 3);
|
|
19027
|
+
}
|
|
18799
19028
|
let id = templateIds.get(template);
|
|
18800
19029
|
if (id === void 0) {
|
|
18801
19030
|
let atlas = atlasIds.get(template.atlas);
|
|
@@ -18822,6 +19051,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
18822
19051
|
colors: new Float32Array(quads * 12),
|
|
18823
19052
|
indices: new Uint16Array(quads * 6),
|
|
18824
19053
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
19054
|
+
biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
|
|
18825
19055
|
atlas: 0,
|
|
18826
19056
|
layer: template.layer,
|
|
18827
19057
|
ambientOcclusion: template.ambientOcclusion
|
|
@@ -18966,7 +19196,7 @@ init_CubeFace();
|
|
|
18966
19196
|
init_InstanceReference();
|
|
18967
19197
|
var WATER_TINT2 = new import_three47.Color(4159204).toArray();
|
|
18968
19198
|
var Chunk = class _Chunk {
|
|
18969
|
-
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
19199
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0, biomeBlend) {
|
|
18970
19200
|
this.onBlocksChanged = onBlocksChanged;
|
|
18971
19201
|
this.sectionModels = sectionModels;
|
|
18972
19202
|
this.neighborCell = neighborCell;
|
|
@@ -18975,6 +19205,7 @@ var Chunk = class _Chunk {
|
|
|
18975
19205
|
this.lightAt = lightAt;
|
|
18976
19206
|
this.onLightCleared = onLightCleared;
|
|
18977
19207
|
this.ambientLight = ambientLight;
|
|
19208
|
+
this.biomeBlend = biomeBlend;
|
|
18978
19209
|
this.data = new ChunkData();
|
|
18979
19210
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
18980
19211
|
this.objectBlocks = /* @__PURE__ */ new Set();
|
|
@@ -18984,6 +19215,7 @@ var Chunk = class _Chunk {
|
|
|
18984
19215
|
this.blockPosition = new import_three47.Vector3();
|
|
18985
19216
|
this.meshDirty = false;
|
|
18986
19217
|
this.meshGeneration = 0;
|
|
19218
|
+
this.blockChanges = /* @__PURE__ */ new Set();
|
|
18987
19219
|
this.scene = scene;
|
|
18988
19220
|
this.x = x;
|
|
18989
19221
|
this.y = y;
|
|
@@ -19082,10 +19314,20 @@ var Chunk = class _Chunk {
|
|
|
19082
19314
|
return this.refreshBiomes();
|
|
19083
19315
|
}
|
|
19084
19316
|
/** Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects. */
|
|
19085
|
-
|
|
19317
|
+
refreshBiomes(columns) {
|
|
19318
|
+
return this.changeBlocks(() => this.refreshBiomeBlocks(columns), true);
|
|
19319
|
+
}
|
|
19320
|
+
async refreshBiomeBlocks(columns) {
|
|
19321
|
+
const blend = columns && this.biomeBlend?.();
|
|
19322
|
+
const ownColumn = columns?.some((column) => column.x === this.x && column.z === this.z);
|
|
19086
19323
|
const affected = /* @__PURE__ */ new Map();
|
|
19087
19324
|
const blocks = [];
|
|
19088
19325
|
for (const index of this.renderedBlocks.keys()) {
|
|
19326
|
+
if (blend) {
|
|
19327
|
+
if (this.objectBlocks.has(index) && !ownColumn) continue;
|
|
19328
|
+
const [x, , z] = this.positionAt(index), radius = blend.radius;
|
|
19329
|
+
if (!columns.some((column) => x >= column.x * 16 - radius && x <= column.x * 16 + 15 + radius && z >= column.z * 16 - radius && z <= column.z * 16 + 15 + radius)) continue;
|
|
19330
|
+
}
|
|
19089
19331
|
const block = this.data.get(index);
|
|
19090
19332
|
const stateKey = ChunkData.paletteKey(block);
|
|
19091
19333
|
let matches = affected.get(stateKey);
|
|
@@ -19100,10 +19342,32 @@ var Chunk = class _Chunk {
|
|
|
19100
19342
|
}
|
|
19101
19343
|
if (await matches) blocks.push({ index, block });
|
|
19102
19344
|
}
|
|
19345
|
+
if (blend) {
|
|
19346
|
+
const groups = /* @__PURE__ */ new Map();
|
|
19347
|
+
for (const entry of blocks) {
|
|
19348
|
+
const key = ChunkData.paletteKey(entry.block);
|
|
19349
|
+
let group = groups.get(key);
|
|
19350
|
+
if (!group) groups.set(key, group = []);
|
|
19351
|
+
group.push(entry);
|
|
19352
|
+
}
|
|
19353
|
+
blocks.length = 0;
|
|
19354
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
19355
|
+
for (const group of groups.values()) {
|
|
19356
|
+
const { contexts, fluid } = await this.resolveState(group[0].block, group.map((entry) => entry.index), biomes);
|
|
19357
|
+
for (const entry of group) {
|
|
19358
|
+
const context = contexts.get(entry.index);
|
|
19359
|
+
const current = this.sectionBlocks.get(entry.index)?.[0]?.biomeTint;
|
|
19360
|
+
const tint = context?.tint;
|
|
19361
|
+
const tintChanged = !!current !== !!tint || tint?.some((value, channel) => value !== current?.[channel]);
|
|
19362
|
+
const waterChanged = fluid?.kind === "water" && (context?.waterTint ?? WATER_TINT2).some((value, channel) => Math.fround(value) !== (this.waterTints?.[entry.index * 3 + channel] ?? Math.fround(WATER_TINT2[channel])));
|
|
19363
|
+
if (this.objectBlocks.has(entry.index) || tintChanged || waterChanged) blocks.push(entry);
|
|
19364
|
+
}
|
|
19365
|
+
}
|
|
19366
|
+
}
|
|
19103
19367
|
if (!blocks.length) return;
|
|
19104
19368
|
const hidden = new Set(this.hiddenBlocks);
|
|
19105
19369
|
try {
|
|
19106
|
-
await this.
|
|
19370
|
+
await this.replaceBlocks(blocks, true);
|
|
19107
19371
|
} finally {
|
|
19108
19372
|
for (const index of hidden) {
|
|
19109
19373
|
this.hiddenBlocks.add(index);
|
|
@@ -19143,6 +19407,20 @@ var Chunk = class _Chunk {
|
|
|
19143
19407
|
}
|
|
19144
19408
|
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
19145
19409
|
async placeBlocks(blocks) {
|
|
19410
|
+
return this.changeBlocks(() => this.replaceBlocks(blocks));
|
|
19411
|
+
}
|
|
19412
|
+
changeBlocks(change, refreshBiomes = false) {
|
|
19413
|
+
const before = refreshBiomes ? Promise.allSettled(this.blockChanges) : this.biomeChange;
|
|
19414
|
+
const result = before ? before.catch(() => void 0).then(change) : change();
|
|
19415
|
+
const pending = result.finally(() => {
|
|
19416
|
+
this.blockChanges.delete(pending);
|
|
19417
|
+
if (this.biomeChange === pending) this.biomeChange = void 0;
|
|
19418
|
+
});
|
|
19419
|
+
this.blockChanges.add(pending);
|
|
19420
|
+
if (refreshBiomes) this.biomeChange = pending;
|
|
19421
|
+
return pending;
|
|
19422
|
+
}
|
|
19423
|
+
async replaceBlocks(blocks, preserveDataOnFailure = false) {
|
|
19146
19424
|
const placements = blocks.map(({ index, block }) => ({
|
|
19147
19425
|
index,
|
|
19148
19426
|
key: block && !ChunkData.isAir(block) ? ChunkData.paletteKey(block) : void 0,
|
|
@@ -19162,6 +19440,10 @@ var Chunk = class _Chunk {
|
|
|
19162
19440
|
const biomes = /* @__PURE__ */ new Map();
|
|
19163
19441
|
const settled = await Promise.allSettled([...states.values()].map(({ stored, indices }) => this.resolveState(stored, indices, biomes)));
|
|
19164
19442
|
const resolutions = new Map([...states.keys()].map((key, i) => [key, settled[i]]));
|
|
19443
|
+
if (preserveDataOnFailure) {
|
|
19444
|
+
const rejected = settled.find((result) => result.status === "rejected");
|
|
19445
|
+
if (rejected?.status === "rejected") throw rejected.reason;
|
|
19446
|
+
}
|
|
19165
19447
|
const positions = [];
|
|
19166
19448
|
let failed = false, failure;
|
|
19167
19449
|
for (const { index, key, block } of placements) {
|
|
@@ -19199,7 +19481,7 @@ var Chunk = class _Chunk {
|
|
|
19199
19481
|
}
|
|
19200
19482
|
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
19201
19483
|
if (templates) {
|
|
19202
|
-
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
19484
|
+
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0, biomeTint: context?.tint })));
|
|
19203
19485
|
this.meshDirty = true;
|
|
19204
19486
|
} else {
|
|
19205
19487
|
object4 = await this.scene.addBlock(blockState3, {
|
|
@@ -19218,7 +19500,11 @@ var Chunk = class _Chunk {
|
|
|
19218
19500
|
}, object: object4 });
|
|
19219
19501
|
if (object4) this.objectBlocks.add(index);
|
|
19220
19502
|
} catch (error) {
|
|
19221
|
-
|
|
19503
|
+
if (preserveDataOnFailure && readBlock) {
|
|
19504
|
+
this.renderedBlocks.set(index, { get block() {
|
|
19505
|
+
return readBlock();
|
|
19506
|
+
}, object: void 0 });
|
|
19507
|
+
} else this.data.assign(index, 0);
|
|
19222
19508
|
this.fluidCells[index] = 0;
|
|
19223
19509
|
object4?.removeFromScene();
|
|
19224
19510
|
if (!failed) failure = error;
|
|
@@ -19229,7 +19515,10 @@ var Chunk = class _Chunk {
|
|
|
19229
19515
|
return positions;
|
|
19230
19516
|
}
|
|
19231
19517
|
/** Replaces every cell from parsed section data. The caller refreshes neighbor culling. */
|
|
19232
|
-
|
|
19518
|
+
placeSection(data) {
|
|
19519
|
+
return this.changeBlocks(() => this.replaceSection(data));
|
|
19520
|
+
}
|
|
19521
|
+
async replaceSection(data) {
|
|
19233
19522
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
19234
19523
|
this.sectionBlocks.clear();
|
|
19235
19524
|
this.fluidCells.fill(0);
|
|
@@ -19276,7 +19565,7 @@ var Chunk = class _Chunk {
|
|
|
19276
19565
|
];
|
|
19277
19566
|
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
19278
19567
|
if (templates) {
|
|
19279
|
-
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
19568
|
+
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0, biomeTint: context?.tint })));
|
|
19280
19569
|
this.meshDirty = true;
|
|
19281
19570
|
} else {
|
|
19282
19571
|
perBlocks.push({ index, blockState: blockState3, biome: context?.biome });
|
|
@@ -19360,12 +19649,35 @@ var Chunk = class _Chunk {
|
|
|
19360
19649
|
}
|
|
19361
19650
|
async resolveState(stored, indices, biomes) {
|
|
19362
19651
|
const blockState3 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
19363
|
-
|
|
19652
|
+
let perBlock = !blockState3 || !this.sectionModels || !!(blockState3.key && BlockEntities.entry(await BlockEntities.getIndex(blockState3.key.root), blockState3.key.toNamespacedString()));
|
|
19364
19653
|
const fluid = await getBlockFluidState(blockState3?.key, stored.properties);
|
|
19365
19654
|
const hasBiomes = this.getBiomeAt(this.x * 16, this.y * 16, this.z * 16) !== void 0 || this.biomeAt?.(this.x * 16, this.y * 16 - 1, this.z * 16) !== void 0;
|
|
19366
19655
|
const source = hasBiomes && blockState3 ? await BlockTints.biomeSource(blockState3.key) : void 0;
|
|
19367
19656
|
const prepare = (color2) => perBlock || fluid?.renderModel === false ? void 0 : this.sectionModels.prepareState(blockState3, stored.properties, color2);
|
|
19368
19657
|
const contexts = /* @__PURE__ */ new Map();
|
|
19658
|
+
const blend = this.biomeBlend?.();
|
|
19659
|
+
if (blend && !perBlock && blockState3 && (source || fluid?.kind === "water")) {
|
|
19660
|
+
const prepared2 = fluid?.renderModel === false ? void 0 : await this.sectionModels.prepareState(blockState3, stored.properties, void 0, true);
|
|
19661
|
+
if (!prepared2 && fluid?.renderModel !== false) {
|
|
19662
|
+
perBlock = true;
|
|
19663
|
+
} else {
|
|
19664
|
+
await Promise.all(indices.map(async (index) => {
|
|
19665
|
+
const position = this.biomePosition(index, blockState3, stored);
|
|
19666
|
+
const biomeColor = (kind) => blend.getColor(kind, blockState3.key, position);
|
|
19667
|
+
const context = {};
|
|
19668
|
+
if (source && prepared2?.biomeTint) {
|
|
19669
|
+
const color2 = await biomeColor(source);
|
|
19670
|
+
if (color2 !== void 0) context.tint = new import_three47.Color(color2).toArray();
|
|
19671
|
+
}
|
|
19672
|
+
if (fluid?.kind === "water") {
|
|
19673
|
+
const color2 = await biomeColor("water");
|
|
19674
|
+
if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three47.Color(color2).toArray();
|
|
19675
|
+
}
|
|
19676
|
+
contexts.set(index, context);
|
|
19677
|
+
}));
|
|
19678
|
+
return { blockState: blockState3, perBlock, fluid, prepared: prepared2, contexts, stored };
|
|
19679
|
+
}
|
|
19680
|
+
}
|
|
19369
19681
|
const groups = /* @__PURE__ */ new Map();
|
|
19370
19682
|
if (blockState3 && (source || fluid?.kind === "water")) {
|
|
19371
19683
|
for (const index of indices) {
|
|
@@ -19413,7 +19725,11 @@ var Chunk = class _Chunk {
|
|
|
19413
19725
|
this.waterTints.set(tint ?? WATER_TINT2, index * 3);
|
|
19414
19726
|
}
|
|
19415
19727
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
19416
|
-
|
|
19728
|
+
setBlockVisibleAt(pos, visible) {
|
|
19729
|
+
const position = pos.clone();
|
|
19730
|
+
return this.changeBlocks(() => this.setBlockVisibility(position, visible));
|
|
19731
|
+
}
|
|
19732
|
+
async setBlockVisibility(pos, visible) {
|
|
19417
19733
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
19418
19734
|
const block = this.renderedBlocks.get(index);
|
|
19419
19735
|
if (!block || visible === !this.hiddenBlocks.has(index)) {
|
|
@@ -19583,6 +19899,7 @@ var Chunk = class _Chunk {
|
|
|
19583
19899
|
}
|
|
19584
19900
|
/** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
|
|
19585
19901
|
async clear(notify = true) {
|
|
19902
|
+
if (this.blockChanges.size) await Promise.allSettled(this.blockChanges);
|
|
19586
19903
|
const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
19587
19904
|
new import_three47.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
19588
19905
|
)) : [];
|