Discord-Whitelist für FiveM: Erlaube Spieler nach Discord-Rolle

Erstelle eine Discord-Rollen-Whitelist für deinen FiveM-Server: playerConnecting mit deferrals, der Discord-Kennung, eine Bot-Rollen-Überprüfung über die REST-API und einen sicheren Token.

Du möchtest, dass nur Spieler mit einer bestimmten Discord-Rolle beitreten: Mitglieder, Unterstützer, Whitelist. FiveM hat keine eingebaute Discord-Überprüfung, daher fügst du eine in playerConnecting hinzu: Lese die Discord-Kennung des Spielers, frage Discord nach ihren Rollen über einen Bot und akzeptiere oder lehne die Verbindung ab.

Du brauchst drei Dinge: einen Discord-Bot in deinem Server, ein Skript auf dem FiveM-Server und einen sicheren Platz für den Token.

Wie es funktioniert

  1. Ein Spieler verbindet sich. FiveM triggert playerConnecting und gibt dir ihre Kennungen.
  2. Du pausierst die Verbindung mit deferrals (siehe playerConnecting und deferrals).
  3. Dein Server fragt die Discord REST-API: Ist dieser Benutzer in der Gilde und welche Rollen haben sie?
  4. Du rufst deferrals.done() auf, um sie einzulassen, oder deferrals.done('reason') um abzulehnen.

Erstelle den Bot

  1. Öffne das Discord-Entwicklerportal und erstelle eine Anwendung, dann füge einen Bot hinzu.
  2. Kopiere den Bot-Token. Behandle ihn wie ein Passwort.
  3. Keine privilegierte Intent ist nötig, um einen Mitglied nach ID zu suchen. (Die Server Members Intent ist nur wichtig, wenn ein Bot jeden Mitglied auflistet oder auf Mitglied-Events hört.)
  4. Laden den Bot zu deinem Discord-Server ein. Er braucht keine Admin-Rechte, er muss nur ein Mitglied sein.
  5. In Discord schalte den Developer Mode ein, kopiere dann die Server (Guild) ID und die Rollen-ID der Whitelist-Rolle.

Halte den Token aus dem Code

Stelle ihn als Convar in server.cfg oder in einer cfg-Datei, die du exec und nie teilst:

cfg
set discord_bot_token "paste-token-here"
set discord_guild_id "123456789012345678"
set discord_whitelist_role "123456789012345679"

Verwende set, nicht setr. Eine setr-Convar wird an jeden Client repliziert, was den Token für Spieler lecken würde.

Lese sie im Skript:

lua
local TOKEN = GetConvar('discord_bot_token', '')
local GUILD = GetConvar('discord_guild_id', '')
local ROLE  = GetConvar('discord_whitelist_role', '')

Achtung: Falls der Token jemals in einem Screenshot, einer Support-Nachricht oder einem öffentlichen Repository endet, setze ihn im Entwicklerportal sofort zurück.

Lese die Discord-Kennung

Die Kennungen eines Spielers sehen wie discord:123456789012345678 aus. Schleife über sie und entferne das Präfix:

lua
local function getDiscordId(src)
    for _, id in ipairs(GetPlayerIdentifiers(src)) do
        if id:sub(1, 8) == 'discord:' then
            return id:sub(9)
        end
    end
end

Frage Discord nach den Rollen

Der Endpunkt ist GET https://discord.com/api/v10/guilds/{guild.id}/members/{user.id}, autorisiert mit Authorization: Bot <token>. Die Antwort enthält ein roles-Array von Rollen-IDs.

lua
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 }
    )
end

Ein 404 bedeutet, dass der Benutzer kein Mitglied deines Discord-Servers ist. Jeder andere Status, wie 429 oder 5xx, ist ein Problem auf dem Weg, kein „Nein".

Der Verbindungs-Handler

lua
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)

Speichere source in einem Local zuerst: Nach Wait zeigt das globale source nicht mehr auf diesen Spieler.

Raten-Limits und Caching

Discord begrenzt API-Anfragen pro Route und global. Bei einem Neustart verbinden sich viele Spieler auf einmal und jeder triggert eine Anforderung. Zwei einfache Schutzmaßnahmen:

  • Cache-Ergebnisse für ein paar Minuten pro Discord-ID, daher ruft ein Spieler, der erneut versucht, die API nicht erneut auf.
  • Behandle 429. Discord antwortet mit einem Retry-After-Header. Zeige eine „Versuchen Sie es später"-Nachricht und loope nicht darauf.
lua
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)
end

Verwende cachedCheck im Handler anstelle von hasWhitelistRole. Ein gecachtes „Ja" bedeutet, dass eine entfernte Rolle bis zu fünf Minuten länger funktioniert, was für eine Whitelist in Ordnung ist.

Andere Punkte

  • Scheitere nicht offen. Falls Discord unten ist, lehne mit einer klaren Nachricht ab, anstatt alle einzulassen, es sei denn, du hast entschieden, dass es akzeptabel ist.
  • Staff-Bypass. Falls du möchtest, dass Admins ohne die Rolle beitreten, überprüfe ihre Kennungen gegen eine Liste, bevor du Discord aufrufst.
  • Spieler ohne Discord bekommen keine Kennung. Deine Nachricht oben sagt ihnen, was zu tun ist.
  • Um einen Cheater für immer zu blockieren, bannen ihn statt eine Rolle zu entfernen. Siehe Moderieren mit txAdmin.

Checkliste

Symptom Behebung
Keine discord:-Kennung Die Discord-App des Spielers muss laufen und angemeldet sein
401 von Discord Falscher oder zurückgesetzter Bot-Token oder fehlendes Bot -Präfix
403 von Discord Der Bot ist nicht in diesem Server oder der Token gehört einem anderen Bot
404 von Discord Der Benutzer ist nicht in deinem Discord-Server
429 von Discord Raten-Limit: cache Ergebnisse und zeige eine Wiederholungs-Nachricht
Token für Spieler sichtbar Verwende set, nicht setr, und halte ihn aus gemeinsamen Dateien
Spieler hängt auf „Checking" Jeder Code-Pfad muss mit deferrals.done enden

Kurze Antworten

Muss der Spieler Discord offen haben, um beizutreten?

Ja. FiveM sendet den discord:-Identifier nur, wenn die Discord-Desktop-App auf dem PC des Spielers läuft und angemeldet ist. Ohne ihn fehlt der Identifier und dein Skript sollte eine klare Nachricht zeigen.

Wohin lege ich den Bot-Token?

In eine Convar, die in server.cfg oder einer separaten cfg-Datei gesetzt wird, gelesen mit GetConvar. Lege ihn nie in eine Lua-Datei, die geteilt, hochgeladen oder in einem Repository gespeichert ist.

Rufe ich die Discord-API bei jedem Beitritt auf?

Du kannst, aber cache das Ergebnis ein paar Minuten lang. Discord begrenzt Anfragen und ein Neustart mit vielen Spielern, die sich wieder verbinden, kann die Grenze treffen.

Scripts ohne dieses Problem

Tebex TemplateEin Premium-Theme ohne Code für deinen Tebex-Shop, komplett im Tebex-Panel anpassbar.Script ansehen →Mic PhoneEin faltbares Handy, das sich zum Tablet aufklappt und bis aufs echte Handy des Spielers reicht.Script ansehen →

Weiterlesen