Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 1.21.3. #3489

Merged
merged 20 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 18 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: 7 additions & 4 deletions lib/plugins/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,13 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
bot._client.on('explosion', (packet) => {
// explosion
const p = new Vec3(packet.x, packet.y, packet.z)
packet.affectedBlockOffsets.forEach((offset) => {
const pt = p.offset(offset.x, offset.y, offset.z)
updateBlockState(pt, 0)
})
if (packet.affectedBlockOffsets) {
// TODO: server no longer sends in 1.21.3. Is client supposed to compute this or is it sent via normal block updates?
packet.affectedBlockOffsets.forEach((offset) => {
const pt = p.offset(offset.x, offset.y, offset.z)
updateBlockState(pt, 0)
})
}
})

bot._client.on('spawn_entity_painting', (packet) => {
Expand Down
26 changes: 24 additions & 2 deletions lib/plugins/creative.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,42 @@ function inject (bot) {
const creativeSlotsUpdates = []

// WARN: This method should not be called twice on the same slot before first promise succeeds
async function setInventorySlot (slot, item) {
async function setInventorySlot (slot, item, waitTimeout = 400) {
assert(slot >= 0 && slot <= 44)

if (Item.equal(bot.inventory.slots[slot], item, true)) return
if (creativeSlotsUpdates[slot]) {
throw new Error(`Setting slot ${slot} cancelled due to calling bot.creative.setInventorySlot(${slot}, ...) again`)
}
creativeSlotsUpdates[slot] = true

bot._client.write('set_creative_slot', {
slot,
item: Item.toNotch(item)
})

if (bot.supportFeature('noAckOnCreateSetSlotPacket')) {
// No ack
bot._setSlot(slot, item)
rom1504 marked this conversation as resolved.
Show resolved Hide resolved
if (waitTimeout === 0) return // no wait
// allow some time to see if server rejects
return new Promise((resolve, reject) => {
function updateSlot (oldItem, newItem) {
console.log('[creative] Slot update', arguments)
if (newItem.itemId !== item.itemId) {
creativeSlotsUpdates[slot] = false
reject(Error('Server rejected'))
}
}
bot.inventory.once(`updateSlot:${slot}`, updateSlot)
setTimeout(() => {
bot.inventory.off(`updateSlot:${slot}`, updateSlot)
console.log('[creative] setSlot OK')
creativeSlotsUpdates[slot] = false
resolve()
}, waitTimeout)
})
}

await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, {
timeout: 5000,
checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata
Expand Down
114 changes: 104 additions & 10 deletions lib/plugins/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,16 @@ function inject (bot) {
bot.emit('entityMoved', entity)
})

// 1.21.3 - merges the packets above
bot._client.on('sync_entity_position', (packet) => {
const entity = fetchEntity(packet.entityId)
entity.position.set(packet.x, packet.y, packet.z)
entity.velocity.update(packet.dx, packet.dy, packet.dz)
entity.yaw = packet.yaw
entity.pitch = packet.pitch
bot.emit('entityMoved', entity)
})

bot._client.on('entity_head_rotation', (packet) => {
// entity head look
const entity = fetchEntity(packet.entityId)
Expand All @@ -361,6 +371,11 @@ function inject (bot) {
if (eventName) bot.emit(eventName, entity)
})

bot._client.on('damage_event', (packet) => { // 1.20+
const entity = bot.entities[packet.entityId]
bot.emit('entityHurt', entity)
})

bot._client.on('attach_entity', (packet) => {
// attach entity
const entity = fetchEntity(packet.entityId)
Expand Down Expand Up @@ -583,8 +598,65 @@ function inject (bot) {
})

bot._client.on('player_info', (packet) => {
console.dir(packet, { depth: null })
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

// player list item(s)

if (typeof packet.action !== 'number') {
// the features checks below this will be un-needed with https://github.com/PrismarineJS/minecraft-data/pull/948
for (const update of packet.data) {
let player = bot.uuidToUsername[update.uuid] ? bot.players[bot.uuidToUsername[update.uuid]] : null
let newPlayer = false

const obj = {
uuid: update.uuid
}

if (!player) newPlayer = true

player ||= obj

if (packet.action.add_player) {
obj.username = update.player.name
obj.displayName = player.displayName || new ChatMessage({ text: '', extra: [{ text: update.player.name }] })
obj.skinData = extractSkinInformation(update.player.properties)
}

if (packet.action.update_game_mode) {
obj.gamemode = update.gamemode
}

if (packet.action.update_latency) {
obj.ping = update.latency
}

if (update.displayName) {
obj.displayName = ChatMessage.fromNotch(update.displayName)
}

if (newPlayer) {
if (!obj.username) continue // Should be unreachable
player = bot.players[obj.username] = obj
bot.uuidToUsername[obj.uuid] = obj.username
} else {
Object.assign(player, obj)
}

const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === player.username)
player.entity = playerEntity

if (playerEntity === bot.entity) {
bot.player = player
}

if (newPlayer) {
bot.emit('playerJoined', player)
} else {
bot.emit('playerUpdated', player)
}
}
return
}

if (bot.supportFeature('playerInfoActionIsBitfield')) {
for (const item of packet.data) {
let player = bot.uuidToUsername[item.uuid] ? bot.players[bot.uuidToUsername[item.uuid]] : null
Expand Down Expand Up @@ -795,20 +867,42 @@ function inject (bot) {
}

function moveVehicle (left, forward) {
bot._client.write('steer_vehicle', {
sideways: left,
forward,
jump: 0x01
})
if (bot.supportFeature('newPlayerInputPacket')) {
// docs:
// * left can take -1 or 1 : -1 means right, 1 means left
// * forward can take -1 or 1 : -1 means backward, 1 means forward
bot._client.write('player_input', {
inputs: {
forward: forward > 0,
backward: forward < 0,
left: left > 0,
right: left < 0
}
})
} else {
bot._client.write('steer_vehicle', {
sideways: left,
forward,
jump: 0x01
})
}
}

function dismount () {
if (bot.vehicle) {
bot._client.write('steer_vehicle', {
sideways: 0.0,
forward: 0.0,
jump: 0x02
})
if (bot.supportFeature('newPlayerInputPacket')) {
bot._client.write('player_input', {
inputs: {
jump: true
}
})
} else {
bot._client.write('steer_vehicle', {
sideways: 0.0,
forward: 0.0,
jump: 0x02
})
}
} else {
bot.emit('error', new Error('dismount: not mounted'))
}
Expand Down
14 changes: 12 additions & 2 deletions lib/plugins/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ const dimensionNames = {
1: 'the_end'
}

const parseGameMode = gameModeBits => gameModes[(gameModeBits & 0b11)] // lower two bits
const parseGameMode = gameModeBits => {
if (gameModeBits < 0 || gameModeBits > 0b11) {
return 'survival'
}
return gameModes[(gameModeBits & 0b11)] // lower two bits
}

function inject (bot, options) {
function getBrandCustomChannelName () {
Expand All @@ -25,7 +30,12 @@ function inject (bot, options) {
function handleRespawnPacketData (packet) {
bot.game.levelType = packet.levelType ?? (packet.isFlat ? 'flat' : 'default')
bot.game.hardcore = packet.isHardcore ?? Boolean(packet.gameMode & 0b100)
bot.game.gameMode = packet.gamemode || parseGameMode(packet.gameMode)
// Either a respawn packet or a login packet. Depending on the packet it can be "gamemode" or "gameMode"
if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5
bot.game.gameMode = packet.gamemode
} else {
bot.game.gameMode = parseGameMode(packet.gamemode ?? packet.gameMode)
}
if (bot.supportFeature('segmentedRegistryCodecData')) { // 1.20.5
if (typeof packet.dimension === 'number') {
bot.game.dimension = bot.registry.dimensionsArray[packet.dimension]?.name?.replace('minecraft:', '')
Expand Down
4 changes: 3 additions & 1 deletion lib/plugins/generic_place.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ function inject (bot) {
cursorX: dx,
cursorY: dy,
cursorZ: dz,
insideBlock: false
insideBlock: false,
sequence: 0, // 1.19.0
worldBorderHit: false // 1.21.3
})
}

Expand Down
18 changes: 12 additions & 6 deletions lib/plugins/inventory.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ function inject (bot, { hideErrors }) {
// TODO: tell the server that we are not sneaking while doing this
await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), false)
// place block message
// TODO: logic below can likely be simplified
if (bot.supportFeature('blockPlaceHasHeldItem')) {
bot._client.write('block_place', {
location: block.position,
Expand Down Expand Up @@ -225,7 +226,9 @@ function inject (bot, { hideErrors }) {
cursorX: cursorPos.x,
cursorY: cursorPos.y,
cursorZ: cursorPos.z,
insideBlock: false
insideBlock: false,
sequence: 0, // 1.19.0+
worldBorderHit: false // 1.21.3+
})
}

Expand Down Expand Up @@ -712,15 +715,18 @@ function inject (bot, { hideErrors }) {
bot.currentWindow = null
bot.emit('windowClose', oldWindow)
})
bot._client.on('set_slot', (packet) => {
bot._setSlot = (slotId, newItem, window = bot.inventory) => {
// set slot
const oldItem = window.slots[slotId]
window.updateSlot(slotId, newItem)
updateHeldItem()
bot.emit(`setSlot:${window.id}`, oldItem, newItem)
}
bot._client.on('set_slot', (packet) => {
const window = packet.windowId === 0 ? bot.inventory : bot.currentWindow
if (!window || window.id !== packet.windowId) return
const newItem = Item.fromNotch(packet.item)
const oldItem = window.slots[packet.slot]
window.updateSlot(packet.slot, newItem)
updateHeldItem()
bot.emit(`setSlot:${window.id}`, oldItem, newItem)
bot._setSlot(packet.slot, newItem, window)
})
bot._client.on('window_items', (packet) => {
const window = packet.windowId === 0 ? bot.inventory : bot.currentWindow
Expand Down
Loading
Loading