Callback сервера возвращает nil: ESX, QBCore и ox_lib callbacks

ESX.TriggerServerCallback, QBCore TriggerCallback и lib.callback.await возвращают nil? Как каждый callback работает на сервере и клиенте и причины, почему они ничего не возвращают.

Скрипт клиента просит сервер о данных, и то, что приходит обратно, — это nil или ничего вообще:

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

Server callbacks — это как клиент просит сервер вопрос и получает ответ. Каждый фреймворк имеет свой, и ox_lib имеет один, который работает везде. Эта статья показывает три и почему они возвращают nil.

ESX

Зарегистрируйте на сервере, инициируйте с клиента:

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)

Функция сервера получает source и cb, и вы передаете ответ к cb. Дополнительные аргументы от клиента прибывают после cb. Функция клиента получает то, что cb отправил.

QBCore

Имена отличаются, форма одинакова:

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)

Если ESX или QBCore равен nil внутри скрипта, callback никогда не регистрируется. Смотрите ESX is nil и QBCore is nil.

ox_lib

ox_lib callbacks не нуждаются в фреймворке, и ответ — это возвращаемое значение вместо функции 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)

Второй аргумент await — это задержка в миллисекундах между вызовом и ответом (используйте false для отсутствия). Аргументы для сервера следуют:

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)

Для того чтобы callback существовал, скрипт загружает ox_lib в его манифесте:

lua
shared_script '@ox_lib/init.lua'

Без него lib равен nil: смотрите ox_lib init.lua not found.

Сервер также может вызвать клиента: lib.callback.await('name', playerId, ...) на сервере, с lib.callback.register на клиенте. Если вы предпочитаете не ждать, lib.callback('name', false, function(result) end) принимает функцию вместо.

Почему callback возвращает nil

Почти каждый случай — это один из этих:

  1. Имя не совпадает. Имена регистрации и инициирования должны быть идентичными, включая случай. Опечатка не вызывает ошибку, которую вы заметите, это просто никогда не отвечает.
  2. Это не зарегистрировано. Файл сервера никогда не работал: это отсутствует в server_scripts, ресурс не запустился или он не выполнился перед достижением строки регистрации.
  3. Ошибка на сервере, перед ответом. Если функция сервера ошибается, например xPlayer равен nil, ответ никогда не отправляется. Проверьте консоль сервера, а не консоль клиента.
  4. Вы никогда не вызываете cb на каждом пути. На ESX и QBCore, ветвь, которая возвращает без вызова cb(...) оставляет клиента в ожидании:
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. Вы забыли return на ox_lib. Функция lib.callback.register, которая не имеет return, отвечает nil.
  2. Вы вызываете слишком рано. Callback клиента, инициированный при запуске скрипта, может достичь сервера перед его регистрацией, после перезагрузки, например. Инициируйте после загрузки игрока.
  3. Смешанные стили. Callback, зарегистрированный с lib.callback.register, не может быть вызван с ESX.TriggerServerCallback. Используйте совпадающую пару.

Совет: чтобы узнать, какой случай у вас, добавьте print как первую строку функции сервера. Нет print означает шаги 1 или 2, print без ответа означает 3 к 5.

Защищайтесь от nil на клиенте

Обрабатывайте ответ как что-то, что может быть отсутствующим:

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

Для более старых фреймворков проверьте аргумент перед его индексированием:

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

Какой использовать

  • Написание для одного фреймворка только: его собственный callback хорош.
  • Написание для нескольких фреймворков или для QBox: используйте ox_lib, поэтому один callback работает везде.
  • Написание нового кода: lib.callback возвращает значения и читает как нормальная функция, что делает ошибки легче заметить.

Если вы переносите скрипт между ESX и QBCore, имена callback — это одна строка в функции карты.

Контрольный список

Симптом Исправление
Результат равен nil Проверьте, что имя точно совпадает на обеих сторонах
Никогда не отвечает Убедитесь, что файл сервера находится в манифесте и ресурс запущен
Ошибка в консоли сервера Исправьте; неудачный callback не отправляет ответ
ESX или QBCore: нет ответа на некоторых путях Вызовите cb(...) на каждой ветви
ox_lib: nil результат Добавьте return в функцию lib.callback.register
lib равен nil Добавьте shared_script '@ox_lib/init.lua' в манифест

Короткие ответы

В чем разница между callback и событием?

Событие отправляет сообщение и не ждет ответа. Callback просит другую сторону и получает значение обратно, поэтому клиент может использовать данные, которые только сервер знает.

Могу ли я использовать ox_lib callbacks на ESX или QBCore?

Да. ox_lib независим от фреймворка, поэтому lib.callback работает на ESX, QBCore и QBox пока ox_lib запущен и загружен скриптом.

Почему lib.callback.await останавливает мой скрипт на время?

Он ждет ответа сервера, поэтому он выдерживает поток. Если сервер никогда не отвечает, потому что callback отсутствует или ошибки, поток продолжает ждать или не выполняется с ошибкой.

Скрипты без этой проблемы

Advanced BoostingУгон машин на заказ через планшет: контракты от класса D до S+, команды и живая очередь.Смотреть скрипт →Quest CreatorВизуальный редактор квестов и диалогов с NPC — узел за узлом прямо в игре.Смотреть скрипт →Pawn Shop AppЛомбард между игроками прямо в lb-phone.Смотреть скрипт →

Читайте также