bool FGameplayDebugger::IsGameplayDebuggerActiveForPlayerController(APlayerController* PlayerController)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if (PlayerController == NULL)
	{
		return false;
	}

	UWorld* World = PlayerController->GetWorld();
	if (World == NULL)
	{
		return false;
	}

	for (auto It = GetAllReplicators(World).CreateConstIterator(); It; ++It)
	{
		AGameplayDebuggingReplicator* Replicator = It->Get();
		if (Replicator && Replicator->GetLocalPlayerOwner() == PlayerController)
		{
			return Replicator->IsDrawEnabled();
		}
	}
#endif

	return false;
}
void FBehaviorTreeDebugger::FindLockedDebugActor(UWorld* World)
{
	APlayerController* LocalPC = GEngine->GetFirstLocalPlayerController(World);
	if (LocalPC && LocalPC->GetHUD() && LocalPC->GetPawnOrSpectator())
	{
		AGameplayDebuggingReplicator* DebuggingReplicator = NULL;
		for (TActorIterator<AGameplayDebuggingReplicator> It(World); It; ++It)
		{
			AGameplayDebuggingReplicator* A = *It;
			if (!A->IsPendingKill())
			{
				DebuggingReplicator = A;
				break;
			}
		}

		const APawn* LockedPawn = DebuggingReplicator != NULL ? Cast<APawn>(DebuggingReplicator->GetSelectedActorToDebug()) : NULL;
		UBehaviorTreeComponent* TestInstance = FindInstanceInActor((APawn*)LockedPawn);
		if (TestInstance)
		{
			TreeInstance = TestInstance;

#if USE_BEHAVIORTREE_DEBUGGER
			ActiveStepIndex = TestInstance->DebuggerSteps.Num() - 1;
#endif
		}
	}
}
void UGameplayDebuggingComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)

    if (World && World->GetNetMode() < NM_Client)
    {
        if (bEnabledTargetSelection)
        {
            AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());
            if (Replicator)
            {
                if (Replicator->GetLocalPlayerOwner())
                {
                    SelectTargetToDebug();
                }
            }
        }
        CollectDataToReplicate(true);
    }

    AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());

#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
//----------------------------------------------------------------------//
// rendering
//----------------------------------------------------------------------//
FPrimitiveSceneProxy* UGameplayDebuggingComponent::CreateSceneProxy()
{
    FDebugRenderSceneCompositeProxy* CompositeProxy = NULL;
    AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());
    if (!World || World->GetNetMode() == NM_DedicatedServer)
    {
        return NULL;
    }

    if (!Replicator || !Replicator->IsDrawEnabled())
    {
        return NULL;
    }

#if WITH_RECAST
    if (ShouldReplicateData(EAIDebugDrawDataView::NavMesh))
    {
        FNavMeshSceneProxyData NewNavmeshRenderData;
        NewNavmeshRenderData.Reset();
        NewNavmeshRenderData.bNeedsNewData = false;
        NewNavmeshRenderData.bEnableDrawing = false;
        PrepareNavMeshData(&NewNavmeshRenderData);

        NavMeshBounds = NewNavmeshRenderData.Bounds;
        CompositeProxy = CompositeProxy ? CompositeProxy : (new FDebugRenderSceneCompositeProxy(this));
        CompositeProxy->AddChild(new FRecastRenderingSceneProxy(this, &NewNavmeshRenderData, true));
    }
#endif

