work-in-progress proxy & catch protodef errors

This commit is contained in:
Chipmunk 2024-07-06 15:14:56 -04:00
parent 74dc561d3d
commit 388d30ce51
4 changed files with 140 additions and 24 deletions

View file

@ -1,23 +0,0 @@
const { literal } = require('brigadier-commands')
const { generateString } = require('/var/tmp/nbt-overflow.js')
const fs = require('fs')
module.exports = {
register (dispatcher) {
const node = dispatcher.register(
literal('test')
.executes(this.testCommand)
)
node.description = 'Tests something'
node.permissionLevel = 1
},
testCommand (context) {
const source = context.source
const bot = source.bot
const payload = fs.readFileSync('/var/tmp/test_payload.bin')
bot.core.run(`data modify storage test '${generateString(payload).replace(/\'/g, m => '\\' + m)}' set value a`)
}
}

View file

@ -54,6 +54,15 @@ async function main () {
bot.on('error', error => bot.console.error(error))
}
process.on('uncaughtException', error => {
if (error.stack.includes('protodef')) {
console.error('Uncaught protodef exception!\n' + error.stack)
return // Ignore protodef-related errors (packet-related)
}
throw error
})
}
main()

View file

@ -11,7 +11,14 @@ function inject (bot) {
block: { x: null, y: null, z: null },
refill () {
const refillCommand = `/fill ${this.start.x} ${this.start.y} ${this.start.z} ${this.end.x} ${this.end.y} ${this.end.z} repeating_command_block{CustomName:'""'}`
const refillCommand = `fill ${this.start.x} ${this.start.y} ${this.start.z} ${this.end.x} ${this.end.y} ${this.end.z} repeating_command_block{CustomName:'""'}`
if (bot.proxy?.client) {
// Use chat commands when a player is logged into the proxy
bot.chat.command(refillCommand)
return
}
const location = { x: Math.floor(bot.position.x), y: Math.floor(bot.position.y) - 1, z: Math.floor(bot.position.z) }
const commandBlockId = bot.registry?.itemsByName.command_block.id

123
plugins/proxy.js Normal file
View file

@ -0,0 +1,123 @@
const mc = require('minecraft-protocol')
const LOGIN_PACKET_NAMES = [
'login',
'difficulty',
'abilities',
'held_item_slot',
'declare_recipes',
'entity_status',
'declare_commands',
'unlock_recipes',
'position',
// 'server_data',
// 'player_info',
'initialize_world_border',
'update_time',
'spawn_position',
'game_state_change',
'set_ticking_state',
'step_tick',
'update_view_position'
]
function createLoginPacketMap () {
return new Map(LOGIN_PACKET_NAMES.map(name => [name, null]))
}
function inject (bot, options) {
if (!options.proxy?.enabled) return
options.proxy.version ??= bot._client.version
options.proxy.enforceSecureProfile ??= false
bot.proxy = {
server: mc.createServer(options.proxy),
options: options.proxy,
client: null,
loginPackets: createLoginPacketMap(),
_players: {}
}
bot.on('end', () => {
bot.proxy.loginPackets = createLoginPacketMap()
bot.proxy._players = {}
})
bot.on('packet.registry_data', packet => {
bot.proxy.options.registryCodec = packet.codec // * nmp gets the registry codec from options
})
bot.on('packet', (data, meta) => {
if (bot.proxy.client && bot.proxy.client.state === mc.states.PLAY && meta.state === mc.states.PLAY) {
// Forward packets
bot.proxy.client.write(meta.name, data)
}
// Store login-related packets
if (!bot.proxy.loginPackets.has(meta.name)) return
if (meta.name === 'entity_status' && (data.entityStatus < 24 || data.entityStatus > 28)) return // Only forward permission level entity statuses on login
if (meta.name === 'game_state_change' && data.reason !== 13) return // Only forward "Start waiting for level chunks"
bot.proxy.loginPackets.set(meta.name, data)
})
bot.proxy.server.on('playerJoin', client => {
if (bot.proxy.client) bot.proxy.client.end('Logged in from another client!')
bot.proxy.client = client
client.on('packet', (data, meta) => {
if (bot._client.state !== mc.states.PLAY || meta.state !== mc.states.PLAY) return
bot._client.write(meta.name, data)
})
client.on('position', packet => {
bot.position.x = packet.x
bot.position.y = packet.y
bot.position.z = packet.z
})
client.on('look', packet => {
bot.position.yaw = packet.yaw
bot.position.pitch = packet.pitch
})
client.on('position_look', packet => {
bot.position.x = packet.x
bot.position.y = packet.y
bot.position.z = packet.z
bot.position.yaw = packet.yaw
bot.position.pitch = packet.pitch
})
client.on('vehicle_move', packet => {
bot.position.x = packet.x
bot.position.y = packet.y
bot.position.z = packet.z
bot.position.yaw = packet.yaw
bot.position.pitch = packet.pitch
})
for (const [name, data] of bot.proxy.loginPackets) {
if (!data) continue
client.write(name, data)
}
// send player info
for (const player of Object.values(bot.proxy._players)) {console.log('writing data for player %s (%s)', player.player?.username, player.uuid)
client.write('player_info', { action: player.flags, data: [{ ...player, flags: undefined }] })
}
})
bot.on('packet.player_info', packet => {
for (const player of packet.data) {
const old = bot.proxy._players[player.uuid] ?? { flags: 0 }
const filteredPlayer = Object.fromEntries(Object.entries(player).filter(([k, v]) => v != null))
bot.proxy._players[player.uuid] = { ...old, ...filteredPlayer, flags: old.flags | packet.action }
}
})
}
module.exports = inject