minerender 2.1.0-alpha.92 → 2.1.0-alpha.93

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
@@ -106662,6 +106662,7 @@ ${shader.fragmentShader}`.replace(
106662
106662
  prefix: () => prefix,
106663
106663
  probeImageSize: () => probeImageSize,
106664
106664
  registerBrowserEnv: () => registerBrowserEnv,
106665
+ resolveLegacyBlock: () => resolveLegacyBlock,
106665
106666
  sampleEntityAnimation: () => sampleEntityAnimation,
106666
106667
  sampleEntityKeyframes: () => sampleEntityKeyframes,
106667
106668
  sampleFluid: () => sampleFluid,
@@ -111945,169 +111946,11 @@ property list uchar int vertex_index
111945
111946
  init_buffer2();
111946
111947
  init_process2();
111947
111948
 
111948
- // src/model/multiblock/LitematicaParser.ts
111949
- init_dirname();
111950
- init_buffer2();
111951
- init_process2();
111952
- init_MineRenderError();
111953
- var LitematicaParser = class {
111954
- /**
111955
- * Parses decoded NBT, preserving subregion placement and omitting air.
111956
- * Later entries in regions replace earlier cells, including with air.
111957
- * Size encloses all region bounds; positions retain the schematic origin.
111958
- * Metadata and scheduled ticks are not imported. Named regions can be placed individually.
111959
- */
111960
- static async parse(nbt) {
111961
- const tags = nbt.value;
111962
- const version3 = integer2(tags.Version, "Version");
111963
- if (version3 < 5 || version3 > 7) throw new MineRenderError(`Unsupported Litematica version ${version3}; expected 5, 6, or 7`);
111964
- const dataVersion = tags.MinecraftDataVersion === void 0 ? void 0 : integer2(tags.MinecraftDataVersion, "MinecraftDataVersion");
111965
- const blocks = /* @__PURE__ */ new Map();
111966
- const regions = [];
111967
- const min = [Infinity, Infinity, Infinity];
111968
- const max2 = [-Infinity, -Infinity, -Infinity];
111969
- for (const [name2, tag] of Object.entries(compound(tags.Regions, "Regions"))) {
111970
- const region = readRegion(compound(tag, `region ${name2}`), name2, dataVersion, blocks);
111971
- regions.push(region);
111972
- for (let axis = 0; axis < 3; axis++) {
111973
- const start = minimum(region.position[axis], region.signedSize[axis]);
111974
- min[axis] = Math.min(min[axis], start);
111975
- max2[axis] = Math.max(max2[axis], start + region.size[axis]);
111976
- }
111977
- }
111978
- return {
111979
- size: regions.length ? min.map((value, axis) => max2[axis] - value) : [0, 0, 0],
111980
- blocks: [...blocks.values()],
111981
- entities: regions.flatMap((region) => region.entities ?? []),
111982
- dataVersion,
111983
- regions
111984
- };
111985
- }
111986
- };
111987
- function readRegion(tags, name2, dataVersion, combined) {
111988
- const position = blockPosition(compound(tags.Position, `region ${name2} Position`));
111989
- const signedSize = blockPosition(compound(tags.Size, `region ${name2} Size`));
111990
- if (signedSize.some((value) => value === 0)) throw new MineRenderError(`Litematica region ${name2} dimensions must be nonzero`);
111991
- const size = signedSize.map(Math.abs);
111992
- const min = position.map((value, axis) => minimum(value, signedSize[axis]));
111993
- const [width, height, length] = size;
111994
- const volume = width * height * length;
111995
- const palette = compounds(tags.BlockStatePalette, "BlockStatePalette").map(blockState);
111996
- if (!palette.length) throw new MineRenderError(`Litematica region ${name2} has no block palette`);
111997
- const bits2 = Math.max(2, Math.ceil(Math.log2(palette.length)));
111998
- if (!Number.isSafeInteger(volume * bits2)) throw new MineRenderError(`Litematica region ${name2} volume is too large`);
111999
- const packed = tags.BlockStates;
112000
- const expected = Math.ceil(volume * bits2 / 64);
112001
- if (packed?.type !== "longArray" || !Array.isArray(packed.value) || packed.value.length !== expected) {
112002
- throw new MineRenderError(`Litematica region ${name2} BlockStates must contain ${expected} longs`);
112003
- }
112004
- const words = packed.value.map((pair) => {
112005
- if (!Array.isArray(pair) || pair.length !== 2 || !pair.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 4294967295)) {
112006
- throw new MineRenderError(`Litematica region ${name2} has an invalid BlockStates long`);
112007
- }
112008
- return [pair[0] >>> 0, pair[1] >>> 0];
112009
- });
112010
- const blockEntities = /* @__PURE__ */ new Map();
112011
- for (const tile of compounds(tags.TileEntities, "TileEntities")) {
112012
- const pos = blockPosition(tile);
112013
- if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
112014
- throw new MineRenderError(`Litematica region ${name2} block entity is outside its dimensions`);
112015
- }
112016
- const index = pos[0] + pos[2] * width + pos[1] * width * length;
112017
- if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Litematica block entity at index ${index}`);
112018
- const value = { ...tile };
112019
- for (const [axis, key] of ["x", "y", "z"].entries()) value[key] = { type: "int", value: pos[axis] + min[axis] };
112020
- blockEntities.set(index, { type: "compound", value });
112021
- }
112022
- const blocks = [];
112023
- const mask = 2 ** bits2 - 1;
112024
- for (let index = 0; index < volume; index++) {
112025
- const word = Math.floor(index * bits2 / 64);
112026
- const shift = index * bits2 % 64;
112027
- const [high, low] = words[word];
112028
- let value = shift < 32 ? low >>> shift : high >>> shift - 32;
112029
- if (shift < 32 && shift + bits2 > 32) value |= high << 32 - shift;
112030
- if (shift + bits2 > 64) value |= words[word + 1][1] << 64 - shift;
112031
- const id = (value & mask) >>> 0;
112032
- const state = palette[id];
112033
- if (!state) throw new MineRenderError(`Litematica region ${name2} palette index ${id} does not exist`);
112034
- const pos = [
112035
- index % width + min[0],
112036
- Math.floor(index / (width * length)) + min[1],
112037
- Math.floor(index / width) % length + min[2]
112038
- ];
112039
- const key = pos.join(",");
112040
- if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) {
112041
- combined.delete(key);
112042
- continue;
112043
- }
112044
- const block = { type: state.type, properties: { ...state.properties }, position: pos, nbt: blockEntities.get(index) };
112045
- blocks.push(block);
112046
- combined.set(key, block);
112047
- }
112048
- const entities = compounds(tags.Entities, "Entities").map((entity) => {
112049
- const pos = entity.Pos;
112050
- if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
112051
- throw new MineRenderError(`Litematica region ${name2} entity Pos must contain three doubles`);
112052
- }
112053
- const absolute = pos.value.value.map((value2, axis) => value2 + position[axis]);
112054
- const value = { ...entity, Pos: { type: "list", value: { type: "double", value: [...absolute] } } };
112055
- return { position: absolute, nbt: { type: "compound", value } };
112056
- });
112057
- return { name: name2, position, signedSize, size, blocks, entities, dataVersion };
112058
- }
112059
- function minimum(position, size) {
112060
- return position + Math.min(0, size + 1);
112061
- }
112062
- function integer2(tag, name2) {
112063
- if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
112064
- throw new MineRenderError(`Litematica ${name2} must be an int`);
112065
- }
112066
- return tag.value;
112067
- }
112068
- function compound(tag, name2) {
112069
- if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
112070
- throw new MineRenderError(`Litematica ${name2} must be a compound`);
112071
- }
112072
- return tag.value;
112073
- }
112074
- function blockPosition(tags) {
112075
- return ["x", "y", "z"].map((axis) => integer2(tags[axis], axis));
112076
- }
112077
- function compounds(tag, name2) {
112078
- if (tag === void 0) return [];
112079
- if (tag.type === "list" && Array.isArray(tag.value.value)) {
112080
- if (tag.value.value.length === 0) return [];
112081
- if (tag.value.type === "compound") return tag.value.value;
112082
- }
112083
- throw new MineRenderError(`Litematica ${name2} must be a compound list`);
112084
- }
112085
- function blockState(tags) {
112086
- const name2 = tags.Name;
112087
- if (name2?.type !== "string" || !/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(name2.value)) {
112088
- throw new MineRenderError("Litematica palette entry must have a block Name");
112089
- }
112090
- const properties = {};
112091
- if (tags.Properties !== void 0) {
112092
- for (const [key, tag] of Object.entries(compound(tags.Properties, "block Properties"))) {
112093
- if (tag?.type !== "string") throw new MineRenderError("Litematica block properties must be strings");
112094
- Object.defineProperty(properties, key, { value: tag.value, enumerable: true, writable: true, configurable: true });
112095
- }
112096
- }
112097
- return { type: name2.value.includes(":") ? name2.value : `minecraft:${name2.value}`, properties };
112098
- }
112099
-
112100
- // src/model/multiblock/MultiBlockStructure.ts
111949
+ // src/model/multiblock/LegacyBlocks.ts
112101
111950
  init_dirname();
