Game Session Management
A centralized session service that owns the lifecycle of every run — status, elapsed time and identity — so no subsystem has to duplicate it.
What the system is for
Every game has a run. It starts, it can be paused and resumed, and it ends either in failure or completion. The problem is that each subsystem that cares about that lifecycle — the HUD, the score counter, the checkpoint system, the music controller — tends to track it independently with its own boolean flags and timer variables.
Game Session in Serenity is the single place where a run's lifecycle lives. It maintains the current GameSessionStatus, the elapsed time, and a stable GameSessionId, and it exposes an immutable GameSessionSnapshot for any system that needs to read that state without mutating it.
The Unity problem
In a Unity project without a session aggregate, the question 'is the run active right now?' gets answered differently by every system. The HUD checks a static flag. The timer checks whether Update is running. The checkpoint system checks a scene-level boolean. They can drift. A pause from one system does not stop the timer in another. Elapsed time accumulates during loading because nothing owns the start and stop.
The deeper issue is that there is no canonical run identity. Resetting a run means hunting down every system that cached something and telling each one individually. Adding a new system that needs session state means deciding yet again where to read it from.
How Serenity approaches it
IGameSessionService centralizes that coordination. It exposes Status, ElapsedTime and SessionId as read properties and drives transitions through explicit methods: StartSession, Pause, Resume, GameOver and Complete. The GameSessionStatus enum captures every valid state — NotStarted, Playing, Paused, GameOver and Completed — so transition logic is unambiguous.
GetSnapshot returns a GameSessionSnapshot: an immutable readonly struct holding the session identity, current status, elapsed time and a score snapshot at that point in time. The HUD, the UI, and any other read-only consumer call GetSnapshot and get a consistent picture of the run without touching mutable state.
How it fits into Serenity
Game Session lives in the Serenity.GameSession namespace and follows the foundation's layered structure. The Domain layer defines the GameSessionStatus enum, the GameSessionId value object, the GameSessionState entity and the GameSessionSnapshot value object. The Application layer exposes IGameSessionService. The Installation layer provides GameSessionInstaller, which wires the service into the initialization pipeline together with an ITimerService dependency for elapsed time tracking.
Game Session cooperates with the Timer aggregate through ConfigureTimer: the service takes ownership of the timer lifecycle — initialize, start, pause, resume, stop — so the timer always reflects the session state exactly. It also cooperates with Score (the snapshot includes a ScoreSnapshot), with Checkpoint for save-point integration, with Game Mode for context, and with the Event Dispatcher for publishing lifecycle signals to interested subsystems.
Practical workflow
- Extend GameSessionInstaller in your project to create and register the IGameSessionService implementation.
- Call ConfigureTimer before StartSession to hand the session its elapsed-time timer.
- Call StartSession with a GameSessionId — use GameSessionId.NewGuid() for auto-generated identities.
- Drive transitions through the service methods: Pause, Resume, GameOver or Complete as your game rules dictate.
- Call Tick each frame so the session can advance the timer while the status is Playing.
- Read session state from any subsystem via GetSnapshot — the returned GameSessionSnapshot is an immutable struct safe to pass anywhere.
What you get
- Session service interface IGameSessionService with Status, ElapsedTime and SessionId properties
- Explicit lifecycle methods StartSession, Pause, Resume, GameOver and Complete
- GameSessionStatus enum covering NotStarted, Playing, Paused, GameOver and Completed
- Immutable read model GameSessionSnapshot with identity, status, elapsed time and score
- GameSessionId value object with auto-generation via NewGuid and stable equality semantics
- Timer ownership through ConfigureTimer — the service starts, pauses and stops the timer automatically
- GameSessionInstaller base class for plugging the service into the initialization pipeline
- Cooperation with Score, Checkpoint, Game Mode and the Event Dispatcher through shared interfaces
When to use this
- Projects where multiple systems each maintain their own version of 'is the run active' and they get out of sync.
- Games that need reliable elapsed time that pauses and resumes with the session rather than running continuously.
- Codebases that want a stable session identity so resetting a run means creating a new session, not hunting down cached state.
- Any project where the HUD or UI needs a consistent, immutable snapshot of session state without coupling to mutable internals.
Related systems
Use Serenity when you want one place that owns the run — so pausing, resuming and ending it propagates automatically to every system that reads from the session instead of requiring coordinated manual updates.
English
Español
Català