void FScriptExecutionNode::GetAllPureNodes(TMap<int32, TSharedPtr<class FScriptExecutionNode>>& PureNodesOut)
{
	GetAllPureNodes_Internal(PureNodesOut, PureNodeScriptCodeRange);

	// Sort pure nodes by script offset (execution order).
	PureNodesOut.KeySort(TLess<int32>());
}
void AGameplayDebuggerReplicator::DrawDebugData(class UCanvas* Canvas, class APlayerController* PC, bool bHideMenu)
{
#if ENABLED_GAMEPLAY_DEBUGGER
	if (!LocalPlayerOwner && IsActorTickEnabled())
	{
		return;
	}

	const bool bAllowToDraw = Canvas && Canvas->SceneView && (Canvas->SceneView->ViewActor == LocalPlayerOwner->AcknowledgedPawn || Canvas->SceneView->ViewActor == LocalPlayerOwner->GetPawnOrSpectator());
	if (!bAllowToDraw)
	{
		// check for spectator debug camera during debug camera
		if (DebugCameraController.IsValid() == false || Canvas->SceneView->ViewActor->GetInstigatorController() != DebugCameraController.Get())
		{
			return;
		}
	}

	const float DebugInfoStartX = UGameplayDebuggerModuleSettings::StaticClass()->GetDefaultObject<UGameplayDebuggerModuleSettings>()->DebugInfoStart.X;
	const float DebugInfoStartY = UGameplayDebuggerModuleSettings::StaticClass()->GetDefaultObject<UGameplayDebuggerModuleSettings>()->DebugInfoStart.Y;
	const FVector SelectedActorLoc = LastSelectedActorToDebug ? LastSelectedActorToDebug->GetActorLocation() + FVector(0, 0, LastSelectedActorToDebug->GetSimpleCollisionHalfHeight()) : DebugTools::InvalidLocation;
	
	UGameplayDebuggerHelper::FPrintContext DefaultContext(GEngine->GetSmallFont(), Canvas, DebugInfoStartX, DebugInfoStartY);
	DefaultContext.FontRenderInfo.bEnableShadow = true;
	const bool bDrawFullData = SelectedActorLoc != DebugTools::InvalidLocation;
	const FVector ScreenLoc = SelectedActorLoc != DebugTools::InvalidLocation ? UGameplayDebuggerHelper::ProjectLocation(DefaultContext, SelectedActorLoc) : FVector::ZeroVector;
	UGameplayDebuggerHelper::FPrintContext OverHeadContext(GEngine->GetSmallFont(), Canvas, ScreenLoc.X, ScreenLoc.Y);

	UGameplayDebuggerHelper::SetOverHeadContext(OverHeadContext);
	UGameplayDebuggerHelper::SetDefaultContext(DefaultContext);

	if (DefaultContext.Canvas != nullptr)
	{
		float XL, YL;
		const FString ToolName = FString::Printf(TEXT("Gameplay Debugger [Timestamp: %05.03f]"), GetWorld()->TimeSeconds);
		UGameplayDebuggerHelper::CalulateStringSize(DefaultContext, nullptr, ToolName, XL, YL);
		UGameplayDebuggerHelper::PrintString(DefaultContext, FColorList::White, ToolName, DefaultContext.Canvas->ClipX / 2.0f - XL / 2.0f, 0);
	}

	if (!bHideMenu)
	{
		DrawMenu(DefaultContext, OverHeadContext);
	}

	TMap<FString, TArray<UGameplayDebuggerBaseObject*> > CategoryToClasses;
	for (UGameplayDebuggerBaseObject* Obj : ReplicatedObjects)
	{
		if (Obj)
		{
			FString Category = Obj->GetCategoryName();
			CategoryToClasses.FindOrAdd(Category).Add(Obj);
		}
	}
	CategoryToClasses.KeySort(TLess<FString>());

	for (auto It(CategoryToClasses.CreateIterator()); It; ++It)
	{
		const FGameplayDebuggerCategorySettings* Element = Categories.FindByPredicate([&](const FGameplayDebuggerCategorySettings& C){ return It.Key() == C.CategoryName; });
		if (Element == nullptr || Element->bPIE == false)
		{
			continue;
		}

		UGameplayDebuggerHelper::PrintString(UGameplayDebuggerHelper::GetDefaultContext(), FString::Printf(TEXT("\n{R=0,G=255,B=0,A=255}%s\n"), *It.Key()));
		TArray<UGameplayDebuggerBaseObject*>& CurrentObjects = It.Value();
		for (UGameplayDebuggerBaseObject* Obj : CurrentObjects)
		{
			Obj->DrawCollectedData(LocalPlayerOwner, LastSelectedActorToDebug);
		}
	}

	const IConsoleVariable* cvarHighlightSelectedActor = IConsoleManager::Get().FindConsoleVariable(TEXT("ai.gd.HighlightSelectedActor"));
	const bool bHighlightSelectedActor = !cvarHighlightSelectedActor || cvarHighlightSelectedActor->GetInt();
	if (LastSelectedActorToDebug && bHighlightSelectedActor)
	{
		FBox ComponentsBoundingBox = LastSelectedActorToDebug->GetComponentsBoundingBox(false);
		DrawDebugBox(GetWorld(), ComponentsBoundingBox.GetCenter(), ComponentsBoundingBox.GetExtent(), FColor::Red, false);
		DrawDebugSolidBox(GetWorld(), ComponentsBoundingBox.GetCenter(), ComponentsBoundingBox.GetExtent(), FColor::Red.WithAlpha(25));
	}
#endif
}
/**
 * Enacts the transaction.
 */
