Shocking how poorly written the AIController and BlackBoardComponent are even in 2023. Pulled apart the top layer of duckttape to see how to deal with it.
Your solution is still fine but UBlackboardComponent::InitializeBlackboard is already called at two points, once on UBlackboardComponent::InitializeComponent if UBlackboardComponent::DefaultBlackboardAsset has been set and UBlackboardComponent::BlackboardAsset has not,
and once on AAIController::OnPossessif UBlackboardComponent::BlackboardAsset has been set.
It does run twice already since UBlackboardComponent::InitializeBlackboard assigns UBlackboardComponent::DefaultBlackboardAsset to UBlackboardComponent::BlackboardAsset.
This thing goes on in circles and circles. Spaghetti code
AIController
> BrainComponent
> AIController
> BlackboardComponent
> BlackboardComponent
> BrainComponent
> AIOwner
> BlackboardComponent
> BlackboardAsset
For people like me who came here from a search engine, searching
how to run WITH a behavior tree:
From both the 4.27 and the 5.2 docs:
Behavior Tree in Unreal Engine - Quick Start Guide | Unreal Engine 5.2 Documentation
In UE5.2.1 The preferred way to initiate AI logic on an AIController seems to be to call this:
AIController::RunBehaviorTree(UBehaviorTree* BTAsset)
During that, if AAIController::BrainComponent == NULL, one will be created automatically of type UBehaviorTreeComponent.
During that, The required UBlackboardComponent will be AAIController::Blackboard as it is or automatically created through AAIController::UseBlackboard.
This means you are not expected to create these in the constructor of the AIController. The only thing you are expected to do is at some point call RunBehaviorTree providing a valid UBehaviorTree containing a valid and compatible UBlackboardData.
It seems to be right to call AIController::RunBehaviorTree OnPossess after Super::OnPossess. Just… expect your eyes to bleed from what’s going on “behind the scenes”.