TeamSirenix / odin-serializer

Fast, robust, powerful and extendible .NET serializer built for Unity
http://www.odininspector.com
Apache License 2.0
1.69k stars 193 forks source link

Simple SerializedScriptableObject ArgumentNullException: Value cannot be null. on DeserializeValue #37

Closed jpdoiron closed 4 years ago

jpdoiron commented 4 years ago

Hello team,

in Unity 2018.3.0f5 when trying to deserialize a simple SerializedScriptableObject I get a NullException and the object return null.

I've created a simple code that reproduce the error.

` using System.IO; using test.OdinSerializer; using UnityEngine; using Debug = UnityEngine.Debug;

[CreateAssetMenu(fileName = "PlayerData", menuName = "_Config/DataCentral/PlayerData", order = 1)] public class PlayerData : SerializedScriptableObject { public string PlayerName; }

public class Save : MonoBehaviour { private PlayerData myData; public PlayerData Template;

void Start()
{
    //instanciate based on my template
    myData = ScriptableObject.Instantiate(Template);
}

void Update()
{
    string jsonString;

    if (Input.GetKeyDown(KeyCode.S))
    {
        myData.PlayerName = "Bob";
        byte[] serializedData = SerializationUtility.SerializeValue<PlayerData>(myData, DataFormat.JSON);

        jsonString = System.Text.Encoding.UTF8.GetString(serializedData);
        File.WriteAllText("save.txt", jsonString);
    }

    if (Input.GetKeyDown(KeyCode.L))
    {
        byte[] jsonBytes = File.ReadAllBytes("save.txt");
        myData = SerializationUtility.DeserializeValue<PlayerData>(jsonBytes,DataFormat.JSON);
        Debug.Log("My data : " + myData); //return NULL
    }
}

}

`

Json value { "$id": 0, "$type": "0|PlayerData, Assembly-CSharp", "serializationData": { "$type": "1|test.OdinSerializer.SerializationData, test.OdinSerializer", "SerializedFormat": 0, "SerializedBytes": { "$id": 1, "$type": "2|System.Byte[], mscorlib", "$plength": 0, "$pcontent": [ ] }, "ReferencedUnityObjects": { "$id": 2, "$type": "3|System.Collections.Generic.List1[[UnityEngine.Object, UnityEngine.CoreModule]], mscorlib", "$rlength": 0, "$rcontent": [ ] }, "SerializedBytesString": "", "Prefab": null, "PrefabModificationsReferencedUnityObjects": { "$id": 3, "$type": 3, "$rlength": 0, "$rcontent": [ ] }, "PrefabModifications": { "$id": 4, "$type": "4|System.Collections.Generic.List1[[System.String, mscorlib]], mscorlib", "$rlength": 0, "$rcontent": [ ] }, "SerializationNodes": { "$id": 5, "$type": "5|System.Collections.Generic.List1[[test.OdinSerializer.SerializationNode, test.OdinSerializer]], mscorlib", "$rlength": 0, "$rcontent": [ ] } }, "PlayerName": "Bob" }`

Error:

ArgumentNullException: Value cannot be null. Parameter name: unityObject test.OdinSerializer.UnitySerializationUtility.DeserializeUnityObject (UnityEngine.Object unityObject, test.OdinSerializer.SerializationData& data, test.OdinSerializer.DeserializationContext context, System.Boolean isPrefabData, System.Collections.Generic.List1[T] prefabInstanceUnityObjects) (at Assets/test.OdinSerializer/Unity Integration/UnitySerializationUtility.cs:1182) test.OdinSerializer.UnitySerializationUtility.DeserializeUnityObject (UnityEngine.Object unityObject, test.OdinSerializer.SerializationData& data, test.OdinSerializer.DeserializationContext context) (at Assets/test.OdinSerializer/Unity Integration/UnitySerializationUtility.cs:1171) test.OdinSerializer.SerializedScriptableObject.UnityEngine.ISerializationCallbackReceiver.OnAfterDeserialize () (at Assets/test.OdinSerializer/Unity Integration/SerializedUnityObjects/SerializedScriptableObject.cs:36) test.OdinSerializer.BaseFormatter1[T].Deserialize (test.OdinSerializer.IDataReader reader) (at Assets/test.OdinSerializer/Core/Formatters/BaseFormatter.cs:256) UnityEngine.Debug:LogException(Exception) test.OdinSerializer.CustomLogger:LogException(Exception) (at Assets/test.OdinSerializer/Core/Misc/CustomLogger.cs:82) test.OdinSerializer.DebugContext:LogException(Exception) (at Assets/test.OdinSerializer/Core/Misc/SerializationConfig.cs:252) test.OdinSerializer.BaseFormatter1:Deserialize(IDataReader) (at Assets/test.OdinSerializer/Core/Formatters/BaseFormatter.cs:261) test.OdinSerializer.ComplexTypeSerializer1:ReadValue(IDataReader) (at Assets/test.OdinSerializer/Core/Serializers/ComplexTypeSerializer.cs:366) test.OdinSerializer.SerializationUtility:DeserializeValue(IDataReader) (at Assets/test.OdinSerializer/Core/Misc/SerializationUtility.cs:469) test.OdinSerializer.SerializationUtility:DeserializeValue(Stream, DataFormat, DeserializationContext) (at Assets/test.OdinSerializer/Core/Misc/SerializationUtility.cs:588) test.OdinSerializer.SerializationUtility:DeserializeValue(Byte[], DataFormat, DeserializationContext) (at Assets/test.OdinSerializer/Core/Misc/SerializationUtility.cs:683) Save:Update() (at Assets/Save.cs:32)

TorVestergaard commented 4 years ago

Hi, thanks for reporting the issue. I'm afraid this is not an error, but expected behaviour.

Odin Serializer cannot - nor should it - serialize Unity objects/assets such as a ScriptableObject to a byte format that can be saved to a file. Unity objects are peculiar and come with a lot of baggage attached that means anything but "illusionary" surface level support is literally impossible. Only Unity itself is allowed to serialize Unity assets, either through in-memory-only instantiation/copying (available at runtime), or through its editor-time-only asset database that can save an asset to a file or scene (not available at runtime). You cannot create or serialize assets to files/a byte format at runtime. Unity objects and Unity's asset system is simply not built for it, sadly, and Odin Serializer cannot support it.

The solution to your issue is to either use Unity's editor-time asset database utilities to save your SO to a file, or if you need to save its data at runtime, to not use an SO at all and not let your data contain any references to Unity objects or assets anywhere.