Zaoszczędź dziś 20% Użyj kodu WELCOME przy kasie. WELCOME

Konwersja FiveM Scripts – ESX, QBCore, QBOX (ramka…

Testujesz darmowy skrypt?

Darmowe skrypty są wystarczające do szybkich kontroli. W przypadku serwerów produkcyjnych porównaj pełne pakiety serwerowe lub płatne skrypty, korzystając z frameworka i przypadku użycia.

To prosty przewodnik po konwersji skryptów FiveM, który pokazuje dokładnie, jak to zrobić, bez zbędnych zbędnych elementów i w którym najpierw piszemy kod. Konwertuj FiveM na Scripts między konfiguracjami ESX, QBCore, QBOX (qbx_core) i niezależnymi od frameworka (standalone). Otrzymasz mapowania API trójstronne, kod adaptera, kroki migracji SQL (mysql-async → oxmysql), szczegóły dotyczące QBOX, listy kontrolne testów i wskazówki dotyczące wzmacniania produkcji.


TL;DR — Migracja w 10 krokach

  1. Migawka i inscenizacja: Utwórz kopię zapasową bazy danych/plików. Uruchom lokalny serwer testowy z docelową strukturą.
  2. Zidentyfikuj zależności: inwentarz, cel, menu/UI, wywołania zwrotne, warstwa bazy danych, rdzeń dostęp.
  3. Wersje pinów i kolejność: oxmysql → ox_lib → framework (es_extended / qb-core / qbx_core) → twoje zasoby.
  4. Przeczytaj ścieżkę kodu: Znajdź wszystkich graczy, pieniądze, zadania/obowiązki, ekwipunek, wywołania/wydarzenia i wywołania bazy danych.
  5. Interfejsy API map: Użyj poniższych tabel Rosetta, aby nanieść mapę ESX ↔ QBCore ↔ QBOX.
  6. Połącz to: Dodaj most.lua adapter, który automatycznie wykrywa strukturę i normalizuje wywołania.
  7. Konwertuj wywołania zwrotne: Wywołania zwrotne ESX/QB → QBOX/ox_lib lib.callback.* gdy jest to potrzebne.
  8. Migracja bazy danych: Przenieś identyfikatory, konta, elementy, pojazdy; przełącz na oxmysql *.czekać na styl.
  9. Wydarzenia Harden: Uprawomocnić źródło, granice, grupy/zadania, własność; nigdy nie ufaj klientowi.
  10. Kontrola jakości i wydanie: Uruchom listy kontrolne, tagi, dziennik zmian i plan wycofania.

Czy jesteś programistą i szukasz rozwiązania w zakresie adapterów? Sprawdź nasz darmowy skrypt adaptera tutaj


1) Frameworki 101: ESX vs QBCore vs QBOX vs Standalone

Przegląd architektoniczny

