Table of Contents

Class ServerRunPlan

Namespace
Valheim.Testing.Game
Assembly
Valheim.Testing.Game.dll

A plan for owned dedicated-server runs on pinned fixtures (see PinnedServerRun). Derive a mod's plan from it and add the mod's scenario fields; Read<T>(string) refuses unknown fields. {runtime}, {world} and {port} in arguments and environment values expand to the copies and the CLI port.

public class ServerRunPlan
Inheritance
object
ServerRunPlan

Fields

MaximumStartupSeconds

Largest bounded server-start budget, in seconds, including mods that generate a network on first load.

public const int MaximumStartupSeconds = 3600

Field Value

int

Properties

Arguments

public string[] Arguments { get; set; }

Property Value

string[]

CommandSeconds

public int CommandSeconds { get; set; }

Property Value

int

Crossplay

Launches the server with -crossplay, the game's PlayFab backend: clients join its lobby (WaitForLobby(GameActor, string, TimeSpan, CancellationToken), JoinCrossplay(string, string, string, string, TimeSpan, bool, CancellationToken, string?)), not its address, and the report records crossplay. -crossplay in Arguments is refused. A crossplay plan names its game port (-port N): the lobby is keyed by the public IP and that port, so two crossplay servers behind one public IP need different ports. Keep a crossplay fixture separate from a Steam one rather than switching one server between modes: a client remembers each server's mode in its recent-server list.

public bool Crossplay { get; set; }

Property Value

bool

Environment

public Dictionary<string, string> Environment { get; set; }

Property Value

Dictionary<string, string>

Executable

Optional: documents the plan's platform and must match what the copied runtime contains.

public string Executable { get; set; }

Property Value

string

ExpectCommand

The strict cli_expect command for the plan's complete bound pins.

public string ExpectCommand { get; }

Property Value

string

LogScan

This run's severities for the teardown log scan's patterns (Names), each with a written reason, for example "rpc-method-missing": { "severity": "Failure", "reason": "..." }; under a new name, a pattern of the run's own with a line regex (Line).

public Dictionary<string, LogClassification> LogScan { get; set; }

Property Value

Dictionary<string, LogClassification>

Pins

Strict ValheimCLI expectations: worlduid and an exact MD5 for every listed plugin. A standalone runner observes any omitted pins from the fixture and staged profile before launch.

public Dictionary<string, string> Pins { get; set; }

Property Value

Dictionary<string, string>

Port

public int Port { get; set; }

Property Value

int

QuitSeconds

How long stopping the owned server (at teardown and for each restart) waits for it to quit after it is asked (SIGINT, or Ctrl+Break on Windows over SSH, Ctrl+C on other Windows hosts): the game can save the world and retire its crossplay lobby. Killed only after that. 0 kills at once, without the game's shutdown. Default 120, at most 1800.

public int QuitSeconds { get; set; }

Property Value

int

Runtime

public PinnedDirectory Runtime { get; set; }

Property Value

PinnedDirectory

RuntimePins

The runtime's game build, loader and patchers by SHA256 (Of(string) computes them), checked on the copy before launch: what ValheimCLI cannot report in game. A standalone runner observes them from the staged profile when omitted; supplied values remain expected pins and are checked against the source install before staging.

public InstallPins? RuntimePins { get; set; }

Property Value

InstallPins

Scenario

public string Scenario { get; set; }

Property Value

string

StartupSeconds

public int StartupSeconds { get; set; }

Property Value

int

World

public PinnedDirectory World { get; set; }

Property Value

PinnedDirectory

Methods

CheckCrossplay()

Refuses -crossplay in Arguments (in any case, as the game reads it) and, for a Crossplay plan, anything but exactly one explicit -port N. The runner checks this for every plan.

public void CheckCrossplay()

CheckExecutable(ServerPlatform)

The runtime decides the platform (DetectServer(string)); a stated executable must agree with it.

public void CheckExecutable(ServerPlatform platform)

Parameters

platform ServerPlatform

CheckLaunchHost(ServerPlatform, bool)

