UNPKG

prismarine-chunk

Version:
214 lines (167 loc) 5.44 kB
'use strict' const Vec3 = require('vec3').Vec3 const w = 16 const l = 16 const h = 128 const BLOCK_DATA_SIZE = w * l * h const REGULAR_DATA_SIZE = BLOCK_DATA_SIZE / 2 const SKYLIGHT_DATA_SIZE = BLOCK_DATA_SIZE / 2 const BLOCKLIGHT_DATA_SIZE = BLOCK_DATA_SIZE / 2 const ADDITIONAL_DATA_SIZE_DIRTY = w * l const ADDITIONAL_DATA_SIZE_COLOR = w * l * 4 const BUFFER_SIZE = BLOCK_DATA_SIZE + REGULAR_DATA_SIZE + SKYLIGHT_DATA_SIZE + BLOCKLIGHT_DATA_SIZE + ADDITIONAL_DATA_SIZE_COLOR + ADDITIONAL_DATA_SIZE_DIRTY const readUInt4LE = require('uint4').readUInt4LE const writeUInt4LE = require('uint4').writeUInt4LE module.exports = loader function loader (registry) { Block = require('prismarine-block')(registry) Chunk.w = w Chunk.l = l Chunk.h = h Chunk.BUFFER_SIZE = BUFFER_SIZE Chunk.version = registry.version return Chunk } let Block function exists (val) { return val !== undefined } const getArrayPosition = function (pos) { return pos.x + w * (pos.z + l * pos.y) } const getBlockCursor = function (pos) { return getArrayPosition(pos) } const getBlockDataCursor = function (pos) { return BLOCK_DATA_SIZE + getArrayPosition(pos) * 0.5 } const getBlockLightCursor = function (pos) { return BLOCK_DATA_SIZE + REGULAR_DATA_SIZE + getArrayPosition(pos) * 0.5 } const getSkyLightCursor = function (pos) { return BLOCK_DATA_SIZE + REGULAR_DATA_SIZE + SKYLIGHT_DATA_SIZE + getArrayPosition(pos) * 0.5 } const getHeightMapCursor = function (pos) { return BLOCK_DATA_SIZE + REGULAR_DATA_SIZE + SKYLIGHT_DATA_SIZE + BLOCKLIGHT_DATA_SIZE + (pos.z * w) + pos.x } const getBiomeCursor = function (pos) { return BLOCK_DATA_SIZE + REGULAR_DATA_SIZE + SKYLIGHT_DATA_SIZE + BLOCKLIGHT_DATA_SIZE + ADDITIONAL_DATA_SIZE_DIRTY + ((pos.z * w) + pos.x) * 4 } class Chunk { constructor () { this.data = Buffer.alloc(BUFFER_SIZE) this.data.fill(0) } toJson () { return JSON.stringify({ data: this.data.toJSON() }) } static fromJson (j) { const parsed = JSON.parse(j) const chunk = new Chunk() chunk.data = Buffer.from(parsed.data) return chunk } initialize (iniFunc) { const p = new Vec3(0, 0, 0) for (p.y = 0; p.y < h; p.y++) { for (p.z = 0; p.z < w; p.z++) { for (p.x = 0; p.x < l; p.x++) { const block = iniFunc(p.x, p.y, p.z) if (block === null) { continue } this.setBlock(p, block) } } } } getBlock (pos) { const block = new Block(this.getBlockType(pos), this.getBiome(pos), this.getBlockData(pos)) block.light = this.getBlockLight(pos) block.skyLight = this.getSkyLight(pos) return block } setBlock (pos, block) { if (exists(block.type)) { this.setBlockType(pos, block.type) } if (exists(block.metadata)) { this.setBlockData(pos, block.metadata) } if (exists(block.biome)) { this.setBiome(pos, block.biome.id) } if (exists(block.skyLight)) { this.setSkyLight(pos, block.skyLight) } if (exists(block.light)) { this.setBlockLight(pos, block.light) } } getBlockType (pos) { if (pos.y < 0 || pos.y >= 256) return 0 return this.data.readUInt8(getBlockCursor(pos)) } setBlockType (pos, id) { if (pos.y < 0 || pos.y >= 256) return this.data.writeUInt8(id, getBlockCursor(pos)) } getBlockData (pos) { if (pos.y < 0 || pos.y >= 256) return 0 return readUInt4LE(this.data, getBlockDataCursor(pos)) } setBlockData (pos, data) { if (pos.y < 0 || pos.y >= 256) return writeUInt4LE(this.data, data, getBlockDataCursor(pos)) } getBlockLight (pos) { if (pos.y < 0 || pos.y >= 256) return 0 return readUInt4LE(this.data, getBlockLightCursor(pos)) } setBlockLight (pos, light) { if (pos.y < 0 || pos.y >= 256) return writeUInt4LE(this.data, light, getBlockLightCursor(pos)) } getSkyLight (pos) { if (pos.y < 0 || pos.y >= 256) return 0 return readUInt4LE(this.data, getSkyLightCursor(pos)) } setSkyLight (pos, light) { if (pos.y < 0 || pos.y >= 256) return writeUInt4LE(this.data, light, getSkyLightCursor(pos)) } getBiomeColor (pos) { const color = this.data.readInt32BE(getBiomeCursor(pos)) & 0xFFFFFF return { r: (color >> 16), g: ((color >> 8) & 0xFF), b: (color & 0xFF) } } setBiomeColor (pos, r, g, b) { this.data.writeInt32BE((this.data.readInt32BE(getBiomeCursor(pos)) & 0xFF000000) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0XFF), getBiomeCursor(pos)) } getBiome (pos) { return (this.data.readInt32BE(getBiomeCursor(pos)) & 0xFF000000) >> 24 } setBiome (pos, id) { this.data.writeInt32BE((this.data.readInt32BE(getBiomeCursor(pos)) & 0xFFFFFF) | (id << 24), getBiomeCursor(pos)) } getHeight (pos) { return this.data.readUInt8(getHeightMapCursor(pos)) } setHeight (pos, value) { this.data.writeUInt8(value, getHeightMapCursor(pos)) } load (data) { if (!Buffer.isBuffer(data)) { throw (new Error('Data must be a buffer')) } if (data.length !== BUFFER_SIZE) { throw (new Error(`Data buffer not correct size (was ${data.length}, expected ${BUFFER_SIZE})`)) } this.data = data } // These methods do nothing, and are present only for API compatibility dumpBiomes () { } dumpLight () { } loadLight () { } loadBiomes () { } dump () { return this.data } getMask () { return 0xFFFF } }