Class ClientRounds
The client half of a persistence scenario, in rounds: the same entry into the world and measurement before and after a restart, with the evidence written in the same shape each time. One loop serves both kinds of client:
- a client that joins an owned dedicated server (Run(GameActor, Func<ClientSession>, Action<ClientRound>, Action<ClientRound>?), with OwnedServer and WorldUid);
- a client that hosts a fixture world itself, as a listen server or locally (
HostedClientRounds.RuninValheim.Testing.GameSessions, whose journalled site places the world, with the plan's HostWorld section): it is both the server and the client of each round.
- waits until the server accepts game connections (WaitUntilJoinable(GameActor));
- joins with the plan's disposable character (JoinWorld(ClientRunPlan, string, CrossplayLobby?, bool, CancellationToken): devcommands first, the join exactly once, the client's world pins verified, the world awaited, which protects the player, and test access on an owned client's character), as one step; a Crossplay client first reads the server's lobby (Lobby) and joins it;
- with an Arrival, has the player arrive there with Arrive(GameActor?, GameActor, HeightExpectation, TimeSpan, CancellationToken, bool, bool) (
{round}-arrival.jsonand{round}-teleport-trace.json); - runs the mod's measurement, which adds its own steps and evidence through ClientRound;
- between rounds: a confirmed world save, the client leaves to its menu, only the owned server restarts (Restart()), and the optional after-restart check runs; after the last round the client leaves.
A hosting client's rounds first run the plan's static preflight (Preflight(IEnumerable<string>): the fixture's pinned files and own world UID, and an owned client's install, whose ValheimCLI set must also provide HostedRounds when the plan names a CliManifest), check the native client's save directory, and place the fixture world through the run's journalled site (HostedWorld), so a wrong fixture, install or ValheimCLI set stops the run before the fixture is copied or the game started. After opening the client they require the session commands the rounds use (HostedRounds); each round then hosts the world (Start(GameActor, ClientRunPlan, string, TimeSpan, CancellationToken, bool); from the second round on, this is the hosted world's restart), measures, saves with confirmation between rounds (Save(string, TimeSpan)) and leaves to the menu, which saves again.
Every step is recorded in Report, those of a round prefixed with its name (first: join ...). The
first failure stops the rounds and is rethrown: nothing after a failed save, restart or measurement runs. The teardown is
the same for both kinds: the client is closed in every outcome (an owned client's process is stopped, an attached client
is detached and left running), then a hosted world is moved into the evidence (hostWorldEvidence) once no client
can still host it; after a failure with an attached client, or an owned client that did not stop, the world is left in
place and named in hostWorldLeftInPlace. A failed teardown fails a passing run and never hides an earlier failure.
public sealed class ClientRounds
- Inheritance
-
objectClientRounds
- Extension Methods
Properties
Arrival
Where the player stands to measure; null leaves the player where it joined. A joining client only.
public HeightExpectation? Arrival { get; init; }
Property Value
ArriveStep
The arrival step's name within a round, saying where the player goes. A joining client only.
public string ArriveStep { get; init; }
Property Value
- string
Cancellation
public CancellationToken Cancellation { get; init; }
Property Value
- CancellationToken
Client
The client plan: join address or HostWorld section, character, password variable, pins and timeouts.
public required ClientRunPlan Client { get; init; }
Property Value
Lobby
For a crossplay client (Crossplay), required: the server's lobby, read before each
round's join because a restarted server opens a new one, for example
server => CrossplayServer.WaitForLobby(server, CrossplayServer.BepInExLog(runtime), timeout).
public Func<GameActor, CrossplayLobby>? Lobby { get; init; }
Property Value
- Func<GameActor, CrossplayLobby>
OpenStep
The client's opening step's name; the default says whether it is launched or attached, with plugins pinned.
public string? OpenStep { get; init; }
Property Value
- string
Output
The run's output directory, where each round's evidence is written.
public required string Output { get; init; }
Property Value
- string
OwnedServer
For a joining client, required: the owned server the rounds wait on before each join and restart between rounds, for
example the runner's ServerActor. A hosting client is its own server: leave this out.
public IOwnedServer? OwnedServer { get; init; }
Property Value
ProtectPlayer
Whether to enable god, ghost and debug protection once in the world. The default protects a character before terrain or movement checks. Set false only for a short load/join smoke or a scenario that needs ordinary gameplay and intentionally avoids those modes; server admin privileges may be unavailable to a clean client.
public bool ProtectPlayer { get; init; }
Property Value
- bool
Report
public required ScenarioReport Report { get; init; }
Property Value
Rounds
The rounds' names, which prefix their steps and evidence files: letters, digits, - and _, all different.
public IReadOnlyList<string> Rounds { get; init; }
Property Value
- IReadOnlyList<string>
WorldUid
The owned server's world UID, which the joined client must report; required for a joining client. A hosting client's world UID is its plan's WorldUid: leave this out or give the same.
public string? WorldUid { get; init; }
Property Value
- string
Methods
Run(GameActor, Func<ClientSession>, Action<ClientRound>, Action<ClientRound>?)
Runs a joining client's rounds against server, the owned server's current actor, opening the client
with openClient (for example Open(ClientRunPlan, string, CancellationToken)). measure runs in
each round once the player is in place; afterRestart, if given, runs after each restart before the
next round's join, for server-side checks of what survived. Returns the server's actor after the last restart.
public GameActor Run(GameActor server, Func<ClientSession> openClient, Action<ClientRound> measure, Action<ClientRound>? afterRestart = null)
Parameters
serverGameActoropenClientFunc<ClientSession>measureAction<ClientRound>afterRestartAction<ClientRound>