minerender 2.1.0-alpha.120 → 2.1.0-alpha.122
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 +49 -3
- package/dist/browser/index.d.ts +49 -3
- package/dist/browser/index.js +236 -15
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +237 -16
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/section.worker.js +60 -6
- package/dist/browser/section.worker.js.map +1 -1
- package/dist/browser/section.worker.mjs +60 -6
- package/dist/browser/section.worker.mjs.map +1 -1
- package/dist/bundle.js +244 -15
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +49 -3
- package/dist/node/index.d.ts +49 -3
- package/dist/node/index.js +236 -15
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +237 -16
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.mjs
CHANGED
|
@@ -12463,6 +12463,10 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12463
12463
|
get blockEntities() {
|
|
12464
12464
|
return this._entities;
|
|
12465
12465
|
}
|
|
12466
|
+
/** Model placements drawn for this block, including its fluid surface. */
|
|
12467
|
+
get models() {
|
|
12468
|
+
return this._models;
|
|
12469
|
+
}
|
|
12466
12470
|
/** Sets visibility for this block's model instances and block entities. */
|
|
12467
12471
|
setVisible(visible) {
|
|
12468
12472
|
this.visible = visible;
|
|
@@ -17224,7 +17228,7 @@ var AnvilWorldSource = class {
|
|
|
17224
17228
|
};
|
|
17225
17229
|
|
|
17226
17230
|
// src/world/Chunk.ts
|
|
17227
|
-
import { Color as Color13, Vector3 as Vector318 } from "three";
|
|
17231
|
+
import { Color as Color13, Matrix3 as Matrix33, Matrix4 as Matrix413, Vector3 as Vector318 } from "three";
|
|
17228
17232
|
init_BlockStates();
|
|
17229
17233
|
init_AssetKey();
|
|
17230
17234
|
|
|
@@ -17403,7 +17407,8 @@ var SectionModels = class {
|
|
|
17403
17407
|
atlas,
|
|
17404
17408
|
cullFaces: new Uint8Array(cullFaces),
|
|
17405
17409
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17406
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
17410
|
+
layer: atlas.hasTranslucency ? 1 : 0,
|
|
17411
|
+
ambientOcclusion: model.ambientocclusion !== false
|
|
17407
17412
|
};
|
|
17408
17413
|
this.templates.add(template);
|
|
17409
17414
|
return template;
|
|
@@ -17594,17 +17599,45 @@ var MineRenderWorld = class {
|
|
|
17594
17599
|
this.light = /* @__PURE__ */ new Map();
|
|
17595
17600
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
17596
17601
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
17602
|
+
this.ambientOcclusionPending = false;
|
|
17597
17603
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
17598
17604
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
17605
|
+
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17599
17606
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
17600
17607
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
17601
17608
|
}
|
|
17602
17609
|
this.scene = scene;
|
|
17603
17610
|
this.savedLighting = options.savedLighting ?? false;
|
|
17604
17611
|
this.ambientLight = options.ambientLight ?? 0;
|
|
17612
|
+
this._ambientOcclusion = options.ambientOcclusion ?? false;
|
|
17605
17613
|
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
17606
17614
|
if (options.renderEntities) this.entities = new WorldEntities(scene);
|
|
17607
17615
|
}
|
|
17616
|
+
/**
|
|
17617
|
+
* Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
|
|
17618
|
+
* Includes fluids and block entities; texture alpha does not change triangle intersections.
|
|
17619
|
+
*/
|
|
17620
|
+
raycast(raycaster) {
|
|
17621
|
+
return Chunk.raycast(this._chunks.values(), raycaster);
|
|
17622
|
+
}
|
|
17623
|
+
/** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
|
|
17624
|
+
get ambientOcclusion() {
|
|
17625
|
+
return this._ambientOcclusion;
|
|
17626
|
+
}
|
|
17627
|
+
/** Rebuilds loaded blocks with or without corner shading. Block data and saved lighting are preserved. */
|
|
17628
|
+
async setAmbientOcclusion(enabled) {
|
|
17629
|
+
if (typeof enabled !== "boolean") throw new TypeError("Ambient occlusion must be a boolean");
|
|
17630
|
+
if (enabled && !this.sectionModels) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17631
|
+
if (enabled === this._ambientOcclusion && !this.ambientOcclusionPending) {
|
|
17632
|
+
await this.culling;
|
|
17633
|
+
return;
|
|
17634
|
+
}
|
|
17635
|
+
this._ambientOcclusion = enabled;
|
|
17636
|
+
this.ambientOcclusionPending = true;
|
|
17637
|
+
for (const chunk of this._chunks.values()) this.pendingCulling.set(chunk, "all");
|
|
17638
|
+
await this.updateCulling([]);
|
|
17639
|
+
this.ambientOcclusionPending = false;
|
|
17640
|
+
}
|
|
17608
17641
|
getBlockAt(posOrX, y, z) {
|
|
17609
17642
|
if (typeof posOrX == "number") {
|
|
17610
17643
|
return this.getBlockAt(new Vector317(posOrX, y, z));
|
|
@@ -17928,7 +17961,7 @@ var MineRenderWorld = class {
|
|
|
17928
17961
|
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
17929
17962
|
let pending = this.pendingCulling.get(section);
|
|
17930
17963
|
if (pending === "all" || pending?.has(index)) continue;
|
|
17931
|
-
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !section.isFluidIndex(index)) continue;
|
|
17964
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !this._ambientOcclusion && !section.isFluidIndex(index)) continue;
|
|
17932
17965
|
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
17933
17966
|
pending.add(index);
|
|
17934
17967
|
}
|
|
@@ -17936,6 +17969,7 @@ var MineRenderWorld = class {
|
|
|
17936
17969
|
}
|
|
17937
17970
|
}
|
|
17938
17971
|
return this.culling ??= Promise.resolve().then(async () => {
|
|
17972
|
+
let sliceStart = performance.now();
|
|
17939
17973
|
try {
|
|
17940
17974
|
while (this.pendingCulling.size) {
|
|
17941
17975
|
const batch = [...this.pendingCulling];
|
|
@@ -17971,6 +18005,11 @@ var MineRenderWorld = class {
|
|
|
17971
18005
|
}
|
|
17972
18006
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
17973
18007
|
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
18008
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
18009
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
18010
|
+
await yieldToEventLoop();
|
|
18011
|
+
sliceStart = performance.now();
|
|
18012
|
+
}
|
|
17974
18013
|
}
|
|
17975
18014
|
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
17976
18015
|
}
|
|
@@ -18077,6 +18116,50 @@ import { BufferGeometry as BufferGeometry9, Color as Color12, DoubleSide as Doub
|
|
|
18077
18116
|
// src/world/SectionGeometry.ts
|
|
18078
18117
|
init_FluidQuads();
|
|
18079
18118
|
|
|
18119
|
+
// src/world/_light/AmbientOcclusion.ts
|
|
18120
|
+
var AXIS_STRIDES = [1, 9, 3];
|
|
18121
|
+
function sectionAmbientOcclusionMask(cells, center) {
|
|
18122
|
+
let mask = 0;
|
|
18123
|
+
for (let y = -1; y <= 1; y++) for (let z = -1; z <= 1; z++) for (let x = -1; x <= 1; x++) {
|
|
18124
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) < 2) continue;
|
|
18125
|
+
if (cells[center + y * 324 + z * 18 + x]) mask |= 1 << (y + 1) * 9 + (z + 1) * 3 + x + 1;
|
|
18126
|
+
}
|
|
18127
|
+
return mask;
|
|
18128
|
+
}
|
|
18129
|
+
function cornerBrightness(mask, center, u, v) {
|
|
18130
|
+
const sideU = mask >>> center + u & 1;
|
|
18131
|
+
const sideV = mask >>> center + v & 1;
|
|
18132
|
+
const corner = sideU && sideV ? 1 : mask >>> center + u + v & 1;
|
|
18133
|
+
return 1 - (sideU + sideV + corner) * 0.2;
|
|
18134
|
+
}
|
|
18135
|
+
function quadAmbientOcclusion(positions, normals, quad, mask, output) {
|
|
18136
|
+
output.fill(1);
|
|
18137
|
+
if (!mask) return;
|
|
18138
|
+
const start = quad * 12;
|
|
18139
|
+
let axis = 0;
|
|
18140
|
+
if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
|
|
18141
|
+
if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
|
|
18142
|
+
const uAxis = (axis + 1) % 3, vAxis = (axis + 2) % 3;
|
|
18143
|
+
if (Math.abs(Math.abs(normals[start + axis]) - 1) > 1e-6 || Math.abs(normals[start + uAxis]) > 1e-6 || Math.abs(normals[start + vAxis]) > 1e-6) return;
|
|
18144
|
+
const sign = normals[start + axis] > 0 ? 1 : -1;
|
|
18145
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18146
|
+
const offset = start + vertex * 3;
|
|
18147
|
+
if (Math.abs(positions[offset + axis] - sign * 8) > 16e-4 || Math.abs(positions[offset + uAxis]) > 8.0016 || Math.abs(positions[offset + vAxis]) > 8.0016) return;
|
|
18148
|
+
}
|
|
18149
|
+
const center = 13 + sign * AXIS_STRIDES[axis];
|
|
18150
|
+
const u = AXIS_STRIDES[uAxis], v = AXIS_STRIDES[vAxis];
|
|
18151
|
+
const lowLow = cornerBrightness(mask, center, -u, -v);
|
|
18152
|
+
const highLow = cornerBrightness(mask, center, u, -v);
|
|
18153
|
+
const lowHigh = cornerBrightness(mask, center, -u, v);
|
|
18154
|
+
const highHigh = cornerBrightness(mask, center, u, v);
|
|
18155
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18156
|
+
const offset = start + vertex * 3;
|
|
18157
|
+
const a = Math.max(0, Math.min(1, (positions[offset + uAxis] + 8) / 16));
|
|
18158
|
+
const b = Math.max(0, Math.min(1, (positions[offset + vAxis] + 8) / 16));
|
|
18159
|
+
output[vertex] = (lowLow * (1 - a) + highLow * a) * (1 - b) + (lowHigh * (1 - a) + highHigh * a) * b;
|
|
18160
|
+
}
|
|
18161
|
+
}
|
|
18162
|
+
|
|
18080
18163
|
// src/world/_light/FaceLight.ts
|
|
18081
18164
|
function lightBrightness(level, ambient = 0) {
|
|
18082
18165
|
if (level === 255) return 1;
|
|
@@ -18102,7 +18185,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18102
18185
|
|
|
18103
18186
|
// src/world/SectionGeometry.ts
|
|
18104
18187
|
function buildSectionGeometry(input) {
|
|
18105
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
|
|
18188
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
18106
18189
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18107
18190
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18108
18191
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
@@ -18113,6 +18196,10 @@ function buildSectionGeometry(input) {
|
|
|
18113
18196
|
if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
|
|
18114
18197
|
throw new RangeError("Section ambient light must be a number from 0 to 1");
|
|
18115
18198
|
}
|
|
18199
|
+
if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some((value) => value > 1))) {
|
|
18200
|
+
throw new RangeError("Section ambient occlusion must cover an 18\xD718\xD718 neighborhood with zero or one per cell");
|
|
18201
|
+
}
|
|
18202
|
+
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18116
18203
|
for (const template of templateData) {
|
|
18117
18204
|
const { quads } = template;
|
|
18118
18205
|
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) {
|
|
@@ -18207,6 +18294,7 @@ function buildSectionGeometry(input) {
|
|
|
18207
18294
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
18208
18295
|
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
18209
18296
|
const outputIndices = new Uint32Array(faces * 6);
|
|
18297
|
+
const blockIndices = new Uint16Array(faces);
|
|
18210
18298
|
let vertex = 0, indexOffset = 0;
|
|
18211
18299
|
for (const entry of page.entries) {
|
|
18212
18300
|
const template = templateData[templates[entry]];
|
|
@@ -18218,8 +18306,11 @@ function buildSectionGeometry(input) {
|
|
|
18218
18306
|
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
18219
18307
|
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
18220
18308
|
const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
|
|
18309
|
+
const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
|
|
18221
18310
|
for (let quad = 0; quad < template.quads; quad++) {
|
|
18222
18311
|
if (cullMasks[entry] & template.cullFaces[quad]) continue;
|
|
18312
|
+
blockIndices[indexOffset / 6] = indices[entry];
|
|
18313
|
+
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
18223
18314
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
18224
18315
|
const start = vertex;
|
|
18225
18316
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
@@ -18236,9 +18327,10 @@ function buildSectionGeometry(input) {
|
|
|
18236
18327
|
uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
18237
18328
|
uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
18238
18329
|
uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
18239
|
-
|
|
18240
|
-
colors[vertex * 3
|
|
18241
|
-
colors[vertex * 3 +
|
|
18330
|
+
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
18331
|
+
colors[vertex * 3] = template.colors[source * 3] * factor;
|
|
18332
|
+
colors[vertex * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
18333
|
+
colors[vertex * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
18242
18334
|
}
|
|
18243
18335
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
18244
18336
|
}
|
|
@@ -18250,6 +18342,7 @@ function buildSectionGeometry(input) {
|
|
|
18250
18342
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
18251
18343
|
const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
|
|
18252
18344
|
for (let quad = 0; quad < quads.sprites.length; quad++) {
|
|
18345
|
+
blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
|
|
18253
18346
|
const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
|
|
18254
18347
|
const brightness = light ? lightBrightness(fluidLightLevel(
|
|
18255
18348
|
light[lightIndex],
|
|
@@ -18280,11 +18373,11 @@ function buildSectionGeometry(input) {
|
|
|
18280
18373
|
indexOffset += 6;
|
|
18281
18374
|
}
|
|
18282
18375
|
}
|
|
18283
|
-
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
|
|
18376
|
+
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
|
|
18284
18377
|
});
|
|
18285
18378
|
}
|
|
18286
18379
|
function sectionGeometryTransferables(pages) {
|
|
18287
|
-
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
|
|
18380
|
+
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer, page.blockIndices.buffer]);
|
|
18288
18381
|
}
|
|
18289
18382
|
|
|
18290
18383
|
// src/world/SectionWorker.ts
|
|
@@ -18387,7 +18480,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
18387
18480
|
indices: new Uint16Array(quads * 6),
|
|
18388
18481
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
18389
18482
|
atlas: 0,
|
|
18390
|
-
layer: template.layer
|
|
18483
|
+
layer: template.layer,
|
|
18484
|
+
ambientOcclusion: template.ambientOcclusion
|
|
18391
18485
|
};
|
|
18392
18486
|
const normal = template.geometry.getAttribute("normal");
|
|
18393
18487
|
const uv = template.geometry.getAttribute("uv");
|
|
@@ -18442,6 +18536,12 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18442
18536
|
constructor() {
|
|
18443
18537
|
super(...arguments);
|
|
18444
18538
|
this.ownedMeshes = [];
|
|
18539
|
+
this.blockIndices = /* @__PURE__ */ new Map();
|
|
18540
|
+
}
|
|
18541
|
+
/** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
|
|
18542
|
+
getBlockIndex(hit) {
|
|
18543
|
+
if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
|
|
18544
|
+
return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
|
|
18445
18545
|
}
|
|
18446
18546
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
18447
18547
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
@@ -18484,6 +18584,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18484
18584
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
18485
18585
|
const mesh = new Mesh10(geometry, material);
|
|
18486
18586
|
section.add(mesh);
|
|
18587
|
+
section.blockIndices.set(mesh, page.blockIndices);
|
|
18487
18588
|
const unsubscribe = [];
|
|
18488
18589
|
for (const { atlas: id, x, y } of page.placements) {
|
|
18489
18590
|
const atlas = atlases[id];
|
|
@@ -18509,6 +18610,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18509
18610
|
mesh.material.dispose();
|
|
18510
18611
|
texture?.dispose();
|
|
18511
18612
|
}
|
|
18613
|
+
this.blockIndices.clear();
|
|
18512
18614
|
this.removeFromParent();
|
|
18513
18615
|
super.dispose();
|
|
18514
18616
|
}
|
|
@@ -18518,6 +18620,8 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18518
18620
|
init_FluidGeometry();
|
|
18519
18621
|
init_FluidQuads();
|
|
18520
18622
|
init_CubeFace();
|
|
18623
|
+
init_InstanceReference();
|
|
18624
|
+
init_three();
|
|
18521
18625
|
var WATER_TINT2 = new Color13(4159204).toArray();
|
|
18522
18626
|
var Chunk = class _Chunk {
|
|
18523
18627
|
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
@@ -18531,6 +18635,7 @@ var Chunk = class _Chunk {
|
|
|
18531
18635
|
this.ambientLight = ambientLight;
|
|
18532
18636
|
this.data = new ChunkData();
|
|
18533
18637
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
18638
|
+
this.objectBlocks = /* @__PURE__ */ new Set();
|
|
18534
18639
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
18535
18640
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
18536
18641
|
this.fluidCells = new Uint8Array(4096);
|
|
@@ -18542,6 +18647,89 @@ var Chunk = class _Chunk {
|
|
|
18542
18647
|
this.y = y;
|
|
18543
18648
|
this.z = z;
|
|
18544
18649
|
}
|
|
18650
|
+
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
18651
|
+
static raycast(chunks, raycaster) {
|
|
18652
|
+
const roots = /* @__PURE__ */ new Map();
|
|
18653
|
+
const targets = /* @__PURE__ */ new Map();
|
|
18654
|
+
const meshes = (root, scene) => {
|
|
18655
|
+
const cached2 = roots.get(root);
|
|
18656
|
+
if (cached2) return cached2;
|
|
18657
|
+
const result = [];
|
|
18658
|
+
roots.set(root, result);
|
|
18659
|
+
let attached = false;
|
|
18660
|
+
for (let parent = root; parent; parent = parent.parent) {
|
|
18661
|
+
if (!parent.visible) return result;
|
|
18662
|
+
if (parent === scene) attached = true;
|
|
18663
|
+
}
|
|
18664
|
+
if (!attached) return result;
|
|
18665
|
+
root.updateWorldMatrix(true, true);
|
|
18666
|
+
root.traverseVisible((object4) => {
|
|
18667
|
+
if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
|
|
18668
|
+
});
|
|
18669
|
+
return result;
|
|
18670
|
+
};
|
|
18671
|
+
const add = (root, owner, reference) => {
|
|
18672
|
+
for (const mesh of meshes(root, owner.chunk.scene)) {
|
|
18673
|
+
if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
|
|
18674
|
+
let entry = targets.get(mesh);
|
|
18675
|
+
if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
|
|
18676
|
+
entry.owners.set(reference?.index, owner);
|
|
18677
|
+
}
|
|
18678
|
+
};
|
|
18679
|
+
for (const chunk of chunks) {
|
|
18680
|
+
for (const index of chunk.objectBlocks) {
|
|
18681
|
+
const block = chunk.renderedBlocks.get(index).object;
|
|
18682
|
+
if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
|
|
18683
|
+
const owner = { chunk, index };
|
|
18684
|
+
for (const model of block.models) {
|
|
18685
|
+
if (isInstanceReference(model)) {
|
|
18686
|
+
if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
|
|
18687
|
+
} else {
|
|
18688
|
+
add(model, owner);
|
|
18689
|
+
}
|
|
18690
|
+
}
|
|
18691
|
+
for (const entity of block.blockEntities) add(entity, owner);
|
|
18692
|
+
}
|
|
18693
|
+
if (chunk.sectionMesh) {
|
|
18694
|
+
for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
|
|
18695
|
+
targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
|
|
18696
|
+
}
|
|
18697
|
+
}
|
|
18698
|
+
}
|
|
18699
|
+
for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
|
|
18700
|
+
if (!hit.face) continue;
|
|
18701
|
+
const mesh = hit.object;
|
|
18702
|
+
const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
|
|
18703
|
+
if (!material?.visible) continue;
|
|
18704
|
+
const entry = targets.get(mesh);
|
|
18705
|
+
let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
|
|
18706
|
+
if (entry.section) {
|
|
18707
|
+
const index = entry.section.mesh.getBlockIndex(hit);
|
|
18708
|
+
if (index !== void 0) owner = { chunk: entry.section.chunk, index };
|
|
18709
|
+
}
|
|
18710
|
+
if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
|
|
18711
|
+
const info = owner.chunk.renderedBlocks.get(owner.index);
|
|
18712
|
+
if (!info) continue;
|
|
18713
|
+
const matrix = mesh.matrixWorld.clone();
|
|
18714
|
+
if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
|
|
18715
|
+
const instance = new Matrix413();
|
|
18716
|
+
mesh.getMatrixAt(hit.instanceId, instance);
|
|
18717
|
+
matrix.multiply(instance);
|
|
18718
|
+
}
|
|
18719
|
+
return {
|
|
18720
|
+
position: new Vector318(
|
|
18721
|
+
owner.chunk.x * 16 + owner.index % 16,
|
|
18722
|
+
owner.chunk.y * 16 + Math.floor(owner.index / 256),
|
|
18723
|
+
owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
|
|
18724
|
+
),
|
|
18725
|
+
block: info.block,
|
|
18726
|
+
point: hit.point.clone(),
|
|
18727
|
+
normal: hit.face.normal.clone().applyNormalMatrix(new Matrix33().getNormalMatrix(matrix)),
|
|
18728
|
+
distance: hit.distance
|
|
18729
|
+
};
|
|
18730
|
+
}
|
|
18731
|
+
return void 0;
|
|
18732
|
+
}
|
|
18545
18733
|
getBlockAt(posOrX, y, z) {
|
|
18546
18734
|
if (typeof posOrX == "number") {
|
|
18547
18735
|
return this.getBlockAt(new Vector318(posOrX, y, z));
|
|
@@ -18662,6 +18850,7 @@ var Chunk = class _Chunk {
|
|
|
18662
18850
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
18663
18851
|
this.fluidCells[index] = 0;
|
|
18664
18852
|
this.renderedBlocks.delete(index);
|
|
18853
|
+
this.objectBlocks.delete(index);
|
|
18665
18854
|
const worldPos = new Vector318(
|
|
18666
18855
|
this.x * 16 + index % 16,
|
|
18667
18856
|
this.y * 16 + Math.floor(index / 256),
|
|
@@ -18704,6 +18893,7 @@ var Chunk = class _Chunk {
|
|
|
18704
18893
|
this.renderedBlocks.set(index, { get block() {
|
|
18705
18894
|
return readBlock();
|
|
18706
18895
|
}, object: object4 });
|
|
18896
|
+
if (object4) this.objectBlocks.add(index);
|
|
18707
18897
|
} catch (error) {
|
|
18708
18898
|
this.data.assign(index, 0);
|
|
18709
18899
|
this.fluidCells[index] = 0;
|
|
@@ -18722,6 +18912,7 @@ var Chunk = class _Chunk {
|
|
|
18722
18912
|
this.fluidCells.fill(0);
|
|
18723
18913
|
this.waterTints = void 0;
|
|
18724
18914
|
this.renderedBlocks.clear();
|
|
18915
|
+
this.objectBlocks.clear();
|
|
18725
18916
|
this.hiddenBlocks.clear();
|
|
18726
18917
|
this.meshDirty = true;
|
|
18727
18918
|
this.data.copyFrom(data);
|
|
@@ -18771,6 +18962,7 @@ var Chunk = class _Chunk {
|
|
|
18771
18962
|
this.renderedBlocks.set(index, { get block() {
|
|
18772
18963
|
return readBlock();
|
|
18773
18964
|
}, object: void 0 });
|
|
18965
|
+
this.objectBlocks.delete(index);
|
|
18774
18966
|
} catch (error) {
|
|
18775
18967
|
this.data.assign(index, 0);
|
|
18776
18968
|
this.fluidCells[index] = 0;
|
|
@@ -18796,10 +18988,12 @@ var Chunk = class _Chunk {
|
|
|
18796
18988
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
18797
18989
|
));
|
|
18798
18990
|
this.renderedBlocks.get(index).object = object4;
|
|
18991
|
+
this.objectBlocks.add(index);
|
|
18799
18992
|
} catch (error) {
|
|
18800
18993
|
this.data.assign(index, 0);
|
|
18801
18994
|
this.fluidCells[index] = 0;
|
|
18802
18995
|
this.renderedBlocks.delete(index);
|
|
18996
|
+
this.objectBlocks.delete(index);
|
|
18803
18997
|
object4?.removeFromScene();
|
|
18804
18998
|
if (!failed) failure = error;
|
|
18805
18999
|
failed = true;
|
|
@@ -18817,6 +19011,25 @@ var Chunk = class _Chunk {
|
|
|
18817
19011
|
if (this.renderedBlocks.has(index)) this.meshDirty = true;
|
|
18818
19012
|
}
|
|
18819
19013
|
}
|
|
19014
|
+
/** Refreshes baked corner shading after edits or a world setting change. Disabled chunks keep no AO neighborhood. */
|
|
19015
|
+
refreshAmbientOcclusion(enabled) {
|
|
19016
|
+
if (!enabled && !this.ambientOcclusionCells) return;
|
|
19017
|
+
const cells = enabled ? this.buildAmbientOcclusionCells() : void 0;
|
|
19018
|
+
if (cells?.some((value, index) => value !== this.ambientOcclusionCells?.[index]) || !!cells !== !!this.ambientOcclusionCells) this.meshDirty = true;
|
|
19019
|
+
this.ambientOcclusionCells = cells;
|
|
19020
|
+
}
|
|
19021
|
+
buildAmbientOcclusionCells() {
|
|
19022
|
+
const cells = new Uint8Array(18 * 18 * 18);
|
|
19023
|
+
for (let y = -1; y <= 16; y++) {
|
|
19024
|
+
for (let z = -1; z <= 16; z++) {
|
|
19025
|
+
for (let x = -1; x <= 16; x++) {
|
|
19026
|
+
const inner = x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 16;
|
|
19027
|
+
cells[(y + 1) * 324 + (z + 1) * 18 + x + 1] = inner ? Number(this.isOccludingIndex(y * 256 + z * 16 + x)) : Number(!!((this.neighborCell?.(this.x * 16 + x, this.y * 16 + y, this.z * 16 + z) ?? 0) & 64));
|
|
19028
|
+
}
|
|
19029
|
+
}
|
|
19030
|
+
}
|
|
19031
|
+
return cells;
|
|
19032
|
+
}
|
|
18820
19033
|
biomePosition(index, blockState3, stored) {
|
|
18821
19034
|
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18822
19035
|
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
@@ -19005,12 +19218,18 @@ var Chunk = class _Chunk {
|
|
|
19005
19218
|
}
|
|
19006
19219
|
}
|
|
19007
19220
|
}
|
|
19008
|
-
|
|
19009
|
-
|
|
19010
|
-
|
|
19011
|
-
|
|
19012
|
-
|
|
19013
|
-
|
|
19221
|
+
let next;
|
|
19222
|
+
try {
|
|
19223
|
+
next = entries.length || fluids ? await SectionMesh.buildAsync(
|
|
19224
|
+
entries,
|
|
19225
|
+
this.sectionModels.maxAtlasSize,
|
|
19226
|
+
fluids,
|
|
19227
|
+
{ light, ambientLight: this.ambientLight, ambientOcclusion: this.ambientOcclusionCells }
|
|
19228
|
+
) : void 0;
|
|
19229
|
+
} catch (error) {
|
|
19230
|
+
if (generation === this.meshGeneration) this.meshDirty = true;
|
|
19231
|
+
throw error;
|
|
19232
|
+
}
|
|
19014
19233
|
if (generation !== this.meshGeneration) {
|
|
19015
19234
|
next?.dispose();
|
|
19016
19235
|
return;
|
|
@@ -19035,9 +19254,11 @@ var Chunk = class _Chunk {
|
|
|
19035
19254
|
this.sectionMesh = void 0;
|
|
19036
19255
|
this.meshDirty = false;
|
|
19037
19256
|
this.renderedBlocks.clear();
|
|
19257
|
+
this.objectBlocks.clear();
|
|
19038
19258
|
this.hiddenBlocks.clear();
|
|
19039
19259
|
this.fluidCells.fill(0);
|
|
19040
19260
|
this.waterTints = void 0;
|
|
19261
|
+
this.ambientOcclusionCells = void 0;
|
|
19041
19262
|
this.data.clear();
|
|
19042
19263
|
this.biomes = void 0;
|
|
19043
19264
|
if (notify) {
|