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.
@@ -23796,158 +23796,6 @@ function isBlockObject(obj) {
23796
23796
  init_FluidGeometry();
23797
23797
  init_FluidModelObject();
23798
23798
 
23799
- // src/model/multiblock/LitematicaParser.ts
23800
- init_MineRenderError();
23801
- var LitematicaParser = class {
23802
- /**
23803
- * Parses decoded NBT, preserving subregion placement and omitting air.
23804
- * Later entries in regions replace earlier cells, including with air.
23805
- * Size encloses all region bounds; positions retain the schematic origin.
23806
- * Metadata and scheduled ticks are not imported. Named regions can be placed individually.
23807
- */
23808
- static async parse(nbt) {
23809
- const tags = nbt.value;
23810
- const version2 = integer2(tags.Version, "Version");
23811
- if (version2 < 5 || version2 > 7) throw new MineRenderError(`Unsupported Litematica version ${version2}; expected 5, 6, or 7`);
23812
- const dataVersion = tags.MinecraftDataVersion === void 0 ? void 0 : integer2(tags.MinecraftDataVersion, "MinecraftDataVersion");
23813
- const blocks = /* @__PURE__ */ new Map();
23814
- const regions = [];
23815
- const min = [Infinity, Infinity, Infinity];
23816
- const max = [-Infinity, -Infinity, -Infinity];
23817
- for (const [name, tag] of Object.entries(compound(tags.Regions, "Regions"))) {
23818
- const region = readRegion(compound(tag, `region ${name}`), name, dataVersion, blocks);
23819
- regions.push(region);
23820
- for (let axis = 0; axis < 3; axis++) {
23821
- const start = minimum(region.position[axis], region.signedSize[axis]);
23822
- min[axis] = Math.min(min[axis], start);
23823
- max[axis] = Math.max(max[axis], start + region.size[axis]);
23824
- }
23825
- }
23826
- return {
23827
- size: regions.length ? min.map((value, axis) => max[axis] - value) : [0, 0, 0],
23828
- blocks: [...blocks.values()],
23829
- entities: regions.flatMap((region) => region.entities ?? []),
23830
- dataVersion,
23831
- regions
23832
- };
23833
- }
23834
- };
23835
- function readRegion(tags, name, dataVersion, combined) {
23836
- const position = blockPosition(compound(tags.Position, `region ${name} Position`));
23837
- const signedSize = blockPosition(compound(tags.Size, `region ${name} Size`));
23838
- if (signedSize.some((value) => value === 0)) throw new MineRenderError(`Litematica region ${name} dimensions must be nonzero`);
23839
- const size = signedSize.map(Math.abs);
23840
- const min = position.map((value, axis) => minimum(value, signedSize[axis]));
23841
- const [width, height, length] = size;
23842
- const volume = width * height * length;
23843
- const palette = compounds(tags.BlockStatePalette, "BlockStatePalette").map(blockState);
23844
- if (!palette.length) throw new MineRenderError(`Litematica region ${name} has no block palette`);
23845
- const bits = Math.max(2, Math.ceil(Math.log2(palette.length)));
23846
- if (!Number.isSafeInteger(volume * bits)) throw new MineRenderError(`Litematica region ${name} volume is too large`);
23847
- const packed = tags.BlockStates;
23848
- const expected = Math.ceil(volume * bits / 64);
23849
- if (packed?.type !== "longArray" || !Array.isArray(packed.value) || packed.value.length !== expected) {
23850
- throw new MineRenderError(`Litematica region ${name} BlockStates must contain ${expected} longs`);
23851
- }
23852
- const words = packed.value.map((pair) => {
23853
- if (!Array.isArray(pair) || pair.length !== 2 || !pair.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 4294967295)) {
23854
- throw new MineRenderError(`Litematica region ${name} has an invalid BlockStates long`);
23855
- }
23856
- return [pair[0] >>> 0, pair[1] >>> 0];
23857
- });
23858
- const blockEntities = /* @__PURE__ */ new Map();
23859
- for (const tile of compounds(tags.TileEntities, "TileEntities")) {
23860
- const pos = blockPosition(tile);
23861
- if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
23862
- throw new MineRenderError(`Litematica region ${name} block entity is outside its dimensions`);
23863
- }
23864
- const index = pos[0] + pos[2] * width + pos[1] * width * length;
23865
- if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Litematica block entity at index ${index}`);
23866
- const value = { ...tile };
23867
- for (const [axis, key] of ["x", "y", "z"].entries()) value[key] = { type: "int", value: pos[axis] + min[axis] };
23868
- blockEntities.set(index, { type: "compound", value });
23869
- }
23870
- const blocks = [];
23871
- const mask = 2 ** bits - 1;
23872
- for (let index = 0; index < volume; index++) {
23873
- const word = Math.floor(index * bits / 64);
23874
- const shift = index * bits % 64;
23875
- const [high, low] = words[word];
23876
- let value = shift < 32 ? low >>> shift : high >>> shift - 32;
23877
- if (shift < 32 && shift + bits > 32) value |= high << 32 - shift;
23878
- if (shift + bits > 64) value |= words[word + 1][1] << 64 - shift;
23879
- const id = (value & mask) >>> 0;
23880
- const state = palette[id];
23881
- if (!state) throw new MineRenderError(`Litematica region ${name} palette index ${id} does not exist`);
23882
- const pos = [
23883
- index % width + min[0],
23884
- Math.floor(index / (width * length)) + min[1],
23885
- Math.floor(index / width) % length + min[2]
23886
- ];
23887
- const key = pos.join(",");
23888
- if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) {
23889
- combined.delete(key);
23890
- continue;
23891
- }
23892
- const block = { type: state.type, properties: { ...state.properties }, position: pos, nbt: blockEntities.get(index) };
23893
- blocks.push(block);
23894
- combined.set(key, block);
23895
- }
23896
- const entities = compounds(tags.Entities, "Entities").map((entity) => {
23897
- const pos = entity.Pos;
23898
- if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
23899
- throw new MineRenderError(`Litematica region ${name} entity Pos must contain three doubles`);
23900
- }
23901
- const absolute = pos.value.value.map((value2, axis) => value2 + position[axis]);
23902
- const value = { ...entity, Pos: { type: "list", value: { type: "double", value: [...absolute] } } };
23903
- return { position: absolute, nbt: { type: "compound", value } };
23904
- });
23905
- return { name, position, signedSize, size, blocks, entities, dataVersion };
23906
- }
23907
- function minimum(position, size) {
23908
- return position + Math.min(0, size + 1);
23909
- }
23910
- function integer2(tag, name) {
23911
- if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
23912
- throw new MineRenderError(`Litematica ${name} must be an int`);
23913
- }
23914
- return tag.value;
23915
- }
23916
- function compound(tag, name) {
23917
- if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
23918
- throw new MineRenderError(`Litematica ${name} must be a compound`);
23919
- }
23920
- return tag.value;
23921
- }
23922
- function blockPosition(tags) {
23923
- return ["x", "y", "z"].map((axis) => integer2(tags[axis], axis));
23924
- }
23925
- function compounds(tag, name) {
23926
- if (tag === void 0) return [];
23927
- if (tag.type === "list" && Array.isArray(tag.value.value)) {
23928
- if (tag.value.value.length === 0) return [];
23929
- if (tag.value.type === "compound") return tag.value.value;
23930
- }
23931
- throw new MineRenderError(`Litematica ${name} must be a compound list`);
23932
- }
23933
- function blockState(tags) {
23934
- const name = tags.Name;
23935
- if (name?.type !== "string" || !/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(name.value)) {
23936
- throw new MineRenderError("Litematica palette entry must have a block Name");
23937
- }
23938
- const properties = {};
23939
- if (tags.Properties !== void 0) {
23940
- for (const [key, tag] of Object.entries(compound(tags.Properties, "block Properties"))) {
23941
- if (tag?.type !== "string") throw new MineRenderError("Litematica block properties must be strings");
23942
- Object.defineProperty(properties, key, { value: tag.value, enumerable: true, writable: true, configurable: true });
23943
- }
23944
- }
23945
- return { type: name.value.includes(":") ? name.value : `minecraft:${name.value}`, properties };
23946
- }
23947
-
23948
- // src/model/multiblock/SchematicParser.ts
23949
- init_MineRenderError();
23950
-
23951
23799
  // src/model/multiblock/legacyBlocks.json
23952
23800
  var legacyBlocks_default = {
23953
23801
  __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",
@@ -24791,12 +24639,20 @@ var legacyBlocks_default = {
24791
24639
  "131:15": "minecraft:tripwire_hook[powered=true,attached=true,facing=east]",
24792
24640
  "132:0": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=false]",
24793
24641
  "132:1": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=false]",
24642
+ "132:2": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=false]",
24643
+ "132:3": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=false]",
24794
24644
  "132:4": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=true]",
24795
24645
  "132:5": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=true]",
24646
+ "132:6": "minecraft:tripwire[disarmed=false,east=false,powered=false,south=false,north=false,west=false,attached=true]",
24647
+ "132:7": "minecraft:tripwire[disarmed=false,east=false,powered=true,south=false,north=false,west=false,attached=true]",
24796
24648
  "132:8": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=false]",
24797
24649
  "132:9": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=false]",
24650
+ "132:10": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=false]",
24651
+ "132:11": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=false]",
24798
24652
  "132:12": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=true]",
24799
24653
  "132:13": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=true]",
24654
+ "132:14": "minecraft:tripwire[disarmed=true,east=false,powered=false,south=false,north=false,west=false,attached=true]",
24655
+ "132:15": "minecraft:tripwire[disarmed=true,east=false,powered=true,south=false,north=false,west=false,attached=true]",
24800
24656
  "133:0": "minecraft:emerald_block",
24801
24657
  "134:0": "minecraft:spruce_stairs[half=bottom,shape=outer_right,facing=east]",
24802
24658
  "134:1": "minecraft:spruce_stairs[half=bottom,shape=outer_right,facing=west]",
@@ -25637,7 +25493,175 @@ var legacyBlocks_default = {
25637
25493
  }
25638
25494
  };
25639
25495
 
25496
+ // src/model/multiblock/LegacyBlocks.ts
25497
+ function resolveLegacyBlock(id, metadata, customMappings = {}, lenient = false) {
25498
+ const mapping = legacyBlocks_default.blocks;
25499
+ const key = `${id}:${metadata}`;
25500
+ let mapped = customMappings[key] ?? mapping[key];
25501
+ if (!mapped && lenient) mapped = customMappings[`${id}:0`] ?? mapping[`${id}:0`];
25502
+ if (!mapped) return void 0;
25503
+ const [type, state] = mapped.split("[");
25504
+ const properties = {};
25505
+ if (state) {
25506
+ for (const property of state.slice(0, -1).split(",")) {
25507
+ const [key2, value] = property.split("=");
25508
+ properties[key2] = value;
25509
+ }
25510
+ }
25511
+ return { type, properties };
25512
+ }
25513
+
25514
+ // src/model/multiblock/LitematicaParser.ts
25515
+ init_MineRenderError();
25516
+ var LitematicaParser = class {
25517
+ /**
25518
+ * Parses decoded NBT, preserving subregion placement and omitting air.
25519
+ * Later entries in regions replace earlier cells, including with air.
25520
+ * Size encloses all region bounds; positions retain the schematic origin.
25521
+ * Metadata and scheduled ticks are not imported. Named regions can be placed individually.
25522
+ */
25523
+ static async parse(nbt) {
25524
+ const tags = nbt.value;
25525
+ const version2 = integer2(tags.Version, "Version");
25526
+ if (version2 < 5 || version2 > 7) throw new MineRenderError(`Unsupported Litematica version ${version2}; expected 5, 6, or 7`);
25527
+ const dataVersion = tags.MinecraftDataVersion === void 0 ? void 0 : integer2(tags.MinecraftDataVersion, "MinecraftDataVersion");
25528
+ const blocks = /* @__PURE__ */ new Map();
25529
+ const regions = [];
25530
+ const min = [Infinity, Infinity, Infinity];
25531
+ const max = [-Infinity, -Infinity, -Infinity];
25532
+ for (const [name, tag] of Object.entries(compound(tags.Regions, "Regions"))) {
25533
+ const region = readRegion(compound(tag, `region ${name}`), name, dataVersion, blocks);
25534
+ regions.push(region);
25535
+ for (let axis = 0; axis < 3; axis++) {
25536
+ const start = minimum(region.position[axis], region.signedSize[axis]);
25537
+ min[axis] = Math.min(min[axis], start);
25538
+ max[axis] = Math.max(max[axis], start + region.size[axis]);
25539
+ }
25540
+ }
25541
+ return {
25542
+ size: regions.length ? min.map((value, axis) => max[axis] - value) : [0, 0, 0],
25543
+ blocks: [...blocks.values()],
25544
+ entities: regions.flatMap((region) => region.entities ?? []),
25545
+ dataVersion,
25546
+ regions
25547
+ };
25548
+ }
25549
+ };
25550
+ function readRegion(tags, name, dataVersion, combined) {
25551
+ const position = blockPosition(compound(tags.Position, `region ${name} Position`));
25552
+ const signedSize = blockPosition(compound(tags.Size, `region ${name} Size`));
25553
+ if (signedSize.some((value) => value === 0)) throw new MineRenderError(`Litematica region ${name} dimensions must be nonzero`);
25554
+ const size = signedSize.map(Math.abs);
25555
+ const min = position.map((value, axis) => minimum(value, signedSize[axis]));
25556
+ const [width, height, length] = size;
25557
+ const volume = width * height * length;
25558
+ const palette = compounds(tags.BlockStatePalette, "BlockStatePalette").map(blockState);
25559
+ if (!palette.length) throw new MineRenderError(`Litematica region ${name} has no block palette`);
25560
+ const bits = Math.max(2, Math.ceil(Math.log2(palette.length)));
25561
+ if (!Number.isSafeInteger(volume * bits)) throw new MineRenderError(`Litematica region ${name} volume is too large`);
25562
+ const packed = tags.BlockStates;
25563
+ const expected = Math.ceil(volume * bits / 64);
25564
+ if (packed?.type !== "longArray" || !Array.isArray(packed.value) || packed.value.length !== expected) {
25565
+ throw new MineRenderError(`Litematica region ${name} BlockStates must contain ${expected} longs`);
25566
+ }
25567
+ const words = packed.value.map((pair) => {
25568
+ if (!Array.isArray(pair) || pair.length !== 2 || !pair.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 4294967295)) {
25569
+ throw new MineRenderError(`Litematica region ${name} has an invalid BlockStates long`);
25570
+ }
25571
+ return [pair[0] >>> 0, pair[1] >>> 0];
25572
+ });
25573
+ const blockEntities = /* @__PURE__ */ new Map();
25574
+ for (const tile of compounds(tags.TileEntities, "TileEntities")) {
25575
+ const pos = blockPosition(tile);
25576
+ if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
25577
+ throw new MineRenderError(`Litematica region ${name} block entity is outside its dimensions`);
25578
+ }
25579
+ const index = pos[0] + pos[2] * width + pos[1] * width * length;
25580
+ if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Litematica block entity at index ${index}`);
25581
+ const value = { ...tile };
25582
+ for (const [axis, key] of ["x", "y", "z"].entries()) value[key] = { type: "int", value: pos[axis] + min[axis] };
25583
+ blockEntities.set(index, { type: "compound", value });
25584
+ }
25585
+ const blocks = [];
25586
+ const mask = 2 ** bits - 1;
25587
+ for (let index = 0; index < volume; index++) {
25588
+ const word = Math.floor(index * bits / 64);
25589
+ const shift = index * bits % 64;
25590
+ const [high, low] = words[word];
25591
+ let value = shift < 32 ? low >>> shift : high >>> shift - 32;
25592
+ if (shift < 32 && shift + bits > 32) value |= high << 32 - shift;
25593
+ if (shift + bits > 64) value |= words[word + 1][1] << 64 - shift;
25594
+ const id = (value & mask) >>> 0;
25595
+ const state = palette[id];
25596
+ if (!state) throw new MineRenderError(`Litematica region ${name} palette index ${id} does not exist`);
25597
+ const pos = [
25598
+ index % width + min[0],
25599
+ Math.floor(index / (width * length)) + min[1],
25600
+ Math.floor(index / width) % length + min[2]
25601
+ ];
25602
+ const key = pos.join(",");
25603
+ if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) {
25604
+ combined.delete(key);
25605
+ continue;
25606
+ }
25607
+ const block = { type: state.type, properties: { ...state.properties }, position: pos, nbt: blockEntities.get(index) };
25608
+ blocks.push(block);
25609
+ combined.set(key, block);
25610
+ }
25611
+ const entities = compounds(tags.Entities, "Entities").map((entity) => {
25612
+ const pos = entity.Pos;
25613
+ if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
25614
+ throw new MineRenderError(`Litematica region ${name} entity Pos must contain three doubles`);
25615
+ }
25616
+ const absolute = pos.value.value.map((value2, axis) => value2 + position[axis]);
25617
+ const value = { ...entity, Pos: { type: "list", value: { type: "double", value: [...absolute] } } };
25618
+ return { position: absolute, nbt: { type: "compound", value } };
25619
+ });
25620
+ return { name, position, signedSize, size, blocks, entities, dataVersion };
25621
+ }
25622
+ function minimum(position, size) {
25623
+ return position + Math.min(0, size + 1);
25624
+ }
25625
+ function integer2(tag, name) {
25626
+ if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
25627
+ throw new MineRenderError(`Litematica ${name} must be an int`);
25628
+ }
25629
+ return tag.value;
25630
+ }
25631
+ function compound(tag, name) {
25632
+ if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
25633
+ throw new MineRenderError(`Litematica ${name} must be a compound`);
25634
+ }
25635
+ return tag.value;
25636
+ }
25637
+ function blockPosition(tags) {
25638
+ return ["x", "y", "z"].map((axis) => integer2(tags[axis], axis));
25639
+ }
25640
+ function compounds(tag, name) {
25641
+ if (tag === void 0) return [];
25642
+ if (tag.type === "list" && Array.isArray(tag.value.value)) {
25643
+ if (tag.value.value.length === 0) return [];
25644
+ if (tag.value.type === "compound") return tag.value.value;
25645
+ }
25646
+ throw new MineRenderError(`Litematica ${name} must be a compound list`);
25647
+ }
25648
+ function blockState(tags) {
25649
+ const name = tags.Name;
25650
+ if (name?.type !== "string" || !/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(name.value)) {
25651
+ throw new MineRenderError("Litematica palette entry must have a block Name");
25652
+ }
25653
+ const properties = {};
25654
+ if (tags.Properties !== void 0) {
25655
+ for (const [key, tag] of Object.entries(compound(tags.Properties, "block Properties"))) {
25656
+ if (tag?.type !== "string") throw new MineRenderError("Litematica block properties must be strings");
25657
+ Object.defineProperty(properties, key, { value: tag.value, enumerable: true, writable: true, configurable: true });
25658
+ }
25659
+ }
25660
+ return { type: name.value.includes(":") ? name.value : `minecraft:${name.value}`, properties };
25661
+ }
25662
+
25640
25663
  // src/model/multiblock/SchematicParser.ts
