minerender 2.1.0-alpha.87 → 2.1.0-alpha.89

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.
package/dist/bundle.js CHANGED
@@ -21996,8 +21996,8 @@ var MineRender = (() => {
21996
21996
  }
21997
21997
  }
21998
21998
  }
21999
- function vertexAttribPointer(index, size, type, normalized, stride, offset, integer2) {
22000
- if (integer2 === true) {
21999
+ function vertexAttribPointer(index, size, type, normalized, stride, offset, integer3) {
22000
+ if (integer3 === true) {
22001
22001
  gl.vertexAttribIPointer(index, size, type, stride, offset);
22002
22002
  } else {
22003
22003
  gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
@@ -22024,7 +22024,7 @@ var MineRender = (() => {
22024
22024
  const buffer2 = attribute.buffer;
22025
22025
  const type = attribute.type;
22026
22026
  const bytesPerElement = attribute.bytesPerElement;
22027
- const integer2 = type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType;
22027
+ const integer3 = type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType;
22028
22028
  if (geometryAttribute.isInterleavedBufferAttribute) {
22029
22029
  const data = geometryAttribute.data;
22030
22030
  const stride = data.stride;
@@ -22050,7 +22050,7 @@ var MineRender = (() => {
22050
22050
  normalized,
22051
22051
  stride * bytesPerElement,
22052
22052
  (offset + size / programAttribute.locationSize * i4) * bytesPerElement,
22053
- integer2
22053
+ integer3
22054
22054
  );
22055
22055
  }
22056
22056
  } else {
@@ -22075,7 +22075,7 @@ var MineRender = (() => {
22075
22075
  normalized,
22076
22076
  size * bytesPerElement,
22077
22077
  size / programAttribute.locationSize * i4 * bytesPerElement,
22078
- integer2
22078
+ integer3
22079
22079
  );
22080
22080
  }
22081
22081
  }
@@ -39810,6 +39810,23 @@ void main() {
39810
39810
  setTimeout(() => resolve(), timeout);
39811
39811
  });
39812
39812
  }
39813
+ function yieldToEventLoop() {
39814
+ const scheduler = globalThis.scheduler;
39815
+ if (scheduler?.yield) return scheduler.yield();
39816
+ return new Promise((resolve) => {
39817
+ if (typeof MessageChannel !== "undefined") {
39818
+ const channel = new MessageChannel();
39819
+ channel.port1.onmessage = () => {
39820
+ channel.port1.close();
39821
+ channel.port2.close();
39822
+ resolve();
39823
+ };
39824
+ channel.port2.postMessage(void 0);
39825
+ } else {
39826
+ setTimeout(resolve, 0);
39827
+ }
39828
+ });
39829
+ }
39813
39830
  function clampRotationDegrees(deg) {
39814
39831
  return deg % 360;
39815
39832
  }
@@ -99623,7 +99640,7 @@ return ${compiler2.callType("value", tagType)}
99623
99640
  });
99624
99641
 
99625
99642
  // ../../node_modules/@zip.js/zip.js/lib/zip-fs.js
99626
- var import_meta, baseURL;
99643
+ var import_meta2, baseURL;
99627
99644
  var init_zip_fs = __esm({
99628
99645
  "../../node_modules/@zip.js/zip.js/lib/zip-fs.js"() {
99629
99646
  init_dirname();
@@ -99638,9 +99655,9 @@ return ${compiler2.callType("value", tagType)}
99638
99655
  init_zip_reader();
99639
99656
  init_zip_writer();
99640
99657
  init_zip_fs_core();
99641
- import_meta = {};
99658
+ import_meta2 = {};
99642
99659
  try {
99643
- baseURL = import_meta.url;
99660
+ baseURL = import_meta2.url;
99644
99661
  } catch (_4) {
99645
99662
  }
99646
99663
  configure({ baseURL });
@@ -106568,12 +106585,14 @@ ${shader.fragmentShader}`.replace(
106568
106585
  SchematicParser: () => SchematicParser,
106569
106586
  SectionMesh: () => SectionMesh,
106570
106587
  SectionModels: () => SectionModels,
106588
+ SectionWorker: () => SectionWorker,
106571
106589
  SkinImage: () => SkinImage,
106572
106590
  SkinObject: () => SkinObject,
106573
106591
  SkinPart: () => SkinPart,
106574
106592
  SkinTextures: () => SkinTextures,
106575
106593
  Skins: () => Skins,
106576
106594
  SpecialItems: () => SpecialItems,
106595
+ SpongeSchematicParser: () => SpongeSchematicParser,
106577
106596
  StructureParser: () => StructureParser,
106578
106597
  TextureAtlas: () => TextureAtlas,
106579
106598
  TextureLoader: () => TextureLoader2,
@@ -106592,6 +106611,7 @@ ${shader.fragmentShader}`.replace(
106592
106611
  axisToVec3: () => axisToVec3,
106593
106612
  base64decode: () => base64decode,
106594
106613
  base64encode: () => base64encode,
106614
+ buildSectionGeometry: () => buildSectionGeometry,
106595
106615
  capeTextureSizes: () => capeTextureSizes,
106596
106616
  captureException: () => captureException,
106597
106617
  changeEvent: () => changeEvent,
@@ -106644,6 +106664,7 @@ ${shader.fragmentShader}`.replace(
106644
106664
  sampleEntityAnimation: () => sampleEntityAnimation,
106645
106665
  sampleEntityKeyframes: () => sampleEntityKeyframes,
106646
106666
  sampleFluid: () => sampleFluid,
106667
+ sectionGeometryTransferables: () => sectionGeometryTransferables,
106647
106668
  serializeBoxGeometryKey: () => serializeBoxGeometryKey,
106648
106669
  serializeImageKey: () => serializeImageKey,
106649
106670
  serializeMaterialKey: () => serializeMaterialKey,
@@ -106661,7 +106682,8 @@ ${shader.fragmentShader}`.replace(
106661
106682
  toDegrees: () => toDegrees,
106662
106683
  toRadians: () => toRadians,
106663
106684
  toTrianglesDrawMode: () => toTrianglesDrawMode,
106664
- trimCanvas: () => trimCanvas
106685
+ trimCanvas: () => trimCanvas,
106686
+ yieldToEventLoop: () => yieldToEventLoop
106665
106687
  });
106666
106688
  init_dirname();
106667
106689
  init_buffer2();
@@ -106762,6 +106784,7 @@ ${shader.fragmentShader}`.replace(
106762
106784
  }
106763
106785
 
106764
106786
  // src/env/browser/BrowserEnv.ts
106787
+ var import_meta = {};
106765
106788
  var BrowserEnv = class {
106766
106789
  constructor() {
106767
106790
  this.name = "browser";
@@ -106789,6 +106812,14 @@ ${shader.fragmentShader}`.replace(
106789
106812
  version: version3
106790
106813
  }));
106791
106814
  }
106815
+ createWorker(name2) {
106816
+ if (name2 !== "section" || typeof Worker === "undefined") return void 0;
106817
+ try {
106818
+ return new Worker(new URL("./section.worker.mjs", import_meta.url), { type: "module" });
106819
+ } catch {
106820
+ return void 0;
106821
+ }
106822
+ }
106792
106823
  };
106793
106824
  function registerBrowserEnv() {
106794
106825
  const env3 = new BrowserEnv();
@@ -111337,46 +111368,46 @@ property list uchar int vertex_index
111337
111368
  }
111338
111369
  var BlockStateResolver = class {
111339
111370
  /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
111340
- static async defaults(blockState) {
111341
- const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
111371
+ static async defaults(blockState2) {
111372
+ const defaults = blockState2.key ? await BlockStates.getDefaultState(blockState2.key) : void 0;
111342
111373
  const state = {};
111343
111374
  if (defaults && Object.keys(defaults).length > 0) {
111344
111375
  for (const key in defaults) state[key] = defaults[key].default;
111345
- } else if (blockState.variants) {
111346
- const variant = Object.keys(blockState.variants)[0];
111376
+ } else if (blockState2.variants) {
111377
+ const variant = Object.keys(blockState2.variants)[0];
111347
111378
  if (variant) {
111348
111379
  for (const property of variant.split(",")) {
111349
111380
  const [key, value] = property.split("=");
111350
111381
  state[key] = value;
111351
111382
  }
111352
111383
  }
111353
- } else if (blockState.multipart) {
111354
- const condition = blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
111384
+ } else if (blockState2.multipart) {
111385
+ const condition = blockState2.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
111355
111386
  for (const [key, value] of Object.entries(condition ?? {})) state[key] = value.split("|")[0];
111356
111387
  }
111357
111388
  return state;
111358
111389
  }
111359
111390
  /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
111360
- static select(blockState, state, choose = this.choose) {
111361
- return this.matching(blockState, state).map(choose);
111391
+ static select(blockState2, state, choose = this.choose) {
111392
+ return this.matching(blockState2, state).map(choose);
111362
111393
  }
111363
111394
  /** Returns matching model groups before choosing weighted alternatives. */
111364
- static matching(blockState, state) {
111395
+ static matching(blockState2, state) {
111365
111396
  const out = [];
111366
- if (blockState.variants) {
111367
- if (Object.keys(blockState.variants).length === 1 && "" in blockState.variants) {
111368
- out.push(blockState.variants[""]);
111397
+ if (blockState2.variants) {
111398
+ if (Object.keys(blockState2.variants).length === 1 && "" in blockState2.variants) {
111399
+ out.push(blockState2.variants[""]);
111369
111400
  } else {
111370
- for (const variantKey in blockState.variants) {
111401
+ for (const variantKey in blockState2.variants) {
111371
111402
  const matches = variantKey.split(",").every((property) => {
111372
111403
  const [key, value] = property.split("=");
111373
111404
  return `${state[key]}` === `${value}`;
111374
111405
  });
111375
- if (matches) out.push(blockState.variants[variantKey]);
111406
+ if (matches) out.push(blockState2.variants[variantKey]);
111376
111407
  }
111377
111408
  }
111378
- } else if (blockState.multipart) {
111379
- for (const part of blockState.multipart) {
111409
+ } else if (blockState2.multipart) {
111410
+ for (const part of blockState2.multipart) {
111380
111411
  if (part.apply && (!part.when || matchesCondition(part.when, state))) {
111381
111412
  out.push(part.apply);
111382
111413
  }
@@ -111515,9 +111546,9 @@ property list uchar int vertex_index
111515
111546
  init_FluidGeometry();
111516
111547
  init_Entities();
111517
111548
  var _BlockObject = class _BlockObject extends SceneObject {
111518
- constructor(blockState, options) {
111549
+ constructor(blockState2, options) {
111519
111550
  super(options);
111520
- this.blockState = blockState;
111551
+ this.blockState = blockState2;
111521
111552
  this.isBlockObject = true;
111522
111553
  this._previousState = {};
111523
111554
  this._state = {};
@@ -113712,6 +113743,160 @@ property list uchar int vertex_index
113712
113743
  throw new MineRenderError(`Schematic ${name2} must be a compound list`);
113713
113744
  }
113714
113745
 
113746
+ // src/model/multiblock/SpongeSchematicParser.ts
113747
+ init_dirname();
113748
+ init_buffer2();
113749
+ init_process2();
113750
+ init_MineRenderError();
113751
+ var SpongeSchematicParser = class {
113752
+ /**
113753
+ * Parses decoded NBT with a local block palette, omitting air blocks.
113754
+ * Applies Offset to block and entity positions; size remains the source dimensions.
113755
+ * Biomes and metadata are not imported, and DataVersion does not trigger migration.
113756
+ */
113757
+ static async parse(nbt) {
113758
+ const tags = nbt.value.Schematic === void 0 ? nbt.value : compound(nbt.value.Schematic, "Schematic");
113759
+ const version3 = integer2(tags.Version, "Version");
113760
+ if (version3 !== 2 && version3 !== 3) {
113761
+ throw new MineRenderError(`Unsupported Sponge schematic version ${version3}; expected 2 or 3`);
113762
+ }
113763
+ const dataVersion = integer2(tags.DataVersion, "DataVersion");
113764
+ const size = ["Width", "Height", "Length"].map((name2) => {
113765
+ const tag = tags[name2];
113766
+ if (tag?.type !== "short" || !Number.isInteger(tag.value) || tag.value < -32768 || tag.value > 65535 || tag.value === 0) {
113767
+ throw new MineRenderError(`Sponge schematic ${name2} must be a positive unsigned short`);
113768
+ }
113769
+ return tag.value & 65535;
113770
+ });
113771
+ const offset = tags.Offset === void 0 ? [0, 0, 0] : intPosition(tags.Offset, "Offset");
113772
+ const blocks = [];
113773
+ const container = version3 === 2 ? tags : tags.Blocks === void 0 ? void 0 : compound(tags.Blocks, "Blocks");
113774
+ if (container) {
113775
+ const paletteTag = container.Palette;
113776
+ if (!paletteTag) throw new MineRenderError("Sponge schematic requires a local Palette; global block IDs are not supported");
113777
+ const palette = /* @__PURE__ */ new Map();
113778
+ const paletteMax = version3 === 2 && tags.PaletteMax !== void 0 ? integer2(tags.PaletteMax, "PaletteMax") : void 0;
113779
+ if (paletteMax !== void 0 && paletteMax <= 0) throw new MineRenderError("Sponge schematic PaletteMax must be positive");
113780
+ for (const [state, tag] of Object.entries(compound(paletteTag, "Palette"))) {
113781
+ const id = integer2(tag, "Palette index");
113782
+ if (id < 0 || palette.has(id) || paletteMax !== void 0 && id >= paletteMax) {
113783
+ throw new MineRenderError(`Invalid or duplicate Sponge schematic palette index ${id}`);
113784
+ }
113785
+ palette.set(id, blockState(state));
113786
+ }
113787
+ const [width, height, length] = size;
113788
+ const volume = width * height * length;
113789
+ const data = container[version3 === 2 ? "BlockData" : "Data"];
113790
+ if (data?.type !== "byteArray" || !Array.isArray(data.value) || data.value.length < volume) {
113791
+ throw new MineRenderError(`Sponge schematic block data must contain ${volume} varints`);
113792
+ }
113793
+ const blockEntities = /* @__PURE__ */ new Map();
113794
+ for (const entity of compoundList2(container, "BlockEntities")) {
113795
+ const pos = intPosition(entity.Pos, "BlockEntities Pos");
113796
+ if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
113797
+ throw new MineRenderError("Sponge schematic block entity position is outside its dimensions");
113798
+ }
113799
+ const index = pos[0] + pos[2] * width + pos[1] * width * length;
113800
+ if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Sponge schematic block entity at index ${index}`);
113801
+ const value = entityData(entity, version3);
113802
+ for (const [axis, name2] of ["x", "y", "z"].entries()) {
113803
+ value[name2] = { type: "int", value: pos[axis] + offset[axis] };
113804
+ }
113805
+ blockEntities.set(index, { type: "compound", value });
113806
+ }
113807
+ let cursor = 0;
113808
+ for (let index = 0; index < volume; index++) {
113809
+ let id = 0;
113810
+ for (let shift = 0; ; shift += 7) {
113811
+ const byte = data.value[cursor++];
113812
+ if (!Number.isInteger(byte) || byte < -128 || byte > 255) {
113813
+ throw new MineRenderError(`Invalid or truncated Sponge schematic varint at index ${index}`);
113814
+ }
113815
+ const unsigned = byte & 255;
113816
+ if (shift === 28 && unsigned > 7) {
113817
+ throw new MineRenderError(`Sponge schematic varint exceeds a nonnegative int at index ${index}`);
113818
+ }
113819
+ id += (unsigned & 127) * 2 ** shift;
113820
+ if ((unsigned & 128) === 0) break;
113821
+ }
113822
+ const state = palette.get(id);
113823
+ if (!state) throw new MineRenderError(`Sponge schematic palette index ${id} does not exist`);
113824
+ if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) continue;
113825
+ blocks.push({
113826
+ type: state.type,
113827
+ properties: { ...state.properties },
113828
+ position: [
113829
+ index % width + offset[0],
113830
+ Math.floor(index / (width * length)) + offset[1],
113831
+ Math.floor(index / width) % length + offset[2]
113832
+ ],
113833
+ nbt: blockEntities.get(index)
113834
+ });
113835
+ }
113836
+ if (cursor !== data.value.length) throw new MineRenderError("Sponge schematic block data has trailing bytes");
113837
+ }
113838
+ const entities = compoundList2(tags, "Entities").map((entity) => {
113839
+ const pos = entity.Pos;
113840
+ if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
113841
+ throw new MineRenderError("Sponge schematic entity Pos must contain three doubles");
113842
+ }
113843
+ const position = pos.value.value.map((value2, axis) => value2 + offset[axis]);
113844
+ const value = entityData(entity, version3);
113845
+ value.Pos = { type: "list", value: { type: "double", value: [...position] } };
113846
+ return { position, nbt: { type: "compound", value } };
113847
+ });
113848
+ return { size, blocks, entities, dataVersion };
113849
+ }
113850
+ };
113851
+ function integer2(tag, name2) {
113852
+ if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
113853
+ throw new MineRenderError(`Sponge schematic ${name2} must be an int`);
113854
+ }
113855
+ return tag.value;
113856
+ }
113857
+ function compound(tag, name2) {
113858
+ if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
113859
+ throw new MineRenderError(`Sponge schematic ${name2} must be a compound`);
113860
+ }
113861
+ return tag.value;
113862
+ }
113863
+ function intPosition(tag, name2) {
113864
+ if (tag?.type !== "intArray" || !Array.isArray(tag.value) || tag.value.length !== 3 || !tag.value.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 2147483647)) {
113865
+ throw new MineRenderError(`Sponge schematic ${name2} must contain three ints`);
113866
+ }
113867
+ return [...tag.value];
113868
+ }
113869
+ function compoundList2(tags, name2) {
113870
+ const tag = tags[name2];
113871
+ if (tag === void 0) return [];
113872
+ if (tag.type === "list" && Array.isArray(tag.value.value)) {
113873
+ if (tag.value.value.length === 0) return [];
113874
+ if (tag.value.type === "compound") return tag.value.value;
113875
+ }
113876
+ throw new MineRenderError(`Sponge schematic ${name2} must be a compound list`);
113877
+ }
113878
+ function blockState(state) {
113879
+ const match = /^((?:[a-z0-9_.-]+:)?[a-z0-9_./-]+)(?:\[([^\[\]]*)\])?$/.exec(state);
113880
+ if (!match) throw new MineRenderError(`Invalid Sponge schematic block state ${state}`);
113881
+ const properties = {};
113882
+ if (match[2]) {
113883
+ for (const entry of match[2].split(",")) {
113884
+ const pair = /^([a-z0-9_]+)=([^\s=,\[\]]+)$/.exec(entry);
113885
+ if (!pair || Object.prototype.hasOwnProperty.call(properties, pair[1])) throw new MineRenderError(`Invalid Sponge schematic block state ${state}`);
113886
+ Object.defineProperty(properties, pair[1], { value: pair[2], enumerable: true, writable: true, configurable: true });
113887
+ }
113888
+ }
113889
+ return { type: match[1].includes(":") ? match[1] : `minecraft:${match[1]}`, properties };
113890
+ }
113891
+ function entityData(entity, version3) {
113892
+ const id = entity.Id;
113893
+ if (id?.type !== "string" || !id.value) throw new MineRenderError("Sponge schematic entity Id must be a nonempty string");
113894
+ const { Id, Pos, ...extra } = entity;
113895
+ const value = version3 === 2 ? extra : entity.Data === void 0 ? {} : { ...compound(entity.Data, "entity Data") };
113896
+ value.id = { type: "string", value: id.value.includes(":") ? id.value : `minecraft:${id.value}` };
113897
+ return value;
113898
+ }
113899
+
113715
113900
  // src/model/multiblock/StructureParser.ts
113716
113901
  init_dirname();
113717
113902
  init_buffer2();
@@ -114971,8 +115156,8 @@ property list uchar int vertex_index
114971
115156
  * Set `options.initialState` to choose block properties such as `facing` or `axis`.
114972
115157
  * Use the returned object's `setPosition` method to move all of its model parts.
114973
115158
  */
114974
- async addBlock(blockState, options, parent = this) {
114975
- return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
115159
+ async addBlock(blockState2, options, parent = this) {
115160
+ return this.addSceneObject(blockState2, () => new BlockObject(blockState2, options), options, parent);
114976
115161
  }
114977
115162
  /**
114978
115163
  * Loads a skin and adds an initialized player model.
@@ -118755,6 +118940,16 @@ gl_FragDepth=readDepth(vUv);
118755
118940
  init_buffer2();
118756
118941
  init_process2();
118757
118942
  init_AssetKey();
118943
+ var blockKeys = /* @__PURE__ */ new Map();
118944
+ function blockKey(type) {
118945
+ let key = blockKeys.get(type);
118946
+ if (!key) {
118947
+ key = AssetKey.parse("blockstates", type);
118948
+ if (blockKeys.size >= 4096) blockKeys.clear();
118949
+ blockKeys.set(type, key);
118950
+ }
118951
+ return key;
118952
+ }
118758
118953
  var ChunkData = class _ChunkData {
118759
118954
  constructor() {
118760
118955
  this.indices = new Uint16Array(4096);
@@ -118782,10 +118977,10 @@ gl_FragDepth=readDepth(vUv);
118782
118977
  let key;
118783
118978
  let nbt;
118784
118979
  if (block && !_ChunkData.isAir(block)) {
118785
- const type = AssetKey.parse("blockstates", block.type).toNamespacedString();
118980
+ const type = blockKey(block.type).toNamespacedString();
118786
118981
  const properties = Object.fromEntries(Object.keys(block.properties ?? {}).sort().map((name2) => [name2, block.properties[name2]]));
118787
118982
  state = Object.freeze(Object.keys(properties).length ? { type, properties: Object.freeze(properties) } : { type });
118788
- key = JSON.stringify([type, properties]);
118983
+ key = _ChunkData.paletteKey(block);
118789
118984
  if (block.nbt !== void 0) nbt = structuredClone(block.nbt);
118790
118985
  }
118791
118986
  const previousId = this.indices[index];
@@ -118822,9 +119017,14 @@ gl_FragDepth=readDepth(vUv);
118822
119017
  }
118823
119018
  static isAir(block) {
118824
119019
  if (typeof block === "undefined" || typeof block.type === "undefined") return true;
118825
- const key = AssetKey.parse("blockstates", block.type);
119020
+ const key = blockKey(block.type);
118826
119021
  return key.namespace === "minecraft" && !key.type && ["air", "cave_air", "void_air"].includes(key.path);
118827
119022
  }
119023
+ /** Identifies a normalized block type and its sorted properties, excluding per-cell NBT. */
119024
+ static paletteKey(block) {
119025
+ const properties = Object.fromEntries(Object.keys(block.properties ?? {}).sort().map((name2) => [name2, block.properties[name2]]));
119026
+ return JSON.stringify([blockKey(block.type).toNamespacedString(), properties]);
119027
+ }
118828
119028
  static copyBlock(state, nbt) {
118829
119029
  const block = { type: state.type };
118830
119030
  if (state.properties) block.properties = { ...state.properties };
@@ -119004,14 +119204,17 @@ gl_FragDepth=readDepth(vUv);
119004
119204
  const perLong = Math.floor(64 / bits2);
119005
119205
  const expected = padded ? Math.ceil(4096 / perLong) : Math.ceil(4096 * bits2 / 64);
119006
119206
  if (tag.value.length !== expected) throw new MineRenderError(`Invalid Anvil block-state array length: expected ${expected}`);
119007
- const words = tag.value.map(([high, low]) => BigInt(high >>> 0) << 32n | BigInt(low >>> 0));
119008
- const mask = (1n << BigInt(bits2)) - 1n;
119207
+ const words = tag.value.map(([high, low]) => [high >>> 0, low >>> 0]);
119208
+ const mask = (1 << bits2) - 1;
119009
119209
  for (let index = 0; index < 4096; index++) {
119010
- const word = padded ? Math.floor(index / perLong) : Math.floor(index * bits2 / 64);
119011
- const shift = padded ? index % perLong * bits2 : index * bits2 % 64;
119012
- let value = words[word] >> BigInt(shift);
119013
- if (!padded && shift + bits2 > 64) value |= words[word + 1] << BigInt(64 - shift);
119014
- indices[index] = Number(value & mask);
119210
+ const bitPos = index * bits2;
119211
+ const word = padded ? Math.floor(index / perLong) : bitPos >>> 6;
119212
+ const shift = padded ? index % perLong * bits2 : bitPos & 63;
119213
+ const [high, low] = words[word];
119214
+ let value = shift < 32 ? low >>> shift : high >>> shift - 32;
119215
+ if (shift < 32 && shift + bits2 > 32) value += high * 2 ** (32 - shift);
119216
+ if (!padded && shift + bits2 > 64) value += words[word + 1][1] * 2 ** (64 - shift);
119217
+ indices[index] = value & mask;
119015
119218
  }
119016
119219
  return indices;
119017
119220
  }
@@ -119167,7 +119370,7 @@ gl_FragDepth=readDepth(vUv);
119167
119370
  init_process2();
119168
119371
  init_three_module();
119169
119372
  init_Model();
119170
- init_BatchedExecutor();
119373
+ init_util();
119171
119374
  init_AssetKey();
119172
119375
  init_BlockStates();
119173
119376
  init_CubeFace();
@@ -119207,18 +119410,18 @@ gl_FragDepth=readDepth(vUv);
119207
119410
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
119208
119411
  }
119209
119412
  /** Returns a cube template, or `undefined` when the block requires an individual render object. */
119210
- async get(blockState, properties = {}) {
119211
- if (!blockState.variants || blockState.multipart) return void 0;
119212
- let states = this.states.get(blockState);
119213
- if (!states) this.states.set(blockState, states = /* @__PURE__ */ new Map());
119413
+ async get(blockState2, properties = {}) {
119414
+ if (!blockState2.variants || blockState2.multipart) return void 0;
119415
+ let states = this.states.get(blockState2);
119416
+ if (!states) this.states.set(blockState2, states = /* @__PURE__ */ new Map());
119214
119417
  const key = JSON.stringify(Object.entries(properties).sort(([a4], [b4]) => a4.localeCompare(b4)));
119215
- const prepared = await cached(states, key, () => this.prepare(blockState, properties));
119418
+ const prepared = await cached(states, key, () => this.prepare(blockState2, properties));
119216
119419
  if (!prepared) return void 0;
119217
119420
  return prepared.templates.get(BlockStateResolver.choose(prepared.variants));
119218
119421
  }
119219
- async prepare(blockState, properties) {
119220
- const state = { ...await BlockStateResolver.defaults(blockState), ...properties };
119221
- const groups = BlockStateResolver.matching(blockState, state);
119422
+ async prepare(blockState2, properties) {
119423
+ const state = { ...await BlockStateResolver.defaults(blockState2), ...properties };
119424
+ const groups = BlockStateResolver.matching(blockState2, state);
119222
119425
  if (groups.length !== 1) return void 0;
119223
119426
  const variants = groups[0];
119224
119427
  const choices = Array.isArray(variants) ? variants : [variants];
@@ -119230,7 +119433,7 @@ gl_FragDepth=readDepth(vUv);
119230
119433
  const atlas = await UVMapper.getAtlas(model);
119231
119434
  const rotation = BlockStateResolver.rotation(variant);
119232
119435
  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;
119233
- const tints = await BlockTints.get(blockState.key, state, model);
119436
+ const tints = await BlockTints.get(blockState2.key, state, model);
119234
119437
  let models = this.models.get(model);
119235
119438
  if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
119236
119439
  const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
@@ -119315,7 +119518,7 @@ gl_FragDepth=readDepth(vUv);
119315
119518
  * Places a structure's blocks at their stored positions, then refreshes neighboring faces.
119316
119519
  * Entity NBT is retained by the structure but is not rendered.
119317
119520
  *
119318
- * @param useBatches - Uses bounded batches by default. Set to `false` for sequential placement.
119521
+ * @param useBatches - Yields between chunks by default. Set to `false` for sequential placement.
119319
119522
  * @param executor - Optional queue for batched placement. The caller remains responsible for stopping it.
119320
119523
  */
119321
119524
  async placeMultiBlock(multiblock, useBatches = true, executor) {
@@ -119332,8 +119535,10 @@ gl_FragDepth=readDepth(vUv);
119332
119535
  };
119333
119536
  const place = (block) => this.placeBlock(new Vector3(...block.position), block, collect);
119334
119537
  const keys = /* @__PURE__ */ new Map();
119538
+ const types2 = /* @__PURE__ */ new Set();
119335
119539
  for (const block of multiblock.blocks) {
119336
- if (Chunk.isAir(block)) continue;
119540
+ if (Chunk.isAir(block) || types2.has(block.type)) continue;
119541
+ types2.add(block.type);
119337
119542
  const key = AssetKey.parse("blockstates", block.type);
119338
119543
  keys.set(key.serialize(), key);
119339
119544
  }
@@ -119342,6 +119547,23 @@ gl_FragDepth=readDepth(vUv);
119342
119547
  for (const block of multiblock.blocks) await place(block);
119343
119548
  return;
119344
119549
  }
119550
+ if (!executor) {
119551
+ const groups2 = /* @__PURE__ */ new Map();
119552
+ const position = new Vector3();
119553
+ for (const block of multiblock.blocks) {
119554
+ const [x4, y5, z4] = block.position;
119555
+ this.validatePosBounds(position.set(x4, y5, z4));
119556
+ const cx = Math.floor(x4 / 16), cy = Math.floor(y5 / 16), cz = Math.floor(z4 / 16);
119557
+ const key = `${cx}_${cy}_${cz}`;
119558
+ const chunk = this._chunks.get(key) ?? (Chunk.isAir(block) ? void 0 : this.getOrCreateChunkAt(position));
119559
+ if (!chunk) continue;
119560
+ let group = groups2.get(chunk);
119561
+ if (!group) groups2.set(chunk, group = []);
119562
+ group.push({ index: (y5 - cy * 16) * 256 + (z4 - cz * 16) * 16 + x4 - cx * 16, block });
119563
+ }
119564
+ await this.placeChunkGroups(groups2, changes);
119565
+ return;
119566
+ }
119345
119567
  const positions = /* @__PURE__ */ new Map();
119346
119568
  for (const block of multiblock.blocks) {
119347
119569
  const key = block.position.join(",");
@@ -119350,19 +119572,34 @@ gl_FragDepth=readDepth(vUv);
119350
119572
  else positions.set(key, [block]);
119351
119573
  }
119352
119574
  const groups = [...positions.values()];
119353
- const queue2 = executor ?? new BatchedExecutor();
119354
- try {
119355
- for (let i4 = 0; i4 < groups.length; i4 += queue2.batch) {
119356
- const results = await Promise.allSettled(groups.slice(i4, i4 + queue2.batch).map(
119357
- (blocks) => queue2.submit(async () => {
119358
- for (const block of blocks) await place(block);
119359
- })
119360
- ));
119361
- const failure = results.find((result) => result.status === "rejected");
119362
- if (failure?.status === "rejected") throw failure.reason;
119575
+ for (let i4 = 0; i4 < groups.length; i4 += executor.batch) {
119576
+ const results = await Promise.allSettled(groups.slice(i4, i4 + executor.batch).map(
119577
+ (blocks) => executor.submit(async () => {
119578
+ for (const block of blocks) await place(block);
119579
+ })
119580
+ ));
119581
+ const failure = results.find((result) => result.status === "rejected");
119582
+ if (failure?.status === "rejected") throw failure.reason;
119583
+ }
119584
+ }
119585
+ async placeChunkGroups(groups, changes) {
119586
+ let sliceStart = performance.now();
119587
+ for (const [chunk, blocks] of groups) {
119588
+ let positions;
119589
+ try {
119590
+ positions = await chunk.placeBlocks(blocks);
119591
+ } finally {
119592
+ positions ?? (positions = blocks.map(({ index }) => new Vector3(
119593
+ chunk.x * 16 + index % 16,
119594
+ chunk.y * 16 + Math.floor(index / 256),
119595
+ chunk.z * 16 + Math.floor(index / 16) % 16
119596
+ )));
119597
+ for (const pos of positions) changes.set(`${pos.x},${pos.y},${pos.z}`, pos);
119598
+ }
119599
+ if (performance.now() - sliceStart > 8) {
119600
+ await yieldToEventLoop();
119601
+ sliceStart = performance.now();
119363
119602
  }
119364
- } finally {
119365
- if (!executor) queue2.stop();
119366
119603
  }
119367
119604
  }
119368
119605
  /** Replaces one chunk column's blocks. Entity NBT remains available on the parsed chunk. */
@@ -119370,7 +119607,24 @@ gl_FragDepth=readDepth(vUv);
119370
119607
  const changes = /* @__PURE__ */ new Map();
119371
119608
  try {
119372
119609
  await this.clearChunkColumn(chunk.x, chunk.z, changes);
119610
+ const groups = /* @__PURE__ */ new Map();
119373
119611
  for (const section of chunk.sections) {
119612
+ if (!executor) {
119613
+ const blocks2 = [];
119614
+ for (let index = 0; index < 4096; index++) {
119615
+ const block = section.data.get(index);
119616
+ if (block) blocks2.push({ index, block });
119617
+ }
119618
+ if (blocks2.length) {
119619
+ const position = new Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
119620
+ this.validatePosBounds(position);
119621
+ const target = this.getOrCreateChunkAt(position);
119622
+ const previous = groups.get(target);
119623
+ if (previous) previous.push(...blocks2);
119624
+ else groups.set(target, blocks2);
119625
+ }
119626
+ continue;
119627
+ }
119374
119628
  const blocks = [];
119375
119629
  for (let index = 0; index < 4096; index++) {
119376
119630
  const block = section.data.get(index);
@@ -119385,6 +119639,7 @@ gl_FragDepth=readDepth(vUv);
119385
119639
  }
119386
119640
  await this.placeBlocks({ size: [16, 16, 16], blocks }, true, executor, changes);
119387
119641
  }
119642
+ if (!executor) await this.placeChunkGroups(groups, changes);
119388
119643
  } finally {
119389
119644
  await this.updateCulling([...changes.values()]);
119390
119645
  }
@@ -119425,19 +119680,23 @@ gl_FragDepth=readDepth(vUv);
119425
119680
  this.sectionModels?.clear();
119426
119681
  }
119427
119682
  updateCulling(positions) {
119683
+ const neighbor = new Vector3();
119428
119684
  for (const pos of positions) {
119429
- this.pendingCulling.set(pos.toArray().join(","), pos.clone());
119430
- for (const offset of CUBE_FACE_OFFSETS) {
119431
- const neighbor = pos.clone().add(new Vector3(...offset));
119432
- this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
119433
- }
119685
+ const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
119686
+ const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
119687
+ const lx = pos.x - cx * 16, ly = pos.y - cy * 16, lz = pos.z - cz * 16;
119434
119688
  for (let y5 = -1; y5 <= 1; y5++) {
119435
119689
  for (let z4 = -1; z4 <= 1; z4++) {
119436
119690
  for (let x4 = -1; x4 <= 1; x4++) {
119437
- const neighbor = pos.clone().add(new Vector3(x4, y5, z4));
119438
- if (this.getBlockAt(neighbor)?.object?.fluidKind) {
119439
- this.pendingCulling.set(neighbor.toArray().join(","), neighbor);
119440
- }
119691
+ const nx = lx + x4, ny = ly + y5, nz = lz + z4;
119692
+ const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${cx + Math.floor(nx / 16)}_${cy + Math.floor(ny / 16)}_${cz + Math.floor(nz / 16)}`);
119693
+ if (!section) continue;
119694
+ const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
119695
+ let pending = this.pendingCulling.get(section);
119696
+ if (pending?.has(index)) continue;
119697
+ if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) > 1 && !section.getBlockAt(neighbor.set(pos.x + x4, pos.y + y5, pos.z + z4))?.object?.fluidKind) continue;
119698
+ if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
119699
+ pending.add(index);
119441
119700
  }
119442
119701
  }
119443
119702
  }
@@ -119445,39 +119704,38 @@ gl_FragDepth=readDepth(vUv);
119445
119704
  return this.culling ?? (this.culling = Promise.resolve().then(async () => {
119446
119705
  try {
119447
119706
  while (this.pendingCulling.size) {
119448
- const batch = [...this.pendingCulling.values()];
119707
+ const batch = [...this.pendingCulling];
119449
119708
  this.pendingCulling.clear();
119450
- const changed = /* @__PURE__ */ new Set();
119451
- for (const pos of batch) {
119452
- const chunk = this.getChunkAt(pos);
119453
- if (!chunk) continue;
119454
- changed.add(chunk);
119455
- const block = chunk.getBlockAt(pos);
119456
- if (!block || !chunk.isBlockVisibleAt(pos)) {
119457
- continue;
119458
- }
119459
- if (block.object?.fluidKind) {
119460
- await block.object.updateFluid((x4, y5, z4) => {
119461
- const neighbor = pos.clone().add(new Vector3(x4, y5, z4));
119462
- const section = this.getChunkAt(neighbor);
119463
- const object3 = section?.isBlockVisibleAt(neighbor) ? section.getBlockAt(neighbor)?.object : void 0;
119464
- return {
119465
- fluid: object3?.fluidKind,
119466
- level: object3?.fluidLevel,
119467
- solid: section?.isOccludingAt(neighbor) ?? false
119468
- };
119469
- });
119470
- }
119471
- let mask = 0;
119472
- for (const [face, offset] of CUBE_FACE_OFFSETS.entries()) {
119473
- const neighbor = pos.clone().add(new Vector3(...offset));
119474
- if (this.getChunkAt(neighbor)?.isOccludingAt(neighbor)) {
119475
- mask |= 1 << face;
119709
+ for (const [chunk, indices] of batch) {
119710
+ for (const index of indices) {
119711
+ if (!chunk.isBlockVisibleIndex(index)) continue;
119712
+ const lx = index % 16, ly = Math.floor(index / 256), lz = Math.floor(index / 16) % 16;
119713
+ const wx = chunk.x * 16 + lx, wy = chunk.y * 16 + ly, wz = chunk.z * 16 + lz;
119714
+ const block = chunk.getBlockAt(neighbor.set(wx, wy, wz));
119715
+ if (block.object?.fluidKind) {
119716
+ await block.object.updateFluid((x4, y5, z4) => {
119717
+ const nx = lx + x4, ny = ly + y5, nz = lz + z4;
119718
+ const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${chunk.x + Math.floor(nx / 16)}_${chunk.y + Math.floor(ny / 16)}_${chunk.z + Math.floor(nz / 16)}`);
119719
+ const neighborIndex = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
119720
+ const object3 = section?.isBlockVisibleIndex(neighborIndex) ? section.getBlockAt(neighbor.set(wx + x4, wy + y5, wz + z4))?.object : void 0;
119721
+ return {
119722
+ fluid: object3?.fluidKind,
119723
+ level: object3?.fluidLevel,
119724
+ solid: section?.isOccludingIndex(neighborIndex) ?? false
119725
+ };
119726
+ });
119727
+ }
119728
+ let mask = 0;
119729
+ for (let face = 0; face < CUBE_FACE_OFFSETS.length; face++) {
119730
+ const offset = CUBE_FACE_OFFSETS[face];
119731
+ const nx = lx + offset[0], ny = ly + offset[1], nz = lz + offset[2];
119732
+ const section = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16 ? chunk : this._chunks.get(`${chunk.x + Math.floor(nx / 16)}_${chunk.y + Math.floor(ny / 16)}_${chunk.z + Math.floor(nz / 16)}`);
119733
+ if (section?.isOccludingIndex((ny & 15) * 256 + (nz & 15) * 16 + (nx & 15))) mask |= 1 << face;
119476
119734
  }
119735
+ await chunk.setCullMaskIndex(index, mask);
119477
119736
  }
119478
- await chunk.setCullMaskAt(pos, mask);
119479
119737
  }
119480
- for (const chunk of changed) chunk.rebuildSectionMesh();
119738
+ await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
119481
119739
  }
119482
119740
  } finally {
119483
119741
  this.culling = void 0;
@@ -119542,7 +119800,234 @@ gl_FragDepth=readDepth(vUv);
119542
119800
  init_process2();
119543
119801
  init_three_module();
119544
119802
  init_CanvasCompat();
119803
+ init_CubeFace();
119545
119804
  init_Materials();
119805
+
119806
+ // src/world/SectionGeometry.ts
119807
+ init_dirname();
119808
+ init_buffer2();
119809
+ init_process2();
119810
+ init_CubeFace();
119811
+ function buildSectionGeometry(input) {
119812
+ const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize } = input;
119813
+ if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
119814
+ if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
119815
+ const visible = [];
119816
+ const visibleAtlases = /* @__PURE__ */ new Set();
119817
+ for (let entry = 0; entry < count; entry++) {
119818
+ const template = templateData[templates[entry]];
119819
+ if (!template.cullFaces.some((direction) => !(cullMasks[entry] & direction))) continue;
119820
+ visible.push(entry);
119821
+ visibleAtlases.add(template.atlas);
119822
+ }
119823
+ const pages = [];
119824
+ const locations = /* @__PURE__ */ new Map();
119825
+ for (const atlas of [...visibleAtlases].sort((a4, b4) => atlases[b4].height - atlases[a4].height)) {
119826
+ const { width, height } = atlases[atlas];
119827
+ if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
119828
+ let selected = -1;
119829
+ for (let i4 = 0; i4 < pages.length; i4++) {
119830
+ const page2 = pages[i4];
119831
+ const nextRow = page2.x + width > maxAtlasSize;
119832
+ if ((nextRow ? page2.y + page2.rowHeight : page2.y) + height > maxAtlasSize) continue;
119833
+ if (nextRow) {
119834
+ page2.y += page2.rowHeight;
119835
+ page2.x = 0;
119836
+ page2.rowHeight = 0;
119837
+ }
119838
+ selected = i4;
119839
+ break;
119840
+ }
119841
+ if (selected < 0) {
119842
+ selected = pages.length;
119843
+ pages.push({ placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 });
119844
+ }
119845
+ const page = pages[selected];
119846
+ page.placements.push({ atlas, x: page.x, y: page.y });
119847
+ locations.set(atlas, { page: selected, x: page.x, y: page.y });
119848
+ page.x += width;
119849
+ page.rowHeight = Math.max(page.rowHeight, height);
119850
+ page.width = Math.max(page.width, page.x);
119851
+ page.height = Math.max(page.height, page.y + height);
119852
+ }
119853
+ for (const entry of visible) pages[locations.get(templateData[templates[entry]].atlas).page].entries.push(entry);
119854
+ return pages.map((page) => {
119855
+ let faces = 0;
119856
+ for (const entry of page.entries) {
119857
+ const template = templateData[templates[entry]];
119858
+ for (let face = 0; face < CUBE_FACES.length; face++) {
119859
+ if (!(cullMasks[entry] & template.cullFaces[face])) faces++;
119860
+ }
119861
+ }
119862
+ const positions = new Float32Array(faces * 12), normals = new Float32Array(faces * 12);
119863
+ const uvs = new Float32Array(faces * 8), uvBounds = new Float32Array(faces * 16), colors = new Float32Array(faces * 12);
119864
+ const outputIndices = new Uint32Array(faces * 6);
119865
+ let vertex2 = 0, indexOffset = 0;
119866
+ for (const entry of page.entries) {
119867
+ const template = templateData[templates[entry]];
119868
+ const atlas = atlases[template.atlas];
119869
+ const placement = locations.get(template.atlas);
119870
+ const mapU = (u4) => (placement.x + u4 * atlas.width) / page.width;
119871
+ const mapV = (v5) => 1 - (placement.y + (1 - v5) * atlas.height) / page.height;
119872
+ const offsetX = indices[entry] % 16 * 16;
119873
+ const offsetY = Math.floor(indices[entry] / 256) * 16;
119874
+ const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
119875
+ for (let face = 0; face < CUBE_FACES.length; face++) {
119876
+ if (cullMasks[entry] & template.cullFaces[face]) continue;
119877
+ const start = vertex2;
119878
+ for (let corner = 0; corner < 4; corner++, vertex2++) {
119879
+ const source = face * 4 + corner;
119880
+ positions[vertex2 * 3] = template.positions[source * 3] + offsetX;
119881
+ positions[vertex2 * 3 + 1] = template.positions[source * 3 + 1] + offsetY;
119882
+ positions[vertex2 * 3 + 2] = template.positions[source * 3 + 2] + offsetZ;
119883
+ normals[vertex2 * 3] = template.normals[source * 3];
119884
+ normals[vertex2 * 3 + 1] = template.normals[source * 3 + 1];
119885
+ normals[vertex2 * 3 + 2] = template.normals[source * 3 + 2];
119886
+ uvs[vertex2 * 2] = mapU(template.uvs[source * 2]);
119887
+ uvs[vertex2 * 2 + 1] = mapV(template.uvs[source * 2 + 1]);
119888
+ uvBounds[vertex2 * 4] = mapU(template.uvBounds[source * 4]);
119889
+ uvBounds[vertex2 * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
119890
+ uvBounds[vertex2 * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
119891
+ uvBounds[vertex2 * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
119892
+ colors[vertex2 * 3] = template.colors[source * 3];
119893
+ colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1];
119894
+ colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2];
119895
+ }
119896
+ for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[face * 6 + corner] - face * 4;
119897
+ }
119898
+ }
119899
+ return { width: page.width, height: page.height, placements: page.placements, positions, normals, uvs, uvBounds, colors, indices: outputIndices };
119900
+ });
119901
+ }
119902
+ function sectionGeometryTransferables(pages) {
119903
+ return pages.flatMap((page) => [page.positions.buffer, page.normals.buffer, page.uvs.buffer, page.uvBounds.buffer, page.colors.buffer, page.indices.buffer]);
119904
+ }
119905
+
119906
+ // src/world/SectionWorker.ts
119907
+ init_dirname();
119908
+ init_buffer2();
119909
+ init_process2();
119910
+ init_Env();
119911
+ var _SectionWorker = class _SectionWorker {
119912
+ constructor(worker) {
119913
+ this.worker = worker;
119914
+ this.nextId = 0;
119915
+ this.pending = /* @__PURE__ */ new Map();
119916
+ worker.addEventListener("message", (event) => {
119917
+ const reply = event.data;
119918
+ const pending = this.pending.get(reply.id);
119919
+ if (!pending) return;
119920
+ this.pending.delete(reply.id);
119921
+ if (reply.type === "pages") pending.resolve(reply.pages);
119922
+ else pending.reject(new Error(reply.message));
119923
+ });
119924
+ worker.addEventListener("error", (event) => this.fail(event.message || "Section worker failed"));
119925
+ worker.addEventListener("messageerror", () => this.fail("Section worker message could not be deserialized"));
119926
+ }
119927
+ /** The shared worker, or undefined when the environment has none or a previous worker failed. */
119928
+ static shared() {
119929
+ if (!this.initialized) {
119930
+ this.initialized = true;
119931
+ const worker = Env.provider.createWorker?.("section");
119932
+ if (worker) this.instance = new _SectionWorker(worker);
119933
+ }
119934
+ return this.instance;
119935
+ }
119936
+ /** Builds geometry without transferring the input buffers away from the caller. */
119937
+ build(input) {
119938
+ if (!this.worker) return Promise.reject(new Error("Section worker terminated"));
119939
+ return new Promise((resolve, reject) => {
119940
+ const id = this.nextId++;
119941
+ this.pending.set(id, { resolve, reject });
119942
+ this.worker.postMessage({ id, type: "build", input });
119943
+ });
119944
+ }
119945
+ /** Rejects pending builds, terminates the worker, and makes shared() return undefined. */
119946
+ terminate() {
119947
+ this.fail("Section worker terminated");
119948
+ }
119949
+ fail(message) {
119950
+ const error2 = new Error(message);
119951
+ for (const pending of this.pending.values()) pending.reject(error2);
119952
+ this.pending.clear();
119953
+ this.worker?.terminate();
119954
+ this.worker = void 0;
119955
+ _SectionWorker.instance = void 0;
119956
+ }
119957
+ };
119958
+ _SectionWorker.initialized = false;
119959
+ var SectionWorker = _SectionWorker;
119960
+
119961
+ // src/world/SectionMesh.ts
119962
+ var templateCache = /* @__PURE__ */ new WeakMap();
119963
+ function toInput(entries, maxAtlasSize) {
119964
+ if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
119965
+ const atlases = [];
119966
+ const atlasIds = /* @__PURE__ */ new Map();
119967
+ const templateIds = /* @__PURE__ */ new Map();
119968
+ const input = {
119969
+ count: entries.length,
119970
+ indices: new Uint16Array(entries.length),
119971
+ templates: new Uint16Array(entries.length),
119972
+ cullMasks: new Uint8Array(entries.length),
119973
+ templateData: [],
119974
+ atlases: [],
119975
+ maxAtlasSize
119976
+ };
119977
+ for (let i4 = 0; i4 < entries.length; i4++) {
119978
+ const { index, template, cullMask } = entries[i4];
119979
+ let id = templateIds.get(template);
119980
+ if (id === void 0) {
119981
+ let atlas = atlasIds.get(template.atlas);
119982
+ if (atlas === void 0) {
119983
+ atlas = atlases.length;
119984
+ atlasIds.set(template.atlas, atlas);
119985
+ atlases.push(template.atlas);
119986
+ input.atlases.push({ width: template.atlas.image.width, height: template.atlas.image.height });
119987
+ }
119988
+ let data = templateCache.get(template);
119989
+ if (!data) {
119990
+ data = {
119991
+ positions: new Float32Array(72),
119992
+ normals: new Float32Array(72),
119993
+ uvs: new Float32Array(48),
119994
+ uvBounds: new Float32Array(96),
119995
+ colors: new Float32Array(72),
119996
+ indices: new Uint16Array(36),
119997
+ cullFaces: new Uint8Array(template.cullFaces),
119998
+ atlas: 0
119999
+ };
120000
+ const position = template.geometry.getAttribute("position");
120001
+ const normal = template.geometry.getAttribute("normal");
120002
+ const uv = template.geometry.getAttribute("uv");
120003
+ const bounds = template.geometry.getAttribute("uvBounds");
120004
+ const color3 = template.geometry.getAttribute("color");
120005
+ for (let vertex2 = 0; vertex2 < CUBE_FACES.length * 4; vertex2++) {
120006
+ data.positions.set([position.getX(vertex2), position.getY(vertex2), position.getZ(vertex2)], vertex2 * 3);
120007
+ data.normals.set([normal.getX(vertex2), normal.getY(vertex2), normal.getZ(vertex2)], vertex2 * 3);
120008
+ data.uvs.set([uv.getX(vertex2), uv.getY(vertex2)], vertex2 * 2);
120009
+ data.uvBounds.set([
120010
+ bounds?.getX(vertex2) ?? 0,
120011
+ bounds?.getY(vertex2) ?? 0,
120012
+ bounds?.getZ(vertex2) ?? 1,
120013
+ bounds?.getW(vertex2) ?? 1
120014
+ ], vertex2 * 4);
120015
+ data.colors.set([color3?.getX(vertex2) ?? 1, color3?.getY(vertex2) ?? 1, color3?.getZ(vertex2) ?? 1], vertex2 * 3);
120016
+ }
120017
+ const indices = template.geometry.getIndex();
120018
+ for (let i5 = 0; i5 < data.indices.length; i5++) data.indices[i5] = indices.getX(i5);
120019
+ templateCache.set(template, data);
120020
+ }
120021
+ id = input.templateData.length;
120022
+ templateIds.set(template, id);
120023
+ input.templateData.push({ ...data, atlas });
120024
+ }
120025
+ input.indices[i4] = index;
120026
+ input.templates[i4] = id;
120027
+ input.cullMasks[i4] = cullMask;
120028
+ }
120029
+ return { input, atlases };
120030
+ }
119546
120031
  var SectionMesh = class _SectionMesh extends Group {
119547
120032
  constructor() {
119548
120033
  super(...arguments);
@@ -119550,86 +120035,31 @@ gl_FragDepth=readDepth(vUv);
119550
120035
  }
119551
120036
  /** Builds section-local meshes from visible cube faces. `maxAtlasSize` limits each atlas dimension in pixels. */
119552
120037
  static build(entries, maxAtlasSize = 2048) {
119553
- if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
119554
- const visible = entries.filter((entry) => entry.template.cullFaces.some((direction) => !(entry.cullMask & direction)));
119555
- const atlases = [...new Set(visible.map((entry) => entry.template.atlas))].sort((a4, b4) => b4.image.height - a4.image.height);
119556
- const pages = [];
119557
- const locations = /* @__PURE__ */ new Map();
119558
- for (const atlas of atlases) {
119559
- const { width, height } = atlas.image;
119560
- if (width > maxAtlasSize || height > maxAtlasSize) throw new RangeError("Model atlas exceeds the section atlas size limit");
119561
- let selected;
119562
- for (const page of pages) {
119563
- const nextRow = page.x + width > maxAtlasSize;
119564
- if ((nextRow ? page.y + page.rowHeight : page.y) + height > maxAtlasSize) continue;
119565
- if (nextRow) {
119566
- page.y += page.rowHeight;
119567
- page.x = 0;
119568
- page.rowHeight = 0;
119569
- }
119570
- selected = page;
119571
- break;
119572
- }
119573
- if (!selected) {
119574
- selected = { placements: [], entries: [], x: 0, y: 0, rowHeight: 0, width: 0, height: 0 };
119575
- pages.push(selected);
119576
- }
119577
- const placement = { atlas, x: selected.x, y: selected.y };
119578
- selected.placements.push(placement);
119579
- selected.x += width;
119580
- selected.rowHeight = Math.max(selected.rowHeight, height);
119581
- selected.width = Math.max(selected.width, selected.x);
119582
- selected.height = Math.max(selected.height, selected.y + height);
119583
- locations.set(atlas, { page: selected, placement });
119584
- }
119585
- for (const entry of visible) locations.get(entry.template.atlas).page.entries.push(entry);
120038
+ const { input, atlases } = toInput(entries, maxAtlasSize);
120039
+ return this.fromPages(buildSectionGeometry(input), atlases);
120040
+ }
120041
+ /** Builds section-local meshes in a browser worker when available, with synchronous fallback. */
120042
+ static async buildAsync(entries, maxAtlasSize = 2048) {
120043
+ const { input, atlases } = toInput(entries, maxAtlasSize);
120044
+ const worker = SectionWorker.shared();
120045
+ const pages = worker ? await worker.build(input).catch(() => buildSectionGeometry(input)) : buildSectionGeometry(input);
120046
+ return this.fromPages(pages, atlases);
120047
+ }
120048
+ static fromPages(pages, atlases) {
119586
120049
  const section = new _SectionMesh();
119587
120050
  for (const page of pages) {
119588
120051
  const canvas = createCanvas(page.width, page.height);
119589
120052
  const context = canvas.getContext("2d");
119590
120053
  for (const { atlas, x: x4, y: y5 } of page.placements) {
119591
- context.drawImage(atlas.image.canvas, x4, y5);
119592
- }
119593
- const positions = [], normals = [], uvs = [], uvBounds = [], colors = [], indices = [];
119594
- for (const { index, template, cullMask } of page.entries) {
119595
- const position = template.geometry.getAttribute("position");
119596
- const normal = template.geometry.getAttribute("normal");
119597
- const uv = template.geometry.getAttribute("uv");
119598
- const bounds = template.geometry.getAttribute("uvBounds");
119599
- const color3 = template.geometry.getAttribute("color");
119600
- const sourceIndices = template.geometry.getIndex();
119601
- const placement = locations.get(template.atlas).placement;
119602
- const mapU = (u4) => (placement.x + u4 * template.atlas.image.width) / page.width;
119603
- const mapV = (v5) => 1 - (placement.y + (1 - v5) * template.atlas.image.height) / page.height;
119604
- const offsetX = index % 16 * 16;
119605
- const offsetY = Math.floor(index / 256) * 16;
119606
- const offsetZ = Math.floor(index / 16) % 16 * 16;
119607
- for (let face = 0; face < 6; face++) {
119608
- if (cullMask & template.cullFaces[face]) continue;
119609
- const start = positions.length / 3;
119610
- for (let corner = 0; corner < 4; corner++) {
119611
- const vertex2 = face * 4 + corner;
119612
- positions.push(position.getX(vertex2) + offsetX, position.getY(vertex2) + offsetY, position.getZ(vertex2) + offsetZ);
119613
- normals.push(normal.getX(vertex2), normal.getY(vertex2), normal.getZ(vertex2));
119614
- uvs.push(mapU(uv.getX(vertex2)), mapV(uv.getY(vertex2)));
119615
- uvBounds.push(
119616
- mapU(bounds?.getX(vertex2) ?? 0),
119617
- mapV(bounds?.getY(vertex2) ?? 0),
119618
- mapU(bounds?.getZ(vertex2) ?? 1),
119619
- mapV(bounds?.getW(vertex2) ?? 1)
119620
- );
119621
- colors.push(color3?.getX(vertex2) ?? 1, color3?.getY(vertex2) ?? 1, color3?.getZ(vertex2) ?? 1);
119622
- }
119623
- for (let corner = 0; corner < 6; corner++) indices.push(start + sourceIndices.getX(face * 6 + corner) - face * 4);
119624
- }
120054
+ context.drawImage(atlases[atlas].image.canvas, x4, y5);
119625
120055
  }
119626
120056
  const geometry = new BufferGeometry();
119627
- geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
119628
- geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
119629
- geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
119630
- geometry.setAttribute("uvBounds", new Float32BufferAttribute(uvBounds, 4));
119631
- geometry.setAttribute("color", new Float32BufferAttribute(colors, 3));
119632
- geometry.setIndex(indices);
120057
+ geometry.setAttribute("position", new Float32BufferAttribute(page.positions.buffer, 3));
120058
+ geometry.setAttribute("normal", new Float32BufferAttribute(page.normals.buffer, 3));
120059
+ geometry.setAttribute("uv", new Float32BufferAttribute(page.uvs.buffer, 2));
120060
+ geometry.setAttribute("uvBounds", new Float32BufferAttribute(page.uvBounds.buffer, 4));
120061
+ geometry.setAttribute("color", new Float32BufferAttribute(page.colors.buffer, 3));
120062
+ geometry.setIndex(new Uint32BufferAttribute(page.indices.buffer, 1));
119633
120063
  geometry.computeBoundingBox();
119634
120064
  geometry.computeBoundingSphere();
119635
120065
  const material = Materials.createShadedCanvasMaterial(canvas, false, false, true);
@@ -119663,7 +120093,9 @@ gl_FragDepth=readDepth(vUv);
119663
120093
  this.renderedBlocks = /* @__PURE__ */ new Map();
119664
120094
  this.sectionBlocks = /* @__PURE__ */ new Map();
119665
120095
  this.hiddenBlocks = /* @__PURE__ */ new Set();
120096
+ this.blockPosition = new Vector3();
119666
120097
  this.meshDirty = false;
120098
+ this.meshGeneration = 0;
119667
120099
  this.scene = scene;
119668
120100
  this.x = x4;
119669
120101
  this.y = y5;
@@ -119676,7 +120108,7 @@ gl_FragDepth=readDepth(vUv);
119676
120108
  if (isTripleArray(posOrX)) {
119677
120109
  return this.getBlockAt(new Vector3(posOrX[0], posOrX[1], posOrX[2]));
119678
120110
  }
119679
- const pos = this.worldPosToChunkPos(posOrX);
120111
+ const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
119680
120112
  const index = _Chunk.chunkPosToBlockIndex(pos);
119681
120113
  return this.renderedBlocks.get(index);
119682
120114
  }
@@ -119700,48 +120132,81 @@ gl_FragDepth=readDepth(vUv);
119700
120132
  worldPos = this.chunkPosToWorldPos(pos);
119701
120133
  }
119702
120134
  const index = _Chunk.chunkPosToBlockIndex(pos);
119703
- this.hiddenBlocks.delete(index);
119704
- this.data.set(index, block);
119705
- const readBlock = this.data.snapshot(index);
119706
- this.renderedBlocks.get(index)?.object?.removeFromScene();
119707
- if (this.sectionBlocks.delete(index)) this.meshDirty = true;
119708
- this.renderedBlocks.delete(index);
119709
- let object3;
119710
120135
  try {
119711
- if (!readBlock) return void 0;
119712
- const stored = readBlock();
119713
- const blockState = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
119714
- if (!blockState) {
119715
- this.data.set(index, void 0);
119716
- return void 0;
119717
- }
119718
- const perBlock = !this.sectionModels || getFluidKind(blockState.key, stored.properties) || blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString());
119719
- const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
119720
- if (template) {
119721
- this.sectionBlocks.set(index, { index, template, cullMask: 0 });
119722
- this.meshDirty = true;
119723
- } else {
119724
- object3 = await this.scene.addBlock(blockState, {
119725
- mergeMeshes: true,
119726
- instanceMeshes: true,
119727
- maxInstanceCount: 2e3,
119728
- initialState: stored.properties
119729
- });
119730
- object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
119731
- }
119732
- const info = { get block() {
119733
- return readBlock();
119734
- }, object: object3 };
119735
- this.renderedBlocks.set(index, info);
119736
- return info;
119737
- } catch (error2) {
119738
- this.data.set(index, void 0);
119739
- object3?.removeFromScene();
119740
- throw error2;
120136
+ await this.placeBlocks([{ index, block }]);
120137
+ return this.renderedBlocks.get(index);
119741
120138
  } finally {
119742
120139
  await onBlocksChanged?.([worldPos]);
119743
120140
  }
119744
120141
  }
120142
+ /** Places cells in input order and returns changed world positions without refreshing neighbors. */
120143
+ async placeBlocks(blocks) {
120144
+ const resolutions = /* @__PURE__ */ new Map();
120145
+ for (const { block } of blocks) {
120146
+ if (!block || ChunkData.isAir(block)) continue;
120147
+ const key = ChunkData.paletteKey(block);
120148
+ if (resolutions.has(key)) continue;
120149
+ const stored = { type: block.type, properties: block.properties ? { ...block.properties } : void 0 };
120150
+ const resolved = (async () => {
120151
+ const blockState2 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
120152
+ const perBlock = !blockState2 || !this.sectionModels || !!getFluidKind(blockState2.key, stored.properties) || !!(blockState2.key && BlockEntities.entry(await BlockEntities.getIndex(blockState2.key.root), blockState2.key.toNamespacedString()));
120153
+ if (!perBlock) await this.sectionModels.get(blockState2, stored.properties);
120154
+ return { blockState: blockState2, perBlock };
120155
+ })();
120156
+ resolutions.set(key, resolved);
120157
+ void resolved.catch(() => void 0);
120158
+ }
120159
+ const positions = [];
120160
+ let failed = false, failure;
120161
+ for (const { index, block } of blocks) {
120162
+ this.hiddenBlocks.delete(index);
120163
+ this.data.set(index, block);
120164
+ const readBlock = this.data.snapshot(index);
120165
+ this.renderedBlocks.get(index)?.object?.removeFromScene();
120166
+ if (this.sectionBlocks.delete(index)) this.meshDirty = true;
120167
+ this.renderedBlocks.delete(index);
120168
+ const worldPos = new Vector3(
120169
+ this.x * 16 + index % 16,
120170
+ this.y * 16 + Math.floor(index / 256),
120171
+ this.z * 16 + Math.floor(index / 16) % 16
120172
+ );
120173
+ positions.push(worldPos);
120174
+ let object3;
120175
+ try {
120176
+ if (!readBlock) continue;
120177
+ const stored = readBlock();
120178
+ const key = ChunkData.paletteKey(stored);
120179
+ const { blockState: blockState2, perBlock } = await resolutions.get(key);
120180
+ if (!blockState2) {
120181
+ this.data.set(index, void 0);
120182
+ continue;
120183
+ }
120184
+ const template = perBlock ? void 0 : await this.sectionModels.get(blockState2, stored.properties);
120185
+ if (template) {
120186
+ this.sectionBlocks.set(index, { index, template, cullMask: 0 });
120187
+ this.meshDirty = true;
120188
+ } else {
120189
+ object3 = await this.scene.addBlock(blockState2, {
120190
+ mergeMeshes: true,
120191
+ instanceMeshes: true,
120192
+ maxInstanceCount: 2e3,
120193
+ initialState: stored.properties
120194
+ });
120195
+ object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
120196
+ }
120197
+ this.renderedBlocks.set(index, { get block() {
120198
+ return readBlock();
120199
+ }, object: object3 });
120200
+ } catch (error2) {
120201
+ this.data.set(index, void 0);
120202
+ object3?.removeFromScene();
120203
+ if (!failed) failure = error2;
120204
+ failed = true;
120205
+ }
120206
+ }
120207
+ if (failed) throw failure;
120208
+ return positions;
120209
+ }
119745
120210
  /** Changes visibility at world block coordinates while preserving the block's data. */
119746
120211
  async setBlockVisibleAt(pos, visible) {
119747
120212
  const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
@@ -119762,15 +120227,24 @@ gl_FragDepth=readDepth(vUv);
119762
120227
  await this.onBlocksChanged?.([pos]);
119763
120228
  }
119764
120229
  isBlockVisibleAt(pos) {
119765
- const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
120230
+ return this.isBlockVisibleIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)));
120231
+ }
120232
+ /** Reports whether a cell has a visible render object or section entry. */
120233
+ isBlockVisibleIndex(index) {
119766
120234
  return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
119767
120235
  }
119768
120236
  isOccludingAt(pos) {
119769
- const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
120237
+ return this.isOccludingIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)));
120238
+ }
120239
+ /** Reports whether a visible cell hides neighboring cube faces. */
120240
+ isOccludingIndex(index) {
119770
120241
  return !this.hiddenBlocks.has(index) && (this.sectionBlocks.has(index) || (this.renderedBlocks.get(index)?.object?.isOccluding ?? false));
119771
120242
  }
119772
120243
  async setCullMaskAt(pos, mask) {
119773
- const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
120244
+ await this.setCullMaskIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)), mask);
120245
+ }
120246
+ /** Updates hidden faces for a cell's section entry or individual render object. */
120247
+ async setCullMaskIndex(index, mask) {
119774
120248
  const entry = this.sectionBlocks.get(index);
119775
120249
  if (entry) {
119776
120250
  if (entry.cullMask !== mask) {
@@ -119781,12 +120255,17 @@ gl_FragDepth=readDepth(vUv);
119781
120255
  await this.renderedBlocks.get(index)?.object?.setCullMask(mask);
119782
120256
  }
119783
120257
  }
119784
- rebuildSectionMesh() {
120258
+ /** Rebuilds visible section geometry and discards results superseded by another rebuild or clear. */
120259
+ async rebuildSectionMesh() {
119785
120260
  if (!this.meshDirty) return;
119786
- const next = this.sectionBlocks.size ? SectionMesh.build(
119787
- [...this.sectionBlocks.values()].filter((entry) => !this.hiddenBlocks.has(entry.index)),
119788
- this.sectionModels.maxAtlasSize
119789
- ) : void 0;
120261
+ this.meshDirty = false;
120262
+ const generation = ++this.meshGeneration;
120263
+ const entries = [...this.sectionBlocks.values()].filter((entry) => !this.hiddenBlocks.has(entry.index));
120264
+ const next = entries.length ? await SectionMesh.buildAsync(entries, this.sectionModels.maxAtlasSize) : void 0;
120265
+ if (generation !== this.meshGeneration) {
120266
+ next?.dispose();
120267
+ return;
120268
+ }
119790
120269
  this.sectionMesh?.dispose();
119791
120270
  this.sectionMesh = next;
119792
120271
  if (next) {
@@ -119794,7 +120273,6 @@ gl_FragDepth=readDepth(vUv);
119794
120273
  this.scene.add(next);
119795
120274
  }
119796
120275
  this.scene.dirty = true;
119797
- this.meshDirty = false;
119798
120276
  }
119799
120277
  /** Removes stored blocks and their render objects, then notifies the owning world of changed positions. */
119800
120278
  async clear(onBlocksChanged = this.onBlocksChanged) {
@@ -119803,6 +120281,7 @@ gl_FragDepth=readDepth(vUv);
119803
120281
  ));
119804
120282
  for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
119805
120283
  this.sectionBlocks.clear();
120284
+ this.meshGeneration++;
119806
120285
  this.sectionMesh?.dispose();
119807
120286
  this.sectionMesh = void 0;
119808
120287
  this.meshDirty = false;