Como resolver duplicidade de personagem após crash no servidor de MU Online
Diagnostique e corrija duplicidade de personagens, inventário e Zen causada por crash do GameServer ou queda de conexão no MU Online, incluindo consulta ao banco de dados, rollback seguro e prevenção via save assíncrono.
Duplicidade de personagem — quando o mesmo personagem, com o mesmo nome e conta, aparece em dois estados diferentes no banco de dados após um crash do GameServer ou uma queda abrupta de conexão — é um dos incidentes mais delicados que um administrador de servidor de MU Online pode enfrentar. Ele mex
Duplicidade de personagem — quando o mesmo personagem, com o mesmo nome e conta, aparece em dois estados diferentes no banco de dados após um crash do GameServer ou uma queda abrupta de conexão — é um dos incidentes mais delicados que um administrador de servidor de MU Online pode enfrentar. Ele mexe diretamente com a confiança do jogador (afinal, é o personagem e os itens dele que estão em risco) e, se mal resolvido, pode gerar acusações de dupe intencional de itens. Este tutorial mostra como diagnosticar a causa raiz, investigar o banco de dados com segurança, decidir qual registro manter e implementar prevenção para não repetir o incidente.
Como a duplicidade acontece tecnicamente
O fluxo normal de um personagem no MU é: o cliente conecta, o GameServer carrega os dados do banco para a memória, o jogador joga, e periodicamente (ou no logout) o GameServer salva o estado de volta no banco. A duplicidade surge quando esse ciclo é interrompido de forma inconsistente:
- O jogador está online, com o personagem carregado na memória do processo do GameServer.
- O GameServer trava (crash) ou a conexão cai abruptamente, sem completar o save final.
- O jogador reconecta rápido demais (ou o watchdog reinicia o processo automaticamente) antes que o banco tenha certeza de que a sessão anterior encerrou.
- Dois estados do mesmo personagem passam a existir: o salvo antes do crash e o que estava em memória no momento da queda — e, dependendo da implementação, ambos podem gerar registros conflitantes.
Sintomas que indicam duplicidade
| Sintoma relatado pelo jogador | O que provavelmente aconteceu |
|---|---|
| "Meu personagem sumiu e voltou zerado" | Save do estado pré-crash sobrescreveu o progresso recente |
| "Tenho dois personagens com o mesmo nome" (via suporte) | Registro duplicado real no banco, não visível ao próprio jogador simultaneamente |
| "Perdi itens que peguei antes do crash" | Estado em memória no momento do crash não foi persistido |
| "Zen apareceu duplicado depois que voltei" | Transação de Zen não foi atômica, save parcial gerou saldo incorreto |
| "Não consigo logar, diz que a conta já está online" | Lock de sessão não foi liberado corretamente após o crash |
Passo 1 — Isolar a conta e suspender login temporariamente
Antes de mexer no banco, impeça que o jogador (ou qualquer sessão) logue na conta afetada. Isso evita que uma nova sessão sobrescreva dados enquanto você investiga. A maioria dos emuladores tem uma flag de bloqueio de conta:
UPDATE MEMB_INFO SET ctlCode = 1 WHERE memb___id = 'nomeDaConta';
Documente o horário exato da suspensão — isso ajuda a delimitar a janela de tempo da investigação.
Passo 2 — Consultar o banco para confirmar duplicidade real
Rode uma consulta direta na tabela de personagens filtrando pela conta e nome, para ver se realmente existem registros conflitantes (e não apenas um erro de cache do cliente):
SELECT Name, AccountID, cLevel, Resets, LastSave
FROM Character
WHERE AccountID = 'nomeDaConta'
ORDER BY LastSave DESC;
Se aparecer mais de um registro com o mesmo nome/conta, ou dois Character.Guid diferentes referenciando itens com o mesmo ItemSerial, você tem duplicidade confirmada — não é problema de exibição do cliente.
Passo 3 — Comparar os registros e escolher o estado correto
Nunca assuma que o registro mais recente é o correto por padrão. Compare:
| Critério | O que verificar |
|---|---|
LastSave (timestamp) | Qual registro foi salvo por último antes/depois do crash |
| Nível e Resets | Qual estado é mais avançado (indício de progresso real do jogador) |
Inventário (Inventory, Warehouse) | Qual registro tem os itens que o jogador relata ter tido |
Zen (Money) | Compare com o histórico de log de transações, se existir |
| Logs do GameServer no horário do crash | Confirmam a última ação registrada antes da queda |
Na maioria dos casos, o registro correto é o que tem o estado mais avançado e consistente com o relato do jogador, não necessariamente o cronologicamente mais recente no banco (que pode ser um save incompleto).
Passo 4 — Fazer o rollback/merge com segurança
Com o registro correto identificado, faça sempre um backup da tabela antes de qualquer alteração:
SELECT * INTO Character_backup_20260731 FROM Character WHERE AccountID = 'nomeDaConta';
Depois, remova ou mescle o registro incorreto. Se for uma duplicidade simples (dois registros, um obsoleto), delete o obsoleto após confirmar 100% que ele não tem dados que faltam no correto:
DELETE FROM Character WHERE Guid = 'guid-do-registro-obsoleto';
Se houver itens legítimos espalhados entre os dois registros (ex.: um tem o personagem certo, o outro tem um item que o jogador realmente conseguiu antes do crash), faça um merge manual, movendo o item para o inventário do registro correto antes de deletar o obsoleto.
Passo 5 — Verificar duplicidade de itens (dupe de Zen/itens)
Duplicidade de personagem às vezes vem acompanhada de duplicidade de itens específicos — o mesmo ItemSerial aparecendo em dois lugares. Isso é mais grave porque pode ser explorado deliberadamente. Rode uma varredura:
SELECT ItemSerial, COUNT(*) as ocorrencias
FROM Inventory
GROUP BY ItemSerial
HAVING COUNT(*) > 1;
Qualquer ItemSerial com mais de uma ocorrência precisa ser investigado individualmente — pode ser o mesmo incidente de crash ou uma exploração de dupe que merece banimento e reversão mais ampla.
Passo 6 — Restaurar a conta e comunicar o jogador
Depois de corrigir o registro, libere a conta:
UPDATE MEMB_INFO SET ctlCode = 0 WHERE memb___id = 'nomeDaConta';
Entre em contato com o jogador explicando o que aconteceu, o que foi restaurado e, se aplicável, uma compensação por transtorno (itens de evento, tempo de VIP). Transparência aqui é o que separa um servidor confiável de um que "sempre trava e some item".
Prevenção — save assíncrono e transações atômicas
A correção pontual resolve o caso, mas não evita recorrência. As mudanças estruturais mais eficazes:
- Transações atômicas para qualquer operação que mexa em Zen ou itens (troca, compra, uso de NPC) — se a transação não completar 100%, ela é revertida, não fica "pela metade".
- Save assíncrono com confirmação: o GameServer só libera a sessão/lock da conta depois de receber confirmação de escrita do banco, não apenas de enviar o comando.
- Lock de sessão por AccountID: impede que a mesma conta seja carregada em dois processos simultaneamente, cenário clássico após reinício rápido pós-crash.
- Watchdog com atraso de restart: em vez de reiniciar o GameServer instantaneamente após um crash, aguardar alguns segundos garante que conexões pendentes de save tenham chance de finalizar ou falhar de forma limpa.
Registro e auditoria contínua
Mantenha um log específico de incidentes de duplicidade, com data, conta afetada, causa identificada e ação tomada. Isso ajuda a identificar padrões (ex.: sempre acontece em determinado horário de pico, ou após um tipo específico de crash) e a justificar mudanças de infraestrutura para a comunidade, caso seja necessário.
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Personagem "voltou zerado" após crash | Save pré-crash sobrescreveu progresso recente | Restaurar do registro com estado mais avançado, comparando logs |
| Item aparece duplicado no inventário | ItemSerial replicado por save parcial | Varredura de ItemSerial duplicado e remoção da cópia extra |
| Conta trava "já está online" | Lock de sessão não liberado após crash | Resetar ctlCode/lock manualmente e revisar timeout do lock |
| Zen duplicado após reconexão | Transação de Zen não atômica | Implementar transação atômica nas operações de Zen |
| Incidente se repete com frequência | Falta de save assíncrono e lock por conta | Implementar as mudanças estruturais de prevenção |
Checklist de resposta a duplicidade de personagem
- Conta suspensa temporariamente antes de qualquer investigação no banco.
- Consulta ao banco confirmando duplicidade real (não erro de cliente).
- Registros comparados por timestamp, nível, inventário e logs do GameServer.
- Backup da tabela feito antes de qualquer DELETE/UPDATE.
- Varredura de ItemSerial duplicado realizada.
- Conta restaurada e jogador comunicado com transparência.
- Causa raiz documentada e prevenção estrutural avaliada (save assíncrono, lock, transações atômicas).
Incidentes de duplicidade são um lembrete de que a estabilidade do banco de dados é tão importante quanto o balanceamento do jogo. Se sua infraestrutura ainda não tem rotina de backup e monitoramento sólida, vale revisar os fundamentos no guia de criação de servidor de MU Online.
Perguntas frequentes
Duplicidade de personagem é sempre um bug do servidor?
Na maioria dos casos sim — é causado por falha na sincronização entre a sessão do jogador e o banco de dados durante um crash ou queda de conexão. Em raros casos pode ser tentativa deliberada de duplicar itens (dupe), o que exige investigação separada e mais rigorosa.
Como sei se um personagem foi duplicado (dupe) e não é só um erro visual?
Consulte diretamente o banco de dados pela tabela de personagens filtrando pelo AccountID e Name. Se houver mais de uma linha com o mesmo nome e conta, ou dois registros com o mesmo GUID de item em contas diferentes, é duplicidade real, não erro de exibição do cliente.
Posso simplesmente deletar o personagem duplicado mais recente?
Não sem antes comparar os dois registros. Às vezes o registro 'duplicado' tem dados mais atualizados (level, itens, Zen) que o original, porque o crash aconteceu no meio de um save. Sempre compare timestamps e escolha manter o registro com o estado mais correto, não necessariamente o mais antigo.
Como evitar que isso aconteça de novo?
Implemente save assíncrono com confirmação de escrita (commit no banco antes de liberar a sessão), transações atômicas para operações críticas (troca de itens, uso de Zen) e um sistema de lock por AccountID que impede login simultâneo da mesma conta em dois processos do GameServer.
Preciso avisar o jogador afetado?
Sim, sempre. Mesmo que o problema tenha sido corrigido tecnicamente, o jogador percebeu o bug e merece uma explicação clara do que aconteceu e o que foi restaurado. Falta de comunicação em casos de duplicidade é uma das maiores causas de perda de confiança na comunidade.