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 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)
}
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::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)
}