<!-- BEGIN CHANGE: artefato de contexto ? updater manual dos clients White Antidote (sem GitHub Actions) -->

# Client updater ? contexto White Antidote

**Status:** plano aprovado (manual, sem GitHub Actions / sem repo de release)  
**Origem da decisão:** chat OTC (`P:\OT\OTC`) ? 2026-07-27  
**Workspace de implementação (portal + host):** `P:\OT\OTSERVER\pedro\otx2-html.code-workspace`  
**Workspace dos clients:** `P:\OT\OTC`

## Objetivo

Player baixa **1x**, instala, e nas aberturas seguintes recebe patch quando houver update ? **sem** pipeline GitHub.

Publicacao = copiar artefatos para o servidor (`html/Downloads`, `html/files-*`, APIs PHP).

**Manual operacional (installer + patch + APK):** [`docs/otc-custom-release-manual.md`](otc-custom-release-manual.md)  
**Skill Cursor:** `.cursor/skills/otc-custom-release/`

<!-- BEGIN CHANGE: portable launchers 2026-08-10 -->
## Portable launchers (atual)

Player baixa um EXE slim; na 1a abertura baixa o client completo para AppData e cria atalho no Desktop.

| Portal | Launcher | AppData | API | Files |
|---|---|---|---|---|
| Custom OTC | `Downloads/WA-OTC-Setup.exe` (Inno) / `WA-OTC.exe` | `%LOCALAPPDATA%\WhiteAntidote\OTC\` | `/api/updater.php?format=launcher` | `/files-otc/` |
| Classic Extended (CIP) | `Downloads/WA-CustomClient.exe` | `%LOCALAPPDATA%\WhiteAntidote\CustomClient\` | `/api/extended-updater.php` | `/files-extended/` |
| Android APK | `Downloads/whiteantidote-android.apk` | (APK) | `/api/updater.php` (in-app) | `/files-otc/` |

Sources: `P:\OT\OTC\launcher` + `tools/build-launchers.ps1`  
Mirror Extended: `tools/publish-extended-release.ps1 -MirrorFilesExtended`  
Flags: `--portable` (install next to exe), `--no-shortcut`  
<!-- END CHANGE -->

## Os 3 clients (escopo)

| # | Produto no portal | Artefato atual | Pasta fonte (OTC) | Estratégia de update |
|---|---|---|---|---|
| 1 | Classic Extended (CIP) | `Downloads/WA-CustomClient.exe` (portable launcher) | `WhiteAntidoteCustomClient/` + `files-extended/` | CRC sync via `extended-updater.php` |
| 2 | Custom OTC | `Downloads/WA-OTC-Setup.exe` (Inno; embeds `WA-OTC.exe`) | `WhiteAntidoteOTC/` / `otclient-meu` + `files-otc/` | Launcher CRC + updater nativo OTCv8 |
| 3 | Android APK | `Downloads/whiteantidote-android.apk` | `otclient-meu` + `create_android_assets.ps1` | Updater nativo para data/modulos; APK = republicar |

Download page: `html/portal/src/app/download/page.tsx`  
Base: `https://ot.whiteantidote.com/Downloads`

---

## Decisão: sem GitHub Actions

- **Não** criar repo de release nem workflow para o player.
- Release = processo manual (ou script local) ? FTP/cópia para `html/`.
- GitHub Actions continua irrelevante para este fluxo (pode existir para outras coisas do portal).

---

## Arquitetura proposta no host (`html/`)

