NodeCanvas Forums › Support › [BUG] Blackboard losing UnityEngine.Object references
Tagged: Blackboard references lost
Okay, this is very strange Unity behaviour. I’ve made this very simple script:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Reference : MonoBehaviour, ISerializationCallbackReceiver { [SerializeField] private UnityEngine.Object _otherRef; public void OnBeforeSerialize() { } public void OnAfterDeserialize() { Debug.Log($"type={_otherRef.GetType().FullName} isNull={_otherRef == null}"); } } |
Then I created prefab A referencing a prefab B through this component.
Then I’ve deleted Library folder as was suggested by the author.
After Unity restarted the Console output was:
Rebuilding Library because the asset database could not be found!
type=UnityEngine.Object isNull=True
type=UnityEngine.Object isNull=True
Then I’ve selected the prefab A and it produced output:
type=UnityEngine.GameObject isNull=False
So looks like on assets reimport references are in some invalid state. And reference type is wrong as you can see and this breaks entire Blackboard.OnAfterDeserialize() logic.
!!!
It scares me because NodeCanvas relies heavily on ISerializationCallbackReceiver callbacks and uses UnityEngine.Objects references withing these callbacks.
UPDATE
Now I understand that Unity cannot resolve this issue because objects can reference each other forming circular dependencies so there is no way to provide valid references in OnAfterDeserialize() for all of them.
Hello there, I am really sorry but unfortunately I wasn’t able to fully work on this for the past two weeks due to other matters. To be honest, it is also one of the hardest issues I’ve come across to fix because from my leads it really has to do with the internal Unity UnityEngine.Object handling and life-cycle. However, now that I am back from those other matters I will attack this issue again. Thank you.
Hi, Gavalakis
To fix this issue I think you have to remove all code from OnAfterDeserialize() and do everything in lazy manner (this is to avoid complete redesign). I mean instead of deserializing BlackboardSource in OnAfterDeserialize() do it later when _blackboard variable is requested.
The problem I see with a lazy approach is that deserialization would be inconsistent and dependent on when the user references a blackboard variable in their graphs, deserialization could even happen during gameplay if the graph uses no blackboard variables until later nodes.
What about doing it in Awake instead?
Hello guys and sorry for the late reply (a lot of things going on simultaneously).
To be honest, using “OnAfterDeserialize” and by its name alone should mean after objects are actually deserialized. I am under the impression that Unity changed something with its Object handling in later Unity versions because this has never been a problem in older versions all this time. In any case and apparently due to how Unity Objects are handled by Unity, I will have to find another place to deserialize the graph and blackboards. This will probably be Awake for MonoBehaviours and OnEnable for ScriptableObject (like graphs). Lazy deserialization is also an option but I would prefer everything to be deserialized “as early as possible”. This will require some very heavy refactoring, but it is currently on the top of the to-do list for sure.
Join us on Discord: https://discord.gg/97q2Rjh
Yeah it’s very odd how Unity’s OnAfterDeserialize behaves. Thanks @Gavalakis!
I do not know how it worked long time ago but now documentation for OnAfterDeserialize says “Implement this method to receive a callback after Unity deserializes your object.” – notice this “your object”.
And documentation for ISerializationCallbackReceiver interface says “Care needs to be taken whilst within these callbacks, as Unity’s serializer runs on a different thread to most of the Unity API.”
Sorry for posting obvious things. It is just for clarity.
Just to clarify guys. I am able to reproduce this (prefab asset reference being lost in a prefab asset blackboard variable) ONLY if the “Library” folder is manually deleted (like the OP said) and not able to reproduce this in any other way. Can you please confirm that this is the case for you as well?
Join us on Discord: https://discord.gg/97q2Rjh
Hi,
I have the same issue.
If I set the blackboard references manually in the Graph Asset it works fine. But if i set the references from script I get these errors in the graph execution at runtime: (Blackboard Log): No Variable of name ‘SpawnClip’ and type ‘AnimationClip’ exists on Blackboard ‘Mannequin_Old_Ragdoll_TEST(Clone)’. Adding new instead… (Blackboard Log): No Variable of name ‘IdleClip’ and type ‘AnimationClip’ exists on Blackboard ‘Mannequin_Old_Ragdoll_TEST(Clone)’. Adding new instead… (Execution Error): A required BBParameter field value named ‘animationClip’ is not set.
What I basically do is Initialize the BBoard and set the values with the FMSGraphOwner API eg: BehaviorGraph.blackboard.SetVariableValue(“ClimbEndClip”, climbEndClip);
Hello @trololocat
The issue you are facing is really not related to the others things said here.
It seems like the graph tries to access those variables BEFORE you have filled them in through code. Can you please confirm that you fill the variable through code BEFORE the graph attempts to access those variables in question?
Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hello guys. I want to let you know that this edge case issue of cycle referenced blackboard prefabs when the Library folder is deleted, is fixed.
The problem was in serialization rather than deserialization. This fix is the following piece of code added at the start of the ‘SelfSerialize’ method in Blackboard.cs
1 2 3 4 5 6 7 8 9 |
#if UNITY_EDITOR //This fixes an edge case of cycle referencing prefab blackboards when the Library folder is deleted //which was basically due to the prefabs being serialized before the database was re-built. if ( UnityEditor.EditorApplication.isUpdating ) { return; } #endif |
Join us on Discord: https://discord.gg/97q2Rjh
Tested the code changes and can confirm this issue is no longer happening, thank you very much @Gavalakis.
Will this fix be included in the next official NodeCanvas release?
Hey,
Thank you for confirming!
Yes, of course. This fix will be part of the next version.
Join us on Discord: https://discord.gg/97q2Rjh
Great, thanks!