A launch needs a host that can execute the runtime's server: a Windows host or not (then Linux).

public static void CheckLaunchHost(ServerPlatform platform, bool windowsHost)

Parameters

platform ServerPlatform
windowsHost bool

CheckLaunchHost(ServerPlatform, ServerPlatform)

A launch needs a host of the runtime's own platform: each dedicated server runs only on its own OS (see LocalServerPlatform for this machine's).

public static void CheckLaunchHost(ServerPlatform platform, ServerPlatform host)

Parameters

platform ServerPlatform
host ServerPlatform

CheckLogScan()

The plan's log scan classifications are well formed (the runner checks them for every plan).

public void CheckLogScan()

CheckOutput(string)

public void CheckOutput(string output)

Parameters

output string

DedicatedStartupEvents(string)

What an owned dedicated server's startup waits on: ValheimCLI's listening line in this boot's BepInEx log (a previous boot's lines never count; a plugin-load failure, a type-load or missing-member exception, or ValheimCLI's "core is not ready" ends startup at once: StartupFailures), then the loaded-world push on a loopback connection of its own. A world state is not mod readiness: the session observation decides that.

public StartupEvents DedicatedStartupEvents(string runtime)

Parameters

runtime string

Returns

StartupEvents

ExecutableFor(ServerPlatform)

public static string ExecutableFor(ServerPlatform platform)

Parameters

platform ServerPlatform

Returns

string

Expand(string, string, string)

public string Expand(string value, string runtime, string world)

Parameters

value string
runtime string
world string

Returns

string

GameLogFile(string, string)

The file the arguments' -logFile names, expanded (for example {runtime}/toolkit-unity.log), or null. The game writes all its own lines there, lobby lines included; BepInEx's log carries them only when BepInEx copies Unity's log.

public string? GameLogFile(string runtime, string world)

Parameters

runtime string
world string

Returns

string

LaunchArguments(string, string)

The server's launch arguments: Arguments expanded (Expand(string, string, string)), then -crossplay for a Crossplay plan.

public string[] LaunchArguments(string runtime, string world)

Parameters

runtime string
world string

Returns

string[]

OnlyForScenario(string, bool, params string[])

Refuses settings (the plan fields, as the plan spells them) when supplied is true and the plan's Scenario is not one of scenarios: a setting another scenario reads would otherwise be ignored silently, and the plan would not test what its author thinks.

public void OnlyForScenario(string settings, bool supplied, params string[] scenarios)

Parameters

settings string
supplied bool
scenarios string[]

Read<T>(string)

public static T Read<T>(string path) where T : ServerRunPlan

Parameters

path string

Returns

T

Type Parameters

T

RequireEnvironmentFlag(string, string)

Requires variable in Environment set to exactly 1, the explicit opt-in a test fixture in the mod needs (for example one that writes terrain when the world loads). Anything else is refused: missing, another value such as true, or a key that differs only in case, which the server's platform may or may not treat as the same variable. purpose completes "set it to 1 to ...".

public void RequireEnvironmentFlag(string variable, string purpose)

Parameters

variable string
purpose string

RequireScenario(params string[])

Refuses a Scenario that is not one of known.

public void RequireScenario(params string[] known)

Parameters

known string[]

ValidateServerPlan(IEnumerable<string>, string)

The rules every dedicated-server plan follows: fully qualified sources, port and time bounds, a known executable, no runner-owned session token or Doorstop variable in the environment, -batchmode -nographics and exactly one -savedir {world}, and exact values for every pin the plan supplies: plugin MD5s, no worldfiles, full fixture hashes and RuntimePins. A standalone runner observes omitted pins from what it stages; after that binding, every requiredPlugins entry must be in the staged plugin set. Each log scan classification names a known pattern with a reason. -crossplay comes only from Crossplay (CheckCrossplay()).

public void ValidateServerPlan(IEnumerable<string> requiredPlugins, string sessionTokenVariable)

Parameters

requiredPlugins IEnumerable<string>
sessionTokenVariable string