Konvertiere ein ESX-Skript zu QBCore (und zurück): Funktionskarte und Bridge

Portiere ein FiveM-Skript zwischen ESX und QBCore: eine Tabelle der häufigen Aufrufe (Spieler, Geld, Job, Gegenstände, Benachrichtigungen, Callbacks) und eine Bridge-Datei, die beide unterstützt.

Du hast ein Skript für ESX geschrieben, und dein Server läuft QBCore, oder umgekehrt. Das meiste des Skripts ist einfach Lua und natives, das sich nicht ändert. Nur die Framework-Aufrufe tun es, und es gibt weniger davon als du denkst. Dieser Artikel gibt dir eine Karte davon, und zeigt dir dann, wie man sie in einer Bridge-Datei isoliert.

Was bleibt und was ändert sich

Native, NUI, deine eigenen Events, Schleifen, Ziele und Menüs funktionieren auf jedem Framework. Was sich ändert ist eine kurze Liste:

  • wie du das Framework-Objekt bekommst
  • wie du einen Spieler bekommst
  • Geld, Jobs und Gegenstände
  • Benachrichtigungen
  • usbare Gegenstände und Callbacks
  • die Datenbanktabellen für Spieler

Suche das Skript nach ESX. und xPlayer und jeder Hit ist etwas zu konvertieren.

Funktionskarte

Aufgabe ESX Legacy QBCore
Besorge das Objekt ESX = exports['es_extended']:getSharedObject() local QBCore = exports['qb-core']:GetCoreObject()
Besorge einen Spieler (Server) ESX.GetPlayerFromId(src) QBCore.Functions.GetPlayer(src)
Spieler-Identifier xPlayer.identifier Player.PlayerData.citizenid
Bargeldbestand xPlayer.getMoney() Player.PlayerData.money.cash
Geld hinzufügen xPlayer.addMoney(n) Player.Functions.AddMoney('cash', n)
Geld entfernen xPlayer.removeMoney(n) Player.Functions.RemoveMoney('cash', n)
Bank hinzufügen xPlayer.addAccountMoney('bank', n) Player.Functions.AddMoney('bank', n)
Bank entfernen xPlayer.removeAccountMoney('bank', n) Player.Functions.RemoveMoney('bank', n)
Jobname xPlayer.job.name Player.PlayerData.job.name
Job-Grad xPlayer.job.grade Player.PlayerData.job.grade.level
Gegenstand hinzufügen xPlayer.addInventoryItem(name, n) Player.Functions.AddItem(name, n)
Gegenstand entfernen xPlayer.removeInventoryItem(name, n) Player.Functions.RemoveItem(name, n)
Gegenstands-Anzahl xPlayer.getInventoryItem(name).count Player.Functions.GetItemByName(name) (nil wenn keine, dann .amount)
Usbar-Gegenstand ESX.RegisterUsableItem(name, function(src) end) QBCore.Functions.CreateUseableItem(name, function(src, item) end)
Benachrichtigung (Client) ESX.ShowNotification(msg) QBCore.Functions.Notify(msg, 'success')
Benachrichtigung (Server) xPlayer.showNotification(msg) TriggerClientEvent('QBCore:Notify', src, msg, 'success')
Spieler-Daten (Client) ESX.GetPlayerData() QBCore.Functions.GetPlayerData()
Spieler-geladen-Event esx:playerLoaded QBCore:Client:OnPlayerLoaded
Job-geändert-Event esx:setJob QBCore:Client:OnJobUpdate
Server-Callback ESX.RegisterServerCallback QBCore.Functions.CreateCallback

Zwei Details verwirren Menschen. Geldtypen: ESX hat money für Bargeld und bank, QBCore verwendet 'cash' und 'bank' als das erste Argument. Und der Grad: ESX gibt eine einfache Zahl, QBCore eine Tabelle, also job.grade.level.

Callbacks, die jedes zweite Skript verwendet, werden detailliert verglichen in Server-Callbacks auf ESX, QBCore und ox_lib.

Die Datenbank

Die Spieler-Tabellen unterscheiden sich, daher braucht jede SELECT oder UPDATE auf ihnen eine Änderung:

