//Spawn Selection code sample:

AProjectPlayerStart* AProjectGameMode::GetBestGameplayPlayerStartPerTeam_Implementation(const TArray<APlayerStart*>& Starts)
{
    // Check if the input array is empty
    if (Starts.Num() == 0)
    {
        return nullptr;
    }

    TArray<AProjectPlayerStart*> AllowedStarts;

    // Cast to AProjectPlayerStart and add valid entries to AllowedStarts
    for (APlayerStart* Start : Starts)
    {
        if (AProjectPlayerStart* PlayerStart = Cast<AProjectPlayerStart>(Start))
        {
            AllowedStarts.Add(PlayerStart);
        }
    }

    UProjectGameInstance* GameInstance = Cast<UProjectGameInstance>(GetWorld()->GetGameInstance());
    AProjectPlayerStart* BestPlayerStart = nullptr;
    TArray<AProjectPlayerStart*> EmptySpawnZones;

    // Find all empty spawn zones
    for (AProjectPlayerStart* PlayerStart : AllowedStarts)
    {
        if (!PlayerStart->GetWhetherStartHasBeenSpawnedAt() &&
            PlayerStart->GetAllPlayersInSpawnZone().Num() == 0)
        {
            EmptySpawnZones.AddUnique(PlayerStart);
        }
    }

    UE_LOG(LogTemp, Log, TEXT("Number of empty spawn zones found: %i"), EmptySpawnZones.Num());

    // If empty spawn zones are found, select the earliest used one 
    if (EmptySpawnZones.Num() > 0)
    {
        // Randomize the first index
        int32 RandomIndex = FMath::RandRange(0, EmptySpawnZones.Num() - 1);
        EmptySpawnZones.Swap(0, RandomIndex);

        float EarliestLastSpawnTime = MAX_FLT;
        for (AProjectPlayerStart* PlayerStart : EmptySpawnZones)
        {
            float LastSpawnTime = PlayerStart->GetGameTimeWhenLastSpawned();
            if (LastSpawnTime < EarliestLastSpawnTime)
            {
                EarliestLastSpawnTime = LastSpawnTime;
                BestPlayerStart = PlayerStart;
            }
        }
    }
    else
    {
        // Find the spawn point furthest away from players
        float FurthestDistanceToPlayer = 0.0f;
        for (AProjectPlayerStart* PlayerStart : AllowedStarts)
        {
            float DistanceToClosestPlayer = PlayerStart->GetDistanceToClosestPlayerInsideSpawnZone();
            if (DistanceToClosestPlayer > FurthestDistanceToPlayer)
            {
                FurthestDistanceToPlayer = DistanceToClosestPlayer;
                BestPlayerStart = PlayerStart;
            }
        }
    }

    // If no suitable start found, pick a random start
    if (!BestPlayerStart)
    {
        BestPlayerStart = AllowedStarts[FMath::RandRange(0, AllowedStarts.Num() - 1)];
    }

    // Mark the selected spawn point as used
    if (BestPlayerStart)
    {
        BestPlayerStart->SetWhetherStartHasBeenSpawnedAt(true);
        UE_LOG(LogTemp, Log, TEXT("Best Player Start selected: %s, LastSpawnGameTime: %f, NumPlayersInZone: %i, DistanceToPlayer: %f"),
            *BestPlayerStart->GetName(),
            BestPlayerStart->GetGameTimeWhenLastSpawned(),
            BestPlayerStart->GetAllPlayersInSpawnZone().Num(),
            BestPlayerStart->GetDistanceToClosestPlayerInsideSpawnZone());
    }

    return BestPlayerStart;
}