From eba07e6b90633b91d191be1db5ca2523d83c41e1 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 20 Feb 2016 16:22:18 +0100 Subject: [PATCH 1/2] add an optional property to add custom packets to createClient and createServer --- doc/README.md | 6 ++- .../client_custom_packets.js | 54 +++++++++++++++++++ examples/client_custom_packets/package.json | 8 +++ src/client.js | 7 +-- src/createClient.js | 2 +- src/createServer.js | 2 +- src/server.js | 5 +- src/transforms/serializer.js | 6 ++- 8 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 examples/client_custom_packets/client_custom_packets.js create mode 100644 examples/client_custom_packets/package.json diff --git a/doc/README.md b/doc/README.md index f87a864..d7deebf 100644 --- a/doc/README.md +++ b/doc/README.md @@ -18,8 +18,9 @@ automatically logged in and validated against mojang's auth. * maxPlayers : default to 20 * keepAlive : send keep alive packets : default to true * version : 1.8 or 1.9 : default to 1.8 + * customPackets (optional) : an object index by state/direction/name, see client_custom_packet for an example -## mc.Server(version) +## mc.Server(version,[customPackets]) Create a server instance for `version` of minecraft. @@ -74,8 +75,9 @@ Returns a `Client` instance and perform login. * keepAlive : send keep alive packets : default to true * checkTimeoutInterval : default to `10*1000` (10s), check if keepalive received at that period, disconnect otherwise. * version : 1.8 or 1.9 or false (to auto-negotiate): default to 1.8 + * customPackets (optional) : an object index by state/direction/name, see client_custom_packet for an example -## mc.Client(isServer,version) +## mc.Client(isServer,version,[customPackets]) Create a new client, if `isServer` is true then it is a server-side client, otherwise it's a client-side client. Takes a minecraft `version` as second argument. diff --git a/examples/client_custom_packets/client_custom_packets.js b/examples/client_custom_packets/client_custom_packets.js new file mode 100644 index 0000000..a7fa7c1 --- /dev/null +++ b/examples/client_custom_packets/client_custom_packets.js @@ -0,0 +1,54 @@ +var mc = require('minecraft-protocol'); + +if(process.argv.length < 4 || process.argv.length > 6) { + console.log("Usage : node echo.js [] []"); + process.exit(1); +} + +var customPackets={ + "play":{ + "toClient":{ + "my_custom_packet": { + "id": "0x7A", + "fields": [ + { + "name": "age", + "type": "i64" + }, + { + "name": "time", + "type": "i64" + } + ] + } + } + } +}; + +var client = mc.createClient({ + host: process.argv[2], + port: parseInt(process.argv[3]), + username: process.argv[4] ? process.argv[4] : "echo", + password: process.argv[5], + customPackets:customPackets +}); + +client.on('connect', function() { + console.info('connected'); +}); +client.on('disconnect', function(packet) { + console.log('disconnected: '+ packet.reason); +}); +client.on('end', function(err) { + console.log('Connection lost'); +}); + +client.on('login',function(){ + client.deserializer.write(new Buffer("7A0000000000909327fffffffffffffc18","hex")); + console.log('login'); + +}); + +client.on('my_custom_packet',function(packet){ + console.log(packet); +}); diff --git a/examples/client_custom_packets/package.json b/examples/client_custom_packets/package.json new file mode 100644 index 0000000..56fcdf2 --- /dev/null +++ b/examples/client_custom_packets/package.json @@ -0,0 +1,8 @@ +{ + "name": "node-minecraft-protocol-example", + "version": "0.0.0", + "private": true, + "dependencies": { + }, + "description": "A node-minecraft-protocol example" +} diff --git a/src/client.js b/src/client.js index 51b22d2..eb6e614 100644 --- a/src/client.js +++ b/src/client.js @@ -10,8 +10,9 @@ const createDeserializer=require("./transforms/serializer").createDeserializer; class Client extends EventEmitter { - constructor(isServer,version) { + constructor(isServer,version,customPackets) { super(); + this.customPackets=customPackets; this.version=version; this.isServer = !!isServer; this.splitter=framing.createSplitter(); @@ -46,9 +47,9 @@ class Client extends EventEmitter setSerializer(state) { - this.serializer = createSerializer({ isServer:this.isServer, version:this.version, state: state}); + this.serializer = createSerializer({ isServer:this.isServer, version:this.version, state: state,customPackets:this.customPackets}); this.deserializer = createDeserializer({ isServer:this.isServer, version:this.version, state: state, packetsToParse: - this.packetsToParse}); + this.packetsToParse,customPackets:this.customPackets}); this.splitter.recognizeLegacyPing = state === states.HANDSHAKING; diff --git a/src/createClient.js b/src/createClient.js index 11d3a31..ee5ab96 100644 --- a/src/createClient.js +++ b/src/createClient.js @@ -25,7 +25,7 @@ function createClient(options) { options.majorVersion = version.majorVersion; options.protocolVersion = version.version; - const client = new Client(false, version.minecraftVersion); + const client = new Client(false, version.minecraftVersion,options.customPackets); tcp_dns(client, options); caseCorrect(client, options); diff --git a/src/createServer.js b/src/createServer.js index af705e8..fe25f60 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -32,7 +32,7 @@ function createServer(options) { const serverKey = ursa.generatePrivateKey(1024); - const server = new Server(version.minecraftVersion); + const server = new Server(version.minecraftVersion,options.customPackets); server.motd = options.motd || "A Minecraft server"; server.maxPlayers = options['max-players'] || 20; server.playerCount = 0; diff --git a/src/server.js b/src/server.js index daab15e..fb96fa2 100644 --- a/src/server.js +++ b/src/server.js @@ -5,13 +5,14 @@ const states = require("./states"); class Server extends EventEmitter { - constructor(version) { + constructor(version,customPackets) { super(); this.version=version; this.socketServer=null; this.cipher=null; this.decipher=null; this.clients={}; + this.customPackets=customPackets; } listen(port, host) { @@ -19,7 +20,7 @@ class Server extends EventEmitter let nextId = 0; self.socketServer = net.createServer(); self.socketServer.on('connection', socket => { - const client = new Client(true,this.version); + const client = new Client(true,this.version,this.customPackets); client._end = client.end; client.end = function end(endReason) { endReason='{"text":"'+endReason+'"}'; diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 23cc982..9eb1f1c 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -36,21 +36,23 @@ function createProtocol(types,packets) return proto; } -function createSerializer({ state = states.HANDSHAKING, isServer = false , version} = {}) +function createSerializer({ state = states.HANDSHAKING, isServer = false , version,customPackets} = {}) { const mcData=require("minecraft-data")(version); const direction = !isServer ? 'toServer' : 'toClient'; const packets = mcData.protocol.states[state][direction]; + if(customPackets && customPackets[state] && customPackets[state][direction]) Object.keys(customPackets[state][direction]).forEach(name => packets[name]=customPackets[state][direction][name]); const proto=createProtocol(mcData.protocol.types,packets); return new Serializer(proto,"packet"); } function createDeserializer({ state = states.HANDSHAKING, isServer = false, - packetsToParse = {"packet": true}, version } = {}) + packetsToParse = {"packet": true}, version,customPackets } = {}) { const mcData=require("minecraft-data")(version); const direction = isServer ? "toServer" : "toClient"; const packets = mcData.protocol.states[state][direction]; + if(customPackets && customPackets[state] && customPackets[state][direction]) Object.keys(customPackets[state][direction]).forEach(name => packets[name]=customPackets[state][direction][name]); const proto=createProtocol(mcData.protocol.types,packets); return new Parser(proto,"packet"); } From 91ccac44df9a093ad1ac6dc564fa2bd754a373d7 Mon Sep 17 00:00:00 2001 From: Romain Beaumont Date: Sat, 20 Feb 2016 16:43:08 +0100 Subject: [PATCH 2/2] index custom packets by version --- doc/README.md | 4 +-- .../client_custom_packets.js | 30 ++++++++++--------- src/transforms/serializer.js | 6 ++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/doc/README.md b/doc/README.md index d7deebf..912a172 100644 --- a/doc/README.md +++ b/doc/README.md @@ -18,7 +18,7 @@ automatically logged in and validated against mojang's auth. * maxPlayers : default to 20 * keepAlive : send keep alive packets : default to true * version : 1.8 or 1.9 : default to 1.8 - * customPackets (optional) : an object index by state/direction/name, see client_custom_packet for an example + * customPackets (optional) : an object index by version/state/direction/name, see client_custom_packet for an example ## mc.Server(version,[customPackets]) @@ -75,7 +75,7 @@ Returns a `Client` instance and perform login. * keepAlive : send keep alive packets : default to true * checkTimeoutInterval : default to `10*1000` (10s), check if keepalive received at that period, disconnect otherwise. * version : 1.8 or 1.9 or false (to auto-negotiate): default to 1.8 - * customPackets (optional) : an object index by state/direction/name, see client_custom_packet for an example + * customPackets (optional) : an object index by version/state/direction/name, see client_custom_packet for an example ## mc.Client(isServer,version,[customPackets]) diff --git a/examples/client_custom_packets/client_custom_packets.js b/examples/client_custom_packets/client_custom_packets.js index a7fa7c1..991d660 100644 --- a/examples/client_custom_packets/client_custom_packets.js +++ b/examples/client_custom_packets/client_custom_packets.js @@ -6,20 +6,22 @@ if(process.argv.length < 4 || process.argv.length > 6) { } var customPackets={ - "play":{ - "toClient":{ - "my_custom_packet": { - "id": "0x7A", - "fields": [ - { - "name": "age", - "type": "i64" - }, - { - "name": "time", - "type": "i64" - } - ] + "1.8": { + "play": { + "toClient": { + "my_custom_packet": { + "id": "0x7A", + "fields": [ + { + "name": "age", + "type": "i64" + }, + { + "name": "time", + "type": "i64" + } + ] + } } } } diff --git a/src/transforms/serializer.js b/src/transforms/serializer.js index 9eb1f1c..98fdb30 100644 --- a/src/transforms/serializer.js +++ b/src/transforms/serializer.js @@ -41,7 +41,8 @@ function createSerializer({ state = states.HANDSHAKING, isServer = false , versi const mcData=require("minecraft-data")(version); const direction = !isServer ? 'toServer' : 'toClient'; const packets = mcData.protocol.states[state][direction]; - if(customPackets && customPackets[state] && customPackets[state][direction]) Object.keys(customPackets[state][direction]).forEach(name => packets[name]=customPackets[state][direction][name]); + const v=mcData.version.majorVersion; + if(customPackets && customPackets[v] && customPackets[v][state] && customPackets[v][state][direction]) Object.keys(customPackets[v][state][direction]).forEach(name => packets[name]=customPackets[v][state][direction][name]); const proto=createProtocol(mcData.protocol.types,packets); return new Serializer(proto,"packet"); } @@ -52,7 +53,8 @@ function createDeserializer({ state = states.HANDSHAKING, isServer = false, const mcData=require("minecraft-data")(version); const direction = isServer ? "toServer" : "toClient"; const packets = mcData.protocol.states[state][direction]; - if(customPackets && customPackets[state] && customPackets[state][direction]) Object.keys(customPackets[state][direction]).forEach(name => packets[name]=customPackets[state][direction][name]); + const v=mcData.version.majorVersion; + if(customPackets && customPackets[v][state] && customPackets[v][state][direction]) Object.keys(customPackets[v][state][direction]).forEach(name => packets[name]=customPackets[v][state][direction][name]); const proto=createProtocol(mcData.protocol.types,packets); return new Parser(proto,"packet"); }