#if USE_EQS_DEBUGGER
    if (ShouldReplicateData(EAIDebugDrawDataView::EQS) && IsClientEQSSceneProxyEnabled())
    {
        const int32 EQSIndex = EQSLocalData.Num() > 0 ? FMath::Clamp(CurrentEQSIndex, 0, EQSLocalData.Num() - 1) : INDEX_NONE;
        if (EQSLocalData.IsValidIndex(EQSIndex))
        {
            CompositeProxy = CompositeProxy ? CompositeProxy : (new FDebugRenderSceneCompositeProxy(this));
            auto& CurrentLocalData = EQSLocalData[EQSIndex];

            FString ViewFlagName = TEXT("Game");
#if WITH_EDITOR
            UEditorEngine* EEngine = Cast<UEditorEngine>(GEngine);
            if (EEngine && EEngine->bIsSimulatingInEditor)
            {
                ViewFlagName = TEXT("DebugAI");
            }
#endif
            CompositeProxy->AddChild(new FEQSSceneProxy(this, ViewFlagName, false, CurrentLocalData.SolidSpheres, CurrentLocalData.Texts));
        }
    }
#endif // USE_EQS_DEBUGGER

    return CompositeProxy;
}
void UGameplayDebuggingComponent::CollectDataToReplicate(bool bCollectExtendedData)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
    if (!GetSelectedActor())
    {
        return;
    }

    if (ShouldReplicateData(EAIDebugDrawDataView::Basic) || ShouldReplicateData(EAIDebugDrawDataView::OverHead))
    {
        CollectBasicData();
    }

    AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());
    const bool bDrawFullData = Replicator->GetSelectedActorToDebug() == GetSelectedActor();
    if (bDrawFullData && ShouldReplicateData(EAIDebugDrawDataView::Basic))
    {
        CollectPathData();
    }

    if (bCollectExtendedData && bDrawFullData)
    {
        if (ShouldReplicateData(EAIDebugDrawDataView::BehaviorTree))
        {
            CollectBehaviorTreeData();
        }

#if WITH_EQS
        if (ShouldReplicateData(EAIDebugDrawDataView::EQS))
        {
            bool bEnabledEnvironmentQueryEd = true;
            if (GConfig)
            {
                GConfig->GetBool(TEXT("EnvironmentQueryEd"), TEXT("EnableEnvironmentQueryEd"), bEnabledEnvironmentQueryEd, GEngineIni);
            }

            if (bEnabledEnvironmentQueryEd)
            {
                CollectEQSData();
            }
        }
#endif // WITH_EQS
    }
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
AGameplayDebuggingReplicator* AGameplayDebuggingHUDComponent::GetDebuggingReplicator()
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if (CachedDebuggingReplicator.IsValid() && CachedDebuggingReplicator->GetLocalPlayerOwner() == PlayerOwner)
	{
		return CachedDebuggingReplicator.Get();
	}
	
	for (TActorIterator<AGameplayDebuggingReplicator> It(GetWorld()); It; ++It)
	{
		AGameplayDebuggingReplicator* Replicator = *It;
		if (!Replicator->IsPendingKill() && Replicator->GetLocalPlayerOwner() == PlayerOwner)
		{
			CachedDebuggingReplicator = Replicator;
			return Replicator;
		}
	}
#endif
	return NULL;
}
void FGameplayDebugger::OnLevelActorDeleted(AActor* InActor)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if (!InActor)
	{
		return;
	}

	UWorld* World = InActor->GetWorld();
	if (!World)
	{
		return;
	}

	AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(InActor);
	if (Replicator)
	{
		RemoveReplicator(World, Replicator);
	}
	else
	{
		APlayerController* PC = Cast<APlayerController>(InActor);
		if (PC)
		{
			// Take a copy because the destroy could lead to removes on the replicator array
			TArray<TWeakObjectPtr<AGameplayDebuggingReplicator>> ReplicatorsForWorld = GetAllReplicators(World);
			for (TWeakObjectPtr<AGameplayDebuggingReplicator> ReplicatorPtr : ReplicatorsForWorld)
			{
				AGameplayDebuggingReplicator* ReplicatorInWorld = ReplicatorPtr.Get();
				if (ReplicatorInWorld && ReplicatorInWorld->GetLocalPlayerOwner() == PC)
				{
					ReplicatorInWorld->Destroy();
					break;
				}
			}
		}
	}