KategoriaESXQBCoreQBOX
Architektura / Dostęp do rdzeniaeksporty['es_extended']:getSharedObject()ESXeksporty['qb-core']:GetCoreObject()QBCoreBrak globalnego obiektu rdzeniowego; użyj eksporty.qbx_core:* dla graczy, grup i powiadomień
Obiekt graczaESX.GetPlayerFromId(źródło)xPlayerQBCore.Functions.GetPlayer(źródło)Odtwarzaczexports.qbx_core:GetPlayer(src)Odtwarzacz z Dane gracza
IdentyfikatoryHistorycznie identyfikator (licencja/Steam)obywatel jako klucz podstawowyobywatel jako klucz podstawowy
Pieniądze ObsługiwaniexPlayer.addMoney() / `addAccountMoney('bank'‘‘'black_money')``Player.Functions.AddMoney('gotówka'‘
Praca i obowiązkixPlayer.job.name, .job.gradePlayer.PlayerData.job.name, .poziom.klasy, Na służbiePomocnicy w pracy/grupie za pośrednictwem eksporty.qbx_core:* (kontrole grupowe, osoby ustalające obowiązki)
SpisDomyślnie ESX / ox_inventory / qb-inwentarz (zalecony: ox_inventory)qb-inwentarz / ox_inventoryox_inventory zalecony
Wywołania zwrotneESX.RegisterServerCallback / ESX.TriggerServerCallbackQBCore.Funkcje.Utwórz wywołanie zwrotne / TriggerCallbackWoleć ox_lib wywołania zwrotne (lib.callback.register/await) lub eksportuje QBOX
Warstwa bazy danychStary: mysql-async → Teraz: oxmysql (MySQL.query.await, MySQL.update.await)oxmysqloxmysql
UI – PowiadomieniaESX PowiadomPowiadomienie QBQBOX powiadomić pomocników lub lib.notify
UI – Menuesx_menu_domyślne / ox_lib:registerContextmenu qb / ox_lib:registerContextox_lib:registerContext / lib.inputDialog
UI – System docelowyesx_target / ox_targetcel qb / ox_targetox_target zalecony

Czym różni się QBOX

  • Nazwa zasobu i eksporty: rdzeń qbx (NIE PobierzCoreObject).
  • Pochyla się na ox_lib (oddzwonienia, powiadomienia) i oxmysql domyślnie.
  • Wbudowane funkcje dla wielu postaci/kolejek/grup; pomocnicy wyrażający swoje zdanie w zakresie zadań/obowiązków.

Ramy FiveM: QBCore kontra ESX

2) Preflight: środowisko i narzędzia

  • Serwer: aktualny Serwer FX artefakty, Lua 5.4, CFX zapewnić zamówienie
  • Zamówienie: upewnij się, że oxmysqlzapewnij ox_libzapewnić ramyzapewnij sobie swoje zasoby
  • Redaktor: Kod VS + Lua LS, rysik; opcjonalnie ripgrep do szybkiego skanowania wzorów
  • Konfiguracja testowa: czysta migawka bazy danych; szczegółowe rejestrowanie; mały zestaw danych zaszczepionych
  • Wzory wyszukiwania użyjesz:
    • ESX. xPlayer. QBCore. Dane gracza rdzeń qbx eksporty.ox_inventory mysql%-async MySQL.

3) Kamień z Rosetty: ESX ↔ QBCore ↔ QBOX (mapowanie trójstronne)

Łatwe w użyciu narzędzie do kopiowania i wklejania. Użyj go, aby zastąpić połączenia telefoniczne lub podłączyć adapter.

Rdzeń i gracz

PojęcieESXQBCoreQBOX
Zdobądź rdzeńeksporty['es_extended']:getSharedObject()eksporty['qb-core']:GetCoreObject()(n/a — użyj eksportów)
Pobierz gracza (źródło)ESX.GetPlayerFromId(źródło)QBCore.Functions.GetPlayer(źródło)exports.qbx_core:GetPlayer(src)
Uzyskaj za pomocą citizenid(zapytanie niestandardowe)QBCore.Functions.GetPlayerByCitizenId(id)exports.qbx_core:GetPlayerByCitizenId(id) (jeśli występuje)

Identyfikatory

PojęcieESXQBCoreQBOX
Podstawowyidentyfikator (licencja/Steam)obywatelobywatel
Przejście dla pieszychtabela id_map(identyfikator, id obywatela)To samoTo samo

Pieniądze

DziałanieESXQBCoreQBOX
Dodaj gotówkęxPlayer.addMoney(a)Player.Functions.AddMoney('gotówka', a)Gracz.PlayerData.money.cash += a (poprzez adapter + zapisz)
Dodaj bankxPlayer.addAccountMoney('bank', a)Player.Functions.AddMoney('bank', a)Gracz.PlayerData.money.bank += a (adapter + zapisz)
Dodaj brudnexPlayer.addAccountMoney('black_money', a)element lub dodatkowe konto (zdefiniowane na serwerze)mapuj do portfela przedmiotów/alternatywnego (np., krypto) (wybór adaptera)

Praca, Obowiązek, Grupy

PojęcieESXQBCoreQBOX
Przeczytaj pracęxPlayer.job.name, .stopieńPlayer.PlayerData.job.name, .poziom.klasyGracz.DaneOdtwarzacza.zadanie.* + pomocnicy grupowi
Na służbie(różnie)Player.PlayerData.job.ondutyUstaw obowiązki służbowe/pomocnicy grupowi poprzez eksporty
Kontrola grupowa(dodatek)(dodatek)exports.qbx_core:HasGroup(src, group) (przykład)

Spis

DziałanieESXQBCoreQBOX
Dodaj elementxPlayer.addInventoryItem(n, c)Player.Functions.AddItem(n, c, ...)woleć ox_inventory eksport przez adapter
ox_inventoryeksporty.ox_inventory:*eksporty.ox_inventory:*eksporty.ox_inventory:*

Wywołania zwrotne

PojęcieESXQBCoreQBOX
Rejestr serweraESX.RegisterServerCallbackQBCore.Funkcje.Utwórz wywołanie zwrotnelib.callback.register (ox_lib)
Wyzwalacz klientaESX.TriggerServerCallbackQBCore.Funkcje.Wywołanie zwrotne wyzwalaczalib.callback.await

Warstwa bazy danych

PojęcieESX/QB (starsza wersja)oxmysql (cel)
AportowaćMySQL.Async.fetchAll(sql, parametry, cb)wiersze lokalne = MySQL.query.await(sql, {p1, ...})
AktualizacjaMySQL.Async.execute(sql, parametry, cb)lokalne aff = MySQL.update.await(sql, {p1, ...})

UI / Powiadom / Cel

PojęcieESXQBCoreQBOX
NotyfikowaćESX.ShowNotification(msg)QBCore.Functions.Notify(wiadomość, typ)exports.qbx_core:Powiadom(...) Lub lib.notify({...})
Menu(różnie)menu qbox_lib:registerContext / wejścia
Cel(dodatek)cel qbox_target

Wskazówka: przychylność ox_lib, ox_inventory, ox_target zachować neutralność w różnych ramach.


4) Samouczek A — ESX → QBCore (praktyczny)

Bramka: Konwertuj prosty zasób sklepu z ESX na QBCore.

Krok 1 — Zależności

  • Zapewnić oxmysql, ox_lib, rdzeń qb są rozpoczęte.
  • Jeśli skrypt używa inwentarza ESX, przeprowadź migrację do ox_inventory (zalecane) lub zmapuj do inwentarza QB.

Krok 2 — Wykryj strukturę i dodaj most

Tworzyć most.lua aby znormalizować graczy/pieniądze/ekwipunek:

-- bridge.lua (ESX/QB/QBOX adapter)
local M = {}
local fw

CreateThread(function()
  if GetResourceState('qbx_core') == 'started' then
    fw = 'qbx'
  elseif GetResourceState('qb-core') == 'started' then
    fw = 'qb'
  elseif GetResourceState('es_extended') == 'started' then
    fw = 'esx'
  else
    fw = 'none'
  end
end)

function M.getFramework()
  return fw
end

function M.getPlayer(src)
  if fw == 'qbx' then
    return exports.qbx_core:GetPlayer(src)
  elseif fw == 'qb' then
    return exports['qb-core']:GetCoreObject().Functions.GetPlayer(src)
  elseif fw == 'esx' then
    return exports['es_extended']:getSharedObject().GetPlayerFromId(src)
  end
end

local function saveQbox(src)
  if fw == 'qbx' and exports.qbx_core and exports.qbx_core.Save then
    exports.qbx_core:Save(src)
  end
end

function M.addMoney(src, account, amount)
  local p = M.getPlayer(src)
  if not p or type(amount) ~= 'number' then return false end
  if fw == 'qb' then
    return p.Functions.AddMoney(account, amount)
  elseif fw == 'esx' then
    if account == 'cash' then
      return p.addMoney(amount)
    elseif account == 'bank' then
      return p.addAccountMoney('bank', amount)
    elseif account == 'black' or account == 'black_money' then
      return p.addAccountMoney('black_money', amount)
    end
  elseif fw == 'qbx' then
    local money = p.PlayerData and p.PlayerData.money or {}
    account = account == 'black' and 'crypto' or account -- example mapping
    money[account] = (money[account] or 0) + amount
    saveQbox(src)
    return true
  end
  return false
end

function M.removeMoney(src, account, amount)
  return M.addMoney(src, account, -math.abs(amount))
end

function M.addItem(src, name, count, meta)
  if GetResourceState('ox_inventory') == 'started' then
    return exports.ox_inventory:AddItem(src, name, count, meta)
  elseif fw == 'qb' then
    return exports['qb-inventory']:AddItem(src, name, count, false, meta)
  elseif fw == 'esx' then
    local p = M.getPlayer(src)
    return p and p.addInventoryItem(name, count)
  elseif fw == 'qbx' then
    return exports.ox_inventory:AddItem(src, name, count, meta)
  end
end

function M.notify(src, msg, ntype)
  if fw == 'qb' then
    TriggerClientEvent('QBCore:Notify', src, msg, ntype or 'primary')
  elseif fw == 'esx' then
    TriggerClientEvent('esx:showNotification', src, msg)
  elseif fw == 'qbx' then
    if exports.qbx_core and exports.qbx_core.Notify then
      exports.qbx_core:Notify(src, msg, ntype or 'info')
    else
      lib.notify(src, { title = 'Notice', description = msg })
    end
  else
    print(('notify(%s): %s'):format(src, msg))
  end
end

return M

Krok 3 — Konwersja wywołań zwrotnych

  • ESX → QB: wymień ESX.RegisterServerCallback z QBCore.Funkcje.Utwórz wywołanie zwrotne.
  • Klient używa QBCore.Funkcje.Wywołanie zwrotne wyzwalacza.
-- server.lua (callback)
local bridge = require 'bridge'

local function getPrice(item)
  return 100
end

if GetResourceState('qb-core') == 'started' then
  local QBCore = exports['qb-core']:GetCoreObject()
  QBCore.Functions.CreateCallback('shop:getPrice', function(source, cb, item)
    cb(getPrice(item))
  end)
else
  -- fallback for QBOX/ESX via ox_lib
  lib.callback.register('shop:getPrice', function(source, item)
    return getPrice(item)
  end)
end
-- client.lua (wywołanie zwrotne) jeśli GetResourceState('qb-core') == 'started' wtedy lokalne QBCore = exports['qb-core']:GetCoreObject() QBCore.Functions.TriggerCallback('shop:getPrice', function(price) print('price', price) end, 'bread') w przeciwnym razie lokalne price = lib.callback.await('shop:getPrice', false, 'bread') print('price', price) end

Krok 4 — Ścieżki pieniężne i zapasy

  • Zastępować xPlayer.addAccountMoney z Funkcje gracza.Dodaj pieniądze (dla QB) lub adapter.
  • Standaryzacja wszystkich zmian stanu magazynowego poprzez adapter.

Krok 5 — Wydarzenia (bezpieczeństwo po stronie serwera)

RegisterNetEvent('sklep:kup', funkcja(przedmiot, ilość) lokalne src = źródło jeśli typ(przedmiot) ~= 'ciąg' lub typ(kwota) ~= 'liczba' wtedy zwróć koniec jeśli ilość < 1 lub ilość > 10 wtedy zwróć koniec lokalne p = bridge.getPlayer(src) jeśli nie p wtedy zwróć koniec lokalne cena = 100 * ilość jeśli nie bridge.removeMoney(src, 'gotówka', cena) wtedy zwróć koniec bridge.addItem(src, przedmiot, ilość) bridge.notify(src, ('Kupiono %dx %s'):format(kwota, przedmiot), 'sukces') koniec)

Krok 6 — Migracja bazy danych (identyfikatory, konta)

  • Utwórz przejście dla pieszych id_map(identyfikator, id obywatela).
  • Zaludniać obywatel dla QB z ESX użytkownicy tabeli za pomocą wybranej reguły (istniejąca kolumna lub wygenerowana).
-- Przykład: utwórz przejście dla pieszych i uzupełnij (dostosuj do swojego schematu) CREATE TABLE IF NOT EXISTS id_map ( identifier VARCHAR(64) PRIMARY KEY, citizenid VARCHAR(64) NOT NULL UNIQUE ); -- Załóżmy, że wygenerowałeś nowe citizenid i zapisałeś je wcześniej INSERT IGNORE INTO id_map(identifier, citizenid) SELECT u.identifier, u.citizenid FROM users u WHERE u.citizenid IS NOT NULL;

mysql‑async → oxmysql

-- przed (mysql-async) MySQL.Async.fetchAll('SELECT * FROM users WHERE identifier = @id', {['@id'] = identifier}, function(rows) ... end) -- po (oxmysql) local rows = MySQL.query.await('SELECT * FROM users WHERE identifier = ?', { identifier })

Krok 7 — Kontrola jakości

  • Twórz przedmioty, kupuj/sprzedawaj, upewniaj się, że saldo zmienia się prawidłowo.
  • Sprawdź, czy wywołania zwrotne zwracają wartość pod obciążeniem.
  • Sprawdź, czy metadane inwentarza są zachowane.

5) Samouczek B — QBCore → ESX (praktyczny)

Kluczowe ostrzeżenia:

  • Zastosowania ESX konta Do bank/czarne_pieniądze. Brudne pieniądze Port QB przedmiot (jeśli używane) na konto ESX lub zachowaj jako przedmiot.
  • Schematy stanowisk różnią się (stopień i poziom). Dokładnie je zaplanuj.

Przykład: Mapowanie pieniędzy za pomocą adaptera

-- in bridge.lua, when fw == 'esx'
function M.qbToEsxMoney(account)
  if account == 'cash' then return 'cash' end
  if account == 'bank' then return 'bank' end
  if account == 'black' or account == 'black_money' then return 'black_money' end
  return account
end

Przykład: Konwersja wywołania zwrotnego (serwer)

jeśli GetResourceState('es_extended') == 'started' wtedy lokalne ESX = exports['es_extended']:getSharedObject() ESX.RegisterServerCallback('garage:getVehicles', function(source, cb) lokalne src = source lokalne p = bridge.getPlayer(src) lokalne rows = MySQL.query.await('SELECT * FROM owned_vehicles WHERE owner = ?', { p.identifier }) cb(rows) koniec) koniec

Lista kontrolna testów

  • Stanowiska pracy/awanse są kontynuowane.
  • Salda bankowe/brudne zmieniają się zgodnie z oczekiwaniami.
  • Potwierdzono własność pojazdu i format tablic rejestracyjnych.

6) Samouczek C — QBCore ↔ QBOX (praktyczny)

QBCore → QBOX

  • Zastępować QBCore.Funkcje.* z eksporty.qbx_core:* Lub ox_lib wywołania zwrotne.
  • Odtwarzacz: QBCore.Functions.GetPlayer(źródło)exports.qbx_core:GetPlayer(src).
  • Notyfikować: QBCore.Funkcje.Powiadomienieexports.qbx_core:Powiadom Lub lib.notify.
  • Obowiązki/grupy: użyj eksportów QBOX (Ustaw obowiązki służbowe, Ma grupę, itp.).

QBOX → QBCore

  • Zastępować eksporty.qbx_core:* z QBCore.Funkcje.* odpowiedników lub adaptera.
  • W razie potrzeby ponownie wprowadź wywołania zwrotne QB i odpowiedniki menu/celów.

Fragmenty przed/po

-- Przed (powiadomienie QB) QBCore.Functions.Notify('Witaj', 'powodzenie') -- Po (QBOX) exports.qbx_core:Notify(source, 'Witaj', 'powodzenie') -- lub lib.notify(source, { title = 'Witaj', description = 'Witaj', type = 'success' })
-- Przed (QB pobierz gracza) lokalny Gracz = QBCore.Functions.GetPlayer(src) -- Po (QBOX) lokalny Gracz = exports.qbx_core:GetPlayer(src)

7) Samouczek D — Framework → Standalone z adapterami

Napisz swoje skrypty raz i uruchamiaj je wszędzie:

  • Utwórz most udostępnianie stabilnego API: pobierzOdtwarzacz, pobierzIdentyfikator, dodaj/usuń pieniądze, dodaj/usuń element, notyfikować, ma grupę, na służbie, wywołania zwrotne obwoluta.
  • Wykryj strukturę w czasie wykonywania (rdzeń qbxrdzeń qbes_rozszerzonynic).
  • Używać ox_lib do wywołań zwrotnych i powiadomień, gdy nie istnieje bezpośredni pomocnik struktury.

Minimalny samodzielny zapasowy

-- when fw == 'none'
function M.getPlayer(src)
  -- implement a minimal table or reject actions gracefully
  return { id = src }
end

function M.notify(src, msg)
  print(('notify(%s): %s'):format(src, msg))
end

8) Wydajność i bezpieczeństwo (wzmocnienie produkcji)

Walidacja po stronie serwera (nigdy nie ufaj klientowi)

  • Uprawomocnić typy I miedza na każdym wydarzeniu.
  • Sprawdzać własność, czasy odnowienia, dystans (jeśli dotyczy), praca/grupa.
  • Upewnij się, że saldo środków pieniężnych nie stanie się ujemne i ogranicz kwoty.
  • Porównywać cena po stronie serwera; nie akceptuj sum podanych przez klienta.

Struktura wydarzenia

  • Użyj jednego zdarzenie serwerowe na akcję; nie udostępniaj klientom surowych funkcji dotyczących zapasów/pieniędzy.
  • Woleć wywołania zwrotne dla przepływów żądanie/odpowiedź.

DB i wydajność

  • Przełącz na oxmysql oczekuj na API, zapisuj wsadowo, unikaj zapytań per-tick.
  • Indeksuj często wyszukiwane kolumny (obywatel, identyfikator, płyta).
  • Zachowaj w pamięci podręcznej konfiguracje/listy cen; wyeksportuj je raz do klientów, a następnie aktualizuj w przypadku zmiany.
  • Używać GlobalState oszczędnie; unikaj aktualizacji w pętli.

9) Typowe pułapki i podręcznik debugowania

  • Zarozumiały PobierzCoreObject istnieje na QBOX → nie; użyj eksporty.qbx_core:*.
  • Po migracji do QBOX połączenia zwrotne nigdy nie powracają → Wywołania zwrotne ESX/QB nie są zarejestrowane; przełącz na lib.callback.register/await.
  • Semantyka brudnych pieniędzy różnią się → zdecyduj, czy chcesz wybrać przedmiot, konto czy alternatywny portfel i ustandaryzuj go w swoim adapterze.
  • Założenia dotyczące mieszanych zapasów → znormalizować na ox_inventory.
  • Problemy z zamówieniem początkowymoxmysqlox_lib → framework → twoje zasoby.
  • Dryf metadanych pojazdu → upewnij się, że kolumny JSON i formaty tablic pasują do docelowej struktury.

10) Najlepsze praktyki fxmanifest.lua

fx_version 'cerulean' gra 'gta5' lua54 'tak' shared_scripts { '@ox_lib/init.lua', 'bridge.lua', 'config.lua' } client_scripts { 'client/*.lua' } server_scripts { '@oxmysql/lib/MySQL.lua', 'server/*.lua' } escrow_ignore { 'bridge.lua', 'config.lua' } -- zależności (wybierz, których używasz): ox_lib, oxmysql, ox_inventory, qb-core LUB qbx_core LUB es_extended
  • Ogłosić Lua 5.4 (lua54 'tak'').
  • Trzymać escrow_ignore minimalne; nigdy nie próbuj ominąć depozytu.

11) Migracja danych: fragmenty kodu SQL (przykłady)

Dostosuj nazwy tabel/kolumn do swojego schematu. Zawsze najpierw uruchamiaj kopię.

Identyfikatory: ESX → QB/QBOX

-- Dodaj citizenid do użytkowników ESX, jeśli ich brakuje ALTER TABLE users ADD COLUMN IF NOT EXISTS citizenid VARCHAR(64); -- Wypełnij przy użyciu deterministycznego generatora lub istniejącej kolumny UPDATE users SET citizenid = LOWER(SUBSTRING(MD5(CONCAT(identifier,'-QB')),1,10)) WHERE citizenid IS NULL; -- Utwórz przejście CREATE TABLE IF NOT EXISTS id_map ( identifier VARCHAR(64) PRIMARY KEY, citizenid VARCHAR(64) NOT NULL UNIQUE ); INSERT IGNORE INTO id_map(identifier, citizenid) SELECT identifier, citizenid FROM users WHERE citizenid IS NOT NULL;

Konta/Pieniądze

-- Przykład: konwersja sald bankowych ESX na tabelę pieniędzy QB (jeśli schemat QB przechowuje je osobno) INSERT INTO player_money (citizenid, account, amount) SELECT m.citizenid, 'bank', a.money FROM ( SELECT u.citizenid, SUM(CASE WHEN account = 'bank' THEN money ELSE 0 END) AS money FROM user_accounts ua JOIN users u ON u.identifier = ua.identifier GROUP BY u.citizenid ) a JOIN users m ON m.citizenid = a.citizenid ON DUPLICATE KEY UPDATE amount = VALUES(amount);

Pojazdy

-- Normalizuj tablice rejestracyjne do formatu docelowego (przykład: 8 znaków u góry) UPDATE owned_vehicles SET plate = UPPER(LEFT(plate,8)); -- Upewnij się, że kolumny metadanych JSON są prawidłowe UPDATE owned_vehicles SET mods = JSON_MERGE_PATCH('{}', mods) WHERE JSON_VALID(mods) = 0;

12) Adaptery, które można ponownie wykorzystać (wersja startowa)

Wrzuć to do most.lua i rozszerzaj zgodnie ze swoimi potrzebami. Automatycznie wykrywa ESX/QB/QBOX i udostępnia stabilne API.

local M = {}
local fw = 'none'

CreateThread(function()
  if GetResourceState('qbx_core') == 'started' then fw = 'qbx'
  elseif GetResourceState('qb-core') == 'started' then fw = 'qb'
  elseif GetResourceState('es_extended') == 'started' then fw = 'esx' end
end)

function M.framework() return fw end

function M.player(src)
  if fw == 'qbx' then return exports.qbx_core:GetPlayer(src)
  elseif fw == 'qb' then return exports['qb-core']:GetCoreObject().Functions.GetPlayer(src)
  elseif fw == 'esx' then return exports['es_extended']:getSharedObject().GetPlayerFromId(src) end
end

function M.identifier(src)
  local p = M.player(src); if not p then return nil end
  if fw == 'qb' or fw == 'qbx' then
    return p.PlayerData and p.PlayerData.citizenid
  elseif fw == 'esx' then
    return p.identifier
  end
end

function M.hasGroup(src, group)
  if fw == 'qbx' and exports.qbx_core and exports.qbx_core.HasGroup then
    return exports.qbx_core:HasGroup(src, group)
  end
  return false
end

function M.notify(src, msg, ntype)
  if fw == 'qb' then
    TriggerClientEvent('QBCore:Notify', src, msg, ntype or 'primary')
  elseif fw == 'esx' then
    TriggerClientEvent('esx:showNotification', src, msg)
  elseif fw == 'qbx' then
    if exports.qbx_core and exports.qbx_core.Notify then
      exports.qbx_core:Notify(src, msg, ntype or 'info')
    else
      lib.notify(src, { description = msg })
    end
  end
end

return M

13) Ostateczne listy kontrolne (skopiuj i wyślij)

A) Odkrywanie i wstępny lot

  • Utwórz migawkę bazy danych/plików; utwórz serwer przejściowy
  • Przypnij artefakty i wersje zasobów; zdefiniuj kolejność początkową
  • Wymieniono zależności ekwipunku/celu/menu
  • Wybierz strategię identyfikacji (przejście dla pieszych z identyfikatorem obywatela)

B) Audyt kodu

  • Grep dla ESX/QB/QBOX/ox_*/mysql‑async
  • Wypisz wszystkie wezwania dotyczące pieniędzy/zapasów/pracy/obowiązków
  • Wyświetlanie listy wywołań zwrotnych i zdarzeń serwera/klienta

C) Mapowanie i projektowanie

  • Wybierz powierzchnię adaptera (gracz, identyfikatory, pieniądze, przedmioty, powiadomienia, wywołania zwrotne)
  • Wybierz strategię dotyczącą brudnych pieniędzy (konto, przedmiot, alternatywny portfel)
  • Preferuj ox_lib/ox_inventory/ox_target

D) Migracja danych

  • Zbuduj przejście dla pieszych dla obywateli
  • Konwersja kont/pieniędzy
  • Normalizacja metadanych i tablic rejestracyjnych pojazdów
  • Przełącz się na wywołania oczekujące Oxmysql

E) Testowanie QA

  • Bezpieczeństwo zdarzeń: typy/granice/własność/czasy odnowienia
  • Wywołania zwrotne: zwracanie wartości pod obciążeniem
  • Zachowano metadane inwentarza
  • Logika zadań/obowiązków/grupy pasuje do projektu

F) Wydanie i wycofanie

  • Wydanie tagu; dziennik zmian
  • Zachowaj migawkę przed migracją przez 7–14 dni
  • Monitoruj błędy/opóźnienia; indeksuj gorące zapytania

14) FAQ (ze schematem JSON‑LD)

P: Czy mogę przenieść skrypty QBCore do QBOX bez konieczności całkowitego przepisania?
A: Z adapterami i ox_lib wywołania zwrotne, większość skryptów wymaga jedynie ponownego mapowania wywołań.

P: Co mam zrobić z czarnymi/brudnymi pieniędzmi?
A: Standaryzacja w adapterze: ESX → czarne_pieniądze Konto; QB → przedmiot lub konto dodatkowe; QBOX → przedmiot lub portfel alternatywny (np. kryptowaluty). Stosuj jedną strategię w całym projekcie.

P: Dlaczego po przejściu na wersję QBOX połączenia zwrotne zostają zawieszone?
A: Wywołania zwrotne ESX/QB nie będą działać na QBOX. Użyj lib.callback.register/await.

P: Jaki jest najlepszy sposób na migrację mysql‑async?
A: Zastąp przez oxmysql oczekuj na API; usuń piramidy wywołań zwrotnych.

P: Jak przekonwertować qb‑target na ox_target?
A: Zastąp wywołania API addBoxZone/Entity w stosunku jeden do jednego; ładunki zdarzeń pozostaną podobne. Zachowaj stabilne nazwy celów.


15) Wizualizacje (sugestie)

  • Schemat blokowy (Odkryj → Mapa → Adaptacja → Migracja bazy danych → Testowanie → Wydanie)
  • Schemat adapterów: Skrypt → Most → Struktura (ESX/QB/QBOX)
  • Tabela Rosetta: dołączone powyżej (eksportuj jako plik CSV do pobrania)
[Odkryj] → [Interfejsy API map] → [Adapter zapisu] → [Migracja bazy danych] → [Wzmocnienie] → [Zapewnienie jakości] → [Wydanie]

  • Szanuj licencje (MIT/GPL/NC). Nie ominąć depozyt lub zaciemnianie.
  • Konwertuj tylko te skrypty, które własny lub uzyskać pozwolenie na adaptację.

17) Materiały do pobrania i szybki przewodnik

Możesz również użyć tego konwertera (nie testowałem):

https://github.com/sledgehamm3r/ESX-QBCore-Converter


28) Następne kroki

  • Upuść most.lua do swojego zasobu i zacznij konwertować najpierw te skrypty, które mają największą wartość.
  • Standaryzować na ox_lib + ox_inventory + ox_target + oxmysql pozostać niezależnym od ram.
  • Korzystaj z list kontrolnych podczas przeglądu i wydania.

Przeczytaj także Migracja SQL i identyfikatorów: steam/license → citizenid i konta → pieniądze (ESX → QBCore/QBOX)

Łukasz
Łukasz

Nazywam się Luke, jestem graczem i uwielbiam pisać o FiveM, GTA i grach RPG. Prowadzę społeczność RPG i mam około 10 lat doświadczenia w administrowaniu serwerami.

Artykuły: 436