```
html/
  Downloads/                          # instaladores / APK full (1ª vez)
    WhiteAntidote.exe                # installer ElfbotNG (+ launcher updater)
    WhiteAntidoteCustom.exe          # installer OTC
    whiteantidote-android.apk

  files-otc/                          # árvore de patch do OTC (data.zip source)
    init.lua
    data/
    modules/
    layouts/
    mods/
    WhiteAntidoteCustom.exe         # binário opcional (GL/DX conforme platform)

  files-classic/                      # árvore / zips de patch do client ElfbotNG
    manifest.json                     # versão + lista de arquivos + hashes
    patches/
      1.0.1.zip                       # zip incremental ou full
    full/
      WhiteAntidote-classic-full.zip

  portal/api/
    updater.php                       # NOVO ? API OTCv8 (Custom + APK assets)
    classic-updater.php               # NOVO ? API do launcher ElfbotNG
```

URLs públicas alvo:

| Uso | URL |
|---|---|
| OTC / APK assets | `https://ot.whiteantidote.com/api/updater.php` |
| Files OTC | `https://ot.whiteantidote.com/files-otc/` |
| Classic launcher | `https://ot.whiteantidote.com/api/classic-updater.php` |
| Files classic | `https://ot.whiteantidote.com/files-classic/` |
| Full downloads | `https://ot.whiteantidote.com/Downloads/...` |

> Nota: portal API atual vive em `html/portal/api/` e em prod costuma ser exposta como `/api/`. Seguir o mesmo padrão dos outros PHP (`lib.php`, CORS, etc.).

---

## A) Custom OTC + APK (updater nativo OTCv8)

### Como o client funciona (já existe)

- Módulo: `modules/updater/updater.lua`
- Só roda se `Services.updater` estiver setado **e** `g_resources.isLoadedFromArchive()` (`data.zip`).
- POST JSON: `{ version, build, os, platform, args }`
- Resposta esperada:

```json
{
  "url": "https://ot.whiteantidote.com/files-otc",
  "files": {
    "/init.lua": "<crc32b>",
    "/data/...": "<crc32b>",
    "/modules/...": "<crc32b>"
  },
  "binary": {
    "file": "/otclient_dx.exe",
    "checksum": "<crc32b>"
  },
  "keepFiles": false
}
```

> Checksum = **CRC32** (`hash_file('crc32b')` no PHP), nao MD5. O client OTCv8 usa zlib CRC32 em `g_resources.filesChecksums` e no download HTTP.

- Client baixa **so** arquivos com CRC diferente, reconstrói `data.zip`, opcionalmente troca o exe, reinicia.

### Config atual (ainda aponta pro OTCv8 público)

Arquivos: `otclient-meu/init.lua` e `WhiteAntidoteCustomOTC/init.lua`

```lua
APP_VERSION = 1341
Services = {
  updater = "http://otclient.ovh/api/updater.php",  -- TROCAR
  ...
}
```

**Mudança necessária:**

```lua
updater = "https://ot.whiteantidote.com/api/updater.php",
```

(Bump `APP_VERSION` quando quiser sinalizar client muito velho.)

### `updater.php` (implementado - Fase 1)

Referência OTCv8 padrão (Kondra / OTLand) + White Antidote:

- Código: `portal/api/updater.php`
- Diretório local = `WA_HTML_ROOT/files-otc` (prod: `/home/ubuntu/portal/assets/files-otc`) ou `html/files-otc` no repo
- URL pública = `https://ot.whiteantidote.com/files-otc` (Alias Apache nos confs de deploy)
- Cache de checksums ~45s em `portal/cache/updater_otc_checksums.json`
- Platform -> binario: `WIN32-WGL` -> `otclient_dx.exe`, `WIN32-EGL` -> `otclient_gl.exe`; Android: sem `binary`
- Inclui no mapa: `init.lua`, `data/`, `modules/`, `layouts/`, `mods/`
- `data/things`: omitido por default (client preserva); com `args.version` inclui só aquela versão + `keepFiles=true`
- README de publicação: `files-otc/README.md`

**Status Fase 1 (portal):** API + pasta + Alias confs.
**Status Fase 1 (OTC):** `Services.updater` aponta para WA; script `P:\OT\OTC\tools\publish-otc-release.ps1`.
Ainda falta: 1o espelho em `files-otc/` no host + teste com `data.zip` antigo.

