attempt to index a nil value (local 'Player'): QBCore e QBox fix

Player é nil em seu script QBCore ou QBox? Por que QBCore.Functions.GetPlayer(source) retorna nil, lookups de citizenid apenas para jogadores online, e os padrões de guarda segura.

No console do 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 não encontrou jogador carregado para aquele id e retornou nil, e a próxima linha o indexou. As causas espelham o caso ESX em ESX xPlayer is nil, com especificidades de QBCore e QBox.

1. O jogador ainda não está carregado

Um jogador pode estar conectado antes de QBCore ter carregado seu character, especialmente enquanto uma tela de multicharacter está aberta. Até o character ser escolhido, GetPlayer(source) retorna nil.

Código que roda em playerJoining, ou de uma thread que começa imediatamente, atinge isso. Espere pelo evento QBCore que dispara quando o jogador está pronto. No server:

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

No cliente, o evento correspondente é QBCore:Client:OnPlayerLoaded:

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

Se seu resource reinicia enquanto jogadores estão online, aqueles eventos não disparam novamente para eles. Ao iniciar, vá através dos jogadores que já estão carregados:

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 mudou após um Wait

source é um global que FiveM define para o evento rodando. Se você chamar Wait dentro do handler, outro evento pode rodar e mudar.

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

Armazene primeiro:

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. O id está errado

GetPlayer espera o server id de um jogador online, como um número.

  • Uma string de um comando. Argumentos são texto, então converta: QBCore.Functions.GetPlayer(tonumber(args[1])).
  • O id errado do cliente. No cliente, PlayerId() é um índice local. O server id é GetPlayerServerId(PlayerId()). Melhor, ignore ids enviados pelo cliente e use source, veja securing server events.
  • O console. Um comando digitado no console do server tem source igual a 0, que não é um jogador.
  • Um id que deixou. O jogador desconectou enquanto seu código esperava.
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. Lookups de citizenid apenas encontram jogadores online

Muitos scripts armazenam o citizenid em vez do source, porque o source muda a cada session. Para pegar o jogador de um citizenid:

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

Isso apenas funciona enquanto aquele jogador está online e carregado. Para um jogador que está offline retorna nil, que não é um erro nos seus dados. Leia o banco de dados para jogadores 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 é armazenado como texto JSON, então decodifique com segurança, veja FiveM json.decode errors. Escrever para um jogador offline é uma tarefa diferente: mude a linha do banco de dados apenas se o jogador estiver realmente offline, ou o próximo save do server sobrescreve sua mudança.

5. Em QBox

O core de QBox é qbx_core. Mantém uma compatibility layer, então QBCore.Functions.GetPlayer ainda funciona em scripts escritos para QBCore. Para código novo, use seus exports, que retornam o mesmo tipo de objeto de jogador ou nil:

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

print(player.PlayerData.citizenid)

Para um jogador online por citizenid:

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

As regras deste artigo se aplicam da mesma forma: sem jogador até o character ser carregado, armazene source antes de um Wait, e espere nil para um jogador offline. Se você está movendo um script entre os cores, veja converting a QBCore script to QBox.

6. playerDropped

Quando um jogador sai, qb-core salva e remove o jogador por conta própria, e a ordem de handlers para playerDropped não é algo em que confiar. Em seu próprio handler playerDropped, GetPlayer(source) pode já ser nil. Mantenha o que você precisa em sua própria tabela enquanto o jogador está 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)

O padrão de guarda

Comece todo handler do server que precisa de um jogador do mesmo jeito:

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)

Dica: se o erro é sobre QBCore em si sendo nil, o problema é o objeto core, não o jogador. Veja attempt to index a nil value (global 'QBCore').

Checklist

Sintoma Solução
Nil logo após o jogador entrar Espere por QBCore:Server:PlayerLoaded em vez de playerJoining
Nil após um Wait Armazene local src = source e use src
Nil de um comando Converta o argumento com tonumber; o console source é 0
GetPlayerByCitizenId retorna nil O jogador está offline; query a tabela players
Server QBox Use exports.qbx_core:GetPlayer(source) e cheque por nil
Nil em playerDropped Mantenha os dados que você precisa em sua própria tabela enquanto o jogador está online
Qualquer nil Adicione if not Player then return end no topo do handler

Respostas rápidas

Por que QBCore.Functions.GetPlayer retorna nil?

Não há jogador carregado com aquele id. O jogador pode ainda estar carregando, o id pode estar errado ou perdido após um Wait, ou o jogador já deixou.

O GetPlayerByCitizenId funciona para jogadores offline?

Não. Apenas encontra jogadores que estão online. Para um jogador offline, leia a tabela players no banco de dados em vez disso.

Qual é o equivalente em QBox de QBCore.Functions.GetPlayer?

exports.qbx_core:GetPlayer(source). Retorna o objeto do jogador, ou nil quando não há jogador carregado para aquele id.

Scripts sem esse problema

Advanced BoostingBoosting de veículos pelo tablet: contratos da classe D à S+, crews e fila ao vivo.Ver script →Drug Dealer AppVendas na rua como app do lb-phone: zonas, compradores NPC, níveis e alertas para a polícia.Ver script →Pawn Shop AppUma casa de penhores entre jogadores dentro do lb-phone.Ver script →

Continue lendo