// Copyright Epic Games, Inc. All Rights Reserved. #include "BehaviorTree/BTTaskNode.h" #include "AIController.h" #include "VisualLogger/VisualLogger.h" #include "GameplayTasksComponent.h" UBTTaskNode::UBTTaskNode(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { bNotifyTick = false; bNotifyTaskFinished = false; bIgnoreRestartSelf = false; } EBTNodeResult::Type UBTTaskNode::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) { return EBTNodeResult::Succeeded; } EBTNodeResult::Type UBTTaskNode::AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) { return EBTNodeResult::Aborted; } EBTNodeResult::Type UBTTaskNode::WrappedExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const { const UBTNode* NodeOb = bCreateNodeInstance ? GetNodeInstance(OwnerComp, NodeMemory) : this; return NodeOb ? ((UBTTaskNode*)NodeOb)->ExecuteTask(OwnerComp, NodeMemory) : EBTNodeResult::Failed; } EBTNodeResult::Type UBTTaskNode::WrappedAbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const { UBTNode* NodeOb = const_cast(bCreateNodeInstance ? GetNodeInstance(OwnerComp, NodeMemory) : this); UBTTaskNode* TaskNodeOb = static_cast(NodeOb); EBTNodeResult::Type Result = TaskNodeOb ? TaskNodeOb->AbortTask(OwnerComp, NodeMemory) : EBTNodeResult::Aborted; return Result; } bool UBTTaskNode::WrappedTickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds, float& NextNeededDeltaTime) const { if (bNotifyTick) { const UBTNode* NodeOb = bCreateNodeInstance ? GetNodeInstance(OwnerComp, NodeMemory) : this; if (NodeOb) { ((UBTTaskNode*)NodeOb)->TickTask(OwnerComp, NodeMemory, DeltaSeconds); NextNeededDeltaTime = 0.0f; return true; } } return false; } void UBTTaskNode::WrappedOnTaskFinished(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTNodeResult::Type TaskResult) const { UBTNode* NodeOb = const_cast(bCreateNodeInstance ? GetNodeInstance(OwnerComp, NodeMemory) : this); if (NodeOb) { UBTTaskNode* TaskNodeOb = static_cast(NodeOb); if (TaskNodeOb->bNotifyTaskFinished) { TaskNodeOb->OnTaskFinished(OwnerComp, NodeMemory, TaskResult); } if (TaskNodeOb->bOwnsGameplayTasks && OwnerComp.GetAIOwner()) { UGameplayTasksComponent* GTComp = OwnerComp.GetAIOwner()->GetGameplayTasksComponent(); if (GTComp) { GTComp->EndAllResourceConsumingTasksOwnedBy(*TaskNodeOb); } } } } void UBTTaskNode::ReceivedMessage(UBrainComponent* BrainComp, const FAIMessage& Message) { UBehaviorTreeComponent* OwnerComp = static_cast(BrainComp); check(OwnerComp); const uint16 InstanceIdx = OwnerComp->FindInstanceContainingNode(this); if (OwnerComp->InstanceStack.IsValidIndex(InstanceIdx)) { uint8* NodeMemory = GetNodeMemory(OwnerComp->InstanceStack[InstanceIdx]); OnMessage(*OwnerComp, NodeMemory, Message.MessageName, Message.RequestID, Message.Status == FAIMessage::Success); } else { UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Warning, TEXT("UBTTaskNode::ReceivedMessage called while %s node no longer in active BT") , *GetNodeName()); } } void UBTTaskNode::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) { // empty in base class } void UBTTaskNode::OnTaskFinished(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTNodeResult::Type TaskResult) { // empty in base class } void UBTTaskNode::OnMessage(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, FName Message, int32 RequestID, bool bSuccess) { const EBTTaskStatus::Type Status = OwnerComp.GetTaskStatus(this); if (Status == EBTTaskStatus::Active) { FinishLatentTask(OwnerComp, bSuccess ? EBTNodeResult::Succeeded : EBTNodeResult::Failed); } else if (Status == EBTTaskStatus::Aborting) { FinishLatentAbort(OwnerComp); } } void UBTTaskNode::FinishLatentTask(UBehaviorTreeComponent& OwnerComp, EBTNodeResult::Type TaskResult) const { // OnTaskFinished must receive valid template node UBTTaskNode* TemplateNode = (UBTTaskNode*)OwnerComp.FindTemplateNode(this); OwnerComp.OnTaskFinished(TemplateNode, TaskResult); } void UBTTaskNode::FinishLatentAbort(UBehaviorTreeComponent& OwnerComp) const { // OnTaskFinished must receive valid template node UBTTaskNode* TemplateNode = (UBTTaskNode*)OwnerComp.FindTemplateNode(this); OwnerComp.OnTaskFinished(TemplateNode, EBTNodeResult::Aborted); } void UBTTaskNode::WaitForMessage(UBehaviorTreeComponent& OwnerComp, FName MessageType) const { // messages delegates should be called on node instances (if they exists) OwnerComp.RegisterMessageObserver(this, MessageType); } void UBTTaskNode::WaitForMessage(UBehaviorTreeComponent& OwnerComp, FName MessageType, int32 RequestID) const { // messages delegates should be called on node instances (if they exists) OwnerComp.RegisterMessageObserver(this, MessageType, RequestID); } void UBTTaskNode::StopWaitingForMessages(UBehaviorTreeComponent& OwnerComp) const { // messages delegates should be called on node instances (if they exists) OwnerComp.UnregisterMessageObserversFrom(this); } #if WITH_EDITOR FName UBTTaskNode::GetNodeIconName() const { return FName("BTEditor.Graph.BTNode.Task.Icon"); } #endif // WITH_EDITOR void UBTTaskNode::OnGameplayTaskDeactivated(UGameplayTask& Task) { ensure(Task.GetTaskOwner() == this); UBehaviorTreeComponent* BTComp = GetBTComponentForTask(Task); if (BTComp) { // this is a super-default behavior. Specific task will surely like to // handle this themselves, finishing with specific result const EBTTaskStatus::Type Status = BTComp->GetTaskStatus(this); FinishLatentTask(*BTComp, Status == EBTTaskStatus::Aborting ? EBTNodeResult::Aborted : EBTNodeResult::Succeeded); } } //----------------------------------------------------------------------// // DEPRECATED //----------------------------------------------------------------------//