Debug Dumps

From GECK
Jump to: navigation, search

Overview

There are various functions in NVSE that allow you to dump debugging information from any game to a text file. This is highly useful when attempting to solve third party bug reports, as all the information you need may be provided by the user simply uploading you a text file, created by running a script which could be triggered by clicking an MCM button, or by console adding some object or spell, etc.

This article describes a template of useful features you may want to include in a debug dump script.

Start

scn CreateDebugDump

int LastEcho
int iTotalMods
int iIndex
array_var UT
array_var aQuests
array_Var aObjects
array_var entry
string_var file_name
string_var svkey
string_var FO_dir
ref rQuest
ref rObject

Begin Function { }

A User Defined Function is a convenient way to run the script, although it could just as easily be on object OnAdd or spell ScriptEffectStart. Above is the variable declaration for the proceeding examples.

File naming

    let file_name := "MyModName-Debug-Dump-"
    let UT := GetUserTime
    foreach entry <- (Ar_List "Year", "Month", "Day", "Hour", "Minute", "Second")
        let svkey := entry["value"]
        if eval svkey == "Hour"
            let file_name += "-"
        endif
        let file_name += "-" + $UT[svkey]
    loop
    let file_name += ".txt"

    con_SCOF $file_name

    Print "Starting debug dump to file: " + file_name

A String Variable and the GetUserTime function can be used to create a unique and recognizable file name for your dump, based on your mod name and the real life time it is created. The Con_SCOF command writes all console output to the specified file, which will be found in the main game directory of the user. The Print command outputs text to the console, and supports many convenient features. (See also the string variables tutorial)

The debug dump file name will look like: "MyModName-Debug-Dump-YEAR-MONTH-DAY--HOUR-MINUTE-SECOND.txt"

Versions

; * Versions
    Print "My Mod Version: " + $MyModMainQuest.version
    Print "My Mod's Master Version: " + $MyMasterMainQuest.version
    Print "NVSE Version: " + $(GetNVSEVersion) + "." + $(GetNVSERevision) + "." + $(GetNVSEBeta)
    Print "NX (An NVSE plugin) Version: " + $(NX_GetVersion)

It is helpful to reliably know what version of your mod, and any requirements it might have that the user has installed. The ToString($) command converts anything to a string for printing. Notice Print allows direct printing of quest variables and function returns (eg: $(GetNVSEVersion), the added brackets allow clear distinction of functions).

Load Order

; * Load Order
    Print "Load Order:"
    let iTotalMods := GetNumLoadedMods
    let iIndex := 0
    while iIndex < iTotalMods
        Print (NumToHex iIndex, 2) + " (" + $iIndex + "): " + (GetNthModName iIndex)
        let iIndex += 1
    loop
    Print " * End Load Order *"

By using GetNthModName you can find out for certain what a user's load order is. This prints all loaded mods with their index in both hexadecimal and decimal. (See also: GetNumLoadedMods, While, NumToHex)

Quest Statuses

; * Quest statuses
    let aQuests := Ar_List MyQuest1, MyQuest2, MyQuest3 ... MyQuest20

    let LastEcho := SetConsoleEcho 1
    foreach entry <- aQuests
        let rQuest := entry["value"]
        Print "Quest: " + $rQuest
        con_SQV rQuest
        Print " * * * * * "
    loop
    SetConsoleEcho LastEcho

The Con_SQV command human readably prints the name and value of all variables attached to a quest (except array_var and string_var, which you get the ID number, not contents), and it's current running status, stage and priority. You need to use SetConsoleEcho before calling it, however.

Above, we create an array with Ar_List and put all the quests we want to dump in it. You can specify up to 20 entries in one Ar_List call, see the arrays tutorial if you want more than 20 entries. Then we print the name of the quest '$rQuest' and do Con_SQV for each one.

Object Script Variables

; * Object Variable Statuses
    let aObjects := Ar_List SunnyREF, MyActorREF, MyDoorREF, PlayerREF...
    let LastEcho := SetConsoleEcho 1
    foreach entry <- aObjects
        let rObject := *entry ; '*' is shorthand for entry["value"]
        Print "Variables for " + $rObject
        Con_ShowVars rObject
        Print " * * * * * "
    loop
    SetConsoleEcho LastEcho

The function, Con_ShowVars is similar to Con_SQV for quests; it prints the name and value of all variables in object scripts attached to the reference (including those on their inventory items). It also requires console echo to be toggled on.

Actor Inventory

; * Player inventory
    Print "Player Inventory: "
    let LastEcho := SetConsoleEcho 1
    PlayerREF.Con_Inv
    SetConsoleEcho LastEcho
    Print " * End Inventory *"

The Con_Inv command is equivalent to typing Inv into the game console to print the contents of an inventory. This command also requires console echo to be toggled on. (You can just toggle it on once at start, if you need it multiple times)

Array dumping

    Ar_Dump SomeQuest.SomeArray

If you have some arrays you want to read, you can use Ar_Dump, or call some UDF that does a more bespoke version.

Player Actor Values

; * Player Actor Values
    Print "Player Actor Values: "
    let iChoice := 0
    while iChoice < 73
        Print $iChoice + " (" + (ActorValueToStringC iChoice) + "): " +  $(PlayerREF.GetAV iChoice)
        let iChoice += 1
    loop
    Print " * End Actor Values *"

To use this convenient code, you need to use the Script Compiler Override to allow you to reference Actor Values by their int codes. It prints the code number, the language localized name, and value for all the player's actor values.

Player NX variables

; Player NX variables
    Print "Player NX variables: "
    foreach entry <- (Ar_List (PlayerREF.NX_GetEVFlAr ""), (PlayerREF.NX_GetEVFoAr ""), (PlayerREF.NX_GetEVStAr ""))
        Ar_Dump entry["value"]
    loop
    Print " * End Player NX variables *"

If you are using the NX NVSE plugin, you can dump the name and value of every NX variable stored on the player like this. Replacing the "" empty strings with your mod prefix allows you to only dump relevant ones.

Misc

; * Misc
    Print "GameDaysPassed: " + $GameDaysPassed
    Print "Hardcore mode: " + $(PlayerREF.IsHardcore)
    Print "Player Level: " + $(PlayerREF.GetLevel)

You can print anything else that might be useful.

End

; * End
    Print "*** All done! ***"
    let FO_dir := GetFalloutDirectory
    MessageBoxEx "My Mod completed a debug dump, please upload the file '%z' to me, which is in your FNV main directory ('%z')" file_name, FO_dir

    Sv_Destruct file_name, svkey, FO_dir

End

Finally, you can use MessageBoxEx (which sadly requires String Formatting unlike Print) to notify the user with your instructions, and tell them what the dump file is called and where they can find it, by using GetFalloutDirectory to return their FNV main directory. You then need to Sv_Destruct the local string variables or they can cause save game bloat.