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/bundle.js
CHANGED
|
@@ -41476,6 +41476,10 @@ void main() {
|
|
|
41476
41476
|
init_esm2();
|
|
41477
41477
|
init_esm();
|
|
41478
41478
|
_Caching = class _Caching {
|
|
41479
|
+
/** Changes when shared assets are cleared, so derived caches can discard their old values. */
|
|
41480
|
+
static get generation() {
|
|
41481
|
+
return this._generation;
|
|
41482
|
+
}
|
|
41479
41483
|
static createAssetCache() {
|
|
41480
41484
|
return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
|
|
41481
41485
|
}
|
|
@@ -41511,6 +41515,7 @@ void main() {
|
|
|
41511
41515
|
}
|
|
41512
41516
|
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
41513
41517
|
static clear() {
|
|
41518
|
+
this._generation++;
|
|
41514
41519
|
for (const cache of this.all) {
|
|
41515
41520
|
cache.invalidateAll();
|
|
41516
41521
|
}
|
|
@@ -41522,6 +41527,7 @@ void main() {
|
|
|
41522
41527
|
* Use {@link shutdown} to also stop requests and the shared Ticker.
|
|
41523
41528
|
*/
|
|
41524
41529
|
static end() {
|
|
41530
|
+
this._generation++;
|
|
41525
41531
|
for (const cache of this.all) {
|
|
41526
41532
|
cache.invalidateAll();
|
|
41527
41533
|
cache.end();
|
|
@@ -41533,6 +41539,7 @@ void main() {
|
|
|
41533
41539
|
};
|
|
41534
41540
|
}
|
|
41535
41541
|
};
|
|
41542
|
+
_Caching._generation = 0;
|
|
41536
41543
|
_Caching.rawImageCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(5)).buildAsync();
|
|
41537
41544
|
_Caching.imageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
|
|
41538
41545
|
_Caching.canvasImageDataCache = Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(10)).buildAsync();
|
|
@@ -107734,18 +107741,23 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107734
107741
|
return this.template(variant, choice, tints);
|
|
107735
107742
|
}));
|
|
107736
107743
|
}
|
|
107737
|
-
/** Resolves
|
|
107738
|
-
async prepareState(blockState3, properties = {}, biomeColor) {
|
|
107744
|
+
/** Resolves shared templates; dynamic biome tints are supplied on section placements instead of cached geometry. */
|
|
107745
|
+
async prepareState(blockState3, properties = {}, biomeColor, dynamicBiomeTint = false) {
|
|
107739
107746
|
const prepared = await this.state(blockState3, properties);
|
|
107740
107747
|
if (!prepared) return void 0;
|
|
107741
107748
|
let color3;
|
|
107742
107749
|
const resolveColor = typeof biomeColor === "function" ? () => color3 ?? (color3 = biomeColor()) : biomeColor;
|
|
107743
107750
|
const templates = /* @__PURE__ */ new Map();
|
|
107751
|
+
const source = dynamicBiomeTint && await BlockTints.biomeSource(blockState3.key);
|
|
107744
107752
|
await Promise.all([...prepared.choices].map(async ([variant, choice]) => {
|
|
107745
107753
|
const tints = await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, resolveColor);
|
|
107746
|
-
|
|
107754
|
+
const biomeTints = source ? await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, 16777215) : void 0;
|
|
107755
|
+
templates.set(variant, await this.template(variant, choice, tints, biomeTints));
|
|
107747
107756
|
}));
|
|
107748
|
-
return {
|
|
107757
|
+
return {
|
|
107758
|
+
pick: (position) => prepared.groups.map((group) => templates.get(BlockStateResolver.choose(group, position))),
|
|
107759
|
+
biomeTint: source ? [...templates.values()].some((template) => template.biomeTint?.some((value) => value === 1)) || void 0 : void 0
|
|
107760
|
+
};
|
|
107749
107761
|
}
|
|
107750
107762
|
async state(blockState3, properties) {
|
|
107751
107763
|
let states = this.states.get(blockState3);
|
|
@@ -107788,10 +107800,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107788
107800
|
}
|
|
107789
107801
|
return { state, groups, choices: prepared };
|
|
107790
107802
|
}
|
|
107791
|
-
async template(variant, { model, atlas, rotation }, tints) {
|
|
107803
|
+
async template(variant, { model, atlas, rotation }, tints, biomeTints) {
|
|
107792
107804
|
let models = this.models.get(model);
|
|
107793
107805
|
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
107794
|
-
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
107806
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints, biomeTints]);
|
|
107795
107807
|
return cached(models, key, async () => {
|
|
107796
107808
|
const object4 = new SectionModel(model, {
|
|
107797
107809
|
instanceMeshes: false,
|
|
@@ -107805,11 +107817,13 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107805
107817
|
object4.clear();
|
|
107806
107818
|
const keep = [];
|
|
107807
107819
|
const cullFaces = [];
|
|
107820
|
+
const biomeTint = biomeTints ? [] : void 0;
|
|
107808
107821
|
for (const element of atlas.model.elements) {
|
|
107809
107822
|
for (const face of CUBE_FACES) {
|
|
107810
107823
|
const data = element.faces[face];
|
|
107811
107824
|
keep.push(data !== void 0);
|
|
107812
107825
|
if (!data) continue;
|
|
107826
|
+
biomeTint?.push(Number(data.tintindex !== void 0 && biomeTints?.[data.tintindex] !== void 0));
|
|
107813
107827
|
const local = CUBE_FACES.findIndex((name2) => name2 === data.cullface);
|
|
107814
107828
|
if (local < 0) {
|
|
107815
107829
|
cullFaces.push(0);
|
|
@@ -107825,6 +107839,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107825
107839
|
geometry,
|
|
107826
107840
|
atlas,
|
|
107827
107841
|
cullFaces: new Uint8Array(cullFaces),
|
|
107842
|
+
biomeTint: biomeTint?.some(Boolean) ? new Uint8Array(biomeTint) : void 0,
|
|
107828
107843
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
107829
107844
|
layer: atlas.hasTranslucency ? 1 : 0,
|
|
107830
107845
|
ambientOcclusion: model.ambientocclusion !== false
|
|
@@ -108063,6 +108078,135 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108063
108078
|
// src/world/MineRenderWorld.ts
|
|
108064
108079
|
init_FluidQuads();
|
|
108065
108080
|
|
|
108081
|
+
// src/world/_biomes/BiomeBlend.ts
|
|
108082
|
+
init_dirname();
|
|
108083
|
+
init_buffer2();
|
|
108084
|
+
init_process2();
|
|
108085
|
+
init_AssetKey();
|
|
108086
|
+
init_AssetLoader();
|
|
108087
|
+
init_Caching();
|
|
108088
|
+
var MAX_TILES = 256;
|
|
108089
|
+
function validateBiomeBlendRadius(radius) {
|
|
108090
|
+
if (!Number.isInteger(radius) || radius < 0 || radius > 7) {
|
|
108091
|
+
throw new RangeError("biomeBlendRadius must be an integer from 0 to 7");
|
|
108092
|
+
}
|
|
108093
|
+
}
|
|
108094
|
+
var BiomeBlend = class {
|
|
108095
|
+
constructor(biomeAt, radius) {
|
|
108096
|
+
this.biomeAt = biomeAt;
|
|
108097
|
+
this.tiles = /* @__PURE__ */ new Map();
|
|
108098
|
+
this.generation = Caching.generation;
|
|
108099
|
+
validateBiomeBlendRadius(radius);
|
|
108100
|
+
this._radius = radius;
|
|
108101
|
+
}
|
|
108102
|
+
get radius() {
|
|
108103
|
+
return this._radius;
|
|
108104
|
+
}
|
|
108105
|
+
clear() {
|
|
108106
|
+
this.tiles.clear();
|
|
108107
|
+
}
|
|
108108
|
+
invalidateColumn(x4, z4) {
|
|
108109
|
+
for (const [key, tile] of this.tiles) {
|
|
108110
|
+
if (Math.abs(tile.x - x4) <= 1 && Math.abs(tile.z - z4) <= 1) this.tiles.delete(key);
|
|
108111
|
+
}
|
|
108112
|
+
}
|
|
108113
|
+
async getColor(kind, origin, position) {
|
|
108114
|
+
const [x4, y5, z4] = position;
|
|
108115
|
+
const biome = this.biomeAt(x4, y5, z4);
|
|
108116
|
+
if (biome === void 0) return void 0;
|
|
108117
|
+
if (this.generation !== Caching.generation) {
|
|
108118
|
+
this.clear();
|
|
108119
|
+
this.generation = Caching.generation;
|
|
108120
|
+
}
|
|
108121
|
+
const tileX = Math.floor(x4 / 16), tileZ = Math.floor(z4 / 16), quartY = Math.floor(y5 / 4);
|
|
108122
|
+
const root = origin?.root ?? AssetLoader.ROOT;
|
|
108123
|
+
const key = JSON.stringify([root, AssetLoader.persistentScope, kind, this._radius, tileX, quartY, tileZ]);
|
|
108124
|
+
let tile = this.tiles.get(key);
|
|
108125
|
+
if (tile) {
|
|
108126
|
+
this.tiles.delete(key);
|
|
108127
|
+
this.tiles.set(key, tile);
|
|
108128
|
+
} else {
|
|
108129
|
+
const snapshot = new AssetKey("minecraft", "", void 0, void 0, "assets", ".json", root);
|
|
108130
|
+
const colors = this.buildTile(kind, snapshot, tileX, quartY, tileZ, this._radius).then((result2) => {
|
|
108131
|
+
if (!result2.complete && this.tiles.get(key)?.colors === colors) this.tiles.delete(key);
|
|
108132
|
+
return result2;
|
|
108133
|
+
}, (error2) => {
|
|
108134
|
+
if (this.tiles.get(key)?.colors === colors) this.tiles.delete(key);
|
|
108135
|
+
throw error2;
|
|
108136
|
+
});
|
|
108137
|
+
tile = { x: tileX, z: tileZ, colors };
|
|
108138
|
+
this.tiles.set(key, tile);
|
|
108139
|
+
if (this.tiles.size > MAX_TILES) this.tiles.delete(this.tiles.keys().next().value);
|
|
108140
|
+
}
|
|
108141
|
+
const result = await tile.colors;
|
|
108142
|
+
if (result.failures.has(biome)) throw result.failures.get(biome);
|
|
108143
|
+
const color3 = result.colors[(z4 - tileZ * 16) * 16 + x4 - tileX * 16];
|
|
108144
|
+
return color3 === -1 ? void 0 : color3;
|
|
108145
|
+
}
|
|
108146
|
+
async buildTile(kind, origin, tileX, quartY, tileZ, radius) {
|
|
108147
|
+
const size = 16 + radius * 2, stride = size + 1;
|
|
108148
|
+
const startX = tileX * 16 - radius, startZ = tileZ * 16 - radius;
|
|
108149
|
+
const quartX = Math.floor(startX / 4), quartZ = Math.floor(startZ / 4);
|
|
108150
|
+
const quartSize = Math.floor((startX + size - 1) / 4) - quartX + 1;
|
|
108151
|
+
const ids = new Array(quartSize * quartSize);
|
|
108152
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
108153
|
+
for (let z4 = 0; z4 < quartSize; z4++) {
|
|
108154
|
+
for (let x4 = 0; x4 < quartSize; x4++) {
|
|
108155
|
+
const id = this.biomeAt((quartX + x4) * 4, quartY * 4, (quartZ + z4) * 4);
|
|
108156
|
+
ids[z4 * quartSize + x4] = id;
|
|
108157
|
+
if (id !== void 0 && !biomes.has(id)) {
|
|
108158
|
+
biomes.set(id, (async () => {
|
|
108159
|
+
const swamp = kind === "grass" && (await Biomes.get(id, origin))?.effects.grass_color_modifier === "swamp";
|
|
108160
|
+
return { color: swamp ? void 0 : await Biomes.getColor(id, kind, origin), swamp };
|
|
108161
|
+
})());
|
|
108162
|
+
}
|
|
108163
|
+
}
|
|
108164
|
+
}
|
|
108165
|
+
const failures = /* @__PURE__ */ new Map();
|
|
108166
|
+
const loaded = new Map(await Promise.all([...biomes].map(async ([id, color3]) => {
|
|
108167
|
+
try {
|
|
108168
|
+
return [id, await color3];
|
|
108169
|
+
} catch (error2) {
|
|
108170
|
+
failures.set(id, error2);
|
|
108171
|
+
return [id, { color: void 0, swamp: false }];
|
|
108172
|
+
}
|
|
108173
|
+
})));
|
|
108174
|
+
const complete = [...loaded.values()].every((value) => value.swamp || value.color !== void 0);
|
|
108175
|
+
const samples = new Int32Array(size * size).fill(-1);
|
|
108176
|
+
const sums = Array.from({ length: 4 }, () => new Uint32Array(stride * stride));
|
|
108177
|
+
for (let z4 = 0; z4 < size; z4++) {
|
|
108178
|
+
const row = [0, 0, 0, 0];
|
|
108179
|
+
for (let x4 = 0; x4 < size; x4++) {
|
|
108180
|
+
const id = ids[(Math.floor((startZ + z4) / 4) - quartZ) * quartSize + Math.floor((startX + x4) / 4) - quartX];
|
|
108181
|
+
const value = id === void 0 ? void 0 : loaded.get(id);
|
|
108182
|
+
const color3 = value?.swamp ? swampGrassColor(startX + x4, startZ + z4) : value?.color;
|
|
108183
|
+
if (color3 !== void 0) {
|
|
108184
|
+
samples[z4 * size + x4] = color3;
|
|
108185
|
+
row[0] += color3 >> 16 & 255;
|
|
108186
|
+
row[1] += color3 >> 8 & 255;
|
|
108187
|
+
row[2] += color3 & 255;
|
|
108188
|
+
row[3]++;
|
|
108189
|
+
}
|
|
108190
|
+
for (let channel = 0; channel < 4; channel++) {
|
|
108191
|
+
sums[channel][(z4 + 1) * stride + x4 + 1] = sums[channel][z4 * stride + x4 + 1] + row[channel];
|
|
108192
|
+
}
|
|
108193
|
+
}
|
|
108194
|
+
}
|
|
108195
|
+
const colors = new Int32Array(256).fill(-1), width = radius * 2 + 1;
|
|
108196
|
+
for (let z4 = 0; z4 < 16; z4++) {
|
|
108197
|
+
for (let x4 = 0; x4 < 16; x4++) {
|
|
108198
|
+
if (samples[(z4 + radius) * size + x4 + radius] === -1) continue;
|
|
108199
|
+
const topLeft = z4 * stride + x4, topRight = topLeft + width;
|
|
108200
|
+
const bottomLeft = (z4 + width) * stride + x4, bottomRight = bottomLeft + width;
|
|
108201
|
+
const sum = (values) => values[bottomRight] - values[bottomLeft] - values[topRight] + values[topLeft];
|
|
108202
|
+
const count = sum(sums[3]);
|
|
108203
|
+
if (count) colors[z4 * 16 + x4] = Math.floor(sum(sums[0]) / count) << 16 | Math.floor(sum(sums[1]) / count) << 8 | Math.floor(sum(sums[2]) / count);
|
|
108204
|
+
}
|
|
108205
|
+
}
|
|
108206
|
+
return { colors, complete, failures };
|
|
108207
|
+
}
|
|
108208
|
+
};
|
|
108209
|
+
|
|
108066
108210
|
// src/world/WorldLight.ts
|
|
108067
108211
|
init_dirname();
|
|
108068
108212
|
init_buffer2();
|
|
@@ -108132,12 +108276,17 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108132
108276
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
108133
108277
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
108134
108278
|
this.ambientOcclusionPending = false;
|
|
108279
|
+
this.pendingBiomes = /* @__PURE__ */ new Map();
|
|
108135
108280
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
108136
108281
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
108137
108282
|
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
108138
108283
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
108139
108284
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
108140
108285
|
}
|
|
108286
|
+
this._biomeBlendRadius = options.biomeBlendRadius ?? 0;
|
|
108287
|
+
validateBiomeBlendRadius(this._biomeBlendRadius);
|
|
108288
|
+
if (this._biomeBlendRadius > 0 && !options.sectionMeshing) throw new TypeError("biomeBlendRadius requires sectionMeshing");
|
|
108289
|
+
if (this._biomeBlendRadius) this.biomeBlend = new BiomeBlend((x4, y5, z4) => this.getBiomeAt(x4, y5, z4), this._biomeBlendRadius);
|
|
108141
108290
|
this.scene = scene;
|
|
108142
108291
|
this.savedLighting = options.savedLighting ?? false;
|
|
108143
108292
|
this.ambientLight = options.ambientLight ?? 0;
|
|
@@ -108178,6 +108327,65 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108178
108327
|
await this.updateCulling([]);
|
|
108179
108328
|
this.ambientOcclusionPending = false;
|
|
108180
108329
|
}
|
|
108330
|
+
/** Horizontal biome-color sampling radius, from 0 to 7 blocks. Zero disables blending. */
|
|
108331
|
+
get biomeBlendRadius() {
|
|
108332
|
+
return this._biomeBlendRadius;
|
|
108333
|
+
}
|
|
108334
|
+
/** Refreshes loaded grass, foliage, and water colors without reloading their source chunks. */
|
|
108335
|
+
async setBiomeBlendRadius(radius) {
|
|
108336
|
+
validateBiomeBlendRadius(radius);
|
|
108337
|
+
if (radius > 0 && !this.sectionModels) throw new TypeError("biomeBlendRadius requires sectionMeshing");
|
|
108338
|
+
if (radius !== this._biomeBlendRadius) {
|
|
108339
|
+
this._biomeBlendRadius = radius;
|
|
108340
|
+
this.biomeBlend?.clear();
|
|
108341
|
+
this.biomeBlend = radius ? new BiomeBlend((x4, y5, z4) => this.getBiomeAt(x4, y5, z4), radius) : void 0;
|
|
108342
|
+
for (const chunk of this._chunks.values()) this.pendingBiomes.set(chunk, void 0);
|
|
108343
|
+
}
|
|
108344
|
+
const failures = await this.refreshBiomes();
|
|
108345
|
+
if (failures.size) throw failures.values().next().value;
|
|
108346
|
+
}
|
|
108347
|
+
markBiomesChanged(x4, z4, y5, includeColumn = true) {
|
|
108348
|
+
const queued = [];
|
|
108349
|
+
if (!this.biomeBlend) return queued;
|
|
108350
|
+
this.biomeBlend.invalidateColumn(x4, z4);
|
|
108351
|
+
for (const chunk of this._chunks.values()) {
|
|
108352
|
+
if (Math.abs(chunk.x - x4) > 1 || Math.abs(chunk.z - z4) > 1 || !includeColumn && chunk.x === x4 && chunk.z === z4 || y5 !== void 0 && chunk.y !== y5 && chunk.y !== y5 + 1) continue;
|
|
108353
|
+
queued.push(chunk);
|
|
108354
|
+
if (!this.pendingBiomes.has(chunk)) this.pendingBiomes.set(chunk, []);
|
|
108355
|
+
const columns = this.pendingBiomes.get(chunk);
|
|
108356
|
+
if (columns && !columns.some((column) => column.x === x4 && column.z === z4)) columns.push({ x: x4, z: z4 });
|
|
108357
|
+
}
|
|
108358
|
+
return queued;
|
|
108359
|
+
}
|
|
108360
|
+
async refreshBiomes() {
|
|
108361
|
+
if (this.biomeRefreshing) await this.biomeRefreshing;
|
|
108362
|
+
if (!this.pendingBiomes.size) return /* @__PURE__ */ new Map();
|
|
108363
|
+
return this.biomeRefreshing ?? (this.biomeRefreshing = Promise.resolve().then(async () => {
|
|
108364
|
+
const failures = /* @__PURE__ */ new Map();
|
|
108365
|
+
const batch = [...this.pendingBiomes.keys()];
|
|
108366
|
+
let sliceStart = performance.now();
|
|
108367
|
+
try {
|
|
108368
|
+
for (const chunk of batch) {
|
|
108369
|
+
const columns = this.pendingBiomes.get(chunk);
|
|
108370
|
+
this.pendingBiomes.delete(chunk);
|
|
108371
|
+
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) !== chunk) continue;
|
|
108372
|
+
try {
|
|
108373
|
+
await chunk.refreshBiomes(columns);
|
|
108374
|
+
} catch (error2) {
|
|
108375
|
+
failures.set(chunk, error2);
|
|
108376
|
+
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
|
|
108377
|
+
}
|
|
108378
|
+
if (performance.now() - sliceStart > 8) {
|
|
108379
|
+
await yieldToEventLoop();
|
|
108380
|
+
sliceStart = performance.now();
|
|
108381
|
+
}
|
|
108382
|
+
}
|
|
108383
|
+
return failures;
|
|
108384
|
+
} finally {
|
|
108385
|
+
this.biomeRefreshing = void 0;
|
|
108386
|
+
}
|
|
108387
|
+
}));
|
|
108388
|
+
}
|
|
108181
108389
|
getBlockAt(posOrX, y5, z4) {
|
|
108182
108390
|
if (typeof posOrX == "number") {
|
|
108183
108391
|
return this.getBlockAt(new Vector3(posOrX, y5, z4));
|
|
@@ -108413,6 +108621,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108413
108621
|
}
|
|
108414
108622
|
await placeEntities?.();
|
|
108415
108623
|
} finally {
|
|
108624
|
+
this.markBiomesChanged(chunk.x, chunk.z, void 0, false);
|
|
108625
|
+
const failures = await this.refreshBiomes();
|
|
108626
|
+
if (failures.size) console.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
108416
108627
|
await this.updateCulling([...changes.values()]);
|
|
108417
108628
|
}
|
|
108418
108629
|
}
|
|
@@ -108429,11 +108640,14 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108429
108640
|
try {
|
|
108430
108641
|
await this.clearChunkColumn(x4, z4);
|
|
108431
108642
|
} finally {
|
|
108643
|
+
const failures = await this.refreshBiomes();
|
|
108644
|
+
if (failures.size) console.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
108432
108645
|
await this.updateCulling([]);
|
|
108433
108646
|
}
|
|
108434
108647
|
}
|
|
108435
108648
|
async clearChunkColumn(x4, z4) {
|
|
108436
108649
|
this.biomes.delete(`${x4}_${z4}`);
|
|
108650
|
+
this.markBiomesChanged(x4, z4, void 0, false);
|
|
108437
108651
|
if (this.savedLighting) {
|
|
108438
108652
|
for (const y5 of this.light.get(`${x4}_${z4}`)?.keys() ?? []) this.markSectionChanged({ x: x4, y: y5, z: z4 });
|
|
108439
108653
|
}
|
|
@@ -108444,6 +108658,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108444
108658
|
for (const [key, section] of previous) {
|
|
108445
108659
|
this._chunks.delete(key);
|
|
108446
108660
|
this.pendingCulling.delete(section);
|
|
108661
|
+
this.pendingBiomes.delete(section);
|
|
108447
108662
|
await section.clear(false);
|
|
108448
108663
|
this.markSectionChanged(section);
|
|
108449
108664
|
}
|
|
@@ -108478,6 +108693,8 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108478
108693
|
const chunks = [...this._chunks.values()];
|
|
108479
108694
|
this._chunks.clear();
|
|
108480
108695
|
this.biomes.clear();
|
|
108696
|
+
this.biomeBlend?.clear();
|
|
108697
|
+
this.pendingBiomes.clear();
|
|
108481
108698
|
this.light.clear();
|
|
108482
108699
|
this.lightValidity.clear();
|
|
108483
108700
|
this.highestSkySection.clear();
|
|
@@ -108596,8 +108813,14 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108596
108813
|
column?.delete(y5);
|
|
108597
108814
|
if (!column?.size) this.biomes.delete(columnKey);
|
|
108598
108815
|
}
|
|
108599
|
-
|
|
108600
|
-
|
|
108816
|
+
if (this.biomeBlend) {
|
|
108817
|
+
const queued = this.markBiomesChanged(x4, z4, y5);
|
|
108818
|
+
const failures = await this.refreshBiomes();
|
|
108819
|
+
for (const chunk2 of queued) if (failures.has(chunk2)) throw failures.get(chunk2);
|
|
108820
|
+
} else {
|
|
108821
|
+
await chunk.refreshBiomes();
|
|
108822
|
+
await this._chunks.get(`${x4}_${y5 + 1}_${z4}`)?.refreshBiomes();
|
|
108823
|
+
}
|
|
108601
108824
|
},
|
|
108602
108825
|
this.savedLighting ? (x5, y6, z5) => this.lightLevelAt(x5, y6, z5) : void 0,
|
|
108603
108826
|
async () => {
|
|
@@ -108614,7 +108837,8 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108614
108837
|
await this.updateCulling([]);
|
|
108615
108838
|
}
|
|
108616
108839
|
},
|
|
108617
|
-
this.ambientLight
|
|
108840
|
+
this.ambientLight,
|
|
108841
|
+
() => this.biomeBlend
|
|
108618
108842
|
);
|
|
108619
108843
|
this._chunks.set(key, chunk);
|
|
108620
108844
|
}
|
|
@@ -108745,9 +108969,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108745
108969
|
|
|
108746
108970
|
// src/world/SectionGeometry.ts
|
|
108747
108971
|
function buildSectionGeometry(input) {
|
|
108748
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
108972
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion, biomeTints } = input;
|
|
108749
108973
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
108750
108974
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
108975
|
+
if (biomeTints && biomeTints.length !== count * 3) throw new RangeError("Section biome tints must contain RGB for each placement");
|
|
108751
108976
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
108752
108977
|
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
108753
108978
|
if (light && (light.length !== 5832 || light.some((level) => level > 15 && level !== 255))) {
|
|
@@ -108762,7 +108987,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108762
108987
|
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
108763
108988
|
for (const template of templateData) {
|
|
108764
108989
|
const { quads } = template;
|
|
108765
|
-
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) {
|
|
108990
|
+
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) {
|
|
108766
108991
|
throw new RangeError("Section template arrays do not match its quad count");
|
|
108767
108992
|
}
|
|
108768
108993
|
}
|
|
@@ -108872,6 +109097,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108872
109097
|
blockIndices[indexOffset / 6] = indices[entry];
|
|
108873
109098
|
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
108874
109099
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
109100
|
+
const tint = biomeTints && template.biomeTint?.[quad] && !Number.isNaN(biomeTints[entry * 3]) ? entry * 3 : void 0;
|
|
108875
109101
|
const start = vertex2;
|
|
108876
109102
|
for (let corner = 0; corner < 4; corner++, vertex2++) {
|
|
108877
109103
|
const source = quad * 4 + corner;
|
|
@@ -108888,9 +109114,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108888
109114
|
uvBounds[vertex2 * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
108889
109115
|
uvBounds[vertex2 * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
108890
109116
|
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
108891
|
-
colors[vertex2 * 3] = template.colors[source * 3] * factor;
|
|
108892
|
-
colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
108893
|
-
colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
109117
|
+
colors[vertex2 * 3] = (tint === void 0 ? template.colors[source * 3] : biomeTints[tint]) * factor;
|
|
109118
|
+
colors[vertex2 * 3 + 1] = (tint === void 0 ? template.colors[source * 3 + 1] : biomeTints[tint + 1]) * factor;
|
|
109119
|
+
colors[vertex2 * 3 + 2] = (tint === void 0 ? template.colors[source * 3 + 2] : biomeTints[tint + 2]) * factor;
|
|
108894
109120
|
}
|
|
108895
109121
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
108896
109122
|
}
|
|
@@ -109014,7 +109240,11 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109014
109240
|
...lighting
|
|
109015
109241
|
};
|
|
109016
109242
|
for (let i4 = 0; i4 < entries.length; i4++) {
|
|
109017
|
-
const { index, template, cullMask } = entries[i4];
|
|
109243
|
+
const { index, template, cullMask, biomeTint } = entries[i4];
|
|
109244
|
+
if (biomeTint) {
|
|
109245
|
+
input.biomeTints ?? (input.biomeTints = new Float32Array(entries.length * 3).fill(NaN));
|
|
109246
|
+
input.biomeTints.set(biomeTint, i4 * 3);
|
|
109247
|
+
}
|
|
109018
109248
|
let id = templateIds.get(template);
|
|
109019
109249
|
if (id === void 0) {
|
|
109020
109250
|
let atlas = atlasIds.get(template.atlas);
|
|
@@ -109041,6 +109271,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109041
109271
|
colors: new Float32Array(quads * 12),
|
|
109042
109272
|
indices: new Uint16Array(quads * 6),
|
|
109043
109273
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
109274
|
+
biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
|
|
109044
109275
|
atlas: 0,
|
|
109045
109276
|
layer: template.layer,
|
|
109046
109277
|
ambientOcclusion: template.ambientOcclusion
|
|
@@ -109185,7 +109416,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109185
109416
|
init_InstanceReference();
|
|
109186
109417
|
var WATER_TINT2 = new Color(4159204).toArray();
|
|
109187
109418
|
var Chunk = class _Chunk {
|
|
109188
|
-
constructor(scene, x4, y5, z4, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
109419
|
+
constructor(scene, x4, y5, z4, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0, biomeBlend) {
|
|
109189
109420
|
this.onBlocksChanged = onBlocksChanged;
|
|
109190
109421
|
this.sectionModels = sectionModels;
|
|
109191
109422
|
this.neighborCell = neighborCell;
|
|
@@ -109194,6 +109425,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109194
109425
|
this.lightAt = lightAt;
|
|
109195
109426
|
this.onLightCleared = onLightCleared;
|
|
109196
109427
|
this.ambientLight = ambientLight;
|
|
109428
|
+
this.biomeBlend = biomeBlend;
|
|
109197
109429
|
this.data = new ChunkData();
|
|
109198
109430
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
109199
109431
|
this.objectBlocks = /* @__PURE__ */ new Set();
|
|
@@ -109203,6 +109435,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109203
109435
|
this.blockPosition = new Vector3();
|
|
109204
109436
|
this.meshDirty = false;
|
|
109205
109437
|
this.meshGeneration = 0;
|
|
109438
|
+
this.blockChanges = /* @__PURE__ */ new Set();
|
|
109206
109439
|
this.scene = scene;
|
|
109207
109440
|
this.x = x4;
|
|
109208
109441
|
this.y = y5;
|
|
@@ -109301,10 +109534,20 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109301
109534
|
return this.refreshBiomes();
|
|
109302
109535
|
}
|
|
109303
109536
|
/** Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects. */
|
|
109304
|
-
|
|
109537
|
+
refreshBiomes(columns) {
|
|
109538
|
+
return this.changeBlocks(() => this.refreshBiomeBlocks(columns), true);
|
|
109539
|
+
}
|
|
109540
|
+
async refreshBiomeBlocks(columns) {
|
|
109541
|
+
const blend = columns && this.biomeBlend?.();
|
|
109542
|
+
const ownColumn = columns?.some((column) => column.x === this.x && column.z === this.z);
|
|
109305
109543
|
const affected = /* @__PURE__ */ new Map();
|
|
109306
109544
|
const blocks = [];
|
|
109307
109545
|
for (const index of this.renderedBlocks.keys()) {
|
|
109546
|
+
if (blend) {
|
|
109547
|
+
if (this.objectBlocks.has(index) && !ownColumn) continue;
|
|
109548
|
+
const [x4, , z4] = this.positionAt(index), radius = blend.radius;
|
|
109549
|
+
if (!columns.some((column) => x4 >= column.x * 16 - radius && x4 <= column.x * 16 + 15 + radius && z4 >= column.z * 16 - radius && z4 <= column.z * 16 + 15 + radius)) continue;
|
|
109550
|
+
}
|
|
109308
109551
|
const block = this.data.get(index);
|
|
109309
109552
|
const stateKey = ChunkData.paletteKey(block);
|
|
109310
109553
|
let matches = affected.get(stateKey);
|
|
@@ -109319,10 +109562,32 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109319
109562
|
}
|
|
109320
109563
|
if (await matches) blocks.push({ index, block });
|
|
109321
109564
|
}
|
|
109565
|
+
if (blend) {
|
|
109566
|
+
const groups = /* @__PURE__ */ new Map();
|
|
109567
|
+
for (const entry of blocks) {
|
|
109568
|
+
const key = ChunkData.paletteKey(entry.block);
|
|
109569
|
+
let group = groups.get(key);
|
|
109570
|
+
if (!group) groups.set(key, group = []);
|
|
109571
|
+
group.push(entry);
|
|
109572
|
+
}
|
|
109573
|
+
blocks.length = 0;
|
|
109574
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
109575
|
+
for (const group of groups.values()) {
|
|
109576
|
+
const { contexts, fluid } = await this.resolveState(group[0].block, group.map((entry) => entry.index), biomes);
|
|
109577
|
+
for (const entry of group) {
|
|
109578
|
+
const context = contexts.get(entry.index);
|
|
109579
|
+
const current = this.sectionBlocks.get(entry.index)?.[0]?.biomeTint;
|
|
109580
|
+
const tint = context?.tint;
|
|
109581
|
+
const tintChanged = !!current !== !!tint || tint?.some((value, channel) => value !== current?.[channel]);
|
|
109582
|
+
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])));
|
|
109583
|
+
if (this.objectBlocks.has(entry.index) || tintChanged || waterChanged) blocks.push(entry);
|
|
109584
|
+
}
|
|
109585
|
+
}
|
|
109586
|
+
}
|
|
109322
109587
|
if (!blocks.length) return;
|
|
109323
109588
|
const hidden = new Set(this.hiddenBlocks);
|
|
109324
109589
|
try {
|
|
109325
|
-
await this.
|
|
109590
|
+
await this.replaceBlocks(blocks, true);
|
|
109326
109591
|
} finally {
|
|
109327
109592
|
for (const index of hidden) {
|
|
109328
109593
|
this.hiddenBlocks.add(index);
|
|
@@ -109362,6 +109627,20 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109362
109627
|
}
|
|
109363
109628
|
/** Places cells in input order and returns changed world positions without refreshing neighbors. */
|
|
109364
109629
|
async placeBlocks(blocks) {
|
|
109630
|
+
return this.changeBlocks(() => this.replaceBlocks(blocks));
|
|
109631
|
+
}
|
|
109632
|
+
changeBlocks(change, refreshBiomes = false) {
|
|
109633
|
+
const before = refreshBiomes ? Promise.allSettled(this.blockChanges) : this.biomeChange;
|
|
109634
|
+
const result = before ? before.catch(() => void 0).then(change) : change();
|
|
109635
|
+
const pending = result.finally(() => {
|
|
109636
|
+
this.blockChanges.delete(pending);
|
|
109637
|
+
if (this.biomeChange === pending) this.biomeChange = void 0;
|
|
109638
|
+
});
|
|
109639
|
+
this.blockChanges.add(pending);
|
|
109640
|
+
if (refreshBiomes) this.biomeChange = pending;
|
|
109641
|
+
return pending;
|
|
109642
|
+
}
|
|
109643
|
+
async replaceBlocks(blocks, preserveDataOnFailure = false) {
|
|
109365
109644
|
const placements = blocks.map(({ index, block }) => ({
|
|
109366
109645
|
index,
|
|
109367
109646
|
key: block && !ChunkData.isAir(block) ? ChunkData.paletteKey(block) : void 0,
|
|
@@ -109381,6 +109660,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109381
109660
|
const biomes = /* @__PURE__ */ new Map();
|
|
109382
109661
|
const settled = await Promise.allSettled([...states.values()].map(({ stored, indices }) => this.resolveState(stored, indices, biomes)));
|
|
109383
109662
|
const resolutions = new Map([...states.keys()].map((key, i4) => [key, settled[i4]]));
|
|
109663
|
+
if (preserveDataOnFailure) {
|
|
109664
|
+
const rejected = settled.find((result) => result.status === "rejected");
|
|
109665
|
+
if (rejected?.status === "rejected") throw rejected.reason;
|
|
109666
|
+
}
|
|
109384
109667
|
const positions = [];
|
|
109385
109668
|
let failed = false, failure;
|
|
109386
109669
|
for (const { index, key, block } of placements) {
|
|
@@ -109418,7 +109701,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109418
109701
|
}
|
|
109419
109702
|
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
109420
109703
|
if (templates) {
|
|
109421
|
-
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
109704
|
+
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0, biomeTint: context?.tint })));
|
|
109422
109705
|
this.meshDirty = true;
|
|
109423
109706
|
} else {
|
|
109424
109707
|
object4 = await this.scene.addBlock(blockState3, {
|
|
@@ -109437,7 +109720,11 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109437
109720
|
}, object: object4 });
|
|
109438
109721
|
if (object4) this.objectBlocks.add(index);
|
|
109439
109722
|
} catch (error2) {
|
|
109440
|
-
|
|
109723
|
+
if (preserveDataOnFailure && readBlock) {
|
|
109724
|
+
this.renderedBlocks.set(index, { get block() {
|
|
109725
|
+
return readBlock();
|
|
109726
|
+
}, object: void 0 });
|
|
109727
|
+
} else this.data.assign(index, 0);
|
|
109441
109728
|
this.fluidCells[index] = 0;
|
|
109442
109729
|
object4?.removeFromScene();
|
|
109443
109730
|
if (!failed) failure = error2;
|
|
@@ -109448,7 +109735,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109448
109735
|
return positions;
|
|
109449
109736
|
}
|
|
109450
109737
|
/** Replaces every cell from parsed section data. The caller refreshes neighbor culling. */
|
|
109451
|
-
|
|
109738
|
+
placeSection(data) {
|
|
109739
|
+
return this.changeBlocks(() => this.replaceSection(data));
|
|
109740
|
+
}
|
|
109741
|
+
async replaceSection(data) {
|
|
109452
109742
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
109453
109743
|
this.sectionBlocks.clear();
|
|
109454
109744
|
this.fluidCells.fill(0);
|
|
@@ -109495,7 +109785,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109495
109785
|
];
|
|
109496
109786
|
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
109497
109787
|
if (templates) {
|
|
109498
|
-
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
109788
|
+
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0, biomeTint: context?.tint })));
|
|
109499
109789
|
this.meshDirty = true;
|
|
109500
109790
|
} else {
|
|
109501
109791
|
perBlocks.push({ index, blockState: blockState3, biome: context?.biome });
|
|
@@ -109579,12 +109869,35 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109579
109869
|
}
|
|
109580
109870
|
async resolveState(stored, indices, biomes) {
|
|
109581
109871
|
const blockState3 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
109582
|
-
|
|
109872
|
+
let perBlock = !blockState3 || !this.sectionModels || !!(blockState3.key && BlockEntities.entry(await BlockEntities.getIndex(blockState3.key.root), blockState3.key.toNamespacedString()));
|
|
109583
109873
|
const fluid = await getBlockFluidState(blockState3?.key, stored.properties);
|
|
109584
109874
|
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;
|
|
109585
109875
|
const source = hasBiomes && blockState3 ? await BlockTints.biomeSource(blockState3.key) : void 0;
|
|
109586
109876
|
const prepare = (color3) => perBlock || fluid?.renderModel === false ? void 0 : this.sectionModels.prepareState(blockState3, stored.properties, color3);
|
|
109587
109877
|
const contexts = /* @__PURE__ */ new Map();
|
|
109878
|
+
const blend = this.biomeBlend?.();
|
|
109879
|
+
if (blend && !perBlock && blockState3 && (source || fluid?.kind === "water")) {
|
|
109880
|
+
const prepared2 = fluid?.renderModel === false ? void 0 : await this.sectionModels.prepareState(blockState3, stored.properties, void 0, true);
|
|
109881
|
+
if (!prepared2 && fluid?.renderModel !== false) {
|
|
109882
|
+
perBlock = true;
|
|
109883
|
+
} else {
|
|
109884
|
+
await Promise.all(indices.map(async (index) => {
|
|
109885
|
+
const position = this.biomePosition(index, blockState3, stored);
|
|
109886
|
+
const biomeColor = (kind) => blend.getColor(kind, blockState3.key, position);
|
|
109887
|
+
const context = {};
|
|
109888
|
+
if (source && prepared2?.biomeTint) {
|
|
109889
|
+
const color3 = await biomeColor(source);
|
|
109890
|
+
if (color3 !== void 0) context.tint = new Color(color3).toArray();
|
|
109891
|
+
}
|
|
109892
|
+
if (fluid?.kind === "water") {
|
|
109893
|
+
const color3 = await biomeColor("water");
|
|
109894
|
+
if (color3 !== void 0 && color3 !== 4159204) context.waterTint = new Color(color3).toArray();
|
|
109895
|
+
}
|
|
109896
|
+
contexts.set(index, context);
|
|
109897
|
+
}));
|
|
109898
|
+
return { blockState: blockState3, perBlock, fluid, prepared: prepared2, contexts, stored };
|
|
109899
|
+
}
|
|
109900
|
+
}
|
|
109588
109901
|
const groups = /* @__PURE__ */ new Map();
|
|
109589
109902
|
if (blockState3 && (source || fluid?.kind === "water")) {
|
|
109590
109903
|
for (const index of indices) {
|
|
@@ -109632,7 +109945,11 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109632
109945
|
this.waterTints.set(tint ?? WATER_TINT2, index * 3);
|
|
109633
109946
|
}
|
|
109634
109947
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
109635
|
-
|
|
109948
|
+
setBlockVisibleAt(pos, visible) {
|
|
109949
|
+
const position = pos.clone();
|
|
109950
|
+
return this.changeBlocks(() => this.setBlockVisibility(position, visible));
|
|
109951
|
+
}
|
|
109952
|
+
async setBlockVisibility(pos, visible) {
|
|
109636
109953
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
109637
109954
|
const block = this.renderedBlocks.get(index);
|
|
109638
109955
|
if (!block || visible === !this.hiddenBlocks.has(index)) {
|
|
@@ -109802,6 +110119,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109802
110119
|
}
|
|
109803
110120
|
/** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
|
|
109804
110121
|
async clear(notify = true) {
|
|
110122
|
+
if (this.blockChanges.size) await Promise.allSettled(this.blockChanges);
|
|
109805
110123
|
const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
109806
110124
|
new Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
109807
110125
|
)) : [];
|