Proper generic read/write/sizeOf functions

This commit is contained in:
roblabla 2014-04-01 15:43:57 +02:00
parent 7b9f170fb2
commit c0ba7f8127
2 changed files with 68 additions and 55 deletions

View File

@ -633,20 +633,21 @@ var packetStates = {toClient: {}, toServer: {}};
var types = { var types = {
'int': [readInt, writeInt, 4],
'short': [readShort, writeShort, 2],
'ushort': [readUShort, writeUShort, 2],
'byte': [readByte, writeByte, 1], 'byte': [readByte, writeByte, 1],
'ubyte': [readUByte, writeUByte, 1], 'ubyte': [readUByte, writeUByte, 1],
'string': [readString, writeString, sizeOfString], 'short': [readShort, writeShort, 2],
'ustring': [readString, writeString, sizeOfUString], 'ushort': [readUShort, writeUShort, 2],
'byteArray16': [readByteArray16, writeByteArray16, sizeOfByteArray16], 'int': [readInt, writeInt, 4],
'bool': [readBool, writeBool, 1],
'double': [readDouble, writeDouble, 8],
'float': [readFloat, writeFloat, 4],
'slot': [readSlot, writeSlot, sizeOfSlot],
'long': [readLong, writeLong, 8], 'long': [readLong, writeLong, 8],
'varint': [readVarInt, writeVarInt, sizeOfVarInt], '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
// TODO : remove type-specific, replace with generic containers and arrays.
'slot': [readSlot, writeSlot, sizeOfSlot],
'byteArray16': [readByteArray16, writeByteArray16, sizeOfByteArray16],
'ascii': [readAscii, writeAscii, sizeOfAscii], 'ascii': [readAscii, writeAscii, sizeOfAscii],
'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata], 'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata],
'byteArray32': [readByteArray32, writeByteArray32, sizeOfByteArray32], 'byteArray32': [readByteArray32, writeByteArray32, sizeOfByteArray32],
@ -728,7 +729,7 @@ function sizeOfEntityMetadata(value) {
var item; var item;
for (var i = 0; i < value.length; ++i) { for (var i = 0; i < value.length; ++i) {
item = value[i]; item = value[i];
size += sizeOf(item.type, item.value); size += sizeOf(item.value, { type: item.type }, {});
} }
return size; return size;
} }
@ -1599,6 +1600,50 @@ function writeMatchArray(value, buffer, offset) {
return offset; return offset;
} }
function read(buffer, cursor, fieldInfo, rootNodes) {
if (fieldInfo.condition && !fieldInfo.condition(rootNodes)) {
return null;
}
var type = types[fieldInfo.type];
if (!type) {
return {
error: new Error("missing data type: " + fieldInfo.type)
};
}
var readResults = type[0](buffer, cursor, fieldInfo.typeArgs, rootNodes);
if (readResults.error) return { error: readResults.error };
return readResults;
}
function write(value, buffer, offset, fieldInfo, rootNodes) {
if (fieldInfo.condition && !fieldInfo.condition(rootNodes)) {
return null;
}
var type = types[fieldInfo.type];
if (!type) {
return {
error: new Error("missing data type: " + fieldInfo.type)
};
}
return type[1](value, buffer, offset, fieldInfo.typeArgs);
}
function sizeOf(value, fieldInfo, rootNodes) {
if (fieldInfo.condition && !fieldInfo.condition(rootNodes)) {
return 0;
}
var type = types[fieldInfo.type];
if (!type) {
throw new Error("missing data type: " + fieldInfo.type);
}
if (typeof type[2] === 'function') {
return type[2](value, fieldInfo.typeArgs);
} else {
return type[2];
}
}
function get(packetId, state, toServer) { function get(packetId, state, toServer) {
var direction = toServer ? "toServer" : "toClient"; var direction = toServer ? "toServer" : "toClient";
var packetInfo = packetFields[state][direction][packetId]; var packetInfo = packetFields[state][direction][packetId];
@ -1608,17 +1653,6 @@ function get(packetId, state, toServer) {
return packetInfo; return packetInfo;
} }
function sizeOf(type, value) {
var dataType = types[type];
assert.ok(dataType, "unknown data type " + type);
var size = dataType[2];
if (typeof size === "function") {
return size(value);
} else {
return size;
}
}
function createPacketBuffer(packetId, state, params, isServer) { function createPacketBuffer(packetId, state, params, isServer) {
var length = 0; var length = 0;
if (typeof packetId === 'string' && typeof state !== 'string' && !params) { if (typeof packetId === 'string' && typeof state !== 'string' && !params) {
@ -1632,10 +1666,7 @@ function createPacketBuffer(packetId, state, params, isServer) {
var packet = get(packetId, state, !isServer); var packet = get(packetId, state, !isServer);
assert.notEqual(packet, null); assert.notEqual(packet, null);
packet.forEach(function(fieldInfo) { packet.forEach(function(fieldInfo) {
var condition = fieldInfo.condition; length += sizeOf(params[fieldInfo.name], fieldInfo, params);
if (typeof condition != "undefined" && !condition(params))
return;
length += sizeOf(fieldInfo.type, params[fieldInfo.name]);
}); });
length += sizeOfVarInt(packetId); length += sizeOfVarInt(packetId);
var size = length + sizeOfVarInt(length); var size = length + sizeOfVarInt(length);
@ -1643,32 +1674,14 @@ function createPacketBuffer(packetId, state, params, isServer) {
var offset = writeVarInt(length, buffer, 0); var offset = writeVarInt(length, buffer, 0);
offset = writeVarInt(packetId, buffer, offset); offset = writeVarInt(packetId, buffer, offset);
packet.forEach(function(fieldInfo) { packet.forEach(function(fieldInfo) {
var condition = fieldInfo.condition;
if (typeof condition != "undefined" && !condition(params))
return;
var write = types[fieldInfo.type][1];
var value = params[fieldInfo.name]; var value = params[fieldInfo.name];
if(typeof value === "undefined") value = 0; if(typeof value === "undefined") value = 0; // TODO : Why ?
offset = write(value, buffer, offset); offset = write(value, buffer, offset, fieldInfo, params);
}); });
return buffer; return buffer;
} }
function parsePacket(buffer, state, isServer) { function parsePacket(buffer, state, isServer) {
function readPacketField(fieldInfo) {
var read = types[fieldInfo.type][0];
if (!read) {
return {
error: new Error("missing reader for data type: " + fieldInfo.type)
}
}
var readResults = read(buffer, cursor);
if (! readResults) return null; // buffer needs to be more full
if (readResults.error) return { error: readResults.error };
return readResults;
}
if (state == null) state == states.PLAY; if (state == null) state == states.PLAY;
var cursor = 0; var cursor = 0;
var lengthField = readVarInt(buffer, 0); var lengthField = readVarInt(buffer, 0);
@ -1697,13 +1710,10 @@ function parsePacket(buffer, state, isServer) {
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];
var condition = fieldInfo.condition; readResults = read(buffer, cursor, fieldInfo, results);
if (typeof condition != "undefined" && !condition(results)) { /* A deserializer cannot return null anymore. Besides, read() returns
results[fieldInfo.name] = null; * null when the condition is not fulfilled.
continue; if (!!!readResults) {
}
readResults = readPacketField(fieldInfo);
if (!!!readResults) {
var error = new Error("A deserializer returned null"); var error = new Error("A deserializer returned null");
error.packetId = packetId; error.packetId = packetId;
error.fieldInfo = fieldInfo.name; error.fieldInfo = fieldInfo.name;
@ -1712,7 +1722,8 @@ function parsePacket(buffer, state, isServer) {
error: error, error: error,
results: results results: results
}; };
} }*/
if (readResults === null) continue;
if (readResults.error) { if (readResults.error) {
return readResults; return readResults;
} }

View File

@ -164,7 +164,9 @@ describe("packets", function() {
// empty object uses default values // empty object uses default values
var packet = {}; var packet = {};
packetInfo.forEach(function(field) { packetInfo.forEach(function(field) {
packet[field.name] = values[field.type]; if (!field.hasOwnProperty("condition") || field.condition(packet)) {
packet[field.name] = values[field.type];
}
}); });
if (toServer) { if (toServer) {
serverClient.once([state, packetId], function(receivedPacket) { serverClient.once([state, packetId], function(receivedPacket) {