FiveM playerConnecting und deferrals: defer, update, done erklärt
Wie AddEventHandler('playerConnecting') mit deferrals funktioniert: defer, Wait(0), update, done(reason), adaptive Karten, und warum Spieler hängen bleiben, wenn du vergisst, done zu rufen.
Du möchtest etwas ausführen, bevor ein Spieler hereingelassen wird: eine Whitelist-Überprüfung, eine Bannliste, eine Datenbankabfrage, eine Willkommenskarte. Der richtige Ort dafür ist das playerConnecting Event, und das Tool ist deferrals. Falsch verwendet, sitzen Spieler auf dem Verbindungsbildschirm ewig fest, also sind die Details wichtig.
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
-- runs when a player starts connecting
end)Was die Argumente sind
name: der Name des Spielers.setKickReason(reason): eine Funktion, die die Verbindung mit einer Nachricht ablehnt. Sie existiert für einfache, sofortige Ablehnungen.deferrals: ein Objekt mit Funktionen, die dir ermöglichen, die Verbindung zu unterbrechen und mit dem Spieler zu kommunizieren, während du arbeitest.
Innerhalb des Handlers ist source die Verbindungs-ID des Spielers.
Die vier Deferral-Aufrufe
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
local src = source -- save it now
deferrals.defer() -- 1. pause the connection
Wait(0) -- 2. let the engine register it
deferrals.update('Checking your account...') -- 3. show a message
-- do your checks here
deferrals.done() -- 4. let the player in
end)deferrals.defer()sagt FiveM, den Spieler zu halten, bis du dich entscheidest. Ohne ihn wird der Spieler hereingelassen, sobald dein Handler zurückgegeben wird, selbst wenn du eine asynchrone Aufgabe gestartet hast.Wait(0)ist direkt nachdefer()notwendig. Aufrufe vonupdate,doneoderpresentCardim gleichen Tick wiedeferfunktionieren möglicherweise nicht.deferrals.update(message)ersetzt den Text, den der Spieler auf dem Verbindungsbildschirm sieht. Verwende es, um den Fortschritt anzuzeigen.deferrals.done(reason)beendet das Warten. Kein Argument bedeutet, der Spieler wird akzeptiert. Eine Zeichenkette bedeutet, dass er abgelehnt wird und diesen Text sieht.
Tipp: Kopiere
sourcegleich am Anfang in eine lokale Variable. NachWaitoder einer HTTP-Anfrage kann das globalesourceauf einen anderen Spieler zeigen.
Einen Spieler ablehnen
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
local src = source
deferrals.defer()
Wait(0)
local license
for _, id in ipairs(GetPlayerIdentifiers(src)) do
if id:sub(1, 8) == 'license:' then license = id break end
end
if not license then
return deferrals.done('No Rockstar license found. Restart the game and try again.')
end
deferrals.done()
end)return deferrals.done(...) beendet den Handler zur gleichen Zeit, was dich davor bewahrt, done zweimal aufzurufen.
Asynchrone Überprüfungen
Deferrals sind für Arbeit gemacht, die Zeit braucht: eine Datenbankabfrage oder ein HTTP-Aufruf. Halte die Verbindung aufgeschoben und rufe done im Callback auf.
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
local src = source
deferrals.defer()
Wait(0)
deferrals.update('Looking you up...')
local license = GetPlayerIdentifierByType(src, 'license')
MySQL.scalar('SELECT 1 FROM whitelist WHERE license = ?', { license }, function(found)
if found then
deferrals.done()
else
deferrals.done('You are not whitelisted.')
end
end)
end)GetPlayerIdentifierByType existiert in aktuellen Server-Builds. Wenn dein Artifact alt ist, schleife über GetPlayerIdentifiers statt dessen, wie oben. Siehe das oxmysql-Handbuch für die Abfragesyntax. Ein vollständiges Beispiel mit Discord-Rollen findest du in Discord-Whitelist für FiveM.
Der häufige Fehler: done vergessen
Spieler, die auf dem Verbindungsbildschirm stecken, bedeuten fast immer, dass ein Code-Pfad niemals deferrals.done erreicht.
-- Bad: nothing happens when the query returns no row
MySQL.single('SELECT * FROM bans WHERE license = ?', { license }, function(row)
if row then
deferrals.done('You are banned.')
end
end)Wenn row nil ist, wird der Spieler auf unbestimmte Zeit halten. Die Behebung ist ein else:
MySQL.single('SELECT * FROM bans WHERE license = ?', { license }, function(row)
if row then
deferrals.done('You are banned.')
else
deferrals.done()
end
end)Drei andere Wege, um stecken zu bleiben:
- Ein Script-Fehler in dem Handler vor
done. Der Handler stoppt und der Spieler wartet. Lese die Konsole. Siehe Fehler in einem FiveM-Script lesen. - Ein HTTP-Aufruf, der nie antwortet. Füge einen Timeout hinzu, zum Beispiel, indem du die Startzeit verfolgst und mit einer Nachricht endet, wenn nichts zurückgekommen ist.
donezweimal aufrufen, oderupdatenachdoneaufrufen. Verwendereturn, um den Handler nach jedem Ende zu verlassen.
Mehrere Handler gleichzeitig
Viele Ressourcen hören auf playerConnecting, und jeder, der defer aufruft, trägt zum Warten bei. Der Spieler wird nur hereingelassen, wenn alle fertig sind. Ein langsamer oder kaputten Handler in einem Script hält alle auf, also teste nur mit dieser Ressource zuerst, wenn Verbindungen hängen bleiben.
Adaptive Karten
deferrals.presentCard zeigt ein Formular oder einen Regelsbildschirm aus einer Adaptive Card, die ein JSON-Layout ist. Der Spieler kann auf einen Button drücken, und dein Callback erhält das Ergebnis.
local card = {
type = 'AdaptiveCard',
version = '1.3',
body = {
{ type = 'TextBlock', text = 'Server rules', weight = 'Bolder', size = 'Large' },
{ type = 'TextBlock', text = 'Be respectful and no cheating.', wrap = true },
},
actions = {
{ type = 'Action.Submit', title = 'I agree', data = { accepted = true } },
},
}
AddEventHandler('playerConnecting', function(name, setKickReason, deferrals)
deferrals.defer()
Wait(0)
deferrals.presentCard(json.encode(card), function(data)
if data and data.accepted then
deferrals.done()
else
deferrals.done('You must accept the rules.')
end
end)
end)Halte Karten einfach: Text, ein Bild und ein oder zwei Buttons. Der Callback muss immer noch mit done enden.
Checkliste
| Symptom | Behebung |
|---|---|
| Spieler sitzt auf Verbindung fest | Ein Pfad ruft deferrals.done nie auf; füge das fehlende else hinzu |
update oder done hat keine Auswirkung |
Rufe Wait(0) direkt nach deferrals.defer() auf |
| Falscher Spieler betroffen | Speichere local src = source zuerst |
| Spieler wird rein gelassen, bevor die Überprüfung endet | Du hast deferrals.defer() vergessen |
| Ablehnen mit einer Nachricht | deferrals.done('reason') |
| Akzeptiere den Spieler | deferrals.done() ohne Argument |
| Verzögerung nur bei vielen Scripts | Der playerConnecting Handler einer anderen Ressource ist langsam oder kaputt |
Kurze Antworten
Warum brauche ich Wait(0) nach deferrals.defer()?
Der Deferral ist nur aktiv, sobald die Engine auf einen Tick fortgeschritten ist. Aufrufe von deferrals.update oder deferrals.done im gleichen Tick können ignoriert werden, also gib zuerst mit Wait(0) einmal nach.
Wie lehne ich einen Spieler ab?
Rufe deferrals.done('dein Grund') mit einer Zeichenkette auf. Der Spieler sieht den Text und darf nicht rein. deferrals.done() ohne Argument erlauben lässt ihn verbinden.
Was passiert, wenn ich deferrals.done nie aufrufe?
Der Spieler bleibt auf dem Verbindungsbildschirm, bis die Verbindung zeitlich abläuft. Jeder Code-Pfad in deinem Handler muss mit deferrals.done enden.

