minerender 2.1.0-alpha.121 → 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.
@@ -12463,6 +12463,10 @@ var BlockObject = class _BlockObject extends SceneObject {
12463
12463
  get blockEntities() {
12464
12464
  return this._entities;
12465
12465
  }
12466
+ /** Model placements drawn for this block, including its fluid surface. */
12467
+ get models() {
12468
+ return this._models;
12469
+ }
12466
12470
  /** Sets visibility for this block's model instances and block entities. */
12467
12471
  setVisible(visible) {
12468
12472
  this.visible = visible;
@@ -17224,7 +17228,7 @@ var AnvilWorldSource = class {
17224
17228
  };
17225
17229
 
17226
17230
  // src/world/Chunk.ts
17227
- import { Color as Color13, Vector3 as Vector318 } from "three";
17231
+ import { Color as Color13, Matrix3 as Matrix33, Matrix4 as Matrix413, Vector3 as Vector318 } from "three";
17228
17232
  init_BlockStates();
17229
17233
  init_AssetKey();
17230
17234
 
@@ -17609,6 +17613,13 @@ var MineRenderWorld = class {
17609
17613
  if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
17610
17614
  if (options.renderEntities) this.entities = new WorldEntities(scene);
17611
17615
  }
17616
+ /**
17617
+ * Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
17618
+ * Includes fluids and block entities; texture alpha does not change triangle intersections.
17619
+ */
17620
+ raycast(raycaster) {
17621
+ return Chunk.raycast(this._chunks.values(), raycaster);
17622
+ }
17612
17623
  /** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
17613
17624
  get ambientOcclusion() {
17614
17625
  return this._ambientOcclusion;
@@ -18283,6 +18294,7 @@ function buildSectionGeometry(input) {
18283
18294
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
18284
18295
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
18285
18296
  const outputIndices = new Uint32Array(faces * 6);
18297
+ const blockIndices = new Uint16Array(faces);
18286
18298
  let vertex = 0, indexOffset = 0;
18287
18299
  for (const entry of page.entries) {
18288
18300
  const template = templateData[templates[entry]];
@@ -18297,6 +18309,7 @@ function buildSectionGeometry(input) {
18297
18309
  const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
18298
18310
  for (let quad = 0; quad < template.quads; quad++) {
18299
18311
  if (cullMasks[entry] & template.cullFaces[quad]) continue;
18312
+ blockIndices[indexOffset / 6] = indices[entry];
18300
18313
  if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
18301
18314
  const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
18302
18315
  const start = vertex;
@@ -18329,6 +18342,7 @@ function buildSectionGeometry(input) {
18329
18342
  const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
18330
18343
  const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
18331
18344
  for (let quad = 0; quad < quads.sprites.length; quad++) {
18345
+ blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
18332
18346
  const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
18333
18347
  const brightness = light ? lightBrightness(fluidLightLevel(
18334
18348
  light[lightIndex],
@@ -18359,11 +18373,11 @@ function buildSectionGeometry(input) {
18359
18373
  indexOffset += 6;
18360
18374
  }
18361
18375
  }
18362
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
18376
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
18363
18377
  });
18364
18378
  }
18365
18379
  function sectionGeometryTransferables(pages) {
18366
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
18380
+ 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]);
18367
18381
  }
18368
18382
 
18369
18383
  // src/world/SectionWorker.ts
@@ -18522,6 +18536,12 @@ var SectionMesh = class _SectionMesh extends Group3 {
18522
18536
  constructor() {
18523
18537
  super(...arguments);
18524
18538
  this.ownedMeshes = [];
18539
+ this.blockIndices = /* @__PURE__ */ new Map();
18540
+ }
18541
+ /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
18542
+ getBlockIndex(hit) {
18543
+ if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
18544
+ return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
18525
18545
  }
18526
18546
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
18527
18547
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
@@ -18564,6 +18584,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
18564
18584
  const texture = material.uniforms?.map?.value ?? material.map;
18565
18585
  const mesh = new Mesh10(geometry, material);
18566
18586
  section.add(mesh);
18587
+ section.blockIndices.set(mesh, page.blockIndices);
18567
18588
  const unsubscribe = [];
18568
18589
  for (const { atlas: id, x, y } of page.placements) {
18569
18590
  const atlas = atlases[id];
@@ -18589,6 +18610,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
18589
18610
  mesh.material.dispose();
18590
18611
  texture?.dispose();
18591
18612
  }
18613
+ this.blockIndices.clear();
18592
18614
  this.removeFromParent();
18593
18615
  super.dispose();
18594
18616
  }
