Skip to content

Online liveness: in-game disconnect grace, occupancy refresh, client ping - #23

Merged
rotundtapir merged 1 commit into
mainfrom
feat/game-disconnect-grace
Aug 22, 2026
Merged

rotundtapir merged 1 commit into
mainfrom
feat/game-disconnect-grace

Conversation

@rotundtapir

@rotundtapir rotundtapir commented Aug 22, 2026 •

Copy link
Copy Markdown
Owner

Three fixes from Jack's cross-client field reports:

  • In-game disconnect grace (gameDisconnectGraceMillis, default 3 min, GAME_GRACE_MILLIS env, 0 = today's instant substitution): the seat parks (SeatHost.awaitingReclaim) instead of botting on socket drop, reclaim inside the grace resumes seamlessly, expiry substitutes as before. Per-slot grace generation defeats stale timers from earlier drops. Protocol untouched.
  • Occupancy refresh on reconnect: SeatStatus is transient, so a client disconnected at announcement time resumed with a stale picture (a reclaimed player showing "(bot)" forever). onReconnect now sends the reconnector every other human seat's current status.
  • 20s WebSocket ping on the JVM/CIO engine: Android silently kills backgrounded sockets and nothing detected the zombie — the receive loop waited indefinitely, so the foregrounded app 'took a long time to receive moves'. Ping bounds detection to ~two intervals. (Browser engine has no frame-ping API; the 500-side foreground nudge covers tabs.)

Three new RoomTest cases; full ./gradlew build green incl. detekt. Client-side follow-up (foreground nudge + backoff reset) lands in 500.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BiTsrURfRLtBDgyyt5s16K

@rotundtapir
rotundtapir force-pushed the feat/game-disconnect-grace branch from 87fbcd3 to 78fafa0 Compare August 22, 2026 11:38
…ping

Three fixes from cross-client field reports (Jack, flipping between the
Android app and the web client mid-game):

1. An app-switch away long enough to drop the socket handed the seat to
   the bot INSTANTLY — the lobby has a 15-minute grace, the game had
   none, and substituteBot even wakes the parked turn. New
   gameDisconnectGraceMillis (default 3 min, GAME_GRACE_MILLIS env,
   0 = old behaviour): the seat parks (SeatHost.awaitingReclaim —
   decide() waits rather than bot-falling-back while it's set), a
   reconnect inside the grace resumes as if nothing happened, expiry
   substitutes as before. A per-slot grace generation stops a stale
   timer from an earlier drop cutting a newer grace short. No status
   broadcast during the grace; the protocol is untouched.

2. A reclaimed player stayed '(bot)' on another client's screen forever:
   SeatStatus is a transient broadcast, so a client disconnected at
   announcement time resumes with a stale occupancy picture and nothing
   corrected it. onReconnect now refreshes the reconnector with every
   other human-owned seat's current status (refreshOccupancy).

3. The JVM/Android client had no WebSocket ping, so a socket Android
   killed in the background was undetectable — the receive loop waited
   on the zombie indefinitely and the app 'took a long time to receive
   moves' after foregrounding. CIO now pings every 20s, bounding dead-
   socket detection to ~two intervals. (The browser engine has no
   frame-ping API; tabs rely on the browser plus the client-side
   foreground nudge landing in 500.)

Tests: grace holds the seat and reclaim resumes it; expiry hands to the
bot; a reconnector receives the occupancy it missed. Fixture pins grace
0 so existing instant-substitution coverage keeps testing that branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BiTsrURfRLtBDgyyt5s16K
Signed-off-by: rotund_tapir <rotund_tapir@protonmail.com>
@rotundtapir rotundtapir changed the title Room: in-game disconnect grace + occupancy refresh on reconnect Online liveness: in-game disconnect grace, occupancy refresh, client ping Aug 22, 2026
@rotundtapir
rotundtapir force-pushed the feat/game-disconnect-grace branch from 78fafa0 to ebaeb02 Compare August 22, 2026 11:38
@rotundtapir
rotundtapir merged commit 9a90a12 into main Aug 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant