Skip to content

Cake Integration Reference

This guide covers the customization points in GameTestsTaskBase and ContextBase, and explains how the task drives the test lifecycle.

For the initial setup, see Cake Integration.

Remember: all ../paths here are resolved relative to CakeBuild.csproj

Execution flow

When you run your RunGameTests Cake target, GameTestsTaskBase.Run() performs the following steps in order:

  1. Cleanup — deletes any previous mod binaries and VS log files, restores the world save from a .orig backup (if one exists).
  2. Write config — writes ModConfig/vintestconfig.json into the data directory, passing some of the CLI arguments to the in-game runner (See Writing Tests — Interaction with VinTest.Cake).
  3. Prepare — calls your Prepare() override. Does nothing by default; create any extra config files or perform additional cleanup here.
  4. Build — calls your Build() override. By default will build the gametests project, which in turn will cause building the main mod.
  5. Launch — starts VintageStory.exe with --addModPath, --addOrigin, --dataPath, and --openWorld arguments.
  6. Wait — polls for TestResults/results.json until VS exits or the timeout is reached. In ManualMode, simply waits for VS to exit.
  7. Scan logs — reads VS log files from Logs/, classifies each line, and collects any errors or warnings.
  8. Print — reports test pass/fail counts and prints the filtered log.

Customizing the build step

If somehow just building the gametests project is not enough in your case, you can override the Build() method to change what gets compiled before VS launches:

protected override void Build(TContext context)
{
    // ...
}

Do not rebuild the Cake project itself

The default Build() intentionally does not rely on building a solution (if one is present), and skips rebuilding the CakeBuild project itself. The Cake executable is already running and its DLL is locked; trying to rebuild it would cause MSBuild to fail.

Customizing asset and mod paths

GetModBinaryPaths() returns the list of directories passed to --addModPath. By default it uses ../<ProjectName>/bin/<Configuration>/Mods output directories of both the main mod and the gametests mod.

GetAssetsPaths() returns directories passed to --addOrigin. It defaults to ../<ProjectName>/assets/.

These paths are based on the structure of vsmodtemplate. If your mod layout differs from that, you can override both methods (and return more than one path, if needed):

protected override IEnumerable<string> GetAssetsPaths(BuildContext context)
{
    return [
        Path.GetFullPath("../assets/"),
        Path.GetFullPath("../more-assets/"),
    ];
}

// or, if your mod has no assets:
protected override IEnumerable<string> GetAssetsPaths(BuildContext context)
{
    return [];
}

Creating additional mod files

Override Prepare() to create any mod-specific files before VS launches. This runs after the generic cleanup, so files you write here are fresh for each run.

protected override void Prepare(BuildContext context)
{
    var configPath = Path.Combine(context.DataPath, "ModConfig", "mymod.json");
    File.WriteAllText(configPath, """{"SomeFlag": true}""");
}

Log filtering

After VS exits, the task scans its <DataPath>/Logs/ directory and classifies each log line into one of three categories based on substring matching:

Type Default patterns Color Effect on build
Error [Error] Red Fails the task (unless --ignore-log-errors)
Warning [Warning],
not found. Hint:
Yellow Printed, no failure
Capture [VinTest] Normal Printed
The "not found" hint

The not found. Hint pattern is part of the warning about patch operation failing on a "missing" clientside/serverside JSON:

[VerboseDebug] Patch 0 in petai:patches/entities/player.json: File game:entities/humanoid/player.json not found. Hint: This asset is usually only loaded Server side

It indicates that, due to the lack of side: server or side: client in the patch file, VS client (or server) is trying to patch a file that it never loaded. It is harmless, and so not considered an error by default, but can be quite verbose and deserves to be highlighted.

Lines that match no bucket are not printed by the Cake task at all.

You can override the AdditionalLogErrors, AdditionalLogWarnings, and AdditionalLogCapture properties to add your own substrings to each category:

protected override string[] AdditionalLogErrors => ["FATAL", "[MyMod] critical:"];
protected override string[] AdditionalLogWarnings => ["[MyMod] warn:"];
protected override string[] AdditionalLogCapture => ["[MyMod]"];

Once initial classification is done, LogSuppressions lets you change the level of specific lines using regex patterns. Each entry is a (Pattern, Level?) pair:

  • If Level is null, the matching line is dropped entirely (not printed, does not count as error).
  • Otherwise the category of the line is changed — so a very specific regular line can become an error, and a very specific error can be silenced.
protected override IEnumerable<(string Pattern, LogLevel? TargetLevel)> LogSuppressions
{
    return [
        // drop a noisy line that always appears
        (@"\[Error\] Font '.*' not found", null),
        // demote a known false-positive error to warning
        (@"\[Error\] Old world format", LogLevel.Warning),
    ];
}

Patterns are compiled as case-insensitive regular expressions.

To filter or not to filter

The main purpose of this mechanism is to prevent you from drowning in warnings about a faulty 3rdparty mod that you depend on, and to customize what deserves a build failure and what deserves a simple highlight. Nevertheless, it is a good idea to keep your code as warning-free as possible without silencing anything.

CLI arguments reference

ContextBase's is constructed by the Cake internals. The sole purpose of this class is to parse the command-line parameters passed after --, provide sensible defaults for the omitted arguments, and expose everything through properties.

powershell
dotnet run --project ./CakeBuild --target RunGameTests

# the above call without any arguments is fully equivalent to:

dotnet run --project ./CakeBuild --target RunGameTests -- # (1)!
  --vs-path <see below> `
  --configuration Release `
  --data-path ../gamedata `
  --test-world autotest `
  --test-timeout 300 `
  --test-filter "" `
  --manual-mode false `
  --ignore-log-errors false `
  1. Note the -- separating Cake's own parameters from the task parameters

The parameters map into following properties:

  • --vs-path (VsPath) — Path to the VintageStory installation directory containing VintageStory.exe.

    If left empty, will first check the Directory.Build.props file, then the VINTAGE_STORY environment variable. See Local Development — Using local Vintage Story installation.

  • --configuration (BuildConfiguration) — Build configuration passed to dotnet build.

  • --data-path (DataPath) — Path to the Vintage Story data directory (Saves/, Logs/, ModConfig/, etc.). If the directory does not exist, Vintage Story will create it.

  • --test-world (TestWorldName) — Name of the world save to open. If no save with such name exist, Vintage Story will create a new creative world.

  • --test-timeout (TestRunTimeoutSeconds) — Seconds to wait for all tests to finish before timing out with an error. Effectively caps the max execution time for your entire test project.

  • --test-filter (TestCaseFilter) — Comma-separated substrings to filter SuiteName.CaseName. When empty, all tests run. See Writing Tests — Filtering tests.

  • --manual-mode (ManualMode) — Launch Vintage Story without running tests automatically; the task indefinitely waits for the game to exit. See Writing Tests — Manual mode.

    Should be activated as --manual-mode true

  • --ignore-log-errors (IgnoreLogErrors) — When set, captured log lines matching error patterns are printed but do not fail the task.

    Should be activated as --ignore-log-errors true

Additional computed properties

ContextBase also exposes a few derived properties: