Inhaltsverzeichnis
Effektives Debugging
Wie schon in Fehler finden und beheben angesprochen wurde, sind Skripte nach dem Erstellen meist nicht fehlerfrei. In Häufige Fehler werden häufige Stolpersteine angesprochen, sobald aber Skripte und damit auch die möglichen Fehler komplexer werden, wird das Debugging schwerer. Daher sollen auf dieser Seite Strategien vorgestellt werden, mit denen auch kompliziertere Bugs gefunden werden können.
Arten von Fehlern
Üblicherweise unterscheidet man drei Arten von Fehlern:
- Syntaktische Fehler: Hierbei handelt es sich um Fehler bezüglich der „Grammatik“ von LUA. Diese werden sowohl von dem debugscript als auch von dem LuaDebugger erkannt, sobald das fehlerhafte Skript geladen wird. Tritt ein solcher Fehler auf, so wird das Skript nicht ausgeführt. Übliche Symptome sind, dass das GFX-Set nicht gesetzt wird, wodurch alles in einen schwarzen Nebel gehüllt wird und auch sonst nichts auf der Karte passiert.
- Semantische Fehler: Hierbei handelt es sich um Fehler, die durch die falsche Verwendung der von Siedler bereitgestellten Funktionen auftreten, z.B. weil diese Funktionen falsche Argumente erhalten. Beispiele hierfür sind
GetPosition("EntityNameWithATypo")
oder
Logic.CreateEntity("PU_Serf", pos.X, pos.Y, rot, pId)
In jedem Fall wird die jeweilige Funktion nicht ausgeführt. Falls eine der Comfortfunktionen falsch benutzt wird, kommt es üblicherweise zu einem „assertion failed“, bei anderen Funktionen wie z.B. den Logic-Funktionen können die Konsequenzen von „garnichts“ bis zu einem Spielabsturz reichen.
- Logische Fehler: Hierbei handelt es sich um Fehler, die sowohl LUA als auch die von Siedler bereitgestellten Funktionen korrekt nutzen, aber trotzdem nicht das gewünschte Verhalten zeigen. Diese Fehler sind üblicherweise am schwersten zu korrigieren, aber mit den hier vorgestellten Methoden auffindbar.
Da syntaktische Fehler von dem Debugger mit Zeilenangabe gefunden werden, werden diese im Folgenden nicht beachtet werden.
Strategien
Die hier vorgestellten Strategien sind nach Aufwand und Verzweiflungslevel geordnet, daher ist es empfohlen, mit die Methoden in der vorgestellten Reihenfolge abzuarbeiten.
Strategie 1: Alles mit Messages zukleistern
Um Fehler zu finden, ist es hilfreich, zu verstehen, welche Variable zu welchem Zeitpunkt welchen Wert besitzt. Die einfachste Methode, den Inhalt von Variablen zu einem gewissen Zeitpunkt auszulesen, ist es, den Wert mittels
Message
oder
LuaDebugger.Log
auszugeben. Hierbei ist es sinnvoll, zwei Regeln zu folgen:
- Jede Ausgabe sollte mit einem kleinen Text versehen werden, um später die Ausgabe auch der richtigen Variable und dem richtigen Zeitpunkt zuordnen zu können.
- Es sollten genug Werte ausgegeben werden, um nachvollziehen zu können, was im Code passiert, aber nicht so viele, dass die Ausgabe unlesbar wird.
TODO: Beispiel bringen?
Strategie 2: Breakpoints setzen
Falls die erste Strategie nicht ausreichend ist, um zu verstehen, was im Code nicht so abläuft wie erwartet, wäre es schön, den Code einfach anhalten zu können. Glücklicherweise ist genau das mit Breakpoints möglich! Wird mit aktivem LuaDebugger die Funktion
LuaDebugger.Break
ausgeführt, so wird Siedler pausiert und es ist möglich, mithilfe des Debuggers den Wert der im aktuellen Scope verfügbaren Variablen ausgeben zu lassen. Außerdem ist es möglich, mithilfe des LuaDebuggers das Programm danach Schritt für Schritt ausführen zu lassen. Während der Breakpoint ausgelöst ist, verändert sich die Oberfläche des LuaDebuggers etwas:
- Mit Resume wird die durch den Breakpoint erzwungene Pause beendet.
- Mit Step Line wird nur die nächste Codezeile ausgeführt.
- Mit Step In wird, sofern die Pause direkt vor einem Funktionsaufruf stattfindet, der „Zeiger“ an den Anfang der auszurufenden Funktion gesetzt.
- Mit Step Out wird die Pause solange aufgehoben, bis die Ausführung der aktuellen Funktion vorbei ist, dann wird das Spiel wieder pausiert und der „Zeiger“ ist in der nächsthöheren Ebene.
Achtung: Werden im Multiplayer Breakpoints gesetzt, so wird, während die Pause aktiv ist, auch die Kommunikation mit dem Server pausiert. Daher ist es möglich, dass der Server, da dieser keine Pakete vom Client erhält, die Verbindung trennt.
TODO: Beispiel?