Class GameSession
- Namespace
- Valheim.Testing.GameSessions
- Assembly
- Valheim.Testing.GameSessions.dll
One run's game processes in their roles (#258, decided on #289): an owned dedicated server (Server) or a client
that hosts its own world (Host, #258 step 8), and named clients (Clients), each with its in-game
handle .Game. A scenario is a function of the session and its
plan, (GameSession session, TPlan plan) => Task, and coordinates the actors only through the barriers, each one
named Setup step with a bounded wait that names itself when it times out:
- StartAsync(): the server boots (or the host, prepared before anything starts, opens to its menu and hosts its world) and every client reaches its menu at the same time; one failure cancels the others, lets them settle, closes the clients and then the server or host, and is rethrown. With the mod's ModDeclaration, its declared Harmony patches must be applied on the server or host when its pins load the mod.
- ServerJoinable(): the server (or the host's world) accepts game connections.
- Join(string, HeightExpectation?, bool, CrossplayLobby?), JoinAll(CrossplayLobby?): a client (every client) in the server's world, by the one join (JoinWorld(ClientRunPlan, string, CrossplayLobby?, bool, CancellationToken)), or in the host's world by the host's identity (JoinHost(ClientRunPlan, GameActor, string, bool, CancellationToken)), optionally standing at an arrival point (Arrive(GameActor?, GameActor, HeightExpectation, TimeSpan, CancellationToken, bool, bool)).
- Rejoin(string, HeightExpectation?, bool, CrossplayLobby?): a client leaves to its menu and joins again.
- Barrier(string, Func<CancellationToken, Task>, TimeSpan): a scenario's own readiness, waited on within a bound.
Disposing it closes the clients in reverse order, then stops the server, each a Cleanup step: clients before their host. A hosting client is closed after its peers, then its placed world is moved into the evidence only once no client can still host it.
public sealed class GameSession
- Inheritance
-
objectGameSession
Properties
CampaignClients
A campaign's client names (RunCampaignAsync<TPlan>(string, TPlan, Func<TPlan, IReadOnlyDictionary<string, ClientRunPlan>>, string, PinnedServerRunOptions<TPlan>)), each opened on its assigned host by OpenClient(ClientRunPlan, string?, string?); empty when clients open on this machine.
public IReadOnlyList<string> CampaignClients { get; }
Property Value
- IReadOnlyList<string>
Cancellation
Cancelled by Ctrl+C or SIGTERM, and when StartAsync() fails.
public CancellationToken Cancellation { get; }
Property Value
- CancellationToken
Clients
The session's clients by name, for example client, or a campaign's client-a and client-b.
public IReadOnlyDictionary<string, ClientActor> Clients { get; }
Property Value
- IReadOnlyDictionary<string, ClientActor>
Host
The client that hosts the session's world (a listen server), or null; a session has it or a Server.
public HostingClientActor? Host { get; }
Property Value
Interval
How often a scenario's observation waits re-read: one second; scenario tests over scripted worlds shorten it.
public TimeSpan Interval { get; }
Property Value
- TimeSpan
Logs
Every actor's kept logs, the server's (or host's) first, for the teardown scan once the processes stopped.
public IReadOnlyList<RunLog> Logs { get; }
Property Value
- IReadOnlyList<RunLog>
Output
The run's new output directory: reports, per-boot logs, command records and kept client logs.
public string Output { get; }
Property Value
- string
Report
The shared report to which actor setup, scenario and teardown add their steps.
public ScenarioReport Report { get; }
Property Value
Server
The owned dedicated server, or null for a session without one.
public ServerActor? Server { get; }
Property Value
Methods
AddLog(RunLog)
Adds a log the teardown scan reads besides the actors' own, for example one a scenario's own tool wrote.
public void AddLog(RunLog log)
Parameters
logRunLog
Barrier(string, Func<CancellationToken, Task>, TimeSpan)
A scenario's own readiness as a named Setup step: wait gets a token that ends after
within (or on the session's cancellation); running out is a WaitTimeoutException that names
name. Wait on events or read-only observations; never issue a mutation more than once.
public Task Barrier(string name, Func<CancellationToken, Task> wait, TimeSpan within)
Parameters
namestringwaitFunc<CancellationToken, Task>withinTimeSpan
Returns
- Task
ClientHost(string)
The host a campaign client runs on, for reading its files or capturing there.
public IGameHost ClientHost(string campaignClient)
Parameters
campaignClientstring
Returns
ClientLog(ClientRunPlan)
An owned client's live BepInEx log on this machine, for a scenario's in-run log reads; null for a campaign's clients (on their hosts) and an attached client (its logs are its operator's).
public string? ClientLog(ClientRunPlan client)
Parameters
clientClientRunPlan
Returns
- string
DisposeAsync()
Closes the clients in reverse order, then stops the server, each a Cleanup step; a failed close is recorded and the rest
still run. The session's token is cancelled first, so a barrier the scenario left running ends now. A hosting client is
closed after its peers: when everything so far passed, it first leaves its world to its menu (the game saves it); an owned
one is then stopped, an operator's detached. Its placed world is moved into the evidence only once no client can still host
it (it left, or its owned process stopped); otherwise it is left in place and named (hostWorldLeftInPlace).
public ValueTask DisposeAsync()
Returns
- ValueTask
Join(string, HeightExpectation?, bool, CrossplayLobby?)
The barrier "client X in world <uid>": the server accepts connections, then client joins it once
(JoinWorld(ClientRunPlan, string, CrossplayLobby?, bool, CancellationToken): by address, or the crossplay lobby; the world pinned and awaited;
protect enables god, ghost and debug protection), within the client plan's join time. With
arrival, the player then stands there (Arrive(GameActor?, GameActor, HeightExpectation, TimeSpan, CancellationToken, bool, bool)) within its arrival time, and
the arrival (its support reading and teleport timing) is returned for the scenario's evidence; otherwise null.
public Task<PlayerPlacement.TeleportArrival?> Join(string client, HeightExpectation? arrival = null, bool protect = true, CrossplayLobby? lobby = null)
Parameters
clientstringarrivalHeightExpectationprotectboollobbyCrossplayLobby
Returns
JoinAll(CrossplayLobby?)
Every client joins, one after another in name order (Join(string, HeightExpectation?, bool, CrossplayLobby?), protected, no arrival point; a crossplay server's lobby; a host's peers by its identity).
public Task JoinAll(CrossplayLobby? lobby = null)
Parameters
lobbyCrossplayLobby
Returns
- Task
OpenClient(ClientRunPlan, string?, string?)
Opens a client of plan through a new ClientActor and returns its session; its logs join
Logs, and one the scenario leaves open is closed at teardown before the server stops. In a campaign,
name names the campaign's client (left out when it declares one), which starts on its assigned host on
its leased Steam identity; otherwise the client opens on this machine. A campaign's client, and any client opened by name,
writes its evidence into its own folder (Valheim.Testing.GameSessions.GameSession.ActorOutput(string, string)). With directory, its evidence goes
to that subdirectory of Output instead, so a second client never overwrites the first one's. Until the
scenarios declare their clients, this is how a scenario opens one. A client opened into its own
directory and no name is named by its directory in the report.
public ClientSession OpenClient(ClientRunPlan plan, string? name = null, string? directory = null)
Parameters
planClientRunPlannamestringdirectorystring
Returns
OpenClientsAsync(IReadOnlyDictionary<string, ClientRunPlan>)
Opens the named campaign clients at once (OpenClient(ClientRunPlan, string?, string?) for each), each on its own host, Steam lease, install and character; all have opened before this returns. If one fails, every client that opened is closed and the first failure is rethrown (not the cancellation it caused in the others).
public Task<IReadOnlyDictionary<string, ClientSession>> OpenClientsAsync(IReadOnlyDictionary<string, ClientRunPlan> clients)
Parameters
clientsIReadOnlyDictionary<string, ClientRunPlan>
Returns
- Task<IReadOnlyDictionary<string, ClientSession>>
Rejoin(string, HeightExpectation?, bool, CrossplayLobby?)
The barrier "client X back at its menu", then Join(string, HeightExpectation?, bool, CrossplayLobby?) again: the client leaves the world (pins verified at the
menu again) and rejoins the server's current boot, or the host's world. It first waits, within the client's join time, for
the client to settle where it is (SessionControl: idle at its menu, or in the world with its player): a client the
world already dropped (a host's restart disconnects its peers) is only re-pinned at its menu and recorded in
rejoinedFromMenu; a leave is issued only from a loaded world.
public Task<PlayerPlacement.TeleportArrival?> Rejoin(string client, HeightExpectation? arrival = null, bool protect = true, CrossplayLobby? lobby = null)
Parameters
clientstringarrivalHeightExpectationprotectboollobbyCrossplayLobby
Returns
ServerJoinable()
The barrier "the server accepts game connections", within the server's startup deadline; with a hosting client, "the host's world accepts game connections" (WaitUntilJoinable(GameActor)), within its plan's join time.
public Task ServerJoinable()
Returns
- Task
StartAsync()
Starts every actor at once: the server's boot ("start and verify owned dedicated fixture") and each client to its menu ("client X at its menu, plugins pinned"), each a Setup step. When one fails, the session's token is cancelled so the others end their waits, every start settles, the session is disposed (clients closed, then the server stopped, each a Cleanup step), and the first failure is rethrown.
public Task StartAsync()
Returns
- Task