mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-27 21:24:25 -04:00
commit
3007740135
@ -119,12 +119,12 @@ The user's session, as returned by the Yggdrasil system.
|
||||
### `packet` event
|
||||
|
||||
Called with every packet parsed. Takes two params, the JSON data we parsed,
|
||||
and the packet metadata (name, id, state)
|
||||
and the packet metadata (name, state)
|
||||
|
||||
### `raw` event
|
||||
|
||||
Called with every packet, but as a buffer. Takes two params, the buffer
|
||||
and the packet metadata (name, id, state)
|
||||
and the packet metadata (name, state)
|
||||
|
||||
### `state` event
|
||||
|
||||
|
@ -2,7 +2,7 @@ var mc = require('../../');
|
||||
|
||||
var states = mc.states;
|
||||
function printHelpAndExit(exitCode) {
|
||||
console.log("usage: node proxy.js [<options>...] <target_srv> <user> [<password>] [<version>]");
|
||||
console.log("usage: node proxy.js [<options>...] <target_srv> [<version>]");
|
||||
console.log("options:");
|
||||
console.log(" --dump name");
|
||||
console.log(" print to stdout messages with the specified name.");
|
||||
@ -35,8 +35,6 @@ process.argv.forEach(function(val, index, array) {
|
||||
var args = process.argv.slice(2);
|
||||
var host;
|
||||
var port = 25565;
|
||||
var user;
|
||||
var passwd;
|
||||
var version;
|
||||
|
||||
var printAllNames = false;
|
||||
@ -62,8 +60,6 @@ var printNameBlacklist = {};
|
||||
}
|
||||
if(!(i + 2 <= args.length && args.length <= i + 4)) printHelpAndExit(1);
|
||||
host = args[i++];
|
||||
user = args[i++];
|
||||
passwd = args[i++];
|
||||
version = args[i++];
|
||||
})();
|
||||
|
||||
@ -98,9 +94,7 @@ srv.on('login', function(client) {
|
||||
var targetClient = mc.createClient({
|
||||
host: host,
|
||||
port: port,
|
||||
username: user,
|
||||
password: passwd,
|
||||
'online-mode': passwd != null ? true : false,
|
||||
username: client.username,
|
||||
keepAlive:false,
|
||||
version:version
|
||||
});
|
||||
@ -108,7 +102,7 @@ srv.on('login', function(client) {
|
||||
if(targetClient.state == states.PLAY && meta.state == states.PLAY) {
|
||||
if(shouldDump(meta.name, "o")) {
|
||||
console.log("client->server:",
|
||||
client.state + ".0x" + meta.id.toString(16) + " :",
|
||||
client.state + " "+ meta.name + " :",
|
||||
JSON.stringify(data));
|
||||
}
|
||||
if(!endedTargetClient)
|
||||
@ -122,18 +116,19 @@ srv.on('login', function(client) {
|
||||
targetClient.state + "." + meta.name + " :" +
|
||||
JSON.stringify(data));
|
||||
}
|
||||
if(!endedClient)
|
||||
if(!endedClient) {
|
||||
client.write(meta.name, data);
|
||||
if (meta.name === 'set_compression' || meta.name === 'compression') // Set compression
|
||||
if (meta.name === 'set_compression') // Set compression
|
||||
client.compressionThreshold = data.threshold;
|
||||
}
|
||||
}
|
||||
});
|
||||
var bufferEqual = require('buffer-equal');
|
||||
targetClient.on('raw', function(buffer, meta) {
|
||||
if(client.state != states.PLAY || meta.state != states.PLAY)
|
||||
return;
|
||||
var packetData = targetClient.deserializer.parsePacketData(buffer).data;
|
||||
var packetBuff = client.serializer.createPacketBuffer(meta.name, packetData);
|
||||
var packetData = targetClient.deserializer.parsePacketBuffer(buffer).data.params;
|
||||
var packetBuff = client.serializer.createPacketBuffer({name:meta.name, params:packetData});
|
||||
if(!bufferEqual(buffer, packetBuff)) {
|
||||
console.log("client<-server: Error in packet " + state + "." + meta.name);
|
||||
console.log(buffer.toString('hex'));
|
||||
@ -152,8 +147,8 @@ srv.on('login', function(client) {
|
||||
client.on('raw', function(buffer, meta) {
|
||||
if(meta.state != states.PLAY || targetClient.state != states.PLAY)
|
||||
return;
|
||||
var packetData = client.deserializer.parsePacketData(buffer).data;
|
||||
var packetBuff = targetClient.serializer.createPacketBuffer(meta.name, packetData);
|
||||
var packetData = client.deserializer.parsePacketBuffer(buffer).data.params;
|
||||
var packetBuff = targetClient.serializer.createPacketBuffer({name:meta.name, params:packetData});
|
||||
if(!bufferEqual(buffer, packetBuff)) {
|
||||
console.log("client->server: Error in packet " + state + "." + meta.name);
|
||||
console.log(buffer.toString('hex'));
|
||||
|
@ -14,6 +14,10 @@ server.on('login', function(client) {
|
||||
console.log('Connection closed', '(' + addr + ')');
|
||||
});
|
||||
|
||||
client.on('error', function(error) {
|
||||
console.log('Error:', error);
|
||||
});
|
||||
|
||||
// send init data so client will start rendering world
|
||||
client.write('login', {
|
||||
entityId: client.id,
|
||||
|
@ -46,10 +46,12 @@
|
||||
"minecraft-data": "^0.13.0",
|
||||
"node-uuid": "~1.4.1",
|
||||
"prismarine-nbt": "0.0.1",
|
||||
"protodef": "0.2.0",
|
||||
"readable-stream": "^1.1.0",
|
||||
"superagent": "~0.10.0",
|
||||
"ursa-purejs": "0.0.3",
|
||||
"uuid": "^2.0.1",
|
||||
"uuid-1345": "^0.99.6",
|
||||
"yggdrasil": "0.1.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@ -1,10 +1,6 @@
|
||||
var readPackets = require("./packets").readPackets;
|
||||
var utils = require("./utils");
|
||||
var serializer = require("./transforms/serializer");
|
||||
|
||||
module.exports = {
|
||||
Client: require('./client'),
|
||||
protocol: require('./protocol'),
|
||||
readPackets:readPackets,
|
||||
supportedVersions:require("./version").supportedVersions
|
||||
};
|
||||
|
@ -1,11 +1,12 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var debug = require('./debug');
|
||||
var serializer = require('./transforms/serializer');
|
||||
var compression = require('./transforms/compression');
|
||||
var framing = require('./transforms/framing');
|
||||
var crypto = require('crypto');
|
||||
var states = serializer.states;
|
||||
var states = require("./states");
|
||||
|
||||
var createSerializer=require("./transforms/serializer").createSerializer;
|
||||
var createDeserializer=require("./transforms/serializer").createDeserializer;
|
||||
|
||||
class Client extends EventEmitter
|
||||
{
|
||||
@ -19,12 +20,14 @@ class Client extends EventEmitter
|
||||
decompressor=null;
|
||||
deserializer;
|
||||
isServer;
|
||||
version;
|
||||
protocolState=states.HANDSHAKING;
|
||||
|
||||
constructor(isServer,version) {
|
||||
super();
|
||||
this.serializer = serializer.createSerializer({ isServer, version:version});
|
||||
this.deserializer = serializer.createDeserializer({ isServer, packetsToParse: this.packetsToParse, version:version});
|
||||
this.version=version;
|
||||
this.isServer = !!isServer;
|
||||
this.setSerializer(states.HANDSHAKING);
|
||||
|
||||
this.on('newListener', function(event, listener) {
|
||||
var direction = this.isServer ? 'toServer' : 'toClient';
|
||||
@ -38,13 +41,76 @@ class Client extends EventEmitter
|
||||
}
|
||||
|
||||
get state(){
|
||||
return this.serializer.protocolState;
|
||||
return this.protocolState;
|
||||
}
|
||||
|
||||
|
||||
setSerializer(state) {
|
||||
this.serializer = createSerializer({ isServer:this.isServer, version:this.version, state: state});
|
||||
this.deserializer = createDeserializer({ isServer:this.isServer, version:this.version, state: state, packetsToParse:
|
||||
this.packetsToParse});
|
||||
|
||||
|
||||
this.serializer.on('error', (e) => {
|
||||
var parts=e.field.split(".");
|
||||
parts.shift();
|
||||
var serializerDirection = !this.isServer ? 'toServer' : 'toClient';
|
||||
e.field = [this.protocolState, serializerDirection].concat(parts).join(".");
|
||||
e.message = `Serialization error for ${e.field} : ${e.message}`;
|
||||
this.emit('error',e);
|
||||
});
|
||||
|
||||
|
||||
this.deserializer.on('error', (e) => {
|
||||
var parts=e.field.split(".");
|
||||
parts.shift();
|
||||
var deserializerDirection = this.isServer ? 'toServer' : 'toClient';
|
||||
e.field = [this.protocolState, deserializerDirection].concat(parts).join(".");
|
||||
e.message = `Deserialization error for ${e.field} : ${e.message}`;
|
||||
this.emit('error',e);
|
||||
});
|
||||
|
||||
this.deserializer.on('data', (parsed) => {
|
||||
parsed.metadata.name=parsed.data.name;
|
||||
parsed.data=parsed.data.params;
|
||||
parsed.metadata.state=state;
|
||||
this.emit('packet', parsed.data, parsed.metadata);
|
||||
this.emit(parsed.metadata.name, parsed.data, parsed.metadata);
|
||||
this.emit('raw.' + parsed.metadata.name, parsed.buffer, parsed.metadata);
|
||||
this.emit('raw', parsed.buffer, parsed.metadata);
|
||||
});
|
||||
}
|
||||
|
||||
set state(newProperty) {
|
||||
var oldProperty = this.serializer.protocolState;
|
||||
this.serializer.protocolState = newProperty;
|
||||
this.deserializer.protocolState = newProperty;
|
||||
var oldProperty = this.protocolState;
|
||||
this.protocolState = newProperty;
|
||||
|
||||
if(!this.compressor)
|
||||
{
|
||||
this.serializer.unpipe(this.framer);
|
||||
this.splitter.unpipe(this.deserializer);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.serializer.unpipe(this.compressor);
|
||||
this.decompressor.unpipe(this.deserializer);
|
||||
}
|
||||
|
||||
this.serializer.removeAllListeners();
|
||||
this.deserializer.removeAllListeners();
|
||||
this.setSerializer(this.protocolState);
|
||||
|
||||
if(!this.compressor)
|
||||
{
|
||||
this.serializer.pipe(this.framer);
|
||||
this.splitter.pipe(this.deserializer);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.serializer.pipe(this.compressor);
|
||||
this.decompressor.pipe(this.deserializer);
|
||||
}
|
||||
|
||||
this.emit('state', newProperty, oldProperty);
|
||||
}
|
||||
|
||||
@ -87,20 +153,11 @@ class Client extends EventEmitter
|
||||
this.socket.on('close', endSocket);
|
||||
this.socket.on('end', endSocket);
|
||||
this.socket.on('timeout', endSocket);
|
||||
this.serializer.on('error', onError);
|
||||
this.deserializer.on('error', onError);
|
||||
this.framer.on('error', onError);
|
||||
this.splitter.on('error', onError);
|
||||
|
||||
this.socket.pipe(this.splitter).pipe(this.deserializer);
|
||||
this.serializer.pipe(this.framer).pipe(this.socket);
|
||||
|
||||
this.deserializer.on('data', (parsed) => {
|
||||
this.emit('packet', parsed.data, parsed.metadata);
|
||||
this.emit(parsed.metadata.name, parsed.data, parsed.metadata);
|
||||
this.emit('raw.' + parsed.metadata.name, parsed.buffer, parsed.metadata);
|
||||
this.emit('raw', parsed.buffer, parsed.metadata);
|
||||
});
|
||||
}
|
||||
|
||||
end(reason) {
|
||||
@ -137,10 +194,10 @@ class Client extends EventEmitter
|
||||
}
|
||||
}
|
||||
|
||||
write(packetName, params) {
|
||||
debug("writing packet " + this.state + "." + packetName);
|
||||
write(name, params) {
|
||||
debug("writing packet " + this.state + "." + name);
|
||||
debug(params);
|
||||
this.serializer.write({ packetName, params });
|
||||
this.serializer.write({ name, params });
|
||||
}
|
||||
|
||||
writeRaw(buffer) {
|
||||
|
@ -6,8 +6,7 @@ var assert = require('assert');
|
||||
var crypto = require('crypto');
|
||||
var yggdrasil = require('yggdrasil')({});
|
||||
var yggserver = require('yggdrasil').server({});
|
||||
var serializer = require("./transforms/serializer");
|
||||
var states = serializer.states;
|
||||
var states = require("./states");
|
||||
var debug = require("./debug");
|
||||
var uuid = require('uuid');
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
var ursa=require("./ursa");
|
||||
var crypto = require('crypto');
|
||||
var yggserver = require('yggdrasil').server({});
|
||||
var serializer = require("./transforms/serializer");
|
||||
var states = serializer.states;
|
||||
var states = require("./states");
|
||||
var bufferEqual = require('buffer-equal');
|
||||
var Server = require('./server');
|
||||
var UUID = require('uuid-1345');
|
||||
|
||||
module.exports=createServer;
|
||||
|
||||
@ -195,10 +195,27 @@ function createServer(options) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/util/UUID.java#L163
|
||||
function javaUUID(s)
|
||||
{
|
||||
var hash = crypto.createHash("md5");
|
||||
hash.update(s, 'utf8');
|
||||
var buffer = hash.digest();
|
||||
buffer[6] = (buffer[6] & 0x0f) | 0x30;
|
||||
buffer[8] = (buffer[8] & 0x3f) | 0x80;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
function nameToMcOfflineUUID(name)
|
||||
{
|
||||
return (new UUID(javaUUID("OfflinePlayer:"+name))).toString();
|
||||
}
|
||||
|
||||
function loginClient() {
|
||||
var isException = !!server.onlineModeExceptions[client.username.toLowerCase()];
|
||||
if(onlineMode == false || isException) {
|
||||
client.uuid = "0-0-0-0-0";
|
||||
client.uuid = nameToMcOfflineUUID(client.username);
|
||||
}
|
||||
client.write('compress', { threshold: 256 }); // Default threshold is 256
|
||||
client.compressionThreshold = 256;
|
||||
|
@ -1,69 +0,0 @@
|
||||
var { getField, getFieldInfo } = require('../utils');
|
||||
|
||||
module.exports = {
|
||||
'switch': [readSwitch, writeSwitch, sizeOfSwitch],
|
||||
'option': [readOption, writeOption, sizeOfOption],
|
||||
};
|
||||
|
||||
function readSwitch(buffer, offset, typeArgs, rootNode) {
|
||||
var compareTo = getField(typeArgs.compareTo, rootNode);
|
||||
var fieldInfo;
|
||||
if (typeof typeArgs.fields[compareTo] === 'undefined' && typeof typeArgs.default === "undefined")
|
||||
throw new Error(compareTo + " has no associated fieldInfo in switch");
|
||||
else if (typeof typeArgs.fields[compareTo] === 'undefined')
|
||||
fieldInfo = getFieldInfo(typeArgs.default);
|
||||
else
|
||||
fieldInfo = getFieldInfo(typeArgs.fields[compareTo]);
|
||||
return this.read(buffer, offset, fieldInfo, rootNode);
|
||||
}
|
||||
|
||||
function writeSwitch(value, buffer, offset, typeArgs, rootNode) {
|
||||
var compareTo = getField(typeArgs.compareTo, rootNode);
|
||||
var fieldInfo;
|
||||
if (typeof typeArgs.fields[compareTo] === 'undefined' && typeof typeArgs.default === "undefined")
|
||||
throw new Error(compareTo + " has no associated fieldInfo in switch");
|
||||
else if (typeof typeArgs.fields[compareTo] === 'undefined')
|
||||
fieldInfo = getFieldInfo(typeArgs.default);
|
||||
else
|
||||
fieldInfo = getFieldInfo(typeArgs.fields[compareTo]);
|
||||
return this.write(value, buffer, offset, fieldInfo, rootNode);
|
||||
}
|
||||
|
||||
function sizeOfSwitch(value, typeArgs, rootNode) {
|
||||
var compareTo = getField(typeArgs.compareTo, rootNode);
|
||||
var fieldInfo;
|
||||
if (typeof typeArgs.fields[compareTo] === 'undefined' && typeof typeArgs.default === "undefined")
|
||||
throw new Error(compareTo + " has no associated fieldInfo in switch");
|
||||
else if (typeof typeArgs.fields[compareTo] === 'undefined')
|
||||
fieldInfo = getFieldInfo(typeArgs.default);
|
||||
else
|
||||
fieldInfo = getFieldInfo(typeArgs.fields[compareTo]);
|
||||
return this.sizeOf(value, fieldInfo, rootNode);
|
||||
}
|
||||
|
||||
function readOption(buffer, offset, typeArgs, context) {
|
||||
var val = buffer.readUInt8(offset++);
|
||||
if (val !== 0) {
|
||||
var retval = this.read(buffer, offset, typeArgs, context);
|
||||
retval.size++;
|
||||
return retval;
|
||||
} else {
|
||||
return {
|
||||
size: 1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function writeOption(value, buffer, offset, typeArgs, context) {
|
||||
if (value != null) {
|
||||
buffer.writeUInt8(1, offset++);
|
||||
this.write(value, buffer, offset, typeArgs, context);
|
||||
} else {
|
||||
buffer.writeUInt8(0, offset++);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
function sizeOfOption(value, typeArgs, context) {
|
||||
return value == null ? 1 : this.sizeOf(value, typeArgs, context) + 1;
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
var nbt = require('prismarine-nbt');
|
||||
var utils = require("./utils");
|
||||
var numeric = require("./numeric");
|
||||
var types=require("protodef").types;
|
||||
var uuid = require('node-uuid');
|
||||
|
||||
// TODO : remove type-specific, replace with generic containers and arrays.
|
||||
module.exports = {
|
||||
'UUID': [readUUID, writeUUID, 16],
|
||||
'slot': [readSlot, writeSlot, sizeOfSlot],
|
||||
'nbt': [readNbt, utils.buffer[1], utils.buffer[2]],
|
||||
'nbt': [readNbt, types.buffer[1], types.buffer[2]],
|
||||
'restBuffer': [readRestBuffer, writeRestBuffer, sizeOfRestBuffer],
|
||||
'entityMetadataLoop': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata]
|
||||
};
|
||||
@ -26,7 +25,7 @@ function writeUUID(value, buffer, offset) {
|
||||
|
||||
function readSlot(buffer, offset) {
|
||||
var value = {};
|
||||
var results = numeric.short[0](buffer, offset);
|
||||
var results = types.short[0](buffer, offset);
|
||||
if(!results) return null;
|
||||
value.blockId = results.value;
|
||||
|
||||
|
@ -1,50 +0,0 @@
|
||||
function readLong(buffer, offset) {
|
||||
if(offset + 8 > buffer.length) return null;
|
||||
return {
|
||||
value: [buffer.readInt32BE(offset), buffer.readInt32BE(offset + 4)],
|
||||
size: 8,
|
||||
};
|
||||
}
|
||||
|
||||
function writeLong(value, buffer, offset) {
|
||||
buffer.writeInt32BE(value[0], offset);
|
||||
buffer.writeInt32BE(value[1], offset + 4);
|
||||
return offset + 8;
|
||||
}
|
||||
|
||||
function generateFunctions(bufferReader,bufferWriter,size)
|
||||
{
|
||||
var reader=function(buffer, offset)
|
||||
{
|
||||
if(offset + size > buffer.length) return null;
|
||||
var value = buffer[bufferReader](offset);
|
||||
return {
|
||||
value: value,
|
||||
size: size
|
||||
};
|
||||
};
|
||||
var writer=function(value, buffer, offset) {
|
||||
buffer[bufferWriter](value, offset);
|
||||
return offset + size;
|
||||
};
|
||||
return [reader, writer, size];
|
||||
}
|
||||
|
||||
var nums= {
|
||||
'byte': ["readInt8", "writeInt8", 1],
|
||||
'ubyte': ["readUInt8", "writeUInt8", 1],
|
||||
'short': ["readInt16BE", "writeInt16BE", 2],
|
||||
'ushort': ["readUInt16BE", "writeUInt16BE", 2],
|
||||
'int': ["readInt32BE", "writeInt32BE", 4],
|
||||
'float': ["readFloatBE", "writeFloatBE", 4],
|
||||
'double': ["readDoubleBE", "writeDoubleBE", 8]
|
||||
};
|
||||
|
||||
var types=Object.keys(nums).reduce(function(types,num){
|
||||
types[num]=generateFunctions(nums[num][0], nums[num][1], nums[num][2]);
|
||||
return types;
|
||||
},{});
|
||||
types["long"]=[readLong, writeLong, 8];
|
||||
|
||||
|
||||
module.exports = types;
|
@ -1,182 +0,0 @@
|
||||
var { getField, tryCatch, addErrorField } = require("../utils");
|
||||
var debug = require("../debug");
|
||||
|
||||
module.exports = {
|
||||
'array': [readArray, writeArray, sizeOfArray],
|
||||
'count': [readCount, writeCount, sizeOfCount],
|
||||
'container': [readContainer, writeContainer, sizeOfContainer]
|
||||
};
|
||||
|
||||
|
||||
function evalCount(count, fields) {
|
||||
if(fields[count["field"]] in count["map"])
|
||||
return count["map"][fields[count["field"]]];
|
||||
return count["default"];
|
||||
}
|
||||
|
||||
function readArray(buffer, offset, typeArgs, rootNode) {
|
||||
var results = {
|
||||
value: [],
|
||||
size: 0
|
||||
};
|
||||
var count;
|
||||
if(typeof typeArgs.count === "object")
|
||||
count = evalCount(typeArgs.count, rootNode);
|
||||
else if (typeof typeArgs.count !== "undefined")
|
||||
count = getField(typeArgs.count, rootNode);
|
||||
else if (typeof typeArgs.countType !== "undefined") {
|
||||
var countResults;
|
||||
tryCatch(() => {
|
||||
countResults = this.read(buffer, offset, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
}, (e) => {
|
||||
addErrorField(e, "$count");
|
||||
throw e;
|
||||
});
|
||||
results.size += countResults.size;
|
||||
offset += countResults.size;
|
||||
count = countResults.value;
|
||||
} else // TODO : broken schema, should probably error out.
|
||||
count = 0;
|
||||
for(var i = 0; i < count; i++) {
|
||||
var readResults;
|
||||
tryCatch(() => {
|
||||
readResults = this.read(buffer, offset, typeArgs.type, rootNode);
|
||||
}, (e) => {
|
||||
addErrorField(e, i);
|
||||
throw e;
|
||||
});
|
||||
results.size += readResults.size;
|
||||
offset += readResults.size;
|
||||
results.value.push(readResults.value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function writeArray(value, buffer, offset, typeArgs, rootNode) {
|
||||
if (typeof typeArgs.count === "undefined" &&
|
||||
typeof typeArgs.countType !== "undefined") {
|
||||
tryCatch(() => {
|
||||
offset = this.write(value.length, buffer, offset, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
}, (e) => {
|
||||
addErrorField(e, "$count");
|
||||
throw e;
|
||||
});
|
||||
} else if (typeof typeArgs.count === "undefined") { // Broken schema, should probably error out
|
||||
}
|
||||
for(var index in value) {
|
||||
tryCatch(() => {
|
||||
offset = this.write(value[index], buffer, offset, typeArgs.type, rootNode);
|
||||
}, (e) => {
|
||||
addErrorField(e, index);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
function sizeOfArray(value, typeArgs, rootNode) {
|
||||
var size = 0;
|
||||
if (typeof typeArgs.count === "undefined" &&
|
||||
typeof typeArgs.countType !== "undefined") {
|
||||
tryCatch(() => {
|
||||
size = this.sizeOf(value.length, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
}, (e) => {
|
||||
addErrorField(e, "$count");
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
for(var index in value) {
|
||||
tryCatch(() => {
|
||||
size += this.sizeOf(value[index], typeArgs.type, rootNode);
|
||||
}, (e) => {
|
||||
addErrorField(e, index);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
function readContainer(buffer, offset, typeArgs, context) {
|
||||
var results = {
|
||||
value: { "..": context },
|
||||
size: 0
|
||||
};
|
||||
typeArgs.forEach((typeArg) => {
|
||||
tryCatch(() => {
|
||||
var readResults = this.read(buffer, offset, typeArg.type, results.value);
|
||||
results.size += readResults.size;
|
||||
offset += readResults.size;
|
||||
if (typeArg.anon) {
|
||||
Object.keys(readResults.value).forEach(function(key) {
|
||||
results.value[key] = readResults.value[key];
|
||||
});
|
||||
} else
|
||||
results.value[typeArg.name] = readResults.value;
|
||||
}, (e) => {
|
||||
if (typeArgs && typeArg && typeArg.name)
|
||||
addErrorField(e, typeArg.name);
|
||||
else
|
||||
addErrorField(e, "unknown");
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
delete results.value[".."];
|
||||
return results;
|
||||
}
|
||||
|
||||
function writeContainer(value, buffer, offset, typeArgs, context) {
|
||||
value[".."] = context;
|
||||
typeArgs.forEach((typeArg) => {
|
||||
tryCatch(() => {
|
||||
if (typeArg.anon)
|
||||
offset = this.write(value, buffer, offset, typeArg.type, value);
|
||||
else
|
||||
offset = this.write(value[typeArg.name], buffer, offset, typeArg.type, value);
|
||||
}, (e) => {
|
||||
if (typeArgs && typeArg && typeArg.name)
|
||||
addErrorField(e, typeArg.name);
|
||||
else
|
||||
addErrorField(e, "unknown");
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
delete value[".."];
|
||||
return offset;
|
||||
}
|
||||
|
||||
function sizeOfContainer(value, typeArgs, context) {
|
||||
value[".."] = context;
|
||||
var size = 0;
|
||||
typeArgs.forEach((typeArg) => {
|
||||
tryCatch(() => {
|
||||
if (typeArg.anon)
|
||||
size += this.sizeOf(value, typeArg.type, value);
|
||||
else
|
||||
size += this.sizeOf(value[typeArg.name], typeArg.type, value);
|
||||
}, (e) => {
|
||||
if (typeArgs && typeArg && typeArg.name)
|
||||
addErrorField(e, typeArg.name);
|
||||
else
|
||||
addErrorField(e, "unknown");
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
delete value[".."];
|
||||
return size;
|
||||
}
|
||||
|
||||
function readCount(buffer, offset, typeArgs, 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, typeArgs.type, rootNode);
|
||||
}
|
||||
|
||||
function sizeOfCount(value, typeArgs, rootNode) {
|
||||
// TODO : should I use value or getField().length ?
|
||||
return this.sizeOf(getField(typeArgs.countFor, rootNode).length, typeArgs.type, rootNode);
|
||||
}
|
@ -1,212 +0,0 @@
|
||||
var assert = require('assert');
|
||||
|
||||
var getField = require("../utils").getField;
|
||||
|
||||
module.exports = {
|
||||
'varint': [readVarInt, writeVarInt, sizeOfVarInt],
|
||||
'bool': [readBool, writeBool, 1],
|
||||
'string': [readString, writeString, sizeOfString],
|
||||
'buffer': [readBuffer, writeBuffer, sizeOfBuffer],
|
||||
'void': [readVoid, writeVoid, 0],
|
||||
'bitfield': [readBitField, writeBitField, sizeOfBitField]
|
||||
};
|
||||
|
||||
function readVarInt(buffer, offset) {
|
||||
var result = 0;
|
||||
var shift = 0;
|
||||
var cursor = offset;
|
||||
|
||||
while(true) {
|
||||
if(cursor + 1 > buffer.length) return null;
|
||||
var b = buffer.readUInt8(cursor);
|
||||
result |= ((b & 0x7f) << shift); // Add the bits to our number, except MSB
|
||||
cursor++;
|
||||
if(!(b & 0x80)) { // If the MSB is not set, we return the number
|
||||
return {
|
||||
value: result,
|
||||
size: cursor - offset
|
||||
};
|
||||
}
|
||||
shift += 7; // we only have 7 bits, MSB being the return-trigger
|
||||
assert.ok(shift < 64, "varint is too big"); // Make sure our shift don't overflow.
|
||||
}
|
||||
}
|
||||
|
||||
function sizeOfVarInt(value) {
|
||||
var cursor = 0;
|
||||
while(value & ~0x7F) {
|
||||
value >>>= 7;
|
||||
cursor++;
|
||||
}
|
||||
return cursor + 1;
|
||||
}
|
||||
|
||||
function writeVarInt(value, buffer, offset) {
|
||||
var cursor = 0;
|
||||
while(value & ~0x7F) {
|
||||
buffer.writeUInt8((value & 0xFF) | 0x80, offset + cursor);
|
||||
cursor++;
|
||||
value >>>= 7;
|
||||
}
|
||||
buffer.writeUInt8(value, offset + cursor);
|
||||
return offset + cursor + 1;
|
||||
}
|
||||
|
||||
|
||||
function readString(buffer, offset) {
|
||||
var length = readVarInt(buffer, offset);
|
||||
if(!!!length) return null;
|
||||
var cursor = offset + length.size;
|
||||
var stringLength = length.value;
|
||||
var strEnd = cursor + stringLength;
|
||||
if(strEnd > buffer.length) return null;
|
||||
|
||||
var value = buffer.toString('utf8', cursor, strEnd);
|
||||
cursor = strEnd;
|
||||
|
||||
return {
|
||||
value: value,
|
||||
size: cursor - offset,
|
||||
};
|
||||
}
|
||||
|
||||
function writeString(value, buffer, offset) {
|
||||
var length = Buffer.byteLength(value, 'utf8');
|
||||
offset = writeVarInt(length, buffer, offset);
|
||||
buffer.write(value, offset, length, 'utf8');
|
||||
return offset + length;
|
||||
}
|
||||
|
||||
|
||||
function sizeOfString(value) {
|
||||
var length = Buffer.byteLength(value, 'utf8');
|
||||
return sizeOfVarInt(length) + length;
|
||||
}
|
||||
|
||||
function readBool(buffer, offset) {
|
||||
if(offset + 1 > buffer.length) return null;
|
||||
var value = buffer.readInt8(offset);
|
||||
return {
|
||||
value: !!value,
|
||||
size: 1,
|
||||
};
|
||||
}
|
||||
|
||||
function writeBool(value, buffer, offset) {
|
||||
buffer.writeInt8(+value, offset);
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
|
||||
function readBuffer(buffer, offset, typeArgs, rootNode) {
|
||||
var size = 0;
|
||||
var count;
|
||||
if (typeof typeArgs.count !== "undefined")
|
||||
count = getField(typeArgs.count, rootNode);
|
||||
else if (typeof typeArgs.countType !== "undefined") {
|
||||
var countResults = this.read(buffer, offset, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
size += countResults.size;
|
||||
offset += countResults.size;
|
||||
count = countResults.value;
|
||||
}
|
||||
return {
|
||||
value: buffer.slice(offset, offset + count),
|
||||
size: size + count
|
||||
};
|
||||
}
|
||||
|
||||
function writeBuffer(value, buffer, offset, typeArgs, rootNode) {
|
||||
if (typeof typeArgs.count === "undefined" &&
|
||||
typeof typeArgs.countType !== "undefined") {
|
||||
offset = this.write(value.length, buffer, offset, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
} else if (typeof typeArgs.count === "undefined") { // Broken schema, should probably error out
|
||||
}
|
||||
value.copy(buffer, offset);
|
||||
return offset + value.length;
|
||||
}
|
||||
|
||||
function sizeOfBuffer(value, typeArgs, rootNode) {
|
||||
var size = 0;
|
||||
if (typeof typeArgs.count === "undefined" &&
|
||||
typeof typeArgs.countType !== "undefined") {
|
||||
size = this.sizeOf(value.length, { type: typeArgs.countType, typeArgs: typeArgs.countTypeArgs }, rootNode);
|
||||
}
|
||||
return size + value.length;
|
||||
}
|
||||
|
||||
function readVoid() {
|
||||
return {
|
||||
value: undefined,
|
||||
size: 0,
|
||||
};
|
||||
}
|
||||
|
||||
function writeVoid(value, buffer, offset) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
function generateBitMask(n) {
|
||||
return (1 << n) - 1;
|
||||
}
|
||||
|
||||
function readBitField(buffer, offset, typeArgs, context) {
|
||||
var beginOffset = offset;
|
||||
var curVal = null;
|
||||
var bits = 0;
|
||||
var results = {};
|
||||
results.value = typeArgs.reduce(function(acc, item) {
|
||||
var size = item.size;
|
||||
var val = 0;
|
||||
while (size > 0) {
|
||||
if (bits == 0) {
|
||||
curVal = buffer[offset++];
|
||||
bits = 8;
|
||||
}
|
||||
var bitsToRead = Math.min(size, bits);
|
||||
val = (val << bitsToRead) | (curVal & generateBitMask(bits)) >> (bits - bitsToRead);
|
||||
bits -= bitsToRead;
|
||||
size -= bitsToRead;
|
||||
}
|
||||
if (item.signed && val >= 1 << (item.size - 1))
|
||||
val -= 1 << item.size;
|
||||
acc[item.name] = val;
|
||||
return acc;
|
||||
}, {});
|
||||
results.size = offset - beginOffset;
|
||||
return results;
|
||||
}
|
||||
function writeBitField(value, buffer, offset, typeArgs, context) {
|
||||
var toWrite = 0;
|
||||
var bits = 0;
|
||||
typeArgs.forEach(function(item) {
|
||||
var val = value[item.name];
|
||||
var size = item.size;
|
||||
var signed = item.signed;
|
||||
if ((!item.signed && val < 0) || (item.signed && val < -(1 << (size - 1))))
|
||||
throw new Error(value + " < " + item.signed ? (-(1 << (size - 1))) : 0);
|
||||
else if ((!item.signed && val >= 1 << size)
|
||||
|| (item.signed && val >= (1 << (size - 1)) - 1))
|
||||
throw new Error(value + " >= " + iteme.signed ? (1 << size) : ((1 << (size - 1)) - 1));
|
||||
while (size > 0) {
|
||||
var writeBits = Math.min(8 - bits, size);
|
||||
toWrite = toWrite << writeBits |
|
||||
((val >> (size - writeBits)) & generateBitMask(writeBits));
|
||||
size -= writeBits;
|
||||
bits += writeBits;
|
||||
if (bits === 8) {
|
||||
buffer[offset++] = toWrite;
|
||||
bits = 0;
|
||||
toWrite = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (bits != 0)
|
||||
buffer[offset++] = toWrite << (8 - bits);
|
||||
return offset;
|
||||
}
|
||||
|
||||
function sizeOfBitField(value, typeArgs, context) {
|
||||
return Math.ceil(typeArgs.reduce(function(acc, item) {
|
||||
return acc + item.size;
|
||||
}, 0) / 8);
|
||||
}
|
@ -2,7 +2,6 @@ var Client = require('./client');
|
||||
var Server = require('./server');
|
||||
var serializer = require("./transforms/serializer");
|
||||
var utils = require("./utils");
|
||||
var readPackets = require("./packets").readPackets;
|
||||
var createClient = require("./createClient");
|
||||
var createServer = require("./createServer");
|
||||
|
||||
@ -11,10 +10,9 @@ module.exports = {
|
||||
createServer: createServer,
|
||||
Client: Client,
|
||||
Server: Server,
|
||||
states: serializer.states,
|
||||
states: require("./states"),
|
||||
createSerializer:serializer.createSerializer,
|
||||
createDeserializer:serializer.createDeserializer,
|
||||
readPackets:readPackets,
|
||||
ping: require('./ping'),
|
||||
supportedVersions:require("./version").supportedVersions
|
||||
};
|
||||
|
@ -1,43 +0,0 @@
|
||||
var assert = require("assert");
|
||||
|
||||
module.exports = {readPackets: readPackets};
|
||||
|
||||
function readPackets(packets, states) {
|
||||
var packetFields = {};
|
||||
var packetNames = {};
|
||||
var packetIds = {};
|
||||
var packetStates = {toClient: {}, toServer: {}};
|
||||
for(var stateName in states) {
|
||||
var state = states[stateName];
|
||||
|
||||
packetFields[state] = {toClient: [], toServer: []};
|
||||
packetNames[state] = {toClient: [], toServer: []};
|
||||
packetIds[state] = {toClient: [], toServer: []};
|
||||
|
||||
['toClient', 'toServer'].forEach(function(direction) {
|
||||
for(var name in packets[state][direction]) {
|
||||
var info = packets[state][direction][name];
|
||||
var id = parseInt(info.id);
|
||||
var fields = info.fields;
|
||||
|
||||
assert(id !== undefined, 'missing id for packet ' + name);
|
||||
assert(fields !== undefined, 'missing fields for packet ' + name);
|
||||
assert(!packetNames[state][direction].hasOwnProperty(id), 'duplicate packet id ' + id + ' for ' + name);
|
||||
assert(!packetIds[state][direction].hasOwnProperty(name), 'duplicate packet name ' + name + ' for ' + id);
|
||||
assert(!packetFields[state][direction].hasOwnProperty(name), 'duplicate packet id ' + id + ' for ' + name);
|
||||
assert(!packetStates[direction].hasOwnProperty(name), 'duplicate packet name ' + name + ' for ' + id + ', must be unique across all states');
|
||||
|
||||
packetNames[state][direction][id] = name;
|
||||
packetIds[state][direction][name] = id;
|
||||
packetFields[state][direction][name] = fields;
|
||||
packetStates[direction][name] = state;
|
||||
}
|
||||
});
|
||||
}
|
||||
return {
|
||||
packetFields: packetFields,
|
||||
packetNames: packetNames,
|
||||
packetIds: packetIds,
|
||||
packetStates: packetStates
|
||||
};
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
var net = require('net');
|
||||
var Client = require('./client');
|
||||
var states = require('./transforms/serializer').states;
|
||||
var states = require("./states");
|
||||
|
||||
module.exports = ping;
|
||||
|
||||
|
120
src/protocol.js
120
src/protocol.js
@ -1,120 +0,0 @@
|
||||
var { getFieldInfo } = require('./utils');
|
||||
var reduce = require('lodash.reduce');
|
||||
|
||||
function isFieldInfo(type) {
|
||||
return typeof type === "string"
|
||||
|| (Array.isArray(type) && typeof type[0] === "string")
|
||||
|| type.type;
|
||||
}
|
||||
|
||||
function findArgs(acc, v, k) {
|
||||
if (typeof v === "string" && v.charAt(0) === '$')
|
||||
acc.push({ "path": k, "val": v.substr(1) });
|
||||
else if (Array.isArray(v) || typeof v === "object")
|
||||
acc = acc.concat(reduce(v, findArgs, []).map((v) => ({ "path": k + "." + v.path, "val": v.val })));
|
||||
return acc;
|
||||
}
|
||||
|
||||
|
||||
function setField(path, val, into) {
|
||||
var c = path.split('.').reverse();
|
||||
while (c.length > 1) {
|
||||
into = into[c.pop()];
|
||||
}
|
||||
into[c.pop()] = val;
|
||||
}
|
||||
|
||||
function extendType(functions, defaultTypeArgs) {
|
||||
var argPos = reduce(defaultTypeArgs, findArgs, []);
|
||||
return [function read(buffer, offset, typeArgs, context) {
|
||||
var args = JSON.parse(JSON.stringify(defaultTypeArgs));
|
||||
argPos.forEach((v) => {
|
||||
setField(v.path, typeArgs[v.val], args);
|
||||
});
|
||||
return functions[0].call(this, buffer, offset, args, context);
|
||||
}, function write(value, buffer, offset, typeArgs, context) {
|
||||
var args = JSON.parse(JSON.stringify(defaultTypeArgs));
|
||||
argPos.forEach((v) => {
|
||||
setField(v.path, typeArgs[v.val], args);
|
||||
});
|
||||
return functions[1].call(this, value, buffer, offset, args, context);
|
||||
}, function sizeOf(value, typeArgs, context) {
|
||||
var args = JSON.parse(JSON.stringify(defaultTypeArgs));
|
||||
argPos.forEach((v) => {
|
||||
setField(v.path, typeArgs[v.val], args);
|
||||
});
|
||||
if (typeof functions[2] === "function")
|
||||
return functions[2].call(this, value, args, context);
|
||||
else
|
||||
return functions[2];
|
||||
}];
|
||||
}
|
||||
|
||||
class NMProtocols
|
||||
{
|
||||
types={};
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
addType(name, functions) {
|
||||
if (functions === "native")
|
||||
return;
|
||||
else if (isFieldInfo(functions)) {
|
||||
var fieldInfo = getFieldInfo(functions);
|
||||
this.types[name] = extendType(this.types[fieldInfo.type], fieldInfo.typeArgs);
|
||||
}
|
||||
else
|
||||
this.types[name] = functions;
|
||||
}
|
||||
|
||||
addTypes(types) {
|
||||
var self = this;
|
||||
Object.keys(types).forEach(function(name) {
|
||||
self.addType(name, types[name]);
|
||||
});
|
||||
}
|
||||
|
||||
read(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 readResults = type[0].call(this, buffer, cursor, fieldInfo.typeArgs, rootNodes);
|
||||
if(readResults == null) {
|
||||
throw new Error("Reader returned null : " + JSON.stringify(fieldInfo));
|
||||
}
|
||||
if(readResults && readResults.error) return {error: readResults.error};
|
||||
return readResults;
|
||||
}
|
||||
|
||||
write(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)
|
||||
};
|
||||
}
|
||||
return type[1].call(this, value, buffer, offset, fieldInfo.typeArgs, rootNode);
|
||||
}
|
||||
|
||||
sizeOf(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') {
|
||||
return type[2].call(this, value, fieldInfo.typeArgs, rootNode);
|
||||
} else {
|
||||
return type[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NMProtocols;
|
@ -1,7 +1,7 @@
|
||||
var net = require('net');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Client = require('./client');
|
||||
var states = require('./transforms/serializer').states;
|
||||
var states = require("./states");
|
||||
|
||||
class Server extends EventEmitter
|
||||
{
|
||||
|
8
src/states.js
Normal file
8
src/states.js
Normal file
@ -0,0 +1,8 @@
|
||||
var states = {
|
||||
"HANDSHAKING": "handshaking",
|
||||
"STATUS": "status",
|
||||
"LOGIN": "login",
|
||||
"PLAY": "play"
|
||||
};
|
||||
|
||||
module.exports=states;
|
@ -1,4 +1,4 @@
|
||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("../datatypes/utils").varint;
|
||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint;
|
||||
var zlib = require("zlib");
|
||||
var Transform = require("readable-stream").Transform;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("../datatypes/utils").varint;
|
||||
var [readVarInt, writeVarInt, sizeOfVarInt] = require("protodef").types.varint;
|
||||
var Transform = require("readable-stream").Transform;
|
||||
|
||||
module.exports.createSplitter = function() {
|
||||
|
@ -1,185 +1,61 @@
|
||||
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');
|
||||
var { getFieldInfo, tryCatch, addErrorField } = require('../utils');
|
||||
var ProtoDef = require("protodef").ProtoDef;
|
||||
var Serializer = require("protodef").Serializer;
|
||||
var Parser = require("protodef").Parser;
|
||||
|
||||
module.exports.createSerializer = function(obj) {
|
||||
return new Serializer(obj);
|
||||
};
|
||||
|
||||
module.exports.createDeserializer = function(obj) {
|
||||
return new Deserializer(obj);
|
||||
};
|
||||
|
||||
// This is really just for the client.
|
||||
var states = {
|
||||
"HANDSHAKING": "handshaking",
|
||||
"STATUS": "status",
|
||||
"LOGIN": "login",
|
||||
"PLAY": "play"
|
||||
};
|
||||
module.exports.states = states;
|
||||
|
||||
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 readPackets = require("../packets").readPackets;
|
||||
var states = require("../states");
|
||||
|
||||
|
||||
function createProtocol(types)
|
||||
function createProtocol(types,packets)
|
||||
{
|
||||
var proto = new NMProtocols();
|
||||
proto.addTypes(numeric);
|
||||
proto.addTypes(utils);
|
||||
var proto = new ProtoDef();
|
||||
proto.addType("string",["pstring",{
|
||||
countType:"varint"
|
||||
}]);
|
||||
proto.addTypes(minecraft);
|
||||
proto.addTypes(structures);
|
||||
proto.addTypes(conditional);
|
||||
proto.addTypes(types);
|
||||
|
||||
Object.keys(packets).forEach(function(name) {
|
||||
proto.addType("packet_"+name,["container",packets[name].fields]);
|
||||
});
|
||||
|
||||
proto.addType("packet",["container", [
|
||||
{ "name": "name", "type":["mapper",{"type": "varint" ,
|
||||
"mappings":Object.keys(packets).reduce(function(acc,name){
|
||||
acc[parseInt(packets[name].id)]=name;
|
||||
return acc;
|
||||
},{})
|
||||
}]},
|
||||
{ "name": "params", "type": ["switch", {
|
||||
"compareTo": "name",
|
||||
"fields": Object.keys(packets).reduce(function(acc,name){
|
||||
acc[name]="packet_"+name;
|
||||
return acc;
|
||||
},{})
|
||||
}]}
|
||||
]]);
|
||||
return proto;
|
||||
}
|
||||
|
||||
|
||||
class Serializer extends Transform {
|
||||
constructor({ state = states.HANDSHAKING, isServer = false , version} = {}) {
|
||||
super({ writableObjectMode: true });
|
||||
this.protocolState = state;
|
||||
this.isServer = isServer;
|
||||
this.version = version;
|
||||
|
||||
function createSerializer({ state = states.HANDSHAKING, isServer = false , version} = {})
|
||||
{
|
||||
var mcData=require("minecraft-data")(version);
|
||||
var packets = mcData.protocol.states;
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
|
||||
this.proto=createProtocol(mcData.protocol.types);
|
||||
|
||||
this.packetFields = packetIndexes.packetFields;
|
||||
this.packetIds = packetIndexes.packetIds;
|
||||
}
|
||||
|
||||
// TODO : This does NOT contain the length prefix anymore.
|
||||
createPacketBuffer(packetName, params) {
|
||||
var direction = !this.isServer ? 'toServer' : 'toClient';
|
||||
var packetId = this.packetIds[this.protocolState][direction][packetName];
|
||||
assert.notEqual(packetId, undefined, `${this.protocolState}.${direction}.${packetName} : ${packetId}`);
|
||||
var packet = this.packetFields[this.protocolState][direction][packetName];
|
||||
packet=packet ? packet : null;
|
||||
|
||||
assert.notEqual(packet, null);
|
||||
|
||||
var length = utils.varint[2](packetId);
|
||||
tryCatch(() => {
|
||||
length += structures.container[2].call(this.proto, params, packet, {});
|
||||
//length += proto.sizeOf(params, ["container", packet], {});
|
||||
}, (e) => {
|
||||
e.field = [this.protocolState, direction, packetName, e.field].join(".");
|
||||
e.message = `SizeOf error for ${e.field} : ${e.message}`;
|
||||
throw e;
|
||||
});
|
||||
|
||||
var buffer = new Buffer(length);
|
||||
var offset = utils.varint[1](packetId, buffer, 0);
|
||||
tryCatch(() => {
|
||||
offset = structures.container[1].call(this.proto, params, buffer, offset, packet, {});
|
||||
//offset = proto.write(params, buffer, offset, ["container", packet], {});
|
||||
}, (e) => {
|
||||
e.field = [this.protocolState, direction, packetName, e.field].join(".");
|
||||
e.message = `Write error for ${e.field} : ${e.message}`;
|
||||
throw e;
|
||||
});
|
||||
return buffer;
|
||||
}
|
||||
|
||||
_transform(chunk, enc, cb) {
|
||||
try {
|
||||
var buf = this.createPacketBuffer(chunk.packetName, chunk.params);
|
||||
this.push(buf);
|
||||
return cb();
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
}
|
||||
var direction = !isServer ? 'toServer' : 'toClient';
|
||||
var packets = mcData.protocol.states[state][direction];
|
||||
var proto=createProtocol(mcData.protocol.types,packets);
|
||||
return new Serializer(proto,"packet");
|
||||
}
|
||||
|
||||
class Deserializer extends Transform {
|
||||
constructor({ state = states.HANDSHAKING, isServer = false, packetsToParse = {"packet": true}, version } = {}) {
|
||||
super({ readableObjectMode: true });
|
||||
this.protocolState = state;
|
||||
this.isServer = isServer;
|
||||
this.packetsToParse = packetsToParse;
|
||||
this.version = version;
|
||||
|
||||
|
||||
function createDeserializer({ state = states.HANDSHAKING, isServer = false,
|
||||
packetsToParse = {"packet": true}, version } = {})
|
||||
{
|
||||
var mcData=require("minecraft-data")(version);
|
||||
var packets = mcData.protocol.states;
|
||||
var packetIndexes = readPackets(packets, states);
|
||||
|
||||
this.proto=createProtocol(mcData.protocol.types);
|
||||
|
||||
this.packetFields = packetIndexes.packetFields;
|
||||
this.packetNames = packetIndexes.packetNames;
|
||||
}
|
||||
|
||||
parsePacketData(buffer) {
|
||||
var { value: packetId, size: cursor } = utils.varint[0](buffer, 0);
|
||||
|
||||
var direction = this.isServer ? "toServer" : "toClient";
|
||||
var packetName = this.packetNames[this.protocolState][direction][packetId];
|
||||
var results = {
|
||||
metadata: {
|
||||
name: packetName,
|
||||
id: packetId,
|
||||
state:this.protocolState
|
||||
},
|
||||
data: {},
|
||||
buffer
|
||||
};
|
||||
|
||||
// Only parse the packet if there is a need for it, AKA if there is a listener
|
||||
// attached to it.
|
||||
var shouldParse =
|
||||
(this.packetsToParse.hasOwnProperty(packetName) && this.packetsToParse[packetName] > 0) ||
|
||||
(this.packetsToParse.hasOwnProperty("packet") && this.packetsToParse["packet"] > 0);
|
||||
if (!shouldParse)
|
||||
return results;
|
||||
|
||||
var packetInfo = this.packetFields[this.protocolState][direction][packetName];
|
||||
packetInfo=packetInfo ? packetInfo : null;
|
||||
if(packetInfo === null)
|
||||
throw new Error("Unrecognized packetId: " + packetId + " (0x" + packetId.toString(16) + ")")
|
||||
else
|
||||
debug("read packetId " + this.protocolState + "." + packetName + " (0x" + packetId.toString(16) + ")");
|
||||
|
||||
var res;
|
||||
tryCatch(() => {
|
||||
res = this.proto.read(buffer, cursor, ["container", packetInfo], {});
|
||||
}, (e) => {
|
||||
e.field = [this.protocolState, direction, packetName, e.field].join(".");
|
||||
e.message = `Read error for ${e.field} : ${e.message}`;
|
||||
throw e;
|
||||
});
|
||||
results.data = res.value;
|
||||
cursor += res.size;
|
||||
if(buffer.length > cursor)
|
||||
throw new Error(`Read error for ${packetName} : Packet data not entirely read :
|
||||
${JSON.stringify(results)}`);
|
||||
debug(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
_transform(chunk, enc, cb) {
|
||||
var packet;
|
||||
try {
|
||||
packet = this.parsePacketData(chunk);
|
||||
} catch (e) {
|
||||
return cb(e);
|
||||
}
|
||||
this.push(packet);
|
||||
return cb();
|
||||
}
|
||||
var direction = isServer ? "toServer" : "toClient";
|
||||
var packets = mcData.protocol.states[state][direction];
|
||||
var proto=createProtocol(mcData.protocol.types,packets);
|
||||
return new Parser(proto,"packet");
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createSerializer:createSerializer,
|
||||
createDeserializer:createDeserializer
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
var ITERATIONS = 100000;
|
||||
var ITERATIONS = 10000;
|
||||
|
||||
var mc = require("../");
|
||||
var util = require('util');
|
||||
@ -15,7 +15,7 @@ mc.supportedVersions.forEach(function(supportedVersion){
|
||||
var mcData=require("minecraft-data")(supportedVersion);
|
||||
var version=mcData.version;
|
||||
describe("benchmark "+version.minecraftVersion,function(){
|
||||
this.timeout(20 * 1000);
|
||||
this.timeout(60 * 1000);
|
||||
var inputData = [];
|
||||
it("bench serializing",function(done){
|
||||
var serializer=new mc.createSerializer({state:states.PLAY,isServer:false,version:version.majorVersion});
|
||||
@ -24,7 +24,7 @@ mc.supportedVersions.forEach(function(supportedVersion){
|
||||
start = Date.now();
|
||||
for(i = 0; i < ITERATIONS; i++) {
|
||||
for(j = 0; j < testDataWrite.length; j++) {
|
||||
inputData.push(serializer.createPacketBuffer(testDataWrite[j].name, testDataWrite[j].params));
|
||||
inputData.push(serializer.createPacketBuffer(testDataWrite[j]));
|
||||
}
|
||||
}
|
||||
var result=(Date.now() - start) / 1000;
|
||||
@ -37,7 +37,7 @@ mc.supportedVersions.forEach(function(supportedVersion){
|
||||
console.log('Beginning read test');
|
||||
start = Date.now();
|
||||
for (j = 0; j < inputData.length; j++) {
|
||||
deserializer.parsePacketData(inputData[j]);
|
||||
deserializer.parsePacketBuffer(inputData[j]);
|
||||
}
|
||||
console.log('Finished read test in ' + (Date.now() - start) / 1000 + ' seconds');
|
||||
done();
|
||||
|
@ -1,248 +0,0 @@
|
||||
var expect = require('chai').expect;
|
||||
|
||||
var numeric = require('../../dist/datatypes/numeric');
|
||||
var getReader = function(dataType) { return dataType[0]; };
|
||||
var getWriter = function(dataType) { return dataType[1]; };
|
||||
var getSizeOf = function(dataType) { return dataType[2]; };
|
||||
/*var getReader = require('../../lib/utils').getReader;
|
||||
var getWriter = require('../../lib/utils').getWriter;
|
||||
var getSizeOf = require('../../lib/utils').getSizeOf;*/
|
||||
|
||||
var testData = {
|
||||
'byte': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x3d]),
|
||||
'value': 61
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0x86]),
|
||||
'value': -122
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00]),
|
||||
'value': 32,
|
||||
'bufferAfter': new Buffer([0x20])
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00]),
|
||||
'value': -122,
|
||||
'bufferAfter': new Buffer([0x86])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 1,
|
||||
}
|
||||
},
|
||||
'ubyte': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x3d]),
|
||||
'value': 61
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0x86]),
|
||||
'value': 134
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00]),
|
||||
'value': 61,
|
||||
'bufferAfter': new Buffer([0x3d])
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00]),
|
||||
'value': 134,
|
||||
'bufferAfter': new Buffer([0x86])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 1,
|
||||
}
|
||||
},
|
||||
'short': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x30, 0x87]),
|
||||
'value': 12423
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0xef, 0x77]),
|
||||
'value': -4233
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00, 0x00]),
|
||||
'value': 12423,
|
||||
'bufferAfter': new Buffer([0x30, 0x87]),
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00, 0x00]),
|
||||
'value': -4233,
|
||||
'bufferAfter': new Buffer([0xef, 0x77])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 2,
|
||||
}
|
||||
},
|
||||
'ushort': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x30, 0x87]),
|
||||
'value': 12423
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0xef, 0x77]),
|
||||
'value': 61303
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00, 0x00]),
|
||||
'value': 12423,
|
||||
'bufferAfter': new Buffer([0x30, 0x87]),
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00, 0x00]),
|
||||
'value': 61303,
|
||||
'bufferAfter': new Buffer([0xef, 0x77])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 2,
|
||||
}
|
||||
},
|
||||
'int': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0xea]),
|
||||
'value': 234
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0xff, 0xff, 0xfc, 0x00]),
|
||||
'value': -1024
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00]),
|
||||
'value': 234,
|
||||
'bufferAfter': new Buffer([0x00, 0x00, 0x00, 0xea])
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00]),
|
||||
'value': -1024,
|
||||
'bufferAfter': new Buffer([0xff, 0xff, 0xfc, 0x00])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 4
|
||||
}
|
||||
},
|
||||
'uint': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0xea]),
|
||||
'value': 234
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0xff, 0xff, 0xfc, 0x00]),
|
||||
'value': 4294966272
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00]),
|
||||
'value': 234,
|
||||
'bufferAfter': new Buffer([0x00, 0x00, 0x00, 0xea])
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00]),
|
||||
'value': 4294966272,
|
||||
'bufferAfter': new Buffer([0xff, 0xff, 0xfc, 0x00])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 4
|
||||
}
|
||||
},
|
||||
'float': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x47, 0x05, 0xc3, 0x00]),
|
||||
'value': 34243
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0xc6, 0x42, 0x4c, 0x00]),
|
||||
'value': -12435
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00]),
|
||||
'value': 34243,
|
||||
'bufferAfter': new Buffer([0x47, 0x05, 0xc3, 0x00])
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00]),
|
||||
'value': -12435,
|
||||
'bufferAfter': new Buffer([0xc6, 0x42, 0x4c, 0x00])
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 4
|
||||
}
|
||||
},
|
||||
'double': {
|
||||
'readPos': {
|
||||
'buffer': new Buffer([0x40, 0xe0, 0xb8, 0x60, 0x00, 0x00, 0x00, 0x00]),
|
||||
'value': 34243
|
||||
},
|
||||
'readNeg': {
|
||||
'buffer': new Buffer([0xc0, 0xc8, 0x49, 0x80, 0x00, 0x00, 0x00, 0x00]),
|
||||
'value': -12435
|
||||
},
|
||||
'writePos': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
|
||||
'value': 34243,
|
||||
'bufferAfter': new Buffer([0x40, 0xe0, 0xb8, 0x60, 0x00, 0x00, 0x00, 0x00]),
|
||||
},
|
||||
'writeNeg': {
|
||||
'buffer': new Buffer([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
|
||||
'value': -12435,
|
||||
'bufferAfter': new Buffer([0xc0, 0xc8, 0x49, 0x80, 0x00, 0x00, 0x00, 0x00]),
|
||||
},
|
||||
'sizeof': {
|
||||
'value': 0x2d,
|
||||
'size': 8
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
describe('Numeric', function() {
|
||||
for (var key in testData) {
|
||||
if (testData.hasOwnProperty(key) && numeric.hasOwnProperty(key)) {
|
||||
var value = testData[key];
|
||||
describe('.' + key, function() {
|
||||
var reader;
|
||||
var writer;
|
||||
var sizeof;
|
||||
before(function() {
|
||||
reader = getReader(numeric[key]);
|
||||
writer = getWriter(numeric[key]);
|
||||
sizeof = getSizeOf(numeric[key]);
|
||||
});
|
||||
it('Returns null if not enough data is provided', function() {
|
||||
expect(reader(new Buffer(0), 0)).to.eql(null);
|
||||
});
|
||||
it('Reads positive values', function() {
|
||||
expect(reader(value.readPos.buffer, 0).value).to.deep.eql(value.readPos.value);
|
||||
});
|
||||
it('Reads big/negative values', function() {
|
||||
expect(reader(value.readNeg.buffer, 0).value).to.deep.eql(value.readNeg.value);
|
||||
});
|
||||
it('Writes positive values', function() {
|
||||
writer(value.writePos.value, value.writePos.buffer, 0);
|
||||
expect(value.writePos.buffer).to.deep.eql(value.writePos.bufferAfter);
|
||||
});
|
||||
it('Writes negative values', function() {
|
||||
writer(value.writeNeg.value, value.writeNeg.buffer, 0);
|
||||
expect(value.writeNeg.buffer).to.deep.eql(value.writeNeg.bufferAfter);
|
||||
});
|
||||
it('Calculates size', function() {
|
||||
var size;
|
||||
if (typeof sizeof === "function") {
|
||||
size = sizeof(value.sizeof.value);
|
||||
} else {
|
||||
size = sizeof;
|
||||
}
|
||||
expect(size).to.eql(value.sizeof.size);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -1,205 +0,0 @@
|
||||
var assert = require('power-assert');
|
||||
var expect = require('chai').expect;
|
||||
|
||||
var utils = require('../../dist/datatypes/utils');
|
||||
var getReader = function(dataType) { return dataType[0]; };
|
||||
var getWriter = function(dataType) { return dataType[1]; };
|
||||
var getSizeOf = function(dataType) { return dataType[2]; };
|
||||
|
||||
describe('Utils', function() {
|
||||
describe('.bool', function() {
|
||||
it('Reads false value for binary 0', function() {
|
||||
assert.deepEqual(getReader(utils.bool)(new Buffer([0]), 0), {value: false, size: 1});
|
||||
});
|
||||
it('Reads true for every other binary value', function() {
|
||||
var buf = new Buffer([0]);
|
||||
var i = 1;
|
||||
while (i < 256) {
|
||||
buf[0] = i++;
|
||||
assert.deepEqual(getReader(utils.bool)(buf, 0), {value: true, size: 1});
|
||||
}
|
||||
});
|
||||
it('Writes false', function() {
|
||||
var buffer = new Buffer(1);
|
||||
getWriter(utils.bool)(false, buffer, 0);
|
||||
assert.deepEqual(buffer, new Buffer([0]));
|
||||
});
|
||||
it('Writes true', function() {
|
||||
var buffer = new Buffer(1);
|
||||
getWriter(utils.bool)(true, buffer, 0);
|
||||
assert.notDeepEqual(buffer, new Buffer([0]));
|
||||
});
|
||||
it('Has a size of 1', function() {
|
||||
assert.equal(typeof getSizeOf(utils.bool), "number");
|
||||
assert.equal(getSizeOf(utils.bool), 1);
|
||||
});
|
||||
});
|
||||
describe('.varint', function() {
|
||||
it.skip('Has no tests', function() {
|
||||
});
|
||||
});
|
||||
describe('.buffer', function() {
|
||||
it.skip('Has no tests', function() {
|
||||
});
|
||||
});
|
||||
describe('.string', function() {
|
||||
it.skip('Has no tests', function() {
|
||||
});
|
||||
});
|
||||
describe('.void', function() {
|
||||
it.skip('Has no tests', function() {
|
||||
});
|
||||
});
|
||||
describe('.bitfield', function() {
|
||||
it('Reads an unsigned 8 bit number', function() {
|
||||
var buf = new Buffer([0xff]);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 8, "signed": false }
|
||||
];
|
||||
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
|
||||
value: { "one": 255 },
|
||||
size: 1
|
||||
});
|
||||
});
|
||||
it('Reads a signed 8 bit number', function() {
|
||||
var buf = new Buffer([0xff]);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 8, "signed": true }
|
||||
];
|
||||
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
|
||||
value: { "one": -1 },
|
||||
size: 1
|
||||
});
|
||||
});
|
||||
it('Reads multiple signed 8 bit numbers', function() {
|
||||
var buf = new Buffer([0xff, 0x80, 0x12]);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 8, "signed": true },
|
||||
{ "name": "two", "size": 8, "signed": true },
|
||||
{ "name": "three", "size": 8, "signed": true }
|
||||
];
|
||||
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
|
||||
value: { "one": -1, "two": -128, "three": 18 },
|
||||
size: 3
|
||||
});
|
||||
});
|
||||
it('Reads multiple unsigned 4 bit numbers', function() {
|
||||
var buf = new Buffer([0xff, 0x80]);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 4, "signed": false },
|
||||
{ "name": "two", "size": 4, "signed": false },
|
||||
{ "name": "three", "size": 4, "signed": false }
|
||||
];
|
||||
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
|
||||
value: { "one": 15, "two": 15, "three": 8 },
|
||||
size: 2
|
||||
});
|
||||
});
|
||||
it('Reads multiple signed 4 bit numbers', function() {
|
||||
var buf = new Buffer([0xff, 0x80]);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 4, "signed": true },
|
||||
{ "name": "two", "size": 4, "signed": true },
|
||||
{ "name": "three", "size": 4, "signed": true }
|
||||
];
|
||||
expect(getReader(utils.bitfield)(buf, 0, typeArgs, {})).to.deep.equal({
|
||||
value: { "one": -1, "two": -1, "three": -8 },
|
||||
size: 2
|
||||
});
|
||||
});
|
||||
it('Reads an unsigned 12 bit number', function() {
|
||||
var buf = new Buffer([0xff, 0x80]);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 12, "signed": false }
|
||||
];
|
||||
assert.deepEqual(getReader(utils.bitfield)(buf, 0, typeArgs, {}), {
|
||||
value: { "one": 4088 },
|
||||
size: 2
|
||||
});
|
||||
});
|
||||
it('Reads a complex structure', function() {
|
||||
var buf = new Buffer([0x00, 0x00, 0x03, 0x05, 0x30, 0x42, 0xE0, 0x65]);
|
||||
var typeArgs = [
|
||||
{ "name": "x", "size": 26, "signed": true },
|
||||
{ "name": "y", "size": 12, "signed": true },
|
||||
{ "name": "z", "size": 26, "signed": true }
|
||||
];
|
||||
var value = { x: 12, y: 332, z: 4382821 };
|
||||
assert.deepEqual(getReader(utils.bitfield)(buf, 0, typeArgs, {}), {
|
||||
value: value,
|
||||
size: 8
|
||||
});
|
||||
});
|
||||
it('Writes an unsigned 8 bit number', function() {
|
||||
var buf = new Buffer(1);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 8, "signed": false }
|
||||
];
|
||||
var value = { "one": 0xff };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 1);
|
||||
assert.deepEqual(buf, new Buffer([0xff]));
|
||||
});
|
||||
it('Writes a signed 8 bit number', function() {
|
||||
var buf = new Buffer(1);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 8, "signed": true }
|
||||
];
|
||||
var value = { "one": -1 };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 1);
|
||||
assert.deepEqual(buf, new Buffer([0xff]));
|
||||
});
|
||||
it('Writes multiple signed 8 bit numbers', function() {
|
||||
var buf = new Buffer(3);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 8, "signed": true },
|
||||
{ "name": "two", "size": 8, "signed": true },
|
||||
{ "name": "three", "size": 8, "signed": true }
|
||||
];
|
||||
var value = { "one": -1, "two": -128, "three": 18 };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 3);
|
||||
assert.deepEqual(buf, new Buffer([0xff, 0x80, 0x12]));
|
||||
});
|
||||
it('Writes multiple unsigned 4 bit numbers', function() {
|
||||
var buf = new Buffer(2);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 4, "signed": false },
|
||||
{ "name": "two", "size": 4, "signed": false },
|
||||
{ "name": "three", "size": 4, "signed": false }
|
||||
];
|
||||
var value = { "one": 15, "two": 15, "three": 8 };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 2);
|
||||
assert.deepEqual(buf, new Buffer([0xff, 0x80]));
|
||||
});
|
||||
it('Writes multiple signed 4 bit numbers', function() {
|
||||
var buf = new Buffer(2);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 4, "signed": true },
|
||||
{ "name": "two", "size": 4, "signed": true },
|
||||
{ "name": "three", "size": 4, "signed": true }
|
||||
];
|
||||
var value = { "one": -1, "two": -1, "three": -8 };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 2);
|
||||
assert.deepEqual(buf, new Buffer([0xff, 0x80]));
|
||||
});
|
||||
it('Writes an unsigned 12 bit number', function() {
|
||||
var buf = new Buffer(2);
|
||||
var typeArgs = [
|
||||
{ "name": "one", "size": 12, "signed": false }
|
||||
];
|
||||
var value = { "one": 4088 };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 2);
|
||||
assert.deepEqual(buf, new Buffer([0xff, 0x80]));
|
||||
});
|
||||
it('Writes a complex structure', function() {
|
||||
var buf = new Buffer(8);
|
||||
var typeArgs = [
|
||||
{ "name": "x", "size": 26, "signed": true },
|
||||
{ "name": "y", "size": 12, "signed": true },
|
||||
{ "name": "z", "size": 26, "signed": true }
|
||||
];
|
||||
var value = { x: 12, y: 332, z: 4382821 };
|
||||
assert.equal(getWriter(utils.bitfield)(value, buf, 0, typeArgs, {}), 8);
|
||||
assert.deepEqual(buf, new Buffer([0x00, 0x00, 0x03, 0x05, 0x30, 0x42, 0xE0, 0x65]));
|
||||
});
|
||||
});
|
||||
});
|
@ -107,8 +107,6 @@ mc.supportedVersions.forEach(function(supportedVersion){
|
||||
var mcData=require("minecraft-data")(supportedVersion);
|
||||
var version=mcData.version;
|
||||
var packets = mcData.protocol.states;
|
||||
var packetIndexes = mc.readPackets(packets, states);
|
||||
var packetFields = packetIndexes.packetFields;
|
||||
|
||||
describe("packets "+version.minecraftVersion, function() {
|
||||
var client, server, serverClient;
|
||||
@ -132,18 +130,18 @@ mc.supportedVersions.forEach(function(supportedVersion){
|
||||
client.end();
|
||||
});
|
||||
var packetName, packetInfo, field;
|
||||
for(state in packetFields) {
|
||||
if(!packetFields.hasOwnProperty(state)) continue;
|
||||
for(packetName in packetFields[state].toServer) {
|
||||
if(!packetFields[state].toServer.hasOwnProperty(packetName)) continue;
|
||||
packetInfo = packetFields[state]["toServer"][packetName];
|
||||
for(state in packets) {
|
||||
if(!packets.hasOwnProperty(state)) continue;
|
||||
for(packetName in packets[state].toServer) {
|
||||
if(!packets[state].toServer.hasOwnProperty(packetName)) continue;
|
||||
packetInfo = packets[state]["toServer"][packetName].fields;
|
||||
packetInfo=packetInfo ? packetInfo : null;
|
||||
it(state + ",ServerBound," + packetName,
|
||||
callTestPacket(packetName, packetInfo, state, true));
|
||||
}
|
||||
for(packetName in packetFields[state].toClient) {
|
||||
if(!packetFields[state].toClient.hasOwnProperty(packetName)) continue;
|
||||
packetInfo = packetFields[state]["toClient"][packetName];
|
||||
for(packetName in packets[state].toClient) {
|
||||
if(!packets[state].toClient.hasOwnProperty(packetName)) continue;
|
||||
packetInfo = packets[state]["toClient"][packetName].fields;
|
||||
packetInfo=packetInfo ? packetInfo : null;
|
||||
it(state + ",ClientBound," + packetName,
|
||||
callTestPacket(packetName, packetInfo, state, false));
|
||||
|
Loading…
x
Reference in New Issue
Block a user