minerender 2.1.0-alpha.91 → 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/browser/index.d.mts +28 -6
- package/dist/browser/index.d.ts +28 -6
- package/dist/browser/index.js +288 -197
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +288 -197
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +300 -204
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +28 -6
- package/dist/node/index.d.ts +28 -6
- package/dist/node/index.js +289 -197
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +288 -197
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
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,168 +111946,10 @@ property list uchar int vertex_index
|
|
|
111945
111946
|
init_buffer2();
|
|
111946
111947
|
init_process2();
|
|
111947
111948
|
|
|
111948
|
-
// src/model/multiblock/
|
|
111949
|
+
// src/model/multiblock/LegacyBlocks.ts
|
|
111949
111950
|
init_dirname();
|
|
111950
111951
|
init_buffer2();
|
|
111951
111952
|
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
|
|
112101
|
-
init_dirname();
|
|
112102
|
-
init_buffer2();
|
|
112103
|
-
init_process2();
|
|
112104
|
-
|
|
112105
|
-
// src/model/multiblock/SchematicParser.ts
|
|
112106
|
-
init_dirname();
|
|
112107
|
-
init_buffer2();
|
|
112108
|
-
init_process2();
|
|
112109
|
-
init_MineRenderError();
|
|
112110
111953
|
|
|
112111
111954
|
// src/model/multiblock/legacyBlocks.json
|
|
112112
111955
|
var legacyBlocks_default = {
|
|
@@ -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
|
|
113849
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|
|
@@ -119319,10 +119335,13 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119319
119335
|
return this.locations(this.bytes(data)).map(({ x: x4, z: z4 }) => ({ x: x4, z: z4 }));
|
|
119320
119336
|
}
|
|
119321
119337
|
/** Decodes all stored chunks. Gzip, zlib, LZ4, and uncompressed payloads are supported. */
|
|
119322
|
-
static async parse(data) {
|
|
119338
|
+
static async parse(data, options = {}) {
|
|
119339
|
+
options.signal?.throwIfAborted();
|
|
119323
119340
|
const bytes = this.bytes(data);
|
|
119324
119341
|
const chunks = [];
|
|
119325
|
-
for (const location of this.locations(bytes))
|
|
119342
|
+
for (const location of this.locations(bytes)) {
|
|
119343
|
+
chunks.push(await this.abortable(this.readChunk(bytes, location, options), options.signal));
|
|
119344
|
+
}
|
|
119326
119345
|
return { chunks };
|
|
119327
119346
|
}
|
|
119328
119347
|
/**
|
|
@@ -119331,13 +119350,28 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119331
119350
|
* @param localZ - Chunk z within the region, from 0 to 31.
|
|
119332
119351
|
* @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
|
|
119333
119352
|
*/
|
|
119334
|
-
static async parseChunk(data, localX, localZ) {
|
|
119353
|
+
static async parseChunk(data, localX, localZ, options = {}) {
|
|
119354
|
+
options.signal?.throwIfAborted();
|
|
119335
119355
|
if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
|
|
119336
119356
|
throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
|
|
119337
119357
|
}
|
|
119338
119358
|
const bytes = this.bytes(data);
|
|
119339
119359
|
const location = this.locations(bytes).find(({ x: x4, z: z4 }) => x4 === localX && z4 === localZ);
|
|
119340
|
-
return location ? this.readChunk(bytes, location) : void 0;
|
|
119360
|
+
return location ? this.abortable(this.readChunk(bytes, location, options), options.signal) : void 0;
|
|
119361
|
+
}
|
|
119362
|
+
static async abortable(promise, signal) {
|
|
119363
|
+
if (!signal) return promise;
|
|
119364
|
+
let abort2;
|
|
119365
|
+
const cancelled = new Promise((_4, reject) => {
|
|
119366
|
+
abort2 = () => reject(signal.reason);
|
|
119367
|
+
signal.addEventListener("abort", abort2, { once: true });
|
|
119368
|
+
if (signal.aborted) abort2();
|
|
119369
|
+
});
|
|
119370
|
+
try {
|
|
119371
|
+
return await Promise.race([promise, cancelled]);
|
|
119372
|
+
} finally {
|
|
119373
|
+
signal.removeEventListener("abort", abort2);
|
|
119374
|
+
}
|
|
119341
119375
|
}
|
|
119342
119376
|
static bytes(data) {
|
|
119343
119377
|
return data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
@@ -119363,20 +119397,41 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119363
119397
|
}
|
|
119364
119398
|
return locations;
|
|
119365
119399
|
}
|
|
119366
|
-
static async readChunk(data, location) {
|
|
119367
|
-
|
|
119368
|
-
|
|
119400
|
+
static async readChunk(data, location, options) {
|
|
119401
|
+
options.signal?.throwIfAborted();
|
|
119402
|
+
const format3 = data[location.offset + 4];
|
|
119403
|
+
const external = (format3 & 128) !== 0;
|
|
119404
|
+
const compression = format3 & 127;
|
|
119369
119405
|
if (compression !== 1 && compression !== 2 && compression !== 3 && compression !== 4) {
|
|
119370
119406
|
throw new MineRenderError(`Unsupported Anvil compression ${compression}`);
|
|
119371
119407
|
}
|
|
119372
119408
|
let payload = data.subarray(location.offset + 5, location.offset + 4 + location.length);
|
|
119409
|
+
let expected;
|
|
119410
|
+
if (external) {
|
|
119411
|
+
if (!options.region || !options.readExternalChunk) {
|
|
119412
|
+
throw new MineRenderError("External Anvil .mcc chunks require region coordinates and readExternalChunk");
|
|
119413
|
+
}
|
|
119414
|
+
if (![options.region.x, options.region.z].every(Number.isSafeInteger)) {
|
|
119415
|
+
throw new RangeError("Anvil region coordinates must be safe integers");
|
|
119416
|
+
}
|
|
119417
|
+
expected = { x: options.region.x * 32 + location.x, z: options.region.z * 32 + location.z };
|
|
119418
|
+
if (![expected.x, expected.z].every(Number.isSafeInteger)) {
|
|
119419
|
+
throw new RangeError("External Anvil chunk coordinates must be safe integers");
|
|
119420
|
+
}
|
|
119421
|
+
const externalData = await options.readExternalChunk(expected.x, expected.z, options.signal);
|
|
119422
|
+
options.signal?.throwIfAborted();
|
|
119423
|
+
if (externalData === void 0) throw new MineRenderError(`External Anvil chunk c.${expected.x}.${expected.z}.mcc is missing`);
|
|
119424
|
+
payload = this.bytes(externalData);
|
|
119425
|
+
}
|
|
119373
119426
|
if (compression === 4) {
|
|
119374
119427
|
payload = decodeAnvilLz4(payload);
|
|
119375
119428
|
} else if (compression !== 3) {
|
|
119376
119429
|
const stream = new Blob([payload]).stream().pipeThrough(new DecompressionStream(compression === 1 ? "gzip" : "deflate"));
|
|
119377
119430
|
payload = new Uint8Array(await new Response(stream).arrayBuffer());
|
|
119378
119431
|
}
|
|
119432
|
+
options.signal?.throwIfAborted();
|
|
119379
119433
|
const nbt = await NBTHelper.fromBuffer(payload, "big");
|
|
119434
|
+
options.signal?.throwIfAborted();
|
|
119380
119435
|
const root = nbt.value;
|
|
119381
119436
|
const level = root.Level?.type === "compound" ? root.Level.value : root;
|
|
119382
119437
|
const dataVersion = root.DataVersion?.type === "int" ? root.DataVersion.value : void 0;
|
|
@@ -119389,28 +119444,37 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119389
119444
|
if ((chunk.x % 32 + 32) % 32 !== location.x || (chunk.z % 32 + 32) % 32 !== location.z) {
|
|
119390
119445
|
throw new MineRenderError("Anvil chunk coordinates do not match its region location");
|
|
119391
119446
|
}
|
|
119447
|
+
if (expected && (chunk.x !== expected.x || chunk.z !== expected.z)) {
|
|
119448
|
+
throw new MineRenderError(`Anvil chunk coordinates do not match external file c.${expected.x}.${expected.z}.mcc`);
|
|
119449
|
+
}
|
|
119450
|
+
const numericStates = /* @__PURE__ */ new Map();
|
|
119392
119451
|
for (const section of this.compounds(level.sections ?? level.Sections, "sections")) {
|
|
119393
119452
|
const y5 = this.integer(section.Y, "section Y");
|
|
119453
|
+
let data2;
|
|
119394
119454
|
if (section.Blocks || section.Data || section.Add) {
|
|
119395
|
-
|
|
119396
|
-
|
|
119397
|
-
|
|
119398
|
-
|
|
119399
|
-
}
|
|
119400
|
-
|
|
119401
|
-
|
|
119402
|
-
|
|
119403
|
-
|
|
119404
|
-
|
|
119405
|
-
const
|
|
119406
|
-
|
|
119407
|
-
|
|
119408
|
-
const
|
|
119409
|
-
|
|
119410
|
-
|
|
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");
|
|
119411
119477
|
}
|
|
119412
|
-
} else if (modern || section.Palette || section.BlockStates) {
|
|
119413
|
-
throw new MineRenderError("Anvil section has block states without a palette");
|
|
119414
119478
|
}
|
|
119415
119479
|
if (chunk.sections.some((section2) => section2.y === y5)) throw new MineRenderError(`Duplicate Anvil section Y ${y5}`);
|
|
119416
119480
|
chunk.sections.push({ y: y5, data: data2 });
|
|
@@ -119438,6 +119502,33 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119438
119502
|
}
|
|
119439
119503
|
return chunk;
|
|
119440
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
|
+
}
|
|
119441
119532
|
static compounds(tag, name2) {
|
|
119442
119533
|
if (!tag) return [];
|
|
119443
119534
|
if (tag.type !== "list" || tag.value.type !== "compound" && tag.value.value.length !== 0) {
|
|
@@ -119523,6 +119614,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119523
119614
|
this.cachedBytes = 0;
|
|
119524
119615
|
this.maxCachedRegions = options.maxCachedRegions ?? 4;
|
|
119525
119616
|
this.maxCachedBytes = options.maxCachedBytes ?? 64 * 1024 * 1024;
|
|
119617
|
+
this.parseOptions = { readExternalChunk: options.readExternalChunk, legacyMappings: options.legacyMappings, lenient: options.lenient };
|
|
119526
119618
|
for (const [name2, value] of Object.entries({ maxCachedRegions: this.maxCachedRegions, maxCachedBytes: this.maxCachedBytes })) {
|
|
119527
119619
|
if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name2} must be a nonnegative safe integer`);
|
|
119528
119620
|
}
|
|
@@ -119536,7 +119628,11 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119536
119628
|
const data = await this.getRegion(regionX, regionZ, signal);
|
|
119537
119629
|
signal?.throwIfAborted();
|
|
119538
119630
|
if (!data) return void 0;
|
|
119539
|
-
const chunk = await
|
|
119631
|
+
const chunk = await AnvilParser.parseChunk(data, x4 - regionX * 32, z4 - regionZ * 32, {
|
|
119632
|
+
...this.parseOptions,
|
|
119633
|
+
region: { x: regionX, z: regionZ },
|
|
119634
|
+
signal
|
|
119635
|
+
});
|
|
119540
119636
|
signal?.throwIfAborted();
|
|
119541
119637
|
if (chunk && (chunk.x !== x4 || chunk.z !== z4)) {
|
|
119542
119638
|
throw new MineRenderError(`Anvil chunk coordinates ${chunk.x},${chunk.z} do not match requested column ${x4},${z4}`);
|
|
@@ -119567,7 +119663,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
119567
119663
|
settled: false,
|
|
119568
119664
|
promise: Promise.resolve().then(() => {
|
|
119569
119665
|
controller.signal.throwIfAborted();
|
|
119570
|
-
return this.readRegion(x4, z4, controller.signal);
|
|
119666
|
+
return abortable2(this.readRegion(x4, z4, controller.signal), controller.signal);
|
|
119571
119667
|
}).then((data) => {
|
|
119572
119668
|
controller.signal.throwIfAborted();
|
|
119573
119669
|
let bytes = data instanceof Uint8Array ? data : data === void 0 ? void 0 : new Uint8Array(data);
|