Initial Commit
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user