alelievr / NodeGraphProcessor

Node graph editor framework focused on data processing using Unity UIElements and C# 4.6
https://github.com/alelievr/NodeGraphProcessor/projects/2
MIT License
2.31k stars 386 forks source link

Recursive Serialization is not supported. You can't dereference a PPtr while loading (occasional crash) #67

Closed cbaggers closed 3 years ago

cbaggers commented 4 years ago

First off, fantastic project. I'm thoroughly impressed with where is going.

Unity version is 2019.3.15f1

Either Unity crashes while loading or, if it does load, I have this error in the console.

Recursive Serialization is not supported. You can't dereference a PPtr while loading. (Constructors of C# classes may not load objects either. See stacktrace.)
UnityEngine.JsonUtility:FromJsonOverwrite(String, Object)
GraphProcessor.SerializableObject:OnAfterDeserialize() (at Assets/com.alelievr.NodeGraphProcessor/Runtime/Utils/SerrializableObject.cs:54)

I checked the Editor.log and found this that looked relevant:

Assertion failed on expression: 'CurrentThread::IsMainThread()'
UnityEngine.JsonUtility:FromJsonInternal(String, Object, Type)
UnityEngine.JsonUtility:FromJsonOverwrite(String, Object)
GraphProcessor.SerializableObject:OnAfterDeserialize() (at Assets\com.alelievr.NodeGraphProcessor\Runtime\Utils\SerrializableObject.cs:54)

[C:\buildslave\unity\build\Runtime/BaseClasses/BaseObject.cpp line 288] 
(Filename: Assets/com.alelievr.NodeGraphProcessor/Runtime/Utils/SerrializableObject.cs Line: 54)

Stacktrace:

  at <unknown> <0xffffffff>
  at (wrapper managed-to-native) UnityEngine.JsonUtility.FromJsonInternal (string,object,System.Type) [0x00009] in <1386288601af43018501cce2912f52f4>:0
  at UnityEngine.JsonUtility.FromJsonOverwrite (string,object) [0x00059] in <1386288601af43018501cce2912f52f4>:0
  at GraphProcessor.SerializableObject.OnAfterDeserialize () [0x00090] in C:\home\Code\NodeGraphProcessor\Assets\com.alelievr.NodeGraphProcessor\Runtime\Utils\SerrializableObject.cs:54
  at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr) [0x00020] in <437ba245d8404784b9fbab9b439ac908>:0

line 54 can be seen here

            else if (typeof(UnityEngine.Object).IsAssignableFrom(type))
            {
                ObjectWrapper obj = new ObjectWrapper();
                JsonUtility.FromJsonOverwrite(serializedValue, obj); // <<<<<<<< LINE 54
                value = obj.value;
            }

which is odd as the documentation for FromJsonOverwrite makes it look like this this should be safe from threads other than main.

I'll post more if I find it.

cbaggers commented 4 years ago

I added this Log call above the call to FromJsonOverwrite

            else if (typeof(UnityEngine.Object).IsAssignableFrom(type))
            {
        UnityEngine.Debug.Log("~~~ name was:" + serializedName+ " Type was: " + type.FullName + ". Json:\nvvvvvvv\n" + serializedValue + "\n^^^^^^^");
                ObjectWrapper obj = new ObjectWrapper();
                JsonUtility.FromJsonOverwrite(serializedValue, obj);
                value = obj.value;
            }

On the first attempt of loading the project Unity started with the You can't dereference a PPtr while loading error, however the second time it crashed I got this:

~~~ name was: Type was: UnityEngine.GameObject. Json:
vvvvvvv
{"value":{"instanceID":14012}}
^^^^^^^

I grepped for the instanceId and found the json in question in Assets/Examples/ExposedGetProperties.asset which makes sense.

I've got no conclusions yet but I hope the data is useful

cbaggers commented 4 years ago

Hmm I guess the issue was that somehow the graph asset itself ended up containing a reference to a GameObject. The repercussions make some sense given that happening.

cbaggers commented 4 years ago

I can force the issue by doing the following:

Next time the project loads you'll get the issue.

The question now remains what I did to cause this the first time. The above actions are pretty dumb so I'd like to think that it can happen another way. However poking around like a noob combined with a few drinks could account for it, and that was definitely the situation I was in.

I wonder if allowSceneObjects would help here

[edit] Actually it seems that the reference has been in there for a while. Last change was here 14a0ae1899e581933a49619fc83df0b6f452d840

alelievr commented 4 years ago

Yeah, I saw this error a while ago. I think the only way to fix this issue is to use the new [SerializeReference] attribute instead of the slow and ugly JSON serialization but it's a big task and will require migration step for old graphs.

Btw I think the object serialization is wrong too, it's serializing an object just with the instance id:

{"value":{"instanceID":14012}}

But the instance id is only valid for the time of the editor session after you restart they will point on other assets. You need to serialize the fileId instead to be sure the asset reference isn't lost after restarting the editor.

IIRC they use something like this in ShaderGraph too but their version is working: https://github.com/Unity-Technologies/Graphics/blob/master/com.unity.shadergraph/Editor/Data/Graphs/SerializableTexture.cs