How to initialize a C++ Blackboard

I am building an C++ based AIController, and I would like to use the Blackboard but not linked with a BehaviorTree.

So, on the constructor of the controller I create the blackboard:

BlackboardComponent = CreateDefaultSubobject<UBlackboardComponent>(TEXT("BlackboardComponent"));

and normally on the override of the Possess(APawn* pawn) method

BlackboardComponent->InitializeBlackboard(*(character->BehaviorTree->BlackboardAsset));
BlackboardComponent->SetValueAsObject(TargetKey, character->FirstNode);
BehaviorTreeComponent->StartTree(*(character->BehaviorTree));

But, since I don’t want to use the behavior tree, I can not figure out how to initialize or setup the blackboard from C++.

BlackboardComponent->InitializeBlackboard( **???** );
BlackboardComponent->SetValueAsObject("Target", character->FirstNode);

Thanks in advance,

You can construct a Blackboard asset in the content manager without using BT. It’s a separate asset type and is associated with BTs only for convenience. You need to build such an asset and use it to initialize your BB.

Cheers,

–mieszko

Thank you Mieszko. My problem was more complex than just NewObject<>.
I had to read some of the UE4 source code to figure out what was going on, in the end I took me a bit of time to understand how the implementation of the Blackboards work. I leave here the steps with some clarification, it may help someone else to figure things out quickly in the future (maybe me in a year time or so).

  1. you were right you can just instantiate a by using NewObject (an you need to follow the UE4 object instantiation)
    BlackboardAsset = NewObject();

Interesting reads:

  1. Prep the UBlackboardData.
    Blackboard does not work as a dynamic Dictionary data structure, that means that simply SetValue does not work it.
    This was may main problem, took me a while to get that, since the documentation is non existent, there was no log, warnings or error messages (I suggest to add a warning in the Log system at least). The SetValue(…) in the UBlackBoardComponent return a bool, but the SetValueAs…(…) are void

So before you initialize the UBlackboardComponent you need to define the key (names) and associated types you want to store. So an obvious function would be to have a AddKey function either on the BlackboardComponent or BlackboardData, but, such thing does not exist. Again documentation was not helpful at all, do I had to dig back into the UE4 code to try to figure out how to add keys.

In the middle of reading 4 or 5 Update methods with very intuitive names I found and Update method which finally allows me to add Keys and finally solve what could have been a very strait forward process.

API reference:

https://docs.unrealengine.com/latest/INT/API/Runtime/AIModule/BehaviorTree/UBlackboardData/index.html
https://docs.unrealengine.com/latest/INT/API/Runtime/AIModule/BehaviorTree/UBlackboardComponent/index.html

In short here is my final solution:

AStateController::AStateController() {
	// Create Blackboard Key Manager
	BlackboardAsset = NewObject<UBlackboardData>();
	BlackboardAsset->UpdatePersistentKey<UBlackboardKeyType_Object>(FName("Target"));

	BlackboardComponent = CreateDefaultSubobject<UBlackboardComponent>(TEXT("BlackboardComponent"));
}

void AStateController::Possess(APawn * pawn) {
	Super::Possess(pawn);
	AStateNPC* character = Cast<AStateNPC>(pawn);

	if (character) {
		BlackboardComponent->InitializeBlackboard(*BlackboardAsset);
		BlackboardComponent->SetValueAsObject("Target", character->FirstNode);
	}
	else {
		UE_LOG(LogAIStealth, Error, TEXT("AStateController is not linked the a AStateNPC."));
	}
}

UE4 Engine suggestions for improvement:

  1. Log a warning message when unsuccessful key is not found on SetValue
  2. Add a clear API document at least to the
  3. Clear instruction on how to set the UBlackboardComponent
1 Like

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”.