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/bundle.js CHANGED
@@ -100712,6 +100712,10 @@ property list uchar int vertex_index
100712
100712
  get blockEntities() {
100713
100713
  return this._entities;
100714
100714
  }
100715
+ /** Model placements drawn for this block, including its fluid surface. */
100716
+ get models() {
100717
+ return this._models;
100718
+ }
100715
100719
  /** Sets visibility for this block's model instances and block entities. */
100716
100720
  setVisible(visible) {
100717
100721
  this.visible = visible;
@@ -107752,7 +107756,8 @@ gl_FragDepth=readDepth(vUv);
107752
107756
  atlas,
107753
107757
  cullFaces: new Uint8Array(cullFaces),
107754
107758
  occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
107755
- layer: atlas.hasTranslucency ? 1 : 0
107759
+ layer: atlas.hasTranslucency ? 1 : 0,
107760
+ ambientOcclusion: model.ambientocclusion !== false
107756
107761
  };
107757
107762
  this.templates.add(template);
107758
107763
  return template;
@@ -107952,17 +107957,45 @@ gl_FragDepth=readDepth(vUv);
107952
107957
  this.light = /* @__PURE__ */ new Map();
107953
107958
  this.lightValidity = /* @__PURE__ */ new Map();
107954
107959
  this.highestSkySection = /* @__PURE__ */ new Map();
107960
+ this.ambientOcclusionPending = false;
107955
107961
  this.pendingCulling = /* @__PURE__ */ new Map();
107956
107962
  if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
107963
+ if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
107957
107964
  if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
107958
107965
  throw new RangeError("ambientLight must be a number from 0 to 1");
107959
107966
  }
107960
107967
  this.scene = scene;
107961
107968
  this.savedLighting = options.savedLighting ?? false;
107962
107969
  this.ambientLight = options.ambientLight ?? 0;
107970
+ this._ambientOcclusion = options.ambientOcclusion ?? false;
107963
107971
  if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
107964
107972
  if (options.renderEntities) this.entities = new WorldEntities(scene);
107965
107973
  }
107974
+ /**
107975
+ * Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
107976
+ * Includes fluids and block entities; texture alpha does not change triangle intersections.
107977
+ */
107978
+ raycast(raycaster) {
107979
+ return Chunk.raycast(this._chunks.values(), raycaster);
107980
+ }
107981
+ /** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
107982
+ get ambientOcclusion() {
107983
+ return this._ambientOcclusion;
107984
+ }
107985
+ /** Rebuilds loaded blocks with or without corner shading. Block data and saved lighting are preserved. */
107986
+ async setAmbientOcclusion(enabled) {
107987
+ if (typeof enabled !== "boolean") throw new TypeError("Ambient occlusion must be a boolean");
107988
+ if (enabled && !this.sectionModels) throw new TypeError("ambientOcclusion requires sectionMeshing");
107989
+ if (enabled === this._ambientOcclusion && !this.ambientOcclusionPending) {
107990
+ await this.culling;
107991
+ return;
107992
+ }
107993
+ this._ambientOcclusion = enabled;
107994
+ this.ambientOcclusionPending = true;
107995
+ for (const chunk of this._chunks.values()) this.pendingCulling.set(chunk, "all");
107996
+ await this.updateCulling([]);
107997
+ this.ambientOcclusionPending = false;
107998
+ }
107966
107999
  getBlockAt(posOrX, y5, z4) {
107967
108000
  if (typeof posOrX == "number") {
107968
108001
  return this.getBlockAt(new Vector3(posOrX, y5, z4));
@@ -108286,7 +108319,7 @@ gl_FragDepth=readDepth(vUv);
108286
108319
  const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
108287
108320
  let pending = this.pendingCulling.get(section);
108288
108321
  if (pending === "all" || pending?.has(index)) continue;
108289
- if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) > 1 && !section.isFluidIndex(index)) continue;
108322
+ if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) > 1 && !this._ambientOcclusion && !section.isFluidIndex(index)) continue;
108290
108323
  if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
108291
108324
  pending.add(index);
108292
108325
  }
@@ -108294,6 +108327,7 @@ gl_FragDepth=readDepth(vUv);
108294
108327
  }
108295
108328
  }
