void UBehaviorTreeGraph::CreateBTFromGraph(UBehaviorTreeGraphNode* RootEdNode)
{
	UBehaviorTree* BTAsset = Cast<UBehaviorTree>(GetOuter());
	BTAsset->RootNode = NULL; //discard old tree

	// let's create new tree from graph
	uint16 ExecutionIndex = 0;
	uint8 TreeDepth = 0;

	BTAsset->RootNode = Cast<UBTCompositeNode>(RootEdNode->NodeInstance);
	if (BTAsset->RootNode)
	{
		BTAsset->RootNode->InitializeNode(NULL, ExecutionIndex, 0, TreeDepth);
		ExecutionIndex++;
	}

	// collect root level decorators
	uint16 DummyIndex = MAX_uint16;
	BTAsset->RootDecorators.Empty();
	BTAsset->RootDecoratorOps.Empty();
	BTGraphHelpers::CollectDecorators(BTAsset, RootEdNode, BTAsset->RootDecorators, BTAsset->RootDecoratorOps, false, NULL, &DummyIndex, 0, 0);

	// connect tree nodes
	BTGraphHelpers::CreateChildren(BTAsset, BTAsset->RootNode, RootEdNode, &ExecutionIndex, TreeDepth + 1);

	// mark root level nodes
	BTGraphHelpers::ClearRootLevelFlags(this);

	RootEdNode->bRootLevel = true;
	for (int32 Index = 0; Index < RootEdNode->Decorators.Num(); Index++)
	{
		UBehaviorTreeGraphNode* Node = RootEdNode->Decorators[Index];
		if (Node)
		{
			Node->bRootLevel = true;
		}
	}

	if (BTAsset->RootNode)
	{
		BTAsset->RootNode->InitializeComposite(ExecutionIndex - 1);
	}

	// Now remove any orphaned nodes left behind after regeneration
	RemoveOrphanedNodes();
}
void UEnvironmentQueryGraph::UpdateAsset()
{
	if (bLockUpdates)
	{
		return;
	}

	//let's find root node
	UEnvironmentQueryGraphNode_Root* RootNode = NULL;
	for (int32 Index = 0; Index < Nodes.Num(); ++Index)
	{
		RootNode = Cast<UEnvironmentQueryGraphNode_Root>(Nodes[Index]);
		if (RootNode != NULL)
		{
			break;
		}
	}

	UEnvQuery* Query = Cast<UEnvQuery>(GetOuter());
	Query->Options.Reset();
	if (RootNode && RootNode->Pins.Num() > 0 && RootNode->Pins[0]->LinkedTo.Num() > 0)
	{
		UEdGraphPin* MyPin = RootNode->Pins[0];

		// sort connections so that they're organized the same as user can see in the editor
		MyPin->LinkedTo.Sort(FCompareNodeXLocation());

		for (int32 Index=0; Index < MyPin->LinkedTo.Num(); ++Index)
		{
			UEnvironmentQueryGraphNode_Option* OptionNode = Cast<UEnvironmentQueryGraphNode_Option>(MyPin->LinkedTo[Index]->GetOwningNode());
			if (OptionNode)
			{
				UEnvQueryOption* OptionInstance = Cast<UEnvQueryOption>(OptionNode->NodeInstance);
				if (OptionInstance != NULL)
				{
					OptionInstance->Tests.Reset();

					for (int32 iTest = 0; iTest < OptionNode->Tests.Num(); iTest++)
					{
						UEnvironmentQueryGraphNode_Test* TestNode = OptionNode->Tests[iTest];
						if (TestNode && TestNode->bTestEnabled)
						{
							UEnvQueryTest* TestInstance = Cast<UEnvQueryTest>(TestNode->NodeInstance);
							if (TestInstance)
							{
								OptionInstance->Tests.Add(TestInstance);
							}
						}
					}

					Query->Options.Add(OptionInstance);
				}
			}
		}
	}

	RemoveOrphanedNodes();
#if USE_EQS_DEBUGGER
	UEnvQueryManager::NotifyAssetUpdate(Query);
#endif
}
void UEnvironmentQueryGraph::UpdateAsset(int32 UpdateFlags)
{
	if (IsLocked())
	{
		return;
	}

	// let's find root node
	UEnvironmentQueryGraphNode_Root* RootNode = NULL;
	for (int32 Idx = 0; Idx < Nodes.Num(); Idx++)
	{
		RootNode = Cast<UEnvironmentQueryGraphNode_Root>(Nodes[Idx]);
		if (RootNode != NULL)
		{
			break;
		}
	}

	UEnvQuery* Query = Cast<UEnvQuery>(GetOuter());
	Query->GetOptionsMutable().Reset();
	if (RootNode && RootNode->Pins.Num() > 0 && RootNode->Pins[0]->LinkedTo.Num() > 0)
	{
		UEdGraphPin* MyPin = RootNode->Pins[0];

		// sort connections so that they're organized the same as user can see in the editor
		MyPin->LinkedTo.Sort(FCompareNodeXLocation());

		for (int32 Idx = 0; Idx < MyPin->LinkedTo.Num(); Idx++)
		{
			UEnvironmentQueryGraphNode_Option* OptionNode = Cast<UEnvironmentQueryGraphNode_Option>(MyPin->LinkedTo[Idx]->GetOwningNode());
			if (OptionNode)
			{
				OptionNode->UpdateNodeData();

				UEnvQueryOption* OptionInstance = Cast<UEnvQueryOption>(OptionNode->NodeInstance);
				if (OptionInstance && OptionInstance->Generator)
				{
					OptionInstance->Tests.Reset();

					for (int32 TestIdx = 0; TestIdx < OptionNode->SubNodes.Num(); TestIdx++)
					{
						UAIGraphNode* SubNode = OptionNode->SubNodes[TestIdx];
						if (SubNode == nullptr)
						{
							continue;
						}

						SubNode->ParentNode = OptionNode;

						UEnvironmentQueryGraphNode_Test* TestNode = Cast<UEnvironmentQueryGraphNode_Test>(SubNode);
						if (TestNode && TestNode->bTestEnabled)
						{
							UEnvQueryTest* TestInstance = Cast<UEnvQueryTest>(TestNode->NodeInstance);
							if (TestInstance)
							{
								OptionInstance->Tests.Add(TestInstance);
							}
						}
					}

					Query->GetOptionsMutable().Add(OptionInstance);
				}
				
				// FORT-16508 tracking BEGIN: log invalid option
				if (OptionInstance && OptionInstance->Generator == nullptr)
				{
					FString DebugMessage = FString::Printf(TEXT("[%s] UpdateAsset found option instance [pin:%d] without a generator! tests:%d"),
						FPlatformTime::StrTimestamp(), Idx, OptionNode->SubNodes.Num());

					RootNode->LogDebugMessage(DebugMessage);
				}
				else if (OptionInstance == nullptr)
				{
					FString DebugMessage = FString::Printf(TEXT("[%s] UpdateAsset found option node [pin:%d] without an instance! tests:%d"),
						FPlatformTime::StrTimestamp(), Idx, OptionNode->SubNodes.Num());

					RootNode->LogDebugMessage(DebugMessage);
				}
				// FORT-16508 tracking END
			}
		}
	}

	RemoveOrphanedNodes();

	// FORT-16508 tracking BEGIN: find corrupted options
	if (RootNode)
	{
		for (int32 Idx = 0; Idx < Nodes.Num(); Idx++)
		{
			UEnvironmentQueryGraphNode_Option* OptionNode = Cast<UEnvironmentQueryGraphNode_Option>(Nodes[Idx]);
			if (OptionNode)
			{
				UEnvQueryOption* OptionInstance = Cast<UEnvQueryOption>(OptionNode->NodeInstance);
				if (OptionNode->NodeInstance == nullptr || OptionInstance == nullptr || OptionInstance->HasAnyFlags(RF_Transient))
				{
					FString DebugMessage = FString::Printf(TEXT("[%s] found corrupted node after RemoveOrphanedNodes! type:instance option:%s instance:%d transient:%d tests:%d"),
						FPlatformTime::StrTimestamp(),
						*GetNameSafe(OptionNode),
						OptionNode->NodeInstance ? (OptionInstance ? 1 : -1) : 0,
						OptionNode->NodeInstance ? (OptionNode->HasAnyFlags(RF_Transient) ? 1 : 0) : -1,
						OptionNode->SubNodes.Num());					

					RootNode->LogDebugError(DebugMessage);
				}

				if (OptionInstance && (OptionInstance->Generator == nullptr || OptionInstance->Generator->HasAnyFlags(RF_Transient)))
				{
					FString DebugMessage = FString::Printf(TEXT("[%s] found corrupted node after RemoveOrphanedNodes! type:generator option:%s instance:%d transient:%d tests:%d"),
						FPlatformTime::StrTimestamp(),
						*GetNameSafe(OptionNode),
						OptionNode->NodeInstance ? 1 : 0,
						OptionNode->NodeInstance ? (OptionNode->HasAnyFlags(RF_Transient) ? 1 : 0) : -1,
						OptionNode->SubNodes.Num());

					RootNode->LogDebugError(DebugMessage);
				}
			}
		}
	}
	// FORT-16508 tracking END

#if USE_EQS_DEBUGGER
	UEnvQueryManager::NotifyAssetUpdate(Query);
#endif
}
void UEnvironmentQueryGraph::UpdateAsset(int32 UpdateFlags)
{
	if (IsLocked())
	{
		return;
	}

	// let's find root node
	UEnvironmentQueryGraphNode_Root* RootNode = NULL;
	for (int32 Idx = 0; Idx < Nodes.Num(); Idx++)
	{
		RootNode = Cast<UEnvironmentQueryGraphNode_Root>(Nodes[Idx]);
		if (RootNode != NULL)
		{
			break;
		}
	}

	UEnvQuery* Query = Cast<UEnvQuery>(GetOuter());
	Query->Options.Reset();
	if (RootNode && RootNode->Pins.Num() > 0 && RootNode->Pins[0]->LinkedTo.Num() > 0)
	{
		UEdGraphPin* MyPin = RootNode->Pins[0];

		// sort connections so that they're organized the same as user can see in the editor
		MyPin->LinkedTo.Sort(FCompareNodeXLocation());

		for (int32 Idx = 0; Idx < MyPin->LinkedTo.Num(); Idx++)
		{
			UEnvironmentQueryGraphNode_Option* OptionNode = Cast<UEnvironmentQueryGraphNode_Option>(MyPin->LinkedTo[Idx]->GetOwningNode());
			if (OptionNode)
			{
				OptionNode->UpdateNodeData();

				UEnvQueryOption* OptionInstance = Cast<UEnvQueryOption>(OptionNode->NodeInstance);
				if (OptionInstance && OptionInstance->Generator)
				{
					OptionInstance->Tests.Reset();

					for (int32 TestIdx = 0; TestIdx < OptionNode->SubNodes.Num(); TestIdx++)
					{
						UAIGraphNode* SubNode = OptionNode->SubNodes[TestIdx];
						if (SubNode == nullptr)
						{
							continue;
						}

						SubNode->ParentNode = OptionNode;

						UEnvironmentQueryGraphNode_Test* TestNode = Cast<UEnvironmentQueryGraphNode_Test>(SubNode);
						if (TestNode && TestNode->bTestEnabled)
						{
							UEnvQueryTest* TestInstance = Cast<UEnvQueryTest>(TestNode->NodeInstance);
							if (TestInstance)
							{
								OptionInstance->Tests.Add(TestInstance);
							}
						}
					}

					Query->Options.Add(OptionInstance);
				}
			}
		}
	}

	RemoveOrphanedNodes();
#if USE_EQS_DEBUGGER
	UEnvQueryManager::NotifyAssetUpdate(Query);
#endif
}