112102
111951
  init_buffer2();
112103
111952
  init_process2();
112104
111953
 
112105
- // src/model/multiblock/SchematicParser.ts
112106
- init_dirname();
112107
- init_buffer2();
112108
- init_process2();
112109
- init_MineRenderError();
112110
-
112111
111954
  // src/model/multiblock/legacyBlocks.json
112112
111955
  var legacyBlocks_default = {
112113
111956
  __comment: "Block mappings from res/idsToNames.json (WorldEdit legacy.json); block names and cauldrons updated for Minecraft 1.21.11. Source: https://github.com/sk89q/WorldEdit/blob/master/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/legacy.json",
@@ -112951,12 +112794,20 @@ property list uchar int vertex_index
112951
112794
  "131:15": "minecraft:tripwire_hook[powered=true,attached=true,facing=east]",
112952
112795
  "132:0": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=false]",
112953
112796
  "132:1": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=false]",
112797
+ "132:2": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=false]",
112798
+ "132:3": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=false]",
112954
112799
  "132:4": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=true]",
112955
112800
  "132:5": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=true]",
112801
+ "132:6": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=true]",
112802
+ "132:7": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=true]",
112956
112803
  "132:8": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=false]",
112957
112804
  "132:9": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=false]",
112805
+ "132:10": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=false]",
112806
+ "132:11": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=false]",
112958
112807
  "132:12": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=true]",
