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.
@@ -12425,6 +12425,10 @@ var _BlockObject = class _BlockObject extends SceneObject {
12425
12425
  get blockEntities() {
12426
12426
  return this._entities;
12427
12427
  }
12428
+ /** Model placements drawn for this block, including its fluid surface. */
12429
+ get models() {
12430
+ return this._models;
12431
+ }
12428
12432
  /** Sets visibility for this block's model instances and block entities. */
12429
12433
  setVisible(visible) {
12430
12434
  this.visible = visible;
@@ -17188,7 +17192,7 @@ var AnvilWorldSource = class {
17188
17192
  };
17189
17193
 
17190
17194
  // src/world/Chunk.ts
17191
- import { Color as Color13, Vector3 as Vector318 } from "three";
17195
+ import { Color as Color13, Matrix3 as Matrix33, Matrix4 as Matrix413, Vector3 as Vector318 } from "three";
17192
17196
  init_BlockStates();
17193
17197
  init_AssetKey();
17194
17198
 
@@ -17573,6 +17577,13 @@ var MineRenderWorld = class {
17573
17577
  if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
17574
17578
  if (options.renderEntities) this.entities = new WorldEntities(scene);
17575
17579
  }
17580
+ /**
17581
+ * Returns the nearest visible block geometry hit, respecting the raycaster's layers and near/far range.
17582
+ * Includes fluids and block entities; texture alpha does not change triangle intersections.
17583
+ */
17584
+ raycast(raycaster) {
17585
+ return Chunk.raycast(this._chunks.values(), raycaster);
17586
+ }
17576
17587
  /** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
17577
17588
  get ambientOcclusion() {
17578
17589
  return this._ambientOcclusion;
@@ -18247,6 +18258,7 @@ function buildSectionGeometry(input) {
18247
18258
  const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
18248
18259
  const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
18249
18260
  const outputIndices = new Uint32Array(faces * 6);
18261
+ const blockIndices = new Uint16Array(faces);
18250
18262
  let vertex = 0, indexOffset = 0;
18251
18263
  for (const entry of page.entries) {
18252
18264
  const template = templateData[templates[entry]];
@@ -18261,6 +18273,7 @@ function buildSectionGeometry(input) {
18261
18273
  const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
18262
18274
  for (let quad = 0; quad < template.quads; quad++) {
18263
18275
  if (cullMasks[entry] & template.cullFaces[quad]) continue;
18276
+ blockIndices[indexOffset / 6] = indices[entry];
18264
18277
  if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
18265
18278
  const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
18266
18279
  const start = vertex;
@@ -18293,6 +18306,7 @@ function buildSectionGeometry(input) {
18293
18306
  const mapV = (v) => 1 - (placement.y + (1 - v) * atlas.height) / page.height;
18294
18307
  const lightIndex = (y + 1) * 324 + (z + 1) * 18 + x + 1;
18295
18308
  for (let quad = 0; quad < quads.sprites.length; quad++) {
18309
+ blockIndices[indexOffset / 6] = x + z * 16 + y * 256;
18296
18310
  const rect = quads.sprites[quad] === 0 ? data.still : data.flow;
18297
18311
  const brightness = light ? lightBrightness(fluidLightLevel(
18298
18312
  light[lightIndex],
@@ -18323,11 +18337,11 @@ function buildSectionGeometry(input) {
18323
18337
  indexOffset += 6;
18324
18338
  }
18325
18339
  }
18326
- return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
18340
+ return { layer: page.layer, width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices, blockIndices };
18327
18341
  });
18328
18342
  }
18329
18343
  function sectionGeometryTransferables(pages) {
18330
- return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
18344
+ return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer, page.blockIndices.buffer]);
18331
18345
  }
18332
18346
 
18333
18347
  // src/world/SectionWorker.ts
@@ -18485,6 +18499,12 @@ var SectionMesh = class _SectionMesh extends Group3 {
18485
18499
  constructor() {
18486
18500
  super(...arguments);
18487
18501
  this.ownedMeshes = [];
18502
+ this.blockIndices = /* @__PURE__ */ new Map();
18503
+ }
18504
+ /** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
18505
+ getBlockIndex(hit) {
18506
+ if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
18507
+ return this.blockIndices.get(hit.object)?.[Math.floor(hit.faceIndex / 2)];
18488
18508
  }
18489
18509
  /** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
18490
18510
  static build(entries, maxAtlasSize = 2048, fluids, lighting) {
@@ -18527,6 +18547,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
18527
18547
  const texture = material.uniforms?.map?.value ?? material.map;
18528
18548
  const mesh = new Mesh10(geometry, material);
18529
18549
  section.add(mesh);
18550
+ section.blockIndices.set(mesh, page.blockIndices);
18530
18551
  const unsubscribe = [];
18531
18552
  for (const { atlas: id, x, y } of page.placements) {
18532
18553
  const atlas = atlases[id];
@@ -18552,6 +18573,7 @@ var SectionMesh = class _SectionMesh extends Group3 {
18552
18573
  mesh.material.dispose();
18553
18574
  texture?.dispose();
18554
18575
  }
18576
+ this.blockIndices.clear();
18555
18577
  this.removeFromParent();
18556
18578
  super.dispose();
18557
18579
  }
@@ -18561,6 +18583,8 @@ var SectionMesh = class _SectionMesh extends Group3 {
18561
18583
  init_FluidGeometry();
18562
18584
  init_FluidQuads();
18563
18585
  init_CubeFace();
18586
+ init_InstanceReference();
18587
+ init_three();
18564
18588
  var WATER_TINT2 = new Color13(4159204).toArray();
18565
18589
  var Chunk = class _Chunk {
18566
18590
  constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged, lightAt, onLightCleared, ambientLight = 0) {
@@ -18574,6 +18598,7 @@ var Chunk = class _Chunk {
18574
18598
  this.ambientLight = ambientLight;
18575
18599
  this.data = new ChunkData();
18576
18600
  this.renderedBlocks = /* @__PURE__ */ new Map();
18601
+ this.objectBlocks = /* @__PURE__ */ new Set();
18577
18602
  this.sectionBlocks = /* @__PURE__ */ new Map();
18578
18603
  this.hiddenBlocks = /* @__PURE__ */ new Set();
18579
18604
  this.fluidCells = new Uint8Array(4096);
@@ -18585,6 +18610,89 @@ var Chunk = class _Chunk {
18585
18610
  this.y = y;
18586
18611
  this.z = z;
18587
18612
  }
18613
+ /** Finds the nearest owned block hit across sections, testing each shared mesh once. */
18614
+ static raycast(chunks, raycaster) {
18615
+ const roots = /* @__PURE__ */ new Map();
18616
+ const targets = /* @__PURE__ */ new Map();
18617
+ const meshes = (root, scene) => {
18618
+ const cached2 = roots.get(root);
18619
+ if (cached2) return cached2;
18620
+ const result = [];
18621
+ roots.set(root, result);
18622
+ let attached = false;
18623
+ for (let parent = root; parent; parent = parent.parent) {
18624
+ if (!parent.visible) return result;
18625
+ if (parent === scene) attached = true;
18626
+ }
18627
+ if (!attached) return result;
18628
+ root.updateWorldMatrix(true, true);
18629
+ root.traverseVisible((object4) => {
18630
+ if (isMesh(object4) && raycaster.layers.test(object4.layers)) result.push(object4);
18631
+ });
18632
+ return result;
18633
+ };
18634
+ const add = (root, owner, reference) => {
18635
+ for (const mesh of meshes(root, owner.chunk.scene)) {
18636
+ if (reference && reference.instanceable.getInstanceReference(mesh, reference.index) !== reference) continue;
18637
+ let entry = targets.get(mesh);
18638
+ if (!entry) targets.set(mesh, entry = { owners: /* @__PURE__ */ new Map() });
18639
+ entry.owners.set(reference?.index, owner);
18640
+ }
18641
+ };
18642
+ for (const chunk of chunks) {
18643
+ for (const index of chunk.objectBlocks) {
18644
+ const block = chunk.renderedBlocks.get(index).object;
18645
+ if (!block || !block.visible || chunk.hiddenBlocks.has(index)) continue;
18646
+ const owner = { chunk, index };
18647
+ for (const model of block.models) {
18648
+ if (isInstanceReference(model)) {
18649
+ if (model.instanceable.isInstanceActive(model.index, model)) add(model.instanceable, owner, model);
18650
+ } else {
18651
+ add(model, owner);
18652
+ }
18653
+ }
18654
+ for (const entity of block.blockEntities) add(entity, owner);
18655
+ }
18656
+ if (chunk.sectionMesh) {
18657
+ for (const mesh of meshes(chunk.sectionMesh, chunk.scene)) {
18658
+ targets.set(mesh, { owners: /* @__PURE__ */ new Map(), section: { chunk, mesh: chunk.sectionMesh } });
18659
+ }
18660
+ }
18661
+ }
18662
+ for (const hit of raycaster.intersectObjects([...targets.keys()], false)) {
18663
+ if (!hit.face) continue;
18664
+ const mesh = hit.object;
18665
+ const material = Array.isArray(mesh.material) ? mesh.material[hit.face.materialIndex] : mesh.material;
18666
+ if (!material?.visible) continue;
18667
+ const entry = targets.get(mesh);
18668
+ let owner = entry.owners.get(hit.instanceId) ?? entry.owners.get(void 0);
18669
+ if (entry.section) {
18670
+ const index = entry.section.mesh.getBlockIndex(hit);
18671
+ if (index !== void 0) owner = { chunk: entry.section.chunk, index };
18672
+ }
18673
+ if (!owner || owner.chunk.hiddenBlocks.has(owner.index)) continue;
18674
+ const info = owner.chunk.renderedBlocks.get(owner.index);
18675
+ if (!info) continue;
18676
+ const matrix = mesh.matrixWorld.clone();
18677
+ if (isInstancedMesh(mesh) && hit.instanceId !== void 0) {
18678
+ const instance = new Matrix413();
18679
+ mesh.getMatrixAt(hit.instanceId, instance);
18680
+ matrix.multiply(instance);
18681
+ }
18682
+ return {
18683
+ position: new Vector318(
18684
+ owner.chunk.x * 16 + owner.index % 16,
18685
+ owner.chunk.y * 16 + Math.floor(owner.index / 256),
18686
+ owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
18687
+ ),
18688
+ block: info.block,
18689
+ point: hit.point.clone(),
18690
+ normal: hit.face.normal.clone().applyNormalMatrix(new Matrix33().getNormalMatrix(matrix)),
18691
+ distance: hit.distance
18692
+ };
18693
+ }
18694
+ return void 0;
18695
+ }
18588
18696
  getBlockAt(posOrX, y, z) {
18589
18697
  if (typeof posOrX == "number") {
18590
18698
  return this.getBlockAt(new Vector318(posOrX, y, z));
@@ -18705,6 +18813,7 @@ var Chunk = class _Chunk {
18705
18813
  if (this.fluidCells[index]) this.meshDirty = true;
18706
18814
  this.fluidCells[index] = 0;
18707
18815
  this.renderedBlocks.delete(index);
18816
+ this.objectBlocks.delete(index);
18708
18817
  const worldPos = new Vector318(
18709
18818
  this.x * 16 + index % 16,
18710
18819
  this.y * 16 + Math.floor(index / 256),
@@ -18747,6 +18856,7 @@ var Chunk = class _Chunk {
18747
18856
  this.renderedBlocks.set(index, { get block() {
18748
18857
  return readBlock();
18749
18858
  }, object: object4 });
18859
+ if (object4) this.objectBlocks.add(index);
18750
18860
  } catch (error) {
18751
18861
  this.data.assign(index, 0);
18752
18862
  this.fluidCells[index] = 0;
@@ -18765,6 +18875,7 @@ var Chunk = class _Chunk {
18765
18875
  this.fluidCells.fill(0);
18766
18876
  this.waterTints = void 0;
18767
18877
  this.renderedBlocks.clear();
18878
+ this.objectBlocks.clear();
18768
18879
  this.hiddenBlocks.clear();
18769
18880
  this.meshDirty = true;
18770
18881
  this.data.copyFrom(data);
@@ -18814,6 +18925,7 @@ var Chunk = class _Chunk {
18814
18925
  this.renderedBlocks.set(index, { get block() {
18815
18926
  return readBlock();
18816
18927
  }, object: void 0 });
18928
+ this.objectBlocks.delete(index);
18817
18929
  } catch (error) {
18818
18930
  this.data.assign(index, 0);
18819
18931
  this.fluidCells[index] = 0;
@@ -18839,10 +18951,12 @@ var Chunk = class _Chunk {
18839
18951
  this.z * 256 + Math.floor(index / 16) % 16 * 16
18840
18952
  ));
18841
18953
  this.renderedBlocks.get(index).object = object4;
18954
+ this.objectBlocks.add(index);
18842
18955
  } catch (error) {
18843
18956
  this.data.assign(index, 0);
18844
18957
  this.fluidCells[index] = 0;
18845
18958
  this.renderedBlocks.delete(index);
18959
+ this.objectBlocks.delete(index);
18846
18960
  object4?.removeFromScene();
18847
18961
  if (!failed) failure = error;
18848
18962
  failed = true;
@@ -19103,6 +19217,7 @@ var Chunk = class _Chunk {
19103
19217
  this.sectionMesh = void 0;
19104
19218
  this.meshDirty = false;
19105
19219
  this.renderedBlocks.clear();
19220
+ this.objectBlocks.clear();
19106
19221
  this.hiddenBlocks.clear();
19107
19222
  this.fluidCells.fill(0);
19108
19223
  this.waterTints = void 0;