The Debug Console

Hello, fellow devs!
With some of the last few PRs a new “Debug Console” feature has been introduced in Thrive, which allows developers and testers to read the Godot console output in-game and execute custom commands. The console can be opened with the hotkey F10.
I’m making this forum post to document the feature, and to have a place to gather suggestions for future improvements.

How to implement custom commands

Programmers may want to implement a custom command to quickly test some feature, or introduce a new cheat. Defining a new command is as simple as defining a static method with a special attribute:

[Command("test", isCheat, "this is a command")]
private static void TestCommand()
{
    GD.Print("Hello, Console!");
}

The attribute parameters are, in the same order as the example, the command name used in the console, a bool flag to determine if the command invocation is a cheat or not, and an help string that is displayed when the user executes the built-in help command.

The command will be automatically registered when Thrive starts up, and can be executed in the console by writing the command name, which in this case would be test with output Hello, Console!. The command name is case insensitive.

Please note that the method must be static, or it will be ignored during the registration. The visibility modifier is ignored, but it’s recommended to keep the method private, as it would be good practice to not invoke the command method from a place different from the console. The method name also doesn’t matter, but I recommend using the NameCommand() style.

Custom parameters

The command can take parameters:

[Command("test", isCheat, "this is a command")]
private static void TestCommand(int foo, float bar, string baz)
{
    GD.Print($"Foo is {foo}, bar is {bar} and the baz message is {baz}");
}

Then the command must be executed in the console with the same number and type of the parameters specified by the method signature. In this case the a correct execution of this command from the console is:

> test 123 4.567 "Hello, world!"

Foo is 123, bar is 4.567 and the baz message is Hello, World!

As you may have noticed, strings must be delimited by quotes, and you can use escape characters in it.

Commands can be overloaded, meaning you can define multiple different commands with the same name, provided that the signature differs in the number or types of the parameters. So you are allowed to register the two test commands of the previous examples together.

Special parameters

Commands also support some special parameters:

  • Enums are supported. If you have an enum:
    enum ExampleEnum
    {
        Foo,
        Bar,
        Baz,
        Qux,
    }
    
    you can define a command as:
    [Command("test", isCheat, "this is a command")]
    private static void TestCommand(ExampleEnum value)
    {
        GD.Print($"The chosen value is {value}.");
    }
    
    then you can execute the command as test qux. Note that the enum parameter input in the command is case insensitive.
    Example:
    > test qux
    
    The chosen value is Qux.
    
  • DebugConsole is another special parameter you must define as first parameter, if used, in the method signature which exposes basic console function to the method body. These include console clearing and printing custom messages. You can take a look at the available methods in the DebugConsole class to get more info. Please note that this parameter is considered experimental and may change in the future versions of this feature.

Return value

Commands support a bool return value to determine success (if true) or failure. If you use this return value, a Success or Failure message will be logged in the console.
Other return values are silently unsupported, so different return values will not influence the execution of the command. Therefore, if the command doesn’t have to return a success feedback I just recommend to use void.

Why the Debug Console?

The necessity for this feature was originally presented in this issue, as it would enable easier access to custom debugging and testing features, while having a direct feedback from the system console.

How it works?

A custom Logger (LogInterceptor) dispatches Godot’s logs from any thread to an inbox, which are then processed and moved by Godot’s main thread to an history, which is read by the DebugConsole instances.

4 Likes