Économisez 20% dès aujourd'hui Utilisez le code BIENVENUE lors du paiement. ACCUEILLIR

Comment migrer ESX → QBCore correctement

Vous souhaitez une migration propre d'ESX vers QBCore sans perte de données ni panne des systèmes centraux. Suivez ce plan. Vous obtiendrez des identifiants stables, des requêtes oxmysql et du code optimisé par ox_lib.

Objectif : déplacer votre serveur d'ESX vers QBCore avec un temps d'arrêt minimal.



Prérequis

  1. Outils
    1. GIT et une branche séparée pour la migration.
    2. MariaDB ou MySQL 8 avec sauvegardes complètes activées.
    3. Un serveur de préparation qui reflète la production.
  2. Artefacts du serveur
    1. Serveur FX mis à jour vers la même version que la production.
    2. QBCore cadre de base et ressources par défaut.
  3. Les bibliothèques que vous utiliserez
    1. oxmysql pour la base de données.
    2. ox_lib pour les rappels, les assistants d'interface utilisateur et les wrappers d'utilitaires.

Étape 1. Élaborez un plan et un point de retour en arrière

  1. Geler les modifications de production. Interrompre les nouvelles installations de scripts et les écritures dans la base de données non nécessaires aux tests.
  2. Sauvegardez l’intégralité de votre vidage de base de données sous forme d’instantané nommé.
  3. Créez une branche dans votre référentiel de serveur et créez un serveur dédié migrer-esx-vers-qbcore bifurquer.
  4. Rédigez un dossier d'exécution. Incluez des commandes pour démarrer et arrêter le serveur de test, restaurer la base de données et exécuter des contrôles d'intégrité.

Étape 2. Construire une base QBCore propre

  1. Déployez une nouvelle base QBCore en phase de test.
  2. Gardez uniquement les éléments essentiels activés. Désactivez les tâches, les inventaires et les scripts personnalisés jusqu'à la fin de la migration de la base de données.
  3. Installez et démarrez d’abord ces ressources
    1. QB-Noyau
    2. véhicules qb ou vos remplacements préférés
    3. oxmysql
    4. ox_lib

Étape 3. Remplacez mysql-async par oxmysql

Si des scripts ESX restants utilisent encore MySQL.AsyncConvertissez les appels vers OxMySQL. Utilisez une fonction simple de recherche et de remplacement avec vérification.

Conversions courantes

-- ESX mysql-async MySQL.Async.fetchAll('SELECT * FROM utilisateurs WHERE identifiant = @id', {['@id'] = identifiant}, fonction(lignes) -- ... fin)
-- QBCore oxmysql local rows = MySQL.query.await('SELECT * FROM players WHERE citizenid = ?', { citizenid }) -- rows est une table Lua ; gère directement les vérifications nil et length
-- Exemple scalaire ESX MySQL.Async.fetchScalar('SELECT COUNT(1) FROM owned_vehicles', {}, function(count) -- ... end)
-- oxmysql scalaire local count = MySQL.scalar.await('SELECT COUNT(1) FROM player_vehicles')
-- ESX insert MySQL.Async.execute('INSÉRER DANS LES VALEURS addon_account (@owner, @name, @money)', { ['@owner'] = identifiant, ['@name'] = nom, ['@money'] = argent })
-- oxmysql insert MySQL.prepare.await('INSÉRER DANS player_accounts (citizenid, nom, montant) VALEURS (?, ?, ?)', { citizenid, nom, montant })

Remarques

  1. Préférer requête.attendre, scalaire.attendre, et préparer.attendre pour un flux propre.
  2. Utilisez des instructions préparées pour les opérations d’écriture.

Étape 4 : Mapper les structures de données ESX vers QBCore

Vous déplacerez les identités des joueurs et les entités détenues. Utilisez cette référence pour mapper les tables.

