Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

320 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "BehaviorTree/BTNode.h"
#include "BTCompositeNode.generated.h"
class UBTCompositeNode;
class UBTDecorator;
class UBTService;
class UBTTaskNode;
DECLARE_DELEGATE_RetVal_ThreeParams(int32, FGetNextChildDelegate, FBehaviorTreeSearchData& /*search data*/, int32 /*last child index*/, EBTNodeResult::Type /*last result*/);
struct FBTCompositeMemory
{
/** index of currently active child node */
int8 CurrentChild;
/** child override for next selection */
int8 OverrideChild;
};
UENUM()
enum class EBTChildIndex : uint8
{
FirstNode,
TaskNode,
};
UENUM()
namespace EBTDecoratorLogic
{
// keep in sync with DescribeLogicOp() in BTCompositeNode.cpp
enum Type : int
{
Invalid,
/** Test decorator conditions. */
Test,
/** logic op: AND */
And,
/** logic op: OR */
Or,
/** logic op: NOT */
Not,
};
}
USTRUCT()
struct FBTDecoratorLogic
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
TEnumAsByte<EBTDecoratorLogic::Type> Operation;
UPROPERTY()
uint16 Number;
FBTDecoratorLogic() : Operation(EBTDecoratorLogic::Invalid), Number(0) {}
FBTDecoratorLogic(uint8 InOperation, uint16 InNumber) : Operation(InOperation), Number(InNumber) {}
};
USTRUCT()
struct FBTCompositeChild
{
GENERATED_USTRUCT_BODY()
/** child node */
UPROPERTY()
TObjectPtr<UBTCompositeNode> ChildComposite = nullptr;
UPROPERTY()
TObjectPtr<UBTTaskNode> ChildTask = nullptr;
/** execution decorators */
UPROPERTY()
TArray<TObjectPtr<UBTDecorator>> Decorators;
/** logic operations for decorators */
UPROPERTY()
TArray<FBTDecoratorLogic> DecoratorOps;
};
UCLASS(Abstract, MinimalAPI)
class UBTCompositeNode : public UBTNode
{
GENERATED_UCLASS_BODY()
/** child nodes */
UPROPERTY()
TArray<FBTCompositeChild> Children;
/** service nodes */
UPROPERTY()
TArray<TObjectPtr<UBTService>> Services;
AIMODULE_API ~UBTCompositeNode();
/** fill in data about tree structure */
AIMODULE_API void InitializeComposite(uint16 InLastExecutionIndex);
/** find next child branch to execute */
AIMODULE_API int32 FindChildToExecute(FBehaviorTreeSearchData& SearchData, EBTNodeResult::Type& LastResult) const;
/** get index of child node (handle subtrees) */
AIMODULE_API int32 GetChildIndex(FBehaviorTreeSearchData& SearchData, const UBTNode& ChildNode) const;
/** get index of child node */
AIMODULE_API int32 GetChildIndex(const UBTNode& ChildNode) const;
/** called before passing search to child node */
AIMODULE_API void OnChildActivation(FBehaviorTreeSearchData& SearchData, const UBTNode& ChildNode) const;
AIMODULE_API void OnChildActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIndex) const;
/**
* Notification called after child has finished search
* @param SearchData for any new addition or removal of extra aux nodes/ descriptor
* @param ChildNode is the children being deactivated
* @param NodeResult the raison of the deactivation
* @param bRequestedFromValidInstance the new requested search start is within the current active instances
*/
AIMODULE_API void OnChildDeactivation(FBehaviorTreeSearchData& SearchData, const UBTNode& ChildNode, EBTNodeResult::Type& NodeResult, const bool bRequestedFromValidInstance) const;
/**
* Notification called after child has finished search
* @param SearchData for any new addition or removal of extra aux nodes/ descriptor
* @param ChildIndex of the child node being deactivated
* @param NodeResult the raison of the deactivation
* @param bRequestedFromValidInstance the new request search start is within the current active instances
*/
AIMODULE_API void OnChildDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIndex, EBTNodeResult::Type& NodeResult, const bool bRequestedFromValidInstance) const;
/** called when start enters this node */
AIMODULE_API void OnNodeActivation(FBehaviorTreeSearchData& SearchData) const;
/** called when search leaves this node */
AIMODULE_API void OnNodeDeactivation(FBehaviorTreeSearchData& SearchData, EBTNodeResult::Type& NodeResult) const;
/** called when search needs to reactivate this node */
AIMODULE_API void OnNodeRestart(FBehaviorTreeSearchData& SearchData) const;
/** notify about task execution start */
AIMODULE_API void ConditionalNotifyChildExecution(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, const UBTNode& ChildNode, EBTNodeResult::Type& NodeResult) const;
/** size of instance memory */
AIMODULE_API virtual uint16 GetInstanceMemorySize() const override;
AIMODULE_API virtual void InitializeMemory(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTMemoryInit::Type InitType) const override;
AIMODULE_API virtual void CleanupMemory(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTMemoryClear::Type CleanupType) const override;
/** @return child node at given index */
UBTNode* GetChildNode(int32 Index) const;
/** @return children count */
int32 GetChildrenNum() const;
/** @return execution index of child node */
AIMODULE_API uint16 GetChildExecutionIndex(int32 Index, EBTChildIndex ChildMode = EBTChildIndex::TaskNode) const;
/** @return execution index of last node in child branches */
uint16 GetLastExecutionIndex() const;
/** set override for next child index */
AIMODULE_API virtual void SetChildOverride(FBehaviorTreeSearchData& SearchData, int8 Index) const;
/** gathers description of all runtime parameters */
AIMODULE_API virtual void DescribeRuntimeValues(const UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTDescriptionVerbosity::Type Verbosity, TArray<FString>& Values) const override;
/** check if child node can execute new subtree */
AIMODULE_API virtual bool CanPushSubtree(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32 ChildIdx) const;
#if WITH_EDITOR
/** @return allowed flow abort modes for decorators */
AIMODULE_API virtual bool CanAbortLowerPriority() const;
AIMODULE_API virtual bool CanAbortSelf() const;
#endif // WITH_EDITOR
/** find branch containing specified node index */
AIMODULE_API int32 GetMatchingChildIndex(int32 ActiveInstanceIdx, FBTNodeIndex& NodeIdx) const;
/** get first execution index of given branch */
AIMODULE_API uint16 GetBranchExecutionIndex(uint16 NodeInBranchIdx) const;
/** is child execution allowed by decorators? */
AIMODULE_API bool DoDecoratorsAllowExecution(UBehaviorTreeComponent& OwnerComp, const int32 InstanceIdx, const int32 ChildIdx) const;
bool IsApplyingDecoratorScope() const;
// Deprecated methods
UE_DEPRECATED(5.0, "This function is deprecated. Please use RequestBranchDeactivation instead.")
void OnChildDeactivation(FBehaviorTreeSearchData& SearchData, const UBTNode& ChildNode, EBTNodeResult::Type& NodeResult) const { OnChildDeactivation(SearchData, ChildNode, NodeResult, /*bRequestedFromValidInstance*/true); }
UE_DEPRECATED(5.0, "This function is deprecated. Please use RequestBranchDeactivation instead.")
void OnChildDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIndex, EBTNodeResult::Type& NodeResult) const { OnChildDeactivation(SearchData, ChildIndex, NodeResult, /*bRequestedFromValidInstance*/true ); }
protected:
/** if set, all decorators in branch below will be removed when execution flow leaves (decorators on this node are not affected) */
UPROPERTY(EditAnywhere, Category = Composite)
uint32 bApplyDecoratorScope : 1;
/** if set, NotifyChildExecution will be called */
uint32 bUseChildExecutionNotify : 1;
/** if set, NotifyNodeActivation will be called */
uint32 bUseNodeActivationNotify : 1;
/** if set, NotifyNodeDeactivation will be called */
uint32 bUseNodeDeactivationNotify : 1;
/** if set, CanNotifyDecoratorsOnActivation will be called */
uint32 bUseDecoratorsActivationCheck : 1;
/** if set, CanNotifyDecoratorsOnDeactivation will be called */
uint32 bUseDecoratorsDeactivationCheck : 1;
/** if set, CanNotifyDecoratorsOnFailedActivation will be called */
uint32 bUseDecoratorsFailedActivationCheck : 1;
/** execution index of last node in child branches */
uint16 LastExecutionIndex;
/** called just after child execution, allows to modify result
* bUseChildExecutionNotify must be set to true for this function to be called
* Calling INIT_COMPOSITE_NODE_NOTIFY_FLAGS in the constructor of the node will set this flag automatically */
AIMODULE_API virtual void NotifyChildExecution(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const;
/** called when start enters this node
* bUseNodeActivationNotify must be set to true for this function to be called
* Calling INIT_COMPOSITE_NODE_NOTIFY_FLAGS in the constructor of the node will set this flag automatically */
AIMODULE_API virtual void NotifyNodeActivation(FBehaviorTreeSearchData& SearchData) const;
/** called when start leaves this node
* bUseNodeDeactivationNotify must be set to true for this function to be called
* Calling INIT_COMPOSITE_NODE_NOTIFY_FLAGS in the constructor of the node will set this flag automatically */
AIMODULE_API virtual void NotifyNodeDeactivation(FBehaviorTreeSearchData& SearchData, EBTNodeResult::Type& NodeResult) const;
/** check if NotifyDecoratorsOnActivation is allowed, requires bUseDecoratorsActivationCheck flag
* bUseDecoratorsActivationCheck must be set to true for this function to be called
* Calling INIT_COMPOSITE_NODE_NOTIFY_FLAGS in the constructor of the node will set this flag automatically */
AIMODULE_API virtual bool CanNotifyDecoratorsOnActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx) const;
/** check if NotifyDecoratorsOnDeactivation is allowed, requires bUseDecoratorsDeactivationCheck flag
* bUseDecoratorsDeactivationCheck must be set to true for this function to be called
* Calling INIT_COMPOSITE_NODE_NOTIFY_FLAGS in the constructor of the node will set this flag automatically */
AIMODULE_API virtual bool CanNotifyDecoratorsOnDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const;
/** check if NotifyDecoratorsOnFailedActivation is allowed, requires bUseDecoratorsActivationCheck flag
* bUseDecoratorsFailedActivationCheck must be set to true for this function to be called
* Calling INIT_COMPOSITE_NODE_NOTIFY_FLAGS in the constructor of the node will set this flag automatically */
AIMODULE_API virtual bool CanNotifyDecoratorsOnFailedActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const;
/** runs through decorators on given child node and notify them about activation */
AIMODULE_API void NotifyDecoratorsOnActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx) const;
/** runs through decorators on given child node and notify them about deactivation */
AIMODULE_API void NotifyDecoratorsOnDeactivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult, const bool bIsInSameActiveInstance) const;
/** runs through decorators on given child node and notify them about failed activation */
AIMODULE_API void NotifyDecoratorsOnFailedActivation(FBehaviorTreeSearchData& SearchData, int32 ChildIdx, EBTNodeResult::Type& NodeResult) const;
/** get next child to process and store it in CurrentChild */
AIMODULE_API int32 GetNextChild(FBehaviorTreeSearchData& SearchData, int32 LastChildIdx, EBTNodeResult::Type LastResult) const;
/** store delayed execution request */
AIMODULE_API void RequestDelayedExecution(UBehaviorTreeComponent& OwnerComp, EBTNodeResult::Type LastResult) const;
protected:
virtual int32 GetNextChildHandler(struct FBehaviorTreeSearchData& SearchData, int32 PrevChild, EBTNodeResult::Type LastResult) const { return BTSpecialChild::ReturnToParent; }
template<typename NotifyChildExecution, typename NotifyNodeActivation, typename NotifyNodeDeactivation,
typename CanNotifyDecoratorsOnActivation, typename CanNotifyDecoratorsOnDeactivation, typename CanNotifyDecoratorsOnFailedActivation>
void InitNotifyFlags(NotifyChildExecution, NotifyNodeActivation, NotifyNodeDeactivation,
CanNotifyDecoratorsOnActivation, CanNotifyDecoratorsOnDeactivation, CanNotifyDecoratorsOnFailedActivation)
{
bUseChildExecutionNotify = !std::is_same_v<decltype(&UBTCompositeNode::NotifyChildExecution), NotifyChildExecution>;
bUseNodeActivationNotify = !std::is_same_v<decltype(&UBTCompositeNode::NotifyNodeActivation), NotifyNodeActivation>;
bUseNodeDeactivationNotify = !std::is_same_v<decltype(&UBTCompositeNode::NotifyNodeDeactivation), NotifyNodeDeactivation>;
bUseDecoratorsActivationCheck = !std::is_same_v<decltype(&UBTCompositeNode::CanNotifyDecoratorsOnActivation), CanNotifyDecoratorsOnActivation>;
bUseDecoratorsDeactivationCheck = !std::is_same_v<decltype(&UBTCompositeNode::CanNotifyDecoratorsOnDeactivation), CanNotifyDecoratorsOnDeactivation>;
bUseDecoratorsFailedActivationCheck = !std::is_same_v<decltype(&UBTCompositeNode::CanNotifyDecoratorsOnFailedActivation), CanNotifyDecoratorsOnFailedActivation>;
}
};
#define INIT_COMPOSITE_NODE_NOTIFY_FLAGS() \
do { \
using NodeType = TRemovePointer<decltype(this)>::Type; \
InitNotifyFlags(&NodeType::NotifyChildExecution,\
&NodeType::NotifyNodeActivation,\
&NodeType::NotifyNodeDeactivation, \
&NodeType::CanNotifyDecoratorsOnActivation,\
&NodeType::CanNotifyDecoratorsOnDeactivation,\
&NodeType::CanNotifyDecoratorsOnFailedActivation); \
} while (false)
//////////////////////////////////////////////////////////////////////////
// Inlines
inline UBTNode* UBTCompositeNode::GetChildNode(int32 Index) const
{
return Children.IsValidIndex(Index) ?
(Children[Index].ChildComposite ?
static_cast<UBTNode*>(Children[Index].ChildComposite) :
static_cast<UBTNode*>(Children[Index].ChildTask)) :
nullptr;
}
inline int32 UBTCompositeNode::GetChildrenNum() const
{
return Children.Num();
}
inline uint16 UBTCompositeNode::GetLastExecutionIndex() const
{
return LastExecutionIndex;
}
inline bool UBTCompositeNode::IsApplyingDecoratorScope() const
{
return bApplyDecoratorScope;
}