InstanceData is used by both StateTree Tasks and StateTree Evaluators. It’s used to hold instance-specific data which can be changed at runtime, and can be bound to properties on other tasks or evaluators. Compare to properties directly on the instance struct, which are only settable via editor, and cannot be bound to other values.
Example
USTRUCT()
struct FMyInstanceData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category=Input)
int32 Foo = 0;
}
Categories
Properties on InstanceData structs should be assigned one of the following categories:
Input
: Values which are required to be bound to something.Output
: Values which are only used for outputting data.Parameter
: Optional input values which can be either bound to runtime values or edited in editor.
These categories can also be used in Blueprint-based tasks and evaluators for their properties.
Configuring InstanceData into a State Tree task
Once you have created the instance data struct, we need to tell the task which one it should use. This requires overriding GetInstanceDataType
, with an optional using
statement which is a common pattern:
struct FMySTTask : public FStateTreeTaskCommonBase
{
//This using statement is optional but a common pattern
using FInstanceDataType = FMyInstanceData;
virtual const UStruct* GetInstanceDataType() const override
{
return FMyInstanceData::StaticStruct();
}
}
Reading and writing InstanceData in the task
To read or write instancedata, use GetInstanceData
:
EStateTreeRunStatus FMySTTask::EnterState(FStateTreeExecutionContext& Context, const FStateTreeTransitionResult& Transition) const
{
FInstanceDataType& InstanceData = Context.GetInstanceData(*this);
//Do something with InstanceData
return EStateTreeRunStatus::Running;
}
Important note about writing into InstanceData:
When using
GetInstanceData
for purposes of outputting values to be used elsewhere in your state tree, remember to use a reference.
//This will not work for writing because you're getting a copy
FInstanceDataType Foo = Context.GetInstanceData(*this);
//This works, as it's a reference and will write into the correct place
FInstanceDataType& Foo = Context.GetInstanceData(*this);
Class-based InstanceData
You can also make your InstanceData an UObject. This is mainly useful if your task or evaluator runs logic which needs to bind dynamic delegates, since you cannot bind them to the task struct itself.
UCLASS()
class UMyInstanceData : public UObject
{
GENERATED_BODY()
}
For UObject data, you use StaticClass()
instead of StaticStruct()
in GetInstanceDataType()
virtual const UStruct* GetInstanceDataType() const override { return UInstanceDataType::StaticClass(); }
Instead of using GetInstanceData
, you need to use GetInstanceDataPtr
:
UInstanceDataType* InstanceData = Context.GetInstanceDataPtr<UInstanceDataType>(*this);
For more examples on how this is used, see FStateTreeTask_PlayContextualAnim
in engine code.