General feedbacks on Behavior

Hi,
Here are some feedback/bugs encontered during my usage of the Behavior package, version 1.0.3 on Unity 6000.0.23f1.

  • When creating a new EventChannel in the Blackboard, the name is “New New <Your_event channel_type>” → word “New” is doubled, not the case with other Blackboard variables types (fixed in 1.0.4)
  • When creating a new action, you can’t choose the base class UnityEngine.Object in the variable type list. I had to choose UnityEngine.GameObject and then changed it to UnityEngine.Object once the C# script was created.
  • I think we need to be able to pass raw UnityEngine.Object in conditions (even if it’s possible to bypass this issue using [SerializeReference] public BlackboardVariable Object; instead of [SerializeReference] public BlackboardVariable<UnityEngine.Object> Object;):
    – The function internal static bool IsBlackboardVariableTypeValid(FieldInfo field, ref Type invalidType) in NodeRegistry.cs has a mistake: the check bool isObject = type.IsSubclassOf(typeof(UnityEngine.Object)); should be bool isObject = type.IsSubclassOf(typeof(UnityEngine.Object)) || type == typeof(UnityEngine.Object); because typeof(UnityEngine.Object).IsSubclassOf(typeof(UnityEngine.Object)) return false. This prevent me to use a generic UnityEngine.Object variable in custom condition.
    – After fixing the previous point locally, it’s still not possible to use generic Unity Object in conditions due to error: ArgumentException: Object of type 'Unity.Behavior.BlackboardVariable1[UnityEngine.GameObject]' cannot be converted to type 'Unity.Behavior.BlackboardVariable1[UnityEngine.Object]'. System.RuntimeType.CheckValue (System.Object value, System.Reflection.Binder binder, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr). The conversion should be possible.
  • Creating an event with a C# keyword as variable name generate scripting error. Either block user creation with a warning or use @the_c_sharp_keyword in the generated script as variable name.
  • When creating an event (or action) with a variable of type Button, the namespace (in this case UnityEngine.UI) isn’t added in the created script, resulting in script compilation error.
  • When choosing the type in the wizard list, it doesn’t display the namespace, so you can have this issue, which one to choose? One is a custom script without namespace, the other is the UnityEngine.UI button.
  • When typing in the inputfield during the action create wizard, using Ctrl+Z undo previous actions in the graph in the background instead of in the wizard. In my case, I deleted by mistake my action description and couldn’t use Ctrl+Z to undo my mistake, I had to redo mannually everything.
  • After creating an event channel with 2 variables, I wanted to invert those variables order. I inverted everything in the script (including in the message). I had no errors, no warnings, but in the public override void SendEventMessage(BlackboardVariable[] messageData) of my event channel, messageData[0] and messageData[1] are still given in the orignial order, thus creating error at runtime. In the graph window, everything is fine. I had to manually find wrong nodes in my graphs, delete and recreate them to reserialize their variables in correct order.
  • After creating an action with a gameObject variable, I decided to change it to a struct because I needed an additionnal boolean.
Script
using System;
using Unity.Behavior;
using UnityEngine;
using Action = Unity.Behavior.Action;
using Unity.Properties;

public struct TestStruct
{
    public GameObject go;
    public bool enable;
}


[Serializable, GeneratePropertyBag]
[NodeDescription(name: "TestStruct", story: "Testing [Struct]", category: "Action", id: "c31205f50f9e1d44fcc81c75a94d87b5")]
public partial class TestStructAction : Action
{
    [SerializeReference] public BlackboardVariable<TestStruct> Struct;

    protected override Status OnStart()
    {
        return Status.Running;
    }

    protected override Status OnUpdate()
    {
        return Status.Success;
    }

    protected override void OnEnd()
    {
    }
}

Now the graph window doesn’t display the graph anymore and spam this error in the console:

Error log

