minerender 2.1.0-alpha.61 → 2.1.0-alpha.63

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.
@@ -3236,11 +3236,11 @@ var init_Entities = __esm({
3236
3236
  return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
3237
3237
  }
3238
3238
  /**
3239
- * Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
3239
+ * Native and sampled vanilla clips by name, or undefined when the model or selected version has none.
3240
3240
  */
3241
3241
  static async getAnimations(modelKey) {
3242
3242
  const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3243
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
3243
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
3244
3244
  const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3245
3245
  return file?.animations;
3246
3246
  }
@@ -3290,7 +3290,7 @@ function sampleEntityKeyframes(keyframes, time) {
3290
3290
  let low = 0, high = keyframes.length;
3291
3291
  while (low < high) {
3292
3292
  const middle = low + high >>> 1;
3293
- if (time <= keyframes[middle].time) high = middle;
3293
+ if (time < keyframes[middle].time) high = middle;
3294
3294
  else low = middle + 1;
3295
3295
  }
3296
3296
  const a = Math.max(0, low - 1);
@@ -3329,6 +3329,7 @@ var init_EntityAnimation = __esm({
3329
3329
  });
3330
3330
 
3331
3331
  // src/entity/scene/EntityAnimationPlayer.ts
3332
+ import { Euler as Euler3, Vector3 as Vector35 } from "three";
3332
3333
  var ZERO, EntityAnimationPlayer;
3333
3334
  var init_EntityAnimationPlayer = __esm({
3334
3335
  "src/entity/scene/EntityAnimationPlayer.ts"() {
@@ -3348,25 +3349,45 @@ var init_EntityAnimationPlayer = __esm({
3348
3349
  return this._time;
3349
3350
  }
3350
3351
  /**
3351
- * Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
3352
- * bones without a matching part are skipped.
3352
+ * Starts an animation on matching named parts. Supplied baked poses are the baseline for offsets;
3353
+ * without them, the current pose is used. Stopping restores the pose from before playback.
3353
3354
  */
3354
- play(layers, animation, options = {}) {
3355
+ play(layers, animation, options = {}, poses) {
3355
3356
  this.stop();
3356
3357
  this._animation = animation;
3357
3358
  this._time = options.time ?? 0;
3358
3359
  this.loop = options.loop ?? animation.loop;
3359
3360
  this.speed = options.speed ?? 1;
3360
3361
  for (const layer of layers) {
3361
- for (const bone of Object.keys(animation.bones)) {
3362
- const object = layer.getObjectByName(`group:${bone}`);
3363
- if (!object) continue;
3364
- this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
3362
+ const objects = [];
3363
+ if (poses) {
3364
+ layer.traverse((object) => {
3365
+ if (poses.has(object)) objects.push(object);
3366
+ });
3367
+ } else {
3368
+ for (const bone of Object.keys(animation.bones)) {
3369
+ const object = layer.getObjectByName(`group:${bone}`);
3370
+ if (object) objects.push(object);
3371
+ }
3372
+ }
3373
+ for (const object of objects) {
3374
+ const bone = object.name.slice("group:".length);
3375
+ const pose = poses?.get(object);
3376
+ this.parts.push({
3377
+ bone,
3378
+ object,
3379
+ position: object.position.clone(),
3380
+ rotation: object.rotation.clone(),
3381
+ scale: object.scale.clone(),
3382
+ basePosition: pose ? new Vector35(...pose.offset) : object.position.clone(),
3383
+ baseRotation: pose ? new Euler3(...pose.rotation, "ZYX") : object.rotation.clone(),
3384
+ baseScale: pose ? new Vector35(...pose.scale ?? [1, 1, 1]) : object.scale.clone()
3385
+ });
3365
3386
  }
3366
3387
  }
3367
3388
  this.apply();
3368
3389
  }
3369
- /** Restores the default poses. Returns whether an animation was active. */
3390
+ /** Restores the poses from before playback. Returns whether an animation was active. */
3370
3391
  stop() {
3371
3392
  if (!this._animation) return false;
3372
3393
  for (const part of this.parts) {
@@ -3395,10 +3416,10 @@ var init_EntityAnimationPlayer = __esm({
3395
3416
  apply() {
3396
3417
  const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
3397
3418
  for (const part of this.parts) {
3398
- const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
3399
- part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
3400
- part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
3401
- part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
3419
+ const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone] ?? {};
3420
+ part.object.position.set(part.basePosition.x + position[0], part.basePosition.y + position[1], part.basePosition.z + position[2]);
3421
+ part.object.rotation.set(part.baseRotation.x + rotation[0], part.baseRotation.y + rotation[1], part.baseRotation.z + rotation[2], part.baseRotation.order);
3422
+ part.object.scale.set(part.baseScale.x + scale[0], part.baseScale.y + scale[1], part.baseScale.z + scale[2]);
3402
3423
  }
3403
3424
  }
3404
3425
  };
@@ -3438,6 +3459,9 @@ var init_InstanceReference = __esm({
3438
3459
  setMatrix(matrix) {
3439
3460
  this.activeInstanceable.setMatrixAt(this.index, matrix);
3440
3461
  }
3462
+ setVisible(visible) {
3463
+ this.activeInstanceable.setInstanceVisibleAt(this.index, visible);
3464
+ }
3441
3465
  setPositionRotationScale(position, rotation, scale) {
3442
3466
  this.activeInstanceable.setPositionRotationScaleAt(this.index, position, rotation, scale);
3443
3467
  }
@@ -3465,7 +3489,7 @@ var init_InstanceReference = __esm({
3465
3489
  });
3466
3490
 
3467
3491
  // src/renderer/SceneObject.ts
3468
- import { Color as Color2, Euler as Euler3, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector35 } from "three";
3492
+ import { Color as Color2, Euler as Euler4, InstancedBufferAttribute, InstancedMesh, MathUtils, Matrix4 as Matrix44, Mesh as Mesh3, Object3D as Object3D2, Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
3469
3493
  function isSceneObject(obj) {
3470
3494
  return obj.isSceneObject;
3471
3495
  }
@@ -3492,6 +3516,7 @@ var init_SceneObject = __esm({
3492
3516
  this._instanceCounter = 0;
3493
3517
  this.instanceReferences = /* @__PURE__ */ new Map();
3494
3518
  this.freeInstanceIndices = [];
3519
+ this.hiddenInstanceMatrices = /* @__PURE__ */ new Map();
3495
3520
  this.options = (0, import_ts_deepmerge3.default)({}, _SceneObject.DEFAULT_OPTIONS, options ?? {});
3496
3521
  console.log("SceneObject options", this.options);
3497
3522
  }
@@ -3686,6 +3711,7 @@ var init_SceneObject = __esm({
3686
3711
  removeInstanceAt(index) {
3687
3712
  if (!this.instanceReferences.has(index)) return;
3688
3713
  const mesh = this.instanceMesh;
3714
+ this.hiddenInstanceMatrices.delete(index);
3689
3715
  this.setMatrixAt(index, new Matrix44().makeScale(0, 0, 0));
3690
3716
  this.instanceReferences.delete(index);
3691
3717
  this.freeInstanceIndices.push(index);
@@ -3718,23 +3744,51 @@ var init_SceneObject = __esm({
3718
3744
  //<editor-fold desc="TRANSFORMATION">
3719
3745
  getMatrixAt(index, matrix = new Matrix44()) {
3720
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
+ }
3721
3751
  this.instanceMesh.getMatrixAt(index, matrix);
3722
3752
  return matrix;
3723
3753
  }
3724
3754
  setMatrixAt(index, matrix) {
3725
3755
  if (!this.instanceReferences.has(index)) throw new MineRenderError("Instance is not active");
3726
3756
  const mesh = this.instanceMesh;
3727
- 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);
3728
3762
  mesh.instanceMatrix.needsUpdate = true;
3729
3763
  mesh.boundingBox = null;
3730
3764
  mesh.boundingSphere = null;
3731
3765
  this.notifyDirty();
3732
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
+ }
3733
3787
  setPositionRotationScaleAt(index, position, rotation, scale) {
3734
3788
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3735
- const oldPosition = new Vector35();
3789
+ const oldPosition = new Vector36();
3736
3790
  const oldRotation = new Quaternion3();
3737
- const oldScale = new Vector35();
3791
+ const oldScale = new Vector36();
3738
3792
  const matrix = new Matrix44();
3739
3793
  if (!scale || !rotation || !position) {
3740
3794
  this.getMatrixAt(index, matrix).decompose(oldPosition, oldRotation, oldScale);
@@ -3750,7 +3804,7 @@ var init_SceneObject = __esm({
3750
3804
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3751
3805
  this.setPositionRotationScaleAt(index, position);
3752
3806
  }
3753
- getPositionAt(index, vector = new Vector35()) {
3807
+ getPositionAt(index, vector = new Vector36()) {
3754
3808
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3755
3809
  const matrix = this.getMatrixAt(index);
3756
3810
  vector.setFromMatrixPosition(matrix);
@@ -3760,17 +3814,17 @@ var init_SceneObject = __esm({
3760
3814
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3761
3815
  this.setPositionRotationScaleAt(index, void 0, rotation, void 0);
3762
3816
  }
3763
- getRotationAt(index, euler = new Euler3()) {
3817
+ getRotationAt(index, euler = new Euler4()) {
3764
3818
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3765
3819
  const rotation = new Quaternion3();
3766
- this.getMatrixAt(index).decompose(new Vector35(), rotation, new Vector35());
3820
+ this.getMatrixAt(index).decompose(new Vector36(), rotation, new Vector36());
3767
3821
  return euler.setFromQuaternion(rotation);
3768
3822
  }
3769
3823
  setScaleAt(index, scale) {
3770
3824
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3771
3825
  this.setPositionRotationScaleAt(index, void 0, void 0, scale);
3772
3826
  }
3773
- getScaleAt(index, vector = new Vector35()) {
3827
+ getScaleAt(index, vector = new Vector36()) {
3774
3828
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
3775
3829
  const matrix = this.getMatrixAt(index);
3776
3830
  vector.setFromMatrixScale(matrix);
@@ -3869,6 +3923,7 @@ var init_SceneObject = __esm({
3869
3923
  if (this._scene) this._scene.stats.instanceCount -= this.instanceReferences.size;
3870
3924
  this.instanceReferences.clear();
3871
3925
  this.freeInstanceIndices.length = 0;
3926
+ this.hiddenInstanceMatrices.clear();
3872
3927
  this._instanceCounter = 0;
3873
3928
  this.instanceMesh.count = 0;
3874
3929
  this.instanceMesh.dispose();
@@ -3902,7 +3957,7 @@ var init_SceneObject = __esm({
3902
3957
  });
3903
3958
 
3904
3959
  // src/entity/scene/EntityObject.ts
3905
- import { Color as Color3, Euler as Euler4, Matrix4 as Matrix45, Object3D as Object3D3 } from "three";
3960
+ import { Color as Color3, Euler as Euler5, Matrix4 as Matrix45, Object3D as Object3D3 } from "three";
3906
3961
  function isEntityObject(obj) {
3907
3962
  return obj.isEntityObject;
3908
3963
  }
@@ -3932,7 +3987,8 @@ var init_EntityObject = __esm({
3932
3987
  this.scrollMaterials = [];
3933
3988
  /** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
3934
3989
  this.age = 0;
3935
- this.animationPlayer = new EntityAnimationPlayer();
3990
+ this.animationPlayers = [];
3991
+ this.partPoses = /* @__PURE__ */ new Map();
3936
3992
  this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
3937
3993
  this.addEventListener("added", () => this.updateScrollSubscription());
3938
3994
  this.addEventListener("removed", () => this.updateScrollSubscription());
@@ -3949,7 +4005,8 @@ var init_EntityObject = __esm({
3949
4005
  for (const geometry of this.geometries) geometry.dispose();
3950
4006
  this.geometries.clear();
3951
4007
  for (const dispose of this.disposeWireframes.splice(0)) dispose();
3952
- this.animationPlayer.clear();
4008
+ for (const player of this.animationPlayers.splice(0)) player.clear();
4009
+ this.partPoses.clear();
3953
4010
  super.disposeAndRemoveAllChildren();
3954
4011
  }
3955
4012
  clearScrollMaterials() {
@@ -3981,36 +4038,61 @@ var init_EntityObject = __esm({
3981
4038
  this.notifyDirty();
3982
4039
  }
3983
4040
  //<editor-fold desc="ANIMATION">
3984
- /** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
4041
+ /** The first active clip, until playback is stopped or the object is disposed. */
3985
4042
  get animation() {
3986
- return this.animationPlayer.animation;
4043
+ return this.animationPlayers[0]?.animation;
4044
+ }
4045
+ /** Clips playing together, each targeting a separate geometry layer. */
4046
+ get activeAnimations() {
4047
+ return this.animationPlayers.map((player) => player.animation);
3987
4048
  }
3988
4049
  /** Seconds since the animation started, before looping. */
3989
4050
  get animationTime() {
3990
- return this.animationPlayer.time;
4051
+ return this.animationPlayers[0]?.time ?? 0;
3991
4052
  }
3992
4053
  /**
3993
- * Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
3994
- * Parts of every layer are matched by name and their current pose is the default the offsets add to.
4054
+ * Plays a clip from {@link Entities.getAnimations}, replacing all active clips.
4055
+ * Offsets apply to the baked pose in the clip's layer (`main` by default), including repeated draws of that layer.
3995
4056
  * The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
3996
4057
  */
3997
4058
  playAnimation(animation, options) {
4059
+ this.playAnimations([animation], options);
4060
+ }
4061
+ /** Plays one clip per selected geometry layer, with a shared clock and no blending between clips. */
4062
+ playAnimations(animations, options) {
4063
+ const targets = /* @__PURE__ */ new Set();
4064
+ const selections = animations.map((animation) => {
4065
+ const layer = animation.layer ?? "main";
4066
+ if (targets.has(layer)) throw new Error(`Multiple animations target layer "${layer}"`);
4067
+ targets.add(layer);
4068
+ const names = Object.keys(this.entityLayers).filter((name) => name.split("#")[0] === layer);
4069
+ if (!names.length) throw new Error(`Entity ${this.entity.id} has no selected animation layer "${layer}"`);
4070
+ return { animation, names };
4071
+ });
3998
4072
  this.createMeshes();
3999
- const layers = Object.keys(this.entityLayers).map((name) => this.getLayerGroup(name)).filter((layer) => !!layer);
4000
- this.animationPlayer.play(layers, animation, options);
4073
+ this.stopAnimation();
4074
+ for (const { animation, names } of selections) {
4075
+ const player = new EntityAnimationPlayer();
4076
+ player.play(names.map((name) => this.getLayerGroup(name)), animation, options, this.partPoses);
4077
+ this.animationPlayers.push(player);
4078
+ }
4001
4079
  this.notifyDirty();
4002
4080
  }
4003
- /** Stops the animation and restores the default pose. */
4081
+ /** Stops all clips and restores the poses from before playback. */
4004
4082
  stopAnimation() {
4005
- if (this.animationPlayer.stop()) this.notifyDirty();
4083
+ const players = this.animationPlayers.splice(0);
4084
+ for (const player of players) player.stop();
4085
+ if (players.length) this.notifyDirty();
4006
4086
  }
4007
4087
  /** Poses the object at an explicit time in seconds. Has no effect without an animation. */
4008
4088
  setAnimationTime(seconds) {
4009
- if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
4089
+ for (const player of this.animationPlayers) player.setTime(seconds);
4090
+ if (this.animationPlayers.length) this.notifyDirty();
4010
4091
  }
4011
4092
  /** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
4012
4093
  advanceAnimation(deltaSeconds) {
4013
- if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
4094
+ for (const player of this.animationPlayers) player.advance(deltaSeconds);
4095
+ if (this.animationPlayers.length) this.notifyDirty();
4014
4096
  }
4015
4097
  //</editor-fold>
4016
4098
  getLayerGroup(name) {
@@ -4049,7 +4131,7 @@ var init_EntityObject = __esm({
4049
4131
  const matrix = new Matrix45();
4050
4132
  if ("scale" in op) matrix.makeScale(...op.scale);
4051
4133
  else if ("translate" in op) matrix.makeTranslation(...op.translate);
4052
- else matrix.makeRotationFromEuler(new Euler4(...op.rotate, "ZYX"));
4134
+ else matrix.makeRotationFromEuler(new Euler5(...op.rotate, "ZYX"));
4053
4135
  modelRoot.matrix.multiply(matrix);
4054
4136
  }
4055
4137
  modelRoot.matrixAutoUpdate = false;
@@ -4070,6 +4152,7 @@ var init_EntityObject = __esm({
4070
4152
  anchor.position.fromArray(part.pose.offset);
4071
4153
  anchor.rotation.set(...part.pose.rotation, "ZYX");
4072
4154
  anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
4155
+ this.partPoses.set(anchor, part.pose);
4073
4156
  parent.add(anchor);
4074
4157
  const size = part.texture ?? textureSize;
4075
4158
  for (const cube of part.cubes) {
@@ -4146,7 +4229,7 @@ import {
4146
4229
  TriangleFanDrawMode,
4147
4230
  TriangleStripDrawMode,
4148
4231
  TrianglesDrawMode,
4149
- Vector3 as Vector39
4232
+ Vector3 as Vector310
4150
4233
  } from "three";
4151
4234
  function computeTangents(geometry) {
4152
4235
  geometry.computeTangents();
@@ -4465,15 +4548,15 @@ function computeMorphedAttributes(object) {
4465
4548
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
4466
4549
  return null;
4467
4550
  }
4468
- const _vA = new Vector39();
4469
- const _vB = new Vector39();
4470
- const _vC = new Vector39();
4471
- const _tempA = new Vector39();
4472
- const _tempB = new Vector39();
4473
- const _tempC = new Vector39();
4474
- const _morphA = new Vector39();
4475
- const _morphB = new Vector39();
4476
- const _morphC = new Vector39();
4551
+ const _vA = new Vector310();
4552
+ const _vB = new Vector310();
4553
+ const _vC = new Vector310();
4554
+ const _tempA = new Vector310();
4555
+ const _tempB = new Vector310();
4556
+ const _tempC = new Vector310();
4557
+ const _morphA = new Vector310();
4558
+ const _morphB = new Vector310();
4559
+ const _morphC = new Vector310();
4477
4560
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
4478
4561
  _vA.fromBufferAttribute(attribute, a2);
4479
4562
  _vB.fromBufferAttribute(attribute, b2);
@@ -4683,7 +4766,7 @@ var init_BufferGeometryUtils = __esm({
4683
4766
  });
4684
4767
 
4685
4768
  // src/model/ModelCulling.ts
4686
- import { Vector3 as Vector310 } from "three";
4769
+ import { Vector3 as Vector311 } from "three";
4687
4770
  var ModelCulling;
4688
4771
  var init_ModelCulling = __esm({
4689
4772
  "src/model/ModelCulling.ts"() {
@@ -4692,7 +4775,7 @@ var init_ModelCulling = __esm({
4692
4775
  static toLocalMask(worldMask, rotation) {
4693
4776
  let localMask = 0;
4694
4777
  for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
4695
- const normal = new Vector310(...offset).applyEuler(rotation);
4778
+ const normal = new Vector311(...offset).applyEuler(rotation);
4696
4779
  const worldFace = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
4697
4780
  if (worldFace < 0) return 0;
4698
4781
  if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
@@ -4919,7 +5002,7 @@ var init_ItemTints = __esm({
4919
5002
  });
4920
5003
 
4921
5004
  // src/model/scene/ModelObject.ts
4922
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler6, Matrix4 as Matrix49 } from "three";
5005
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler7, Matrix4 as Matrix49 } from "three";
4923
5006
  function isModelObject(obj) {
4924
5007
  return obj.isModelObject;
4925
5008
  }
@@ -5023,7 +5106,7 @@ var init_ModelObject = __esm({
5023
5106
  elGeo.clearGroups();
5024
5107
  }
5025
5108
  if (this.options.uvLockRotation) {
5026
- UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler6(...this.options.uvLockRotation));
5109
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new Euler7(...this.options.uvLockRotation));
5027
5110
  }
5028
5111
  if (this.options.tints) {
5029
5112
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
@@ -5684,7 +5767,7 @@ import {
5684
5767
  Color as Color4,
5685
5768
  Matrix3,
5686
5769
  Vector2 as Vector22,
5687
- Vector3 as Vector36
5770
+ Vector3 as Vector37
5688
5771
  } from "three";
5689
5772
  var OBJExporter = class {
5690
5773
  parse(object) {
@@ -5692,9 +5775,9 @@ var OBJExporter = class {
5692
5775
  let indexVertex = 0;
5693
5776
  let indexVertexUvs = 0;
5694
5777
  let indexNormals = 0;
5695
- const vertex = new Vector36();
5778
+ const vertex = new Vector37();
5696
5779
  const color = new Color4();
5697
- const normal = new Vector36();
5780
+ const normal = new Vector37();
5698
5781
  const uv = new Vector22();
5699
5782
  const face = [];
5700
5783
  function parseMesh(mesh) {
@@ -5823,7 +5906,7 @@ var OBJExporter = class {
5823
5906
  // ../../node_modules/three/examples/jsm/exporters/PLYExporter.js
5824
5907
  import {
5825
5908
  Matrix3 as Matrix32,
5826
- Vector3 as Vector37,
5909
+ Vector3 as Vector38,
5827
5910
  Color as Color5
5828
5911
  } from "three";
5829
5912
  var PLYExporter = class {
@@ -5916,7 +5999,7 @@ property list uchar int vertex_index
5916
5999
  `;
5917
6000
  }
5918
6001
  header += "end_header\n";
5919
- const vertex = new Vector37();
6002
+ const vertex = new Vector38();
5920
6003
  const normalMatrixWorld = new Matrix32();
5921
6004
  let result = null;
5922
6005
  if (options.binary === true) {
@@ -6115,7 +6198,7 @@ import {
6115
6198
  Source,
6116
6199
  SRGBColorSpace as SRGBColorSpace4,
6117
6200
  CompressedTexture,
6118
- Vector3 as Vector38,
6201
+ Vector3 as Vector39,
6119
6202
  Quaternion as Quaternion4
6120
6203
  } from "three";
6121
6204
 
@@ -6576,7 +6659,7 @@ var GLTFWriter = class {
6576
6659
  isNormalizedNormalAttribute(normal) {
6577
6660
  const cache = this.cache;
6578
6661
  if (cache.attributesNormalized.has(normal)) return false;
6579
- const v = new Vector38();
6662
+ const v = new Vector39();
6580
6663
  for (let i = 0, il = normal.count; i < il; i++) {
6581
6664
  if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1) > 5e-4) return false;
6582
6665
  }
@@ -6593,7 +6676,7 @@ var GLTFWriter = class {
6593
6676
  const cache = this.cache;
6594
6677
  if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal);
6595
6678
  const attribute = normal.clone();
6596
- const v = new Vector38();
6679
+ const v = new Vector39();
6597
6680
  for (let i = 0, il = attribute.count; i < il; i++) {
6598
6681
  v.fromBufferAttribute(attribute, i);
6599
6682
  if (v.x === 0 && v.y === 0 && v.z === 0) {
@@ -7860,9 +7943,9 @@ var GLTFMeshGpuInstancing = class {
7860
7943
  const rotationAttr = new Float32Array(mesh.count * 4);
7861
7944
  const scaleAttr = new Float32Array(mesh.count * 3);
7862
7945
  const matrix = new Matrix46();
7863
- const position = new Vector38();
7946
+ const position = new Vector39();
7864
7947
  const quaternion = new Quaternion4();
7865
- const scale = new Vector38();
7948
+ const scale = new Vector39();
7866
7949
  for (let i = 0; i < mesh.count; i++) {
7867
7950
  mesh.getMatrixAt(i, matrix);
7868
7951
  matrix.decompose(position, quaternion, scale);
@@ -8855,7 +8938,7 @@ init_SpecialItems();
8855
8938
  init_BlockStates();
8856
8939
  init_MineRenderError();
8857
8940
  init_util();
8858
- import { Euler as Euler7 } from "three";
8941
+ import { Euler as Euler8 } from "three";
8859
8942
  function matchesCondition(condition, state) {
8860
8943
  return Object.entries(condition).every(([key, value]) => {
8861
8944
  if (Array.isArray(value)) {
@@ -8930,7 +9013,7 @@ var BlockStateResolver = class {
8930
9013
  return variants[variants.length - 1];
8931
9014
  }
8932
9015
  static rotation(variant) {
8933
- const rotation = new Euler7();
9016
+ const rotation = new Euler8();
8934
9017
  if (typeof variant.x !== "undefined") {
8935
9018
  rotation.x = toRadians(clampRotationDegrees(variant.x));
8936
9019
  }
@@ -9025,7 +9108,7 @@ var import_ts_deepmerge6 = __toESM(require_dist());
9025
9108
  init_MineRenderError();
9026
9109
  init_InstanceReference();
9027
9110
  init_AssetKey();
9028
- import { Euler as Euler8, Matrix4 as Matrix411, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
9111
+ import { Euler as Euler9, Matrix4 as Matrix411, Quaternion as Quaternion5, Vector3 as Vector312 } from "three";
9029
9112
  init_ModelCulling();
9030
9113
  init_FluidGeometry();
9031
9114
  init_Entities();
@@ -9088,6 +9171,21 @@ var _BlockObject = class _BlockObject extends SceneObject {
9088
9171
  get blockEntities() {
9089
9172
  return this._entities;
9090
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
+ }
9091
9189
  /**
9092
9190
  * Draws the block through the dataset's block-entity index. Returns false, leaving nothing behind,
9093
9191
  * when the block is not listed or one of its models cannot be loaded.
@@ -9121,6 +9219,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
9121
9219
  BlockEntities.matrix(resolved, this._entityPlacement);
9122
9220
  this._entities = created;
9123
9221
  this.placeEntities();
9222
+ this.setVisible(this.visible);
9124
9223
  return true;
9125
9224
  }
9126
9225
  placeEntities() {
@@ -9130,6 +9229,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
9130
9229
  }
9131
9230
  }
9132
9231
  get isOccluding() {
9232
+ if (!this.visible) {
9233
+ return false;
9234
+ }
9133
9235
  return this._models.some((model) => {
9134
9236
  const object = isInstanceReference(model) ? model.instanceable : model;
9135
9237
  return object.isOpaqueFullCube && this.getModelCullMask(model, 63) === 63;
@@ -9143,12 +9245,12 @@ var _BlockObject = class _BlockObject extends SceneObject {
9143
9245
  getModelCullMask(model, worldMask) {
9144
9246
  const object = isInstanceReference(model) ? model.instanceable : model;
9145
9247
  if (object.options.displayPosition) return 0;
9146
- const position = new Vector311();
9248
+ const position = new Vector312();
9147
9249
  const rotation = new Quaternion5();
9148
- const scale = new Vector311();
9250
+ const scale = new Vector312();
9149
9251
  this.getModelMatrix(model).decompose(position, rotation, scale);
9150
- if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector311(1, 1, 1)) > 1e-10) return 0;
9151
- return ModelCulling.toLocalMask(worldMask, new Euler8().setFromQuaternion(rotation));
9252
+ if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new Vector312(1, 1, 1)) > 1e-10) return 0;
9253
+ return ModelCulling.toLocalMask(worldMask, new Euler9().setFromQuaternion(rotation));
9152
9254
  }
9153
9255
  async setCullMask(worldMask) {
9154
9256
  worldMask &= 63;
@@ -9185,6 +9287,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
9185
9287
  this._models = replacements;
9186
9288
  this._cullMask = worldMask;
9187
9289
  this.removeModels(previous.filter((model) => !replacements.includes(model)));
9290
+ if (!this.visible) {
9291
+ this.setVisible(false);
9292
+ }
9188
9293
  this.notifyDirty();
9189
9294
  }
9190
9295
  get state() {
@@ -9220,6 +9325,9 @@ var _BlockObject = class _BlockObject extends SceneObject {
9220
9325
  this._isInstanced || (this._isInstanced = isInstanceReference(replacement));
9221
9326
  this._instanceCounter = this._isInstanced ? 1 : 0;
9222
9327
  if (previous) this.removeModels([previous]);
9328
+ if (!this.visible) {
9329
+ this.setVisible(false);
9330
+ }
9223
9331
  this.notifyDirty();
9224
9332
  }
9225
9333
  nextInstance() {
@@ -9248,6 +9356,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
9248
9356
  this._models.push(await this.createVariant(blockStateVariant));
9249
9357
  }
9250
9358
  await this.updateFluid(this._fluidSampler);
9359
+ this.setVisible(this.visible);
9251
9360
  }
9252
9361
  async hasGeometry(variant) {
9253
9362
  const modelKey = AssetKey.parse("models", variant.model);
@@ -12398,7 +12507,7 @@ function isMineRenderScene(obj) {
12398
12507
  }
12399
12508
 
12400
12509
  // src/renderer/Renderer.ts
12401
- import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector313, WebGLRenderer as WebGLRenderer2 } from "three";
12510
+ import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector314, WebGLRenderer as WebGLRenderer2 } from "three";
12402
12511
  var import_ts_deepmerge9 = __toESM(require_dist());
12403
12512
  init_util();
12404
12513
  init_Model();
@@ -12414,7 +12523,7 @@ import {
12414
12523
  Spherical,
12415
12524
  TOUCH,
12416
12525
  Vector2 as Vector25,
12417
- Vector3 as Vector312
12526
+ Vector3 as Vector313
12418
12527
  } from "three";
12419
12528
  var _changeEvent = { type: "change" };
12420
12529
  var _startEvent = { type: "start" };
@@ -12428,7 +12537,7 @@ var OrbitControls = class extends EventDispatcher {
12428
12537
  this.domElement = domElement;
12429
12538
  this.domElement.style.touchAction = "none";
12430
12539
  this.enabled = true;
12431
- this.target = new Vector312();
12540
+ this.target = new Vector313();
12432
12541
  this.minDistance = 0;
12433
12542
  this.maxDistance = Infinity;
12434
12543
  this.minZoom = 0;
@@ -12480,10 +12589,10 @@ var OrbitControls = class extends EventDispatcher {
12480
12589
  state = STATE.NONE;
12481
12590
  };
12482
12591
  this.update = function() {
12483
- const offset = new Vector312();
12484
- const quat = new Quaternion6().setFromUnitVectors(object.up, new Vector312(0, 1, 0));
12592
+ const offset = new Vector313();
12593
+ const quat = new Quaternion6().setFromUnitVectors(object.up, new Vector313(0, 1, 0));
12485
12594
  const quatInverse = quat.clone().invert();
12486
- const lastPosition = new Vector312();
12595
+ const lastPosition = new Vector313();
12487
12596
  const lastQuaternion = new Quaternion6();
12488
12597
  const twoPI = 2 * Math.PI;
12489
12598
  return function update() {
@@ -12573,7 +12682,7 @@ var OrbitControls = class extends EventDispatcher {
12573
12682
  const spherical = new Spherical();
12574
12683
  const sphericalDelta = new Spherical();
12575
12684
  let scale = 1;
12576
- const panOffset = new Vector312();
12685
+ const panOffset = new Vector313();
12577
12686
  let zoomChanged = false;
12578
12687
  const rotateStart = new Vector25();
12579
12688
  const rotateEnd = new Vector25();
@@ -12599,7 +12708,7 @@ var OrbitControls = class extends EventDispatcher {
12599
12708
  sphericalDelta.phi -= angle;
12600
12709
  }
12601
12710
  const panLeft = function() {
12602
- const v = new Vector312();
12711
+ const v = new Vector313();
12603
12712
  return function panLeft2(distance, objectMatrix) {
12604
12713
  v.setFromMatrixColumn(objectMatrix, 0);
12605
12714
  v.multiplyScalar(-distance);
@@ -12607,7 +12716,7 @@ var OrbitControls = class extends EventDispatcher {
12607
12716
  };
12608
12717
  }();
12609
12718
  const panUp = function() {
12610
- const v = new Vector312();
12719
+ const v = new Vector313();
12611
12720
  return function panUp2(distance, objectMatrix) {
12612
12721
  if (scope.screenSpacePanning === true) {
12613
12722
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -12620,7 +12729,7 @@ var OrbitControls = class extends EventDispatcher {
12620
12729
  };
12621
12730
  }();
12622
12731
  const pan = function() {
12623
- const offset = new Vector312();
12732
+ const offset = new Vector313();
12624
12733
  return function pan2(deltaX, deltaY) {
12625
12734
  const element = scope.domElement;
12626
12735
  if (scope.object.isPerspectiveCamera) {
@@ -13437,8 +13546,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
13437
13546
  top: void 0,
13438
13547
  bottom: void 0
13439
13548
  },
13440
- position: new Vector313(50, 50, 50),
13441
- lookingAt: new Vector313(0, 0, 0)
13549
+ position: new Vector314(50, 50, 50),
13550
+ lookingAt: new Vector314(0, 0, 0)
13442
13551
  },
13443
13552
  render: {
13444
13553
  fpsLimit: 60,
@@ -13903,13 +14012,13 @@ var AnvilParser = class {
13903
14012
  };
13904
14013
 
13905
14014
  // src/world/Chunk.ts
13906
- import { Vector3 as Vector316 } from "three";
14015
+ import { Vector3 as Vector317 } from "three";
13907
14016
  init_BlockStates();
13908
14017
  init_AssetKey();
13909
14018
 
13910
14019
  // src/world/MineRenderWorld.ts
13911
14020
  init_Model();
13912
- import { Vector3 as Vector315 } from "three";
14021
+ import { Vector3 as Vector316 } from "three";
13913
14022
  init_BatchedExecutor();
13914
14023
  init_AssetKey();
13915
14024
  init_BlockStates();
@@ -13919,7 +14028,7 @@ init_CubeFace();
13919
14028
  init_AssetKey();
13920
14029
  init_Models();
13921
14030
  init_CubeFace();
13922
- import { Matrix4 as Matrix412, Vector3 as Vector314 } from "three";
14031
+ import { Matrix4 as Matrix412, Vector3 as Vector315 } from "three";
13923
14032
  init_ModelCulling();
13924
14033
  init_ModelObject();
13925
14034
  init_UVMapper();
@@ -13987,7 +14096,7 @@ var SectionModels = class {
13987
14096
  const cullFaces = CUBE_FACES.map((face) => {
13988
14097
  const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
13989
14098
  if (local < 0) return 0;
13990
- const normal = new Vector314(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
14099
+ const normal = new Vector315(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
13991
14100
  const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
13992
14101
  return 1 << world;
13993
14102
  });
@@ -14017,20 +14126,20 @@ var MineRenderWorld = class {
14017
14126
  }
14018
14127
  getBlockAt(posOrX, y, z) {
14019
14128
  if (typeof posOrX == "number") {
14020
- return this.getBlockAt(new Vector315(posOrX, y, z));
14129
+ return this.getBlockAt(new Vector316(posOrX, y, z));
14021
14130
  }
14022
14131
  if (isTripleArray(posOrX)) {
14023
- return this.getBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]));
14132
+ return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
14024
14133
  }
14025
14134
  this.validatePosBounds(posOrX);
14026
14135
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
14027
14136
  }
14028
14137
  async setBlockAt(posOrX, yOrBlock, z, block) {
14029
14138
  if (typeof posOrX == "number") {
14030
- return this.setBlockAt(new Vector315(posOrX, yOrBlock, z), block);
14139
+ return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
14031
14140
  }
14032
14141
  if (isTripleArray(posOrX)) {
14033
- return this.setBlockAt(new Vector315(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
14142
+ return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
14034
14143
  }
14035
14144
  return this.placeBlock(posOrX, yOrBlock);
14036
14145
  }
@@ -14039,6 +14148,16 @@ var MineRenderWorld = class {
14039
14148
  const chunk = Chunk.isAir(value) ? this.getChunkAt(pos) : this.getOrCreateChunkAt(pos);
14040
14149
  return chunk?.setBlockInChunkAt(chunk.worldPosToChunkPos(pos), value, pos, onBlocksChanged);
14041
14150
  }
14151
+ async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
14152
+ if (typeof posOrX === "number") {
14153
+ return this.setBlockVisibleAt(new Vector316(posOrX, yOrVisible, z), visible);
14154
+ }
14155
+ if (isTripleArray(posOrX)) {
14156
+ return this.setBlockVisibleAt(new Vector316(...posOrX), yOrVisible);
14157
+ }
14158
+ this.validatePosBounds(posOrX);
14159
+ await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
14160
+ }
14042
14161
  async placeMultiBlock(multiblock, useBatches = true, executor) {
14043
14162
  const changes = /* @__PURE__ */ new Map();
14044
14163
  try {
@@ -14051,7 +14170,7 @@ var MineRenderWorld = class {
14051
14170
  const collect = async (positions2) => {
14052
14171
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
14053
14172
  };
14054
- const place = (block) => this.placeBlock(new Vector315(...block.position), block, collect);
14173
+ const place = (block) => this.placeBlock(new Vector316(...block.position), block, collect);
14055
14174
  const keys = /* @__PURE__ */ new Map();
14056
14175
  for (const block of multiblock.blocks) {
14057
14176
  if (Chunk.isAir(block)) continue;
@@ -14129,13 +14248,13 @@ var MineRenderWorld = class {
14129
14248
  for (const pos of positions) {
14130
14249
  this.pendingCulling.set(pos.toArray().join(","), pos.clone());
14131
14250
  for (const offset of CUBE_FACE_OFFSETS) {
14132
- const neighbor = pos.clone().add(new Vector315(...offset));
14251
+ const neighbor = pos.clone().add(new Vector316(...offset));
14133
14252
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
14134
14253
  }
14135
14254
  for (let y = -1; y <= 1; y++) {
14136
14255
  for (let z = -1; z <= 1; z++) {
14137
14256
  for (let x = -1; x <= 1; x++) {
14138
- const neighbor = pos.clone().add(new Vector315(x, y, z));
14257
+ const neighbor = pos.clone().add(new Vector316(x, y, z));
14139
14258
  if (this.getBlockAt(neighbor)?.object?.fluidKind) {
14140
14259
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
14141
14260
  }
@@ -14154,12 +14273,14 @@ var MineRenderWorld = class {
14154
14273
  if (!chunk) continue;
14155
14274
  changed.add(chunk);
14156
14275
  const block = chunk.getBlockAt(pos);
14157
- if (!block) continue;
14276
+ if (!block || !chunk.isBlockVisibleAt(pos)) {
14277
+ continue;
14278
+ }
14158
14279
  if (block.object?.fluidKind) {
14159
14280
  await block.object.updateFluid((x, y, z) => {
14160
- const neighbor = pos.clone().add(new Vector315(x, y, z));
14281
+ const neighbor = pos.clone().add(new Vector316(x, y, z));
14161
14282
  const section = this.getChunkAt(neighbor);
14162
- const object = section?.getBlockAt(neighbor)?.object;
14283
+ const object = section?.isBlockVisibleAt(neighbor) ? section.getBlockAt(neighbor)?.object : void 0;
14163
14284
  return {
14164
14285
  fluid: object?.fluidKind,
14165
14286
  level: object?.fluidLevel,
@@ -14169,7 +14290,7 @@ var MineRenderWorld = class {
14169
14290
  }
14170
14291
  let mask = 0;
14171
14292
  for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
14172
- const neighbor = pos.clone().add(new Vector315(...offset));
14293
+ const neighbor = pos.clone().add(new Vector316(...offset));
14173
14294
  if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
14174
14295
  mask |= 1 << face;
14175
14296
  }
@@ -14203,14 +14324,14 @@ var MineRenderWorld = class {
14203
14324
  return this._chunks.get(this.worldPosToChunkKey(pos));
14204
14325
  }
14205
14326
  static worldToScenePosition(pos) {
14206
- return new Vector315(
14327
+ return new Vector316(
14207
14328
  pos.x * 16,
14208
14329
  pos.y * 16,
14209
14330
  pos.z * 16
14210
14331
  );
14211
14332
  }
14212
14333
  static sceneToWorldPosition(pos) {
14213
- return new Vector315(
14334
+ return new Vector316(
14214
14335
  pos.x / 16,
14215
14336
  pos.y / 16,
14216
14337
  pos.z / 16
@@ -14346,6 +14467,7 @@ var Chunk = class _Chunk {
14346
14467
  this.data = new ChunkData();
14347
14468
  this.renderedBlocks = /* @__PURE__ */ new Map();
14348
14469
  this.sectionBlocks = /* @__PURE__ */ new Map();
14470
+ this.hiddenBlocks = /* @__PURE__ */ new Set();
14349
14471
  this.meshDirty = false;
14350
14472
  this.scene = scene;
14351
14473
  this.x = x;
@@ -14354,10 +14476,10 @@ var Chunk = class _Chunk {
14354
14476
  }
14355
14477
  getBlockAt(posOrX, y, z) {
14356
14478
  if (typeof posOrX == "number") {
14357
- return this.getBlockAt(new Vector316(posOrX, y, z));
14479
+ return this.getBlockAt(new Vector317(posOrX, y, z));
14358
14480
  }
14359
14481
  if (isTripleArray(posOrX)) {
14360
- return this.getBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]));
14482
+ return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
14361
14483
  }
14362
14484
  const pos = this.worldPosToChunkPos(posOrX);
14363
14485
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -14365,10 +14487,10 @@ var Chunk = class _Chunk {
14365
14487
  }
14366
14488
  async setBlockAt(posOrX, yOrBlock, z, block) {
14367
14489
  if (typeof posOrX == "number") {
14368
- return this.setBlockAt(new Vector316(posOrX, yOrBlock, z), block);
14490
+ return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
14369
14491
  }
14370
14492
  if (isTripleArray(posOrX)) {
14371
- return this.setBlockAt(new Vector316(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
14493
+ return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
14372
14494
  }
14373
14495
  const worldPos = posOrX;
14374
14496
  const pos = this.worldPosToChunkPos(worldPos);
@@ -14383,6 +14505,7 @@ var Chunk = class _Chunk {
14383
14505
  worldPos = this.chunkPosToWorldPos(pos);
14384
14506
  }
14385
14507
  const index = _Chunk.chunkPosToBlockIndex(pos);
14508
+ this.hiddenBlocks.delete(index);
14386
14509
  this.data.set(index, block);
14387
14510
  const readBlock = this.data.snapshot(index);
14388
14511
  this.renderedBlocks.get(index)?.object?.removeFromScene();
@@ -14424,9 +14547,31 @@ var Chunk = class _Chunk {
14424
14547
  await onBlocksChanged?.([worldPos]);
14425
14548
  }
14426
14549
  }
14550
+ async setBlockVisibleAt(pos, visible) {
14551
+ const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
14552
+ const block = this.renderedBlocks.get(index);
14553
+ if (!block || visible === !this.hiddenBlocks.has(index)) {
14554
+ return;
14555
+ }
14556
+ if (visible) {
14557
+ this.hiddenBlocks.delete(index);
14558
+ } else {
14559
+ this.hiddenBlocks.add(index);
14560
+ }
14561
+ block.object?.setVisible(visible);
14562
+ if (this.sectionBlocks.has(index)) {
14563
+ this.meshDirty = true;
14564
+ }
14565
+ this.scene.dirty = true;
14566
+ await this.onBlocksChanged?.([pos]);
14567
+ }
14568
+ isBlockVisibleAt(pos) {
14569
+ const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
14570
+ return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
14571
+ }
14427
14572
  isOccludingAt(pos) {
14428
14573
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
14429
- return this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false);
14574
+ return !this.hiddenBlocks.has(index) && (this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false));
14430
14575
  }
14431
14576
  async setCullMaskAt(pos, mask) {
14432
14577
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
@@ -14442,7 +14587,10 @@ var Chunk = class _Chunk {
14442
14587
  }
14443
14588
  rebuildSectionMesh() {
14444
14589
  if (!this.meshDirty) return;
14445
- const next = this.sectionBlocks.size ? SectionMesh.build([...this.sectionBlocks.values()], this.sectionModels.maxAtlasSize) : void 0;
14590
+ const next = this.sectionBlocks.size ? SectionMesh.build(
14591
+ [...this.sectionBlocks.values()].filter((entry) => !this.hiddenBlocks.has(entry.index)),
14592
+ this.sectionModels.maxAtlasSize
14593
+ ) : void 0;
14446
14594
  this.sectionMesh?.dispose();
14447
14595
  this.sectionMesh = next;
14448
14596
  if (next) {
@@ -14454,7 +14602,7 @@ var Chunk = class _Chunk {
14454
14602
  }
14455
14603
  async clear(onBlocksChanged = this.onBlocksChanged) {
14456
14604
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
14457
- new Vector316(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
14605
+ new Vector317(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
14458
14606
  ));
14459
14607
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
14460
14608
  this.sectionBlocks.clear();
@@ -14462,6 +14610,7 @@ var Chunk = class _Chunk {
14462
14610
  this.sectionMesh = void 0;
14463
14611
  this.meshDirty = false;
14464
14612
  this.renderedBlocks.clear();
14613
+ this.hiddenBlocks.clear();
14465
14614
  this.data.clear();
14466
14615
  await onBlocksChanged?.(positions);
14467
14616
  }
@@ -14478,14 +14627,14 @@ var Chunk = class _Chunk {
14478
14627
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
14479
14628
  }
14480
14629
  worldPosToChunkPos(pos) {
14481
- return new Vector316(
14630
+ return new Vector317(
14482
14631
  pos.x - this.x * 16,
14483
14632
  pos.y - this.y * 16,
14484
14633
  pos.z - this.z * 16
14485
14634
  );
14486
14635
  }
14487
14636
  chunkPosToWorldPos(pos) {
14488
- return new Vector316(
14637
+ return new Vector317(
14489
14638
  this.x * 16 + pos.x,
14490
14639
  this.y * 16 + pos.y,
14491
14640
  this.z * 16 + pos.z