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/browser/index.js
CHANGED
|
@@ -12596,6 +12596,10 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12596
12596
|
get blockEntities() {
|
|
12597
12597
|
return this._entities;
|
|
12598
12598
|
}
|
|
12599
|
+
/** Model placements drawn for this block, including its fluid surface. */
|
|
12600
|
+
get models() {
|
|
12601
|
+
return this._models;
|
|
12602
|
+
}
|
|
12599
12603
|
/** Sets visibility for this block's model instances and block entities. */
|
|
12600
12604
|
setVisible(visible) {
|
|
12601
12605
|
this.visible = visible;
|
|
@@ -17530,7 +17534,8 @@ var SectionModels = class {
|
|
|
17530
17534
|
atlas,
|
|
17531
17535
|
cullFaces: new Uint8Array(cullFaces),
|
|
17532
17536
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17533
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
17537
|
+
layer: atlas.hasTranslucency ? 1 : 0,
|
|
17538
|
+
ambientOcclusion: model.ambientocclusion !== false
|
|
17534
17539
|
};
|
|
17535
17540
|
this.templates.add(template);
|
|
17536
17541
|
return template;
|
|
@@ -17721,17 +17726,45 @@ var MineRenderWorld = class {
|
|
|
17721
17726
|
this.light = /* @__PURE__ */ new Map();
|
|
17722
17727
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
17723
17728
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
17729
|
+
this.ambientOcclusionPending = false;
|
|
17724
17730
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
17725
17731
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
17732
|
+
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17726
17733
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
17727
17734
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
17728
17735
|
}
|
|
17729
17736
|
this.scene = scene;
|
|
17730
17737
|
this.savedLighting = options.savedLighting ?? false;
|
|
17731
17738
|
this.ambientLight = options.ambientLight ?? 0;
|
|
17739
|
+
this._ambientOcclusion = options.ambientOcclusion ?? false;
|
|
17732
17740
|
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
17733
17741
|
if (options.renderEntities) this.entities = new WorldEntities(scene);
|
|
17734
17742
|
}
|
|
17743
|
+
/**
|
|
17744
|
+
* Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
|
|
17745
|
+
* Includes fluids and block entities; texture alpha does not change triangle intersections.
|
|
17746
|
+
*/
|
|
17747
|
+
raycast(raycaster) {
|
|
17748
|
+
return Chunk.raycast(this._chunks.values(), raycaster);
|
|
17749
|
+
}
|
|
17750
|
+
/** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
|
|
17751
|
+
get ambientOcclusion() {
|
|
17752
|
+
return this._ambientOcclusion;
|
|
17753
|
+
}
|
|
17754
|
+
/** Rebuilds loaded blocks with or without corner shading. Block data and saved lighting are preserved. */
|
|
17755
|
+
async setAmbientOcclusion(enabled) {
|
|
17756
|
+
if (typeof enabled !== "boolean") throw new TypeError("Ambient occlusion must be a boolean");
|
|
17757
|
+
if (enabled && !this.sectionModels) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17758
|
+
if (enabled === this._ambientOcclusion && !this.ambientOcclusionPending) {
|
|
17759
|
+
await this.culling;
|
|
17760
|
+
return;
|
|
17761
|
+
}
|
|
17762
|
+
this._ambientOcclusion = enabled;
|
|
17763
|
+
this.ambientOcclusionPending = true;
|
|
17764
|
+
for (const chunk of this._chunks.values()) this.pendingCulling.set(chunk, "all");
|
|
17765
|
+
await this.updateCulling([]);
|
|
17766
|
+
this.ambientOcclusionPending = false;
|
|
17767
|
+
}
|
|
17735
17768
|
getBlockAt(posOrX, y, z) {
|
|
17736
17769
|
if (typeof posOrX == "number") {
|
|
17737
17770
|
return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
|
|
@@ -18055,7 +18088,7 @@ var MineRenderWorld = class {
|
|
|
18055
18088
|
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
18056
18089
|
let pending = this.pendingCulling.get(section);
|
|
18057
18090
|
if (pending === "all" || pending?.has(index)) continue;
|
|
18058
|
-
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !section.isFluidIndex(index)) continue;
|
|
18091
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !this._ambientOcclusion && !section.isFluidIndex(index)) continue;
|
|
18059
18092
|
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
18060
18093
|
pending.add(index);
|
|
18061
18094
|
}
|
|
@@ -18063,6 +18096,7 @@ var MineRenderWorld = class {
|
|
|
18063
18096
|
}
|
|
18064
18097
|
}
|
|
18065
18098
|
return this.culling ?? (this.culling = Promise.resolve().then(async () => {
|
|
18099
|
+
let sliceStart = performance.now();
|
|
18066
18100
|
try {
|
|
18067
18101
|
while (this.pendingCulling.size) {
|
|
18068
18102
|
const batch = [...this.pendingCulling];
|
|
@@ -18098,6 +18132,11 @@ var MineRenderWorld = class {
|
|
|
18098
18132
|
}
|
|
18099
18133
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
18100
18134
|
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
18135
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
18136
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
18137
|
+
await yieldToEventLoop();
|
|
18138
|
+
sliceStart = performance.now();
|
|
18139
|
+
}
|
|
18101
18140
|
}
|
|
18102
18141
|
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
18103
18142
|
}
|
|
@@ -18204,6 +18243,50 @@ init_Materials();
|
|
|
18204
18243
|
// src/world/SectionGeometry.ts
|
|
18205
18244
|
init_FluidQuads();
|
|
18206
18245
|
|
|
18246
|
+
// src/world/_light/AmbientOcclusion.ts
|
|
18247
|
+
var AXIS_STRIDES = [1, 9, 3];
|
|
18248
|
+
function sectionAmbientOcclusionMask(cells, center) {
|
|
18249
|
+
let mask = 0;
|
|
18250
|
+
for (let y = -1; y <= 1; y++) for (let z = -1; z <= 1; z++) for (let x = -1; x <= 1; x++) {
|
|
18251
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) < 2) continue;
|
|
18252
|
+
if (cells[center + y * 324 + z * 18 + x]) mask |= 1 << (y + 1) * 9 + (z + 1) * 3 + x + 1;
|
|
18253
|
+
}
|
|
18254
|
+
return mask;
|
|
18255
|
+
}
|
|
18256
|
+
function cornerBrightness(mask, center, u, v) {
|
|
18257
|
+
const sideU = mask >>> center + u & 1;
|
|
18258
|
+
const sideV = mask >>> center + v & 1;
|
|
18259
|
+
const corner = sideU && sideV ? 1 : mask >>> center + u + v & 1;
|
|
18260
|
+
return 1 - (sideU + sideV + corner) * 0.2;
|
|
18261
|
+
}
|
|
18262
|
+
function quadAmbientOcclusion(positions, normals, quad, mask, output) {
|
|
18263
|
+
output.fill(1);
|
|
18264
|
+
if (!mask) return;
|
|
18265
|
+
const start = quad * 12;
|
|
18266
|
+
let axis = 0;
|
|
18267
|
+
if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
|
|
18268
|
+
if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
|
|
18269
|
+
const uAxis = (axis + 1) % 3, vAxis = (axis + 2) % 3;
|
|
18270
|
+
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;
|
|
18271
|
+
const sign = normals[start + axis] > 0 ? 1 : -1;
|
|
18272
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18273
|
+
const offset = start + vertex * 3;
|
|
18274
|
+
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;
|
|
18275
|
+
}
|
|
18276
|
+
const center = 13 + sign * AXIS_STRIDES[axis];
|
|
18277
|
+
const u = AXIS_STRIDES[uAxis], v = AXIS_STRIDES[vAxis];
|
|
18278
|
+
const lowLow = cornerBrightness(mask, center, -u, -v);
|
|
18279
|
+
const highLow = cornerBrightness(mask, center, u, -v);
|
|
18280
|
+
const lowHigh = cornerBrightness(mask, center, -u, v);
|
|
18281
|
+
const highHigh = cornerBrightness(mask, center, u, v);
|
|
18282
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18283
|
+
const offset = start + vertex * 3;
|
|
18284
|
+
const a = Math.max(0, Math.min(1, (positions[offset + uAxis] + 8) / 16));
|
|
18285
|
+
const b = Math.max(0, Math.min(1, (positions[offset + vAxis] + 8) / 16));
|
|
18286
|
+
output[vertex] = (lowLow * (1 - a) + highLow * a) * (1 - b) + (lowHigh * (1 - a) + highHigh * a) * b;
|
|
18287
|
+
}
|
|
18288
|
+
}
|
|
18289
|
+
|
|
18207
18290
|
// src/world/_light/FaceLight.ts
|
|
18208
18291
|
function lightBrightness(level, ambient = 0) {
|
|
18209
18292
|
if (level === 255) return 1;
|
|
@@ -18229,7 +18312,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18229
18312
|
|
|
18230
18313
|
// src/world/SectionGeometry.ts
|
|
18231
18314
|
function buildSectionGeometry(input) {
|
|
18232
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
|
|
18315
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
18233
18316
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18234
18317
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18235
18318
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
@@ -18240,6 +18323,10 @@ function buildSectionGeometry(input) {
|
|
|
18240
18323
|
if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
|
|
18241
18324
|
throw new RangeError("Section ambient light must be a number from 0 to 1");
|
|
18242
18325
|
}
|
|
18326
|
+
if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some((value) => value > 1))) {
|
|
18327
|
+
throw new RangeError("Section ambient occlusion must cover an 18\xD718\xD718 neighborhood with zero or one per cell");
|
|
18328
|
+
}
|
|
18329
|
+
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18243
18330
|
for (const template of templateData) {
|
|
18244
18331
|
const { quads } = template;
|
|
18245
18332
|
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) {
|
|
@@ -18334,6 +18421,7 @@ function buildSectionGeometry(input) {
|
|
|
18334
18421
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
18335
18422
|
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
18336
18423
|
const outputIndices = new Uint32Array(faces * 6);
|
|
18424
|
+
const blockIndices = new Uint16Array(faces);
|
|
18337
18425
|
let vertex = 0, indexOffset = 0;
|
|
18338
18426
|
for (const entry of page.entries) {
|
|
18339
18427
|
const template = templateData[templates[entry]];
|
|
@@ -18345,8 +18433,11 @@ function buildSectionGeometry(input) {
|
|
|
18345
18433
|
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
18346
18434
|
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
18347
18435
|
const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
|
|
18436
|
+
const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
|
|
18348
18437
|
for (let quad = 0; quad < template.quads; quad++) {
|
|
18349
18438
|
if (cullMasks[entry] & template.cullFaces[quad]) continue;
|
|
18439
|
+
blockIndices[indexOffset / 6] = indices[entry];
|
|
18440
|
+
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
18350
18441
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
18351
18442
|
const start = vertex;
|
|
18352
18443
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
@@ -18363,9 +18454,10 @@ function buildSectionGeometry(input) {
|
|
|
18363
18454
|
uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
18364
18455
|
uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
18365
18456
|
uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
18366
|
-
|
|
18367
|
-
colors[vertex * 3
|
|
18368
|
-
colors[vertex * 3 +
|
|
18457
|
+
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
18458
|
+
colors[vertex * 3] = template.colors[source * 3] * factor;
|
|
18459
|
+
colors[vertex * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
18460
|
+
colors[vertex * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
18369
18461
|
}
|
|
18370
18462
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
18371
18463
|
}
|
|
@@ -18377,6 +18469,7 @@ function buildSectionGeometry(input) {
|
|
|
18377
18469
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
18378
18470
|
const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
|
|
18379
18471
|
for (let quad = 0; quad < quads.sprites.length; quad++) {
|
|
18472
|
+
blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
|
|
18380
18473
|
const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
|
|
18381
18474
|
const brightness = light ? lightBrightness(fluidLightLevel(
|
|
18382
18475
|
light[lightIndex],
|
|
@@ -18407,11 +18500,11 @@ function buildSectionGeometry(input) {
|
|
|
18407
18500
|
indexOffset += 6;
|
|
18408
18501
|
}
|
|
18409
18502
|
}
|
|
18410
|
-
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
|
|
18503
|
+
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
|
|
18411
18504
|
});
|
|
18412
18505
|
}
|
|
18413
18506
|
function sectionGeometryTransferables(pages) {
|
|
18414
|
-
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
|
|
18507
|
+
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]);
|
|
18415
18508
|
}
|
|
18416
18509
|
|
|
18417
18510
|
// src/world/SectionWorker.ts
|
|
@@ -18513,7 +18606,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
18513
18606
|
indices: new Uint16Array(quads * 6),
|
|
18514
18607
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
18515
18608
|
atlas: 0,
|
|
18516
|
-
layer: template.layer
|
|
18609
|
+
layer: template.layer,
|
|
18610
|
+
ambientOcclusion: template.ambientOcclusion
|
|
18517
18611
|
};
|
|
18518
18612
|
const normal = template.geometry.getAttribute("normal");
|
|
18519
18613
|
const uv = template.geometry.getAttribute("uv");
|
|
@@ -18568,6 +18662,12 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18568
18662
|
constructor() {
|
|
18569
18663
|
super(...arguments);
|
|
18570
18664
|
this.ownedMeshes = [];
|
|
18665
|
+
this.blockIndices = /* @__PURE__ */ new Map();
|
|
18666
|
+
}
|
|
18667
|
+
/** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
|
|
18668
|
+
getBlockIndex(hit) {
|
|
18669
|
+
if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
|
|
18670
|
+
return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
|
|
18571
18671
|
}
|
|
18572
18672
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
18573
18673
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
@@ -18610,6 +18710,7 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18610
18710
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
18611
18711
|
const mesh = new import_three43.Mesh(geometry, material);
|
|
18612
18712
|
section.add(mesh);
|
|
18713
|
+
section.blockIndices.set(mesh, page.blockIndices);
|
|
18613
18714
|
const unsubscribe = [];
|
|
18614
18715
|
for (const { atlas: id, x, y } of page.placements) {
|
|
18615
18716
|
const atlas = atlases[id];
|
|
@@ -18635,6 +18736,7 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18635
18736
|
mesh.material.dispose();
|
|
18636
18737
|
texture?.dispose();
|
|
18637
18738
|
}
|
|
18739
|
+
this.blockIndices.clear();
|
|
18638
18740
|
this.removeFromParent();
|
|
18639
18741
|
super.dispose();
|
|
18640
18742
|
}
|
|
@@ -18644,6 +18746,8 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
|
18644
18746
|
init_FluidGeometry();
|
|
18645
18747
|
init_FluidQuads();
|
|
18646
18748
|
init_CubeFace();
|
|
18749
|
+
init_InstanceReference();
|
|
18750
|
+
init_three();
|
|
18647
18751
|
var WATER_TINT2 = new import_three44.Color(4159204).toArray();
|
|
18648
18752
|
var Chunk = class _Chunk {
|
|
18649
18753
|
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
@@ -18657,6 +18761,7 @@ var Chunk = class _Chunk {
|
|
|
18657
18761
|
this.ambientLight = ambientLight;
|
|
18658
18762
|
this.data = new ChunkData();
|
|
18659
18763
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
18764
|
+
this.objectBlocks = /* @__PURE__ */ new Set();
|
|
18660
18765
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
18661
18766
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
18662
18767
|
this.fluidCells = new Uint8Array(4096);
|
|
@@ -18668,6 +18773,89 @@ var Chunk = class _Chunk {
|
|
|
18668
18773
|
this.y = y;
|
|
18669
18774
|
this.z = z;
|
|
18670
18775
|
}
|
|
18776
|
+
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
18777
|
+
static raycast(chunks, raycaster) {
|
|
18778
|
+
const roots = /* @__PURE__ */ new Map();
|
|
18779
|
+
const targets = /* @__PURE__ */ new Map();
|
|
18780
|
+
const meshes = (root, scene) => {
|
|
18781
|
+
const cached2 = roots.get(root);
|
|
18782
|
+
if (cached2) return cached2;
|
|
18783
|
+
const result = [];
|
|
18784
|
+
roots.set(root, result);
|
|
18785
|
+
let attached = false;
|
|
18786
|
+
for (let parent = root; parent; parent = parent.parent) {
|
|
18787
|
+
if (!parent.visible) return result;
|
|
18788
|
+
if (parent === scene) attached = true;
|
|
18789
|
+
}
|
|
18790
|
+
if (!attached) return result;
|
|
18791
|
+
root.updateWorldMatrix(true, true);
|
|
18792
|
+
root.traverseVisible((object4) => {
|
|
18793
|
+
if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
|
|
18794
|
+
});
|
|
18795
|
+
return result;
|
|
18796
|
+
};
|
|
18797
|
+
const add = (root, owner, reference) => {
|
|
18798
|
+
for (const mesh of meshes(root, owner.chunk.scene)) {
|
|
18799
|
+
if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
|
|
18800
|
+
let entry = targets.get(mesh);
|
|
18801
|
+
if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
|
|
18802
|
+
entry.owners.set(reference?.index, owner);
|
|
18803
|
+
}
|
|
18804
|
+
};
|
|
18805
|
+
for (const chunk of chunks) {
|
|
18806
|
+
for (const index of chunk.objectBlocks) {
|
|
18807
|
+
const block = chunk.renderedBlocks.get(index).object;
|
|
18808
|
+
if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
|
|
18809
|
+
const owner = { chunk, index };
|
|
18810
|
+
for (const model of block.models) {
|
|
18811
|
+
if (isInstanceReference(model)) {
|
|
18812
|
+
if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
|
|
18813
|
+
} else {
|
|
18814
|
+
add(model, owner);
|
|
18815
|
+
}
|
|
18816
|
+
}
|
|
18817
|
+
for (const entity of block.blockEntities) add(entity, owner);
|
|
18818
|
+
}
|
|
18819
|
+
if (chunk.sectionMesh) {
|
|
18820
|
+
for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
|
|
18821
|
+
targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
|
|
18822
|
+
}
|
|
18823
|
+
}
|
|
18824
|
+
}
|
|
18825
|
+
for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
|
|
18826
|
+
if (!hit.face) continue;
|
|
18827
|
+
const mesh = hit.object;
|
|
18828
|
+
const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
|
|
18829
|
+
if (!material?.visible) continue;
|
|
18830
|
+
const entry = targets.get(mesh);
|
|
18831
|
+
let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
|
|
18832
|
+
if (entry.section) {
|
|
18833
|
+
const index = entry.section.mesh.getBlockIndex(hit);
|
|
18834
|
+
if (index !== void 0) owner = { chunk: entry.section.chunk, index };
|
|
18835
|
+
}
|
|
18836
|
+
if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
|
|
18837
|
+
const info = owner.chunk.renderedBlocks.get(owner.index);
|
|
18838
|
+
if (!info) continue;
|
|
18839
|
+
const matrix = mesh.matrixWorld.clone();
|
|
18840
|
+
if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
|
|
18841
|
+
const instance = new import_three44.Matrix4();
|
|
18842
|
+
mesh.getMatrixAt(hit.instanceId, instance);
|
|
18843
|
+
matrix.multiply(instance);
|
|
18844
|
+
}
|
|
18845
|
+
return {
|
|
18846
|
+
position: new import_three44.Vector3(
|
|
18847
|
+
owner.chunk.x * 16 + owner.index % 16,
|
|
18848
|
+
owner.chunk.y * 16 + Math.floor(owner.index / 256),
|
|
18849
|
+
owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
|
|
18850
|
+
),
|
|
18851
|
+
block: info.block,
|
|
18852
|
+
point: hit.point.clone(),
|
|
18853
|
+
normal: hit.face.normal.clone().applyNormalMatrix(new import_three44.Matrix3().getNormalMatrix(matrix)),
|
|
18854
|
+
distance: hit.distance
|
|
18855
|
+
};
|
|
18856
|
+
}
|
|
18857
|
+
return void 0;
|
|
18858
|
+
}
|
|
18671
18859
|
getBlockAt(posOrX, y, z) {
|
|
18672
18860
|
if (typeof posOrX == "number") {
|
|
18673
18861
|
return this.getBlockAt(new import_three44.Vector3(posOrX, y, z));
|
|
@@ -18788,6 +18976,7 @@ var Chunk = class _Chunk {
|
|
|
18788
18976
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
18789
18977
|
this.fluidCells[index] = 0;
|
|
18790
18978
|
this.renderedBlocks.delete(index);
|
|
18979
|
+
this.objectBlocks.delete(index);
|
|
18791
18980
|
const worldPos = new import_three44.Vector3(
|
|
18792
18981
|
this.x * 16 + index % 16,
|
|
18793
18982
|
this.y * 16 + Math.floor(index / 256),
|
|
@@ -18830,6 +19019,7 @@ var Chunk = class _Chunk {
|
|
|
18830
19019
|
this.renderedBlocks.set(index, { get block() {
|
|
18831
19020
|
return readBlock();
|
|
18832
19021
|
}, object: object4 });
|
|
19022
|
+
if (object4) this.objectBlocks.add(index);
|
|
18833
19023
|
} catch (error) {
|
|
18834
19024
|
this.data.assign(index, 0);
|
|
18835
19025
|
this.fluidCells[index] = 0;
|
|
@@ -18848,6 +19038,7 @@ var Chunk = class _Chunk {
|
|
|
18848
19038
|
this.fluidCells.fill(0);
|
|
18849
19039
|
this.waterTints = void 0;
|
|
18850
19040
|
this.renderedBlocks.clear();
|
|
19041
|
+
this.objectBlocks.clear();
|
|
18851
19042
|
this.hiddenBlocks.clear();
|
|
18852
19043
|
this.meshDirty = true;
|
|
18853
19044
|
this.data.copyFrom(data);
|
|
@@ -18897,6 +19088,7 @@ var Chunk = class _Chunk {
|
|
|
18897
19088
|
this.renderedBlocks.set(index, { get block() {
|
|
18898
19089
|
return readBlock();
|
|
18899
19090
|
}, object: void 0 });
|
|
19091
|
+
this.objectBlocks.delete(index);
|
|
18900
19092
|
} catch (error) {
|
|
18901
19093
|
this.data.assign(index, 0);
|
|
18902
19094
|
this.fluidCells[index] = 0;
|
|
@@ -18922,10 +19114,12 @@ var Chunk = class _Chunk {
|
|
|
18922
19114
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
18923
19115
|
));
|
|
18924
19116
|
this.renderedBlocks.get(index).object = object4;
|
|
19117
|
+
this.objectBlocks.add(index);
|
|
18925
19118
|
} catch (error) {
|
|
18926
19119
|
this.data.assign(index, 0);
|
|
18927
19120
|
this.fluidCells[index] = 0;
|
|
18928
19121
|
this.renderedBlocks.delete(index);
|
|
19122
|
+
this.objectBlocks.delete(index);
|
|
18929
19123
|
object4?.removeFromScene();
|
|
18930
19124
|
if (!failed) failure = error;
|
|
18931
19125
|
failed = true;
|
|
@@ -18943,6 +19137,25 @@ var Chunk = class _Chunk {
|
|
|
18943
19137
|
if (this.renderedBlocks.has(index)) this.meshDirty = true;
|
|
18944
19138
|
}
|
|
18945
19139
|
}
|
|
19140
|
+
/** Refreshes baked corner shading after edits or a world setting change. Disabled chunks keep no AO neighborhood. */
|
|
19141
|
+
refreshAmbientOcclusion(enabled) {
|
|
19142
|
+
if (!enabled && !this.ambientOcclusionCells) return;
|
|
19143
|
+
const cells = enabled ? this.buildAmbientOcclusionCells() : void 0;
|
|
19144
|
+
if (cells?.some((value, index) => value !== this.ambientOcclusionCells?.[index]) || !!cells !== !!this.ambientOcclusionCells) this.meshDirty = true;
|
|
19145
|
+
this.ambientOcclusionCells = cells;
|
|
19146
|
+
}
|
|
19147
|
+
buildAmbientOcclusionCells() {
|
|
19148
|
+
const cells = new Uint8Array(18 * 18 * 18);
|
|
19149
|
+
for (let y = -1; y <= 16; y++) {
|
|
19150
|
+
for (let z = -1; z <= 16; z++) {
|
|
19151
|
+
for (let x = -1; x <= 16; x++) {
|
|
19152
|
+
const inner = x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 16;
|
|
19153
|
+
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));
|
|
19154
|
+
}
|
|
19155
|
+
}
|
|
19156
|
+
}
|
|
19157
|
+
return cells;
|
|
19158
|
+
}
|
|
18946
19159
|
biomePosition(index, blockState3, stored) {
|
|
18947
19160
|
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18948
19161
|
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
@@ -19131,12 +19344,18 @@ var Chunk = class _Chunk {
|
|
|
19131
19344
|
}
|
|
19132
19345
|
}
|
|
19133
19346
|
}
|
|
19134
|
-
|
|
19135
|
-
|
|
19136
|
-
|
|
19137
|
-
|
|
19138
|
-
|
|
19139
|
-
|
|
19347
|
+
let next;
|
|
19348
|
+
try {
|
|
19349
|
+
next = entries.length || fluids ? await SectionMesh.buildAsync(
|
|
19350
|
+
entries,
|
|
19351
|
+
this.sectionModels.maxAtlasSize,
|
|
19352
|
+
fluids,
|
|
19353
|
+
{ light, ambientLight: this.ambientLight, ambientOcclusion: this.ambientOcclusionCells }
|
|
19354
|
+
) : void 0;
|
|
19355
|
+
} catch (error) {
|
|
19356
|
+
if (generation === this.meshGeneration) this.meshDirty = true;
|
|
19357
|
+
throw error;
|
|
19358
|
+
}
|
|
19140
19359
|
if (generation !== this.meshGeneration) {
|
|
19141
19360
|
next?.dispose();
|
|
19142
19361
|
return;
|
|
@@ -19161,9 +19380,11 @@ var Chunk = class _Chunk {
|
|
|
19161
19380
|
this.sectionMesh = void 0;
|
|
19162
19381
|
this.meshDirty = false;
|
|
19163
19382
|
this.renderedBlocks.clear();
|
|
19383
|
+
this.objectBlocks.clear();
|
|
19164
19384
|
this.hiddenBlocks.clear();
|
|
19165
19385
|
this.fluidCells.fill(0);
|
|
19166
19386
|
this.waterTints = void 0;
|
|
19387
|
+
this.ambientOcclusionCells = void 0;
|
|
19167
19388
|
this.data.clear();
|
|
19168
19389
|
this.biomes = void 0;
|
|
19169
19390
|
if (notify) {
|