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);
			}
		}
	}
}
コード例 #4
0
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;
			}
		}
	}
}
コード例 #5
0
//----------------------------------------------------------------------//
// 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);
		}
	}
}
コード例 #6
0
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);
			}
		}
	}
}
コード例 #7
0
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;
}
コード例 #8
0
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;
}
コード例 #9
0
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);
	}
}
コード例 #10
0
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
		}
	}
}