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.
@@ -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;
@@ -17351,12 +17355,12 @@ var AnvilWorldSource = class {
17351
17355
  };
17352
17356
 
17353
17357
  // src/world/Chunk.ts
17354
- var import_three44 = require("three");
17358
+ var import_three47 = require("three");
17355
17359
  init_BlockStates();
17356
17360
  init_AssetKey();
17357
17361
 
17358
17362
  // src/world/MineRenderWorld.ts
17359
- var import_three42 = require("three");
17363
+ var import_three45 = require("three");
17360
17364
  init_Model();
17361
17365
  init_util();
17362
17366
  init_AssetKey();
@@ -17621,11 +17625,74 @@ function resolveSavedEntity(entity) {
17621
17625
 
17622
17626
  // src/world/_entities/WorldEntities.ts
17623
17627
  init_BannerPatterns();
17628
+ var import_three44 = require("three");
17629
+
17630
+ // src/world/_picking/Picking.ts
17631
+ var import_three42 = require("three");
17632
+ init_three();
17633
+ function pickableMeshes(root, scene, raycaster) {
17634
+ const result = [];
17635
+ let attached = false;
17636
+ for (let parent = root; parent; parent = parent.parent) {
17637
+ if (!parent.visible) return result;
17638
+ if (parent === scene) attached = true;
17639
+ }
17640
+ if (!attached) return result;
17641
+ root.updateWorldMatrix(true, true);
17642
+ root.traverseVisible((object4) => {
17643
+ if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
17644
+ });
17645
+ return result;
17646
+ }
17647
+ function visibleHits(raycaster, meshes) {
17648
+ return raycaster.intersectObjects(meshes, false).filter((hit) => {
17649
+ if (!hit.face) return false;
17650
+ const mesh = hit.object;
17651
+ const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
17652
+ return material?.visible;
17653
+ });
17654
+ }
17655
+ function hitNormal(hit) {
17656
+ const mesh = hit.object;
17657
+ const matrix = mesh.matrixWorld.clone();
17658
+ if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
17659
+ const instance = new import_three42.Matrix4();
17660
+ mesh.getMatrixAt(hit.instanceId, instance);
17661
+ matrix.multiply(instance);
17662
+ }
17663
+ return hit.face.normal.clone().applyNormalMatrix(new import_three42.Matrix3().getNormalMatrix(matrix));
17664
+ }
17665
+
17666
+ // src/world/_entities/WorldEntities.ts
17624
17667
  var WorldEntities = class {
17625
17668
  constructor(scene) {
17626
17669
  this.scene = scene;
17627
17670
  this.columns = /* @__PURE__ */ new Map();
17628
17671
  }
17672
+ /** Finds the nearest visible triangle belonging to an entity owned by this world. */
17673
+ raycast(raycaster) {
17674
+ const owners = /* @__PURE__ */ new Map();
17675
+ for (const column of this.columns.values()) {
17676
+ for (const [object4, placement] of column) {
17677
+ for (const mesh of pickableMeshes(object4, this.scene, raycaster)) {
17678
+ owners.set(mesh, { object: object4, ...placement });
17679
+ }
17680
+ }
17681
+ }
17682
+ for (const hit of visibleHits(raycaster, [...owners.keys()])) {
17683
+ const mesh = hit.object;
17684
+ const owner = owners.get(mesh);
17685
+ return {
17686
+ type: owner.type,
17687
+ position: new import_three44.Vector3(...owner.position),
17688
+ object: owner.object,
17689
+ point: hit.point.clone(),
17690
+ normal: hitNormal(hit),
17691
+ distance: hit.distance
17692
+ };
17693
+ }
17694
+ return void 0;
17695
+ }
17629
17696
  /** Captures column ownership before asynchronous block or asset loading starts. */
17630
17697
  prepare(entities = [], column) {
17631
17698
  const placements = entities.flatMap((entity) => {
@@ -17634,7 +17701,7 @@ var WorldEntities = class {
17634
17701
  const position = [...entity.position];
17635
17702
  const key = column?.join(",") ?? `${Math.floor(position[0] / 16)},${Math.floor(position[2] / 16)}`;
17636
17703
  let owner = this.columns.get(key);
17637
- if (!owner) this.columns.set(key, owner = /* @__PURE__ */ new Set());
17704
+ if (!owner) this.columns.set(key, owner = /* @__PURE__ */ new Map());
17638
17705
  return [{ ...resolved, position, column: key, owner }];
17639
17706
  });
17640
17707
  return async () => {
@@ -17660,7 +17727,7 @@ var WorldEntities = class {
17660
17727
  object4.rotation.y = placement.yaw;
17661
17728
  await object4.init();
17662
17729
  if (!current()) return;
17663
- placement.owner.add(object4);
17730
+ placement.owner.set(object4, { type: placement.key.toNamespacedString(), position: placement.position });
17664
17731
  this.scene.add(object4);
17665
17732
  } catch (error) {
17666
17733
  console.warn(`Could not draw saved entity ${placement.key.toNamespacedString()}, skipping it`, error);
@@ -17675,7 +17742,7 @@ var WorldEntities = class {
17675
17742
  const objects = this.columns.get(key);
17676
17743
  this.columns.delete(key);
17677
17744
  if (!objects) return;
17678
- for (const object4 of objects) {
17745
+ for (const object4 of objects.keys()) {
17679
17746
  object4.removeFromScene();
17680
17747
  object4.dispose();
17681
17748
  }
@@ -17736,6 +17803,21 @@ var MineRenderWorld = class {
17736
17803
  if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
17737
17804
  if (options.renderEntities) this.entities = new WorldEntities(scene);
17738
17805
  }
17806
+ /**
17807
+ * Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
17808
+ * Includes fluids and block entities; texture alpha does not change triangle intersections.
17809
+ */
17810
+ raycast(raycaster) {
17811
+ return Chunk.raycast(this._chunks.values(), raycaster);
17812
+ }
17813
+ /**
17814
+ * Returns the nearest visible mob geometry hit when renderEntities is enabled.
17815
+ * Respects layers and near/far; compare its distance with raycast() to account for blocks.
17816
+ * Texture alpha does not change triangle intersections.
17817
+ */
17818
+ raycastEntities(raycaster) {
17819
+ return this.entities?.raycast(raycaster);
17820
+ }
17739
17821
  /** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
17740
17822
  get ambientOcclusion() {
17741
17823
  return this._ambientOcclusion;
@@ -17756,25 +17838,25 @@ var MineRenderWorld = class {
17756
17838
  }
17757
17839
  getBlockAt(posOrX, y, z) {
17758
17840
  if (typeof posOrX == "number") {
17759
- return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
17841
+ return this.getBlockAt(new import_three45.Vector3(posOrX, y, z));
17760
17842
  }
17761
17843
  if (isTripleArray(posOrX)) {
17762
- return this.getBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]));
17844
+ return this.getBlockAt(new import_three45.Vector3(posOrX[0], posOrX[1], posOrX[2]));
17763
17845
  }
17764
17846
  this.validatePosBounds(posOrX);
17765
17847
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
17766
17848
  }
17767
17849
  getBiomeAt(posOrX, y, z) {
17768
- if (typeof posOrX === "number") return this.getBiomeAt(new import_three42.Vector3(posOrX, y, z));
17769
- if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three42.Vector3(...posOrX));
17850
+ if (typeof posOrX === "number") return this.getBiomeAt(new import_three45.Vector3(posOrX, y, z));
17851
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three45.Vector3(...posOrX));
17770
17852
  this.validatePosBounds(posOrX);
17771
17853
  const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
17772
17854
  const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
17773
17855
  return this.biomes.get(`${cx}_${cz}`)?.get(cy)?.[Math.floor(lx / 4) + Math.floor(lz / 4) * 4 + Math.floor(ly / 4) * 16];
17774
17856
  }
17775
17857
  getLightAt(posOrX, y, z) {
17776
- if (typeof posOrX === "number") return this.getLightAt(new import_three42.Vector3(posOrX, y, z));
17777
- if (isTripleArray(posOrX)) return this.getLightAt(new import_three42.Vector3(...posOrX));
17858
+ if (typeof posOrX === "number") return this.getLightAt(new import_three45.Vector3(posOrX, y, z));
17859
+ if (isTripleArray(posOrX)) return this.getLightAt(new import_three45.Vector3(...posOrX));
17778
17860
  this.validatePosBounds(posOrX);
17779
17861
  const { x, y: py, z: pz } = posOrX;
17780
17862
  const cx = Math.floor(x / 16), cy = Math.floor(py / 16), cz = Math.floor(pz / 16);
@@ -17792,10 +17874,10 @@ var MineRenderWorld = class {
17792
17874
  }
17793
17875
  async setBlockAt(posOrX, yOrBlock, z, block) {
17794
17876
  if (typeof posOrX == "number") {
17795
- return this.setBlockAt(new import_three42.Vector3(posOrX, yOrBlock, z), block);
17877
+ return this.setBlockAt(new import_three45.Vector3(posOrX, yOrBlock, z), block);
17796
17878
  }
17797
17879
  if (isTripleArray(posOrX)) {
17798
- return this.setBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17880
+ return this.setBlockAt(new import_three45.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
17799
17881
  }
17800
17882
  return this.placeBlock(posOrX, yOrBlock);
17801
17883
  }
@@ -17806,10 +17888,10 @@ var MineRenderWorld = class {
17806
17888
  }
17807
17889
  async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
17808
17890
  if (typeof posOrX === "number") {
17809
- return this.setBlockVisibleAt(new import_three42.Vector3(posOrX, yOrVisible, z), visible);
17891
+ return this.setBlockVisibleAt(new import_three45.Vector3(posOrX, yOrVisible, z), visible);
17810
17892
  }
17811
17893
  if (isTripleArray(posOrX)) {
17812
- return this.setBlockVisibleAt(new import_three42.Vector3(...posOrX), yOrVisible);
17894
+ return this.setBlockVisibleAt(new import_three45.Vector3(...posOrX), yOrVisible);
17813
17895
  }
17814
17896
  this.validatePosBounds(posOrX);
17815
17897
  await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
@@ -17835,7 +17917,7 @@ var MineRenderWorld = class {
17835
17917
  const collect = async (positions2) => {
17836
17918
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
17837
17919
  };
17838
- const place = (block) => this.placeBlock(new import_three42.Vector3(...block.position), block, collect);
17920
+ const place = (block) => this.placeBlock(new import_three45.Vector3(...block.position), block, collect);
17839
17921
  const keys = /* @__PURE__ */ new Map();
17840
17922
  const types = /* @__PURE__ */ new Set();
17841
17923
  for (const block of multiblock.blocks) {
@@ -17851,7 +17933,7 @@ var MineRenderWorld = class {
17851
17933
  }
17852
17934
  if (!executor) {
17853
17935
  const groups2 = /* @__PURE__ */ new Map();
17854
- const position = new import_three42.Vector3();
17936
+ const position = new import_three45.Vector3();
17855
17937
  for (const block of multiblock.blocks) {
17856
17938
  const [x, y, z] = block.position;
17857
17939
  this.validatePosBounds(position.set(x, y, z));
@@ -17891,7 +17973,7 @@ var MineRenderWorld = class {
17891
17973
  try {
17892
17974
  positions = await chunk.placeBlocks(blocks);
17893
17975
  } finally {
17894
- positions ?? (positions = blocks.map(({ index }) => new import_three42.Vector3(
17976
+ positions ?? (positions = blocks.map(({ index }) => new import_three45.Vector3(
17895
17977
  chunk.x * 16 + index % 16,
17896
17978
  chunk.y * 16 + Math.floor(index / 256),
17897
17979
  chunk.z * 16 + Math.floor(index / 16) % 16
@@ -17943,7 +18025,7 @@ var MineRenderWorld = class {
17943
18025
  }
17944
18026
  for (const section of chunk.sections) {
17945
18027
  if (section.biomes) {
17946
- const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
18028
+ const position = new import_three45.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
17947
18029
  this.validatePosBounds(position);
17948
18030
  const copy = [...section.biomes];
17949
18031
  if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
@@ -17959,7 +18041,7 @@ var MineRenderWorld = class {
17959
18041
  for (const section of chunk.sections) {
17960
18042
  if (!executor) {
17961
18043
  if (!occupiedSections.has(section.y)) continue;
17962
- const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
18044
+ const position = new import_three45.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
17963
18045
  this.validatePosBounds(position);
17964
18046
  const target = this.getOrCreateChunkAt(position);
17965
18047
  try {
@@ -18063,7 +18145,7 @@ var MineRenderWorld = class {
18063
18145
  this.sectionModels?.clear();
18064
18146
  }
18065
18147
  updateCulling(positions) {
18066
- const neighbor = new import_three42.Vector3();
18148
+ const neighbor = new import_three45.Vector3();
18067
18149
  for (const pos of positions) {
18068
18150
  const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
18069
18151
  const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
@@ -18194,7 +18276,7 @@ var MineRenderWorld = class {
18194
18276
  }
18195
18277
  /** Converts block coordinates to scene units by multiplying each component by 16. */
18196
18278
  static worldToScenePosition(pos) {
18197
- return new import_three42.Vector3(
18279
+ return new import_three45.Vector3(
18198
18280
  pos.x * 16,
18199
18281
  pos.y * 16,
18200
18282
  pos.z * 16
@@ -18202,7 +18284,7 @@ var MineRenderWorld = class {
18202
18284
  }
18203
18285
  /** Converts scene units to block coordinates without rounding to an integer block. */
18204
18286
  static sceneToWorldPosition(pos) {
18205
- return new import_three42.Vector3(
18287
+ return new import_three45.Vector3(
18206
18288
  pos.x / 16,
18207
18289
  pos.y / 16,
18208
18290
  pos.z / 16
@@ -18225,7 +18307,7 @@ var MineRenderWorld = class {
18225
18307
  init_Model();
18226
18308
 
18227
18309
  // src/world/SectionMesh.ts
18228
- var import_three43 = require("three");
18310
+ var import_three46 = require("three");
18229
18311
  init_CanvasCompat();
18230
18312
  init_Materials();
18231
18313
 
@@ -18410,6 +18492,7 @@ function buildSectionGeometry(input) {
18410
18492
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
18411
18493
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
18412
18494
  const outputIndices = new Uint32Array(faces * 6);
18495
+ const blockIndices = new Uint16Array(faces);
18413
18496
  let vertex = 0, indexOffset = 0;
18414
18497
  for (const entry of page.entries) {
18415
18498
  const template = templateData[templates[entry]];
@@ -18424,6 +18507,7 @@ function buildSectionGeometry(input) {
18424
18507
  const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
18425
18508
  for (let quad = 0; quad < template.quads; quad++) {
18426
18509
  if (cullMasks[entry] & template.cullFaces[quad]) continue;
18510
+ blockIndices[indexOffset / 6] = indices[entry];
18427
18511
  if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
18428
18512
  const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
18429
18513
  const start = vertex;
@@ -18456,6 +18540,7 @@ function buildSectionGeometry(input) {
18456
18540
  const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
18457
18541
  const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
18458
18542
  for (let quad = 0; quad < quads.sprites.length; quad++) {
18543
+ blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
18459
18544
  const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
18460
18545
  const brightness = light ? lightBrightness(fluidLightLevel(
18461
18546
  light[lightIndex],
@@ -18486,11 +18571,11 @@ function buildSectionGeometry(input) {
18486
18571
  indexOffset += 6;
18487
18572
  }
18488
18573
  }
18489
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
18574
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
18490
18575
  });
18491
18576
  }
18492
18577
  function sectionGeometryTransferables(pages) {
18493
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
18578
+ 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]);
18494
18579
  }
18495
18580
 
18496
18581
  // src/world/SectionWorker.ts
@@ -18547,7 +18632,7 @@ var SectionWorker = _SectionWorker;
18547
18632
 
18548
18633
  // src/world/SectionMesh.ts
18549
18634
  var templateCache = /* @__PURE__ */ new WeakMap();
18550
- var WATER_TINT = new import_three43.Color(4159204).toArray();
18635
+ var WATER_TINT = new import_three46.Color(4159204).toArray();
18551
18636
  function toInput(entries, maxAtlasSize, fluids, lighting) {
18552
18637
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
18553
18638
  const atlases = [];
@@ -18644,10 +18729,16 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
18644
18729
  }
18645
18730
  return { input, atlases };
18646
18731
  }
18647
- var SectionMesh = class _SectionMesh extends import_three43.Group {
18732
+ var SectionMesh = class _SectionMesh extends import_three46.Group {
18648
18733
  constructor() {
18649
18734
  super(...arguments);
18650
18735
  this.ownedMeshes = [];
18736
+ this.blockIndices = /* @__PURE__ */ new Map();
18737
+ }
18738
+ /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
18739
+ getBlockIndex(hit) {
18740
+ if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
18741
+ return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
18651
18742
  }
18652
18743
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
18653
18744
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
@@ -18669,27 +18760,28 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
18669
18760
  for (const { atlas, x, y } of page.placements) {
18670
18761
  context.drawImage(atlases[atlas].image.canvas, x, y);
18671
18762
  }
18672
- const geometry = new import_three43.BufferGeometry();
18673
- geometry.setAttribute("position", new import_three43.Float32BufferAttribute(page.positions.buffer, 3));
18674
- geometry.setAttribute("normal", new import_three43.Float32BufferAttribute(page.normals.buffer, 3));
18675
- geometry.setAttribute("uv", new import_three43.Float32BufferAttribute(page.uvs.buffer, 2));
18676
- geometry.setAttribute("uvBounds", new import_three43.Float32BufferAttribute(page.uvBounds.buffer, 4));
18677
- geometry.setAttribute("color", new import_three43.Float32BufferAttribute(page.colors.buffer, 3));
18678
- geometry.setIndex(new import_three43.Uint32BufferAttribute(page.indices.buffer, 1));
18763
+ const geometry = new import_three46.BufferGeometry();
18764
+ geometry.setAttribute("position", new import_three46.Float32BufferAttribute(page.positions.buffer, 3));
18765
+ geometry.setAttribute("normal", new import_three46.Float32BufferAttribute(page.normals.buffer, 3));
18766
+ geometry.setAttribute("uv", new import_three46.Float32BufferAttribute(page.uvs.buffer, 2));
18767
+ geometry.setAttribute("uvBounds", new import_three46.Float32BufferAttribute(page.uvBounds.buffer, 4));
18768
+ geometry.setAttribute("color", new import_three46.Float32BufferAttribute(page.colors.buffer, 3));
18769
+ geometry.setIndex(new import_three46.Uint32BufferAttribute(page.indices.buffer, 1));
18679
18770
  geometry.computeBoundingBox();
18680
18771
  geometry.computeBoundingSphere();
18681
18772
  const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;
18682
18773
  const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
18683
- material.side = import_three43.FrontSide;
18774
+ material.side = import_three46.FrontSide;
18684
18775
  if (page.layer === 2) {
18685
- material.side = import_three43.DoubleSide;
18776
+ material.side = import_three46.DoubleSide;
18686
18777
  material.forceSinglePass = true;
18687
18778
  material.depthWrite = !material.transparent;
18688
18779
  }
18689
18780
  material.vertexColors = true;
18690
18781
  const texture = material.uniforms?.map?.value ?? material.map;
18691
- const mesh = new import_three43.Mesh(geometry, material);
18782
+ const mesh = new import_three46.Mesh(geometry, material);
18692
18783
  section.add(mesh);
18784
+ section.blockIndices.set(mesh, page.blockIndices);
18693
18785
  const unsubscribe = [];
18694
18786
  for (const { atlas: id, x, y } of page.placements) {
18695
18787
  const atlas = atlases[id];
@@ -18715,6 +18807,7 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
18715
18807
  mesh.material.dispose();
18716
18808
  texture?.dispose();
18717
18809
  }
18810
+ this.blockIndices.clear();
18718
18811
  this.removeFromParent();
18719
18812
  super.dispose();
18720
18813
  }
@@ -18724,7 +18817,8 @@ var SectionMesh = class _SectionMesh extends import_three43.Group {
18724
18817
  init_FluidGeometry();
18725
18818
  init_FluidQuads();
18726
18819
  init_CubeFace();
18727
- var WATER_TINT2 = new import_three44.Color(4159204).toArray();
18820
+ init_InstanceReference();
18821
+ var WATER_TINT2 = new import_three47.Color(4159204).toArray();
18728
18822
  var Chunk = class _Chunk {
18729
18823
  constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
18730
18824
  this.onBlocksChanged = onBlocksChanged;
@@ -18737,10 +18831,11 @@ var Chunk = class _Chunk {
18737
18831
  this.ambientLight = ambientLight;
18738
18832
  this.data = new ChunkData();
18739
18833
  this.renderedBlocks = /* @__PURE__ */ new Map();
18834
+ this.objectBlocks = /* @__PURE__ */ new Set();
18740
18835
  this.sectionBlocks = /* @__PURE__ */ new Map();
18741
18836
  this.hiddenBlocks = /* @__PURE__ */ new Set();
18742
18837
  this.fluidCells = new Uint8Array(4096);
18743
- this.blockPosition = new import_three44.Vector3();
18838
+ this.blockPosition = new import_three47.Vector3();
18744
18839
  this.meshDirty = false;
18745
18840
  this.meshGeneration = 0;
18746
18841
  this.scene = scene;
@@ -18748,20 +18843,84 @@ var Chunk = class _Chunk {
18748
18843
  this.y = y;
18749
18844
  this.z = z;
18750
18845
  }
18846
+ /** Finds the nearest owned block hit across sections, testing each shared mesh once. */
18847
+ static raycast(chunks, raycaster) {
18848
+ const roots = /* @__PURE__ */ new Map();
18849
+ const targets = /* @__PURE__ */ new Map();
18850
+ const meshes = (root, scene) => {
18851
+ const cached2 = roots.get(root);
18852
+ if (cached2) return cached2;
18853
+ const result = pickableMeshes(root, scene, raycaster);
18854
+ roots.set(root, result);
18855
+ return result;
18856
+ };
18857
+ const add = (root, owner, reference) => {
18858
+ for (const mesh of meshes(root, owner.chunk.scene)) {
18859
+ if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
18860
+ let entry = targets.get(mesh);
18861
+ if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
18862
+ entry.owners.set(reference?.index, owner);
18863
+ }
18864
+ };
18865
+ for (const chunk of chunks) {
18866
+ for (const index of chunk.objectBlocks) {
18867
+ const block = chunk.renderedBlocks.get(index).object;
18868
+ if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
18869
+ const owner = { chunk, index };
18870
+ for (const model of block.models) {
18871
+ if (isInstanceReference(model)) {
18872
+ if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
18873
+ } else {
18874
+ add(model, owner);
18875
+ }
18876
+ }
18877
+ for (const entity of block.blockEntities) add(entity, owner);
18878
+ }
18879
+ if (chunk.sectionMesh) {
18880
+ for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
18881
+ targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
18882
+ }
18883
+ }
18884
+ }
18885
+ for (const hit of visibleHits(raycaster, [...targets.keys()])) {
18886
+ const mesh = hit.object;
18887
+ const entry = targets.get(mesh);
18888
+ let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
18889
+ if (entry.section) {
18890
+ const index = entry.section.mesh.getBlockIndex(hit);
18891
+ if (index !== void 0) owner = { chunk: entry.section.chunk, index };
18892
+ }
18893
+ if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
18894
+ const info = owner.chunk.renderedBlocks.get(owner.index);
18895
+ if (!info) continue;
18896
+ return {
18897
+ position: new import_three47.Vector3(
18898
+ owner.chunk.x * 16 + owner.index % 16,
18899
+ owner.chunk.y * 16 + Math.floor(owner.index / 256),
18900
+ owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
18901
+ ),
18902
+ block: info.block,
18903
+ point: hit.point.clone(),
18904
+ normal: hitNormal(hit),
18905
+ distance: hit.distance
18906
+ };
18907
+ }
18908
+ return void 0;
18909
+ }
18751
18910
  getBlockAt(posOrX, y, z) {
18752
18911
  if (typeof posOrX == "number") {
18753
- return this.getBlockAt(new import_three44.Vector3(posOrX, y, z));
18912
+ return this.getBlockAt(new import_three47.Vector3(posOrX, y, z));
18754
18913
  }
18755
18914
  if (isTripleArray(posOrX)) {
18756
- return this.getBlockAt(new import_three44.Vector3(posOrX[0], posOrX[1], posOrX[2]));
18915
+ return this.getBlockAt(new import_three47.Vector3(posOrX[0], posOrX[1], posOrX[2]));
18757
18916
  }
18758
18917
  const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
18759
18918
  const index = _Chunk.chunkPosToBlockIndex(pos);
18760
18919
  return this.renderedBlocks.get(index);
18761
18920
  }
18762
18921
  getBiomeAt(posOrX, y, z) {
18763
- if (typeof posOrX === "number") return this.getBiomeAt(new import_three44.Vector3(posOrX, y, z));
18764
- if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three44.Vector3(...posOrX));
18922
+ if (typeof posOrX === "number") return this.getBiomeAt(new import_three47.Vector3(posOrX, y, z));
18923
+ if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three47.Vector3(...posOrX));
18765
18924
  const pos = this.worldPosToChunkPos(posOrX);
18766
18925
  _Chunk.chunkPosToBlockIndex(pos);
18767
18926
  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];
@@ -18804,17 +18963,17 @@ var Chunk = class _Chunk {
18804
18963
  this.hiddenBlocks.add(index);
18805
18964
  this.renderedBlocks.get(index)?.object?.setVisible(false);
18806
18965
  }
18807
- const positions = blocks.map(({ index }) => new import_three44.Vector3(...this.positionAt(index)));
18966
+ const positions = blocks.map(({ index }) => new import_three47.Vector3(...this.positionAt(index)));
18808
18967
  if (this.onBlocksChanged) await this.onBlocksChanged(positions);
18809
18968
  else await this.rebuildSectionMesh();
18810
18969
  }
18811
18970
  }
18812
18971
  async setBlockAt(posOrX, yOrBlock, z, block) {
18813
18972
  if (typeof posOrX == "number") {
18814
- return this.setBlockAt(new import_three44.Vector3(posOrX, yOrBlock, z), block);
18973
+ return this.setBlockAt(new import_three47.Vector3(posOrX, yOrBlock, z), block);
18815
18974
  }
18816
18975
  if (isTripleArray(posOrX)) {
18817
- return this.setBlockAt(new import_three44.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
18976
+ return this.setBlockAt(new import_three47.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
18818
18977
  }
18819
18978
  const worldPos = posOrX;
18820
18979
  const pos = this.worldPosToChunkPos(worldPos);
@@ -18868,7 +19027,8 @@ var Chunk = class _Chunk {
18868
19027
  if (this.fluidCells[index]) this.meshDirty = true;
18869
19028
  this.fluidCells[index] = 0;
18870
19029
  this.renderedBlocks.delete(index);
18871
- const worldPos = new import_three44.Vector3(
19030
+ this.objectBlocks.delete(index);
19031
+ const worldPos = new import_three47.Vector3(
18872
19032
  this.x * 16 + index % 16,
18873
19033
  this.y * 16 + Math.floor(index / 256),
18874
19034
  this.z * 16 + Math.floor(index / 16) % 16
@@ -18910,6 +19070,7 @@ var Chunk = class _Chunk {
18910
19070
  this.renderedBlocks.set(index, { get block() {
18911
19071
  return readBlock();
18912
19072
  }, object: object4 });
19073
+ if (object4) this.objectBlocks.add(index);
18913
19074
  } catch (error) {
18914
19075
  this.data.assign(index, 0);
18915
19076
  this.fluidCells[index] = 0;
@@ -18928,6 +19089,7 @@ var Chunk = class _Chunk {
18928
19089
  this.fluidCells.fill(0);
18929
19090
  this.waterTints = void 0;
18930
19091
  this.renderedBlocks.clear();
19092
+ this.objectBlocks.clear();
18931
19093
  this.hiddenBlocks.clear();
18932
19094
  this.meshDirty = true;
18933
19095
  this.data.copyFrom(data);
@@ -18977,6 +19139,7 @@ var Chunk = class _Chunk {
18977
19139
  this.renderedBlocks.set(index, { get block() {
18978
19140
  return readBlock();
18979
19141
  }, object: void 0 });
19142
+ this.objectBlocks.delete(index);
18980
19143
  } catch (error) {
18981
19144
  this.data.assign(index, 0);
18982
19145
  this.fluidCells[index] = 0;
@@ -18996,16 +19159,18 @@ var Chunk = class _Chunk {
18996
19159
  biome,
18997
19160
  biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
18998
19161
  });
18999
- object4.setPosition(new import_three44.Vector3(
19162
+ object4.setPosition(new import_three47.Vector3(
19000
19163
  this.x * 256 + index % 16 * 16,
19001
19164
  this.y * 256 + Math.floor(index / 256) * 16,
19002
19165
  this.z * 256 + Math.floor(index / 16) % 16 * 16
19003
19166
  ));
19004
19167
  this.renderedBlocks.get(index).object = object4;
19168
+ this.objectBlocks.add(index);
19005
19169
  } catch (error) {
19006
19170
  this.data.assign(index, 0);
19007
19171
  this.fluidCells[index] = 0;
19008
19172
  this.renderedBlocks.delete(index);
19173
+ this.objectBlocks.delete(index);
19009
19174
  object4?.removeFromScene();
19010
19175
  if (!failed) failure = error;
19011
19176
  failed = true;
@@ -19086,7 +19251,7 @@ var Chunk = class _Chunk {
19086
19251
  context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
19087
19252
  if (fluid?.kind === "water" && await available()) {
19088
19253
  const color2 = await Biomes.getColor(biome, "water", blockState3?.key);
19089
- if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three44.Color(color2).toArray();
19254
+ if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three47.Color(color2).toArray();
19090
19255
  }
19091
19256
  }
19092
19257
  for (const index of indices2) contexts.set(index, context);
@@ -19257,7 +19422,7 @@ var Chunk = class _Chunk {
19257
19422
  /** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
19258
19423
  async clear(notify = true) {
19259
19424
  const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
19260
- new import_three44.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
19425
+ new import_three47.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
19261
19426
  )) : [];
19262
19427
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
19263
19428
  this.sectionBlocks.clear();
@@ -19266,6 +19431,7 @@ var Chunk = class _Chunk {
19266
19431
  this.sectionMesh = void 0;
19267
19432
  this.meshDirty = false;
19268
19433
  this.renderedBlocks.clear();
19434
+ this.objectBlocks.clear();
19269
19435
  this.hiddenBlocks.clear();
19270
19436
  this.fluidCells.fill(0);
19271
19437
  this.waterTints = void 0;
@@ -19292,14 +19458,14 @@ var Chunk = class _Chunk {
19292
19458
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
19293
19459
  }
19294
19460
  worldPosToChunkPos(pos) {
19295
- return new import_three44.Vector3(
19461
+ return new import_three47.Vector3(
19296
19462
  pos.x - this.x * 16,
19297
19463
  pos.y - this.y * 16,
19298
19464
  pos.z - this.z * 16
19299
19465
  );
19300
19466
  }
19301
19467
  chunkPosToWorldPos(pos) {
19302
- return new import_three44.Vector3(
19468
+ return new import_three47.Vector3(
19303
19469
  this.x * 16 + pos.x,
19304
19470
  this.y * 16 + pos.y,
19305
19471
  this.z * 16 + pos.z