當前位置:網站首頁>UBTDecorator_BlueprintBase源碼分析
UBTDecorator_BlueprintBase源碼分析
2022-01-27 00:51:43 【JK Chen】
// Copyright Epic Games, Inc. All Rights Reserved.
#include "BehaviorTree/Decorators/BTDecorator_BlueprintBase.h"
#include "AIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "BehaviorTree/BTFunctionLibrary.h"
#include "BlueprintNodeHelpers.h"
#include "BehaviorTree/BehaviorTree.h"
UBTDecorator_BlueprintBase::UBTDecorator_BlueprintBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
/* 判斷代碼內是否實現了Tick、開始執行、結束執行、Observer開始觀察、結束觀察 */
UClass* StopAtClass = UBTDecorator_BlueprintBase::StaticClass();
ReceiveTickImplementations = FBTNodeBPImplementationHelper::CheckEventImplementationVersion(TEXT("ReceiveTick"), TEXT("ReceiveTickAI"), *this, *StopAtClass);
ReceiveExecutionStartImplementations = FBTNodeBPImplementationHelper::CheckEventImplementationVersion(TEXT("ReceiveExecutionStart"), TEXT("ReceiveExecutionStartAI"), *this, *StopAtClass);
ReceiveExecutionFinishImplementations = FBTNodeBPImplementationHelper::CheckEventImplementationVersion(TEXT("ReceiveExecutionFinish"), TEXT("ReceiveExecutionFinishAI"), *this, *StopAtClass);
ReceiveObserverActivatedImplementations = FBTNodeBPImplementationHelper::CheckEventImplementationVersion(TEXT("ReceiveObserverActivated"), TEXT("ReceiveObserverActivatedAI"), *this, *StopAtClass);
ReceiveObserverDeactivatedImplementations = FBTNodeBPImplementationHelper::CheckEventImplementationVersion(TEXT("ReceiveObserverDeactivated"), TEXT("ReceiveObserverDeactivatedAI"), *this, *StopAtClass);
PerformConditionCheckImplementations = FBTNodeBPImplementationHelper::CheckEventImplementationVersion(TEXT("PerformConditionCheck"), TEXT("PerformConditionCheckAI"), *this, *StopAtClass);
bNotifyBecomeRelevant = ReceiveObserverActivatedImplementations != 0;
bNotifyCeaseRelevant = ReceiveObserverDeactivatedImplementations != 0;
bNotifyTick = ReceiveTickImplementations != 0;
bNotifyActivation = ReceiveExecutionStartImplementations != 0;
bNotifyDeactivation = ReceiveExecutionFinishImplementations != 0;
/* 編輯器內是否顯示屬性詳情 */
bShowPropertyDetails = true;
/* Observer的中止,僅通過屬性變化,關閉Tick;雖然可能實現Tick,但是不一定每個Tick都檢測一次條件 */
bCheckConditionOnlyBlackBoardChanges = false;
/* 是否有黑板鍵(用於屬性修改觀察) */
bIsObservingBB = false;
/* 創建實例,打破公用限制 */
bCreateNodeInstance = true;
}
void UBTDecorator_BlueprintBase::InitializeProperties()
{
/* 是否是DefaultObject */
if (HasAnyFlags(RF_ClassDefaultObject))
{
/* 初始化屬性數組 */
UClass* StopAtClass = UBTDecorator_BlueprintBase::StaticClass();
BlueprintNodeHelpers::CollectPropertyData(this, StopAtClass, PropertyData);
/* 判斷是否有屬性是黑板鍵 */
bIsObservingBB = BlueprintNodeHelpers::HasAnyBlackboardSelectors(this, StopAtClass);
}
}
void UBTDecorator_BlueprintBase::PostInitProperties()
{
Super::PostInitProperties();
InitializeProperties();
/* FORCEINLINE bool GetNeedsTickForConditionChecking() const { return PerformConditionCheckImplementations != 0 && (bIsObservingBB == false || bCheckConditionOnlyBlackBoardChanges == false); } 這個函數用於判斷是否需要Tick(1)實現了Tick函數(2)不是只觀察黑板鍵變化 BecomeRelevant和CeaseRelevant用於開關Tick和添加黑板鍵修改委托 */
if (PerformConditionCheckImplementations || bIsObservingBB)
{
bNotifyBecomeRelevant = true;
bNotifyCeaseRelevant = true;
}
}
void UBTDecorator_BlueprintBase::PostLoad()
{
Super::PostLoad();
/* 獲取所有黑板鍵的Name,當然需要FlowAbortMode不是None */
if (GetFlowAbortMode() != EBTFlowAbortMode::None && bIsObservingBB)
{
ObservedKeyNames.Reset();
UClass* StopAtClass = UBTDecorator_BlueprintBase::StaticClass();
BlueprintNodeHelpers::CollectBlackboardSelectors(this, StopAtClass, ObservedKeyNames);
ensure(ObservedKeyNames.Num() > 0);
}
}
void UBTDecorator_BlueprintBase::InitializeFromAsset(UBehaviorTree& Asset)
{
Super::InitializeFromAsset(Asset);
/* 自動化ResolveBlackboardSelector */
if (Asset.BlackboardAsset)
{
BlueprintNodeHelpers::ResolveBlackboardSelectors(*this, *StaticClass(), *Asset.BlackboardAsset);
}
}
/* 存儲AAIController,用於為實現的函數提供參數 */
void UBTDecorator_BlueprintBase::SetOwner(AActor* InActorOwner)
{
ActorOwner = InActorOwner;
AIOwner = Cast<AAIController>(InActorOwner);
}
void UBTDecorator_BlueprintBase::OnBecomeRelevant(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
if (AIOwner != nullptr && (ReceiveObserverActivatedImplementations & FBTNodeBPImplementationHelper::AISpecific))
{
ReceiveObserverActivatedAI(AIOwner, AIOwner->GetPawn());
}
else if (ReceiveObserverActivatedImplementations & FBTNodeBPImplementationHelper::Generic)
{
ReceiveObserverActivated(ActorOwner);
}
/* 為Check提供Tick */
if (GetNeedsTickForConditionChecking())
{
// if set up as observer, and has a condition check, we want to check the condition every frame
// highly inefficient, but hopefully people will use it only for prototyping.
bNotifyTick = true;
}
/* 為所有黑板鍵添加委托 */
UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent();
if (BlackboardComp)
{
for (int32 NameIndex = 0; NameIndex < ObservedKeyNames.Num(); NameIndex++)
{
const FBlackboard::FKey KeyID = BlackboardComp->GetKeyID(ObservedKeyNames[NameIndex]);
if (KeyID != FBlackboard::InvalidKey)
{
BlackboardComp->RegisterObserver(KeyID, this, FOnBlackboardChangeNotification::CreateUObject(this, &UBTDecorator_BlueprintBase::OnBlackboardKeyValueChange));
}
}
}
}
void UBTDecorator_BlueprintBase::OnCeaseRelevant(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
/* 為所有黑板鍵解除委托 */
UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent();
if (BlackboardComp)
{
BlackboardComp->UnregisterObserversFrom(this);
}
if (AIOwner != nullptr && (ReceiveObserverDeactivatedImplementations & FBTNodeBPImplementationHelper::AISpecific))
{
ReceiveObserverDeactivatedAI(AIOwner, AIOwner->GetPawn());
}
else if (ReceiveObserverDeactivatedImplementations & FBTNodeBPImplementationHelper::Generic)
{
ReceiveObserverDeactivated(ActorOwner);
}
/* 關閉為Check提供的Tick(如果實現了Tick函數則不能關閉) */
if (GetNeedsTickForConditionChecking() == true && ReceiveTickImplementations == 0)
{
// clean up the tick request if no longer "active"
bNotifyTick = false;
}
}
void UBTDecorator_BlueprintBase::OnNodeActivation(FBehaviorTreeSearchData& SearchData)
{
if (AIOwner != nullptr && (ReceiveExecutionStartImplementations & FBTNodeBPImplementationHelper::AISpecific))
{
ReceiveExecutionStartAI(AIOwner, AIOwner->GetPawn());
}
else if (ReceiveExecutionStartImplementations & FBTNodeBPImplementationHelper::Generic)
{
ReceiveExecutionStart(ActorOwner);
}
}
void UBTDecorator_BlueprintBase::OnNodeDeactivation(FBehaviorTreeSearchData& SearchData, EBTNodeResult::Type NodeResult)
{
if (AIOwner != nullptr && (ReceiveExecutionFinishImplementations & FBTNodeBPImplementationHelper::AISpecific))
{
ReceiveExecutionFinishAI(AIOwner, AIOwner->GetPawn(), NodeResult);
}
else if (ReceiveExecutionFinishImplementations & FBTNodeBPImplementationHelper::Generic)
{
ReceiveExecutionFinish(ActorOwner, NodeResult);
}
}
void UBTDecorator_BlueprintBase::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
if (AIOwner != nullptr && (ReceiveTickImplementations & FBTNodeBPImplementationHelper::AISpecific))
{
ReceiveTickAI(AIOwner, AIOwner->GetPawn(), DeltaSeconds);
}
else if (ReceiveTickImplementations & FBTNodeBPImplementationHelper::Generic)
{
ReceiveTick(ActorOwner, DeltaSeconds);
}
/* 如果Check需要Tick,並且Should Abort */
// possible this got ticked due to the decorator being configured as an observer
if (GetNeedsTickForConditionChecking() && GetShouldAbort(OwnerComp))
{
OwnerComp.RequestExecution(this);
}
}
bool UBTDecorator_BlueprintBase::GetShouldAbort(UBehaviorTreeComponent& OwnerComp) const
{
/* 沒實現Check條件默認當前裝飾器可以通過 */
// if there's no condition-checking function implemented we always want to abort on any change
if (PerformConditionCheckImplementations == 0)
{
return true;
}
/* 是否在激活的分支內 */
const bool bIsOnActiveBranch = OwnerComp.IsExecutingBranch(GetMyNode(), GetChildIndex());
bool bShouldAbort = false;
/* 在激活的分支內(Self)並且條件為不通過,則ShouldAbort(執行一次OwnerComp.RequestExecution(this),內部會再次檢測,不通過,從而起到打斷Self的效果) */
if (bIsOnActiveBranch)
{
bShouldAbort = (FlowAbortMode == EBTFlowAbortMode::Self || FlowAbortMode == EBTFlowAbortMode::Both) && CalculateRawConditionValueImpl(OwnerComp) == IsInversed();
}
/* 不在激活的分支,且當前節點在Tick,說明當前執行的是LowerPriority;此時條件通過則回到當前分支,打斷低優先級 */
else
{
bShouldAbort = (FlowAbortMode == EBTFlowAbortMode::LowerPriority || FlowAbortMode == EBTFlowAbortMode::Both) && CalculateRawConditionValueImpl(OwnerComp) != IsInversed();
}
return bShouldAbort;
}
bool UBTDecorator_BlueprintBase::CalculateRawConditionValueImpl(UBehaviorTreeComponent& OwnerComp) const
{
/* 通過藍圖內的實現檢測條件 */
bool CurrentCallResult = false;
if (PerformConditionCheckImplementations != 0)
{
// can't use const functions with blueprints
UBTDecorator_BlueprintBase* MyNode = (UBTDecorator_BlueprintBase*)this;
if (AIOwner != nullptr && (PerformConditionCheckImplementations & FBTNodeBPImplementationHelper::AISpecific))
{
CurrentCallResult = MyNode->PerformConditionCheckAI(MyNode->AIOwner, MyNode->AIOwner->GetPawn());
}
else if (PerformConditionCheckImplementations & FBTNodeBPImplementationHelper::Generic)
{
CurrentCallResult = MyNode->PerformConditionCheck(MyNode->ActorOwner);
}
}
return CurrentCallResult;
}
bool UBTDecorator_BlueprintBase::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
{
return CalculateRawConditionValueImpl(OwnerComp);
}
bool UBTDecorator_BlueprintBase::IsDecoratorExecutionActive() const
{
/* 是否執行當前分支 */
UBehaviorTreeComponent* OwnerComp = Cast<UBehaviorTreeComponent>(GetOuter());
return OwnerComp && OwnerComp->IsExecutingBranch(GetMyNode(), GetChildIndex());
}
bool UBTDecorator_BlueprintBase::IsDecoratorObserverActive() const
{
/* Observer是否激活(當前分支或者子優先級) */
UBehaviorTreeComponent* OwnerComp = Cast<UBehaviorTreeComponent>(GetOuter());
return OwnerComp && OwnerComp->IsAuxNodeActive(this);
}
FString UBTDecorator_BlueprintBase::GetStaticDescription() const
{
FString ReturnDesc =
#if WITH_EDITORONLY_DATA
CustomDescription.Len() ? CustomDescription :
#endif // WITH_EDITORONLY_DATA
Super::GetStaticDescription();
/* 通過之前獲取的各個參數,組成Description */
UBTDecorator_BlueprintBase* CDO = (UBTDecorator_BlueprintBase*)(GetClass()->GetDefaultObject());
if (bShowPropertyDetails && CDO)
{
UClass* StopAtClass = UBTDecorator_BlueprintBase::StaticClass();
FString PropertyDesc = BlueprintNodeHelpers::CollectPropertyDescription(this, StopAtClass, CDO->PropertyData);
if (PropertyDesc.Len())
{
ReturnDesc += TEXT(":\n\n");
ReturnDesc += PropertyDesc;
}
}
return ReturnDesc;
}
void UBTDecorator_BlueprintBase::DescribeRuntimeValues(const UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTDescriptionVerbosity::Type Verbosity, TArray<FString>& Values) const
{
UBTDecorator_BlueprintBase* CDO = (UBTDecorator_BlueprintBase*)(GetClass()->GetDefaultObject());
if (CDO && CDO->PropertyData.Num())
{
BlueprintNodeHelpers::DescribeRuntimeValues(this, CDO->PropertyData, Values);
}
}
/* 黑板鍵修改時重新檢測 */
EBlackboardNotificationResult UBTDecorator_BlueprintBase::OnBlackboardKeyValueChange(const UBlackboardComponent& Blackboard, FBlackboard::FKey ChangedKeyID)
{
UBehaviorTreeComponent* BehaviorComp = (UBehaviorTreeComponent*)Blackboard.GetBrainComponent();
if (BehaviorComp && GetShouldAbort(*BehaviorComp))
{
BehaviorComp->RequestExecution(this);
}
return BehaviorComp ? EBlackboardNotificationResult::ContinueObserving : EBlackboardNotificationResult::RemoveObserver;
}
/* 因為創建了實例,所以銷毀時需要一些處理 */
void UBTDecorator_BlueprintBase::OnInstanceDestroyed(UBehaviorTreeComponent& OwnerComp)
{
// force dropping all pending latent actions associated with this blueprint
BlueprintNodeHelpers::AbortLatentActions(OwnerComp, *this);
}
#if WITH_EDITOR
FName UBTDecorator_BlueprintBase::GetNodeIconName() const
{
if(PerformConditionCheckImplementations != 0)
{
return FName("BTEditor.Graph.BTNode.Decorator.Conditional.Icon");
}
else
{
return FName("BTEditor.Graph.BTNode.Decorator.NonConditional.Icon");
}
}
bool UBTDecorator_BlueprintBase::UsesBlueprint() const
{
return true;
}
#endif // WITH_EDITOR
版權聲明
本文為[JK Chen]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/01/202201270051430266.html
邊欄推薦
猜你喜歡
隨機推薦
- uniapp上傳圖片及組件傳值
- 瑞利年金險資金保障安全嗎?收益高不高啊?
- 華為手機USB連不上電腦的解决方法
- Flutter 2,移動金融應用開發
- 關於st25系列NFC標簽簡單介紹及st25TV系列用於門禁讀取時的注意事項總結
- 關於用ffmpeg轉手機視頻發現視頻長寬倒了的問題
- 函數 / 類模板--模板2
- 數組中的第k個最大的元素--優先級隊列、排序、堆、排序
- 單片機實例27——ADC0809A/D轉換器基本應用技術(硬件電路圖+匯編程序+C語言程序)
- Collection集合的學習
- 一場面試結束,某度員工從事Android 5年為何還是初級工程師?
- 3本書閱讀筆記【人月神話-Go語言實戰-研發能力持續成長路線】01
- PHP垃圾回收機制
- 【電子技術】什麼是LFSR?
- 死鎖?如何定比特到死鎖?如何修複死鎖?(jps和jstack兩個工具)
- 快樂寒假 22/01/20
- image
- 噴程序員?SURE?
- LDO分壓電阻計算小工具
- 面試之求一串字符串中每個字符的出現次數
- 【ISO15765_UDS&OBD診斷】-01-概述
- 【Mysql上分之路】第九篇:Mysql存儲引擎
- RHCE 第一次作業
- 2021.10.16我的第一篇博客:一切皆有可能!
- CTA-敏感行為-讀取IMEI
- 面試被問怎麼排查平時遇到的系統CPU飆高和頻繁GC,該怎麼回答?
- nuxt項目總結-綜合
- 自然語言處理學習筆記(一)
- C語言第一課
- 各比特大佬,Spark的重點難點系列暫時更新完畢
- 基於 esbuild 的 universal bundler 設計
- XCTFre逆向(四):insanity
- 理解什麼是真正的並發數
- JVM腦圖
- 【Pytorch(四)】學習如何使用 PyTorch 讀取並處理數據集
- 函數棧幀的創建與銷毀
- 構建神經網絡- 手寫字體識別案例
- 多模態生成模型ERNIE-VILG
- kotlin不容忽視的小細節
- 備戰一年,終於斬獲騰訊T3,我堅信成功是可以複制的