attempt to index a nil value (local 'Player'): QBCore und QBox Behebung

Player ist nil in deinem QBCore oder QBox Script? Warum QBCore.Functions.GetPlayer(source) nil zurückgibt, citizenid Lookups nur für online Spieler, und die sicheren Guard-Muster.

In der Server-Konsole:

text
SCRIPT ERROR: @my_script/server/main.lua:27: attempt to index a nil value (local 'Player')
lua
local Player = QBCore.Functions.GetPlayer(source)
Player.Functions.AddMoney('cash', 100)   -- Player is nil

GetPlayer fand keinen geladenen Spieler für diese ID und gab nil zurück, und die nächste Zeile indizierte ihn. Die Ursachen spiegeln den ESX-Fall in ESX xPlayer ist nil mit QBCore und QBox-Besonderheiten wider.

1. Der Spieler ist nicht geladen

Ein Spieler kann verbunden sein, bevor QBCore seinen Charakter geladen hat, besonders während ein multicharacter Bildschirm offen ist. Bis der Charakter gewählt wird, gibt GetPlayer(source) nil zurück.

Code, der auf playerJoining läuft, oder aus einem Thread, der sofort startet, trifft dies. Warte auf das QBCore-Event, das auslöst, wenn der Spieler bereit ist. Auf dem Server:

lua
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
    print(Player.PlayerData.citizenid .. ' is loaded')
end)

Auf dem Client ist das passende Event QBCore:Client:OnPlayerLoaded:

lua
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
    PlayerLoaded = true
end)

Wenn deine Ressource neu gestartet wird, während Spieler online sind, werden diese Events für sie nicht erneut ausgelöst. Beim Start gehe durch die Spieler, die bereits geladen sind:

lua
CreateThread(function()
    for _, src in pairs(QBCore.Functions.GetPlayers()) do
        local Player = QBCore.Functions.GetPlayer(src)
        if Player then
            -- set up the player
        end
    end
end)

2. source ändert sich nach einem Wait

source ist ein Global, das FiveM für das laufende Event setzt. Wenn du Wait in dem Handler aufrufst, kann ein anderes Event laufen und ihn ändern.

lua
RegisterNetEvent('my_script:sell', function()
    Wait(1000)
    local Player = QBCore.Functions.GetPlayer(source)   -- may be wrong, or nil
end)

Speichere es zuerst:

lua
RegisterNetEvent('my_script:sell', function()
    local src = source
    Wait(1000)

    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end
end)

3. Die ID ist falsch

GetPlayer erwartet die Server-ID eines Online-Spielers als Zahl.

  • Eine Zeichenkette aus einem Befehl. Argumente sind Text, also konvertiere sie: QBCore.Functions.GetPlayer(tonumber(args[1])).
  • Die falsche ID vom Client. Auf dem Client ist PlayerId() ein lokaler Index. Die Server-ID ist GetPlayerServerId(PlayerId()). Besser, ignoriere IDs, die vom Client gesendet werden, und verwende source, siehe sichere Server-Events.
  • Die Konsole. Ein Befehl, der in der Server-Konsole eingegeben wird, hat source gleich 0, was kein Spieler ist.
  • Eine ID, die verlassen hat. Der Spieler hat die Verbindung getrennt, während dein Code wartete.
lua
QBCore.Commands.Add('givecash', 'Give cash', { { name = 'id', help = 'Player id' }, { name = 'amount', help = 'Amount' } }, true, function(source, args)
    local target = QBCore.Functions.GetPlayer(tonumber(args[1]))
    local amount = tonumber(args[2])
    if not target or not amount then return end

    target.Functions.AddMoney('cash', amount)
end, 'admin')

4. citizenid Lookups finden nur Online-Spieler

Viele Scripts speichern die citizenid statt der source, weil sich die source bei jeder Session ändert. Um den Spieler aus einer citizenid zu bekommen:

lua
local Player = QBCore.Functions.GetPlayerByCitizenId(citizenid)

Dies funktioniert nur, während dieser Spieler online und geladen ist. Für einen Spieler, der offline ist, gibt es nil zurück, was kein Fehler in deinen Daten ist. Lese die Datenbank für Offline-Spieler:

lua
local row = MySQL.single.await('SELECT charinfo, job FROM players WHERE citizenid = ?', { citizenid })
if row then
    local charinfo = json.decode(row.charinfo)
