Skip to content
lewri edited this page Aug 29, 2022 · 4 revisions

Description and usage of the ingame Lua console

Introduction

Since r992, CorsixTH features an ingame Lua console which allows you to run arbitrary code during runtime. This can be useful for debugging since it allows you to inspect or change any values of the game while it is running. This page will explain the usage of the Lua console and give a few examples what can be done with it.

Disclaimer

Please note that there are no restrictions on the code you can run from this console. This means that you can completely mess up your game if you change some part of the game data to something the game is not expecting. Thus, usage of the Lua console is on your own responsibility and we will not help recover a savegame that has been tampered with by means of the Lua console.

Description

The Lua console can be accessed by setting debug = true in the Configuration File, and then selecting "Lua console" from the debug menu, or pressing F12.

This will open up a window with a text field, an execute button, and a close button. You can enter lua code into the text field, and press execute to run it. Output is shown in the console where debug output of CorsixTH is also shown (not the ingame lua console).

When you press the execute button, your input will first be parsed. If you made a syntax error, this will be indicated by a line "Error while loading !UserFunction:", followed by the error.

Otherwise, your code will be run. If it causes an error, it will be printed in the console as "Error while executing !UserFunction:", followed by the error. This will not crash the game, unless you changed something that also causes errors during the game handlers (for an example see section Changing a value).

Usage

As the name suggests, the code you enter has to be valid Lua 5.1 code. See the Lua 5.1 Reference Manual for information on the language.

You can define your own local variables with local foo = "bar", but they will not persist until the next execution.

TheApp can be used to get the application object. From there, you can get access to all the interesting stuff, e.g. TheApp.ui or TheApp.world.

You can call existing lua functions from your code, e.g. TheApp.ui:getWindow(...),

Print out values with the print() function. To inspect objects, the utility function print_table(table, levels) can be useful, where levels is the maximum depth to visit when printing nested tables (0 or more, omitting is possible but not recommended).

Since r1228, _ is a shorthand for TheApp.ui.debug_cursor_entity, which is the entity (humanoid or object) last hovered over with the mouse. This allows you to inspect any entity with minimal amount of code to enter.

Examples

Hello World

This will print "Hello world!" to the console:

print("Hello world!")

This slightly more interesting version will let the adviser say the greeting instead:

TheApp.ui.adviser:say({text = "Hello world!"})

Inspect an entity

Hover over the entity (humanoid or object) you want to know more about, then execute this code:

print(serialize(_, {detect_cycles = true, max_depth = 1, pretty = true}))

To recurse into the members of that entity that are themselves tables, use a higher value than 1 for max_depth (entities usually have some values at depth 2), but be wary of too high values, since some references (e.g. to world) can result in a huge number of lines to be printed into the console; or could cause a crash or infinite loop.

Inspect an open window

This will print the values of a window of type UIStaff (staff window) that is currently open. If no such window is open, the function will return nil (but it will not crash the game).

local w = TheApp.ui:getWindow(UIStaff)
print(serialize(w, {detect_cycles = true, max_depth = 1, pretty = true}))

Changing a value

In this example, we will change some values of the running game to something else. First, let's see a valid example:

TheApp.world.day = 1

This will change the date to the 1st of the current month. This works pretty well, you can immediately see the date changing at the bottom of the screen when you execute the code. However, when you use the lua console not only to inspect something but to change a value, be careful not to enter a value the game may not be expecting.

For example, we could also set the day to 300 or even -10.5.

TheApp.world.day = -10.5

Surprisingly, the game handles this quite gracefully: In both cases the days will continue to count up until it hits the last day (or more) of the current month, then continue normally with the first of the next month (the display may look a bit weird since neither the minus sign nor decimal point exist in the font, or the number may not fit). Note that this is not guaranteed to be the case in all parts of the code. Values out of the expected range can and will cause erratic behavior and/or crashes.

But we're not done yet. The dynamic typing of Lua allows us to enter something even more sinister:

TheApp.world.day = "apple"

Now this will not crash the game immediately, and the date will even be shown as the appleth of January (or whatever month it was) for a short moment, but as soon as the next day arrives, the game will crash (as you cannot add 1 to "apple").

Congratulations, you have managed to crash the game. The lesson of this of course is not to change any values unless you know exactly what you are doing.

Loading a lua script from a file

While the lua console is certainly good enough to write a one-liner or a few quick lines, it isn't comparable to a full-fledged text editor. Notably, you cannot currently select a section of text, nor copy&paste. There are also still some minor display / usability issues. So you might want to write a lua script in the text editor of your choice, save it in the same dir as the CorsixTH executable, and then execute it from the lua console. You can do that with the following code:

loadfile("myfile.lua")()

Note that the lua function dofile cannot be used as it is redefined in CorsixTH.lua.