minerender 2.1.0-alpha.121 → 2.1.0-alpha.123

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.
@@ -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;
@@ -17386,12 +17390,12 @@ var AnvilWorldSource = class {
17386
17390
  };
17387
17391
 
17388
17392
  // src/world/Chunk.ts
17389
- var import_three44 = require("three");
17393
+ var import_three47 = require("three");
17390
17394
  init_BlockStates();
17391
17395
  init_AssetKey();
17392
17396
 
17393
17397
  // src/world/MineRenderWorld.ts
17394
- var import_three42 = require("three");
17398
+ var import_three45 = require("three");
17395
17399
  init_Model();
17396
17400
  init_util();
17397
17401
  init_AssetKey();
@@ -17656,11 +17660,74 @@ function resolveSavedEntity(entity) {
17656
17660
 
17657
17661
  // src/world/_entities/WorldEntities.ts
17658
17662
  init_BannerPatterns();
17663
+ var import_three44 = require("three");
17664
+
17665
+ // src/world/_picking/Picking.ts
17666
+ var import_three42 = require("three");
17667
+ init_three();
17668
+ function pickableMeshes(root, scene, raycaster) {
17669
+ const result = [];
17670
+ let attached = false;
17671
+ for (let parent = root; parent; parent = parent.parent) {
17672
+ if (!parent.visible) return result;
17673
+ if (parent === scene) attached = true;
17674
+ }
17675
+ if (!attached) return result;
17676
+ root.updateWorldMatrix(true, true);
17677
+ root.traverseVisible((object4) => {
17678
+ if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
17679
+ });
17680
+ return result;
17681
+ }
17682
+ function visibleHits(raycaster, meshes) {
17683
+ return raycaster.intersectObjects(meshes, false).filter((hit) => {
17684
+ if (!hit.face) return false;
17685
+ const mesh = hit.object;
17686
+ const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
17687
+ return material?.visible;
17688
+ });
17689
+ }
17690
+ function hitNormal(hit) {
17691
+ const mesh = hit.object;
17692
+ const matrix = mesh.matrixWorld.clone();
17693
+ if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
17694
+ const instance = new import_three42.Matrix4();
17695
+ mesh.getMatrixAt(hit.instanceId, instance);
17696
+ matrix.multiply(instance);
17697
+ }
17698
+ return hit.face.normal.clone().applyNormalMatrix(new import_three42.Matrix3().getNormalMatrix(matrix));
17699
+ }
17700
+
17701
+ // src/world/_entities/WorldEntities.ts
17659
17702
  var WorldEntities = class {
17660
17703
  constructor(scene) {
17661
17704
  this.scene = scene;
17662
17705
  this.columns = /* @__PURE__ */ new Map();
17663
17706
  }
17707
+ /** Finds the nearest visible triangle belonging to an entity owned by this world. */
17708
+ raycast(raycaster) {
17709
+ const owners = /* @__PURE__ */ new Map();
17710
+ for (const column of this.columns.values()) {
17711
+ for (const [object4, placement] of column) {
17712
+ for (const mesh of pickableMeshes(object4, this.scene, raycaster)) {
17713
+ owners.set(mesh, { object: object4, ...placement });
17714
+ }
17715
+ }
17716
+ }
17717
+ for (const hit of visibleHits(raycaster, [...owners.keys()])) {
17718
+ const mesh = hit.object;
17719
+ const owner = owners.get(mesh);
17720
+ return {
17721
+ type: owner.type,
17722
+ position: new import_three44.Vector3(...owner.position),
17723
+ object: owner.object,
17724
+ point: hit.point.clone(),
17725
+ normal: hitNormal(hit),
17726
+ distance: hit.distance
17727
+ };
17728
+ }
17729
+ return void 0;
17730
+ }
17664
17731
  /** Captures column ownership before asynchronous block or asset loading starts. */
17665
17732
  prepare(entities = [], column) {
17666
17733
  const placements = entities.flatMap((entity) => {
@@ -17669,7 +17736,7 @@ var WorldEntities = class {
17669
17736
  const position = [...entity.position];
17670
17737
  const key = column?.join(",") ?? `${Math.floor(position[0] / 16)},${Math.floor(position[2] / 16)}`;
17671
17738
  let owner = this.columns.get(key);
17672
- if (!owner) this.columns.set(key, owner = /* @__PURE__ */ new Set());
17739
+ if (!owner) this.columns.set(key, owner = /* @__PURE__ */ new Map());
17673
17740
  return [{ ...resolved, position, column: key, owner }];
17674
17741
  });
17675
17742
  return async () => {
@@ -17695,7 +17762,7 @@ var WorldEntities = class {
17695
17762
  object4.rotation.y = placement.yaw;
17696
17763
  await object4.init();
17697
17764
  if (!current()) return;
17698
- placement.owner.add(object4);
17765
+ placement.owner.set(object4, { type: placement.key.toNamespacedString(), position: placement.position });
17699
17766
  this.scene.add(object4);
17700
17767
  } catch (error) {
17701
17768
  console.warn(`Could not draw saved entity ${placement.key.toNamespacedString()}, skipping it`, error);
@@ -17710,7 +17777,7 @@ var WorldEntities = class {
17710
17777
  const objects = this.columns.get(key);
17711
17778
  this.columns.delete(key);
17712
17779
  if (!objects) return;
17713
- for (const object4 of objects) {
17780
+ for (const object4 of objects.keys()) {
17714
17781
  object4.removeFromScene();
17715
17782
  object4.dispose();
17716
17783
  }
@@ -17771,6 +17838,21 @@ var MineRenderWorld = class {
17771
17838
  if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
17772
17839
  if (options.renderEntities) this.entities = new WorldEntities(scene);
17773
17840
  }
17841
+ /**
17842
+ * Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
17843
+ * Includes fluids and block entities; texture alpha does not change triangle intersections.
17844
+ */
17845
+ raycast(raycaster) {
17846
+ return Chunk.raycast(this._chunks.values(), raycaster);
17847
+ }
17848
+ /**
17849
+ * Returns the nearest visible mob geometry hit when renderEntities is enabled.
17850
+ * Respects layers and near/far; compare its distance with raycast() to account for blocks.
17851
+ * Texture alpha does not change triangle intersections.
17852
+ */
17853
+ raycastEntities(raycaster) {
17854
+ return this.entities?.raycast(raycaster);
17855
+ }
17774
17856
  /** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
17775
17857
  get ambientOcclusion() {
17776
17858
  return this._ambientOcclusion;
@@ -17791,25 +17873,25 @@ var MineRenderWorld = class {
17791
17873
  }
17792
17874
  getBlockAt(posOrX, y, z) {
17793
17875
  if (typeof posOrX == "number") {
17794
- return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
17876
+ return this.getBlockAt(new import_three45.Vector3(posOrX, y, z));
17795
17877
  }
17796
17878
  if (isTripleArray(posOrX)) {
17797
- return this.getBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]));
17879
+ return this.getBlockAt(new import_three45.Vector3(posOrX[0], posOrX[1], posOrX[2]));
17798
17880
  }
17799
17881
  this.validatePosBounds(posOrX);
17800
17882
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
17801
17883
  }
17802
17884
  getBiomeAt(posOrX, y, z) {
17803
- if (typeof posOrX === "number") return this.getBiomeAt(new import_three42.Vector3(posOrX, y, z));
17804
- if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three42.Vector3(...posOrX));
17885
+ if (typeof posOrX === "number") return this.getBiomeAt(new import_three45.Vector3(posOrX, y, z));
17886
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three45.Vector3(...posOrX));
17805
17887
  this.validatePosBounds(posOrX);
17806
17888
  const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
17807
17889
  const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
17808
17890
  return this.biomes.get(`${cx}_${cz}`)?.get(cy)?.[Math.floor(lx / 4) + Math.floor(lz / 4) * 4 + Math.floor(ly / 4) * 16];
17809
17891
  }
17810
17892
  getLightAt(posOrX, y, z) {
17811
- if (typeof posOrX === "number") return this.getLightAt(new import_three42.Vector3(posOrX, y, z));
17812
- if (isTripleArray(posOrX)) return this.getLightAt(new import_three42.Vector3(...posOrX));
17893
+ if (typeof posOrX === "number") return this.getLightAt(new import_three45.Vector3(posOrX, y, z));
17894
+ if (isTripleArray(posOrX)) return this.getLightAt(new import_three45.Vector3(...posOrX));
17813
17895
  this.validatePosBounds(posOrX);
17814
17896
  const { x, y: py, z: pz } = posOrX;
17815
17897
  const cx = Math.floor(x / 16), cy = Math.floor(py / 16), cz = Math.floor(pz / 16);
@@ -17827,10 +17909,10 @@ var MineRenderWorld = class {
17827
17909
  }
17828
17910
  async setBlockAt(posOrX, yOrBlock, z, block) {
17829
17911
  if (typeof posOrX == "number") {
17830
- return this.setBlockAt(new import_three42.Vector3(posOrX, yOrBlock, z), block);
17912
+ return this.setBlockAt(new import_three45.Vector3(posOrX, yOrBlock, z), block);
17831
17913
  }
17832
17914
  if (isTripleArray(posOrX)) {
17833
- return this.setBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17915
+ return this.setBlockAt(new import_three45.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17834
17916
  }
17835
17917
  return this.placeBlock(posOrX, yOrBlock);
17836
17918
  }
@@ -17841,10 +17923,10 @@ var MineRenderWorld = class {
17841
17923
  }
17842
17924
  async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
17843
17925
  if (typeof posOrX === "number") {
17844
- return this.setBlockVisibleAt(new import_three42.Vector3(posOrX, yOrVisible, z), visible);
17926
+ return this.setBlockVisibleAt(new import_three45.Vector3(posOrX, yOrVisible, z), visible);
17845
17927
  }
17846
17928
  if (isTripleArray(posOrX)) {
17847
- return this.setBlockVisibleAt(new import_three42.Vector3(...posOrX), yOrVisible);
17929
+ return this.setBlockVisibleAt(new import_three45.Vector3(...posOrX), yOrVisible);
17848
17930
  }
17849
17931
  this.validatePosBounds(posOrX);
17850
17932
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
@@ -17870,7 +17952,7 @@ var MineRenderWorld = class {
17870
17952
  const collect = async (positions2) => {
17871
17953
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
17872
17954
  };
17873
- const place = (block) => this.placeBlock(new import_three42.Vector3(...block.position), block, collect);
17955
+ const place = (block) => this.placeBlock(new import_three45.Vector3(...block.position), block, collect);
17874
17956
  const keys = /* @__PURE__ */ new Map();
17875
17957
  const types = /* @__PURE__ */ new Set();
17876
17958
  for (const block of multiblock.blocks) {
@@ -17886,7 +17968,7 @@ var MineRenderWorld = class {
17886
17968
  }
17887
17969
  if (!executor) {
17888
17970
  const groups2 = /* @__PURE__ */ new Map();
17889
- const position = new import_three42.Vector3();
17971
+ const position = new import_three45.Vector3();
17890
17972
  for (const block of multiblock.blocks) {
17891
17973
  const [x, y, z] = block.position;
17892
17974
  this.validatePosBounds(position.set(x, y, z));
@@ -17926,7 +18008,7 @@ var MineRenderWorld = class {
17926
18008
  try {
17927
18009
  positions = await chunk.placeBlocks(blocks);
17928
18010
  } finally {
17929
- positions ??= blocks.map(({ index }) => new import_three42.Vector3(
18011
+ positions ??= blocks.map(({ index }) => new import_three45.Vector3(
17930
18012
  chunk.x * 16 + index % 16,
17931
18013
  chunk.y * 16 + Math.floor(index / 256),
17932
18014
  chunk.z * 16 + Math.floor(index / 16) % 16
@@ -17978,7 +18060,7 @@ var MineRenderWorld = class {
17978
18060
  }
17979
18061
  for (const section of chunk.sections) {
17980
18062
  if (section.biomes) {
17981
- const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
18063
+ const position = new import_three45.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
17982
18064
  this.validatePosBounds(position);
17983
18065
  const copy = [...section.biomes];
17984
18066
  if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
@@ -17994,7 +18076,7 @@ var MineRenderWorld = class {
17994
18076
  for (const section of chunk.sections) {
17995
18077
  if (!executor) {
17996
18078
  if (!occupiedSections.has(section.y)) continue;
17997
- const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
18079
+ const position = new import_three45.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
17998
18080
  this.validatePosBounds(position);
17999
18081
  const target = this.getOrCreateChunkAt(position);
18000
18082
  try {
@@ -18098,7 +18180,7 @@ var MineRenderWorld = class {
18098
18180
  this.sectionModels?.clear();
18099
18181
  }
18100
18182
  updateCulling(positions) {
18101
- const neighbor = new import_three42.Vector3();
18183
+ const neighbor = new import_three45.Vector3();
18102
18184
  for (const pos of positions) {
18103
18185
  const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
18104
18186
  const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
@@ -18229,7 +18311,7 @@ var MineRenderWorld = class {
18229
18311
  }
18230
18312
  /** Converts block coordinates to scene units by multiplying each component by 16. */
18231
18313
  static worldToScenePosition(pos) {
18232
- return new import_three42.Vector3(
18314
+ return new import_three45.Vector3(
18233
18315
  pos.x * 16,
18234
18316
  pos.y * 16,
18235
18317
  pos.z * 16
@@ -18237,7 +18319,7 @@ var MineRenderWorld = class {
18237
18319
  }
18238
18320
  /** Converts scene units to block coordinates without rounding to an integer block. */
18239
18321
  static sceneToWorldPosition(pos) {
18240
- return new import_three42.Vector3(
18322
+ return new import_three45.Vector3(
18241
18323
  pos.x / 16,
18242
18324
  pos.y / 16,
18243
18325
  pos.z / 16
@@ -18260,7 +18342,7 @@ var MineRenderWorld = class {
18260
18342
  init_Model();
18261
18343
 
18262
18344
  // src/world/SectionMesh.ts
18263
- var import_three43 = require("three");
18345
+ var import_three46 = require("three");
18264
18346
  init_CanvasCompat();
18265
18347
  init_Materials();
18266
18348
 
@@ -18445,6 +18527,7 @@ function buildSectionGeometry(input) {
18445
18527
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
18446
18528
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
18447
18529
  const outputIndices = new Uint32Array(faces * 6);
18530
+ const blockIndices = new Uint16Array(faces);
18448
18531
  let vertex = 0, indexOffset = 0;
18449
18532
  for (const entry of page.entries) {
18450
18533
  const template = templateData[templates[entry]];
@@ -18459,6 +18542,7 @@ function buildSectionGeometry(input) {
18459
18542
  const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
18460
18543
  for (let quad = 0; quad < template.quads; quad++) {
18461
18544
  if (cullMasks[entry] & template.cullFaces[quad]) continue;
18545
+ blockIndices[indexOffset / 6] = indices[entry];
18462
18546
  if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
18463
18547
  const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
18464
18548
  const start = vertex;
@@ -18491,6 +18575,7 @@ function buildSectionGeometry(input) {
18491
18575
  const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
18492
18576
  const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
18493
18577
  for (let quad = 0; quad < quads.sprites.length; quad++) {
18578
+ blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
18494
18579
  const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
18495
18580
  const brightness = light ? lightBrightness(fluidLightLevel(
18496
18581
  light[lightIndex],
@@ -18521,11 +18606,11 @@ function buildSectionGeometry(input) {
18521
18606
  indexOffset += 6;
18522
18607
  }
18523
18608
  }
18524
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
18609
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
18525
18610
  });
18526
18611
  }
18527
18612
  function sectionGeometryTransferables(pages) {
18528
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
18613
+ 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]);
18529
18614
  }
18530
18615
 
18531
18616
  // src/world/SectionWorker.ts
@@ -18583,7 +18668,7 @@ var SectionWorker = class _SectionWorker {
18583
18668
 
18584
18669
  // src/world/SectionMesh.ts
18585
18670
  var templateCache = /* @__PURE__ */ new WeakMap();
18586
- var WATER_TINT = new import_three43.Color(4159204).toArray();
18671
+ var WATER_TINT = new import_three46.Color(4159204).toArray();
18587
18672
  function toInput(entries, maxAtlasSize, fluids, lighting) {
18588
18673
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
18589
18674
  const atlases = [];
@@ -18680,10 +18765,16 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
18680
18765
  }
18681
18766
  return { input, atlases };
18682
18767
  }
18683
- var SectionMesh = class _SectionMesh extends import_three43.Group {
18768
+ var SectionMesh = class _SectionMesh extends import_three46.Group {
18684
18769
  constructor() {
18685
18770
  super(...arguments);
18686
18771
  this.ownedMeshes = [];
18772
+ this.blockIndices = /* @__PURE__ */ new Map();
18773
+ }
18774
+ /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
18775
+ getBlockIndex(hit) {
18776
+ if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
18777
+ return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
18687
18778
  }
18688
18779
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
18689
18780
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
@@ -18705,27 +18796,28 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
18705
18796
  for (const { atlas, x, y } of page.placements) {
18706
18797
  context.drawImage(atlases[atlas].image.canvas, x, y);
18707
18798
  }
18708
- const geometry = new import_three43.BufferGeometry();
18709
- geometry.setAttribute("position", new import_three43.Float32BufferAttribute(page.positions.buffer, 3));
18710
- geometry.setAttribute("normal", new import_three43.Float32BufferAttribute(page.normals.buffer, 3));
18711
- geometry.setAttribute("uv", new import_three43.Float32BufferAttribute(page.uvs.buffer, 2));
18712
- geometry.setAttribute("uvBounds", new import_three43.Float32BufferAttribute(page.uvBounds.buffer, 4));
18713
- geometry.setAttribute("color", new import_three43.Float32BufferAttribute(page.colors.buffer, 3));
18714
- geometry.setIndex(new import_three43.Uint32BufferAttribute(page.indices.buffer, 1));
18799
+ const geometry = new import_three46.BufferGeometry();
18800
+ geometry.setAttribute("position", new import_three46.Float32BufferAttribute(page.positions.buffer, 3));
18801
+ geometry.setAttribute("normal", new import_three46.Float32BufferAttribute(page.normals.buffer, 3));
18802
+ geometry.setAttribute("uv", new import_three46.Float32BufferAttribute(page.uvs.buffer, 2));
18803
+ geometry.setAttribute("uvBounds", new import_three46.Float32BufferAttribute(page.uvBounds.buffer, 4));
18804
+ geometry.setAttribute("color", new import_three46.Float32BufferAttribute(page.colors.buffer, 3));
18805
+ geometry.setIndex(new import_three46.Uint32BufferAttribute(page.indices.buffer, 1));
18715
18806
  geometry.computeBoundingBox();
18716
18807
  geometry.computeBoundingSphere();
18717
18808
  const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;
18718
18809
  const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
18719
- material.side = import_three43.FrontSide;
18810
+ material.side = import_three46.FrontSide;
18720
18811
  if (page.layer === 2) {
18721
- material.side = import_three43.DoubleSide;
18812
+ material.side = import_three46.DoubleSide;
18722
18813
  material.forceSinglePass = true;
18723
18814
  material.depthWrite = !material.transparent;
18724
18815
  }
18725
18816
  material.vertexColors = true;
18726
18817
  const texture = material.uniforms?.map?.value ?? material.map;
18727
- const mesh = new import_three43.Mesh(geometry, material);
18818
+ const mesh = new import_three46.Mesh(geometry, material);
18728
18819
  section.add(mesh);
18820
+ section.blockIndices.set(mesh, page.blockIndices);
18729
18821
  const unsubscribe = [];
18730
18822
  for (const { atlas: id, x, y } of page.placements) {
18731
18823
  const atlas = atlases[id];
@@ -18751,6 +18843,7 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
18751
18843
  mesh.material.dispose();
18752
18844
  texture?.dispose();
18753
18845
  }
18846
+ this.blockIndices.clear();
18754
18847
  this.removeFromParent();
18755
18848
  super.dispose();
18756
18849
  }
@@ -18760,7 +18853,8 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
18760
18853
  init_FluidGeometry();
18761
18854
  init_FluidQuads();
18762
18855
  init_CubeFace();
18763
- var WATER_TINT2 = new import_three44.Color(4159204).toArray();
18856
+ init_InstanceReference();
18857
+ var WATER_TINT2 = new import_three47.Color(4159204).toArray();
18764
18858
  var Chunk = class _Chunk {
18765
18859
  constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
18766
18860
  this.onBlocksChanged = onBlocksChanged;
@@ -18773,10 +18867,11 @@ var Chunk = class _Chunk {
18773
18867
  this.ambientLight = ambientLight;
18774
18868
  this.data = new ChunkData();
18775
18869
  this.renderedBlocks = /* @__PURE__ */ new Map();
18870
+ this.objectBlocks = /* @__PURE__ */ new Set();
18776
18871
  this.sectionBlocks = /* @__PURE__ */ new Map();
18777
18872
  this.hiddenBlocks = /* @__PURE__ */ new Set();
18778
18873
  this.fluidCells = new Uint8Array(4096);
18779
- this.blockPosition = new import_three44.Vector3();
18874
+ this.blockPosition = new import_three47.Vector3();
18780
18875
  this.meshDirty = false;
18781
18876
  this.meshGeneration = 0;
18782
18877
  this.scene = scene;
@@ -18784,20 +18879,84 @@ var Chunk = class _Chunk {
18784
18879
  this.y = y;
18785
18880
  this.z = z;
18786
18881
  }
18882
+ /** Finds the nearest owned block hit across sections, testing each shared mesh once. */
18883
+ static raycast(chunks, raycaster) {
18884
+ const roots = /* @__PURE__ */ new Map();
18885
+ const targets = /* @__PURE__ */ new Map();
18886
+ const meshes = (root, scene) => {
18887
+ const cached2 = roots.get(root);
18888
+ if (cached2) return cached2;
18889
+ const result = pickableMeshes(root, scene, raycaster);
18890
+ roots.set(root, result);
18891
+ return result;
18892
+ };
18893
+ const add = (root, owner, reference) => {
18894
+ for (const mesh of meshes(root, owner.chunk.scene)) {
18895
+ if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
18896
+ let entry = targets.get(mesh);
18897
+ if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
18898
+ entry.owners.set(reference?.index, owner);
18899
+ }
18900
+ };
18901
+ for (const chunk of chunks) {
18902
+ for (const index of chunk.objectBlocks) {
18903
+ const block = chunk.renderedBlocks.get(index).object;
18904
+ if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
18905
+ const owner = { chunk, index };
18906
+ for (const model of block.models) {
18907
+ if (isInstanceReference(model)) {
18908
+ if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
18909
+ } else {
18910
+ add(model, owner);
18911
+ }
18912
+ }
18913
+ for (const entity of block.blockEntities) add(entity, owner);
18914
+ }
18915
+ if (chunk.sectionMesh) {
18916
+ for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
18917
+ targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
18918
+ }
18919
+ }
18920
+ }
18921
+ for (const hit of visibleHits(raycaster, [...targets.keys()])) {
18922
+ const mesh = hit.object;
18923
+ const entry = targets.get(mesh);
18924
+ let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
18925
+ if (entry.section) {
18926
+ const index = entry.section.mesh.getBlockIndex(hit);
18927
+ if (index !== void 0) owner = { chunk: entry.section.chunk, index };
18928
+ }
18929
+ if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
18930
+ const info = owner.chunk.renderedBlocks.get(owner.index);
18931
+ if (!info) continue;
18932
+ return {
18933
+ position: new import_three47.Vector3(
18934
+ owner.chunk.x * 16 + owner.index % 16,
18935
+ owner.chunk.y * 16 + Math.floor(owner.index / 256),
18936
+ owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
18937
+ ),
18938
+ block: info.block,
18939
+ point: hit.point.clone(),
18940
+ normal: hitNormal(hit),
18941
+ distance: hit.distance
18942
+ };
18943
+ }
18944
+ return void 0;
18945
+ }
18787
18946
  getBlockAt(posOrX, y, z) {
18788
18947
  if (typeof posOrX == "number") {
18789
- return this.getBlockAt(new import_three44.Vector3(posOrX, y, z));
18948
+ return this.getBlockAt(new import_three47.Vector3(posOrX, y, z));
18790
18949
  }
18791
18950
  if (isTripleArray(posOrX)) {
18792
- return this.getBlockAt(new import_three44.Vector3(posOrX[0], posOrX[1], posOrX[2]));
18951
+ return this.getBlockAt(new import_three47.Vector3(posOrX[0], posOrX[1], posOrX[2]));
18793
18952
  }
18794
18953
  const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
18795
18954
  const index = _Chunk.chunkPosToBlockIndex(pos);
18796
18955
  return this.renderedBlocks.get(index);
18797
18956
  }
18798
18957
  getBiomeAt(posOrX, y, z) {
18799
- if (typeof posOrX === "number") return this.getBiomeAt(new import_three44.Vector3(posOrX, y, z));
18800
- if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three44.Vector3(...posOrX));
18958
+ if (typeof posOrX === "number") return this.getBiomeAt(new import_three47.Vector3(posOrX, y, z));
18959
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three47.Vector3(...posOrX));
18801
18960
  const pos = this.worldPosToChunkPos(posOrX);
18802
18961
  _Chunk.chunkPosToBlockIndex(pos);
18803
18962
  return this.biomeAt ? this.biomeAt(posOrX.x, posOrX.y, posOrX.z) : this.biomes?.[Math.floor(pos.x / 4) + Math.floor(pos.z / 4) * 4 + Math.floor(pos.y / 4) * 16];
@@ -18840,17 +18999,17 @@ var Chunk = class _Chunk {
18840
18999
  this.hiddenBlocks.add(index);
18841
19000
  this.renderedBlocks.get(index)?.object?.setVisible(false);
18842
19001
  }
18843
- const positions = blocks.map(({ index }) => new import_three44.Vector3(...this.positionAt(index)));
19002
+ const positions = blocks.map(({ index }) => new import_three47.Vector3(...this.positionAt(index)));
18844
19003
  if (this.onBlocksChanged) await this.onBlocksChanged(positions);
18845
19004
  else await this.rebuildSectionMesh();
18846
19005
  }
18847
19006
  }
18848
19007
  async setBlockAt(posOrX, yOrBlock, z, block) {
18849
19008
  if (typeof posOrX == "number") {
18850
- return this.setBlockAt(new import_three44.Vector3(posOrX, yOrBlock, z), block);
19009
+ return this.setBlockAt(new import_three47.Vector3(posOrX, yOrBlock, z), block);
18851
19010
  }
18852
19011
  if (isTripleArray(posOrX)) {
18853
- return this.setBlockAt(new import_three44.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
19012
+ return this.setBlockAt(new import_three47.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
18854
19013
  }
18855
19014
  const worldPos = posOrX;
18856
19015
  const pos = this.worldPosToChunkPos(worldPos);
@@ -18904,7 +19063,8 @@ var Chunk = class _Chunk {
18904
19063
  if (this.fluidCells[index]) this.meshDirty = true;
18905
19064
  this.fluidCells[index] = 0;
18906
19065
  this.renderedBlocks.delete(index);
18907
- const worldPos = new import_three44.Vector3(
19066
+ this.objectBlocks.delete(index);
19067
+ const worldPos = new import_three47.Vector3(
18908
19068
  this.x * 16 + index % 16,
18909
19069
  this.y * 16 + Math.floor(index / 256),
18910
19070
  this.z * 16 + Math.floor(index / 16) % 16
@@ -18946,6 +19106,7 @@ var Chunk = class _Chunk {
18946
19106
  this.renderedBlocks.set(index, { get block() {
18947
19107
  return readBlock();
18948
19108
  }, object: object4 });
19109
+ if (object4) this.objectBlocks.add(index);
18949
19110
  } catch (error) {
18950
19111
  this.data.assign(index, 0);
18951
19112
  this.fluidCells[index] = 0;
@@ -18964,6 +19125,7 @@ var Chunk = class _Chunk {
18964
19125
  this.fluidCells.fill(0);
18965
19126
  this.waterTints = void 0;
18966
19127
  this.renderedBlocks.clear();
19128
+ this.objectBlocks.clear();
18967
19129
  this.hiddenBlocks.clear();
18968
19130
  this.meshDirty = true;
18969
19131
  this.data.copyFrom(data);
@@ -19013,6 +19175,7 @@ var Chunk = class _Chunk {
19013
19175
  this.renderedBlocks.set(index, { get block() {
19014
19176
  return readBlock();
19015
19177
  }, object: void 0 });
19178
+ this.objectBlocks.delete(index);
19016
19179
  } catch (error) {
19017
19180
  this.data.assign(index, 0);
19018
19181
  this.fluidCells[index] = 0;
@@ -19032,16 +19195,18 @@ var Chunk = class _Chunk {
19032
19195
  biome,
19033
19196
  biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
19034
19197
  });
19035
- object4.setPosition(new import_three44.Vector3(
19198
+ object4.setPosition(new import_three47.Vector3(
19036
19199
  this.x * 256 + index % 16 * 16,
19037
19200
  this.y * 256 + Math.floor(index / 256) * 16,
19038
19201
  this.z * 256 + Math.floor(index / 16) % 16 * 16
19039
19202
  ));
19040
19203
  this.renderedBlocks.get(index).object = object4;
19204
+ this.objectBlocks.add(index);
19041
19205
  } catch (error) {
19042
19206
  this.data.assign(index, 0);
19043
19207
  this.fluidCells[index] = 0;
19044
19208
  this.renderedBlocks.delete(index);
19209
+ this.objectBlocks.delete(index);
19045
19210
  object4?.removeFromScene();
19046
19211
  if (!failed) failure = error;
19047
19212
  failed = true;
@@ -19122,7 +19287,7 @@ var Chunk = class _Chunk {
19122
19287
  context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
19123
19288
  if (fluid?.kind === "water" && await available()) {
19124
19289
  const color2 = await Biomes.getColor(biome, "water", blockState3?.key);
19125
- if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three44.Color(color2).toArray();
19290
+ if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three47.Color(color2).toArray();
19126
19291
  }
19127
19292
  }
19128
19293
  for (const index of indices2) contexts.set(index, context);
@@ -19293,7 +19458,7 @@ var Chunk = class _Chunk {
19293
19458
  /** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
19294
19459
  async clear(notify = true) {
19295
19460
  const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
19296
- new import_three44.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
19461
+ new import_three47.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
19297
19462
  )) : [];
19298
19463
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
19299
19464
  this.sectionBlocks.clear();
@@ -19302,6 +19467,7 @@ var Chunk = class _Chunk {
19302
19467
  this.sectionMesh = void 0;
19303
19468
  this.meshDirty = false;
19304
19469
  this.renderedBlocks.clear();
19470
+ this.objectBlocks.clear();
19305
19471
  this.hiddenBlocks.clear();
19306
19472
  this.fluidCells.fill(0);
19307
19473
  this.waterTints = void 0;
@@ -19328,14 +19494,14 @@ var Chunk = class _Chunk {
19328
19494
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
19329
19495
  }
19330
19496
  worldPosToChunkPos(pos) {
19331
- return new import_three44.Vector3(
19497
+ return new import_three47.Vector3(
19332
19498
  pos.x - this.x * 16,
19333
19499
  pos.y - this.y * 16,
19334
19500
  pos.z - this.z * 16
19335
19501
  );
19336
19502
  }
19337
19503
  chunkPosToWorldPos(pos) {
19338
- return new import_three44.Vector3(
19504
+ return new import_three47.Vector3(
19339
19505
  this.x * 16 + pos.x,
19340
19506
  this.y * 16 + pos.y,
19341
19507
  this.z * 16 + pos.z