@@ -18598,6 +18620,8 @@ var SectionMesh = class _SectionMesh extends Group3 {
18598
18620
  init_FluidGeometry();
18599
18621
  init_FluidQuads();
18600
18622
  init_CubeFace();
18623
+ init_InstanceReference();
18624
+ init_three();
18601
18625
  var WATER_TINT2 = new Color13(4159204).toArray();
18602
18626
  var Chunk = class _Chunk {
18603
18627
  constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
@@ -18611,6 +18635,7 @@ var Chunk = class _Chunk {
18611
18635
  this.ambientLight = ambientLight;
18612
18636
  this.data = new ChunkData();
18613
18637
  this.renderedBlocks = /* @__PURE__ */ new Map();
18638
+ this.objectBlocks = /* @__PURE__ */ new Set();
18614
18639
  this.sectionBlocks = /* @__PURE__ */ new Map();
18615
18640
  this.hiddenBlocks = /* @__PURE__ */ new Set();
18616
18641
  this.fluidCells = new Uint8Array(4096);
@@ -18622,6 +18647,89 @@ var Chunk = class _Chunk {
18622
18647
  this.y = y;
18623
18648
  this.z = z;
18624
18649
  }
18650
+ /** Finds the nearest owned block hit across sections, testing each shared mesh once. */
18651
+ static raycast(chunks, raycaster) {
18652
+ const roots = /* @__PURE__ */ new Map();
18653
+ const targets = /* @__PURE__ */ new Map();
18654
+ const meshes = (root, scene) => {
18655
+ const cached2 = roots.get(root);
18656
+ if (cached2) return cached2;
18657
+ const result = [];
18658
+ roots.set(root, result);
18659
+ let attached = false;
18660
+ for (let parent = root; parent; parent = parent.parent) {
18661
+ if (!parent.visible) return result;
18662
+ if (parent === scene) attached = true;
18663
+ }
18664
+ if (!attached) return result;
18665
+ root.updateWorldMatrix(true, true);
18666
+ root.traverseVisible((object4) => {
18667
+ if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
18668
+ });
18669
+ return result;
18670
+ };
18671
+ const add = (root, owner, reference) => {
18672
+ for (const mesh of meshes(root, owner.chunk.scene)) {
18673
+ if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
18674
+ let entry = targets.get(mesh);
18675
+ if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
18676
+ entry.owners.set(reference?.index, owner);
18677
+ }
18678
+ };
18679
+ for (const chunk of chunks) {
18680
+ for (const index of chunk.objectBlocks) {
18681
+ const block = chunk.renderedBlocks.get(index).object;
18682
+ if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
18683
+ const owner = { chunk, index };
18684
+ for (const model of block.models) {
18685
+ if (isInstanceReference(model)) {
18686
+ if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
18687
+ } else {
18688
+ add(model, owner);
18689
+ }
18690
+ }
18691
+ for (const entity of block.blockEntities) add(entity, owner);
18692
+ }
18693
+ if (chunk.sectionMesh) {
18694
+ for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
18695
+ targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
18696
+ }
18697
+ }
18698
+ }
18699
+ for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
18700
+ if (!hit.face) continue;
18701
+ const mesh = hit.object;
18702
+ const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
18703
+ if (!material?.visible) continue;
18704
+ const entry = targets.get(mesh);
18705
+ let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
18706
+ if (entry.section) {
18707
+ const index = entry.section.mesh.getBlockIndex(hit);
18708
+ if (index !== void 0) owner = { chunk: entry.section.chunk, index };
18709
+ }
18710
+ if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
18711
+ const info = owner.chunk.renderedBlocks.get(owner.index);
18712
+ if (!info) continue;
18713
+ const matrix = mesh.matrixWorld.clone();
18714
+ if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
18715
+ const instance = new Matrix413();
18716
+ mesh.getMatrixAt(hit.instanceId, instance);
18717
+ matrix.multiply(instance);
18718
+ }
18719
+ return {
18720
+ position: new Vector318(
18721
+ owner.chunk.x * 16 + owner.index % 16,
18722
+ owner.chunk.y * 16 + Math.floor(owner.index / 256),
18723
+ owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
18724
+ ),
18725
+ block: info.block,
18726
+ point: hit.point.clone(),
18727
+ normal: hit.face.normal.clone().applyNormalMatrix(new Matrix33().getNormalMatrix(matrix)),
18728
+ distance: hit.distance
18729
+ };
18730
+ }
18731
+ return void 0;
18732
+ }
18625
18733
  getBlockAt(posOrX, y, z) {
18626
18734
  if (typeof posOrX == "number") {
18627
18735
  return this.getBlockAt(new Vector318(posOrX, y, z));
@@ -18742,6 +18850,7 @@ var Chunk = class _Chunk {
18742
18850
  if (this.fluidCells[index]) this.meshDirty = true;
18743
18851
  this.fluidCells[index] = 0;
18744
18852
  this.renderedBlocks.delete(index);
18853
+ this.objectBlocks.delete(index);
18745
18854
  const worldPos = new Vector318(
18746
18855
  this.x * 16 + index % 16,
18747
18856
  this.y * 16 + Math.floor(index / 256),
@@ -18784,6 +18893,7 @@ var Chunk = class _Chunk {
18784
18893
  this.renderedBlocks.set(index, { get block() {
18785
18894
  return readBlock();
18786
18895
  }, object: object4 });
18896
+ if (object4) this.objectBlocks.add(index);
18787
18897
  } catch (error) {
18788
18898
  this.data.assign(index, 0);
18789
18899
  this.fluidCells[index] = 0;
@@ -18802,6 +18912,7 @@ var Chunk = class _Chunk {
18802
18912
  this.fluidCells.fill(0);
18803
18913
  this.waterTints = void 0;
18804
18914
  this.renderedBlocks.clear();
18915
+ this.objectBlocks.clear();
18805
18916
  this.hiddenBlocks.clear();
18806
18917
  this.meshDirty = true;
18807
18918
  this.data.copyFrom(data);
@@ -18851,6 +18962,7 @@ var Chunk = class _Chunk {
18851
18962
  this.renderedBlocks.set(index, { get block() {
18852
18963
  return readBlock();
18853
18964
  }, object: void 0 });
18965
+ this.objectBlocks.delete(index);
18854
18966
  } catch (error) {
18855
18967
  this.data.assign(index, 0);
18856
18968
  this.fluidCells[index] = 0;
@@ -18876,10 +18988,12 @@ var Chunk = class _Chunk {
18876
18988
  this.z * 256 + Math.floor(index / 16) % 16 * 16
18877
18989
  ));
18878
18990
  this.renderedBlocks.get(index).object = object4;
18991
+ this.objectBlocks.add(index);
18879
18992
  } catch (error) {
18880
18993
  this.data.assign(index, 0);
18881
18994
  this.fluidCells[index] = 0;
18882
18995
  this.renderedBlocks.delete(index);
18996
+ this.objectBlocks.delete(index);
18883
18997
  object4?.removeFromScene();
18884
18998
  if (!failed) failure = error;
18885
18999
  failed = true;
@@ -19140,6 +19254,7 @@ var Chunk = class _Chunk {
19140
19254
  this.sectionMesh = void 0;
19141
19255
  this.meshDirty = false;
19142
19256
  this.renderedBlocks.clear();
19257
+ this.objectBlocks.clear();
19143
19258
  this.hiddenBlocks.clear();
19144
19259
  this.fluidCells.fill(0);
19145
19260
  this.waterTints = void 0;