UNPKG

@minecraft/creator-tools

Version:

Minecraft Creator Tools command line and libraries.

485 lines (483 loc) 17 kB
"use strict"; // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. Object.defineProperty(exports, "__esModule", { value: true }); exports.NbtTagType = void 0; const Utilities_1 = require("./../core/Utilities"); const Log_1 = require("./../core/Log"); const INbtTag_1 = require("./INbtTag"); var NbtTagType; (function (NbtTagType) { NbtTagType[NbtTagType["end"] = 0] = "end"; NbtTagType[NbtTagType["byte"] = 1] = "byte"; NbtTagType[NbtTagType["short"] = 2] = "short"; NbtTagType[NbtTagType["int"] = 3] = "int"; NbtTagType[NbtTagType["long"] = 4] = "long"; NbtTagType[NbtTagType["float"] = 5] = "float"; NbtTagType[NbtTagType["double"] = 6] = "double"; NbtTagType[NbtTagType["byteArray"] = 7] = "byteArray"; NbtTagType[NbtTagType["string"] = 8] = "string"; NbtTagType[NbtTagType["list"] = 9] = "list"; NbtTagType[NbtTagType["compound"] = 10] = "compound"; NbtTagType[NbtTagType["intArray"] = 11] = "intArray"; NbtTagType[NbtTagType["longArray"] = 12] = "longArray"; NbtTagType[NbtTagType["unknown"] = 99] = "unknown"; })(NbtTagType = exports.NbtTagType || (exports.NbtTagType = {})); class NbtBinaryTag { get childrenWithEnd() { return this._children; } getTagChildren() { if (this._children.length === 0) { return []; } if (this.lastTagIsEnd) { return this._children.slice(0, -1); } return this._children; } getTagLength() { if (this.lastTagIsEnd) { return this._children.length - 1; } return this._children.length; } get lastTagIsEnd() { if (this._children.length === 0) { return false; } const lastTag = this._children[this._children.length - 1]; if (lastTag.type === NbtTagType.end) { return true; } else if (this.childTagType === NbtTagType.end && lastTag._children.length === 0) { return true; } return false; } get valueAsString() { if (typeof this.value === "number") { return this.value.toString(); } else if (typeof this.value === "string") { return this.value; } return ""; } get valueAsJSONObject() { let obj = undefined; const str = this.valueAsString; if (str) { try { obj = JSON.parse(str); } catch (e) { obj = undefined; } } return obj; } get valueAsNumericArray() { const childTags = this.getTagChildren(); const numarr = []; for (const childTag of childTags) { numarr.push(childTag.valueAsInt); } return numarr; } get valueAsStringArray() { const childTags = this.getTagChildren(); const numarr = []; for (const childTag of childTags) { numarr.push(childTag.valueAsString); } return numarr; } get valueAsBoolean() { if (typeof this.value === "boolean") { return this.value; } else if (typeof this.value === "string") { if (this.value === "true" || this.value === "TRUE" || this.value === "1") { return true; } return false; } else if (typeof this.value === "number") { if (this.value <= 0) { return false; } return true; } return false; } get valueAsInt() { if (typeof this.value === "number") { return this.value; } else if (typeof this.value === "string") { return parseInt(this.value); } else if (typeof this.value === "boolean" && this.value === true) { return 1; } return 0; } get valueAsFloat() { if (typeof this.value === "number") { return this.value; } else if (typeof this.value === "string") { return parseFloat(this.value); } return 0; } get valueAsBigInt() { if (typeof this.value === "bigint") { return this.value; } const type = typeof this.value; if (this.value !== null && (type === "number" || type === "string" || type === "boolean" || type === "bigint")) { return BigInt(this.value); } return BigInt(0); } constructor(type, name, isListChild) { this.childTagType = NbtTagType.unknown; this.value = null; this._children = []; this.type = type; this.name = name; this.isListChild = isListChild; } setListFromArray(arr) { let children = this.getTagChildren(); if (children.length > arr.length) { while (children.length > arr.length) { this.removeTagByIndex(children.length - 1); children = this.getTagChildren(); } } else { while (children.length < arr.length) { const newTag = new NbtBinaryTag(NbtTagType.int, "", this.type === NbtTagType.list); this.pushTag(newTag); children = this.getTagChildren(); } } for (let i = 0; i < children.length; i++) { children[i].value = arr[i]; } } pushTag(tag) { // if this is a list we've got an end tag at the 0 slot, swap it out if (this.type === NbtTagType.list && this.lastTagIsEnd && this._children.length === 1 && tag.type !== NbtTagType.end) { this._children[0] = tag; if ((this.childTagType === NbtTagType.unknown || this.childTagType === NbtTagType.end) && tag.childTagType !== NbtTagType.end) { this.childTagType = tag.type; } } else if (this.type === NbtTagType.list) { if ((this.childTagType === NbtTagType.unknown || this.childTagType === NbtTagType.end) && tag.childTagType !== NbtTagType.end) { this.childTagType = tag.type; } this._children.push(tag); } else if (this.type === NbtTagType.compound && this.lastTagIsEnd && tag.type !== NbtTagType.end) { // duplicate the End tag a the end this._children.push(this._children[this._children.length - 1]); this._children[this._children.length - 2] = tag; } else { this._children.push(tag); } } prepareForSave(includingChildren) { if (this.type === NbtTagType.list) { if (this._children.length === 0) { this.childTagType = NbtTagType.end; this.addTag(NbtTagType.end); } else if (this._children.length > 1 && this.lastTagIsEnd) { this._children = this._children.slice(0, -1); } } else if (this.type === NbtTagType.compound && !this.lastTagIsEnd) { this.addTag(NbtTagType.end); } if (includingChildren) { for (let i = 0; i < this._children.length; i++) { this._children[i].prepareForSave(includingChildren); } } } getByteSize() { this.prepareForSave(false); let byteSize = 0; if (!this.isListChild) { byteSize += 1; // one byte for type of NBT Tag if (this.type !== NbtTagType.end) { byteSize += 2 + this.name.length; // two bytes + name length for name. assumes name is ASCII (1 byte per char) } } switch (this.type) { case NbtTagType.byte: byteSize += 1; break; case NbtTagType.short: byteSize += 2; break; case NbtTagType.int: byteSize += 4; break; case NbtTagType.long: byteSize += 8; break; case NbtTagType.float: byteSize += 4; break; case NbtTagType.double: byteSize += 8; break; case NbtTagType.string: byteSize += 2; // length of string is 2-byte short if (typeof this.value === "string") { const bytes = Utilities_1.default.convertStringToBytes(this.value, "UTF-8"); if (bytes === undefined) { throw new Error("Unexpected NBT conversion error in writing string."); } byteSize += bytes.length; } break; case NbtTagType.list: byteSize += 5; // one byte for type of items, + 4 bytes for length; break; case NbtTagType.intArray: byteSize += 4; // length of array byteSize += 4 * this.value.length; break; case NbtTagType.longArray: byteSize += 4; // length of array byteSize += 8 * this.value.length; break; default: break; } for (let i = 0; i < this._children.length; i++) { byteSize += this._children[i].getByteSize(); } return byteSize; } getJsonString() { return JSON.stringify(this.getJson(), null, 2); } getJson() { this.prepareForSave(false); const tag = new INbtTag_1.default(); if (this.name !== undefined && this.name !== "") { tag.name = this.name; } if (this.type !== NbtTagType.unknown) { tag.type = this.type; } if (this.value !== undefined) { tag.value = this.value; } if (this.childTagType !== NbtTagType.unknown) { tag.childTagType = this.childTagType; } if (this._children.length > 0) { tag.children = []; for (let i = 0; i < this._children.length; i++) { tag.children.push(this._children[i].getJson()); } } return tag; } writeBytes(bytes, index, littleEndian) { this.prepareForSave(false); const byteLength = bytes.buffer.byteLength; const dv = new DataView(bytes.buffer, 0, byteLength); if (!this.isListChild) { // write out type. dv.setInt8(index, this.type); index += 1; if (this.type !== NbtTagType.end) { // write out name length; dv.setInt16(index, this.name.length, littleEndian); index += 2; // TODO: probably an incorrect assumption that name is always "ASCII" for (let j = 0; j < this.name.length; j++) { bytes[index++] = this.name.charCodeAt(j); } } } switch (this.type) { case NbtTagType.byte: dv.setInt8(index, this.valueAsInt); index += 1; break; case NbtTagType.short: dv.setInt16(index, this.valueAsInt, littleEndian); index += 2; break; case NbtTagType.int: dv.setInt32(index, this.valueAsInt, littleEndian); index += 4; break; case NbtTagType.long: dv.setBigInt64(index, this.valueAsBigInt, littleEndian); index += 8; break; case NbtTagType.float: dv.setFloat32(index, this.valueAsFloat, littleEndian); index += 4; break; case NbtTagType.double: dv.setFloat64(index, this.valueAsFloat, littleEndian); index += 8; break; case NbtTagType.string: if (typeof this.value === "string") { const bytes = Utilities_1.default.convertStringToBytes(this.value, "UTF-8"); if (bytes === undefined) { throw new Error("Unexpected NBT conversion error in writing string."); } dv.setInt16(index, bytes.length, littleEndian); index += 2; index = Utilities_1.default.writeString(dv, index, this.value, "UTF-8"); if (index < 0 || index >= byteLength) { throw new Error("Unexpected error writing string."); } } else { dv.setInt16(index, 0, littleEndian); index += 2; } break; case NbtTagType.list: dv.setInt8(index, this.childTagType); index += 1; dv.setInt32(index, this.getTagLength(), littleEndian); index += 4; break; case NbtTagType.intArray: // array length dv.setInt32(index, this._children.length, littleEndian); index += 4; const nums = this.value; for (let i = 0; i < nums.length; i++) { dv.setInt32(index, nums[i], littleEndian); index += 4; } break; case NbtTagType.longArray: // array length dv.setInt32(index, this._children.length, littleEndian); index += 4; const bigints = this.value; for (let i = 0; i < bigints.length; i++) { dv.setBigInt64(index, bigints[i], littleEndian); index += 8; } break; } for (let i = 0; i < this._children.length; i++) { index = this._children[i].writeBytes(bytes, index, littleEndian); } return index; } removeTagByIndex(index) { const newChildren = []; let removedItem = false; for (let i = 0; i < this._children.length; i++) { if (i !== index) { newChildren.push(this._children[i]); } else { removedItem = true; } } this._children = newChildren; return removedItem; } removeTag(tagName) { const newChildren = []; let removedItem = false; for (let i = 0; i < this._children.length; i++) { if (this._children[i].name !== tagName) { newChildren.push(this._children[i]); } else { removedItem = true; } } this._children = newChildren; return removedItem; } ensureTag(tagName, tagType) { const tag = this.child(tagName); if (tag !== null) { Log_1.default.assert(tag.type === tagType, "Unexpected data type '" + tag.type + "' for an nbt tag '" + tagName + "'"); return tag; } return this.addTag(tagType, tagName); } addTag(tagType, tagName) { if (this.type !== NbtTagType.compound && this.type !== NbtTagType.list) { throw new Error("Unsupported type for adding a tag"); } if (tagName === undefined) { tagName = ""; } const newTag = new NbtBinaryTag(tagType, tagName, this.type === NbtTagType.list); this.pushTag(newTag); return newTag; } getProperty(name) { for (let i = 0; i < this._children.length; i++) { if (this._children[i].name === name) { return this._children[i]; } } return null; } child(name) { if (this.name === name) { return this; } for (let i = 0; i < this._children.length; i++) { if (this._children[i].name === name) { return this._children[i]; } } return null; } find(name) { if (this.name === name) { return this; } for (let i = 0; i < this._children.length; i++) { if (this._children[i].name === name) { return this._children[i]; } } for (let i = 0; i < this._children.length; i++) { const tagChild = this._children[i]; if (tagChild.type === NbtTagType.compound || tagChild.type === NbtTagType.list) { const result = tagChild.find(name); if (result != null) { return result; } } } return null; } } exports.default = NbtBinaryTag; //# sourceMappingURL=../maps/minecraft/NbtBinaryTag.js.map