diff --git a/src/ConnWorker.js b/src/ConnWorker.js index f6d38d3..81e7507 100644 --- a/src/ConnWorker.js +++ b/src/ConnWorker.js @@ -1,4 +1,4 @@ -const RakClient = require('@jsprismarine/raknet/client') +const RakClient = require('jsp-raknet/client') const { Worker, isMainThread, parentPort } = require('worker_threads') const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') diff --git a/src/client.js b/src/client.js index bd2da33..e83d8db 100644 --- a/src/client.js +++ b/src/client.js @@ -119,18 +119,55 @@ class Client extends Connection { process.exit(1) } + tryRencode(name, params, actual) { + if (name == 'level_chunk') { + console.log("Skipping chunk validation, it's broken right now") + return + } + const packet = this.serializer.createPacketBuffer({ name, params }) + + console.assert(packet.toString('hex') == actual.toString('hex')) + if (packet.toString('hex') !== actual.toString('hex')) { + + const ours = packet.toString('hex').match(/.{1,16}/g).join('\n') + const theirs = actual.toString('hex').match(/.{1,16}/g).join('\n') + + fs.writeFileSync('ours.txt', ours) + fs.writeFileSync('theirs.txt', theirs) + fs.writeFileSync('ours.json', serialize(params)) + fs.writeFileSync('theirs.json', serialize(this.deserializer.parsePacketBuffer(packet).data.params)) + + throw new Error(name + ' Packet comparison failed!') + } + } + readPacket(packet) { // console.log('packet', packet) const des = this.deserializer.parsePacketBuffer(packet) const pakData = { name: des.data.name, params: des.data.params } console.log('->', pakData.name, serialize(pakData.params).slice(0, 100)) + + // No idea what this exotic 0xA0 packet is, it's not implemented anywhere + // and seems empty. Possible gibberish from the raknet impl + if (pakData.name == '160' || !pakData.name) { // eslint-ignore-line + console.warn('?? Ignoring extraneous packet ', des) + return + } + + // 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 { if (!fs.existsSync(`./packets/${pakData.name}.json`)) { fs.writeFileSync(`./packets/${pakData.name}.json`, serialize(pakData.params, 2)) fs.writeFileSync(`./packets/${pakData.name}.txt`, packet.toString('hex')) } - } catch {} + } catch { } + switch (des.data.name) { case 'server_to_client_handshake': this.emit('client.server_handshake', des.data.params) @@ -143,6 +180,10 @@ class Client extends Connection { break case 'start_game': fs.writeFileSync('start_game.json', JSON.stringify(des.data.params, (k, v) => typeof v == 'bigint' ? v.toString() : v)) + break + case 'level_chunk': + fs.writeFileSync(`./chunks/chunk-${chunks++}.txt`, packet.toString('hex')) + break default: // console.log('Sending to listeners') } @@ -151,6 +192,8 @@ class Client extends Connection { } } +var chunks = 0; + function serialize(obj = {}, fmt) { return JSON.stringify(obj, (k, v) => typeof v == 'bigint' ? v.toString() : v, fmt) } diff --git a/src/clientTest.js b/src/clientTest.js index 39bb310..43af281 100644 --- a/src/clientTest.js +++ b/src/clientTest.js @@ -1,20 +1,42 @@ // process.env.DEBUG = 'minecraft-protocol raknet' const { Client } = require('./client') - +const fs = require('fs') // console.log = () => async function test() { - const client = new Client({ - hostname: '127.0.0.1', - port: 19132 + const client = new Client({ + hostname: '127.0.0.1', + port: 19132 + }) + + client.once('resource_packs_info', (packet) => { + client.write('resource_pack_client_response', { + response_status: 'completed', + resourcepackids: [] }) - - 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.once('resource_packs_info', (packet) => { + // client.write('resource_pack_client_response', { + // response_status: 'completed', + // resourcepackids: [] + // }) + // }) + }) + + + + // var read = 0; + // client.on('level_chunk', (packet) => { + // read++ + // fs.writeFileSync(`level_chunk-${read}.json`, JSON.stringify(packet, null, 2)) + // }) } test() \ No newline at end of file diff --git a/src/connection.js b/src/connection.js index 1ecbee2..3fa2475 100644 --- a/src/connection.js +++ b/src/connection.js @@ -2,8 +2,8 @@ const BinaryStream = require('@jsprismarine/jsbinaryutils').default const BatchPacket = require('./datatypes/BatchPacket') const cipher = require('./transforms/encryption') const { EventEmitter } = require('events') -const EncapsulatedPacket = require('@jsprismarine/raknet/protocol/encapsulated_packet') - +const EncapsulatedPacket = require('jsp-raknet/protocol/encapsulated_packet') +const debug = require('debug')('minecraft-protocol') class Connection extends EventEmitter { startEncryption(iv) { @@ -15,8 +15,10 @@ class Connection extends EventEmitter { write(name, params) { // TODO: Batch console.log('Need to encode', name, params) + // console.log('<-', name) const batch = new BatchPacket() const packet = this.serializer.createPacketBuffer({ name, params }) + console.log('Sending buf', packet.toString('hex')) batch.addEncodedPacket(packet) if (this.encryptionEnabled) { @@ -45,6 +47,19 @@ class Connection extends EventEmitter { } } + /** + * Sends a MCPE packet buffer + */ + sendBuffer(buffer) { + const batch = new BatchPacket() + batch.addEncodedPacket(buffer) + if (this.encryptionEnabled) { + this.sendEncryptedBatch(batch) + } else { + this.sendDecryptedBatch(batch) + } + } + sendDecryptedBatch(batch) { const buf = batch.encode() // send to raknet @@ -53,10 +68,11 @@ class Connection extends EventEmitter { sendEncryptedBatch(batch) { const buf = batch.stream.getBuffer() - console.log('Sending encrypted batch', batch) + debug('Sending encrypted batch', batch) this.encrypt(buf) } + // TODO: Rename this to sendEncapsulated sendMCPE(buffer, immediate) { if (this.worker) { console.log('-> buf', buffer)