#endif
}
bool FGameplayDebugger::CreateGameplayDebuggerForPlayerController(APlayerController* PlayerController)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if (PlayerController == NULL)
	{
		return false;
	}

	bool bIsServer = PlayerController->GetNetMode() < ENetMode::NM_Client; // (Only create on some sort of server)
	if (!bIsServer)
	{
		return false;
	}

	UWorld* World = PlayerController->GetWorld();
	if (World == NULL)
	{
		return false;
	}

	if (DoesGameplayDebuggingReplicatorExistForPlayerController(PlayerController))
	{
		// No need to create one if we already have one.
		return false;
	}

	FActorSpawnParameters SpawnInfo;
	SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	SpawnInfo.ObjectFlags = RF_Transient;
	SpawnInfo.Name = *FString::Printf(TEXT("GameplayDebuggingReplicator_%s"), *PlayerController->GetName());
	AGameplayDebuggingReplicator* DestActor = World->SpawnActor<AGameplayDebuggingReplicator>(FVector::ZeroVector, FRotator::ZeroRotator, SpawnInfo);
	if (DestActor != NULL)
	{
		DestActor->SetLocalPlayerOwner(PlayerController);
		DestActor->SetReplicates(true);
		DestActor->SetAsGlobalInWorld(false);
#if WITH_EDITOR
		UEditorEngine* EEngine = Cast<UEditorEngine>(GEngine);
		if (EEngine && EEngine->bIsSimulatingInEditor)
		{
			DestActor->CreateTool();
			DestActor->EnableTool();
		}
#endif
		AddReplicator(World, DestActor);
		return true;
	}
#endif
	
	return false;
}
void FGameplayDebugger::WorldAdded(UWorld* InWorld)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	bool bIsServer = InWorld && InWorld->GetNetMode() < ENetMode::NM_Client; // (Only server code)
	if (!bIsServer)
	{
		return;
	}

	if (InWorld == NULL || InWorld->IsPendingKill() || InWorld->IsGameWorld() == false)
	{
		return;
	}

	for (auto It = GetAllReplicators(InWorld).CreateConstIterator(); It; ++It)
	{
		AGameplayDebuggingReplicator* Replicator = It->Get();
		if (Replicator && Replicator->IsGlobalInWorld())
		{
			// Ok, we have global replicator on level
			return;
		}
	}

	// create global replicator on level
	FActorSpawnParameters SpawnInfo;
	SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
	SpawnInfo.ObjectFlags = RF_Transient;
	SpawnInfo.Name = *FString::Printf(TEXT("GameplayDebuggingReplicator_Global"));
	AGameplayDebuggingReplicator* DestActor = InWorld->SpawnActor<AGameplayDebuggingReplicator>(FVector::ZeroVector, FRotator::ZeroRotator, SpawnInfo);
	if (DestActor != NULL)
	{
		DestActor->SetLocalPlayerOwner(NULL);
		DestActor->SetReplicates(false);
		DestActor->SetActorTickEnabled(true);
		DestActor->SetAsGlobalInWorld(true);
		AddReplicator(InWorld, DestActor);
	}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
