minerender 2.1.0-alpha.119 → 2.1.0-alpha.120
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 +121 -73
- package/dist/browser/index.d.ts +121 -73
- package/dist/browser/index.js +203 -19
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +203 -19
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/section.worker.js +43 -5
- package/dist/browser/section.worker.js.map +1 -1
- package/dist/browser/section.worker.mjs +43 -5
- package/dist/browser/section.worker.mjs.map +1 -1
- package/dist/bundle.js +209 -19
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +121 -73
- package/dist/node/index.d.ts +121 -73
- package/dist/node/index.js +205 -19
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +203 -19
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -7719,6 +7719,7 @@ __export(index_node_exports, {
|
|
|
7719
7719
|
classicSkinTextureCoordinates: () => classicSkinTextureCoordinates,
|
|
7720
7720
|
computeMorphedAttributes: () => computeMorphedAttributes,
|
|
7721
7721
|
computeTangents: () => computeTangents,
|
|
7722
|
+
copySectionLight: () => copySectionLight,
|
|
7722
7723
|
createCanvas: () => createCanvas2,
|
|
7723
7724
|
createFluidGeometry: () => createFluidGeometry,
|
|
7724
7725
|
createGuiTextGeometry: () => createGuiTextGeometry,
|
|
@@ -7770,6 +7771,7 @@ __export(index_node_exports, {
|
|
|
7770
7771
|
sampleEntityAnimation: () => sampleEntityAnimation,
|
|
7771
7772
|
sampleEntityKeyframes: () => sampleEntityKeyframes,
|
|
7772
7773
|
sampleFluid: () => sampleFluid,
|
|
7774
|
+
sampleSectionLight: () => sampleSectionLight,
|
|
7773
7775
|
sectionGeometryTransferables: () => sectionGeometryTransferables,
|
|
7774
7776
|
serializeBoxGeometryKey: () => serializeBoxGeometryKey,
|
|
7775
7777
|
serializeImageKey: () => serializeImageKey,
|
|
@@ -17027,11 +17029,20 @@ var AnvilParser = class {
|
|
|
17027
17029
|
const { root, expected } = await this.readNBT(data, location, options);
|
|
17028
17030
|
const level = root.Level?.type === "compound" ? root.Level.value : root;
|
|
17029
17031
|
const dataVersion = root.DataVersion?.type === "int" ? root.DataVersion.value : void 0;
|
|
17032
|
+
const sections = this.compounds(level.sections ?? level.Sections, "sections");
|
|
17033
|
+
const lightFlagName = level.isLightOn ? "isLightOn" : "LightPopulated";
|
|
17034
|
+
const lightFlag = level[lightFlagName];
|
|
17035
|
+
if (lightFlag && (lightFlag.type !== "byte" || lightFlag.value !== 0 && lightFlag.value !== 1)) {
|
|
17036
|
+
throw new MineRenderError(`Anvil ${lightFlagName} must be a byte containing 0 or 1`);
|
|
17037
|
+
}
|
|
17038
|
+
const modernLighting = root.Level?.type !== "compound" || sections.some((section) => section.Palette || section.BlockStates || section.block_states);
|
|
17039
|
+
const lightValid = lightFlag ? lightFlag.value === 1 : modernLighting ? false : void 0;
|
|
17030
17040
|
const chunk = {
|
|
17031
17041
|
x: this.integer(level.xPos, "xPos"),
|
|
17032
17042
|
z: this.integer(level.zPos, "zPos"),
|
|
17033
17043
|
dataVersion,
|
|
17034
|
-
sections: []
|
|
17044
|
+
sections: [],
|
|
17045
|
+
...lightValid !== void 0 ? { lightValid } : {}
|
|
17035
17046
|
};
|
|
17036
17047
|
if ((chunk.x % 32 + 32) % 32 !== location.x || (chunk.z % 32 + 32) % 32 !== location.z) {
|
|
17037
17048
|
throw new MineRenderError("Anvil chunk coordinates do not match its region location");
|
|
@@ -17041,7 +17052,7 @@ var AnvilParser = class {
|
|
|
17041
17052
|
}
|
|
17042
17053
|
const numericStates = /* @__PURE__ */ new Map();
|
|
17043
17054
|
let legacyMappings;
|
|
17044
|
-
for (const section of
|
|
17055
|
+
for (const section of sections) {
|
|
17045
17056
|
const y = this.integer(section.Y, "section Y");
|
|
17046
17057
|
let data2;
|
|
17047
17058
|
if (section.Blocks || section.Data || section.Add) {
|
|
@@ -17071,7 +17082,8 @@ var AnvilParser = class {
|
|
|
17071
17082
|
}
|
|
17072
17083
|
if (chunk.sections.some((section2) => section2.y === y)) throw new MineRenderError(`Duplicate Anvil section Y ${y}`);
|
|
17073
17084
|
const biomes = this.biomes(section.biomes);
|
|
17074
|
-
|
|
17085
|
+
const light = this.light(section, y, chunk.lightValid);
|
|
17086
|
+
chunk.sections.push({ y, data: data2, ...biomes ? { biomes } : {}, ...light ? { light } : {} });
|
|
17075
17087
|
}
|
|
17076
17088
|
for (const entry of this.compounds(level.block_entities ?? level.TileEntities, "block entities")) {
|
|
17077
17089
|
const x = this.integer(entry.x, "block entity x") - chunk.x * 16;
|
|
@@ -17124,6 +17136,18 @@ var AnvilParser = class {
|
|
|
17124
17136
|
return { position: [...position.value.value], nbt: { type: "compound", value } };
|
|
17125
17137
|
});
|
|
17126
17138
|
}
|
|
17139
|
+
static light(section, y, valid) {
|
|
17140
|
+
const light = {};
|
|
17141
|
+
for (const [name, channel] of [["BlockLight", "block"], ["SkyLight", "sky"]]) {
|
|
17142
|
+
const tag = section[name];
|
|
17143
|
+
if (!tag) continue;
|
|
17144
|
+
if (tag.type !== "byteArray" || !Array.isArray(tag.value) || tag.value.length !== 2048) {
|
|
17145
|
+
throw new MineRenderError(`Anvil section ${y} ${name} must contain 2048 bytes`);
|
|
17146
|
+
}
|
|
17147
|
+
light[channel] = Uint8Array.from(tag.value);
|
|
17148
|
+
}
|
|
17149
|
+
return light.block || light.sky || valid ? light : void 0;
|
|
17150
|
+
}
|
|
17127
17151
|
static biomes(tag) {
|
|
17128
17152
|
if (!tag) return void 0;
|
|
17129
17153
|
if (tag.type !== "compound") throw new MineRenderError("Anvil biomes must be a compound");
|
|
@@ -17701,12 +17725,45 @@ var WorldEntities = class {
|
|
|
17701
17725
|
|
|
17702
17726
|
// src/world/MineRenderWorld.ts
|
|
17703
17727
|
init_FluidQuads();
|
|
17728
|
+
|
|
17729
|
+
// src/world/WorldLight.ts
|
|
17730
|
+
function copySectionLight(light) {
|
|
17731
|
+
const copy = {};
|
|
17732
|
+
for (const channel of ["block", "sky"]) {
|
|
17733
|
+
const bytes = light[channel];
|
|
17734
|
+
if (bytes === void 0) continue;
|
|
17735
|
+
if (!(bytes instanceof Uint8Array) || bytes.length !== 2048) {
|
|
17736
|
+
throw new RangeError(`Section ${channel} light must contain 2048 packed bytes`);
|
|
17737
|
+
}
|
|
17738
|
+
copy[channel] = new Uint8Array(bytes);
|
|
17739
|
+
}
|
|
17740
|
+
return copy;
|
|
17741
|
+
}
|
|
17742
|
+
function sampleSectionLight(light, index) {
|
|
17743
|
+
if (!light) return void 0;
|
|
17744
|
+
const shift = (index & 1) * 4;
|
|
17745
|
+
return {
|
|
17746
|
+
block: (light.block?.[index >> 1] ?? 0) >> shift & 15,
|
|
17747
|
+
sky: (light.sky?.[index >> 1] ?? 0) >> shift & 15
|
|
17748
|
+
};
|
|
17749
|
+
}
|
|
17750
|
+
|
|
17751
|
+
// src/world/MineRenderWorld.ts
|
|
17704
17752
|
var MineRenderWorld = class {
|
|
17705
17753
|
constructor(scene, options = {}) {
|
|
17706
17754
|
this._chunks = /* @__PURE__ */ new Map();
|
|
17707
17755
|
this.biomes = /* @__PURE__ */ new Map();
|
|
17756
|
+
this.light = /* @__PURE__ */ new Map();
|
|
17757
|
+
this.lightValidity = /* @__PURE__ */ new Map();
|
|
17758
|
+
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
17708
17759
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
17760
|
+
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
17761
|
+
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
17762
|
+
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
17763
|
+
}
|
|
17709
17764
|
this.scene = scene;
|
|
17765
|
+
this.savedLighting = options.savedLighting ?? false;
|
|
17766
|
+
this.ambientLight = options.ambientLight ?? 0;
|
|
17710
17767
|
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
17711
17768
|
if (options.renderEntities) this.entities = new WorldEntities(scene);
|
|
17712
17769
|
}
|
|
@@ -17728,6 +17785,24 @@ var MineRenderWorld = class {
|
|
|
17728
17785
|
const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
|
|
17729
17786
|
return this.biomes.get(`${cx}_${cz}`)?.get(cy)?.[Math.floor(lx / 4) + Math.floor(lz / 4) * 4 + Math.floor(ly / 4) * 16];
|
|
17730
17787
|
}
|
|
17788
|
+
getLightAt(posOrX, y, z) {
|
|
17789
|
+
if (typeof posOrX === "number") return this.getLightAt(new import_three42.Vector3(posOrX, y, z));
|
|
17790
|
+
if (isTripleArray(posOrX)) return this.getLightAt(new import_three42.Vector3(...posOrX));
|
|
17791
|
+
this.validatePosBounds(posOrX);
|
|
17792
|
+
const { x, y: py, z: pz } = posOrX;
|
|
17793
|
+
const cx = Math.floor(x / 16), cy = Math.floor(py / 16), cz = Math.floor(pz / 16);
|
|
17794
|
+
const key = `${cx}_${cz}`, top = this.highestSkySection.get(key);
|
|
17795
|
+
const sample = sampleSectionLight(this.light.get(key)?.get(cy), (x & 15) + (pz & 15) * 16 + (py & 15) * 256);
|
|
17796
|
+
return top !== void 0 && cy > top ? { block: sample?.block ?? 0, sky: 15 } : sample;
|
|
17797
|
+
}
|
|
17798
|
+
lightLevelAt(x, y, z) {
|
|
17799
|
+
const cx = Math.floor(x / 16), cy = Math.floor(y / 16), cz = Math.floor(z / 16), key = `${cx}_${cz}`;
|
|
17800
|
+
if (this.lightValidity.get(key) === false) return 255;
|
|
17801
|
+
const top = this.highestSkySection.get(key);
|
|
17802
|
+
if (top !== void 0 && cy > top) return 15;
|
|
17803
|
+
const sample = sampleSectionLight(this.light.get(key)?.get(cy), (x & 15) + (z & 15) * 16 + (y & 15) * 256);
|
|
17804
|
+
return sample ? Math.max(sample.block, sample.sky) : 255;
|
|
17805
|
+
}
|
|
17731
17806
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
17732
17807
|
if (typeof posOrX == "number") {
|
|
17733
17808
|
return this.setBlockAt(new import_three42.Vector3(posOrX, yOrBlock, z), block);
|
|
@@ -17842,7 +17917,7 @@ var MineRenderWorld = class {
|
|
|
17842
17917
|
}
|
|
17843
17918
|
}
|
|
17844
17919
|
}
|
|
17845
|
-
/** Replaces a chunk column's blocks and
|
|
17920
|
+
/** Replaces a chunk column's blocks, biomes, and saved light and, with `renderEntities`, its supported saved mobs. */
|
|
17846
17921
|
async placeChunk(chunk, executor) {
|
|
17847
17922
|
if (![chunk.x, chunk.z].every(Number.isSafeInteger)) {
|
|
17848
17923
|
throw new RangeError("Chunk column coordinates must be safe integers");
|
|
@@ -17850,6 +17925,11 @@ var MineRenderWorld = class {
|
|
|
17850
17925
|
if (!chunk.sections.every((section) => Number.isSafeInteger(section.y))) {
|
|
17851
17926
|
throw new RangeError("Chunk section coordinates must be safe integers");
|
|
17852
17927
|
}
|
|
17928
|
+
const lights = /* @__PURE__ */ new Map();
|
|
17929
|
+
for (const section of chunk.sections) {
|
|
17930
|
+
const light = section.light ?? (chunk.lightValid === true ? {} : void 0);
|
|
17931
|
+
if (light) lights.set(section.y, copySectionLight(light));
|
|
17932
|
+
}
|
|
17853
17933
|
this.entities?.clearColumn(chunk.x, chunk.z);
|
|
17854
17934
|
const placeEntities = this.entities?.prepare(chunk.entities, [chunk.x, chunk.z]);
|
|
17855
17935
|
const changes = /* @__PURE__ */ new Map();
|
|
@@ -17865,6 +17945,15 @@ var MineRenderWorld = class {
|
|
|
17865
17945
|
}
|
|
17866
17946
|
try {
|
|
17867
17947
|
await this.clearChunkColumn(chunk.x, chunk.z);
|
|
17948
|
+
const columnKey = `${chunk.x}_${chunk.z}`;
|
|
17949
|
+
if (lights.size) this.light.set(columnKey, lights);
|
|
17950
|
+
for (const [y, light] of lights) {
|
|
17951
|
+
if (light.sky) this.highestSkySection.set(columnKey, Math.max(y, this.highestSkySection.get(columnKey) ?? -Infinity));
|
|
17952
|
+
}
|
|
17953
|
+
if (chunk.lightValid !== void 0) this.lightValidity.set(columnKey, chunk.lightValid);
|
|
17954
|
+
if (this.savedLighting) {
|
|
17955
|
+
for (const y of lights.keys()) this.markSectionChanged({ x: chunk.x, y, z: chunk.z });
|
|
17956
|
+
}
|
|
17868
17957
|
for (const section of chunk.sections) {
|
|
17869
17958
|
if (section.biomes) {
|
|
17870
17959
|
const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
@@ -17934,6 +18023,12 @@ var MineRenderWorld = class {
|
|
|
17934
18023
|
}
|
|
17935
18024
|
async clearChunkColumn(x, z) {
|
|
17936
18025
|
this.biomes.delete(`${x}_${z}`);
|
|
18026
|
+
if (this.savedLighting) {
|
|
18027
|
+
for (const y of this.light.get(`${x}_${z}`)?.keys() ?? []) this.markSectionChanged({ x, y, z });
|
|
18028
|
+
}
|
|
18029
|
+
this.light.delete(`${x}_${z}`);
|
|
18030
|
+
this.lightValidity.delete(`${x}_${z}`);
|
|
18031
|
+
this.highestSkySection.delete(`${x}_${z}`);
|
|
17937
18032
|
const previous = [...this._chunks.entries()].filter(([, section]) => section.x === x && section.z === z);
|
|
17938
18033
|
for (const [key, section] of previous) {
|
|
17939
18034
|
this._chunks.delete(key);
|
|
@@ -17943,7 +18038,8 @@ var MineRenderWorld = class {
|
|
|
17943
18038
|
}
|
|
17944
18039
|
}
|
|
17945
18040
|
markSectionChanged(chunk) {
|
|
17946
|
-
|
|
18041
|
+
const current = this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`);
|
|
18042
|
+
if (current && current === chunk) this.pendingCulling.set(current, "all");
|
|
17947
18043
|
for (let dy = -1; dy <= 1; dy++) {
|
|
17948
18044
|
for (let dz = -1; dz <= 1; dz++) {
|
|
17949
18045
|
for (let dx = -1; dx <= 1; dx++) {
|
|
@@ -17971,6 +18067,9 @@ var MineRenderWorld = class {
|
|
|
17971
18067
|
const chunks = [...this._chunks.values()];
|
|
17972
18068
|
this._chunks.clear();
|
|
17973
18069
|
this.biomes.clear();
|
|
18070
|
+
this.light.clear();
|
|
18071
|
+
this.lightValidity.clear();
|
|
18072
|
+
this.highestSkySection.clear();
|
|
17974
18073
|
for (const chunk of chunks) {
|
|
17975
18074
|
await chunk.dispose();
|
|
17976
18075
|
}
|
|
@@ -18033,6 +18132,7 @@ var MineRenderWorld = class {
|
|
|
18033
18132
|
}
|
|
18034
18133
|
}
|
|
18035
18134
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
18135
|
+
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
18036
18136
|
}
|
|
18037
18137
|
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
18038
18138
|
}
|
|
@@ -18073,7 +18173,23 @@ var MineRenderWorld = class {
|
|
|
18073
18173
|
}
|
|
18074
18174
|
await chunk.refreshBiomes();
|
|
18075
18175
|
await this._chunks.get(`${x}_${y + 1}_${z}`)?.refreshBiomes();
|
|
18076
|
-
}
|
|
18176
|
+
},
|
|
18177
|
+
this.savedLighting ? (x2, y2, z2) => this.lightLevelAt(x2, y2, z2) : void 0,
|
|
18178
|
+
async () => {
|
|
18179
|
+
if (this._chunks.get(key) !== chunk) return;
|
|
18180
|
+
const columnKey = `${x}_${z}`, column = this.light.get(columnKey);
|
|
18181
|
+
if (!column?.delete(y)) return;
|
|
18182
|
+
if (!column.size) this.light.delete(columnKey);
|
|
18183
|
+
this.highestSkySection.delete(columnKey);
|
|
18184
|
+
for (const [y2, light] of column) {
|
|
18185
|
+
if (light.sky) this.highestSkySection.set(columnKey, Math.max(y2, this.highestSkySection.get(columnKey) ?? -Infinity));
|
|
18186
|
+
}
|
|
18187
|
+
if (this.savedLighting) {
|
|
18188
|
+
this.markSectionChanged(chunk);
|
|
18189
|
+
await this.updateCulling([]);
|
|
18190
|
+
}
|
|
18191
|
+
},
|
|
18192
|
+
this.ambientLight
|
|
18077
18193
|
);
|
|
18078
18194
|
this._chunks.set(key, chunk);
|
|
18079
18195
|
}
|
|
@@ -18122,12 +18238,43 @@ init_Materials();
|
|
|
18122
18238
|
|
|
18123
18239
|
// src/world/SectionGeometry.ts
|
|
18124
18240
|
init_FluidQuads();
|
|
18241
|
+
|
|
18242
|
+
// src/world/_light/FaceLight.ts
|
|
18243
|
+
function lightBrightness(level, ambient = 0) {
|
|
18244
|
+
if (level === 255) return 1;
|
|
18245
|
+
const curve = level / (60 - 3 * level);
|
|
18246
|
+
return curve + ambient * (1 - curve);
|
|
18247
|
+
}
|
|
18248
|
+
function quadLightIndex(positions, normals, quad) {
|
|
18249
|
+
const start = quad * 12;
|
|
18250
|
+
let axis = 0;
|
|
18251
|
+
if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
|
|
18252
|
+
if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
|
|
18253
|
+
const positive2 = normals[start + axis] > 0;
|
|
18254
|
+
const boundary = positive2 ? 8 : -8;
|
|
18255
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18256
|
+
if (Math.abs(positions[start + vertex * 3 + axis] - boundary) > 16e-4) return 0;
|
|
18257
|
+
}
|
|
18258
|
+
return axis * 2 + (positive2 ? 1 : 2);
|
|
18259
|
+
}
|
|
18260
|
+
function fluidLightLevel(center, neighbor) {
|
|
18261
|
+
return Math.max(center === 255 ? 15 : center, neighbor === 255 ? 15 : neighbor);
|
|
18262
|
+
}
|
|
18263
|
+
var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
18264
|
+
|
|
18265
|
+
// src/world/SectionGeometry.ts
|
|
18125
18266
|
function buildSectionGeometry(input) {
|
|
18126
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids } = input;
|
|
18267
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
|
|
18127
18268
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18128
18269
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18129
18270
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
18130
18271
|
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
18272
|
+
if (light && (light.length !== 5832 || light.some((level) => level > 15 && level !== 255))) {
|
|
18273
|
+
throw new RangeError("Section light must cover an 18\xD718\xD718 neighborhood with levels from 0 to 15 or 255");
|
|
18274
|
+
}
|
|
18275
|
+
if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
|
|
18276
|
+
throw new RangeError("Section ambient light must be a number from 0 to 1");
|
|
18277
|
+
}
|
|
18131
18278
|
for (const template of templateData) {
|
|
18132
18279
|
const { quads } = template;
|
|
18133
18280
|
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) {
|
|
@@ -18232,8 +18379,10 @@ function buildSectionGeometry(input) {
|
|
|
18232
18379
|
const offsetX = indices[entry] % 16 * 16;
|
|
18233
18380
|
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
18234
18381
|
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
18382
|
+
const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
|
|
18235
18383
|
for (let quad = 0; quad < template.quads; quad++) {
|
|
18236
18384
|
if (cullMasks[entry] & template.cullFaces[quad]) continue;
|
|
18385
|
+
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
18237
18386
|
const start = vertex;
|
|
18238
18387
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
18239
18388
|
const source = quad * 4 + corner;
|
|
@@ -18249,9 +18398,9 @@ function buildSectionGeometry(input) {
|
|
|
18249
18398
|
uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
18250
18399
|
uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
18251
18400
|
uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
18252
|
-
colors[vertex * 3] = template.colors[source * 3];
|
|
18253
|
-
colors[vertex * 3 + 1] = template.colors[source * 3 + 1];
|
|
18254
|
-
colors[vertex * 3 + 2] = template.colors[source * 3 + 2];
|
|
18401
|
+
colors[vertex * 3] = template.colors[source * 3] * brightness;
|
|
18402
|
+
colors[vertex * 3 + 1] = template.colors[source * 3 + 1] * brightness;
|
|
18403
|
+
colors[vertex * 3 + 2] = template.colors[source * 3 + 2] * brightness;
|
|
18255
18404
|
}
|
|
18256
18405
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
18257
18406
|
}
|
|
@@ -18261,8 +18410,13 @@ function buildSectionGeometry(input) {
|
|
|
18261
18410
|
const placement = page.placements[0];
|
|
18262
18411
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
18263
18412
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
18413
|
+
const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
|
|
18264
18414
|
for (let quad = 0; quad < quads.sprites.length; quad++) {
|
|
18265
18415
|
const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
|
|
18416
|
+
const brightness = light ? lightBrightness(fluidLightLevel(
|
|
18417
|
+
light[lightIndex],
|
|
18418
|
+
light[lightIndex + (quads.normals[quad * 12 + 1] < 0 ? -324 : 324)]
|
|
18419
|
+
), ambientLight) : 1;
|
|
18266
18420
|
const start = vertex;
|
|
18267
18421
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
18268
18422
|
const source = quad * 4 + corner;
|
|
@@ -18280,7 +18434,9 @@ function buildSectionGeometry(input) {
|
|
|
18280
18434
|
mapU((rect[0] + rect[2]) / atlas.width),
|
|
18281
18435
|
mapV(1 - rect[1] / atlas.height)
|
|
18282
18436
|
], vertex * 4);
|
|
18283
|
-
colors
|
|
18437
|
+
colors[vertex * 3] = tint[0] * brightness;
|
|
18438
|
+
colors[vertex * 3 + 1] = tint[1] * brightness;
|
|
18439
|
+
colors[vertex * 3 + 2] = tint[2] * brightness;
|
|
18284
18440
|
}
|
|
18285
18441
|
outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);
|
|
18286
18442
|
indexOffset += 6;
|
|
@@ -18349,7 +18505,7 @@ var SectionWorker = class _SectionWorker {
|
|
|
18349
18505
|
// src/world/SectionMesh.ts
|
|
18350
18506
|
var templateCache = /* @__PURE__ */ new WeakMap();
|
|
18351
18507
|
var WATER_TINT = new import_three43.Color(4159204).toArray();
|
|
18352
|
-
function toInput(entries, maxAtlasSize, fluids) {
|
|
18508
|
+
function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
18353
18509
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18354
18510
|
const atlases = [];
|
|
18355
18511
|
const atlasIds = /* @__PURE__ */ new Map();
|
|
@@ -18361,7 +18517,8 @@ function toInput(entries, maxAtlasSize, fluids) {
|
|
|
18361
18517
|
cullMasks: new Uint8Array(entries.length),
|
|
18362
18518
|
templateData: [],
|
|
18363
18519
|
atlases: [],
|
|
18364
|
-
maxAtlasSize
|
|
18520
|
+
maxAtlasSize,
|
|
18521
|
+
...lighting
|
|
18365
18522
|
};
|
|
18366
18523
|
for (let i = 0; i < entries.length; i++) {
|
|
18367
18524
|
const { index, template, cullMask } = entries[i];
|
|
@@ -18449,13 +18606,13 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18449
18606
|
this.ownedMeshes = [];
|
|
18450
18607
|
}
|
|
18451
18608
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
18452
|
-
static build(entries, maxAtlasSize = 2048, fluids) {
|
|
18453
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids);
|
|
18609
|
+
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
18610
|
+
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
18454
18611
|
return this.fromPages(buildSectionGeometry(input), atlases);
|
|
18455
18612
|
}
|
|
18456
18613
|
/** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
|
|
18457
|
-
static async buildAsync(entries, maxAtlasSize = 2048, fluids) {
|
|
18458
|
-
const { input, atlases } = toInput(entries, maxAtlasSize, fluids);
|
|
18614
|
+
static async buildAsync(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
18615
|
+
const { input, atlases } = toInput(entries, maxAtlasSize, fluids, lighting);
|
|
18459
18616
|
const worker = SectionWorker.shared();
|
|
18460
18617
|
const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
|
|
18461
18618
|
return this.fromPages(pages, atlases);
|
|
@@ -18525,12 +18682,15 @@ init_FluidQuads();
|
|
|
18525
18682
|
init_CubeFace();
|
|
18526
18683
|
var WATER_TINT2 = new import_three44.Color(4159204).toArray();
|
|
18527
18684
|
var Chunk = class _Chunk {
|
|
18528
|
-
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged) {
|
|
18685
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
18529
18686
|
this.onBlocksChanged = onBlocksChanged;
|
|
18530
18687
|
this.sectionModels = sectionModels;
|
|
18531
18688
|
this.neighborCell = neighborCell;
|
|
18532
18689
|
this.biomeAt = biomeAt;
|
|
18533
18690
|
this.onBiomesChanged = onBiomesChanged;
|
|
18691
|
+
this.lightAt = lightAt;
|
|
18692
|
+
this.onLightCleared = onLightCleared;
|
|
18693
|
+
this.ambientLight = ambientLight;
|
|
18534
18694
|
this.data = new ChunkData();
|
|
18535
18695
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
18536
18696
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
@@ -18812,6 +18972,13 @@ var Chunk = class _Chunk {
|
|
|
18812
18972
|
positionAt(index) {
|
|
18813
18973
|
return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
|
|
18814
18974
|
}
|
|
18975
|
+
/** Refreshes saved lighting after adjacent columns load or unload, including columns with only light data. */
|
|
18976
|
+
async refreshLight(indices) {
|
|
18977
|
+
if (!this.lightAt) return;
|
|
18978
|
+
for (const index of indices ?? this.renderedBlocks.keys()) {
|
|
18979
|
+
if (this.renderedBlocks.has(index)) this.meshDirty = true;
|
|
18980
|
+
}
|
|
18981
|
+
}
|
|
18815
18982
|
biomePosition(index, blockState3, stored) {
|
|
18816
18983
|
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18817
18984
|
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
@@ -18989,7 +19156,23 @@ var Chunk = class _Chunk {
|
|
|
18989
19156
|
fluids[kind] = await this.sectionModels.fluidAtlas(kind, state?.key?.root);
|
|
18990
19157
|
}
|
|
18991
19158
|
}
|
|
18992
|
-
|
|
19159
|
+
let light;
|
|
19160
|
+
if (this.lightAt) {
|
|
19161
|
+
light = new Uint8Array(18 * 18 * 18);
|
|
19162
|
+
for (let y = -1; y <= 16; y++) {
|
|
19163
|
+
for (let z = -1; z <= 16; z++) {
|
|
19164
|
+
for (let x = -1; x <= 16; x++) {
|
|
19165
|
+
light[(y + 1) * 324 + (z + 1) * 18 + x + 1] = this.lightAt(this.x * 16 + x, this.y * 16 + y, this.z * 16 + z);
|
|
19166
|
+
}
|
|
19167
|
+
}
|
|
19168
|
+
}
|
|
19169
|
+
}
|
|
19170
|
+
const next = entries.length || fluids ? await SectionMesh.buildAsync(
|
|
19171
|
+
entries,
|
|
19172
|
+
this.sectionModels.maxAtlasSize,
|
|
19173
|
+
fluids,
|
|
19174
|
+
light ? { light, ambientLight: this.ambientLight } : void 0
|
|
19175
|
+
) : void 0;
|
|
18993
19176
|
if (generation !== this.meshGeneration) {
|
|
18994
19177
|
next?.dispose();
|
|
18995
19178
|
return;
|
|
@@ -19021,6 +19204,7 @@ var Chunk = class _Chunk {
|
|
|
19021
19204
|
this.biomes = void 0;
|
|
19022
19205
|
if (notify) {
|
|
19023
19206
|
await this.onBiomesChanged?.(void 0);
|
|
19207
|
+
await this.onLightCleared?.();
|
|
19024
19208
|
await this.onBlocksChanged?.(positions);
|
|
19025
19209
|
}
|
|
19026
19210
|
}
|
|
@@ -19530,6 +19714,7 @@ var NodeRenderer = class _NodeRenderer extends Renderer {
|
|
|
19530
19714
|
classicSkinTextureCoordinates,
|
|
19531
19715
|
computeMorphedAttributes,
|
|
19532
19716
|
computeTangents,
|
|
19717
|
+
copySectionLight,
|
|
19533
19718
|
createCanvas,
|
|
19534
19719
|
createFluidGeometry,
|
|
19535
19720
|
createGuiTextGeometry,
|
|
@@ -19581,6 +19766,7 @@ var NodeRenderer = class _NodeRenderer extends Renderer {
|
|
|
19581
19766
|
sampleEntityAnimation,
|
|
19582
19767
|
sampleEntityKeyframes,
|
|
19583
19768
|
sampleFluid,
|
|
19769
|
+
sampleSectionLight,
|
|
19584
19770
|
sectionGeometryTransferables,
|
|
19585
19771
|
serializeBoxGeometryKey,
|
|
19586
19772
|
serializeImageKey,
|