Convertir un script ESX en QBCore (et inversement) : correspondance des fonctions et pont

Portez un script FiveM entre ESX et QBCore : un tableau des appels courants (joueur, argent, job, objets, notifications, callbacks) et un fichier pont qui supporte les deux.

Vous avez un script écrit pour ESX, et votre serveur exécute QBCore, ou l'inverse. La plupart du script est du Lua simple et des natives qui ne changent pas. Seulement les appels du framework changent, et il y en a moins que vous ne l'attendez. Cet article vous en donne une correspondance, puis montre comment les isoler dans un fichier pont.

Ce qui reste et ce qui change

Les natives, NUI, vos propres événements, boucles, cibles et menus fonctionnent sur n'importe quel framework. Ce qui change est une courte liste :

  • comment vous obtenez l'objet framework
  • comment vous obtenez un joueur
  • argent, jobs et objets
  • notifications
  • objets utilisables et callbacks
  • les tables de base de données pour les joueurs

Cherchez ESX. et xPlayer dans le script, et chaque résultat est quelque chose à convertir.

Table de correspondance des fonctions

Tâche ESX Legacy QBCore
Obtenir l'objet ESX = exports['es_extended']:getSharedObject() local QBCore = exports['qb-core']:GetCoreObject()
Obtenir un joueur (serveur) ESX.GetPlayerFromId(src) QBCore.Functions.GetPlayer(src)
Identifiant du joueur xPlayer.identifier Player.PlayerData.citizenid
Solde d'argent xPlayer.getMoney() Player.PlayerData.money.cash
Ajouter argent xPlayer.addMoney(n) Player.Functions.AddMoney('cash', n)
Retirer argent xPlayer.removeMoney(n) Player.Functions.RemoveMoney('cash', n)
Banque ajouter xPlayer.addAccountMoney('bank', n) Player.Functions.AddMoney('bank', n)
Banque retirer xPlayer.removeAccountMoney('bank', n) Player.Functions.RemoveMoney('bank', n)
Nom du job xPlayer.job.name Player.PlayerData.job.name
Grade du job xPlayer.job.grade Player.PlayerData.job.grade.level
Ajouter objet xPlayer.addInventoryItem(name, n) Player.Functions.AddItem(name, n)
Retirer objet xPlayer.removeInventoryItem(name, n) Player.Functions.RemoveItem(name, n)
Compter objet xPlayer.getInventoryItem(name).count Player.Functions.GetItemByName(name) (nil si aucun, puis .amount)
Objet utilisable ESX.RegisterUsableItem(name, function(src) end) QBCore.Functions.CreateUseableItem(name, function(src, item) end)
Notifier (client) ESX.ShowNotification(msg) QBCore.Functions.Notify(msg, 'success')
Notifier (serveur) xPlayer.showNotification(msg) TriggerClientEvent('QBCore:Notify', src, msg, 'success')
Données du joueur (client) ESX.GetPlayerData() QBCore.Functions.GetPlayerData()
Événement joueur chargé esx:playerLoaded QBCore:Client:OnPlayerLoaded
Événement job changé esx:setJob QBCore:Client:OnJobUpdate
Callback serveur ESX.RegisterServerCallback QBCore.Functions.CreateCallback

Deux détails dérangent les gens. Types d'argent : ESX a money pour l'argent et bank, QBCore utilise 'cash' et 'bank' comme premier argument. Et le grade : ESX donne un nombre simple, QBCore une table, donc job.grade.level.

Les callbacks, que chaque deuxième script utilise, sont comparés en détail dans callbacks serveur sur ESX, QBCore et ox_lib.

La base de données

Les tables de joueurs diffèrent, donc n'importe quel SELECT ou UPDATE sur eux a besoin d'un changement :

ESX QBCore
Joueurs users players
Clé du joueur identifier (une chaîne license:) citizenid
Véhicules owned_vehicles player_vehicles

Un script qui stocke ses propres données, avec ses propres tables, continue généralement de fonctionner, tant qu'il indexe les lignes sur une valeur que vous pouvez obtenir d'un des deux frameworks. Utiliser l'identifiant license pour cela fonctionne sur les deux.

QBox

QBox est plus proche de QBCore que d'ESX. Son core est qbx_core, il garde une couche de compatibilité pour exports['qb-core']:GetCoreObject(), et son inventaire est ox_inventory. Un script converti en QBCore s'exécute généralement sur QBox avec peu de changements, à part les appels d'inventaire.

L'approche du fichier pont

Si le script doit s'exécuter sur les deux, ne le parsemez pas avec if ESX then ... else ... end. Mettez chaque appel du framework dans un fichier, et faites en sorte que le reste du script appelle ce fichier.

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

Dans le manifest, chargez-le avant les fichiers qui l'utilisent :

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

Le script se lit ensuite comme ceci, et ne mentionne jamais un 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)

Ajoutez un pont client pour les notifications et les données du joueur de la même façon. Quand vous ajoutez un nouveau framework, comme QBox avec qbx_core, vous ajoutez une branche dans le pont, et le script reste tel qu'il est.

Rappelez-vous qu'un pont fonctionne seulement si le framework démarre en premier. Mettez ensure es_extended ou ensure qb-core au-dessus du script dans server.cfg, et lisez ESX est nil si l'objet revient nil.

Checklist

Problème Solution
attempt to index a nil value (global 'ESX') sur QBCore Un appel ESX reste ; remplacez-le depuis la correspondance ci-dessus
L'argent ou le job toujours nil Vous lisez PlayerData sur ESX, ou xPlayer.job sur QBCore
Erreurs de comptage d'objets sur QBCore GetItemByName retourne nil quand le joueur n'en a aucun ; vérifiez d'abord
Mauvaise table dans une requête users et identifier sur ESX, players et citizenid sur QBCore
Le callback ne retourne rien Utilisez les appels register et trigger correspondants pour le framework
Besoin des deux frameworks Déplacez chaque appel du framework dans un fichier pont

Réponses rapides

Puis-je convertir n'importe quel script ESX en QBCore ?

Les scripts qui utilisent seulement le framework pour les joueurs, l'argent, les jobs, les objets et les notifications convertissent bien. Les scripts construits autour de ressources spécifiques au framework, comme esx_society ou qb-management, ont besoin que ces parties soient aussi réécrites.

La base de données change-t-elle quand je change de framework ?

Oui. ESX stocke les joueurs dans users avec un identifier, et QBCore dans players avec un citizenid. Les requêtes et les noms de tables dans le script doivent suivre le framework que vous exécutez.

Un fichier pont est-il mieux que la conversion ?

Si vous avez besoin du script sur les deux frameworks, oui : vous changez un fichier, pas le script entier. Si vous exécutez seulement un framework, convertissez une fois et abandonnez l'autre branche.

Des scripts sans ce problème

Item Creator V2Créez des items utilisables avec animations, props, effets et plus — sans écrire une ligne de code.Voir le script →Shop CreatorCréez un magasin en moins d’une minute — propriétaires, employés, coffres et braquages inclus.Voir le script →Advanced BoostingDu boosting de véhicules piloté par tablette : contrats de classe D à S+, crews et file d’attente en direct.Voir le script →

À lire aussi