### Packaging OTC (obrigatório para o updater ligar)

1. Build do exe (GL/DX).
2. Gerar **`data.zip`** contendo `init.lua`, `data`, `modules`, `layouts`, `mods` (mesmo espírito do `create_android_assets.ps1`).
3. Distribuição release = pasta com `WhiteAntidoteCustom.exe` + `data.zip` (não pasta `data/` solta).
4. Espelhar a **mesma árvore descompactada** em `html/files-otc/` no servidor.
5. Installer InstallAware só na 1ª instalação; patches = updater.

### Packaging APK

1. `create_android_assets.ps1` ? `assets/data.zip`.
2. Build APK ? publicar em `Downloads/whiteantidote-android.apk` quando o **binário** mudar.
3. Com updater apontando para a API WA: mudanças só em Lua/data atualizam via patch **sem** novo APK (desde que o client rode em archive mode).
4. Troca de engine/NDK/permissions = novo APK full.

### Rotina manual de release OTC/APK (sem GitHub)

1. Alterar fontes em `P:\OT\OTC\otclient-meu` (ou CustomOTC).
2. Regenerar `data.zip` / espelhar em `html/files-otc/`.
3. Se mudou exe: copiar binário para `files-otc/` e, se for 1ª instalação, atualizar installer em `Downloads/`.
4. Se mudou APK engine: substituir `Downloads/whiteantidote-android.apk`.
5. (Opcional) incrementar `APP_VERSION` no `init.lua` e republicar no `files-otc`.
6. Testar: client com `data.zip` antigo deve baixar só diffs.

---

## B) Elfbot NG ? updater **separado** (launcher)

### Por que separado

`WhiteAntidoteElfbotNG` é Tibia 8.60 clássico (`Tibia.exe`, `.dat`, `.spr`, `.pic`). **Não** há `updater.lua`.  
O installer atual empacota o client completo (`installer-whiteantidote.iit` ? `WhiteAntidote.exe`).

### Desenho mínimo do launcher

Nome sugerido: `WAUpdater.exe` (ou `WhiteAntidoteLauncher.exe`), instalado **junto** do client clássico.

Fluxo:

1. Player abre o atalho ? sobe o **launcher**, não o `Tibia.exe` direto.
2. Launcher GET/POST `classic-updater.php`.
3. Compara `localVersion` (arquivo `version.txt` na pasta do client) com `remoteVersion`.
4. Se igual ? inicia `Tibia.exe` e encerra.
5. Se diferente ? baixa zip(s) de `files-classic/`, extrai por cima da pasta de instalação (exceto configs do elfbot se marcados), atualiza `version.txt`, inicia `Tibia.exe`.

### Contrato sugerido - `classic-updater.php`

**Implementado (2026-08-04):** dois formatos na mesma API.

#### A) Extender TibiaEx / Falumir-compatible (default GET/POST)

Espelha `http://sv.falumirot.com.br/updater/updater_old.php`:

```json
{
  "ddraw.dll": { "crc32": "d8cc8b09", "size": 1200128 },
  "Tibia.dat": { "crc32": "...", "size": 4283512 },
  "Tibia.spr": { "crc32": "...", "size": 394164938 },
  "Tibia.pic": { "crc32": "...", "size": 11781052 }
}
```

Arquivos em `files-classic/` (raiz). Download: `/files-classic/<file>` ou `/updater/old/<file>`.
Status UI: `/api/classic-status.php` (ou `/updater/status.php`).

#### B) WAUpdater launcher (POST com product)

Request (exemplo):

```json
{ "product": "whiteantidote-classic", "version": "1.0.0", "os": "windows" }
```

Response:

```json
{
  "version": "1.0.1",
  "mandatory": true,
  "notes": "Sprites + IP",
  "url": "https://ot.whiteantidote.com/files-classic/patches/1.0.1.zip",
  "sha256": "...",
  "size": 12345678,
  "launch": "Tibia.exe"
}
```

