# Depuração e desempenho

> Por que um tick está lento, por que um comando não teve efeito, por que o jogo não se mexe. Investigue pelo sintoma e confirme com os scripts de verificação em partidas reais que vêm no projeto.

Fonte: https://war3ai.com/pt/docs/debugging/

## Veja o recibo

O recibo de cada comando é a pista de primeira mão:

```python
r = g.cast(hero, "blizzard", x=tx, y=ty)
if not r:
    print(r.reason, r.verdict)     # rejected（…） e o código de motivo
print(r.exec_us, r.engine_us)      # microssegundos que este comando levou na thread do jogo / quanto disso foi a própria função de ordem do motor
```

Normalmente, um comando leva de alguns microssegundos a algumas centenas de microssegundos na thread do jogo. Ao fim de um bloco de lote, `g.last_receipts` contém o recibo de cada comando do lote.

## Veja dentro do jogo

```python
g.say(unit, "Recuar")          # um balão de fala aparece sobre a unidade (não afeta o jogo)
g.message("Indo creepar")      # uma linha na área de mensagens, no canto inferior esquerdo (só visível nesta máquina)
```

O que você imprime com `print` aparece no terminal onde o Bot está rodando. Imprimir as decisões-chave de cada tick, junto com os balões de fala, é muito mais rápido do que ler o código.

## Um tick está lento

Veja primeiro se é um destes casos:

| Causa | Correção |
|---|---|
| Enviar comandos um a um, cada um esperando um frame | Envolva em `with g.batch():`; dezenas de comandos esperam uma vez só |
| Chamar `g.visible()` / `g.can_do()` uma a uma (cada chamada passa pela via rápida e espera um frame) | Para visibilidade, use `u.visible_to()` do snapshot; para viabilidade, pergunte em lote com `g.can_do_many([...])` |
| `sleep` ou espera dentro de `on_tick` | Anote o tempo de jogo e verifique de novo no tick seguinte |
| Recalcular algo caro a cada tick (caminhos, varredura do mapa inteiro) | Guarde o resultado em cache e recalcule a cada poucos ticks. `g.grid()` já tem cache de 2 segundos, e os níveis de tecnologia de `g.stats()` são atualizados a cada 5 segundos |

## O jogo não se mexe / o Bot não consegue entrar na partida

| Sintoma | Causa provável |
|---|---|
| Fica sempre “esperando a partida” | Número de instância errado; ou a janela do jogo está **minimizada** — minimizado, a simulação do jogo para (o relógio não anda) |
| O jogo roda, mas as ordens do Bot não têm efeito | Ordens para unidades de outro jogador (recibo `not_owner`); ou o Bot se conectou como observer (`forbidden`) |
| O comando fica `held` | A unidade está presa por uma camada de prioridade maior (a camada reflexa do cérebro de referência, uma ordem manual do console) e o comando não foi enviado |
| Ainda dá para dar comandos com o jogo pausado | Normal: na pausa, o relógio do motor para, mas a distribuição de eventos continua e os comandos são executados normalmente |

## Conecte e veja o status

```bash
python -m openwar3 status --inst 5
```

Mostra o estado da conexão: pid do jogo, período de publicação do mundo e tempo de cada coleta, contadores da via rápida, se há uma partida em andamento, número de unidades, relógio do jogo.

## Scripts de verificação em partidas reais

Abra uma instância de teste e verifique, item por item, se os recursos do SDK funcionam na sua máquina:

```bash
python tools/sdk_live_check.py --inst 20                 # tudo
python tools/sdk_live_check.py --inst 20 --only prod     # só uma seção
```

Seções: lote, tempo, produção, comandos em fila, atributos de combate, caminhos, modo justo. Cada seção dá comandos numa partida real, lê o efeito de volta e imprime quantos itens passaram.

Os testes offline não precisam do jogo aberto:

```bash
python tools/run_tests.py
```

## “Parece bug”, mas não é

- **O recibo de construção foi aceito, mas a fundação nunca aparece**: o motor aceita na hora até pontos dentro da floresta, e a falha só vem quando o trabalhador chega. Use `build_near`, que acompanha a construção e põe o ponto que falhou numa lista negra por um tempo.
- **O recibo do feitiço foi aceito, mas nada foi lançado**: ele foi interrompido ou faltou mana. No tick seguinte, veja se `g.cooldown()` entrou em recarga.
- **A ordem de ataque foi aceita, mas as tropas atacam outro alvo**: para atacar um alvo específico, use `g.attack(tropa, inimigo)` (semântica do clique direito). A ordem de ataque crua só troca a ordem, sem registrar o alvo, e a unidade vai atacar outra coisa por perto.
- **A contagem de trabalhadores não bate**: trabalhadores dentro da mina de ouro não estão no snapshot.
- **Não dá para treinar o herói que morreu**: o herói é único; use `g.revive(altar)`. Reviver exige comida, e só é possível cerca de 3 segundos de jogo depois da morte.
