Economize 20% hoje mesmo Use o código WELCOME ao finalizar a compra. BEM-VINDO

Como migrar ESX → QBCore da maneira certa

Você quer uma migração limpa do ESX para o QBCore, sem perda de dados ou interrupção dos sistemas principais. Siga este plano. Você concluirá com identificadores estáveis, consultas oxmysql e código baseado em ox_lib.

Objetivo: mover seu servidor do ESX para o QBCore com o mínimo de tempo de inatividade.



Pré-requisitos

  1. Ferramentas
    1. GIT e uma ramificação separada para a migração.
    2. MariaDB ou MySQL 8 com backups completos habilitados.
    3. Um servidor de preparação que espelha a produção.
  2. Artefatos do servidor
    1. Servidor FX atualizado para a mesma compilação da produção.
    2. QBCore estrutura base e recursos padrão.
  3. Bibliotecas que você usará
    1. oxmysql para banco de dados.
    2. boi_lib para retornos de chamada, auxiliares de IU e wrappers de utilitários.

Etapa 1. Faça um plano e um ponto de reversão

  1. Congele as alterações de produção. Interrompa novas instalações de scripts e gravações em banco de dados desnecessárias para testes.
  2. Faça backup de todo o dump do seu banco de dados como um snapshot nomeado.
  3. Ramifique seu repositório de servidor e crie um dedicado migrar-esx-para-qbcore filial.
  4. Escreva um runbook. Inclua comandos para iniciar e parar o servidor de preparação, restaurar o banco de dados e executar verificações de integridade.

Etapa 2. Crie uma base QBCore limpa

  1. Implante uma nova base QBCore para preparação.
  2. Mantenha apenas os recursos essenciais habilitados. Desabilite tarefas, inventários e scripts personalizados até depois da migração do banco de dados.
  3. Instale e inicie esses recursos primeiro
    1. qb-núcleo
    2. veículos qb ou suas substituições preferidas
    3. oxmysql
    4. boi_lib

Etapa 3. Substitua mysql-async por oxmysql

Se algum script ESX restante ainda usar MySQL.Async, converta as chamadas para oxmysql. Use localizar e substituir com verificação simples.

Conversões comuns

-- ESX mysql-async MySQL.Async.fetchAll('SELECT * FROM usuários ONDE identificador = @id', {['@id'] = identificador}, função(linhas) -- ... fim)
-- QBCore oxmysql local rows = MySQL.query.await('SELECT * FROM players WHERE citizenid = ?', { citizenid }) -- rows é uma tabela Lua; manipula verificações de nulo e comprimento diretamente
-- Exemplo escalar ESX MySQL.Async.fetchScalar('SELECT COUNT(1) FROM owned_vehicles', {}, function(count) -- ... end)
-- contagem local escalar oxmysql = MySQL.scalar.await('SELECT COUNT(1) FROM player_vehicles')
-- ESX insere MySQL.Async.execute('INSERIR EM VALORES da conta addon (@owner, @name, @money)', { ['@owner'] = identificador, ['@name'] = nome, ['@money'] = dinheiro })
-- oxmysql insert MySQL.prepare.await('INSERT INTO player_accounts (citizenid, nome, valor) VALORES (?, ?, ?)', { citizenid, nome, valor })

Notas

  1. Prefer consulta.aguarde, escalar.aguardar, e preparar.aguardar para um fluxo limpo.
  2. Use instruções preparadas para operações de gravação.

Etapa 4. Mapear estruturas de dados ESX para QBCore

Você moverá identidades de jogadores e entidades de sua propriedade. Use esta referência para mapear tabelas.

Tabela ESXColuna chaveTabela QBCoreColuna chaveNotas
Usuáriosidentificadorjogadoresidentidade de cidadãoConverta identificadores e crie identidade de cidadão para cada linha
veículos própriosproprietárioveículos_jogadoresidentidade de cidadãoConverter revestimento de placa e cargas úteis JSON
dados_do_armazenamento_de_dadosproprietáriometadados do jogadoridentidade de cidadãoSe você armazenar JSON, mescle com cuidado
dados_da_conta_adicionalproprietáriocontas_de_jogadoridentidade de cidadãoMapear nomes de contas para QBCore banking ou dinheiro
itens_de_inventário_adicionaisproprietárioinventários_de_jogadoresidentidade de cidadãoSe você se mudar para inventário de bois, migrar separadamente

Você pode manter tabelas personalizadas. Ajuste apenas chaves estrangeiras que façam referência a identificadores ESX.


Etapa 5. Estabilizar identificadores

O ESX geralmente armazena um identificador CFX como licença:xxxx ou histórico vapor:xxxx. QBCore usa identidade de cidadão como a chave do jogador estável e mantém os identificadores de tempo de execução apenas para autenticação.

