I’m using State Tree in my C++ code.
NPC is always null in Condition while in task its available.
USTRUCT()
struct WAREHOUSEBOI_API FIsAtSpawnLocationConditionInstance
{
GENERATED_BODY()
UPROPERTY(VisibleAnywhere, Category = "Output")
TWeakObjectPtr<ATruckDriverNPC> NPC;
};
USTRUCT(meta = (DisplayName = "Is At Spawn Location"))
struct WAREHOUSEBOI_API FIsAtSpawnLocationCondition : public FStateTreeConditionCommonBase
{
GENERATED_BODY()
using FInstanceDataType = FIsAtSpawnLocationConditionInstance;
virtual bool TestCondition(FStateTreeExecutionContext& Context) const override;
virtual const UStruct* GetInstanceDataType() const override { return FIsAtSpawnLocationConditionInstance::StaticStruct(); }
UPROPERTY(EditAnywhere, Category = "Parameters")
float AcceptanceRadius = 10.0f;
};
// CPP
bool FIsAtSpawnLocationCondition::TestCondition(FStateTreeExecutionContext& Context) const
{
const FIsAtSpawnLocationConditionInstance& Instance = Context.GetInstanceData<FIsAtSpawnLocationConditionInstance>(*this);
const ATruckDriverNPC* NPC = Instance.NPC.Get();
if (!NPC) return false;
const float DistanceToSpawn = FVector::Distance(NPC->GetActorLocation(), NPC->SpawnPosition);
return DistanceToSpawn <= AcceptanceRadius;
}
As you can see in the below State Tree Details panel I have assigned NPC in Task which I got from the Evaluator context.
Evaluator:
evaluator header:
USTRUCT()
struct WAREHOUSEBOI_API FTruckDriverNPCEvaluatorInstance
{
GENERATED_BODY()
UPROPERTY(VisibleAnywhere, Category = "Output")
TWeakObjectPtr<ATruckDriverNPC> NPC;
};
/**
* Evaluator that provides NPC reference to all State Tree tasks and conditions
* This runs once at State Tree startup and makes the NPC available everywhere
*/
USTRUCT(meta = (DisplayName = "Truck Driver NPC Reference"))
struct WAREHOUSEBOI_API FTruckDriverNPCEvaluator : public FStateTreeEvaluatorCommonBase
{
GENERATED_BODY()
virtual void TreeStart(FStateTreeExecutionContext& Context) const override;
virtual const UStruct* GetInstanceDataType() const override
{
return FTruckDriverNPCEvaluatorInstance::StaticStruct();
}
};
evaluator cpp
/*
* 1. Runs once at State Tree startup
2. Gets the owner actor (your NPC)
3. Stores reference in the evaluator instance
4. All tasks/conditions can access this reference through their instance data
*/
void FTruckDriverNPCEvaluator::TreeStart(FStateTreeExecutionContext& Context) const
{
FTruckDriverNPCEvaluatorInstance& Evaluator = Context.GetInstanceData<FTruckDriverNPCEvaluatorInstance>(*this);
// Get the Actor that owns this State Tree Component
AActor* Owner = Cast<AActor>(Context.GetOwner());
if (!Owner)
{
UE_LOG(LogTemp, Error, TEXT("FTruckDriverNPCEvaluator::TreeStart: No Actor found for State Tree Component."));
return;
}
Evaluator.NPC = Cast<ATruckDriverNPC>(Owner);
if (!Evaluator.NPC.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("FTruckDriverNPCEvaluator: Owner is not a TruckDriverNPC"));
} else
{
UE_LOG(LogTemp, Warning, TEXT("FTruckDriverNPCEvaluator: Successfully bound to NPC %s"), *Evaluator.NPC->GetName());
}
}