Sichern Sie sich heute 20%. Verwenden Sie beim Bezahlvorgang den Code WELCOME. WILLKOMMEN

Converting FiveM Scripts – ESX, QBCore, QBOX (Frame…

Dies ist ein Code-First-Leitfaden zur einfachen Konvertierung von FiveM-Skripten ohne Schnickschnack, der Ihnen genau zeigt, wie Sie Konvertieren Sie FiveM-Skripte zwischen ESX, QBCore, QBOX (qbx_core) und Framework-agnostischen (eigenständigen) Setups. Sie erhalten dreiseitige API-Zuordnungen, Adaptercode, SQL-Migrationsschritte (mysql-async → oxmysql), QBOX-Spezifikationen, Test-Checklisten und Tipps zur Produktionshärtung.


TL;DR – Migration in 10 Schritten

  1. Momentaufnahme und Staging: DB/Dateien sichern. Starten Sie einen lokalen Testserver mit dem Zielframework.
  2. Abhängigkeiten identifizieren: Inventar, Ziel, Menü/UI, Rückrufe, DB-Ebene, Kern Zugang.
  3. Pin-Versionen & Bestellung: oxmysql → ox_lib → Framework (es_extended / qb-core / qbx_core) → Ihre Ressourcen.
  4. Lesen Sie den Codepfad: Finden Sie alle Spieler-, Geld-, Job-/Aufgaben-, Inventar-, Rückruf-/Ereignis- und DB-Anrufe.
  5. Karten-APIs: Verwenden Sie die folgenden Rosetta-Tabellen, um ESX ↔ QBCore ↔ QBOX zuzuordnen.
  6. Überbrücken Sie es: Fügen Sie einen bridge.lua Adapter, der das Framework automatisch erkennt und Anrufe normalisiert.
  7. Rückrufe konvertieren: ESX/QB-Rückrufe → QBOX/ox_lib lib.callback.* bei Bedarf.
  8. Datenbank migrieren: Verschieben Sie Kennungen, Konten, Artikel, Fahrzeuge; wechseln Sie zu oxmysql *.erwarten Stil.
  9. Ereignisse härten: Bestätigen Quelle, Grenzen, Gruppen/Jobs, Eigentum; vertraue niemals dem Client.
  10. Qualitätssicherung und Veröffentlichung: Führen Sie die Checklisten aus: Tag, Änderungsprotokoll und Rollback-Plan.

Sind Sie ein Entwickler, der nach einer Adapterlösung sucht? Schauen Sie sich hier unser kostenloses Adapterskript an


1) Frameworks 101: ESX vs. QBCore vs. QBOX vs. Standalone

Architekturübersicht

