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.
-- 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
endDans le manifest, chargez-le avant les fichiers qui l'utilisent :
server_scripts {
'bridge.lua',
'server.lua',
}Le script se lit ensuite comme ceci, et ne mentionne jamais un framework :
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 →