void FTransaction::Apply()
{
	checkSlow(Inc==1||Inc==-1);

	// Figure out direction.
	const int32 Start = Inc==1 ? 0             : Records.Num()-1;
	const int32 End   = Inc==1 ? Records.Num() :              -1;

	// Init objects.
	TMap<UObject*, TSharedPtr<ITransactionObjectAnnotation>> ChangedObjects;
	for( int32 i=Start; i!=End; i+=Inc )
	{
		FObjectRecord& Record = Records[i];
		Record.bRestored = false;

		UObject* Object = Record.Object.Get();
		if (!ChangedObjects.Contains(Object))
		{
			Object->CheckDefaultSubobjects();
			Object->PreEditUndo();
		}

		ChangedObjects.Add(Object, Record.ObjectAnnotation);
	}
	for( int32 i=Start; i!=End; i+=Inc )
	{
		Records[i].Restore( this );
	}

	// An Actor's components must always get its PostEditUndo before the owning Actor so do a quick sort
	ChangedObjects.KeySort([](UObject& A, UObject& B)
	{
		UActorComponent* BAsComponent = Cast<UActorComponent>(&B);
		return (BAsComponent ? (BAsComponent->GetOwner() != &A) : true);
	});

	NumModelsModified = 0;		// Count the number of UModels that were changed.
	for (auto ChangedObjectIt : ChangedObjects)
	{
		UObject* ChangedObject = ChangedObjectIt.Key;
		UModel* Model = Cast<UModel>(ChangedObject);
		if (Model && Model->Nodes.Num())
		{
			FBSPOps::bspBuildBounds(Model);
			++NumModelsModified;
		}
		TSharedPtr<ITransactionObjectAnnotation> ChangedObjectTransactionAnnotation = ChangedObjectIt.Value;
		if (ChangedObjectTransactionAnnotation.IsValid())
		{
			ChangedObject->PostEditUndo(ChangedObjectTransactionAnnotation);
		}
		else
		{
			ChangedObject->PostEditUndo();
		}
	}

	// Flip it.
	if (bFlip)
	{
		Inc *= -1;
	}
	for (auto ChangedObjectIt : ChangedObjects)
	{
		UObject* ChangedObject = ChangedObjectIt.Key;
		ChangedObject->CheckDefaultSubobjects();
	}
}