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.mjs
CHANGED
|
@@ -12425,6 +12425,10 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12425
12425
|
get blockEntities() {
|
|
12426
12426
|
return this._entities;
|
|
12427
12427
|
}
|
|
12428
|
+
/** Model placements drawn for this block, including its fluid surface. */
|
|
12429
|
+
get models() {
|
|
12430
|
+
return this._models;
|
|
12431
|
+
}
|
|
12428
12432
|
/** Sets visibility for this block's model instances and block entities. */
|
|
12429
12433
|
setVisible(visible) {
|
|
12430
12434
|
this.visible = visible;
|
|
@@ -17188,7 +17192,7 @@ var AnvilWorldSource = class {
|
|
|
17188
17192
|
};
|
|
17189
17193
|
|
|
17190
17194
|
// src/world/Chunk.ts
|
|
17191
|
-
import { Color as Color13, Vector3 as Vector318 } from "three";
|
|
17195
|
+
import { Color as Color13, Matrix3 as Matrix33, Matrix4 as Matrix413, Vector3 as Vector318 } from "three";
|
|
17192
17196
|
init_BlockStates();
|
|
17193
17197
|
init_AssetKey();
|
|
17194
17198
|
|
|
@@ -17367,7 +17371,8 @@ var SectionModels = class {
|
|
|
17367
17371
|
atlas,
|
|
17368
17372
|
cullFaces: new Uint8Array(cullFaces),
|
|
17369
17373
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17370
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
17374
|
+
layer: atlas.hasTranslucency ? 1 : 0,
|
|
17375
|
+
ambientOcclusion: model.ambientocclusion !== false
|
|
17371
17376
|
};
|
|
17372
17377
|
this.templates.add(template);
|
|
17373
17378
|
return template;
|
|
@@ -17558,17 +17563,45 @@ var MineRenderWorld = class {
|
|
|
17558
17563
|
this.light = /* @__PURE__ */ new Map();
|
|
17559
17564
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
17560
17565
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
17566
|
+
this.ambientOcclusionPending = false;
|
|
17561
17567
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
17562
17568
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
17569
|
+
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17563
17570
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
17564
17571
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
17565
17572
|
}
|
|
17566
17573
|
this.scene = scene;
|
|
17567
17574
|
this.savedLighting = options.savedLighting ?? false;
|
|
17568
17575
|
this.ambientLight = options.ambientLight ?? 0;
|
|
17576
|
+
this._ambientOcclusion = options.ambientOcclusion ?? false;
|
|
17569
17577
|
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
17570
17578
|
if (options.renderEntities) this.entities = new WorldEntities(scene);
|
|
17571
17579
|
}
|
|
17580
|
+
/**
|
|
17581
|
+
* Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
|
|
17582
|
+
* Includes fluids and block entities; texture alpha does not change triangle intersections.
|
|
17583
|
+
*/
|
|
17584
|
+
raycast(raycaster) {
|
|
17585
|
+
return Chunk.raycast(this._chunks.values(), raycaster);
|
|
17586
|
+
}
|
|
17587
|
+
/** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
|
|
17588
|
+
get ambientOcclusion() {
|
|
17589
|
+
return this._ambientOcclusion;
|
|
17590
|
+
}
|
|
17591
|
+
/** Rebuilds loaded blocks with or without corner shading. Block data and saved lighting are preserved. */
|
|
17592
|
+
async setAmbientOcclusion(enabled) {
|
|
17593
|
+
if (typeof enabled !== "boolean") throw new TypeError("Ambient occlusion must be a boolean");
|
|
17594
|
+
if (enabled && !this.sectionModels) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
17595
|
+
if (enabled === this._ambientOcclusion && !this.ambientOcclusionPending) {
|
|
17596
|
+
await this.culling;
|
|
17597
|
+
return;
|
|
17598
|
+
}
|
|
17599
|
+
this._ambientOcclusion = enabled;
|
|
17600
|
+
this.ambientOcclusionPending = true;
|
|
17601
|
+
for (const chunk of this._chunks.values()) this.pendingCulling.set(chunk, "all");
|
|
17602
|
+
await this.updateCulling([]);
|
|
17603
|
+
this.ambientOcclusionPending = false;
|
|
17604
|
+
}
|
|
17572
17605
|
getBlockAt(posOrX, y, z) {
|
|
17573
17606
|
if (typeof posOrX == "number") {
|
|
17574
17607
|
return this.getBlockAt(new Vector317(posOrX, y, z));
|
|
@@ -17892,7 +17925,7 @@ var MineRenderWorld = class {
|
|
|
17892
17925
|
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
17893
17926
|
let pending = this.pendingCulling.get(section);
|
|
17894
17927
|
if (pending === "all" || pending?.has(index)) continue;
|
|
17895
|
-
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !section.isFluidIndex(index)) continue;
|
|
17928
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) > 1 && !this._ambientOcclusion && !section.isFluidIndex(index)) continue;
|
|
17896
17929
|
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
17897
17930
|
pending.add(index);
|
|
17898
17931
|
}
|
|
@@ -17900,6 +17933,7 @@ var MineRenderWorld = class {
|
|
|
17900
17933
|
}
|
|
17901
17934
|
}
|
|
17902
17935
|
return this.culling ?? (this.culling = Promise.resolve().then(async () => {
|
|
17936
|
+
let sliceStart = performance.now();
|
|
17903
17937
|
try {
|
|
17904
17938
|
while (this.pendingCulling.size) {
|
|
17905
17939
|
const batch = [...this.pendingCulling];
|
|
@@ -17935,6 +17969,11 @@ var MineRenderWorld = class {
|
|
|
17935
17969
|
}
|
|
17936
17970
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
17937
17971
|
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
17972
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
17973
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
17974
|
+
await yieldToEventLoop();
|
|
17975
|
+
sliceStart = performance.now();
|
|
17976
|
+
}
|
|
17938
17977
|
}
|
|
17939
17978
|
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
17940
17979
|
}
|
|
@@ -18041,6 +18080,50 @@ import { BufferGeometry as BufferGeometry9, Color as Color12, DoubleSide as Doub
|
|
|
18041
18080
|
// src/world/SectionGeometry.ts
|
|
18042
18081
|
init_FluidQuads();
|
|
18043
18082
|
|
|
18083
|
+
// src/world/_light/AmbientOcclusion.ts
|
|
18084
|
+
var AXIS_STRIDES = [1, 9, 3];
|
|
18085
|
+
function sectionAmbientOcclusionMask(cells, center) {
|
|
18086
|
+
let mask = 0;
|
|
18087
|
+
for (let y = -1; y <= 1; y++) for (let z = -1; z <= 1; z++) for (let x = -1; x <= 1; x++) {
|
|
18088
|
+
if (Math.abs(x) + Math.abs(y) + Math.abs(z) < 2) continue;
|
|
18089
|
+
if (cells[center + y * 324 + z * 18 + x]) mask |= 1 << (y + 1) * 9 + (z + 1) * 3 + x + 1;
|
|
18090
|
+
}
|
|
18091
|
+
return mask;
|
|
18092
|
+
}
|
|
18093
|
+
function cornerBrightness(mask, center, u, v) {
|
|
18094
|
+
const sideU = mask >>> center + u & 1;
|
|
18095
|
+
const sideV = mask >>> center + v & 1;
|
|
18096
|
+
const corner = sideU && sideV ? 1 : mask >>> center + u + v & 1;
|
|
18097
|
+
return 1 - (sideU + sideV + corner) * 0.2;
|
|
18098
|
+
}
|
|
18099
|
+
function quadAmbientOcclusion(positions, normals, quad, mask, output) {
|
|
18100
|
+
output.fill(1);
|
|
18101
|
+
if (!mask) return;
|
|
18102
|
+
const start = quad * 12;
|
|
18103
|
+
let axis = 0;
|
|
18104
|
+
if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
|
|
18105
|
+
if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
|
|
18106
|
+
const uAxis = (axis + 1) % 3, vAxis = (axis + 2) % 3;
|
|
18107
|
+
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;
|
|
18108
|
+
const sign = normals[start + axis] > 0 ? 1 : -1;
|
|
18109
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18110
|
+
const offset = start + vertex * 3;
|
|
18111
|
+
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;
|
|
18112
|
+
}
|
|
18113
|
+
const center = 13 + sign * AXIS_STRIDES[axis];
|
|
18114
|
+
const u = AXIS_STRIDES[uAxis], v = AXIS_STRIDES[vAxis];
|
|
18115
|
+
const lowLow = cornerBrightness(mask, center, -u, -v);
|
|
18116
|
+
const highLow = cornerBrightness(mask, center, u, -v);
|
|
18117
|
+
const lowHigh = cornerBrightness(mask, center, -u, v);
|
|
18118
|
+
const highHigh = cornerBrightness(mask, center, u, v);
|
|
18119
|
+
for (let vertex = 0; vertex < 4; vertex++) {
|
|
18120
|
+
const offset = start + vertex * 3;
|
|
18121
|
+
const a = Math.max(0, Math.min(1, (positions[offset + uAxis] + 8) / 16));
|
|
18122
|
+
const b = Math.max(0, Math.min(1, (positions[offset + vAxis] + 8) / 16));
|
|
18123
|
+
output[vertex] = (lowLow * (1 - a) + highLow * a) * (1 - b) + (lowHigh * (1 - a) + highHigh * a) * b;
|
|
18124
|
+
}
|
|
18125
|
+
}
|
|
18126
|
+
|
|
18044
18127
|
// src/world/_light/FaceLight.ts
|
|
18045
18128
|
function lightBrightness(level, ambient = 0) {
|
|
18046
18129
|
if (level === 255) return 1;
|
|
@@ -18066,7 +18149,7 @@ var LIGHT_SAMPLE_OFFSETS = [0, 1, -1, 324, -324, 18, -18];
|
|
|
18066
18149
|
|
|
18067
18150
|
// src/world/SectionGeometry.ts
|
|
18068
18151
|
function buildSectionGeometry(input) {
|
|
18069
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
|
|
18152
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
18070
18153
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
18071
18154
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
18072
18155
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
@@ -18077,6 +18160,10 @@ function buildSectionGeometry(input) {
|
|
|
18077
18160
|
if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
|
|
18078
18161
|
throw new RangeError("Section ambient light must be a number from 0 to 1");
|
|
18079
18162
|
}
|
|
18163
|
+
if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some((value) => value > 1))) {
|
|
18164
|
+
throw new RangeError("Section ambient occlusion must cover an 18\xD718\xD718 neighborhood with zero or one per cell");
|
|
18165
|
+
}
|
|
18166
|
+
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
18080
18167
|
for (const template of templateData) {
|
|
18081
18168
|
const { quads } = template;
|
|
18082
18169
|
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) {
|
|
@@ -18171,6 +18258,7 @@ function buildSectionGeometry(input) {
|
|
|
18171
18258
|
const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
|
|
18172
18259
|
const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
|
|
18173
18260
|
const outputIndices = new Uint32Array(faces * 6);
|
|
18261
|
+
const blockIndices = new Uint16Array(faces);
|
|
18174
18262
|
let vertex = 0, indexOffset = 0;
|
|
18175
18263
|
for (const entry of page.entries) {
|
|
18176
18264
|
const template = templateData[templates[entry]];
|
|
@@ -18182,8 +18270,11 @@ function buildSectionGeometry(input) {
|
|
|
18182
18270
|
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
18183
18271
|
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
18184
18272
|
const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
|
|
18273
|
+
const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
|
|
18185
18274
|
for (let quad = 0; quad < template.quads; quad++) {
|
|
18186
18275
|
if (cullMasks[entry] & template.cullFaces[quad]) continue;
|
|
18276
|
+
blockIndices[indexOffset / 6] = indices[entry];
|
|
18277
|
+
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
18187
18278
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
18188
18279
|
const start = vertex;
|
|
18189
18280
|
for (let corner = 0; corner < 4; corner++, vertex++) {
|
|
@@ -18200,9 +18291,10 @@ function buildSectionGeometry(input) {
|
|
|
18200
18291
|
uvBounds[vertex * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
18201
18292
|
uvBounds[vertex * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
18202
18293
|
uvBounds[vertex * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
18203
|
-
|
|
18204
|
-
colors[vertex * 3
|
|
18205
|
-
colors[vertex * 3 +
|
|
18294
|
+
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
18295
|
+
colors[vertex * 3] = template.colors[source * 3] * factor;
|
|
18296
|
+
colors[vertex * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
18297
|
+
colors[vertex * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
18206
18298
|
}
|
|
18207
18299
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
18208
18300
|
}
|
|
@@ -18214,6 +18306,7 @@ function buildSectionGeometry(input) {
|
|
|
18214
18306
|
const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
|
|
18215
18307
|
const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
|
|
18216
18308
|
for (let quad = 0; quad < quads.sprites.length; quad++) {
|
|
18309
|
+
blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
|
|
18217
18310
|
const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
|
|
18218
18311
|
const brightness = light ? lightBrightness(fluidLightLevel(
|
|
18219
18312
|
light[lightIndex],
|
|
@@ -18244,11 +18337,11 @@ function buildSectionGeometry(input) {
|
|
|
18244
18337
|
indexOffset += 6;
|
|
18245
18338
|
}
|
|
18246
18339
|
}
|
|
18247
|
-
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
|
|
18340
|
+
return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
|
|
18248
18341
|
});
|
|
18249
18342
|
}
|
|
18250
18343
|
function sectionGeometryTransferables(pages) {
|
|
18251
|
-
return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
|
|
18344
|
+
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]);
|
|
18252
18345
|
}
|
|
18253
18346
|
|
|
18254
18347
|
// src/world/SectionWorker.ts
|
|
@@ -18350,7 +18443,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
18350
18443
|
indices: new Uint16Array(quads * 6),
|
|
18351
18444
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
18352
18445
|
atlas: 0,
|
|
18353
|
-
layer: template.layer
|
|
18446
|
+
layer: template.layer,
|
|
18447
|
+
ambientOcclusion: template.ambientOcclusion
|
|
18354
18448
|
};
|
|
18355
18449
|
const normal = template.geometry.getAttribute("normal");
|
|
18356
18450
|
const uv = template.geometry.getAttribute("uv");
|
|
@@ -18405,6 +18499,12 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18405
18499
|
constructor() {
|
|
18406
18500
|
super(...arguments);
|
|
18407
18501
|
this.ownedMeshes = [];
|
|
18502
|
+
this.blockIndices = /* @__PURE__ */ new Map();
|
|
18503
|
+
}
|
|
18504
|
+
/** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
|
|
18505
|
+
getBlockIndex(hit) {
|
|
18506
|
+
if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
|
|
18507
|
+
return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
|
|
18408
18508
|
}
|
|
18409
18509
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
18410
18510
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
@@ -18447,6 +18547,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18447
18547
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
18448
18548
|
const mesh = new Mesh10(geometry, material);
|
|
18449
18549
|
section.add(mesh);
|
|
18550
|
+
section.blockIndices.set(mesh, page.blockIndices);
|
|
18450
18551
|
const unsubscribe = [];
|
|
18451
18552
|
for (const { atlas: id, x, y } of page.placements) {
|
|
18452
18553
|
const atlas = atlases[id];
|
|
@@ -18472,6 +18573,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18472
18573
|
mesh.material.dispose();
|
|
18473
18574
|
texture?.dispose();
|
|
18474
18575
|
}
|
|
18576
|
+
this.blockIndices.clear();
|
|
18475
18577
|
this.removeFromParent();
|
|
18476
18578
|
super.dispose();
|
|
18477
18579
|
}
|
|
@@ -18481,6 +18583,8 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
18481
18583
|
init_FluidGeometry();
|
|
18482
18584
|
init_FluidQuads();
|
|
18483
18585
|
init_CubeFace();
|
|
18586
|
+
init_InstanceReference();
|
|
18587
|
+
init_three();
|
|
18484
18588
|
var WATER_TINT2 = new Color13(4159204).toArray();
|
|
18485
18589
|
var Chunk = class _Chunk {
|
|
18486
18590
|
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
|
|
@@ -18494,6 +18598,7 @@ var Chunk = class _Chunk {
|
|
|
18494
18598
|
this.ambientLight = ambientLight;
|
|
18495
18599
|
this.data = new ChunkData();
|
|
18496
18600
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
18601
|
+
this.objectBlocks = /* @__PURE__ */ new Set();
|
|
18497
18602
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
18498
18603
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
18499
18604
|
this.fluidCells = new Uint8Array(4096);
|
|
@@ -18505,6 +18610,89 @@ var Chunk = class _Chunk {
|
|
|
18505
18610
|
this.y = y;
|
|
18506
18611
|
this.z = z;
|
|
18507
18612
|
}
|
|
18613
|
+
/** Finds the nearest owned block hit across sections, testing each shared mesh once. */
|
|
18614
|
+
static raycast(chunks, raycaster) {
|
|
18615
|
+
const roots = /* @__PURE__ */ new Map();
|
|
18616
|
+
const targets = /* @__PURE__ */ new Map();
|
|
18617
|
+
const meshes = (root, scene) => {
|
|
18618
|
+
const cached2 = roots.get(root);
|
|
18619
|
+
if (cached2) return cached2;
|
|
18620
|
+
const result = [];
|
|
18621
|
+
roots.set(root, result);
|
|
18622
|
+
let attached = false;
|
|
18623
|
+
for (let parent = root; parent; parent = parent.parent) {
|
|
18624
|
+
if (!parent.visible) return result;
|
|
18625
|
+
if (parent === scene) attached = true;
|
|
18626
|
+
}
|
|
18627
|
+
if (!attached) return result;
|
|
18628
|
+
root.updateWorldMatrix(true, true);
|
|
18629
|
+
root.traverseVisible((object4) => {
|
|
18630
|
+
if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
|
|
18631
|
+
});
|
|
18632
|
+
return result;
|
|
18633
|
+
};
|
|
18634
|
+
const add = (root, owner, reference) => {
|
|
18635
|
+
for (const mesh of meshes(root, owner.chunk.scene)) {
|
|
18636
|
+
if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
|
|
18637
|
+
let entry = targets.get(mesh);
|
|
18638
|
+
if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
|
|
18639
|
+
entry.owners.set(reference?.index, owner);
|
|
18640
|
+
}
|
|
18641
|
+
};
|
|
18642
|
+
for (const chunk of chunks) {
|
|
18643
|
+
for (const index of chunk.objectBlocks) {
|
|
18644
|
+
const block = chunk.renderedBlocks.get(index).object;
|
|
18645
|
+
if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
|
|
18646
|
+
const owner = { chunk, index };
|
|
18647
|
+
for (const model of block.models) {
|
|
18648
|
+
if (isInstanceReference(model)) {
|
|
18649
|
+
if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
|
|
18650
|
+
} else {
|
|
18651
|
+
add(model, owner);
|
|
18652
|
+
}
|
|
18653
|
+
}
|
|
18654
|
+
for (const entity of block.blockEntities) add(entity, owner);
|
|
18655
|
+
}
|
|
18656
|
+
if (chunk.sectionMesh) {
|
|
18657
|
+
for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
|
|
18658
|
+
targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
|
|
18659
|
+
}
|
|
18660
|
+
}
|
|
18661
|
+
}
|
|
18662
|
+
for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
|
|
18663
|
+
if (!hit.face) continue;
|
|
18664
|
+
const mesh = hit.object;
|
|
18665
|
+
const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
|
|
18666
|
+
if (!material?.visible) continue;
|
|
18667
|
+
const entry = targets.get(mesh);
|
|
18668
|
+
let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
|
|
18669
|
+
if (entry.section) {
|
|
18670
|
+
const index = entry.section.mesh.getBlockIndex(hit);
|
|
18671
|
+
if (index !== void 0) owner = { chunk: entry.section.chunk, index };
|
|
18672
|
+
}
|
|
18673
|
+
if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
|
|
18674
|
+
const info = owner.chunk.renderedBlocks.get(owner.index);
|
|
18675
|
+
if (!info) continue;
|
|
18676
|
+
const matrix = mesh.matrixWorld.clone();
|
|
18677
|
+
if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
|
|
18678
|
+
const instance = new Matrix413();
|
|
18679
|
+
mesh.getMatrixAt(hit.instanceId, instance);
|
|
18680
|
+
matrix.multiply(instance);
|
|
18681
|
+
}
|
|
18682
|
+
return {
|
|
18683
|
+
position: new Vector318(
|
|
18684
|
+
owner.chunk.x * 16 + owner.index % 16,
|
|
18685
|
+
owner.chunk.y * 16 + Math.floor(owner.index / 256),
|
|
18686
|
+
owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
|
|
18687
|
+
),
|
|
18688
|
+
block: info.block,
|
|
18689
|
+
point: hit.point.clone(),
|
|
18690
|
+
normal: hit.face.normal.clone().applyNormalMatrix(new Matrix33().getNormalMatrix(matrix)),
|
|
18691
|
+
distance: hit.distance
|
|
18692
|
+
};
|
|
18693
|
+
}
|
|
18694
|
+
return void 0;
|
|
18695
|
+
}
|
|
18508
18696
|
getBlockAt(posOrX, y, z) {
|
|
18509
18697
|
if (typeof posOrX == "number") {
|
|
18510
18698
|
return this.getBlockAt(new Vector318(posOrX, y, z));
|
|
@@ -18625,6 +18813,7 @@ var Chunk = class _Chunk {
|
|
|
18625
18813
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
18626
18814
|
this.fluidCells[index] = 0;
|
|
18627
18815
|
this.renderedBlocks.delete(index);
|
|
18816
|
+
this.objectBlocks.delete(index);
|
|
18628
18817
|
const worldPos = new Vector318(
|
|
18629
18818
|
this.x * 16 + index % 16,
|
|
18630
18819
|
this.y * 16 + Math.floor(index / 256),
|
|
@@ -18667,6 +18856,7 @@ var Chunk = class _Chunk {
|
|
|
18667
18856
|
this.renderedBlocks.set(index, { get block() {
|
|
18668
18857
|
return readBlock();
|
|
18669
18858
|
}, object: object4 });
|
|
18859
|
+
if (object4) this.objectBlocks.add(index);
|
|
18670
18860
|
} catch (error) {
|
|
18671
18861
|
this.data.assign(index, 0);
|
|
18672
18862
|
this.fluidCells[index] = 0;
|
|
@@ -18685,6 +18875,7 @@ var Chunk = class _Chunk {
|
|
|
18685
18875
|
this.fluidCells.fill(0);
|
|
18686
18876
|
this.waterTints = void 0;
|
|
18687
18877
|
this.renderedBlocks.clear();
|
|
18878
|
+
this.objectBlocks.clear();
|
|
18688
18879
|
this.hiddenBlocks.clear();
|
|
18689
18880
|
this.meshDirty = true;
|
|
18690
18881
|
this.data.copyFrom(data);
|
|
@@ -18734,6 +18925,7 @@ var Chunk = class _Chunk {
|
|
|
18734
18925
|
this.renderedBlocks.set(index, { get block() {
|
|
18735
18926
|
return readBlock();
|
|
18736
18927
|
}, object: void 0 });
|
|
18928
|
+
this.objectBlocks.delete(index);
|
|
18737
18929
|
} catch (error) {
|
|
18738
18930
|
this.data.assign(index, 0);
|
|
18739
18931
|
this.fluidCells[index] = 0;
|
|
@@ -18759,10 +18951,12 @@ var Chunk = class _Chunk {
|
|
|
18759
18951
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
18760
18952
|
));
|
|
18761
18953
|
this.renderedBlocks.get(index).object = object4;
|
|
18954
|
+
this.objectBlocks.add(index);
|
|
18762
18955
|
} catch (error) {
|
|
18763
18956
|
this.data.assign(index, 0);
|
|
18764
18957
|
this.fluidCells[index] = 0;
|
|
18765
18958
|
this.renderedBlocks.delete(index);
|
|
18959
|
+
this.objectBlocks.delete(index);
|
|
18766
18960
|
object4?.removeFromScene();
|
|
18767
18961
|
if (!failed) failure = error;
|
|
18768
18962
|
failed = true;
|
|
@@ -18780,6 +18974,25 @@ var Chunk = class _Chunk {
|
|
|
18780
18974
|
if (this.renderedBlocks.has(index)) this.meshDirty = true;
|
|
18781
18975
|
}
|
|
18782
18976
|
}
|
|
18977
|
+
/** Refreshes baked corner shading after edits or a world setting change. Disabled chunks keep no AO neighborhood. */
|
|
18978
|
+
refreshAmbientOcclusion(enabled) {
|
|
18979
|
+
if (!enabled && !this.ambientOcclusionCells) return;
|
|
18980
|
+
const cells = enabled ? this.buildAmbientOcclusionCells() : void 0;
|
|
18981
|
+
if (cells?.some((value, index) => value !== this.ambientOcclusionCells?.[index]) || !!cells !== !!this.ambientOcclusionCells) this.meshDirty = true;
|
|
18982
|
+
this.ambientOcclusionCells = cells;
|
|
18983
|
+
}
|
|
18984
|
+
buildAmbientOcclusionCells() {
|
|
18985
|
+
const cells = new Uint8Array(18 * 18 * 18);
|
|
18986
|
+
for (let y = -1; y <= 16; y++) {
|
|
18987
|
+
for (let z = -1; z <= 16; z++) {
|
|
18988
|
+
for (let x = -1; x <= 16; x++) {
|
|
18989
|
+
const inner = x >= 0 && x < 16 && y >= 0 && y < 16 && z >= 0 && z < 16;
|
|
18990
|
+
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));
|
|
18991
|
+
}
|
|
18992
|
+
}
|
|
18993
|
+
}
|
|
18994
|
+
return cells;
|
|
18995
|
+
}
|
|
18783
18996
|
biomePosition(index, blockState3, stored) {
|
|
18784
18997
|
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18785
18998
|
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
@@ -18968,12 +19181,18 @@ var Chunk = class _Chunk {
|
|
|
18968
19181
|
}
|
|
18969
19182
|
}
|
|
18970
19183
|
}
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
|
|
18974
|
-
|
|
18975
|
-
|
|
18976
|
-
|
|
19184
|
+
let next;
|
|
19185
|
+
try {
|
|
19186
|
+
next = entries.length || fluids ? await SectionMesh.buildAsync(
|
|
19187
|
+
entries,
|
|
19188
|
+
this.sectionModels.maxAtlasSize,
|
|
19189
|
+
fluids,
|
|
19190
|
+
{ light, ambientLight: this.ambientLight, ambientOcclusion: this.ambientOcclusionCells }
|
|
19191
|
+
) : void 0;
|
|
19192
|
+
} catch (error) {
|
|
19193
|
+
if (generation === this.meshGeneration) this.meshDirty = true;
|
|
19194
|
+
throw error;
|
|
19195
|
+
}
|
|
18977
19196
|
if (generation !== this.meshGeneration) {
|
|
18978
19197
|
next?.dispose();
|
|
18979
19198
|
return;
|
|
@@ -18998,9 +19217,11 @@ var Chunk = class _Chunk {
|
|
|
18998
19217
|
this.sectionMesh = void 0;
|
|
18999
19218
|
this.meshDirty = false;
|
|
19000
19219
|
this.renderedBlocks.clear();
|
|
19220
|
+
this.objectBlocks.clear();
|
|
19001
19221
|
this.hiddenBlocks.clear();
|
|
19002
19222
|
this.fluidCells.fill(0);
|
|
19003
19223
|
this.waterTints = void 0;
|
|
19224
|
+
this.ambientOcclusionCells = void 0;
|
|
19004
19225
|
this.data.clear();
|
|
19005
19226
|
this.biomes = void 0;
|
|
19006
19227
|
if (notify) {
|