Whitelist Discord per FiveM: consenti i giocatori per ruolo Discord
Costruisci una whitelist di ruoli Discord per il tuo server FiveM: playerConnecting con deferrals, l'identificatore Discord, un controllo dei ruoli bot tramite REST API, e un token sicuro.
Vuoi che solo i giocatori con un certo ruolo Discord si possano unire: membri, supporter, whitelisted. FiveM non ha un controllo Discord integrato, quindi ne aggiungi uno in playerConnecting: leggi l'identificatore Discord del giocatore, chiedi a Discord i loro ruoli attraverso un bot, e accetta o rifiuta la connessione.
Hai bisogno di tre cose: un bot Discord nel tuo server, uno script nel server FiveM, e un luogo sicuro per il token.
Come funziona
- Un giocatore si connette. FiveM attiva
playerConnectinge ti dà i loro identificatori. - Metti in pausa la connessione con deferrals (vedi playerConnecting and deferrals).
- Il tuo server chiede all'API REST Discord: questo utente è nella guild, e quali ruoli ha?
- Chiama
deferrals.done()per farlo entrare, odeferrals.done('reason')per rifiutare.
Crea il bot
- Apri il portale degli sviluppatori Discord e crea un'applicazione, quindi aggiungi un Bot ad essa.
- Copia il token del bot. Trattalo come una password.
- Nessun intent privilegiato è necessario per cercare un membro per ID. (Il Server Members Intent conta solo se un bot elenca ogni membro o ascolta gli eventi dei membri.)
- Invita il bot al tuo server Discord. Non ha bisogno di diritti admin, deve solo essere un membro.
- Su Discord, attiva la Modalità sviluppatore, quindi copia l'ID del server (guild) e l'ID del ruolo del ruolo della whitelist.
Mantieni il token fuori dal codice
Impostalo come convar in server.cfg, o in un file cfg che exec e mai condividi:
set discord_bot_token "paste-token-here"
set discord_guild_id "123456789012345678"
set discord_whitelist_role "123456789012345679"Usa set, non setr. Una convar setr viene replicata ad ogni client, il che farebbe perdere il token ai giocatori.
Leggili nello script:
local TOKEN = GetConvar('discord_bot_token', '')
local GUILD = GetConvar('discord_guild_id', '')
local ROLE = GetConvar('discord_whitelist_role', '')Attenzione: se il token finisce mai in uno screenshot, un messaggio di supporto o un repository pubblico, reimpostalo nel portale degli sviluppatori subito.
Leggi l'identificatore Discord
Gli identificatori di un giocatore somigliano a discord:123456789012345678. Scorri su di essi e rimuovi il prefisso:
local function getDiscordId(src)
for _, id in ipairs(GetPlayerIdentifiers(src)) do
if id:sub(1, 8) == 'discord:' then
return id:sub(9)
end
end
endChiedi a Discord i ruoli
L'endpoint è GET https://discord.com/api/v10/guilds/{guild.id}/members/{user.id}, autorizzato con Authorization: Bot <token>. La risposta contiene un array roles di ID ruolo.
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 }
)
endUn 404 significa che l'utente non è un membro del tuo server Discord. Qualsiasi altro stato, come 429 o 5xx, è un problema sulla strada, non un "no".
L'handler di connessione
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)Salva source in una variabile locale per primo: dopo Wait, il source globale non punta più a questo giocatore.
Limiti di frequenza e caching
Discord limita le richieste API per rotta e globalmente. Su un riavvio, molti giocatori si riconnettono contemporaneamente e ognuno attiva una richiesta. Due protezioni semplici:
- Cache i risultati per pochi minuti per ogni ID Discord, così un giocatore che riprova non chiama l'API di nuovo.
- Gestisci
429. Discord risponde con un headerRetry-After. Mostra un messaggio "riprova" e non fare un loop su di esso.
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)
endUsa cachedCheck nell'handler al posto di hasWhitelistRole. Un "sì" cache significa che un ruolo rimosso funziona fino a cinque minuti più a lungo, il che va bene per una whitelist.
Altri punti
- Non fallire aperto. Se Discord è giù, rifiuta con un messaggio chiaro invece di lasciare entrare tutti, a meno che tu non abbia deciso che è accettabile.
- Bypass dello staff. Se vuoi che gli admin entrino senza il ruolo, controlla i loro identificatori rispetto a una lista prima di chiamare Discord.
- Giocatori senza Discord non ottengono identificatore. Il tuo messaggio sopra dice loro cosa fare.
- Per bloccare un cheater una volta per tutte, bannalo invece di rimuovere un ruolo. Vedi moderating with txAdmin.
Checklist
| Sintomo | Soluzione |
|---|---|
Nessun identificatore discord: |
L'app Discord del giocatore deve essere in esecuzione e loggata |
401 da Discord |
Token del bot errato o ripristinato, o mancante prefisso Bot |
403 da Discord |
Il bot non è in quel server, o il token appartiene a un altro bot |
404 da Discord |
L'utente non è nel tuo server Discord |
429 da Discord |
Limite di frequenza: cache i risultati e mostra un messaggio di retry |
| Token visibile ai giocatori | Usa set, non setr, e mantienilo fuori dai file condivisi |
| Giocatore bloccato su "Checking" | Ogni percorso di codice deve terminare con deferrals.done |
Risposte rapide
Il giocatore ha bisogno che Discord sia aperto per entrare?
Sì. FiveM invia solo l'identificatore discord: quando l'app Discord desktop è in esecuzione e loggata sul PC del giocatore. Senza di essa, l'identificatore è mancante e il tuo script dovrebbe mostrare un messaggio chiaro.
Dove metto il token del bot?
In una convar impostata in server.cfg o in un file cfg separato, letta con GetConvar. Non metterla mai in un file Lua che è condiviso, caricato o memorizzato in un repository.
Chiamo l'API Discord ad ogni connessione?
Puoi, ma cache il risultato per pochi minuti. Discord applica limiti di frequenza alle richieste e un riavvio con molti giocatori che si riconnettono può colpire il limite.

