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 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;
            }
        }