當前位置:網站首頁>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

隨機推薦