minerender 2.1.0-alpha.62 → 2.1.0-alpha.64

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.
@@ -3459,6 +3459,9 @@ var init_InstanceReference = __esm({
3459
3459
  setMatrix(matrix) {
3460
3460
  this.activeInstanceable.setMatrixAt(this.index, matrix);
3461
3461
  }
3462
+ setVisible(visible) {
3463
+ this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
3464
+ }
3462
3465
  setPositionRotationScale(position, rotation, scale) {
3463
3466
  this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
3464
3467
  }
@@ -3513,6 +3516,7 @@ var init_SceneObject = __esm({
3513
3516
  this._instanceCounter = 0;
3514
3517
  this.instanceReferences = /* @__PURE__ */ new Map();
3515
3518
  this.freeInstanceIndices = [];
3519
+ this.hiddenInstanceMatrices = /* @__PURE__ */ new Map();
3516
3520
  this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
3517
3521
  console.log("SceneObject options", this.options);
3518
3522
  }
@@ -3707,6 +3711,7 @@ var init_SceneObject = __esm({
3707
3711
  removeInstanceAt(index) {
3708
3712
  if (!this.instanceReferences.has(index)) return;
3709
3713
  const mesh = this.instanceMesh;
3714
+ this.hiddenInstanceMatrices.delete(index);
3710
3715
  this.setMatrixAt(index, new Matrix44().makeScale(0, 0, 0));
3711
3716
  this.instanceReferences.delete(index);
3712
3717
  this.freeInstanceIndices.push(index);
@@ -3739,18 +3744,46 @@ var init_SceneObject = __esm({
3739
3744
  //<editor-fold desc="TRANSFORMATION">
3740
3745
  getMatrixAt(index, matrix = new Matrix44()) {
3741
3746
  if (!this.instanceReferences.has(index)) throw new MineRenderError("Instance is not active");
3747
+ const hidden = this.hiddenInstanceMatrices.get(index);
3748
+ if (hidden) {
3749
+ return matrix.copy(hidden);
3750
+ }
3742
3751
  this.instanceMesh.getMatrixAt(index, matrix);
3743
3752
  return matrix;
3744
3753
  }
3745
3754
  setMatrixAt(index, matrix) {
3746
3755
  if (!this.instanceReferences.has(index)) throw new MineRenderError("Instance is not active");
3747
3756
  const mesh = this.instanceMesh;
3748
- mesh.setMatrixAt(index, matrix);
3757
+ const hidden = this.hiddenInstanceMatrices.get(index);
3758
+ if (hidden) {
3759
+ hidden.copy(matrix);
3760
+ }
3761
+ mesh.setMatrixAt(index, hidden ? new Matrix44().makeScale(0, 0, 0) : matrix);
3749
3762
  mesh.instanceMatrix.needsUpdate = true;
3750
3763
  mesh.boundingBox = null;
3751
3764
  mesh.boundingSphere = null;
3752
3765
  this.notifyDirty();
3753
3766
  }
3767
+ setInstanceVisibleAt(index, visible) {
3768
+ if (!this.instanceReferences.has(index)) {
3769
+ throw new MineRenderError("Instance is not active");
3770
+ }
3771
+ const hidden = this.hiddenInstanceMatrices.get(index);
3772
+ if (visible) {
3773
+ if (!hidden) {
3774
+ return;
3775
+ }
3776
+ this.hiddenInstanceMatrices.delete(index);
3777
+ this.setMatrixAt(index, hidden);
3778
+ } else {
3779
+ if (hidden) {
3780
+ return;
3781
+ }
3782
+ const matrix = this.getMatrixAt(index);
3783
+ this.hiddenInstanceMatrices.set(index, matrix);
3784
+ this.setMatrixAt(index, matrix);
3785
+ }
3786
+ }
3754
3787
  setPositionRotationScaleAt(index, position, rotation, scale) {
3755
3788
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3756
3789
  const oldPosition = new Vector36();
@@ -3890,6 +3923,7 @@ var init_SceneObject = __esm({
3890
3923
  if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
3891
3924
  this.instanceReferences.clear();
3892
3925
  this.freeInstanceIndices.length = 0;
3926
+ this.hiddenInstanceMatrices.clear();
3893
3927
  this._instanceCounter = 0;
3894
3928
  this.instanceMesh.count = 0;
3895
3929
  this.instanceMesh.dispose();
@@ -9137,6 +9171,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
9137
9171
  get blockEntities() {
9138
9172
  return this._entities;
9139
9173
  }
9174
+ /** Sets visibility for this block's model instances and block entities. */
9175
+ setVisible(visible) {
9176
+ this.visible = visible;
9177
+ for (const model of this._models) {
9178
+ if (isInstanceReference(model)) {
9179
+ model.setVisible(visible);
9180
+ } else {
9181
+ model.visible = visible;
9182
+ }
9183
+ }
9184
+ for (const entity of this._entities) {
9185
+ entity.visible = visible;
9186
+ }
9187
+ this.notifyDirty();
9188
+ }
9140
9189
  /**
9141
9190
  * Draws the block through the dataset's block-entity index. Returns false, leaving nothing behind,
9142
9191
  * when the block is not listed or one of its models cannot be loaded.
@@ -9170,6 +9219,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
9170
9219
  BlockEntities.matrix(resolved, this._entityPlacement);
9171
9220
  this._entities = created;
9172
9221
  this.placeEntities();
9222
+ this.setVisible(this.visible);
9173
9223
  return true;
9174
9224
  }
9175
9225
  placeEntities() {
@@ -9179,6 +9229,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
9179
9229
  }
9180
9230
  }
9181
9231
  get isOccluding() {
9232
+ if (!this.visible) {
9233
+ return false;
9234
+ }
9182
9235
  return this._models.some((model) => {
9183
9236
  const object = isInstanceReference(model) ? model.instanceable : model;
9184
9237
  return object.isOpaqueFullCube && this.getModelCullMask(model, 63) === 63;
@@ -9234,6 +9287,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
9234
9287
  this._models = replacements;
9235
9288
  this._cullMask = worldMask;
9236
9289
  this.removeModels(previous.filter((model) => !replacements.includes(model)));
9290
+ if (!this.visible) {
9291
+ this.setVisible(false);
9292
+ }
9237
9293
  this.notifyDirty();
9238
9294
  }
9239
9295
  get state() {
@@ -9269,6 +9325,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
9269
9325
  this._isInstanced || (this._isInstanced = isInstanceReference(replacement));
9270
9326
  this._instanceCounter = this._isInstanced ? 1 : 0;
9271
9327
  if (previous) this.removeModels([previous]);
9328
+ if (!this.visible) {
9329
+ this.setVisible(false);
9330
+ }
9272
9331
  this.notifyDirty();
9273
9332
  }
9274
9333
  nextInstance() {
@@ -9297,6 +9356,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
9297
9356
  this._models.push(await this.createVariant(blockStateVariant));
9298
9357
  }
9299
9358
  await this.updateFluid(this._fluidSampler);
9359
+ this.setVisible(this.visible);
9300
9360
  }
9301
9361
  async hasGeometry(variant) {
9302
9362
  const modelKey = AssetKey.parse("models", variant.model);
@@ -11134,7 +11194,11 @@ var legacyBlocks_default = {
11134
11194
 
11135
11195
  // src/model/multiblock/SchematicParser.ts
11136
11196
  var SchematicParser = class {
11137
- static async parse(nbt) {
11197
+ /**
11198
+ * Parses a legacy schematic using custom mappings before the bundled defaults.
11199
+ * Keys are `id:metadata`; values are block states such as `minecraft:oak_log[axis=x]`.
11200
+ */
11201
+ static async parse(nbt, customMappings = {}) {
11138
11202
  const tags = nbt.value;
11139
11203
  if (tags.Materials?.type !== "string" || tags.Materials.value !== "Alpha") {
11140
11204
  throw new MineRenderError("Schematic Materials must be Alpha");
@@ -11176,15 +11240,16 @@ var SchematicParser = class {
11176
11240
  const high = packed >> (index & 1) * 4 & 15;
11177
11241
  const id = high << 8 | ids.value[index] & 255;
11178
11242
  const metadata = data.value[index] & 255;
11179
- const mapped = mapping[`${id}:${metadata}`];
11243
+ const key = `${id}:${metadata}`;
11244
+ const mapped = customMappings[key] ?? mapping[key];
11180
11245
  if (!mapped) throw new MineRenderError(`Unsupported legacy block ${id}:${metadata} at schematic index ${index}`);
11181
11246
  const [type, state] = mapped.split("[");
11182
11247
  if (type === "minecraft:air") continue;
11183
11248
  const properties = {};
11184
11249
  if (state) {
11185
11250
  for (const property of state.slice(0, -1).split(",")) {
11186
- const [key, value] = property.split("=");
11187
- properties[key] = value;
11251
+ const [key2, value] = property.split("=");
11252
+ properties[key2] = value;
11188
11253
  }
11189
11254
  }
11190
11255
  blocks.push({
@@ -14088,6 +14153,16 @@ var MineRenderWorld = class {
14088
14153
  const chunk = Chunk.isAir(value) ? this.getChunkAt(pos) : this.getOrCreateChunkAt(pos);
14089
14154
  return chunk?.setBlockInChunkAt(chunk.worldPosToChunkPos(pos), value, pos, onBlocksChanged);
14090
14155
  }
14156
+ async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
14157
+ if (typeof posOrX === "number") {
14158
+ return this.setBlockVisibleAt(new Vector316(posOrX, yOrVisible, z), visible);
14159
+ }
14160
+ if (isTripleArray(posOrX)) {
14161
+ return this.setBlockVisibleAt(new Vector316(...posOrX), yOrVisible);
14162
+ }
14163
+ this.validatePosBounds(posOrX);
14164
+ await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
14165
+ }
14091
14166
  async placeMultiBlock(multiblock, useBatches = true, executor) {
14092
14167
  const changes = /* @__PURE__ */ new Map();
14093
14168
  try {
@@ -14203,12 +14278,14 @@ var MineRenderWorld = class {
14203
14278
  if (!chunk) continue;
14204
14279
  changed.add(chunk);
14205
14280
  const block = chunk.getBlockAt(pos);
14206
- if (!block) continue;
14281
+ if (!block || !chunk.isBlockVisibleAt(pos)) {
14282
+ continue;
14283
+ }
14207
14284
  if (block.object?.fluidKind) {
14208
14285
  await block.object.updateFluid((x, y, z) => {
14209
14286
  const neighbor = pos.clone().add(new Vector316(x, y, z));
14210
14287
  const section = this.getChunkAt(neighbor);
14211
- const object = section?.getBlockAt(neighbor)?.object;
14288
+ const object = section?.isBlockVisibleAt(neighbor) ? section.getBlockAt(neighbor)?.object : void 0;
14212
14289
  return {
14213
14290
  fluid: object?.fluidKind,
14214
14291
  level: object?.fluidLevel,
@@ -14395,6 +14472,7 @@ var Chunk = class _Chunk {
14395
14472
  this.data = new ChunkData();
14396
14473
  this.renderedBlocks = /* @__PURE__ */ new Map();
14397
14474
  this.sectionBlocks = /* @__PURE__ */ new Map();
14475
+ this.hiddenBlocks = /* @__PURE__ */ new Set();
14398
14476
  this.meshDirty = false;
14399
14477
  this.scene = scene;
14400
14478
  this.x = x;
@@ -14432,6 +14510,7 @@ var Chunk = class _Chunk {
14432
14510
  worldPos = this.chunkPosToWorldPos(pos);
14433
14511
  }
14434
14512
  const index = _Chunk.chunkPosToBlockIndex(pos);
14513
+ this.hiddenBlocks.delete(index);
14435
14514
  this.data.set(index, block);
14436
14515
  const readBlock = this.data.snapshot(index);
14437
14516
  this.renderedBlocks.get(index)?.object?.removeFromScene();
@@ -14473,9 +14552,31 @@ var Chunk = class _Chunk {
14473
14552
  await onBlocksChanged?.([worldPos]);
14474
14553
  }
14475
14554
  }
14555
+ async setBlockVisibleAt(pos, visible) {
14556
+ const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
14557
+ const block = this.renderedBlocks.get(index);
14558
+ if (!block || visible === !this.hiddenBlocks.has(index)) {
14559
+ return;
14560
+ }
14561
+ if (visible) {
14562
+ this.hiddenBlocks.delete(index);
14563
+ } else {
14564
+ this.hiddenBlocks.add(index);
14565
+ }
14566
+ block.object?.setVisible(visible);
14567
+ if (this.sectionBlocks.has(index)) {
14568
+ this.meshDirty = true;
14569
+ }
14570
+ this.scene.dirty = true;
14571
+ await this.onBlocksChanged?.([pos]);
14572
+ }
14573
+ isBlockVisibleAt(pos) {
14574
+ const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
14575
+ return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
14576
+ }
14476
14577
  isOccludingAt(pos) {
14477
14578
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
14478
- return this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false);
14579
+ return !this.hiddenBlocks.has(index) && (this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false));
14479
14580
  }
14480
14581
  async setCullMaskAt(pos, mask) {
14481
14582
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
@@ -14491,7 +14592,10 @@ var Chunk = class _Chunk {
14491
14592
  }
14492
14593
  rebuildSectionMesh() {
14493
14594
  if (!this.meshDirty) return;
14494
- const next = this.sectionBlocks.size ? SectionMesh.build([...this.sectionBlocks.values()], this.sectionModels.maxAtlasSize) : void 0;
14595
+ const next = this.sectionBlocks.size ? SectionMesh.build(
14596
+ [...this.sectionBlocks.values()].filter((entry) => !this.hiddenBlocks.has(entry.index)),
14597
+ this.sectionModels.maxAtlasSize
14598
+ ) : void 0;
14495
14599
  this.sectionMesh?.dispose();
14496
14600
  this.sectionMesh = next;
14497
14601
  if (next) {
@@ -14511,6 +14615,7 @@ var Chunk = class _Chunk {
14511
14615
  this.sectionMesh = void 0;
14512
14616
  this.meshDirty = false;
14513
14617
  this.renderedBlocks.clear();
14618
+ this.hiddenBlocks.clear();
14514
14619
  this.data.clear();
14515
14620
  await onBlocksChanged?.(positions);
14516
14621
  }