O maior portal de MU Online do Brasil — desde 2003
Tutorial Avançado Cliente

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.

GA Gabriel · Atualizado em 20 ago 2024 · ⏱ 23 min de leitura
Resposta rápida

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

ItemRecomendaçãoPapel no fluxo
Cliente base íntegroPasta completa do MU da sua seasonFonte de verdade dos arquivos
Launcher funcionalLauncher .NET que consome manifestoAplica o patch no jogador
Servidor de distribuiçãoApache/Nginx + HTTPS, subdomínio dedicadoHospeda manifesto e patches
PowerShell 5+Já vem no WindowsRoda o script de patch
Ferramenta de compactação7-Zip (opcional)Empacotar patches grandes
Controle de versãoGit ou pasta versionadaHistó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:

  1. Detecção automática do que mudou, comparando hashes com o manifesto anterior — nada de lembrar manualmente quais arquivos você editou.
  2. Empacotamento incremental: só os arquivos alterados vão para a pasta de publicação, reduzindo o upload.
  3. Manifesto sempre íntegro: os hashes vêm da mesma varredura que gerou a lista, então nunca ficam dessincronizados.
  4. 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:

  1. Suba primeiro todos os arquivos de patch para /patches/.
  2. Confirme que estão acessíveis (curl -I em alguns deles).
  3. Só então suba o version.json atualizado.
# 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:

  1. Identifique a última versão estável (ex.: 3.2.0).
  2. Garanta que os arquivos daquela versão ainda existem em patches/ — se o patch ruim sobrescreveu algum, restaure a partir do seu build versionado.
  3. 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

SintomaCausa provávelSolução
Launcher recebe 404 durante o patchManifesto subido antes dos arquivosSuba arquivos primeiro, version.json por último
Patch baixa arquivos que não mudaramComparaçã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 antigaversion.json cacheado por CDN/proxyCache-Control: no-cache no manifesto; purgue a CDN
Cliente quebra após patchArquivo corrompido ou de season errada publicadoRollback para o manifesto estável anterior
Upload demorado a cada patchEnviando cliente inteiro em vez do diffUse o script que copia só os arquivos alterados
Rollback não restaura arquivosBytes antigos foram sobrescritos e perdidosMantenha builds versionados das últimas versões
Manifesto e arquivos dessincronizadosManifesto gerado antes de finalizar as ediçõesGere 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.0 deve 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.ps1 testado 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-cache no version.json; cache longo em patches/
  • 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.

GA
Editor de guias e builds

Gabriel cobre gameplay, builds de classes, PvP e progressão. Testa cada estratégia em servidor antes de publicar.

Continue lendo

Artigos relacionados