NullReferenceException: Object reference not set to an instance of an object
Unity.Behavior.ReflectionElement+<>c.b__5_0 (System.String variableName, Unity.Behavior.GraphFramework.SerializableType type) (at ./Packages/com.unity.behavior/Authoring/UI/AssetEditor/Nodes/ReflectionElement.cs:50)
Unity.Behavior.StoryElementUtility.FindAndAddField (System.String fieldName, System.Collections.Generic.List1[T] variables, UnityEngine.UIElements.VisualElement element, Unity.Behavior.StoryElementUtility+OnCreateLinkField onCreateLinkField, Unity.Behavior.StoryElementUtility+OnCreateComparisonElement comparisonElementCallback) (at ./Packages/com.unity.behavior/Authoring/UI/StoryElementUtility.cs:93) Unity.Behavior.StoryElementUtility.CreateStoryElement (System.String story, System.Collections.Generic.List1[T] variables, UnityEngine.UIElements.VisualElement element, Unity.Behavior.StoryElementUtility+OnCreateLinkField onCreateLinkField, Unity.Behavior.StoryElementUtility+OnCreateComparisonElement comparisonElementCallback) (at ./Packages/com.unity.behavior/Authoring/UI/StoryElementUtility.cs:35)
Unity.Behavior.ReflectionElement.CreateFields (Unity.Behavior.NodeInfo nodeInfo) (at ./Packages/com.unity.behavior/Authoring/UI/AssetEditor/Nodes/ReflectionElement.cs:47)
Unity.Behavior.ActionNodeUI.InitFromNodeInfo (Unity.Behavior.NodeInfo nodeInfo) (at ./Packages/com.unity.behavior/Authoring/UI/AssetEditor/Nodes/ActionNodeUI.cs:36)
Unity.Behavior.ActionNodeUI…ctor (Unity.Behavior.GraphFramework.NodeModel nodeModel) (at ./Packages/com.unity.behavior/Authoring/UI/AssetEditor/Nodes/ActionNodeUI.cs:25)
System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object parameters, System.Boolean wrapExceptions) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object parameters, System.Boolean wrapExceptions) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Reflection.RuntimeConstructorInfo.DoInvoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object parameters, System.Globalization.CultureInfo culture) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Reflection.RuntimeConstructorInfo.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object parameters, System.Globalization.CultureInfo culture) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object args, System.Globalization.CultureInfo culture, System.Object activationAttributes, System.Threading.StackCrawlMark& stackMark) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object args, System.Globalization.CultureInfo culture, System.Object activationAttributes) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Activator.CreateInstance (System.Type type, System.Object args) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
Unity.Behavior.GraphFramework.GraphViewState.CreateNodeUI (Unity.Behavior.GraphFramework.NodeModel nodeModel) (at ./Packages/com.unity.behavior/Tools/Graph/GraphView.cs:439)
Unity.Behavior.GraphFramework.GraphViewState.RefreshNodeUI (System.Boolean isDragging, System.Collections.Generic.List`1[T] nodesToRefresh) (at ./Packages/com.unity.behavior/Tools/Graph/GraphView.cs:370)
Unity.Behavior.GraphFramework.GraphViewState.RefreshFromAsset (System.Boolean isDragging) (at ./Packages/com.unity.behavior/Tools/Graph/GraphView.cs:244)
Unity.Behavior.GraphFramework.GraphView.RefreshFromAsset () (at ./Packages/com.unity.behavior/Tools/Graph/GraphView.cs:158)
UnityEngine.UIElements.VisualElement+SimpleScheduledItem.PerformTimerUpdate (UnityEngine.UIElements.TimerState state) (at <39dcd6cb83f94d46afd27f779648424a>:0)
UnityEngine.UIElements.TimerEventScheduler.UpdateScheduledEvents () (at <39dcd6cb83f94d46afd27f779648424a>:0)
UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.UpdateSchedulers () (at <39dcd6cb83f94d46afd27f779648424a>:0)
UnityEngine.UIElements.UIEventRegistration.UpdateSchedulers () (at <39dcd6cb83f94d46afd27f779648424a>:0)
UnityEditor.RetainedMode.UpdateSchedulers () (at :0)

It will be way better to take care of this error, display the graph with the “placeholder node” that user can delete, or fix the script.
Are custom structs usage in action/event channel supported? I tried to add [Serializable] and/or [GeneratePropertyBag] to my struct but it didn’t change anything. I backed off to simply use 2 variables in my action.

  • I miss events to know the progress of the graph in the BehaviorAgent component. I would love to have a loopPointReached event similar to the VideoPlayer that is triggered when the graph execution ends or restart because repeat is activated.
  • When building for IL2CPP, a script called BehaviorIL2CPPTypes is created at the root of the asset folder. Please let us move it where we want in the project (for me Assets/Scripts/Behavior) without failing at the next build. Other solution might be to automatically delete it after the build completed. (fixed in 1.0.4, moved to Library/com.unity.behavior :slight_smile:)
  • The package decalare a dependency on newtonsoft json but don’t use it at all. It uses the Unity serialization package instead.

Thank you for this package. Fixing those quirks in the futur will improve user experience :slight_smile:

1 Like

All of the above! I’ll also add:

  • There is no way to delete an existing subgraph representation. If you clear the text field and hit confirm, it doesn’t delete it from the scriptable object for that graph.
  • Allow us to render out multiple conditions if we want to rather than grouping them together with the label “If any of 2 Conditions are true”. I have just been using separate condition guards to avoid that like so:
  • A way to add variables for a List of components other than GameObjects

Hi @Pitou22 ,

Thank you for the feedback and sorry for the delayed response! I’m still catching up post time-off and sickness.

Let me address these 1 by 1.

When creating a new EventChannel in the Blackboard, the name is “New New <Your_event channel_type>” → word “New” is doubled, not the case with other Blackboard variables types

This is now fixed internally and will be out in 1.0.4.

When creating a new action, you can’t choose the base class UnityEngine.Object in the variable type list. I had to choose UnityEngine.GameObject and then changed it to UnityEngine.Object once the C# script was created.

We can add this :+1:

I think we need to be able to pass raw UnityEngine.Object in conditions (even if it’s possible to bypass this issue using [SerializeReference] public BlackboardVariable Object; instead of [SerializeReference] public BlackboardVariable<UnityEngine.Object> Object; ):

Can you help clarify what’s missing? You mentioned public BlackboardVariable Object, but to be clear, you want public BlackboardVariable<UnityEngine.Object> Object ? Is there any issue beyond the fact you need to do it in the code right now? I assume we probably need to add casters for it. We can do that :slight_smile:

– The function internal static bool IsBlackboardVariableTypeValid(FieldInfo field, ref Type invalidType) in NodeRegistry.cs has a mistake: the check bool isObject = type.IsSubclassOf(typeof(UnityEngine.Object)); should be bool isObject = type.IsSubclassOf(typeof(UnityEngine.Object)) || type == typeof(UnityEngine.Object); because typeof(UnityEngine.Object).IsSubclassOf(typeof(UnityEngine.Object)) return false . This prevent me to use a generic UnityEngine.Object variable in custom condition.

Thank you! Will fix it :slight_smile:

– After fixing the previous point locally, it’s still not possible to use generic Unity Object in conditions due to error: ArgumentException: Object of type 'Unity.Behavior.BlackboardVariable1[UnityEngine.GameObject]' cannot be converted to type 'Unity.Behavior.BlackboardVariable1[UnityEngine.Object]'. System.RuntimeType.CheckValue (System.Object value, System.Reflection.Binder binder, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) . The conversion should be possible.

I’ll fix this also!

Creating an event with a C# keyword as variable name generate scripting error. Either block user creation with a warning or use @the_c_sharp_keyword in the generated script as variable name.

We’ll look into adding @ :slight_smile:

When creating an event (or action) with a variable of type Button, the namespace (in this case UnityEngine.UI) isn’t added in the created script, resulting in script compilation error.

We’ll investigate this! Thank you.

When choosing the type in the wizard list, it doesn’t display the namespace, so you can have this issue, which one to choose? One is a custom script without namespace, the other is the UnityEngine.UI button.

Yikes! We’ll chat with Design to see what’s the right way to go about this. It might take a bit more work to fix due to the architecture of our search window.

When typing in the inputfield during the action create wizard, using Ctrl+Z undo previous actions in the graph in the background instead of in the wizard. In my case, I deleted by mistake my action description and couldn’t use Ctrl+Z to undo my mistake, I had to redo mannually everything.

Yikes! I’ll open a bug.

After creating an event channel with 2 variables, I wanted to invert those variables order. I inverted everything in the script (including in the message). I had no errors, no warnings, but in the public override void SendEventMessage(BlackboardVariable[] messageData) of my event channel, messageData[0] and messageData[1] are still given in the orignial order, thus creating error at runtime. In the graph window, everything is fine. I had to manually find wrong nodes in my graphs, delete and recreate them to reserialize their variables in correct order.

This makes sense as it serialized it in the original order. We’ll have to look into potential solutions.

After creating an action with a gameObject variable, I decided to change it to a struct because I needed an additionnal boolean.

I’m afraid we don’t support custom struct or classes as BlackboardVariables yet, only UnityEngine.Object derivatives. It’s coming. We should improve error handling for now.

  • I miss events to know the progress of the graph in the BehaviorAgent component. I would love to have a loopPointReached event similar to the VideoPlayer that is triggered when the graph execution ends or restart because repeat is activated.

I’m not sure I understand this one, can you clarify it for me?

  • When building for IL2CPP, a script called BehaviorIL2CPPTypes is created at the root of the asset folder. Please let us move it where we want in the project (for me Assets/Scripts/Behavior) without failing at the next build. Other solution might be to automatically delete it after the build completed.

Yes! We have a task to change this. The person who has it is currently out of office. Hopefully soon!

@fendercodes

There is no way to delete an existing subgraph representation. If you clear the text field and hit confirm, it doesn’t delete it from the scriptable object for that graph.

Sounds like a bug! I’ll open a ticket :slight_smile:

Allow us to render out multiple conditions if we want to rather than grouping them together with the label “If any of 2 Conditions are true”. I have just been using separate condition guards to avoid that like so:

We’ll add the truncate option explicitly to it also :slight_smile:

A way to add variables for a List of components other than GameObjects

Yes! It’s coming :slight_smile:

Thank you both for the feedback!!

Hi @ShaneeNishry, thank you for reading my list and answering clearly point by point, no worries for the delay, take care of yourself :slight_smile:

Yes, that’s it. I just want to use public BlackboardVariable<UnityEngine.Object> Object in code. In 1.0.3, we can’t because of the two sub-points I mentionned just after.

First, I just noticed the component BehaviorGraphAgent is displayed as Behavior Agent in inspector. It’s better to keep the same name displayed in inspector as the name to use in script to avoid confusion.

The BehaviorGraphAgent component gives access to the BehaviorGraph, and the graph has public properties such as “IsRunning”. I want to know when my graph ended (regardless of what’s happening in the graph), so I have to do active check to know when it ends running:

private bool wasRunning = true;

void Update()
{
    if (wasRunning && !_behaviorGraphAgent.Graph.IsRunning)
    {
        wasRunning = false;
        // do my custom thing
    }
}

Instead of doing this, I’d like to have an event in the graph that is raised when it ends or starts to repeat. It can be like what the Unity VideoPlayer does with its loopPointReached event :slight_smile:

Ahh thank you for clarifying! I’ll add tickets for that :slight_smile:

1 Like

@Pitou22 , follow up, would you also like a callback for when execution ended? Would you like it to trigger before if it’s about to restart or only if it ended?

In my usecase, I don’t repeat the graph, so an event just for the end will be fine.

But thinking wider, it can be also usefull for repeating graph. Imagine you want to count how many time a graph has repeated in a BehaviorGraphAgent.

The event triggered can be the same for when execution ended and before graph restart.

Hi @Pitou22 ,

FYI a fix for this is in review right now. I noticed it was working in Nodes, but not events and I’ve made sure it works for both :slight_smile:

1 Like

Hey @Pitou22 , just letting you know this is in the works! I’m working with UX to improve this :grimacing:

1 Like

Hey, thank you for the updates!

Keep up the good work :slight_smile: :+1:

You’re welcome! Support for UnityEngine.Object variable is next on my list :smiley: