2018-04-21 02:41:01 +02:00

94 lines
3.9 KiB
C#

using MLAPI.Attributes;
using MLAPI.Data;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace MLAPI.NetworkingManagerComponents.Binary
{
/// <summary>
/// Helper class for serializing classes to binary
/// </summary>
public static class BinarySerializer
{
private static Dictionary<string, FieldInfo[]> cachedFields = new Dictionary<string, FieldInfo[]>();
/// <summary>
/// Clears the cache of the serializer
/// </summary>
public static void ClearCache()
{
cachedFields.Clear();
}
/// <summary>
/// Serializes a class instance to binary
/// </summary>
/// <typeparam name="T">The class type to serialize</typeparam>
/// <param name="instance">The instance to serialize</param>
/// <returns>Binary serialized version of the instance</returns>
public static byte[] Serialize<T>(T instance)
{
FieldInfo[] sortedFields;
if (cachedFields.ContainsKey(instance.GetType().FullName))
sortedFields = cachedFields[instance.GetType().FullName];
else
{
sortedFields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderBy(x => x.Name).Where(x => !x.IsDefined(typeof(BinaryIgnore), true)).ToArray();
cachedFields.Add(instance.GetType().FullName, sortedFields);
}
using (BitWriter writer = new BitWriter())
{
for (int i = 0; i < sortedFields.Length; i++)
{
FieldType fieldType = FieldTypeHelper.GetFieldType(sortedFields[i].FieldType);
if (fieldType == FieldType.Invalid)
{
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 writer.Finalize();
}
}
/// <summary>
/// Deserializes binary and turns it back into the original class
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="binary">The binary to deserialize</param>
/// <returns>An instance of T</returns>
public static T Deserialize<T>(byte[] binary) where T : new()
{
T instance = new T();
FieldInfo[] sortedFields;
if (cachedFields.ContainsKey(instance.GetType().FullName))
sortedFields = cachedFields[instance.GetType().FullName];
else
{
sortedFields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).OrderBy(x => x.Name).Where(x => !x.IsDefined(typeof(BinaryIgnore), true)).ToArray();
cachedFields.Add(instance.GetType().FullName, sortedFields);
}
BitReader reader = new BitReader(binary);
for (int i = 0; i < sortedFields.Length; i++)
{
FieldType fieldType = FieldTypeHelper.GetFieldType(sortedFields[i].FieldType);
if (fieldType == FieldType.Invalid)
{
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;
}
}
}