Загрузка данных


-- 1. Ждем полной загрузки игры и персонажа (обязательно для autoexec)
if not game:IsLoaded() then
    game.Loaded:Wait()
end

local Players = game:GetService("Players")
local HttpService = game:GetService("HttpService")
local TeleportService = game:GetService("TeleportService")
local GuiService = game:GetService("GuiService")

local player = Players.LocalPlayer
if not player then
    player = Players.PlayerAdded:Wait()
end

-- Небольшая пауза, чтобы клиент Roblox успел прогрузить список всех игроков на сервере
task.wait(3)

-- НАСТРОЙКИ
local MAX_PLAYERS = 5 -- Максимальное количество игроков (если станет 6 и больше — реконнект)

local placeId = game.PlaceId
local currentJobId = game.JobId

local env = (getgenv and getgenv()) or _G
env.FailedServers = env.FailedServers or {}
env.CandidateServers = {}
env.IsBusy = false
env.HandlingError = false

-- Очищаем старые подписки при перезапуске скрипта
if env.TeleportFailConn then env.TeleportFailConn:Disconnect() end
if env.ErrorMsgConn then env.ErrorMsgConn:Disconnect() end
if env.PlayerAddedConn then env.PlayerAddedConn:Disconnect() end

local findAliveServers

local function tryNextServer()
    if env.IsBusy then
        return
    end
    env.IsBusy = true

    while #env.CandidateServers > 0 do
        local targetServerId = table.remove(env.CandidateServers)

        if not env.FailedServers[targetServerId] and targetServerId ~= currentJobId then
            env.FailedServers[targetServerId] = true
            print("[AutoHop] Переход на сервер: " .. targetServerId .. " (В запасе: " .. #env.CandidateServers .. ")")

            pcall(function()
                GuiService:ClearError()
            end)

            local success, err = pcall(function()
                TeleportService:TeleportToPlaceInstance(placeId, targetServerId, player)
            end)

            if not success then
                warn("[AutoHop] Ошибка вызова телепорта: " .. tostring(err))
                task.wait(1.5)
            else
                task.delay(8, function()
                    if env.IsBusy and not env.HandlingError then
                        env.IsBusy = false
                    end
                end)
                return
            end
        end
    end

    env.IsBusy = false
    warn("[AutoHop] Список серверов закончился. Повторное сканирование через 2 сек...")
    task.wait(2)
    findAliveServers()
end

local function handleFailure(reason)
    if env.HandlingError then
        return
    end
    env.HandlingError = true
    warn("[AutoHop] Сбой подключения (" .. tostring(reason) .. "). Смена сервера через 2 сек...")

    pcall(function()
        GuiService:ClearError()
    end)

    task.wait(2)

    pcall(function()
        GuiService:ClearError()
    end)

    env.IsBusy = false
    env.HandlingError = false
    tryNextServer()
end

-- Перехват ошибок телепорта (772 и др.)
env.TeleportFailConn = TeleportService.TeleportInitFailed:Connect(function(failedPlayer, teleportResult, errorMessage)
    if failedPlayer == player then
        handleFailure(tostring(teleportResult.Name) .. " - " .. tostring(errorMessage))
    end
end)

-- Перехват сетевых ошибок (277 и др.)
env.ErrorMsgConn = GuiService.ErrorMessageChanged:Connect(function(errorMessage)
    if errorMessage and errorMessage ~= "" then
        handleFailure("Окно ошибки: " .. tostring(errorMessage))
    end
end)

local function getServers(cursor)
    local url = "https://games.roblox.com/v1/games/" .. placeId .. "/servers/Public?sortOrder=Asc&excludeFullGames=true&limit=100"
    if cursor then
        url = url .. "&cursor=" .. HttpService:UrlEncode(cursor)
    end

    local success, decoded = pcall(function()
        local response = game:HttpGet(url)
        return HttpService:JSONDecode(response)
    end)

    if success and type(decoded) == "table" and type(decoded.data) == "table" then
        return decoded
    end
    return nil
end

findAliveServers = function()
    local cursor = nil
    local pagesChecked = 0
    env.CandidateServers = {}
    local backupServers = {}

    print("[AutoHop] На сервере больше " .. MAX_PLAYERS .. " игроков! Ищем пустой живой сервер...")

    repeat
        local data = getServers(cursor)
        if not data then
            warn("[AutoHop] Лимит запросов API Roblox. Ждем 3 сек...")
            task.wait(3)
            break
        end

        for _, server in ipairs(data.data) do
            if type(server) == "table" and type(server.id) == "string" then
                local playing = tonumber(server.playing) or 0
                local maxPlayers = tonumber(server.maxPlayers) or 0
                local fps = tonumber(server.fps) or 0
                local ping = tonumber(server.ping) or 0
                local tokens = (type(server.playerTokens) == "table" and #server.playerTokens) or 0

                if server.id ~= currentJobId and not env.FailedServers[server.id] and (maxPlayers - playing) >= 2 then
                    -- Фильтр против ошибки 277 (живой FPS, адекватный пинг, реальные токены)
                    local isAlive = (fps >= 45) and (ping >= 15 and ping <= 350) and (tokens >= playing)

                    if playing == 1 and isAlive then
                        table.insert(env.CandidateServers, server.id)
                    elseif (playing == 2 or playing == 3) and isAlive then
                        table.insert(backupServers, server.id)
                    end
                end
            end
        end

        if #env.CandidateServers >= 6 then
            break
        end

        pagesChecked = pagesChecked + 1
        cursor = data.nextPageCursor

        if cursor and pagesChecked < 4 then
            task.wait(0.3)
        end
    until not cursor or pagesChecked >= 4

    -- Если серверов с 1 игроком нет в живых, берем живые с 2-3 игроками (это всё равно меньше лимита в 5)
    if #env.CandidateServers == 0 and #backupServers > 0 then
        env.CandidateServers = backupServers
    end

    if #env.CandidateServers > 0 then
        print("[AutoHop] Найдено подходящих серверов: " .. #env.CandidateServers)
        env.IsBusy = false
        tryNextServer()
    else
        warn("[AutoHop] Подходящих серверов пока нет, повтор через 4 сек...")
        task.wait(4)
        findAliveServers()
    end
end

-- Функция проверки количества игроков на текущем сервере
local function checkPlayerCount()
    local currentCount = #Players:GetPlayers()
    if currentCount > MAX_PLAYERS then
        warn("[AutoHop] Игроков на сервере: " .. currentCount .. " (Лимит: " .. MAX_PLAYERS .. "). Переключаем сервер!")
        if not env.IsBusy and not env.HandlingError then
            findAliveServers()
        end
    else
        print("[AutoHop] Сервер подходит! Сейчас игроков: " .. currentCount .. " из " .. MAX_PLAYERS .. " допустимых.")
    end
end

-- 2. Проверяем онлайн сразу при заходе на сервер
checkPlayerCount()

-- 3. Следим за заходом новых игроков: если зайдет 6-й человек — сразу прыгаем дальше
env.PlayerAddedConn = Players.PlayerAdded:Connect(function()
    task.wait(0.5)
    checkPlayerCount()
end)