Class ClientRunPlan
The game client a system test joins to its server, as a plan section. owned: the runner launches it from
Install and stops only that process (Launch(ClientRunPlan, string, CancellationToken));
it must run in the desktop session where Steam is running and signed in, with a display. attach: an operator
launched and signed in the client; the runner only connects to its ValheimCLI port and never touches the process.
The join password stays in the client's own process environment, named by PasswordVariable.
public sealed class ClientRunPlan
- Inheritance
-
objectClientRunPlan
Properties
Architecture
Owned only: the slice a macOS client (Valheim.app) runs as, x64 or arm64. Left out, it is
arm64 on Apple Silicon and x64 elsewhere. Select x64 explicitly for Rosetta on Apple Silicon.
The native path needs a Doorstop library with an arm64 slice and a
BepInEx core built on MonoMod 25 or later, and the launch refuses one without them rather than fall back to Rosetta.
A Windows client is x64 only, so arm64 is refused for it. Validate(params string[]) runs the launch's slice
and core check on a Valheim.app install on this machine, so a runner refuses such a plan before it starts anything.
Recorded in client-process.json.
public string Architecture { get; set; }
Property Value
- string
ArrivalSeconds
public int ArrivalSeconds { get; set; }
Property Value
- int
BepInExSeconds
Owned only: how long after the launch BepInEx may take to write its first line to this launch's
BepInEx/LogOutput.log, 5 to 1800 seconds (default 60; never more than StartSeconds). Doorstop starts
BepInEx before the game's first frame, so a game still running without that line runs without BepInEx, and startup
ends then instead of at the start deadline.
public int BepInExSeconds { get; set; }
Property Value
- int
Capabilities
The ValheimCLI extension commands (owner/command, such as valheim.world/terrain) the run uses beyond what
its runner requires itself (ClientRounds adds HostedRounds). Checked
against CliManifest before an owned launch, and live once the client answers, owned or attached
(Require(GameActor, params string[])).
public string[] Capabilities { get; set; }
Property Value
- string[]
Character
An existing, disposable local character (never a cloud character).
public string Character { get; set; }
Property Value
- string
CliManifest
Owned only: the full path of the CliCapabilityManifest of a ValheimCLI build (one plugin). For a disposable copy (the default) it names the set the copy stages, its DLLs beside the manifest; left out, the copy stages the toolkit's pinned bundle and checks against that bundle's manifest. With InPlace it names the set the install already holds; left out there, no static check runs and the report says so. Before launch the install (the copy, or the install in place) must hold exactly that set by SHA256 and offer every capability the run uses; a manifest that is missing or malformed is refused, never skipped. An attached client's files are its operator's, so it takes no manifest.
public string? CliManifest { get; set; }
Property Value
- string
CliPreflight
Which capability checks apply, for the report's cliPreflight. An owned client: static and live (its copy's
staged set, or the in-place install against its named CliManifest); an attached client: live only.
An owned client in place without a manifest: live only, and says the static check was not run.
[JsonIgnore]
public string CliPreflight { get; }
Property Value
- string
Crossplay
Joins the server's crossplay (PlayFab) lobby instead of its address (JoinCrossplay(string, string, string, string, TimeSpan, bool, CancellationToken, string?)), for a server plan with Crossplay. Leave out Join and PasswordVariable: the crossplay join command would carry a password as text, so the fixture server runs private without one.
public bool Crossplay { get; set; }
Property Value
- bool
Environment
Owned only: non-secret process variables for this disposable client. Loader overrides are refused.
public Dictionary<string, string> Environment { get; set; }
Property Value
- Dictionary<string, string>
Host
public string Host { get; set; }
Property Value
- string
HostWorld
The client hosts this fixture world from its menu (a listen server) instead of joining a server (ClientRounds). Leave out Join, PasswordVariable and Crossplay.
public HostWorldPlan? HostWorld { get; set; }
Property Value
InPlace
Owned only: run Install itself, as it is, instead of a disposable copy (the --in-place option of the
toolkit's runners sets it for every client of a run). Nothing is written into the install: no ValheimCLI set is staged and
no loader swapped. Preflight refuses an install without BepInEx or ValheimCLI, naming what is missing. The static
ValheimCLI check runs only when the plan names a CliManifest; otherwise the report says it was not run
(CliPreflight). Running Valheim, the run journal, leases and local-only test characters are checked as for a copy.
public bool InPlace { get; set; }
Property Value
- bool
Install
Owned only: the client install. By default the run never launches it: a GameSession or ClientActor copies it
into a disposable copy first, stages the pinned ValheimCLI set (the plan's CliManifest, or the toolkit's
pinned bundle) and the loader rule into that copy, and launches the copy, so nothing in the install changes. With
InPlace the run launches this install as it is, and it must already hold BepInEx and ValheimCLI.
public string Install { get; set; }
Property Value
- string
InstallPins
Owned only: the install's game build, loader and patchers by SHA256 (Of(string)), checked against the source before a disposable profile is staged. When omitted for a disposable profile, the staged values are observed and enforced. An in-place client requires them. An attached client's install is its operator's and is not read, so its build is not pinned (the game refuses a join only across network versions).
public InstallPins? InstallPins { get; set; }
Property Value
Join
The server address the client joins, host:port. Left out for a Crossplay or hosting (HostWorld) client.
public string Join { get; set; }
Property Value
- string
JoinSeconds
public int JoinSeconds { get; set; }
Property Value
- int
JoinsHost
The client is a peer of the run's hosting client (HostingClientActor): it joins the host's world by the
host's multiplayer identity (JoinHost(ClientRunPlan, GameActor, string, bool, CancellationToken)), since a listen server is reached through Steam, not
at an address. Leave out Join, PasswordVariable, Crossplay and HostWorld.
public bool JoinsHost { get; set; }
Property Value
- bool
LaunchArchitecture
Architecture as the launch takes it; an omitted value uses this client's host default.
[JsonIgnore]
public ClientArchitecture LaunchArchitecture { get; }
Property Value
LaunchArguments
Owned only: extra game arguments; ForClient(string, IEnumerable<string>, IReadOnlyDictionary<string, string>?, ClientPlatform?, ClientArchitecture?, bool, IEnumerable<string>?) adds -console.
public string[] LaunchArguments { get; set; }
Property Value
- string[]
MenuExpectations
Strict pins at the menu: plugins only.
public string MenuExpectations { get; }
Property Value
- string
Mode
public string Mode { get; set; }
Property Value
- string
Owned
public bool Owned { get; }
Property Value
- bool
PasswordVariable
The environment variable, in the client's process, that holds the join password.
public string? PasswordVariable { get; set; }
Property Value
- string
Pins
Every plugin the client loads by exact MD5, or absent. No world key: the runner adds the server's.
public Dictionary<string, string> Pins { get; set; }
Property Value
- Dictionary<string, string>
Port
The client's ValheimCLI port (its [Server] Port setting); it must differ from the server's.
public int Port { get; set; }
Property Value
- int
StartSeconds
public int StartSeconds { get; set; }
Property Value
- int
Targetable
Protects the joined player without ghost mode (Protect(GameActor, bool)): it cannot die, but creatures see, hear and hunt it. Only for a test of AI, aggro or targeting that needs a player creatures notice; by default every joined player is protected with ghost mode, which holds on every peer that runs ValheimCLI.
public bool Targetable { get; set; }
Property Value
- bool
Methods
CheckCliManifest(IEnumerable<string>?)
The static capability check alone: an owned client's install against its CliManifest
(Check(string, IEnumerable<string>)), requiring only the ValheimCLI-owned entries in
Capabilities and capabilities. A mod's own extensions are
checked from the live game after its plugin loads; the ValheimCLI capability manifest cannot declare them.
Before a disposable copy exists (Valheim.Testing.Game.ClientRunPlan.CopySource), capabilities are recorded for the copy's
check before its launch, and a named CliManifest must offer them already; the result is then null. Null,
with nothing read, also for an attached client and an owned one run in place without a manifest, whose capabilities only
the live check sees (CliPreflight says so). Refuses a missing manifest (System.IO.FileNotFoundException),
a malformed one (System.IO.InvalidDataException) and an install that is not its set or lacks a capability
(System.InvalidOperationException). A profile on another host is read there, as its profile owner bound it.
public CliManifestCheck? CheckCliManifest(IEnumerable<string>? capabilities = null)
Parameters
capabilitiesIEnumerable<string>
Returns
CheckInstallPins()
Checks owned pinned files and always refuses a profile if its source game changed after staging.
public void CheckInstallPins()
Preflight()
The static preflight of the run, after Validate(params string[]) and before anything is copied or started; every fact it
needs is on disk here. A hosting client's fixture must still be its pinned files and must hold the world
WorldUid names (Preflight()). An owned client's install must pass
what its launch checks first: its InstallPins (patchers included) and BepInEx loader (a Doorstop proxy and
configuration from different versions included). Then: every pinned plugin build is installed exactly once in
BepInEx/plugins or BepInEx/scripts (a hash typed by hand or a wrong staged file matches none), a pinned
plugin in scripts has ScriptEngine pinned and set to LoadOnStart, and ValheimCLI's standing expectations
file, when its config sets one, parses one pin per line, names a world when strict, and agrees with the plan's pins and
hosted world. With a CliManifest, last, the
install's ValheimCLI files must be exactly its set and provide its own requested pack capabilities
(CheckCliManifest(IEnumerable<string>?)). A mod adapter's extensions are confirmed after the client loads.
An attached client's install is its operator's and is not read. Launch(ClientRunPlan, string, CancellationToken)
runs the install part itself; ClientRounds runs all of it before it places the fixture.
public void Preflight()
Preflight(IEnumerable<string>)
Preflight(), with capabilities (owner/command) that the runner itself uses
added to Capabilities for the manifest check (ClientRounds passes HostedRounds).
public void Preflight(IEnumerable<string> capabilities)
Parameters
capabilitiesIEnumerable<string>
RequirePasswordSource()
Refuses an owned joined client whose password variable is missing from this runner's process before any game or fixture is copied. The value must not be put in Environment, which is ordinary serialized plan data; the launched local client inherits the runner's variable, and a remote client receives it as a secret variable. Attached clients keep their operator's environment.
public void RequirePasswordSource()
Validate(params string[])
The rules every client section follows, plus absentPlugins, which must be pinned absent
when the claim is what a client without them sees (a server-only mod). An owned client pins its install
(InstallPins). A disposable profile may omit pins; its owner observes and binds the staged values.
public void Validate(params string[] absentPlugins)
Parameters
absentPluginsstring[]
WorldExpectations(string)
Strict pins once joined: plugins and the server's world.
public string WorldExpectations(string worldUid)
Parameters
worldUidstring
Returns
- string