ESX QBCore
Spieler users players
Spieler-Schlüssel identifier (ein license:-String) citizenid
Fahrzeuge owned_vehicles player_vehicles

Ein Skript, das seine eigenen Daten speichert, mit seinen eigenen Tabellen, funktioniert normalerweise weiterhin, solange es die Zeilen mit einem Wert schlüsselt, den du von jedem Framework bekommen kannst. Den License-Identifier dafür zu verwenden funktioniert auf beiden.

QBox

QBox ist näher an QBCore als an ESX. Sein Kern ist qbx_core, es behält eine Kompatibilitätsschicht für exports['qb-core']:GetCoreObject() und sein Inventar ist ox_inventory. Ein Skript, das zu QBCore konvertiert wurde, läuft normalerweise auf QBox mit wenigen Änderungen, abgesehen von Inventar-Aufrufen.

Der Bridge-Datei-Ansatz

Wenn das Skript auf beiden laufen muss, verteile es nicht mit if ESX then ... else ... end. Lege jeden Framework-Aufruf in eine Datei und lasse den Rest des Skripts diese Datei aufrufen.

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

Im Manifest lade es vor den Dateien, die es verwenden:

lua
server_scripts {
    'bridge.lua',
    'server.lua',
}

Das Skript liest sich dann so und erwähnt nie ein Framework:

lua
RegisterNetEvent('my_script:pay', function()
    local src = source
    local job = Bridge.GetJob(src)
    if job == 'mechanic' then
        Bridge.AddCash(src, 100)
    end
end)

Füge eine Client-Bridge für Benachrichtigungen und Spieler-Daten auf die gleiche Weise hinzu. Wenn du ein neues Framework hinzufügst, wie QBox mit qbx_core, fügst du einen Zweig in der Bridge hinzu, und das Skript bleibt wie es ist.

Denk daran, dass eine Bridge nur funktioniert, wenn das Framework zuerst startet. Lege ensure es_extended oder ensure qb-core über dem Skript in server.cfg ein und lese ESX ist nil, falls das Objekt nil zurückkommt.

Checkliste

Symptom Behebung
attempt to index a nil value (global 'ESX') bei QBCore Ein ESX-Aufruf bleibt; ersetze ihn aus der obigen Karte
Geld oder Job immer nil Du liest PlayerData auf ESX oder xPlayer.job auf QBCore
Gegenstands-Anzahl-Fehler auf QBCore GetItemByName gibt nil zurück, wenn der Spieler keine hat; überprüfe es zuerst
Falsche Tabelle in einer Abfrage users und identifier auf ESX, players und citizenid auf QBCore
Callback gibt nichts zurück Verwende die passenden Register- und Trigger-Aufrufe für das Framework
Braucht beide Frameworks Verschiebe jeden Framework-Aufruf in eine Bridge-Datei

Kurze Antworten

Kann ich jedes ESX-Skript zu QBCore konvertieren?

Skripte, die das Framework nur für Spieler, Geld, Jobs, Gegenstände und Benachrichtigungen verwenden, konvertieren sich gut. Skripte, die um Framework-spezifische Ressourcen wie esx_society oder qb-management herum gebaut sind, müssen auch diese Teile umgeschrieben werden.

Ändert sich die Datenbank, wenn ich Framework wechsle?

Ja. ESX speichert Spieler in users mit einem identifier, und QBCore in players mit einer citizenid. Abfragen und Tabellennamen im Skript müssen dem Framework folgen, das du laufen lässt.

Ist eine Bridge-Datei besser als Konvertierung?

Wenn du das Skript auf beiden Frameworks brauchst, ja: Du änderst eine Datei, nicht das ganze Skript. Wenn du nur ein Framework laufen lässt, konvertiere einmal und verwerfe den anderen Zweig.

Scripts ohne dieses Problem

Item Creator V2Erstelle nutzbare Items mit Animationen, Props, Effekten und mehr — ganz ohne Code.Script ansehen →Shop CreatorBau einen Shop in unter einer Minute — Besitzer, Angestellte, Tresore und Überfälle inklusive.Script ansehen →Advanced BoostingFahrzeug-Boosting per Tablet: Aufträge von Klasse D bis S+, Crews und eine Live-Warteschlange.Script ansehen →

Weiterlesen