END_SLATE_FUNCTION_BUILD_OPTIMIZATION void FBehaviorDecoratorDetails::UpdateAllowedAbortModes() { ModeValues.Reset(); UBTDecorator* MyDecorator = Cast<UBTDecorator>(MyNode); UBTCompositeNode* MyParentNode = MyDecorator ? MyDecorator->GetParentNode() : NULL; const bool bAllowAbortNone = MyDecorator == NULL || MyDecorator->bAllowAbortNone; const bool bAllowAbortSelf = (MyDecorator == NULL || MyDecorator->bAllowAbortChildNodes) && (MyParentNode == NULL || MyParentNode->CanAbortSelf()); const bool bAllowAbortLowerPriority = (MyDecorator == NULL || MyDecorator->bAllowAbortLowerPri) && (MyParentNode == NULL || MyParentNode->CanAbortLowerPriority()); const bool AbortCondition[] = { bAllowAbortNone, bAllowAbortSelf, bAllowAbortLowerPriority, bAllowAbortSelf && bAllowAbortLowerPriority }; EBTFlowAbortMode::Type AbortValues[] = { EBTFlowAbortMode::None, EBTFlowAbortMode::Self, EBTFlowAbortMode::LowerPriority, EBTFlowAbortMode::Both }; for (int32 i = 0; i < 4; i++) { if (AbortCondition[i]) { FStringIntPair ModeDesc; ModeDesc.Int = AbortValues[i]; ModeDesc.Str = UBehaviorTreeTypes::DescribeFlowAbortMode(AbortValues[i]); ModeValues.Add(ModeDesc); } } bIsModeEnabled = MyDecorator && ModeValues.Num(); bShowMode = ModeValues.Num() > 0; }
void UBehaviorTreeDecoratorGraphNode_Decorator::PostPlacedNewNode() { UClass* NodeClass = ClassData.GetClass(true); if (NodeClass != NULL) { UBehaviorTreeGraphNode_CompositeDecorator* OwningNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(GetDecoratorGraph()->GetOuter()); if (OwningNode) { UBehaviorTree* BT = Cast<UBehaviorTree>(OwningNode->GetOuter()->GetOuter()); if (BT) { UBTDecorator* MyDecorator = NewObject<UBTDecorator>(BT, NodeClass); MyDecorator->InitializeFromAsset(*BT); OwningNode->InitializeDecorator(MyDecorator); NodeInstance = MyDecorator; } } } }
void UBehaviorTreeDecoratorGraphNode_Decorator::PostEditImport() { ResetNodeOwner(); if (NodeInstance) { UBehaviorTreeGraphNode_CompositeDecorator* OwningNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(GetDecoratorGraph()->GetOuter()); if (OwningNode) { UBehaviorTree* BT = Cast<UBehaviorTree>(OwningNode->GetOuter()->GetOuter()); if (BT) { UBTDecorator* MyDecorator = (UBTDecorator*)NodeInstance; MyDecorator->InitializeFromAsset(*BT); MyDecorator->InitializeNode(NULL, MAX_uint16, 0, 0); OwningNode->InitializeDecorator(MyDecorator); } } } }
void UBehaviorTreeGraphNode_CompositeDecorator::OnInnerGraphChanged() { BuildDescription(); bCanAbortFlow = false; UBehaviorTreeDecoratorGraph* MyGraph = Cast<UBehaviorTreeDecoratorGraph>(BoundGraph); if (MyGraph) { for (int32 i = 0; i < MyGraph->Nodes.Num(); i++) { UBehaviorTreeDecoratorGraphNode_Decorator* MyNode = Cast<UBehaviorTreeDecoratorGraphNode_Decorator>(MyGraph->Nodes[i]); UBTDecorator* MyNodeInstance = MyNode ? Cast<UBTDecorator>(MyNode->NodeInstance) : NULL; if (MyNodeInstance && MyNodeInstance->GetFlowAbortMode() != EBTFlowAbortMode::None) { bCanAbortFlow = true; break; } } } }
//----------------------------------------------------------------------// // FBehaviorTreeInstance //----------------------------------------------------------------------// void FBehaviorTreeInstance::Initialize(UBehaviorTreeComponent& OwnerComp, UBTCompositeNode& Node, int32& InstancedIndex, EBTMemoryInit::Type InitType) { for (int32 ServiceIndex = 0; ServiceIndex < Node.Services.Num(); ServiceIndex++) { Node.Services[ServiceIndex]->InitializeInSubtree(OwnerComp, Node.Services[ServiceIndex]->GetNodeMemory<uint8>(*this), InstancedIndex, InitType); } uint8* NodeMemory = Node.GetNodeMemory<uint8>(*this); Node.InitializeInSubtree(OwnerComp, NodeMemory, InstancedIndex, InitType); UBTCompositeNode* InstancedComposite = Cast<UBTCompositeNode>(Node.GetNodeInstance(OwnerComp, NodeMemory)); if (InstancedComposite) { InstancedComposite->InitializeComposite(Node.GetLastExecutionIndex()); } for (int32 ChildIndex = 0; ChildIndex < Node.Children.Num(); ChildIndex++) { FBTCompositeChild& ChildInfo = Node.Children[ChildIndex]; for (int32 DecoratorIndex = 0; DecoratorIndex < ChildInfo.Decorators.Num(); DecoratorIndex++) { UBTDecorator* DecoratorOb = ChildInfo.Decorators[DecoratorIndex]; uint8* DecoratorMemory = DecoratorOb->GetNodeMemory<uint8>(*this); DecoratorOb->InitializeInSubtree(OwnerComp, DecoratorMemory, InstancedIndex, InitType); UBTDecorator* InstancedDecoratorOb = Cast<UBTDecorator>(DecoratorOb->GetNodeInstance(OwnerComp, DecoratorMemory)); if (InstancedDecoratorOb) { InstancedDecoratorOb->InitializeParentLink(DecoratorOb->GetChildIndex()); } } if (ChildInfo.ChildComposite) { Initialize(OwnerComp, *(ChildInfo.ChildComposite), InstancedIndex, InitType); } else if (ChildInfo.ChildTask) { for (int32 ServiceIndex = 0; ServiceIndex < ChildInfo.ChildTask->Services.Num(); ServiceIndex++) { UBTService* ServiceOb = ChildInfo.ChildTask->Services[ServiceIndex]; uint8* ServiceMemory = ServiceOb->GetNodeMemory<uint8>(*this); ServiceOb->InitializeInSubtree(OwnerComp, ServiceMemory, InstancedIndex, InitType); UBTService* InstancedServiceOb = Cast<UBTService>(ServiceOb->GetNodeInstance(OwnerComp, ServiceMemory)); if (InstancedServiceOb) { InstancedServiceOb->InitializeParentLink(ServiceOb->GetChildIndex()); } } ChildInfo.ChildTask->InitializeInSubtree(OwnerComp, ChildInfo.ChildTask->GetNodeMemory<uint8>(*this), InstancedIndex, InitType); } } }
void UBTTask_RunBehavior::CleanupMemory(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, EBTMemoryClear::Type CleanupType) const { Super::CleanupMemory(OwnerComp, NodeMemory, CleanupType); if (GetParentNode() && BehaviorAsset) { FBTInstancedNodeMemory* NodeMemoryHeader = (FBTInstancedNodeMemory*)NodeMemory; uint8* InjectedMemoryBase = NodeMemory + sizeof(FBTInstancedNodeMemory); const int32 NumInjectedDecorators = BehaviorAsset->RootDecorators.Num(); for (int32 Idx = 0; Idx < NumInjectedDecorators; Idx++) { const int32 InstancedNodeIdx = NodeMemoryHeader->NodeIdx + Idx; UBTDecorator* InstancedOb = OwnerComp.NodeInstances.IsValidIndex(InstancedNodeIdx) ? Cast<UBTDecorator>(OwnerComp.NodeInstances[InstancedNodeIdx]) : NULL; if (InstancedOb) { uint8* InjectedNodeMemory = InjectedMemoryBase + (InstancedOb->GetMemoryOffset() - GetMemoryOffset()); InstancedOb->CleanupMemory(OwnerComp, InjectedNodeMemory, CleanupType); } } } }
bool UBTCompositeNode::DoDecoratorsAllowExecution(class UBehaviorTreeComponent* OwnerComp, int32 InstanceIdx, int32 ChildIdx) const { const FBTCompositeChild& ChildInfo = Children[ChildIdx]; bool bResult = true; if (ChildInfo.Decorators.Num() == 0) { return bResult; } FBehaviorTreeInstance& MyInstance = OwnerComp->InstanceStack[InstanceIdx]; if (ChildInfo.DecoratorOps.Num() == 0) { // simple check: all decorators must agree for (int32 i = 0; i < ChildInfo.Decorators.Num(); i++) { const UBTDecorator* TestDecorator = ChildInfo.Decorators[i]; const bool bIsAllowed = TestDecorator->CanExecute(OwnerComp, TestDecorator->GetNodeMemory<uint8>(MyInstance)); OwnerComp->StoreDebuggerSearchStep(TestDecorator, InstanceIdx, bIsAllowed); if (!bIsAllowed) { UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("Child[%d] execution forbidden by %s"), ChildIdx, *UBehaviorTreeTypes::DescribeNodeHelper(TestDecorator)); bResult = false; break; } } } else { // advanced check: follow decorator logic operations (composite decorator on child link) UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("Child[%d] execution test with logic operations"), ChildIdx); TArray<FOperationStackInfo> OperationStack; FString Indent; // debugger data collection: // - get index of each decorator from main AND test, they will match graph nodes // - if first operator is not AND it means, that there's only single composite decorator on line // - while updating top level stack, grab index of first failed node int32 NodeDecoratorIdx = INDEX_NONE; int32 FailedDecoratorIdx = INDEX_NONE; bool bShouldStoreNodeIndex = true; for (int32 i = 0; i < ChildInfo.DecoratorOps.Num(); i++) { const FBTDecoratorLogic& DecoratorOp = ChildInfo.DecoratorOps[i]; if (IsLogicOp(DecoratorOp)) { OperationStack.Add(FOperationStackInfo(DecoratorOp)); Indent += TEXT(" "); UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("%spushed %s:%d"), *Indent, *DescribeLogicOp(DecoratorOp.Operation), DecoratorOp.Number); } else if (DecoratorOp.Operation == EBTDecoratorLogic::Test) { const bool bHasOverride = OperationStack.Num() ? OperationStack.Last().bHasForcedResult : false; const bool bCurrentOverride = OperationStack.Num() ? OperationStack.Last().bForcedResult : false; // debugger: store first decorator of graph node if (bShouldStoreNodeIndex) { bShouldStoreNodeIndex = false; NodeDecoratorIdx = DecoratorOp.Number; } UBTDecorator* TestDecorator = ChildInfo.Decorators[DecoratorOp.Number]; const bool bIsAllowed = bHasOverride ? bCurrentOverride : TestDecorator->CanExecute(OwnerComp, TestDecorator->GetNodeMemory<uint8>(MyInstance)); UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("%s%s %s: %s"), *Indent, bHasOverride ? TEXT("skipping") : TEXT("testing"), *UBehaviorTreeTypes::DescribeNodeHelper(TestDecorator), bIsAllowed ? TEXT("allowed") : TEXT("forbidden")); bResult = UpdateOperationStack(OwnerComp, Indent, OperationStack, bIsAllowed, FailedDecoratorIdx, NodeDecoratorIdx, bShouldStoreNodeIndex); if (OperationStack.Num() == 0) { UE_VLOG(OwnerComp->GetOwner(), LogBehaviorTree, Verbose, TEXT("finished execution test: %s"), bResult ? TEXT("allowed") : TEXT("forbidden")); OwnerComp->StoreDebuggerSearchStep(ChildInfo.Decorators[FMath::Max(0, FailedDecoratorIdx)], InstanceIdx, bResult); break; } } } } return bResult; }
bool UBehaviorTreeGraphNode_SubtreeTask::UpdateInjectedNodes() { bool bUpdated = false; // check if cached data needs to be updated UBTTask_RunBehavior* MyNode = Cast<UBTTask_RunBehavior>(NodeInstance); if (MyNode == NULL) { return bUpdated; } UBehaviorTreeGraph* MyGraph = MyNode->GetSubtreeAsset() ? Cast<UBehaviorTreeGraph>(MyNode->GetSubtreeAsset()->BTGraph) : NULL; int32 MyVersion = MyGraph ? MyGraph->GraphVersion : 0; FString MyPath = MyNode->GetSubtreeAsset() ? MyNode->GetSubtreeAsset()->GetName() : FString(); if (MyPath == SubtreePath && MyVersion == SubtreeVersion) { return bUpdated; } SubtreePath = MyPath; SubtreeVersion = MyVersion; bUpdated = true; // remove existing injected nodes for (int32 Index = Decorators.Num() - 1; Index >= 0; Index--) { if (Decorators[Index] && Decorators[Index]->bInjectedNode) { Decorators.RemoveAt(Index, 1, false); } } // find root graph node of subtree UBehaviorTreeGraphNode* SubRoot = NULL; if (MyGraph && MyNode->GetSubtreeAsset()->RootDecorators.Num()) { for (int32 Index = 0; Index < MyGraph->Nodes.Num(); Index++) { UBehaviorTreeGraphNode_Root* BTNode = Cast<UBehaviorTreeGraphNode_Root>(MyGraph->Nodes[Index]); if (BTNode && BTNode->Pins.IsValidIndex(0) && BTNode->Pins[0]->LinkedTo.IsValidIndex(0)) { SubRoot = Cast<UBehaviorTreeGraphNode>(BTNode->Pins[0]->LinkedTo[0]->GetOwningNode()); break; } } } // add root level subnodes as injected nodes if (SubRoot) { UBehaviorTree* BTAsset = Cast<UBehaviorTree>(GetBehaviorTreeGraph()->GetOuter()); if(BTAsset) { for (int32 Index = 0; Index < SubRoot->Decorators.Num(); Index++) { UBehaviorTreeGraphNode* SubNode = SubRoot->Decorators[Index]; if (SubNode) { SubNode->PrepareForCopying(); UBehaviorTreeGraphNode* InjectedNode = Cast<UBehaviorTreeGraphNode>(StaticDuplicateObject(SubNode, GetOuter(), TEXT(""))); SubNode->PostCopyNode(); InjectedNode->PostCopyNode(); InjectedNode->ParentNode = this; InjectedNode->bInjectedNode = true; UBTDecorator* InjectedInstance = Cast<UBTDecorator>(InjectedNode->NodeInstance); if (InjectedInstance) { InjectedInstance->InitializeFromAsset(*BTAsset); } UBehaviorTreeGraphNode_CompositeDecorator* CompNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(InjectedNode); if (CompNode) { UEdGraph* SubGraph = CompNode->GetBoundGraph(); if (SubGraph) { SubGraph->bEditable = false; for (int32 SubIndex = 0; SubIndex < SubGraph->Nodes.Num(); SubIndex++) { UBehaviorTreeDecoratorGraphNode_Decorator* InjectedDecorator = Cast<UBehaviorTreeDecoratorGraphNode_Decorator>(SubGraph->Nodes[SubIndex]); if (InjectedDecorator) { InjectedInstance = Cast<UBTDecorator>(InjectedDecorator->NodeInstance); if (InjectedInstance) { InjectedInstance->InitializeFromAsset(*BTAsset); } } } } } Decorators.Add(InjectedNode); } } } } UEdGraph* ParentGraph = GetGraph(); if (ParentGraph && bUpdated) { ParentGraph->NotifyGraphChanged(); } return bUpdated; }
static void InitializeNodeHelper(UBTCompositeNode* ParentNode, UBTNode* NodeOb, uint8 TreeDepth, uint16& ExecutionIndex, TArray<FNodeInitializationData>& InitList, UBehaviorTree& TreeAsset, UObject* NodeOuter) { // special case: subtrees UBTTask_RunBehavior* SubtreeTask = Cast<UBTTask_RunBehavior>(NodeOb); if (SubtreeTask) { ExecutionIndex += SubtreeTask->GetInjectedNodesCount(); } InitList.Add(FNodeInitializationData(NodeOb, ParentNode, ExecutionIndex, TreeDepth, NodeOb->GetInstanceMemorySize(), NodeOb->GetSpecialMemorySize())); NodeOb->InitializeFromAsset(TreeAsset); ExecutionIndex++; UBTCompositeNode* CompositeOb = Cast<UBTCompositeNode>(NodeOb); if (CompositeOb) { for (int32 ServiceIndex = 0; ServiceIndex < CompositeOb->Services.Num(); ServiceIndex++) { if (CompositeOb->Services[ServiceIndex] == NULL) { UE_LOG(LogBehaviorTree, Warning, TEXT("%s has missing service node! (parent: %s)"), *TreeAsset.GetName(), *UBehaviorTreeTypes::DescribeNodeHelper(CompositeOb)); CompositeOb->Services.RemoveAt(ServiceIndex, 1, false); ServiceIndex--; continue; } UBTService* Service = Cast<UBTService>(StaticDuplicateObject(CompositeOb->Services[ServiceIndex], NodeOuter, TEXT("None")));; CompositeOb->Services[ServiceIndex] = Service; InitList.Add(FNodeInitializationData(Service, CompositeOb, ExecutionIndex, TreeDepth, Service->GetInstanceMemorySize(), Service->GetSpecialMemorySize())); Service->InitializeFromAsset(TreeAsset); ExecutionIndex++; } for (int32 ChildIndex = 0; ChildIndex < CompositeOb->Children.Num(); ChildIndex++) { FBTCompositeChild& ChildInfo = CompositeOb->Children[ChildIndex]; for (int32 DecoratorIndex = 0; DecoratorIndex < ChildInfo.Decorators.Num(); DecoratorIndex++) { if (ChildInfo.Decorators[DecoratorIndex] == NULL) { UE_LOG(LogBehaviorTree, Warning, TEXT("%s has missing decorator node! (parent: %s, branch: %d)"), *TreeAsset.GetName(), *UBehaviorTreeTypes::DescribeNodeHelper(CompositeOb), ChildIndex); ChildInfo.Decorators.RemoveAt(DecoratorIndex, 1, false); DecoratorIndex--; continue; } UBTDecorator* Decorator = Cast<UBTDecorator>(StaticDuplicateObject(ChildInfo.Decorators[DecoratorIndex], NodeOuter, TEXT("None"))); ChildInfo.Decorators[DecoratorIndex] = Decorator; InitList.Add(FNodeInitializationData(Decorator, CompositeOb, ExecutionIndex, TreeDepth, Decorator->GetInstanceMemorySize(), Decorator->GetSpecialMemorySize())); Decorator->InitializeFromAsset(TreeAsset); Decorator->InitializeDecorator(ChildIndex); ExecutionIndex++; } UBTNode* ChildNode = NULL; if (ChildInfo.ChildComposite) { ChildInfo.ChildComposite = Cast<UBTCompositeNode>(StaticDuplicateObject(ChildInfo.ChildComposite, NodeOuter, TEXT("None"))); ChildNode = ChildInfo.ChildComposite; } else if (ChildInfo.ChildTask) { ChildInfo.ChildTask = Cast<UBTTaskNode>(StaticDuplicateObject(ChildInfo.ChildTask, NodeOuter, TEXT("None"))); ChildNode = ChildInfo.ChildTask; } if (ChildNode) { InitializeNodeHelper(CompositeOb, ChildNode, TreeDepth + 1, ExecutionIndex, InitList, TreeAsset, NodeOuter); } } CompositeOb->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 } } }