123 lines
3.5 KiB
JavaScript
123 lines
3.5 KiB
JavaScript
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
|