UNPKG

prismarine-chunk

Version:
200 lines (169 loc) 5.63 kB
const BitArray = require('../common/BitArray') const neededBits = require('../common/neededBits') const constants = require('../common/constants') const varInt = require('../common/varInt') const GLOBAL_BITS_PER_BLOCK = 13 function getBlockIndex (pos) { return (pos.y << 8) | (pos.z << 4) | pos.x } class ChunkSection { constructor (options = {}) { if (options === null) { return } if (typeof options.solidBlockCount === 'undefined') { options.solidBlockCount = 0 if (options.data) { for (let i = 0; i < constants.BLOCK_SECTION_VOLUME; i++) { if (options.data.get(i) !== 0) { options.solidBlockCount += 1 } } } } if (!options.data) { options.data = new BitArray({ bitsPerValue: 4, capacity: constants.BLOCK_SECTION_VOLUME }) } if (options.palette === undefined) { // dont create palette if its null options.palette = [0] } if (!options.blockLight) { options.blockLight = new BitArray({ bitsPerValue: 4, capacity: constants.BLOCK_SECTION_VOLUME }) } if (options.skyLight === undefined) { // dont create skylight if its null options.skyLight = new BitArray({ bitsPerValue: 4, capacity: constants.BLOCK_SECTION_VOLUME }) } this.data = options.data this.palette = options.palette this.isDirty = false this.blockLight = options.blockLight this.skyLight = options.skyLight this.solidBlockCount = options.solidBlockCount this.maxBitsPerBlock = options.maxBitsPerBlock || GLOBAL_BITS_PER_BLOCK } toJson () { return JSON.stringify({ data: this.data.toJson(), palette: this.palette, isDirty: this.isDirty, blockLight: this.blockLight.toJson(), skyLight: this.skyLight ? this.skyLight.toJson() : this.skyLight, solidBlockCount: this.solidBlockCount }) } static fromJson (j) { const parsed = JSON.parse(j) return new ChunkSection({ data: BitArray.fromJson(parsed.data), palette: parsed.palette, blockLight: BitArray.fromJson(parsed.blockLight), skyLight: parsed.skyLight ? BitArray.fromJson(parsed.skyLight) : parsed.skyLight, solidBlockCount: parsed.solidBlockCount }) } getBlock (pos) { // index in palette or block id // depending on if the global palette or the section palette is used let stateId = this.data.get(getBlockIndex(pos)) if (this.palette !== null) { stateId = this.palette[stateId] } return stateId } setBlock (pos, stateId) { const blockIndex = getBlockIndex(pos) let palettedIndex if (this.palette !== null) { // if necessary, add the block to the palette const indexInPalette = this.palette.indexOf(stateId) // binarySearch(this.palette, stateId, cmp) if (indexInPalette >= 0) { // block already in our palette palettedIndex = indexInPalette } else { // get new block palette index this.palette.push(stateId) palettedIndex = this.palette.length - 1 // check if resize is necessary const bitsPerValue = neededBits(palettedIndex) // if new block requires more bits than the current data array if (bitsPerValue > this.data.getBitsPerValue()) { // is value still enough for section palette if (bitsPerValue <= constants.MAX_BITS_PER_BLOCK) { this.data = this.data.resizeTo(bitsPerValue) } else { // switches to the global palette const newData = new BitArray({ bitsPerValue: this.maxBitsPerBlock, capacity: constants.BLOCK_SECTION_VOLUME }) for (let i = 0; i < constants.BLOCK_SECTION_VOLUME; i++) { const stateId = this.palette[this.data.get(i)] newData.set(i, stateId) } this.palette = null palettedIndex = stateId this.data = newData } } } } else { // uses global palette palettedIndex = stateId } const oldBlock = this.getBlock(pos) if (stateId === 0 && oldBlock !== 0) { this.solidBlockCount -= 1 } else if (stateId !== 0 && oldBlock === 0) { this.solidBlockCount += 1 } this.data.set(blockIndex, palettedIndex) } getBlockLight (pos) { return this.blockLight.get(getBlockIndex(pos)) } getSkyLight (pos) { return this.skyLight ? this.skyLight.get(getBlockIndex(pos)) : 0 } setBlockLight (pos, light) { return this.blockLight.set(getBlockIndex(pos), light) } setSkyLight (pos, light) { return this.skyLight ? this.skyLight.set(getBlockIndex(pos), light) : 0 } isEmpty () { return this.solidBlockCount === 0 } // writes the complete section into a smart buffer object write (smartBuffer) { smartBuffer.writeUInt8(this.data.getBitsPerValue()) // write palette if (this.palette !== null) { varInt.write(smartBuffer, this.palette.length) this.palette.forEach(paletteElement => { varInt.write(smartBuffer, paletteElement) }) } else { // write 0 length for missing palette varInt.write(smartBuffer, 0) } // write block data varInt.write(smartBuffer, this.data.length()) this.data.writeBuffer(smartBuffer) // write block light data this.blockLight.writeBuffer(smartBuffer) if (this.skyLight !== null) { // write sky light data this.skyLight.writeBuffer(smartBuffer) } } } module.exports = ChunkSection