I understand how to save and load individual Assets. I have a very specific scenario that I don’t fully understand.
public abstract class Node : ScriptableObject {}
//various other types of Nodes inheriting from Node.
public class BehaviorTree : ScriptableObject {
public List<Node> nodes;
public Node root;
}
How exactly would you save and load this structure?
Each Node has to be saved.
BehaviorTree has to be saved.
Root will lose reference on Load unless you create Root as a new instance of Node and save it also, but all I need is a pointer to some Node in nodes.
There is an example on a documentation page Unity - Manual: Script serialization. Simply put, you don’t try to serialize the tree normally. You need to use ISerializationCallbackReceiver to build a non-tree structure list that is serialized, and then build a non-serialized tree structure for runtime use.
I build the tree structure through a NodeGraph editor that I created which drops all of those Nodes in a List to be saved to the AssetDatabase. I can then load asset from path in a monobehaviour “wrapper” which attaches to the character and has functions to process tree and link the Tree to a desired Component
…it’s probably easier if I just create a Root type inheriting from Node which has a single Child. Root.Tick() just needs to call Child.Tick().
Unless you want to fill the project folders with every node (which is going to require a separate asset for each node), you are going to need to serialize the tree under a different method. Unless you intend to attach each asset to something in the editor, it doesn’t make much sense to have so many assets save for being a work around for serializing.
You could save all the nodes into a single asset if you wanted. HideFlags would improve the situation as well so that you only see the root itself. That’s actually kinda what we do with Mecanim…
As long as all the nodes are being saved to assets somewhere, references between them Should Just Work.
You can add objects to an Asset, so a BehaviorTree would basically be a List of Nodes and all of the Nodes are added to that Asset. AFAIK, ScriptableObjects are the only way to Save/Load “something” to be used later during runtime. IE, I build a tree in a visual editor extension, save the tree, and I tell some component to Load that Asset. I could be wrong though as I only got a very basic tree Asset processing.
That’s what I figured. Thanks superpid, just wanted to make sure I was on the right track. How would I use HideFlags? I have not used that yet. In this case, I don’t even need a List of the Nodes outside of re-drawing the Editor windows. I can just save the Nodes themselves with their references in the Asset…
Not exactly. If you want to save something out of the scene and into the project folder, the main class is likely to need to be a scriptable object, but everything else in the class just needs to be serializable to Unity (this would include other classes that don’t inherit from scriptableobject). Just because it a class needs to be saved, that doesn’t mean it needs to be a scriptable object, like how not every class needs to inherit from monobehaviour.
So I am guessing the only way to get this to work is to essentially copy everything from the AssetDatabase file to a new instance (like first response thread SerializedNode → Node)