UNPKG

prismarine-world

Version:

The core implementation of the world for prismarine

214 lines (187 loc) 6.3 kB
const { Vec3 } = require('vec3') const { EventEmitter } = require('events') const { RaycastIterator } = require('./iterators') function posInChunk (pos) { return new Vec3(Math.floor(pos.x) & 15, Math.floor(pos.y), Math.floor(pos.z) & 15) } class WorldSync extends EventEmitter { constructor (world) { super() this.async = world } initialize (iniFunc, length, width, height = 256, iniPos = new Vec3(0, 0, 0)) { function inZone (x, y, z) { if (x >= width || x < 0) { return false } if (z >= length || z < 0) { return false } if (y >= height || y < 0) { return false } return true } const iniPosInChunk = posInChunk(iniPos) const chunkLength = Math.ceil((length + iniPosInChunk.z) / 16) const chunkWidth = Math.ceil((width + iniPosInChunk.x) / 16) for (let chunkZ = 0; chunkZ < chunkLength; chunkZ++) { const actualChunkZ = chunkZ + Math.floor(iniPos.z / 16) for (let chunkX = 0; chunkX < chunkWidth; chunkX++) { const actualChunkX = chunkX + Math.floor(iniPos.x / 16) const chunk = this.getColumn(actualChunkX, actualChunkZ) const offsetX = chunkX * 16 - iniPosInChunk.x const offsetZ = chunkZ * 16 - iniPosInChunk.z chunk.initialize((x, y, z) => inZone(x + offsetX, y - iniPos.y, z + offsetZ) ? iniFunc(x + offsetX, y - iniPos.y, z + offsetZ) : null) this.setColumn(actualChunkX, actualChunkZ, chunk) } } } raycast (from, direction, range, matcher = null) { const iter = new RaycastIterator(from, direction, range) let pos = iter.next() while (pos) { const position = new Vec3(pos.x, pos.y, pos.z) const block = this.getBlock(position) if (block) { if (matcher) { if (matcher(block, iter)) { return block } } else { const intersect = iter.intersect(block.shapes, position) if (intersect) { block.face = intersect.face block.intersect = intersect.pos return block } } } pos = iter.next() } return null } _emitBlockUpdate (oldBlock, newBlock, position) { oldBlock.position = position.floored() newBlock.position = oldBlock.position this.emit('blockUpdate', oldBlock, newBlock) this.emit(`blockUpdate:${position}`, oldBlock, newBlock) } unloadColumn (chunkX, chunkZ) { this.async.unloadColumn(chunkX, chunkZ) const columnCorner = new Vec3(chunkX * 16, 0, chunkZ * 16) this.emit('chunkColumnUnload', columnCorner) } getColumns () { return this.async.getColumns() } getColumn (chunkX, chunkZ) { return this.async.getLoadedColumn(chunkX, chunkZ) } getColumnAt (pos) { return this.async.getLoadedColumnAt(pos) } setColumn (chunkX, chunkZ, chunk, save = true) { this.async.setLoadedColumn(chunkX, chunkZ, chunk, save) const columnCorner = new Vec3(chunkX * 16, 0, chunkZ * 16) this.emit('chunkColumnLoad', columnCorner) } // Block accessors: getBlock (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return null const block = chunk.getBlock(posInChunk(pos)) block.position = pos.floored() return block } getBlockStateId (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return 0 return chunk.getBlockStateId(posInChunk(pos)) } getBlockType (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return 0 return chunk.getBlockType(posInChunk(pos)) } getBlockData (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return 0 return chunk.getBlockData(posInChunk(pos)) } getBlockLight (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return 0 return chunk.getBlockLight(posInChunk(pos)) } getSkyLight (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return 0 return chunk.getSkyLight(posInChunk(pos)) } getBiome (pos) { const chunk = this.getColumnAt(pos) if (!chunk) return 0 return chunk.getBiome(posInChunk(pos)) } setBlock (pos, block) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setBlock(pInChunk, block) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, block, pos) } setBlockStateId (pos, stateId) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setBlockStateId(pInChunk, stateId) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos) } setBlockType (pos, blockType) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setBlockType(pInChunk, blockType) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos) } setBlockData (pos, data) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setBlockData(pInChunk, data) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos) } setBlockLight (pos, light) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setBlockLight(pInChunk, light) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos) } setSkyLight (pos, light) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setSkyLight(pInChunk, light) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos) } setBiome (pos, biome) { const chunk = this.getColumnAt(pos) if (!chunk) return const pInChunk = posInChunk(pos) const oldBlock = chunk.getBlock(pInChunk) chunk.setBiome(pInChunk, biome) this.async.saveAt(pos) this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos) } } module.exports = WorldSync