Monday 27 November 2017

Debugging your TTS mods with console++ : Watch List

This will be the final installment of the tutorial series about console++ which began here.

In this enthralling episode we'll look at the 'watch' command; a very useful debugging tool.  'watch' allows you to monitor a variable or object in your game (or even a function: more on that later), displaying a message in the chat window whenever it changes.

In order to use this feature of console++ you must call 'console.update()' in an 'onUpdate' event.  The example module already includes this command:

If you've followed this series so far then after firing up the example module in Tabletop Simulator you'll already be in command mode (thanks to console.autoexec);  type 'slow' to enable the card display.  Now if we type 'ls' a few times, waiting a short delay between each, we'll see the next_check variable increasing:

This is a pretty awful way to check its progress however; lets use 'watch' instead:
Type 'watch /next_check'.  Every two seconds the next_check variable will change and we'll see it do so.  This is because we currently have check_delay set to 2 seconds; type 'fast' to change check_delay to 0.2, and you'll see the variable change every 0.2 seconds instead.  Switch it back to 2 seconds with 'slow'.  You wouldn't want this running after the point where you get the info you want; it's filling the chat window.  To clear the watch list type 'watch -c'.  The '-c' parameter clears the watch list if it's used on its own.  You may instead supply it with a variable name to only clear that variable from the watch list: here we could have typed 'watch -c /next_check'.

We can also watch objects: type 'watch /dice/d6' then roll the dice.

You can see it will track the objects rotation and position.  This is fine for an object which you have used in your program, but not all objects will be stored in a variable.  Happily we can also track objects via their GUID; right click the chess rook and in the scripting menu click on its GUID to copy it to the clipboard.  Now type 'watch -g ' and hit ctrl-v  to paste in the rook's GUID.  Pick up the rook and move it around to see it being watched.

You can see what variables you are watching by typing 'watch' without any parameters:

You can also disable the watch list temporarily by pausing it with the '-p' parameter; this lets you stop the watch list outputting to the chat window without clearing it (and losing everything you are tracking).  Try it now: type 'watch -p' and move the rook around; no updates! Do it again to unpause (use up-arrow to fetch the previous command).

Grab the rook and move it around; the watch list really spams the chat window, since every tick the position changes.  In a lot of cases this will be too much information, so the watch command allows you to throttle its output for each given item.  Use the up-arrow key to fetch the command that added the rook to the watch list ('watch -g b27933', unless your GUID is different) and then add to the end of it '-t2'.  This will add a 2 second throttle to the watch.  Now drag the rook around and notice the difference.  Notice also that this command has replaced the previous version of the item in the watch list, overwriting the old, unthrottled item; each variable or object may generally only appear once in the watch list.

Now clear the watch list  with 'watch -c'.

As well as tracking variables and objects, we can also watch their member functions.  Type 'watch /dice/d6/getValue', and then roll the dice:

Clear the list, and then try to do the same for the dice's position with 'watch /dice/d6/getPosition'.  Argh, what's happening here?

What is happening is that every tick the watch list is calling the getPosition function of the dice, and every tick it is getting a new table.  Even though the table's member values are identical, the table itself is changing, so the watch list is outputting it each frame. This is definitely not useful!  We can mitigate this by using the '-/' parameter; this parameter specifies a member of the returned table to watch, instead of the table itself.  Type 'watch /dice/d6/getPosition -/x'; phew, the spam has stopped.   Move the dice around to see the 'x' value being tracked, then clear the watch list.

As well as variables and objects, we can also watch functions. To test this out we'll need one so let's see what functions we have available with 'ls -f'.  Ah: 'dice_total' is nice and simple as it has no parameters; lets watch it with 'watch /dice_total'.  Roll the dice to see the function changing.

We can also use functions with parameters; let's do that, but lets make things a little more complex, more like a situation you might find yourself in while actually debugging your mod.

What does the near function do?  Here is its source:

Not too complicated a function; it checks if two objects are near each other on the x and z axis.  We're going to use it to check when the rook is near the d4.

Our first problem is that we do not have a variable for the rook in our program; remember when we were watching it before we were doing so via its GUID.  That's not an option here: the near function does not take a GUID as a parameter, it takes two object variables.  Therefor the first thing we have to do is make one up for the rook.  We'll do so using the 'call' command: type 'call getObjectFromGUID 'b27933'', and then 'add /rook ~'.  (the '~' special variable holds the last result).

Now we have a variable holding our rook we can use it as a parameter to the near function; type 'watch /near /dice/d4 /rook', and then pick up the rook and move it around, over the d4 and away from it.

The near function is fairly simplistic, but I hope you can see how we can write debug functions in our code, and then hook them up to problematic objects during a play session, using them to work out what is going wrong with the mod.  More persistently, if you know you want to track certain variables or objects you can add 'watch' commands to your console.autoexec, giving you feedback on events which you want to know happen (but which don't necessarily throw error messages) every time you play your mod.

No comments:

Post a Comment