Table ESXColonne cléTableau QBCoreColonne cléRemarques
utilisateursidentifiantjoueurscitoyenidConvertir les identifiants et créer citoyenid pour chaque ligne
véhicules possédéspropriétairevéhicules_joueurscitoyenidConvertir les boîtiers de plaques et les charges utiles JSON
magasin_de_donnéespropriétairemétadonnées du joueurcitoyenidSi vous stockez du JSON, fusionnez-le avec précaution
données_du_compte_addonpropriétairecomptes_joueurscitoyenidAssocier les noms de compte aux services bancaires ou aux espèces QBCore
addon_inventory_itemspropriétaireinventaires_des_joueurscitoyenidSi vous déménagez à ox_inventaire, migrer séparément

Vous pouvez conserver des tables personnalisées. Ajustez uniquement les clés étrangères qui référencent des identifiants ESX.


Étape 5. Stabiliser les identifiants

ESX stocke souvent un identifiant CFX comme licence:xxxx ou historique vapeur:xxxx. QBCore utilise citoyenid en tant que clé de lecteur stable et conserve les identifiants d'exécution uniquement pour l'authentification.

Vous serez

  1. Créer un citoyenid pour chaque joueur.
  2. Liez les identifiants hérités au nouvel enregistrement.
  3. Conservez une table de consultation pour le support et les audits.

Amorçage SQL

Exécutez ceci sur une copie de votre base de données ESX pour préparer les tables QBCore.

-- 1) Créez la table des joueurs si elle est manquante. Adaptez-la à votre schéma QBCore. CREATE TABLE IF NOT EXISTS players ( citizenid VARCHAR(11) PRIMARY KEY, license VARCHAR(64) UNIQUE, identifiers JSON NOT NULL, name VARCHAR(64), charinfo JSON NOT NULL, metadata JSON NOT NULL, money JSON NOT NULL, job JSON NOT NULL, position VARCHAR(128) DEFAULT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 2) L'équivalent d'une fonction d'assistance en SQL utilisant un générateur déterministe serait complexe. -- Au lieu de cela, organisez le mappage dans une table séparée et générez citizenid en Lua. CREATE TABLE IF NOT EXISTS legacy_identifier_map ( license VARCHAR(64) PRIMARY KEY, steam VARCHAR(64) NULL, fivem VARCHAR(64) NULL, discord VARCHAR(64) NULL, xbl VARCHAR(64) NULL, liveid VARCHAR(64) NULL, citizenid VARCHAR(11) UNIQUE ); -- 3) Amorcer le mappage à partir des utilisateurs ESX INSERT INTO legacy_identifier_map (license) SELECT DISTINCT REPLACE(identifier, 'identifier:', '') FROM users WHERE identifier LIKE 'license:%' OR identifier LIKE 'steam:%';

Générer un citizenid et insérer des joueurs dans Lua

Exécutez une fois en mode staging. Sauvegardez d'abord.

