tentative d'indexer une valeur nil (local 'Player') : correction QBCore et QBox

Player est nil dans votre script QBCore ou QBox ? Pourquoi QBCore.Functions.GetPlayer(source) retourne nil, les recherches par citizenid pour les joueurs en ligne seulement, et les motifs de garde sûrs.

Dans la console du serveur :

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 n'a trouvé aucun joueur chargé pour cet ID et a retourné nil, et la ligne suivante l'a indexé. Les causes reflètent le cas ESX dans ESX xPlayer est nil, avec les spécificités QBCore et QBox.

1. Le joueur n'est pas encore chargé

Un joueur peut être connecté avant que QBCore ait chargé son personnage, surtout si un écran multicharacter est ouvert. Jusqu'à ce que le personnage soit choisi, GetPlayer(source) retourne nil.

Le code qui s'exécute sur playerJoining, ou à partir d'un thread qui démarre immédiatement, frappe ceci. Attendez l'événement QBCore qui se déclenche quand le joueur est prêt. Sur le serveur :

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

Sur le client, l'événement correspondant est QBCore:Client:OnPlayerLoaded :

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

Si votre ressource redémarre pendant que les joueurs sont en ligne, ces événements ne se déclenchent pas à nouveau pour eux. Au démarrage, parcourez les joueurs qui sont déjà chargés :

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 a changé après une Wait

source est un global que FiveM définit pour l'événement en cours. Si vous appelez Wait à l'intérieur du gestionnaire, un autre événement peut s'exécuter et le changer.

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

Enregistrez-le d'abord :

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 est mauvais

GetPlayer attend l'ID serveur d'un joueur en ligne, en tant que nombre.

  • Une chaîne à partir d'une commande. Les arguments sont du texte, alors convertissez-les : QBCore.Functions.GetPlayer(tonumber(args[1])).
  • Le mauvais ID du client. Sur le client, PlayerId() est un index local. L'ID serveur est GetPlayerServerId(PlayerId()). Mieux encore, ignorez les IDs envoyés par le client et utilisez source, consultez sécuriser les événements du serveur.
  • La console. Une commande tapée dans la console du serveur a source égal à 0, ce qui n'est pas un joueur.
  • Un ID qui est parti. Le joueur s'est déconnecté pendant que votre code attendait.
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. Les recherches par citizenid ne trouvent que les joueurs en ligne

De nombreux scripts enregistrent le citizenid au lieu de la source, car la source change à chaque session. Pour obtenir le joueur à partir d'un citizenid :

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

Cela ne fonctionne que pendant que ce joueur est en ligne et chargé. Pour un joueur qui est hors ligne, il retourne nil, ce qui n'est pas une erreur dans vos données. Lisez la base de données pour les joueurs hors ligne :

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 est stocké en tant que texte JSON, donc décodez-le en toute sécurité, consultez erreurs FiveM json.decode. L'écriture pour un joueur hors ligne est une tâche différente : modifiez uniquement la ligne de la base de données si le joueur est vraiment hors ligne, ou la prochaine sauvegarde du serveur écrase votre modification.

5. Sur QBox

Le noyau de QBox est qbx_core. Il garde une couche de compatibilité, donc QBCore.Functions.GetPlayer fonctionne toujours dans les scripts écrits pour QBCore. Pour le nouveau code, utilisez ses exports, qui retournent le même genre d'objet joueur ou nil :

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

print(player.PlayerData.citizenid)

Pour un joueur en ligne par citizenid :

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

Les règles de cet article s'appliquent de la même manière : pas de joueur jusqu'à ce que le personnage soit chargé, enregistrez source avant une Wait, et attendez-vous à nil pour un joueur hors ligne. Si vous déplacez un script entre les noyaux, consultez conversion d'un script QBCore en QBox.

6. playerDropped

Quand un joueur part, qb-core enregistre et supprime le joueur de son propre chef, et l'ordre des gestionnaires pour playerDropped n'est pas quelque chose sur lequel compter. Dans votre propre gestionnaire playerDropped, GetPlayer(source) peut déjà être nil. Gardez ce dont vous avez besoin dans votre propre table pendant que le joueur est en ligne :

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)

Le motif de garde

Commencez chaque gestionnaire serveur qui a besoin d'un joueur de la même façon :

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)

Conseil : si l'erreur concerne QBCore lui-même étant nil, le problème est l'objet noyau, pas le joueur. Consultez tentative d'indexer une valeur nil (global 'QBCore').

Liste de contrôle

Symptôme Correction
Nil juste après que le joueur rejoigne Attendez QBCore:Server:PlayerLoaded au lieu de playerJoining
Nil après une Wait Enregistrez local src = source et utilisez src
Nil à partir d'une commande Convertissez l'argument avec tonumber ; la console source est 0
GetPlayerByCitizenId retourne nil Le joueur est hors ligne ; interrogez la table players
Serveur QBox Utilisez exports.qbx_core:GetPlayer(source) et vérifiez nil
Nil dans playerDropped Gardez les données dont vous avez besoin dans votre propre table pendant que le joueur est en ligne
N'importe quel nil Ajoutez if not Player then return end en haut du gestionnaire

Réponses rapides

Pourquoi QBCore.Functions.GetPlayer retourne nil ?

Il n'y a pas de joueur chargé avec cet ID. Le joueur peut toujours être en cours de chargement, l'ID peut être mauvais ou perdu après une Wait, ou le joueur est déjà parti.

GetPlayerByCitizenId fonctionne-t-il pour les joueurs hors ligne ?

Non. Il ne trouve que les joueurs qui sont en ligne. Pour un joueur hors ligne, lisez plutôt la table players dans la base de données.

Quel est l'équivalent QBox de QBCore.Functions.GetPlayer ?

exports.qbx_core:GetPlayer(source). Il retourne l'objet du joueur, ou nil quand il n'y a pas de joueur chargé pour cet ID.

Des scripts sans ce problème

Advanced BoostingDu boosting de véhicules piloté par tablette : contrats de classe D à S+, crews et file d’attente en direct.Voir le script →Drug Dealer AppLa vente de rue en app lb-phone : zones, acheteurs PNJ, niveaux et alertes police.Voir le script →Pawn Shop AppUn marché de prêt sur gage entre joueurs, directement dans lb-phone.Voir le script →

À lire aussi