Behavior Package 1.0.7 Released! Changelog inside

Hey all,

Ho, ho ho! Ok, perhaps Santa isn’t my style, but!! We’re happy to announce the release of 1.0.7, with a bunch more fixes!

I apologise for the delay, we hoped to release it last week, but some things we wanted to include weren’t quite ready yet. Thank you for your patience.

Please keep sending us feedback and being amazing at communicating with us so we can make this the best game AI / behavior tree package for you! :slight_smile:

Changelog below:

Added

  • Added new Interrupted status and ensure that all incomplete child nodes of Parallel composites are marked as interrupted.

  • Added a checkbox to the behavior project settings to contnrol if nodes and condition scripts should automatically open after creation.

Changed

  • Selection of a node now brings it to the front.

  • Selection of a node in a sequence brings the sequence to the front.

  • Small tweak to node selected border radius.

  • Nodes replaced with Placeholder Nodes will not be replaced in the asset, only in the UI, reducing risk in recovery.

  • When saving a new Node/Condition from the wizard, a postfix of the node type (Action/Modifier/Flow) or Condition won’t be added to the suggested filename if it already ends with it.

  • Updated AppUI dependency to 2.0.0-pre14 and created a settings file to exclude AppUI Shaders and execution from builds. This can be overriden with a custom user App UI Settings file.

  • Exposed SaveFolderEventChannels in the Project Settings → Behavior menu.

  • Improved documentation description for the GameObject API inside the Node class.

  • Improved asset rebuilding and saving mechanism to avoid frequent regeneration.

Fixed

  • Editing Subgraph Representation will no longer add duplicate variables.

  • Softened search fields filtering so that, for example, ‘int list’ and ‘list int’ will return ‘Integer List’.

  • Fixed WaitForAnyComposite not ending correctly yielding multiple runs of child nodes.

  • Editing a node with the node wizard (edit node definition) will no longer remove to Action/Modifer/Sequence postfix.

  • Fixed an issue where automatic save path for enums and event channels saved the file name into the save path settings and caused an infinite loop when saving the next file.

  • Remove erroneous references to Muse in the API docs.

  • Improved Undo support for editing Behavior Agent on a GameObject.

  • Adding a Run In Parallel node and its various types from the branch dialog will set the correct mode.

  • Subassets of Graph and Blackboard will have their names track more correctly with the main asset.

  • BehaviorWindow will now close during autosave if its asset is invalid.

Known Issues

  • Deleting a behavior graph asset while the window is open can cause the graph editor window to be stuck and the user will need to reset their layout to get rid of it.

  • Runtime serialization of nodes in user assemblies don’t serialize some properties correctly.

  • Assigning values in a subgraph node using subgraph representation doesn’t correctly override the value, as a workaround you should assign them in the node inspector for the subgraph instead.

  • AppUI sometimes throws an error about collection modified, recommend updating to AppUI pre15 for the fix. We’ll update the dependency for the next release.

14 Likes

When I tested it the next day, debugging worked perfectly… It seems like it was a temporary issue with the Unity editor.


Hello, When I first used this package, I was really impressed by its excellent UX.

I have recently started using your Behavior package in my command system. As you can see in the code below, I designed the system to start and stop behaviors using the enabled field of the Behavior Agent component, and it works as expected.

However, when call _agent.Restart(); method , the debugging connection for all selected objects is lost, and I have to re-select the object to continue debugging. I don’t consider this issue to be of high priority, but I hope it will be fixed someday.


using System;
using System.Threading;
using Santutu.RTS.Commandable.Runtime.NCommand;
using Unity.Behavior;
using UnityEngine;

namespace Santutu.RTS.Commandable.Samples.Scripts.Commands
{
    [Serializable]
    public struct AttackTargetCommand : ICommand
    {
        private readonly BehaviorGraphAgent _agent;

        [field: SerializeField] public GameObject Target { get; set; }


        public AttackTargetCommand(BehaviorGraphAgent agent, GameObject target)
        {
            _agent = agent;
            Target = target;
        }

        public void OnStart()
        {
            _agent.BlackboardReference.SetVariableValue("Target", Target);
            _agent.Restart();
            _agent.enabled = true;
        }

        public async Awaitable Execute(CancellationToken ct = default)
        {
            while (true)
            {
                ct.ThrowIfCancellationRequested();

                if (!_agent.Graph.IsRunning)
                {
                    return;
                }

                await Awaitable.NextFrameAsync(ct);
            }
        }

        public void OnEnd()
        {
            _agent.enabled = false;
        }
    }
}

Hello, it seems that the Restart() function on line 481 of BehaviorGraphAgent.cs should execute the following: m_IsStarted = true;. When Restart() is called while m_IsStarted is false, Start gets called twice due to the Update, causing unexpected behavior.

1 Like

Is it possible to add a feature to insert a node by dragging it onto an edge? Surprised how often I need to delete an edge + reconnect nodes, it would be really useful, I think.

1 Like

Hello,
I’ve been exploring your behavior package further, and I believe it would be great if UnityEvents could be added to the blackboard.

This feature could enable various useful functionalities, allowing agents to behave differently depending on the object, which would ultimately enhance the reusability of behaviors.

Currently, my use case involves registering listeners to determine whether to deal damage or perform some other action on a per-object basis when an ability-used event occurs.

The image below shows a simple mockup I tried as an experiment.

2 Likes

Hi @santutu2 & @Redrag0n,

Great suggestions in general, Unity Events is definitely something we want to see working in the future.

For the issue you mentioned Santutu, do you have repro steps with how I can reproduce easily so I can test my side & look into fixing the issue?

3 Likes

Hello. This is an edge case, and I don’t think this will cause any bugs in the actual game, so I consider it a very minor issue.

