Add packet dumper, configuable vanilla server, client events

This commit is contained in:
extremeheat 2021-03-23 03:35:38 -04:00
commit cf6471f6eb
3 changed files with 105 additions and 26 deletions

View file

@ -108,10 +108,8 @@ class Client extends Connection {
}
onDisconnectRequest (packet) {
// We're talking over UDP, so there is no connection to close, instead
// we stop communicating with the server
console.warn(`Server requested ${packet.hide_disconnect_reason ? 'silent disconnect' : 'disconnect'}: ${packet.message}`)
process.exit(1) // TODO: handle
this.emit('kick', packet)
}
onPlayStatus (statusPacket) {
@ -125,6 +123,7 @@ class Client extends Connection {
}
close () {
this.emit('close')
clearInterval(this.loop)
clearTimeout(this.connectTimeout)
this.q = []
@ -155,22 +154,13 @@ class Client extends Connection {
const des = this.deserializer.parsePacketBuffer(packet)
const pakData = { name: des.data.name, params: des.data.params }
this.inLog('-> C', pakData.name/*, serialize(pakData.params).slice(0, 100) */)
this.emit('packet', pakData)
if (debugging) {
// Packet verifying (decode + re-encode + match test)
if (pakData.name) {
this.tryRencode(pakData.name, pakData.params, packet)
}
// console.info('->', JSON.stringify(pakData, (k,v) => typeof v == 'bigint' ? v.toString() : v))
// Packet dumping
try {
const root = __dirname + `../data/${this.options.version}/sample/`
if (!fs.existsSync(root + `packets/${pakData.name}.json`)) {
fs.writeFileSync(root + `packets/${pakData.name}.json`, serialize(pakData.params, 2))
fs.writeFileSync(root + `packets/${pakData.name}.txt`, packet.toString('hex'))
}
} catch { }
}
// Abstract some boilerplate before sending to listeners
@ -187,8 +177,6 @@ class Client extends Connection {
case 'play_status':
this.onPlayStatus(pakData.params)
break
default:
// console.log('Sending to listeners')
}
// Emit packet

83
tools/genPacketDumps.js Normal file
View file

@ -0,0 +1,83 @@
/* eslint-disable */
// Collect sample packets needed for `serverTest.js`
// process.env.DEBUG = 'minecraft-protocol'
const fs = require('fs')
const vanillaServer = require('../tools/startVanillaServer')
const { Client } = require('../src/client')
const { serialize, waitFor } = require('../src/datatypes/util')
const { CURRENT_VERSION } = require('../src/options')
const { join } = require('path')
let loop
async function main() {
const random = ((Math.random() * 100) | 0)
const port = 19130 + random
const handle = await vanillaServer.startServerAndWait(CURRENT_VERSION, 1000 * 120, { 'server-port': port, path: 'bds_' })
console.log('Started server')
const client = new Client({
hostname: '127.0.0.1',
port,
username: 'Boat' + random,
offline: true
})
return waitFor(async res => {
const root = join(__dirname, `../data/${client.options.version}/sample/packets/`)
if (!fs.existsSync(root)) {
fs.mkdirSync(root, { recursive: true })
}
client.once('resource_packs_info', (packet) => {
client.write('resource_pack_client_response', {
response_status: 'completed',
resourcepackids: []
})
client.once('resource_pack_stack', (stack) => {
client.write('resource_pack_client_response', {
response_status: 'completed',
resourcepackids: []
})
})
client.queue('client_cache_status', { enabled: false })
client.queue('request_chunk_radius', { chunk_radius: 1 })
// client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: 0n })
clearInterval(loop)
loop = setInterval(() => {
client.queue('tick_sync', { request_time: BigInt(Date.now()), response_time: BigInt(Date.now()) })
}, 200)
})
client.on('packet', pakData => { // Packet dumping
if (pakData.name == 'level_chunk') return
try {
if (!fs.existsSync(root + `${pakData.name}.json`)) {
fs.promises.writeFile(root + `${pakData.name}.json`, serialize(pakData.params, 2))
}
} catch (e) { console.log(e) }
})
console.log('Awaiting join...')
client.on('spawn', () => {
console.log('Spawned!')
clearInterval(loop)
client.close()
handle.kill()
res()
})
}, 1000 * 60, () => {
clearInterval(loop)
throw Error('timed out')
})
}
main().then(() => {
console.log('Successfully dumped packets')
})

View file

@ -17,18 +17,18 @@ function fetchLatestStable () {
}
// Download + extract vanilla server and enter the directory
async function download (os, version) {
async function download (os, version, path = 'bds-') {
process.chdir(__dirname)
const verStr = version.split('.').slice(0, 3).join('.')
const dir = 'bds-' + version
const dir = path + version
if (fs.existsSync(dir) && getFiles(dir).length) {
process.chdir('bds-' + version) // Enter server folder
process.chdir(path + version) // Enter server folder
return verStr
}
try { fs.mkdirSync(dir) } catch { }
process.chdir('bds-' + version) // Enter server folder
process.chdir(path + version) // Enter server folder
const url = (os, version) => `https://minecraft.azureedge.net/bin-${os}/bedrock-server-${version}.zip`
let found = false
@ -53,10 +53,18 @@ async function download (os, version) {
return verStr
}
const defaultOptions = {
'level-generator': '2',
'server-port': '19130',
'online-mode': 'false'
}
// Setup the server
function configure () {
function configure (options = {}) {
const opts = { ...defaultOptions, ...options }
let config = fs.readFileSync('./server.properties', 'utf-8')
config += '\nlevel-generator=2\nserver-port=19130\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator\nonline-mode=false'
config += '\nplayer-idle-timeout=1\nallow-cheats=true\ndefault-player-permission-level=operator'
for (const o in opts) config += `\n${o}=${opts[o]}`
fs.writeFileSync('./server.properties', config)
}
@ -66,13 +74,13 @@ function run (inheritStdout = true) {
}
// Run the server
async function startServer (version, onStart) {
async function startServer (version, onStart, options = {}) {
const os = process.platform === 'win32' ? 'win' : process.platform
if (os !== 'win' && os !== 'linux') {
throw Error('unsupported os ' + os)
}
await download(os, version)
configure()
await download(os, version, options.path)
configure(options)
const handle = run(!onStart)
if (onStart) {
handle.stdout.on('data', data => data.includes('Server started.') ? onStart() : null)
@ -83,10 +91,10 @@ async function startServer (version, onStart) {
}
// Start the server and wait for it to be ready, with a timeout
async function startServerAndWait (version, withTimeout) {
async function startServerAndWait (version, withTimeout, options) {
let handle
await waitFor(async res => {
handle = await startServer(version, res)
handle = await startServer(version, res, options)
}, withTimeout, () => {
handle?.kill()
throw new Error('Server did not start on time ' + withTimeout)