Você irá

  1. Criar um identidade de cidadão para cada jogador.
  2. Vincule identificadores legados ao novo registro.
  3. Mantenha uma tabela de consulta para suporte e auditorias.

Bootstrap SQL

Execute isso em uma cópia do seu banco de dados ESX para preparar tabelas QBCore.

-- 1) Crie uma tabela de jogadores se estiver faltando. Ajuste ao seu esquema 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) Uma função auxiliar equivalente em SQL usando um gerador determinístico seria complexa. -- Em vez disso, prepare o mapeamento em uma tabela separada e gere citizenid em Lua. CRIAR TABELA SE NÃO EXISTIR legacy_identifier_map (licença VARCHAR(64) CHAVE PRIMÁRIA, 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) Semear o mapeamento de usuários ESX INSERT INTO legacy_identifier_map (licença) SELECT DISTINCT REPLACE(identificador, 'identificador:', '') FROM usuários WHERE identificador LIKE 'licença:%' OR identificador LIKE 'steam:%';

Gerar citizenid e inserir jogadores em Lua

Execute uma vez no staging. Faça o backup primeiro.

-- server/migrate_identifiers.lua local QBCore = exports['qb-core']:GetCoreObject() função local generateCitizenId() conjunto de caracteres local = {} para c = 65, 90 faça table.insert(conjunto de caracteres, string.char(c)) fim para n = 48, 57 faça table.insert(conjunto de caracteres, string.char(n)) fim math.randomseed(GetGameTimer()) id local = {} para i = 1, 11 faça id[i] = conjunto de caracteres[math.random(1, #charset)] fim return table.concat(id) fim local rows = MySQL.query.await('SELECIONE licença DE legacy_identifier_map ONDE citizenid É NULL') para _, r em ipairs(linhas) faça citizenid local = generateCitizenId() MySQL.prepare.await('ATUALIZAR legacy_identifier_map SET citizenid = ? WHERE license = ?', { citizenid, r.license }) end -- Crie jogadores a partir de usuários 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 }) metadados locais = json.encode({ fome = 100, sede = 100 }) dinheiro local = json.encode({ dinheiro = 0, banco = 0, criptografia = 0 }) emprego local = json.encode({ nome = 'desempregado', rótulo = 'Desempregado', nota = { nome = '0', nível = 0 }}) MySQL.prepare.await('INSERT IGNORE INTO jogadores (idcidadão, licença, identificadores, nome, charinfo, metadados, dinheiro, emprego) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', { mapa.idcidadão, licença, json.encode({ licença = licença }), nome, charinfo, metadados, dinheiro, emprego }) fim fim print('Migração de identificador concluída')

Mover veículos próprios

INSERIR IGNORE EM player_vehicles (citizenid, placa, veículo, garagem, estado) SELECIONAR m.citizenid, UPPER(JSON_UNQUOTE(JSON_EXTRACT(v.vehicle, '$.plate'))), v.vehicle, 'legion', 1 DE owned_vehicles v JUNTAR legacy_identifier_map m EM m.license = v.owner;

Valide amostras aleatórias no jogo. Verifique formatos de placas e garagens.


Etapa 6. Portar código ESX para QBCore com ox_lib

Substitua a API de tempo de execução do ESX por equivalentes do QBCore. Use ox_lib para retornos de chamada e notificações.

Objeto do jogador

-- ESX xPlayer local = ESX.GetPlayerFromId(origem) xPlayer.addMoney(100)
-- Jogador local QBCore = QBCore.Functions.GetPlayer(origem) Jogador.Functions.AddMoney('dinheiro', 100)

Empregos

-- Verificação de tarefa ESX se xPlayer.getJob().name == 'police' então -- ... fim
-- Verificação de trabalho QBCore trabalho local = Player.PlayerData.job se job e job.name == 'police' então -- ... fim

Retornos de chamada e interface do usuário

-- Retorno de chamada do servidor ESX ESX.RegisterServerCallback('resource:getData', function(source, cb) cb({ ok = true }) end)
-- retorno de chamada ox_lib lib.callback.register('resource:getData', function(source) return { ok = true } end)
-- Notificação lib.notify(source, { title = 'Job', description = 'Promotion granted', type = 'success' })

Comandos

-- ESX RegisterCommand('pagar', função(origem, argumentos) valor local = tonumber(args[1]) ou 0 xPlayer.removeMoney(valor) fim)
-- QBCore com permissões QBCore.Commands.Add('pay', 'Pay cash', {{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)

Etapa 7. Inventário e Itens

Se você se mudar de es_extendido inventários para qb-inventário ou inventário de bois, trate isso como uma submigração separada.

  1. Congele adições de itens.
  2. Exporte a lista mestra de itens.
  3. Mapeie os nomes dos itens um a um.
  4. Migre inventários de jogadores em lotes. Valide tamanhos e pesos de pilhas.

Exemplo de mapeamento de item CSV

esx_name,qb_name,notes pão,pão, água,água, lockpick,lockpick,

Etapa 8. Teste e implemente

  1. Testes unitários
    1. Teste pesquisas de identificadores para um conjunto aleatório de jogadores.
    2. Teste transferências de dinheiro, mudanças de emprego e propriedade de veículos.
  2. Testes de jogabilidade
    1. Crie jogadores com identificadores ESX antigos e confirme o mapeamento automático.
    2. Execute um fluxo de serviço policial, um assalto a uma loja e uma compra de veículo.
  3. Testes de desempenho
    1. Usar resmon para observar CPU e memória.
    2. Confirme se as contagens de consultas do banco de dados caíram após a conversão do oxmysql.
  4. Plano de implementação
    1. Mova o banco de dados de preparação para produção durante uma janela de manutenção.
    2. Anuncie um tempo de inatividade de 60 minutos.
    3. Monitore logs em busca de identificadores ausentes e erros de chave estrangeira.

Solução de problemas

  1. Cidadãos duplicados
    1. Motivo. Executar a migração duas vezes.
    2. Correção. Aplicar chaves exclusivas em identidade de cidadão e usar INSERIR IGNORAR durante a semeadura.
  2. Veículos desaparecidos
    1. Causa. Incompatibilidade de chave do proprietário entre veículos_próprios.proprietário e legacy_identifier_map.license.
    2. Correção. Normalize os valores do proprietário e execute novamente o encarte do veículo para as placas afetadas.
  3. Jogadores surgem sem inventário
    1. Motivo. Migração de inventário ignorada.
    2. Corrigir. Reconstrua o mapeamento de inventário e importe novamente.
  4. Os scripts falham com MySQL.Async não encontrado
    1. Causa. O script ainda depende do mysql-async.
    2. Correção. Substitua as chamadas por oxmysql e remova mysql-async do servidor.

Lista de verificação de transição

  1. Faça backup do banco de dados de produção com um registro de data e hora.
  2. Pare o servidor e bloqueie as entradas dos jogadores.
  3. Restaure o dump de preparação final para produção.
  4. Implantar compilação QBCore com qb-núcleo, oxmysql, boi_lib primeiro na ordem de garantia.
  5. Execute o script de semeadura do identificador uma vez.
  6. Habilite scripts convertidos somente quando suas consultas estiverem no oxmysql.
  7. Reabra o servidor e observe os logs por 30 minutos.
  8. Publique um plano de reversão caso apareçam erros críticos.

Apêndice A. Exemplo de fxmanifest para auxiliar de migração

fx_version 'cerúleo' jogo 'gta5' lua54 'sim' server_scripts { '@oxmysql/lib/MySQL.lua', '@ox_lib/init.lua', 'server/migrate_identifiers.lua' }

Apêndice B. Auxiliares JSON seguros

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

O que você conquistou

  1. Registros de jogadores estáveis marcados por identidade de cidadão.
  2. Uma camada oxmysql limpa com instruções preparadas e esperas.
  3. Código ESX portado para QBCore usando callbacks e utilitários ox_lib.
  4. Um plano versionado que você pode repetir para servidores futuros.

  1. Centro de conversão de framework. https://fivemx.com/framework-conversion
  2. Guia do MySQL Async para oxmysql. https://fivemx.com/mysql-async-to-oxmysql
  3. Migração de identificadores SQL. https://fivemx.com/sql-identifiers-migration
  4. Padrões de adaptadores para portas de script. https://fivemx.com/adapter-patterns
  5. Início rápido de instalação do QBCore. https://fivemx.com/how-to-install-qbcore
  6. Lista de verificação de conversão de script. https://fivemx.com/converting-fivem-scripts
  7. QBOX com visão geral da pilha de bois. https://fivemx.com/qbox-ox-stack
  8. Resmon e desempenho. https://fivemx.com/how-to-use-resmon-in-fivem-optimize-resources

Referências externas

  1. Estrutura QBCore
  2. documentação do oxmysql.
  3. documentação ox_lib.
  4. Referência de identificadores CFX.re.

Lucas
Lucas

Eu sou Luke, sou um gamer e adoro escrever sobre FiveM, GTA e roleplay. Eu administro uma comunidade de roleplay e tenho cerca de 10 anos de experiência em administração de servidores.

Artigos: 570