end

charinfo wird als JSON-Text gespeichert, also dekodiere es sicher, siehe FiveM json.decode Fehler. Das Schreiben auf einen Offline-Spieler ist eine andere Aufgabe: ändere die Datenbankzeile nur, wenn der Spieler wirklich offline ist, oder die nächste Speicherung vom Server überschreibt deine Änderung.

5. In QBox

Der Core von QBox ist qbx_core. Es behält eine Kompatibilitätsebene, also funktioniert QBCore.Functions.GetPlayer immer noch in Scripts, die für QBCore geschrieben sind. Für neuen Code verwende seine Exports, die das gleiche Spieler-Objekt oder nil zurückgeben:

lua
local player = exports.qbx_core:GetPlayer(source)
if not player then return end

print(player.PlayerData.citizenid)

Für einen Online-Spieler per citizenid:

lua
local player = exports.qbx_core:GetPlayerByCitizenId(citizenid)

Die Regeln aus diesem Artikel gelten auf die gleiche Weise: kein Spieler bis der Charakter geladen ist, speichere source vor einem Wait, und erwarte nil für einen Offline-Spieler. Wenn du ein Script zwischen den Cores bewegst, siehe Konvertiere ein QBCore-Script zu QBox.

6. playerDropped

Wenn ein Spieler verlässt, speichert qb-core und entfernt den Spieler von selbst, und die Reihenfolge der Handler für playerDropped ist nichts, auf das man sich verlassen sollte. In deinem eigenen playerDropped Handler kann GetPlayer(source) bereits nil sein. Behalte, was du brauchst, in deiner eigenen Tabelle, während der Spieler online ist:

lua
local sessions = {}

AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
    sessions[Player.PlayerData.source] = Player.PlayerData.citizenid
end)

AddEventHandler('playerDropped', function()
    local citizenid = sessions[source]
    sessions[source] = nil
    if citizenid then
        print(citizenid .. ' left')
    end
end)

Das Guard-Muster

Beginne jeden Server-Handler, der einen Spieler braucht, auf die gleiche Weise:

lua
RegisterNetEvent('my_script:action', function()
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    -- Player is safe to use here
end)

Tipp: Wenn der Fehler über QBCore selbst nil ist, ist das Problem das Core-Objekt, nicht der Spieler. Siehe attempt to index a nil value (global 'QBCore').

Checkliste

Symptom Behebung
Nil direkt nach dem Spieler beitritt Warte auf QBCore:Server:PlayerLoaded anstelle von playerJoining
Nil nach einem Wait Speichere local src = source und verwende src
Nil aus einem Befehl Konvertiere das Argument mit tonumber; die Konsole source ist 0
GetPlayerByCitizenId gibt nil zurück Der Spieler ist offline; frage die players Tabelle ab
QBox Server Verwende exports.qbx_core:GetPlayer(source) und überprüfe auf nil
Nil in playerDropped Behalte die Daten, die du brauchst, in deiner eigenen Tabelle, während der Spieler online ist
Jeder nil Füge if not Player then return end am Anfang des Handlers ein

Kurze Antworten

Warum gibt QBCore.Functions.GetPlayer nil zurück?

Es gibt keinen geladenen Spieler mit dieser ID. Der Spieler lädt möglicherweise noch, die ID könnte falsch sein oder nach einem Wait verloren gehen, oder der Spieler hat bereits verlassen.

Funktioniert GetPlayerByCitizenId für Offline-Spieler?

Nein. Es findet nur Spieler, die online sind. Für einen Offline-Spieler lese stattdessen die players Tabelle in der Datenbank.

Was ist das QBox-Äquivalent von QBCore.Functions.GetPlayer?

exports.qbx_core:GetPlayer(source). Es gibt das Spieler-Objekt zurück, oder nil wenn es keinen geladenen Spieler für diese ID gibt.

Scripts ohne dieses Problem

Advanced BoostingFahrzeug-Boosting per Tablet: Aufträge von Klasse D bis S+, Crews und eine Live-Warteschlange.Script ansehen →Drug Dealer AppStraßenverkauf als lb-phone-App: Zonen, NPC-Käufer, Level und Polizeialarme.Script ansehen →Pawn Shop AppEin Pfandmarkt zwischen Spielern, direkt in lb-phone.Script ansehen →

Weiterlesen