Merge pull request #253 from roblabla/feature-newContextSyntax

New context syntax
This commit is contained in:
Robin Lambertz 2015-09-23 19:39:36 +02:00
commit a7e74cdb1d
6 changed files with 88 additions and 96 deletions

View file

@ -4,19 +4,18 @@ var states = mc.states;
function printHelpAndExit(exitCode) { function printHelpAndExit(exitCode) {
console.log("usage: node proxy.js [<options>...] <target_srv> <user> [<password>]"); console.log("usage: node proxy.js [<options>...] <target_srv> <user> [<password>]");
console.log("options:"); console.log("options:");
console.log(" --dump ID"); console.log(" --dump name");
console.log(" print to stdout messages with the specified ID."); console.log(" print to stdout messages with the specified name.");
console.log(" --dump-all"); console.log(" --dump-all");
console.log(" print to stdout all messages, except those specified with -x."); console.log(" print to stdout all messages, except those specified with -x.");
console.log(" -x ID"); console.log(" -x name");
console.log(" do not print messages with this ID."); console.log(" do not print messages with this name.");
console.log(" ID"); console.log(" name");
console.log(" an integer in decimal or hex (given to JavaScript's parseInt())"); console.log(" a packet name as defined in protocol.json");
console.log(" optionally prefixed with o for client->server or i for client<-server.");
console.log("examples:"); console.log("examples:");
console.log(" node proxy.js --dump-all -x 0x0 -x 0x3 -x 0x12 -x 0x015 -x 0x16 -x 0x17 -x 0x18 -x 0x19 localhost Player"); console.log(" node proxy.js --dump-all -x keep_alive -x update_time -x entity_velocity -x rel_entity_move -x entity_look -x entity_move_look -x entity_teleport -x entity_head_rotation -x position -x localhost Player");
console.log(" print all messages except for some of the most prolific."); console.log(" print all messages except for some of the most prolific.");
console.log(" node examples/proxy.js --dump i0x2d --dump i0x2e --dump i0x2f dump i0x30 --dump i0x31 --dump i0x32 --dump o0x0d --dump o0x0e --dump o0x0f --dump o0x10 --dump o0x11 localhost Player"); console.log(" node examples/proxy.js --dump open_window --dump close_window --dump set_slot --dump window_items --dump craft_progress_bar --dump transaction --dump close_window --dump window_click --dump set_creative_slot --dump enchant_item localhost Player");
console.log(" print messages relating to inventory management."); console.log(" print messages relating to inventory management.");
process.exit(exitCode); process.exit(exitCode);
@ -39,27 +38,23 @@ var port = 25565;
var user; var user;
var passwd; var passwd;
var printAllIds = false; var printAllNames = false;
var printIdWhitelist = {}; var printNameWhitelist = {};
var printIdBlacklist = {}; var printNameBlacklist = {};
(function() { (function() {
for(var i = 0; i < args.length; i++) { for(var i = 0; i < args.length; i++) {
var option = args[i]; var option = args[i];
if(!/^-/.test(option)) break; if(!/^-/.test(option)) break;
if(option == "--dump-all") { if(option == "--dump-all") {
printAllIds = true; printAllNames = true;
continue; continue;
} }
i++; i++;
var match = /^([io]?)(.*)/.exec(args[i]); var name = args[i];
var prefix = match[1];
if(prefix === "") prefix = "io";
var number = parseInt(match[2]);
if(isNaN(number)) printHelpAndExit(1);
if(option == "--dump") { if(option == "--dump") {
printIdWhitelist[number] = prefix; printNameWhitelist[name] = "io";
} else if(option == "-x") { } else if(option == "-x") {
printIdBlacklist[number] = prefix; printNameBlacklist[name] = "io";
} else { } else {
printHelpAndExit(1); printHelpAndExit(1);
} }
@ -105,41 +100,38 @@ srv.on('login', function(client) {
'online-mode': passwd != null ? true : false, 'online-mode': passwd != null ? true : false,
keepAlive:false keepAlive:false
}); });
var brokenPackets = [/*0x04, 0x2f, 0x30*/]; client.on('packet', function(data, meta) {
client.on('packet', function(packet) { if(targetClient.state == states.PLAY && meta.state == states.PLAY) {
if(targetClient.state == states.PLAY && packet.state == states.PLAY) { if(shouldDump(meta.name, "o")) {
if(shouldDump(packet.id, "o")) {
console.log("client->server:", console.log("client->server:",
client.state + ".0x" + packet.id.toString(16) + " :", client.state + ".0x" + meta.id.toString(16) + " :",
JSON.stringify(packet)); JSON.stringify(data));
} }
if(!endedTargetClient) if(!endedTargetClient)
targetClient.write(packet.id, packet); targetClient.write(meta.name, data);
} }
}); });
targetClient.on('packet', function(packet) { targetClient.on('packet', function(data, meta) {
if(packet.state == states.PLAY && client.state == states.PLAY && if(meta.state == states.PLAY && client.state == states.PLAY) {
brokenPackets.indexOf(packet.id) === -1) { if(shouldDump(meta.name, "i")) {
if(shouldDump(packet.id, "i")) {
console.log("client<-server:", console.log("client<-server:",
targetClient.state + ".0x" + packet.id.toString(16) + " :", targetClient.state + "." + meta.name + " :" +
(packet.id != 38 ? JSON.stringify(packet) : "Packet too big")); JSON.stringify(data));
} }
if(!endedClient) if(!endedClient)
client.write(packet.id, packet); client.write(meta.name, data);
if (packet.id === 0x46) // Set compression if (meta.name === 'set_compression' || meta.name === 'compression') // Set compression
client.compressionThreshold = packet.threshold; client.compressionThreshold = data.threshold;
} }
}); });
var buffertools = require('buffertools'); var buffertools = require('buffertools');
targetClient.on('raw', function(buffer, state) { targetClient.on('raw', function(buffer, meta) {
if(client.state != states.PLAY || state != states.PLAY) if(client.state != states.PLAY || meta.state != states.PLAY)
return; return;
var packetId = mc.types.varint[0](buffer, 0); var packetData = mc.parsePacketData(buffer, meta.state, false, {"packet": 1}).data;
var packetData = mc.parsePacketData(buffer, state, false, {"packet": 1}).results; var packetBuff = mc.createPacketBuffer(meta.name, meta.state, packetData, true);
var packetBuff = mc.createPacketBuffer(packetData.id, packetData.state, packetData, true);
if(buffertools.compare(buffer, packetBuff) != 0) { if(buffertools.compare(buffer, packetBuff) != 0) {
console.log("client<-server: Error in packetId " + state + ".0x" + packetId.value.toString(16)); console.log("client<-server: Error in packet " + state + "." + meta.name);
console.log(buffer.toString('hex')); console.log(buffer.toString('hex'));
console.log(packetBuff.toString('hex')); console.log(packetBuff.toString('hex'));
console.log(buffer.length); console.log(buffer.length);
@ -153,14 +145,13 @@ srv.on('login', function(client) {
client.writeRaw(buffer); client.writeRaw(buffer);
}*/ }*/
}); });
client.on('raw', function(buffer, state) { client.on('raw', function(buffer, meta) {
if(state != states.PLAY || targetClient.state != states.PLAY) if(meta.state != states.PLAY || targetClient.state != states.PLAY)
return; return;
var packetId = mc.types.varint[0](buffer, 0); var packetData = mc.parsePacketData(buffer, meta.state, true, {"packet": 1}).data;
var packetData = mc.parsePacketData(buffer, state, true, {"packet": 1}).results; var packetBuff = mc.createPacketBuffer(meta.name, meta.state, packetData, false);
var packetBuff = mc.createPacketBuffer(packetData.id, packetData.state, packetData, false);
if(buffertools.compare(buffer, packetBuff) != 0) { if(buffertools.compare(buffer, packetBuff) != 0) {
console.log("client->server: Error in packetId " + state + ".0x" + packetId.value.toString(16)); console.log("client->server: Error in packet " + state + "." + meta.name);
console.log(buffer.toString('hex')); console.log(buffer.toString('hex'));
console.log(packetBuff.toString('hex')); console.log(packetBuff.toString('hex'));
console.log(buffer.length); console.log(buffer.length);
@ -182,10 +173,10 @@ srv.on('login', function(client) {
}); });
}); });
function shouldDump(id, direction) { function shouldDump(name, direction) {
if(matches(printIdBlacklist[id])) return false; if(matches(printNameBlacklist[name])) return false;
if(printAllIds) return true; if(printAllNames) return true;
if(matches(printIdWhitelist[id])) return true; if(matches(printNameWhitelist[name])) return true;
return false; return false;
function matches(result) { function matches(result) {
return result != null && result.indexOf(direction) !== -1; return result != null && result.indexOf(direction) !== -1;

View file

@ -44,7 +44,7 @@
"babel-runtime": "^5.4.4", "babel-runtime": "^5.4.4",
"buffer-equal": "0.0.0", "buffer-equal": "0.0.0",
"lodash.reduce": "^3.1.2", "lodash.reduce": "^3.1.2",
"minecraft-data": "0.10.0", "minecraft-data": "0.11.0",
"node-uuid": "~1.4.1", "node-uuid": "~1.4.1",
"prismarine-nbt": "0.0.1", "prismarine-nbt": "0.0.1",
"readable-stream": "^1.1.0", "readable-stream": "^1.1.0",

View file

@ -97,17 +97,14 @@ function sizeOfArray(value, typeArgs, rootNode) {
} }
function readContainer(buffer, offset, typeArgs, rootNode) { function readContainer(buffer, offset, typeArgs, context) {
var results = { var results = {
value: {}, value: { "..": context },
size: 0 size: 0
}; };
var backupThis = rootNode.this;
rootNode.this = results.value;
typeArgs.forEach((typeArg) => { typeArgs.forEach((typeArg) => {
var readResults;
tryCatch(() => { tryCatch(() => {
readResults = this.read(buffer, offset, typeArg.type, rootNode); var readResults = this.read(buffer, offset, typeArg.type, results.value);
results.size += readResults.size; results.size += readResults.size;
offset += readResults.size; offset += readResults.size;
if (typeArg.anon) { if (typeArg.anon) {
@ -124,19 +121,18 @@ function readContainer(buffer, offset, typeArgs, rootNode) {
throw e; throw e;
}); });
}); });
rootNode.this = backupThis; delete results.value[".."];
return results; return results;
} }
function writeContainer(value, buffer, offset, typeArgs, rootNode) { function writeContainer(value, buffer, offset, typeArgs, context) {
var backupThis = rootNode.this; value[".."] = context;
rootNode.this = value;
typeArgs.forEach((typeArg) => { typeArgs.forEach((typeArg) => {
tryCatch(() => { tryCatch(() => {
if (typeArg.anon) if (typeArg.anon)
offset = this.write(value, buffer, offset, typeArg.type, rootNode); offset = this.write(value, buffer, offset, typeArg.type, value);
else else
offset = this.write(value[typeArg.name], buffer, offset, typeArg.type, rootNode); offset = this.write(value[typeArg.name], buffer, offset, typeArg.type, value);
}, (e) => { }, (e) => {
if (typeArgs && typeArg && typeArg.name) if (typeArgs && typeArg && typeArg.name)
addErrorField(e, typeArg.name); addErrorField(e, typeArg.name);
@ -145,20 +141,19 @@ function writeContainer(value, buffer, offset, typeArgs, rootNode) {
throw e; throw e;
}); });
}); });
rootNode.this = backupThis; delete value[".."];
return offset; return offset;
} }
function sizeOfContainer(value, typeArgs, rootNode) { function sizeOfContainer(value, typeArgs, context) {
value[".."] = context;
var size = 0; var size = 0;
var backupThis = rootNode.this;
rootNode.this = value;
typeArgs.forEach((typeArg) => { typeArgs.forEach((typeArg) => {
tryCatch(() => { tryCatch(() => {
if (typeArg.anon) if (typeArg.anon)
size += this.sizeOf(value, typeArg.type, rootNode); size += this.sizeOf(value, typeArg.type, value);
else else
size += this.sizeOf(value[typeArg.name], typeArg.type, rootNode); size += this.sizeOf(value[typeArg.name], typeArg.type, value);
}, (e) => { }, (e) => {
if (typeArgs && typeArg && typeArg.name) if (typeArgs && typeArg && typeArg.name)
addErrorField(e, typeArg.name); addErrorField(e, typeArg.name);
@ -167,7 +162,7 @@ function sizeOfContainer(value, typeArgs, rootNode) {
throw e; throw e;
}); });
}); });
rootNode.this = backupThis; delete value[".."];
return size; return size;
} }

View file

@ -63,7 +63,7 @@ var packetStates = packetIndexes.packetStates;
function createPacketBuffer(packetName, state, params, isServer) { function createPacketBuffer(packetName, state, params, isServer) {
var direction = !isServer ? 'toServer' : 'toClient'; var direction = !isServer ? 'toServer' : 'toClient';
var packetId = packetIds[state][direction][packetName]; var packetId = packetIds[state][direction][packetName];
assert.notEqual(packetId, undefined); assert.notEqual(packetId, undefined, `${state}.${isServer}.${packetName} : ${packetId}`);
var packet = get(packetName, state, !isServer); var packet = get(packetName, state, !isServer);
assert.notEqual(packet, null); assert.notEqual(packet, null);
@ -140,7 +140,8 @@ function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": tr
results.data = res.value; results.data = res.value;
cursor += res.size; cursor += res.size;
if(buffer.length > cursor) if(buffer.length > cursor)
throw new Error(`Read error for ${packetName} : Packet data not entirely read`); throw new Error(`Read error for ${packetName} : Packet data not entirely read :
${JSON.stringify(results)}`);
debug(results); debug(results);
return results; return results;
} }

View file

@ -5,13 +5,18 @@ module.exports = {
tryCatch: tryCatch, tryCatch: tryCatch,
}; };
function getField(countField, rootNode) { function getField(countField, context) {
var countFieldArr = countField.split("."); var countFieldArr = countField.split("/");
var count = rootNode; var i = 0;
for(var index = 0; index < countFieldArr.length; index++) { if (countFieldArr[i] === "") {
count = count[countFieldArr[index]]; while (context.hasOwnProperty(".."))
context = context[".."];
i++;
} }
return count; for(; i < countFieldArr.length; i++) {
context = context[countFieldArr[i]];
}
return context;
} }
function getFieldInfo(fieldInfo) { function getFieldInfo(fieldInfo) {

View file

@ -32,29 +32,29 @@ var values = {
'ubyte': 8, 'ubyte': 8,
'string': "hi hi this is my client string", 'string': "hi hi this is my client string",
'buffer': new Buffer(8), 'buffer': new Buffer(8),
'array': function(typeArgs, packet) { 'array': function(typeArgs, context) {
var count; var count;
if (typeof typeArgs.count === "object") if (typeof typeArgs.count === "object")
count = evalCount(typeArgs.count, packet); count = evalCount(typeArgs.count, context);
else if (typeof typeArgs.count !== "undefined") else if (typeof typeArgs.count !== "undefined")
count = getField(typeArgs.count, rootNode); count = getField(typeArgs.count, context);
else if (typeof typeArgs.countType !== "undefined") else if (typeof typeArgs.countType !== "undefined")
count = 1; count = 1;
var arr = []; var arr = [];
while (count > 0) { while (count > 0) {
arr.push(getValue(typeArgs.type, packet)); arr.push(getValue(typeArgs.type, context));
count--; count--;
} }
return arr; return arr;
}, },
'container': function(typeArgs, packet) { 'container': function(typeArgs, context) {
var results = {}; var results = {
"..": context;
};
for(var index in typeArgs) { for(var index in typeArgs) {
var backupThis = packet.this; results[typeArgs[index].name] = getValue(typeArgs[index].type, results);
packet.this = results;
results[typeArgs[index].name] = getValue(typeArgs[index].type, packet);
packet.this = backupThis;
} }
delete context[".."];
return results; return results;
}, },
'count': 1, // TODO : might want to set this to a correct value 'count': 1, // TODO : might want to set this to a correct value
@ -90,15 +90,15 @@ var values = {
'UUID': "00112233-4455-6677-8899-aabbccddeeff", 'UUID': "00112233-4455-6677-8899-aabbccddeeff",
'position': {x: 12, y: 332, z: 4382821}, 'position': {x: 12, y: 332, z: 4382821},
'restBuffer': new Buffer(0), 'restBuffer': new Buffer(0),
'switch': function(typeArgs, packet) { 'switch': function(typeArgs, context) {
var i = typeArgs.fields[getField(typeArgs.compareTo, packet)]; var i = typeArgs.fields[getField(typeArgs.compareTo, context)];
if (typeof i === "undefined") if (typeof i === "undefined")
return getValue(typeArgs.default, packet); return getValue(typeArgs.default, context);
else else
return getValue(i, packet); return getValue(i, context);
}, },
'option': function(typeArgs, packet) { 'option': function(typeArgs, context) {
return getValue(typeArgs, packet); return getValue(typeArgs, context);
} }
}; };