Skip to content

Commit

Permalink
add the same block events as mineflayer (#56)
Browse files Browse the repository at this point in the history
* add the same block events as mineflayer

see https://github.com/PrismarineJS/mineflayer/blob/master/docs/api.md#blockupdate-oldblock-newblock

working towards PrismarineJS/mineflayer#334 (comment)

this will do a get at each set, making the set methods a bit slower
it is needed to keep compatibility with mineflayer

I think it is ok as initialize can be used to do a faster set for many blocks

* fix posInChunk thing
  • Loading branch information
rom1504 committed Feb 20, 2021
1 parent bc94235 commit 5f2702e
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 100 deletions.
106 changes: 21 additions & 85 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ Create a world instance, takes an optional `generateChunk(chunkX, chunkZ)` funct
If provided, prismarine-world will first try to load the map from these regions, and then try to generate the world if
the chunk isn't saved. `savingInterval` default to 50ms.

#### "blockUpdate" (oldBlock, newBlock)

Fires when a block updates. Both `oldBlock` and `newBlock` provided for
comparison.

Note that `oldBlock` may be `null`.

#### "blockUpdate:(x, y, z)" (oldBlock, newBlock)

Fires for a specific point. Both `oldBlock` and `newBlock` provided for
comparison.

Note that `oldBlock` may be `null`.

#### "chunkColumnLoad" (point)
#### "chunkColumnUnload" (point)

Fires when a chunk has updated. `point` is the coordinates to the corner
of the chunk with the smallest x, y, and z values.

### World.initialize(iniFunc,length,width,height=256,iniPos=new Vec3(0,0,0))

Initialize the world with a given blocks cube. Useful to load quickly a schematic.
Expand Down Expand Up @@ -127,91 +147,7 @@ Returns a promise that is resolved when all saving is done.

Build a sync world, will delegate all the saving work to the async one

### World.initialize(iniFunc,length,width,height=256,iniPos=new Vec3(0,0,0))

Initialize the world with a given blocks cube. Useful to load quickly a schematic.

* `iniFunc` is a function(x,y,z) that returns a prismarine-block
* `length`, `width` and `height` are the size to iterate on
* `iniPos` is the position where to start the iteration

Returns an array of `{chunkX,chunkZ}`

This works only on loaded columns.

### World.sync.getColumns()

Return all loaded columns

All the following methods are sync.

### World.sync.unloadColumn(chunkX,chunkZ)

Unload column from memory

### World.sync.setColumn(chunkX,chunkZ,chunk)

Set `chunk` at `chunkX` and `chunkZ`

### World.sync.getColumn(chunkX,chunkZ)

Return the column at `chunkX` and `chunkZ`

### World.sync.getBlock(pos)

Get the [Block](https://github.com/PrismarineJS/prismarine-block) at [pos](https://github.com/andrewrk/node-vec3)

### World.sync.setBlock(pos,block)

Set the [Block](https://github.com/PrismarineJS/prismarine-block) at [pos](https://github.com/andrewrk/node-vec3)

### World.sync.getBlockStateId(pos)

Get the block state at `pos`

### World.sync.getBlockType(pos)

Get the block type at `pos`

### World.sync.getBlockData(pos)

Get the block data (metadata) at `pos`

### World.sync.getBlockLight(pos)

Get the block light at `pos`

### World.sync.getSkyLight(pos)

Get the block sky light at `pos`

### World.sync.getBiome(pos)

Get the block biome id at `pos`

### World.sync.setBlockStateId(pos, stateId)

Set the block state `stateId` at `pos`

### World.sync.setBlockType(pos, id)

Set the block type `id` at `pos`

### World.sync.setBlockData(pos, data)

Set the block `data` (metadata) at `pos`

### World.sync.setBlockLight(pos, light)

Set the block `light` at `pos`

### World.sync.setSkyLight(pos, light)

Set the block sky `light` at `pos`

### World.sync.setBiome(pos, biome)

Set the block `biome` id at `pos`
It exposes the same methods as World but all methods are sync.

## Iterators

Expand Down
35 changes: 35 additions & 0 deletions examples/simple.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const World = require('../index')('1.16')
const Chunk = require('prismarine-chunk')('1.16')
const Vec3 = require('vec3')

function generateSimpleChunk (chunkX, chunkZ) {
const chunk = new Chunk()

for (let x = 0; x < 16; x++) {
for (let z = 0; z < 16; z++) {
chunk.setBlockType(new Vec3(x, 50, z), 2)
for (let y = 0; y < 256; y++) {
chunk.setSkyLight(new Vec3(x, y, z), 15)
}
}
}

return chunk
}

const world = new World(generateSimpleChunk)

async function main () {
world.on('blockUpdate', (oldBlock, newBlock) => {
console.log('blockUpdate', oldBlock.stateId, newBlock.stateId)
})
world.on('blockUpdate:(3, 50, 3)', (oldBlock, newBlock) => {
console.log('blockUpdate:(3, 50, 3)', oldBlock.stateId, newBlock.stateId)
})
const pos = new Vec3(3, 50, 3)
console.log('initial', await world.getBlockStateId(pos))
await world.setBlockStateId(pos, 47)
console.log('last', await world.getBlockStateId(pos))
}

main()
52 changes: 45 additions & 7 deletions src/world.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,18 @@ class World extends EventEmitter {
return this.columns[key]
}

_emitBlockUpdate (oldBlock, newBlock, position) {
this.emit('blockUpdate', oldBlock, newBlock)
this.emit(`blockUpdate:${position}`, oldBlock, newBlock)
}

setLoadedColumn (chunkX, chunkZ, chunk, save = true) {
const key = columnKeyXZ(chunkX, chunkZ)
this.columns[key] = chunk

const columnCorner = new Vec3(chunkX * 16, 0, chunkZ * 16)
this.emit('chunkColumnLoad', columnCorner)

if (this.storageProvider && save) { this.queueSaving(chunkX, chunkZ) }
}

Expand All @@ -115,6 +123,8 @@ class World extends EventEmitter {
unloadColumn (chunkX, chunkZ) {
const key = columnKeyXZ(chunkX, chunkZ)
delete this.columns[key]
const columnCorner = new Vec3(chunkX * 16, 0, chunkZ * 16)
this.emit('chunkColumnUnload', columnCorner)
}

async saveNow () {
Expand Down Expand Up @@ -183,8 +193,12 @@ class World extends EventEmitter {
}

async setBlock (pos, block) {
(await this.getColumnAt(pos)).setBlock(posInChunk(pos), block)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBlock(pInChunk, block)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, block, pos)
}

async getBlock (pos) {
Expand Down Expand Up @@ -216,33 +230,57 @@ class World extends EventEmitter {
}

async setBlockStateId (pos, stateId) {
(await this.getColumnAt(pos)).setBlockStateId(posInChunk(pos), stateId)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBlockStateId(pInChunk, stateId)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}

async setBlockType (pos, blockType) {
(await this.getColumnAt(pos)).setBlockType(posInChunk(pos), blockType)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBlockType(pInChunk, blockType)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}

async setBlockData (pos, data) {
(await this.getColumnAt(pos)).setBlockData(posInChunk(pos), data)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBlockData(pInChunk, data)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}

async setBlockLight (pos, light) {
(await this.getColumnAt(pos)).setBlockLight(posInChunk(pos), light)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBlockLight(pInChunk, light)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}

async setSkyLight (pos, light) {
(await this.getColumnAt(pos)).setSkyLight(posInChunk(pos), light)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setSkyLight(pInChunk, light)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}

async setBiome (pos, biome) {
(await this.getColumnAt(pos)).setBiome(posInChunk(pos), biome)
const chunk = (await this.getColumnAt(pos))
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBiome(pInChunk, biome)
this.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}
}

Expand Down
46 changes: 38 additions & 8 deletions src/worldsync.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,15 @@ class WorldSync extends EventEmitter {
return null
}

_emitBlockUpdate (oldBlock, newBlock, position) {
this.emit('blockUpdate', oldBlock, newBlock)
if (position) 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 () {
Expand All @@ -74,7 +81,9 @@ class WorldSync extends EventEmitter {
}

setColumn (chunkX, chunkZ, chunk, save = true) {
return this.async.setLoadedColumn(chunkX, chunkZ, chunk, save)
this.async.setLoadedColumn(chunkX, chunkZ, chunk, save)
const columnCorner = new Vec3(chunkX * 16, 0, chunkZ * 16)
this.emit('chunkColumnLoad', columnCorner)
}

// Block accessors:
Expand Down Expand Up @@ -124,50 +133,71 @@ class WorldSync extends EventEmitter {
setBlock (pos, block) {
const chunk = this.getColumnAt(pos)
if (!chunk) return
chunk.setBlock(posInChunk(pos), block)
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBlock(pInChunk, block)
this.async.saveAt(pos)
this._emitBlockUpdate(oldBlock, block)
}

setBlockStateId (pos, stateId) {
const chunk = this.getColumnAt(pos)
if (!chunk) return
chunk.setBlockStateId(posInChunk(pos), stateId)
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
chunk.setBlockType(posInChunk(pos), blockType)
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
chunk.setBlockData(posInChunk(pos), data)
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
chunk.setBlockLight(posInChunk(pos), light)
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
chunk.setSkyLight(posInChunk(pos), light)
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
chunk.setBiome(posInChunk(pos), biome)
const pInChunk = posInChunk(pos)
const oldBlock = chunk.getBlock(pInChunk)
chunk.setBiome(pInChunk, biome)
this.async.saveAt(pos)
this._emitBlockUpdate(oldBlock, chunk.getBlock(pInChunk), pos)
}
}

Expand Down

0 comments on commit 5f2702e

Please sign in to comment.