El callback del servidor devuelve nil: callbacks de ESX, QBCore y ox_lib

¿ESX.TriggerServerCallback, QBCore TriggerCallback y lib.callback.await devuelven nil? Cómo funciona cada callback en el servidor y cliente, y las razones por las que no devuelven nada.

Un script de cliente pregunta al servidor por datos, y lo que regresa es nil, o nada en absoluto:

text
SCRIPT ERROR: @my_script/client/main.lua:21: attempt to index a nil value (local 'result')

Los callbacks del servidor son cómo el cliente pregunta al servidor una pregunta y obtiene una respuesta. Cada framework tiene el suyo propio, y ox_lib tiene uno que funciona en todas partes. Este artículo muestra los tres y por qué devuelven nil.

ESX

Registra en el servidor, activa desde el cliente:

lua
-- server
ESX.RegisterServerCallback('my_script:getMoney', function(source, cb)
    local xPlayer = ESX.GetPlayerFromId(source)
    cb(xPlayer.getMoney())
end)
lua
-- client
ESX.TriggerServerCallback('my_script:getMoney', function(money)
    print(money)
end)

La función del servidor obtiene source y cb, y pasas la respuesta a cb. Los argumentos extra del cliente llegan después de cb. La función del cliente recibe lo que cb envió.

QBCore

Los nombres difieren, la forma es la misma:

lua
-- server
local QBCore = exports['qb-core']:GetCoreObject()

QBCore.Functions.CreateCallback('my_script:getMoney', function(source, cb)
    local Player = QBCore.Functions.GetPlayer(source)
    cb(Player.PlayerData.money.cash)
end)
lua
-- client
local QBCore = exports['qb-core']:GetCoreObject()

QBCore.Functions.TriggerCallback('my_script:getMoney', function(money)
    print(money)
end)

Si ESX o QBCore es nil dentro del script, el callback nunca se registra. Consulta ESX es nil y QBCore es nil.

ox_lib

Los callbacks de ox_lib no necesitan un framework, y la respuesta es un valor de retorno en lugar de una función cb:

lua
-- server
lib.callback.register('my_script:getMoney', function(source)
    local xPlayer = ESX.GetPlayerFromId(source)
    return xPlayer.getMoney()
end)
lua
-- client
local money = lib.callback.await('my_script:getMoney', false)
print(money)

El segundo argumento de await es un retraso en milisegundos entre la llamada y la respuesta (usa false para ninguno). Los argumentos para el servidor lo siguen:

lua
local ok = lib.callback.await('my_script:buy', false, 'burger', 2)
lua
lib.callback.register('my_script:buy', function(source, item, amount)
    -- ...
    return true
end)

Para que el callback exista, el script carga ox_lib en su manifiesto:

lua
shared_script '@ox_lib/init.lua'

Sin él, lib es nil: consulta ox_lib init.lua no encontrado.

El servidor también puede llamar a un cliente: lib.callback.await('name', playerId, ...) en el servidor, con lib.callback.register en el cliente. Si prefieres no esperar, lib.callback('name', false, function(result) end) toma una función en su lugar.

Por qué un callback devuelve nil

Casi todos los casos son uno de estos:

  1. El nombre no coincide. Los nombres de registro y disparo deben ser idénticos, incluyendo mayúsculas/minúsculas. Un typo no genera un error que notarás, simplemente nunca responde.
  2. No está registrado. El archivo del servidor nunca se ejecutó: falta de server_scripts, el recurso no se inició, o falló antes de alcanzar la línea de registro.
  3. Un error en el servidor, antes de la respuesta. Si la función del servidor da error, por ejemplo xPlayer es nil, la respuesta nunca se envía. Comprueba la consola del servidor, no la del cliente.
  4. Nunca llamas a cb en cada ruta. En ESX y QBCore, una rama que regresa sin llamar a cb(...) deja al cliente esperando:
lua
-- wrong: no cb when the player is missing
ESX.RegisterServerCallback('my_script:getJob', function(source, cb)
    local xPlayer = ESX.GetPlayerFromId(source)
    if xPlayer then
        cb(xPlayer.job.name)
    end
end)
lua
-- right
ESX.RegisterServerCallback('my_script:getJob', function(source, cb)
    local xPlayer = ESX.GetPlayerFromId(source)
    cb(xPlayer and xPlayer.job.name or nil)
end)
  1. Olvidaste return en ox_lib. Una función lib.callback.register que no tiene return responde nil.
  2. Lo llamaste demasiado pronto. Un callback de cliente disparado al inicio del script puede llegar al servidor antes de que se ejecute su registro, después de un reinicio por ejemplo. Actívalo después de que el jugador haya cargado.
  3. Estilos mezclados. Un callback registrado con lib.callback.register no puede ser llamado con ESX.TriggerServerCallback. Usa el par correspondiente.

Consejo: para saber cuál caso tienes, añade un print como la primera línea de la función del servidor. Sin print significa pasos 1 o 2, un print sin respuesta significa 3 a 5.

Protégete contra nil en el cliente

Trata la respuesta como algo que puede estar faltando:

lua
local money = lib.callback.await('my_script:getMoney', false)
if not money then
    return print('No answer from the server')
end

Para los frameworks más antiguos, comprueba el argumento antes de indexarlo:

lua
QBCore.Functions.TriggerCallback('my_script:getJob', function(job)
    if not job then return end
    print(job)
end)

Cuál usar

  • Escribir solo para un framework: su propio callback está bien.
  • Escribir para varios frameworks, o para QBox: usa ox_lib, así que un callback funciona en todas partes.
  • Escribir código nuevo: lib.callback devuelve valores y se lee como una función normal, lo que hace que los errores sean más fáciles de detectar.

Si portas un script entre ESX y QBCore, los nombres de callback son una fila en el mapa de funciones.

Lista de verificación

Síntoma Solución
El resultado es nil Comprueba que el nombre coincida exactamente en ambos lados
Nunca responde Asegúrate de que el archivo del servidor está en el manifiesto y el recurso se inició
Error en la consola del servidor Arréglalo; un callback que falla no envía respuesta
ESX o QBCore: sin respuesta en algunas rutas Llama a cb(...) en cada rama
ox_lib: resultado nil Añade return a la función lib.callback.register
lib es nil Añade shared_script '@ox_lib/init.lua' al manifiesto

Respuestas rápidas

¿Cuál es la diferencia entre un callback y un evento?

Un evento envía un mensaje y no espera una respuesta. Un callback pregunta al otro lado y obtiene un valor de vuelta, así que el cliente puede usar datos que solo el servidor conoce.

¿Puedo usar callbacks de ox_lib en ESX o QBCore?

Sí. ox_lib es independiente del framework, así que lib.callback funciona en ESX, QBCore y QBox siempre que ox_lib esté iniciado y cargado por el script.

¿Por qué lib.callback.await detiene mi script un rato?

Espera la respuesta del servidor, así que cede el thread. Si el servidor nunca responde porque el callback falta o da error, el thread sigue esperando o falla con un error.

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 →Quest CreatorUn editor visual de misiones y diálogos con NPC, nodo a nodo dentro del juego.Ver script →Pawn Shop AppUn mercado de empeños entre jugadores dentro de lb-phone.Ver script →

Sigue leyendo