How to update Variable Property Mapping?

Zurigan

New member
What's the easiest (is there any!) way to update/add a property mapping programmatically?

C#:
tree.SetVariable("AttackRange", (SharedFloat)AttackRange);

Didn't seem to work ... in my case, I somehow lost all the mappings on 10 prefab entities, redoing these all by hand is tiresome. If it makes any difference each of the prefab entities is referencing the same external behaviour. Thanks!
 

chaneynow

New member
I would also like to know if there is any way to assign property mappings through code. I lose all property mappings when I share an External Behavior Tree placed on the External Behavior slot on the Behavior Tree Component. I understand why this happens. It's because the mappings are now to a different gameobject. But what a pain to have to reestablish all of the mappings. All of my properties are maintained in the same controller class so some way to establish a master reference to that class should be able to do it.
 

Justin

Administrator
Staff member
The variable mapping is stored within SharedVariable.PropertyMapping/PropertyMappingOwner so you should be able to set those at runtime. Make sure you call InitializePropertyMapping after the assignment so it updates the getters/setters.

Code:
sharedInt.PropertyMapping = "UnityEngine.Transform/childCount";
sharedInt.PropertyMappingOwner = myGameObject;
sharedInt.InitializePropertyMapping(behaviorTreeSource);
 

Zurigan

New member
Ah great, many thanks ... I've added this extension method to my project:

C#:
    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());
    }

... would be handy if InitializePropertyMapping() could give errors/warnings if (ok when) called on a protected/private property!
 

Zurigan

New member
I ran into a problem using the above while setting external the external behavior tree through code. If you Init() the pooled trees, as per the example code, then setting new mappings like this seems to get ignored.

I 'fixed' this by taking out the Init() completely. Then setting property mappings triggers the CheckSerialization() setup, everything works as expected again ... really confused by this.

Is there a way to change either the Init() call or the SetPropertyMapping() extension method (above) so it all works?

edit - the issue with delaying CheckSerialization() until property mappings are set is that this removes the point of pre-pooling in shifting heavy loading operations up-front / hidden behind a load screen.
 
Last edited:

Justin

Administrator
Staff member
After the tree is initialized you should call the set property mapping. If you call it before the tree is initialized there's a chance that not all of the variables are setup for that behavior tree.
 

Zurigan

New member
The issue is that if I set property mappings after initializing the tree then the mapping doesn't work. The mapping is visible in the BD Editor, it 'looks' fine, but updating the underlying property doesn't do anything - the tree values won't ever reflect the underlying property value.
 

Zurigan

New member
Finally tracked this down to this code in SharedVariable.cs:

C#:
if (!BehaviorManager.IsPlaying || !(behaviorSource.Owner.GetObject() is Behavior)) {
    return;
}

The issue is behaviorSource.Owner is of type ExternalBehaviorTree ... so the mGetter/mGetter are never set. I fixed this by changing this to:

C#:
if (!BehaviorManager.IsPlaying) {
    return;
}

As a sanity check this is the sequence of operations:

C#:
// in Awake(), on a singleton, runs as soon as the program starts.
Awake(){
    externalTree = Instantiate(monsterTree);
    externalTree.Init();
}


// later, when I want an entity alive using that external tree. At this point, 'behaviorTree' exists as a component but doesn't contain any tasks or variables.
EntityInit(){

...

    behaviorTree.ExternalBehavior = GetExternalTreeFromSingleton();
    // now 'behaviorTree' has a bunch of variables, has the external tree, but nothing mapped.
    behaviorTree.SetPropertyMapping("EntityController", gameObject, nameof(MovementSpeed), MovementSpeed);

...

}

// updated extension method to add property mapping to a tree
public static void SetPropertyMapping(this BehaviorTree tree, string containingClassName, GameObject propertyMappingOwner, string propertyName, object property)

{
   var sharedVariable = tree.GetVariable(propertyName) ?? AddProperty(tree, propertyName, property);
   sharedVariable.PropertyMapping = containingClassName+"/"+propertyName;
   sharedVariable.PropertyMappingOwner = propertyMappingOwner;
   sharedVariable.InitializePropertyMapping(tree.GetBehaviorSource());
}

So ... is this a BD bug? Or was there some other way I should have been initializing everything?

FWIW - setting property mappings before setting the external tree doesn't solve this - the mapping itself does get copied over but the mGetter/setter still aren't assigned.
 

Justin

Administrator
Staff member
Or was there some other way I should have been initializing everything?
I wouldn't set the property mappings directly on the external tree. Instead you should set them on the behavior tree component after the external tree has been loaded.
 

Zurigan

New member
I wouldn't set the property mappings directly on the external tree. Instead you should set them on the behavior tree component after the external tree has been loaded.
As per my 'FWIW' at the end - this doesn't work either. The mapping gets created on the behavior tree correctly, then setting the external tree copies the mapping over but skips adding the getter/setters. The end result is the same - a mapping that 'looks' fine in the editor but doesn't work.
 
Top