-- server/migrate_identifiers.lua local QBCore = exports['qb-core']:GetCoreObject() local function generateCitizenId() local charset = {} pour c = 65, 90 faire table.insert(charset, string.char(c)) fin pour n = 48, 57 faire table.insert(charset, string.char(n)) fin math.randomseed(GetGameTimer()) local id = {} pour i = 1, 11 faire id[i] = charset[math.random(1, #charset)] fin renvoyer table.concat(id) fin local rows = MySQL.query.await('SELECT license FROM legacy_identifier_map WHERE citizenid IS NULL') pour _, r dans ipairs(rows) faire local citizenid = generateCitizenId() MySQL.prepare.await('UPDATE legacy_identifier_map SET citizenid = ? WHERE license = ?', { citizenid, r.license }) end -- Construire des joueurs à partir d'utilisateurs ESX local users = MySQL.query.await([[SELECT u.identifier, u.firstname, u.lastname, u.dateofbirth, u.sex, u.height FROM users u]]) for _, u in ipairs(users) do local license = u.identifier local map = MySQL.single.await('SELECT citizenid FROM legacy_identifier_map WHERE license = ?', { license }) if map and map.citizenid then local name = string.format('%s %s', u.firstname or 'John', u.lastname or 'Doe') local charinfo = json.encode({ firstname = u.firstname, lastname = u.lastname, birthdate = u.dateofbirth, gender = u.sex, height = u.height }) local metadata = json.encode({ faim = 100, soif = 100 }) argent local = json.encode({ cash = 0, banque = 0, crypto = 0 }) emploi local = json.encode({ name = 'chômeur', label = 'Chômeur', grade = { name = '0', niveau = 0 }}) MySQL.prepare.await('INSERT IGNORE INTO players (citizenid, licence, identifiers, nom, charinfo, métadonnées, argent, travail) VALEURS (?, ?, ?, ?, ?, ?, ?, ?, ?)', { map.citizenid, licence, json.encode({ license = licence }), nom, charinfo, métadonnées, argent, travail }) end end print('Migration des identifiants terminée')

Déplacer les véhicules possédés

INSÉRER IGNORER DANS player_vehicles (citizenid, plaque, véhicule, garage, état) SÉLECTIONNER m.citizenid, UPPER(JSON_UNQUOTE(JSON_EXTRACT(v.vehicle, '$.plate'))), v.vehicle, 'legion', 1 DE owned_vehicles v JOIN legacy_identifier_map m ON m.license = v.owner;

Valider des échantillons aléatoires dans le jeu. Vérifier les formats de plaques et les garages.


Étape 6. Porter le code ESX vers QBCore avec ox_lib

Remplacez l'API d'exécution ESX par des équivalents QBCore. Utilisez ox_lib pour les rappels et les notifications.

Objet joueur

-- ESX local xPlayer = ESX.GetPlayerFromId(src) xPlayer.addMoney(100)
-- Lecteur local QBCore = QBCore.Functions.GetPlayer(src) Player.Functions.AddMoney('cash', 100)

Emplois

-- Vérification de la tâche ESX si xPlayer.getJob().name == 'police' alors -- ... fin
-- Vérification du travail QBCore travail local = Player.PlayerData.job si job et job.name == 'police' alors -- ... fin

Rappels et interface utilisateur

-- Rappel du serveur ESX ESX.RegisterServerCallback('resource:getData', function(source, cb) cb({ ok = true }) end)
-- ox_lib rappel lib.callback.register('resource:getData', function(source) return { ok = true } fin)
-- Notification lib.notify(source, { title = 'Emploi', description = 'Promotion accordée', type = 'succès' })

Commandes

-- ESX RegisterCommand('pay', function(src, args) local amount = tonumber(args[1]) ou 0 xPlayer.removeMoney(amount) end)
-- QBCore avec les autorisations QBCore.Commands.Add('pay', 'Payer en espèces', {{name = 'amount', help = 'Amount'}}, false, function(src, args) local amount = tonumber(args[1]) ou 0 local Player = QBCore.Functions.GetPlayer(src) Player.Functions.RemoveMoney('cash', amount) end)

Étape 7. Inventaire et articles

Si vous déménagez de es_extended stocks à qb-inventaire ou ox_inventaire, traitez cela comme une sous-migration distincte.

  1. Geler les ajouts d'articles.
  2. Exporter la liste principale des articles.
  3. Mapper les noms des éléments un à un.
  4. Migrez les inventaires des joueurs par lots. Validez la taille et le poids des piles.

Exemple de mappage d'éléments CSV

esx_name,qb_name,notes pain,pain, eau,eau, crochetage,crochetage,

Étape 8. Test et déploiement

  1. Tests unitaires
    1. Recherche d'identifiants de test pour un ensemble aléatoire de joueurs.
    2. Testez les transferts d’argent, les changements d’emploi et la possession d’un véhicule.
  2. Tests de gameplay
    1. Créez des joueurs avec d'anciens identifiants ESX et confirmez le mappage automatique.
    2. Exécutez une mission de police, un vol de magasin et un achat de véhicule.
  3. Tests de performance
    1. Utiliser résmon pour surveiller le CPU et la mémoire.
    2. Confirmez que le nombre de requêtes DB a chuté après la conversion oxmysql.
  4. Plan de déploiement
    1. Déplacer la base de données intermédiaire vers la production pendant une fenêtre de maintenance.
    2. Annoncez un temps d’arrêt de 60 minutes.
    3. Surveillez les journaux pour les identifiants manquants et les erreurs de clé étrangère.

Dépannage

  1. Citoyens en double
    1. Cause : Exécution de la migration deux fois.
    2. Correction. Appliquer des clés uniques sur citoyenid et utiliser INSÉRER IGNORER pendant le semis.
  2. Véhicules disparus
    1. Cause. La clé du propriétaire ne correspond pas entre owned_vehicles.owner et legacy_identifier_map.license.
    2. Correction. Normaliser les valeurs du propriétaire et relancer l'insertion du véhicule pour les plaques concernées.
  3. Les joueurs apparaissent sans inventaire
    1. Cause. La migration de l'inventaire a été ignorée.
    2. Correction. Reconstruisez la cartographie de l'inventaire et réimportez.
  4. Les scripts échouent avec MySQL.Async non trouvé
    1. Cause. Le script dépend toujours de mysql-async.
    2. Correction. Remplacez les appels par oxmysql et supprimez mysql-async du serveur.

Liste de contrôle de basculement

  1. Sauvegarder la base de données de production avec un horodatage.
  2. Arrêtez le serveur et verrouillez les connexions des joueurs.
  3. Restaurez le vidage final en production.
  4. Déployer la version QBCore avec QB-Noyau, oxmysql, ox_lib premier dans l'ordre d'assurance.
  5. Exécutez le script d’amorçage de l’identifiant une fois.
  6. Activez les scripts convertis uniquement lorsque leurs requêtes sont sur oxmysql.
  7. Rouvrez le serveur et surveillez les journaux pendant 30 minutes.
  8. Postez un plan de restauration si des erreurs critiques apparaissent.

Annexe A. Exemple de fxmanifest pour l'assistant de migration

fx_version 'cerulean' jeu 'gta5' lua54 'oui' server_scripts { '@oxmysql/lib/MySQL.lua', '@ox_lib/init.lua', 'server/migrate_identifiers.lua' }

Annexe B. Aides JSON sécurisées

local function safeDecode(jsonStr, fallback)
  if type(jsonStr) ~= 'string' or jsonStr == '' then return fallback end
  local ok, result = pcall(json.decode, jsonStr)
  if not ok then return fallback end
  return result
end

Ce que vous avez accompli

  1. Enregistrements de joueurs stables indexés par citoyenid.
  2. Une couche oxmysql propre avec des instructions préparées et des attentes.
  3. Code ESX porté vers QBCore à l'aide des rappels et des utilitaires ox_lib.
  4. Un plan versionné que vous pouvez répéter pour les futurs serveurs.

  1. Centre de conversion de framework. https://fivemx.com/framework-conversion
  2. Guide MySQL Async vers oxmysql. https://fivemx.com/mysql-async-to-oxmysql
  3. Migration des identifiants SQL. https://fivemx.com/sql-identifiers-migration
  4. Modèles d'adaptateur pour les ports de script. https://fivemx.com/adapter-patterns
  5. Démarrage rapide de l'installation de QBCore. https://fivemx.com/how-to-install-qbcore
  6. Liste de contrôle de conversion de script. https://fivemx.com/converting-fivem-scripts
  7. Aperçu de QBOX avec pile ox. https://fivemx.com/qbox-ox-stack
  8. Résmon et la performance. https://fivemx.com/how-to-use-resmon-in-fivem-optimize-resources

Références externes

  1. Cadre QBCore
  2. Documentation d'oxmysql.
  3. Documentation d'ox_lib.
  4. Référence des identifiants CFX.re.

Luc
Luc

Je m'appelle Luke, je suis un joueur et j'adore écrire sur FiveM, GTA et le jeu de rôle. Je dirige une communauté de jeu de rôle et j'ai environ 10 ans d'expérience dans l'administration de serveurs.

Articles: 570