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