minerender 2.1.0-alpha.37 → 2.1.0-alpha.38

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.
@@ -144,6 +144,7 @@ __export(index_browser_exports, {
144
144
  BrowserCache: () => BrowserCache,
145
145
  BrowserEnv: () => BrowserEnv,
146
146
  CUBE_FACES: () => CUBE_FACES,
147
+ CUBE_FACE_OFFSETS: () => CUBE_FACE_OFFSETS,
147
148
  Caching: () => Caching,
148
149
  CanvasImage: () => CanvasImage,
149
150
  Chunk: () => Chunk,
@@ -177,6 +178,7 @@ __export(index_browser_exports, {
177
178
  MineRenderWorld: () => MineRenderWorld,
178
179
  MinecraftCubeTexture: () => MinecraftCubeTexture,
179
180
  MinecraftFaceUV: () => MinecraftFaceUV,
181
+ ModelCulling: () => ModelCulling,
180
182
  ModelGenerator: () => ModelGenerator,
181
183
  ModelMerger: () => ModelMerger,
182
184
  ModelObject: () => ModelObject,
@@ -474,6 +476,14 @@ var CubeFaceIndex = /* @__PURE__ */ ((CubeFaceIndex2) => {
474
476
  return CubeFaceIndex2;
475
477
  })(CubeFaceIndex || {});
476
478
  var CUBE_FACES = Object.values(CubeFace);
479
+ var CUBE_FACE_OFFSETS = [
480
+ [1, 0, 0],
481
+ [-1, 0, 0],
482
+ [0, 1, 0],
483
+ [0, -1, 0],
484
+ [0, 0, 1],
485
+ [0, 0, -1]
486
+ ];
477
487
 
478
488
  // src/Disposable.ts
479
489
  function isDisposable(obj) {
@@ -3962,6 +3972,42 @@ function isQuadArray(obj) {
3962
3972
  return Array.isArray(obj) && obj.length === 4;
3963
3973
  }
3964
3974
 
3975
+ // src/model/ModelCulling.ts
3976
+ var import_three16 = require("three");
3977
+ var ModelCulling = class {
3978
+ static toLocalMask(worldMask, rotation) {
3979
+ let localMask = 0;
3980
+ for (const [localFace, offset] of CUBE_FACE_OFFSETS.entries()) {
3981
+ const normal = new import_three16.Vector3(...offset).applyEuler(rotation);
3982
+ 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);
3983
+ if (worldFace < 0) return 0;
3984
+ if (worldMask & 1 << worldFace) localMask |= 1 << localFace;
3985
+ }
3986
+ return localMask;
3987
+ }
3988
+ static isOpaqueFullCube(atlas) {
3989
+ if (!atlas || atlas.hasTransparency !== false || atlas.model.elements?.length !== 1) return false;
3990
+ const element = atlas.model.elements[0];
3991
+ if (element.from.length !== 3 || !element.from.every((value) => value === 0) || element.to.length !== 3 || !element.to.every((value) => value === 16) || element.rotation && element.rotation.angle !== 0 || element.mappedUv?.length !== 48 || !element.mappedUv.every(Number.isFinite)) return false;
3992
+ if (!(atlas.image.width > 0 && atlas.image.height > 0)) return false;
3993
+ return CUBE_FACES.every((face, faceIndex) => {
3994
+ const texture = element.faces[face]?.texture;
3995
+ if (!texture?.startsWith("#")) return false;
3996
+ const key = texture.slice(1);
3997
+ const position = atlas.positions[key];
3998
+ const size = atlas.sizes[key];
3999
+ if (position?.length !== 2 || !position.every(Number.isFinite) || size?.length !== 2 || !size.every((value) => value > 0 && Number.isFinite(value))) return false;
4000
+ for (let vertex = 0; vertex < 4; vertex++) {
4001
+ const uvIndex = (faceIndex * 4 + vertex) * 2;
4002
+ const x = element.mappedUv[uvIndex] * atlas.image.width;
4003
+ const y = (1 - element.mappedUv[uvIndex + 1]) * atlas.image.height;
4004
+ if (x < position[0] - 1e-6 || x > position[0] + size[0] + 1e-6 || y < position[1] - 1e-6 || y > position[1] + size[1] + 1e-6) return false;
4005
+ }
4006
+ return true;
4007
+ });
4008
+ }
4009
+ };
4010
+
3965
4011
  // src/model/block/blockTints.json
3966
4012
  var blockTints_default = {
3967
4013
  "minecraft:large_fern": { source: "grass" },
@@ -4048,10 +4094,10 @@ var BlockTints = class {
4048
4094
  };
4049
4095
 
4050
4096
  // src/model/scene/ModelObject.ts
4051
- var import_three17 = require("three");
4097
+ var import_three18 = require("three");
4052
4098
 
4053
4099
  // src/three/BufferGeometryUtils.js
4054
- var import_three16 = require("three");
4100
+ var import_three17 = require("three");
4055
4101
  function computeTangents(geometry) {
4056
4102
  geometry.computeTangents();
4057
4103
  console.warn("THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.");
@@ -4063,7 +4109,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
4063
4109
  const attributes = {};
4064
4110
  const morphAttributes = {};
4065
4111
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
4066
- const mergedGeometry = new import_three16.BufferGeometry();
4112
+ const mergedGeometry = new import_three17.BufferGeometry();
4067
4113
  let offset = 0;
4068
4114
  for (let i = 0; i < geometries.length; ++i) {
4069
4115
  const geometry = geometries[i];
@@ -4187,7 +4233,7 @@ function mergeBufferAttributes(attributes) {
4187
4233
  array.set(attributes[i].array, offset);
4188
4234
  offset += attributes[i].array.length;
4189
4235
  }
4190
- return new import_three16.BufferAttribute(array, itemSize, normalized);
4236
+ return new import_three17.BufferAttribute(array, itemSize, normalized);
4191
4237
  }
4192
4238
  function interleaveAttributes(attributes) {
4193
4239
  let TypedArray;
@@ -4203,7 +4249,7 @@ function interleaveAttributes(attributes) {
4203
4249
  arrayLength += attribute.array.length;
4204
4250
  stride += attribute.itemSize;
4205
4251
  }
4206
- const interleavedBuffer = new import_three16.InterleavedBuffer(new TypedArray(arrayLength), stride);
4252
+ const interleavedBuffer = new import_three17.InterleavedBuffer(new TypedArray(arrayLength), stride);
4207
4253
  let offset = 0;
4208
4254
  const res = [];
4209
4255
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -4212,7 +4258,7 @@ function interleaveAttributes(attributes) {
4212
4258
  const attribute = attributes[j];
4213
4259
  const itemSize = attribute.itemSize;
4214
4260
  const count = attribute.count;
4215
- const iba = new import_three16.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
4261
+ const iba = new import_three17.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
4216
4262
  res.push(iba);
4217
4263
  offset += itemSize;
4218
4264
  for (let c = 0; c < count; c++) {
@@ -4296,13 +4342,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
4296
4342
  const name = attributeNames[i];
4297
4343
  const oldAttribute = geometry.getAttribute(name);
4298
4344
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
4299
- const attribute = new import_three16.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
4345
+ const attribute = new import_three17.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
4300
4346
  result.setAttribute(name, attribute);
4301
4347
  if (name in morphAttrsArrays) {
4302
4348
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
4303
4349
  const oldMorphAttribute = geometry.morphAttributes[name][j];
4304
4350
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
4305
- const morphAttribute = new import_three16.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
4351
+ const morphAttribute = new import_three17.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
4306
4352
  result.morphAttributes[name][j] = morphAttribute;
4307
4353
  }
4308
4354
  }
@@ -4311,11 +4357,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
4311
4357
  return result;
4312
4358
  }
4313
4359
  function toTrianglesDrawMode(geometry, drawMode) {
4314
- if (drawMode === import_three16.TrianglesDrawMode) {
4360
+ if (drawMode === import_three17.TrianglesDrawMode) {
4315
4361
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
4316
4362
  return geometry;
4317
4363
  }
4318
- if (drawMode === import_three16.TriangleFanDrawMode || drawMode === import_three16.TriangleStripDrawMode) {
4364
+ if (drawMode === import_three17.TriangleFanDrawMode || drawMode === import_three17.TriangleStripDrawMode) {
4319
4365
  let index = geometry.getIndex();
4320
4366
  if (index === null) {
4321
4367
  const indices = [];
@@ -4333,7 +4379,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
4333
4379
  }
4334
4380
  const numberOfTriangles = index.count - 2;
4335
4381
  const newIndices = [];
4336
- if (drawMode === import_three16.TriangleFanDrawMode) {
4382
+ if (drawMode === import_three17.TriangleFanDrawMode) {
4337
4383
  for (let i = 1; i <= numberOfTriangles; i++) {
4338
4384
  newIndices.push(index.getX(0));
4339
4385
  newIndices.push(index.getX(i));
@@ -4369,15 +4415,15 @@ function computeMorphedAttributes(object) {
4369
4415
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
4370
4416
  return null;
4371
4417
  }
4372
- const _vA = new import_three16.Vector3();
4373
- const _vB = new import_three16.Vector3();
4374
- const _vC = new import_three16.Vector3();
4375
- const _tempA = new import_three16.Vector3();
4376
- const _tempB = new import_three16.Vector3();
4377
- const _tempC = new import_three16.Vector3();
4378
- const _morphA = new import_three16.Vector3();
4379
- const _morphB = new import_three16.Vector3();
4380
- const _morphC = new import_three16.Vector3();
4418
+ const _vA = new import_three17.Vector3();
4419
+ const _vB = new import_three17.Vector3();
4420
+ const _vC = new import_three17.Vector3();
4421
+ const _tempA = new import_three17.Vector3();
4422
+ const _tempB = new import_three17.Vector3();
4423
+ const _tempC = new import_three17.Vector3();
4424
+ const _morphA = new import_three17.Vector3();
4425
+ const _morphB = new import_three17.Vector3();
4426
+ const _morphC = new import_three17.Vector3();
4381
4427
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
4382
4428
  _vA.fromBufferAttribute(attribute, a2);
4383
4429
  _vB.fromBufferAttribute(attribute, b2);
@@ -4572,8 +4618,8 @@ function computeMorphedAttributes(object) {
4572
4618
  }
4573
4619
  }
4574
4620
  }
4575
- const morphedPositionAttribute = new import_three16.Float32BufferAttribute(modifiedPosition, 3);
4576
- const morphedNormalAttribute = new import_three16.Float32BufferAttribute(modifiedNormal, 3);
4621
+ const morphedPositionAttribute = new import_three17.Float32BufferAttribute(modifiedPosition, 3);
4622
+ const morphedNormalAttribute = new import_three17.Float32BufferAttribute(modifiedNormal, 3);
4577
4623
  return {
4578
4624
  positionAttribute,
4579
4625
  normalAttribute,
@@ -4603,6 +4649,9 @@ var _ModelObject = class _ModelObject extends SceneObject {
4603
4649
  get textureAtlas() {
4604
4650
  return this.atlas;
4605
4651
  }
4652
+ get isOpaqueFullCube() {
4653
+ return !this.options.displayPosition && ModelCulling.isOpaqueFullCube(this.atlas);
4654
+ }
4606
4655
  //TODO: support for replacing textures
4607
4656
  async loadTextures() {
4608
4657
  this.atlas = await UVMapper.getAtlas(this.originalModel);
@@ -4616,8 +4665,17 @@ var _ModelObject = class _ModelObject extends SceneObject {
4616
4665
  if (this.atlas.model.elements) {
4617
4666
  this.atlas.model.elements?.forEach((el) => {
4618
4667
  const elGeo = this._getBoxGeometryFromElement(el).clone();
4668
+ if (this.options.cullMask) {
4669
+ const indices = Array.from(elGeo.getIndex().array);
4670
+ elGeo.setIndex(indices.filter((_, index) => {
4671
+ const face = CUBE_FACES[Math.floor(index / 6)];
4672
+ const direction = CUBE_FACES.findIndex((name) => name === el.faces[face]?.cullface);
4673
+ return direction < 0 || !(this.options.cullMask & 1 << direction);
4674
+ }));
4675
+ elGeo.clearGroups();
4676
+ }
4619
4677
  if (this.options.uvLockRotation) {
4620
- UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three17.Euler(...this.options.uvLockRotation));
4678
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three18.Euler(...this.options.uvLockRotation));
4621
4679
  }
4622
4680
  if (this.options.tints) {
4623
4681
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
@@ -4626,19 +4684,19 @@ var _ModelObject = class _ModelObject extends SceneObject {
4626
4684
  if (tintIndex === void 0 || tintIndex < 0) continue;
4627
4685
  const tint = this.options.tints[tintIndex];
4628
4686
  if (tint === void 0) continue;
4629
- const color = new import_three17.Color(tint);
4687
+ const color = new import_three18.Color(tint);
4630
4688
  for (let vertex = 0; vertex < 4; vertex++) {
4631
4689
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4632
4690
  }
4633
4691
  }
4634
- elGeo.setAttribute("color", new import_three17.BufferAttribute(colors, 3));
4692
+ elGeo.setAttribute("color", new import_three18.BufferAttribute(colors, 3));
4635
4693
  }
4636
- elGeo.applyMatrix4(new import_three17.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4637
- elGeo.applyMatrix4(new import_three17.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4694
+ elGeo.applyMatrix4(new import_three18.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4695
+ elGeo.applyMatrix4(new import_three18.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4638
4696
  if (el.rotation) {
4639
4697
  applyElementRotation(el.rotation, elGeo);
4640
4698
  }
4641
- elGeo.applyMatrix4(new import_three17.Matrix4().makeTranslation(-8, -8, -8));
4699
+ elGeo.applyMatrix4(new import_three18.Matrix4().makeTranslation(-8, -8, -8));
4642
4700
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4643
4701
  if (this.options.mergeMeshes) {
4644
4702
  allGeos.push(elGeo);
@@ -4660,7 +4718,7 @@ var _ModelObject = class _ModelObject extends SceneObject {
4660
4718
  if (allGeos.length > 0) {
4661
4719
  combinedGeo = mergeBufferGeometries(allGeos);
4662
4720
  } else {
4663
- combinedGeo = new import_three17.BoxGeometry(16, 16, 16);
4721
+ combinedGeo = new import_three18.BoxGeometry(16, 16, 16);
4664
4722
  if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4665
4723
  }
4666
4724
  combinedGeo.computeBoundingBox();
@@ -4715,7 +4773,7 @@ function isModelObject(obj) {
4715
4773
 
4716
4774
  // src/model/block/scene/BlockObject.ts
4717
4775
  var import_ts_deepmerge6 = __toESM(require_dist());
4718
- var import_three18 = require("three");
4776
+ var import_three19 = require("three");
4719
4777
  var p10 = prefix("BlockObject");
4720
4778
  function matchesCondition(condition, state) {
4721
4779
  return Object.entries(condition).every(([key, value]) => {
@@ -4740,6 +4798,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4740
4798
  this._instanceModel = [];
4741
4799
  this._variants = [];
4742
4800
  this._models = [];
4801
+ this._cullMask = 0;
4743
4802
  this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
4744
4803
  }
4745
4804
  async init() {
@@ -4773,12 +4832,69 @@ var _BlockObject = class _BlockObject extends SceneObject {
4773
4832
  super.removeFromScene();
4774
4833
  }
4775
4834
  clearModels() {
4776
- for (const model of this._models.splice(0)) {
4835
+ this.removeModels(this._models.splice(0));
4836
+ this._isInstanced = false;
4837
+ this._instanceCounter = 0;
4838
+ }
4839
+ removeModels(models) {
4840
+ for (const model of models) {
4777
4841
  model.removeFromScene();
4778
4842
  if (!isInstanceReference(model)) model.dispose();
4779
4843
  }
4780
- this._isInstanced = false;
4781
- this._instanceCounter = 0;
4844
+ }
4845
+ get isOccluding() {
4846
+ return this._models.some((model) => {
4847
+ const object = isInstanceReference(model) ? model.instanceable : model;
4848
+ return object.isOpaqueFullCube && this.getModelCullMask(model, 63) === 63;
4849
+ });
4850
+ }
4851
+ getModelMatrix(model) {
4852
+ if (isInstanceReference(model)) return model.getMatrix();
4853
+ if (model.matrixAutoUpdate) model.updateMatrix();
4854
+ return model.matrix.clone();
4855
+ }
4856
+ getModelCullMask(model, worldMask) {
4857
+ const object = isInstanceReference(model) ? model.instanceable : model;
4858
+ if (object.options.displayPosition) return 0;
4859
+ const position = new import_three19.Vector3();
4860
+ const rotation = new import_three19.Quaternion();
4861
+ const scale = new import_three19.Vector3();
4862
+ this.getModelMatrix(model).decompose(position, rotation, scale);
4863
+ if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new import_three19.Vector3(1, 1, 1)) > 1e-10) return 0;
4864
+ return ModelCulling.toLocalMask(worldMask, new import_three19.Euler().setFromQuaternion(rotation));
4865
+ }
4866
+ async setCullMask(worldMask) {
4867
+ worldMask &= 63;
4868
+ const replacements = [];
4869
+ try {
4870
+ for (const model of this._models) {
4871
+ const object = isInstanceReference(model) ? model.instanceable : model;
4872
+ const cullMask = this.getModelCullMask(model, worldMask);
4873
+ if (cullMask === (object.options.cullMask ?? 0)) {
4874
+ replacements.push(model);
4875
+ continue;
4876
+ }
4877
+ const matrix = this.getModelMatrix(model);
4878
+ const replacement = await this.scene.addModel(object.originalModel, { ...object.options, cullMask });
4879
+ replacements.push(replacement);
4880
+ if (isInstanceReference(replacement)) {
4881
+ replacement.setMatrix(matrix);
4882
+ } else {
4883
+ replacement.matrix.copy(matrix);
4884
+ matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
4885
+ replacement.matrixAutoUpdate = object.matrixAutoUpdate;
4886
+ replacement.visible = object.visible;
4887
+ }
4888
+ }
4889
+ } catch (error) {
4890
+ this.removeModels(replacements.filter((model) => !this._models.includes(model)));
4891
+ throw error;
4892
+ }
4893
+ const previous = this._models;
4894
+ this._models = replacements;
4895
+ this._cullMask = worldMask;
4896
+ this.removeModels(previous.filter((model) => !replacements.includes(model)));
4897
+ this.notifyDirty();
4782
4898
  }
4783
4899
  get state() {
4784
4900
  return this._state;
@@ -4858,7 +4974,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4858
4974
  await this.createVariant(variant);
4859
4975
  }
4860
4976
  async createVariant(variant) {
4861
- const rotation = new import_three18.Euler();
4977
+ const rotation = new import_three19.Euler();
4862
4978
  if (typeof variant.x !== "undefined") {
4863
4979
  rotation.x = toRadians(clampRotationDegrees(variant.x));
4864
4980
  }
@@ -4871,7 +4987,8 @@ var _BlockObject = class _BlockObject extends SceneObject {
4871
4987
  const options = {
4872
4988
  ...this.options,
4873
4989
  tints: model ? await BlockTints.get(this.blockState.key, this.state, model, this.options.tints) : this.options.tints,
4874
- uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
4990
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0,
4991
+ cullMask: this.options.displayPosition ? 0 : ModelCulling.toLocalMask(this._cullMask, rotation)
4875
4992
  };
4876
4993
  const obj = await this.scene.addModel(model, options);
4877
4994
  if (isInstanceReference(obj) || obj.isInstanced) {
@@ -4948,7 +5065,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
4948
5065
  setPositionRotationScaleAt(index, position, rotation, scale) {
4949
5066
  super.setPositionRotationScaleAt(index, position, rotation, scale);
4950
5067
  }
4951
- getMatrixAt(index, matrix = new import_three18.Matrix4()) {
5068
+ getMatrixAt(index, matrix = new import_three19.Matrix4()) {
4952
5069
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
4953
5070
  const child = this._models[0];
4954
5071
  if (child && isModelObject(child)) {
@@ -5027,7 +5144,7 @@ var StructureParser = class {
5027
5144
  };
5028
5145
 
5029
5146
  // src/renderer/MineRenderScene.ts
5030
- var import_three20 = require("three");
5147
+ var import_three21 = require("three");
5031
5148
  var import_ts_deepmerge8 = __toESM(require_dist());
5032
5149
 
5033
5150
  // src/skin/SkinPart.ts
@@ -5752,7 +5869,7 @@ var slimSkinGeometries = {
5752
5869
  var import_ts_deepmerge7 = __toESM(require_dist());
5753
5870
 
5754
5871
  // src/skin/SkinTextures.ts
5755
- var import_three19 = require("three");
5872
+ var import_three20 = require("three");
5756
5873
 
5757
5874
  // src/skin/SkinImage.ts
5758
5875
  var SkinImage = class {
@@ -5829,11 +5946,11 @@ var SkinTextures = class {
5829
5946
  });
5830
5947
  }
5831
5948
  static createMaterial(pixels, width, height, transparent = true) {
5832
- const texture = Textures.initTextureProps(new import_three19.DataTexture(pixels, width, height));
5833
- texture.colorSpace = import_three19.SRGBColorSpace;
5949
+ const texture = Textures.initTextureProps(new import_three20.DataTexture(pixels, width, height));
5950
+ texture.colorSpace = import_three20.SRGBColorSpace;
5834
5951
  texture.flipY = true;
5835
5952
  texture.needsUpdate = true;
5836
- return new import_three19.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three19.DoubleSide : import_three19.FrontSide, alphaTest: transparent ? 0.1 : 0 });
5953
+ return new import_three20.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three20.DoubleSide : import_three20.FrontSide, alphaTest: transparent ? 0.1 : 0 });
5837
5954
  }
5838
5955
  static isSlim(image, scale) {
5839
5956
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -6060,7 +6177,7 @@ var SkinObject = class extends SceneObject {
6060
6177
  };
6061
6178
 
6062
6179
  // src/renderer/MineRenderScene.ts
6063
- var _MineRenderScene = class _MineRenderScene extends import_three20.Scene {
6180
+ var _MineRenderScene = class _MineRenderScene extends import_three21.Scene {
6064
6181
  constructor(options) {
6065
6182
  super();
6066
6183
  this.isMineRenderScene = true;
@@ -6133,11 +6250,12 @@ var _MineRenderScene = class _MineRenderScene extends import_three20.Scene {
6133
6250
  console.log("instanceMeshes + key");
6134
6251
  let key = asset.key.serialize();
6135
6252
  if (isModelObject(obj)) {
6136
- const { displayPosition, uvLockRotation, tints } = obj.options;
6253
+ const { displayPosition, uvLockRotation, tints, cullMask } = obj.options;
6137
6254
  if (displayPosition) key += `|display:${displayPosition}`;
6138
6255
  if (uvLockRotation) key += `|uvlock:${uvLockRotation.join(",")}`;
6139
6256
  const palette = Object.entries(tints ?? {}).sort(([a], [b]) => Number(a) - Number(b));
6140
6257
  if (palette.length) key += `|tints:${JSON.stringify(palette)}`;
6258
+ if (cullMask) key += `|cull:${cullMask}`;
6141
6259
  }
6142
6260
  return this.instanceManager.getOrCreate(key, async () => {
6143
6261
  obj.scene = this;
@@ -6183,17 +6301,17 @@ function isMineRenderScene(obj) {
6183
6301
  }
6184
6302
 
6185
6303
  // src/renderer/Renderer.ts
6186
- var import_three22 = require("three");
6304
+ var import_three23 = require("three");
6187
6305
  var import_ts_deepmerge9 = __toESM(require_dist());
6188
6306
  var import_stats = __toESM(require("stats.js"));
6189
6307
  var import_postprocessing = require("postprocessing");
6190
6308
 
6191
6309
  // src/three/OrbitControls.js
6192
- var import_three21 = require("three");
6310
+ var import_three22 = require("three");
6193
6311
  var _changeEvent = { type: "change" };
6194
6312
  var _startEvent = { type: "start" };
6195
6313
  var _endEvent = { type: "end" };
6196
- var OrbitControls = class extends import_three21.EventDispatcher {
6314
+ var OrbitControls = class extends import_three22.EventDispatcher {
6197
6315
  constructor(object, domElement) {
6198
6316
  super();
6199
6317
  if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
@@ -6202,7 +6320,7 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6202
6320
  this.domElement = domElement;
6203
6321
  this.domElement.style.touchAction = "none";
6204
6322
  this.enabled = true;
6205
- this.target = new import_three21.Vector3();
6323
+ this.target = new import_three22.Vector3();
6206
6324
  this.minDistance = 0;
6207
6325
  this.maxDistance = Infinity;
6208
6326
  this.minZoom = 0;
@@ -6224,8 +6342,8 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6224
6342
  this.autoRotate = false;
6225
6343
  this.autoRotateSpeed = 2;
6226
6344
  this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
6227
- this.mouseButtons = { LEFT: import_three21.MOUSE.ROTATE, MIDDLE: import_three21.MOUSE.DOLLY, RIGHT: import_three21.MOUSE.PAN };
6228
- this.touches = { ONE: import_three21.TOUCH.ROTATE, TWO: import_three21.TOUCH.DOLLY_PAN };
6345
+ this.mouseButtons = { LEFT: import_three22.MOUSE.ROTATE, MIDDLE: import_three22.MOUSE.DOLLY, RIGHT: import_three22.MOUSE.PAN };
6346
+ this.touches = { ONE: import_three22.TOUCH.ROTATE, TWO: import_three22.TOUCH.DOLLY_PAN };
6229
6347
  this.target0 = this.target.clone();
6230
6348
  this.position0 = this.object.position.clone();
6231
6349
  this.zoom0 = this.object.zoom;
@@ -6254,11 +6372,11 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6254
6372
  state = STATE.NONE;
6255
6373
  };
6256
6374
  this.update = function() {
6257
- const offset = new import_three21.Vector3();
6258
- const quat = new import_three21.Quaternion().setFromUnitVectors(object.up, new import_three21.Vector3(0, 1, 0));
6375
+ const offset = new import_three22.Vector3();
6376
+ const quat = new import_three22.Quaternion().setFromUnitVectors(object.up, new import_three22.Vector3(0, 1, 0));
6259
6377
  const quatInverse = quat.clone().invert();
6260
- const lastPosition = new import_three21.Vector3();
6261
- const lastQuaternion = new import_three21.Quaternion();
6378
+ const lastPosition = new import_three22.Vector3();
6379
+ const lastQuaternion = new import_three22.Quaternion();
6262
6380
  const twoPI = 2 * Math.PI;
6263
6381
  return function update() {
6264
6382
  const position = scope.object.position;
@@ -6344,20 +6462,20 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6344
6462
  };
6345
6463
  let state = STATE.NONE;
6346
6464
  const EPS = 1e-6;
6347
- const spherical = new import_three21.Spherical();
6348
- const sphericalDelta = new import_three21.Spherical();
6465
+ const spherical = new import_three22.Spherical();
6466
+ const sphericalDelta = new import_three22.Spherical();
6349
6467
  let scale = 1;
6350
- const panOffset = new import_three21.Vector3();
6468
+ const panOffset = new import_three22.Vector3();
6351
6469
  let zoomChanged = false;
6352
- const rotateStart = new import_three21.Vector2();
6353
- const rotateEnd = new import_three21.Vector2();
6354
- const rotateDelta = new import_three21.Vector2();
6355
- const panStart = new import_three21.Vector2();
6356
- const panEnd = new import_three21.Vector2();
6357
- const panDelta = new import_three21.Vector2();
6358
- const dollyStart = new import_three21.Vector2();
6359
- const dollyEnd = new import_three21.Vector2();
6360
- const dollyDelta = new import_three21.Vector2();
6470
+ const rotateStart = new import_three22.Vector2();
6471
+ const rotateEnd = new import_three22.Vector2();
6472
+ const rotateDelta = new import_three22.Vector2();
6473
+ const panStart = new import_three22.Vector2();
6474
+ const panEnd = new import_three22.Vector2();
6475
+ const panDelta = new import_three22.Vector2();
6476
+ const dollyStart = new import_three22.Vector2();
6477
+ const dollyEnd = new import_three22.Vector2();
6478
+ const dollyDelta = new import_three22.Vector2();
6361
6479
  const pointers = [];
6362
6480
  const pointerPositions = {};
6363
6481
  function getAutoRotationAngle() {
@@ -6373,7 +6491,7 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6373
6491
  sphericalDelta.phi -= angle;
6374
6492
  }
6375
6493
  const panLeft = function() {
6376
- const v = new import_three21.Vector3();
6494
+ const v = new import_three22.Vector3();
6377
6495
  return function panLeft2(distance, objectMatrix) {
6378
6496
  v.setFromMatrixColumn(objectMatrix, 0);
6379
6497
  v.multiplyScalar(-distance);
@@ -6381,7 +6499,7 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6381
6499
  };
6382
6500
  }();
6383
6501
  const panUp = function() {
6384
- const v = new import_three21.Vector3();
6502
+ const v = new import_three22.Vector3();
6385
6503
  return function panUp2(distance, objectMatrix) {
6386
6504
  if (scope.screenSpacePanning === true) {
6387
6505
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -6394,7 +6512,7 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6394
6512
  };
6395
6513
  }();
6396
6514
  const pan = function() {
6397
- const offset = new import_three21.Vector3();
6515
+ const offset = new import_three22.Vector3();
6398
6516
  return function pan2(deltaX, deltaY) {
6399
6517
  const element = scope.domElement;
6400
6518
  if (scope.object.isPerspectiveCamera) {
@@ -6643,12 +6761,12 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6643
6761
  mouseAction = -1;
6644
6762
  }
6645
6763
  switch (mouseAction) {
6646
- case import_three21.MOUSE.DOLLY:
6764
+ case import_three22.MOUSE.DOLLY:
6647
6765
  if (scope.enableZoom === false) return;
6648
6766
  handleMouseDownDolly(event);
6649
6767
  state = STATE.DOLLY;
6650
6768
  break;
6651
- case import_three21.MOUSE.ROTATE:
6769
+ case import_three22.MOUSE.ROTATE:
6652
6770
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6653
6771
  if (scope.enablePan === false) return;
6654
6772
  handleMouseDownPan(event);
@@ -6659,7 +6777,7 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6659
6777
  state = STATE.ROTATE;
6660
6778
  }
6661
6779
  break;
6662
- case import_three21.MOUSE.PAN:
6780
+ case import_three22.MOUSE.PAN:
6663
6781
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
6664
6782
  if (scope.enableRotate === false) return;
6665
6783
  handleMouseDownRotate(event);
@@ -6715,12 +6833,12 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6715
6833
  switch (pointers.length) {
6716
6834
  case 1:
6717
6835
  switch (scope.touches.ONE) {
6718
- case import_three21.TOUCH.ROTATE:
6836
+ case import_three22.TOUCH.ROTATE:
6719
6837
  if (scope.enableRotate === false) return;
6720
6838
  handleTouchStartRotate();
6721
6839
  state = STATE.TOUCH_ROTATE;
6722
6840
  break;
6723
- case import_three21.TOUCH.PAN:
6841
+ case import_three22.TOUCH.PAN:
6724
6842
  if (scope.enablePan === false) return;
6725
6843
  handleTouchStartPan();
6726
6844
  state = STATE.TOUCH_PAN;
@@ -6731,12 +6849,12 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6731
6849
  break;
6732
6850
  case 2:
6733
6851
  switch (scope.touches.TWO) {
6734
- case import_three21.TOUCH.DOLLY_PAN:
6852
+ case import_three22.TOUCH.DOLLY_PAN:
6735
6853
  if (scope.enableZoom === false && scope.enablePan === false) return;
6736
6854
  handleTouchStartDollyPan();
6737
6855
  state = STATE.TOUCH_DOLLY_PAN;
6738
6856
  break;
6739
- case import_three21.TOUCH.DOLLY_ROTATE:
6857
+ case import_three22.TOUCH.DOLLY_ROTATE:
6740
6858
  if (scope.enableZoom === false && scope.enableRotate === false) return;
6741
6859
  handleTouchStartDollyRotate();
6742
6860
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -6803,7 +6921,7 @@ var OrbitControls = class extends import_three21.EventDispatcher {
6803
6921
  function trackPointer(event) {
6804
6922
  let position = pointerPositions[event.pointerId];
6805
6923
  if (position === void 0) {
6806
- position = new import_three21.Vector2();
6924
+ position = new import_three22.Vector2();
6807
6925
  pointerPositions[event.pointerId] = position;
6808
6926
  }
6809
6927
  position.set(event.pageX, event.pageY);
@@ -6823,10 +6941,10 @@ var MapControls = class extends OrbitControls {
6823
6941
  constructor(object, domElement) {
6824
6942
  super(object, domElement);
6825
6943
  this.screenSpacePanning = false;
6826
- this.mouseButtons.LEFT = import_three21.MOUSE.PAN;
6827
- this.mouseButtons.RIGHT = import_three21.MOUSE.ROTATE;
6828
- this.touches.ONE = import_three21.TOUCH.PAN;
6829
- this.touches.TWO = import_three21.TOUCH.DOLLY_ROTATE;
6944
+ this.mouseButtons.LEFT = import_three22.MOUSE.PAN;
6945
+ this.mouseButtons.RIGHT = import_three22.MOUSE.ROTATE;
6946
+ this.touches.ONE = import_three22.TOUCH.PAN;
6947
+ this.touches.TWO = import_three22.TOUCH.DOLLY_ROTATE;
6830
6948
  }
6831
6949
  };
6832
6950
 
@@ -6863,14 +6981,14 @@ var _Renderer = class _Renderer {
6863
6981
  switch (this.options.camera.type) {
6864
6982
  case "perspective":
6865
6983
  default:
6866
- return new import_three22.PerspectiveCamera(
6984
+ return new import_three23.PerspectiveCamera(
6867
6985
  this.options.camera.perspective.fov,
6868
6986
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
6869
6987
  this.options.camera.near,
6870
6988
  this.options.camera.far
6871
6989
  );
6872
6990
  case "orthographic":
6873
- return new import_three22.OrthographicCamera(
6991
+ return new import_three23.OrthographicCamera(
6874
6992
  this.options.camera.orthographic.left ?? this.viewWidth / -2,
6875
6993
  this.options.camera.orthographic.right ?? this.viewWidth / 2,
6876
6994
  this.options.camera.orthographic.top ?? this.viewHeight / 2,
@@ -6881,7 +6999,7 @@ var _Renderer = class _Renderer {
6881
6999
  }
6882
7000
  }
6883
7001
  createRenderer() {
6884
- const renderer = new import_three22.WebGLRenderer({
7002
+ const renderer = new import_three23.WebGLRenderer({
6885
7003
  antialias: this.options.render.antialias,
6886
7004
  alpha: true,
6887
7005
  powerPreference: "high-performance",
@@ -6889,8 +7007,8 @@ var _Renderer = class _Renderer {
6889
7007
  });
6890
7008
  renderer.setClearColor(0, 0);
6891
7009
  renderer.shadowMap.enabled = true;
6892
- renderer.shadowMap.type = import_three22.PCFSoftShadowMap;
6893
- renderer.outputColorSpace = import_three22.SRGBColorSpace;
7010
+ renderer.shadowMap.type = import_three23.PCFSoftShadowMap;
7011
+ renderer.outputColorSpace = import_three23.SRGBColorSpace;
6894
7012
  renderer.setSize(this.viewWidth, this.viewHeight);
6895
7013
  return renderer;
6896
7014
  }
@@ -6924,20 +7042,20 @@ var _Renderer = class _Renderer {
6924
7042
  window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
6925
7043
  }
6926
7044
  if (this.options.debug.grid) {
6927
- const gridHelper = new import_three22.GridHelper(128, 16);
7045
+ const gridHelper = new import_three23.GridHelper(128, 16);
6928
7046
  this._debugHelpers.push(gridHelper);
6929
7047
  this.scene.add(gridHelper);
6930
- const gridHelper2 = new import_three22.GridHelper(128, 16);
7048
+ const gridHelper2 = new import_three23.GridHelper(128, 16);
6931
7049
  this._debugHelpers.push(gridHelper2);
6932
7050
  gridHelper2.rotation.x = 90 * (Math.PI / 180);
6933
7051
  this.scene.add(gridHelper2);
6934
- const gridHelper3 = new import_three22.GridHelper(128, 16);
7052
+ const gridHelper3 = new import_three23.GridHelper(128, 16);
6935
7053
  this._debugHelpers.push(gridHelper3);
6936
7054
  gridHelper3.rotation.z = 90 * (Math.PI / 180);
6937
7055
  this.scene.add(gridHelper3);
6938
7056
  }
6939
7057
  if (this.options.debug.axes) {
6940
- const axesHelper = new import_three22.AxesHelper(64);
7058
+ const axesHelper = new import_three23.AxesHelper(64);
6941
7059
  this._debugHelpers.push(axesHelper);
6942
7060
  this.scene.add(axesHelper);
6943
7061
  }
@@ -7141,8 +7259,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
7141
7259
  top: void 0,
7142
7260
  bottom: void 0
7143
7261
  },
7144
- position: new import_three22.Vector3(50, 50, 50),
7145
- lookingAt: new import_three22.Vector3(0, 0, 0)
7262
+ position: new import_three23.Vector3(50, 50, 50),
7263
+ lookingAt: new import_three23.Vector3(0, 0, 0)
7146
7264
  },
7147
7265
  render: {
7148
7266
  fpsLimit: 60,
@@ -7330,7 +7448,7 @@ var Skins = class {
7330
7448
  };
7331
7449
 
7332
7450
  // src/world/Chunk.ts
7333
- var import_three25 = require("three");
7451
+ var import_three26 = require("three");
7334
7452
 
7335
7453
  // src/world/ChunkData.ts
7336
7454
  var ChunkData = class _ChunkData {
@@ -7414,28 +7532,29 @@ var ChunkData = class _ChunkData {
7414
7532
  };
7415
7533
 
7416
7534
  // src/world/MineRenderWorld.ts
7417
- var import_three24 = require("three");
7535
+ var import_three25 = require("three");
7418
7536
  var MineRenderWorld = class {
7419
7537
  constructor(scene) {
7420
7538
  this._chunks = /* @__PURE__ */ new Map();
7539
+ this.pendingCulling = /* @__PURE__ */ new Map();
7421
7540
  this.scene = scene;
7422
7541
  }
7423
7542
  getBlockAt(posOrX, y, z) {
7424
7543
  if (typeof posOrX == "number") {
7425
- return this.getBlockAt(new import_three24.Vector3(posOrX, y, z));
7544
+ return this.getBlockAt(new import_three25.Vector3(posOrX, y, z));
7426
7545
  }
7427
7546
  if (isTripleArray(posOrX)) {
7428
- return this.getBlockAt(new import_three24.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7547
+ return this.getBlockAt(new import_three25.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7429
7548
  }
7430
7549
  this.validatePosBounds(posOrX);
7431
7550
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
7432
7551
  }
7433
7552
  async setBlockAt(posOrX, yOrBlock, z, block) {
7434
7553
  if (typeof posOrX == "number") {
7435
- return this.setBlockAt(new import_three24.Vector3(posOrX, yOrBlock, z), block);
7554
+ return this.setBlockAt(new import_three25.Vector3(posOrX, yOrBlock, z), block);
7436
7555
  }
7437
7556
  if (isTripleArray(posOrX)) {
7438
- return this.setBlockAt(new import_three24.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7557
+ return this.setBlockAt(new import_three25.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7439
7558
  }
7440
7559
  this.validatePosBounds(posOrX);
7441
7560
  const value = yOrBlock;
@@ -7478,16 +7597,54 @@ var MineRenderWorld = class {
7478
7597
  }
7479
7598
  }
7480
7599
  async clear() {
7481
- for (const chunk of this._chunks.values()) {
7600
+ await this.culling;
7601
+ const chunks = [...this._chunks.values()];
7602
+ this._chunks.clear();
7603
+ for (const chunk of chunks) {
7482
7604
  await chunk.dispose();
7483
7605
  }
7484
- this._chunks.clear();
7606
+ }
7607
+ updateCulling(positions) {
7608
+ for (const pos of positions) {
7609
+ this.pendingCulling.set(pos.toArray().join(","), pos.clone());
7610
+ for (const offset of CUBE_FACE_OFFSETS) {
7611
+ const neighbor = pos.clone().add(new import_three25.Vector3(...offset));
7612
+ this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
7613
+ }
7614
+ }
7615
+ return this.culling ?? (this.culling = Promise.resolve().then(async () => {
7616
+ try {
7617
+ while (this.pendingCulling.size) {
7618
+ const batch = [...this.pendingCulling.values()];
7619
+ this.pendingCulling.clear();
7620
+ for (const pos of batch) {
7621
+ const block = this.getBlockAt(pos)?.object;
7622
+ if (!block) continue;
7623
+ let mask = 0;
7624
+ for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
7625
+ if (this.getBlockAt(pos.clone().add(new import_three25.Vector3(...offset)))?.object.isOccluding) {
7626
+ mask |= 1 << face;
7627
+ }
7628
+ }
7629
+ await block.setCullMask(mask);
7630
+ }
7631
+ }
7632
+ } finally {
7633
+ this.culling = void 0;
7634
+ }
7635
+ }));
7485
7636
  }
7486
7637
  getOrCreateChunkAt(pos) {
7487
7638
  const key = this.worldPosToChunkKey(pos);
7488
7639
  let chunk = this._chunks.get(key);
7489
7640
  if (typeof chunk === "undefined") {
7490
- chunk = new Chunk(this.scene, Math.floor(pos.x / 16), Math.floor(pos.y / 16), Math.floor(pos.z / 16));
7641
+ chunk = new Chunk(
7642
+ this.scene,
7643
+ Math.floor(pos.x / 16),
7644
+ Math.floor(pos.y / 16),
7645
+ Math.floor(pos.z / 16),
7646
+ (positions) => this.updateCulling(positions)
7647
+ );
7491
7648
  this._chunks.set(key, chunk);
7492
7649
  }
7493
7650
  return chunk;
@@ -7496,14 +7653,14 @@ var MineRenderWorld = class {
7496
7653
  return this._chunks.get(this.worldPosToChunkKey(pos));
7497
7654
  }
7498
7655
  static worldToScenePosition(pos) {
7499
- return new import_three24.Vector3(
7656
+ return new import_three25.Vector3(
7500
7657
  pos.x * 16,
7501
7658
  pos.y * 16,
7502
7659
  pos.z * 16
7503
7660
  );
7504
7661
  }
7505
7662
  static sceneToWorldPosition(pos) {
7506
- return new import_three24.Vector3(
7663
+ return new import_three25.Vector3(
7507
7664
  pos.x / 16,
7508
7665
  pos.y / 16,
7509
7666
  pos.z / 16
@@ -7524,7 +7681,8 @@ var MineRenderWorld = class {
7524
7681
 
7525
7682
  // src/world/Chunk.ts
7526
7683
  var Chunk = class _Chunk {
7527
- constructor(scene, x, y, z) {
7684
+ constructor(scene, x, y, z, onBlocksChanged) {
7685
+ this.onBlocksChanged = onBlocksChanged;
7528
7686
  this.data = new ChunkData();
7529
7687
  this.renderedBlocks = /* @__PURE__ */ new Map();
7530
7688
  this.scene = scene;
@@ -7534,10 +7692,10 @@ var Chunk = class _Chunk {
7534
7692
  }
7535
7693
  getBlockAt(posOrX, y, z) {
7536
7694
  if (typeof posOrX == "number") {
7537
- return this.getBlockAt(new import_three25.Vector3(posOrX, y, z));
7695
+ return this.getBlockAt(new import_three26.Vector3(posOrX, y, z));
7538
7696
  }
7539
7697
  if (isTripleArray(posOrX)) {
7540
- return this.getBlockAt(new import_three25.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7698
+ return this.getBlockAt(new import_three26.Vector3(posOrX[0], posOrX[1], posOrX[2]));
7541
7699
  }
7542
7700
  const pos = this.worldPosToChunkPos(posOrX);
7543
7701
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -7545,10 +7703,10 @@ var Chunk = class _Chunk {
7545
7703
  }
7546
7704
  async setBlockAt(posOrX, yOrBlock, z, block) {
7547
7705
  if (typeof posOrX == "number") {
7548
- return this.setBlockAt(new import_three25.Vector3(posOrX, yOrBlock, z), block);
7706
+ return this.setBlockAt(new import_three26.Vector3(posOrX, yOrBlock, z), block);
7549
7707
  }
7550
7708
  if (isTripleArray(posOrX)) {
7551
- return this.setBlockAt(new import_three25.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7709
+ return this.setBlockAt(new import_three26.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
7552
7710
  }
7553
7711
  const worldPos = posOrX;
7554
7712
  const pos = this.worldPosToChunkPos(worldPos);
@@ -7567,10 +7725,10 @@ var Chunk = class _Chunk {
7567
7725
  const readBlock = this.data.snapshot(index);
7568
7726
  this.renderedBlocks.get(index)?.object.removeFromScene();
7569
7727
  this.renderedBlocks.delete(index);
7570
- if (!readBlock) return void 0;
7571
- const stored = readBlock();
7572
7728
  let object;
7573
7729
  try {
7730
+ if (!readBlock) return void 0;
7731
+ const stored = readBlock();
7574
7732
  const blockState = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
7575
7733
  if (!blockState) {
7576
7734
  this.data.set(index, void 0);
@@ -7592,12 +7750,18 @@ var Chunk = class _Chunk {
7592
7750
  this.data.set(index, void 0);
7593
7751
  object?.removeFromScene();
7594
7752
  throw error;
7753
+ } finally {
7754
+ await this.onBlocksChanged?.([worldPos]);
7595
7755
  }
7596
7756
  }
7597
7757
  async clear() {
7758
+ const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
7759
+ new import_three26.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
7760
+ ));
7598
7761
  for (const info of this.renderedBlocks.values()) info.object.removeFromScene();
7599
7762
  this.renderedBlocks.clear();
7600
7763
  this.data.clear();
7764
+ await this.onBlocksChanged?.(positions);
7601
7765
  }
7602
7766
  async dispose() {
7603
7767
  await this.clear();
@@ -7612,14 +7776,14 @@ var Chunk = class _Chunk {
7612
7776
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
7613
7777
  }
7614
7778
  worldPosToChunkPos(pos) {
7615
- return new import_three25.Vector3(
7779
+ return new import_three26.Vector3(
7616
7780
  pos.x - this.x * 16,
7617
7781
  pos.y - this.y * 16,
7618
7782
  pos.z - this.z * 16
7619
7783
  );
7620
7784
  }
7621
7785
  chunkPosToWorldPos(pos) {
7622
- return new import_three25.Vector3(
7786
+ return new import_three26.Vector3(
7623
7787
  this.x * 16 + pos.x,
7624
7788
  this.y * 16 + pos.y,
7625
7789
  this.z * 16 + pos.z