Can't quite get PropertyMapping for external trees on a prefab working

CToia

New member
I am trying to set some variables such as sharedSpeed for an external tree that is on an prefab.

When my prefab is created (at runtime), I have this which pulls the stats from my scriptable, sets the values and then maps them to the behavior tree component on this entity:
Code:
   public ScriptableUnitBase UnitData; // Reference to ScriptableUnitBase

    private void Awake()
    {
        // Initialise unit stats
        SetStats(UnitData.BaseStats);
        // set stat values here
        UnitData.UpdateBaseIntStat(Stats.StatType.Health, 150);
        UnitData.UpdateBaseFloatStat(Stats.StatType.Speed, 100);
        //Debug.Log(Stats.health);

        var gameObject = this.gameObject;
        var behaviorTree = GetComponent<BehaviorTree>();
        behaviorTree.SetPropertyMapping("sharedSpeed", UnitData.BaseStats.speed.ToString(), gameObject);
        behaviorTree.EnableBehavior();
    }

I have a BehaviorTreeExtensions.cs file that contains the SetPropertyMapping method:
Code:
using UnityEngine;
using BehaviorDesigner.Runtime;

public static class BehaviorTreeExtensions
{
    public static void SetPropertyMapping(this BehaviorTree tree, string treeVariableName, string mapping, GameObject owner)
    {
        var sharedVariable = tree.GetVariable(treeVariableName);
        sharedVariable.PropertyMapping = mapping;
        sharedVariable.PropertyMappingOwner = owner;
        sharedVariable.InitializePropertyMapping(tree.GetBehaviorSource());
    }
}

The sharedSpeed variable is being updated in the behavior tree inspector but an error is being thrown:
ArgumentException: Type cannot be null.
BehaviorDesigner.Runtime.SharedVariable

Now, it looks to be because the variable is on the external tree and the variable it is trying to map to must be on the behavior tree component itself. How do I map to the external tree variable that is on my objects behavior tree component?
 
Last edited:
I've made some progress.

Here is my updated CharacterUnitBase script (which is extended by Character, which is the script component that is attached to my prefab):
Code:
public abstract class CharacterUnitBase : UnitBase
{
    public ScriptableUnitBase UnitData; // Reference to ScriptableUnitBase

    protected void Start()
    {
        // Initialise unit stats
        SetStats(UnitData.BaseStats);
        // set stat values here
        UnitData.UpdateBaseIntStat(Stats.StatType.health, 150);
        UnitData.UpdateBaseFloatStat(Stats.StatType.speed, 100);
        //Debug.Log(Stats.health);
        var speed = UnitData.BaseStats.speed;
        var gameObject = this.gameObject;
        var behaviorTree = GetComponent<BehaviorTree>();
        behaviorTree.SetPropertyMapping("sharedSpeed", nameof(speed), speed, gameObject);
        behaviorTree.EnableBehavior();
    }
}

And, here is my updated SetPropertyMappings method:
Code:
public static class BehaviorTreeExtensions
{
    public static void SetPropertyMapping(this BehaviorTree tree, string treeVariableName, string mapping, object property, GameObject propertyMappingOwner)
    {
        Debug.Log($"SetPropertyMapping: {treeVariableName} {mapping} {propertyMappingOwner}");

        var sharedVariable = tree.GetVariable(treeVariableName);
        if (sharedVariable == null)
        {
            Debug.LogError($"SharedVariable not found for mapping: {treeVariableName}");
            return;
        } else
        {
            Debug.Log($"SharedVariable found for mapping: {treeVariableName}");
        }

        sharedVariable.PropertyMapping = "Character/" + mapping;
        sharedVariable.PropertyMappingOwner = propertyMappingOwner;
        sharedVariable.InitializePropertyMapping(tree.GetBehaviorSource());
    }
}

I can validate that the tree.GetVariable portion is working as the debug log is registering it as found. I think my issue is sitting in:

Code:
sharedVariable.PropertyMapping = "Character/" + mapping;

If I have a float that is being registered in CharacterUnitBase, which is extended by Character and attached to the prefab should property mapping be something other than Character/speed? (I'm trying to map it to sharedSpeed which is the tree variable).
 
The format of property mapped variables is:

FullPath/PropertyName

So for example:

UnityEngine.Animator/speed

The property mapping is local to the GameObject that the behavior tree is on. You are not able to grab the property from a different GameObject.
 
My speed variable is coming from a script component (Character) which is on the same game object as the tree. I've tried $"{nameof(Character)}/{nameof(speed)}"; but it doesn't work. I don't get any errors. Is there some other way to get the full path of the script component or a way around this?

Might be worth checking if I am approaching this right. I am trying to load the characters stats from a scriptable. Is property mapping what I should be using? I want a 2 way sync for the variables.
 
Actually, rather than keep them in sync, I will use GetVariable and SetVariable. I think I was unnecessarily trying to find a sync state.
 
My speed variable is coming from a script component (Character) which is on the same game object as the tree. I've tried $"{nameof(Character)}/{nameof(speed)}"; but it doesn't work. I don't get any errors. Is there some other way to get the full path of the script component or a way around this?
If you do a GetType() within your character component what is the path to it? Also, is speed a public property that has a getter and setter?

Might be worth checking if I am approaching this right. I am trying to load the characters stats from a scriptable. Is property mapping what I should be using? I want a 2 way sync for the variables
Yes, that is correct.
 
Sorry for the delayed response. I got back into looking at this and can see I hadn't added a getter and setter to my speed property... it works great now. Thanks!
 
Top