112959
112808
  "132:13": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=true]",
112809
+ "132:14": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=true]",
112810
+ "132:15": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=true]",
112960
112811
  "133:0": "minecraft:emerald_block",
112961
112812
  "134:0": "minecraft:spruce_stairs[half=bottom,shape=outer_right,facing=east]",
112962
112813
  "134:1": "minecraft:spruce_stairs[half=bottom,shape=outer_right,facing=west]",
@@ -113797,7 +113648,186 @@ property list uchar int vertex_index
113797
113648
  }
113798
113649
  };
113799
113650
 
113651
+ // src/model/multiblock/LegacyBlocks.ts
113652
+ function resolveLegacyBlock(id, metadata, customMappings = {}, lenient = false) {
113653
+ const mapping = legacyBlocks_default.blocks;
113654
+ const key = `${id}:${metadata}`;
113655
+ let mapped = customMappings[key] ?? mapping[key];
113656
+ if (!mapped && lenient) mapped = customMappings[`${id}:0`] ?? mapping[`${id}:0`];
113657
+ if (!mapped) return void 0;
113658
+ const [type, state] = mapped.split("[");
113659
+ const properties = {};
113660
+ if (state) {
113661
+ for (const property of state.slice(0, -1).split(",")) {
113662
+ const [key2, value] = property.split("=");
113663
+ properties[key2] = value;
113664
+ }
113665
+ }
113666
+ return { type, properties };
113667
+ }
113668
+
113669
+ // src/model/multiblock/LitematicaParser.ts
113670
+ init_dirname();
113671
+ init_buffer2();
113672
+ init_process2();
113673
+ init_MineRenderError();
113674
+ var LitematicaParser = class {
113675
+ /**
113676
+ * Parses decoded NBT, preserving subregion placement and omitting air.
113677
+ * Later entries in regions replace earlier cells, including with air.
113678
+ * Size encloses all region bounds; positions retain the schematic origin.
113679
+ * Metadata and scheduled ticks are not imported. Named regions can be placed individually.
113680
+ */
113681
+ static async parse(nbt) {
113682
+ const tags = nbt.value;
113683
+ const version3 = integer2(tags.Version, "Version");
113684
+ if (version3 < 5 || version3 > 7) throw new MineRenderError(`Unsupported Litematica version ${version3}; expected 5, 6, or 7`);
113685
+ const dataVersion = tags.MinecraftDataVersion === void 0 ? void 0 : integer2(tags.MinecraftDataVersion, "MinecraftDataVersion");
113686
+ const blocks = /* @__PURE__ */ new Map();
113687
+ const regions = [];
113688
+ const min = [Infinity, Infinity, Infinity];
113689
+ const max2 = [-Infinity, -Infinity, -Infinity];
113690
+ for (const [name2, tag] of Object.entries(compound(tags.Regions, "Regions"))) {
113691
+ const region = readRegion(compound(tag, `region ${name2}`), name2, dataVersion, blocks);
113692
+ regions.push(region);
113693
+ for (let axis = 0; axis < 3; axis++) {
113694
+ const start = minimum(region.position[axis], region.signedSize[axis]);
113695
+ min[axis] = Math.min(min[axis], start);
113696
+ max2[axis] = Math.max(max2[axis], start + region.size[axis]);
113697
+ }
113698
+ }
113699
+ return {
113700
+ size: regions.length ? min.map((value, axis) => max2[axis] - value) : [0, 0, 0],
113701
+ blocks: [...blocks.values()],
113702
+ entities: regions.flatMap((region) => region.entities ?? []),
113703
+ dataVersion,
113704
+ regions
113705
+ };
113706
+ }
113707
+ };
113708
+ function readRegion(tags, name2, dataVersion, combined) {
113709
+ const position = blockPosition(compound(tags.Position, `region ${name2} Position`));
113710
+ const signedSize = blockPosition(compound(tags.Size, `region ${name2} Size`));
113711
+ if (signedSize.some((value) => value === 0)) throw new MineRenderError(`Litematica region ${name2} dimensions must be nonzero`);
113712
+ const size = signedSize.map(Math.abs);
113713
+ const min = position.map((value, axis) => minimum(value, signedSize[axis]));
113714
+ const [width, height, length] = size;
113715
+ const volume = width * height * length;
113716
+ const palette = compounds(tags.BlockStatePalette, "BlockStatePalette").map(blockState);
113717
+ if (!palette.length) throw new MineRenderError(`Litematica region ${name2} has no block palette`);
113718
+ const bits2 = Math.max(2, Math.ceil(Math.log2(palette.length)));
113719
+ if (!Number.isSafeInteger(volume * bits2)) throw new MineRenderError(`Litematica region ${name2} volume is too large`);
113720
+ const packed = tags.BlockStates;
113721
+ const expected = Math.ceil(volume * bits2 / 64);
113722
+ if (packed?.type !== "longArray" || !Array.isArray(packed.value) || packed.value.length !== expected) {
113723
+ throw new MineRenderError(`Litematica region ${name2} BlockStates must contain ${expected} longs`);
113724
+ }
113725
+ const words = packed.value.map((pair) => {
113726
+ if (!Array.isArray(pair) || pair.length !== 2 || !pair.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 4294967295)) {
113727
+ throw new MineRenderError(`Litematica region ${name2} has an invalid BlockStates long`);
113728
+ }
113729
+ return [pair[0] >>> 0, pair[1] >>> 0];
113730
+ });
113731
+ const blockEntities = /* @__PURE__ */ new Map();
113732
+ for (const tile of compounds(tags.TileEntities, "TileEntities")) {
113733
+ const pos = blockPosition(tile);
113734
+ if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
113735
+ throw new MineRenderError(`Litematica region ${name2} block entity is outside its dimensions`);
113736
+ }
113737
+ const index = pos[0] + pos[2] * width + pos[1] * width * length;
113738
+ if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Litematica block entity at index ${index}`);
113739
+ const value = { ...tile };
113740
+ for (const [axis, key] of ["x", "y", "z"].entries()) value[key] = { type: "int", value: pos[axis] + min[axis] };
113741
+ blockEntities.set(index, { type: "compound", value });
113742
+ }
113743
+ const blocks = [];
113744
+ const mask = 2 ** bits2 - 1;
113745
+ for (let index = 0; index < volume; index++) {
113746
+ const word = Math.floor(index * bits2 / 64);
113747
+ const shift = index * bits2 % 64;
113748
+ const [high, low] = words[word];
113749
+ let value = shift < 32 ? low >>> shift : high >>> shift - 32;
113750
+ if (shift < 32 && shift + bits2 > 32) value |= high << 32 - shift;
113751
+ if (shift + bits2 > 64) value |= words[word + 1][1] << 64 - shift;
113752
+ const id = (value & mask) >>> 0;
113753
+ const state = palette[id];
113754
+ if (!state) throw new MineRenderError(`Litematica region ${name2} palette index ${id} does not exist`);
113755
+ const pos = [
113756
+ index % width + min[0],
113757
+ Math.floor(index / (width * length)) + min[1],
113758
+ Math.floor(index / width) % length + min[2]
113759
+ ];
113760
+ const key = pos.join(",");
113761
+ if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) {
113762
+ combined.delete(key);
113763
+ continue;
113764
+ }
113765
+ const block = { type: state.type, properties: { ...state.properties }, position: pos, nbt: blockEntities.get(index) };
113766
+ blocks.push(block);
113767
+ combined.set(key, block);
113768
+ }
113769
+ const entities = compounds(tags.Entities, "Entities").map((entity) => {
113770
+ const pos = entity.Pos;
113771
+ if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
113772
+ throw new MineRenderError(`Litematica region ${name2} entity Pos must contain three doubles`);
113773
+ }
113774
+ const absolute = pos.value.value.map((value2, axis) => value2 + position[axis]);
113775
+ const value = { ...entity, Pos: { type: "list", value: { type: "double", value: [...absolute] } } };
113776
+ return { position: absolute, nbt: { type: "compound", value } };
113777
+ });
113778
+ return { name: name2, position, signedSize, size, blocks, entities, dataVersion };
113779
+ }
113780
+ function minimum(position, size) {
113781
+ return position + Math.min(0, size + 1);
113782
+ }
113783
+ function integer2(tag, name2) {
113784
+ if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
113785
+ throw new MineRenderError(`Litematica ${name2} must be an int`);
113786
+ }
113787
+ return tag.value;
113788
+ }
113789
+ function compound(tag, name2) {
113790
+ if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
113791
+ throw new MineRenderError(`Litematica ${name2} must be a compound`);
113792
+ }
113793
+ return tag.value;
113794
+ }
113795
+ function blockPosition(tags) {
113796
+ return ["x", "y", "z"].map((axis) => integer2(tags[axis], axis));
113797
+ }
113798
+ function compounds(tag, name2) {
113799
+ if (tag === void 0) return [];
113800
+ if (tag.type === "list" && Array.isArray(tag.value.value)) {
113801
+ if (tag.value.value.length === 0) return [];
113802
+ if (tag.value.type === "compound") return tag.value.value;
113803
+ }
113804
+ throw new MineRenderError(`Litematica ${name2} must be a compound list`);
113805
+ }
113806
+ function blockState(tags) {
113807
+ const name2 = tags.Name;
113808
+ if (name2?.type !== "string" || !/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(name2.value)) {
113809
+ throw new MineRenderError("Litematica palette entry must have a block Name");
113810
+ }
113811
+ const properties = {};
113812
+ if (tags.Properties !== void 0) {
113813
+ for (const [key, tag] of Object.entries(compound(tags.Properties, "block Properties"))) {
113814
+ if (tag?.type !== "string") throw new MineRenderError("Litematica block properties must be strings");
113815
+ Object.defineProperty(properties, key, { value: tag.value, enumerable: true, writable: true, configurable: true });
113816
+ }
113817
+ }
113818
+ return { type: name2.value.includes(":") ? name2.value : `minecraft:${name2.value}`, properties };
113819
+ }
113820
+
113821
+ // src/model/multiblock/MultiBlockStructure.ts
113822
+ init_dirname();
113823
+ init_buffer2();
113824
+ init_process2();
113825
+
113800
113826
  // src/model/multiblock/SchematicParser.ts
113827
+ init_dirname();
113828
+ init_buffer2();
113829
+ init_process2();
113830
+ init_MineRenderError();
113801
113831
  var SchematicParser = class {
113802
113832
  /**
113803
113833
  * Parses a legacy schematic using custom mappings before the bundled defaults.
@@ -113839,35 +113869,21 @@ property list uchar int vertex_index
113839
113869
  tileEntities.set((y5 * length + z4) * width + x4, { type: "compound", value: tile });
113840
113870
  }
113841
113871
  const blocks = [];
113842
- const mapping = legacyBlocks_default.blocks;
113843
113872
  for (let index = 0; index < volume; index++) {
113844
113873
  const packed = addBlocks?.value[index >> 1] ?? 0;
113845
113874
  const high = packed >> (index & 1) * 4 & 15;
113846
113875
  const id = high << 8 | ids.value[index] & 255;
113847
113876
  const metadata = data.value[index] & 255;
113848
- const key = `${id}:${metadata}`;
113849
- let mapped = customMappings[key] ?? mapping[key];
113850
- if (!mapped && options.lenient) {
113851
- mapped = customMappings[`${id}:0`] ?? mapping[`${id}:0`];
113852
- }
113853
- if (!mapped) {
113877
+ const block = resolveLegacyBlock(id, metadata, customMappings, options.lenient);
113878
+ if (!block) {
113854
113879
  if (options.lenient) {
113855
113880
  continue;
113856
113881
  }
113857
113882
  throw new MineRenderError(`Unsupported legacy block ${id}:${metadata} at schematic index ${index}`);
113858
113883
  }
113859
- const [type, state] = mapped.split("[");
113860
- if (type === "minecraft:air") continue;
113861
- const properties = {};
113862
- if (state) {
113863
- for (const property of state.slice(0, -1).split(",")) {
113864
- const [key2, value] = property.split("=");
113865
- properties[key2] = value;
113866
- }
113867
- }
113884
+ if (block.type === "minecraft:air") continue;
113868
113885
  blocks.push({
113869
- type,
113870
- properties,
113886
+ ...block,
113871
113887
  position: [index % width, Math.floor(index / (width * length)), Math.floor(index / width) % length],
113872
113888
  nbt: tileEntities.get(index)
113873
113889
  });
@@ -119431,28 +119447,34 @@ gl_FragDepth=readDepth(vUv);
119431
119447
  if (expected && (chunk.x !== expected.x || chunk.z !== expected.z)) {
119432
119448
  throw new MineRenderError(`Anvil chunk coordinates do not match external file c.${expected.x}.${expected.z}.mcc`);
119433
119449
  }
119450
+ const numericStates = /* @__PURE__ */ new Map();
119434
119451
  for (const section of this.compounds(level.sections ?? level.Sections, "sections")) {
119435
119452
  const y5 = this.integer(section.Y, "section Y");
119453
+ let data2;
119436
119454
  if (section.Blocks || section.Data || section.Add) {
119437
- throw new MineRenderError("Numeric Anvil block IDs before Minecraft 1.13 are not supported");
119438
- }
119439
- if (section.block_states && section.block_states.type !== "compound") {
119440
- throw new MineRenderError("Anvil block_states must be a compound");
119441
- }
119442
- const modern = section.block_states?.type === "compound" ? section.block_states.value : void 0;
119443
- const paletteTag = modern ? modern.palette : section.Palette;
119444
- const palette = paletteTag?.type === "list" && paletteTag.value.type === "string" ? paletteTag.value.value : this.compounds(paletteTag, "block palette");
119445
- const data2 = new ChunkData();
119446
- if (palette.length) {
119447
- const states = palette.map((entry) => this.block(entry));
119448
- const indices = this.unpack(modern ? modern.data : section.BlockStates, states.length, !!modern, dataVersion);
119449
- for (let index = 0; index < 4096; index++) {
119450
- const state = states[indices[index]];
119451
- if (!state) throw new MineRenderError(`Anvil palette index ${indices[index]} is out of range`);
119452
- if (!ChunkData.isAir(state)) data2.set(index, state);
119455
+ if (section.Palette || section.BlockStates || section.block_states) {
119456
+ throw new MineRenderError(`Anvil section ${y5} mixes numeric and paletted block states`);
119457
+ }
119458
+ data2 = this.numericSection(section, y5, options, numericStates);
119459
+ } else {
119460
+ if (section.block_states && section.block_states.type !== "compound") {
119461
+ throw new MineRenderError("Anvil block_states must be a compound");
119462
+ }
119463
+ const modern = section.block_states?.type === "compound" ? section.block_states.value : void 0;
119464
+ const paletteTag = modern ? modern.palette : section.Palette;
119465
+ const palette = paletteTag?.type === "list" && paletteTag.value.type === "string" ? paletteTag.value.value : this.compounds(paletteTag, "block palette");
119466
+ data2 = new ChunkData();
119467
+ if (palette.length) {
119468
+ const states = palette.map((entry) => this.block(entry));
119469
+ const indices = this.unpack(modern ? modern.data : section.BlockStates, states.length, !!modern, dataVersion);
119470
+ for (let index = 0; index < 4096; index++) {
119471
+ const state = states[indices[index]];
119472
+ if (!state) throw new MineRenderError(`Anvil palette index ${indices[index]} is out of range`);
119473
+ if (!ChunkData.isAir(state)) data2.set(index, state);
119474
+ }
119475
+ } else if (modern || section.Palette || section.BlockStates) {
119476
+ throw new MineRenderError("Anvil section has block states without a palette");
119453
119477
  }
119454
- } else if (modern || section.Palette || section.BlockStates) {
119455
- throw new MineRenderError("Anvil section has block states without a palette");
119456
119478
  }
119457
119479
  if (chunk.sections.some((section2) => section2.y === y5)) throw new MineRenderError(`Duplicate Anvil section Y ${y5}`);
119458
119480
  chunk.sections.push({ y: y5, data: data2 });
@@ -119480,6 +119502,33 @@ gl_FragDepth=readDepth(vUv);
119480
119502
  }
119481
119503
  return chunk;
119482
119504
  }
119505
+ static numericSection(section, y5, options, states) {
119506
+ const bytes = (name2, length, optional = false) => {
119507
+ const tag = section[name2];
119508
+ if (!tag && optional) return void 0;
119509
+ if (tag?.type !== "byteArray" || !Array.isArray(tag.value) || tag.value.length !== length) {
119510
+ throw new MineRenderError(`Anvil section ${y5} ${name2} must contain ${length} bytes`);
119511
+ }
119512
+ return tag.value;
119513
+ };
119514
+ const ids = bytes("Blocks", 4096);
119515
+ const metadata = bytes("Data", 2048, true);
119516
+ const extra = bytes("Add", 2048, true);
119517
+ const data = new ChunkData();
119518
+ for (let index = 0; index < 4096; index++) {
119519
+ const shift = (index & 1) * 4;
119520
+ const id = ids[index] & 255 | ((extra?.[index >> 1] ?? 0) >> shift & 15) << 8;
119521
+ const value = (metadata?.[index >> 1] ?? 0) >> shift & 15;
119522
+ const key = id * 16 + value;
119523
+ if (!states.has(key)) states.set(key, resolveLegacyBlock(id, value, options.legacyMappings, options.lenient));
119524
+ const block = states.get(key);
119525
+ if (!block && !options.lenient) {
119526
+ throw new MineRenderError(`Unsupported legacy block ${id}:${value} at Anvil section ${y5} index ${index}`);
119527
+ }
119528
+ if (block && !ChunkData.isAir(block)) data.set(index, block);
119529
+ }
119530
+ return data;
119531
+ }
119483
119532
  static compounds(tag, name2) {
119484
119533
  if (!tag) return [];
119485
119534
  if (tag.type !== "list" || tag.value.type !== "compound" && tag.value.value.length !== 0) {
@@ -119565,7 +119614,7 @@ gl_FragDepth=readDepth(vUv);
119565
119614
  this.cachedBytes = 0;
119566
119615
  this.maxCachedRegions = options.maxCachedRegions ?? 4;
119567
119616
  this.maxCachedBytes = options.maxCachedBytes ?? 64 * 1024 * 1024;
119568
- this.readExternalChunk = options.readExternalChunk;
119617
+ this.parseOptions = { readExternalChunk: options.readExternalChunk, legacyMappings: options.legacyMappings, lenient: options.lenient };
119569
119618
  for (const [name2, value] of Object.entries({ maxCachedRegions: this.maxCachedRegions, maxCachedBytes: this.maxCachedBytes })) {
119570
119619
  if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name2} must be a nonnegative safe integer`);
119571
119620
  }
@@ -119580,8 +119629,8 @@ gl_FragDepth=readDepth(vUv);
119580
119629
  signal?.throwIfAborted();
119581
119630
  if (!data) return void 0;
119582
119631
  const chunk = await AnvilParser.parseChunk(data, x4 - regionX * 32, z4 - regionZ * 32, {
119632
+ ...this.parseOptions,
119583
119633
  region: { x: regionX, z: regionZ },
119584
- readExternalChunk: this.readExternalChunk,
119585
119634
  signal
119586
119635
  });
119587
119636
  signal?.throwIfAborted();