Table of Contents

Class LogoutCycle

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

A logout and the next login, observed: the character file is rewritten when the player leaves to the menu, and the mod's custom data comes back when the character joins again. Mods that keep state in the player profile (Player.m_customData) lose it when the file is not written, for example when another mod removes every Harmony patch at quit or a server-character mod has no time to finish.

In 1.0.16 the save happens inside the logout itself, before the menu loads: Game.Logout shuts the game session down, which saves the player into its profile and writes the profile (PlayerProfile.Save): a new file <name>.fch.new, the previous file moved to <name>.fch.old and the new one renamed to <name>.fch. ValheimCLI's session leave issues that logout and replies once the menu is up, so the new file is normally there when the leave returns; the runner still waits up to WriteTimeout for its hash to change, woken by file events, because it may see the client's disk late. The game skips the save entirely when its save system blocks character saves (logged "Character save blocked") and when the disk is full.

Run(ClientRound, ClientRunPlan, string, CancellationToken, string) reads the Keys (each must be set), hashes the profile file, has the client leave to its menu, waits for a different hash, joins again with the plan's character by address (JoinWorld(ClientRunPlan, string, CrossplayLobby?, bool, CancellationToken), the join ClientRounds uses: protected, and test access on an owned client) and requires every key back with its value; a crossplay or hosting plan is refused before anything is sent. Only a disposable local character: the game must report it saved Local, and CharactersDirectory must be the game's local character folder, characters_local, never a cloud copy. The client is joined again when it returns.

An unchanged hash is all the runner can see of a save that rewrote identical bytes; a moved player, a longer play time or a changed value makes the file differ. Another save in the window (a world save asks every client to save its profile) is indistinguishable from the logout's own; OldMatchesBefore is false then.

public sealed class LogoutCycle
Inheritance
object
LogoutCycle

Properties

Capability

ValheimCLI's custom-data observation, for example valheim.observe/custom-data.

public required string Capability { get; init; }

Property Value

string

CharactersDirectory

The client's local character folder as this runner reads it (the game's characters_local under its save root), for example the owned client's save root plus characters_local. The file is its <profile file>.fch.

public required string CharactersDirectory { get; init; }

Property Value

string

KeyPrefix

Only the custom data keys starting with this are read (one token); null reads them all.

public string? KeyPrefix { get; init; }

Property Value

string

Keys

The custom data keys that must come back: at least one, all set before the logout.

public required IReadOnlyList<string> Keys { get; init; }

Property Value

IReadOnlyList<string>

RereadInterval

How often the file is re-read when no file event arrives (some filesystems raise none).

public TimeSpan RereadInterval { get; init; }

Property Value

TimeSpan

WriteTimeout

How long after the leave returns the file's hash may take to change.

public required TimeSpan WriteTimeout { get; init; }

Property Value

TimeSpan

Methods

ProfilePath(CustomDataReading)

The profile file of reading's character in CharactersDirectory.

public string ProfilePath(CustomDataReading reading)

Parameters

reading CustomDataReading

Returns

string

Run(ClientRound, ClientRunPlan, string, CancellationToken, string)

Runs the cycle within a ClientRounds measurement: each part is a {round}: ... step and the readings are written to {round}-{evidence}.json (default logout) whether it passes or fails. plan and worldUid are the ones the rounds use, for the join.

public LogoutResult Run(ClientRound round, ClientRunPlan plan, string worldUid, CancellationToken cancellation = default, string evidence = "logout")

Parameters

round ClientRound
plan ClientRunPlan
worldUid string
cancellation CancellationToken
evidence string

Returns

LogoutResult

Run(GameActor, ClientRunPlan, string, CancellationToken)

The same cycle outside ClientRounds: client is joined to worldUid with plan's character.

public LogoutResult Run(GameActor client, ClientRunPlan plan, string worldUid, CancellationToken cancellation = default)

Parameters

client GameActor
plan ClientRunPlan
worldUid string
cancellation CancellationToken

Returns

LogoutResult