Skip to content
Closed
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
3 changes: 2 additions & 1 deletion lib/plugins/bed.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const enumValue = require('../protocol_enum')
const { Vec3 } = require('vec3')

module.exports = inject
Expand Down Expand Up @@ -70,7 +71,7 @@ function inject (bot) {
} else {
bot._client.write('entity_action', {
entityId: bot.entity.id,
actionId: 2,
actionId: enumValue(bot, 'entity_action', 'actionId', 'leave_bed', 2),
jumpBoost: 0
})
}
Expand Down
5 changes: 4 additions & 1 deletion lib/plugins/creative.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const assert = require('assert')
const { Vec3 } = require('vec3')
const { sleep, onceWithCleanup } = require('../promise_utils')
const { once } = require('../promise_utils')
const enumValue = require('../protocol_enum')

module.exports = inject

Expand Down Expand Up @@ -46,7 +47,9 @@ function inject (bot) {
resolve()
}, timeoutMs)
pendingStatsRequests.push(request)
bot._client.write('client_command', bot.supportFeature('respawnIsPayload') ? { payload: 1 } : { actionId: 1 })
bot._client.write('client_command', bot.supportFeature('respawnIsPayload')
? { payload: 1 }
: { actionId: enumValue(bot, 'client_command', 'actionId', 'request_stats', 1) })
})
}

Expand Down
5 changes: 4 additions & 1 deletion lib/plugins/game.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const enumValue = require('../protocol_enum')
const nbt = require('prismarine-nbt')
module.exports = inject

Expand Down Expand Up @@ -123,7 +124,9 @@ function inject (bot, options) {

bot._client.on('game_state_change', (packet) => {
if ((packet.reason === 4 || packet.reason === 'win_game') && packet.gameMode === 1) {
bot._client.write('client_command', { action: 0 })
bot._client.write('client_command', bot.supportFeature('respawnIsPayload')
? { payload: 0 }
: { actionId: enumValue(bot, 'client_command', 'actionId', 'perform_respawn', 0) })
}
if ((packet.reason === 3) || (packet.reason === 'change_game_mode')) {
bot.game.gameMode = parseGameMode(packet.gameMode)
Expand Down
5 changes: 4 additions & 1 deletion lib/plugins/health.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const enumValue = require('../protocol_enum')
module.exports = inject

function inject (bot, options) {
Expand Down Expand Up @@ -41,7 +42,9 @@ function inject (bot, options) {

const respawn = () => {
if (bot.isAlive) return
bot._client.write('client_command', bot.supportFeature('respawnIsPayload') ? { payload: 0 } : { actionId: 0 })
bot._client.write('client_command', bot.supportFeature('respawnIsPayload')
? { payload: 0 }
: { actionId: enumValue(bot, 'client_command', 'actionId', 'perform_respawn', 0) })
}

bot.respawn = respawn
Expand Down
8 changes: 8 additions & 0 deletions lib/protocol_enum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Some enum fields are a string mapper in newer protocols and a plain id in older ones
// (entity_action.actionId from 1.21.6, client_command.actionId from 26.1). protodef only
// writes the form the loaded version declares.
module.exports = function enumValue (bot, packetName, fieldName, name, id) {
const field = bot.registry.protocol.play.toServer.types[`packet_${packetName}`][1]
.find(f => f.name === fieldName)
return Array.isArray(field?.type) && field.type[0] === 'mapper' ? name : id
}
50 changes: 50 additions & 0 deletions test/internalTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,56 @@ for (const supportedVersion of mineflayer.testedVersions) {
})

describe('game', () => {
it('respawns with the action id or name this version declares', (done) => {
server.on('playerJoin', async (client) => {
await bot.test.pluginsLoaded
const loggedIn = once(bot, 'login')
await client.write('login', bot.test.generateLoginPacket())
await loggedIn
const writes = []
// Every write must match this version's packet shape.
bot._client.write = (name, params) => {
bot._client.serializer.createPacketBuffer({ name, params })
if (name === 'client_command') writes.push(params)
}
bot.isAlive = false
bot.respawn()
try {
const field = registry.protocol.play.toServer.types.packet_client_command[1][0]
const usesNames = Array.isArray(field.type) && field.type[0] === 'mapper'
assert.deepStrictEqual(writes, [{ [field.name]: usesNames ? 'perform_respawn' : 0 }])
done()
} catch (err) {
done(err)
}
})
})

it('wakes with the action id or name this version declares', (done) => {
server.on('playerJoin', async (client) => {
await bot.test.pluginsLoaded
const loggedIn = once(bot, 'login')
await client.write('login', bot.test.generateLoginPacket())
await loggedIn
const writes = []
bot._client.write = (name, params) => {
bot._client.serializer.createPacketBuffer({ name, params })
if (name === 'entity_action') writes.push(params.actionId)
}
bot.isSleeping = true
bot.wake().then(() => {
try {
const field = registry.protocol.play.toServer.types.packet_entity_action[1][1]
const usesNames = Array.isArray(field.type) && field.type[0] === 'mapper'
assert.deepStrictEqual(writes, [usesNames ? 'leave_bed' : 2])
done()
} catch (err) {
done(err)
}
}, done)
})
})

it('responds to ping / transaction packets', (done) => { // only on 1.17
server.on('playerJoin', async (client) => {
if (bot.supportFeature('transactionPacketExists')) {
Expand Down
Loading