Debug Blackboard Value not being set

I am new to Unreal, coming from Unity.

I followed the Behavior Tree Quick Start Guide and wanted to try to make the same system in C++.

At step 7.5 in that guide a sequence is set up with a Blackboard Decorator to query HasLineOfSight.

Since I couldn’t find any guide in C++, I attempted my own solution. One of the problems I initially had was getting a reference to the Blackboard but found out you could add a Blackboard Component to my enemy character so I used that.

Problem: What I see when I run my Behavior Tree, is that it never executes the nodes under the Decorator, even though I set HasLineOfSight to true.

At first I thought maybe I misspelled HasLineOfSight like HasLineofSight (lowercase O for example) in either the Blackboard or C++ but I double checked, copied the key from the Blackboard into code to make sure.

Apart from if someone can spot what I am doing wrong, is there any way to see the actual Values in the Blackboard for the running Behavior Tree in some editor?

void AEnemy_AIController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);

	auto EnemyCharacter = Cast<AEnemyCharacter>(InPawn);

	if (EnemyCharacter == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("Pawn does not inherit from AEnemyCharacter"));
		return;
	}

	Blackboard = Cast<UBlackboardComponent>(EnemyCharacter->GetComponentByClass(UBlackboardComponent::StaticClass()));

	if (Blackboard == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("Pawn has no Blackboard Component"));
		return;
	}
	
	// GetBehaviorTree is custom, just returns a UPROPERTY for a UBehaviorTree*
	RunBehaviorTree(EnemyCharacter->GetBehaviorTree());
}

void AEnemy_AIController::OnActorSense(AActor* Actor, FAIStimulus Stimulus)
{
	if (Stimulus.WasSuccessfullySensed() && Actor->ActorHasTag(FName("Player")))
	{
		UE_LOG(LogTemp, Display, TEXT("Detected Player"));

		GetWorldTimerManager().ClearTimer(LineOfSightTimer);
		
		if (Blackboard == nullptr)
		{
			UE_LOG(LogTemp, Error, TEXT("No Blackboard present in AEnemy_AIController"));
		}
		else
		{
			// This is logged appropriately when detecting player.
			// But the Behavior Trees Decorator never passes flow to child nodes.
			UE_LOG(LogTemp, Display, TEXT("HasLineOfSight = true"));

			// This acts as if never being set
			Blackboard->SetValueAsBool("HasLineOfSight", true); 
			Blackboard->SetValueAsObject("EnemyActor", Actor);
		}
	}
	else
	{
		UE_LOG(LogTemp, Display, TEXT("Lost Player"));

		GetWorldTimerManager().SetTimer(LineOfSightTimer, this, &AEnemy_AIController::ForgetPlayer, 4.0f, false);
	}
}

void AEnemy_AIController::ForgetPlayer()
{
	UE_LOG(LogTemp, Display, TEXT("Forgot Player"));

	if (Blackboard == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("No Blackboard present in AEnemy_AIController"));
	}
	else
	{
		// This is logged appropriately when 4 seconds have passed since losing track of Player
		UE_LOG(LogTemp, Display, TEXT("HasLineOfSight = False"));
		Blackboard->SetValueAsBool("HasLineOfSight", false);
		Blackboard->SetValueAsObject("EnemyActor", nullptr);
	}
}

I solved the problem by making a Blueprint instance from the C++ custom AIController class, adding a Blackboard component to the blueprint instance and setup its Default Blackboard Asset member variable in details panel.

I also moved the UBehaviorTree* member to the custom AIController and set it up via details on the blueprint.

Running the game now I can debug the Behavior Tree and all Key values when selected object from the dropdown at the top of the Behavior Tree window.

Lastly, On my enemy character I had to change the blueprint value of AI Controller Class to point to the Blueprint instance of the C++ custom AI Controller class, instead of the actual C++ custom AI Controller class.

void AEnemy_AIController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);
	RunBehaviorTree(BehaviorTree);
}

void AEnemy_AIController::OnActorSense(AActor* Actor, FAIStimulus Stimulus)
{
	if (Stimulus.WasSuccessfullySensed() && Actor->ActorHasTag("Player"))
	{
		// Notices player.
		GetWorldTimerManager().ClearTimer(LineOfSightTimer);
		
		if (Blackboard)
		{
			Blackboard->SetValueAsBool("HasLineOfSight", true);
			Blackboard->SetValueAsObject("EnemyActor", Actor);
		}
	}
	else
	{
		// Lost sight of player.
		// Forget player after 4 seconds.
		GetWorldTimerManager().SetTimer(LineOfSightTimer, this, &AEnemy_AIController::ForgetPlayer, 4.0f, false);
	}
}

void AEnemy_AIController::ForgetPlayer()
{
	if (Blackboard)
	{
		Blackboard->SetValueAsBool("HasLineOfSight", false);
		Blackboard->SetValueAsObject("EnemyActor", nullptr);
	}
}