public static T OdinDeserialize <T>(this OdinSerializationData data) { var instance = default(T); OdinDeserializeInto(data, ref instance); return(instance); }
public void TryFetchSystemBuffer(string systemBufferIdentifier) { Ensure.That(nameof(systemBufferIdentifier)).IsNotNullOrEmpty(systemBufferIdentifier); if (!EditorGUIUtility.systemCopyBuffer.StartsWith(systemBufferIdentifier)) { return; } if (EditorGUIUtility.systemCopyBuffer == lastSystemCopy) { return; } data = new OdinSerializationData { SerializedBytes = Convert.FromBase64String(EditorGUIUtility.systemCopyBuffer.TrimStart(systemBufferIdentifier)) }; dataType = null; try { var contents = data.Value.OdinDeserialize <object>(); dataType = contents.GetType(); } catch (Exception ex) { Debug.LogWarning("Failed to deserialize data in system clipboard: \n" + ex); data = null; dataType = null; } }
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 OdinSerializationData OdinSerialize <T>(this T value, ref OdinSerializationData data, DataFormat format = DataFormat.Binary) { try { var context = BeginOdinSerializationContext(); if (value is UnityObject uo) { UnitySerializationUtility.SerializeUnityObject(uo, ref data, true, context); } else { data.SerializedFormat = format; if (format == DataFormat.Binary) { var bytes = SerializationUtility.SerializeValue(value, format, out var unityObjects, context); data.SerializedBytes = bytes; data.ReferencedUnityObjects = unityObjects; } else if (format == DataFormat.JSON) { var bytes = SerializationUtility.SerializeValue(value, format, out var unityObjects, context); data.SerializedBytesString = Convert.ToBase64String(bytes); data.ReferencedUnityObjects = unityObjects; } else if (format == DataFormat.Nodes) { using (var writer = new SerializationNodeDataWriter(context)) { SerializationUtility.SerializeValue(writer, format, out var unityObjects, context); data.SerializationNodes = writer.Nodes; data.ReferencedUnityObjects = unityObjects; } } else { throw new UnexpectedEnumValueException <DataFormat>(format); } } EndOdinSerializationContext(context); return(data); } catch (Exception ex) { throw new SerializationException($"Serialization of '{value?.GetType().ToString() ?? "null"}' failed.", ex); } }
public static void OdinDeserializeInto <T>(this OdinSerializationData data, ref T instance) { try { var context = BeginOdinDeserializationContext(); if (instance is UnityObject uo) { UnitySerializationUtility.DeserializeUnityObject(uo, ref data, context); } else { instance = SerializationUtility.DeserializeValue <T>(data.SerializedBytes, data.SerializedFormat, data.ReferencedUnityObjects, context); } EndOdinDeserializationContext(context); } catch (ThreadAbortException) { } catch (Exception ex) { throw new SerializationException($"Deserialization into '{instance?.GetType().ToString() ?? "null"}' failed.", ex); } }
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; } }
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 bool ContainsRealData(this OdinSerializationData data) { return(data.SerializedBytes != null && data.SerializedBytes.Length > 0 || data.SerializationNodes != null && data.SerializationNodes.Count > 0 || !string.IsNullOrEmpty(data.SerializedBytesString)); }
public static string GetDebugString(this OdinSerializationData data, string title = null) { using (var writer = new StringWriter()) { writer.WriteLine("Odin Serializer Data"); if (!string.IsNullOrEmpty(title)) { writer.WriteLine(title); } writer.WriteLine(); writer.WriteLine("Object References: "); WriteObjectReferenceDebug(writer, data.ReferencedUnityObjects); writer.WriteLine(); if (data.SerializedFormat == DataFormat.Nodes) { writer.WriteLine("Nodes: "); if (data.SerializationNodes == null) { writer.WriteLine("(Null)"); } else if (data.SerializationNodes.Count == 0) { writer.WriteLine("(Empty)"); } else { var indent = 0; foreach (var node in data.SerializationNodes) { switch (node.Entry) { case EntryType.EndOfNode: case EntryType.EndOfArray: indent--; break; } writer.Write(new string('\t', Mathf.Max(indent, 0))); writer.Write(node.Entry); if (!string.IsNullOrEmpty(node.Name)) { writer.Write(": " + node.Name); } if (!string.IsNullOrEmpty(node.Data)) { writer.Write(" = " + node.Data); } writer.WriteLine(); switch (node.Entry) { case EntryType.StartOfNode: case EntryType.StartOfArray: indent++; break; } } } } else if (data.SerializedFormat == DataFormat.JSON) { writer.WriteLine("JSON: "); if (data.SerializedBytesString == null) { writer.WriteLine("(Null)"); } else if (data.SerializedBytesString == string.Empty) { writer.WriteLine("(Empty)"); } else { writer.WriteLine(PrettyPrint(Encoding.UTF8.GetString(Convert.FromBase64String(data.SerializedBytesString)))); } } else if (data.SerializedFormat == DataFormat.Binary) { writer.WriteLine("Bytes: "); if (data.SerializedBytes == null) { writer.WriteLine("(Null)"); } else if (data.SerializedBytes.Length == 0) { writer.WriteLine("(Empty)"); } else { StringUtility.WordWrap(BitConverter.ToString(data.SerializedBytes).Replace('-', ' '), 16 * 3); } } writer.WriteLine(); writer.WriteLine("Prefab Modifications Object References: "); WriteObjectReferenceDebug(writer, data.PrefabModificationsReferencedUnityObjects); writer.WriteLine(); writer.WriteLine("Prefab Modifications: "); if (data.PrefabModifications == null) { writer.WriteLine("(Null)"); } else if (data.PrefabModifications.Count == 0) { writer.WriteLine("(Empty)"); } else { foreach (var node in data.PrefabModifications) { writer.WriteLine(node); } } return(writer.ToString()); } }
public static OdinSerializationData OdinSerialize <T>(this T value, DataFormat format = DataFormat.Binary) { var data = new OdinSerializationData(); return(OdinSerialize(value, ref data, format)); }