From 3624ec4809f315102e76878e6486a05b0e48a25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albin=20Cor=C3=A9n?= <2108U9@gmail.com> Date: Sat, 21 Apr 2018 02:41:01 +0200 Subject: [PATCH] Reworked BinarySerializer to use BitWriter --- MLAPI/Data/FieldType.cs | 122 ++++++++++++++- .../MonoBehaviours/Core/NetworkedBehaviour.cs | 11 ++ .../Binary/BinarySerializer.cs | 140 ++---------------- 3 files changed, 148 insertions(+), 125 deletions(-) diff --git a/MLAPI/Data/FieldType.cs b/MLAPI/Data/FieldType.cs index 3c761e3..a0a61ac 100644 --- a/MLAPI/Data/FieldType.cs +++ b/MLAPI/Data/FieldType.cs @@ -45,6 +45,124 @@ namespace MLAPI.Data internal static class FieldTypeHelper { + internal static object ReadFieldType(BitReader reader, FieldType fieldType) + { + switch (fieldType) + { + case FieldType.Bool: + return reader.ReadBool(); + case FieldType.Byte: + return reader.ReadByte(); + case FieldType.Double: + return reader.ReadDouble(); + case FieldType.Single: + return reader.ReadFloat(); + case FieldType.Int: + return reader.ReadInt(); + case FieldType.Long: + return reader.ReadLong(); + case FieldType.SByte: + return reader.ReadSByte(); + case FieldType.Short: + return reader.ReadShort(); + case FieldType.UInt: + return reader.ReadUInt(); + case FieldType.ULong: + return reader.ReadULong(); + case FieldType.UShort: + return reader.ReadUShort(); + case FieldType.String: + return reader.ReadString(); + case FieldType.Vector3: + Vector3 vector3 = Vector3.zero; + vector3.x = reader.ReadFloat(); + vector3.y = reader.ReadFloat(); + vector3.z = reader.ReadFloat(); + return vector3; + case FieldType.Vector2: + Vector2 vector2 = Vector2.zero; + vector2.x = reader.ReadFloat(); + vector2.y = reader.ReadFloat(); + return vector2; + case FieldType.Quaternion: + Vector3 eulerAngle = Vector3.zero; + eulerAngle.x = reader.ReadFloat(); + eulerAngle.y = reader.ReadFloat(); + eulerAngle.z = reader.ReadFloat(); + return Quaternion.Euler(eulerAngle); + case FieldType.BoolArray: + ushort boolCount = reader.ReadUShort(); + bool[] bools = new bool[boolCount]; + for (int j = 0; j < boolCount; j++) + bools[j] = reader.ReadBool(); + return bools; + case FieldType.ByteArray: + return reader.ReadByteArray(); + case FieldType.DoubleArray: + return reader.ReadDoubleArray(); + case FieldType.SingleArray: + return reader.ReadFloatArray(); + case FieldType.IntArray: + return reader.ReadIntArray(); + case FieldType.LongArray: + return reader.ReadLongArray(); + case FieldType.SByteArray: + return reader.ReadSByteArray(); + case FieldType.ShortArray: + return reader.ReadShortArray(); + case FieldType.UIntArray: + return reader.ReadUIntArray(); + case FieldType.ULongArray: + return reader.ReadULongArray(); + case FieldType.UShortArray: + return reader.ReadUShortArray(); + case FieldType.StringArray: + ushort stringCount = reader.ReadUShort(); + string[] strings = new string[stringCount]; + for (int j = 0; j < stringCount; j++) + strings[j] = reader.ReadString(); + return strings; + case FieldType.Vector3Array: + ushort vector3Count = reader.ReadUShort(); + Vector3[] vector3s = new Vector3[vector3Count]; + for (int j = 0; j < vector3Count; j++) + { + Vector3 vec3 = Vector3.zero; + vec3.x = reader.ReadFloat(); + vec3.y = reader.ReadFloat(); + vec3.z = reader.ReadFloat(); + vector3s[j] = vec3; + } + return vector3s; + case FieldType.Vector2Array: + ushort vector2Count = reader.ReadUShort(); + Vector2[] vector2s = new Vector2[vector2Count]; + for (int j = 0; j < vector2Count; j++) + { + Vector2 vec2 = Vector2.zero; + vec2.x = reader.ReadFloat(); + vec2.y = reader.ReadFloat(); + vector2s[j] = vec2; + } + return vector2s; + case FieldType.QuaternionArray: + ushort quaternionCount = reader.ReadUShort(); + Quaternion[] quaternions = new Quaternion[quaternionCount]; + for (int j = 0; j < quaternionCount; j++) + { + Vector3 vec3 = Vector3.zero; + vec3.x = reader.ReadFloat(); + vec3.y = reader.ReadFloat(); + vec3.z = reader.ReadFloat(); + quaternions[j] = Quaternion.Euler(vec3); + } + return quaternions; + case FieldType.Invalid: + return null; + } + return null; + } + internal static void WriteFieldType(BitWriter writer, object value, FieldType fieldType) { switch (fieldType) @@ -440,8 +558,10 @@ namespace MLAPI.Data break; case FieldType.BoolArray: ushort boolCount = reader.ReadUShort(); + bool[] bools = new bool[boolCount]; for (int j = 0; j < boolCount; j++) - returnVal[i] = reader.ReadBool(); + bools[j] = reader.ReadBool(); + returnVal[i] = bools; break; case FieldType.ByteArray: returnVal[i] = reader.ReadByteArray(); diff --git a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs index 186709d..1191928 100644 --- a/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs +++ b/MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs @@ -284,6 +284,17 @@ namespace MLAPI.MonoBehaviours.Core return counter; } + /// + /// Deserializes a message that has been serialized by the BinarySerializer. This is the same as calling BinarySerializer.Deserialize + /// + /// The type + /// The serialized version + /// Instance of type + protected T DeserializeMessage(byte[] binary) where T : new() + { + return BinarySerializer.Deserialize(binary); + } + /// /// Deregisters a given message handler /// diff --git a/MLAPI/NetworkingManagerComponents/Binary/BinarySerializer.cs b/MLAPI/NetworkingManagerComponents/Binary/BinarySerializer.cs index 08f9c8a..e4b644f 100644 --- a/MLAPI/NetworkingManagerComponents/Binary/BinarySerializer.cs +++ b/MLAPI/NetworkingManagerComponents/Binary/BinarySerializer.cs @@ -1,9 +1,8 @@ using MLAPI.Attributes; +using MLAPI.Data; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; -using System.Text; using UnityEngine; namespace MLAPI.NetworkingManagerComponents.Binary @@ -41,90 +40,19 @@ namespace MLAPI.NetworkingManagerComponents.Binary cachedFields.Add(instance.GetType().FullName, sortedFields); } - int outputSize = 0; - //Calculate output size - for (int i = 0; i < sortedFields.Length; i++) + using (BitWriter writer = new BitWriter()) { - if (sortedFields[i].FieldType == typeof(bool)) - outputSize += 1; - else if (sortedFields[i].FieldType == typeof(byte)) - outputSize += 1; - else if (sortedFields[i].FieldType == typeof(char)) - outputSize += 2; - else if (sortedFields[i].FieldType == typeof(double)) - outputSize += 8; - else if (sortedFields[i].FieldType == typeof(float)) - outputSize += 4; - else if (sortedFields[i].FieldType == typeof(decimal)) - outputSize += 16; - else if (sortedFields[i].FieldType == typeof(int)) - outputSize += 4; - else if (sortedFields[i].FieldType == typeof(long)) - outputSize += 8; - else if (sortedFields[i].FieldType == typeof(sbyte)) - outputSize += 1; - else if (sortedFields[i].FieldType == typeof(short)) - outputSize += 2; - else if (sortedFields[i].FieldType == typeof(uint)) - outputSize += 4; - else if (sortedFields[i].FieldType == typeof(ulong)) - outputSize += 8; - else if (sortedFields[i].FieldType == typeof(ushort)) - outputSize += 2; - else if (sortedFields[i].FieldType == typeof(string)) - outputSize += Encoding.UTF8.GetByteCount((string)sortedFields[i].GetValue(instance)) + 2; - else if (sortedFields[i].FieldType == typeof(byte[])) - outputSize += ((byte[])sortedFields[i].GetValue(instance)).Length + 2; //Two bytes to specify the size - else - Debug.LogWarning("MLAPI: The type \"" + sortedFields[i].FieldType.Name + "\" is not supported by the Binary Serializer. It will be ignored"); - } - - //Write data - using (MemoryStream stream = new MemoryStream(outputSize)) - { - using (BinaryWriter writer = new BinaryWriter(stream)) + for (int i = 0; i < sortedFields.Length; i++) { - for (int i = 0; i < sortedFields.Length; i++) + FieldType fieldType = FieldTypeHelper.GetFieldType(sortedFields[i].FieldType); + if (fieldType == FieldType.Invalid) { - if (sortedFields[i].FieldType == typeof(bool)) - writer.Write((bool)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(byte)) - writer.Write((byte)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(char)) - writer.Write((char)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(double)) - writer.Write((double)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(float)) - writer.Write((float)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(decimal)) - writer.Write((decimal)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(int)) - writer.Write((int)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(long)) - writer.Write((long)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(sbyte)) - writer.Write((sbyte)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(short)) - writer.Write((short)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(uint)) - writer.Write((uint)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(ulong)) - writer.Write((ulong)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(ushort)) - writer.Write((ushort)sortedFields[i].GetValue(instance)); - else if (sortedFields[i].FieldType == typeof(string)) - { - writer.Write((ushort)Encoding.UTF8.GetByteCount((string)sortedFields[i].GetValue(instance))); //Size of string in bytes - writer.Write(Encoding.UTF8.GetBytes((string)sortedFields[i].GetValue(instance))); - } - else if (sortedFields[i].FieldType == typeof(byte[])) - { - writer.Write((ushort)((byte[])sortedFields[i].GetValue(instance)).Length); //Size of byte array - writer.Write((byte[])sortedFields[i].GetValue(instance)); - } + Debug.LogWarning("MLAPI: The field " + sortedFields[i].Name + " will not be serialized as it's not of a supported type. Add the BinaryIgnore attribute to prevent this message from shwoing up."); + continue; } + FieldTypeHelper.WriteFieldType(writer, sortedFields[i].GetValue(instance), fieldType); } - return stream.ToArray(); + return writer.Finalize(); } } @@ -148,52 +76,16 @@ namespace MLAPI.NetworkingManagerComponents.Binary cachedFields.Add(instance.GetType().FullName, sortedFields); } - using (MemoryStream stream = new MemoryStream(binary)) + BitReader reader = new BitReader(binary); + for (int i = 0; i < sortedFields.Length; i++) { - using (BinaryReader reader = new BinaryReader(stream)) + FieldType fieldType = FieldTypeHelper.GetFieldType(sortedFields[i].FieldType); + if (fieldType == FieldType.Invalid) { - for (int i = 0; i < sortedFields.Length; i++) - { - if (sortedFields[i].FieldType == typeof(bool)) - sortedFields[i].SetValue(instance, reader.ReadBoolean()); - else if (sortedFields[i].FieldType == typeof(byte)) - sortedFields[i].SetValue(instance, reader.ReadByte()); - else if (sortedFields[i].FieldType == typeof(char)) - sortedFields[i].SetValue(instance, reader.ReadChar()); - else if (sortedFields[i].FieldType == typeof(double)) - sortedFields[i].SetValue(instance, reader.ReadDouble()); - else if (sortedFields[i].FieldType == typeof(float)) - sortedFields[i].SetValue(instance, reader.ReadSingle()); - else if (sortedFields[i].FieldType == typeof(decimal)) - sortedFields[i].SetValue(instance, reader.ReadDecimal()); - else if (sortedFields[i].FieldType == typeof(int)) - sortedFields[i].SetValue(instance, reader.ReadInt32()); - else if (sortedFields[i].FieldType == typeof(long)) - sortedFields[i].SetValue(instance, reader.ReadInt64()); - else if (sortedFields[i].FieldType == typeof(sbyte)) - sortedFields[i].SetValue(instance, reader.ReadSByte()); - else if (sortedFields[i].FieldType == typeof(short)) - sortedFields[i].SetValue(instance, reader.ReadInt16()); - else if (sortedFields[i].FieldType == typeof(uint)) - sortedFields[i].SetValue(instance, reader.ReadUInt32()); - else if (sortedFields[i].FieldType == typeof(ulong)) - sortedFields[i].SetValue(instance, reader.ReadUInt64()); - else if (sortedFields[i].FieldType == typeof(ushort)) - sortedFields[i].SetValue(instance, reader.ReadUInt64()); - else if (sortedFields[i].FieldType == typeof(string)) - { - ushort size = reader.ReadUInt16(); - sortedFields[i].SetValue(instance, Encoding.UTF8.GetString(reader.ReadBytes(size))); - } - else if (sortedFields[i].FieldType == typeof(byte[])) - { - ushort size = reader.ReadUInt16(); - sortedFields[i].SetValue(instance, reader.ReadBytes(size)); - } - else - Debug.LogWarning("MLAPI: The type \"" + sortedFields[i].FieldType.Name + "\" is not supported by the Binary Serializer. It will be ignored"); - } + Debug.LogWarning("MLAPI: The field " + sortedFields[i].Name + " will not be deserialized as it's not of a supported type. Add the BinaryIgnore attribute to prevent this message from shwoing up."); + continue; } + sortedFields[i].SetValue(instance, FieldTypeHelper.ReadFieldType(reader, fieldType)); } return instance; }