Switched from constructors to functions in serialization code

This commit is contained in:
Matt Bell 2013-03-18 13:02:57 -07:00
parent 169fa1c986
commit 367b8a96da

View File

@ -475,58 +475,56 @@ var packets = {
}; };
var types = { var types = {
'int': [readInt, IntWriter], 'int': [readInt, writeInt, 4],
'short': [readShort, ShortWriter], 'short': [readShort, writeShort, 2],
'ushort': [readUShort, UShortWriter], 'ushort': [readUShort, writeUShort, 2],
'byte': [readByte, ByteWriter], 'byte': [readByte, writeByte, 1],
'ubyte': [readUByte, UByteWriter], 'ubyte': [readUByte, writeUByte, 1],
'string': [readString, StringWriter], 'string': [readString, writeString, sizeOfString],
'byteArray16': [readByteArray16, ByteArray16Writer], 'byteArray16': [readByteArray16, writeByteArray16, sizeOfByteArray16],
'bool': [readBool, BoolWriter], 'bool': [readBool, writeBool, 1],
'double': [readDouble, DoubleWriter], 'double': [readDouble, writeDouble, 8],
'float': [readFloat, FloatWriter], 'float': [readFloat, writeFloat, 4],
'slot': [readSlot, SlotWriter], 'slot': [readSlot, writeSlot, sizeOfSlot],
'long': [readLong, LongWriter], 'long': [readLong, writeLong, 8],
'ascii': [readAscii, AsciiWriter], 'ascii': [readAscii, writeAscii, sizeOfAscii],
'entityMetadata': [readEntityMetadata, EntityMetadataWriter], 'entityMetadata': [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata],
'byteArray32': [readByteArray32, ByteArray32Writer], 'byteArray32': [readByteArray32, writeByteArray32, sizeOfByteArray32],
'slotArray': [readSlotArray, SlotArrayWriter], 'slotArray': [readSlotArray, writeSlotArray, sizeOfSlotArray],
'mapChunkBulk': [readMapChunkBulk, MapChunkBulkWriter], 'mapChunkBulk': [readMapChunkBulk, writeMapChunkBulk, sizeOfMapChunkBulk],
'objectData': [readObjectData, ObjectDataWriter], 'objectData': [readObjectData, writeObjectData, sizeOfObjectData],
'intArray8': [readIntArray8, IntArray8Writer], 'intArray8': [readIntArray8, writeIntArray8, sizeOfIntArray8],
'intVector': [readIntVector, IntVectorWriter], 'intVector': [readIntVector, writeIntVector, 12],
'byteVector': [readByteVector, ByteVectorWriter], 'byteVector': [readByteVector, writeByteVector, 3],
'byteVectorArray': [readByteVectorArray, ByteVectorArrayWriter], 'byteVectorArray': [readByteVectorArray, writeByteVectorArray, sizeOfByteVectorArray],
'stringArray': [readStringArray, StringArrayWriter], 'stringArray': [readStringArray, writeStringArray, sizeOfStringArray],
}; };
function ByteArray32Writer(value) { function sizeOfByteArray32(value) {
this.value = value; return 4 + value.length;
this.size = 4 + value.length;
} }
ByteArray32Writer.prototype.write = function(buffer, offset) { function writeByteArray32(value, buffer, offset) {
buffer.writeInt32BE(this.value.length, offset); buffer.writeInt32BE(value.length, offset);
this.value.copy(buffer, offset + 4); value.copy(buffer, offset + 4);
return offset + 4 + value.length;
} }
function SlotArrayWriter(value) { function sizeOfSlotArray(value) {
this.value = new Array(value.length) var size = 2;
this.size = 2;
var slotWriter;
for (var i = 0; i < value.length; ++i) { for (var i = 0; i < value.length; ++i) {
this.value[i] = slotWriter = new SlotWriter(value[i]); size += sizeOfSlot(value[i]);
this.size += slotWriter.size;
} }
return size;
} }
SlotArrayWriter.prototype.write = function(buffer, offset) { function writeSlotArray(value, buffer, offset) {
buffer.writeInt16BE(this.value.length, offset); buffer.writeInt16BE(value.length, offset);
offset += 2; offset += 2;
this.value.forEach(function(slotWriter) { value.forEach(function(slot) {
slotWriter.write(buffer, offset); offset = writeSlot(slot, buffer, offset);
offset += slotWriter.size;
}); });
return offset;
} }
var entityMetadataTypes = { var entityMetadataTypes = {
@ -545,73 +543,62 @@ for (var n in entityMetadataTypes) {
entityMetadataTypeBytes[entityMetadataTypes[n]] = n; entityMetadataTypeBytes[entityMetadataTypes[n]] = n;
} }
function EntityMetadataWriter(value) { function sizeOfEntityMetadata(value) {
this.value = []; var size = 1 + value.length;
this.size = 1 + value.length; var item, dataType;
var item, Writer, writer, dataType;
for (var i = 0; i < value.length; ++i) { for (var i = 0; i < value.length; ++i) {
item = value[i]; item = value[i];
dataType = types[item.type]; size += sizeOf(item.type, item.value);
assert.ok(dataType, "unknown data type " + dataType);
Writer = dataType[1];
assert.ok(Writer, "missing writer for data type " + item.type);
writer = new Writer(item.value);
this.size += writer.size;
this.value.push({
writer: writer,
key: item.key,
type: entityMetadataTypeBytes[item.type],
});
} }
return size;
} }
EntityMetadataWriter.prototype.write = function(buffer, offset) { function writeEntityMetadata(value, buffer, offset) {
this.value.forEach(function(item) { value.forEach(function(item) {
var headerByte = (item.type << 5) | item.key; var headerByte = (item.type << 5) | item.key;
buffer.writeUInt8(headerByte, offset); buffer.writeUInt8(headerByte, offset);
offset += 1; offset += 1;
item.writer.write(buffer, offset); offset = types[item.type][1](item.value, buffer, offset);
offset += item.writer.size;
}); });
buffer.writeUInt8(0x7f, offset); buffer.writeUInt8(0x7f, offset);
return offset + 1;
} }
function ObjectDataWriter(value) { function sizeOfObjectData(value) {
this.value = value; return value.intField === 0 ? 4 : 10;
this.size = value.intField === 0 ? 4 : 10;
} }
ObjectDataWriter.prototype.write = function(buffer, offset) { function writeObjectData(value, buffer, offset) {
buffer.writeInt32BE(this.value.intField, offset); buffer.writeInt32BE(value.intField, offset);
if (this.value.intField === 0) return; if (value.intField === 0) return;
offset += 4; offset += 4;
buffer.writeInt16BE(this.value.velocityX, offset); buffer.writeInt16BE(value.velocityX, offset);
offset += 2; offset += 2;
buffer.writeInt16BE(this.value.velocityY, offset); buffer.writeInt16BE(value.velocityY, offset);
offset += 2; offset += 2;
buffer.writeInt16BE(this.value.velocityZ, offset); buffer.writeInt16BE(value.velocityZ, offset);
return offset + 2;
} }
function MapChunkBulkWriter(value) { function sizeOfMapChunkBulk(value) {
this.value = value; return 7 + value.compressedChunkData.length + 12 * value.meta.length;
this.size = 7 + value.compressedChunkData.length + 12 * value.meta.length;
} }
MapChunkBulkWriter.prototype.write = function(buffer, offset) { function writeMapChunkBulk(value, buffer, offset) {
buffer.writeInt16BE(this.value.meta.length, offset); buffer.writeInt16BE(value.meta.length, offset);
offset += 2; offset += 2;
buffer.writeInt32BE(this.value.compressedChunkData.length, offset); buffer.writeInt32BE(value.compressedChunkData.length, offset);
offset += 4; offset += 4;
buffer.writeInt8(+this.value.skyLightSent, offset); buffer.writeInt8(+value.skyLightSent, offset);
offset += 1; offset += 1;
this.value.compressedChunkData.copy(buffer, offset); value.compressedChunkData.copy(buffer, offset);
offset += this.value.compressedChunkData.length; offset += value.compressedChunkData.length;
var meta; var meta;
for (var i = 0; i < this.value.meta.length; ++i) { for (var i = 0; i < value.meta.length; ++i) {
meta = this.value.meta[i]; meta = value.meta[i];
buffer.writeInt32BE(meta.x, offset); buffer.writeInt32BE(meta.x, offset);
offset += 4; offset += 4;
buffer.writeInt32BE(meta.z, offset); buffer.writeInt32BE(meta.z, offset);
@ -621,54 +608,46 @@ MapChunkBulkWriter.prototype.write = function(buffer, offset) {
buffer.writeUInt16BE(meta.addBitMap, offset); buffer.writeUInt16BE(meta.addBitMap, offset);
offset += 2; offset += 2;
} }
return offset;
} }
function IntArray8Writer(value) { function sizeOfIntArray8(value) {
this.value = value; return 1 + 4 * value.length;
this.size = 1 + 4 * value.length;
} }
IntArray8Writer.prototype.write = function(buffer, offset) { function writeIntArray8(value, buffer, offset) {
buffer.writeInt8(this.value.length, offset); buffer.writeInt8(value.length, offset);
offset += 1; offset += 1;
this.value.forEach(function(item) { value.forEach(function(item) {
buffer.writeInt32BE(item, offset); buffer.writeInt32BE(item, offset);
offset += 4; offset += 4;
}); });
return offset;
} }
function IntVectorWriter(value) { function writeIntVector(value, buffer, offset) {
this.value = value; buffer.writeInt32BE(value.x, offset);
this.size = 12; buffer.writeInt32BE(value.y, offset + 4);
buffer.writeInt32BE(value.z, offset + 8);
return offset + 12;
} }
IntVectorWriter.prototype.write = function(buffer, offset) { function writeByteVector(value, buffer, offset) {
buffer.writeInt32BE(this.value.x, offset); buffer.writeInt8(value.x, offset);
buffer.writeInt32BE(this.value.y, offset + 4); buffer.writeInt8(value.y, offset + 1);
buffer.writeInt32BE(this.value.z, offset + 8); buffer.writeInt8(value.z, offset + 2);
return offset + 3;
} }
function ByteVectorWriter(value) { function sizeOfByteVectorArray(value) {
this.value = value; return 4 + 3 * value.length;
this.size = 3;
} }
ByteVectorWriter.prototype.write = function(buffer, offset) { function writeByteVectorArray(value, buffer, offset) {
buffer.writeInt8(this.value.x, offset); buffer.writeInt32BE(value.length, offset);
buffer.writeInt8(this.value.y, offset + 1);
buffer.writeInt8(this.value.z, offset + 2);
}
function ByteVectorArrayWriter(value) {
this.value = value;
this.size = 4 + 3 * value.length;
}
ByteVectorArrayWriter.prototype.write = function(buffer, offset) {
buffer.writeInt32BE(this.value.length, offset);
offset += 4; offset += 4;
this.value.forEach(function(vec) { value.forEach(function(vec) {
buffer.writeInt8(vec.x, offset); buffer.writeInt8(vec.x, offset);
offset += 1; offset += 1;
buffer.writeInt8(vec.y, offset); buffer.writeInt8(vec.y, offset);
@ -676,25 +655,24 @@ ByteVectorArrayWriter.prototype.write = function(buffer, offset) {
buffer.writeInt8(vec.z, offset); buffer.writeInt8(vec.z, offset);
offset += 1; offset += 1;
}); });
return offset;
} }
function StringArrayWriter(value) { function sizeOfStringArray(value) {
this.value = new Array(value.length); var size = 2;
this.size = 2;
for (var i = 0; i < value.length; ++i) { for (var i = 0; i < value.length; ++i) {
var stringWriter = new StringWriter(value[i]); size += sizeOfString(value[i]);
this.value[i] = stringWriter;
this.size += stringWriter.size;
} }
return size;
} }
StringArrayWriter.prototype.write = function(buffer, offset) { function writeStringArray(value, buffer, offset) {
buffer.writeInt16BE(this.value.length, offset); buffer.writeInt16BE(value.length, offset);
offset += 2; offset += 2;
this.value.forEach(function(stringWriter) { value.forEach(function(string) {
stringWriter.write(buffer, offset); offset = writeString(string, buffer, offset);
offset += stringWriter.size;
}); });
return offset;
} }
function readIntArray8(buffer, offset) { function readIntArray8(buffer, offset) {
@ -1107,146 +1085,108 @@ function readSlot(buffer, offset) {
}; };
} }
function SlotWriter(value) { function sizeOfSlot(value) {
this.value = value; return value.id === -1 ? 2 : 7 + value.nbtData.length;
this.size = value.id === -1 ? 2 : 7 + this.value.nbtData.length;
} }
SlotWriter.prototype.write = function(buffer, offset) { function writeSlot(value, buffer, offset) {
buffer.writeInt16BE(this.value.id, offset); buffer.writeInt16BE(value.id, offset);
if (this.value.id === -1) return; if (value.id === -1) return offset + 2;
buffer.writeInt8(this.value.itemCount, offset + 2); buffer.writeInt8(value.itemCount, offset + 2);
buffer.writeInt16BE(this.value.itemDamage, offset + 3); buffer.writeInt16BE(value.itemDamage, offset + 3);
var nbtDataSize = this.value.nbtData.length; var nbtDataSize = value.nbtData.length;
if (nbtDataSize === 0) nbtDataSize = -1; // I don't know wtf mojang smokes if (nbtDataSize === 0) nbtDataSize = -1; // I don't know wtf mojang smokes
buffer.writeInt16BE(nbtDataSize, offset + 5); buffer.writeInt16BE(nbtDataSize, offset + 5);
this.value.nbtData.copy(buffer, offset + 7); value.nbtData.copy(buffer, offset + 7);
return offset + 7 + value.nbtData.length;
}; };
function StringWriter(value) { function sizeOfString(value) {
assert.ok(value.length < STRING_MAX_LENGTH, "string greater than max length"); assert.ok(value.length < STRING_MAX_LENGTH, "string greater than max length");
this.value = value; return 2 + 2 * value.length;
this.size = 2 + 2 * value.length;
} }
StringWriter.prototype.write = function(buffer, offset) { function writeString(value, buffer, offset) {
var cursor = offset; buffer.writeInt16BE(value.length, offset);
buffer.writeInt16BE(this.value.length, cursor); offset += 2;
cursor += 2;
for (var i = 0; i < this.value.length; ++i) { for (var i = 0; i < value.length; ++i) {
buffer.writeUInt16BE(this.value.charCodeAt(i), cursor); buffer.writeUInt16BE(value.charCodeAt(i), offset);
cursor += 2; offset += 2;
} }
return offset;
}; };
function AsciiWriter(value) { function sizeOfAscii(value) {
this.value = value; return 2 + value.length;
this.size = 2 + value.length;
} }
AsciiWriter.prototype.write = function(buffer, offset) { function writeAscii(value, buffer, offset) {
var cursor = offset; buffer.writeInt16BE(value.length, offset);
buffer.writeInt16BE(this.value.length, cursor); offset += 2;
cursor += 2;
for (var i = 0; i < this.value.length; ++i) { for (var i = 0; i < value.length; ++i) {
buffer.writeUInt8(this.value.charCodeAt(i), cursor); buffer.writeUInt8(value.charCodeAt(i), offset);
cursor += 1; offset += 1;
} }
return offset;
}; };
function ByteArray16Writer(value) { function sizeOfByteArray16(value) {
assert.ok(Buffer.isBuffer(value), "non buffer passed to ByteArray16Writer"); assert.ok(Buffer.isBuffer(value), "non buffer passed to ByteArray16Writer");
this.value = value; return 2 + value.length;
this.size = 2 + value.length;
} }
ByteArray16Writer.prototype.write = function(buffer, offset) { function writeByteArray16(value, buffer, offset) {
buffer.writeInt16BE(this.value.length, offset); buffer.writeInt16BE(value.length, offset);
this.value.copy(buffer, offset + 2); value.copy(buffer, offset + 2);
return offset + 2 + value.length;
}; };
function ByteWriter(value) { function writeByte(value, buffer, offset) {
this.value = value == null ? 0 : value; buffer.writeInt8(value, offset);
this.size = 1; return offset + 1;
} }
ByteWriter.prototype.write = function(buffer, offset) { function writeBool(value, buffer, offset) {
buffer.writeInt8(this.value, offset); buffer.writeInt8(+value, offset);
return offset + 1;
} }
function BoolWriter(value) { function writeUByte(value, buffer, offset) {
this.value = value; buffer.writeUInt8(value, offset);
this.size = 1; return offset + 1;
}
BoolWriter.prototype.write = function(buffer, offset) {
buffer.writeInt8(this.value ? 1 : 0, offset);
}
function UByteWriter(value) {
this.value = value;
this.size = 1;
}
UByteWriter.prototype.write = function(buffer, offset) {
buffer.writeUInt8(this.value, offset);
}; };
function FloatWriter(value) { function writeFloat(value, buffer, offset) {
this.value = value; buffer.writeFloatBE(value, offset);
this.size = 4; return offset + 4;
} }
FloatWriter.prototype.write = function(buffer, offset) { function writeDouble(value, buffer, offset) {
buffer.writeFloatBE(this.value, offset); buffer.writeDoubleBE(value, offset);
return offset + 8;
} }
function DoubleWriter(value) { function writeShort(value, buffer, offset) {
this.value = value; buffer.writeInt16BE(value, offset);
this.size = 8; return offset + 2;
} }
DoubleWriter.prototype.write = function(buffer, offset) { function writeUShort(value, buffer, offset) {
buffer.writeDoubleBE(this.value, offset); buffer.writeUInt16BE(value, offset);
return offset + 2;
} }
function ShortWriter(value) { function writeInt(value, buffer, offset) {
this.value = value; buffer.writeInt32BE(value, offset);
this.size = 2; return offset + 4;
} }
ShortWriter.prototype.write = function(buffer, offset) { function writeLong(value, buffer, offset) {
buffer.writeInt16BE(this.value, offset); buffer.writeInt32BE(value[0], offset);
} buffer.writeInt32BE(value[1], offset + 4);
return offset + 8;
function UShortWriter(value) {
this.value = value;
this.size = 2;
}
UShortWriter.prototype.write = function(buffer, offset) {
buffer.writeUInt16BE(this.value, offset);
}
function IntWriter(value) {
this.value = value;
this.size = 4;
}
IntWriter.prototype.write = function(buffer, offset) {
buffer.writeInt32BE(this.value, offset);
}
function LongWriter(value) {
this.value = value;
this.size = 8;
}
LongWriter.prototype.write = function(buffer, offset) {
buffer.writeInt32BE(this.value[0], offset);
buffer.writeInt32BE(this.value[1], offset + 4);
} }
function get(packetId, toServer) { function get(packetId, toServer) {
@ -1261,24 +1201,31 @@ function get(packetId, toServer) {
packetInfo.toClient; packetInfo.toClient;
} }
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, params, isServer) { function createPacketBuffer(packetId, params, isServer) {
var size = 1; var size = 1;
var fields = [ new UByteWriter(packetId) ];
var packet = get(packetId, !isServer); var packet = get(packetId, !isServer);
assert.notEqual(packet, null); assert.notEqual(packet, null);
packet.forEach(function(fieldInfo) { packet.forEach(function(fieldInfo) {
var value = params[fieldInfo.name]; size += sizeOf(fieldInfo.type, params[fieldInfo.name]);
var Writer = types[fieldInfo.type][1];
assert.ok(Writer, "missing writer for data type: " + fieldInfo.type);
var field = new Writer(value);
size += field.size;
fields.push(field);
}); });
var buffer = new Buffer(size); var buffer = new Buffer(size);
var cursor = 0; var offset = writeUByte(packetId, buffer, 0);
fields.forEach(function(field) { packet.forEach(function(fieldInfo) {
field.write(buffer, cursor); var write = types[fieldInfo.type][1];
cursor += field.size; var value = params[fieldInfo.name];
if(typeof value === "undefined") value = 0;
offset = write(value, buffer, offset);
}); });
return buffer; return buffer;
} }