feat(observer): add observer mode and disconnect recovery
This commit is contained in:
+20
-4
@@ -1,9 +1,8 @@
|
||||
# Authoritative game core
|
||||
|
||||
Milestones 006 and 007 provide the portable movement engine, gameplay object
|
||||
systems, terminal results, and view projector. The ESP remains the only owner
|
||||
of mutable game state. Reconnect behavior and browser controls remain out of
|
||||
scope until their later milestones.
|
||||
Milestones 006, 007, and 009 provide the portable movement engine, gameplay
|
||||
object systems, terminal results, view projector, and disconnect recovery. The
|
||||
ESP remains the only owner of mutable game state.
|
||||
|
||||
## Command processing
|
||||
|
||||
@@ -87,3 +86,20 @@ compass hint, and own-exit status. An opponent's carried key is included only
|
||||
while that opponent is currently visible. Observer snapshots contain both
|
||||
inventories and effect counters, both exit states and authoritative exit
|
||||
timestamps, every remaining ground object, and the public match result.
|
||||
|
||||
## Disconnect recovery
|
||||
|
||||
Both players start connected. Disconnecting either player during `active` or
|
||||
`finish_pending` stores that exact phase, clears queued commands, enters
|
||||
`paused`, and assigns the disconnected player a monotonic deadline 60,000 ms
|
||||
after detection. Commands processed during the pause are rejected before any
|
||||
position, inventory, effect counter, or result can change.
|
||||
If the disconnect occurs during `finish_pending`, the remaining 200 ms result
|
||||
window is preserved and continues only after both players reconnect.
|
||||
|
||||
Restoring the reserved player session before the deadline reconnects the same
|
||||
player record. The stored phase resumes only when both player records are
|
||||
connected, so a second disconnected player cannot be bypassed. Reaching a
|
||||
disconnected player's deadline ends the match with the authoritative `draw`
|
||||
result and clears queued commands. Observer connection state never enters this
|
||||
state machine.
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Observer browser mode
|
||||
|
||||
Milestone 009 adds a password-free observer role to the same local browser
|
||||
application. The role is still authenticated by its temporary session token,
|
||||
but joining it does not request a player name or consume either player slot.
|
||||
At most four observer sessions are connected at once.
|
||||
|
||||
## Projection and authorization
|
||||
|
||||
An observer renders only the server's `observer` view projection. That
|
||||
projection contains all maze cells, remaining objects, both player positions,
|
||||
inventories, effects, exit state, phase, and result. The browser does not
|
||||
simulate movements or infer updates. Each player status also reflects the
|
||||
server-owned WebSocket connection state. A complete projection establishes the
|
||||
server-approved static geometry on join, restoration, and match start.
|
||||
Subsequent bounded projections replace all dynamic player and object state
|
||||
while reusing only that authoritative geometry, avoiding an 8,192-cell
|
||||
retransmission after every move.
|
||||
|
||||
The observer screen contains no movement, start, or drop-key control. This is
|
||||
only presentation-level defense: the gateway also rejects and logs observer
|
||||
`start`, `move`, and `drop_key` attempts before they reach authoritative
|
||||
mutation. Disconnecting an observer changes only lobby presence and never
|
||||
pauses the game.
|
||||
|
||||
## Viewport and navigation
|
||||
|
||||
At `1024 x 768` CSS pixels and above, the complete `128 x 64` default map is
|
||||
initially scaled to fit the available stage. The observer can zoom with the
|
||||
labelled buttons or mouse wheel and pan with pointer dragging. Zoom is bounded
|
||||
between 0.25 and 6 times the eight-pixel base cell size; the **Вся карта**
|
||||
control restores the calculated fit and centered position.
|
||||
|
||||
When either viewport dimension is below the supported minimum, the map and
|
||||
controls are hidden and the Russian message **Нужен экран побольше** explains
|
||||
the `1024 x 768` requirement. All assets remain local and use the shared
|
||||
retro-arcade visual language.
|
||||
@@ -57,3 +57,6 @@ Russian; protocol identifiers remain English.
|
||||
Sound and supported vibration are enabled after the first pointer or keyboard
|
||||
interaction. Both are progressive enhancements: unsupported devices continue
|
||||
without an error.
|
||||
|
||||
Observer presentation and its read-only interaction boundary are documented in
|
||||
`OBSERVER_UI.md`.
|
||||
|
||||
+19
-6
@@ -33,10 +33,12 @@ is only echoed for correlation; it grants no authority.
|
||||
- `suggest_name`: `{}`.
|
||||
- `start`: `{}`. Only connected Player 1 may use it, and both player slots must
|
||||
be connected.
|
||||
- `move`: `{"direction":"north|east|south|west"}`. Only a player in an active,
|
||||
unpaused match may submit movement intent.
|
||||
- `drop_key`: `{}`. Only a player in an active, unpaused match may submit the
|
||||
key-drop intent.
|
||||
- `heartbeat`: `{}` after a session has been joined or restored.
|
||||
|
||||
No Milestone 005 maze or movement messages are implemented by this milestone.
|
||||
|
||||
## Server messages
|
||||
|
||||
- `session`: the private role result containing `role`, `slot`, and temporary
|
||||
@@ -47,10 +49,21 @@ No Milestone 005 maze or movement messages are implemented by this milestone.
|
||||
- `countdown`: the single authoritative `[3,2,1]` event with common monotonic
|
||||
`startedAtMs` and `activationAtMs` values. It is sent to both players.
|
||||
- `active`: the exact authoritative activation instant.
|
||||
- `view`: a bounded chunk of a role-specific authoritative game projection.
|
||||
Observer chunks contain the complete maze and both player records, including
|
||||
their connection state; player chunks retain the fog-of-war boundary.
|
||||
- `pause`: identifies the disconnected player slot and its monotonic reconnect
|
||||
deadline.
|
||||
- `resume`: reports that both players are attached and authoritative gameplay
|
||||
has resumed.
|
||||
- `match_result`: reports the terminal winner or draw.
|
||||
- `ack`: successful heartbeat correlation.
|
||||
- `error`: a stable English `code` and Russian player-facing `message`.
|
||||
|
||||
An observer session can receive snapshots but cannot issue `start`. Player
|
||||
tokens reserve their original slot after disconnection so a refresh can restore
|
||||
it. A disconnected observer token may be restored until its bounded slot is
|
||||
reused by a new observer.
|
||||
An observer session can receive snapshots but cannot issue `start`, `move`, or
|
||||
`drop_key`; attempts are rejected with `read_only` where applicable and logged
|
||||
by the gateway. Player tokens reserve their original slot after disconnection
|
||||
so a refresh can restore it. A player disconnect pauses the game for at most 60
|
||||
seconds; restoration reattaches the same state, while expiry produces a draw.
|
||||
A disconnected observer token may be restored until its bounded slot is reused
|
||||
by a new observer, and observer disconnects never pause the match.
|
||||
|
||||
Reference in New Issue
Block a user