mirror of
https://github.com/PrismarineJS/node-minecraft-protocol.git
synced 2024-11-14 19:04:59 -05:00
Add the new type syntax support. Old type syntax doesn't work
This commit is contained in:
parent
5ca49a21ab
commit
ba8a3790aa
8 changed files with 97 additions and 70 deletions
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"prepublish": "gulp",
|
||||
"test": "mocha --reporter spec"
|
||||
"test": "mocha --require source-map-support/register --reporter spec"
|
||||
},
|
||||
"keywords": [
|
||||
"minecraft",
|
||||
|
@ -28,14 +28,15 @@
|
|||
},
|
||||
"browser": "browser.js",
|
||||
"devDependencies": {
|
||||
"batch": "~0.3.1",
|
||||
"gulp": "^3.8.11",
|
||||
"gulp-plumber": "^1.0.1",
|
||||
"gulp-babel": "^5.1.0",
|
||||
"gulp-plumber": "^1.0.1",
|
||||
"gulp-sourcemaps": "^1.3.0",
|
||||
"mkdirp": "~0.3.4",
|
||||
"mocha": "~1.8.2",
|
||||
"rimraf": "~2.1.1",
|
||||
"batch": "~0.3.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"zfill": "0.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -46,7 +47,7 @@
|
|||
"readable-stream": "^1.1.0",
|
||||
"superagent": "~0.10.0",
|
||||
"ursa-purejs": "0.0.3",
|
||||
"minecraft-data": "0.5.1"
|
||||
"minecraft-data": "0.6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"ursa": "~0.8.0"
|
||||
|
|
|
@ -7,19 +7,19 @@ module.exports = {
|
|||
function readCondition(buffer, offset, typeArgs, rootNode) {
|
||||
if(!evalCondition(typeArgs, rootNode))
|
||||
return {value: null, size: 0};
|
||||
return this.read(buffer, offset, {type: typeArgs.type, typeArgs: typeArgs.typeArgs}, rootNode);
|
||||
return this.read(buffer, offset, typeArgs.type, rootNode);
|
||||
}
|
||||
|
||||
function writeCondition(value, buffer, offset, typeArgs, rootNode) {
|
||||
if(!evalCondition(typeArgs, rootNode))
|
||||
return offset;
|
||||
|
||||
return this.write(value, buffer, offset, {type: typeArgs.type, typeArgs: typeArgs.typeArgs}, rootNode);
|
||||
return this.write(value, buffer, offset, typeArgs.type, rootNode);
|
||||
}
|
||||
|
||||
function sizeOfCondition(value, fieldInfo, rootNode) {
|
||||
if(!evalCondition(fieldInfo, rootNode))
|
||||
function sizeOfCondition(value, typeArgs, rootNode) {
|
||||
if(!evalCondition(typeArgs, rootNode))
|
||||
return 0;
|
||||
|
||||
return this.sizeOf(value, fieldInfo, rootNode);
|
||||
return this.sizeOf(value, typeArgs.type, rootNode);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports = {
|
|||
'position': [readPosition, writePosition, 8],
|
||||
'slot': [readSlot, writeSlot, sizeOfSlot],
|
||||
'nbt': [readNbt, utils.buffer[1], utils.buffer[2]],
|
||||
'restBuffer': [readRestBuffer, utils.buffer[1], utils.buffer[2]],
|
||||
'restBuffer': [readRestBuffer, writeRestBuffer, sizeOfRestBuffer],
|
||||
'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata]
|
||||
};
|
||||
|
||||
|
@ -131,13 +131,21 @@ function sizeOfNbt(value) {
|
|||
}
|
||||
|
||||
|
||||
function readRestBuffer(buffer, offset, typeArgs, rootNode) {
|
||||
function readRestBuffer(buffer, offset) {
|
||||
return {
|
||||
value: buffer.slice(offset),
|
||||
size: buffer.length - offset
|
||||
};
|
||||
}
|
||||
|
||||
function writeRestBuffer(value, buffer, offset) {
|
||||
value.copy(buffer, offset);
|
||||
return offset + value.length;
|
||||
}
|
||||
|
||||
function sizeOfRestBuffer(value) {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
var entityMetadataTypes = {
|
||||
0: {type: 'byte'},
|
||||
|
|
|
@ -33,7 +33,7 @@ function readArray(buffer, offset, typeArgs, rootNode) {
|
|||
} else // TODO : broken schema, should probably error out.
|
||||
count = 0;
|
||||
for(var i = 0; i < count; i++) {
|
||||
var readResults = this.read(buffer, offset, {type: typeArgs.type, typeArgs: typeArgs.typeArgs}, rootNode);
|
||||
var readResults = this.read(buffer, offset, typeArgs.type, rootNode);
|
||||
results.size += readResults.size;
|
||||
offset += readResults.size;
|
||||
results.value.push(readResults.value);
|
||||
|
@ -48,7 +48,7 @@ function writeArray(value, buffer, offset, typeArgs, rootNode) {
|
|||
} else if (typeof typeArgs.count === "undefined") { // Broken schema, should probably error out
|
||||
}
|
||||
for(var index in value) {
|
||||
offset = this.write(value[index], buffer, offset, {type: typeArgs.type, typeArgs: typeArgs.typeArgs}, rootNode);
|
||||
offset = this.write(value[index], buffer, offset, typeArgs.type, rootNode);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ function sizeOfArray(value, typeArgs, rootNode) {
|
|||
size = this.sizeOf(value.length, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
}
|
||||
for(var index in value) {
|
||||
size += this.sizeOf(value[index], {type: typeArgs.type, typeArgs: typeArgs.typeArgs}, rootNode);
|
||||
size += this.sizeOf(value[index], typeArgs.type, rootNode);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
@ -76,58 +76,51 @@ function readContainer(buffer, offset, typeArgs, rootNode) {
|
|||
// TODO : what I do inside of roblabla/Protocols is have each "frame" create a new empty slate with just a "super" object pointing to the parent.
|
||||
var backupThis = rootNode.this;
|
||||
rootNode.this = results.value;
|
||||
for(var index in typeArgs.fields) {
|
||||
var readResults = this.read(buffer, offset, typeArgs.fields[index], rootNode);
|
||||
for(var index in typeArgs) {
|
||||
var readResults = this.read(buffer, offset, typeArgs[index].type, rootNode);
|
||||
if(readResults == null || readResults.value == null) {
|
||||
continue;
|
||||
}
|
||||
results.size += readResults.size;
|
||||
offset += readResults.size;
|
||||
results.value[typeArgs.fields[index].name] = readResults.value;
|
||||
results.value[typeArgs[index].name] = readResults.value;
|
||||
}
|
||||
rootNode.this = backupThis;
|
||||
return results;
|
||||
}
|
||||
|
||||
function writeContainer(value, buffer, offset, typeArgs, rootNode) {
|
||||
var context = value.this ? value.this : value;
|
||||
var backupThis = rootNode.this;
|
||||
rootNode.this = value;
|
||||
for(var index in typeArgs.fields) {
|
||||
if(!context.hasOwnProperty(typeArgs.fields[index].name) && typeArgs.fields[index].type != "count" &&
|
||||
(typeArgs.fields[index].type != "condition" || evalCondition(typeArgs.fields[index].typeArgs, rootNode))) {
|
||||
debug(new Error("Missing Property " + typeArgs.fields[index].name).stack);
|
||||
console.log(context);
|
||||
}
|
||||
offset = this.write(context[typeArgs.fields[index].name], buffer, offset, typeArgs.fields[index], rootNode);
|
||||
for(var index in typeArgs) {
|
||||
offset = this.write(value[typeArgs[index].name], buffer, offset, typeArgs[index].type, rootNode);
|
||||
}
|
||||
rootNode.this = backupThis;;
|
||||
rootNode.this = backupThis;
|
||||
return offset;
|
||||
}
|
||||
|
||||
function sizeOfContainer(value, typeArgs, rootNode) {
|
||||
var size = 0;
|
||||
var context = value.this ? value.this : value;
|
||||
var backupThis = rootNode.this;
|
||||
rootNode.this = value;
|
||||
for(var index in typeArgs.fields) {
|
||||
size += this.sizeOf(context[typeArgs.fields[index].name], typeArgs.fields[index], rootNode);
|
||||
for(var index in typeArgs) {
|
||||
size += this.sizeOf(value[typeArgs[index].name], typeArgs[index].type, rootNode);
|
||||
}
|
||||
rootNode.this = backupThis;
|
||||
return size;
|
||||
}
|
||||
|
||||
function readCount(buffer, offset, typeArgs, rootNode) {
|
||||
return this.read(buffer, offset, {type: typeArgs.type}, rootNode);
|
||||
return this.read(buffer, offset, typeArgs.type, rootNode);
|
||||
}
|
||||
|
||||
function writeCount(value, buffer, offset, typeArgs, rootNode) {
|
||||
// Actually gets the required field, and writes its length. Value is unused.
|
||||
// TODO : a bit hackityhack.
|
||||
return this.write(getField(typeArgs.countFor, rootNode).length, buffer, offset, {type: typeArgs.type}, rootNode);
|
||||
return this.write(getField(typeArgs.countFor, rootNode).length, buffer, offset, typeArgs.type, rootNode);
|
||||
}
|
||||
|
||||
function sizeOfCount(value, typeArgs, rootNode) {
|
||||
// TODO : should I use value or getField().length ?
|
||||
return this.sizeOf(getField(typeArgs.countFor, rootNode).length, {type: typeArgs.type}, rootNode);
|
||||
return this.sizeOf(getField(typeArgs.countFor, rootNode).length, typeArgs.type, rootNode);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
var { getFieldInfo } = require('./utils');
|
||||
|
||||
function NMProtocols() {
|
||||
this.types = {};
|
||||
}
|
||||
|
@ -13,15 +15,15 @@ NMProtocols.prototype.addTypes = function(types) {
|
|||
});
|
||||
};
|
||||
|
||||
NMProtocols.prototype.read = function(buffer, cursor, fieldInfo, rootNodes) {
|
||||
NMProtocols.prototype.read = function(buffer, cursor, _fieldInfo, rootNodes) {
|
||||
let fieldInfo = getFieldInfo(_fieldInfo);
|
||||
var type = this.types[fieldInfo.type];
|
||||
if(!type) {
|
||||
return {
|
||||
error: new Error("missing data type: " + fieldInfo.type)
|
||||
};
|
||||
}
|
||||
var typeArgs = fieldInfo.typeArgs || {};
|
||||
var readResults = type[0].call(this, buffer, cursor, typeArgs, rootNodes);
|
||||
var readResults = type[0].call(this, buffer, cursor, fieldInfo.typeArgs, rootNodes);
|
||||
if(readResults == null) {
|
||||
throw new Error("Reader returned null : " + JSON.stringify(fieldInfo));
|
||||
}
|
||||
|
@ -29,25 +31,25 @@ NMProtocols.prototype.read = function(buffer, cursor, fieldInfo, rootNodes) {
|
|||
return readResults;
|
||||
};
|
||||
|
||||
NMProtocols.prototype.write = function(value, buffer, offset, fieldInfo, rootNode) {
|
||||
NMProtocols.prototype.write = function(value, buffer, offset, _fieldInfo, rootNode) {
|
||||
let fieldInfo = getFieldInfo(_fieldInfo);
|
||||
var type = this.types[fieldInfo.type];
|
||||
if(!type) {
|
||||
return {
|
||||
error: new Error("missing data type: " + fieldInfo.type)
|
||||
};
|
||||
}
|
||||
var typeArgs = fieldInfo.typeArgs || {};
|
||||
return type[1].call(this, value, buffer, offset, typeArgs, rootNode);
|
||||
return type[1].call(this, value, buffer, offset, fieldInfo.typeArgs, rootNode);
|
||||
};
|
||||
|
||||
NMProtocols.prototype.sizeOf = function(value, fieldInfo, rootNode) {
|
||||
NMProtocols.prototype.sizeOf = function(value, _fieldInfo, rootNode) {
|
||||
let fieldInfo = getFieldInfo(_fieldInfo);
|
||||
var type = this.types[fieldInfo.type];
|
||||
if(!type) {
|
||||
throw new Error("missing data type: " + fieldInfo.type);
|
||||
}
|
||||
if(typeof type[2] === 'function') {
|
||||
var typeArgs = fieldInfo.typeArgs || {};
|
||||
return type[2].call(this, value, typeArgs, rootNode);
|
||||
return type[2].call(this, value, fieldInfo.typeArgs, rootNode);
|
||||
} else {
|
||||
return type[2];
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ var protocol = require("../protocol");
|
|||
var Transform = require("readable-stream").Transform;
|
||||
var debug = require("../debug");
|
||||
var assert = require('assert');
|
||||
var { getFieldInfo } = require('../utils');
|
||||
|
||||
module.exports.createSerializer = function(obj) {
|
||||
return new Serializer(obj);
|
||||
|
@ -73,7 +74,7 @@ function createPacketBuffer(packetId, state, params, isServer) {
|
|||
assert.notEqual(packet, null);
|
||||
packet.forEach(function(fieldInfo) {
|
||||
try {
|
||||
length += proto.sizeOf(params[fieldInfo.name], fieldInfo, params);
|
||||
length += proto.sizeOf(params[fieldInfo.name], fieldInfo.type, params);
|
||||
} catch(e) {
|
||||
console.log("fieldInfo : " + JSON.stringify(fieldInfo));
|
||||
console.log("params : " + JSON.stringify(params));
|
||||
|
@ -90,7 +91,7 @@ function createPacketBuffer(packetId, state, params, isServer) {
|
|||
// 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);
|
||||
offset = proto.write(value, buffer, offset, fieldInfo.type, params);
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
@ -109,9 +110,7 @@ function get(packetId, state, toServer) {
|
|||
// 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 { value: packetId, size: cursor } = utils.varint[0](buffer, cursor);
|
||||
|
||||
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
|
||||
|
@ -140,7 +139,7 @@ function parsePacketData(buffer, state, isServer, packetsToParse = {"packet": tr
|
|||
var i, fieldInfo, readResults;
|
||||
for(i = 0; i < packetInfo.length; ++i) {
|
||||
fieldInfo = packetInfo[i];
|
||||
readResults = proto.read(buffer, cursor, fieldInfo, results);
|
||||
readResults = proto.read(buffer, cursor, fieldInfo.type, results);
|
||||
/* A deserializer cannot return null anymore. Besides, proto.read() returns
|
||||
* null when the condition is not fulfilled.
|
||||
if (!!!readResults) {
|
||||
|
|
11
src/utils.js
11
src/utils.js
|
@ -1,5 +1,6 @@
|
|||
module.exports = {
|
||||
getField: getField,
|
||||
getFieldInfo: getFieldInfo,
|
||||
evalCondition: evalCondition
|
||||
};
|
||||
|
||||
|
@ -12,6 +13,16 @@ function getField(countField, rootNode) {
|
|||
return count;
|
||||
}
|
||||
|
||||
function getFieldInfo(fieldInfo) {
|
||||
if (typeof fieldInfo === "string")
|
||||
return { type: fieldInfo };
|
||||
else if (Array.isArray(fieldInfo))
|
||||
return { type: fieldInfo[0], typeArgs: fieldInfo[1] };
|
||||
else if (typeof fieldInfo.type === "string")
|
||||
return fieldInfo;
|
||||
else
|
||||
throw new Error("Not a fieldinfo");
|
||||
}
|
||||
|
||||
function evalCondition(condition, field_values) {
|
||||
var field_value_to_test = "this" in condition && condition["this"] ? field_values["this"][condition.field] : field_values[condition.field];
|
||||
|
|
59
test/test.js
59
test/test.js
|
@ -14,6 +14,8 @@ var mc = require('../')
|
|||
, MC_SERVER_JAR = process.env.MC_SERVER_JAR
|
||||
, SURVIVE_TIME = 10000
|
||||
, MC_SERVER_PATH = path.join(__dirname, 'server')
|
||||
, getFieldInfo = require('../dist/utils').getFieldInfo
|
||||
, evalCondition = require('../dist/utils').evalCondition
|
||||
;
|
||||
|
||||
var defaultServerProps = {
|
||||
|
@ -60,25 +62,29 @@ var values = {
|
|||
'ubyte': 8,
|
||||
'string': "hi hi this is my client string",
|
||||
'buffer': new Buffer(8),
|
||||
'array': function(typeArgs) {
|
||||
'array': function(_typeArgs, packet) {
|
||||
var typeArgs = getFieldInfo(_typeArgs.type)
|
||||
if(typeof values[typeArgs.type] === "undefined") {
|
||||
throw new Error("No data type for " + typeArgs.type);
|
||||
}
|
||||
if(typeof values[typeArgs.type] === "function") {
|
||||
return [values[typeArgs.type](typeArgs.typeArgs)];
|
||||
return [values[typeArgs.type](typeArgs.typeArgs, packet)];
|
||||
}
|
||||
return [values[typeArgs.type]];
|
||||
},
|
||||
'container': function(typeArgs) {
|
||||
'container': function(typeArgs, packet) {
|
||||
var results = {};
|
||||
for(var index in typeArgs.fields) {
|
||||
if(typeof values[typeArgs.fields[index].type] === "undefined") {
|
||||
throw new Error("No data type for " + typeArgs.fields[index].type);
|
||||
for(var index in typeArgs) {
|
||||
if(typeof values[getFieldInfo(typeArgs[index].type).type] === "undefined") {
|
||||
throw new Error("No data type for " + typeArgs[index].type);
|
||||
}
|
||||
if(typeof values[typeArgs.fields[index].type] === "function") {
|
||||
results[typeArgs.fields[index].name] = values[typeArgs.fields[index].type](typeArgs.fields[index].typeArgs);
|
||||
if(typeof values[getFieldInfo(typeArgs[index].type).type] === "function") {
|
||||
var backupThis = packet.this;
|
||||
packet.this = results;
|
||||
results[typeArgs[index].name] = values[getFieldInfo(typeArgs[index].type).type](getFieldInfo(typeArgs[index].type).typeArgs, packet);
|
||||
packet.this = backupThis;
|
||||
} else {
|
||||
results[typeArgs.fields[index].name] = values[typeArgs.fields[index].type];
|
||||
results[typeArgs[index].name] = values[getFieldInfo(typeArgs[index].type).type];
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
@ -121,10 +127,13 @@ var values = {
|
|||
'UUID': "00112233-4455-6677-8899-aabbccddeeff",
|
||||
'position': {x: 12, y: 332, z: 4382821},
|
||||
'restBuffer': new Buffer(0),
|
||||
'condition': function(typeArgs) {
|
||||
// check whether this should return undefined if needed instead ? (using evalCondition)
|
||||
// probably not since we only send values that respect the condition
|
||||
return values[typeArgs.type];
|
||||
'condition': function(typeArgs, packet) {
|
||||
if (evalCondition(typeArgs, packet)) {
|
||||
if (typeof values[getFieldInfo(typeArgs.type).type] === "function")
|
||||
return values[getFieldInfo(typeArgs.type).type](getFieldInfo(typeArgs.type).typeArgs, packet);
|
||||
else
|
||||
return values[getFieldInfo(typeArgs.type).type];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -179,22 +188,25 @@ describe("packets", function() {
|
|||
// empty object uses default values
|
||||
var packet = {};
|
||||
packetInfo.forEach(function(field) {
|
||||
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);
|
||||
}
|
||||
if(typeof fieldVal === "function") {
|
||||
fieldVal = fieldVal(field.typeArgs);
|
||||
}
|
||||
packet[field.name] = fieldVal;
|
||||
var fieldVal = values[getFieldInfo(field.type).type];
|
||||
if(typeof fieldVal === "undefined") {
|
||||
throw new Error("No value for type " + field.type);
|
||||
}
|
||||
if(typeof fieldVal === "function") {
|
||||
fieldVal = fieldVal(getFieldInfo(field.type).typeArgs, packet);
|
||||
}
|
||||
packet[field.name] = fieldVal;
|
||||
});
|
||||
if(toServer) {
|
||||
serverClient.once([state, packetId], function(receivedPacket) {
|
||||
delete receivedPacket.id;
|
||||
delete receivedPacket.state;
|
||||
try {
|
||||
assertPacketsMatch(packet, receivedPacket);
|
||||
} catch (e) {
|
||||
console.log(packet, receivedPacket);
|
||||
throw e;
|
||||
}
|
||||
done();
|
||||
});
|
||||
client.write(packetId, packet);
|
||||
|
@ -215,7 +227,8 @@ describe("packets", function() {
|
|||
});
|
||||
var field;
|
||||
for(field in p1) {
|
||||
assert.ok(field in p2, "field " + field + " missing in p2, in p1 it has value " + JSON.stringify(p1[field]));
|
||||
if (p1[field] !== undefined)
|
||||
assert.ok(field in p2, "field " + field + " missing in p2, in p1 it has value " + JSON.stringify(p1[field]));
|
||||
}
|
||||
for(field in p2) {
|
||||
assert.ok(field in p1, "field " + field + " missing in p1, in p2 it has value " + JSON.stringify(p2[field]));
|
||||
|
|
Loading…
Reference in a new issue