Correct workflow for saving/reloading a behavior

simonrcodrington

New member
Hi

I've got a question about the correct way to handle saving/loading state when it comes to behaviors. I would really appreciate any feedback because it feels like I'm not doing this optimally.

I've been using Behavior Designer to create various actions in my game. Each of these behaviors is an external behavior and takes care of a single series of tasks (such as collecting a resource, moving an agent to multiple positions etc).

I've created a prefab and it contains a BehaviorTree component with an external behavior and a custom monobehavior component. Here is a 'collectionResource' behavior.

Screenshot 2024-06-03 091259.png

Overall the agent will start, get given a 'resource' to look for, find that resource on one of the businesses, move to it, collect it and take it back to it's origin

The variables are all mapped from the external behaviors to the custom monobehavior component

Screenshot 2024-06-03 091322.png

The reason for this custom monobehavior along-side this behavior tree is that I need to save and load this data. I'm using Easy Save 3 to save the public variables on it and overall I'm able to save the values below :

1717370357872.png

And then re-load them later (right now it's just a button in the UI to load the data), but it calls the following:
1717370398226.png

Since this is a prefab, I just instantiate the prefab onto the agent and access my custom monobehavior on it, via that I can access the BehaviorTree component and set up variables (and start the behaviorTree). All of this works and I can swap out behaviors on the fly for a single agent (imagine a sim game where an agent can chop a tree, finish and then go mine gold etc)

My question is about HOW I'm supposed to set these behavior trees up logically. If I load the data, all of the data gets copied back into the behavior (via setting the variables up as above) so that's great. However, because this could get saved at any moment, I'm having issues creating the trees such that the behavior can re-start and get back to the proper state it should be.

1717370623612.png

I've managed to get this working by setting this up as above, a top level SELECTOR that looks at a series of sequences, inside each of the sequences I've created a custom 'CompareSharedCollectionBehaviorType' which is a copy of your 'CompareSharedInt' comparison conditional. Inside the behavior I have a 'SharedCollectionBehaviorState' which is just a custom shared type so I can use an Enum here for comparisons. This lets me check the variable to see if it's 'START', 'SEARCH_BUSINESS', 'MOVE_TO_BUSINESS', 'MOVE_TO_ORIGIN' etc.

I tried to use the CODE editing options here, but i get a 500 ERROR when positing it. This system is just an enum, a shared enum I created and a comparison conditional.

To the right of this ENUM check is a custom action, where inside I manually update that 'SharedCollectionBehaviorState' variable. When I've successfully found a business, moved to the business or moved back to origin I update that accordingly. Like below, the start action just moves the state to the next, the search business phase.

This works fine, as soon as one of these tasks finishes, the selector returns true and the behavior finishes, when it finishes it restarts and now moves from left to right hitting each sequence and checking that conditional so it selects where it should execute from.

This works on this smaller behavior, but as I create more complex behaviors I feel like setting it up this way is going to become super complex. I've looked into the resources on Conditional Aborts, but I can't really see how they would help me improve this design (as it needs to be written in such a way that if we're creating a brand new agents it can move left to right, manually setting up it's data / when we reload it can resume at the proper state and continue)

Id really appreciate any feedback on how to improve this. I can make a small self-contained unity example if that would help illustrate what I'm trying to achieve.

Regards

Simon
 
Last edited:
Save/Load is not a feature supported by the current version of Behavior Designer. I am working on a DOTS version of Behavior Designer and in that version I have Save/Load working. So it will depend on your own implementation.

The behavior tree state is saved within the BehaviorManager objects. You'll need to make sure you save the state of all of those structures, and then load them correspondingly as well. The actual values for each task are saved within each task instance, which I believe that you are saving right now using Easy Save.

Unfortunately Save/Load is a pretty detailed topic so I'm not able to add it to version 1 of Behavior Designer.
 
Hey Justin thanks for the quick reply.

I've tried to use Easy Save previously to save the BehaviorTree object and ran into a recursion issue (it reached the max 64 depth limit) and when I had a look it just looks like it references itself over and over. I'll have a look again to see if I can save and reload that data

In my approach above (where I manually set those variables for the behavior), is there any better way I should be creating my trees? Right now it's basically a single Selector that will assess each child sequence and then depending on an enum it's either succeed or fail (eventually finding the correct sequence). In each of my 'actions' I'm basically performing a task and when it's complete I'm updating my enum and returning.

In previous threads I've read on here when people mentioned wanting to jump to a specific task you mentioned having conditional aborts and making the structure of the tree such that you eventually fall into the right sequence to continue where you left off, is there any better way by chance to do what I'm doing above or is this a decent way to handling it? (I'd hate to make a dozen of these and then find out later it's a terrible way of handling the issue)

Cheers
 
You will definitely be wanting to take the approach of saving the Behavior Tree / Behavior Manager objects. All of the execution state is saved within the Behavior Manager. While there is no way to jump to a specific task with the built in functionality, if you save the Behavior Manager state then you'll automatically be able to since that is where it stores what task is executing (as well as things like conditional aborts).
 
Back
Top