108296
108329
  return this.culling ?? (this.culling = Promise.resolve().then(async () => {
108330
+ let sliceStart = performance.now();
108297
108331
  try {
108298
108332
  while (this.pendingCulling.size) {
108299
108333
  const batch = [...this.pendingCulling];
@@ -108329,6 +108363,11 @@ gl_FragDepth=readDepth(vUv);
108329
108363
  }
108330
108364
  for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
108331
108365
  await chunk.refreshLight(indices === "all" ? void 0 : indices);
108366
+ chunk.refreshAmbientOcclusion(this._ambientOcclusion);
108367
+ if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
108368
+ await yieldToEventLoop();
108369
+ sliceStart = performance.now();
108370
+ }
108332
108371
  }
108333
108372
  await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
108334
108373
  }
@@ -108441,6 +108480,53 @@ gl_FragDepth=readDepth(vUv);
108441
108480
  init_process2();
108442
108481
  init_FluidQuads();
108443
108482
 
108483
+ // src/world/_light/AmbientOcclusion.ts
108484
+ init_dirname();
108485
+ init_buffer2();
108486
+ init_process2();
108487
+ var AXIS_STRIDES = [1, 9, 3];
108488
+ function sectionAmbientOcclusionMask(cells, center) {
108489
+ let mask = 0;
108490
+ for (let y5 = -1; y5 <= 1; y5++) for (let z4 = -1; z4 <= 1; z4++) for (let x4 = -1; x4 <= 1; x4++) {
108491
+ if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) < 2) continue;
108492
+ if (cells[center + y5 * 324 + z4 * 18 + x4]) mask |= 1 << (y5 + 1) * 9 + (z4 + 1) * 3 + x4 + 1;
108493
+ }
108494
+ return mask;
108495
+ }
108496
+ function cornerBrightness(mask, center, u4, v5) {
108497
+ const sideU = mask >>> center + u4 & 1;
108498
+ const sideV = mask >>> center + v5 & 1;
108499
+ const corner = sideU && sideV ? 1 : mask >>> center + u4 + v5 & 1;
108500
+ return 1 - (sideU + sideV + corner) * 0.2;
108501
+ }
108502
+ function quadAmbientOcclusion(positions, normals, quad, mask, output) {
108503
+ output.fill(1);
108504
+ if (!mask) return;
108505
+ const start = quad * 12;
108506
+ let axis = 0;
108507
+ if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
108508
+ if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
108509
+ const uAxis = (axis + 1) % 3, vAxis = (axis + 2) % 3;
108510
+ 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;
108511
+ const sign = normals[start + axis] > 0 ? 1 : -1;
108512
+ for (let vertex2 = 0; vertex2 < 4; vertex2++) {
108513
+ const offset = start + vertex2 * 3;
108514
+ 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;
108515
+ }
108516
+ const center = 13 + sign * AXIS_STRIDES[axis];
108517
+ const u4 = AXIS_STRIDES[uAxis], v5 = AXIS_STRIDES[vAxis];
108518
+ const lowLow = cornerBrightness(mask, center, -u4, -v5);
108519
+ const highLow = cornerBrightness(mask, center, u4, -v5);
108520
+ const lowHigh = cornerBrightness(mask, center, -u4, v5);
108521
+ const highHigh = cornerBrightness(mask, center, u4, v5);
108522
+ for (let vertex2 = 0; vertex2 < 4; vertex2++) {
108523
+ const offset = start + vertex2 * 3;
108524
+ const a4 = Math.max(0, Math.min(1, (positions[offset + uAxis] + 8) / 16));
108525
+ const b4 = Math.max(0, Math.min(1, (positions[offset + vAxis] + 8) / 16));
108526
+ output[vertex2] = (lowLow * (1 - a4) + highLow * a4) * (1 - b4) + (lowHigh * (1 - a4) + highHigh * a4) * b4;
108527
+ }
108528
+ }
108529
+
108444
108530
  // src/world/_light/FaceLight.ts
108445
108531
  init_dirname();
108446
108532
  init_buffer2();
@@ -108469,7 +108555,7 @@ gl_FragDepth=readDepth(vUv);
108469
108555
 
108470
108556
  // src/world/SectionGeometry.ts
