Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
- [bot.game.serverBrand](#botgameserverbrand)
- [bot.game.minY](#botgameminy)
- [bot.game.height](#botgameheight)
- [bot.abilities](#botabilities)
- [bot.physicsEnabled](#botphysicsenabled)
- [bot.player](#botplayer)
- [bot.players](#botplayers)
Expand Down Expand Up @@ -183,6 +184,7 @@
- ["death"](#death)
- ["health"](#health)
- ["breath"](#breath)
- ["abilities" (abilities)](#abilities-abilities)
- ["entityAttributes" (entity)](#entityattributes-entity)
- ["entitySwingArm" (entity)](#entityswingarm-entity)
- ["entityHurt" (entity)](#entityhurt-entity)
Expand Down Expand Up @@ -906,6 +908,23 @@ minimum y of the world

world height

#### bot.abilities

What the server last allowed the player in the abilities packet.

```js
{
invulnerable: false,
// the server has the player in flight; physics stops applying gravity
flying: false,
// the player is allowed to start flying
mayFly: false,
instantBuild: false,
flyingSpeed: 0.05,
walkingSpeed: 0.1
}
```

#### bot.physicsEnabled

Enable physics, default true.
Expand Down Expand Up @@ -1321,6 +1340,10 @@ Fires when your hp or food change.

Fires when your oxygen level change.

#### "abilities" (abilities)

Fires when the server sends the abilities packet, with the new [bot.abilities](#botabilities).

#### "entityAttributes" (entity)

Fires when an attribute of an entity changes.
Expand Down
11 changes: 11 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export interface BotEvents {
death: () => Promise<void> | void
health: () => Promise<void> | void
breath: () => Promise<void> | void
abilities: (abilities: Abilities) => Promise<void> | void
entitySwingArm: (entity: Entity) => Promise<void> | void
entityHurt: (entity: Entity, source: Entity) => Promise<void> | void
entityDead: (entity: Entity) => Promise<void> | void
Expand Down Expand Up @@ -198,6 +199,7 @@ export interface Bot extends TypedEmitter<BotEvents> {
oxygenLevel: number
physics: PhysicsOptions
physicsEnabled: boolean
abilities: Abilities
time: Time
quickBarSlot: number
inventory: Window<StorageEvents>
Expand Down Expand Up @@ -535,6 +537,15 @@ export interface Experience {
progress: number
}

export interface Abilities {
invulnerable: boolean
flying: boolean
mayFly: boolean
instantBuild: boolean
flyingSpeed: number
walkingSpeed: number
}

export interface PhysicsOptions {
maxGroundSpeed: number
terminalVelocity: number
Expand Down
1 change: 1 addition & 0 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const mc = require('minecraft-protocol')
const { EventEmitter } = require('events')
const pluginLoader = require('./plugin_loader')
const plugins = {
abilities: require('./plugins/abilities'),
bed: require('./plugins/bed'),
title: require('./plugins/title'),
block_actions: require('./plugins/block_actions'),
Expand Down
36 changes: 36 additions & 0 deletions lib/plugins/abilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module.exports = inject

// ClientboundPlayerAbilitiesPacket's flag bits.
const FLAG_INVULNERABLE = 1
const FLAG_FLYING = 2
const FLAG_MAY_FLY = 4
const FLAG_INSTANT_BUILD = 8

function inject (bot) {
// Abilities' defaults, until the server says otherwise.
bot.abilities = {
invulnerable: false,
flying: false,
mayFly: false,
instantBuild: false,
flyingSpeed: 0.05,
walkingSpeed: 0.1
}

bot._client.on('abilities', (packet) => {
bot.abilities = {
invulnerable: (packet.flags & FLAG_INVULNERABLE) !== 0,
flying: (packet.flags & FLAG_FLYING) !== 0,
mayFly: (packet.flags & FLAG_MAY_FLY) !== 0,
instantBuild: (packet.flags & FLAG_INSTANT_BUILD) !== 0,
flyingSpeed: packet.flyingSpeed,
walkingSpeed: packet.walkingSpeed
}
// prismarine-physics reads the flight state off the entity.
if (bot.entity) {
bot.entity.flying = bot.abilities.flying
bot.entity.flyingSpeed = bot.abilities.flyingSpeed
}
bot.emit('abilities', bot.abilities)
})
}
32 changes: 32 additions & 0 deletions test/internalTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,38 @@ for (const supportedVersion of mineflayer.testedVersions) {
})
})

describe('abilities', () => {
it('tracks what the server allows', (done) => {
server.on('playerJoin', (client) => {
bot.once('abilities', (abilities) => {
assert.strictEqual(abilities.invulnerable, true)
assert.strictEqual(abilities.flying, true)
assert.strictEqual(abilities.mayFly, true)
assert.strictEqual(abilities.instantBuild, false)
assert.strictEqual(abilities.flyingSpeed, 0.05000000074505806)
assert.strictEqual(abilities.walkingSpeed, 0.10000000149011612)
assert.strictEqual(bot.abilities, abilities)
// prismarine-physics reads the flight state off the entity
assert.strictEqual(bot.entity.flying, true)
done()
})
client.write('login', bot.test.generateLoginPacket())
bot.once('login', () => {
// Abilities' own defaults hold until the server sends the packet
assert.deepStrictEqual(bot.abilities, {
invulnerable: false,
flying: false,
mayFly: false,
instantBuild: false,
flyingSpeed: 0.05,
walkingSpeed: 0.1
})
client.write('abilities', { flags: 7, flyingSpeed: 0.05, walkingSpeed: 0.1 })
})
})
})
})

describe('entities', () => {
it('entity id changes on login', (done) => {
const loginPacket = bot.test.generateLoginPacket()
Expand Down
Loading