Skip to content

start,end turn, stop functionality #9

@abaines

Description

@abaines

Clean Description

Description
Implement the core state machine for the multiplayer count-up timer. The backend will act as the single source of truth for all time calculations. The frontend acts purely as a remote control (sending intent) and a display (rendering state).

This logic governs the "Unclaimed Time" model, where time acts as a growing bucket that is retroactively assigned to the specific user who triggers the "End Turn" event.

💰 The "Time Billing" Logic (Crucial)

  1. Start: Sets the anchor_time.
  2. Ticking: Time passes. (No DB updates, purely temporal).
  3. End Turn (Player X):
  • Server calculates: (Date.now() - anchor_time) + accrued_paused_time.
  • Server adds this result to Player X's running total.
  • Server resets accrued_paused_time to 0.
  • Server updates anchor_time to Date.now().
  • Server broadcasts: Player X finished turn (+23s). New turn started.
  1. Pause:
  • Server calculates: (Date.now() - anchor_time).
  • Adds result to accrued_paused_time.
  • Sets State to PAUSED.
  1. Resume:
  • Sets anchor_time to Date.now().
  • Sets State to RUNNING.
  1. Stop:
  • Calculates nothing.
  • Resets accrued_paused_time and anchor_time.
  • Sets State to STOPPED.
  • Broadcasts final totals.

✅ Acceptance Criteria

State Management

[ ] Server maintains a global GameState enum: { STOPPED, RUNNING, PAUSED }.

[ ] Server rejects commands that are invalid for the current state (e.g., Start when already RUNNING, End Turn when STOPPED).

Time Calculation (Server Authority)

[ ] All time math uses server-side timestamps. FE timestamps are ignored.

[ ] On END_TURN event, the duration is calculated and persisted to the specific userId that sent the message.

[ ] PAUSE events successfully "freeze" the accumulator. Time spent in PAUSED state is never added to any player's total.

[ ] RESUME picks up the accumulation exactly where PAUSE left off.

Broadcasting

[ ] After any state change or time assignment, Server broadcasts the full updated state (State, Current Totals, Last Event Timestamp) to all clients in the room.

[ ] Broadcast message includes last_anchor_time so Frontends can render their own "ticking" UI locally (by doing now - last_anchor_time).

🛡️ Edge Case Handling
The "Snipe": If Player A and Player B send End Turn almost simultaneously:

Process Player A: Assigns full time. Reset anchor.

Process Player B: Assigns difference (e.g., 50ms). Reset anchor.

Outcome: Accepted behavior.

🚫 Constraints
No frontend logic for calculating durations.

No "Turn Order" enforcement. Any player can claim the current time bucket.

🧠Brainstorming notes

So we finally have solid baseline. Next is the core of the application.

The POC is a like a multiplayer chess timer that counts up. At the end (stop button) it would display/show the total amount of time that each player spent on their turn.

One player would be able to start the global timer. Each time a player ends their turn (button), the time since the last event (start or resume or previous player's end turn) would then be assigned to the player ending their turn; and a new timer would begin. This would repeat when the next player ends their turn.

Any player can start/stop/pause/resume/end-turn.

If the timer is running any player can end-turn and they get billed the available time. A new counter is started, which will then be billed to the next player. (Retroactive assignment)

Once any player stops (button), then the totals for each player would be shown/displayed.

Players are expected to have multiple turns, so their total would be a sum of all of their turns.

If possible, running total could be updated each time any player ends their turn.

The start, resume buttons would only be enabled if the timer isn't ticking.

The end, pause and end turn buttons would only be enabled if the timer is ticking.

Time between pause and resume is not attributed to anyone, even though anyone can pause or resume.

When a player stops (button) any remaining time is lost and not assigned to anyone. If a player wanted to assign time to themselves near the end of the game, they could end turn then immediately end/stop.

Any player can start/pause/resume/end if the global state is correct. The only event that assigns time to players is end turn. Which is the time since the last start/end-turn event (minus any paused time).

Don't worry about background clients.

Backend web Server is authority for time tracking. When it receives a WS, that is when the event happens. The FE shouldn't be doing any Date.now() or time subtracting math or sums. That is all BE job.

Players are expected to be paying attention to the board game we are playing together and their phones should only being used for tracking time. If they lose time because they are multi-tasking, that is on them.

No DBs. Everything in memory server-side.

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions