minerender 2.1.0-alpha.41 → 2.1.0-alpha.42

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.
@@ -37,8 +37,8 @@ var require_dist = __commonJS({
37
37
  __assign = Object.assign || function(t) {
38
38
  for (var s, i = 1, n = arguments.length; i < n; i++) {
39
39
  s = arguments[i];
40
- for (var p11 in s) if (Object.prototype.hasOwnProperty.call(s, p11))
41
- t[p11] = s[p11];
40
+ for (var p10 in s) if (Object.prototype.hasOwnProperty.call(s, p10))
41
+ t[p10] = s[p10];
42
42
  }
43
43
  return t;
44
44
  };
@@ -139,6 +139,7 @@ __export(index_node_exports, {
139
139
  BasicAssetKey: () => BasicAssetKey,
140
140
  BatchedExecutor: () => BatchedExecutor,
141
141
  BlockObject: () => BlockObject,
142
+ BlockStateResolver: () => BlockStateResolver,
142
143
  BlockStates: () => BlockStates,
143
144
  BlockTints: () => BlockTints,
144
145
  BrowserArchiveProxy: () => BrowserArchiveProxy,
@@ -197,6 +198,8 @@ __export(index_node_exports, {
197
198
  SceneStats: () => SceneStats,
198
199
  SceneStatsDisplay: () => SceneStatsDisplay,
199
200
  SchematicParser: () => SchematicParser,
201
+ SectionMesh: () => SectionMesh,
202
+ SectionModels: () => SectionModels,
200
203
  SkinImage: () => SkinImage,
201
204
  SkinObject: () => SkinObject,
202
205
  SkinPart: () => SkinPart,
@@ -931,11 +934,11 @@ var ImageLoader = class _ImageLoader {
931
934
  static async loadCanvasData(src) {
932
935
  const keyStr = serializeImageKey({ src });
933
936
  const info = this.getInfo(src);
934
- const cached = Caching.rawImageCache.getIfPresent(keyStr);
937
+ const cached2 = Caching.rawImageCache.getIfPresent(keyStr);
935
938
  try {
936
939
  return await this.infoToCanvasData(await info);
937
940
  } catch (err) {
938
- if (cached && Caching.rawImageCache.getIfPresent(keyStr) === cached) {
941
+ if (cached2 && Caching.rawImageCache.getIfPresent(keyStr) === cached2) {
939
942
  Caching.rawImageCache.invalidate(keyStr);
940
943
  }
941
944
  throw err;
@@ -1072,8 +1075,8 @@ var Textures = class _Textures {
1072
1075
  }
1073
1076
  static getImage(key) {
1074
1077
  const keyStr = serializeTextureKey(key);
1075
- const cached = Caching.textureCache.peek(keyStr);
1076
- if (cached && TextureLoader.hasFailed(cached)) {
1078
+ const cached2 = Caching.textureCache.peek(keyStr);
1079
+ if (cached2 && TextureLoader.hasFailed(cached2)) {
1077
1080
  Caching.textureCache.invalidate(keyStr);
1078
1081
  }
1079
1082
  return Caching.textureCache.get(keyStr, (k) => {
@@ -1341,12 +1344,12 @@ var AssetKey = class _AssetKey extends BasicAssetKey {
1341
1344
  return a.join("/");
1342
1345
  }
1343
1346
  getFullPath() {
1344
- let p11 = [];
1347
+ let p10 = [];
1345
1348
  if (this.type) {
1346
- p11.push(this.type);
1349
+ p10.push(this.type);
1347
1350
  }
1348
- p11.push(this.path);
1349
- return p11.join("/");
1351
+ p10.push(this.path);
1352
+ return p10.join("/");
1350
1353
  }
1351
1354
  toNamespacedString() {
1352
1355
  return this.namespace + ":" + this.getFullPath();
@@ -1433,7 +1436,7 @@ var ModelMerger = class {
1433
1436
  merged.display = { ...inheritedDisplay, ...DisplayTransforms.withHandFallbacks(source.display) };
1434
1437
  }
1435
1438
  }
1436
- merged.hierarchy = models.map((m) => m.parent).filter((p11) => `${p11}`);
1439
+ merged.hierarchy = models.map((m) => m.parent).filter((p10) => `${p10}`);
1437
1440
  merged.hierarchy.push(`${merged.parent}`);
1438
1441
  return merged;
1439
1442
  }
@@ -2162,7 +2165,7 @@ var ModelTextures = class {
2162
2165
  static async get(key) {
2163
2166
  const keyStr = key.serialize();
2164
2167
  const pending = this.preload(key);
2165
- const cached = Caching.textureAssetCache.getIfPresent(keyStr);
2168
+ const cached2 = Caching.textureAssetCache.getIfPresent(keyStr);
2166
2169
  try {
2167
2170
  const asset = await pending;
2168
2171
  if (asset) {
@@ -2170,7 +2173,7 @@ var ModelTextures = class {
2170
2173
  }
2171
2174
  return void 0;
2172
2175
  } catch (err) {
2173
- if (cached && Caching.textureAssetCache.getIfPresent(keyStr) === cached) {
2176
+ if (cached2 && Caching.textureAssetCache.getIfPresent(keyStr) === cached2) {
2174
2177
  Caching.textureAssetCache.invalidate(keyStr);
2175
2178
  }
2176
2179
  throw err;
@@ -4063,6 +4066,93 @@ var ModelCulling = class {
4063
4066
  }
4064
4067
  };
4065
4068
 
4069
+ // src/model/block/BlockStateResolver.ts
4070
+ var import_three17 = require("three");
4071
+ function matchesCondition(condition, state) {
4072
+ return Object.entries(condition).every(([key, value]) => {
4073
+ if (Array.isArray(value)) {
4074
+ if (key === "OR") return value.some((child) => matchesCondition(child, state));
4075
+ if (key === "AND") return value.every((child) => matchesCondition(child, state));
4076
+ return false;
4077
+ }
4078
+ return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4079
+ });
4080
+ }
4081
+ var BlockStateResolver = class {
4082
+ static async defaults(blockState) {
4083
+ const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
4084
+ const state = {};
4085
+ if (defaults && Object.keys(defaults).length > 0) {
4086
+ for (const key in defaults) state[key] = defaults[key].default;
4087
+ } else if (blockState.variants) {
4088
+ const variant = Object.keys(blockState.variants)[0];
4089
+ if (variant) {
4090
+ for (const property of variant.split(",")) {
4091
+ const [key, value] = property.split("=");
4092
+ state[key] = value;
4093
+ }
4094
+ }
4095
+ } else if (blockState.multipart) {
4096
+ const condition = blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4097
+ for (const [key, value] of Object.entries(condition ?? {})) state[key] = value.split("|")[0];
4098
+ }
4099
+ return state;
4100
+ }
4101
+ static select(blockState, state, choose = this.choose) {
4102
+ return this.matching(blockState, state).map(choose);
4103
+ }
4104
+ static matching(blockState, state) {
4105
+ const out = [];
4106
+ if (blockState.variants) {
4107
+ if (Object.keys(blockState.variants).length === 1 && "" in blockState.variants) {
4108
+ out.push(blockState.variants[""]);
4109
+ } else {
4110
+ for (const variantKey in blockState.variants) {
4111
+ const matches = variantKey.split(",").every((property) => {
4112
+ const [key, value] = property.split("=");
4113
+ return `${state[key]}` === `${value}`;
4114
+ });
4115
+ if (matches) out.push(blockState.variants[variantKey]);
4116
+ }
4117
+ }
4118
+ } else if (blockState.multipart) {
4119
+ for (const part of blockState.multipart) {
4120
+ if (part.apply && (!part.when || matchesCondition(part.when, state))) {
4121
+ out.push(part.apply);
4122
+ }
4123
+ }
4124
+ }
4125
+ return out;
4126
+ }
4127
+ static choose(variants) {
4128
+ if (!Array.isArray(variants)) return variants;
4129
+ if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
4130
+ const total = variants.reduce((sum, variant) => {
4131
+ const weight = variant.weight ?? 1;
4132
+ if (!Number.isInteger(weight) || weight < 1) {
4133
+ throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
4134
+ }
4135
+ return sum + weight;
4136
+ }, 0);
4137
+ let choice = Math.random() * total;
4138
+ for (const variant of variants) {
4139
+ choice -= variant.weight ?? 1;
4140
+ if (choice < 0) return variant;
4141
+ }
4142
+ return variants[variants.length - 1];
4143
+ }
4144
+ static rotation(variant) {
4145
+ const rotation = new import_three17.Euler();
4146
+ if (typeof variant.x !== "undefined") {
4147
+ rotation.x = toRadians(clampRotationDegrees(variant.x));
4148
+ }
4149
+ if (typeof variant.y !== "undefined") {
4150
+ rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
4151
+ }
4152
+ return rotation;
4153
+ }
4154
+ };
4155
+
4066
4156
  // src/model/block/blockTints.json
4067
4157
  var blockTints_default = {
4068
4158
  "minecraft:large_fern": { source: "grass" },
@@ -4149,10 +4239,10 @@ var BlockTints = class {
4149
4239
  };
4150
4240
 
4151
4241
  // src/model/scene/ModelObject.ts
4152
- var import_three18 = require("three");
4242
+ var import_three19 = require("three");
4153
4243
 
4154
4244
  // src/three/BufferGeometryUtils.js
4155
- var import_three17 = require("three");
4245
+ var import_three18 = require("three");
4156
4246
  function computeTangents(geometry) {
4157
4247
  geometry.computeTangents();
4158
4248
  console.warn("THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.");
@@ -4164,7 +4254,7 @@ function mergeBufferGeometries(geometries, useGroups = false) {
4164
4254
  const attributes = {};
4165
4255
  const morphAttributes = {};
4166
4256
  const morphTargetsRelative = geometries[0].morphTargetsRelative;
4167
- const mergedGeometry = new import_three17.BufferGeometry();
4257
+ const mergedGeometry = new import_three18.BufferGeometry();
4168
4258
  let offset = 0;
4169
4259
  for (let i = 0; i < geometries.length; ++i) {
4170
4260
  const geometry = geometries[i];
@@ -4288,7 +4378,7 @@ function mergeBufferAttributes(attributes) {
4288
4378
  array.set(attributes[i].array, offset);
4289
4379
  offset += attributes[i].array.length;
4290
4380
  }
4291
- return new import_three17.BufferAttribute(array, itemSize, normalized);
4381
+ return new import_three18.BufferAttribute(array, itemSize, normalized);
4292
4382
  }
4293
4383
  function interleaveAttributes(attributes) {
4294
4384
  let TypedArray;
@@ -4304,7 +4394,7 @@ function interleaveAttributes(attributes) {
4304
4394
  arrayLength += attribute.array.length;
4305
4395
  stride += attribute.itemSize;
4306
4396
  }
4307
- const interleavedBuffer = new import_three17.InterleavedBuffer(new TypedArray(arrayLength), stride);
4397
+ const interleavedBuffer = new import_three18.InterleavedBuffer(new TypedArray(arrayLength), stride);
4308
4398
  let offset = 0;
4309
4399
  const res = [];
4310
4400
  const getters = ["getX", "getY", "getZ", "getW"];
@@ -4313,7 +4403,7 @@ function interleaveAttributes(attributes) {
4313
4403
  const attribute = attributes[j];
4314
4404
  const itemSize = attribute.itemSize;
4315
4405
  const count = attribute.count;
4316
- const iba = new import_three17.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
4406
+ const iba = new import_three18.InterleavedBufferAttribute(interleavedBuffer, itemSize, offset, attribute.normalized);
4317
4407
  res.push(iba);
4318
4408
  offset += itemSize;
4319
4409
  for (let c = 0; c < count; c++) {
@@ -4397,13 +4487,13 @@ function mergeVertices(geometry, tolerance = 1e-4) {
4397
4487
  const name = attributeNames[i];
4398
4488
  const oldAttribute = geometry.getAttribute(name);
4399
4489
  const buffer = new oldAttribute.array.constructor(attrArrays[name]);
4400
- const attribute = new import_three17.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
4490
+ const attribute = new import_three18.BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
4401
4491
  result.setAttribute(name, attribute);
4402
4492
  if (name in morphAttrsArrays) {
4403
4493
  for (let j = 0; j < morphAttrsArrays[name].length; j++) {
4404
4494
  const oldMorphAttribute = geometry.morphAttributes[name][j];
4405
4495
  const buffer2 = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
4406
- const morphAttribute = new import_three17.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
4496
+ const morphAttribute = new import_three18.BufferAttribute(buffer2, oldMorphAttribute.itemSize, oldMorphAttribute.normalized);
4407
4497
  result.morphAttributes[name][j] = morphAttribute;
4408
4498
  }
4409
4499
  }
@@ -4412,11 +4502,11 @@ function mergeVertices(geometry, tolerance = 1e-4) {
4412
4502
  return result;
4413
4503
  }
4414
4504
  function toTrianglesDrawMode(geometry, drawMode) {
4415
- if (drawMode === import_three17.TrianglesDrawMode) {
4505
+ if (drawMode === import_three18.TrianglesDrawMode) {
4416
4506
  console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.");
4417
4507
  return geometry;
4418
4508
  }
4419
- if (drawMode === import_three17.TriangleFanDrawMode || drawMode === import_three17.TriangleStripDrawMode) {
4509
+ if (drawMode === import_three18.TriangleFanDrawMode || drawMode === import_three18.TriangleStripDrawMode) {
4420
4510
  let index = geometry.getIndex();
4421
4511
  if (index === null) {
4422
4512
  const indices = [];
@@ -4434,7 +4524,7 @@ function toTrianglesDrawMode(geometry, drawMode) {
4434
4524
  }
4435
4525
  const numberOfTriangles = index.count - 2;
4436
4526
  const newIndices = [];
4437
- if (drawMode === import_three17.TriangleFanDrawMode) {
4527
+ if (drawMode === import_three18.TriangleFanDrawMode) {
4438
4528
  for (let i = 1; i <= numberOfTriangles; i++) {
4439
4529
  newIndices.push(index.getX(0));
4440
4530
  newIndices.push(index.getX(i));
@@ -4470,15 +4560,15 @@ function computeMorphedAttributes(object) {
4470
4560
  console.error("THREE.BufferGeometryUtils: Geometry is not of type BufferGeometry.");
4471
4561
  return null;
4472
4562
  }
4473
- const _vA = new import_three17.Vector3();
4474
- const _vB = new import_three17.Vector3();
4475
- const _vC = new import_three17.Vector3();
4476
- const _tempA = new import_three17.Vector3();
4477
- const _tempB = new import_three17.Vector3();
4478
- const _tempC = new import_three17.Vector3();
4479
- const _morphA = new import_three17.Vector3();
4480
- const _morphB = new import_three17.Vector3();
4481
- const _morphC = new import_three17.Vector3();
4563
+ const _vA = new import_three18.Vector3();
4564
+ const _vB = new import_three18.Vector3();
4565
+ const _vC = new import_three18.Vector3();
4566
+ const _tempA = new import_three18.Vector3();
4567
+ const _tempB = new import_three18.Vector3();
4568
+ const _tempC = new import_three18.Vector3();
4569
+ const _morphA = new import_three18.Vector3();
4570
+ const _morphB = new import_three18.Vector3();
4571
+ const _morphC = new import_three18.Vector3();
4482
4572
  function _calculateMorphedAttributeData(object2, material2, attribute, morphAttribute, morphTargetsRelative2, a2, b2, c2, modifiedAttributeArray) {
4483
4573
  _vA.fromBufferAttribute(attribute, a2);
4484
4574
  _vB.fromBufferAttribute(attribute, b2);
@@ -4673,8 +4763,8 @@ function computeMorphedAttributes(object) {
4673
4763
  }
4674
4764
  }
4675
4765
  }
4676
- const morphedPositionAttribute = new import_three17.Float32BufferAttribute(modifiedPosition, 3);
4677
- const morphedNormalAttribute = new import_three17.Float32BufferAttribute(modifiedNormal, 3);
4766
+ const morphedPositionAttribute = new import_three18.Float32BufferAttribute(modifiedPosition, 3);
4767
+ const morphedNormalAttribute = new import_three18.Float32BufferAttribute(modifiedNormal, 3);
4678
4768
  return {
4679
4769
  positionAttribute,
4680
4770
  normalAttribute,
@@ -4733,7 +4823,7 @@ var ModelObject = class _ModelObject extends SceneObject {
4733
4823
  elGeo.clearGroups();
4734
4824
  }
4735
4825
  if (this.options.uvLockRotation) {
4736
- UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three18.Euler(...this.options.uvLockRotation));
4826
+ UVMapper.lockUvs(elGeo, el.faces, this.atlas, new import_three19.Euler(...this.options.uvLockRotation));
4737
4827
  }
4738
4828
  if (this.options.tints) {
4739
4829
  const colors = new Float32Array(elGeo.getAttribute("position").count * 3).fill(1);
@@ -4742,19 +4832,19 @@ var ModelObject = class _ModelObject extends SceneObject {
4742
4832
  if (tintIndex === void 0 || tintIndex < 0) continue;
4743
4833
  const tint = this.options.tints[tintIndex];
4744
4834
  if (tint === void 0) continue;
4745
- const color = new import_three18.Color(tint);
4835
+ const color = new import_three19.Color(tint);
4746
4836
  for (let vertex = 0; vertex < 4; vertex++) {
4747
4837
  color.toArray(colors, (faceIndex * 4 + vertex) * 3);
4748
4838
  }
4749
4839
  }
4750
- elGeo.setAttribute("color", new import_three18.BufferAttribute(colors, 3));
4840
+ elGeo.setAttribute("color", new import_three19.BufferAttribute(colors, 3));
4751
4841
  }
4752
- 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));
4753
- elGeo.applyMatrix4(new import_three18.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4842
+ elGeo.applyMatrix4(new import_three19.Matrix4().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4843
+ elGeo.applyMatrix4(new import_three19.Matrix4().makeTranslation(el.from[0], el.from[1], el.from[2]));
4754
4844
  if (el.rotation) {
4755
4845
  applyElementRotation(el.rotation, elGeo);
4756
4846
  }
4757
- elGeo.applyMatrix4(new import_three18.Matrix4().makeTranslation(-8, -8, -8));
4847
+ elGeo.applyMatrix4(new import_three19.Matrix4().makeTranslation(-8, -8, -8));
4758
4848
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4759
4849
  if (this.options.mergeMeshes) {
4760
4850
  allGeos.push(elGeo);
@@ -4776,7 +4866,7 @@ var ModelObject = class _ModelObject extends SceneObject {
4776
4866
  if (allGeos.length > 0) {
4777
4867
  combinedGeo = mergeBufferGeometries(allGeos);
4778
4868
  } else {
4779
- combinedGeo = new import_three18.BoxGeometry(16, 16, 16);
4869
+ combinedGeo = new import_three19.BoxGeometry(16, 16, 16);
4780
4870
  if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
4781
4871
  }
4782
4872
  combinedGeo.computeBoundingBox();
@@ -4829,18 +4919,7 @@ function isModelObject(obj) {
4829
4919
 
4830
4920
  // src/model/block/scene/BlockObject.ts
4831
4921
  var import_ts_deepmerge6 = __toESM(require_dist());
4832
- var import_three19 = require("three");
4833
- var p10 = prefix("BlockObject");
4834
- function matchesCondition(condition, state) {
4835
- return Object.entries(condition).every(([key, value]) => {
4836
- if (Array.isArray(value)) {
4837
- if (key === "OR") return value.some((child) => matchesCondition(child, state));
4838
- if (key === "AND") return value.every((child) => matchesCondition(child, state));
4839
- return false;
4840
- }
4841
- return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
4842
- });
4843
- }
4922
+ var import_three20 = require("three");
4844
4923
  var BlockObject = class _BlockObject extends SceneObject {
4845
4924
  constructor(blockState, options) {
4846
4925
  super(options);
@@ -4864,22 +4943,7 @@ var BlockObject = class _BlockObject extends SceneObject {
4864
4943
  }
4865
4944
  async init() {
4866
4945
  if (this.options.applyDefaultState) {
4867
- const defaultState = this.blockState.key ? await BlockStates.getDefaultState(this.blockState.key) : void 0;
4868
- if (defaultState && Object.keys(defaultState).length > 0) {
4869
- const state = {};
4870
- for (let k in defaultState) {
4871
- state[k] = defaultState[k].default;
4872
- }
4873
- this._setState(state);
4874
- } else {
4875
- if (this.blockState.variants) {
4876
- this._setState(Object.keys(this.blockState.variants)[0]);
4877
- } else if (this.blockState.multipart) {
4878
- const condition = this.blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
4879
- const state = Object.fromEntries(Object.entries(condition ?? {}).map(([key, value]) => [key, value.split("|")[0]]));
4880
- this._setState(state);
4881
- }
4882
- }
4946
+ this._setState(await BlockStateResolver.defaults(this.blockState));
4883
4947
  }
4884
4948
  if (this.options.initialState !== void 0) this._setState(this.options.initialState);
4885
4949
  await this.recreateModels();
@@ -4917,12 +4981,12 @@ var BlockObject = class _BlockObject extends SceneObject {
4917
4981
  getModelCullMask(model, worldMask) {
4918
4982
  const object = isInstanceReference(model) ? model.instanceable : model;
4919
4983
  if (object.options.displayPosition) return 0;
4920
- const position = new import_three19.Vector3();
4921
- const rotation = new import_three19.Quaternion();
4922
- const scale = new import_three19.Vector3();
4984
+ const position = new import_three20.Vector3();
4985
+ const rotation = new import_three20.Quaternion();
4986
+ const scale = new import_three20.Vector3();
4923
4987
  this.getModelMatrix(model).decompose(position, rotation, scale);
4924
- if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new import_three19.Vector3(1, 1, 1)) > 1e-10) return 0;
4925
- return ModelCulling.toLocalMask(worldMask, new import_three19.Euler().setFromQuaternion(rotation));
4988
+ if (position.distanceToSquared(this.position) > 1e-10 || scale.distanceToSquared(new import_three20.Vector3(1, 1, 1)) > 1e-10) return 0;
4989
+ return ModelCulling.toLocalMask(worldMask, new import_three20.Euler().setFromQuaternion(rotation));
4926
4990
  }
4927
4991
  async setCullMask(worldMask) {
4928
4992
  worldMask &= 63;
@@ -4970,39 +5034,7 @@ var BlockObject = class _BlockObject extends SceneObject {
4970
5034
  return ref;
4971
5035
  }
4972
5036
  async mapStateToVariant(state) {
4973
- const out = [];
4974
- if (this.blockState.variants) {
4975
- if (Object.keys(this.blockState.variants).length === 1 && "" in this.blockState.variants) {
4976
- out.push(this.getSingleVariant(this.blockState.variants[""]));
4977
- } else {
4978
- for (let variantKey in this.blockState.variants) {
4979
- const split = variantKey.split(",");
4980
- let matches = true;
4981
- for (let s of split) {
4982
- const [k, v] = s.split("=");
4983
- if (`${state[k]}` !== `${v}`) {
4984
- matches = false;
4985
- break;
4986
- }
4987
- }
4988
- if (matches) {
4989
- const variants = this.blockState.variants[variantKey];
4990
- out.push(this.getSingleVariant(variants));
4991
- }
4992
- }
4993
- }
4994
- } else if (this.blockState.multipart) {
4995
- for (let part of this.blockState.multipart) {
4996
- if (!part.apply) {
4997
- console.debug(p10, "Missing apply for blockState part", part);
4998
- continue;
4999
- }
5000
- if (!part.when || matchesCondition(part.when, state)) {
5001
- out.push(this.getSingleVariant(part.apply));
5002
- }
5003
- }
5004
- }
5005
- return out;
5037
+ return BlockStateResolver.select(this.blockState, state, (variants) => this.getSingleVariant(variants));
5006
5038
  }
5007
5039
  async recreateModels() {
5008
5040
  this.clearModels();
@@ -5013,21 +5045,7 @@ var BlockObject = class _BlockObject extends SceneObject {
5013
5045
  }
5014
5046
  }
5015
5047
  getSingleVariant(variants) {
5016
- if (!Array.isArray(variants)) return variants;
5017
- if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
5018
- const total = variants.reduce((sum, variant) => {
5019
- const weight = variant.weight ?? 1;
5020
- if (!Number.isInteger(weight) || weight < 1) {
5021
- throw new MineRenderError(`Invalid blockstate variant weight: ${weight}`);
5022
- }
5023
- return sum + weight;
5024
- }, 0);
5025
- let choice = Math.random() * total;
5026
- for (const variant of variants) {
5027
- choice -= variant.weight ?? 1;
5028
- if (choice < 0) return variant;
5029
- }
5030
- return variants[variants.length - 1];
5048
+ return BlockStateResolver.choose(variants);
5031
5049
  }
5032
5050
  // @deprecated
5033
5051
  async createAVariant(variants, instanceInfo) {
@@ -5035,13 +5053,7 @@ var BlockObject = class _BlockObject extends SceneObject {
5035
5053
  await this.createVariant(variant);
5036
5054
  }
5037
5055
  async createVariant(variant) {
5038
- const rotation = new import_three19.Euler();
5039
- if (typeof variant.x !== "undefined") {
5040
- rotation.x = toRadians(clampRotationDegrees(variant.x));
5041
- }
5042
- if (typeof variant.y !== "undefined") {
5043
- rotation.y = toRadians(clampRotationDegrees(typeof variant.x !== "undefined" ? variant.y : 360 - variant.y));
5044
- }
5056
+ const rotation = BlockStateResolver.rotation(variant);
5045
5057
  const modelKey = AssetKey.parse("models", variant.model);
5046
5058
  modelKey.root = this.blockState.key?.root;
5047
5059
  const model = await Models.getMerged(modelKey);
@@ -5126,7 +5138,7 @@ var BlockObject = class _BlockObject extends SceneObject {
5126
5138
  setPositionRotationScaleAt(index, position, rotation, scale) {
5127
5139
  super.setPositionRotationScaleAt(index, position, rotation, scale);
5128
5140
  }
5129
- getMatrixAt(index, matrix = new import_three19.Matrix4()) {
5141
+ getMatrixAt(index, matrix = new import_three20.Matrix4()) {
5130
5142
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
5131
5143
  const child = this._models[0];
5132
5144
  if (child && isModelObject(child)) {
@@ -6978,7 +6990,7 @@ var StructureParser = class {
6978
6990
  };
6979
6991
 
6980
6992
  // src/renderer/MineRenderScene.ts
6981
- var import_three21 = require("three");
6993
+ var import_three22 = require("three");
6982
6994
  var import_ts_deepmerge8 = __toESM(require_dist());
6983
6995
 
6984
6996
  // src/skin/SkinPart.ts
@@ -7703,7 +7715,7 @@ var slimSkinGeometries = {
7703
7715
  var import_ts_deepmerge7 = __toESM(require_dist());
7704
7716
 
7705
7717
  // src/skin/SkinTextures.ts
7706
- var import_three20 = require("three");
7718
+ var import_three21 = require("three");
7707
7719
 
7708
7720
  // src/skin/SkinImage.ts
7709
7721
  var SkinImage = class {
@@ -7780,11 +7792,11 @@ var SkinTextures = class {
7780
7792
  });
7781
7793
  }
7782
7794
  static createMaterial(pixels, width, height, transparent = true) {
7783
- const texture = Textures.initTextureProps(new import_three20.DataTexture(pixels, width, height));
7784
- texture.colorSpace = import_three20.SRGBColorSpace;
7795
+ const texture = Textures.initTextureProps(new import_three21.DataTexture(pixels, width, height));
7796
+ texture.colorSpace = import_three21.SRGBColorSpace;
7785
7797
  texture.flipY = true;
7786
7798
  texture.needsUpdate = true;
7787
- return new import_three20.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three20.DoubleSide : import_three20.FrontSide, alphaTest: transparent ? 0.1 : 0 });
7799
+ return new import_three21.MeshBasicMaterial({ map: texture, transparent, side: transparent ? import_three21.DoubleSide : import_three21.FrontSide, alphaTest: transparent ? 0.1 : 0 });
7788
7800
  }
7789
7801
  static isSlim(image, scale) {
7790
7802
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -8011,7 +8023,7 @@ var SkinObject = class extends SceneObject {
8011
8023
  };
8012
8024
 
8013
8025
  // src/renderer/MineRenderScene.ts
8014
- var MineRenderScene = class _MineRenderScene extends import_three21.Scene {
8026
+ var MineRenderScene = class _MineRenderScene extends import_three22.Scene {
8015
8027
  constructor(options) {
8016
8028
  super();
8017
8029
  this.isMineRenderScene = true;
@@ -8136,17 +8148,17 @@ function isMineRenderScene(obj) {
8136
8148
  }
8137
8149
 
8138
8150
  // src/renderer/Renderer.ts
8139
- var import_three23 = require("three");
8151
+ var import_three24 = require("three");
8140
8152
  var import_ts_deepmerge9 = __toESM(require_dist());
8141
8153
  var import_stats = __toESM(require("stats.js"));
8142
8154
  var import_postprocessing = require("postprocessing");
8143
8155
 
8144
8156
  // src/three/OrbitControls.js
8145
- var import_three22 = require("three");
8157
+ var import_three23 = require("three");
8146
8158
  var _changeEvent = { type: "change" };
8147
8159
  var _startEvent = { type: "start" };
8148
8160
  var _endEvent = { type: "end" };
8149
- var OrbitControls = class extends import_three22.EventDispatcher {
8161
+ var OrbitControls = class extends import_three23.EventDispatcher {
8150
8162
  constructor(object, domElement) {
8151
8163
  super();
8152
8164
  if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
@@ -8155,7 +8167,7 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8155
8167
  this.domElement = domElement;
8156
8168
  this.domElement.style.touchAction = "none";
8157
8169
  this.enabled = true;
8158
- this.target = new import_three22.Vector3();
8170
+ this.target = new import_three23.Vector3();
8159
8171
  this.minDistance = 0;
8160
8172
  this.maxDistance = Infinity;
8161
8173
  this.minZoom = 0;
@@ -8177,8 +8189,8 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8177
8189
  this.autoRotate = false;
8178
8190
  this.autoRotateSpeed = 2;
8179
8191
  this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
8180
- this.mouseButtons = { LEFT: import_three22.MOUSE.ROTATE, MIDDLE: import_three22.MOUSE.DOLLY, RIGHT: import_three22.MOUSE.PAN };
8181
- this.touches = { ONE: import_three22.TOUCH.ROTATE, TWO: import_three22.TOUCH.DOLLY_PAN };
8192
+ this.mouseButtons = { LEFT: import_three23.MOUSE.ROTATE, MIDDLE: import_three23.MOUSE.DOLLY, RIGHT: import_three23.MOUSE.PAN };
8193
+ this.touches = { ONE: import_three23.TOUCH.ROTATE, TWO: import_three23.TOUCH.DOLLY_PAN };
8182
8194
  this.target0 = this.target.clone();
8183
8195
  this.position0 = this.object.position.clone();
8184
8196
  this.zoom0 = this.object.zoom;
@@ -8207,11 +8219,11 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8207
8219
  state = STATE.NONE;
8208
8220
  };
8209
8221
  this.update = function() {
8210
- const offset = new import_three22.Vector3();
8211
- const quat = new import_three22.Quaternion().setFromUnitVectors(object.up, new import_three22.Vector3(0, 1, 0));
8222
+ const offset = new import_three23.Vector3();
8223
+ const quat = new import_three23.Quaternion().setFromUnitVectors(object.up, new import_three23.Vector3(0, 1, 0));
8212
8224
  const quatInverse = quat.clone().invert();
8213
- const lastPosition = new import_three22.Vector3();
8214
- const lastQuaternion = new import_three22.Quaternion();
8225
+ const lastPosition = new import_three23.Vector3();
8226
+ const lastQuaternion = new import_three23.Quaternion();
8215
8227
  const twoPI = 2 * Math.PI;
8216
8228
  return function update() {
8217
8229
  const position = scope.object.position;
@@ -8297,20 +8309,20 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8297
8309
  };
8298
8310
  let state = STATE.NONE;
8299
8311
  const EPS = 1e-6;
8300
- const spherical = new import_three22.Spherical();
8301
- const sphericalDelta = new import_three22.Spherical();
8312
+ const spherical = new import_three23.Spherical();
8313
+ const sphericalDelta = new import_three23.Spherical();
8302
8314
  let scale = 1;
8303
- const panOffset = new import_three22.Vector3();
8315
+ const panOffset = new import_three23.Vector3();
8304
8316
  let zoomChanged = false;
8305
- const rotateStart = new import_three22.Vector2();
8306
- const rotateEnd = new import_three22.Vector2();
8307
- const rotateDelta = new import_three22.Vector2();
8308
- const panStart = new import_three22.Vector2();
8309
- const panEnd = new import_three22.Vector2();
8310
- const panDelta = new import_three22.Vector2();
8311
- const dollyStart = new import_three22.Vector2();
8312
- const dollyEnd = new import_three22.Vector2();
8313
- const dollyDelta = new import_three22.Vector2();
8317
+ const rotateStart = new import_three23.Vector2();
8318
+ const rotateEnd = new import_three23.Vector2();
8319
+ const rotateDelta = new import_three23.Vector2();
8320
+ const panStart = new import_three23.Vector2();
8321
+ const panEnd = new import_three23.Vector2();
8322
+ const panDelta = new import_three23.Vector2();
8323
+ const dollyStart = new import_three23.Vector2();
8324
+ const dollyEnd = new import_three23.Vector2();
8325
+ const dollyDelta = new import_three23.Vector2();
8314
8326
  const pointers = [];
8315
8327
  const pointerPositions = {};
8316
8328
  function getAutoRotationAngle() {
@@ -8326,7 +8338,7 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8326
8338
  sphericalDelta.phi -= angle;
8327
8339
  }
8328
8340
  const panLeft = function() {
8329
- const v = new import_three22.Vector3();
8341
+ const v = new import_three23.Vector3();
8330
8342
  return function panLeft2(distance, objectMatrix) {
8331
8343
  v.setFromMatrixColumn(objectMatrix, 0);
8332
8344
  v.multiplyScalar(-distance);
@@ -8334,7 +8346,7 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8334
8346
  };
8335
8347
  }();
8336
8348
  const panUp = function() {
8337
- const v = new import_three22.Vector3();
8349
+ const v = new import_three23.Vector3();
8338
8350
  return function panUp2(distance, objectMatrix) {
8339
8351
  if (scope.screenSpacePanning === true) {
8340
8352
  v.setFromMatrixColumn(objectMatrix, 1);
@@ -8347,7 +8359,7 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8347
8359
  };
8348
8360
  }();
8349
8361
  const pan = function() {
8350
- const offset = new import_three22.Vector3();
8362
+ const offset = new import_three23.Vector3();
8351
8363
  return function pan2(deltaX, deltaY) {
8352
8364
  const element = scope.domElement;
8353
8365
  if (scope.object.isPerspectiveCamera) {
@@ -8596,12 +8608,12 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8596
8608
  mouseAction = -1;
8597
8609
  }
8598
8610
  switch (mouseAction) {
8599
- case import_three22.MOUSE.DOLLY:
8611
+ case import_three23.MOUSE.DOLLY:
8600
8612
  if (scope.enableZoom === false) return;
8601
8613
  handleMouseDownDolly(event);
8602
8614
  state = STATE.DOLLY;
8603
8615
  break;
8604
- case import_three22.MOUSE.ROTATE:
8616
+ case import_three23.MOUSE.ROTATE:
8605
8617
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
8606
8618
  if (scope.enablePan === false) return;
8607
8619
  handleMouseDownPan(event);
@@ -8612,7 +8624,7 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8612
8624
  state = STATE.ROTATE;
8613
8625
  }
8614
8626
  break;
8615
- case import_three22.MOUSE.PAN:
8627
+ case import_three23.MOUSE.PAN:
8616
8628
  if (event.ctrlKey || event.metaKey || event.shiftKey) {
8617
8629
  if (scope.enableRotate === false) return;
8618
8630
  handleMouseDownRotate(event);
@@ -8668,12 +8680,12 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8668
8680
  switch (pointers.length) {
8669
8681
  case 1:
8670
8682
  switch (scope.touches.ONE) {
8671
- case import_three22.TOUCH.ROTATE:
8683
+ case import_three23.TOUCH.ROTATE:
8672
8684
  if (scope.enableRotate === false) return;
8673
8685
  handleTouchStartRotate();
8674
8686
  state = STATE.TOUCH_ROTATE;
8675
8687
  break;
8676
- case import_three22.TOUCH.PAN:
8688
+ case import_three23.TOUCH.PAN:
8677
8689
  if (scope.enablePan === false) return;
8678
8690
  handleTouchStartPan();
8679
8691
  state = STATE.TOUCH_PAN;
@@ -8684,12 +8696,12 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8684
8696
  break;
8685
8697
  case 2:
8686
8698
  switch (scope.touches.TWO) {
8687
- case import_three22.TOUCH.DOLLY_PAN:
8699
+ case import_three23.TOUCH.DOLLY_PAN:
8688
8700
  if (scope.enableZoom === false && scope.enablePan === false) return;
8689
8701
  handleTouchStartDollyPan();
8690
8702
  state = STATE.TOUCH_DOLLY_PAN;
8691
8703
  break;
8692
- case import_three22.TOUCH.DOLLY_ROTATE:
8704
+ case import_three23.TOUCH.DOLLY_ROTATE:
8693
8705
  if (scope.enableZoom === false && scope.enableRotate === false) return;
8694
8706
  handleTouchStartDollyRotate();
8695
8707
  state = STATE.TOUCH_DOLLY_ROTATE;
@@ -8756,7 +8768,7 @@ var OrbitControls = class extends import_three22.EventDispatcher {
8756
8768
  function trackPointer(event) {
8757
8769
  let position = pointerPositions[event.pointerId];
8758
8770
  if (position === void 0) {
8759
- position = new import_three22.Vector2();
8771
+ position = new import_three23.Vector2();
8760
8772
  pointerPositions[event.pointerId] = position;
8761
8773
  }
8762
8774
  position.set(event.pageX, event.pageY);
@@ -8776,10 +8788,10 @@ var MapControls = class extends OrbitControls {
8776
8788
  constructor(object, domElement) {
8777
8789
  super(object, domElement);
8778
8790
  this.screenSpacePanning = false;
8779
- this.mouseButtons.LEFT = import_three22.MOUSE.PAN;
8780
- this.mouseButtons.RIGHT = import_three22.MOUSE.ROTATE;
8781
- this.touches.ONE = import_three22.TOUCH.PAN;
8782
- this.touches.TWO = import_three22.TOUCH.DOLLY_ROTATE;
8791
+ this.mouseButtons.LEFT = import_three23.MOUSE.PAN;
8792
+ this.mouseButtons.RIGHT = import_three23.MOUSE.ROTATE;
8793
+ this.touches.ONE = import_three23.TOUCH.PAN;
8794
+ this.touches.TWO = import_three23.TOUCH.DOLLY_ROTATE;
8783
8795
  }
8784
8796
  };
8785
8797
 
@@ -8824,8 +8836,8 @@ var Renderer = class _Renderer {
8824
8836
  top: void 0,
8825
8837
  bottom: void 0
8826
8838
  },
8827
- position: new import_three23.Vector3(50, 50, 50),
8828
- lookingAt: new import_three23.Vector3(0, 0, 0)
8839
+ position: new import_three24.Vector3(50, 50, 50),
8840
+ lookingAt: new import_three24.Vector3(0, 0, 0)
8829
8841
  },
8830
8842
  render: {
8831
8843
  fpsLimit: 60,
@@ -8855,14 +8867,14 @@ var Renderer = class _Renderer {
8855
8867
  switch (this.options.camera.type) {
8856
8868
  case "perspective":
8857
8869
  default:
8858
- return new import_three23.PerspectiveCamera(
8870
+ return new import_three24.PerspectiveCamera(
8859
8871
  this.options.camera.perspective.fov,
8860
8872
  this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
8861
8873
  this.options.camera.near,
8862
8874
  this.options.camera.far
8863
8875
  );
8864
8876
  case "orthographic":
8865
- return new import_three23.OrthographicCamera(
8877
+ return new import_three24.OrthographicCamera(
8866
8878
  this.options.camera.orthographic.left ?? this.viewWidth / -2,
8867
8879
  this.options.camera.orthographic.right ?? this.viewWidth / 2,
8868
8880
  this.options.camera.orthographic.top ?? this.viewHeight / 2,
@@ -8873,7 +8885,7 @@ var Renderer = class _Renderer {
8873
8885
  }
8874
8886
  }
8875
8887
  createRenderer() {
8876
- const renderer = new import_three23.WebGLRenderer({
8888
+ const renderer = new import_three24.WebGLRenderer({
8877
8889
  antialias: this.options.render.antialias,
8878
8890
  alpha: true,
8879
8891
  powerPreference: "high-performance",
@@ -8881,8 +8893,8 @@ var Renderer = class _Renderer {
8881
8893
  });
8882
8894
  renderer.setClearColor(0, 0);
8883
8895
  renderer.shadowMap.enabled = true;
8884
- renderer.shadowMap.type = import_three23.PCFSoftShadowMap;
8885
- renderer.outputColorSpace = import_three23.SRGBColorSpace;
8896
+ renderer.shadowMap.type = import_three24.PCFSoftShadowMap;
8897
+ renderer.outputColorSpace = import_three24.SRGBColorSpace;
8886
8898
  renderer.setSize(this.viewWidth, this.viewHeight);
8887
8899
  return renderer;
8888
8900
  }
@@ -8916,20 +8928,20 @@ var Renderer = class _Renderer {
8916
8928
  window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
8917
8929
  }
8918
8930
  if (this.options.debug.grid) {
8919
- const gridHelper = new import_three23.GridHelper(128, 16);
8931
+ const gridHelper = new import_three24.GridHelper(128, 16);
8920
8932
  this._debugHelpers.push(gridHelper);
8921
8933
  this.scene.add(gridHelper);
8922
- const gridHelper2 = new import_three23.GridHelper(128, 16);
8934
+ const gridHelper2 = new import_three24.GridHelper(128, 16);
8923
8935
  this._debugHelpers.push(gridHelper2);
8924
8936
  gridHelper2.rotation.x = 90 * (Math.PI / 180);
8925
8937
  this.scene.add(gridHelper2);
8926
- const gridHelper3 = new import_three23.GridHelper(128, 16);
8938
+ const gridHelper3 = new import_three24.GridHelper(128, 16);
8927
8939
  this._debugHelpers.push(gridHelper3);
8928
8940
  gridHelper3.rotation.z = 90 * (Math.PI / 180);
8929
8941
  this.scene.add(gridHelper3);
8930
8942
  }
8931
8943
  if (this.options.debug.axes) {
8932
- const axesHelper = new import_three23.AxesHelper(64);
8944
+ const axesHelper = new import_three24.AxesHelper(64);
8933
8945
  this._debugHelpers.push(axesHelper);
8934
8946
  this.scene.add(axesHelper);
8935
8947
  }
@@ -9536,32 +9548,121 @@ var AnvilParser = class {
9536
9548
  };
9537
9549
 
9538
9550
  // src/world/Chunk.ts
9551
+ var import_three29 = require("three");
9552
+
9553
+ // src/world/MineRenderWorld.ts
9554
+ var import_three27 = require("three");
9555
+
9556
+ // src/world/SectionModels.ts
9539
9557
  var import_three26 = require("three");
9558
+ var SectionModel = class extends ModelObject {
9559
+ applyTextures() {
9560
+ }
9561
+ };
9562
+ function cached(map, key, load) {
9563
+ let value = map.get(key);
9564
+ if (!value) {
9565
+ value = load().catch((error) => {
9566
+ map.delete(key);
9567
+ throw error;
9568
+ });
9569
+ map.set(key, value);
9570
+ }
9571
+ return value;
9572
+ }
9573
+ var SectionModels = class {
9574
+ constructor(maxAtlasSize = 2048) {
9575
+ this.maxAtlasSize = maxAtlasSize;
9576
+ this.states = /* @__PURE__ */ new WeakMap();
9577
+ this.models = /* @__PURE__ */ new WeakMap();
9578
+ this.templates = /* @__PURE__ */ new Set();
9579
+ if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
9580
+ }
9581
+ async get(blockState, properties = {}) {
9582
+ if (!blockState.variants || blockState.multipart) return void 0;
9583
+ let states = this.states.get(blockState);
9584
+ if (!states) this.states.set(blockState, states = /* @__PURE__ */ new Map());
9585
+ const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
9586
+ const prepared = await cached(states, key, () => this.prepare(blockState, properties));
9587
+ if (!prepared) return void 0;
9588
+ return prepared.templates.get(BlockStateResolver.choose(prepared.variants));
9589
+ }
9590
+ async prepare(blockState, properties) {
9591
+ const state = { ...await BlockStateResolver.defaults(blockState), ...properties };
9592
+ const groups = BlockStateResolver.matching(blockState, state);
9593
+ if (groups.length !== 1) return void 0;
9594
+ const variants = groups[0];
9595
+ const choices = Array.isArray(variants) ? variants : [variants];
9596
+ if (!choices.length) return void 0;
9597
+ const templates = /* @__PURE__ */ new Map();
9598
+ for (const variant of choices) {
9599
+ const model = await Models.getMerged(AssetKey.parse("models", variant.model));
9600
+ if (!model) return void 0;
9601
+ const atlas = await UVMapper.getAtlas(model);
9602
+ const rotation = BlockStateResolver.rotation(variant);
9603
+ if (!atlas || atlas.hasAnimation || !ModelCulling.isOpaqueFullCube(atlas) || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize || ModelCulling.toLocalMask(63, rotation) !== 63) return void 0;
9604
+ const tints = await BlockTints.get(blockState.key, state, model);
9605
+ let models = this.models.get(model);
9606
+ if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
9607
+ const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
9608
+ const template = await cached(models, key, async () => {
9609
+ const object = new SectionModel(model, {
9610
+ instanceMeshes: false,
9611
+ mergeMeshes: false,
9612
+ tints,
9613
+ uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
9614
+ });
9615
+ await object.init();
9616
+ const geometry = object.children[0].geometry;
9617
+ geometry.applyMatrix4(new import_three26.Matrix4().makeRotationFromEuler(rotation));
9618
+ object.clear();
9619
+ const cullFaces = CUBE_FACES.map((face) => {
9620
+ const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
9621
+ if (local < 0) return 0;
9622
+ const normal = new import_three26.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
9623
+ 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);
9624
+ return 1 << world;
9625
+ });
9626
+ const template2 = { geometry, atlas, cullFaces };
9627
+ this.templates.add(template2);
9628
+ return template2;
9629
+ });
9630
+ templates.set(variant, template);
9631
+ }
9632
+ return { variants, templates };
9633
+ }
9634
+ clear() {
9635
+ for (const template of this.templates) template.geometry.dispose();
9636
+ this.templates.clear();
9637
+ this.states = /* @__PURE__ */ new WeakMap();
9638
+ this.models = /* @__PURE__ */ new WeakMap();
9639
+ }
9640
+ };
9540
9641
 
9541
9642
  // src/world/MineRenderWorld.ts
9542
- var import_three25 = require("three");
9543
9643
  var MineRenderWorld = class {
9544
- constructor(scene) {
9644
+ constructor(scene, options = {}) {
9545
9645
  this._chunks = /* @__PURE__ */ new Map();
9546
9646
  this.pendingCulling = /* @__PURE__ */ new Map();
9547
9647
  this.scene = scene;
9648
+ if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
9548
9649
  }
9549
9650
  getBlockAt(posOrX, y, z) {
9550
9651
  if (typeof posOrX == "number") {
9551
- return this.getBlockAt(new import_three25.Vector3(posOrX, y, z));
9652
+ return this.getBlockAt(new import_three27.Vector3(posOrX, y, z));
9552
9653
  }
9553
9654
  if (isTripleArray(posOrX)) {
9554
- return this.getBlockAt(new import_three25.Vector3(posOrX[0], posOrX[1], posOrX[2]));
9655
+ return this.getBlockAt(new import_three27.Vector3(posOrX[0], posOrX[1], posOrX[2]));
9555
9656
  }
9556
9657
  this.validatePosBounds(posOrX);
9557
9658
  return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
9558
9659
  }
9559
9660
  async setBlockAt(posOrX, yOrBlock, z, block) {
9560
9661
  if (typeof posOrX == "number") {
9561
- return this.setBlockAt(new import_three25.Vector3(posOrX, yOrBlock, z), block);
9662
+ return this.setBlockAt(new import_three27.Vector3(posOrX, yOrBlock, z), block);
9562
9663
  }
9563
9664
  if (isTripleArray(posOrX)) {
9564
- return this.setBlockAt(new import_three25.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
9665
+ return this.setBlockAt(new import_three27.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
9565
9666
  }
9566
9667
  return this.placeBlock(posOrX, yOrBlock);
9567
9668
  }
@@ -9582,7 +9683,7 @@ var MineRenderWorld = class {
9582
9683
  const collect = async (positions2) => {
9583
9684
  for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
9584
9685
  };
9585
- const place = (block) => this.placeBlock(new import_three25.Vector3(...block.position), block, collect);
9686
+ const place = (block) => this.placeBlock(new import_three27.Vector3(...block.position), block, collect);
9586
9687
  const keys = /* @__PURE__ */ new Map();
9587
9688
  for (const block of multiblock.blocks) {
9588
9689
  if (Chunk.isAir(block)) continue;
@@ -9654,12 +9755,13 @@ var MineRenderWorld = class {
9654
9755
  for (const chunk of chunks) {
9655
9756
  await chunk.dispose();
9656
9757
  }
9758
+ this.sectionModels?.clear();
9657
9759
  }
9658
9760
  updateCulling(positions) {
9659
9761
  for (const pos of positions) {
9660
9762
  this.pendingCulling.set(pos.toArray().join(","), pos.clone());
9661
9763
  for (const offset of CUBE_FACE_OFFSETS) {
9662
- const neighbor = pos.clone().add(new import_three25.Vector3(...offset));
9764
+ const neighbor = pos.clone().add(new import_three27.Vector3(...offset));
9663
9765
  this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
9664
9766
  }
9665
9767
  }
@@ -9668,17 +9770,22 @@ var MineRenderWorld = class {
9668
9770
  while (this.pendingCulling.size) {
9669
9771
  const batch = [...this.pendingCulling.values()];
9670
9772
  this.pendingCulling.clear();
9773
+ const changed = /* @__PURE__ */ new Set();
9671
9774
  for (const pos of batch) {
9672
- const block = this.getBlockAt(pos)?.object;
9673
- if (!block) continue;
9775
+ const chunk = this.getChunkAt(pos);
9776
+ if (!chunk) continue;
9777
+ changed.add(chunk);
9778
+ if (!chunk.getBlockAt(pos)) continue;
9674
9779
  let mask = 0;
9675
9780
  for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
9676
- if (this.getBlockAt(pos.clone().add(new import_three25.Vector3(...offset)))?.object.isOccluding) {
9781
+ const neighbor = pos.clone().add(new import_three27.Vector3(...offset));
9782
+ if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
9677
9783
  mask |= 1 << face;
9678
9784
  }
9679
9785
  }
9680
- await block.setCullMask(mask);
9786
+ await chunk.setCullMaskAt(pos, mask);
9681
9787
  }
9788
+ for (const chunk of changed) chunk.rebuildSectionMesh();
9682
9789
  }
9683
9790
  } finally {
9684
9791
  this.culling = void 0;
@@ -9694,7 +9801,8 @@ var MineRenderWorld = class {
9694
9801
  Math.floor(pos.x / 16),
9695
9802
  Math.floor(pos.y / 16),
9696
9803
  Math.floor(pos.z / 16),
9697
- (positions) => this.updateCulling(positions)
9804
+ (positions) => this.updateCulling(positions),
9805
+ this.sectionModels
9698
9806
  );
9699
9807
  this._chunks.set(key, chunk);
9700
9808
  }
@@ -9704,14 +9812,14 @@ var MineRenderWorld = class {
9704
9812
  return this._chunks.get(this.worldPosToChunkKey(pos));
9705
9813
  }
9706
9814
  static worldToScenePosition(pos) {
9707
- return new import_three25.Vector3(
9815
+ return new import_three27.Vector3(
9708
9816
  pos.x * 16,
9709
9817
  pos.y * 16,
9710
9818
  pos.z * 16
9711
9819
  );
9712
9820
  }
9713
9821
  static sceneToWorldPosition(pos) {
9714
- return new import_three25.Vector3(
9822
+ return new import_three27.Vector3(
9715
9823
  pos.x / 16,
9716
9824
  pos.y / 16,
9717
9825
  pos.z / 16
@@ -9730,12 +9838,118 @@ var MineRenderWorld = class {
9730
9838
  }
9731
9839
  };
9732
9840
 
9841
+ // src/world/SectionMesh.ts
9842
+ var import_three28 = require("three");
9843
+ var SectionMesh = class _SectionMesh extends import_three28.Group {
9844
+ constructor() {
9845
+ super(...arguments);
9846
+ this.ownedMeshes = [];
9847
+ }
9848
+ static build(entries, maxAtlasSize = 2048) {
9849
+ if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
9850
+ const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
9851
+ const atlases = [...new Set(visible.map((entry) => entry.template.atlas))].sort((a, b) => b.image.height - a.image.height);
9852
+ const pages = [];
9853
+ const locations = /* @__PURE__ */ new Map();
9854
+ for (const atlas of atlases) {
9855
+ const { width, height } = atlas.image;
9856
+ if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
9857
+ let selected;
9858
+ for (const page of pages) {
9859
+ const nextRow = page.x + width > maxAtlasSize;
9860
+ if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;
9861
+ if (nextRow) {
9862
+ page.y += page.rowHeight;
9863
+ page.x = 0;
9864
+ page.rowHeight = 0;
9865
+ }
9866
+ selected = page;
9867
+ break;
9868
+ }
9869
+ if (!selected) {
9870
+ selected = { placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 };
9871
+ pages.push(selected);
9872
+ }
9873
+ const placement = { atlas, x: selected.x, y: selected.y };
9874
+ selected.placements.push(placement);
9875
+ selected.x += width;
9876
+ selected.rowHeight = Math.max(selected.rowHeight, height);
9877
+ selected.width = Math.max(selected.width, selected.x);
9878
+ selected.height = Math.max(selected.height, selected.y + height);
9879
+ locations.set(atlas, { page: selected, placement });
9880
+ }
9881
+ for (const entry of visible) locations.get(entry.template.atlas).page.entries.push(entry);
9882
+ const section = new _SectionMesh();
9883
+ for (const page of pages) {
9884
+ const canvas = createCanvas2(page.width, page.height);
9885
+ const context = canvas.getContext("2d");
9886
+ for (const { atlas, x, y } of page.placements) {
9887
+ context.drawImage(atlas.image.canvas, x, y);
9888
+ }
9889
+ const positions = [], normals = [], uvs = [], colors = [], indices = [];
9890
+ for (const { index, template, cullMask } of page.entries) {
9891
+ const position = template.geometry.getAttribute("position");
9892
+ const normal = template.geometry.getAttribute("normal");
9893
+ const uv = template.geometry.getAttribute("uv");
9894
+ const color = template.geometry.getAttribute("color");
9895
+ const sourceIndices = template.geometry.getIndex();
9896
+ const placement = locations.get(template.atlas).placement;
9897
+ const offsetX = index % 16 * 16;
9898
+ const offsetY = Math.floor(index / 256) * 16;
9899
+ const offsetZ = Math.floor(index / 16) % 16 * 16;
9900
+ for (let face = 0; face < 6; face++) {
9901
+ if (cullMask & template.cullFaces[face]) continue;
9902
+ const start = positions.length / 3;
9903
+ for (let corner = 0; corner < 4; corner++) {
9904
+ const vertex = face * 4 + corner;
9905
+ positions.push(position.getX(vertex) + offsetX, position.getY(vertex) + offsetY, position.getZ(vertex) + offsetZ);
9906
+ normals.push(normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex));
9907
+ uvs.push(
9908
+ (placement.x + uv.getX(vertex) * template.atlas.image.width) / page.width,
9909
+ 1 - (placement.y + (1 - uv.getY(vertex)) * template.atlas.image.height) / page.height
9910
+ );
9911
+ colors.push(color?.getX(vertex) ?? 1, color?.getY(vertex) ?? 1, color?.getZ(vertex) ?? 1);
9912
+ }
9913
+ for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
9914
+ }
9915
+ }
9916
+ const geometry = new import_three28.BufferGeometry();
9917
+ geometry.setAttribute("position", new import_three28.Float32BufferAttribute(positions, 3));
9918
+ geometry.setAttribute("normal", new import_three28.Float32BufferAttribute(normals, 3));
9919
+ geometry.setAttribute("uv", new import_three28.Float32BufferAttribute(uvs, 2));
9920
+ geometry.setAttribute("color", new import_three28.Float32BufferAttribute(colors, 3));
9921
+ geometry.setIndex(indices);
9922
+ geometry.computeBoundingBox();
9923
+ geometry.computeBoundingSphere();
9924
+ const material = Materials.createShadedCanvasMaterial(canvas, false);
9925
+ material.vertexColors = true;
9926
+ const texture = material.uniforms?.map?.value ?? material.map;
9927
+ const mesh = new import_three28.Mesh(geometry, material);
9928
+ section.add(mesh);
9929
+ section.ownedMeshes.push({ mesh, texture });
9930
+ }
9931
+ return section;
9932
+ }
9933
+ dispose() {
9934
+ for (const { mesh, texture } of this.ownedMeshes.splice(0)) {
9935
+ mesh.removeFromParent();
9936
+ mesh.geometry.dispose();
9937
+ mesh.material.dispose();
9938
+ texture?.dispose();
9939
+ }
9940
+ this.removeFromParent();
9941
+ }
9942
+ };
9943
+
9733
9944
  // src/world/Chunk.ts
9734
9945
  var Chunk = class _Chunk {
9735
- constructor(scene, x, y, z, onBlocksChanged) {
9946
+ constructor(scene, x, y, z, onBlocksChanged, sectionModels) {
9736
9947
  this.onBlocksChanged = onBlocksChanged;
9948
+ this.sectionModels = sectionModels;
9737
9949
  this.data = new ChunkData();
9738
9950
  this.renderedBlocks = /* @__PURE__ */ new Map();
9951
+ this.sectionBlocks = /* @__PURE__ */ new Map();
9952
+ this.meshDirty = false;
9739
9953
  this.scene = scene;
9740
9954
  this.x = x;
9741
9955
  this.y = y;
@@ -9743,10 +9957,10 @@ var Chunk = class _Chunk {
9743
9957
  }
9744
9958
  getBlockAt(posOrX, y, z) {
9745
9959
  if (typeof posOrX == "number") {
9746
- return this.getBlockAt(new import_three26.Vector3(posOrX, y, z));
9960
+ return this.getBlockAt(new import_three29.Vector3(posOrX, y, z));
9747
9961
  }
9748
9962
  if (isTripleArray(posOrX)) {
9749
- return this.getBlockAt(new import_three26.Vector3(posOrX[0], posOrX[1], posOrX[2]));
9963
+ return this.getBlockAt(new import_three29.Vector3(posOrX[0], posOrX[1], posOrX[2]));
9750
9964
  }
9751
9965
  const pos = this.worldPosToChunkPos(posOrX);
9752
9966
  const index = _Chunk.chunkPosToBlockIndex(pos);
@@ -9754,10 +9968,10 @@ var Chunk = class _Chunk {
9754
9968
  }
9755
9969
  async setBlockAt(posOrX, yOrBlock, z, block) {
9756
9970
  if (typeof posOrX == "number") {
9757
- return this.setBlockAt(new import_three26.Vector3(posOrX, yOrBlock, z), block);
9971
+ return this.setBlockAt(new import_three29.Vector3(posOrX, yOrBlock, z), block);
9758
9972
  }
9759
9973
  if (isTripleArray(posOrX)) {
9760
- return this.setBlockAt(new import_three26.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
9974
+ return this.setBlockAt(new import_three29.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
9761
9975
  }
9762
9976
  const worldPos = posOrX;
9763
9977
  const pos = this.worldPosToChunkPos(worldPos);
@@ -9774,7 +9988,8 @@ var Chunk = class _Chunk {
9774
9988
  const index = _Chunk.chunkPosToBlockIndex(pos);
9775
9989
  this.data.set(index, block);
9776
9990
  const readBlock = this.data.snapshot(index);
9777
- this.renderedBlocks.get(index)?.object.removeFromScene();
9991
+ this.renderedBlocks.get(index)?.object?.removeFromScene();
9992
+ if (this.sectionBlocks.delete(index)) this.meshDirty = true;
9778
9993
  this.renderedBlocks.delete(index);
9779
9994
  let object;
9780
9995
  try {
@@ -9785,13 +10000,19 @@ var Chunk = class _Chunk {
9785
10000
  this.data.set(index, void 0);
9786
10001
  return void 0;
9787
10002
  }
9788
- object = await this.scene.addBlock(blockState, {
9789
- mergeMeshes: true,
9790
- instanceMeshes: true,
9791
- maxInstanceCount: 2e3,
9792
- initialState: stored.properties
9793
- });
9794
- object.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
10003
+ const template = await this.sectionModels?.get(blockState, stored.properties);
10004
+ if (template) {
10005
+ this.sectionBlocks.set(index, { index, template, cullMask: 0 });
10006
+ this.meshDirty = true;
10007
+ } else {
10008
+ object = await this.scene.addBlock(blockState, {
10009
+ mergeMeshes: true,
10010
+ instanceMeshes: true,
10011
+ maxInstanceCount: 2e3,
10012
+ initialState: stored.properties
10013
+ });
10014
+ object.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
10015
+ }
9795
10016
  const info = { get block() {
9796
10017
  return readBlock();
9797
10018
  }, object };
@@ -9805,11 +10026,43 @@ var Chunk = class _Chunk {
9805
10026
  await onBlocksChanged?.([worldPos]);
9806
10027
  }
9807
10028
  }
10029
+ isOccludingAt(pos) {
10030
+ const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
10031
+ return this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false);
10032
+ }
10033
+ async setCullMaskAt(pos, mask) {
10034
+ const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
10035
+ const entry = this.sectionBlocks.get(index);
10036
+ if (entry) {
10037
+ if (entry.cullMask !== mask) {
10038
+ entry.cullMask = mask;
10039
+ this.meshDirty = true;
10040
+ }
10041
+ } else {
10042
+ await this.renderedBlocks.get(index)?.object?.setCullMask(mask);
10043
+ }
10044
+ }
10045
+ rebuildSectionMesh() {
10046
+ if (!this.meshDirty) return;
10047
+ const next = this.sectionBlocks.size ? SectionMesh.build([...this.sectionBlocks.values()], this.sectionModels.maxAtlasSize) : void 0;
10048
+ this.sectionMesh?.dispose();
10049
+ this.sectionMesh = next;
10050
+ if (next) {
10051
+ next.position.set(this.x * 256, this.y * 256, this.z * 256);
10052
+ this.scene.add(next);
10053
+ }
10054
+ this.scene.dirty = true;
10055
+ this.meshDirty = false;
10056
+ }
9808
10057
  async clear(onBlocksChanged = this.onBlocksChanged) {
9809
10058
  const positions = [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
9810
- new import_three26.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
10059
+ new import_three29.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
9811
10060
  ));
9812
- for (const info of this.renderedBlocks.values()) info.object.removeFromScene();
10061
+ for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
10062
+ this.sectionBlocks.clear();
10063
+ this.sectionMesh?.dispose();
10064
+ this.sectionMesh = void 0;
10065
+ this.meshDirty = false;
9813
10066
  this.renderedBlocks.clear();
9814
10067
  this.data.clear();
9815
10068
  await onBlocksChanged?.(positions);
@@ -9827,14 +10080,14 @@ var Chunk = class _Chunk {
9827
10080
  return pos.y * 16 * 16 + pos.z * 16 + pos.x;
9828
10081
  }
9829
10082
  worldPosToChunkPos(pos) {
9830
- return new import_three26.Vector3(
10083
+ return new import_three29.Vector3(
9831
10084
  pos.x - this.x * 16,
9832
10085
  pos.y - this.y * 16,
9833
10086
  pos.z - this.z * 16
9834
10087
  );
9835
10088
  }
9836
10089
  chunkPosToWorldPos(pos) {
9837
- return new import_three26.Vector3(
10090
+ return new import_three29.Vector3(
9838
10091
  this.x * 16 + pos.x,
9839
10092
  this.y * 16 + pos.y,
9840
10093
  this.z * 16 + pos.z
@@ -9858,6 +10111,7 @@ var Chunk = class _Chunk {
9858
10111
  BasicAssetKey,
9859
10112
  BatchedExecutor,
9860
10113
  BlockObject,
10114
+ BlockStateResolver,
9861
10115
  BlockStates,
9862
10116
  BlockTints,
9863
10117
  BrowserArchiveProxy,
@@ -9916,6 +10170,8 @@ var Chunk = class _Chunk {
9916
10170
  SceneStats,
9917
10171
  SceneStatsDisplay,
9918
10172
  SchematicParser,
10173
+ SectionMesh,
10174
+ SectionModels,
9919
10175
  SkinImage,
9920
10176
  SkinObject,
9921
10177
  SkinPart,