108471
108557
  function buildSectionGeometry(input) {
108472
- const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
108558
+ const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
108473
108559
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
108474
108560
  if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
108475
108561
  if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
@@ -108480,6 +108566,10 @@ gl_FragDepth=readDepth(vUv);
108480
108566
  if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
108481
108567
  throw new RangeError("Section ambient light must be a number from 0 to 1");
108482
108568
  }
108569
+ if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some((value) => value > 1))) {
108570
+ throw new RangeError("Section ambient occlusion must cover an 18\xD718\xD718 neighborhood with zero or one per cell");
108571
+ }
108572
+ const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
108483
108573
  for (const template of templateData) {
108484
108574
  const { quads } = template;
108485
108575
  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) {
@@ -108574,6 +108664,7 @@ gl_FragDepth=readDepth(vUv);
108574
108664
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
108575
108665
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
108576
108666
  const outputIndices = new Uint32Array(faces * 6);
108667
+ const blockIndices = new Uint16Array(faces);
108577
108668
  let vertex2 = 0, indexOffset = 0;
108578
108669
  for (const entry of page.entries) {
108579
108670
  const template = templateData[templates[entry]];
@@ -108585,8 +108676,11 @@ gl_FragDepth=readDepth(vUv);
108585
108676
  const offsetY = Math.floor(indices[entry] / 256) * 16;
108586
108677
  const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
108587
108678
  const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
108679
+ const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
108588
108680
  for (let quad = 0; quad < template.quads; quad++) {
108589
108681
  if (cullMasks[entry] & template.cullFaces[quad]) continue;
108682
+ blockIndices[indexOffset / 6] = indices[entry];
108683
+ if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
108590
108684
  const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
108591
108685
  const start = vertex2;
108592
108686
  for (let corner = 0; corner < 4; corner++, vertex2++) {
@@ -108603,9 +108697,10 @@ gl_FragDepth=readDepth(vUv);
108603
108697
  uvBounds[vertex2 * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
108604
108698
  uvBounds[vertex2 * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
108605
108699
  uvBounds[vertex2 * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
108606
- colors[vertex2 * 3] = template.colors[source * 3] * brightness;
108607
- colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1] * brightness;
108608
- colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2] * brightness;
108700
+ const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
108701
+ colors[vertex2 * 3] = template.colors[source * 3] * factor;
108702
+ colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1] * factor;
108703
+ colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2] * factor;
108609
108704
  }
108610
108705
  for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
108611
108706
  }
@@ -108617,6 +108712,7 @@ gl_FragDepth=readDepth(vUv);
108617
108712
  const mapV = (v5) => 1 - (placement.y + (1 - v5) * atlas.height) / page.height;
108618
108713
  const lightIndex = (y5 + 1) * 324 + (z4 + 1) * 18 + x4 + 1;
108619
108714
  for (let quad = 0; quad < quads.sprites.length; quad++) {
108715
+ blockIndices[indexOffset / 6] = x4 + z4 * 16 + y5 * 256;
108620
108716
  const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
108621
108717
  const brightness = light ? lightBrightness(fluidLightLevel(
108622
108718
  light[lightIndex],
@@ -108647,11 +108743,11 @@ gl_FragDepth=readDepth(vUv);
108647
108743
  indexOffset += 6;
108648
108744
  }
108649
108745
  }
108650
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
108746
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
108651
108747
  });
108652
108748
  }
108653
108749
  function sectionGeometryTransferables(pages) {
108654
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
108750
+ 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]);
108655
108751
  }
108656
108752
 
108657
108753
  // src/world/SectionWorker.ts
@@ -108756,7 +108852,8 @@ gl_FragDepth=readDepth(vUv);
108756
108852
  indices: new Uint16Array(quads * 6),
108757
108853
  cullFaces: new Uint8Array(template.cullFaces),
108758
108854
  atlas: 0,
108759
- layer: template.layer
108855
+ layer: template.layer,
108856
+ ambientOcclusion: template.ambientOcclusion
108760
108857
  };
108761
108858
  const normal = template.geometry.getAttribute("normal");
108762
108859
  const uv = template.geometry.getAttribute("uv");
