mc-anvil
Version:
A Typescript library for reading Minecraft Anvil format files and Minecraft NBT format files in the browser.
144 lines • 6.51 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SaveParser = exports.parseRegionName = exports.isValidRegionFileName = void 0;
const JSZip = require("jszip");
const queryz_1 = require("queryz");
const __1 = require("..");
const REGION_FORMAT_FILE_NAME = /^r[\.]([\-]?[0-9,]+)[\.]([\-]?[0-9,]+)[\.]mca$/g;
function isValidRegionFileName(name) {
return name.match(REGION_FORMAT_FILE_NAME) !== null;
}
exports.isValidRegionFileName = isValidRegionFileName;
function parseRegionName(name) {
if (!isValidRegionFileName(name))
throw new Error(`${name} is not a valid region file name; expected r.<x>.<z>.mca`);
const m = name.matchAll(REGION_FORMAT_FILE_NAME).next();
return {
x: +m.value[1],
z: +m.value[2]
};
}
exports.parseRegionName = parseRegionName;
function writeDirectoryToZip(d, z, path, overrideMap) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
d.createReader().readEntries(entries => Promise.all(entries.map(e => {
const thispath = `${path}/${e.name}`;
if (overrideMap === null || overrideMap === void 0 ? void 0 : overrideMap.has(thispath))
return new Promise(resolve => {
z.file(thispath, overrideMap.get(thispath));
resolve();
});
return e.isDirectory
? writeDirectoryToZip(e, z, thispath, overrideMap)
: new Promise((resolve, reject) => e.file(f => {
f.arrayBuffer().then(a => { z.file(thispath, a); resolve(); }).catch(reject);
}));
})).then(() => resolve()).catch(reject), reject);
});
});
}
class SaveParser {
constructor(root) {
this.cachedRegions = new Map([]);
this.dirtyRegions = new Map([]);
this.root = root;
}
getRegions() {
return __awaiter(this, void 0, void 0, function* () {
const allEntries = [];
const readEntriesRecursively = (directory) => (new Promise((resolve, reject) => {
const reader = directory.createReader();
const readBatch = () => {
reader.readEntries(entries => {
if (entries.length === 0) {
resolve();
return;
}
allEntries.push(...entries
.filter(x => x.isFile && isValidRegionFileName(x.name))
.map(x => (Object.assign(Object.assign({}, parseRegionName(x.name)), { file: x }))));
readBatch();
}, error => reject(error));
};
readBatch();
}));
return new Promise((resolve, reject) => {
this.root.getDirectory("region", undefined, (regionDirectory) => {
readEntriesRecursively(regionDirectory).then(() => {
resolve(allEntries);
}).catch(reject);
}, reject);
});
});
}
getLevel() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
this.root.getFile("level.dat", undefined, resolve, reject);
});
});
}
getRegionFileContainingCoordinate(coordinate) {
return __awaiter(this, void 0, void 0, function* () {
if (this.cachedRegions.size === 0)
this.cachedRegions = queryz_1.associateBy(yield this.getRegions(), x => `${x.x},${x.z}`, x => x);
const x = Math.floor(coordinate[0] / 512);
const z = Math.floor(coordinate[2] / 512);
return this.cachedRegions.get(`${x},${z}`);
});
}
getAnvilParserByCoordinate(coordinate) {
return __awaiter(this, void 0, void 0, function* () {
const region = yield this.getRegionFileContainingCoordinate(coordinate);
if (!region)
return;
const x = region.x;
const z = region.z;
return new Promise((resolve, reject) => {
if (this.dirtyRegions.get(`${x},${z}`))
resolve(this.dirtyRegions.get(`${x},${z}`));
region.file.file(f => f.arrayBuffer().then(xx => {
const parser = new __1.AnvilParser(xx);
this.dirtyRegions.set(`${x},${z}`, parser);
resolve(parser);
}).catch(reject), reject);
});
});
}
setBlock(coordinates, name, properties) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
(_a = (yield this.getAnvilParserByCoordinate(coordinates))) === null || _a === void 0 ? void 0 : _a.setBlock(coordinates, name, properties);
});
}
getBlock(coordinates) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
return (_a = (yield this.getAnvilParserByCoordinate(coordinates))) === null || _a === void 0 ? void 0 : _a.getBlock(coordinates);
});
}
asZip() {
return __awaiter(this, void 0, void 0, function* () {
const dirtyRegions = [...this.dirtyRegions.keys()];
const zip = new JSZip();
const overrideMap = new Map(dirtyRegions.map(key => [
`/region/r.${key.replace(/,/g, '.')}.mca`,
this.dirtyRegions.get(key).buffer()
]));
yield writeDirectoryToZip(this.root, zip, "", overrideMap);
return zip;
});
}
}
exports.SaveParser = SaveParser;
//# sourceMappingURL=save.js.map