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.
Quittungen lesen
Die Quittung jedes Befehls ist die erste Spur:
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
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
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:
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:
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_nearverfolgt 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.