void FBehaviorTreeDebugger::CollectBreakpointsFromAsset(class UBehaviorTreeGraphNode* Node) { if (Node == NULL) { return; } for (int32 PinIdx = 0; PinIdx < Node->Pins.Num(); PinIdx++) { UEdGraphPin* Pin = Node->Pins[PinIdx]; if (Pin->Direction != EGPD_Output) { continue; } for (int32 i = 0; i < Pin->LinkedTo.Num(); i++) { UBehaviorTreeGraphNode* LinkedNode = Cast<UBehaviorTreeGraphNode>(Pin->LinkedTo[i]->GetOwningNode()); if (LinkedNode) { UBTNode* BTNode = Cast<UBTNode>(LinkedNode->NodeInstance); if (BTNode && LinkedNode->bHasBreakpoint && LinkedNode->bIsBreakpointEnabled) { ActiveBreakpoints.Add(BTNode->GetExecutionIndex()); } CollectBreakpointsFromAsset(LinkedNode); } } } }
void UBTNode::InitializeInSubtree(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32& NextInstancedIndex, EBTMemoryInit::Type InitType) const { if (bCreateNodeInstance) { // composite nodes can't be instanced! check(IsA(UBTCompositeNode::StaticClass()) == false); UBTNode* NodeInstance = OwnerComp.NodeInstances.IsValidIndex(NextInstancedIndex) ? OwnerComp.NodeInstances[NextInstancedIndex] : NULL; if (NodeInstance == NULL) { NodeInstance = NewObject<UBTNode>(&OwnerComp, GetClass(), GetFName(), RF_NoFlags, (UObject*)(this)); NodeInstance->InitializeNode(GetParentNode(), GetExecutionIndex(), GetMemoryOffset(), GetTreeDepth()); NodeInstance->bIsInstanced = true; OwnerComp.NodeInstances.Add(NodeInstance); } check(NodeInstance); NodeInstance->SetOwner(OwnerComp.GetOwner()); FBTInstancedNodeMemory* MyMemory = GetSpecialNodeMemory<FBTInstancedNodeMemory>(NodeMemory); MyMemory->NodeIdx = NextInstancedIndex; NodeInstance->OnInstanceCreated(OwnerComp); NextInstancedIndex++; } else { InitializeMemory(OwnerComp, NodeMemory, InitType); } }
void FBehaviorTreeDebugger::OnBreakpointRemoved(class UBehaviorTreeGraphNode* Node) { if (IsDebuggerReady()) { UBTNode* BTNode = Cast<UBTNode>(Node->NodeInstance); if (BTNode) { ActiveBreakpoints.RemoveSingleSwap(BTNode->GetExecutionIndex()); } } }
const UBlackboardData* FBlackboardSelectorDetails::FindBlackboardAsset(UObject* InObj) { for (UObject* TestOb = InObj; TestOb; TestOb = TestOb->GetOuter()) { UBTNode* NodeOb = Cast<UBTNode>(TestOb); if (NodeOb) { return NodeOb->GetBlackboardAsset(); } } return NULL; }
void UBehaviorTreeGraphNode::PostEditImport() { ResetNodeOwner(); if (NodeInstance) { UBehaviorTree* BT = Cast<UBehaviorTree>(GetBehaviorTreeGraph()->GetOuter()); if (BT) { UBTNode* BTNode = (UBTNode*)NodeInstance; BTNode->InitializeFromAsset(*BT); BTNode->InitializeNode(NULL, MAX_uint16, 0, 0); } } }
void UBehaviorTreeGraph::RebuildExecutionOrder() { // initial cleanup & root node search UBehaviorTreeGraphNode_Root* RootNode = NULL; for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UBehaviorTreeGraphNode* Node = Cast<UBehaviorTreeGraphNode>(Nodes[Index]); // prepare node instance UBTNode* NodeInstance = Cast<UBTNode>(Node->NodeInstance); if (NodeInstance) { // mark all nodes as disconnected first, path from root will replace it with valid values later NodeInstance->InitializeNode(NULL, MAX_uint16, 0, 0); } // cache root if (RootNode == NULL) { RootNode = Cast<UBehaviorTreeGraphNode_Root>(Nodes[Index]); } UBehaviorTreeGraphNode_CompositeDecorator* CompositeDecorator = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(Nodes[Index]); if (CompositeDecorator) { CompositeDecorator->ResetExecutionRange(); } } if (RootNode && RootNode->Pins.Num() > 0 && RootNode->Pins[0]->LinkedTo.Num() > 0) { UBehaviorTreeGraphNode* Node = Cast<UBehaviorTreeGraphNode>(RootNode->Pins[0]->LinkedTo[0]->GetOwningNode()); if (Node) { UBTCompositeNode* BTNode = Cast<UBTCompositeNode>(Node->NodeInstance); if (BTNode) { uint16 ExecutionIndex = 0; uint8 TreeDepth = 0; BTNode->InitializeNode(NULL, ExecutionIndex, 0, TreeDepth); ExecutionIndex++; BTGraphHelpers::RebuildExecutionOrder(Node, BTNode, &ExecutionIndex, TreeDepth); } } } }
void UBehaviorTreeGraphNode::PostPlacedNewNode() { UClass* NodeClass = ClassData.GetClass(true); if (NodeClass) { UBehaviorTree* BT = Cast<UBehaviorTree>(GetBehaviorTreeGraph()->GetOuter()); if (BT) { NodeInstance = ConstructObject<UBTNode>(NodeClass, BT); UBTNode* BTNode = (UBTNode*)NodeInstance; BTNode->SetFlags(RF_Transactional); BTNode->InitializeFromAsset(*BT); BTNode->InitializeNode(NULL, MAX_uint16, 0, 0); } } }
void UBehaviorTreeGraphNode_CompositeDecorator::OnBlackboardUpdate() { UBehaviorTreeDecoratorGraph* MyGraph = Cast<UBehaviorTreeDecoratorGraph>(BoundGraph); UBehaviorTree* BTAsset = Cast<UBehaviorTree>(GetOuter()->GetOuter()); if (MyGraph && BTAsset) { for (int32 i = 0; i < MyGraph->Nodes.Num(); i++) { UBehaviorTreeDecoratorGraphNode_Decorator* MyNode = Cast<UBehaviorTreeDecoratorGraphNode_Decorator>(MyGraph->Nodes[i]); UBTNode* MyNodeInstance = MyNode ? Cast<UBTNode>(MyNode->NodeInstance) : NULL; if (MyNodeInstance) { MyNodeInstance->InitializeFromAsset(*BTAsset); } } } }
void UBehaviorTreeGraph::UpdateAbortHighlight(struct FAbortDrawHelper& Mode0, struct FAbortDrawHelper& Mode1) { for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UBehaviorTreeGraphNode* Node = Cast<UBehaviorTreeGraphNode>(Nodes[Index]); UBTNode* NodeInstance = Node ? Cast<UBTNode>(Node->NodeInstance) : NULL; if (NodeInstance) { const uint16 ExecIndex = NodeInstance->GetExecutionIndex(); Node->bHighlightInAbortRange0 = (ExecIndex != MAX_uint16) && (ExecIndex >= Mode0.AbortStart) && (ExecIndex <= Mode0.AbortEnd); Node->bHighlightInAbortRange1 = (ExecIndex != MAX_uint16) && (ExecIndex >= Mode1.AbortStart) && (ExecIndex <= Mode1.AbortEnd); Node->bHighlightInSearchRange0 = (ExecIndex != MAX_uint16) && (ExecIndex >= Mode0.SearchStart) && (ExecIndex <= Mode0.SearchEnd); Node->bHighlightInSearchRange1 = (ExecIndex != MAX_uint16) && (ExecIndex >= Mode1.SearchStart) && (ExecIndex <= Mode1.SearchEnd); Node->bHighlightInSearchTree = false; } } }
END_SLATE_FUNCTION_BUILD_OPTIMIZATION void FBlackboardDecoratorDetails::CacheBlackboardData(IDetailLayoutBuilder& DetailLayout) { TArray<TWeakObjectPtr<UObject> > MyOuters; DetailLayout.GetObjectsBeingCustomized(MyOuters); CachedBlackboardAsset.Reset(); for (int32 i = 0; i < MyOuters.Num(); i++) { UBTNode* NodeOb = Cast<UBTNode>(MyOuters[i].Get()); if (NodeOb) { CachedBlackboardAsset = NodeOb->GetBlackboardAsset(); break; } } }
void UBehaviorTreeGraphNode::FindDiffs(UEdGraphNode* OtherNode, FDiffResults& Results) { FDiffSingleResult Diff; Diff.Diff = EDiffType::NODE_PROPERTY; Diff.Node1 = this; Diff.Node2 = OtherNode; Diff.ToolTip = LOCTEXT("DIF_NodePropertyToolTip", "A Property of the node has changed"); Diff.DisplayColor = FLinearColor(0.25f,0.71f,0.85f); UBehaviorTreeGraphNode* ThisBehaviorTreeNode = Cast<UBehaviorTreeGraphNode>(this); UBehaviorTreeGraphNode* OtherBehaviorTreeNode = Cast<UBehaviorTreeGraphNode>(OtherNode); if(ThisBehaviorTreeNode && OtherBehaviorTreeNode) { DiffProperties( ThisBehaviorTreeNode->GetClass(), ThisBehaviorTreeNode, OtherBehaviorTreeNode, Results, Diff ); UBTNode* ThisNodeInstance = Cast<UBTNode>(ThisBehaviorTreeNode->NodeInstance); UBTNode* OtherNodeInstance = Cast<UBTNode>(OtherBehaviorTreeNode->NodeInstance); if(ThisNodeInstance && OtherNodeInstance) { DiffProperties( ThisNodeInstance->GetClass(), ThisNodeInstance, OtherNodeInstance, Results, Diff ); } } }
void UBehaviorTreeGraph::UpdateBlackboardChange() { UBehaviorTree* BTAsset = Cast<UBehaviorTree>(GetOuter()); if (BTAsset == nullptr) { return; } for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UBehaviorTreeGraphNode* MyNode = Cast<UBehaviorTreeGraphNode>(Nodes[Index]); if (MyNode) { UBTNode* MyNodeInstance = Cast<UBTNode>(MyNode->NodeInstance); if (MyNodeInstance) { MyNodeInstance->InitializeFromAsset(*BTAsset); } } for (int32 iDecorator = 0; iDecorator < MyNode->Decorators.Num(); iDecorator++) { UBTNode* MyNodeInstance = MyNode->Decorators[iDecorator] ? Cast<UBTNode>(MyNode->Decorators[iDecorator]->NodeInstance) : NULL; if (MyNodeInstance) { MyNodeInstance->InitializeFromAsset(*BTAsset); } UBehaviorTreeGraphNode_CompositeDecorator* CompDecoratorNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(MyNode->Decorators[iDecorator]); if (CompDecoratorNode) { CompDecoratorNode->OnBlackboardUpdate(); } } for (int32 iService = 0; iService < MyNode->Services.Num(); iService++) { UBTNode* MyNodeInstance = MyNode->Services[iService] ? Cast<UBTNode>(MyNode->Services[iService]->NodeInstance) : NULL; if (MyNodeInstance) { MyNodeInstance->InitializeFromAsset(*BTAsset); } } } }
void UBTNode::InitializeInSubtree(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32& NextInstancedIndex, EBTMemoryInit::Type InitType) const { FBTInstancedNodeMemory* SpecialMemory = GetSpecialNodeMemory<FBTInstancedNodeMemory>(NodeMemory); if (SpecialMemory) { SpecialMemory->NodeIdx = INDEX_NONE; } if (bCreateNodeInstance) { // composite nodes can't be instanced! check(IsA(UBTCompositeNode::StaticClass()) == false); UBTNode* NodeInstance = OwnerComp.NodeInstances.IsValidIndex(NextInstancedIndex) ? OwnerComp.NodeInstances[NextInstancedIndex] : NULL; if (NodeInstance == NULL) { NodeInstance = (UBTNode*)StaticDuplicateObject(this, &OwnerComp); NodeInstance->InitializeNode(GetParentNode(), GetExecutionIndex(), GetMemoryOffset(), GetTreeDepth()); NodeInstance->bIsInstanced = true; OwnerComp.NodeInstances.Add(NodeInstance); } check(NodeInstance); check(SpecialMemory); SpecialMemory->NodeIdx = NextInstancedIndex; NodeInstance->SetOwner(OwnerComp.GetOwner()); NodeInstance->InitializeMemory(OwnerComp, NodeMemory, InitType); check(TreeAsset); NodeInstance->InitializeFromAsset(*TreeAsset); NodeInstance->OnInstanceCreated(OwnerComp); NextInstancedIndex++; } else { InitializeMemory(OwnerComp, NodeMemory, InitType); } }
void UBehaviorTreeGraph::RemoveOrphanedNodes() { UBehaviorTree* BTAsset = CastChecked<UBehaviorTree>(GetOuter()); // Obtain a list of all nodes that should be in the asset TSet<UBTNode*> AllNodes; for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UBehaviorTreeGraphNode* MyNode = Cast<UBehaviorTreeGraphNode>(Nodes[Index]); if (MyNode) { UBTNode* MyNodeInstance = Cast<UBTNode>(MyNode->NodeInstance); if (MyNodeInstance) { AllNodes.Add(MyNodeInstance); } for (int32 iDecorator = 0; iDecorator < MyNode->Decorators.Num(); iDecorator++) { UBehaviorTreeGraphNode_CompositeDecorator* SubgraphNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(MyNode->Decorators[iDecorator]); if (SubgraphNode) { TArray<UBTDecorator*> NodeInstances; TArray<FBTDecoratorLogic> DummyOps; SubgraphNode->CollectDecoratorData(NodeInstances, DummyOps); for (int32 SubIdx = 0; SubIdx < NodeInstances.Num(); SubIdx++) { AllNodes.Add(NodeInstances[SubIdx]); } } else { UBTNode* MyDecoratorNodeInstance = MyNode->Decorators[iDecorator] ? Cast<UBTNode>(MyNode->Decorators[iDecorator]->NodeInstance) : NULL; if (MyDecoratorNodeInstance) { AllNodes.Add(MyDecoratorNodeInstance); } } } for (int32 iService = 0; iService < MyNode->Services.Num(); iService++) { UBTNode* MyServiceNodeInstance = MyNode->Services[iService] ? Cast<UBTNode>(MyNode->Services[iService]->NodeInstance) : NULL; if (MyServiceNodeInstance) { AllNodes.Add(MyServiceNodeInstance); } } } } // Obtain a list of all nodes actually in the asset and discard unused nodes TArray<UObject*> AllInners; const bool bIncludeNestedObjects = false; GetObjectsWithOuter(BTAsset, AllInners, bIncludeNestedObjects); for (auto InnerIt = AllInners.CreateConstIterator(); InnerIt; ++InnerIt) { UBTNode* Node = Cast<UBTNode>(*InnerIt); if (Node && !AllNodes.Contains(Node)) { Node->SetFlags(RF_Transient); Node->Rename(NULL, GetTransientPackage(), REN_DontCreateRedirectors | REN_NonTransactional | REN_ForceNoResetLoaders); } } }
void UBehaviorTreeGraph::UpdateAsset(EDebuggerFlags DebuggerFlags, bool bBumpVersion) { if (bLockUpdates) { return; } // initial cleanup & root node search UBehaviorTreeGraphNode_Root* RootNode = NULL; for (int32 Index = 0; Index < Nodes.Num(); ++Index) { UBehaviorTreeGraphNode* Node = Cast<UBehaviorTreeGraphNode>(Nodes[Index]); // debugger flags if (DebuggerFlags == ClearDebuggerFlags) { Node->ClearDebuggerState(); for (int32 iAux = 0; iAux < Node->Services.Num(); iAux++) { Node->Services[iAux]->ClearDebuggerState(); } for (int32 iAux = 0; iAux < Node->Decorators.Num(); iAux++) { Node->Decorators[iAux]->ClearDebuggerState(); } } // parent chain Node->ParentNode = NULL; for (int32 iAux = 0; iAux < Node->Services.Num(); iAux++) { Node->Services[iAux]->ParentNode = Node; } for (int32 iAux = 0; iAux < Node->Decorators.Num(); iAux++) { Node->Decorators[iAux]->ParentNode = Node; } // prepare node instance UBTNode* NodeInstance = Cast<UBTNode>(Node->NodeInstance); if (NodeInstance) { // mark all nodes as disconnected first, path from root will replace it with valid values later NodeInstance->InitializeNode(NULL, MAX_uint16, 0, 0); } // cache root if (RootNode == NULL) { RootNode = Cast<UBehaviorTreeGraphNode_Root>(Nodes[Index]); } UBehaviorTreeGraphNode_CompositeDecorator* CompositeDecorator = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(Nodes[Index]); if (CompositeDecorator) { CompositeDecorator->ResetExecutionRange(); } } if (RootNode && RootNode->Pins.Num() > 0 && RootNode->Pins[0]->LinkedTo.Num() > 0) { UBehaviorTreeGraphNode* Node = Cast<UBehaviorTreeGraphNode>(RootNode->Pins[0]->LinkedTo[0]->GetOwningNode()); if (Node) { CreateBTFromGraph(Node); if (bBumpVersion) { GraphVersion++; } } } }
void RebuildExecutionOrder(UBehaviorTreeGraphNode* RootEdNode, UBTCompositeNode* RootNode, uint16* ExecutionIndex, uint8 TreeDepth) { if (RootEdNode == NULL || RootEdNode == NULL) { return; } // collect services if (RootEdNode->Services.Num()) { for (int32 i = 0; i < RootEdNode->Services.Num(); i++) { UBTService* ServiceInstance = RootEdNode->Services[i] ? Cast<UBTService>(RootEdNode->Services[i]->NodeInstance) : NULL; if (ServiceInstance) { ServiceInstance->InitializeNode(RootNode, *ExecutionIndex, 0, TreeDepth); *ExecutionIndex += 1; } } } // gather all nodes int32 ChildIdx = 0; for (int32 PinIdx = 0; PinIdx < RootEdNode->Pins.Num(); PinIdx++) { UEdGraphPin* Pin = RootEdNode->Pins[PinIdx]; if (Pin->Direction != EGPD_Output) { continue; } // sort connections so that they're organized the same as user can see in the editor TArray<UEdGraphPin*> SortedPins = Pin->LinkedTo; SortedPins.Sort(FCompareNodeXLocation()); for (int32 Index = 0; Index < SortedPins.Num(); ++Index) { UBehaviorTreeGraphNode* GraphNode = Cast<UBehaviorTreeGraphNode>(SortedPins[Index]->GetOwningNode()); if (GraphNode == NULL) { continue; } UBTTaskNode* TaskInstance = Cast<UBTTaskNode>(GraphNode->NodeInstance); UBTCompositeNode* CompositeInstance = Cast<UBTCompositeNode>(GraphNode->NodeInstance); UBTNode* ChildNode = CompositeInstance ? (UBTNode*)CompositeInstance : (UBTNode*)TaskInstance; if (ChildNode == NULL) { continue; } // collect decorators TArray<UBTDecorator*> DecoratorInstances; TArray<FBTDecoratorLogic> DecoratorOperations; CollectDecorators(NULL, GraphNode, DecoratorInstances, DecoratorOperations, true, RootNode, ExecutionIndex, TreeDepth, ChildIdx); InitializeInjectedNodes(GraphNode, RootNode, *ExecutionIndex, TreeDepth, ChildIdx); // special case: subtrees UBTTask_RunBehavior* SubtreeTask = Cast<UBTTask_RunBehavior>(TaskInstance); if (SubtreeTask) { *ExecutionIndex += SubtreeTask->GetInjectedNodesCount(); } ChildNode->InitializeNode(RootNode, *ExecutionIndex, 0, TreeDepth); *ExecutionIndex += 1; ChildIdx++; if (CompositeInstance) { RebuildExecutionOrder(GraphNode, CompositeInstance, ExecutionIndex, TreeDepth + 1); CompositeInstance->InitializeComposite((*ExecutionIndex) - 1); } } } }
void CreateChildren(UBehaviorTree* BTAsset, UBTCompositeNode* RootNode, const UBehaviorTreeGraphNode* RootEdNode, uint16* ExecutionIndex, uint8 TreeDepth) { if (RootEdNode == NULL) { return; } RootNode->Children.Reset(); RootNode->Services.Reset(); // collect services if (RootEdNode->Services.Num()) { for (int32 i = 0; i < RootEdNode->Services.Num(); i++) { UBTService* ServiceInstance = RootEdNode->Services[i] ? Cast<UBTService>(RootEdNode->Services[i]->NodeInstance) : NULL; if (ServiceInstance) { if (Cast<UBehaviorTree>(ServiceInstance->GetOuter()) == NULL) { ServiceInstance->Rename(NULL, BTAsset); } ServiceInstance->InitializeNode(RootNode, *ExecutionIndex, 0, TreeDepth); *ExecutionIndex += 1; RootNode->Services.Add(ServiceInstance); } } } // gather all nodes int32 ChildIdx = 0; for (int32 PinIdx = 0; PinIdx < RootEdNode->Pins.Num(); PinIdx++) { UEdGraphPin* Pin = RootEdNode->Pins[PinIdx]; if (Pin->Direction != EGPD_Output) { continue; } // sort connections so that they're organized the same as user can see in the editor Pin->LinkedTo.Sort(FCompareNodeXLocation()); for (int32 Index = 0; Index < Pin->LinkedTo.Num(); ++Index) { UBehaviorTreeGraphNode* GraphNode = Cast<UBehaviorTreeGraphNode>(Pin->LinkedTo[Index]->GetOwningNode()); if (GraphNode == NULL) { continue; } UBTTaskNode* TaskInstance = Cast<UBTTaskNode>(GraphNode->NodeInstance); if (TaskInstance && Cast<UBehaviorTree>(TaskInstance->GetOuter()) == NULL) { TaskInstance->Rename(NULL, BTAsset); } UBTCompositeNode* CompositeInstance = Cast<UBTCompositeNode>(GraphNode->NodeInstance); if (CompositeInstance && Cast<UBehaviorTree>(CompositeInstance->GetOuter()) == NULL) { CompositeInstance->Rename(NULL, BTAsset); } if (TaskInstance == NULL && CompositeInstance == NULL) { continue; } // collect decorators TArray<UBTDecorator*> DecoratorInstances; TArray<FBTDecoratorLogic> DecoratorOperations; CollectDecorators(BTAsset, GraphNode, DecoratorInstances, DecoratorOperations, true, RootNode, ExecutionIndex, TreeDepth, ChildIdx); // store child data RootNode->Children.AddZeroed(); FBTCompositeChild& ChildInfo = RootNode->Children[ChildIdx]; ChildInfo.ChildComposite = CompositeInstance; ChildInfo.ChildTask = TaskInstance; ChildInfo.Decorators = DecoratorInstances; ChildInfo.DecoratorOps = DecoratorOperations; ChildIdx++; UBTNode* ChildNode = CompositeInstance ? (UBTNode*)CompositeInstance : (UBTNode*)TaskInstance; if (ChildNode && Cast<UBehaviorTree>(ChildNode->GetOuter()) == NULL) { ChildNode->Rename(NULL, BTAsset); } InitializeInjectedNodes(GraphNode, RootNode, *ExecutionIndex, TreeDepth, ChildIdx); // special case: subtrees UBTTask_RunBehavior* SubtreeTask = Cast<UBTTask_RunBehavior>(TaskInstance); if (SubtreeTask) { *ExecutionIndex += SubtreeTask->GetInjectedNodesCount(); } ChildNode->InitializeNode(RootNode, *ExecutionIndex, 0, TreeDepth); *ExecutionIndex += 1; VerifyDecorators(GraphNode); if (CompositeInstance) { CreateChildren(BTAsset, CompositeInstance, GraphNode, ExecutionIndex, TreeDepth + 1); CompositeInstance->InitializeComposite((*ExecutionIndex) - 1); } } } }
void UBTTask_RunBehavior::InjectNodes(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, int32& InstancedIndex) const { if (BehaviorAsset == NULL || BehaviorAsset->RootDecorators.Num() == 0) { return; } const int32 NumInjectedDecorators = BehaviorAsset->RootDecorators.Num(); FBTInstancedNodeMemory* NodeMemoryHeader = (FBTInstancedNodeMemory*)NodeMemory; int32 FirstNodeIdx = NodeMemoryHeader->NodeIdx; uint8* InjectedMemoryBase = NodeMemory + sizeof(FBTInstancedNodeMemory); // initialize on first access if (!OwnerComp.NodeInstances.IsValidIndex(InstancedIndex)) { TArray<uint16> MemoryOffsets; int32 MemorySize = 0; UBehaviorTreeManager::InitializeMemoryHelper(BehaviorAsset->RootDecorators, MemoryOffsets, MemorySize); const int32 AlignedInstanceMemorySize = UBehaviorTreeManager::GetAlignedDataSize(sizeof(FBTInstancedNodeMemory)); // prepare dummy memory block for nodes that won't require instancing and offset it by special data size // InitializeInSubtree will read it through GetSpecialNodeMemory function, which moves pointer back FBTInstancedNodeMemory DummyMemory; uint8* RawDummyMemory = ((uint8*)&DummyMemory) + AlignedInstanceMemorySize; // newly created nodes = full init EBTMemoryInit::Type InitType = EBTMemoryInit::Initialize; NodeMemoryHeader->NodeIdx = InstancedIndex; FirstNodeIdx = InstancedIndex; // create nodes for (int32 Idx = 0; Idx < NumInjectedDecorators; Idx++) { UBTDecorator* DecoratorOb = BehaviorAsset->RootDecorators[Idx]; const bool bUsesInstancing = DecoratorOb->HasInstance(); if (bUsesInstancing) { DecoratorOb->InitializeInSubtree(OwnerComp, InjectedMemoryBase + MemoryOffsets[Idx], InstancedIndex, InitType); } else { DecoratorOb->ForceInstancing(true); DecoratorOb->InitializeInSubtree(OwnerComp, RawDummyMemory, InstancedIndex, InitType); DecoratorOb->ForceInstancing(false); UBTDecorator* InstancedOb = Cast<UBTDecorator>(OwnerComp.NodeInstances.Last()); InstancedOb->InitializeMemory(OwnerComp, InjectedMemoryBase + MemoryOffsets[Idx], InitType); } } // setup their properties uint16 NewExecutionIdx = GetExecutionIndex() - GetInjectedNodesCount(); for (int32 Idx = 0; Idx < NumInjectedDecorators; Idx++) { UBTDecorator* InstancedOb = Cast<UBTDecorator>(OwnerComp.NodeInstances[FirstNodeIdx + Idx]); InstancedOb->InitializeNode(GetParentNode(), NewExecutionIdx, GetMemoryOffset() + MemoryOffsets[Idx], GetTreeDepth() - 1); InstancedOb->MarkInjectedNode(); NewExecutionIdx++; } } else { // restoring existing nodes = partial init EBTMemoryInit::Type InitType = EBTMemoryInit::RestoreSubtree; // initialize memory for injected nodes for (int32 Idx = 0; Idx < NumInjectedDecorators; Idx++) { UBTDecorator* DecoratorOb = BehaviorAsset->RootDecorators[Idx]; UBTDecorator* InstancedOb = Cast<UBTDecorator>(OwnerComp.NodeInstances[FirstNodeIdx + Idx]); const bool bUsesInstancing = DecoratorOb->HasInstance(); if (bUsesInstancing) { InstancedOb->OnInstanceCreated(OwnerComp); } else { uint8* InjectedNodeMemory = InjectedMemoryBase + (InstancedOb->GetMemoryOffset() - GetMemoryOffset()); InstancedOb->InitializeMemory(OwnerComp, InjectedNodeMemory, InitType); } } InstancedIndex += NumInjectedDecorators; } // inject nodes if (GetParentNode()) { const int32 ChildIdx = GetParentNode()->GetChildIndex(*this); if (ChildIdx != INDEX_NONE) { FBTCompositeChild& LinkData = GetParentNode()->Children[ChildIdx]; // check if link already has injected decorators bool bAlreadyInjected = false; for (int32 Idx = 0; Idx < LinkData.Decorators.Num(); Idx++) { if (LinkData.Decorators[Idx] && LinkData.Decorators[Idx]->IsInjected()) { bAlreadyInjected = true; break; } } // add decorators to link const int32 NumOriginalDecorators = LinkData.Decorators.Num(); for (int32 Idx = 0; Idx < NumInjectedDecorators; Idx++) { UBTDecorator* InstancedOb = Cast<UBTDecorator>(OwnerComp.NodeInstances[FirstNodeIdx + Idx]); InstancedOb->InitializeFromAsset(*BehaviorAsset); InstancedOb->InitializeDecorator(ChildIdx); if (!bAlreadyInjected) { LinkData.Decorators.Add(InstancedOb); } } // update composite logic operators if (!bAlreadyInjected && (LinkData.DecoratorOps.Num() || BehaviorAsset->RootDecoratorOps.Num())) { const int32 NumOriginalOps = LinkData.DecoratorOps.Num(); if (NumOriginalDecorators > 0) { // and operator for two groups of composites: original and new one FBTDecoratorLogic MasterAndOp(EBTDecoratorLogic::And, LinkData.DecoratorOps.Num() ? 2 : (NumOriginalDecorators + 1)); LinkData.DecoratorOps.Insert(MasterAndOp, 0); if (NumOriginalOps == 0) { // add Test operations, original link didn't have composite operators for (int32 Idx = 0; Idx < NumOriginalDecorators; Idx++) { FBTDecoratorLogic TestOp(EBTDecoratorLogic::Test, Idx); LinkData.DecoratorOps.Add(TestOp); } } } // add injected operators if (BehaviorAsset->RootDecoratorOps.Num() == 0) { FBTDecoratorLogic InjectedAndOp(EBTDecoratorLogic::And, NumInjectedDecorators); LinkData.DecoratorOps.Add(InjectedAndOp); for (int32 Idx = 0; Idx < NumInjectedDecorators; Idx++) { FBTDecoratorLogic TestOp(EBTDecoratorLogic::Test, NumOriginalDecorators + Idx); LinkData.DecoratorOps.Add(TestOp); } } else { for (int32 Idx = 0; Idx < BehaviorAsset->RootDecoratorOps.Num(); Idx++) { FBTDecoratorLogic InjectedOp = BehaviorAsset->RootDecoratorOps[Idx]; if (InjectedOp.Operation == EBTDecoratorLogic::Test) { InjectedOp.Number += NumOriginalDecorators; } LinkData.DecoratorOps.Add(InjectedOp); } } } #if USE_BEHAVIORTREE_DEBUGGER if (!bAlreadyInjected) { // insert to NextExecutionNode list for debugger UBTNode* NodeIt = GetParentNode(); while (NodeIt && NodeIt->GetNextNode() != this) { NodeIt = NodeIt->GetNextNode(); } if (NodeIt) { NodeIt->InitializeExecutionOrder(OwnerComp.NodeInstances[FirstNodeIdx]); NodeIt = NodeIt->GetNextNode(); for (int32 Idx = 1; Idx < NumInjectedDecorators; Idx++) { NodeIt->InitializeExecutionOrder(OwnerComp.NodeInstances[FirstNodeIdx + Idx]); NodeIt = NodeIt->GetNextNode(); } NodeIt->InitializeExecutionOrder((UBTNode*)this); } } #endif } } }
bool UBehaviorTreeGraphNode::UsesBlueprint() const { UBTNode* BTNodeInstance = Cast<UBTNode>(NodeInstance); return BTNodeInstance != nullptr ? BTNodeInstance->UsesBlueprint() : false; }
FName UBehaviorTreeGraphNode::GetNameIcon() const { UBTNode* BTNodeInstance = Cast<UBTNode>(NodeInstance); return BTNodeInstance != nullptr ? BTNodeInstance->GetNodeIconName() : FName("BTEditor.Graph.BTNode.Icon"); }