attempt to index a nil value (local 'xPlayer'): ESX-Lösung
xPlayer ist nil in deinem ESX-Skript? Warum ESX.GetPlayerFromId(source) nil zurückgibt: Spieler nicht geladen, source nach Wait verloren, String-IDs, playerDropped. Mit Guard-Mustern.
Die Server-Konsole zeigt:
SCRIPT ERROR: @my_script/server/main.lua:23: attempt to index a nil value (local 'xPlayer')local xPlayer = ESX.GetPlayerFromId(source)
xPlayer.addMoney(100) -- xPlayer is nilESX.GetPlayerFromId hat keinen Spieler für diese ID gefunden und hat nil zurückgegeben, und die nächste Zeile indizierte ihn. Der Aufruf ist in Ordnung. Die ID, die du ihm gibst, passt zu keinem geladenen ESX-Spieler. Hier sind die üblichen Gründe und wie man sich gegen jeden schützt.
1. Der Spieler ist nicht geladen
Ein Spieler ist mit dem Server verbunden, bevor ESX sein Zeichen fertig geladen hat. Während dieser Lücke und während ein Mehrfach-Charakter-Bildschirm offen ist, gibt ESX.GetPlayerFromId(source) nil zurück.
Dies trifft Code, der früh läuft, wie die generischen FiveM-Events playerJoining oder playerConnecting, oder einen Thread, der startet, wenn deine Ressource startet.
Verwende das ESX-Event, das ausgelöst wird, wenn der Spieler bereit ist, auf dem Server:
AddEventHandler('esx:playerLoaded', function(playerId, xPlayer, isNew)
print(('%s is loaded'):format(xPlayer.getName()))
end)Auf dem Client sagt das gleiche Event-Name deinem Client-Skript, dass der Spieler verwendet werden kann:
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
PlayerLoaded = true
end)Wenn dein Skript neu gestartet werden kann, während Spieler online sind, hat dieses Event bereits für sie ausgelöst. Beim Start durchlaufe die Spieler, die ESX bereits hat:
CreateThread(function()
for _, playerId in ipairs(GetPlayers()) do
local xPlayer = ESX.GetPlayerFromId(tonumber(playerId))
if xPlayer then
-- set up the player
end
end
end)2. source ändert sich nach einem Wait
source ist ein spezielles Global, das FiveM für das laufende Event setzt. Wenn du in dem Handler wartest, kann ein anderes Event in der Zwischenzeit laufen und source gehört nicht mehr deinem Spieler.
RegisterNetEvent('my_script:buy', function(item)
Wait(500)
local xPlayer = ESX.GetPlayerFromId(source) -- source may be someone else, or invalid
end)Speichere es in einer lokalen vor allem anderen:
RegisterNetEvent('my_script:buy', function(item)
local src = source
Wait(500)
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
end)Das Gleiche gilt in einem Rückruf oder einer Funktion, an die du source später übergibst: Übergebe den gespeicherten Wert, nicht das Global.
3. Die ID ist falsch
ESX.GetPlayerFromId braucht die Server-ID als Zahl eines Spielers, der online ist.
- Eine String-ID. Befehlsargumente sind Text.
ESX.GetPlayerFromId(args[1])kann nil zurückgeben, währendESX.GetPlayerFromId(tonumber(args[1]))funktioniert. - Die falsche ID vom Client. Auf dem Client ist
PlayerId()ein lokaler Index, nicht die Server-ID. Die Server-ID istGetPlayerServerId(PlayerId()). Das Senden der falschen gibt einen Spieler, der nicht existiert, oder den falschen Spieler. - Die Konsole. Ein Befehl, der in der Server-Konsole eingegeben ist, hat
sourcegleich0, was kein Spieler ist. - Eine ID aus einem Identifier-Lookup.
ESX.GetPlayerFromIdentifier(identifier)findet nur Spieler, die online sind. Für einen Offline-Spieler, lese stattdessen die Datenbank, siehe die oxmysql queries guide.
RegisterCommand('givecash', function(source, args)
local target = tonumber(args[1])
local amount = tonumber(args[2])
if not target or not amount then
return print('Usage: /givecash [id] [amount]')
end
local xTarget = ESX.GetPlayerFromId(target)
if not xTarget then
return print('Player not found or not loaded')
end
xTarget.addMoney(amount)
end, true)Vertraue nicht auf eine ID, die vom Client für etwas, das wichtig ist, gesendet wurde. Verwende source, das nicht gefälscht werden kann, wie in securing server events erläutert.
4. Der Spieler hat verlassen
Wenn der Spieler die Verbindung abbricht, während dein Code wartet, zum Beispiel in einer langen Schleife oder einem Timer, gibt GetPlayerFromId nil zurück, wenn es schließlich läuft. Dies ist ein normaler Fall, keine Bombe, und es braucht die gleiche Guard.
In playerDropped ist die Situation weniger klar, da ESX auch dieses Event verarbeitet, um den Spieler zu speichern und zu entfernen, und die Reihenfolge der Handler ist nicht etwas, auf das man sich verlassen sollte. ESX Legacy löst auch sein eigenes esx:playerDropped-Event aus, aber überprüfe, ob deine Version es hat. Der robusteste Ansatz ist, die Daten selbst zu behalten, während der Spieler online ist:
local sessions = {}
AddEventHandler('esx:playerLoaded', function(playerId, xPlayer)
sessions[playerId] = {
identifier = xPlayer.identifier,
job = xPlayer.job.name,
}
end)
AddEventHandler('playerDropped', function()
local data = sessions[source]
if data then
print(('%s left, job %s'):format(data.identifier, data.job))
sessions[source] = nil
end
end)Das Guard-Muster
Starten Sie jeden Server-Handler, der einen Spieler verwendet, auf die gleiche Weise:
RegisterNetEvent('my_script:sell', function(item, count)
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
if not xPlayer then return end
-- from here xPlayer is safe to use
xPlayer.addMoney(100)
end)Die gleiche Prüfung geht in Server-Callbacks, die mit ESX.RegisterServerCallback registriert sind, wo das erste Argument die Quelle des Spielers ist:
ESX.RegisterServerCallback('my_script:getJob', function(source, cb)
local xPlayer = ESX.GetPlayerFromId(source)
if not xPlayer then return cb(nil) end
cb(xPlayer.job.name)
end)Überprüfe auch die Client-Seite: Sie muss eine nil-Antwort vom Rückruf akzeptieren.
Tipp: Wenn der Fehler stattdessen
attempt to index a nil value (global 'ESX')ist, ist das Problem das ESX-Objekt, nicht der Spieler. Siehe ESX is nil: fixing esx:getSharedObject.
Checkliste
| Symptom | Lösung |
|---|---|
| Nil direkt nach dem Spieler beitritt | Warte auf esx:playerLoaded anstelle von playerJoining |
Nil nach einem Wait |
Speichere local src = source zuerst und verwende src |
| Nil von einem Befehl | Konvertiere das Argument mit tonumber; source ist 0 in der Konsole |
| Nil mit einer ID, die vom Client gesendet wurde | Verwende source; auf dem Client ist die Server-ID GetPlayerServerId(PlayerId()) |
Nil in playerDropped |
Behalte die Daten, die du brauchst, in deiner eigenen Tabelle, während der Spieler online ist |
| Nil für einen Offline-Spieler | GetPlayerFromId findet nur Online-Spieler; frage die Datenbank ab |
| Jede Nil | Füge if not xPlayer then return end oben im Handler hinzu |
Kurze Antworten
Warum ist xPlayer nil in ESX?
ESX.GetPlayerFromId(source) gibt nil zurück, wenn ESX keinen geladenen Spieler für diese ID hat. Der Spieler hat möglicherweise nicht fertig geladen, die ID kann falsch oder ein String sein, oder der Spieler hat bereits verlassen.
Sollte ich xPlayer in jedem Event überprüfen?
Ja. Jedes Server-Event kann mit einem Spieler ausgelöst werden, der nicht geladen ist, also starten Sie den Handler mit if not xPlayer then return end. Es kostet nichts und verhindert den Fehler.
Kann ich xPlayer in playerDropped verwenden?
Es ist nicht sicher, sich darauf zu verlassen, da ESX den Spieler möglicherweise bereits entfernt hat. Speichere die Daten, die du brauchst, in deiner eigenen Tabelle, während der Spieler online ist, und lese sie von dort.
Scripts ohne dieses Problem
Shop CreatorBau einen Shop in unter einer Minute — Besitzer, Angestellte, Tresore und Überfälle inklusive.Script ansehen →
Pawn Shop AppEin Pfandmarkt zwischen Spielern, direkt in lb-phone.Script ansehen →
Drug Dealer AppStraßenverkauf als lb-phone-App: Zonen, NPC-Käufer, Level und Polizeialarme.Script ansehen →