It can be implemented with a simple behavior and test mono code.

using Unity.Behavior;
using UnityEngine;


public class Test : MonoBehaviour
{
    public BehaviorGraphAgent agent;

    private void Start()
    {
        agent.enabled = false;
    }

    public void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            agent.Restart();
            agent.enabled = true;
        }

        else if (Input.GetKeyDown(KeyCode.S))
        {
            agent.enabled = false;
        }
    }
}

After playing the game,

When pressing the A button for the first time:

Expected - “test” should print once

Actual - “test” prints twice

When pressing the S button and then pressing the A button again:

Expected - “test” should print once

Actual - “test” prints once

In other words, the update occurs twice only during the initial enable.

I don’t know the exact internal cause, but it seems to be happening because the restart function doesn’t set m_IsStarted = true;

I’m a little concerned about performance at the moment.
The graph generates about 320b GC every other frame or so, and this is for a simple Update (1 node is at Running) with no actual calculations performed. Any repeats\cycles will balloon GC generation up to 2Kb. It’s not uncommon to have 5Kb+ GC generation every other frame. Thankfully, it seems that the number of agents doesn’t matter and this amount is the same for 1 or 1000 agents, but still, that’s a lot.
Is my readings correct? Will it be possible to do something about it? Should I be worried at all (I don’t know how bad is 2.5Kb\frame GC in 2025)?

1 Like

Hi @Redrag0n,

We will be working on a runtime performance pass soon enough.
We will definitely be looking at all allocations made also.

Hope you have a great Christmas!

5 Likes

While 2.5Kb\frame GC is not so much, but it’s CPU pressure case, where CPU could perform tasks faster, before prepare next frame, but GC Alloc makes heap allocations, produces additional memory tracking and, of course, memory cleanup cycles, which also takes CPU time.
GC Alloc is a very slow operation (even more slow in case of OOP where allocations are fragemented = for the CPU it’s longer to lookup) in comparison with cache lookup or registers, so, this is more about effective CPU time usage.

On small scales it’s not problem and can be ignored in most cases, but bigger problem for the bigger projects and for the mobile platforms (where memory is slower and bandwidth is lesser).

2 Likes

Hi.
How to add custom type in blackboard?

using System;

[Serializable]
public class EntityReference
{
    public int Num;  
    //public Entity Entity {get; set;}   
}
[SerializeReference] public BlackboardVariable<EntityReference> EntytyReference;

This does not shows this type in blackboard and in task UI.

Hi @TextusGames,

Currently we only support custom blackboard variables that derive from MonoBehaviour.
We do want to support the use case you provided in the future and it’s on our roadmap, but we have some other things to tackle first.

Sorry about the inconvenience!

1 Like

I was trying to add variable dynamicly in black board from script.
And it seems worked.

Entity entity = ...;
behaviorGraphAgent.BlackboardReference.AddVariable("SelfEntity", entity);
behaviorGraphAgent.BlackboardReference.SetVariableValue("SelfEntity", entity);

But in Custom Action I can not access Graph.BlackBoard property.
I can access GameObject and get component BehaviorAgent and get blackboard reference.
But shouldn’t Action be able to access Blackboard or graph directly?

1 Like

Hi @TextusGames,

Inside custom Actions there is no way of knowing which graph or Blackboard is associated with an action.

You can pass a reference to a variable on the blackboard to the action via the inspector or in the node itself also.

The intended use & design is that an action can be used in many different graphs & each of those graphs can have their own blackboard. This way things can be made in a more modular way.

1 Like

That’s some decently fast progress but with such verbose node definition and obtuse workflow, it is still not aligned with Unity’s core mission: to make our life easier and to speed up iteration time.

For that, you need attribute + reflection on monos.

instant node definition

[Behavior]
Public bool MyInstantNode(float myFloat)
{
    if (behavior.isStarting) 
    {
          // node was just called
    }

}

running nodes

[Behavior]
Public void MyRunningNode(float myFloat)
{
    ...
    if (someCondition)
           Behavior.Succeed();
}

direct access

 
behavior.Goto ("Subtree Name")

And a hook in the profiler or a performance overlay so we can identify expensive reflection nodes and convert them into hard nodes.

Could someone please provide us with an example of interruption usage? It sounds like a very useful feature for me (I have it implemented in a rather messy way).

Thanks!

Hi @santutu2 ! Thanks for reporting this, we indeed missed it when reworking the init flow! We’ll get it for 1.0.8. Sorry about that!

2 Likes

Hi @laurentlavigne ,

Thank you for this feedback. However I would like to respectfully disagree with you on this:

  1. While it is true you could use an attribute to create actions, this would rely on reflection at runtime, which we want to avoid for performance sake.

  2. We help the user create all the boilerplate code by providing the “Node Wizards”, which guides them through creating actions and other nodes and generates all the boilerplate for them. You can do it all from inside the graph and go into your coding IDE immediately with a right click → edit script (also, by default we open the generated node for you).

  3. The example you show is stateless, which means serialization would be more complicated and less performant. Users tend to need serialization for production.

So while I see the merit in your suggestion, I don’t think we’re going against Unity’s mission, or that we’re overly verbose, especially given all the help we’re providing in the workflows to generate the boilerplate and aid users in serialization, which is something most Unity packages do not do and projects often need.

One thing I do think we should improve is adding Node creation options directly in the project window so you don’t need to open the graph for it and can do so just as you generate a C# script in your project.

Hi @mishakozlov74 !

Do you mean the new interrupt state we added to nodes, or do you mean the Abort/Restart nodes we have that might cancel a node’s execution?

The interrupt state is mostly for our own state tracking, but also for debugging because it’s neither a success or a failure so we needed to show it correctly.