public static void Init() { ImplSerialization.Init(); DefSerialization.Init(); }
private static object ReadSyncObjectInternal(ByteReader data, SyncType syncType) { Type type = syncType.type; try { if (typeof(object) == type) { return(null); } if (type.IsByRef) { return(null); } if (SyncDictFast.syncWorkers.TryGetValue(type, out SyncWorkerEntry syncWorkerEntryEarly)) { object res = null; if (syncWorkerEntryEarly.shouldConstruct || type.IsValueType) { res = Activator.CreateInstance(type); } syncWorkerEntryEarly.Invoke(new ReadingSyncWorker(data), ref res); return(res); } if (syncType.expose) { if (!typeof(IExposable).IsAssignableFrom(type)) { throw new SerializationException($"Type {type} can't be exposed because it isn't IExposable"); } byte[] exposableData = data.ReadPrefixedBytes(); return(ExposableSerialization.ReadExposable(type, exposableData)); } if (typeof(ISynchronizable).IsAssignableFrom(type)) { var obj = Activator.CreateInstance(type); ((ISynchronizable)obj).Sync(new ReadingSyncWorker(data)); return(obj); } if (type.IsEnum) { Type underlyingType = Enum.GetUnderlyingType(type); return(Enum.ToObject(type, ReadSyncObject(data, underlyingType))); } if (type.IsArray) { if (type.GetArrayRank() != 1) { throw new SerializationException("Multi dimensional arrays aren't supported."); } ushort length = data.ReadUShort(); if (length == ushort.MaxValue) { return(null); } Type elementType = type.GetElementType(); Array arr = Array.CreateInstance(elementType, length); for (int i = 0; i < length; i++) { arr.SetValue(ReadSyncObject(data, elementType), i); } return(arr); } if (type.IsGenericType) { var genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List <>)) { ushort size = data.ReadUShort(); if (size == ushort.MaxValue) { return(null); } Type listObjType = type.GetGenericArguments()[0]; IList list = (IList)Activator.CreateInstance(type, size); for (int j = 0; j < size; j++) { list.Add(ReadSyncObject(data, listObjType)); } return(list); } if (genericTypeDefinition == typeof(IEnumerable <>)) { Type element = type.GetGenericArguments()[0]; return(ReadSyncObject(data, typeof(List <>).MakeGenericType(element))); } if (genericTypeDefinition == typeof(Nullable <>)) { bool isNull = data.ReadBool(); if (isNull) { return(null); } return(Activator.CreateInstance(type, ReadSyncObject(data, Nullable.GetUnderlyingType(type)))); } if (genericTypeDefinition == typeof(Dictionary <,>)) { Type[] arguments = type.GetGenericArguments(); Array keys = (Array)ReadSyncObject(data, arguments[0].MakeArrayType()); if (keys == null) { return(null); } Array values = (Array)ReadSyncObject(data, arguments[1].MakeArrayType()); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); for (int i = 0; i < keys.Length; i++) { var key = keys.GetValue(i); if (key != null) { dictionary.Add(key, values.GetValue(i)); } } return(dictionary); } if (genericTypeDefinition == typeof(Pair <,>)) { Type[] arguments = type.GetGenericArguments(); object[] parameters = { ReadSyncObject(data, arguments[0]), ReadSyncObject(data, arguments[1]), }; return(type.GetConstructors().First().Invoke(parameters)); } if (typeof(ITuple).IsAssignableFrom(genericTypeDefinition)) // ValueTuple or Tuple { Type[] arguments = type.GetGenericArguments(); int size = data.ReadInt32(); object[] values = new object[size]; for (int i = 0; i < size; i++) { values[i] = ReadSyncObject(data, arguments[i]); } return(type.GetConstructors().First().Invoke(values)); } } if (typeof(ISyncSimple).IsAssignableFrom(type)) { var obj = MpUtil.NewObjectNoCtor(type); foreach (var field in AccessTools.GetDeclaredFields(type)) { field.SetValue(obj, ReadSyncObject(data, field.FieldType)); } return(obj); } // Def is a special case until the workers can read their own type if (typeof(Def).IsAssignableFrom(type)) { ushort defTypeIndex = data.ReadUShort(); if (defTypeIndex == ushort.MaxValue) { return(null); } ushort shortHash = data.ReadUShort(); var defType = DefSerialization.DefTypes[defTypeIndex]; var def = DefSerialization.GetDef(defType, shortHash); if (def == null) { throw new SerializationException($"Couldn't find {defType} with short hash {shortHash}"); } return(def); } // Designators can't be handled by SyncWorkers due to the type change if (typeof(Designator).IsAssignableFrom(type)) { ushort desId = ReadSync <ushort>(data); type = ImplSerialization.designatorTypes[desId]; // Replaces the type! } // Where the magic happens if (SyncDict.syncWorkers.TryGetValue(type, out var syncWorkerEntry)) { object res = null; if (syncWorkerEntry.shouldConstruct || type.IsValueType) { res = Activator.CreateInstance(type); } syncWorkerEntry.Invoke(new ReadingSyncWorker(data), ref res); return(res); } throw new SerializationException("No reader for type " + type); } catch { Log.Error($"Multiplayer: Error reading type: {type}"); throw; } }