bool FGameplayDebugger::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	bool bHandled = false;

	if (FParse::Command(&Cmd, TEXT("RunEQS")) && InWorld)
	{
		APlayerController* MyPC = InWorld->GetGameInstance() ? InWorld->GetGameInstance()->GetFirstLocalPlayerController() : nullptr;
		UAISystem* AISys = UAISystem::GetCurrent(*InWorld);

		UEnvQueryManager* EQS = AISys ? AISys->GetEnvironmentQueryManager() : NULL;
		if (MyPC && EQS)
		{
			AGameplayDebuggingReplicator* DebuggingReplicator = NULL;
			for (TActorIterator<AGameplayDebuggingReplicator> It(InWorld); It; ++It)
			{
				AGameplayDebuggingReplicator* A = *It;
				if (!A->IsPendingKill())
				{
					DebuggingReplicator = A;
					if (!DebuggingReplicator->IsGlobalInWorld() && DebuggingReplicator->GetLocalPlayerOwner() == MyPC)
					{
						break;
					}
				}
			}

			UObject* Target = DebuggingReplicator != NULL ? DebuggingReplicator->GetSelectedActorToDebug() : NULL;
			FString QueryName = FParse::Token(Cmd, 0);
			if (Target)
			{
				AISys->RunEQS(QueryName, Target);
			}
			else
			{
				MyPC->ClientMessage(TEXT("No debugging target to run EQS"));
			}
		}

		return true;
	}


	if (FParse::Command(&Cmd, TEXT("EnableGDT")) == false)
	{
		return false;
	}

	FString UniquePlayerId = FParse::Token(Cmd, 0);
	APlayerController* LocalPC = NULL;
	UWorld* MyWorld = InWorld;

	if (MyWorld == nullptr)
	{
		if (UniquePlayerId.Len() > 0)
		{
			// let's find correct world based on Player Id
			const TIndirectArray<FWorldContext> WorldContexts = GEngine->GetWorldContexts();
			for (auto& Context : WorldContexts)
			{
				if (Context.WorldType != EWorldType::Game && Context.WorldType != EWorldType::PIE)
				{
					continue;
				}

				UWorld *CurrentWorld = Context.World();
				for (FConstPlayerControllerIterator Iterator = CurrentWorld->GetPlayerControllerIterator(); Iterator; ++Iterator)
				{
					APlayerController* PC = *Iterator;
					if (PC && PC->PlayerState->UniqueId.ToString() == UniquePlayerId)
					{
						LocalPC = PC;
						MyWorld = PC->GetWorld();
						break;
					}
				}

				if (LocalPC && MyWorld)
				{
					break;
				}
			}
		}
	}

	if (MyWorld == nullptr)
	{
		return false;
	}

	if (LocalPC == nullptr)
	{
		if (UniquePlayerId.Len() > 0)
		{
			for (FConstPlayerControllerIterator Iterator = MyWorld->GetPlayerControllerIterator(); Iterator; ++Iterator)
			{
				APlayerController* PlayerController = *Iterator;
				UE_LOG(LogGameplayDebugger, Log, TEXT("- Client: %s"), *PlayerController->PlayerState->UniqueId.ToString());
				if (PlayerController && PlayerController->PlayerState->UniqueId.ToString() == UniquePlayerId)
				{
					LocalPC = PlayerController;
					break;
				}
			}
		}

		if (!LocalPC && MyWorld->GetNetMode() != NM_DedicatedServer)
		{
			LocalPC = MyWorld->GetGameInstance() ? MyWorld->GetGameInstance()->GetFirstLocalPlayerController() : nullptr;
		}
	}

	if (LocalPC == nullptr)
	{
		return false;
	}

	if (MyWorld->GetNetMode() == NM_Client)
	{
		AGameplayDebuggingReplicator* Replicator = NULL;
		for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It)
		{
			Replicator = *It;
			if (Replicator && !Replicator->IsPendingKill())
			{
				APlayerController* PCOwner = Replicator->GetLocalPlayerOwner();
				if (LocalPC == PCOwner)
				{
					break;
				}
			}
			Replicator = NULL;
		}

		if (!Replicator)
		{
			LocalPC->ClientMessage(TEXT("Enabling GameplayDebugger on server, please wait for replicated data..."));
			if (LocalPC->PlayerState)
			{
				const FString ServerCheatString = FString::Printf(TEXT("cheat EnableGDT %s"), *LocalPC->PlayerState->UniqueId.ToString());
				UE_LOG(LogGameplayDebugger, Warning, TEXT("Sending to Server: %s"), *ServerCheatString);
				LocalPC->ConsoleCommand(*ServerCheatString);
				bHandled = true;
			}
		}
		else
		{
			if (Replicator->IsToolCreated() == false)
			{
				Replicator->CreateTool();
			}
			Replicator->EnableTool();
			bHandled = true;
		}
	}
	else
	{
		UE_LOG(LogGameplayDebugger, Warning, TEXT("Got from client: EnableGDT %s"), *UniquePlayerId);
		{
			AGameplayDebuggingReplicator* Replicator = NULL;
			for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It)
			{
				Replicator = *It;
				if (Replicator && !Replicator->IsPendingKill())
				{
					APlayerController* PCOwner = Replicator->GetLocalPlayerOwner();
					if (LocalPC == PCOwner)
					{
						break;
					}
				}
				Replicator = NULL;
			}

			if (!Replicator)
			{
				CreateGameplayDebuggerForPlayerController(LocalPC);
				for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It)
				{
					Replicator = *It;
					if (Replicator && !Replicator->IsPendingKill())
					{
						APlayerController* PCOwner = Replicator->GetLocalPlayerOwner();
						if (LocalPC == PCOwner)
						{
							break;
						}
					}
					Replicator = NULL;
				}
			}

			if (MyWorld->GetNetMode() != NM_DedicatedServer)
			{
				if (Replicator && !Replicator->IsToolCreated())
				{
					Replicator->CreateTool();
					Replicator->EnableTool();
					bHandled = true;
				}
			}
			else
			{
				if (Replicator)
				{
					Replicator->ClientAutoActivate();
					bHandled = true;
				}
			}
		}
	}

	return bHandled;
