mc-anvil
Version:
A Typescript library for reading Minecraft Anvil format files and Minecraft NBT format files in the browser.
174 lines • 8.98 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlockDataParser = exports.paletteBlockList = exports.paletteAsList = exports.paletteNameList = exports.blockTypeID = exports.block = exports.blockTypeString = void 0;
const MD5 = require("crypto-js/md5");
const queryz_1 = require("queryz");
const nbt_1 = require("../nbt");
const nbt_2 = require("../nbt/nbt");
const util_1 = require("../util");
const chunk_1 = require("./chunk");
function blockTypeString(t) {
var _a, _b;
const name = ((_a = t.find(x => x.name.toLowerCase() === "name")) === null || _a === void 0 ? void 0 : _a.data) || "";
const properties = (((_b = t.find(x => x.name.toLowerCase() === "properties")) === null || _b === void 0 ? void 0 : _b.data) || [])
.filter(x => x.type === nbt_1.TagType.STRING)
.sort((a, b) => a.name.localeCompare(b.name))
.map(x => `${x.name}:${x.data}`);
return `${name}(${properties.join(",")})`;
}
exports.blockTypeString = blockTypeString;
function block(t) {
var _a, _b;
const name = ((_a = t.find(x => x.name.toLowerCase() === "name")) === null || _a === void 0 ? void 0 : _a.data) || "";
const properties = {};
(((_b = t.find(x => x.name.toLowerCase() === "properties")) === null || _b === void 0 ? void 0 : _b.data) || [])
.filter(x => x.type === nbt_1.TagType.STRING)
.forEach(x => { properties[x.name] = x.data; });
return { name, properties };
}
exports.block = block;
function blockTypeID(t) {
const w = MD5(blockTypeString(t)).words;
return w[0];
}
exports.blockTypeID = blockTypeID;
function paletteNameList(palette) {
return palette.data.data.map(x => { var _a; return (((_a = x.find(x => x.name.toLowerCase() === "name")) === null || _a === void 0 ? void 0 : _a.data) || ""); });
}
exports.paletteNameList = paletteNameList;
function paletteAsList(palette) {
return palette.data.data.map(block);
}
exports.paletteAsList = paletteAsList;
function paletteBlockList(palette) {
return palette.data.data.map(blockTypeString);
}
exports.paletteBlockList = paletteBlockList;
class BlockDataParser extends util_1.BitParser {
constructor(blockStates, palette) {
const d = new util_1.BinaryParser(blockStates.data);
const b = new BigUint64Array(d.remainingLength() / 8);
for (let i = 0; i < b.length; ++i)
b[i] = d.getUInt64LE();
super(b.buffer);
this.palette = palette;
this.paletteNames = paletteNameList(this.palette);
this.blockTypeStringMap = null;
this.blockTypeIDMap = null;
this.blockTypeIDToStringMap = null;
}
static writeBlockStates(states, palette) {
const blocks = states.map(state => palette ? blockTypeString(palette.data.data[state]) : "" + state);
const new_id_map = new Map([...new Set(blocks)].map((x, i) => [x, i]));
const palette_map = new Map(palette === null || palette === void 0 ? void 0 : palette.data.data.map(x => [blockTypeString(x), x]));
const new_palette = palette ? [...new Set(blocks)].sort((a, b) => new_id_map.get(a) - new_id_map.get(b)).map(block => palette_map.get(block)) : undefined;
palette = palette && new_palette ? Object.assign(Object.assign({}, palette), { data: Object.assign(Object.assign({}, palette.data), { data: new_palette }) }) : palette;
if (palette)
states = blocks.map(block => new_id_map.get(block));
const paletteSize = (palette === null || palette === void 0 ? void 0 : palette.data.data.length) === undefined ? Math.max(...states) : palette.data.data.length - 1;
const l = Math.floor(Math.log2(paletteSize || 1)) + 1;
const length = l < 4 ? 4 : l;
const c = Math.floor(64 / length);
const toSkip = 64 % c;
const r = new ArrayBuffer(8 * Math.ceil(states.length / c));
const d = new util_1.BitParser(r);
let workingList = [];
for (let i = 0; i < states.length; ++i) {
if (c > 0 && c < Infinity && i % c === 0) {
if (workingList.length > 0)
d.setBits(toSkip, 0);
for (let i = workingList.length - 1; i >= 0; --i)
d.setBits(length, workingList[i]);
workingList = [];
}
workingList.push(states[i]);
}
if (workingList.length > 0)
d.setBits(toSkip, 0);
for (let i = 0; i < c - workingList.length; ++i)
d.setBits(length, 0);
for (let i = workingList.length - 1; i >= 0; --i)
d.setBits(length, workingList[i]);
return [r, palette];
}
getBlocksGenericOriginal(f, limit) {
const paletteSize = this.palette.data.data.length;
const toRead = paletteSize ? Math.ceil(Math.log2(paletteSize)) : 0;
const total = limit || chunk_1.Chunk.BLOCKS_PER_CHUNK;
const r = [];
for (let i = 0; i < total; ++i)
r.push(f(this.getBits(toRead)));
return r;
}
getBlocksGeneric(f, limit) {
const paletteSize = this.palette.data.data.length;
const l = Math.floor(Math.log2((paletteSize - 1) || 1)) + 1;
const toRead = paletteSize ? (l < 4 ? 4 : l) : 0;
const r = [];
const skipIndex = Math.floor(64 / toRead);
const toSkip = 64 % toRead;
const total = limit || (this.view.byteLength / 8 * skipIndex);
let workingList = [];
for (let i = 0; i < total; ++i) {
if (skipIndex > 0 && skipIndex < Infinity && i % skipIndex === 0) {
this.getBits(toSkip);
for (let i = workingList.length - 1; i >= 0; --i)
r.push(f(workingList[i]));
workingList = [];
}
workingList.push(this.getBits(toRead));
}
for (let i = workingList.length - 1; i >= 0; --i)
r.push(f(workingList[i]));
if (total > chunk_1.Chunk.BLOCKS_PER_CHUNK)
return r.slice(0, chunk_1.Chunk.BLOCKS_PER_CHUNK);
return r;
}
getBlockTypeIDMap() {
this.blockTypeIDMap = queryz_1.associateBy(this.palette.data.data, x => { var _a; return (((_a = x.find(x => x.name.toLowerCase() === "name")) === null || _a === void 0 ? void 0 : _a.data) || ""); }, blockTypeID);
}
getBlockTypeStringMap() {
this.blockTypeStringMap = queryz_1.associateBy(this.palette.data.data, x => { var _a; return (((_a = x.find(x => x.name.toLowerCase() === "name")) === null || _a === void 0 ? void 0 : _a.data) || ""); }, blockTypeString);
}
getBlockTypeIDToStringMap() {
this.blockTypeIDToStringMap = queryz_1.associateBy(this.palette.data.data, blockTypeID, blockTypeString);
}
getRawBlocks(original, limit) {
return original
? this.getBlocksGenericOriginal(x => x, limit)
: this.getBlocksGeneric(x => x, limit);
}
getBlocks(original, limit) {
return original
? this.getBlocksGenericOriginal(x => this.palette.data.data[x], limit)
: this.getBlocksGeneric(x => this.palette.data.data[x], limit);
}
getBlockTypeNames(original, limit) {
if (this.blockTypeStringMap === null)
this.getBlockTypeStringMap();
return original
? this.getBlocksGenericOriginal(x => { var _a; return (_a = this.blockTypeStringMap) === null || _a === void 0 ? void 0 : _a.get(this.paletteNames[x]); }, limit)
: this.getBlocksGeneric(x => { var _a; return (_a = this.blockTypeStringMap) === null || _a === void 0 ? void 0 : _a.get(this.paletteNames[x]); }, limit);
}
getBlockTypeIDs(original, limit) {
if (this.blockTypeIDMap === null)
this.getBlockTypeIDMap();
return original
? this.getBlocksGenericOriginal(x => { var _a; return (_a = this.blockTypeIDMap) === null || _a === void 0 ? void 0 : _a.get(this.paletteNames[x]); }, limit)
: this.getBlocksGeneric(x => { var _a; return (_a = this.blockTypeIDMap) === null || _a === void 0 ? void 0 : _a.get(this.paletteNames[x]); }, limit);
}
blockStateFromHash(hash) {
var _a;
if (this.blockTypeIDToStringMap === null)
this.getBlockTypeIDToStringMap();
return ((_a = this.blockTypeIDToStringMap) === null || _a === void 0 ? void 0 : _a.get(hash)) || "";
}
findBlocksByName(name) {
var _a, _b;
const blocks = this.getRawBlocks();
const nameIndex = (_b = (_a = nbt_2.findCompoundListChildren(this.palette, x => x.name.toLowerCase() === "name")) === null || _a === void 0 ? void 0 : _a.map((x, i) => ({ x, i })).find(x => { var _a; return ((_a = x.x) === null || _a === void 0 ? void 0 : _a.data) === name; })) === null || _b === void 0 ? void 0 : _b.i;
return blocks.map((x, i) => ({ x, i })).filter(x => x.x === nameIndex).map(x => x.i);
}
}
exports.BlockDataParser = BlockDataParser;
//# sourceMappingURL=block.js.map