Se ja atualizado:

```json
{ "version": "1.0.0", "upToDate": true, "launch": "Tibia.exe" }
```

### Conteúdo típico do patch zip (classic)

- `Tibia.dat` / `Tibia.spr` / `Tibia.pic` (quando mudarem)
- `Tibia.exe` (raro)
- **Não** sobrescrever configs do usuário/elfbot sem necessidade (excluir `*.cfg` de usuário no zip, ou lista `preserve` no manifest)

### Manifest local

Na pasta instalada:

```
version.txt          # ex: 1.0.0
WAUpdater.exe
Tibia.exe
Tibia.dat
Tibia.spr
Tibia.pic
...
```

Atalho do Menu Iniciar / Desktop aponta para `WAUpdater.exe`.

### Implementação do launcher (escolha simples)

Preferência: **um exe pequeno** (C# / Go / Rust) ? sem depender de PowerShell do usuário.

Escopo v1:

- UI mínima (barra de progresso + erro)
- HTTPS download + SHA256
- Extrair zip para o diretório do launcher
- Restart / run `Tibia.exe`
- Sem auto-update do próprio launcher na v1 (se precisar, incluir `WAUpdater.exe` no zip e reiniciar)

Alternativa ainda mais simples (MVP): script + `curl` embutido ? evitar se players tiverem AV agressivo; preferir exe único.

### Packaging / installer ElfbotNG

1. Incluir `WAUpdater.exe` + `version.txt` no InstallAware (`installer-whiteantidote.iit`).
2. Atalho ? launcher.
3. Continuar publicando `Downloads/WhiteAntidote.exe` como instalador **full** (novos players / reinstall).
4. Patches vão só para `files-classic/` + bump no `classic-updater.php` / `manifest.json`.

### Rotina manual de release classic

1. Alterar assets em `WhiteAntidoteElfbotNG\`.
2. Montar zip do patch com só arquivos mudados (ou full se preferir simplicidade no v1).
3. Subir zip em `html/files-classic/patches/<versão>.zip`.
4. Atualizar resposta do `classic-updater.php` (versão + sha256 + url).
5. Atualizar installer full em `Downloads/` quando a base mudar muito (opcional, mas recomendado periodicamente).

---

## Ordem de implementação sugerida

### Fase 1 - OTC (maior ganho, API ja conhecida) - **portal + init.lua feitos**

1. ~~Criar `portal/api/updater.php` + pasta `html/files-otc/`.~~
2. ~~Apontar `Services.updater` nos `init.lua` (workspace OTC).~~
3. Empacotar release com `data.zip` via `P:\OT\OTC\tools\publish-otc-release.ps1`; espelhar arvore em `files-otc/`; testar diff de 1 arquivo.
4. Espelhar processo no APK (assets).
5. Aplicar Alias Apache `/files-otc` no host + criar `/home/ubuntu/portal/assets/files-otc`.

### Fase 2 - Classic launcher / extender updater

1. ~~Criar `portal/api/classic-updater.php` + `html/files-classic/`.~~ (2026-08-04)
   - Default = mapa CRC32 estilo Falumir `updater_old.php`
   - `classic-status.php` = shape Falumir `status.php`
   - Alias Apache `/files-classic` + `/updater/old|status.php|updater_old.php`
   - Formato launcher zip via `product=whiteantidote-classic` + `manifest.json`
2. Implementar `WAUpdater.exe` minimo (ainda pendente; extender TibiaEx ja atualiza via CRC).
3. Integrar no installer ElfbotNG + atalho (ou patch ddraw URLs para host WA).
4. Testar patch de `.spr`/`.dat` no server de testes (`ot-test`).

### Fase 3 ? Portal UX (opcional)

- Textos na `/download` explicando ?atualiza sozinho após instalar?.
- Link de ?reinstalação completa? vs ?já tenho o client?.

---

## O que **não** fazer neste plano

- Repo GitHub / Actions para publicar patch ao player.
- Depender de `otclient.ovh` em produção.
- Esperar que pasta `data/` solta (dev) rode o updater OTC.
- Usar o updater OTC no client ElfbotNG.

---

## Como prosseguir neste workspace (instruções ao agente / humano)

Abrir no Cursor:

`P:\OT\OTSERVER\pedro\otx2-html.code-workspace`

Prompt sugerido (copiar):

```
Leia html/docs/client-updater-context.md e implemente a Fase 1:
- portal/api/updater.php (contrato OTCv8)
- pasta html/files-otc/ (estrutura + README de como publicar)
- não use GitHub Actions
Depois descreva o checklist manual de release.
Não implemente ainda o launcher ElfbotNG (Fase 2) a menos que eu peça.
```

Para a Fase 2 (classic), no **mesmo** workspace portal + um projeto pequeno do launcher (pode viver em `P:\OT\OTC\tools\wa-classic-updater\` ou pasta dedicada):

```
Leia html/docs/client-updater-context.md seção B e implemente:
- classic-updater.php + files-classic/
- especificação + esqueleto do WAUpdater.exe
Clients fonte: P:\OT\OTC\WhiteAntidoteElfbotNG
```

No workspace OTC, em paralelo quando a API existir:

```
Aponte Services.updater para https://ot.whiteantidote.com/api/updater.php
em otclient-meu/init.lua e WhiteAntidoteCustomOTC/init.lua
e documente/gere script local de data.zip para release (sem GitHub).
```

**Feito:** updater URL + `tools/publish-otc-release.ps1`. Proximo: `-MirrorFilesOtc` + sync no host.

---

## Referências rápidas de paths

| Item | Path |
|---|---|
| Workspace portal | `P:\OT\OTSERVER\pedro\otx2-html.code-workspace` |
| Portal API | `P:\OT\OTSERVER\pedro\html\portal\api\` |
| Downloads prod | `P:\OT\OTSERVER\pedro\html\Downloads\` |
| Download UI | `P:\OT\OTSERVER\pedro\html\portal\src\app\download\page.tsx` |
| OTC source | `P:\OT\OTC\otclient-meu\` |
| OTC dist | `P:\OT\OTC\WhiteAntidoteCustomOTC\` |
| Classic dist | `P:\OT\OTC\WhiteAntidoteElfbotNG\` |
| Updater módulo | `...\modules\updater\updater.lua` |
| Android zip script | `otclient-meu\create_android_assets.ps1` |
| Installers | `P:\OT\OTC\installer-whiteantidote*.iit` |

<!-- END CHANGE -->


<!-- BEGIN CHANGE: Inno Setup Extended 2026-08-25 -->
### Classic Extended Setup (Inno)
- Script: P:/OT/OTC/launcher/inno/wa-customclient-setup.iss
- Build: P:/OT/OTC/tools/build-extended-setup.ps1
- Output: html/Downloads/WA-CustomClient-Setup.exe
- Install: %%LOCALAPPDATA%%\\WhiteAntidote\\CustomClient\\
- Shortcut targets updater every launch (CRC then client).
<!-- END CHANGE -->

<!-- BEGIN CHANGE: Inno Setup OTC 2026-08-25 -->
### Custom OTC Setup (Inno)
- Script: P:/OT/OTC/launcher/inno/wa-otc-setup.iss
- Build: P:/OT/OTC/tools/build-otc-setup.ps1
- Output: html/Downloads/WA-OTC-Setup.exe
- Icon: html/Downloads/otc-icone.ico (launcher + Setup; not Tibia.ico)
- Install: %%LOCALAPPDATA%%\\WhiteAntidote\\OTC\\
- Shortcut targets updater every launch (CRC then client). Portal /download points here.
<!-- END CHANGE -->
