From 0a4b3652423134a5ef4581b70c818b651dec0e8a Mon Sep 17 00:00:00 2001 From: roblabla Date: Fri, 11 Apr 2014 01:48:06 +0200 Subject: [PATCH 1/4] Add opportunistic parsing. --- lib/client.js | 56 +++++++++++++++++++++++++++++++++++++++++++------ lib/protocol.js | 23 +++++++++++++++----- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/lib/client.js b/lib/client.js index 58f5bbe..eb88eb9 100644 --- a/lib/client.js +++ b/lib/client.js @@ -30,9 +30,48 @@ function Client(isServer) { this.encryptionEnabled = false; this.cipher = null; this.decipher = null; + this.packetsToParse = {}; + this.on('newListener', function(event, listener) { + var direction = this.isServer ? 'toServer' : 'toClient'; + if (protocol.packetStates[direction].hasOwnProperty(event)) { + if (typeof this.packetsToParse[event] === "undefined") this.packetsToParse[event] = 1; + else this.packetsToParse[event] += 1; + } + }); + this.on('removeListener', function(event, listener) { + var direction = this.isServer ? 'toServer' : 'toClient'; + if (protocol.packetStates[direction].hasOwnProperty(event)) { + this.packetsToParse[event] -= 1; + } + }); } + util.inherits(Client, EventEmitter); +// Transform weird "packet" types into string representing their type. Should be mostly retro-compatible +Client.prototype.on = function(type, func) { + var direction = this.isServer ? 'toServer' : 'toClient'; + if (Array.isArray(type)) { + arguments[0] = protocol.packetNames[type[0]][direction][type[1]]; + } else if (typeof type === "number") { + arguments[0] = protocol.packetNames[this.state][direction][type]; + } + EventEmitter.prototype.on.apply(this, arguments); +}; + +Client.prototype.onRaw = function(type, func) { + var arg = "raw."; + if (Array.isArray(type)) { + arg += protocol.packetNames[type[0]][direction][type[1]]; + } else if (typeof type === "number") { + arg += protocol.packetNames[this.state][direction][type]; + } else { + arg += type; + } + arguments[0] = arg; + EventEmitter.prototype.on.apply(this, arguments); +}; + Client.prototype.setSocket = function(socket) { var self = this; self.socket = socket; @@ -42,7 +81,7 @@ Client.prototype.setSocket = function(socket) { incomingBuffer = Buffer.concat([incomingBuffer, data]); var parsed, packet; while (true) { - parsed = parsePacket(incomingBuffer, self.state, self.isServer); + parsed = parsePacket(incomingBuffer, self.state, self.isServer, self.packetsToParse); if (! parsed) break; if (parsed.error) { this.emit('error', parsed.error); @@ -53,11 +92,8 @@ Client.prototype.setSocket = function(socket) { incomingBuffer = incomingBuffer.slice(parsed.size); var packetName = protocol.packetNames[self.state][self.isServer ? 'toServer' : 'toClient'][packet.id]; - if (packetName !== undefined) self.emit(packetName, packet); - - self.emit([self.state, packet.id], packet); - self.emit(packet.id, packet); - self.emit('packet', packet); + self.emit(packetName, packet); + self.emit('raw.' + packetName, parsed.buffer); } }); @@ -120,3 +156,11 @@ Client.prototype.write = function(packetId, params) { this.socket.write(out); return true; }; + +Client.prototype.writeRaw = function(buffer, shouldEncrypt) { + if (shouldEncrypt === null) { + shouldEncrypt = true; + } + var out = (shouldEncrypt && this.encryptionEnabled) ? new Buffer(this.cipher.update(buffer), 'binary') : buffer; + this.socket.write(out); +}; \ No newline at end of file diff --git a/lib/protocol.js b/lib/protocol.js index 62ddc80..d20e85e 100644 --- a/lib/protocol.js +++ b/lib/protocol.js @@ -1270,7 +1270,7 @@ function createPacketBuffer(packetId, state, params, isServer) { return buffer; } -function parsePacket(buffer, state, isServer) { +function parsePacket(buffer, state, isServer, packetsToParse) { if (state == null) state == states.PLAY; var cursor = 0; var lengthField = readVarInt(buffer, 0); @@ -1279,19 +1279,30 @@ function parsePacket(buffer, state, isServer) { cursor += lengthField.size; if (length + lengthField.size > buffer.length) return null; var buffer = buffer.slice(0, length + cursor); // fail early if too much is read. - - var packetIdField = readVarInt(buffer, lengthField.size); + + var packetIdField = readVarInt(buffer, cursor); var packetId = packetIdField.value; cursor += packetIdField.size; - + var results = { id: packetId }; + // Only parse the packet if there is a need for it, AKA if there is a listener attached to it + var name = packetNames[state][isServer ? "toServer" : "toClient"][packetId]; + if (!packetsToParse.hasOwnProperty(name) || packetsToParse[name] <= 0) { + return { + size: length + lengthField.size, + buffer: buffer, + results: results + }; + } + var packetInfo = get(packetId, state, isServer); if (packetInfo === null) { return { error: new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")"), size: length + lengthField.size, + buffer: buffer, results: results - } + }; } else { debug("read packetId " + packetId + " (0x" + packetId.toString(16) + ")"); } @@ -1323,6 +1334,7 @@ function parsePacket(buffer, state, isServer) { return { size: length + lengthField.size, results: results, + buffer: buffer }; } @@ -1336,6 +1348,7 @@ module.exports = { packetIds: packetIds, packetNames: packetNames, packetFields: packetFields, + packetStates: packetStates, states: states, get: get, debug: debug, From b7dd1ba04e075f5466f81c02a306565f986ff36a Mon Sep 17 00:00:00 2001 From: roblabla Date: Fri, 11 Apr 2014 01:48:42 +0200 Subject: [PATCH 2/4] Remove old debug code --- lib/yggdrasil.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/yggdrasil.js b/lib/yggdrasil.js index d1d2f49..3b34a17 100644 --- a/lib/yggdrasil.js +++ b/lib/yggdrasil.js @@ -80,7 +80,6 @@ function joinServer(username, serverId, accessToken, selectedProfile, cb) { function validateSession(username, serverId, cb) { superagent.get("https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + username + "&serverId=" + serverId) .end(function(resp) { - console.log(resp.body); if (resp.ok) { if ("id" in resp.body) { cb(null, resp.body.id); From c1a5b8294bec3ed4164322a2cd8250b6037f041d Mon Sep 17 00:00:00 2001 From: roblabla Date: Fri, 11 Apr 2014 02:08:17 +0200 Subject: [PATCH 3/4] woops, add back the 'packet' event --- lib/client.js | 5 +++-- lib/protocol.js | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/client.js b/lib/client.js index eb88eb9..5dbe4b0 100644 --- a/lib/client.js +++ b/lib/client.js @@ -33,14 +33,14 @@ function Client(isServer) { this.packetsToParse = {}; this.on('newListener', function(event, listener) { var direction = this.isServer ? 'toServer' : 'toClient'; - if (protocol.packetStates[direction].hasOwnProperty(event)) { + if (protocol.packetStates[direction].hasOwnProperty(event) || event === "packet") { if (typeof this.packetsToParse[event] === "undefined") this.packetsToParse[event] = 1; else this.packetsToParse[event] += 1; } }); this.on('removeListener', function(event, listener) { var direction = this.isServer ? 'toServer' : 'toClient'; - if (protocol.packetStates[direction].hasOwnProperty(event)) { + if (protocol.packetStates[direction].hasOwnProperty(event) || event === "packet") { this.packetsToParse[event] -= 1; } }); @@ -93,6 +93,7 @@ Client.prototype.setSocket = function(socket) { var packetName = protocol.packetNames[self.state][self.isServer ? 'toServer' : 'toClient'][packet.id]; self.emit(packetName, packet); + self.emit('packet', packet); self.emit('raw.' + packetName, parsed.buffer); } }); diff --git a/lib/protocol.js b/lib/protocol.js index d20e85e..b2df675 100644 --- a/lib/protocol.js +++ b/lib/protocol.js @@ -1287,7 +1287,9 @@ function parsePacket(buffer, state, isServer, packetsToParse) { var results = { id: packetId }; // Only parse the packet if there is a need for it, AKA if there is a listener attached to it var name = packetNames[state][isServer ? "toServer" : "toClient"][packetId]; - if (!packetsToParse.hasOwnProperty(name) || packetsToParse[name] <= 0) { + var shouldParse = (!packetsToParse.hasOwnProperty(name) || packetsToParse[name] <= 0) + && (!packetsToParse.hasOwnProperty("packet") || packetsToParse["packet"] <= 0); + if (shouldParse) { return { size: length + lengthField.size, buffer: buffer, From 879dd3a5e462f5d278faac226d4eea5427816f2e Mon Sep 17 00:00:00 2001 From: roblabla Date: Fri, 11 Apr 2014 17:07:33 +0200 Subject: [PATCH 4/4] Quickfix : type in UUID field --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index dfe2b84..f48a9c9 100644 --- a/index.js +++ b/index.js @@ -177,14 +177,14 @@ function createServer(options) { client.end("Failed to verify username!"); return; } - client.UUID = uuid; + client.uuid = uuid; loginClient(); }); } } function loginClient() { - client.write(0x02, {uuid: (client.UUID | 0).toString(10), username: client.username}); + client.write(0x02, {uuid: (client.uuid | 0).toString(10), username: client.username}); client.state = states.PLAY; loggedIn = true; startKeepAlive();