diff --git a/index.js b/index.js index 57710f3..035b287 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const { Vec3 } = require('vec3') const mcData = require('minecraft-data') const sponge = require('./lib/spongeSchematic') +const spongeV3 = require('./lib/spongeV3Schematic') const mcedit = require('./lib/mceditSchematic') class Schematic { @@ -130,11 +131,15 @@ class Schematic { static async read (buffer, version = null) { const schem = nbt.simplify(await parseNbt(buffer)) - try { - return sponge.read(schem, version) - } catch { - return mcedit.read(schem, version) + const formats = [sponge, spongeV3, mcedit] + for (const format of formats) { + try { + return format.read(schem, version) + } catch (e) { + + } } + throw new Error('The schematic did not match any supported format') } async write () { diff --git a/lib/spongeV3Schematic.js b/lib/spongeV3Schematic.js new file mode 100644 index 0000000..ebc2394 --- /dev/null +++ b/lib/spongeV3Schematic.js @@ -0,0 +1,65 @@ +const { Vec3 } = require('vec3') +const versions = require('minecraft-data').versions.pc +const { parseBlockName, getStateId } = require('./states') + +function findVersion (dataVersion) { + for (const v of versions) { + if (v.dataVersion === dataVersion) { + return v.minecraftVersion + } + } + return versions[0].minecraftVersion // default to latest +} + +function parsePalette (mcData, palette) { + const out = [] + for (const [str, id] of Object.entries(palette)) { + const { name, properties } = parseBlockName(str) + out[id] = getStateId(mcData, name, properties) + } + return out +} + +function byteArrayToVarintArray (byteArray) { + const varintArray = [] + let i = 0 + while (i < byteArray.length) { + let value = 0 + let varintLength = 0 + while (true) { + value |= (byteArray[i] & 127) << (varintLength++ * 7) + if (varintLength > 5) throw new Error('VarInt too big (probably corrupted data)') + if ((byteArray[i++] & 128) !== 128) break + } + varintArray.push(value) + } + return varintArray +} + +function read (nbt, version) { + const { Schematic } = require('../') + if (!version) { + version = findVersion(nbt.Schematic.DataVersion) + } + let mcData = require('minecraft-data')(version) + if (!mcData) { + version = '1.20.6' + console.log(`Warning, ${version} is not supported, using 1.20.6 as fallback`) + mcData = require('minecraft-data')(version) + } + const palette = parsePalette(mcData, nbt.Schematic.Blocks.Palette) + const size = new Vec3(nbt.Schematic.Width, nbt.Schematic.Height, nbt.Schematic.Length) + let offset = new Vec3(0, 0, 0) + + if (nbt.Schematic.Offset) { + offset = new Vec3( + nbt.Schematic.Offset[0], + nbt.Schematic.Offset[1], + nbt.Schematic.Offset[2]) + } + const blocks = byteArrayToVarintArray(nbt.Schematic.Blocks.Data) + const schem = new Schematic(version, size, offset, palette, blocks) + return schem +} + +module.exports = { read } diff --git a/test/cycle.test.js b/test/cycle.test.js index 9abc3da..4d31a93 100644 --- a/test/cycle.test.js +++ b/test/cycle.test.js @@ -13,7 +13,6 @@ describe('cycle test', () => { const schemFile = path.join(__dirname, 'schematics', schemName) test(`${schemName} read / write`, async () => { const schematic = await Schematic.read(await fs.readFile(schemFile)) - const tmpFile = path.join(__dirname, schemName + '_test.schem') await fs.writeFile(tmpFile, await schematic.write()) diff --git a/test/schematics/spongeV3.schem b/test/schematics/spongeV3.schem new file mode 100644 index 0000000..d7a989c Binary files /dev/null and b/test/schematics/spongeV3.schem differ