# Debugging & Performance

> Warum ein Tick langsam ist, warum ein Befehl nicht greift, warum das Spiel steht: nach Symptom eingrenzen, dann mit den mitgelieferten Live-Prüfskripten bestätigen.

Quelle: https://war3ai.com/de/docs/debugging/

## Quittungen lesen

Die Quittung jedes Befehls ist die erste Spur:

```python
r = g.cast(hero, "blizzard", x=tx, y=ty)
if not r:
    print(r.reason, r.verdict)     # rejected（…） und der Reason-Code
print(r.exec_us, r.engine_us)      # Mikrosekunden auf dem Spiel-Thread / davon in der Befehlsfunktion der Engine selbst
```

Normalerweise kostet ein Befehl auf dem Spiel-Thread einige bis einige hundert Mikrosekunden. Nach einem Batch-Block enthält `g.last_receipts` die Quittung jedes einzelnen Befehls dieses Batches.

## Im Spiel beobachten

```python
g.say(unit, "Rückzug")         # Chat-Blase über der Einheit (beeinflusst das Spiel nicht)
g.message("Creepen beginnt")   # eine Zeile im Nachrichtenbereich unten links (nur lokal sichtbar)
```

Ausgaben von `print` landen im Terminal, in dem der Bot läuft. Die wichtigsten Entscheidungen jedes Ticks ausgeben und dazu die Sprechblasen nutzen – das geht viel schneller, als den Code zu lesen.

## Ein Tick ist langsam

Prüf zuerst, ob einer dieser Fälle vorliegt:

| Ursache | Lösung |
|---|---|
| Befehle einzeln gesendet, jeder wartet einen Frame | In `with g.batch():` packen – Dutzende Befehle warten nur einmal |
| `g.visible()` / `g.can_do()` einzeln aufgerufen (jeder Aufruf geht über die Schnellspur und wartet einen Frame) | Sichtbarkeit per `u.visible_to()` aus dem Snapshot; Machbarkeit gebündelt per `g.can_do_many([...])` |
| `sleep` oder Warten in `on_tick` | Spielzeit merken und im nächsten Tick erneut prüfen |
| Teures in jedem Tick neu berechnen (Wegfindung, Scans der ganzen Karte) | Ergebnisse cachen, nur alle paar Ticks neu rechnen. `g.grid()` hat einen eigenen 2-s-Cache, die Technologiestufen in `g.stats()` werden 5 s gecacht |

## Spiel steht / Bot wartet ewig auf Spielbeginn

| Symptom | Meistens |
|---|---|
| Hängt dauerhaft bei „warte auf Spiel“ | Falsche Instanznummer; oder das Spielfenster ist **minimiert** – minimiert steht die Spielsimulation (die Uhr läuft nicht) |
| Spiel läuft, Bot-Befehle bewirken nichts | Befehle an fremde Einheiten (Quittung `not_owner`); oder der Bot ist als observer verbunden (`forbidden`) |
| Befehl ist `held` | Die Einheit wird von einer höher priorisierten Schicht gehalten (Reflex-Schicht des Referenz-Brains, manueller Befehl aus der Konsole) und der Befehl nicht gesendet |
| Nach einer Pause gehen Befehle noch durch | Normal: In der Pause steht die Engine-Uhr, aber Event-Dispatch und Befehlsausführung laufen weiter |

## Verbinden und Status prüfen

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

Gibt den Verbindungsstatus aus: Spiel-PID, Veröffentlichungsintervall der Welt und Dauer jeder Erfassung, Zähler der Schnellspur, ob ein Spiel läuft, Einheitenzahl, Spieluhr.

## Live-Prüfskripte

Starte eine Testinstanz und prüfe Punkt für Punkt, ob die SDK-Fähigkeiten auf deinem Rechner funktionieren:

```bash
python tools/sdk_live_check.py --inst 20                 # alles
python tools/sdk_live_check.py --inst 20 --only prod     # nur einen Abschnitt prüfen
```

Abschnitte: Batch, Zeit, Produktion, Befehle mit Warteschlange, Kampfwerte, Wegfindung, Fair-Modus. Jeder Abschnitt erteilt in einem echten Spiel Befehle, liest die Wirkung zurück und gibt die Zahl der bestandenen Prüfungen aus.

Offline-Tests brauchen kein laufendes Spiel:

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

## Typische „sieht aus wie ein Bug“-Fälle

- **Bau-Quittung angenommen, aber nie ein Fundament**: Auch einen Punkt im Wald nimmt die Engine sofort an; scheitern tut der Befehl erst, wenn der Arbeiter ankommt. `build_near` verfolgt das und sperrt fehlgeschlagene Punkte eine Zeit lang.
- **Fähigkeit angenommen, aber nicht gewirkt**: Unterbrochen, oder kein Mana. Im Tick danach prüfen, ob `g.cooldown()` läuft.
- **Angriff angenommen, aber die Einheiten greifen etwas anderes an**: Für ein konkretes Ziel `g.attack(units, enemy)` verwenden (Rechtsklick-Semantik). Der rohe Angriffsbefehl ändert bei einem Ziel nur die Order, merkt sich das Ziel aber nicht und greift dann etwas anderes in der Nähe an.
- **Arbeiterzahl stimmt nicht**: Arbeiter in der Goldmine fehlen im Snapshot.
- **Toter Held lässt sich nicht ausbilden**: Helden sind einzigartig, du brauchst `g.revive(altar)`; Wiederbeleben kostet Nahrung und geht erst etwa 3 Spielsekunden nach dem Tod.
