Como configurar patch automático via launcher no MU Online
Monte um fluxo de patch automático de ponta a ponta para o cliente de MU Online — do empacotamento dos arquivos alterados à publicação do manifesto, com versionamento, rollback e distribuição pelo launcher.
Distribuir um patch de MU Online parece trivial até o dia em que você altera três arquivos e precisa garantir que centenas de jogadores, em máquinas e conexões diferentes, tenham exatamente os mesmos bytes que você. É aí que um fluxo de patch automático deixa de ser luxo e passa a ser infraestrutura
Distribuir um patch de MU Online parece trivial até o dia em que você altera três arquivos e precisa garantir que centenas de jogadores, em máquinas e conexões diferentes, tenham exatamente os mesmos bytes que você. É aí que um fluxo de patch automático deixa de ser luxo e passa a ser infraestrutura. Neste guia você vai montar o processo completo do lado do servidor — detecção de mudanças, empacotamento, versionamento, publicação e rollback — que alimenta o launcher que roda na máquina do jogador.
Este é um tutorial de cliente: trata dos arquivos que o jogador baixa e executa, e de como o launcher os mantém sincronizados. Não cobrimos a configuração do game server em si — se você ainda está montando o servidor, comece pelo guia de como criar servidor de MU Online. Aqui o foco é a esteira de patches.
O que é "patch automático" de verdade
Muita gente chama de patch automático apenas o fato de o launcher baixar arquivos. Isso é só metade. O patch automático completo tem dois lados:
- Lado servidor (build/deploy): um processo que compara a pasta do cliente atual com a última versão publicada, identifica o que mudou, gera um manifesto com hashes e sobe os arquivos alterados para o servidor de distribuição.
- Lado cliente (launcher): a ferramenta que lê o manifesto, compara com o que está instalado e baixa somente as diferenças.
O elo entre os dois é o manifesto, um arquivo JSON com a lista de arquivos e seus hashes. Quando você automatiza a geração desse manifesto, elimina a maior fonte de bug em servidores de MU: o patch publicado "pela metade", com o manifesto apontando para um arquivo que não foi enviado ou com hash desatualizado.
VOCÊ ALTERA ARQUIVOS
│
▼
[ SCRIPT DE PATCH ] ── varre, calcula hash, compara com versão anterior
│ gera manifesto + separa arquivos alterados
▼
[ SERVIDOR DE DISTRIBUIÇÃO ] (Apache/Nginx com HTTPS)
│ version.json + /patches/<versão>/...
▼
[ LAUNCHER DO JOGADOR ] ── baixa só o diff, valida hash, aplica
│
▼
Main.exe atualizado
Pré-requisitos
| Item | Recomendação | Papel no fluxo |
|---|---|---|
| Cliente base íntegro | Pasta completa do MU da sua season | Fonte de verdade dos arquivos |
| Launcher funcional | Launcher .NET que consome manifesto | Aplica o patch no jogador |
| Servidor de distribuição | Apache/Nginx + HTTPS, subdomínio dedicado | Hospeda manifesto e patches |
| PowerShell 5+ | Já vem no Windows | Roda o script de patch |
| Ferramenta de compactação | 7-Zip (opcional) | Empacotar patches grandes |
| Controle de versão | Git ou pasta versionada | Histórico para rollback |
Um pré-requisito conceitual: defina o que é distribuível. Nem tudo na pasta do cliente deve ir para o patch. Logs, configurações locais do jogador (resolução escolhida, volume) e arquivos temporários devem ficar de fora. Crie uma lista de exclusão desde o início.
Passo 1 — Estruturar o versionamento no servidor
Antes de automatizar, defina a estrutura de pastas no servidor de distribuição. Recomendo versionar por pasta, mantendo o histórico:
/var/www/cdn/
├── version.json ← manifesto ATUAL (o que o launcher lê)
├── manifests/
│ ├── 3.1.0.json ← histórico de manifestos (para rollback)
│ ├── 3.2.0.json
│ └── 3.3.0.json
└── patches/
├── Data/
│ ├── Item.bmd
│ └── Local/Text.bmd
├── Interface/
│ └── loading01.jpg
└── Main.exe
Aqui usamos um esquema em que patches/ sempre contém a versão mais recente de cada arquivo (espelho do cliente distribuível), e manifests/ guarda o histórico. O version.json na raiz é simplesmente uma cópia do manifesto da versão vigente. Isso simplifica o launcher: ele baixa qualquer arquivo em patch_base_url + path e sempre pega a versão atual.
> A estrutura Data/, Interface/, Main.exe é um exemplo típico de Season 6. A organização real das pastas e quais arquivos BMD existem variam por season/cliente. Ajuste a lista de exclusão e os caminhos à sua distribuição.
Passo 2 — O script de patch automático
O coração do sistema é um script que faz tudo: varre, calcula hashes, compara com a versão anterior, monta o manifesto e reporta o que mudou. Este script PowerShell é o modelo:
# publicar-patch.ps1
param(
[Parameter(Mandatory)] [string] $NovaVersao # ex: "3.3.0"
)
$clienteDir = "C:\Build\ClienteMU" # cliente distribuível (fonte)
$saidaDir = "C:\Build\Publicar" # o que será enviado ao servidor
$baseUrl = "https://cdn.meuservidor.com/patches/"
$exclusoes = @("*.log", "config.local.ini", "Screenshots\*", "*.tmp")
# --- 1. Varrer arquivos, aplicando exclusões ---
$arquivos = Get-ChildItem $clienteDir -Recurse -File | Where-Object {
$rel = $_.FullName.Substring($clienteDir.Length + 1)
-not ($exclusoes | Where-Object { $rel -like $_ })
}
# --- 2. Calcular hash de cada arquivo ---
$lista = foreach ($f in $arquivos) {
$rel = $f.FullName.Substring($clienteDir.Length + 1).Replace('\','/')
$hash = (Get-FileHash $f.FullName -Algorithm SHA256).Hash.ToLower()
[ordered]@{ path = $rel; hash = $hash; size = $f.Length }
}
# --- 3. Comparar com o manifesto anterior (diff) ---
$anterior = @{}
if (Test-Path ".\version.json") {
(Get-Content ".\version.json" -Raw | ConvertFrom-Json).files |
ForEach-Object { $anterior[$_.path] = $_.hash }
}
$alterados = $lista | Where-Object { $anterior[$_.path] -ne $_.hash }
Write-Host "Arquivos alterados/novos: $($alterados.Count)"
# --- 4. Copiar somente os alterados para a pasta de publicação ---
if (Test-Path $saidaDir) { Remove-Item $saidaDir -Recurse -Force }
foreach ($a in $alterados) {
$origem = Join-Path $clienteDir ($a.path -replace '/','\')
$destino = Join-Path $saidaDir ($a.path -replace '/','\')
New-Item -ItemType Directory -Force -Path (Split-Path $destino) | Out-Null
Copy-Item $origem $destino
}
# --- 5. Gerar manifesto novo ---
$manifesto = [ordered]@{
version = $NovaVersao
patch_base_url = $baseUrl
main_exe = "Main.exe"
files = $lista
}
$json = $manifesto | ConvertTo-Json -Depth 4
$json | Out-File ".\version.json" -Encoding utf8
$json | Out-File ".\manifests\$NovaVersao.json" -Encoding utf8
Write-Host "Patch $NovaVersao pronto. Envie:"
Write-Host " - conteúdo de $saidaDir -> /var/www/cdn/patches/"
Write-Host " - version.json -> /var/www/cdn/version.json"
O que esse script garante:
- Detecção automática do que mudou, comparando hashes com o manifesto anterior — nada de lembrar manualmente quais arquivos você editou.
- Empacotamento incremental: só os arquivos alterados vão para a pasta de publicação, reduzindo o upload.
- Manifesto sempre íntegro: os hashes vêm da mesma varredura que gerou a lista, então nunca ficam dessincronizados.
- Histórico versionado em
manifests/, pré-requisito para rollback.
Passo 3 — Ordem de publicação (a regra de ouro)
A causa número um de cliente quebrado durante um patch é a ordem de upload errada. O launcher pode buscar o version.json no exato instante em que você está subindo os arquivos. Se ele pega o manifesto novo antes de os arquivos existirem, recebe 404 e falha.
A ordem correta é sempre:
- Suba primeiro todos os arquivos de patch para
/patches/. - Confirme que estão acessíveis (
curl -Iem alguns deles). - Só então suba o
version.jsonatualizado.
# no seu terminal, após rodar o script:
# 1) arquivos primeiro
rsync -avz C:/Build/Publicar/ usuario@servidor:/var/www/cdn/patches/
# 2) verificar
curl -I https://cdn.meuservidor.com/patches/Main.exe # espera 200
# 3) manifesto por último
scp version.json usuario@servidor:/var/www/cdn/version.json
Assim, durante todo o processo os jogadores enxergam o manifesto antigo (consistente) até o momento em que o novo entra no ar já com tudo disponível.
Passo 4 — Configurar o servidor de distribuição
O servidor web precisa servir os arquivos como conteúdo estático, com dois cuidados: sem cache no manifesto e com cache nos patches (que são imutáveis por hash). Exemplo de configuração Nginx:
server {
listen 443 ssl;
server_name cdn.meuservidor.com;
root /var/www/cdn;
# manifesto nunca deve ser cacheado
location = /version.json {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
}
# patches podem ser cacheados por muito tempo
location /patches/ {
add_header Cache-Control "public, max-age=604800";
}
}
Se você usa uma CDN na frente, respeite a mesma lógica: o version.json deve ter TTL baixíssimo, e os arquivos de patches/ podem ter TTL longo, já que qualquer alteração de conteúdo muda o hash e, portanto, o comportamento do launcher.
Passo 5 — Rollback quando um patch quebra
Mais cedo ou mais tarde um patch vai sair ruim: uma textura corrompida, um Main.exe da season errada, um arquivo Data com formato inválido. Como o sistema é baseado em hash e você guardou o histórico, o rollback é rápido.
Estratégia de rollback em três passos:
- Identifique a última versão estável (ex.:
3.2.0). - Garanta que os arquivos daquela versão ainda existem em
patches/— se o patch ruim sobrescreveu algum, restaure a partir do seu build versionado. - Republique o manifesto estável como
version.json:
# reverter para 3.2.0
cp /var/www/cdn/manifests/3.2.0.json /var/www/cdn/version.json
Na próxima abertura, o launcher compara os hashes atuais dos jogadores com o manifesto 3.2.0, percebe a divergência nos arquivos afetados e baixa de volta as versões estáveis. O jogador nem precisa saber que houve um problema.
> Guarde sempre pelo menos as duas ou três últimas versões completas do cliente distribuível. Rollback só funciona se os bytes antigos ainda existirem em algum lugar.
Passo 6 — Comunicar o patch ao jogador
Um bom fluxo de patch também informa. Publique um news.json que o launcher exibe, com o changelog:
{
"version": "3.3.0",
"date": "2026-07-10",
"highlights": [
"Novo evento sazonal habilitado",
"Correção de textura no mapa Kanturu",
"Ajuste de balance de drops"
]
}
Mostrar o changelog reduz suporte ("o que mudou?") e transmite a sensação de um servidor ativo e bem cuidado — o que retém jogadores.
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Launcher recebe 404 durante o patch | Manifesto subido antes dos arquivos | Suba arquivos primeiro, version.json por último |
| Patch baixa arquivos que não mudaram | Comparação de hash falha (caixa ou fim de linha) | Normalize hashes para minúsculo; não altere arquivos binários acidentalmente |
| Jogadores presos em versão antiga | version.json cacheado por CDN/proxy | Cache-Control: no-cache no manifesto; purgue a CDN |
| Cliente quebra após patch | Arquivo corrompido ou de season errada publicado | Rollback para o manifesto estável anterior |
| Upload demorado a cada patch | Enviando cliente inteiro em vez do diff | Use o script que copia só os arquivos alterados |
| Rollback não restaura arquivos | Bytes antigos foram sobrescritos e perdidos | Mantenha builds versionados das últimas versões |
| Manifesto e arquivos dessincronizados | Manifesto gerado antes de finalizar as edições | Gere o manifesto sempre por último, na mesma varredura |
Boas práticas do fluxo de patch
- Automatize tudo em um comando:
publicar-patch.ps1 3.3.0deve fazer o build completo. Passos manuais são onde os erros nascem. - Teste em uma pasta espelho antes de publicar em produção. Aponte um launcher de teste para um manifesto de staging.
- HTTPS em todo o caminho, do manifesto aos patches. Patch sem TLS é vetor de injeção de malware no cliente.
- Versione o cliente distribuível (Git LFS ou pasta datada) para viabilizar rollback confiável.
- Nunca inclua arquivos locais do jogador no patch (config de vídeo, som, capturas). Use a lista de exclusão.
- Registre cada publicação: versão, data, arquivos alterados. Esse log salva investigações quando algo quebra.
Checklist de lançamento
- Estrutura de pastas do servidor definida (
version.json,manifests/,patches/) - Script
publicar-patch.ps1testado e gerando diff correto - Lista de exclusão cobrindo logs e configs locais do jogador
- Ordem de upload respeitada (arquivos antes do manifesto)
Cache-Control: no-cachenoversion.json; cache longo empatches/- HTTPS ativo no subdomínio de distribuição
- Histórico de manifestos guardado para rollback
- Build versionado das últimas versões do cliente
- Procedimento de rollback testado em ambiente de staging
news.json/changelog publicado junto do patch- Launcher de teste validando o patch antes de liberar a todos
- Log de publicação atualizado após cada patch
Perguntas frequentes
Qual a diferença entre patch automático e um launcher comum?
O launcher é a ferramenta que roda na máquina do jogador. O patch automático é o processo completo do lado do servidor: detectar o que mudou, empacotar, versionar e publicar o manifesto que o launcher consome. Um sem o outro fica incompleto.
Preciso reenviar o cliente inteiro a cada patch?
Não. O objetivo do patch automático é justamente enviar só os arquivos alterados. O manifesto lista o hash de cada arquivo e o launcher baixa apenas as diferenças, economizando banda e tempo do jogador.
Como faço rollback se um patch quebrar o cliente?
Mantenha versões anteriores do manifesto e dos arquivos. Para reverter, republique o manifesto apontando para os hashes da versão estável anterior. Como o launcher confia no hash, ele restaura os arquivos antigos automaticamente.
Posso automatizar tudo com um script?
Sim, e é o recomendado. Um script varre a pasta do cliente, calcula hashes, compara com a última versão, empacota os alterados e sobe manifesto e arquivos. Assim o patch vira um comando só e elimina erro humano.
O patch automático depende da season do servidor?
A lógica é a mesma para qualquer season. O que muda é quais arquivos existem na pasta do cliente e a estrutura de pastas (Data, texturas BMD, Main.exe). Trate esses caminhos como exemplo, pois variam por season/cliente.