public static object FullDeserialize(this FullSerializationData data, bool forceReflected = false) { object instance = null; FullDeserializeInto(data, ref instance, forceReflected); return(instance); }
public static void FullDeserializeInto(this FullSerializationData data, ref object instance, bool forceReflected = false) { try { if (string.IsNullOrEmpty(data.json)) { instance = null; return; } var operation = BeginFullOperation(); operation.objectReferences.AddRange(data.objectReferences); FullDeserializeJson(operation.serializer, data.json, ref instance, forceReflected); EndFullOperation(operation); } catch (Exception ex) { try { Debug.LogWarning(data.GetDebugString("Deserialization Failure Data"), instance as UnityObject); } catch (Exception ex2) { Debug.LogWarning("Failed to log deserialization failure data:\n" + ex2, instance as UnityObject); } throw new SerializationException($"Deserialization into '{instance?.GetType().ToString() ?? "null"}' failed.", ex); } }
public static void OnBeforeSerializeImplementation <T>(T uo, ref FullSerializationData fullData, ref OdinSerializationData odinData, bool deserializationFailed) where T : UnityObject, ILudiqRootObject { // To prevent data loss, we don't serialize something that failed to deserialize in the first place if (deserializationFailed) { Debug.LogWarning($"Skipping serialization of {uo.ToSafeString()} to prevent data loss because it failed to deserialize.\n", uo); return; } // Run the user handler try { uo.OnBeforeSerialize(); } catch (Exception ex) { Debug.LogError($"Failed to run OnBeforeSerialize on {uo.ToSafeString()}.\n{ex}", uo); return; } // Check if we are migrating legacy FS data into OS to notify the user var migrating = fullData.ContainsRealData && !odinData.ContainsRealData(); try { // Serialize the data using OS only from now on odinData = uo.OdinSerialize(ref odinData); if (migrating) { // Clear the legacy FS data so that it isn't used as a fallback during deserialization from now on. fullData = default; Debug.Log($"Migrated legacy serialization data on {uo.ToSafeString()} from Full Serializer to Odin Serializer.\n", uo); } } catch (Exception ex) { Debug.LogError($"Failed to serialize {uo.ToSafeString()} using Odin Serializer.\n{ex}", uo); return; } // Run the user handler try { uo.OnAfterSerialize(); } catch (Exception ex) { Debug.LogError($"Failed to run OnAfterSerialize on {uo.ToSafeString()}.\n{ex}", uo); return; } }
public static void ShowData(string title, FullSerializationData fullData, OdinSerializationData odinData) { var guid = Guid.NewGuid(); var fileName = string.IsNullOrEmpty(title) ? guid.ToString() : title + "." + guid; var fullDataPath = Path.GetTempPath() + fileName + ".full.txt"; var odinDataPath = Path.GetTempPath() + fileName + ".odin.txt"; File.WriteAllText(fullDataPath, GetDebugString(fullData)); File.WriteAllText(odinDataPath, GetDebugString(odinData)); Process.Start(fullDataPath); Process.Start(odinDataPath); }
public static FullSerializationData FullSerialize(this object value, bool forceReflected = false) { try { var operation = BeginFullOperation(); var json = FullSerializeJson(operation.serializer, value, forceReflected); var objectReferences = operation.objectReferences.ToArray(); var data = new FullSerializationData(json, objectReferences); EndFullOperation(operation); #if DEBUG_SERIALIZATION Debug.Log(data.ToString($"<color=#88FF00>Serialized: <b>{value?.GetType().Name ?? "null"} [{value?.GetHashCode().ToString() ?? "N/A"}]</b></color>")); #endif return(data); } catch (Exception ex) { throw new SerializationException($"Serialization of '{value?.GetType().ToString() ?? "null"}' failed.", ex); } }
public static string GetDebugString(this FullSerializationData data, string title = null) { using (var writer = new StringWriter()) { writer.WriteLine("Full Serializer Data"); if (!string.IsNullOrEmpty(title)) { writer.WriteLine(title); } writer.WriteLine(); writer.WriteLine("Object References: "); WriteObjectReferenceDebug(writer, data.objectReferences); writer.WriteLine(); writer.WriteLine("JSON: "); if (data.json == null) { writer.WriteLine("(Null)"); } else if (data.json == string.Empty) { writer.WriteLine("(Empty)"); } else { writer.WriteLine(PrettyPrint(data.json)); } return(writer.ToString()); } }
public static void OnAfterDeserializeImplementation <T>(T uo, FullSerializationData fullData, OdinSerializationData odinData, ref bool deserializationFailed) where T : UnityObject, ILudiqRootObject { // Set a flag to indicate to our API checker that Unity calls are forbidden isUnityDeserializing = true; try { object _this = uo; // If we don't reach the complete end of the process for any reason, the failure flag will be set. deserializationFailed = true; // Run the user callback try { uo.OnBeforeDeserialize(); } catch (Exception ex) { Debug.LogError($"Failed to run OnBeforeDeserialize on {uo.ToSafeString()}.\n{ex}", uo); return; } // Deserialize with OS data if it is available if (odinData.ContainsRealData()) { try { odinData.OdinDeserializeInto(ref _this); } catch (Exception ex) { Debug.LogError($"Failed to deserialize {uo.ToSafeString()} using Odin Serializer.\n{ex}", uo); return; } } // In theory, there shouldn't be a case where we have both OS and FS data because we clear the FS data on a successful OS deserialization. // Just to be absolutely safe we don't rollback to earlier FS data though, we're being mutually exclusive on deserialization too. else { // Fallback to legacy FS data try { fullData.FullDeserializeInto(ref _this, true); } catch (Exception ex) { Debug.LogError($"Failed to deserialize {uo.ToSafeString()} using legacy Full Serializer data.\n{ex}", uo); return; } } // Run the user callback try { uo.OnAfterDeserialize(); } catch (Exception ex) { Debug.LogError($"Failed to run OnAfterDeserialize on {uo.ToSafeString()}.\n{ex}", uo); return; } // We managed to execute everything successfully, clear the failure flag. deserializationFailed = false; } finally { // Clear our API lock regardless of what happened isUnityDeserializing = false; } }