intento de indexar un valor nil (local 'Player'): solución de QBCore y QBox
¿Player es nil en tu script de QBCore o QBox? Por qué QBCore.Functions.GetPlayer(source) devuelve nil, las búsquedas de ciudadanid solo para jugadores en línea, y los patrones de protección seguros.
En la consola del servidor:
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 no encontró ningún jugador cargado para ese id y devolvió nil, y la siguiente línea lo indexó. Las causas reflejan el caso de ESX en ESX xPlayer es nil, con especificidades de QBCore y QBox.
1. El jugador aún no está cargado
Un jugador puede estar conectado antes de que QBCore haya cargado su personaje, especialmente mientras está abierta una pantalla multicharacter. Hasta que se elige el personaje, GetPlayer(source) devuelve nil.
El código que se ejecuta en playerJoining, o desde un thread que comienza inmediatamente, lo golpea. Espera el evento de QBCore que se dispara cuando el jugador está listo. En el servidor:
AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
print(Player.PlayerData.citizenid .. ' is loaded')
end)En el cliente, el evento correspondiente es QBCore:Client:OnPlayerLoaded:
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
PlayerLoaded = true
end)Si tu recurso se reinicia mientras los jugadores están en línea, esos eventos no se disparan nuevamente para ellos. Al inicio, pasa por los jugadores que ya están cargados:
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 cambió después de un Wait
source es una variable global que FiveM establece para el evento en ejecución. Si llamas a Wait dentro del manejador, otro evento puede ejecutarse y cambiarlo.
RegisterNetEvent('my_script:sell', function()
Wait(1000)
local Player = QBCore.Functions.GetPlayer(source) -- may be wrong, or nil
end)Guárdalo primero:
RegisterNetEvent('my_script:sell', function()
local src = source
Wait(1000)
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
end)3. El id es incorrecto
GetPlayer espera el id de servidor de un jugador en línea, como un número.
- Una cadena de un comando. Los argumentos son texto, así que conviértelos:
QBCore.Functions.GetPlayer(tonumber(args[1])). - El id incorrecto del cliente. En el cliente,
PlayerId()es un índice local. El id del servidor esGetPlayerServerId(PlayerId()). Mejor, ignora los ids enviados por el cliente y usasource, consulta asegurar eventos del servidor. - La consola. Un comando escrito en la consola del servidor tiene
sourceigual a0, que no es un jugador. - Un id que se ha ido. El jugador se desconectó mientras tu código esperaba.
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. Las búsquedas de ciudadanid solo encuentran jugadores en línea
Muchos scripts almacenan el ciudadanid en lugar del source, porque el source cambia en cada sesión. Para obtener el jugador de un ciudadanid:
local Player = QBCore.Functions.GetPlayerByCitizenId(citizenid)Esto solo funciona mientras ese jugador esté en línea y cargado. Para un jugador que está sin conexión devuelve nil, que no es un error en tus datos. Lee la base de datos para jugadores sin conexión:
local row = MySQL.single.await('SELECT charinfo, job FROM players WHERE citizenid = ?', { citizenid })
if row then
local charinfo = json.decode(row.charinfo)
endcharinfo se almacena como texto JSON, así que decodifícalo de forma segura, consulta errores de FiveM json.decode. Escribir en un jugador sin conexión es una tarea diferente: cambia la fila de la base de datos solo si el jugador realmente está sin conexión, o el siguiente guardado del servidor sobrescribirá tu cambio.
5. En QBox
El núcleo de QBox es qbx_core. Mantiene una capa de compatibilidad, así que QBCore.Functions.GetPlayer aún funciona en scripts escritos para QBCore. Para código nuevo, usa sus exportaciones, que devuelven el mismo tipo de objeto de jugador o nil:
local player = exports.qbx_core:GetPlayer(source)
if not player then return end
print(player.PlayerData.citizenid)Para un jugador en línea por ciudadanid:
local player = exports.qbx_core:GetPlayerByCitizenId(citizenid)Las reglas de este artículo se aplican de la misma manera: ningún jugador hasta que se cargue el personaje, guarda source antes de un Wait, y espera nil para un jugador sin conexión. Si estás moviendo un script entre los núcleos, consulta convertir un script de QBCore a QBox.
6. playerDropped
Cuando un jugador se va, qb-core guarda y elimina al jugador por su cuenta, y el orden de los manejadores de playerDropped no es algo en lo que confiar. En tu propio manejador playerDropped, GetPlayer(source) ya puede ser nil. Mantén lo que necesites en tu propia tabla mientras el jugador está en línea:
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)El patrón de protección
Comienza cada manejador del servidor que necesita un jugador de la misma manera:
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)Consejo: si el error es sobre
QBCoresiendo nil, el problema es el objeto del núcleo, no el jugador. Consulta intento de indexar un valor nil (global 'QBCore').
Lista de verificación
| Síntoma | Solución |
|---|---|
| Nil justo después de que el jugador se une | Espera QBCore:Server:PlayerLoaded en lugar de playerJoining |
Nil después de un Wait |
Guarda local src = source y usa src |
| Nil de un comando | Convierte el argumento con tonumber; el source de consola es 0 |
GetPlayerByCitizenId devuelve nil |
El jugador está sin conexión; consulta la tabla players |
| Servidor QBox | Usa exports.qbx_core:GetPlayer(source) y comprueba nil |
Nil en playerDropped |
Mantén los datos que necesitas en tu propia tabla mientras el jugador está en línea |
| Cualquier nil | Añade if not Player then return end en la parte superior del manejador |
Respuestas rápidas
¿Por qué QBCore.Functions.GetPlayer devuelve nil?
No hay ningún jugador cargado con ese id. El jugador aún puede estar cargando, el id puede ser incorrecto o perderse después de un Wait, o el jugador ya se ha ido.
¿GetPlayerByCitizenId funciona para jugadores sin conexión?
No. Solo encuentra jugadores que están en línea. Para un jugador sin conexión, lee la tabla players en la base de datos en su lugar.
¿Cuál es el equivalente de QBox de QBCore.Functions.GetPlayer?
exports.qbx_core:GetPlayer(source). Devuelve el objeto del jugador, o nil cuando no hay ningún jugador cargado para ese id.
Scripts que evitan este problema
Advanced BoostingBoosting de vehículos desde una tablet: contratos de clase D a S+, crews y cola en vivo.Ver script →
Drug Dealer AppVenta callejera como app de lb-phone: zonas, compradores NPC, niveles y avisos a la policía.Ver script →
Pawn Shop AppUn mercado de empeños entre jugadores dentro de lb-phone.Ver script →