KategorieESXQBCoreQBOX
Architektur/Core-Zugriffexports['es_extended']:getSharedObject()ESXexports['qb-core']:GetCoreObject()QBCoreKein globales Kernobjekt; verwenden exports.qbx_core:* für Spieler, Gruppen und Benachrichtigungen
SpielerobjektESX.GetPlayerFromId(src)xPlayerQBCore.Functions.GetPlayer(src)Spielerexports.qbx_core:GetPlayer(src)Spieler mit Spielerdaten
KennungenHistorisch Kennung (Lizenz/Steam)Bürger-ID als PrimärschlüsselBürger-ID als Primärschlüssel
Geld HandhabungxPlayer.addMoney() / `addAccountMoney('bank''Schwarzgeld')``Player.Functions.AddMoney('Bargeld'
Berufe & PflichtenxPlayer.job.name, .Job.GradePlayer.PlayerData.job.name, .Klassenstufe, Im DienstJob-/Gruppenhelfer über exports.qbx_core:* (Gruppenkontrollen, Dienstplaner)
InventarESX-Standard / ox_inventory / qb-inventar (empfohlen: ox_inventory)qb-inventar / ox_inventoryox_inventory empfohlen
RückrufeESX.RegisterServerCallback / ESX.TriggerServerCallbackQBCore.Functions.CreateCallback / TriggerCallbackBevorzugen ox_lib Rückrufe (lib.callback.register/await) oder QBOX-Exporte
DatenbankebeneAlt: mysql-async → Jetzt: oxmysql (MySQL.query.await, MySQL.update.await)oxmysqloxmysql
Benutzeroberfläche – BenachrichtigungenESX-BenachrichtigungQB-BenachrichtigungQBOX Helfer benachrichtigen oder lib.notify
UI – Menüsesx_menu_default / ox_lib:registerContextqb-menü / ox_lib:registerContextox_lib:registerContext / lib.inputDialog
UI – Zielsystemesx_target / ox_zielqb-ziel / ox_zielox_ziel empfohlen

Wo sich QBOX unterscheidet

  • Ressourcenname und Exporte: qbx_core (NEIN GetCoreObject).
  • Stützt sich auf ox_lib (Rückrufe, Benachrichtigungen) und oxmysql standardmäßig.
  • Integrierte Funktionen für mehrere Charaktere/Warteschlangen/Gruppen; eigensinnige Helfer für Jobs/Aufgaben.

FiveM Frameworks: QBCore vs. ESX

2) Preflight: Umgebung und Werkzeuge

  • Server: aktuell FXServer Artefakte, Lua 5.4, CFX sicherstellen Befehl
  • Befehl: stellen Sie Oxmysql sicherStellen Sie ox_lib sicherRahmen gewährleistenStellen Sie sicher, dass Ihre Ressource
  • Editor: VS Code + Lua LS, Stift; optional ripgrep für schnelle Musterscans
  • Versuchsaufbau: sauberer Datenbank-Snapshot; ausführliche Protokollierung; kleiner Datensatz
  • Suchmuster Sie verwenden:
    • ESX. xPlayer. QBCore. Spielerdaten qbx_core exports.ox_inventory mysql%-async MySQL.

3) Rosetta Stone: ESX ↔ QBCore ↔ QBOX (Dreiwege-Mapping)

Benutzerfreundliche Referenz kopieren und einfügen. Verwenden Sie sie, um Anrufe zu ersetzen oder Ihren Adapter zu verkabeln.

Kern & Spieler

KonzeptESXQBCoreQBOX
Holen Sie sich den Kernexports['es_extended']:getSharedObject()exports['qb-core']:GetCoreObject()(n. z. – Exporte verwenden)
Spieler holen (Quelle)ESX.GetPlayerFromId(src)QBCore.Functions.GetPlayer(src)exports.qbx_core:GetPlayer(src)
Erhalten Sie per Bürger-ID(benutzerdefinierte Abfrage)QBCore.Functions.GetPlayerByCitizenId(id)exports.qbx_core:GetPlayerByCitizenId(id) (falls vorhanden)

Kennungen

KonzeptESXQBCoreQBOX
PrimärKennung (Lizenz/Steam)Bürger-IDBürger-ID
ZebrastreifenTisch id_map(Kennung, Bürger-ID)DasselbeDasselbe

Geld

AktionESXQBCoreQBOX
Bargeld hinzufügenxPlayer.addMoney(a)Player.Functions.AddMoney('Bargeld', a)Player.PlayerData.money.cash += a (über Adapter + Speichern)
Bank hinzufügenxPlayer.addAccountMoney('bank', a)Player.Functions.AddMoney('bank', a)Player.PlayerData.money.bank += a (Adapter + Speichern)
Schmutzig hinzufügenxPlayer.addAccountMoney('schwarzes_Geld', a)Artikel oder zusätzliches Konto (serverdefiniert)Karte zu Artikel/Alt-Wallet (zB, Krypto) (Adapterauswahl)

Jobs, Pflichten, Gruppen

KonzeptESXQBCoreQBOX
Stellenanzeige lesenxPlayer.job.name, .GradPlayer.PlayerData.job.name, .KlassenstufeSpieler.Spielerdaten.Job.* + Gruppenhelfer
Im Dienst(variiert)Player.PlayerData.job.ondutySetJobDuty/Gruppenhelfer über Exporte
Gruppenprüfung(hinzufügen Auf)(hinzufügen Auf)exports.qbx_core:HasGroup(src, group) (Beispiel)

Inventar

AktionESXQBCoreQBOX
Artikel hinzufügenxPlayer.addInventoryItem(n, c)Player.Functions.AddItem(n, c, ...)bevorzugen ox_inventory Export über Adapter
ox_inventoryexports.ox_inventory:*exports.ox_inventory:*exports.ox_inventory:*

Rückrufe

KonzeptESXQBCoreQBOX
Server registrierenESX.RegisterServerCallbackQBCore.Functions.CreateCallbacklib.callback.register (ox_lib)
Client-TriggerESX.TriggerServerCallbackQBCore.Functions.TriggerCallbacklib.callback.await

DB-Schicht

KonzeptESX/QB (alt)oxmysql (Ziel)
BringenMySQL.Async.fetchAll(sql, params, cb)lokale Zeilen = MySQL.query.await(sql, {p1, ...})
AktualisierenMySQL.Async.execute(sql, params, cb)lokales aff = MySQL.update.await(sql, {p1, ...})

UI / Benachrichtigen / Ziel

KonzeptESXQBCoreQBOX
BenachrichtigenESX.ShowNotification(msg)QBCore.Functions.Notify(msg, Typ)exports.qbx_core:Benachrichtigen(...) oder lib.notify({...})
Speisekarte(variiert)qb-menüox_lib:registerContext / Eingänge
Ziel(hinzufügen Auf)qb-zielox_ziel

Tipp: favorisieren ox_lib, ox_inventory, ox_ziel um über Frameworks hinweg neutral zu bleiben.


4) Tutorial A – ESX → QBCore (praktisch)

Ziel: Konvertieren Sie eine einfache Shop-Ressource von ESX zu QBCore.

Schritt 1 – Abhängigkeiten

  • Sicherstellen oxmysql, ox_lib, qb-kern werden gestartet.
  • Wenn das Skript ESX-Inventar verwendet, migrieren Sie zu ox_inventory (empfohlen) oder dem QB-Inventar zuordnen.

Schritt 2 – Framework erkennen und eine Brücke hinzufügen

Erstellen bridge.lua um Spieler/Geld/Inventar zu normalisieren:

-- 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

Schritt 3 – Rückrufe konvertieren

  • ESX → QB: ersetzen ESX.RegisterServerCallback mit QBCore.Functions.CreateCallback.
  • Client-Anwendungen QBCore.Functions.TriggerCallback.
-- 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 (callback)
if GetResourceState('qb-core') == 'started' then
  local QBCore = exports['qb-core']:GetCoreObject()
  QBCore.Functions.TriggerCallback('shop:getPrice', function(price)
    print('price', price)
  end, 'bread')
else
  local price = lib.callback.await('shop:getPrice', false, 'bread')
  print('price', price)
end

Schritt 4 – Geld- und Inventarpfade

  • Ersetzen xPlayer.addAccountMoney mit Player.Functions.AddMoney (für QB) oder Adapter.
  • Standardisieren Sie alle Bestandsänderungen über den Adapter.

Schritt 5 – Ereignisse (serverseitige Sicherheit)

RegisterNetEvent('shop:buy', Funktion(Artikel, Betrag) lokale Quelle = Quelle wenn Typ(Artikel) ~= 'Zeichenfolge' oder Typ(Betrag) ~= 'Zahl' dann returniere Ende wenn Betrag < 1 oder Betrag > 10 dann returniere Ende lokales p = bridge.getPlayer(Quelle) wenn nicht p dann returniere Ende lokaler Preis = 100 * Betrag wenn nicht bridge.removeMoney(Quelle, 'Bargeld', Preis) dann returniere Ende bridge.addItem(Quelle, Artikel, Betrag) bridge.notify(Quelle, ('Gekauft %dx %s'):Format(Betrag, Artikel), 'Erfolg') Ende)

Schritt 6 – DB-Migration (Kennungen, Konten)

  • Erstellen Sie einen Zebrastreifen id_map(Kennung, Bürger-ID).
  • Bevölkern Bürger-ID für QB von ESX Benutzer Tabelle über Auswahlregel (vorhandene Spalte oder generiert).
-- Beispiel: Erstellen Sie einen Crosswalk und füllen Sie ihn nach (passen Sie ihn an Ihr Schema an) CREATE TABLE IF NOT EXISTS id_map (Bezeichner VARCHAR(64) PRIMARY KEY, Bürger-ID VARCHAR(64) NOT NULL UNIQUE); -- Angenommen, Sie haben neue Bürger-IDs generiert und diese zuvor gespeichert INSERT IGNORE INTO id_map(Bezeichner, Bürger-ID) SELECT u.Bezeichner, u.Bürger-ID FROM Benutzer u WHERE u.Bürger-ID IS NOT NULL;

mysql‑async → oxmysql

-- before (mysql-async)
MySQL.Async.fetchAll('SELECT * FROM users WHERE identifier = @id', {['@id'] = identifier}, function(rows) ... end)

-- after (oxmysql)
local rows = MySQL.query.await('SELECT * FROM users WHERE identifier = ?', { identifier })

Schritt 7 – Qualitätssicherung

  • Spawnen Sie Gegenstände, kaufen/verkaufen Sie, stellen Sie sicher, dass sich die Salden korrekt ändern.
  • Überprüfen Sie, ob Rückrufe unter Last zurückgegeben werden.
  • Überprüfen Sie, ob die Inventarmetadaten erhalten bleiben.

5) Tutorial B – QBCore → ESX (praktisch)

Wichtige Vorbehalte:

  • ESX verwendet Konten für Bank/Schwarzgeld. Port QBs schmutziges Geld Artikel (falls verwendet) zum ESX-Konto oder behalten Sie es als Element.
  • Das Stellenschema ist unterschiedlich (Klasse vs. Niveau). Planen Sie sorgfältig.

Beispiel: Money-Mapping per Adapter

-- 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

Beispiel: Callback-Konvertierung (Server)

if GetResourceState('es_extended') == 'started' then
  local ESX = exports['es_extended']:getSharedObject()
  ESX.RegisterServerCallback('garage:getVehicles', function(source, cb)
    local src = source
    local p = bridge.getPlayer(src)
    local rows = MySQL.query.await('SELECT * FROM owned_vehicles WHERE owner = ?', { p.identifier })
    cb(rows)
  end)
end

Test-Checkliste

  • Stellenangebote/Beförderungen bleiben bestehen.
  • Bankguthaben/unsaubere Guthaben mutieren wie erwartet.
  • Fahrzeugbesitz und Kennzeichenformate validiert.

6) Tutorial C — QBCore ↔ QBOX (Hands-on)

QBCore → QBOX

  • Ersetzen QBCore.Funktionen.* mit exports.qbx_core:* oder ox_lib Rückrufe.
  • Spieler: QBCore.Functions.GetPlayer(src)exports.qbx_core:GetPlayer(src).
  • Benachrichtigen: QBCore.Functions.Notifyexports.qbx_core:Benachrichtigen oder lib.notify.
  • Aufgaben/Gruppen: QBOX-Exporte nutzen (SetJobDuty, HasGroup, usw.).

QBOX → QBCore

  • Ersetzen exports.qbx_core:* mit QBCore.Funktionen.* Äquivalente oder Ihren Adapter.
  • Führen Sie QB-Rückrufe und Menü-/Zieläquivalente nach Bedarf wieder ein.

Vorher/Nachher-Ausschnitte

-- Vorher (QB notify) QBCore.Functions.Notify('Hallo', 'Erfolg') -- Nachher (QBOX) exports.qbx_core:Notify(source, 'Hallo', 'Erfolg') -- oder lib.notify(source, { title = 'Hallo', description = 'Willkommen', type = 'Erfolg' })
-- Vorher (QB holt Spieler) lokaler Spieler = QBCore.Functions.GetPlayer(src) -- Nachher (QBOX) lokaler Spieler = exports.qbx_core:GetPlayer(src)

7) Tutorial D – Framework → Standalone mit Adaptern

Schreiben Sie Ihre Skripte einmal und führen Sie sie überall aus:

  • Erstellen Sie ein Brücke Bereitstellung einer stabilen API: getPlayer, getIdentifier, Geld hinzufügen/entfernen, Artikel hinzufügen/entfernen, benachrichtigen, hatGruppe, im Dienst, Rückrufe Verpackung.
  • Framework zur Laufzeit erkennen (qbx_coreqb-kernes_extendedkeiner).
  • Verwenden ox_lib für Rückrufe und Benachrichtigungen, wenn kein direkter Framework-Helfer vorhanden ist.

Minimaler Standalone-Fallback

-- 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) Leistung und Sicherheit (Produktionshärtung)

Serverseitige Validierung (Client niemals vertrauen)

  • Bestätigen Typen Und Grenzen bei jeder Veranstaltung.
  • Überprüfen Eigentum, Abklingzeiten, Distanz (falls relevant), Job/Gruppe.
  • Stellen Sie sicher, dass der Betrag nicht ins Minus rutscht, begrenzen Sie die Beträge.
  • Vergleichen Preis serverseitig; vom Client bereitgestellte Gesamtsummen werden nicht akzeptiert.

Veranstaltungsstruktur

  • Verwenden Sie eine Serverereignis pro Aktion; legen Sie den Kunden keine Rohinventar-/Geldfunktionen offen.
  • Bevorzugen Rückrufe für Anforderungs-/Antwortflüsse.

DB & Leistung

  • Wechseln zu oxmysql Warten Sie auf APIs; Batch-Schreibvorgänge; vermeiden Sie Abfragen pro Tick.
  • Indexieren Sie häufig abgefragte Spalten (Bürger-ID, Kennung, Platte).
  • Konfigurations-/Preislisten im Speicher zwischenspeichern; sie einmal an Clients exportieren und dann bei Änderungen vergleichen.
  • Verwenden GlobalState sparsam; vermeiden Sie Hot-Loop-Updates.

9) Häufige Fehler und Debugging-Playbook

  • Angenommen GetCoreObject existiert auf QBOX → das tut es nicht; verwenden exports.qbx_core:*.
  • Rückrufe werden nach der Migration zu QBOX nie wieder angezeigt → ESX/QB-Callbacks werden nicht registriert; wechseln Sie zu lib.callback.register/await.
  • Semantik des schmutzigen Geldes unterscheiden → entscheiden Sie sich für Artikel vs. Konto vs. Alt-Wallet und standardisieren Sie in Ihrem Adapter.
  • Gemischte Bestandsannahmen → normalisieren auf ox_inventory.
  • Probleme mit der Startreihenfolgeoxmysqlox_lib → Rahmen → Ihre Ressourcen.
  • Drift der Fahrzeugmetadaten → Stellen Sie sicher, dass die JSON-Spalten und Plattenformate mit dem Zielframework übereinstimmen.

10) Best Practices für fxmanifest.lua

fx_version 'cerulean' game 'gta5' lua54 'yes' 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' } -- Abhängigkeiten (wählen Sie aus, was Sie verwenden): ox_lib, oxmysql, ox_inventory, qb-core ODER qbx_core ODER es_extended
  • Erklären Lua 5.4 (lua54 'ja').
  • Halten escrow_ignore minimal; versuchen Sie niemals, das Treuhandkonto zu umgehen.

11) Datenmigration: SQL-Snippets (Beispiele)

Passen Sie Tabellen-/Spaltennamen an Ihr Schema an. Führen Sie es immer zuerst auf einer Kopie aus.

Kennungen: ESX → QB/QBOX

- CitizenID zu ESX-Benutzern hinzufügen, falls fehlend ALTER TABLE users ADD COLUMN IF NOT EXISTS citizenid VARCHAR(64); - Mit einem deterministischen Generator oder einer vorhandenen Spalte auffüllen UPDATE users SET citizenid = LOWER(SUBSTRING(MD5(CONCAT(identifier,'-QB')),1,10)) WHERE citizenid IS NULL; - Crosswalk erstellen 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;

Konten/Geld

-- Beispiel: Konvertieren Sie ESX-Bankguthaben in eine QB-Geldtabelle (wenn Ihr QB-Schema diese separat speichert) 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);

Fahrzeuge

-- Kennzeichen auf Zielformat normalisieren (Beispiel: 8 Zeichen höher) UPDATE owned_vehicles SET plate = UPPER(LEFT(plate,8)); -- Sicherstellen, dass JSON-Metadatenspalten gültig sind UPDATE owned_vehicles SET mods = JSON_MERGE_PATCH('{}', mods) WHERE JSON_VALID(mods) = 0;

12) Adapter, die Sie wiederverwenden können (Starter)

Legen Sie dies in bridge.lua und erweitern Sie es nach Ihren Bedürfnissen. Es erkennt ESX/QB/QBOX automatisch und stellt eine stabile API bereit.

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) Abschließende Checklisten (Kopieren und Versenden)

A) Entdeckung und Preflight

  • Snapshot-DB/Dateien; Erstellen eines Staging-Servers
  • Artefakte und Ressourcenversionen anheften; Startreihenfolge festlegen
  • Inventar-/Ziel-/Menüabhängigkeiten aufgelistet
  • Identifikationsstrategie festlegen (Citizenid Crosswalk)

B) Code-Audit

  • Grep für ESX/QB/QBOX/ox_*/mysql‑async
  • Listen Sie alle Geld-/Inventar-/Job-/Pflichtanrufe auf
  • Rückrufe und Server-/Client-Ereignisse auflisten

C) Kartierung und Design

  • Adapteroberfläche auswählen (Player, IDs, Geld, Gegenstände, Benachrichtigungen, Rückrufe)
  • Legen Sie eine Strategie für schmutziges Geld fest (Konto vs. Artikel vs. alternative Geldbörse)
  • Bevorzugen Sie ox_lib/ox_inventory/ox_target

D) Datenmigration

  • Bauen Sie einen CitizenID-Zebrastreifen
  • Konten/Geld umwandeln
  • Normalisieren Sie Fahrzeugmetadaten und Kennzeichen
  • Wechseln Sie zu Oxmysql-Await-Aufrufen

E) QS-Tests

  • Ereignissicherheit: Typen/Grenzen/Eigentum/Abkühlungszeiten
  • Rückrufe: Rückgabewerte unter Last
  • Inventarmetadaten bleiben erhalten
  • Job-/Pflichten-/Gruppenlogik entspricht Design

F) Freigabe und Rollback

  • Tag-Release; Änderungsprotokoll
  • Snapshot vor der Migration 7–14 Tage lang aufbewahren
  • Überwachen Sie Fehler/Latenz; indizieren Sie Hot Queries

14) FAQ (mit JSON‑LD Schema)

F: Kann ich QBCore-Skripte ohne vollständige Neuschreibung auf QBOX portieren?
A: Mit Adaptern und ox_lib Rückrufe, die meisten Skripte benötigen nur eine Neuzuordnung der Anrufe.

F: Was mache ich mit Schwarzgeld/Schmutzgeld?
A: Standardisieren Sie Ihren Adapter: ESX → Schwarzgeld Konto; QB → Artikel oder zusätzliches Konto; QBOX → Artikel oder alternative Wallet (z. B. Krypto). Behalten Sie projektweit eine Strategie bei.

F: Warum bleiben Rückrufe nach dem Wechsel zu QBOX hängen?
A: ESX/QB-Rückrufe werden auf QBOX nicht ausgelöst. Verwenden Sie lib.callback.register/await.

F: Beste Möglichkeit, MySQL-Async zu migrieren?
A: Ersetzen durch oxmysql Warten Sie auf APIs; entfernen Sie Rückrufpyramiden.

F: Wie konvertiere ich qb‑target in ox_target?
A: Ersetzen Sie addBoxZone/Entity-API-Aufrufe eins zu eins; die Ereignisnutzlasten bleiben ähnlich. Halten Sie die Zielnamen stabil.

{ “@context”: “https://schema.org”, “@type”: “FAQPage”, “mainEntity”: [ { “@type”: “Question”, “name”: “Can I port QBCore scripts to QBOX without a full rewrite?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “With adapters and ox_lib callbacks, most scripts need only call remapping.”} }, { “@type”: “Question”, “name”: “What do I do with black/dirty money?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Standardize in your adapter: ESX → black_money account; QB → item or extra account; QBOX → item or alt wallet (e.g., crypto).”} }, { “@type”: “Question”, “name”: “Why do callbacks hang after moving to QBOX?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “ESX/QB callbacks won’t fire on QBOX. Use lib.callback.register/await.”} }, { “@type”: “Question”, “name”: “Best way to migrate mysql-async?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Replace with oxmysql await APIs; remove callback pyramids.”} }, { “@type”: “Question”, “name”: “How do I convert qb-target to ox_target?”, “acceptedAnswer”: {“@type”: “Answer”, “text”: “Replace addBoxZone/Entity API calls one-for-one; event payloads remain similar. Keep target names stable.”} } ] }

15) Visuals (Vorschläge)

  • Flussdiagramm (Entdecken → Zuordnen → Anpassen → Datenbank migrieren → Testen → Freigeben)
  • Adapterdiagramm: Skript → Bridge → Framework (ESX/QB/QBOX)
  • Rosetta-Tabelle: oben enthalten (Export als CSV zum Download)
[Discover] → [Map APIs] → [Write Adapter] → [Migrate DB] → [Harden] → [QA] → [Release]

16) Rechtlich und ethisch

  • Beachten Sie die Lizenzen (MIT/GPL/NC). Nicht Umgehung von Treuhandkonten oder Verschleierung.
  • Konvertieren Sie nur Skripte, die Sie eigen oder die Erlaubnis zur Anpassung haben.

17) Downloads und Kurzanleitung

Sie können auch diesen Konverter verwenden (allerdings nicht getestet):

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


28) Nächste Schritte

  • Lassen Sie die bridge.lua in Ihre Ressource und beginnen Sie zuerst mit der Konvertierung Ihrer Skripte mit dem höchsten Wert.
  • Standardisieren Sie auf ox_lib + ox_inventory + ox_target + oxmysql um rahmenunabhängig zu bleiben.
  • Verwenden Sie die Checklisten während der Überprüfung und Freigabe.

Lesen Sie auch SQL- und Kennungsmigration: Steam/Lizenz → CitizenID und Konten → Geld (ESX → QBCore/QBOX)

Lukas
Lukas

Ich bin Luke, ein Gamer und schreibe gerne über FiveM, GTA und Rollenspiele. Ich betreibe eine Rollenspiel-Community und habe etwa 10 Jahre Erfahrung in der Verwaltung von Servern.

Artikel570