Oblivion:Debuggen von Scripts

Aus Skript-Wiki
Wechseln zu: Navigation, Suche

Einleitung

Das Debuggen im CS ist ziemlich zeitaufwändig und die mitgelieferten Tools sind nicht sehr zufriedenstellend. Hier sind also Hinweise zum Debuggen von Scripts, falls unerwünschte Ergebnisse aufkommen sollten.


Script Processing

Zuerst sollte ein Blick auf das Script Processing geworfen werden, um zu verstehen wie die einzelnen Script-Arten funktionieren.

Nur Quest Scripts werden durchgehend in bestimmten Abständen ausgeführt.

Objekt Scripts werden jeden Frame ausgeführt, aber es kann sein, dass sie für eine Weile nicht ausgeführt werden, wenn der Spieler nicht in der Nähe ist. Es gibt sogar Fälle, in denen die AI das Ausführen der Scripts verhindert. Dies ist der Fall für Follow-Packages, falls sie Bedingungen von Script-Variablen des selben Objektes abfragen.

Um herauszufinden, ob ein Script ausgeführt wird, kann einfach ein Code wie Folgender eingebaut und anschließend ingame geprüft werden:

<tesscript>; long benutzen, falls die Frames über längeren

Zeitraum beobachtet werden sollen

short FramesRun

Begin GameMode Set FramesRun To FramesRun + 1

... restlicher Code

End</tesscript>


Kontrollieren von Variablen

Es gibt verschiedene Möglichkeiten, den momentanen Inhalt von Variablen zu überprüfen.

Der einfachste und zuverlässigste Weg wären die Konsolen-Funktionen - zum Beispiel prid und tst oder sv. Damit lässt sich immer der aktuelle Inhalt einer Variable erhalten.

Also zuerst das zu kontrollierende Objekt aktivieren (mit einem NPC reden, ein Buch lesen, etc.), dann die Konsole öffnen. Am oberen Rand des Bildschirms lässt sich nun die FormID ablesen. Falls nicht, muss das Objekt mit einem Linksklick auf die Maus ausgewählt werden.

Falls das entsprechende Objekt nicht ausgewählt werden kann (weil es in einer andere Zelle, oder disabled ist), kann es mit prid ausgewählt werden, sofern die FormID bekannt ist. Das prid-Kommando kann zu jedem Objekt wechseln, wenn also das Script eines NPCs geprüft werden soll und der NPC die FormID 0b002089 hat, muss einfach Folgendes eingegeben werden:

<tesscript>prid 0b002089</tesscript>

Falls es in dem Script nicht zu viele Variablen gibt, lässt sich ShowVars/sv verwenden um sie anzeigen zu lassen. Dazu einfach eingeben:

<tesscript>sv</tesscript>

Falls viele Variablen genutzt werden, werden möglicherweise nur die Letzten angezeigt. In dem Fall können mit Bild-Hoch auch die restlichen Variablen angezeigt werden.

Eine spezielle Variable lässt sich mit Show/tst ausgeben. Wenn nun also kontrolliert werden soll, wie oft das Script ausgeführt wurde und falls eine FrameRuns-Variable eingesetzt wurde, einfach Folgendes eingeben:

<tesscript>show FrameRuns</tesscript>

Falls diese Variable nicht bei jedem neuen Öffnen der Konsole größer wird, könnte es sein, dass ein AI Package das Script an der Ausführung hindert.

Um alle Variablen eines Quests anzeigen zu lassen, kann ShowQuestVariables(oder sqv) verwendet werden:

<tesscript>sqv QuestID</tesscript>

Aufpassen, wenn in dem Script Message oder MessageBox genutzt wird!

Message kann hilfreich sein um herauszufinden, welcher Teil des Codes grade ausgeführt wird, oder welchen Wert eine Variable grade hat, aber da eine Nachricht immer eine Sekunde lang angezeigt wird, kommen aufeinanderfolgende Nachrichten erst verspätet. Das bedeutet, dass der Wert, der angezeigt wird sich schon wieder verändert haben könnte. Die PrintToConsole-Funktion von OBSE kann dies vereinfachen.

MessageBox verhält sich da anders. Falls mehrere Messageboxen angezeigt werden sollen, kann es vorkommen, dass nur die letzte angezeigt wird und der Rest ignoriert wird, aber es sollte dennoch funktionieren.

Zumindest gibt MessageBox den aktuellen Wert aus.


Bugs finden, die nicht vom CS oder Oblivion gemeldet werden

Das CS gibt normalerweise ein paar Hinweise aus, wenn ein Script gespeichert wird. Allerdings ist das recht unzuverlässig, da nur Syntax-Fehler angezeigt werden - zum Beispiel, wenn auf Objekte verwiesen wird, die nicht existieren, oder wenn inkorrekte If-Blöcke enthalten sind.

Trotzdem können Fehler geschehen, die nicht vom CS erkannt werden.

Leider unterstützt Oblivion keine Ingame-Fehlermeldungen. Falls in einem Script ein Fehler auftritt, wird das entsprechende Script einfach beendet, ohne den Nutzer zu informieren. Deswegen ist es hilfreich, eine Variable einzubauen, die sich jeden Frame erhöht - durch das Überprüfen dieser Variable lässt sich feststellen, ob ein Script beendet wurde, oder noch läuft.

