# Depuración y rendimiento

> Por qué un tick va lento, por qué un comando no surtió efecto, por qué el juego no se mueve. Diagnostica por síntomas y confírmalo con los scripts de verificación en vivo incluidos.

Fuente: https://war3ai.com/es/docs/debugging/

## Mira el recibo

El recibo de cada comando es la primera pista:

```python
r = g.cast(hero, "blizzard", x=tx, y=ty)
if not r:
    print(r.reason, r.verdict)     # rejected（…） y el código de motivo
print(r.exec_us, r.engine_us)      # microsegundos en el hilo del juego / de ellos, cuánto tardó la propia función de órdenes del motor
```

Lo normal es que un comando tarde entre unos microsegundos y unos cientos de microsegundos en el hilo del juego. Al terminar un bloque de lote, `g.last_receipts` contiene el recibo de cada comando del lote.

## Míralo en el juego

```python
g.say(unit, "¡Retirada!")               # burbuja de chat sobre la unidad (no afecta al juego)
g.message("Voy a hacer creeping")       # una línea en el área de mensajes de abajo a la izquierda (solo se ve en tu equipo)
```

Lo que imprimas con `print` aparece en la terminal donde se ejecuta el Bot. Imprimir las decisiones clave de cada tick, junto con las burbujas, es mucho más rápido que leer el código.

## Un tick va lento

Primero comprueba si es uno de estos casos:

| Causa | Solución |
|---|---|
| Enviar los comandos uno a uno, cada uno esperando un fotograma | Envuélvelos en `with g.batch():`; decenas de comandos esperan una sola vez |
| Llamar a `g.visible()` / `g.can_do()` una y otra vez (cada llamada va por el carril rápido y espera un fotograma) | Para la visibilidad, usa `u.visible_to()` del snapshot; para la viabilidad, pregunta en lote con `g.can_do_many([...])` |
| `sleep` o esperas dentro de `on_tick` | Anota el tiempo de juego y vuelve a comprobarlo en el siguiente tick |
| Recalcular cosas caras en cada tick (rutas, barridos de todo el mapa) | Cachea el resultado y recalcula cada varios ticks. `g.grid()` trae una caché de 2 segundos, y los niveles de tecnología de `g.stats()` se cachean 5 segundos |

## El juego no se mueve / el Bot nunca entra en la partida

| Síntoma | Causa probable |
|---|---|
| Se queda siempre "esperando a la partida" | Número de instancia incorrecto, o la ventana del juego está **minimizada**: al minimizarla, la simulación se detiene (el reloj no avanza) |
| El juego corre, pero las órdenes del Bot no hacen nada | Estás dando órdenes a unidades ajenas (recibo `not_owner`), o el Bot se conectó con el rol observer (`forbidden`) |
| Comandos `held` | Una capa de mayor prioridad retiene esa unidad (la capa de reflejos del cerebro de referencia, las órdenes manuales de la consola) y no se enviaron |
| Se pueden dar comandos en pausa | Es normal: en pausa el reloj del motor se detiene, pero el despacho de eventos sigue funcionando y los comandos se ejecutan |

## Conéctate y mira el estado

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

Muestra el estado de la conexión: pid del juego, ciclo de publicación del mundo y tiempo de cada recogida, contadores del carril rápido, si hay partida en curso, número de unidades y reloj del juego.

## Scripts de verificación en vivo

Abre una instancia de prueba y comprueba, punto por punto, que las capacidades del SDK funcionan en tu máquina:

```bash
python tools/sdk_live_check.py --inst 20                 # todo
python tools/sdk_live_check.py --inst 20 --only prod     # solo una sección
```

Secciones: lotes, tiempo, producción, órdenes en cola, estadísticas de combate, rutas, modo justo. Cada sección da comandos en una partida real, lee el efecto e imprime cuántas comprobaciones pasan.

Las pruebas offline no necesitan abrir el juego:

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

## Cosas que "parecen un bug"

- **El recibo de construcción fue aceptado, pero nunca aparecen los cimientos**: el motor acepta al momento incluso un punto dentro de un bosque; falla cuando llega el trabajador. Usa `build_near`, que hace el seguimiento y veta durante un tiempo los puntos que fallan.
- **El recibo del hechizo fue aceptado, pero no se lanzó**: lo interrumpieron o faltaba maná. En el tick siguiente, comprueba si `g.cooldown()` ha entrado en enfriamiento.
- **La orden de ataque fue aceptada, pero las tropas atacan a otro**: para atacar un objetivo concreto, usa `g.attack(unidad, enemigo)` (semántica de clic derecho). La orden de ataque en bruto sobre un objetivo solo cambia la orden sin fijar el objetivo, y la unidad acaba atacando a otra cosa cercana.
- **El número de trabajadores no cuadra**: los trabajadores que están dentro de la mina de oro no aparecen en el snapshot.
- **No puedo entrenar al héroe que murió**: el héroe es único; usa `g.revive(altar)`. Revivir requiere comida y solo es posible unos 3 segundos de juego después de su muerte.