@@ -108811,6 +108908,12 @@ gl_FragDepth=readDepth(vUv);
108811
108908
  constructor() {
108812
108909
  super(...arguments);
108813
108910
  this.ownedMeshes = [];
108911
+ this.blockIndices = /* @__PURE__ */ new Map();
108912
+ }
108913
+ /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
108914
+ getBlockIndex(hit) {
108915
+ if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
108916
+ return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
108814
108917
  }
108815
108918
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
108816
108919
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
@@ -108853,6 +108956,7 @@ gl_FragDepth=readDepth(vUv);
108853
108956
  const texture = material.uniforms?.map?.value ?? material.map;
108854
108957
  const mesh = new Mesh(geometry, material);
108855
108958
  section.add(mesh);
108959
+ section.blockIndices.set(mesh, page.blockIndices);
108856
108960
  const unsubscribe = [];
108857
108961
  for (const { atlas: id, x: x4, y: y5 } of page.placements) {
108858
108962
  const atlas = atlases[id];
@@ -108878,6 +108982,7 @@ gl_FragDepth=readDepth(vUv);
108878
108982
  mesh.material.dispose();
108879
108983
  texture?.dispose();
108880
108984
  }
108985
+ this.blockIndices.clear();
108881
108986
  this.removeFromParent();
108882
108987
  super.dispose();
108883
108988
  }
@@ -108887,6 +108992,8 @@ gl_FragDepth=readDepth(vUv);
108887
108992
  init_FluidGeometry();
108888
108993
  init_FluidQuads();
108889
108994
  init_CubeFace();
108995
+ init_InstanceReference();
108996
+ init_three();
108890
108997
  var WATER_TINT2 = new Color(4159204).toArray();
