public static T OdinDeserialize <T>(this OdinSerializationData data)
        {
            var instance = default(T);

            OdinDeserializeInto(data, ref instance);
            return(instance);
        }
Beispiel #2
0
        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));
        }