BehaviorTree
BehaviorTree
#Overview
name: BehaviorTree
The value of this variable can be defined or overridden in .ini config files. 1
.ini config file referencing this setting variable.
It is referenced in 52
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of BehaviorTree is to provide a structure for defining AI behavior in Unreal Engine. It is a core component of the AI system used for creating complex, hierarchical behaviors for AI-controlled characters or entities.
Key points about BehaviorTree:
-
It is part of the AI Module in Unreal Engine.
-
The BehaviorTree asset contains a graph (BTGraph) that defines the AI logic.
-
It is closely associated with the BlackboardData asset, which stores key-value pairs used by the behavior tree.
-
BehaviorTree is used in conjunction with AIControllers to drive AI behavior.
-
It can be assigned and run on AI characters through code or Blueprint.
-
The BehaviorTreeEditor is used to create and edit BehaviorTree assets.
-
BehaviorTree assets can be compared and diffed using the SBehaviorTreeDiff tool.
-
It supports debugging through the BehaviorTreeDebugger.
Developers should be aware that:
-
Changes to the BehaviorTree asset may require updating associated AIControllers and Blackboard assets.
-
The BehaviorTree asset is tightly coupled with its graph (BTGraph) and should be manipulated through proper editor tools.
-
When spawning AI with a BehaviorTree, ensure the PawnClass has an appropriate AIController set.
-
BehaviorTrees can be assigned dynamically at runtime using AIController’s RunBehaviorTree function.
Best practices:
-
Use the BehaviorTreeEditor for creating and modifying BehaviorTree assets.
-
Utilize the Blackboard for sharing data between different parts of the behavior tree.
-
Keep behavior trees modular and reusable where possible.
-
Make use of the debugging tools provided to troubleshoot complex behaviors.
-
Consider performance implications when designing large or complex behavior trees.
-
Use version control to track changes in behavior tree assets over time.
#Setting Variables
#References In INI files
Location: <Workspace>/Engine/Config/BaseEngine.ini:3246, section: [GameplayDebuggerSettings]
- INI Section:
GameplayDebuggerSettings
- Raw value:
False
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Plugins/Experimental/CommonConversation/Source/CommonConversationEditor/Private/ConversationDebugger.cpp:1039
Scope (from outer to inner):
file
function void FConversationDebugger::StopPlaySession
Source code excerpt:
// @TODO: we need a unified flow to leave debugging mode from the different debuggers to prevent strong coupling between modules.
// Each debugger (Blueprint & BehaviorTree for now) could then take the appropriate actions to resume the session.
if (FSlateApplication::Get().InKismetDebuggingMode())
{
FSlateApplication::Get().LeaveDebuggingMode();
}
}
}
#Loc: <Workspace>/Engine/Plugins/Experimental/CommonConversation/Source/CommonConversationEditor/Private/ConversationDebugger.cpp:1060
Scope (from outer to inner):
file
function void FConversationDebugger::ResumePlaySession
Source code excerpt:
{
// @TODO: we need a unified flow to leave debugging mode from the different debuggers to prevent strong coupling between modules.
// Each debugger (Blueprint & BehaviorTree for now) could then take the appropriate actions to resume the session.
if (FSlateApplication::Get().InKismetDebuggingMode())
{
FSlateApplication::Get().LeaveDebuggingMode();
}
GUnrealEd->PlaySessionResumed();
#Loc: <Workspace>/Engine/Plugins/Experimental/GameplayBehaviors/Source/GameplayBehaviorsModule/Private/AI/GameplayBehaviorConfig_BehaviorTree.cpp:16
Scope (from outer to inner):
file
function UBehaviorTree* UGameplayBehaviorConfig_BehaviorTree::GetBehaviorTree
Source code excerpt:
UBehaviorTree* UGameplayBehaviorConfig_BehaviorTree::GetBehaviorTree() const
{
return BehaviorTree.IsPending()
? BehaviorTree.LoadSynchronous()
: BehaviorTree.Get();
}
#Loc: <Workspace>/Engine/Plugins/Experimental/GameplayBehaviors/Source/GameplayBehaviorsModule/Public/AI/GameplayBehaviorConfig_BehaviorTree.h:21
Scope (from outer to inner):
file
class class UGameplayBehaviorConfig_BehaviorTree : public UGameplayBehaviorConfig
Source code excerpt:
protected:
UPROPERTY(EditAnywhere, Category = SmartObject)
mutable TSoftObjectPtr<UBehaviorTree> BehaviorTree;
UPROPERTY(EditAnywhere, Category = SmartObject)
uint32 bRevertToPreviousBTOnFinish : 1;
};
#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_2
#Loc: <Workspace>/Engine/Plugins/Experimental/GameplayBehaviors/Source/GameplayBehaviorsModule/Public/AI/GameplayBehavior_BehaviorTree.h:30
Scope (from outer to inner):
file
function class GAMEPLAYBEHAVIORSMODULE_API UGameplayBehavior_BehaviorTree : public UGameplayBehavior { GENERATED_BODY
Source code excerpt:
TObjectPtr<AAIController> AIController;
/** Indicates if BehaviorTree should run only once or in loop. */
UPROPERTY(EditAnywhere, Category = SmartObject)
bool bSingleRun = true;
FTimerHandle TimerHandle;
};
#Loc: <Workspace>/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/EditorAssetAutomationTests.cpp:591
Scope (from outer to inner):
file
function bool FAssetEditorTest::RunTest
Source code excerpt:
if (!FModuleManager::Get().IsModuleLoaded(TEXT("BehaviorTreeEditor")))
{
//NOTE: This module gets left in after the test completes otherwise the content browser would crash when it tries to access the created BehaviorTree.
FModuleManager::Get().LoadModule(TEXT("BehaviorTreeEditor"));
}
}
//Holds info on each asset we are creating
TArray< TSharedPtr<CreateAssetHelper::FCreateAssetInfo> > AssetInfos;
#Loc: <Workspace>/Engine/Plugins/Tests/EditorTests/Source/EditorTests/Private/UnrealEd/EditorAssetAutomationTests.cpp:638
Scope: file
Source code excerpt:
ASSET_TEST_CREATE(USlateBrushAsset, USlateBrushAssetFactory, SB, )
ASSET_TEST_CREATE(USlateWidgetStyleAsset, USlateWidgetStyleAssetFactory, SWS, FactoryInst->StyleType = UButtonWidgetStyle::StaticClass();)
ASSET_TEST_CREATE_BY_NAME(AIModule.BehaviorTree, BehaviorTreeEditor.BehaviorTreeFactory, BT, )
ASSET_TEST_CREATE(UBlueprint, UBlueprintFunctionLibraryFactory, BFL, )
ASSET_TEST_CREATE(UBlueprint, UBlueprintMacroFactory, MPL, FactoryInst->ParentClass = AActor::StaticClass();)
ASSET_TEST_CREATE(UCurveBase, UCurveFactory, C, FactoryInst->CurveClass = UCurveFloat::StaticClass();)
UClass* GameplayAbilityClass = StaticLoadClass(UObject::StaticClass(), NULL, TEXT("GameplayAbilities.GameplayAbilitySet"), NULL, LOAD_None, NULL);
if (GameplayAbilityClass)
{
#Loc: <Workspace>/Engine/Source/Developer/FunctionalTesting/Classes/FunctionalAITest.h:91
Scope: file
Source code excerpt:
/** if set will be applied to spawned AI */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=AISpawn)
TObjectPtr<class UBehaviorTree> BehaviorTree;
FAITestSpawnInfo()
: BehaviorTree(nullptr)
{}
FORCEINLINE virtual bool IsValid() const override { return PawnClass != NULL && FAITestSpawnInfoBase::IsValid(); }
virtual bool Spawn(AFunctionalAITestBase* AITest) const override;
};
#Loc: <Workspace>/Engine/Source/Developer/FunctionalTesting/Private/FunctionalAITest.cpp:371
Scope (from outer to inner):
file
function bool FAITestSpawnInfo::Spawn
Source code excerpt:
bool bSuccessfullySpawned = false;
APawn* SpawnedPawn = UAIBlueprintHelperLibrary::SpawnAIFromClass(AITest->GetWorld(), PawnClass, BehaviorTree
, AITest->GetRandomizedLocation(SpawnLocation->GetActorLocation())
, SpawnLocation->GetActorRotation()
, /*bNoCollisionFail=*/true);
if (SpawnedPawn == NULL)
{
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/AssetDefinition_BehaviorTree.cpp:35
Scope (from outer to inner):
file
function EAssetCommandResult UAssetDefinition_BehaviorTree::OpenAssets
Source code excerpt:
const EToolkitMode::Type Mode = OpenArgs.GetToolkitMode();
for (UBehaviorTree* BehaviorTree : OpenArgs.LoadObjects<UBehaviorTree>())
{
// check if we have an editor open for this BT's blackboard & use that if we can
bool bFoundExisting = false;
if (BehaviorTree->BlackboardAsset != nullptr)
{
constexpr bool bFocusIfOpen = false;
FBehaviorTreeEditor* ExistingInstance = static_cast<FBehaviorTreeEditor*>(GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->FindEditorForAsset(BehaviorTree->BlackboardAsset, bFocusIfOpen));
if (ExistingInstance != nullptr && ExistingInstance->GetBehaviorTree() == nullptr)
{
ExistingInstance->InitBehaviorTreeEditor(Mode, OpenArgs.ToolkitHost, BehaviorTree);
bFoundExisting = true;
}
}
if (!bFoundExisting)
{
FBehaviorTreeEditorModule& BehaviorTreeEditorModule = FModuleManager::GetModuleChecked<FBehaviorTreeEditorModule>("BehaviorTreeEditor");
BehaviorTreeEditorModule.CreateBehaviorTreeEditor(Mode, OpenArgs.ToolkitHost, BehaviorTree);
}
}
return EAssetCommandResult::Handled;
}
EAssetCommandResult UAssetDefinition_BehaviorTree::PerformAssetDiff(const FAssetDiffArgs& DiffArgs) const
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDebugger.cpp:1078
Scope (from outer to inner):
file
function void FBehaviorTreeDebugger::StopPlaySession
Source code excerpt:
// @TODO: we need a unified flow to leave debugging mode from the different debuggers to prevent strong coupling between modules.
// Each debugger (Blueprint & BehaviorTree for now) could then take the appropriate actions to resume the session.
if (FSlateApplication::Get().InKismetDebuggingMode())
{
FSlateApplication::Get().LeaveDebuggingMode();
}
}
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeDebugger.cpp:1099
Scope (from outer to inner):
file
function void FBehaviorTreeDebugger::ResumePlaySession
Source code excerpt:
{
// @TODO: we need a unified flow to leave debugging mode from the different debuggers to prevent strong coupling between modules.
// Each debugger (Blueprint & BehaviorTree for now) could then take the appropriate actions to resume the session.
if (FSlateApplication::Get().InKismetDebuggingMode())
{
FSlateApplication::Get().LeaveDebuggingMode();
}
GUnrealEd->PlaySessionResumed();
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:139
Scope (from outer to inner):
file
function FBehaviorTreeEditor::FBehaviorTreeEditor
Source code excerpt:
bHasMultipleServiceBP = false;
BehaviorTree = nullptr;
BlackboardData = nullptr;
bCheckDirtyOnAssetSave = true;
GraphClass = UBehaviorTreeGraph::StaticClass();
GraphName = "Behavior Tree";
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:197
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::NotifyPostChange
Source code excerpt:
if(PropertyChangedEvent.Property != nullptr && PropertyChangedEvent.Property->GetFName() == TEXT("BlackboardAsset"))
{
BlackboardData = BehaviorTree->BlackboardAsset;
}
RefreshBlackboardViewsAssociatedObject();
}
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:223
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::InitBehaviorTreeEditor
Source code excerpt:
if(BehaviorTreeToEdit != nullptr)
{
BehaviorTree = BehaviorTreeToEdit;
if(BehaviorTree->BlackboardAsset != nullptr)
{
BlackboardData = BehaviorTree->BlackboardAsset;
}
}
else if(BlackboardDataToEdit != nullptr)
{
BlackboardData = BlackboardDataToEdit;
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:253
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::InitBehaviorTreeEditor
Source code excerpt:
TArray<UObject*> ObjectsToEdit;
if(BehaviorTree != nullptr)
{
ObjectsToEdit.Add(BehaviorTree);
}
if(BlackboardData != nullptr)
{
ObjectsToEdit.Add(BlackboardData);
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:268
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::InitBehaviorTreeEditor
Source code excerpt:
// if we are already editing objects, dont try to recreate the editor from scratch but update the list of objects in edition
// ex: BehaviorTree may want to reuse an editor already opened for its associated Blackboard asset.
const TArray<UObject*>* EditedObjects = GetObjectsCurrentlyBeingEdited();
if(EditedObjects == nullptr || EditedObjects->Num() == 0)
{
FGraphEditorCommands::Register();
FBTCommonCommands::Register();
FBTDebuggerCommands::Register();
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:286
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::InitBehaviorTreeEditor
Source code excerpt:
Debugger = MakeShareable(new FBehaviorTreeDebugger);
Debugger->Setup(BehaviorTree, SharedThis(this));
BindDebuggerToolbarCommands();
FBehaviorTreeEditorModule& BehaviorTreeEditorModule = FModuleManager::LoadModuleChecked<FBehaviorTreeEditorModule>( "BehaviorTreeEditor" );
AddMenuExtender(BehaviorTreeEditorModule.GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
AddToolbarExtender(BehaviorTreeEditorModule.GetToolBarExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects()));
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:315
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::InitBehaviorTreeEditor
Source code excerpt:
{
check(Debugger.IsValid());
Debugger->Setup(BehaviorTree, SharedThis(this));
for (UObject* ObjectToEdit : ObjectsToEdit)
{
if (!EditedObjects->Contains(ObjectToEdit))
{
AddEditingObject(ObjectToEdit);
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:342
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::RestoreBehaviorTree
Source code excerpt:
{
// Update BT asset data based on saved graph to have correct data in editor
UBehaviorTreeGraph* MyGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
const bool bNewGraph = MyGraph == NULL;
if (MyGraph == NULL)
{
const TSubclassOf<UEdGraphSchema> SchemaClass = GetDefault<UBehaviorTreeGraph>(GraphClass)->Schema;
check(SchemaClass);
BehaviorTree->BTGraph = FBlueprintEditorUtils::CreateNewGraph(BehaviorTree, GraphName, GraphClass, SchemaClass);
MyGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
// Initialize the behavior tree graph
const UEdGraphSchema* Schema = MyGraph->GetSchema();
Schema->CreateDefaultNodesForGraph(*MyGraph);
MyGraph->OnCreated();
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:367
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::RestoreBehaviorTree
Source code excerpt:
TSharedPtr<SDockTab> DocumentTab = DocumentManager->OpenDocument(Payload, bNewGraph ? FDocumentTracker::OpenNewDocument : FDocumentTracker::RestorePreviousDocument);
if(BehaviorTree->LastEditedDocuments.Num() > 0)
{
TSharedRef<SGraphEditor> GraphEditor = StaticCastSharedRef<SGraphEditor>(DocumentTab->GetContent());
GraphEditor->SetViewLocation(BehaviorTree->LastEditedDocuments[0].SavedViewOffset, BehaviorTree->LastEditedDocuments[0].SavedZoomAmount);
}
const bool bIncreaseVersionNum = false;
if(bNewGraph)
{
MyGraph->UpdateAsset(UBehaviorTreeGraph::ClearDebuggerFlags | UBehaviorTreeGraph::KeepRebuildCounter);
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:396
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::SaveEditedObjectState
Source code excerpt:
{
// Clear currently edited documents
BehaviorTree->LastEditedDocuments.Empty();
// Ask all open documents to save their state, which will update LastEditedDocuments
DocumentManager->SaveAllState();
}
void FBehaviorTreeEditor::HandleBlackboardEntrySelected(const FBlackboardEntry* BlackboardEntry, bool bIsInherited)
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:780
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::OnSelectedNodesChanged
Source code excerpt:
TArray<UObject*> Selection = BehaviorTreeEditorUtils::GetSelectionForPropertyEditor(NewSelection, SelectionInfo);
UBehaviorTreeGraph* MyGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
FAbortDrawHelper Mode0, Mode1;
bShowDecoratorRangeLower = false;
bShowDecoratorRangeSelf = false;
bForceDisablePropertyEdit = SelectionInfo.bInjectedNode;
bSelectedNodeIsInjected = SelectionInfo.bInjectedNode;
bSelectedNodeIsRootLevel = SelectionInfo.bRootLevelNode;
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1143
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::OnFinishedChangingProperties
Source code excerpt:
GetAbortModePreview(Cast<UBTDecorator>(DecoratorNode->NodeInstance), Mode0, Mode1);
UBehaviorTreeGraph* MyGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
MyGraph->UpdateAbortHighlight(Mode0, Mode1);
}
}
}
}
else if(PropertyChangedEvent.Property->GetFName() == TEXT("BlackboardAsset"))
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1160
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::OnFinishedChangingProperties
Source code excerpt:
if (PropertyChangedEvent.Property && PropertyChangedEvent.Property->GetFName() == TEXT("BehaviorAsset"))
{
UBehaviorTreeGraph* MyGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
MyGraph->UpdateInjectedNodes();
MyGraph->UpdateAsset(UBehaviorTreeGraph::ClearDebuggerFlags);
}
const TSharedPtr<SGraphEditor> FocusedGraphEd = UpdateGraphEdPtr.Pin();
if (FocusedGraphEd.IsValid() && FocusedGraphEd->GetCurrentGraph())
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1174
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::OnPackageSaved
Source code excerpt:
void FBehaviorTreeEditor::OnPackageSaved(const FString& PackageFileName, UPackage* Package, FObjectPostSaveContext ObjectSaveContext)
{
UBehaviorTreeGraph* MyGraph = BehaviorTree ? Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph) : NULL;
if (MyGraph)
{
const bool bUpdated = MyGraph->UpdateInjectedNodes();
if (bUpdated)
{
MyGraph->UpdateAsset(UBehaviorTreeGraph::ClearDebuggerFlags);
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1406
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::SaveAsset_Execute
Source code excerpt:
void FBehaviorTreeEditor::SaveAsset_Execute()
{
if (BehaviorTree)
{
UBehaviorTreeGraph* BTGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
if (BTGraph)
{
BTGraph->OnSave();
}
}
// save it
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1605
Scope (from outer to inner):
file
function bool FBehaviorTreeEditor::CanAccessBehaviorTreeMode
Source code excerpt:
bool FBehaviorTreeEditor::CanAccessBehaviorTreeMode() const
{
return BehaviorTree != nullptr;
}
FText FBehaviorTreeEditor::GetLocalizedMode(FName InMode)
{
static TMap< FName, FText > LocModes;
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1626
Scope (from outer to inner):
file
function UEdGraphNode* FBehaviorTreeEditor::FindInjectedNode
Source code excerpt:
UEdGraphNode* FBehaviorTreeEditor::FindInjectedNode(int32 Index) const
{
UBehaviorTreeGraph* BTGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
return BTGraph ? BTGraph->FindInjectedNode(Index) : NULL;
}
void FBehaviorTreeEditor::DoubleClickNode(UEdGraphNode* Node)
{
FocusAttentionOnNode(Node);
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1649
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::FocusWindow
Source code excerpt:
void FBehaviorTreeEditor::FocusWindow(UObject* ObjectToFocusOn)
{
if(ObjectToFocusOn == BehaviorTree)
{
SetCurrentMode(BehaviorTreeMode);
}
else if(ObjectToFocusOn == GetBlackboardData())
{
SetCurrentMode(BlackboardMode);
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1663
Scope (from outer to inner):
file
function bool FBehaviorTreeEditor::IncludeAssetInRestoreOpenAssetsPrompt
Source code excerpt:
bool FBehaviorTreeEditor::IncludeAssetInRestoreOpenAssetsPrompt(UObject* Asset) const
{
// If we're in a BT editor which has a valid BehaviorTree, then don't reopen the BB during restore, only the BT
return Asset && (!Asset->IsA(UBlackboardData::StaticClass()) || !BehaviorTree);
}
void FBehaviorTreeEditor::OnNodeTitleCommitted(const FText& NewText, ETextCommit::Type CommitInfo, UEdGraphNode* NodeBeingChanged)
{
if (NodeBeingChanged)
{
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1702
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::DebuggerUpdateGraph
Source code excerpt:
void FBehaviorTreeEditor::DebuggerUpdateGraph()
{
UBehaviorTreeGraph* BTGraph = BehaviorTree ? Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph) : NULL;
if (BTGraph)
{
BTGraph->RebuildExecutionOrder();
}
}
FText FBehaviorTreeEditor::GetToolkitName() const
{
const UObject* EditingObject = GetCurrentMode() == BehaviorTreeMode ? (UObject*)BehaviorTree : (UObject*)GetBlackboardData();
if(EditingObject != nullptr)
{
return FAssetEditorToolkit::GetLabelForObject(EditingObject);
}
return FText();
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1722
Scope (from outer to inner):
file
function FText FBehaviorTreeEditor::GetToolkitToolTipText
Source code excerpt:
FText FBehaviorTreeEditor::GetToolkitToolTipText() const
{
const UObject* EditingObject = GetCurrentMode() == BehaviorTreeMode ? (UObject*)BehaviorTree : (UObject*)GetBlackboardData();
if(EditingObject != nullptr)
{
return FAssetEditorToolkit::GetToolTipTextForObject(EditingObject);
}
return FText();
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1733
Scope (from outer to inner):
file
function UBehaviorTree* FBehaviorTreeEditor::GetBehaviorTree
Source code excerpt:
UBehaviorTree* FBehaviorTreeEditor::GetBehaviorTree() const
{
return BehaviorTree;
}
UBlackboardData* FBehaviorTreeEditor::GetBlackboardData() const
{
return BehaviorTree == nullptr ? BlackboardData : ToRawPtr(BehaviorTree->BlackboardAsset);
}
void FBehaviorTreeEditor::RefreshDebugger()
{
Debugger->Refresh();
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1818
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::HandleNewNodeClassPicked
Source code excerpt:
{
UE_CLOG(InClass == nullptr, LogBehaviorTreeEditor, Error, TEXT("Trying to handle new node of NULL class for Behavior Treee %s ")
, *GetNameSafe(BehaviorTree));
if(BehaviorTree != nullptr && InClass != nullptr && BehaviorTree->GetOutermost())
{
const FString ClassName = FBlueprintEditorUtils::GetClassNameWithoutSuffix(InClass);
FString PathName = BehaviorTree->GetOutermost()->GetPathName();
PathName = FPaths::GetPath(PathName);
// Now that we've generated some reasonable default locations/names for the package, allow the user to have the final say
// before we create the package and initialize the blueprint inside of it.
FSaveAssetDialogConfig SaveAssetDialogConfig;
SaveAssetDialogConfig.DialogTitleOverride = LOCTEXT("SaveAssetDialogTitle", "Save Asset As");
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1911
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::CreateNewBlackboard
Source code excerpt:
void FBehaviorTreeEditor::CreateNewBlackboard()
{
FString PathName = BehaviorTree->GetOutermost()->GetPathName();
PathName = FPaths::GetPath(PathName);
const FString PathNameWithFilename = PathName / LOCTEXT("NewBlackboardName", "NewBlackboardData").ToString();
FString Name;
FString PackageName;
FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1925
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::CreateNewBlackboard
Source code excerpt:
if (NewAsset != nullptr)
{
UBehaviorTreeGraph* BTGraph = Cast<UBehaviorTreeGraph>(BehaviorTree->BTGraph);
if (BTGraph)
{
// Update root node with the newly created asset
UBehaviorTreeGraphNode_Root* RootNode = nullptr;
for (const auto& Node : BTGraph->Nodes)
{
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/BehaviorTreeEditor.cpp:1943
Scope (from outer to inner):
file
function void FBehaviorTreeEditor::CreateNewBlackboard
Source code excerpt:
}
UE_CLOG(BehaviorTree->BlackboardAsset != nullptr, LogBehaviorTreeEditor, Log, TEXT("Blackboard data asset %s has been replaced by %s"), *GetNameSafe(BlackboardData), *GetNameSafe(NewAsset));
BehaviorTree->BlackboardAsset = NewAsset;
BlackboardData = NewAsset;
RefreshBlackboardViewsAssociatedObject();
}
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/FindInBT.h:66
Scope: file
Source code excerpt:
};
/** Widget for searching for (BT nodes) across focused BehaviorTree */
class SFindInBT : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SFindInBT){}
SLATE_END_ARGS()
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.cpp:142
Scope (from outer to inner):
file
function BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SBehaviorTreeDiff::Construct
Source code excerpt:
FDiffListCommands::Register();
PanelOld.BehaviorTree = InArgs._BehaviorTreeOld;
PanelNew.BehaviorTree = InArgs._BehaviorTreeNew;
PanelOld.RevisionInfo = InArgs._OldRevision;
PanelNew.RevisionInfo = InArgs._NewRevision;
PanelOld.bShowAssetName = InArgs._ShowAssetNames;
PanelNew.bShowAssetName = InArgs._ShowAssetNames;
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.cpp:223
Scope (from outer to inner):
file
function BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SBehaviorTreeDiff::Construct
Source code excerpt:
];
PanelOld.GeneratePanel(PanelOld.BehaviorTree ? PanelOld.BehaviorTree->BTGraph : nullptr, FoundDiffs);
PanelNew.GeneratePanel(PanelNew.BehaviorTree ? PanelNew.BehaviorTree->BTGraph : nullptr, FoundDiffs);
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
FReply SBehaviorTreeDiff::OnOpenInDefaults()
{
OpenInDefaults.ExecuteIfBound(PanelOld.BehaviorTree, PanelNew.BehaviorTree);
return FReply::Handled();
}
TSharedRef<SWidget> SBehaviorTreeDiff::GenerateDiffListWidget()
{
BuildDiffSourceArray();
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.cpp:303
Scope (from outer to inner):
file
function void SBehaviorTreeDiff::BuildDiffSourceArray
Source code excerpt:
FoundDiffs->Empty();
DiffListSource.Empty();
if (!PanelOld.BehaviorTree || !PanelNew.BehaviorTree)
{
return;
}
FGraphDiffControl::DiffGraphs(PanelOld.BehaviorTree->BTGraph, PanelNew.BehaviorTree->BTGraph, *FoundDiffs);
for (auto DiffIt(FoundDiffs->CreateConstIterator()); DiffIt; ++DiffIt)
{
DiffListSource.Add(FSharedDiffOnGraph(new FTreeDiffResultItem(*DiffIt)));
}
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.cpp:456
Scope (from outer to inner):
file
function SBehaviorTreeDiff::FBehaviorTreeDiffPanel::FBehaviorTreeDiffPanel
Source code excerpt:
SBehaviorTreeDiff::FBehaviorTreeDiffPanel::FBehaviorTreeDiffPanel()
{
BehaviorTree = NULL;
}
void SBehaviorTreeDiff::FBehaviorTreeDiffPanel::GeneratePanel(UEdGraph* Graph, TSharedPtr<TArray<FDiffSingleResult>> DiffResults)
{
TSharedPtr<SWidget> Widget = SNew(SBorder)
.HAlign(HAlign_Center)
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.cpp:544
Scope (from outer to inner):
file
function FText SBehaviorTreeDiff::FBehaviorTreeDiffPanel::GetTitle
Source code excerpt:
const FText ChangelistText = FText::AsNumber(RevisionInfo.Changelist, &FNumberFormattingOptions::DefaultNoGrouping());
if (bShowAssetName && BehaviorTree)
{
FString AssetName = BehaviorTree->GetName();
if(ISourceControlModule::Get().GetProvider().UsesChangelists())
{
FText LocalizedFormat = LOCTEXT("NamedRevisionDiffFmtUsesChangelists", "{0} - Revision {1}, CL {2}, {3}");
Title = FText::Format(LocalizedFormat, FText::FromString(AssetName), RevisionText, ChangelistText, DateText);
}
else
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.cpp:572
Scope (from outer to inner):
file
function FText SBehaviorTreeDiff::FBehaviorTreeDiffPanel::GetTitle
Source code excerpt:
}
}
else if (bShowAssetName && BehaviorTree)
{
FString AssetName = BehaviorTree->GetName();
FText LocalizedFormat = LOCTEXT("NamedCurrentRevisionFmt", "{0} - Current Revision");
Title = FText::Format(LocalizedFormat, FText::FromString(AssetName));
}
return Title;
}
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Private/SBehaviorTreeDiff.h:91
Scope (from outer to inner):
file
class class SBehaviorTreeDiff: public SCompoundWidget
Source code excerpt:
// The behavior Tree that owns the graph we are showing
class UBehaviorTree* BehaviorTree;
// Revision information for this behavior tree
FRevisionInfo RevisionInfo;
// The border around the graph editor, used to change the content when new graphs are set
TSharedPtr<SBorder> GraphEditorBorder;
#Loc: <Workspace>/Engine/Source/Editor/BehaviorTreeEditor/Public/BehaviorTreeEditor.h:306
Scope (from outer to inner):
file
class class FBehaviorTreeEditor : public IBehaviorTreeEditor, public FAIGraphEditor, public FNotifyHook
Source code excerpt:
/* The Behavior Tree being edited */
UBehaviorTree* BehaviorTree;
/* The Blackboard Data being edited */
UBlackboardData* BlackboardData;
TWeakObjectPtr<class UBehaviorTreeGraphNode_CompositeDecorator> FocusedGraphOwner;
#Loc: <Workspace>/Engine/Source/Runtime/AIModule/Classes/Blueprint/AIBlueprintHelperLibrary.h:35
Scope (from outer to inner):
file
class class UAIBlueprintHelperLibrary : public UBlueprintFunctionLibrary
Source code excerpt:
/** Spawns AI agent of a given class. The PawnClass needs to have AIController
* set for the function to spawn a controller as well.
* @param BehaviorTree if set, and the function has successfully spawned
* and AI controller, this BehaviorTree asset will be assigned to the AI
* controller, and run.
* @param Owner lets you spawn the AI in a sublevel rather than in the
* persistent level (which is the default behavior).
*/
UFUNCTION(BlueprintCallable, Category="AI", meta=(WorldContext="WorldContextObject", UnsafeDuringActorConstruction="true", AdvancedDisplay = "Owner"))
static AIMODULE_API APawn* SpawnAIFromClass(UObject* WorldContextObject, TSubclassOf<APawn> PawnClass, UBehaviorTree* BehaviorTree, FVector Location, FRotator Rotation = FRotator::ZeroRotator, bool bNoCollisionFail = false, AActor* Owner = nullptr);
/** The way it works exactly is if the actor passed in is a pawn, then the function retrieves
* pawn's controller cast to AIController. Otherwise the function returns actor cast to AIController. */
UFUNCTION(BlueprintPure, Category = "AI", meta = (DefaultToSelf = "ControlledObject"))
static AIMODULE_API AAIController* GetAIController(AActor* ControlledActor);
UFUNCTION(BlueprintPure, Category="AI", meta=(DefaultToSelf="Target"))
#Loc: <Workspace>/Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTree.cpp:2
Scope: file
Source code excerpt:
#include "BehaviorTree/BehaviorTree.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(BehaviorTree)
DEFINE_LOG_CATEGORY(LogBehaviorTree);
UBehaviorTree::UBehaviorTree(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
}
#Loc: <Workspace>/Engine/Source/Runtime/AIModule/Private/Blueprint/AIBlueprintHelperLibrary.cpp:184
Scope (from outer to inner):
file
function APawn* UAIBlueprintHelperLibrary::SpawnAIFromClass
Source code excerpt:
}
APawn* UAIBlueprintHelperLibrary::SpawnAIFromClass(UObject* WorldContextObject, TSubclassOf<APawn> PawnClass, UBehaviorTree* BehaviorTree, FVector Location, FRotator Rotation, bool bNoCollisionFail, AActor *Owner)
{
APawn* NewPawn = NULL;
UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull);
if (World && *PawnClass)
{
#Loc: <Workspace>/Engine/Source/Runtime/AIModule/Private/Blueprint/AIBlueprintHelperLibrary.cpp:204
Scope (from outer to inner):
file
function APawn* UAIBlueprintHelperLibrary::SpawnAIFromClass
Source code excerpt:
}
if (BehaviorTree != NULL)
{
AAIController* AIController = Cast<AAIController>(NewPawn->Controller);
if (AIController != NULL)
{
AIController->RunBehaviorTree(BehaviorTree);
}
}
}
}
return NewPawn;
#Loc: <Workspace>/Engine/Source/Runtime/CoreUObject/Public/UObject/ObjectMacros.h:1193
Scope (from outer to inner):
file
namespace UM
Source code excerpt:
IgnoreCategoryKeywordsInSubclasses,
/// [ClassMetadata] For BehaviorTree nodes indicates that the class is deprecated and will display a warning when compiled.
DeprecatedNode,
/// [ClassMetadata] [PropertyMetadata] [FunctionMetadata] Used in conjunction with DeprecatedNode, DeprecatedProperty, or DeprecatedFunction to customize the warning message displayed to the user.
DeprecationMessage,
/// [ClassMetadata] [PropertyMetadata] [FunctionMetadata] The name to display for this class, property, or function instead of auto-generating it from the name.