108891
108998
  var Chunk = class _Chunk {
108892
108999
  constructor(scene, x4, y5, z4, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
@@ -108900,6 +109007,7 @@ gl_FragDepth=readDepth(vUv);
108900
109007
  this.ambientLight = ambientLight;
108901
109008
  this.data = new ChunkData();
108902
109009
  this.renderedBlocks = /* @__PURE__ */ new Map();
109010
+ this.objectBlocks = /* @__PURE__ */ new Set();
108903
109011
  this.sectionBlocks = /* @__PURE__ */ new Map();
108904
109012
  this.hiddenBlocks = /* @__PURE__ */ new Set();
108905
109013
  this.fluidCells = new Uint8Array(4096);
@@ -108911,6 +109019,89 @@ gl_FragDepth=readDepth(vUv);
108911
109019
  this.y = y5;
108912
109020
  this.z = z4;
108913
109021
  }
109022
+ /** Finds the nearest owned block hit across sections, testing each shared mesh once. */
109023
+ static raycast(chunks, raycaster) {
109024
+ const roots = /* @__PURE__ */ new Map();
109025
+ const targets = /* @__PURE__ */ new Map();
109026
+ const meshes = (root, scene) => {
109027
+ const cached2 = roots.get(root);
109028
+ if (cached2) return cached2;
109029
+ const result = [];
109030
+ roots.set(root, result);
109031
+ let attached = false;
109032
+ for (let parent = root; parent; parent = parent.parent) {
109033
+ if (!parent.visible) return result;
109034
+ if (parent === scene) attached = true;
109035
+ }
109036
+ if (!attached) return result;
109037
+ root.updateWorldMatrix(true, true);
109038
+ root.traverseVisible((object4) => {
109039
+ if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
109040
+ });
109041
+ return result;
109042
+ };
109043
+ const add = (root, owner, reference) => {
109044
+ for (const mesh of meshes(root, owner.chunk.scene)) {
109045
+ if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
109046
+ let entry = targets.get(mesh);
109047
+ if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
109048
+ entry.owners.set(reference?.index, owner);
109049
+ }
109050
+ };
109051
+ for (const chunk of chunks) {
109052
+ for (const index of chunk.objectBlocks) {
109053
+ const block = chunk.renderedBlocks.get(index).object;
109054
+ if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
109055
+ const owner = { chunk, index };
109056
+ for (const model of block.models) {
109057
+ if (isInstanceReference(model)) {
109058
+ if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
109059
+ } else {
109060
+ add(model, owner);
109061
+ }
109062
+ }
109063
+ for (const entity of block.blockEntities) add(entity, owner);
109064
+ }
109065
+ if (chunk.sectionMesh) {
109066
+ for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
109067
+ targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
109068
+ }
109069
+ }
109070
+ }
109071
+ for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
109072
+ if (!hit.face) continue;
109073
+ const mesh = hit.object;
109074
+ const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
109075
+ if (!material?.visible) continue;
109076
+ const entry = targets.get(mesh);
109077
+ let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
109078
+ if (entry.section) {
109079
+ const index = entry.section.mesh.getBlockIndex(hit);
109080
+ if (index !== void 0) owner = { chunk: entry.section.chunk, index };
109081
+ }
109082
+ if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
109083
+ const info = owner.chunk.renderedBlocks.get(owner.index);
109084
+ if (!info) continue;
109085
+ const matrix = mesh.matrixWorld.clone();
109086
+ if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
109087
+ const instance = new Matrix4();
109088
+ mesh.getMatrixAt(hit.instanceId, instance);
109089
+ matrix.multiply(instance);
109090
+ }
109091
+ return {
109092
+ position: new Vector3(
109093
+ owner.chunk.x * 16 + owner.index % 16,
109094
+ owner.chunk.y * 16 + Math.floor(owner.index / 256),
109095
+ owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
109096
+ ),
109097
+ block: info.block,
109098
+ point: hit.point.clone(),
109099
+ normal: hit.face.normal.clone().applyNormalMatrix(new Matrix3().getNormalMatrix(matrix)),
109100
+ distance: hit.distance
109101
+ };
109102
+ }
109103
+ return void 0;
109104
+ }
108914
109105
  getBlockAt(posOrX, y5, z4) {
108915
109106
  if (typeof posOrX == "number") {
108916
109107
  return this.getBlockAt(new Vector3(posOrX, y5, z4));
@@ -109031,6 +109222,7 @@ gl_FragDepth=readDepth(vUv);
109031
109222
  if (this.fluidCells[index]) this.meshDirty = true;
109032
109223
  this.fluidCells[index] = 0;
109033
109224
  this.renderedBlocks.delete(index);
109225
+ this.objectBlocks.delete(index);
109034
109226
  const worldPos = new Vector3(
109035
109227
  this.x * 16 + index % 16,
109036
109228
  this.y * 16 + Math.floor(index / 256),
@@ -109073,6 +109265,7 @@ gl_FragDepth=readDepth(vUv);
109073
109265
  this.renderedBlocks.set(index, { get block() {
109074
109266
  return readBlock();
109075
109267
  }, object: object4 });
109268
+ if (object4) this.objectBlocks.add(index);
109076
109269
  } catch (error2) {
109077
109270
  this.data.assign(index, 0);
109078
109271
  this.fluidCells[index] = 0;
@@ -109091,6 +109284,7 @@ gl_FragDepth=readDepth(vUv);
109091
109284
  this.fluidCells.fill(0);
109092
109285
  this.waterTints = void 0;
109093
109286
  this.renderedBlocks.clear();
109287
+ this.objectBlocks.clear();
109094
109288
  this.hiddenBlocks.clear();
109095
109289
  this.meshDirty = true;
109096
109290
  this.data.copyFrom(data);
@@ -109140,6 +109334,7 @@ gl_FragDepth=readDepth(vUv);
109140
109334
  this.renderedBlocks.set(index, { get block() {
109141
109335
  return readBlock();
109142
109336
  }, object: void 0 });
109337
+ this.objectBlocks.delete(index);
109143
109338
  } catch (error2) {
109144
109339
  this.data.assign(index, 0);
109145
109340
  this.fluidCells[index] = 0;
@@ -109165,10 +109360,12 @@ gl_FragDepth=readDepth(vUv);
109165
109360
  this.z * 256 + Math.floor(index / 16) % 16 * 16
109166
109361
  ));
109167
109362
  this.renderedBlocks.get(index).object = object4;
109363
+ this.objectBlocks.add(index);
109168
109364
  } catch (error2) {
109169
109365
  this.data.assign(index, 0);
109170
109366
  this.fluidCells[index] = 0;
109171
109367
  this.renderedBlocks.delete(index);
109368
+ this.objectBlocks.delete(index);
109172
109369
  object4?.removeFromScene();
109173
109370
  if (!failed) failure = error2;
109174
109371
  failed = true;
@@ -109186,6 +109383,25 @@ gl_FragDepth=readDepth(vUv);
109186
109383
  if (this.renderedBlocks.has(index)) this.meshDirty = true;
109187
109384
  }
