Преобразование ESX скрипта в QBCore (и обратно): карта функций и мост
Портируйте FiveM скрипт между ESX и QBCore: таблица общих вызовов (игрок, деньги, работа, предметы, уведомления, обратные вызовы) и файл моста, который поддерживает оба.
У вас есть скрипт, написанный для ESX, и ваш сервер запускает QBCore, или наоборот. Большинство скрипта — это простой Lua и natives, которые не меняются. Только вызовы фреймворка, и их меньше, чем вы ожидаете. Эта статья даёт вам карту их, а затем показывает, как изолировать их в один файл моста.
Что остаётся и что меняется
Natives, NUI, ваши собственные события, циклы, targets и меню работают на любом фреймворке. Что меняется, так это короткий список:
- как вы получаете объект фреймворка
- как вы получаете игрока
- деньги, работы и предметы
- уведомления
- используемые предметы и обратные вызовы
- таблицы базы данных для игроков
Ищите в скрипте ESX. и xPlayer, и каждое попадание — это что-то для преобразования.
Карта функций
| Задача | ESX Legacy | QBCore |
|---|---|---|
| Получить объект | ESX = exports['es_extended']:getSharedObject() |
local QBCore = exports['qb-core']:GetCoreObject() |
| Получить игрока (сервер) | ESX.GetPlayerFromId(src) |
QBCore.Functions.GetPlayer(src) |
| Идентификатор игрока | xPlayer.identifier |
Player.PlayerData.citizenid |
| Баланс наличных | xPlayer.getMoney() |
Player.PlayerData.money.cash |
| Добавить наличные | xPlayer.addMoney(n) |
Player.Functions.AddMoney('cash', n) |
| Удалить наличные | xPlayer.removeMoney(n) |
Player.Functions.RemoveMoney('cash', n) |
| Добавить в банк | xPlayer.addAccountMoney('bank', n) |
Player.Functions.AddMoney('bank', n) |
| Удалить из банка | xPlayer.removeAccountMoney('bank', n) |
Player.Functions.RemoveMoney('bank', n) |
| Имя работы | xPlayer.job.name |
Player.PlayerData.job.name |
| Уровень работы | xPlayer.job.grade |
Player.PlayerData.job.grade.level |
| Добавить предмет | xPlayer.addInventoryItem(name, n) |
Player.Functions.AddItem(name, n) |
| Удалить предмет | xPlayer.removeInventoryItem(name, n) |
Player.Functions.RemoveItem(name, n) |
| Количество предметов | xPlayer.getInventoryItem(name).count |
Player.Functions.GetItemByName(name) (nil если нет, затем .amount) |
| Используемый предмет | ESX.RegisterUsableItem(name, function(src) end) |
QBCore.Functions.CreateUseableItem(name, function(src, item) end) |
| Уведомить (клиент) | ESX.ShowNotification(msg) |
QBCore.Functions.Notify(msg, 'success') |
| Уведомить (сервер) | xPlayer.showNotification(msg) |
TriggerClientEvent('QBCore:Notify', src, msg, 'success') |
| Данные игрока (клиент) | ESX.GetPlayerData() |
QBCore.Functions.GetPlayerData() |
| Событие загрузки игрока | esx:playerLoaded |
QBCore:Client:OnPlayerLoaded |
| Событие изменения работы | esx:setJob |
QBCore:Client:OnJobUpdate |
| Обратный вызов сервера | ESX.RegisterServerCallback |
QBCore.Functions.CreateCallback |
Два деталя сбивают людей с толку. Типы денег: ESX имеет money для наличных и bank, QBCore использует 'cash' и 'bank' как первый аргумент. И уровень: ESX даёт простое число, QBCore таблицу, поэтому job.grade.level.
Обратные вызовы, которые использует каждый второй скрипт, сравниваются в деталях в server callbacks on ESX, QBCore and ox_lib.
База данных
Таблицы игроков отличаются, поэтому любой SELECT или UPDATE на них требует изменения:
| ESX | QBCore | |
|---|---|---|
| Игроки | users |
players |
| Ключ игрока | identifier (строка license:) |
citizenid |
| Транспортные средства | owned_vehicles |
player_vehicles |
Скрипт, который хранит свои собственные данные, с его собственными таблицами, обычно продолжает работать, пока он ключирует строки на значение, которое вы можете получить от любого фреймворка. Использование license идентификатора для этого работает на обоих.
QBox
QBox ближе к QBCore, чем к ESX. Его ядро — qbx_core, оно содержит слой совместимости для exports['qb-core']:GetCoreObject(), и его инвентарь — ox_inventory. Скрипт, преобразованный в QBCore, обычно запускается на QBox с небольшими изменениями, кроме вызовов инвентаря.
Подход файла моста
Если скрипт должен работать на обоих, не размещайте его if ESX then ... else ... end. Поместите каждый вызов фреймворка в один файл, и пусть остальной скрипт вызывает этот файл.
-- bridge.lua (server)
Bridge = {}
local framework
if GetResourceState('es_extended') == 'started' then
framework = 'esx'
ESX = exports['es_extended']:getSharedObject()
elseif GetResourceState('qb-core') == 'started' then
framework = 'qb'
QBCore = exports['qb-core']:GetCoreObject()
end
function Bridge.GetPlayer(src)
if framework == 'esx' then return ESX.GetPlayerFromId(src) end
return QBCore.Functions.GetPlayer(src)
end
function Bridge.AddCash(src, amount)
local player = Bridge.GetPlayer(src)
if not player then return false end
if framework == 'esx' then
player.addMoney(amount)
else
player.Functions.AddMoney('cash', amount)
end
return true
end
function Bridge.GetJob(src)
local player = Bridge.GetPlayer(src)
if not player then return nil end
if framework == 'esx' then
return player.job.name, player.job.grade
end
return player.PlayerData.job.name, player.PlayerData.job.grade.level
endВ манифесте, загрузите его перед файлами, которые его используют:
server_scripts {
'bridge.lua',
'server.lua',
}Затем скрипт читается так и никогда не упоминает фреймворк:
RegisterNetEvent('my_script:pay', function()
local src = source
local job = Bridge.GetJob(src)
if job == 'mechanic' then
Bridge.AddCash(src, 100)
end
end)Добавьте клиентский мост для уведомлений и данных игрока так же. Когда вы добавляете новый фреймворк, такой как QBox с qbx_core, вы добавляете ветвь в мост, и скрипт остаётся так же.
Помните, что мост работает только если фреймворк запускается первым. Поместите ensure es_extended или ensure qb-core выше скрипта в server.cfg, и читайте ESX is nil, если объект приходит обратно nil.
Контрольный список
| Проблема | Решение |
|---|---|
attempt to index a nil value (global 'ESX') на QBCore |
Вызов ESX остался; замените его из карты выше |
| Деньги или работа всегда nil | Вы читаете PlayerData на ESX, или xPlayer.job на QBCore |
| Ошибки количества предметов на QBCore | GetItemByName возвращает nil, когда у игрока нет ни одного; проверьте первым |
| Неправильная таблица в запросе | users и identifier на ESX, players и citizenid на QBCore |
| Обратный вызов возвращает ничего | Используйте совпадающие регистр и вызовы триггера для фреймворка |
| Требуется оба фреймворка | Переместите каждый вызов фреймворка в файл моста |
Короткие ответы
Могу ли я преобразовать любой ESX скрипт в QBCore?
Скрипты, которые используют фреймворк только для игроков, денег, работ, предметов и уведомлений, преобразуются хорошо. Скрипты, построенные вокруг ресурсов фреймворка, таких как esx_society или qb-management, требуют переписывания и этих частей.
Меняется ли база данных, когда я переключаюсь на фреймворк?
Да. ESX хранит игроков в users с identifier, а QBCore в players с citizenid. Запросы и имена таблиц в скрипте должны следовать фреймворку, который вы запускаете.
Лучше ли файл моста, чем преобразование?
Если вам нужен скрипт на обоих фреймворках, да: вы меняете один файл, не весь скрипт. Если вы запускаете только один фреймворк, преобразуйте один раз и отбросьте другую ветвь.
Скрипты без этой проблемы
Item Creator V2Создавайте используемые предметы с анимациями, пропами, эффектами и не только — без кода.Смотреть скрипт →
Shop CreatorМагазин меньше чем за минуту — владельцы, сотрудники, сейфы и ограбления в комплекте.Смотреть скрипт →
Advanced BoostingУгон машин на заказ через планшет: контракты от класса D до S+, команды и живая очередь.Смотреть скрипт →