int32 UBTCompositeNode::GetNextChild(struct FBehaviorTreeSearchData& SearchData, int32 LastChildIdx, EBTNodeResult::Type LastResult) const { FBTCompositeMemory* NodeMemory = GetNodeMemory<FBTCompositeMemory>(SearchData); int32 NextChildIndex = BTSpecialChild::ReturnToParent; uint16 ActiveInstanceIdx = SearchData.OwnerComp->GetActiveInstanceIdx(); // newly activated node, search range not reached yet: select search branch for decorator test if (LastChildIdx == BTSpecialChild::NotInitialized && SearchData.SearchStart.IsSet() && FBTNodeIndex(ActiveInstanceIdx, GetExecutionIndex()).TakesPriorityOver(SearchData.SearchStart)) { NextChildIndex = GetMatchingChildIndex(ActiveInstanceIdx, SearchData.SearchStart); } else if (NodeMemory->OverrideChild != BTSpecialChild::NotInitialized && !SearchData.OwnerComp->IsRestartPending()) { NextChildIndex = NodeMemory->OverrideChild; NodeMemory->OverrideChild = BTSpecialChild::NotInitialized; } // or use composite's logic else if (OnNextChild.IsBound()) { NextChildIndex = OnNextChild.Execute(SearchData, LastChildIdx, LastResult); } return NextChildIndex; }
int32 UBTCompositeNode::GetMatchingChildIndex(int32 ActiveInstanceIdx, struct FBTNodeIndex& NodeIdx) const { const int32 OutsideRange = BTSpecialChild::ReturnToParent; const int32 UnlimitedRange = Children.Num() - 1; // search ends at the same instance level: use execution index to determine branch containing node index if (ActiveInstanceIdx == NodeIdx.InstanceIndex) { // is composite even in range of search? if (GetExecutionIndex() > NodeIdx.ExecutionIndex) { return OutsideRange; } // find child outside range for (int32 i = 0; i < Children.Num(); i++) { const UBTNode* ChildNode = GetChildNode(i); if (ChildNode->GetExecutionIndex() > NodeIdx.ExecutionIndex) { return i ? (i - 1) : 0; } } return UnlimitedRange; } // search ends at higher level: allow every node // search ends at lower level: outside allowed range return (ActiveInstanceIdx > NodeIdx.InstanceIndex) ? UnlimitedRange : OutsideRange; }
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 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 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 } } }