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:
SCRIPT ERROR: @my_script/server/main.lua:27: attempt to index a nil value (local 'Player')local Player = QBCore.Functions.GetPlayer(source)
Player.Functions.AddMoney('cash', 100) -- Player is nilGetPlayer 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:
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
print(Player.PlayerData.citizenid .. ' is loaded')
end)Sul client, l'evento corrispondente è QBCore:Client:OnPlayerLoaded:
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:
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.
RegisterNetEvent('my_script:sell', function()
Wait(1000)
local Player = QBCore.Functions.GetPlayer(source) -- may be wrong, or nil
end)Salvalo prima:
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 usasource, vedi securing server events. - La console. Un comando digitato nella console del server ha
sourceuguale a0, che non è un giocatore. - Un id che ha lasciato. Il giocatore si è disconnesso mentre il tuo codice aspettava.
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:
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:
local row = MySQL.single.await('SELECT charinfo, job FROM players WHERE citizenid = ?', { citizenid })
if row then
local charinfo = json.decode(row.charinfo)
endcharinfo è 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:
local player = exports.qbx_core:GetPlayer(source)
if not player then return end
print(player.PlayerData.citizenid)Per un giocatore online per citizenid:
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:
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:
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
QBCorestesso 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 →