Преобразование QBCore скрипта в QBox: qbx_core, ox_inventory, ox_target
Как портировать QBCore скрипт в QBox: слой совместимости qbx_core, GetPlayer, ox_inventory предметы, ox_lib уведомления и прогресс, ox_target, и что обычно ломается.
У вас есть скрипт, написанный для QBCore и сервер, запускающий QBox. Иногда он запускается и работает, иногда консоль заполняется ошибками о отсутствующем qb-inventory, qb-target или qb-menu. Вот порядок для его портирования и места, где он обычно ломается.
Если вы всё ещё выбираете ядро, то же самое задание с другого направления находится в преобразование ESX скрипта в QBCore.
Что QBox меняет и что он сохраняет
QBox построен на qbx_core плюс ресурсы Overextended: ox_lib, oxmysql, ox_inventory и ox_target. Он сохраняет слой совместимости, поэтому exports['qb-core']:GetCoreObject() всё ещё отвечает и PlayerData имеет ту же форму (citizenid, job, charinfo, metadata, money). Вот почему многие скрипты запускаются без изменений.
Что он не сохраняет, так это старые QB служебные ресурсы. Где QBCore использовал qb-inventory, qb-target, qb-menu, qb-input и qb-progressbar, QBox ожидает ox_inventory, ox_target и ox_lib. Это куски, которые вы портируете.
Первый шаг — убедиться, что ядро запущено правильно:
ensure oxmysql
ensure ox_lib
ensure qbx_core
ensure ox_inventory
ensure ox_target
ensure my_scriptУдалите любую оставшуюся папку qb-core, так как два ядра конфликтуют. См. QBCore is nil: GetCoreObject, если объект отсутствует.
Шаг 1: зависимости в манифесте
fx_version 'cerulean'
game 'gta5'
lua54 'yes'
shared_script '@ox_lib/init.lua'
dependencies { 'qbx_core', 'ox_lib', 'ox_inventory', 'ox_target' }@ox_lib/init.lua — это то, что даёт вам глобальный lib. Если это не найдено, см. ox_lib init.lua не найден.
Шаг 2: получение игрока
Оба эти работают на QBox. Первый — стиль совместимости, второй — способ QBox:
-- QBCore style (still works through the compatibility layer)
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
-- QBox style
local player = exports.qbx_core:GetPlayer(source)
if player then
print(player.PlayerData.citizenid, player.PlayerData.job.name)
endОба возвращают nil для игрока, который не загружен, поэтому сохраняйте nil проверку. Чтобы найти загруженного игрока по citizen id, QBox также имеет GetPlayerByCitizenId. Когда вы портируете, вы можете оставить вызовы QBCore на месте и заменить их один за другим позже.
Шаг 3: инвентарь
Это то, где большинство скриптов ломается. qb-inventory и ox_inventory не делятся определениями предметов или именами функций.
| Задача | QBCore | QBox с ox_inventory |
|---|---|---|
| Добавить предмет | Player.Functions.AddItem('water', 1) |
exports.ox_inventory:AddItem(source, 'water', 1) |
| Удалить предмет | Player.Functions.RemoveItem('water', 1) |
exports.ox_inventory:RemoveItem(source, 'water', 1) |
| Количество | Player.Functions.GetItemByName('water').amount |
exports.ox_inventory:GetItemCount(source, 'water') |
| Метаданные | таблица info |
таблица metadata |
local src = source
local ok = exports.ox_inventory:AddItem(src, 'water', 2, { quality = 100 })
if not ok then
lib.notify(src, { description = 'Your inventory is full', type = 'error' })
endAddItem возвращает ложное значение, когда предмет не существует или не может быть переносимым, поэтому проверьте это. Определения предметов тоже переходят. QBCore хранит их в qb-core/shared/items.lua, ox_inventory в ox_inventory/data/items.lua. Добавьте каждый предмет, который скрипт использует там, в формате ox_inventory. Как это сделать находится в добавить предметы в ox_inventory, и формат QBCore, из которого вы приходите, находится в добавить предметы в qb-inventory.
Используемые предметы также регистрируются иначе: QBCore.Functions.CreateUseableItem становится export, установленным в определении предмета в ox_inventory, который указывает на функцию в вашем скрипте. Вызовы QBCore могут всё ещё работать через слой совместимости, поэтому протестируйте предмет перед его переписыванием.
Шаг 4: уведомления, прогресс и меню с ox_lib
ox_lib заменяет отдельные QB служебные ресурсы. Вызовы близки к тому, что вы знаете:
-- QBCore
QBCore.Functions.Notify('Done', 'success', 5000)
-- ox_lib (client)
lib.notify({ title = 'Job', description = 'Done', type = 'success', duration = 5000 })-- QBCore: QBCore.Functions.Progressbar(...) with a callback
-- ox_lib: returns true when completed, false when cancelled
if lib.progressBar({
duration = 5000,
label = 'Repairing',
useWhileDead = false,
canCancel = true,
disable = { car = true, move = true },
anim = { dict = 'mini@repair', clip = 'fixing_a_ped' },
}) then
print('finished')
else
print('cancelled')
endМеню переходят из qb-menu в lib.registerContext и lib.showContext, и формы ввода из qb-input в lib.inputDialog. Полные примеры находятся в уведомления и полосы прогресса на ESX, QBCore и ox_lib и ox_lib контекстные меню.
Шаг 5: ox_target вместо qb-target
qb-target принимает имя, координаты и таблицу опций в его собственном макете. ox_target принимает одну таблицу:
-- qb-target
exports['qb-target']:AddBoxZone('my_zone', vector3(215.0, -810.0, 30.7), 1.5, 1.5, {
name = 'my_zone', heading = 0, minZ = 29.7, maxZ = 32.7,
}, {
options = { { event = 'my_script:client:open', icon = 'fas fa-box', label = 'Open', job = 'police' } },
distance = 2.0,
})
-- ox_target
exports.ox_target:addBoxZone({
coords = vector3(215.0, -810.0, 30.7),
size = vector3(1.5, 1.5, 3.0),
rotation = 0,
options = {
{ name = 'my_zone_open', icon = 'fas fa-box', label = 'Open', groups = 'police',
onSelect = function() TriggerEvent('my_script:client:open') end },
},
})Обратите внимание event становится onSelect (или event всё ещё работает для события клиента), и job становится groups. Детали находятся в qb-target vs ox_target и ox_target зоны.
Что обычно ломается
- Ошибки отсутствующих предметов. Предмет существует в общем файле qb-core, но не в ox_inventory. Добавьте его.
No such exportдля qb-inventory, qb-target или qb-menu. Скрипт вызывает их напрямую: портируйте те вызовы, или он никогда не запустится.- Обратные вызовы.
lib.callback— это стиль QBox. Если скрипт всё ещё используетQBCore.Functions.CreateCallback, протестируйте его и переместите его в ox_lib, если он не удаётся: см. server callbacks. - Работы и банды с уровнями. QBox имеет свои собственные данные работы и группы. Протестируйте каждую проверку работы, особенно on-duty и сравнения уровней.
- Смешанные ядра. Оставшийся ресурс
qb-coreзапущен рядом сqbx_core. - Порядок запуска. Ваш скрипт выше ox_lib, ox_inventory или qbx_core в
server.cfg.
Контрольный список
| Проблема | Решение |
|---|---|
GetCoreObject nil |
Запустите qbx_core сначала и удалите любую папку qb-core |
No such export для qb-inventory |
Используйте exports.ox_inventory:AddItem(source, item, count) |
| Предмет не найден | Добавьте его в ox_inventory/data/items.lua |
| Вызовы qb-target не удаются | Портируйте в exports.ox_target:addBoxZone или addLocalEntity |
lib nil |
Добавьте shared_script '@ox_lib/init.lua' |
| Проверка работы всегда false | Протестируйте PlayerData.job.name и уровень на QBox |
Короткие ответы
Работают ли QBCore скрипты на QBox без изменений?
Многие работают, потому что qbx_core имеет слой совместимости для qb-core. Скрипты, которые зависят от qb-inventory, qb-target или qb-menu, обычно требуют работы, так как QBox использует ox_inventory, ox_target и ox_lib вместо этого.
Как я получаю игрока на QBox?
На сервере, exports.qbx_core:GetPlayer(source) возвращает игрока, с той же таблицей PlayerData, которую вы знаете из QBCore.
Нужно ли мне переписывать всё, чтобы переместиться на QBox?
Нет. Запустите скрипт на QBox, читайте ошибки, и замените куски, которые не удаются: инвентарь, target, меню и уведомления. Остальное, такое как PlayerData, работы и метаданные, сохраняет свою форму.
Скрипты без этой проблемы
Item Creator V2Создавайте используемые предметы с анимациями, пропами, эффектами и не только — без кода.Смотреть скрипт →
Shop CreatorМагазин меньше чем за минуту — владельцы, сотрудники, сейфы и ограбления в комплекте.Смотреть скрипт →
Quest CreatorВизуальный редактор квестов и диалогов с NPC — узел за узлом прямо в игре.Смотреть скрипт →