tentativo di indicizzare un valore nil (local 'Player'): QBCore e QBox fix

Player è nil nel tuo script QBCore o QBox? Perché QBCore.Functions.GetPlayer(source) ritorna nil, le ricerche per citizenid solo per giocatori online, e i pattern di guardia sicuri.

Nella console del server:

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 non ha trovato nessun giocatore caricato per quell'id e ha ritornato nil, e la riga successiva l'ha indicizzato. Le cause rispecchiano il caso ESX in ESX xPlayer è nil, con specifiche di QBCore e QBox.

1. Il giocatore non è ancora caricato

Un giocatore può essere connesso prima che QBCore abbia caricato il suo personaggio, specialmente mentre una schermata multicharacter è aperta. Fino a quando il personaggio non è scelto, GetPlayer(source) ritorna nil.

Il codice che gira su playerJoining, o da un thread che inizia immediatamente, urta questo. Aspetta l'evento QBCore che si attiva quando il giocatore è pronto. Sul server:

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

Sul client, l'evento corrispondente è QBCore:Client:OnPlayerLoaded:

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

Se la tua risorsa si riavvia mentre i giocatori sono online, questi eventi non si attivano di nuovo per loro. All'avvio, vai attraverso i giocatori che sono già caricati:

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 cambiato dopo un Wait

source è un globale che FiveM imposta per l'evento che gira. Se chiami Wait dentro l'handler, un altro evento può girare e cambiarlo.

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

Salvalo prima:

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. L'id è sbagliato

GetPlayer si aspetta l'id server di un giocatore online, come numero.

  • Una stringa da un comando. Gli argomenti sono testo, quindi convertili: QBCore.Functions.GetPlayer(tonumber(args[1])).
  • L'id sbagliato dal client. Sul client, PlayerId() è un indice locale. L'id del server è GetPlayerServerId(PlayerId()). Meglio, ignora gli id inviati dal client e usa source, vedi securing server events.
  • La console. Un comando digitato nella console del server ha source uguale a 0, che non è un giocatore.
  • Un id che ha lasciato. Il giocatore si è disconnesso mentre il tuo codice aspettava.
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. Ricerche cittadinid trovano solo giocatori online

Molti script memorizzano il citizenid invece della source, perché la source cambia ad ogni sessione. Per ottenere il giocatore da un citizenid:

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

Questo funziona solo mentre quel giocatore è online e caricato. Per un giocatore che è offline ritorna nil, che non è un errore nei tuoi dati. Leggi il database per i giocatori offline:

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 è memorizzato come testo JSON, quindi decodificalo in modo sicuro, vedi errori FiveM json.decode. Scrivere a un giocatore offline è un compito diverso: cambia la riga del database solo se il giocatore è veramente offline, o il prossimo salvataggio dal server sovrascrive il tuo cambio.

5. Su QBox

Il core di QBox è qbx_core. Mantiene un livello di compatibilità, quindi QBCore.Functions.GetPlayer funziona ancora negli script scritti per QBCore. Per il codice nuovo, usa i suoi export, che ritornano lo stesso tipo di oggetto giocatore o nil:

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

print(player.PlayerData.citizenid)

Per un giocatore online per citizenid:

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

Le regole da questo articolo si applicano nello stesso modo: nessun giocatore fino a che il personaggio non è caricato, salva source prima di un Wait, e aspettati nil per un giocatore offline. Se stai spostando uno script tra i core, vedi convertire uno script QBCore a QBox.

6. playerDropped

Quando un giocatore lascia, qb-core salva e rimuove il giocatore da solo, e l'ordine dei handler per playerDropped non è qualcosa su cui fare affidamento. Nel tuo proprio handler playerDropped, GetPlayer(source) può già essere nil. Mantieni quello che hai bisogno nella tua stessa tabella mentre il giocatore è online:

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)

Il pattern di guardia

Inizia ogni handler server che ha bisogno di un giocatore nello stesso modo:

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)

Suggerimento: se l'errore riguarda QBCore stesso che è nil, il problema è l'oggetto core, non il giocatore. Vedi tentativo di indicizzare un valore nil (globale 'QBCore').

Checklist

Sintomo Soluzione
Nil subito dopo che il giocatore si unisce Aspetta QBCore:Server:PlayerLoaded invece di playerJoining
Nil dopo un Wait Salva local src = source e usa src
Nil da un comando Converti l'argomento con tonumber; la console source è 0
GetPlayerByCitizenId ritorna nil Il giocatore è offline; interroga la tabella players
Server QBox Usa exports.qbx_core:GetPlayer(source) e controlla per nil
Nil in playerDropped Mantieni i dati che hai bisogno nella tua tabella mentre il giocatore è online
Qualsiasi nil Aggiungi if not Player then return end in cima all'handler

Risposte rapide

Perché QBCore.Functions.GetPlayer ritorna nil?

Non c'è nessun giocatore caricato con quell'id. Il giocatore potrebbe ancora stare caricando, l'id potrebbe essere sbagliato o perso dopo un Wait, o il giocatore ha già lasciato.

GetPlayerByCitizenId funziona per i giocatori offline?

No. Trova solo i giocatori che sono online. Per un giocatore offline, leggi la tabella players nel database.

Qual è l'equivalente QBox di QBCore.Functions.GetPlayer?

exports.qbx_core:GetPlayer(source). Ritorna l'oggetto giocatore, o nil quando non c'è nessun giocatore caricato per quell'id.

Script senza questo problema

Advanced BoostingBoosting di veicoli dal tablet: contratti dalla classe D alla S+, crew e coda in tempo reale.Vedi script →Drug Dealer AppSpaccio di strada come app per lb-phone: zone, acquirenti NPC, livelli e allerte alla polizia.Vedi script →Pawn Shop AppUn banco dei pegni tra giocatori dentro lb-phone.Vedi script →

Continua a leggere