/// <summary> /// Serializes the data in the specified object to the stream. /// </summary> /// <param name="obj">The object to be serialized.</param> /// <param name="writer">The location where the data will be written.</param> public void SerializeData(object obj, BinaryWriter writer) { onSerializing?.Invoke(obj, null); foreach (var pair in serializableFields) { var sfield = pair.Value; try { FastSerializationManager.WriteValue(writer, sfield.targetType, sfield. GetValue(obj)); } catch (Exception e) { Debug.LogErrorFormat("Error while serializing field {0} on template {1}: {2}", sfield.field.Name, targetType.Name, e.ToString()); throw; } } foreach (var pair in serializableProperties) { var sprop = pair.Value; try { FastSerializationManager.WriteValue(writer, sprop.targetType, sprop. GetValue(obj)); } catch (Exception e) { Debug.LogErrorFormat("Error while serializing property {0} on template {1}: {2}", sprop.property.Name, targetType.Name, e.ToString()); throw; } } customSerialize?.Invoke(obj, new object[] { writer }); onSerialized?.Invoke(obj, null); }
/// <summary> /// Reads an array, which is encoded the same way for lists and plain old arrays. /// </summary> /// <param name="typeInfo">The array type to read.</param> /// <param name="reader">The stream containing serialized data.</param> /// <param name="optimizePOD">If true, plain-old-data (POD) arrays will be deserialized /// using a faster method. Only can be used if they were serialized using the fast method.</param> /// <returns>The deserialized array, or null if it was empty.</returns> private static Array ReadArray(TypeInfo typeInfo, IReader reader, bool optimizePOD) { int n = reader.ReadInt32(); Array array = null; if (n >= 0) { var elementType = typeInfo.subTypes[0]; array = Array.CreateInstance(elementType.type, n); if (Helper.IsPOD(elementType.info) && optimizePOD) { ReadArrayFast(array, elementType, reader); } else if (Helper.IsValueType(elementType.info)) { var template = FastSerializationManager.GetFastDeserializationMapping( elementType.type); object element = template.CreateInstance(); for (int i = 0; i < n; i++) { template.Deserialize(element, reader); array.SetValue(element, i); } } else { for (int i = 0; i < n; i++) { array.SetValue(ReadValue(elementType, reader, null), i); } } } return(array); }
/// <summary> /// Applied before SerializeTypeless runs. /// </summary> internal static bool Prefix(object obj, BinaryWriter writer) { var type = obj.GetType(); var template = FastSerializationManager.GetFastSerializationTemplate(type); template.SerializeData(obj, writer); return(false); }
/// <summary> /// Saves the game to disk in the background. /// </summary> /// <param name="data">The uncompressed save data.</param> private void DoSave(BackgroundSaveData data) { try { var stream = data.Stream; PUtil.LogDebug("Background save to: " + data.FileName); stream.Seek(0L, SeekOrigin.Begin); CleanAutosaves(); // Write the file header using (var writer = new BinaryWriter(File.Open(data.FileName, FileMode. Create))) { var saveHeader = SaveGame.Instance.GetSaveHeader(true, data.Compress, out SaveGame.Header header); writer.Write(header.buildVersion); writer.Write(header.headerSize); writer.Write(header.headerVersion); writer.Write(header.compression); writer.Write(saveHeader); if (FastSaveOptions.Instance.DelegateSave) { FastSerializationManager.SerializeDirectory(writer); } else { KSerialization.Manager.SerializeDirectory(writer); } writer.Flush(); if (data.Compress) { COMPRESS_CONTENTS.Invoke(writer, stream.GetBuffer(), (int)stream. Length); } else { stream.CopyTo(writer.BaseStream); } } stream.Dispose(); status = SaveStatus.Done; PUtil.LogDebug("Background save complete"); } catch (IOException e) { // Autosave error! PUtil.LogExcWarn(e); status = SaveStatus.IOError; } catch (Exception e) { // Allowing it to continue here will crash with a simdll error PUtil.LogException(e); status = SaveStatus.Failed; } finally { try { // Cannot throw during a finally, or it will discard the original exception data.Dispose(); } catch { } } }
/// <summary> /// Applied before DeserializeTypeless runs. /// </summary> internal static bool Prefix(Type type, object obj, IReader reader, ref bool __result) { var mapping = FastSerializationManager.GetFastDeserializationMapping(type); try { mapping.Deserialize(obj, reader); } catch (Exception e) { Debug.LogErrorFormat("Exception occurred while attempting to deserialize object {0}({1}).\n{2}", obj, obj.GetType(), e.ToString()); throw; } __result = true; return(false); }
/// <summary> /// Applied before Deserialize runs. /// </summary> internal static bool Prefix(Type type, IReader reader, out object result, ref bool __result) { var mapping = FastSerializationManager.GetFastDeserializationMapping(type); try { object obj = mapping.CreateInstance(); mapping.Deserialize(obj, reader); result = obj; } catch (Exception e) { Debug.LogErrorFormat("Exception occurred while attempting to deserialize into object of type {0}.\n{1}", type.ToString(), e.ToString()); throw; } __result = true; return(false); }
/// <summary> /// Starts saving the game in the background. This function is not reentrant! /// </summary> /// <param name="filename">The file name where the save should be stored.</param> public void StartSave(string filename) { var buffer = new MemoryStream(BUFFER_SIZE); var inst = SaveLoader.Instance; bool save = true; if (inst != null) { if (FastSaveOptions.Instance.DelegateSave) { FastSerializationManager.ClearSmart(); } else { KSerialization.Manager.Clear(); } #if DEBUG PUtil.LogDebug("Starting serialization of save"); #endif bool compress = true; // This field is currently always true if (COMPRESS_SAVE_DATA != null) { try { compress = COMPRESS_SAVE_DATA.Get(inst); } catch { } } // Keep this part on the foreground try { SAVE.Invoke(inst, new BinaryWriter(buffer)); } catch (Exception e) { buffer.Dispose(); PUtil.LogError("Error when saving game:"); PUtil.LogException(e); save = false; } // In Unity 4 GetComponent no longer works on background threads if (save) { StartSave(new BackgroundSaveData(buffer, compress, filename)); } } }
/// <summary> /// Reads a basic value from the stream. /// </summary> /// <param name="typeInfo">The type to be deserialized.</param> /// <param name="reader">The stream containing serialized data.</param> /// <param name="baseValue">The default value for this field.</param> /// <returns>The deserialized value.</returns> internal static object ReadValue(TypeInfo typeInfo, IReader reader, object baseValue) { object result = null; int n; var info = typeInfo.info & SerializationTypeInfo.VALUE_MASK; switch (info) { case SerializationTypeInfo.UserDefined: n = reader.ReadInt32(); if (n >= 0) { var itemType = typeInfo.type; if (baseValue == null) { result = ConstructorDelegator.CreateInstance(itemType); } else { result = baseValue; } FastSerializationManager.GetFastDeserializationMapping(itemType). Deserialize(result, reader); } break; case SerializationTypeInfo.SByte: result = reader.ReadSByte(); break; case SerializationTypeInfo.Byte: result = reader.ReadByte(); break; case SerializationTypeInfo.Boolean: result = reader.ReadByte() == 1; break; case SerializationTypeInfo.Int16: result = reader.ReadInt16(); break; case SerializationTypeInfo.UInt16: result = reader.ReadUInt16(); break; case SerializationTypeInfo.Int32: result = reader.ReadInt32(); break; case SerializationTypeInfo.UInt32: result = reader.ReadUInt32(); break; case SerializationTypeInfo.Int64: result = reader.ReadInt64(); break; case SerializationTypeInfo.UInt64: result = reader.ReadUInt64(); break; case SerializationTypeInfo.Single: result = reader.ReadSingle(); break; case SerializationTypeInfo.Double: result = reader.ReadDouble(); break; case SerializationTypeInfo.String: result = reader.ReadKleiString(); break; case SerializationTypeInfo.Enumeration: result = Enum.ToObject(typeInfo.type, reader.ReadInt32()); break; case SerializationTypeInfo.Vector2I: result = reader.ReadVector2I(); break; case SerializationTypeInfo.Vector2: result = reader.ReadVector2(); break; case SerializationTypeInfo.Vector3: result = reader.ReadVector3(); break; case SerializationTypeInfo.Array: reader.ReadInt32(); result = ReadArray(typeInfo, reader, true); break; case SerializationTypeInfo.Pair: n = reader.ReadInt32(); if (n >= 0) { TypeInfo keyType = typeInfo.subTypes[0], valueType = typeInfo.subTypes[1]; object key = ReadValue(keyType, reader, null); object value = ReadValue(valueType, reader, null); result = KeyValuePairDelegator.GetDelegates(keyType.type, valueType.type). CreateInstance(key, value); } break; case SerializationTypeInfo.Dictionary: reader.ReadInt32(); n = reader.ReadInt32(); if (n >= 0) { // Preallocate dictionary to correct size result = DictionaryDelegator.CreateInstance(typeInfo. genericInstantiationType, n); var dict = result as System.Collections.IDictionary; var keyType = typeInfo.subTypes[0]; var valueType = typeInfo.subTypes[1]; var values = ListPool <object, FastDeserializationMapping> .Allocate(); for (int i = 0; i < n; i++) { values.Add(ReadValue(valueType, reader, null)); } for (int i = 0; i < n; i++) { dict.Add(ReadValue(keyType, reader, null), values[i]); } values.Recycle(); } break; case SerializationTypeInfo.HashSet: reader.ReadInt32(); result = ReadArray(typeInfo, reader, false); if (result != null) { result = CollectionDelegator.CreateInstance(typeInfo. genericInstantiationType, result); } break; case SerializationTypeInfo.List: case SerializationTypeInfo.Queue: reader.ReadInt32(); result = ReadArray(typeInfo, reader, true); if (result != null) { // Due to how POD lists/queues are encoded, must go through a temporary // array to make best usage of ReadArrayFast, sorry memory usage result = CollectionDelegator.CreateInstance(typeInfo. genericInstantiationType, result); } break; case SerializationTypeInfo.Colour: result = reader.ReadColour(); break; default: throw new ArgumentException("Unknown type " + info); } return(result); }
/// <summary> /// Applied before SerializeDirectory runs. /// </summary> internal static bool Prefix(BinaryWriter writer) { FastSerializationManager.SerializeDirectory(writer); return(false); }
/// <summary> /// Applied before HasDeserializationMapping runs. /// </summary> internal static bool Prefix(Type type, ref bool __result) { __result = FastSerializationManager.HasDeserializationMapping(type); return(false); }
/// <summary> /// Applied before GetSerializationTemplate runs. /// </summary> internal static bool Prefix(Type type, ref SerializationTemplate __result) { __result = FastSerializationManager.GetKleiSerializationTemplate(type); return(false); }
/// <summary> /// Applied before DeserializeDirectory runs. /// </summary> internal static bool Prefix(IReader reader) { FastSerializationManager.DeserializeDirectory(reader); return(false); }
/// <summary> /// Applied before Clear runs. /// </summary> internal static bool Prefix() { FastSerializationManager.ClearSmart(); return(false); }
/// <summary> /// Applied before WriteValue runs. /// </summary> internal static bool Prefix(BinaryWriter writer, TypeInfo type_info, object value) { FastSerializationManager.WriteValue(writer, type_info, value); return(false); }