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
11 changes: 11 additions & 0 deletions lib/enum_field.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// A protocol version can describe an enum field as a mapper, which protodef writes by name,
// or as the plain index. Take the index the protocol documents and return whichever form
// this version's schema asks for.
function enumField (registry, packetName, fieldName, index) {
const field = registry.protocol.play?.toServer?.types?.['packet_' + packetName]?.[1]
?.find(entry => entry.name === fieldName)
if (!Array.isArray(field?.type) || field.type[0] !== 'mapper') return index
return field.type[1].mappings[index]
}

module.exports = { enumField }
3 changes: 2 additions & 1 deletion lib/plugins/bed.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { Vec3 } = require('vec3')
const { enumField } = require('../enum_field')

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: enumField(bot.registry, 'entity_action', 'actionId', 2), // leave_bed
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 { enumField } = require('../enum_field')

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: enumField(bot.registry, 'client_command', 'actionId', 1) }) // request_stats
})
}

Expand Down
4 changes: 4 additions & 0 deletions lib/plugins/entities.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { Vec3 } = require('vec3')
const conv = require('../conversions')
const mojangson = require('mojangson')
const { enumField } = require('../enum_field')
// These values are only accurate for versions 1.14 and above (crouch hitbox changes)
// Todo: hitbox sizes for sleeping, swimming/crawling, and flying with elytra
const PLAYER_HEIGHT = 1.8
Expand Down Expand Up @@ -35,6 +36,7 @@ function inject (bot) {
const Entity = require('prismarine-entity')(bot.version)
const Item = require('prismarine-item')(bot.version)
const ChatMessage = require('prismarine-chat')(bot.registry)
const interactHand = enumField(bot.registry, 'use_entity', 'hand', 0) // main hand

// ONLY 1.17 has this destroy_entity packet which is the same thing as entity_destroy packet except the entity is singular
// 1.17.1 reverted this change so this is just a simpler fix
Expand Down Expand Up @@ -916,13 +918,15 @@ function inject (bot) {
y,
z,
sneaking,
hand: interactHand,
location: new Vec3(x, y, z)
})
} else {
bot._client.write('use_entity', {
target: target.id,
mouse: leftClick,
sneaking,
hand: interactHand,
location: new Vec3(0, 0, 0)
})
}
Expand Down
4 changes: 3 additions & 1 deletion lib/plugins/game.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const nbt = require('prismarine-nbt')
const { enumField } = require('../enum_field')

module.exports = inject

const difficultyNames = ['peaceful', 'easy', 'normal', 'hard']
Expand Down Expand Up @@ -123,7 +125,7 @@ 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', { actionId: enumField(bot.registry, 'client_command', 'actionId', 0) }) // perform_respawn
}
if ((packet.reason === 3) || (packet.reason === 'change_game_mode')) {
bot.game.gameMode = parseGameMode(packet.gameMode)
Expand Down
6 changes: 5 additions & 1 deletion lib/plugins/health.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { enumField } = require('../enum_field')

module.exports = inject

function inject (bot, options) {
Expand Down Expand Up @@ -41,7 +43,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: enumField(bot.registry, 'client_command', 'actionId', 0) }) // perform_respawn
}

bot.respawn = respawn
Expand Down
6 changes: 4 additions & 2 deletions lib/plugins/inventory.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 { once, sleep, createDoneTask, createTask, withTimeout } = require('../promise_utils')
const { toNotchianYaw, toNotchianPitch } = require('../conversions')
const { enumField } = require('../enum_field')

module.exports = inject

Expand All @@ -25,6 +26,7 @@ const ALWAYS_CONSUMABLES = [
function inject (bot, { hideErrors }) {
const Item = require('prismarine-item')(bot.registry)
const windows = require('prismarine-windows')(bot.version)
const interactHand = enumField(bot.registry, 'use_entity', 'hand', 0) // main hand

let eatingTask = createDoneTask()
let sequence = 0
Expand Down Expand Up @@ -252,7 +254,7 @@ function inject (bot, { hideErrors }) {
target: entity.id,
mouse: 0, // interact with entity
sneaking: false,
hand: 0, // interact with the main hand
hand: interactHand,
location: new Vec3(0, 0, 0)
})
}
Expand All @@ -264,7 +266,7 @@ function inject (bot, { hideErrors }) {
target: entity.id,
mouse: 2, // interact with entity at
sneaking: false,
hand: 0, // interact with the main hand
hand: interactHand,
x: position.x - entity.position.x,
y: position.y - entity.position.y,
z: position.z - entity.position.z,
Expand Down
40 changes: 40 additions & 0 deletions test/internalTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,46 @@ for (const supportedVersion of mineflayer.testedVersions) {
})
})

it('activateEntity sends an interact the server can read', (done) => {
server.on('playerJoin', (client) => {
client.on('use_entity', (packet) => {
assert.strictEqual(packet.target, 42)
done()
})
client.write('login', bot.test.generateLoginPacket())
const chunk = bot.test.buildChunk()
chunk.setBlockType(vec3(1, 65, 1), bot.registry.blocksByName.gold_block.id)
client.write('map_chunk', generateChunkPacket(chunk))
client.write('position', {
x: 1.5,
y: 66,
z: 1.5,
dx: 0, // 1.21.3
dy: 0, // 1.21.3
dz: 0, // 1.21.3
pitch: 0,
yaw: 0,
flags: bot.supportFeature('positionPacketHasBitflags') ? { x: false, y: false, z: false, yaw: false, pitch: false } : 0,
teleportId: 0
})
bot.once('forcedMove', () => {
bot.entities[42] = { id: 42, position: vec3(2.5, 66, 1.5) }
bot.activateEntity(bot.entities[42])
})
})
})

it('respawn sends a client_command the server can read', (done) => {
server.on('playerJoin', (client) => {
client.on('client_command', () => done())
client.write('login', bot.test.generateLoginPacket())
bot.once('login', () => {
bot.isAlive = false
bot.respawn()
})
})
})

it('\'itemDrop\' event', function (done) {
const itemData = {
itemId: 149,
Expand Down
Loading