mirror of
https://github.com/unmojang/node-minecraft-protocol.git
synced 2025-09-29 14:13:45 -04:00
Merge pull request #161 from rom1504/divide_protocol_js
Divide protocol js into several datatypes files
This commit is contained in:
commit
ec0f6860c6
@ -9,7 +9,7 @@ var sourcemaps = require('gulp-sourcemaps');
|
|||||||
|
|
||||||
gulp.task('compile', function() {
|
gulp.task('compile', function() {
|
||||||
gulp
|
gulp
|
||||||
.src('src/*.js')
|
.src('src/**/*.js')
|
||||||
.pipe(sourcemaps.init())
|
.pipe(sourcemaps.init())
|
||||||
.pipe(babel(options))
|
.pipe(babel(options))
|
||||||
.pipe(sourcemaps.write('maps/'))
|
.pipe(sourcemaps.write('maps/'))
|
||||||
@ -17,7 +17,7 @@ gulp.task('compile', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('watch', function() {
|
gulp.task('watch', function() {
|
||||||
gulp.watch('src/*.js', ['compile']);
|
gulp.watch('src/**/*.js', ['compile']);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('default', ['compile']);
|
gulp.task('default', ['compile']);
|
||||||
|
@ -5,13 +5,12 @@ var EventEmitter = require('events').EventEmitter
|
|||||||
, compressPacketBuffer = protocol.compressPacketBuffer
|
, compressPacketBuffer = protocol.compressPacketBuffer
|
||||||
, oldStylePacket = protocol.oldStylePacket
|
, oldStylePacket = protocol.oldStylePacket
|
||||||
, newStylePacket = protocol.newStylePacket
|
, newStylePacket = protocol.newStylePacket
|
||||||
, parsePacket = protocol.parsePacket
|
|
||||||
, parsePacketData = protocol.parsePacketData
|
, parsePacketData = protocol.parsePacketData
|
||||||
, parseNewStylePacket = protocol.parseNewStylePacket
|
, parseNewStylePacket = protocol.parseNewStylePacket
|
||||||
, packetIds = protocol.packetIds
|
, packetIds = protocol.packetIds
|
||||||
, packetNames = protocol.packetNames
|
, packetNames = protocol.packetNames
|
||||||
, states = protocol.states
|
, states = protocol.states
|
||||||
, debug = protocol.debug
|
, debug = require('./debug')
|
||||||
;
|
;
|
||||||
|
|
||||||
module.exports = Client;
|
module.exports = Client;
|
||||||
|
26
src/datatypes/conditional.js
Normal file
26
src/datatypes/conditional.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
var evalCondition= require("../utils").evalCondition;
|
||||||
|
|
||||||
|
module.exports= {
|
||||||
|
'condition': [readCondition, writeCondition, sizeOfCondition]
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeOfCondition(value, fieldInfo, rootNode) {
|
||||||
|
if(!evalCondition(fieldInfo,rootNode))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return this.sizeOf(value,fieldInfo, rootNode);
|
||||||
|
}
|
239
src/datatypes/minecraft.js
Normal file
239
src/datatypes/minecraft.js
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
var nbt = require('prismarine-nbt');
|
||||||
|
var utils = require("./utils");
|
||||||
|
var numeric = require("./numeric");
|
||||||
|
|
||||||
|
// TODO : remove type-specific, replace with generic containers and arrays.
|
||||||
|
module.exports = {
|
||||||
|
'UUID': [readUUID, writeUUID, 16],
|
||||||
|
'position': [readPosition, writePosition, 8],
|
||||||
|
'slot': [readSlot, writeSlot, sizeOfSlot],
|
||||||
|
'nbt': [readNbt, utils.buffer[1], utils.buffer[2]],
|
||||||
|
'restBuffer': [readRestBuffer, utils.buffer[1], utils.buffer[2]],
|
||||||
|
'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata]
|
||||||
|
};
|
||||||
|
|
||||||
|
function readUUID(buffer, offset) {
|
||||||
|
return {
|
||||||
|
value: [
|
||||||
|
buffer.readUInt32BE(offset),
|
||||||
|
buffer.readUInt32BE(offset + 4),
|
||||||
|
buffer.readUInt32BE(offset + 8),
|
||||||
|
buffer.readUInt32BE(offset + 12),
|
||||||
|
],
|
||||||
|
size: 16,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeUUID(value, buffer, offset) {
|
||||||
|
buffer.writeUInt32BE(value[0], offset);
|
||||||
|
buffer.writeUInt32BE(value[1], offset + 4);
|
||||||
|
buffer.writeUInt32BE(value[2], offset + 8);
|
||||||
|
buffer.writeUInt32BE(value[3], offset + 12);
|
||||||
|
return offset + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readPosition(buffer, offset) {
|
||||||
|
var longVal = numeric.long[0](buffer, offset).value;
|
||||||
|
var x = signExtend26(longVal[0] >> 6);
|
||||||
|
var y = signExtend12(((longVal[0] & 0x3f) << 6) | ((longVal[1] >> 26) & 0x3f));
|
||||||
|
var z = signExtend26(longVal[1] & 0x3FFFFFF);
|
||||||
|
return {
|
||||||
|
value: { x: x, y: y, z: z },
|
||||||
|
size: 8
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function signExtend26(value) {
|
||||||
|
if (value > 0x2000000) value -= 0x4000000;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
function signExtend12(value) {
|
||||||
|
if (value > 0x800) value -= 0x1000;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function writePosition(value, buffer, offset) {
|
||||||
|
var longVal = [];
|
||||||
|
longVal[0] = ((value.x & 0x3FFFFFF) << 6) | ((value.y & 0xFFF) >> 6);
|
||||||
|
longVal[1] = ((value.y & 0x3F) << 26) | (value.z & 0x3FFFFFF);
|
||||||
|
return numeric.long[1](longVal, buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readSlot(buffer, offset) {
|
||||||
|
var value = {};
|
||||||
|
var results = numeric.short[0](buffer, offset);
|
||||||
|
if (! results) return null;
|
||||||
|
value.blockId = results.value;
|
||||||
|
|
||||||
|
if (value.blockId === -1) {
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cursorEnd = offset + 6;
|
||||||
|
if (cursorEnd > buffer.length) return null;
|
||||||
|
value.itemCount = buffer.readInt8(offset + 2);
|
||||||
|
value.itemDamage = buffer.readInt16BE(offset + 3);
|
||||||
|
var nbtData = buffer.readInt8(offset + 5);
|
||||||
|
if (nbtData == 0) {
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var nbtData = readNbt(buffer, offset + 5);
|
||||||
|
value.nbtData = nbtData.value;
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: nbtData.size + 5
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeSlot(value, buffer, offset) {
|
||||||
|
buffer.writeInt16BE(value.blockId, offset);
|
||||||
|
if (value.blockId === -1) return offset + 2;
|
||||||
|
buffer.writeInt8(value.itemCount, offset + 2);
|
||||||
|
buffer.writeInt16BE(value.itemDamage, offset + 3);
|
||||||
|
var nbtDataLen;
|
||||||
|
if (value.nbtData)
|
||||||
|
{
|
||||||
|
var newbuf = nbt.writeUncompressed(value.nbtData);
|
||||||
|
newbuf.copy(buffer, offset + 5);
|
||||||
|
nbtDataLen = newbuf.length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer.writeInt8(0, offset + 5);
|
||||||
|
nbtDataLen = 1;
|
||||||
|
}
|
||||||
|
return offset + 5 + nbtDataLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeOfSlot(value) {
|
||||||
|
if (value.blockId === -1)
|
||||||
|
return (2);
|
||||||
|
else if (!value.nbtData) {
|
||||||
|
return (6);
|
||||||
|
} else {
|
||||||
|
return (5 + sizeOfNbt(value.nbtData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readNbt(buffer, offset) {
|
||||||
|
buffer = buffer.slice(offset);
|
||||||
|
return nbt.parseUncompressed(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeNbt(value, buffer, offset) {
|
||||||
|
var newbuf = nbt.writeUncompressed(value);
|
||||||
|
newbuf.copy(buffer, offset);
|
||||||
|
return offset + newbuf.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeOfNbt(value) {
|
||||||
|
return nbt.writeUncompressed(value).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readRestBuffer(buffer, offset, typeArgs, rootNode) {
|
||||||
|
return {
|
||||||
|
value: buffer.slice(offset),
|
||||||
|
size: buffer.length - offset
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var entityMetadataTypes = {
|
||||||
|
0: { type: 'byte' },
|
||||||
|
1: { type: 'short' },
|
||||||
|
2: { type: 'int' },
|
||||||
|
3: { type: 'float' },
|
||||||
|
4: { type: 'string' },
|
||||||
|
5: { type: 'slot' },
|
||||||
|
6: { type: 'container', typeArgs: { fields: [
|
||||||
|
{ name: 'x', type: 'int' },
|
||||||
|
{ name: 'y', type: 'int' },
|
||||||
|
{ name: 'z', type: 'int' }
|
||||||
|
]}},
|
||||||
|
7: { type: 'container', typeArgs: { fields: [
|
||||||
|
{ name: 'pitch', type: 'float' },
|
||||||
|
{ name: 'yaw', type: 'float' },
|
||||||
|
{ name: 'roll', type: 'float' }
|
||||||
|
]}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// maps string type name to number
|
||||||
|
var entityMetadataTypeBytes = {};
|
||||||
|
for (var n in entityMetadataTypes) {
|
||||||
|
if (!entityMetadataTypes.hasOwnProperty(n)) continue;
|
||||||
|
|
||||||
|
entityMetadataTypeBytes[entityMetadataTypes[n].type] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readEntityMetadata(buffer, offset) {
|
||||||
|
var cursor = offset;
|
||||||
|
var metadata = [];
|
||||||
|
var item, key, type, results, reader, typeName, dataType;
|
||||||
|
while (true) {
|
||||||
|
if (cursor + 1 > buffer.length) return null;
|
||||||
|
item = buffer.readUInt8(cursor);
|
||||||
|
cursor += 1;
|
||||||
|
if (item === 0x7f) {
|
||||||
|
return {
|
||||||
|
value: metadata,
|
||||||
|
size: cursor - offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
key = item & 0x1f;
|
||||||
|
type = item >> 5;
|
||||||
|
dataType = entityMetadataTypes[type];
|
||||||
|
typeName = dataType.type;
|
||||||
|
//debug("Reading entity metadata type " + dataType + " (" + ( typeName || "unknown" ) + ")");
|
||||||
|
if (!dataType) {
|
||||||
|
return {
|
||||||
|
error: new Error("unrecognized entity metadata type " + type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results = this.read(buffer, cursor, dataType, {});
|
||||||
|
if (! results) return null;
|
||||||
|
metadata.push({
|
||||||
|
key: key,
|
||||||
|
value: results.value,
|
||||||
|
type: typeName,
|
||||||
|
});
|
||||||
|
cursor += results.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function writeEntityMetadata(value, buffer, offset) {
|
||||||
|
var self=this;
|
||||||
|
value.forEach(function(item) {
|
||||||
|
var type = entityMetadataTypeBytes[item.type];
|
||||||
|
var headerByte = (type << 5) | item.key;
|
||||||
|
buffer.writeUInt8(headerByte, offset);
|
||||||
|
offset += 1;
|
||||||
|
offset = self.write(item.value, buffer, offset, entityMetadataTypes[type], {});
|
||||||
|
});
|
||||||
|
buffer.writeUInt8(0x7f, offset);
|
||||||
|
return offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function sizeOfEntityMetadata(value) {
|
||||||
|
var size = 1 + value.length;
|
||||||
|
var item;
|
||||||
|
for (var i = 0; i < value.length; ++i) {
|
||||||
|
item = value[i];
|
||||||
|
size += this.sizeOf(item.value, entityMetadataTypes[entityMetadataTypeBytes[item.type]], {});
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
127
src/datatypes/numeric.js
Normal file
127
src/datatypes/numeric.js
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
module.exports={
|
||||||
|
'byte': [readByte, writeByte, 1],
|
||||||
|
'ubyte': [readUByte, writeUByte, 1],
|
||||||
|
'short': [readShort, writeShort, 2],
|
||||||
|
'ushort': [readUShort, writeUShort, 2],
|
||||||
|
'int': [readInt, writeInt, 4],
|
||||||
|
'long': [readLong, writeLong, 8],
|
||||||
|
'float': [readFloat, writeFloat, 4],
|
||||||
|
'double': [readDouble, writeDouble, 8]
|
||||||
|
};
|
||||||
|
|
||||||
|
function readByte(buffer, offset) {
|
||||||
|
if (offset + 1 > buffer.length) return null;
|
||||||
|
var value = buffer.readInt8(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeByte(value, buffer, offset) {
|
||||||
|
buffer.writeInt8(value, offset);
|
||||||
|
return offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readUByte(buffer, offset) {
|
||||||
|
if (offset + 1 > buffer.length) return null;
|
||||||
|
var value = buffer.readUInt8(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeUByte(value, buffer, offset) {
|
||||||
|
buffer.writeUInt8(value, offset);
|
||||||
|
return offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readFloat(buffer, offset) {
|
||||||
|
if (offset + 4 > buffer.length) return null;
|
||||||
|
var value = buffer.readFloatBE(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 4,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeFloat(value, buffer, offset) {
|
||||||
|
buffer.writeFloatBE(value, offset);
|
||||||
|
return offset + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDouble(buffer, offset) {
|
||||||
|
if (offset + 8 > buffer.length) return null;
|
||||||
|
var value = buffer.readDoubleBE(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 8,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeDouble(value, buffer, offset) {
|
||||||
|
buffer.writeDoubleBE(value, offset);
|
||||||
|
return offset + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readShort(buffer, offset) {
|
||||||
|
if (offset + 2 > buffer.length) return null;
|
||||||
|
var value = buffer.readInt16BE(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function writeShort(value, buffer, offset) {
|
||||||
|
buffer.writeInt16BE(value, offset);
|
||||||
|
return offset + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readUShort(buffer, offset) {
|
||||||
|
if (offset + 2 > buffer.length) return null;
|
||||||
|
var value = buffer.readUInt16BE(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeUShort(value, buffer, offset) {
|
||||||
|
buffer.writeUInt16BE(value, offset);
|
||||||
|
return offset + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readInt(buffer, offset) {
|
||||||
|
if (offset + 4 > buffer.length) return null;
|
||||||
|
var value = buffer.readInt32BE(offset);
|
||||||
|
return {
|
||||||
|
value: value,
|
||||||
|
size: 4,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeInt(value, buffer, offset) {
|
||||||
|
buffer.writeInt32BE(value, offset);
|
||||||
|
return offset + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
114
src/datatypes/structures.js
Normal file
114
src/datatypes/structures.js
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
var getField= require("../utils").getField;
|
||||||
|
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
|
||||||
|
count = getField(typeArgs.count, rootNode);
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
var readResults = this.read(buffer, offset, { type: typeArgs.type, typeArgs: typeArgs.typeArgs }, rootNode);
|
||||||
|
results.size += readResults.size;
|
||||||
|
offset += readResults.size;
|
||||||
|
results.value.push(readResults.value);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeArray(value, buffer, offset, typeArgs, rootNode) {
|
||||||
|
for (var index in value) {
|
||||||
|
offset = this.write(value[index], buffer, offset, { type: typeArgs.type, typeArgs: typeArgs.typeArgs }, rootNode);
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeOfArray(value, typeArgs, rootNode) {
|
||||||
|
var size = 0;
|
||||||
|
for (var index in value) {
|
||||||
|
size += this.sizeOf(value[index], { type: typeArgs.type, typeArgs: typeArgs.typeArgs }, rootNode);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function readContainer(buffer, offset, typeArgs, rootNode) {
|
||||||
|
var results = {
|
||||||
|
value: {},
|
||||||
|
size: 0
|
||||||
|
};
|
||||||
|
// BLEIGH. Huge hack because I have no way of knowing my current name.
|
||||||
|
// TODO : either pass fieldInfo instead of typeArgs as argument (bleigh), or send name as argument (verybleigh).
|
||||||
|
// 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.
|
||||||
|
rootNode.this = results.value;
|
||||||
|
for (var index in typeArgs.fields) {
|
||||||
|
var readResults = this.read(buffer, offset, typeArgs.fields[index], rootNode);
|
||||||
|
if (readResults == null || readResults.value==null) { continue; }
|
||||||
|
results.size += readResults.size;
|
||||||
|
offset += readResults.size;
|
||||||
|
results.value[typeArgs.fields[index].name] = readResults.value;
|
||||||
|
}
|
||||||
|
delete rootNode.this;
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeContainer(value, buffer, offset, typeArgs, rootNode) {
|
||||||
|
var context = value.this ? value.this : value;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
delete rootNode.this;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeOfContainer(value, typeArgs, rootNode) {
|
||||||
|
var size = 0;
|
||||||
|
var context = value.this ? value.this : value;
|
||||||
|
rootNode.this = value;
|
||||||
|
for (var index in typeArgs.fields) {
|
||||||
|
size += this.sizeOf(context[typeArgs.fields[index].name], typeArgs.fields[index], rootNode);
|
||||||
|
}
|
||||||
|
delete rootNode.this;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCount(buffer, offset, typeArgs, rootNode) {
|
||||||
|
return this.read(buffer, offset, { type: 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
125
src/datatypes/utils.js
Normal file
125
src/datatypes/utils.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
var STRING_MAX_LENGTH = 240;
|
||||||
|
var SRV_STRING_MAX_LENGTH = 32767;
|
||||||
|
var getField= require("../utils").getField;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
'varint': [readVarInt, writeVarInt, sizeOfVarInt],
|
||||||
|
'bool': [readBool, writeBool, 1],
|
||||||
|
'string': [readString, writeString, sizeOfString],
|
||||||
|
'ustring': [readString, writeString, sizeOfUString], // TODO : remove ustring
|
||||||
|
'buffer': [readBuffer, writeBuffer, sizeOfBuffer]
|
||||||
|
};
|
||||||
|
|
||||||
|
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');
|
||||||
|
assert.ok(length < STRING_MAX_LENGTH, "string greater than max length");
|
||||||
|
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 count = getField(typeArgs.count, rootNode);
|
||||||
|
return {
|
||||||
|
value: buffer.slice(offset, offset + count),
|
||||||
|
size: count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeBuffer(value, buffer, offset) {
|
||||||
|
value.copy(buffer, offset);
|
||||||
|
return offset + value.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sizeOfBuffer(value) {
|
||||||
|
return value.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sizeOfUString(value) {
|
||||||
|
var length = Buffer.byteLength(value, 'utf8');
|
||||||
|
assert.ok(length < SRV_STRING_MAX_LENGTH, "string greater than max length");
|
||||||
|
return sizeOfVarInt(length) + length;
|
||||||
|
}
|
17
src/debug.js
Normal file
17
src/debug.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
var util = require('util')
|
||||||
|
|
||||||
|
var debug;
|
||||||
|
if (process.env.NODE_DEBUG && /(minecraft-protocol|mc-proto)/.test(process.env.NODE_DEBUG)) {
|
||||||
|
var pid = process.pid;
|
||||||
|
debug = function(x) {
|
||||||
|
// if console is not set up yet, then skip this.
|
||||||
|
if (!console.error)
|
||||||
|
return;
|
||||||
|
console.error('MC-PROTO: %d', pid,
|
||||||
|
util.format.apply(util, arguments).slice(0, 500));
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
debug = function() { };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = debug;
|
@ -1,9 +1,6 @@
|
|||||||
var EventEmitter = require('events').EventEmitter
|
var assert = require('assert')
|
||||||
, util = require('util')
|
|
||||||
, assert = require('assert')
|
|
||||||
, crypto = require('crypto')
|
, crypto = require('crypto')
|
||||||
, bufferEqual = require('buffer-equal')
|
, bufferEqual = require('buffer-equal')
|
||||||
, superagent = require('superagent')
|
|
||||||
, protocol = require('./protocol')
|
, protocol = require('./protocol')
|
||||||
, Client = require('./client')
|
, Client = require('./client')
|
||||||
, dns = require('dns')
|
, dns = require('dns')
|
||||||
@ -14,7 +11,7 @@ var EventEmitter = require('events').EventEmitter
|
|||||||
, validateSession = Yggdrasil.validateSession
|
, validateSession = Yggdrasil.validateSession
|
||||||
, joinServer = Yggdrasil.joinServer
|
, joinServer = Yggdrasil.joinServer
|
||||||
, states = protocol.states
|
, states = protocol.states
|
||||||
, debug = protocol.debug
|
, debug = require("./debug")
|
||||||
;
|
;
|
||||||
var ursa;
|
var ursa;
|
||||||
try {
|
try {
|
||||||
|
44
src/packets.js
Normal file
44
src/packets.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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(id), '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][id] = fields;
|
||||||
|
packetStates[direction][name] = state;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
packetFields:packetFields,
|
||||||
|
packetNames:packetNames,
|
||||||
|
packetIds:packetIds,
|
||||||
|
packetStates:packetStates
|
||||||
|
};
|
||||||
|
}
|
771
src/protocol.js
771
src/protocol.js
@ -1,10 +1,10 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var util = require('util');
|
|
||||||
var zlib = require('zlib');
|
var zlib = require('zlib');
|
||||||
var nbt = require('prismarine-nbt');
|
|
||||||
|
|
||||||
var STRING_MAX_LENGTH = 240;
|
var evalCondition = require("./utils").evalCondition;
|
||||||
var SRV_STRING_MAX_LENGTH = 32767;
|
var readPackets = require("./packets").readPackets;
|
||||||
|
var debug = require("./debug");
|
||||||
|
|
||||||
|
|
||||||
// This is really just for the client.
|
// This is really just for the client.
|
||||||
var states = {
|
var states = {
|
||||||
@ -12,702 +12,83 @@ var states = {
|
|||||||
"STATUS": "status",
|
"STATUS": "status",
|
||||||
"LOGIN": "login",
|
"LOGIN": "login",
|
||||||
"PLAY": "play"
|
"PLAY": "play"
|
||||||
}
|
};
|
||||||
|
|
||||||
var packets=require("../protocol/protocol");
|
var packets=require("../protocol/protocol");
|
||||||
|
var packetIndexes=readPackets(packets,states);
|
||||||
|
|
||||||
var packetFields = {};
|
var packetFields = packetIndexes.packetFields;
|
||||||
var packetNames = {};
|
var packetNames = packetIndexes.packetNames;
|
||||||
var packetIds = {};
|
var packetIds = packetIndexes.packetIds;
|
||||||
var packetStates = {toClient: {}, toServer: {}};
|
var packetStates = packetIndexes.packetStates;
|
||||||
(function() {
|
|
||||||
for (var stateName in states) {
|
|
||||||
var state = states[stateName];
|
|
||||||
|
|
||||||
packetFields[state] = {toClient: [], toServer: []};
|
function NMProtocols()
|
||||||
packetNames[state] = {toClient: [], toServer: []};
|
{
|
||||||
packetIds[state] = {toClient: [], toServer: []};
|
this.types={};
|
||||||
|
}
|
||||||
|
|
||||||
['toClient', 'toServer'].forEach(function(direction) {
|
NMProtocols.prototype.addType = function(name,functions)
|
||||||
for (var name in packets[state][direction]) {
|
{
|
||||||
var info = packets[state][direction][name];
|
this.types[name]=functions;
|
||||||
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(id), '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][id] = fields;
|
|
||||||
packetStates[direction][name] = state;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var types = {
|
|
||||||
'byte': [readByte, writeByte, 1],
|
|
||||||
'ubyte': [readUByte, writeUByte, 1],
|
|
||||||
'short': [readShort, writeShort, 2],
|
|
||||||
'ushort': [readUShort, writeUShort, 2],
|
|
||||||
'int': [readInt, writeInt, 4],
|
|
||||||
'long': [readLong, writeLong, 8],
|
|
||||||
'varint': [readVarInt, writeVarInt, sizeOfVarInt],
|
|
||||||
'float': [readFloat, writeFloat, 4],
|
|
||||||
'double': [readDouble, writeDouble, 8],
|
|
||||||
'bool': [readBool, writeBool, 1],
|
|
||||||
'string': [readString, writeString, sizeOfString],
|
|
||||||
'ustring': [readString, writeString, sizeOfUString], // TODO : remove ustring
|
|
||||||
'UUID': [readUUID, writeUUID, 16],
|
|
||||||
'container': [readContainer, writeContainer, sizeOfContainer],
|
|
||||||
'array': [readArray, writeArray, sizeOfArray],
|
|
||||||
'buffer': [readBuffer, writeBuffer, sizeOfBuffer],
|
|
||||||
'restBuffer': [readRestBuffer, writeBuffer, sizeOfBuffer],
|
|
||||||
'count': [readCount, writeCount, sizeOfCount],
|
|
||||||
// TODO : remove type-specific, replace with generic containers and arrays.
|
|
||||||
'position': [readPosition, writePosition, 8],
|
|
||||||
'slot': [readSlot, writeSlot, sizeOfSlot],
|
|
||||||
'nbt': [readNbt, writeBuffer, sizeOfBuffer],
|
|
||||||
'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata],
|
|
||||||
'condition': [readCondition, writeCondition, sizeOfCondition]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var debug;
|
NMProtocols.prototype.addTypes = function(types)
|
||||||
if (process.env.NODE_DEBUG && /(minecraft-protocol|mc-proto)/.test(process.env.NODE_DEBUG)) {
|
{
|
||||||
var pid = process.pid;
|
var self=this;
|
||||||
debug = function(x) {
|
Object.keys(types).forEach(function(name){
|
||||||
// if console is not set up yet, then skip this.
|
self.addType(name,types[name]);
|
||||||
if (!console.error)
|
});
|
||||||
return;
|
|
||||||
console.error('MC-PROTO: %d', pid,
|
|
||||||
util.format.apply(util, arguments).slice(0, 500));
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
debug = function() { };
|
|
||||||
}
|
|
||||||
|
|
||||||
var entityMetadataTypes = {
|
|
||||||
0: { type: 'byte' },
|
|
||||||
1: { type: 'short' },
|
|
||||||
2: { type: 'int' },
|
|
||||||
3: { type: 'float' },
|
|
||||||
4: { type: 'string' },
|
|
||||||
5: { type: 'slot' },
|
|
||||||
6: { type: 'container', typeArgs: { fields: [
|
|
||||||
{ name: 'x', type: 'int' },
|
|
||||||
{ name: 'y', type: 'int' },
|
|
||||||
{ name: 'z', type: 'int' }
|
|
||||||
]}},
|
|
||||||
7: { type: 'container', typeArgs: { fields: [
|
|
||||||
{ name: 'pitch', type: 'float' },
|
|
||||||
{ name: 'yaw', type: 'float' },
|
|
||||||
{ name: 'roll', type: 'float' }
|
|
||||||
]}}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// maps string type name to number
|
NMProtocols.prototype.read = function(buffer, cursor, fieldInfo, rootNodes) {
|
||||||
var entityMetadataTypeBytes = {};
|
var type = this.types[fieldInfo.type];
|
||||||
for (var n in entityMetadataTypes) {
|
|
||||||
if (!entityMetadataTypes.hasOwnProperty(n)) continue;
|
|
||||||
|
|
||||||
entityMetadataTypeBytes[entityMetadataTypes[n].type] = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readCondition(buffer,offset,typeArgs, rootNode)
|
|
||||||
{
|
|
||||||
if(!evalCondition(typeArgs,rootNode))
|
|
||||||
return { value: null, size: 0 };
|
|
||||||
return read(buffer, offset, { type: typeArgs.type, typeArgs:typeArgs.typeArgs }, rootNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeCondition(value, buffer, offset, typeArgs, rootNode) {
|
|
||||||
if(!evalCondition(typeArgs,rootNode))
|
|
||||||
return offset;
|
|
||||||
|
|
||||||
return write(value, buffer, offset, { type: typeArgs.type, typeArgs:typeArgs.typeArgs }, rootNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfCondition(value, fieldInfo, rootNode) {
|
|
||||||
if(!evalCondition(fieldInfo,rootNode))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return sizeOf(value,fieldInfo, rootNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function evalCondition(condition,field_values)
|
|
||||||
{
|
|
||||||
var field_value_to_test="this" in condition && condition["this"] ? field_values["this"][condition.field] : field_values[condition.field];
|
|
||||||
var b=condition.values.some(function(value) {return field_value_to_test===value;});
|
|
||||||
if("different" in condition && condition["different"])
|
|
||||||
return !b;
|
|
||||||
else
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfEntityMetadata(value) {
|
|
||||||
var size = 1 + value.length;
|
|
||||||
var item;
|
|
||||||
for (var i = 0; i < value.length; ++i) {
|
|
||||||
item = value[i];
|
|
||||||
size += sizeOf(item.value, entityMetadataTypes[entityMetadataTypeBytes[item.type]], {});
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeEntityMetadata(value, buffer, offset) {
|
|
||||||
value.forEach(function(item) {
|
|
||||||
var type = entityMetadataTypeBytes[item.type];
|
|
||||||
var headerByte = (type << 5) | item.key;
|
|
||||||
buffer.writeUInt8(headerByte, offset);
|
|
||||||
offset += 1;
|
|
||||||
offset = write(item.value, buffer, offset, entityMetadataTypes[type], {});
|
|
||||||
});
|
|
||||||
buffer.writeUInt8(0x7f, offset);
|
|
||||||
return offset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUUID(value, buffer, offset) {
|
|
||||||
buffer.writeUInt32BE(value[0], offset);
|
|
||||||
buffer.writeUInt32BE(value[1], offset + 4);
|
|
||||||
buffer.writeUInt32BE(value[2], offset + 8);
|
|
||||||
buffer.writeUInt32BE(value[3], offset + 12);
|
|
||||||
return offset + 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readEntityMetadata(buffer, offset) {
|
|
||||||
var cursor = offset;
|
|
||||||
var metadata = [];
|
|
||||||
var item, key, type, results, reader, typeName, dataType;
|
|
||||||
while (true) {
|
|
||||||
if (cursor + 1 > buffer.length) return null;
|
|
||||||
item = buffer.readUInt8(cursor);
|
|
||||||
cursor += 1;
|
|
||||||
if (item === 0x7f) {
|
|
||||||
return {
|
|
||||||
value: metadata,
|
|
||||||
size: cursor - offset,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
key = item & 0x1f;
|
|
||||||
type = item >> 5;
|
|
||||||
dataType = entityMetadataTypes[type];
|
|
||||||
typeName = dataType.type;
|
|
||||||
//debug("Reading entity metadata type " + dataType + " (" + ( typeName || "unknown" ) + ")");
|
|
||||||
if (!dataType) {
|
|
||||||
return {
|
|
||||||
error: new Error("unrecognized entity metadata type " + type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
results = read(buffer, cursor, dataType, {});
|
|
||||||
if (! results) return null;
|
|
||||||
metadata.push({
|
|
||||||
key: key,
|
|
||||||
value: results.value,
|
|
||||||
type: typeName,
|
|
||||||
});
|
|
||||||
cursor += results.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readNbt(buffer, offset) {
|
|
||||||
buffer = buffer.slice(offset);
|
|
||||||
return nbt.parseUncompressed(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeNbt(value, buffer, offset) {
|
|
||||||
var newbuf = nbt.writeUncompressed(value);
|
|
||||||
newbuf.copy(buffer, offset);
|
|
||||||
return offset + newbuf.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfNbt(value) {
|
|
||||||
return nbt.writeUncompressed(value).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 readUUID(buffer, offset) {
|
|
||||||
return {
|
|
||||||
value: [
|
|
||||||
buffer.readUInt32BE(offset),
|
|
||||||
buffer.readUInt32BE(offset + 4),
|
|
||||||
buffer.readUInt32BE(offset + 8),
|
|
||||||
buffer.readUInt32BE(offset + 12),
|
|
||||||
],
|
|
||||||
size: 16,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readShort(buffer, offset) {
|
|
||||||
if (offset + 2 > buffer.length) return null;
|
|
||||||
var value = buffer.readInt16BE(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 2,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUShort(buffer, offset) {
|
|
||||||
if (offset + 2 > buffer.length) return null;
|
|
||||||
var value = buffer.readUInt16BE(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 2,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readInt(buffer, offset) {
|
|
||||||
if (offset + 4 > buffer.length) return null;
|
|
||||||
var value = buffer.readInt32BE(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 4,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readFloat(buffer, offset) {
|
|
||||||
if (offset + 4 > buffer.length) return null;
|
|
||||||
var value = buffer.readFloatBE(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 4,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readDouble(buffer, offset) {
|
|
||||||
if (offset + 8 > buffer.length) return null;
|
|
||||||
var value = buffer.readDoubleBE(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 8,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readLong(buffer, offset) {
|
|
||||||
if (offset + 8 > buffer.length) return null;
|
|
||||||
return {
|
|
||||||
value: [buffer.readInt32BE(offset), buffer.readInt32BE(offset + 4)],
|
|
||||||
size: 8,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readByte(buffer, offset) {
|
|
||||||
if (offset + 1 > buffer.length) return null;
|
|
||||||
var value = buffer.readInt8(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readUByte(buffer, offset) {
|
|
||||||
if (offset + 1 > buffer.length) return null;
|
|
||||||
var value = buffer.readUInt8(offset);
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readBool(buffer, offset) {
|
|
||||||
if (offset + 1 > buffer.length) return null;
|
|
||||||
var value = buffer.readInt8(offset);
|
|
||||||
return {
|
|
||||||
value: !!value,
|
|
||||||
size: 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function readPosition(buffer, offset) {
|
|
||||||
var longVal = readLong(buffer, offset).value;
|
|
||||||
var x = signExtend26(longVal[0] >> 6);
|
|
||||||
var y = signExtend12(((longVal[0] & 0x3f) << 6) | ((longVal[1] >> 26) & 0x3f));
|
|
||||||
var z = signExtend26(longVal[1] & 0x3FFFFFF);
|
|
||||||
return {
|
|
||||||
value: { x: x, y: y, z: z },
|
|
||||||
size: 8
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function signExtend26(value) {
|
|
||||||
if (value > 0x2000000) value -= 0x4000000;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
function signExtend12(value) {
|
|
||||||
if (value > 0x800) value -= 0x1000;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readSlot(buffer, offset) {
|
|
||||||
var value = {};
|
|
||||||
var results = readShort(buffer, offset);
|
|
||||||
if (! results) return null;
|
|
||||||
value.blockId = results.value;
|
|
||||||
|
|
||||||
if (value.blockId === -1) {
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 2,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var cursorEnd = offset + 6;
|
|
||||||
if (cursorEnd > buffer.length) return null;
|
|
||||||
value.itemCount = buffer.readInt8(offset + 2);
|
|
||||||
value.itemDamage = buffer.readInt16BE(offset + 3);
|
|
||||||
var nbtData = buffer.readInt8(offset + 5);
|
|
||||||
if (nbtData == 0) {
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var nbtData = readNbt(buffer, offset + 5);
|
|
||||||
value.nbtData = nbtData.value;
|
|
||||||
return {
|
|
||||||
value: value,
|
|
||||||
size: nbtData.size + 5
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfSlot(value) {
|
|
||||||
if (value.blockId === -1)
|
|
||||||
return (2);
|
|
||||||
else if (!value.nbtData) {
|
|
||||||
return (6);
|
|
||||||
} else {
|
|
||||||
return (5 + sizeOfNbt(value.nbtData));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function writePosition(value, buffer, offset) {
|
|
||||||
var longVal = [];
|
|
||||||
longVal[0] = ((value.x & 0x3FFFFFF) << 6) | ((value.y & 0xFFF) >> 6);
|
|
||||||
longVal[1] = ((value.y & 0x3F) << 26) | (value.z & 0x3FFFFFF);
|
|
||||||
return writeLong(longVal, buffer, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeSlot(value, buffer, offset) {
|
|
||||||
buffer.writeInt16BE(value.blockId, offset);
|
|
||||||
if (value.blockId === -1) return offset + 2;
|
|
||||||
buffer.writeInt8(value.itemCount, offset + 2);
|
|
||||||
buffer.writeInt16BE(value.itemDamage, offset + 3);
|
|
||||||
var nbtDataLen;
|
|
||||||
if (value.nbtData)
|
|
||||||
{
|
|
||||||
var newbuf = nbt.writeUncompressed(value.nbtData);
|
|
||||||
newbuf.copy(buffer, offset + 5);
|
|
||||||
nbtDataLen = newbuf.length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer.writeInt8(0, offset + 5);
|
|
||||||
nbtDataLen = 1;
|
|
||||||
}
|
|
||||||
return offset + 5 + nbtDataLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfString(value) {
|
|
||||||
var length = Buffer.byteLength(value, 'utf8');
|
|
||||||
assert.ok(length < STRING_MAX_LENGTH, "string greater than max length");
|
|
||||||
return sizeOfVarInt(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfUString(value) {
|
|
||||||
var length = Buffer.byteLength(value, 'utf8');
|
|
||||||
assert.ok(length < SRV_STRING_MAX_LENGTH, "string greater than max length");
|
|
||||||
return sizeOfVarInt(length) + length;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 writeByte(value, buffer, offset) {
|
|
||||||
buffer.writeInt8(value, offset);
|
|
||||||
return offset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeBool(value, buffer, offset) {
|
|
||||||
buffer.writeInt8(+value, offset);
|
|
||||||
return offset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUByte(value, buffer, offset) {
|
|
||||||
buffer.writeUInt8(value, offset);
|
|
||||||
return offset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeFloat(value, buffer, offset) {
|
|
||||||
buffer.writeFloatBE(value, offset);
|
|
||||||
return offset + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeDouble(value, buffer, offset) {
|
|
||||||
buffer.writeDoubleBE(value, offset);
|
|
||||||
return offset + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeShort(value, buffer, offset) {
|
|
||||||
buffer.writeInt16BE(value, offset);
|
|
||||||
return offset + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeUShort(value, buffer, offset) {
|
|
||||||
buffer.writeUInt16BE(value, offset);
|
|
||||||
return offset + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeInt(value, buffer, offset) {
|
|
||||||
buffer.writeInt32BE(value, offset);
|
|
||||||
return offset + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeLong(value, buffer, offset) {
|
|
||||||
buffer.writeInt32BE(value[0], offset);
|
|
||||||
buffer.writeInt32BE(value[1], offset + 4);
|
|
||||||
return offset + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 readContainer(buffer, offset, typeArgs, rootNode) {
|
|
||||||
var results = {
|
|
||||||
value: {},
|
|
||||||
size: 0
|
|
||||||
};
|
|
||||||
// BLEIGH. Huge hack because I have no way of knowing my current name.
|
|
||||||
// TODO : either pass fieldInfo instead of typeArgs as argument (bleigh), or send name as argument (verybleigh).
|
|
||||||
// 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.
|
|
||||||
rootNode.this = results.value;
|
|
||||||
for (var index in typeArgs.fields) {
|
|
||||||
var readResults = read(buffer, offset, typeArgs.fields[index], rootNode);
|
|
||||||
if (readResults == null || readResults.value==null) { continue; }
|
|
||||||
results.size += readResults.size;
|
|
||||||
offset += readResults.size;
|
|
||||||
results.value[typeArgs.fields[index].name] = readResults.value;
|
|
||||||
}
|
|
||||||
delete rootNode.this;
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeContainer(value, buffer, offset, typeArgs, rootNode) {
|
|
||||||
var context = value.this ? value.this : value;
|
|
||||||
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 = write(context[typeArgs.fields[index].name], buffer, offset, typeArgs.fields[index], rootNode);
|
|
||||||
}
|
|
||||||
delete rootNode.this;
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfContainer(value, typeArgs, rootNode) {
|
|
||||||
var size = 0;
|
|
||||||
var context = value.this ? value.this : value;
|
|
||||||
rootNode.this = value;
|
|
||||||
for (var index in typeArgs.fields) {
|
|
||||||
size += sizeOf(context[typeArgs.fields[index].name], typeArgs.fields[index], rootNode);
|
|
||||||
}
|
|
||||||
delete rootNode.this;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readBuffer(buffer, offset, typeArgs, rootNode) {
|
|
||||||
var count = getField(typeArgs.count, rootNode);
|
|
||||||
return {
|
|
||||||
value: buffer.slice(offset, offset + count),
|
|
||||||
size: count
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeBuffer(value, buffer, offset) {
|
|
||||||
value.copy(buffer, offset);
|
|
||||||
return offset + value.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfBuffer(value) {
|
|
||||||
return value.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readRestBuffer(buffer, offset, typeArgs, rootNode) {
|
|
||||||
return {
|
|
||||||
value: buffer.slice(offset),
|
|
||||||
size: buffer.length - offset
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
count = getField(typeArgs.count, rootNode);
|
|
||||||
for (var i = 0; i < count; i++) {
|
|
||||||
var readResults = read(buffer, offset, { type: typeArgs.type, typeArgs: typeArgs.typeArgs }, rootNode);
|
|
||||||
results.size += readResults.size;
|
|
||||||
offset += readResults.size;
|
|
||||||
results.value.push(readResults.value);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeArray(value, buffer, offset, typeArgs, rootNode) {
|
|
||||||
for (var index in value) {
|
|
||||||
offset = write(value[index], buffer, offset, { type: typeArgs.type, typeArgs: typeArgs.typeArgs }, rootNode);
|
|
||||||
}
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfArray(value, typeArgs, rootNode) {
|
|
||||||
var size = 0;
|
|
||||||
for (var index in value) {
|
|
||||||
size += sizeOf(value[index], { type: typeArgs.type, typeArgs: typeArgs.typeArgs }, rootNode);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getField(countField, rootNode) {
|
|
||||||
var countFieldArr = countField.split(".");
|
|
||||||
var count = rootNode;
|
|
||||||
for (var index = 0; index < countFieldArr.length; index++) {
|
|
||||||
count = count[countFieldArr[index]];
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readCount(buffer, offset, typeArgs, rootNode) {
|
|
||||||
return read(buffer, offset, { type: 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 write(getField(typeArgs.countFor, rootNode).length, buffer, offset, { type: typeArgs.type }, rootNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sizeOfCount(value, typeArgs, rootNode) {
|
|
||||||
// TODO : should I use value or getField().length ?
|
|
||||||
return sizeOf(getField(typeArgs.countFor, rootNode).length, { type: typeArgs.type }, rootNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function read(buffer, cursor, fieldInfo, rootNodes) {
|
|
||||||
var type = types[fieldInfo.type];
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return {
|
return {
|
||||||
error: new Error("missing data type: " + fieldInfo.type)
|
error: new Error("missing data type: " + fieldInfo.type)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var readResults = type[0](buffer, cursor, fieldInfo.typeArgs, rootNodes);
|
var readResults = type[0].call(this,buffer, cursor, fieldInfo.typeArgs, rootNodes);
|
||||||
if (readResults == null) {
|
if (readResults == null) {
|
||||||
throw new Error("Reader returned null : " + JSON.stringify(fieldInfo));
|
throw new Error("Reader returned null : " + JSON.stringify(fieldInfo));
|
||||||
}
|
}
|
||||||
if (readResults && readResults.error) return { error: readResults.error };
|
if (readResults && readResults.error) return { error: readResults.error };
|
||||||
return readResults;
|
return readResults;
|
||||||
}
|
};
|
||||||
|
|
||||||
function write(value, buffer, offset, fieldInfo, rootNode) {
|
NMProtocols.prototype.write = function(value, buffer, offset, fieldInfo, rootNode) {
|
||||||
var type = types[fieldInfo.type];
|
var type = this.types[fieldInfo.type];
|
||||||
if (!type) {
|
if (!type) {
|
||||||
return {
|
return {
|
||||||
error: new Error("missing data type: " + fieldInfo.type)
|
error: new Error("missing data type: " + fieldInfo.type)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return type[1](value, buffer, offset, fieldInfo.typeArgs, rootNode);
|
return type[1].call(this,value, buffer, offset, fieldInfo.typeArgs, rootNode);
|
||||||
}
|
};
|
||||||
|
|
||||||
function sizeOf(value, fieldInfo, rootNode) {
|
NMProtocols.prototype.sizeOf = function(value, fieldInfo, rootNode) {
|
||||||
var type = types[fieldInfo.type];
|
var type = this.types[fieldInfo.type];
|
||||||
if (!type) {
|
if (!type) {
|
||||||
throw new Error("missing data type: " + fieldInfo.type);
|
throw new Error("missing data type: " + fieldInfo.type);
|
||||||
}
|
}
|
||||||
if (typeof type[2] === 'function') {
|
if (typeof type[2] === 'function') {
|
||||||
return type[2](value, fieldInfo.typeArgs, rootNode);
|
return type[2].call(this,value, fieldInfo.typeArgs, rootNode);
|
||||||
} else {
|
} else {
|
||||||
return type[2];
|
return type[2];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var numeric=require("./datatypes/numeric");
|
||||||
|
var utils=require("./datatypes/utils");
|
||||||
|
var minecraft=require("./datatypes/minecraft");
|
||||||
|
var structures=require("./datatypes/structures");
|
||||||
|
var conditional=require("./datatypes/conditional");
|
||||||
|
|
||||||
|
var proto=new NMProtocols();
|
||||||
|
proto.addTypes(numeric);
|
||||||
|
proto.addTypes(utils);
|
||||||
|
proto.addTypes(minecraft);
|
||||||
|
proto.addTypes(structures);
|
||||||
|
proto.addTypes(conditional);
|
||||||
|
|
||||||
function get(packetId, state, toServer) {
|
function get(packetId, state, toServer) {
|
||||||
var direction = toServer ? "toServer" : "toClient";
|
var direction = toServer ? "toServer" : "toClient";
|
||||||
@ -733,24 +114,24 @@ function createPacketBuffer(packetId, state, params, isServer) {
|
|||||||
assert.notEqual(packet, null);
|
assert.notEqual(packet, null);
|
||||||
packet.forEach(function(fieldInfo) {
|
packet.forEach(function(fieldInfo) {
|
||||||
try {
|
try {
|
||||||
length += sizeOf(params[fieldInfo.name], fieldInfo, params);
|
length += proto.sizeOf(params[fieldInfo.name], fieldInfo, params);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("fieldInfo : " + JSON.stringify(fieldInfo));
|
console.log("fieldInfo : " + JSON.stringify(fieldInfo));
|
||||||
console.log("params : " + JSON.stringify(params));
|
console.log("params : " + JSON.stringify(params));
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
length += sizeOfVarInt(packetId);
|
length += utils.varint[2](packetId);
|
||||||
var size = length;// + sizeOfVarInt(length);
|
var size = length;// + utils.varint[2](length);
|
||||||
var buffer = new Buffer(size);
|
var buffer = new Buffer(size);
|
||||||
var offset = 0;//writeVarInt(length, buffer, 0);
|
var offset = 0;//utils.varint[1](length, buffer, 0);
|
||||||
offset = writeVarInt(packetId, buffer, offset);
|
offset = utils.varint[1](packetId, buffer, offset);
|
||||||
packet.forEach(function(fieldInfo) {
|
packet.forEach(function(fieldInfo) {
|
||||||
var value = params[fieldInfo.name];
|
var value = params[fieldInfo.name];
|
||||||
// TODO : A better check is probably needed
|
// TODO : A better check is probably needed
|
||||||
if(typeof value === "undefined" && fieldInfo.type != "count" && (fieldInfo.type !="condition" || evalCondition(fieldInfo.typeArgs,params)))
|
if(typeof value === "undefined" && fieldInfo.type != "count" && (fieldInfo.type !="condition" || evalCondition(fieldInfo.typeArgs,params)))
|
||||||
debug(new Error("Missing Property " + fieldInfo.name).stack);
|
debug(new Error("Missing Property " + fieldInfo.name).stack);
|
||||||
offset = write(value, buffer, offset, fieldInfo, params);
|
offset = proto.write(value, buffer, offset, fieldInfo, params);
|
||||||
});
|
});
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -766,26 +147,26 @@ function compressPacketBuffer(buffer, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function oldStylePacket(buffer, callback) {
|
function oldStylePacket(buffer, callback) {
|
||||||
var packet = new Buffer(sizeOfVarInt(buffer.length) + buffer.length);
|
var packet = new Buffer(utils.varint[2](buffer.length) + buffer.length);
|
||||||
var cursor = writeVarInt(buffer.length, packet, 0);
|
var cursor = utils.varint[1](buffer.length, packet, 0);
|
||||||
writeBuffer(buffer, packet, cursor);
|
utils.buffer[1](buffer, packet, cursor);
|
||||||
callback(null, packet);
|
callback(null, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
function newStylePacket(buffer, callback) {
|
function newStylePacket(buffer, callback) {
|
||||||
var sizeOfDataLength = sizeOfVarInt(0);
|
var sizeOfDataLength = utils.varint[2](0);
|
||||||
var sizeOfLength = sizeOfVarInt(buffer.length + sizeOfDataLength);
|
var sizeOfLength = utils.varint[2](buffer.length + sizeOfDataLength);
|
||||||
var size = sizeOfLength + sizeOfDataLength + buffer.length;
|
var size = sizeOfLength + sizeOfDataLength + buffer.length;
|
||||||
var packet = new Buffer(size);
|
var packet = new Buffer(size);
|
||||||
var cursor = writeVarInt(size - sizeOfLength, packet, 0);
|
var cursor = utils.varint[1](size - sizeOfLength, packet, 0);
|
||||||
cursor = writeVarInt(0, packet, cursor);
|
cursor = utils.varint[1](0, packet, cursor);
|
||||||
writeBuffer(buffer, packet, cursor);
|
utils.buffer[1](buffer, packet, cursor);
|
||||||
callback(null, packet);
|
callback(null, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePacketData(buffer, state, isServer, packetsToParse) {
|
function parsePacketData(buffer, state, isServer, packetsToParse) {
|
||||||
var cursor = 0;
|
var cursor = 0;
|
||||||
var packetIdField = readVarInt(buffer, cursor);
|
var packetIdField = utils.varint[0](buffer, cursor);
|
||||||
var packetId = packetIdField.value;
|
var packetId = packetIdField.value;
|
||||||
cursor += packetIdField.size;
|
cursor += packetIdField.size;
|
||||||
|
|
||||||
@ -816,8 +197,8 @@ function parsePacketData(buffer, state, isServer, packetsToParse) {
|
|||||||
var i, fieldInfo, readResults;
|
var i, fieldInfo, readResults;
|
||||||
for (i = 0; i < packetInfo.length; ++i) {
|
for (i = 0; i < packetInfo.length; ++i) {
|
||||||
fieldInfo = packetInfo[i];
|
fieldInfo = packetInfo[i];
|
||||||
readResults = read(buffer, cursor, fieldInfo, results);
|
readResults = proto.read(buffer, cursor, fieldInfo, results);
|
||||||
/* A deserializer cannot return null anymore. Besides, read() returns
|
/* A deserializer cannot return null anymore. Besides, proto.read() returns
|
||||||
* null when the condition is not fulfilled.
|
* null when the condition is not fulfilled.
|
||||||
if (!!!readResults) {
|
if (!!!readResults) {
|
||||||
var error = new Error("A deserializer returned null");
|
var error = new Error("A deserializer returned null");
|
||||||
@ -845,21 +226,8 @@ function parsePacketData(buffer, state, isServer, packetsToParse) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePacket(buffer, state, isServer, packetsToParse) {
|
|
||||||
if (state == null) state = states.PLAY;
|
|
||||||
var cursor = 0;
|
|
||||||
var lengthField = readVarInt(buffer, 0);
|
|
||||||
if (!!!lengthField) return null;
|
|
||||||
var length = lengthField.value;
|
|
||||||
cursor += lengthField.size;
|
|
||||||
if (length + lengthField.size > buffer.length) return null; // fail early
|
|
||||||
var result = parsePacketData(buffer.slice(cursor, length + cursor), state, isServer, packetsToParse);
|
|
||||||
result.size = lengthField.size + length;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseNewStylePacket(buffer, state, isServer, packetsToParse, cb) {
|
function parseNewStylePacket(buffer, state, isServer, packetsToParse, cb) {
|
||||||
var dataLengthField = readVarInt(buffer, 0);
|
var dataLengthField = utils.varint[0](buffer, 0);
|
||||||
var buf = buffer.slice(dataLengthField.size);
|
var buf = buffer.slice(dataLengthField.size);
|
||||||
if(dataLengthField.value != 0) {
|
if(dataLengthField.value != 0) {
|
||||||
zlib.inflate(buf, function(err, newbuf) {
|
zlib.inflate(buf, function(err, newbuf) {
|
||||||
@ -879,21 +247,18 @@ module.exports = {
|
|||||||
version: 47,
|
version: 47,
|
||||||
minecraftVersion: '1.8.1',
|
minecraftVersion: '1.8.1',
|
||||||
sessionVersion: 13,
|
sessionVersion: 13,
|
||||||
parsePacket: parsePacket,
|
|
||||||
parsePacketData: parsePacketData,
|
parsePacketData: parsePacketData,
|
||||||
parseNewStylePacket: parseNewStylePacket,
|
parseNewStylePacket: parseNewStylePacket,
|
||||||
createPacketBuffer: createPacketBuffer,
|
createPacketBuffer: createPacketBuffer,
|
||||||
compressPacketBuffer: compressPacketBuffer,
|
compressPacketBuffer: compressPacketBuffer,
|
||||||
oldStylePacket: oldStylePacket,
|
oldStylePacket: oldStylePacket,
|
||||||
newStylePacket: newStylePacket,
|
newStylePacket: newStylePacket,
|
||||||
STRING_MAX_LENGTH: STRING_MAX_LENGTH,
|
|
||||||
packetIds: packetIds,
|
packetIds: packetIds,
|
||||||
packetNames: packetNames,
|
packetNames: packetNames,
|
||||||
packetFields: packetFields,
|
packetFields: packetFields,
|
||||||
packetStates: packetStates,
|
packetStates: packetStates,
|
||||||
types: types,
|
types: proto.types,
|
||||||
states: states,
|
states: states,
|
||||||
get: get,
|
get: get,
|
||||||
debug: debug,
|
|
||||||
evalCondition:evalCondition
|
evalCondition:evalCondition
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
var net = require('net')
|
var net = require('net')
|
||||||
, EventEmitter = require('events').EventEmitter
|
, EventEmitter = require('events').EventEmitter
|
||||||
, util = require('util')
|
, util = require('util')
|
||||||
, assert = require('assert')
|
|
||||||
, Client = require('./client')
|
, Client = require('./client')
|
||||||
, states = require('./protocol').states
|
, states = require('./protocol').states
|
||||||
;
|
;
|
||||||
|
24
src/utils.js
Normal file
24
src/utils.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports={
|
||||||
|
getField:getField,
|
||||||
|
evalCondition:evalCondition
|
||||||
|
};
|
||||||
|
|
||||||
|
function getField(countField, rootNode) {
|
||||||
|
var countFieldArr = countField.split(".");
|
||||||
|
var count = rootNode;
|
||||||
|
for (var index = 0; index < countFieldArr.length; index++) {
|
||||||
|
count = count[countFieldArr[index]];
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function evalCondition(condition,field_values)
|
||||||
|
{
|
||||||
|
var field_value_to_test="this" in condition && condition["this"] ? field_values["this"][condition.field] : field_values[condition.field];
|
||||||
|
var b=condition.values.some(function(value) {return field_value_to_test===value;});
|
||||||
|
if("different" in condition && condition["different"])
|
||||||
|
return !b;
|
||||||
|
else
|
||||||
|
return b;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user