121 lines
6.0 KiB
Markdown
121 lines
6.0 KiB
Markdown
# game-server-engine-sessions — sessions + players (Wave B-2)
|
||
|
||
**Package**: `@suaveplan/game-server`
|
||
**Status**: PROPOSED
|
||
**Type**: feature (Wave B-2 migration slice)
|
||
|
||
- **Design**: see this file
|
||
- **Spec delta**: ./specs/game-server/spec.md
|
||
|
||
## Why
|
||
|
||
Wave A landed the foundations and Wave A interfaces (`ISessionManager`,
|
||
`IPlayerManager` et al). Wave B-1 shipped the engine top-level (GameEngine
|
||
+ GameLoop + PluginManager). Waves B-3 and B-4 shipped state + network.
|
||
|
||
What is missing: the session and player runtime that backs those Wave A
|
||
interfaces. Without it, the engine has nowhere to register a session or
|
||
track a connected player, and the `ISessionManager` /
|
||
`IPlayerManager` slots in `GameEngine` can only be filled by ad-hoc
|
||
stubs.
|
||
|
||
This slice (Wave B-2) ships five engine modules that round out the
|
||
runtime:
|
||
|
||
- `SessionLifecycle` — per-session FSM (`lobby → active → ended`) with
|
||
transition validation, audit history, and OTel dwell metrics.
|
||
- `SessionGraphNode` — internal mutable graph node implementing Wave A's
|
||
read-only `SessionNode` interface.
|
||
- `SessionTree` — hierarchical graph (`Map<id, node>` + `Set<rootId>`)
|
||
with O(1) lookups, Zod-validated boundaries, and typed event emission.
|
||
- `SessionStore` — `ISessionManager` implementation composing
|
||
`SessionTree` with an injectable `SessionPersistence` adapter for
|
||
durability.
|
||
- `PlayerManager` — `IPlayerManager` implementation with heartbeat-driven
|
||
liveness, reconnection grace window, and a timer-driven monitor that
|
||
routes through `TimersLike`.
|
||
|
||
This is a re-dispatch of an earlier B-2 attempt that branched from a
|
||
stale base and re-invented Wave A's interfaces. The new work builds on
|
||
top of the existing canonical interfaces and types.
|
||
|
||
## What changes
|
||
|
||
- ADDED: `SessionGraphNode` (`engine/session-node`) — internal mutable
|
||
graph node, structurally compatible with Wave A's `SessionNode`
|
||
interface; preserves timestamps on persistence round-trips.
|
||
- ADDED: `SessionTree` (`engine/session-tree`) — graph manager with
|
||
`createSession`/`destroySession`/`getStats`/`validateIntegrity` plus
|
||
the `attachRestored` seam used by `SessionStore.restore`.
|
||
- ADDED: `SessionStore` (`engine/session-store`) — `ISessionManager`
|
||
implementation with pluggable `SessionPersistence` (default in-memory).
|
||
- ADDED: `SessionLifecycle` (`engine/session-lifecycle`) — per-session
|
||
FSM with stable error codes for every rejection path.
|
||
- ADDED: `PlayerManager` (`engine/player-manager`) — `IPlayerManager`
|
||
implementation with injectable `Clock`/`TimersLike`/`EventBus`.
|
||
- ADDED: `GAME_SERVER.*` codes — `SESSION_NOT_FOUND`,
|
||
`SESSION_ALREADY_ENDED`, `INVALID_SESSION_TRANSITION`,
|
||
`DUPLICATE_PLAYER_IN_SESSION`, `INVALID_SESSION_DATA`,
|
||
`DUPLICATE_SESSION_ID`, `PARENT_SESSION_NOT_FOUND`,
|
||
`INVALID_SESSION_STORE_OPTIONS`, `INVALID_PLAYER_MANAGER_OPTIONS`,
|
||
`INVALID_HEARTBEAT_INTERVAL`, `PLAYER_DISCONNECTED`.
|
||
- ADDED: OTel instruments — `game_server.session.lifecycle_total`
|
||
counter, `game_server.session.dwell_ms` histogram,
|
||
`game_server.player.lifecycle_total` counter.
|
||
- ADDED: subpath exports `./engine/session-lifecycle`,
|
||
`./engine/session-node`, `./engine/session-store`,
|
||
`./engine/session-tree`, `./engine/player-manager`.
|
||
|
||
## Out of scope
|
||
|
||
- `GameEngine` re-wiring to consume `SessionStore` / `PlayerManager` at
|
||
construction (later orchestration slice; engine accepts them via DI).
|
||
- Hono / network plugin layer for session/player REST (later slice).
|
||
- The matchmaking / queue surface in upstream's `enhanced/` — out of
|
||
scope for B-2.
|
||
|
||
## Source mapping
|
||
|
||
| Requirement | Source lines | Notes |
|
||
|---|---|---|
|
||
| SessionNode graph helpers | `packages/universal/game-server/src/engine/SessionNode.ts` L8–L175 | Recast — `Date.now()` replaced by injectable `Clock`; idempotent `addChild`. |
|
||
| SessionTree O(1) graph | `packages/universal/game-server/src/engine/SessionTree.ts` L16–L441 | Recast — plain `Error` → `GameServerError`; Zod-validated boundary; persistence concern lifted into `SessionStore`. |
|
||
| SessionStore persistence | `packages/universal/game-server/src/engine/SessionStore.ts` L22–L132 | Recast — `AbstractStorage` byte API replaced by `SessionPersistence` adapter accepting structured records. |
|
||
| PlayerManager lifecycle | `packages/universal/game-server/src/engine/PlayerManager.ts` L13–L357 | Recast — `setInterval` replaced by `TimersLike`-driven self-rescheduling tick; reconnection grace window. |
|
||
|
||
### Requirements with no source line
|
||
|
||
| Requirement | Justification |
|
||
|---|---|
|
||
| `SessionLifecycle` FSM | Genesis bar — upstream `SessionLifecycle.ts` was a session+player coordinator, NOT an FSM. The B-2 dispatch explicitly requires a per-session `lobby → active → ended` FSM with transition validation + audit history. |
|
||
| OTel session lifecycle counter + dwell histogram | Genesis bar — upstream had no OTel. |
|
||
| OTel player lifecycle counter | Genesis bar — upstream had no OTel. |
|
||
| Zod-validated `SessionData` and option boundaries | Genesis bar. |
|
||
|
||
## Verification approach
|
||
|
||
- `src/engine/session-lifecycle/session-lifecycle.test.ts` — FSM
|
||
transition table, audit history, dwell sample emission, error paths.
|
||
- `src/engine/session-node/session-node.test.ts` — tree-walking helpers,
|
||
idempotent attach, persistence round-trip with preserved timestamps.
|
||
- `src/engine/session-tree/session-tree.test.ts` — Zod boundary, O(1)
|
||
lookups, bottom-up cascade, integrity audit, restore seam.
|
||
- `src/engine/session-store/session-store.test.ts` — `ISessionManager`
|
||
conformance harness, persist/restore round-trip, orphan handling.
|
||
- `src/engine/player-manager/player-manager.test.ts` —
|
||
`IPlayerManager` conformance harness, heartbeat monitor scheduling,
|
||
grace-window eviction, reconnection metadata merge.
|
||
|
||
## Impact
|
||
|
||
### Affected dependents
|
||
|
||
The package has no shipped dependents on genesis at the time of this
|
||
change. Additive surface only.
|
||
|
||
## Migration impact
|
||
|
||
None — additive only. Existing `./errors`, `./types`, `./core`, `./engine/*`
|
||
surfaces are unchanged. `GAME_SERVER_CODES` registry is **extended**;
|
||
all existing codes are preserved.
|