Server callback retorna nil: ESX, QBCore e callbacks ox_lib

ESX.TriggerServerCallback, QBCore TriggerCallback e lib.callback.await retornando nil? Como cada callback funciona no server e cliente, e as razões que retornam nada.

Um cliente script pede ao server por dados, e o que volta é nil, ou nada absolutamente:

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

Server callbacks são como o cliente pergunta ao server uma pergunta e pega uma resposta. Cada framework tem seu próprio, e ox_lib tem um que funciona em todos os lugares. Este artigo mostra os três e por que retornam nil.

ESX

Registre no server, dispare do 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)

A função do server recebe source e cb, e você passa a resposta para cb. Argumentos extras do cliente chegam depois de cb. A função do cliente recebe o que cb enviou.

QBCore

Os nomes diferem, a forma é a mesma:

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)

Se ESX ou QBCore é nil dentro do script, o callback nunca registra. Veja ESX is nil e QBCore is nil.

ox_lib

Callbacks ox_lib não precisam de um framework, e a resposta é um valor de retorno em vez de uma função 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)

O segundo argumento de await é um atraso em milissegundos entre a chamada e a resposta (use false para nenhum). Argumentos para o server o seguem:

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 o callback existir, o script carrega ox_lib em seu manifest:

lua
shared_script '@ox_lib/init.lua'

Sem isso, lib é nil: veja ox_lib init.lua not found.

O server também consegue chamar um cliente: lib.callback.await('name', playerId, ...) no server, com lib.callback.register no cliente. Se você prefere sem esperar, lib.callback('name', false, function(result) end) pega uma função em vez disso.

Por que um callback retorna nil

Quase todo caso é um desses:

  1. O nome não combina. O register e trigger names devem ser idênticos, incluindo case. Um typo não levanta um erro que você vai notar, apenas nunca responde.
  2. Não está registrado. O arquivo do server nunca rodou: está faltando do server_scripts, o recurso não começou, ou falhou antes de alcançar a linha de register.
  3. Um erro no server, antes da resposta. Se a função do server erra, por exemplo xPlayer é nil, a resposta nunca é enviada. Verifique o console do server, não o do cliente.
  4. Você nunca chama cb em cada caminho. Em ESX e QBCore, um ramo que retorna sem chamar cb(...) deixa o 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. Você esqueceu return em ox_lib. Uma função lib.callback.register que não tem return responde nil.
  2. Você chamou muito cedo. Um callback de cliente disparado no script start pode alcançar o server antes de seu register rodar, depois de um restart por exemplo. Dispare depois que o jogador carregou.
  3. Estilos mistos. Um callback registrado com lib.callback.register não consegue ser chamado com ESX.TriggerServerCallback. Use o par correspondente.

Dica: para descobrir qual caso você tem, adicione um print como a primeira linha da função do server. Sem print significa passos 1 ou 2, um print sem resposta significa 3 a 5.

Proteja-se contra nil no cliente

Trate a resposta como algo que pode 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 os frameworks mais antigos, verifique o argumento antes de indexá-lo:

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

Qual usar

  • Escrevendo para apenas um framework: seu próprio callback é fino.
  • Escrevendo para vários frameworks, ou para QBox: use ox_lib, então um callback funciona em todos os lugares.
  • Escrevendo código novo: lib.callback retorna valores e lê como uma função normal, que torna erros mais fáceis de notar.

Se você transporta um script entre ESX e QBCore, os nomes de callback são uma linha no function map.

Checklist

Sintoma Solução
Resultado é nil Verifique que o nome combina exatamente em ambos os lados
Nunca responde Tenha certeza que o arquivo do server está no manifest e o recurso começou
Erro no console do server Conserte-o; um callback que falha não envia resposta
ESX ou QBCore: sem resposta em alguns caminhos Chame cb(...) em cada ramo
ox_lib: resultado nil Adicione return à função lib.callback.register
lib é nil Adicione shared_script '@ox_lib/init.lua' ao manifest

Respostas rápidas

Qual é a diferença entre um callback e um evento?

Um evento envia uma mensagem e não espera por uma resposta. Um callback pergunta ao outro lado e pega um valor de volta, então o cliente consegue usar dados que apenas o server conhece.

Posso usar callbacks ox_lib em ESX ou QBCore?

Sim. ox_lib é independente do framework, então lib.callback funciona em ESX, QBCore e QBox contanto que ox_lib seja iniciado e carregado pelo script.

Por que lib.callback.await para meu script por um tempo?

Espera pela resposta do server, então cede a thread. Se o server nunca responde porque o callback está faltando ou erro, a thread continua esperando ou falha com um erro.

Scripts sem esse problema

Advanced BoostingBoosting de veículos pelo tablet: contratos da classe D à S+, crews e fila ao vivo.Ver script →Quest CreatorUm editor visual de missões e diálogos com NPCs, montado nó por nó dentro do jogo.Ver script →Pawn Shop AppUma casa de penhores entre jogadores dentro do lb-phone.Ver script →

Continue lendo