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:
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:
-- server
ESX.RegisterServerCallback('my_script:getMoney', function(source, cb)
local xPlayer = ESX.GetPlayerFromId(source)
cb(xPlayer.getMoney())
end)-- 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:
-- 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)-- 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:
-- server
lib.callback.register('my_script:getMoney', function(source)
local xPlayer = ESX.GetPlayerFromId(source)
return xPlayer.getMoney()
end)-- 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:
local ok = lib.callback.await('my_script:buy', false, 'burger', 2)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:
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:
- 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.
- 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. - 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. - Você nunca chama
cbem cada caminho. Em ESX e QBCore, um ramo que retorna sem chamarcb(...)deixa o cliente esperando:
-- 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)-- right
ESX.RegisterServerCallback('my_script:getJob', function(source, cb)
local xPlayer = ESX.GetPlayerFromId(source)
cb(xPlayer and xPlayer.job.name or nil)
end)- Você esqueceu
returnem ox_lib. Uma funçãolib.callback.registerque não temreturnrespondenil. - 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.
- Estilos mistos. Um callback registrado com
lib.callback.registernão consegue ser chamado comESX.TriggerServerCallback. Use o par correspondente.
Dica: para descobrir qual caso você tem, adicione um
Proteja-se contra nil no cliente
Trate a resposta como algo que pode estar faltando:
local money = lib.callback.await('my_script:getMoney', false)
if not money then
return print('No answer from the server')
endPara os frameworks mais antigos, verifique o argumento antes de indexá-lo:
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.callbackretorna 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 →