Discord whitelist dla FiveM: pozwól graczom po roli Discord
Zbuduj whitelist roli Discord dla serwera FiveM: playerConnecting z deferrals, identyfikator Discord, sprawdzenie roli bota przez REST API i bezpieczny token.
Chcesz, aby przyłączyć się tylko gracze z określoną rolą Discord: członkowie, zwolennicy, whitelisted. FiveM nie ma wbudowanego sprawdzenia Discord, więc dodajesz jedno w playerConnecting: przeczytaj identyfikator Discord gracza, poproś Discord o ich role przez bota, i zaakceptuj lub odrzuć połączenie.
Potrzebujesz trzech rzeczy: bot Discord na twoim serwerze, skrypt na serwerze FiveM i bezpieczne miejsce na token.
Jak to działa
- Gracz się przyłącza. FiveM wyzwala
playerConnectingi daje ci ich identyfikatory. - Pausujesz połączenie z deferrals (zobacz playerConnecting and deferrals).
- Twój serwer pyta Discord REST API: czy ten użytkownik jest w gildii, i jakie role ma?
- Wołasz
deferrals.done(), aby ich wpuścić, lubdeferrals.done('reason'), aby odrzucić.
Utwórz bota
- Otwórz portal deweloperów Discord i utwórz aplikację, potem dodaj Bota do niej.
- Skopiuj token bota. Traktuj to jak hasło.
- Brak uprzywilejowanego zamysłu jest potrzebny, aby wyszukać jednego członka po ID. (Server Members Intent liczy się tylko jeśli bot wymieniła każdego członka lub słucha zdarzeń członków.)
- Zaproś bota na serwer Discord. Nie potrzebuje uprawnień administratora, musi tylko być członkiem.
- W Discord, włącz Tryb Dewelopera, potem skopiuj serwer (guild) ID i role ID roli whitelist.
Trzymaj token poza kodem
Ustaw go jako convar w server.cfg, lub w pliku cfg, który exec i nigdy nie dzielisz:
set discord_bot_token "paste-token-here"
set discord_guild_id "123456789012345678"
set discord_whitelist_role "123456789012345679"Użyj set, nie setr. Convar setr jest replikowany do każdego klienta, co przecieknęłoby token graczom.
Przeczytaj je w skrypcie:
local TOKEN = GetConvar('discord_bot_token', '')
local GUILD = GetConvar('discord_guild_id', '')
local ROLE = GetConvar('discord_whitelist_role', '')Ostrzeżenie: jeśli token kiedykolwiek skończy się na zrzucie ekranu, wiadomości pomocy lub publicznym repozytorium, zresetuj go w portalu deweloperów zaraz.
Przeczytaj identyfikator Discord
Identyfikatory gracza wyglądają jak discord:123456789012345678. Pętla nad nimi i usuń przedrostek:
local function getDiscordId(src)
for _, id in ipairs(GetPlayerIdentifiers(src)) do
if id:sub(1, 8) == 'discord:' then
return id:sub(9)
end
end
endPoproś Discord o role
Punkt końcowy to GET https://discord.com/api/v10/guilds/{guild.id}/members/{user.id}, autoryzowany z Authorization: Bot <token>. Odpowiedź zawiera tablicę roles ID roli.
local function hasWhitelistRole(discordId, cb)
PerformHttpRequest(
('https://discord.com/api/v10/guilds/%s/members/%s'):format(GUILD, discordId),
function(status, body)
if status == 200 then
local member = json.decode(body)
for _, role in ipairs(member.roles or {}) do
if role == ROLE then return cb(true) end
end
return cb(false)
elseif status == 404 then
return cb(false, 'not_in_guild')
end
cb(nil, status) -- rate limit or Discord error
end,
'GET', '',
{ ['Authorization'] = 'Bot ' .. TOKEN }
)
end404 oznacza, że użytkownik nie jest członkiem twojego serwera Discord. Każdy inny status, takie jak 429 lub 5xx, to problem w drodze, nie "nie".
Handler połączenia
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
local src = source
deferrals.defer()
Wait(0)
deferrals.update('Checking your Discord role...')
local discordId = getDiscordId(src)
if not discordId then
return deferrals.done('Open the Discord app on your PC, then reconnect.')
end
hasWhitelistRole(discordId, function(ok, info)
if ok then
deferrals.done()
elseif ok == false and info == 'not_in_guild' then
deferrals.done('Join our Discord server first.')
elseif ok == false then
deferrals.done('You do not have the whitelist role.')
else
deferrals.done('Could not reach Discord (' .. tostring(info) .. '). Try again in a moment.')
end
end)
end)Zapisz source w lokalnym najpierw: po Wait, globalny source już nie wskazuje tego gracza.
Limity tempa i cachowanie
Discord limituje żądania API na trasę i globalnie. Przy restarcie, wielu graczy przyłącza się naraz i każdy wyzwala żądanie. Dwie proste ochrony:
- Cachuj wyniki przez kilka minut na Discord ID, więc gracz, który ponawia, nie wołuje API ponownie.
- Obsłużyć
429. Discord odpowiada nagłówkiemRetry-After. Pokaż wiadomość "spróbuj ponownie" i nie pętli na nim.
local cache = {}
local TTL = 5 * 60 * 1000
local function cachedCheck(discordId, cb)
local hit = cache[discordId]
if hit and GetGameTimer() - hit.at < TTL then
return cb(hit.ok)
end
hasWhitelistRole(discordId, function(ok, info)
if ok ~= nil then cache[discordId] = { ok = ok, at = GetGameTimer() } end
cb(ok, info)
end)
endUżyj cachedCheck w handleru zamiast hasWhitelistRole. Cachowany "tak" oznacza, że usunięta rola działa do pięciu minut dłużej, co jest ok dla whitelist.
Inne punkty
- Nie nie otwieraj. Jeśli Discord jest wyłączony, odrzuć z jasną wiadomością zamiast wpuszczać wszystkich, chyba że zdecydowałeś, że to jest ok.
- Obejście personelu. Jeśli chcesz, aby administratorzy przyłączyli się bez roli, sprawdzić ich identyfikatory wobec listy przed wołaniem Discord.
- Gracze bez Discord nie otrzymają identyfikatora. Twoja wiadomość powyżej mówi im, co robić.
- Aby zablokować oszusta na zawsze, zamiast usuwania roli ich zabanuj. Zobacz moderating with txAdmin.
Lista kontrolna
| Symptom | Naprawa |
|---|---|
Brak identyfikatora discord: |
Discord app gracza musi być uruchomiona i zalogowana |
401 z Discord |
Złyły lub zresetowany token bota, lub brakujący przedrostek Bot |
403 z Discord |
Bot nie jest na tym serwerze, lub token należy do innego bota |
404 z Discord |
Użytkownik nie jest na twoim serwerze Discord |
429 z Discord |
Limit tempa: cachuj wyniki i pokaż wiadomość ponowienia |
| Token widoczny dla graczy | Użyj set, nie setr, i trzymaj go poza plikami wspólnymi |
| Gracz utknął na "Checking" | Każda ścieżka kodu musi kończyć się deferrals.done |
Szybkie odpowiedzi
Czy gracz potrzebuje Discord otwartego, aby przyłączyć się?
Tak. FiveM wysyła identyfikator discord: tylko, gdy aplikacja Discord jest uruchomiona i zalogowana na PC gracza. Bez tego, identyfikator brakuje i twój skrypt powinien pokazać jasną wiadomość.
Gdzie włóż token bota?
W convar ustawiony w server.cfg lub osobnym pliku cfg, przeczytany z GetConvar. Nigdy nie włóż go w plik Lua, który jest wspólny, załadowany lub przechowywany w repozytorium.
Czy wołam Discord API przy każdym połączeniu?
Możesz, ale cachuj wynik przez kilka minut. Discord limituje żądania i restart z wieloma graczami przyłączającymi się może trafić limit.