109188
109385
  }
109386
+ /** Refreshes baked corner shading after edits or a world setting change. Disabled chunks keep no AO neighborhood. */
109387
+ refreshAmbientOcclusion(enabled) {
109388
+ if (!enabled && !this.ambientOcclusionCells) return;
109389
+ const cells = enabled ? this.buildAmbientOcclusionCells() : void 0;
109390
+ if (cells?.some((value, index) => value !== this.ambientOcclusionCells?.[index]) || !!cells !== !!this.ambientOcclusionCells) this.meshDirty = true;
109391
+ this.ambientOcclusionCells = cells;
109392
+ }
109393
+ buildAmbientOcclusionCells() {
109394
+ const cells = new Uint8Array(18 * 18 * 18);
109395
+ for (let y5 = -1; y5 <= 16; y5++) {
109396
+ for (let z4 = -1; z4 <= 16; z4++) {
109397
+ for (let x4 = -1; x4 <= 16; x4++) {
109398
+ const inner = x4 >= 0 && x4 < 16 && y5 >= 0 && y5 < 16 && z4 >= 0 && z4 < 16;
109399
+ cells[(y5 + 1) * 324 + (z4 + 1) * 18 + x4 + 1] = inner ? Number(this.isOccludingIndex(y5 * 256 + z4 * 16 + x4)) : Number(!!((this.neighborCell?.(this.x * 16 + x4, this.y * 16 + y5, this.z * 16 + z4) ?? 0) & 64));
109400
+ }
109401
+ }
109402
+ }
109403
+ return cells;
109404
+ }
109189
109405
  biomePosition(index, blockState3, stored) {
109190
109406
  const position = this.positionAt(index), name2 = blockState3.key?.toNamespacedString();
109191
109407
  if (stored.properties?.half === "upper" && (name2 === "minecraft:tall_grass" || name2 === "minecraft:large_fern")) position[1]--;
@@ -109374,12 +109590,18 @@ gl_FragDepth=readDepth(vUv);
109374
109590
  }
109375
109591
  }
109376
109592
  }
109377
- const next = entries.length || fluids ? await SectionMesh.buildAsync(
109378
- entries,
109379
- this.sectionModels.maxAtlasSize,
109380
- fluids,
109381
- light ? { light, ambientLight: this.ambientLight } : void 0
109382
- ) : void 0;
109593
+ let next;
109594
+ try {
109595
+ next = entries.length || fluids ? await SectionMesh.buildAsync(
109596
+ entries,
109597
+ this.sectionModels.maxAtlasSize,
109598
+ fluids,
109599
+ { light, ambientLight: this.ambientLight, ambientOcclusion: this.ambientOcclusionCells }
109600
+ ) : void 0;
109601
+ } catch (error2) {
109602
+ if (generation === this.meshGeneration) this.meshDirty = true;
109603
+ throw error2;
109604
+ }
109383
109605
  if (generation !== this.meshGeneration) {
109384
109606
  next?.dispose();
109385
109607
  return;
@@ -109404,9 +109626,11 @@ gl_FragDepth=readDepth(vUv);
109404
109626
  this.sectionMesh = void 0;
109405
109627
  this.meshDirty = false;
109406
109628
  this.renderedBlocks.clear();
109629
+ this.objectBlocks.clear();
109407
109630
  this.hiddenBlocks.clear();
109408
109631
  this.fluidCells.fill(0);
109409
109632
  this.waterTints = void 0;
109633
+ this.ambientOcclusionCells = void 0;
109410
109634
  this.data.clear();
109411
109635
  this.biomes = void 0;
109412
109636
  if (notify) {
@@ -109444,6 +109668,11 @@ gl_FragDepth=readDepth(vUv);
109444
109668
  }
109445
109669
  };
109446
109670
 
109671
+ // src/world/WorldBlockIntersection.ts
109672
+ init_dirname();
109673
+ init_buffer2();
109674
+ init_process2();
109675
+
109447
109676
  // src/world/WorldChunkSource.ts
109448
109677
  init_dirname();
109449
109678
  init_buffer2();