mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-27 13:14:41 -04:00
move createPacketBuffer and parsePacketData functions to serializer, also move protocol's exports to serializer
This commit is contained in:
parent
2b1a0f86cd
commit
1a9e08cbd8
@ -1,4 +1 @@
|
||||
module.exports = {
|
||||
Client: require('./dist/client'),
|
||||
protocol: require('./dist/protocol')
|
||||
};
|
||||
module.exports = require('./dist/browser.js');
|
||||
|
@ -1,7 +1,7 @@
|
||||
var readline = require('readline');
|
||||
var color = require("ansi-color").set;
|
||||
var mc = require('../../');
|
||||
var states = mc.protocol.states;
|
||||
var states = mc.states;
|
||||
var util = require('util');
|
||||
|
||||
var colors = new Array();
|
||||
|
@ -1,5 +1,5 @@
|
||||
var mc = require('../../')
|
||||
, states = mc.protocol.states
|
||||
, states = mc.states
|
||||
|
||||
var client = mc.createClient({
|
||||
username: process.env.MC_USERNAME,
|
||||
|
@ -1,6 +1,6 @@
|
||||
var mc = require('../../');
|
||||
|
||||
var states = mc.protocol.states;
|
||||
var states = mc.states;
|
||||
function printHelpAndExit(exitCode) {
|
||||
console.log("usage: node proxy.js [<options>...] <target_srv> <user> [<password>]");
|
||||
console.log("options:");
|
||||
@ -133,9 +133,9 @@ srv.on('login', function(client) {
|
||||
targetClient.on('raw', function(buffer, state) {
|
||||
if(client.state != states.PLAY || state != states.PLAY)
|
||||
return;
|
||||
var packetId = mc.protocol.types.varint[0](buffer, 0);
|
||||
var packetData = mc.protocol.parsePacketData(buffer, state, false, {"packet": 1}).results;
|
||||
var packetBuff = mc.protocol.createPacketBuffer(packetData.id, packetData.state, packetData, true);
|
||||
var packetId = mc.types.varint[0](buffer, 0);
|
||||
var packetData = mc.parsePacketData(buffer, state, false, {"packet": 1}).results;
|
||||
var packetBuff = mc.createPacketBuffer(packetData.id, packetData.state, packetData, true);
|
||||
if(buffertools.compare(buffer, packetBuff) != 0) {
|
||||
console.log("client<-server: Error in packetId " + state + ".0x" + packetId.value.toString(16));
|
||||
console.log(buffer.toString('hex'));
|
||||
@ -152,9 +152,9 @@ srv.on('login', function(client) {
|
||||
client.on('raw', function(buffer, state) {
|
||||
if(state != states.PLAY || targetClient.state != states.PLAY)
|
||||
return;
|
||||
var packetId = mc.protocol.types.varint[0](buffer, 0);
|
||||
var packetData = mc.protocol.parsePacketData(buffer, state, true, {"packet": 1}).results;
|
||||
var packetBuff = mc.protocol.createPacketBuffer(packetData.id, packetData.state, packetData, false);
|
||||
var packetId = mc.types.varint[0](buffer, 0);
|
||||
var packetData = mc.parsePacketData(buffer, state, true, {"packet": 1}).results;
|
||||
var packetBuff = mc.createPacketBuffer(packetData.id, packetData.state, packetData, false);
|
||||
if(buffertools.compare(buffer, packetBuff) != 0) {
|
||||
console.log("client->server: Error in packetId " + state + ".0x" + packetId.value.toString(16));
|
||||
console.log(buffer.toString('hex'));
|
||||
|
@ -1,5 +1,5 @@
|
||||
var mc = require('../../');
|
||||
var states = mc.protocol.states;
|
||||
var states = mc.states;
|
||||
|
||||
var options = {
|
||||
motd: 'Vox Industries',
|
||||
|
19
src/browser.js
Normal file
19
src/browser.js
Normal file
@ -0,0 +1,19 @@
|
||||
var packets = require("../protocol/protocol");
|
||||
var readPackets = require("./packets").readPackets;
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
var utils = require("./utils");
|
||||
var serializer = require("./transforms/serializer");
|
||||
|
||||
module.exports = {
|
||||
Client: require('./client'),
|
||||
protocol: require('./protocol'),
|
||||
createPacketBuffer: serializer.createPacketBuffer,
|
||||
parsePacketData: serializer.parsePacketData,
|
||||
packetFields: packetIndexes.packetFields,
|
||||
packetNames: packetIndexes.packetNames,
|
||||
packetIds: packetIndexes.packetIds,
|
||||
packetStates: packetIndexes.packetStates,
|
||||
types: serializer.types,
|
||||
get: serializer.get,
|
||||
evalCondition: utils.evalCondition,
|
||||
};
|
@ -1,22 +1,17 @@
|
||||
var EventEmitter = require('events').EventEmitter
|
||||
, util = require('util')
|
||||
, protocol = require('./protocol')
|
||||
, createPacketBuffer = protocol.createPacketBuffer
|
||||
, compressPacketBuffer = protocol.compressPacketBuffer
|
||||
, oldStylePacket = protocol.oldStylePacket
|
||||
, newStylePacket = protocol.newStylePacket
|
||||
, parsePacketData = protocol.parsePacketData
|
||||
, parseNewStylePacket = protocol.parseNewStylePacket
|
||||
, packetIds = protocol.packetIds
|
||||
, packetNames = protocol.packetNames
|
||||
, states = protocol.states
|
||||
, debug = require('./debug')
|
||||
, serializer = require('./transforms/serializer')
|
||||
, compression = require('./transforms/compression')
|
||||
, framing = require('./transforms/framing')
|
||||
, crypto = require('crypto')
|
||||
, states = serializer.states
|
||||
;
|
||||
|
||||
var packets = require("../protocol/protocol");
|
||||
var readPackets = require("./packets").readPackets;
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
|
||||
module.exports = Client;
|
||||
|
||||
function Client(isServer) {
|
||||
@ -56,14 +51,14 @@ function Client(isServer) {
|
||||
|
||||
this.on('newListener', function(event, listener) {
|
||||
var direction = this.isServer ? 'toServer' : 'toClient';
|
||||
if(protocol.packetStates[direction].hasOwnProperty(event) || event === "packet") {
|
||||
if(packetIndexes.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) || event === "packet") {
|
||||
if(packetIndexes.packetStates[direction].hasOwnProperty(event) || event === "packet") {
|
||||
this.packetsToParse[event] -= 1;
|
||||
}
|
||||
});
|
||||
@ -75,9 +70,9 @@ util.inherits(Client, EventEmitter);
|
||||
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]];
|
||||
arguments[0] = packetIndexes.packetNames[type[0]][direction][type[1]];
|
||||
} else if(typeof type === "number") {
|
||||
arguments[0] = protocol.packetNames[this.state][direction][type];
|
||||
arguments[0] = packetIndexes.packetNames[this.state][direction][type];
|
||||
}
|
||||
EventEmitter.prototype.on.apply(this, arguments);
|
||||
};
|
||||
@ -85,9 +80,9 @@ Client.prototype.on = function(type, func) {
|
||||
Client.prototype.onRaw = function(type, func) {
|
||||
var arg = "raw.";
|
||||
if(Array.isArray(type)) {
|
||||
arg += protocol.packetNames[type[0]][direction][type[1]];
|
||||
arg += packetIndexes.packetNames[type[0]][direction][type[1]];
|
||||
} else if(typeof type === "number") {
|
||||
arg += protocol.packetNames[this.state][direction][type];
|
||||
arg += packetIndexes.packetNames[this.state][direction][type];
|
||||
} else {
|
||||
arg += type;
|
||||
}
|
||||
@ -136,7 +131,7 @@ Client.prototype.setSocket = function(socket) {
|
||||
|
||||
this.deserializer.on('data', (parsed) => {
|
||||
var packet = parsed.results;
|
||||
var packetName = protocol.packetNames[packet.state][this.isServer ? 'toServer' : 'toClient'][packet.id];
|
||||
var packetName = packetIndexes.packetNames[packet.state][this.isServer ? 'toServer' : 'toClient'][packet.id];
|
||||
this.emit('packet', packet);
|
||||
this.emit(packetName, packet);
|
||||
this.emit('raw.' + packetName, parsed.buffer, packet.state);
|
||||
@ -185,8 +180,8 @@ Client.prototype.write = function(packetId, params) {
|
||||
packetId = packetId[1];
|
||||
}
|
||||
if(typeof packetId === "string")
|
||||
packetId = protocol.packetIds[this.state][this.isServer ? "toClient" : "toServer"][packetId];
|
||||
var packetName = protocol.packetNames[this.state][this.isServer ? "toClient" : "toServer"][packetId];
|
||||
packetId = packetIndexes.packetIds[this.state][this.isServer ? "toClient" : "toServer"][packetId];
|
||||
var packetName = packetIndexes.packetNames[this.state][this.isServer ? "toClient" : "toServer"][packetId];
|
||||
debug("writing packetId " + this.state + "." + packetName + " (0x" + packetId.toString(16) + ")");
|
||||
debug(params);
|
||||
this.serializer.write({ packetId, params });
|
||||
|
31
src/index.js
31
src/index.js
@ -1,7 +1,6 @@
|
||||
var assert = require('assert')
|
||||
, crypto = require('crypto')
|
||||
, bufferEqual = require('buffer-equal')
|
||||
, protocol = require('./protocol')
|
||||
, Client = require('./client')
|
||||
, dns = require('dns')
|
||||
, net = require('net')
|
||||
@ -10,8 +9,10 @@ var assert = require('assert')
|
||||
, getSession = Yggdrasil.getSession
|
||||
, validateSession = Yggdrasil.validateSession
|
||||
, joinServer = Yggdrasil.joinServer
|
||||
, states = protocol.states
|
||||
, serializer = require("./transforms/serializer")
|
||||
, states = serializer.states
|
||||
, debug = require("./debug")
|
||||
, utils = require("./utils")
|
||||
;
|
||||
|
||||
var ursa;
|
||||
@ -23,14 +24,32 @@ try {
|
||||
ursa = require("ursa-purejs");
|
||||
}
|
||||
|
||||
var version = 47;
|
||||
var minecraftVersion = '1.8.1';
|
||||
|
||||
var packets = require("../protocol/protocol");
|
||||
var readPackets = require("./packets").readPackets;
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
|
||||
module.exports = {
|
||||
createClient: createClient,
|
||||
createServer: createServer,
|
||||
Client: Client,
|
||||
Server: Server,
|
||||
states: states,
|
||||
createPacketBuffer: serializer.createPacketBuffer,
|
||||
parsePacketData: serializer.parsePacketData,
|
||||
packetFields: packetIndexes.packetFields,
|
||||
packetNames: packetIndexes.packetNames,
|
||||
packetIds: packetIndexes.packetIds,
|
||||
packetStates: packetIndexes.packetStates,
|
||||
types: serializer.types,
|
||||
get: serializer.get,
|
||||
evalCondition: utils.evalCondition,
|
||||
ping: require('./ping'),
|
||||
protocol: protocol,
|
||||
yggdrasil: Yggdrasil,
|
||||
version: version,
|
||||
minecraftVersion: minecraftVersion
|
||||
};
|
||||
|
||||
function createServer(options) {
|
||||
@ -108,8 +127,8 @@ function createServer(options) {
|
||||
function onPing(packet) {
|
||||
var response = {
|
||||
"version": {
|
||||
"name": protocol.minecraftVersion,
|
||||
"protocol": protocol.version
|
||||
"name": minecraftVersion,
|
||||
"protocol": version
|
||||
},
|
||||
"players": {
|
||||
"max": server.maxPlayers,
|
||||
@ -291,7 +310,7 @@ function createClient(options) {
|
||||
|
||||
function onConnect() {
|
||||
client.write(0x00, {
|
||||
protocolVersion: protocol.version,
|
||||
protocolVersion: version,
|
||||
serverHost: host,
|
||||
serverPort: port,
|
||||
nextState: 2
|
||||
|
@ -1,7 +1,6 @@
|
||||
var net = require('net')
|
||||
, Client = require('./client')
|
||||
, protocol = require('./protocol')
|
||||
, states = protocol.states
|
||||
, states = require('./transforms/serializer').states
|
||||
;
|
||||
|
||||
module.exports = ping;
|
||||
|
164
src/protocol.js
164
src/protocol.js
@ -1,26 +1,3 @@
|
||||
var assert = require('assert');
|
||||
var zlib = require('zlib');
|
||||
|
||||
var evalCondition = require("./utils").evalCondition;
|
||||
var readPackets = require("./packets").readPackets;
|
||||
var debug = require("./debug");
|
||||
|
||||
|
||||
// This is really just for the client.
|
||||
var states = {
|
||||
"HANDSHAKING": "handshaking",
|
||||
"STATUS": "status",
|
||||
"LOGIN": "login",
|
||||
"PLAY": "play"
|
||||
};
|
||||
var packets = require("../protocol/protocol");
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
|
||||
var packetFields = packetIndexes.packetFields;
|
||||
var packetNames = packetIndexes.packetNames;
|
||||
var packetIds = packetIndexes.packetIds;
|
||||
var packetStates = packetIndexes.packetStates;
|
||||
|
||||
function NMProtocols() {
|
||||
this.types = {};
|
||||
}
|
||||
@ -74,144 +51,5 @@ NMProtocols.prototype.sizeOf = function(value, fieldInfo, rootNode) {
|
||||
};
|
||||
|
||||
|
||||
var numeric = require("./datatypes/numeric");
|
||||
var utils = require("./datatypes/utils");
|
||||
var minecraft = require("./datatypes/minecraft");
|
||||
var structures = require("./datatypes/structures");
|
||||
var conditional = require("./datatypes/conditional");
|
||||
|
||||
var proto = new NMProtocols();
|
||||
proto.addTypes(numeric);
|
||||
proto.addTypes(utils);
|
||||
proto.addTypes(minecraft);
|
||||
proto.addTypes(structures);
|
||||
proto.addTypes(conditional);
|
||||
|
||||
function get(packetId, state, toServer) {
|
||||
var direction = toServer ? "toServer" : "toClient";
|
||||
var packetInfo = packetFields[state][direction][packetId];
|
||||
if(!packetInfo) {
|
||||
return null;
|
||||
}
|
||||
return packetInfo;
|
||||
}
|
||||
|
||||
// TODO : This does NOT contain the length prefix anymore.
|
||||
function createPacketBuffer(packetId, state, params, isServer) {
|
||||
var length = 0;
|
||||
if(typeof packetId === 'string' && typeof state !== 'string' && !params) {
|
||||
// simplified two-argument usage, createPacketBuffer(name, params)
|
||||
params = state;
|
||||
state = packetStates[!isServer ? 'toServer' : 'toClient'][packetId];
|
||||
}
|
||||
if(typeof packetId === 'string') packetId = packetIds[state][!isServer ? 'toServer' : 'toClient'][packetId];
|
||||
assert.notEqual(packetId, undefined);
|
||||
|
||||
var packet = get(packetId, state, !isServer);
|
||||
assert.notEqual(packet, null);
|
||||
packet.forEach(function(fieldInfo) {
|
||||
try {
|
||||
length += proto.sizeOf(params[fieldInfo.name], fieldInfo, params);
|
||||
} catch(e) {
|
||||
console.log("fieldInfo : " + JSON.stringify(fieldInfo));
|
||||
console.log("params : " + JSON.stringify(params));
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
length += utils.varint[2](packetId);
|
||||
var size = length;// + utils.varint[2](length);
|
||||
var buffer = new Buffer(size);
|
||||
var offset = 0;//utils.varint[1](length, buffer, 0);
|
||||
offset = utils.varint[1](packetId, buffer, offset);
|
||||
packet.forEach(function(fieldInfo) {
|
||||
var value = params[fieldInfo.name];
|
||||
// TODO : A better check is probably needed
|
||||
if(typeof value === "undefined" && fieldInfo.type != "count" && (fieldInfo.type != "condition" || evalCondition(fieldInfo.typeArgs, params)))
|
||||
debug(new Error("Missing Property " + fieldInfo.name).stack);
|
||||
offset = proto.write(value, buffer, offset, fieldInfo, params);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// By default, parse every packets.
|
||||
function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": true}) {
|
||||
var cursor = 0;
|
||||
var packetIdField = utils.varint[0](buffer, cursor);
|
||||
var packetId = packetIdField.value;
|
||||
cursor += packetIdField.size;
|
||||
|
||||
var results = {id: packetId, state: state};
|
||||
// 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];
|
||||
var shouldParse = (!packetsToParse.hasOwnProperty(name) || packetsToParse[name] <= 0)
|
||||
&& (!packetsToParse.hasOwnProperty("packet") || packetsToParse["packet"] <= 0);
|
||||
if(shouldParse) {
|
||||
return {
|
||||
buffer: buffer,
|
||||
results: results
|
||||
};
|
||||
}
|
||||
|
||||
var packetInfo = get(packetId, state, isServer);
|
||||
if(packetInfo === null) {
|
||||
return {
|
||||
error: new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")"),
|
||||
buffer: buffer,
|
||||
results: results
|
||||
};
|
||||
} else {
|
||||
var packetName = packetNames[state][isServer ? "toServer" : "toClient"][packetId];
|
||||
debug("read packetId " + state + "." + packetName + " (0x" + packetId.toString(16) + ")");
|
||||
}
|
||||
|
||||
var i, fieldInfo, readResults;
|
||||
for(i = 0; i < packetInfo.length; ++i) {
|
||||
fieldInfo = packetInfo[i];
|
||||
readResults = proto.read(buffer, cursor, fieldInfo, results);
|
||||
/* A deserializer cannot return null anymore. Besides, proto.read() returns
|
||||
* null when the condition is not fulfilled.
|
||||
if (!!!readResults) {
|
||||
var error = new Error("A deserializer returned null");
|
||||
error.packetId = packetId;
|
||||
error.fieldInfo = fieldInfo.name;
|
||||
return {
|
||||
size: length + lengthField.size,
|
||||
error: error,
|
||||
results: results
|
||||
};
|
||||
}*/
|
||||
// TODO : investigate readResults returning null : shouldn't happen.
|
||||
// When there is not enough data to read, we should return an error.
|
||||
// As a general rule, it would be a good idea to introduce a whole bunch
|
||||
// of new error classes to differenciate the errors.
|
||||
if(readResults === null || readResults.value == null) continue;
|
||||
if(readResults.error) {
|
||||
return readResults;
|
||||
}
|
||||
results[fieldInfo.name] = readResults.value;
|
||||
cursor += readResults.size;
|
||||
}
|
||||
if(buffer.length > cursor)
|
||||
debug("Too much data to read for packetId: " + packetId + " (0x" + packetId.toString(16) + ")");
|
||||
debug(results);
|
||||
return {
|
||||
results: results,
|
||||
buffer: buffer
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
version: 47,
|
||||
minecraftVersion: '1.8.1',
|
||||
sessionVersion: 13,
|
||||
parsePacketData: parsePacketData,
|
||||
createPacketBuffer: createPacketBuffer,
|
||||
packetIds: packetIds,
|
||||
packetNames: packetNames,
|
||||
packetFields: packetFields,
|
||||
packetStates: packetStates,
|
||||
types: proto.types,
|
||||
states: states,
|
||||
get: get,
|
||||
evalCondition: evalCondition
|
||||
};
|
||||
module.exports = NMProtocols;
|
||||
|
@ -2,7 +2,7 @@ var net = require('net')
|
||||
, EventEmitter = require('events').EventEmitter
|
||||
, util = require('util')
|
||||
, Client = require('./client')
|
||||
, states = require('./protocol').states
|
||||
, states = require('./transforms/serializer').states
|
||||
;
|
||||
|
||||
module.exports = Server;
|
||||
|
@ -1,17 +1,179 @@
|
||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("../datatypes/utils").varint;
|
||||
var protocol = require("../protocol");
|
||||
var Transform = require("readable-stream").Transform;
|
||||
var debug = require("../debug");
|
||||
var assert = require('assert');
|
||||
|
||||
module.exports.createSerializer = function(obj) {
|
||||
return new Serializer(obj);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.createDeserializer = function(obj) {
|
||||
return new Deserializer(obj);
|
||||
};
|
||||
|
||||
module.exports.createPacketBuffer=createPacketBuffer;
|
||||
module.exports.parsePacketData=parsePacketData;
|
||||
|
||||
// This is really just for the client.
|
||||
var states = {
|
||||
"HANDSHAKING": "handshaking",
|
||||
"STATUS": "status",
|
||||
"LOGIN": "login",
|
||||
"PLAY": "play"
|
||||
};
|
||||
module.exports.states = states;
|
||||
|
||||
module.exports.get = get;
|
||||
|
||||
|
||||
|
||||
var NMProtocols = require("../protocol");
|
||||
|
||||
var numeric = require("../datatypes/numeric");
|
||||
var utils = require("../datatypes/utils");
|
||||
var minecraft = require("../datatypes/minecraft");
|
||||
var structures = require("../datatypes/structures");
|
||||
var conditional = require("../datatypes/conditional");
|
||||
|
||||
var proto = new NMProtocols();
|
||||
proto.addTypes(numeric);
|
||||
proto.addTypes(utils);
|
||||
proto.addTypes(minecraft);
|
||||
proto.addTypes(structures);
|
||||
proto.addTypes(conditional);
|
||||
|
||||
|
||||
module.exports.types = proto.types;
|
||||
|
||||
var evalCondition = require("../utils").evalCondition;
|
||||
var packets = require("../../protocol/protocol");
|
||||
var readPackets = require("../packets").readPackets;
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
|
||||
var packetFields = packetIndexes.packetFields;
|
||||
var packetNames = packetIndexes.packetNames;
|
||||
var packetIds = packetIndexes.packetIds;
|
||||
var packetStates = packetIndexes.packetStates;
|
||||
|
||||
|
||||
// TODO : This does NOT contain the length prefix anymore.
|
||||
function createPacketBuffer(packetId, state, params, isServer) {
|
||||
var length = 0;
|
||||
if(typeof packetId === 'string' && typeof state !== 'string' && !params) {
|
||||
// simplified two-argument usage, createPacketBuffer(name, params)
|
||||
params = state;
|
||||
state = packetStates[!isServer ? 'toServer' : 'toClient'][packetId];
|
||||
}
|
||||
if(typeof packetId === 'string') packetId = packetIds[state][!isServer ? 'toServer' : 'toClient'][packetId];
|
||||
assert.notEqual(packetId, undefined);
|
||||
|
||||
var packet = get(packetId, state, !isServer);
|
||||
assert.notEqual(packet, null);
|
||||
packet.forEach(function(fieldInfo) {
|
||||
try {
|
||||
length += proto.sizeOf(params[fieldInfo.name], fieldInfo, params);
|
||||
} catch(e) {
|
||||
console.log("fieldInfo : " + JSON.stringify(fieldInfo));
|
||||
console.log("params : " + JSON.stringify(params));
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
length += utils.varint[2](packetId);
|
||||
var size = length;// + utils.varint[2](length);
|
||||
var buffer = new Buffer(size);
|
||||
var offset = 0;//utils.varint[1](length, buffer, 0);
|
||||
offset = utils.varint[1](packetId, buffer, offset);
|
||||
packet.forEach(function(fieldInfo) {
|
||||
var value = params[fieldInfo.name];
|
||||
// TODO : A better check is probably needed
|
||||
if(typeof value === "undefined" && fieldInfo.type != "count" && (fieldInfo.type != "condition" || evalCondition(fieldInfo.typeArgs, params)))
|
||||
debug(new Error("Missing Property " + fieldInfo.name).stack);
|
||||
offset = proto.write(value, buffer, offset, fieldInfo, params);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
function get(packetId, state, toServer) {
|
||||
var direction = toServer ? "toServer" : "toClient";
|
||||
var packetInfo = packetFields[state][direction][packetId];
|
||||
if(!packetInfo) {
|
||||
return null;
|
||||
}
|
||||
return packetInfo;
|
||||
}
|
||||
|
||||
|
||||
// By default, parse every packets.
|
||||
function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": true}) {
|
||||
var cursor = 0;
|
||||
var packetIdField = utils.varint[0](buffer, cursor);
|
||||
var packetId = packetIdField.value;
|
||||
cursor += packetIdField.size;
|
||||
|
||||
var results = {id: packetId, state: state};
|
||||
// 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];
|
||||
var shouldParse = (!packetsToParse.hasOwnProperty(name) || packetsToParse[name] <= 0)
|
||||
&& (!packetsToParse.hasOwnProperty("packet") || packetsToParse["packet"] <= 0);
|
||||
if(shouldParse) {
|
||||
return {
|
||||
buffer: buffer,
|
||||
results: results
|
||||
};
|
||||
}
|
||||
|
||||
var packetInfo = get(packetId, state, isServer);
|
||||
if(packetInfo === null) {
|
||||
return {
|
||||
error: new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")"),
|
||||
buffer: buffer,
|
||||
results: results
|
||||
};
|
||||
} else {
|
||||
var packetName = packetNames[state][isServer ? "toServer" : "toClient"][packetId];
|
||||
debug("read packetId " + state + "." + packetName + " (0x" + packetId.toString(16) + ")");
|
||||
}
|
||||
|
||||
var i, fieldInfo, readResults;
|
||||
for(i = 0; i < packetInfo.length; ++i) {
|
||||
fieldInfo = packetInfo[i];
|
||||
readResults = proto.read(buffer, cursor, fieldInfo, results);
|
||||
/* A deserializer cannot return null anymore. Besides, proto.read() returns
|
||||
* null when the condition is not fulfilled.
|
||||
if (!!!readResults) {
|
||||
var error = new Error("A deserializer returned null");
|
||||
error.packetId = packetId;
|
||||
error.fieldInfo = fieldInfo.name;
|
||||
return {
|
||||
size: length + lengthField.size,
|
||||
error: error,
|
||||
results: results
|
||||
};
|
||||
}*/
|
||||
// TODO : investigate readResults returning null : shouldn't happen.
|
||||
// When there is not enough data to read, we should return an error.
|
||||
// As a general rule, it would be a good idea to introduce a whole bunch
|
||||
// of new error classes to differenciate the errors.
|
||||
if(readResults === null || readResults.value == null) continue;
|
||||
if(readResults.error) {
|
||||
return readResults;
|
||||
}
|
||||
results[fieldInfo.name] = readResults.value;
|
||||
cursor += readResults.size;
|
||||
}
|
||||
if(buffer.length > cursor)
|
||||
debug("Too much data to read for packetId: " + packetId + " (0x" + packetId.toString(16) + ")");
|
||||
debug(results);
|
||||
return {
|
||||
results: results,
|
||||
buffer: buffer
|
||||
};
|
||||
}
|
||||
|
||||
class Serializer extends Transform {
|
||||
constructor({ state = protocol.states.HANDSHAKING, isServer = false } = {}) {
|
||||
constructor({ state = states.HANDSHAKING, isServer = false } = {}) {
|
||||
super({ writableObjectMode: true });
|
||||
this.protocolState = state;
|
||||
this.isServer = isServer;
|
||||
@ -20,7 +182,7 @@ class Serializer extends Transform {
|
||||
// TODO : Might make sense to make createPacketBuffer async.
|
||||
_transform(chunk, enc, cb) {
|
||||
try {
|
||||
var buf = protocol.createPacketBuffer(chunk.packetId, this.protocolState, chunk.params, this.isServer);
|
||||
var buf = createPacketBuffer(chunk.packetId, this.protocolState, chunk.params, this.isServer);
|
||||
this.push(buf);
|
||||
return cb();
|
||||
} catch (e) {
|
||||
@ -30,7 +192,7 @@ class Serializer extends Transform {
|
||||
}
|
||||
|
||||
class Deserializer extends Transform {
|
||||
constructor({ state = protocol.states.HANDSHAKING, isServer = false, packetsToParse = {"packet": true} } = {}) {
|
||||
constructor({ state = states.HANDSHAKING, isServer = false, packetsToParse = {"packet": true} } = {}) {
|
||||
super({ readableObjectMode: true });
|
||||
this.protocolState = state;
|
||||
this.isServer = isServer;
|
||||
@ -40,7 +202,7 @@ class Deserializer extends Transform {
|
||||
_transform(chunk, enc, cb) {
|
||||
var packet;
|
||||
try {
|
||||
packet = protocol.parsePacketData(chunk, this.protocolState, this.isServer, this.packetsToParse);
|
||||
packet = parsePacketData(chunk, this.protocolState, this.isServer, this.packetsToParse);
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
var ITERATIONS = 100000;
|
||||
|
||||
var protocol = require('../dist/protocol'),
|
||||
var mc = require("../");
|
||||
util = require('util'),
|
||||
states = protocol.states;
|
||||
states = mc.states;
|
||||
|
||||
var testDataWrite = [
|
||||
{id: 0x00, params: {keepAliveId: 957759560}},
|
||||
@ -18,7 +18,7 @@ console.log('Beginning write test');
|
||||
start = Date.now();
|
||||
for(i = 0; i < ITERATIONS; i++) {
|
||||
for(j = 0; j < testDataWrite.length; j++) {
|
||||
inputData.push(protocol.createPacketBuffer(testDataWrite[j].id, states.PLAY, testDataWrite[j].params, false));
|
||||
inputData.push(mc.createPacketBuffer(testDataWrite[j].id, states.PLAY, testDataWrite[j].params, false));
|
||||
}
|
||||
}
|
||||
console.log('Finished write test in ' + (Date.now() - start) / 1000 + ' seconds');
|
||||
@ -26,6 +26,6 @@ console.log('Finished write test in ' + (Date.now() - start) / 1000 + ' seconds'
|
||||
console.log('Beginning read test');
|
||||
start = Date.now();
|
||||
for (j = 0; j < inputData.length; j++) {
|
||||
protocol.parsePacketData(inputData[j], states.PLAY, true);
|
||||
mc.parsePacketData(inputData[j], states.PLAY, true);
|
||||
}
|
||||
console.log('Finished read test in ' + (Date.now() - start) / 1000 + ' seconds');
|
||||
|
21
test/test.js
21
test/test.js
@ -1,6 +1,5 @@
|
||||
var mc = require('../')
|
||||
, protocol = mc.protocol
|
||||
, states = protocol.states
|
||||
, states = mc.states
|
||||
, Client = mc.Client
|
||||
, Server = mc.Server
|
||||
, spawn = require('child_process').spawn
|
||||
@ -152,19 +151,19 @@ describe("packets", function() {
|
||||
client.end();
|
||||
});
|
||||
var packetId, packetInfo, field;
|
||||
for(state in protocol.packetFields) {
|
||||
if(!protocol.packetFields.hasOwnProperty(state)) continue;
|
||||
for(packetId in protocol.packetFields[state].toServer) {
|
||||
if(!protocol.packetFields[state].toServer.hasOwnProperty(packetId)) continue;
|
||||
for(state in mc.packetFields) {
|
||||
if(!mc.packetFields.hasOwnProperty(state)) continue;
|
||||
for(packetId in mc.packetFields[state].toServer) {
|
||||
if(!mc.packetFields[state].toServer.hasOwnProperty(packetId)) continue;
|
||||
packetId = parseInt(packetId, 10);
|
||||
packetInfo = protocol.get(packetId, state, true);
|
||||
packetInfo = mc.get(packetId, state, true);
|
||||
it(state + ",ServerBound,0x" + zfill(parseInt(packetId, 10).toString(16), 2),
|
||||
callTestPacket(packetId, packetInfo, state, true));
|
||||
}
|
||||
for(packetId in protocol.packetFields[state].toClient) {
|
||||
if(!protocol.packetFields[state].toClient.hasOwnProperty(packetId)) continue;
|
||||
for(packetId in mc.packetFields[state].toClient) {
|
||||
if(!mc.packetFields[state].toClient.hasOwnProperty(packetId)) continue;
|
||||
packetId = parseInt(packetId, 10);
|
||||
packetInfo = protocol.get(packetId, state, false);
|
||||
packetInfo = mc.get(packetId, state, false);
|
||||
it(state + ",ClientBound,0x" + zfill(parseInt(packetId, 10).toString(16), 2),
|
||||
callTestPacket(packetId, packetInfo, state, false));
|
||||
}
|
||||
@ -181,7 +180,7 @@ describe("packets", function() {
|
||||
// empty object uses default values
|
||||
var packet = {};
|
||||
packetInfo.forEach(function(field) {
|
||||
if(field.type !== "condition" || protocol.evalCondition(field.typeArgs, packet)) {
|
||||
if(field.type !== "condition" || mc.evalCondition(field.typeArgs, packet)) {
|
||||
var fieldVal = values[field.type];
|
||||
if(typeof fieldVal === "undefined") {
|
||||
throw new Error("No value for type " + field.type);
|
||||
|
Loading…
x
Reference in New Issue
Block a user