forked from Unity-Technologies/com.unity.netcode.gameobjects
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSerializationManager.cs
More file actions
144 lines (126 loc) · 6.02 KB
/
SerializationManager.cs
File metadata and controls
144 lines (126 loc) · 6.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using MLAPI.Reflection;
using UnityEngine;
namespace MLAPI.Serialization
{
/// <summary>
/// Helper class to manage the MLAPI serialization.
/// </summary>
public static class SerializationManager
{
private static Dictionary<Type, FieldInfo[]> s_FieldCache = new Dictionary<Type, FieldInfo[]>();
private static Dictionary<Type, BoxedSerializationDelegate> s_CachedExternalSerializers = new Dictionary<Type, BoxedSerializationDelegate>();
private static Dictionary<Type, BoxedDeserializationDelegate> s_CachedExternalDeserializers = new Dictionary<Type, BoxedDeserializationDelegate>();
/// <summary>
/// The delegate used when registering custom deserialization for a type.
/// </summary>
/// <param name="stream">The stream to read the data required to construct the type.</param>
/// <typeparam name="T">The type to deserialize.</typeparam>
public delegate T CustomDeserializationDelegate<T>(Stream stream);
/// <summary>
/// The delegate used when registering custom serialization for a type.
/// </summary>
/// <param name="stream">The stream to write data to that is required to reconstruct the type in the deserialization delegate.</param>
/// <param name="instance">The instance to serialize to the stream.</param>
/// <typeparam name="T">The type to serialize.</typeparam>
public delegate void CustomSerializationDelegate<T>(Stream stream, T instance);
// These two are what we use internally. They box the value.
private delegate void BoxedSerializationDelegate(Stream stream, object instance);
private delegate object BoxedDeserializationDelegate(Stream stream);
/// <summary>
/// Registers a custom serialization and deserialization pair for a object.
/// This is useful for writing objects that are behind the third party wall. Such as .NET types.
/// </summary>
/// <param name="onSerialize">The delegate to invoke to serialize the type.</param>
/// <param name="onDeserialize">The delegate to invoke to deserialize the type.</param>
/// <typeparam name="T">The type to register.</typeparam>
public static void RegisterSerializationHandlers<T>(CustomSerializationDelegate<T> onSerialize, CustomDeserializationDelegate<T> onDeserialize)
{
s_CachedExternalSerializers[typeof(T)] = (stream, instance) => onSerialize(stream, (T)instance);
s_CachedExternalDeserializers[typeof(T)] = stream => onDeserialize(stream);
}
/// <summary>
/// Removes a serialization handler that was registered previously for a specific type.
/// This will remove both the serialization and deserialization handler.
/// </summary>
/// <typeparam name="T">The type for the serialization handlers to remove.</typeparam>
/// <returns>Whether or not either the serialization or deserialization handlers for the type was removed.</returns>
public static bool RemoveSerializationHandlers<T>()
{
bool serializationRemoval = s_CachedExternalSerializers.Remove(typeof(T));
bool deserializationRemoval = s_CachedExternalDeserializers.Remove(typeof(T));
return serializationRemoval || deserializationRemoval;
}
internal static bool TrySerialize(Stream stream, object obj)
{
if (s_CachedExternalSerializers.ContainsKey(obj.GetType()))
{
s_CachedExternalSerializers[obj.GetType()](stream, obj);
return true;
}
return false;
}
internal static bool TryDeserialize(Stream stream, Type type, out object obj)
{
if (s_CachedExternalDeserializers.ContainsKey(type))
{
obj = s_CachedExternalDeserializers[type](stream);
return true;
}
obj = null;
return false;
}
internal static FieldInfo[] GetFieldsForType(Type type)
{
if (s_FieldCache.ContainsKey(type)) return s_FieldCache[type];
FieldInfo[] fields = type
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => (x.IsPublic || x.GetCustomAttributes(typeof(SerializeField), true).Length > 0) && IsTypeSupported(x.FieldType))
.OrderBy(x => x.Name, StringComparer.Ordinal).ToArray();
s_FieldCache.Add(type, fields);
return fields;
}
private static HashSet<Type> s_SupportedTypes = new HashSet<Type>()
{
typeof(byte),
typeof(byte),
typeof(sbyte),
typeof(ushort),
typeof(short),
typeof(int),
typeof(uint),
typeof(long),
typeof(ulong),
typeof(float),
typeof(double),
typeof(string),
typeof(bool),
typeof(Vector2),
typeof(Vector3),
typeof(Vector4),
typeof(Color),
typeof(Color32),
typeof(Ray),
typeof(Quaternion),
typeof(char),
typeof(GameObject),
typeof(NetworkObject),
typeof(NetworkBehaviour)
};
/// <summary>
/// Returns if a type is supported for serialization
/// </summary>
/// <param name="type">The type to check</param>
/// <returns>Whether or not the type is supported</returns>
public static bool IsTypeSupported(Type type)
{
return type.IsEnum || s_SupportedTypes.Contains(type) || type.HasInterface(typeof(INetworkSerializable)) ||
(s_CachedExternalSerializers.ContainsKey(type) && s_CachedExternalDeserializers.ContainsKey(type)) ||
(type.IsArray && type.HasElementType && IsTypeSupported(type.GetElementType()));
}
}
}