Hier ein Beispiel: Es hat einen ganzen Tag gedauert, bis ich feststellen konnte, dass mein Script nicht ausgeführt wurde. Der Grund war, dass ich die Befehle GetCurrentAIPackage und GetIsCurrentPackage verwechselt habe.

Also hat dieser Teil

<tesscript>If ( GetCurrentAIPackage "00MyPackage1" )

  Set PackageLoaded To 1

ElseIf ( GetCurrentAIPackage "00MyPackage2" )

  Set PackageLoaded To 2

...</tesscript>

den Interpreter das Script zum Anhalten bringen lassen. Falls das "00MyPackage" Verwunderung verursacht: die Apostrophe sind empfehlenswert, wenn eine EditorID mit Ziffern beginnt. Ich habe dort zwei Nullen einsetzt, damit mein Objekt immer ganz oben gelistet wird.

Was ich also eigentlich machen musste, war Folgendes:

<tesscript>If ( GetIsCurrentPackage "00MyPackage1" )

  Set PackageLoaded To 1

ElseIf ( GetIsCurrentPackage "00MyPackage2" )

  Set PackageLoaded To 2

...</tesscript>

Aber das Script wurde problemlos gespeichert und ich bekam ingame keine Meldungen über einen Fehler. Das kommt daher, dass der Compiler häufig zusätzliche Parameter ignoriert. So werden diese Zeilen zum Beispiel - obwohl sie inkorrekt sind - problemlos gespeichert:

<tesscript>disable objectID 1 PickIdle My name is Bob</tesscript>

Das GetCurrentAIPackage funktionierte in dem Fall wie ein Return-Befehl, so dass kein Code nach dem ersten Auftreten von GetCurrentAIPackage mehr ausgeführt wurde, da es nicht richtig eingesetzt wurde, obwohl ein gültiges Package angegeben war. Hier noch ein Beispiel dazu:

<tesscript>GetCurrentAIPackage "ValidPackageName" PickIdle My name is Bob</tesscript>

Oder

<tesscript>If ( GetCurrentAIPackage "ValidPackageName" )

 PickIdle My name is Bob

EndIf</tesscript>

Du möchtest vielleicht das Folgende mit einem NPC der nicht zum Package gehört testen, aber du wirst feststellen, dass das Script ohne gültiges Package nicht gespeichert werden kann. Außerdem kann es vorkommen, dass das Script nachher nicht mehr ausgeführt wird. In meinem Fall blieb FramesRun bei dem Wert 1, auch wenn ich mit dem NPC geredet habe - Details zu meinem Spiel siehe unten.

<tesscript>short FramesRun Begin GameMode

Set FramesRun To FramesRun+1 Message "Test vor GetCurrentAIPackage"

If ( GetCurrentAIPackage aaaCreatureExterior1500 )

  Message "Test aaaCreatureExterior1500 package name"

EndIf

Message "Still alive"

... weiterer Code End</tesscript>

Du siehst also, verschiedene Funktionen (besonders welche, die auch wie ein Return-Befehl funktionieren können) können sich unerwartet verhalten, während andere dies nicht tun!

Details zu meiner Konfiguration: Ich spiele mit einer deutschen Version mit Patch V1.1, Oblivion Deutsch 3.0 und BTMod 2.20


Debug-Nachrichten ingame an bestimmten Stellen

Falls du an einem bestimmten Punkt eine Message oder MessageBox erhalten möchtest, ist es hilfreich eine debugOn-Variable im Script zu definieren und sie mit mit Hilfe eines General Topics oder Quest Topics zu setzen.

Der Code würde so aussehen:

<tesscript>short debugOn ... dein Code If debugOn

  Message "Was auch immer ausgegeben werden sol %.0f" MyVar

EndIf ... dein Code If debugOn

  Message "Was auch immer ausgegeben werden sol %.0f" MyVar2

EndIf ... und so weiter

und falls du die Nachrichten gerne pro Frame
haben möchtest, füge ein ShowEnchantment am Anfang
oder Ende des GameMode-Blocks hinzu

If debugOn

  ShowEnchantment

EndIf</tesscript>

Vielleicht möchtest du das Debuggen aber auch erst an einer bestimmten Stelle starten. Nichts leichter als das:

<tesscript>short debugOn

notfalls Teile auskommentieren

Set debugOn to 0 ... dein Code If debugOn

  Message "Was auch immer ausgegeben werden soll %.0f" MyVar

EndIf ... dein Code If YourConditionBlockToInspect

 Set debugOn to 1
 ; ab hier die Nachrichten
 If debugOn
    Message "Was auch immer ausgegeben werden soll %.0f" MyVar2
 EndIf
 ; und falls du die Nachrichten gerne pro Frame
 ; haben möchtest, füge ein ShowEnchantment am Anfang 
 ; oder Ende des GameMode-Blocks hinzu:  
 ShowEnchantment
 ; Ich habe nicht in allen Fällen geprüft, ob ShowEnchantment 
 ; wie ein Return-Befehl funktioniert(normalerweise nicht) 
 ; Aber dann aufpassen bei Scripts, die nur bis zu diesem  
 ; Punkt ausgeführt werden und notfalls auskommentieren
 ; Ab hier keine Nachrichten mehr
 Set debugOn to 0

EndIf ... und so weiter</tesscript>

In der finalen Version des Scripts sollten die Debug-Nachrichten und debugOn-Blöcke entfernt werden, da das Script dadurch nur unnötig länger braucht, um ausgeführt zu werden.


Weiterführende Links