Has anyone found a way to assign / update values to a StateTree parameter?
Yeah it get’s complicated. You have to use your evaluator in combination with your actor to pass information back and forth.
So you can’t update the parameter specifically, you use those as default values, pass them into your evaluator and then adjust there.
Hopefully that makes sense.
Does that work, sure, does it make sense? That is another story. The current workflow I have found makes parameters useless. If I am going to have default variables or anything I need to update or set from outside the actor using state tree I have to set up a bunch of variables on the actor. Was hoping this would be more like Blackboard and Behaviour Tree than needing to make an external data housing component or the such.
Can you elaborate? I tried what you described but it’s not working.
The parameter in state tree:
The variable in the evaluator:
Changing the variable’s value in the evaluator did not update the corresponding state tree parameter.
As far as I know, parameters are “set once, read only” data. If you want runtime parameters, you have to
- Make a task, global task or evaluator where the variable will be calculated.
- Make your variable in this object.
- Make it instance editable (click on the eye), or in C++ make it VisibleAnywhere or EditAnywhere (I believe either should work)
- Move it to the Output category. It must be spelled correctly, it won’t work otherwise.
- Add the task or evaluator object to the tree. If you did everything correctly, you should see a gray bubble saying OUT and you won’t be able to bind to this variable (since you’ll be writing to it)
- Set this variable only from this object.
Other tasks and evaluators can then bind themselves to read from this variable.
This is a poorly documented feature, but I got it to work doing these steps.
// for 5.4
template <typename T>
EPropertyBagResult SetStateTreeReferenceParameter(FStateTreeReference& StateTreeReference, const FName ValueName, const T& Value)
{
auto& InstancedPropertyBag = StateTreeReference.GetMutableParameters();
const auto PropertyBagResult = InstancedPropertyBag.SetValueStruct(ValueName, Value);
ensure(PropertyBagResult == EPropertyBagResult::Success);
// set overriden flag
if (auto* Desc = InstancedPropertyBag.FindPropertyDescByName(ValueName))
{
StateTreeReference.SetPropertyOverridden(Desc->ID, true);
}
return PropertyBagResult;
}
This is working but emitting warnings, and I didn’t test it in production.
Is making the variables on the actor itself an option or does it HAVE to be on the state tree?
Because on the context actor its easy peasy to read and write variables.
I need almost exactly this, just with the twist that I need to “write” into the evaluator’s variable, not just “read”.
Is this even possible?
Edit:
For anyone out there interested in the answer of my question:
It’s not possible manipulating the value of a variable of an Evaluator via a StateTree-Task. People I have talked with told me - if it is realy needed - to create global variables e.g in the Player’s ActorBP and to create a reference to that Actor in the “Context”-Section of the StateTree so that the tasks or any other area of StateTree can read/write those values via the vairable in that Actor.
Thank you!
This is the method that I have gone with. It works great because in all of the bindings (ie. enter conditions), you can reference variables from the context actor, all while being able to modify them anywhere necessary. HIGHLY recommend this approach.
Are you on 5.4? Have you tried using FStateTreePropertyRef for your tasks that you want to update the parameters? There are limitations on what can be used with FStateTreePropertyRef and the allowed types can be found in StateTreePropertyRef.h. It would require using C++ as the property refs are not Blueprintable.
-James
I just started using FStateTreePropertyRef today with UE 5.5 for writing values to variables from tasks to be used by later tasks and it works quite well. I used FStateTreeRunEnvQueryTask as reference and changed my tasks to be derived from FStateTreeTaskCommonBase instead of UStateTreeNodeBlueprintBase, which is viable for me since I’m not using blueprints for several of my tasks. When you create your InstanceData struct with the FStateTreePropertyRefs, you simply promote those to a parameter on the Task that will be writing to your variable, then reference the parameter in later tasks to get the modified value.
There are some things that do not work as expected. For the InstanceDataType structs, you cannot specify the Category of the FStateTreePropertyRef to be Output, otherwise you cannot promote/bind that to a parameter on the state tree. So for example, a runtime writable float would need to be declared like this without the Output category in order to be able to write to it:
UPROPERTY(EditAnywhere, Category = Out, meta = (RefType = "float"))
FStateTreePropertyRef AfterAttackDelay;
You don’t get the nice UI showing that the parameter is an output parameter this way unfortunately.
I can see how this can be confusing with using the property refs. The ref is inherently both an input and an output (possibly, but not a requirement as the ref to an array is faster than a copy).
Is the issue largely that the property ref does not show in the consuming task’s binding list as TaskName->AfterAttackDelay
like you see for an output parameter? The data from the ref is still able to be gathered as it is stored as a parameter on the tree, whereas the data from a task would be destroyed once the task ended if nothing was bound to the Output variable.