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.js
CHANGED
|
@@ -12633,6 +12633,10 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12633
12633
|
get blockEntities() {
|
|
12634
12634
|
return this._entities;
|
|
12635
12635
|
}
|
|
12636
|
+
/** Model placements drawn for this block, including its fluid surface. */
|
|
12637
|
+
get models() {
|
|
12638
|
+
return this._models;
|
|
12639
|
+
}
|
|
12636
12640
|
/** Sets visibility for this block's model instances and block entities. */
|
|
12637
12641
|
setVisible(visible) {
|
|
12638
12642
|
this.visible = visible;
|
|
@@ -17565,7 +17569,8 @@ var SectionModels = class {
|
|
|
17565
17569
|
atlas,
|
|
17566
17570
|
cullFaces: new Uint8Array(cullFaces),
|
|
17567
17571
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17568
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
17572
|
+
layer: atlas.hasTranslucency ? 1 : 0,
|
|
17573
|
+
ambientOcclusion: model.ambientocclusion !== false
|
|
17569
17574
|
};
|
|
17570
17575
|
this.templates.add(template);
|
|
17571
17576
|
return template;
|
|
@@ -17756,17 +17761,45 @@ var MineRenderWorld = class {
|
|
|
17756
17761
|
this.light = /* @__PURE__ */ new Map();
|
|
17757
17762
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
17758
17763
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
17764
|
+
this.ambientOcclusionPending = false;
|
|
17759
17765
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
17760
17766
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
17767
|
+
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17761
17768
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
17762
17769
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
17763
17770
|
}
|
|
17764
17771
|
this.scene = scene;
|
|
17765
17772
|
this.savedLighting = options.savedLighting ?? false;
|
|
17766
17773
|
this.ambientLight = options.ambientLight ?? 0;
|
|
17774
|
+
this._ambientOcclusion = options.ambientOcclusion ?? false;
|
|
17767
17775
|
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
17768
17776
|
if (options.renderEntities) this.entities = new WorldEntities(scene);
|
|
17769
17777
|
}
|
|
17778
|
+
/**
|
|
17779
|
+
* Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
|
|
17780
|
+
* Includes fluids and block entities; texture alpha does not change triangle intersections.
|
|
17781
|
+
*/
|
|
17782
|
+
raycast(raycaster) {
|
|
17783
|
+
return Chunk.raycast(this._chunks.values(), raycaster);
|
|
17784
|
+
}
|
|
17785
|
+
/** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
|
|
17786
|
+
get ambientOcclusion() {
|
|
17787
|
+
return this._ambientOcclusion;
|
|
17788
|
+
}
|
|
17789
|
+
/** Rebuilds loaded blocks with or without corner shading. Block data and saved lighting are preserved. */
|
|
17790
|
+
async setAmbientOcclusion(enabled) {
|
|
17791
|
+
if (typeof enabled !== "boolean") throw new TypeError("Ambient occlusion must be a boolean");
|
|
17792
|
+
if (enabled && !this.sectionModels) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17793
|
+
if (enabled === this._ambientOcclusion && !this.ambientOcclusionPending) {
|
|
17794
|
+
await this.culling;
|
|
17795
|
+
return;
|
|
17796
|
+
}
|
|
17797
|
+
this._ambientOcclusion = enabled;
|
|
17798
|
+
this.ambientOcclusionPending = true;
|
|
17799
|
+
for (const chunk of this._chunks.values()) this.pendingCulling.set(chunk, "all");
|
|
17800
|
+
await this.updateCulling([]);
|
|
17801
|
+
this.ambientOcclusionPending = false;
|
|
17802
|
+
}
|
|
17770
17803
|
getBlockAt(posOrX, y, z) {
|
|
17771
17804
|
if (typeof posOrX == "number") {
|
|
17772
17805
|
return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
|
|
@@ -18090,7 +18123,7 @@ var MineRenderWorld = class {
|
|
|
18090
18123
|
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
18091
18124
|
let pending = this.pendingCulling.get(section);
|
|
18092
18125
|
if (pending === "all" || pending?.has(index)) continue;
|
|
18093
|
-
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !section.isFluidIndex(index)) continue;
|
|
18126
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !this._ambientOcclusion && !section.isFluidIndex(index)) continue;
|
|
18094
18127
|
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
18095
18128
|
pending.add(index);
|
|
18096
18129
|
}
|
|
@@ -18098,6 +18131,7 @@ var MineRenderWorld = class {
|
|
|
18098
18131
|
}
|
|
18099
18132
|
}
|
|
18100
18133
|
return this.culling ??= Promise.resolve().then(async () => {
|
|
18134
|
+
let sliceStart = performance.now();
|
|
18101
18135
|
try {
|
|
18102
18136
|
while (this.pendingCulling.size) {
|
|
18103
18137
|
const batch = [...this.pendingCulling];
|
|
@@ -18133,6 +18167,11 @@ var MineRenderWorld = class {
|
|
|
18133
18167
|
}
|
|
18134
18168
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
18135
18169
|
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
18170
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
18171
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
18172
|
+
await yieldToEventLoop();
|
|
18173
|
+
sliceStart = performance.now();
|
|
18174
|
+
}
|
|
18136
18175
|
}
|
|
18137
18176
|
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
18138
18177
|
}
|
|
@@ -18239,6 +18278,50 @@ init_Materials();
|
|
|
18239
18278
|
// src/world/SectionGeometry.ts
|
|
18240
18279
|
init_FluidQuads();
|
|
18241
18280
|
|
|
18281
|
+
// src/world/_light/AmbientOcclusion.ts
|
|
18282
|
+
var AXIS_STRIDES = [1, 9, 3];
|
|
18283
|
+
function sectionAmbientOcclusionMask(cells, center) {
|
|
18284
|
+
let mask = 0;
|
|
18285
|
+
for (let y = -1; y <= 1; y++) for (let z = -1; z <= 1; z++) for (let x = -1; x <= 1; x++) {
|
|
18286
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) < 2) continue;
|
|
18287
|
+
if (cells[center + y * 324 + z * 18 + x]) mask |= 1 << (y + 1) * 9 + (z + 1) * 3 + x + 1;
|
|
18288
|
+
}
|
|
18289
|
+
return mask;
|
|
18290
|
+
}
|
|
18291
|
+
function cornerBrightness(mask, center, u, v) {
|
|
18292
|
+
const sideU = mask >>> center + u & 1;
|
|
18293
|
+
const sideV = mask >>> center + v & 1;
|
|
18294
|
+
const corner = sideU && sideV ? 1 : mask >>> center + u + v & 1;
|
|
18295
|
+
return 1 - (sideU + sideV + corner) * 0.2;
|
|
18296
|
+
}
|
|
18297
|
+
function quadAmbientOcclusion(positions, normals, quad, mask, output) {
|
|
18298
|
+
output.fill(1);
|
|
18299
|
+
if (!mask) return;
|
|
18300
|
+
const start = quad * 12;
|
|
18301
|
+
let axis = 0;
|
|
18302
|
+
if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
|
|
18303
|
+
if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
|
|
18304
|
+
const uAxis = (axis + 1) % 3, vAxis = (axis + 2) % 3;
|
|
18305
|
+
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;
|
|
18306
|
+
const sign = normals[start + axis] > 0 ? 1 : -1;
|
|
18307
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18308
|
+
const offset = start + vertex * 3;
|
|
18309
|
+
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;
|
|
18310
|
+
}
|
|
18311
|
+
const center = 13 + sign * AXIS_STRIDES[axis];
|
|
18312
|
+
const u = AXIS_STRIDES[uAxis], v = AXIS_STRIDES[vAxis];
|
|
18313
|
+
const lowLow = cornerBrightness(mask, center, -u, -v);
|
|
18314
|
+
const highLow = cornerBrightness(mask, center, u, -v);
|
|
18315
|
+
const lowHigh = cornerBrightness(mask, center, -u, v);
|
|
18316
|
+
const highHigh = cornerBrightness(mask, center, u, v);
|
|
18317
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18318
|
+
const offset = start + vertex * 3;
|
|
18319
|
+
const a = Math.max(0, Math.min(1, (positions[offset + uAxis] + 8) / 16));
|
|
18320
|
+
const b = Math.max(0, Math.min(1, (positions[offset + vAxis] + 8) / 16));
|
|
18321
|
+
output[vertex] = (lowLow * (1 - a) + highLow * a) * (1 - b) + (lowHigh * (1 - a) + highHigh * a) * b;
|
|
18322
|
+
}
|
|
18323
|
+
}
|
|
18324
|
+
|
|
18242
18325
|
// src/world/_light/FaceLight.ts
|
|
18243
18326
|
function lightBrightness(level, ambient = 0) {
|
|
18244
18327
|
if (level === 255) return 1;
|
|
@@ -18264,7 +18347,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18264
18347
|
|
|
18265
18348
|
// src/world/SectionGeometry.ts
|
|
18266
18349
|
function buildSectionGeometry(input) {
|
|
18267
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
|
|
18350
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
18268
18351
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18269
18352
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18270
18353
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
@@ -18275,6 +18358,10 @@ function buildSectionGeometry(input) {
|
|
|
18275
18358
|
if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
|
|
18276
18359
|
throw new RangeError("Section ambient light must be a number from 0 to 1");
|
|
18277
18360
|
}
|
|
18361
|
+
if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some((value) => value > 1))) {
|
|
18362
|
+
throw new RangeError("Section ambient occlusion must cover an 18\xD718\xD718 neighborhood with zero or one per cell");
|
|
18363
|
+
}
|
|
18364
|
+
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18278
18365
|
for (const template of templateData) {
|
|
18279
18366
|
const { quads } = template;
|
|
18280
18367
|
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) {
|
|
@@ -18369,6 +18456,7 @@ function buildSectionGeometry(input) {
|
|
|
18369
18456
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
18370
18457
|
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
18371
18458
|
const outputIndices = new Uint32Array(faces * 6);
|
|
18459
|
+
const blockIndices = new Uint16Array(faces);
|
|
18372
18460
|
let vertex = 0, indexOffset = 0;
|
|
18373
18461
|
for (const entry of page.entries) {
|
|
18374
18462
|
const template = templateData[templates[entry]];
|
|
@@ -18380,8 +18468,11 @@ function buildSectionGeometry(input) {
|
|
|
18380
18468
|
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
18381
18469
|
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
18382
18470
|
const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
|
|
18471
|
+
const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
|
|
18383
18472
|
for (let quad = 0; quad < template.quads; quad++) {
|
|
18384
18473
|
if (cullMasks[entry] & template.cullFaces[quad]) continue;
|
|
18474
|
+
blockIndices[indexOffset / 6] = indices[entry];
|
|
18475
|
+
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
18385
18476
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
18386
18477
|
const start = vertex;
|
|
18387
18478
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
@@ -18398,9 +18489,10 @@ function buildSectionGeometry(input) {
|
|
|
18398
18489
|
uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
18399
18490
|
uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
18400
18491
|
uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
18401
|
-
|
|
18402
|
-
colors[vertex * 3
|
|
18403
|
-
colors[vertex * 3 +
|
|
18492
|
+
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
18493
|
+
colors[vertex * 3] = template.colors[source * 3] * factor;
|
|
18494
|
+
colors[vertex * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
18495
|
+
colors[vertex * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
18404
18496
|
}
|
|
18405
18497
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
18406
18498
|
}
|
|
@@ -18412,6 +18504,7 @@ function buildSectionGeometry(input) {
|
|
|
18412
18504
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
18413
18505
|
const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
|
|
18414
18506
|
for (let quad = 0; quad < quads.sprites.length; quad++) {
|
|
18507
|
+
blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
|
|
18415
18508
|
const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
|
|
18416
18509
|
const brightness = light ? lightBrightness(fluidLightLevel(
|
|
18417
18510
|
light[lightIndex],
|
|
@@ -18442,11 +18535,11 @@ function buildSectionGeometry(input) {
|
|
|
18442
18535
|
indexOffset += 6;
|
|
18443
18536
|
}
|
|
18444
18537
|
}
|
|
18445
|
-
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
|
|
18538
|
+
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
|
|
18446
18539
|
});
|
|
18447
18540
|
}
|
|
18448
18541
|
function sectionGeometryTransferables(pages) {
|
|
18449
|
-
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
|
|
18542
|
+
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]);
|
|
18450
18543
|
}
|
|
18451
18544
|
|
|
18452
18545
|
// src/world/SectionWorker.ts
|
|
@@ -18549,7 +18642,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
18549
18642
|
indices: new Uint16Array(quads * 6),
|
|
18550
18643
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
18551
18644
|
atlas: 0,
|
|
18552
|
-
layer: template.layer
|
|
18645
|
+
layer: template.layer,
|
|
18646
|
+
ambientOcclusion: template.ambientOcclusion
|
|
18553
18647
|
};
|
|
18554
18648
|
const normal = template.geometry.getAttribute("normal");
|
|
18555
18649
|
const uv = template.geometry.getAttribute("uv");
|
|
@@ -18604,6 +18698,12 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18604
18698
|
constructor() {
|
|
18605
18699
|
super(...arguments);
|
|
18606
18700
|
this.ownedMeshes = [];
|
|
18701
|
+
this.blockIndices = /* @__PURE__ */ new Map();
|
|
18702
|
+
}
|
|
18703
|
+
/** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
|
|
18704
|
+
getBlockIndex(hit) {
|
|
18705
|
+
if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
|
|
18706
|
+
return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
|
|
18607
18707
|
}
|
|
18608
18708
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
18609
18709
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
@@ -18646,6 +18746,7 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18646
18746
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
18647
18747
|
const mesh = new import_three43.Mesh(geometry, material);
|
|
18648
18748
|
section.add(mesh);
|
|
18749
|
+
section.blockIndices.set(mesh, page.blockIndices);
|
|
18649
18750
|
const unsubscribe = [];
|
|
18650
18751
|
for (const { atlas: id, x, y } of page.placements) {
|
|
18651
18752
|
const atlas = atlases[id];
|
|
@@ -18671,6 +18772,7 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18671
18772
|
mesh.material.dispose();
|
|
18672
18773
|
texture?.dispose();
|
|
18673
18774
|
}
|
|
18775
|
+
this.blockIndices.clear();
|
|
18674
18776
|
this.removeFromParent();
|
|
18675
18777
|
super.dispose();
|
|
18676
18778
|
}
|
|
@@ -18680,6 +18782,8 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18680
18782
|
init_FluidGeometry();
|
|
18681
18783
|
init_FluidQuads();
|
|
18682
18784
|
init_CubeFace();
|
|
18785
|
+
init_InstanceReference();
|
|
18786
|
+
init_three();
|
|
18683
18787
|
var WATER_TINT2 = new import_three44.Color(4159204).toArray();
|
|
18684
18788
|
var Chunk = class _Chunk {
|
|
18685
18789
|
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
@@ -18693,6 +18797,7 @@ var Chunk = class _Chunk {
|
|
|
18693
18797
|
this.ambientLight = ambientLight;
|
|
18694
18798
|
this.data = new ChunkData();
|
|
18695
18799
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
18800
|
+
this.objectBlocks = /* @__PURE__ */ new Set();
|
|
18696
18801
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
18697
18802
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
18698
18803
|
this.fluidCells = new Uint8Array(4096);
|
|
@@ -18704,6 +18809,89 @@ var Chunk = class _Chunk {
|
|
|
18704
18809
|
this.y = y;
|
|
18705
18810
|
this.z = z;
|
|
18706
18811
|
}
|
|
18812
|
+
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
18813
|
+
static raycast(chunks, raycaster) {
|
|
18814
|
+
const roots = /* @__PURE__ */ new Map();
|
|
18815
|
+
const targets = /* @__PURE__ */ new Map();
|
|
18816
|
+
const meshes = (root, scene) => {
|
|
18817
|
+
const cached2 = roots.get(root);
|
|
18818
|
+
if (cached2) return cached2;
|
|
18819
|
+
const result = [];
|
|
18820
|
+
roots.set(root, result);
|
|
18821
|
+
let attached = false;
|
|
18822
|
+
for (let parent = root; parent; parent = parent.parent) {
|
|
18823
|
+
if (!parent.visible) return result;
|
|
18824
|
+
if (parent === scene) attached = true;
|
|
18825
|
+
}
|
|
18826
|
+
if (!attached) return result;
|
|
18827
|
+
root.updateWorldMatrix(true, true);
|
|
18828
|
+
root.traverseVisible((object4) => {
|
|
18829
|
+
if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
|
|
18830
|
+
});
|
|
18831
|
+
return result;
|
|
18832
|
+
};
|
|
18833
|
+
const add = (root, owner, reference) => {
|
|
18834
|
+
for (const mesh of meshes(root, owner.chunk.scene)) {
|
|
18835
|
+
if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
|
|
18836
|
+
let entry = targets.get(mesh);
|
|
18837
|
+
if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
|
|
18838
|
+
entry.owners.set(reference?.index, owner);
|
|
18839
|
+
}
|
|
18840
|
+
};
|
|
18841
|
+
for (const chunk of chunks) {
|
|
18842
|
+
for (const index of chunk.objectBlocks) {
|
|
18843
|
+
const block = chunk.renderedBlocks.get(index).object;
|
|
18844
|
+
if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
|
|
18845
|
+
const owner = { chunk, index };
|
|
18846
|
+
for (const model of block.models) {
|
|
18847
|
+
if (isInstanceReference(model)) {
|
|
18848
|
+
if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
|
|
18849
|
+
} else {
|
|
18850
|
+
add(model, owner);
|
|
18851
|
+
}
|
|
18852
|
+
}
|
|
18853
|
+
for (const entity of block.blockEntities) add(entity, owner);
|
|
18854
|
+
}
|
|
18855
|
+
if (chunk.sectionMesh) {
|
|
18856
|
+
for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
|
|
18857
|
+
targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
|
|
18858
|
+
}
|
|
18859
|
+
}
|
|
18860
|
+
}
|
|
18861
|
+
for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
|
|
18862
|
+
if (!hit.face) continue;
|
|
18863
|
+
const mesh = hit.object;
|
|
18864
|
+
const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
|
|
18865
|
+
if (!material?.visible) continue;
|
|
18866
|
+
const entry = targets.get(mesh);
|
|
18867
|
+
let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
|
|
18868
|
+
if (entry.section) {
|
|
18869
|
+
const index = entry.section.mesh.getBlockIndex(hit);
|
|
18870
|
+
if (index !== void 0) owner = { chunk: entry.section.chunk, index };
|
|
18871
|
+
}
|
|
18872
|
+
if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
|
|
18873
|
+
const info = owner.chunk.renderedBlocks.get(owner.index);
|
|
18874
|
+
if (!info) continue;
|
|
18875
|
+
const matrix = mesh.matrixWorld.clone();
|
|
18876
|
+
if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
|
|
18877
|
+
const instance = new import_three44.Matrix4();
|
|
18878
|
+
mesh.getMatrixAt(hit.instanceId, instance);
|
|
18879
|
+
matrix.multiply(instance);
|
|
18880
|
+
}
|
|
18881
|
+
return {
|
|
18882
|
+
position: new import_three44.Vector3(
|
|
18883
|
+
owner.chunk.x * 16 + owner.index % 16,
|
|
18884
|
+
owner.chunk.y * 16 + Math.floor(owner.index / 256),
|
|
18885
|
+
owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
|
|
18886
|
+
),
|
|
18887
|
+
block: info.block,
|
|
18888
|
+
point: hit.point.clone(),
|
|
18889
|
+
normal: hit.face.normal.clone().applyNormalMatrix(new import_three44.Matrix3().getNormalMatrix(matrix)),
|
|
18890
|
+
distance: hit.distance
|
|
18891
|
+
};
|
|
18892
|
+
}
|
|
18893
|
+
return void 0;
|
|
18894
|
+
}
|
|
18707
18895
|
getBlockAt(posOrX, y, z) {
|
|
18708
18896
|
if (typeof posOrX == "number") {
|
|
18709
18897
|
return this.getBlockAt(new import_three44.Vector3(posOrX, y, z));
|
|
@@ -18824,6 +19012,7 @@ var Chunk = class _Chunk {
|
|
|
18824
19012
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
18825
19013
|
this.fluidCells[index] = 0;
|
|
18826
19014
|
this.renderedBlocks.delete(index);
|
|
19015
|
+
this.objectBlocks.delete(index);
|
|
18827
19016
|
const worldPos = new import_three44.Vector3(
|
|
18828
19017
|
this.x * 16 + index % 16,
|
|
18829
19018
|
this.y * 16 + Math.floor(index / 256),
|
|
@@ -18866,6 +19055,7 @@ var Chunk = class _Chunk {
|
|
|
18866
19055
|
this.renderedBlocks.set(index, { get block() {
|
|
18867
19056
|
return readBlock();
|
|
18868
19057
|
}, object: object4 });
|
|
19058
|
+
if (object4) this.objectBlocks.add(index);
|
|
18869
19059
|
} catch (error) {
|
|
18870
19060
|
this.data.assign(index, 0);
|
|
18871
19061
|
this.fluidCells[index] = 0;
|
|
@@ -18884,6 +19074,7 @@ var Chunk = class _Chunk {
|
|
|
18884
19074
|
this.fluidCells.fill(0);
|
|
18885
19075
|
this.waterTints = void 0;
|
|
18886
19076
|
this.renderedBlocks.clear();
|
|
19077
|
+
this.objectBlocks.clear();
|
|
18887
19078
|
this.hiddenBlocks.clear();
|
|
18888
19079
|
this.meshDirty = true;
|
|
18889
19080
|
this.data.copyFrom(data);
|
|
@@ -18933,6 +19124,7 @@ var Chunk = class _Chunk {
|
|
|
18933
19124
|
this.renderedBlocks.set(index, { get block() {
|
|
18934
19125
|
return readBlock();
|
|
18935
19126
|
}, object: void 0 });
|
|
19127
|
+
this.objectBlocks.delete(index);
|
|
18936
19128
|
} catch (error) {
|
|
18937
19129
|
this.data.assign(index, 0);
|
|
18938
19130
|
this.fluidCells[index] = 0;
|
|
@@ -18958,10 +19150,12 @@ var Chunk = class _Chunk {
|
|
|
18958
19150
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
18959
19151
|
));
|
|
18960
19152
|
this.renderedBlocks.get(index).object = object4;
|
|
19153
|
+
this.objectBlocks.add(index);
|
|
18961
19154
|
} catch (error) {
|
|
18962
19155
|
this.data.assign(index, 0);
|
|
18963
19156
|
this.fluidCells[index] = 0;
|
|
18964
19157
|
this.renderedBlocks.delete(index);
|
|
19158
|
+
this.objectBlocks.delete(index);
|
|
18965
19159
|
object4?.removeFromScene();
|
|
18966
19160
|
if (!failed) failure = error;
|
|
18967
19161
|
failed = true;
|
|
@@ -18979,6 +19173,25 @@ var Chunk = class _Chunk {
|
|
|
18979
19173
|
if (this.renderedBlocks.has(index)) this.meshDirty = true;
|
|
18980
19174
|
}
|
|
18981
19175
|
}
|
|
19176
|
+
/** Refreshes baked corner shading after edits or a world setting change. Disabled chunks keep no AO neighborhood. */
|
|
19177
|
+
refreshAmbientOcclusion(enabled) {
|
|
19178
|
+
if (!enabled && !this.ambientOcclusionCells) return;
|
|
19179
|
+
const cells = enabled ? this.buildAmbientOcclusionCells() : void 0;
|
|
19180
|
+
if (cells?.some((value, index) => value !== this.ambientOcclusionCells?.[index]) || !!cells !== !!this.ambientOcclusionCells) this.meshDirty = true;
|
|
19181
|
+
this.ambientOcclusionCells = cells;
|
|
19182
|
+
}
|
|
19183
|
+
buildAmbientOcclusionCells() {
|
|
19184
|
+
const cells = new Uint8Array(18 * 18 * 18);
|
|
19185
|
+
for (let y = -1; y <= 16; y++) {
|
|
19186
|
+
for (let z = -1; z <= 16; z++) {
|
|
19187
|
+
for (let x = -1; x <= 16; x++) {
|
|
19188
|
+
const inner = x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 16;
|
|
19189
|
+
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));
|
|
19190
|
+
}
|
|
19191
|
+
}
|
|
19192
|
+
}
|
|
19193
|
+
return cells;
|
|
19194
|
+
}
|
|
18982
19195
|
biomePosition(index, blockState3, stored) {
|
|
18983
19196
|
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18984
19197
|
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
@@ -19167,12 +19380,18 @@ var Chunk = class _Chunk {
|
|
|
19167
19380
|
}
|
|
19168
19381
|
}
|
|
19169
19382
|
}
|
|
19170
|
-
|
|
19171
|
-
|
|
19172
|
-
|
|
19173
|
-
|
|
19174
|
-
|
|
19175
|
-
|
|
19383
|
+
let next;
|
|
19384
|
+
try {
|
|
19385
|
+
next = entries.length || fluids ? await SectionMesh.buildAsync(
|
|
19386
|
+
entries,
|
|
19387
|
+
this.sectionModels.maxAtlasSize,
|
|
19388
|
+
fluids,
|
|
19389
|
+
{ light, ambientLight: this.ambientLight, ambientOcclusion: this.ambientOcclusionCells }
|
|
19390
|
+
) : void 0;
|
|
19391
|
+
} catch (error) {
|
|
19392
|
+
if (generation === this.meshGeneration) this.meshDirty = true;
|
|
19393
|
+
throw error;
|
|
19394
|
+
}
|
|
19176
19395
|
if (generation !== this.meshGeneration) {
|
|
19177
19396
|
next?.dispose();
|
|
19178
19397
|
return;
|
|
@@ -19197,9 +19416,11 @@ var Chunk = class _Chunk {
|
|
|
19197
19416
|
this.sectionMesh = void 0;
|
|
19198
19417
|
this.meshDirty = false;
|
|
19199
19418
|
this.renderedBlocks.clear();
|
|
19419
|
+
this.objectBlocks.clear();
|
|
19200
19420
|
this.hiddenBlocks.clear();
|
|
19201
19421
|
this.fluidCells.fill(0);
|
|
19202
19422
|
this.waterTints = void 0;
|
|
19423
|
+
this.ambientOcclusionCells = void 0;
|
|
19203
19424
|
this.data.clear();
|
|
19204
19425
|
this.biomes = void 0;
|
|
19205
19426
|
if (notify) {
|