25664
+ init_MineRenderError();
25641
25665
  var SchematicParser = class {
25642
25666
  /**
25643
25667
  * Parses a legacy schematic using custom mappings before the bundled defaults.
@@ -25679,35 +25703,21 @@ var SchematicParser = class {
25679
25703
  tileEntities.set((y * length + z) * width + x, { type: "compound", value: tile });
25680
25704
  }
25681
25705
  const blocks = [];
25682
- const mapping = legacyBlocks_default.blocks;
25683
25706
  for (let index = 0; index < volume; index++) {
25684
25707
  const packed = addBlocks?.value[index >> 1] ?? 0;
25685
25708
  const high = packed >> (index & 1) * 4 & 15;
25686
25709
  const id = high << 8 | ids.value[index] & 255;
25687
25710
  const metadata = data.value[index] & 255;
25688
- const key = `${id}:${metadata}`;
25689
- let mapped = customMappings[key] ?? mapping[key];
25690
- if (!mapped && options.lenient) {
25691
- mapped = customMappings[`${id}:0`] ?? mapping[`${id}:0`];
25692
- }
25693
- if (!mapped) {
25711
+ const block = resolveLegacyBlock(id, metadata, customMappings, options.lenient);
25712
+ if (!block) {
25694
25713
  if (options.lenient) {
25695
25714
  continue;
25696
25715
  }
25697
25716
  throw new MineRenderError(`Unsupported legacy block ${id}:${metadata} at schematic index ${index}`);
25698
25717
  }
25699
- const [type, state] = mapped.split("[");
25700
- if (type === "minecraft:air") continue;
25701
- const properties = {};
25702
- if (state) {
25703
- for (const property of state.slice(0, -1).split(",")) {
25704
- const [key2, value] = property.split("=");
25705
- properties[key2] = value;
25706
- }
25707
- }
25718
+ if (block.type === "minecraft:air") continue;
25708
25719
  blocks.push({
25709
- type,
25710
- properties,
25720
+ ...block,
25711
25721
  position: [index % width, Math.floor(index / (width * length)), Math.floor(index / width) % length],
25712
25722
  nbt: tileEntities.get(index)
25713
25723
  });
@@ -29209,28 +29219,34 @@ var AnvilParser = class {
29209
29219
  if (expected && (chunk.x !== expected.x || chunk.z !== expected.z)) {
29210
29220
  throw new MineRenderError(`Anvil chunk coordinates do not match external file c.${expected.x}.${expected.z}.mcc`);
29211
29221
  }
29222
+ const numericStates = /* @__PURE__ */ new Map();
29212
29223
  for (const section of this.compounds(level.sections ?? level.Sections, "sections")) {
29213
29224
  const y = this.integer(section.Y, "section Y");
29225
+ let data2;
29214
29226
  if (section.Blocks || section.Data || section.Add) {
29215
- throw new MineRenderError("Numeric Anvil block IDs before Minecraft 1.13 are not supported");
29216
- }
29217
- if (section.block_states && section.block_states.type !== "compound") {
29218
- throw new MineRenderError("Anvil block_states must be a compound");
29219
- }
29220
- const modern = section.block_states?.type === "compound" ? section.block_states.value : void 0;
29221
- const paletteTag = modern ? modern.palette : section.Palette;
29222
- const palette = paletteTag?.type === "list" && paletteTag.value.type === "string" ? paletteTag.value.value : this.compounds(paletteTag, "block palette");
29223
- const data2 = new ChunkData();
29224
- if (palette.length) {
29225
- const states = palette.map((entry) => this.block(entry));
29226
- const indices = this.unpack(modern ? modern.data : section.BlockStates, states.length, !!modern, dataVersion);
29227
- for (let index = 0; index < 4096; index++) {
29228
- const state = states[indices[index]];
29229
- if (!state) throw new MineRenderError(`Anvil palette index ${indices[index]} is out of range`);
29230
- if (!ChunkData.isAir(state)) data2.set(index, state);
29227
+ if (section.Palette || section.BlockStates || section.block_states) {
29228
+ throw new MineRenderError(`Anvil section ${y} mixes numeric and paletted block states`);
29229
+ }
29230
+ data2 = this.numericSection(section, y, options, numericStates);
29231
+ } else {
29232
+ if (section.block_states && section.block_states.type !== "compound") {
29233
+ throw new MineRenderError("Anvil block_states must be a compound");
29234
+ }
29235
+ const modern = section.block_states?.type === "compound" ? section.block_states.value : void 0;
29236
+ const paletteTag = modern ? modern.palette : section.Palette;
29237
+ const palette = paletteTag?.type === "list" && paletteTag.value.type === "string" ? paletteTag.value.value : this.compounds(paletteTag, "block palette");
29238
+ data2 = new ChunkData();
29239
+ if (palette.length) {
29240
+ const states = palette.map((entry) => this.block(entry));
29241
+ const indices = this.unpack(modern ? modern.data : section.BlockStates, states.length, !!modern, dataVersion);
29242
+ for (let index = 0; index < 4096; index++) {
29243
+ const state = states[indices[index]];
29244
+ if (!state) throw new MineRenderError(`Anvil palette index ${indices[index]} is out of range`);
29245
+ if (!ChunkData.isAir(state)) data2.set(index, state);
29246
+ }
29247
+ } else if (modern || section.Palette || section.BlockStates) {
29248
+ throw new MineRenderError("Anvil section has block states without a palette");
29231
29249
  }
29232
- } else if (modern || section.Palette || section.BlockStates) {
29233
- throw new MineRenderError("Anvil section has block states without a palette");
29234
29250
  }
29235
29251
  if (chunk.sections.some((section2) => section2.y === y)) throw new MineRenderError(`Duplicate Anvil section Y ${y}`);
29236
29252
  chunk.sections.push({ y, data: data2 });
@@ -29258,6 +29274,33 @@ var AnvilParser = class {
29258
29274
  }
29259
29275
  return chunk;
29260
29276
  }
29277
+ static numericSection(section, y, options, states) {
29278
+ const bytes = (name, length, optional = false) => {
29279
+ const tag = section[name];
29280
+ if (!tag && optional) return void 0;
29281
+ if (tag?.type !== "byteArray" || !Array.isArray(tag.value) || tag.value.length !== length) {
29282
+ throw new MineRenderError(`Anvil section ${y} ${name} must contain ${length} bytes`);
29283
+ }
29284
+ return tag.value;
29285
+ };
29286
+ const ids = bytes("Blocks", 4096);
29287
+ const metadata = bytes("Data", 2048, true);
29288
+ const extra = bytes("Add", 2048, true);
29289
+ const data = new ChunkData();
29290
+ for (let index = 0; index < 4096; index++) {
29291
+ const shift = (index & 1) * 4;
29292
+ const id = ids[index] & 255 | ((extra?.[index >> 1] ?? 0) >> shift & 15) << 8;
29293
+ const value = (metadata?.[index >> 1] ?? 0) >> shift & 15;
29294
+ const key = id * 16 + value;
29295
+ if (!states.has(key)) states.set(key, resolveLegacyBlock(id, value, options.legacyMappings, options.lenient));
29296
+ const block = states.get(key);
29297
+ if (!block && !options.lenient) {
29298
+ throw new MineRenderError(`Unsupported legacy block ${id}:${value} at Anvil section ${y} index ${index}`);
29299
+ }
29300
+ if (block && !ChunkData.isAir(block)) data.set(index, block);
29301
+ }
29302
+ return data;
29303
+ }
29261
29304
  static compounds(tag, name) {
29262
29305
  if (!tag) return [];
29263
29306
  if (tag.type !== "list" || tag.value.type !== "compound" && tag.value.value.length !== 0) {
@@ -29340,7 +29383,7 @@ var AnvilWorldSource = class {
29340
29383
  this.cachedBytes = 0;
29341
29384
  this.maxCachedRegions = options.maxCachedRegions ?? 4;
29342
29385
  this.maxCachedBytes = options.maxCachedBytes ?? 64 * 1024 * 1024;
29343
- this.readExternalChunk = options.readExternalChunk;
29386
+ this.parseOptions = { readExternalChunk: options.readExternalChunk, legacyMappings: options.legacyMappings, lenient: options.lenient };
29344
29387
  for (const [name, value] of Object.entries({ maxCachedRegions: this.maxCachedRegions, maxCachedBytes: this.maxCachedBytes })) {
29345
29388
  if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name} must be a nonnegative safe integer`);
29346
29389
  }
@@ -29355,8 +29398,8 @@ var AnvilWorldSource = class {
29355
29398
  signal?.throwIfAborted();
29356
29399
  if (!data) return void 0;
29357
29400
  const chunk = await AnvilParser.parseChunk(data, x - regionX * 32, z - regionZ * 32, {
29401
+ ...this.parseOptions,
29358
29402
  region: { x: regionX, z: regionZ },
29359
- readExternalChunk: this.readExternalChunk,
29360
29403
  signal
29361
29404
  });
29362
29405
  signal?.throwIfAborted();
@@ -30737,6 +30780,7 @@ export {
30737
30780
  parseSceneDocument,
30738
30781
  prefix,
30739
30782
  registerNodeEnv,
30783
+ resolveLegacyBlock,
30740
30784
  sampleEntityAnimation,
30741
30785
  sampleEntityKeyframes,
30742
30786
  sampleFluid,