94 lines
3.9 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|