#else
	return false;
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void UGameplayDebuggingComponent::SelectTargetToDebug()
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
    AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner());
    APlayerController* MyPC = Replicator->GetLocalPlayerOwner();

    if (MyPC )
    {
        APawn* BestTarget = NULL;
        if (MyPC->GetViewTarget() != NULL && MyPC->GetViewTarget() != MyPC->GetPawn())
        {
            BestTarget = Cast<APawn>(MyPC->GetViewTarget());
            if (BestTarget && ((BestTarget->PlayerState != NULL && BestTarget->PlayerState->bIsABot == false) || BestTarget->GetActorEnableCollision() == false))
            {
                BestTarget = NULL;
            }
        }

        float bestAim = 0.f;
        FVector CamLocation;
        FRotator CamRotation;
        check(MyPC->PlayerCameraManager != NULL);
        MyPC->PlayerCameraManager->GetCameraViewPoint(CamLocation, CamRotation);
        FVector FireDir = CamRotation.Vector();
        UWorld* World = MyPC->GetWorld();
        check( World );

        APawn* PossibleTarget = NULL;
        for (FConstPawnIterator Iterator = World->GetPawnIterator(); Iterator; ++Iterator )
        {
            APawn* NewTarget = *Iterator;
            if (NewTarget == NULL || NewTarget == MyPC->GetPawn()
                    || (NewTarget->PlayerState != NULL && NewTarget->PlayerState->bIsABot == false)
                    || NewTarget->GetActorEnableCollision() == false)
            {
                continue;
            }

            if (BestTarget == NULL && (NewTarget != MyPC->GetPawn()))
            {
                // look for best controlled pawn target
                const FVector AimDir = NewTarget->GetActorLocation() - CamLocation;
                float FireDist = AimDir.SizeSquared();
                // only find targets which are < 25000 units away
                if (FireDist < 625000000.f)
                {
                    FireDist = FMath::Sqrt(FireDist);
                    float newAim = FireDir | AimDir;
                    newAim = newAim/FireDist;
                    if (newAim > bestAim)
                    {
                        PossibleTarget = NewTarget;
                        bestAim = newAim;
                    }
                }
            }
        }

        BestTarget = BestTarget == NULL ? PossibleTarget : BestTarget;
        if (BestTarget != NULL && BestTarget != GetSelectedActor())
        {
            if (AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner()))
            {
                Replicator->SetActorToDebug(Cast<AActor>(BestTarget));
            }

            //always update component for best target
            SetActorToDebug(Cast<AActor>(BestTarget));
            ServerReplicateData(EDebugComponentMessage::ActivateReplication, EAIDebugDrawDataView::Empty);
        }
    }
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}