Skip to content

fix: add state machine validation and fix vote/captain disconnect handling#136

Open
Flegma wants to merge 5 commits intomainfrom
audit/396-state-machine
Open

fix: add state machine validation and fix vote/captain disconnect handling#136
Flegma wants to merge 5 commits intomainfrom
audit/396-state-machine

Conversation

@Flegma
Copy link
Copy Markdown
Contributor

@Flegma Flegma commented Apr 8, 2026

Summary

Test plan

  • Verify match progresses through normal flow: Scheduled -> Warmup -> Knife -> Live -> Finished
  • Verify illegal transitions (e.g. Finished -> Live, Paused -> Knife when not previously in Knife) are logged and rejected
  • Verify captain removal works during knife round (disconnect a captain during knife, confirm reassignment)
  • Verify captain-only votes resolve when one captain disconnects (start a captain vote, disconnect one captain, confirm remaining captain's vote resolves it)
  • Verify normal 2-captain votes still work as before (both captains present, both vote)

Flegma added 4 commits April 8, 2026 12:39
… disconnect

Add allowed-transitions dictionary to MatchManager.UpdateMapStatus so
illegal state jumps (e.g. Finished -> Live) are rejected with a warning.

Fix CaptainSystem.RemoveCaptain to allow captain removal during knife
round in addition to warmup.

Replace hardcoded captain vote count of 2 in VoteSystem.CheckVotes with
the dynamic expectedVoteCount so a single remaining captain can resolve
a vote when the other disconnects. Remove stray extra semicolon in
GetExpectedVoteCount.
SendSurrender() in GameEnd.cs calls UpdateMapStatus(Finished) after a
surrender, so Surrendered cannot be a terminal state. Without this,
the surrender flow silently fails to mark the map as Finished.
When a player disconnects, their vote was persisting in active votes
while GetExpectedVoteCount excluded them, causing inconsistent tallies.
Now cleans up votes from surrender, pause, resume, and restore systems.
Move the allowed-transition guard above CheckForBackupRestore so
illegal transitions are rejected before any side effects run.
@Flegma Flegma requested a review from lukepolo April 10, 2026 09:18
new HashSet<eMapStatus> { eMapStatus.Live, eMapStatus.Paused }
},
{
eMapStatus.Live,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sometimes we may need to restart go bk to warmup / restart knife round.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Added restart transitions in abbd6d3:

  • LiveWarmup / Knife (restart from live)
  • OvertimeWarmup / Knife / Live (full or knife restart during OT, or roll OT back to regulation)
  • KnifeWarmup (go back to warmup from knife)

The downstream handlers (StartWarmup, StartKnife with mp_restartgame 1) already cover the game-side reset, so no other changes needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads-up on a related concern the reviewer flagged (pre-existing, not introduced here but worth your call):

When going Live/Overtime/KnifeWarmup (or Knife), StartWarmup()/StartKnife() do not stop the demo or reset backup state:

  • _matchDemos.Start() (GameDemos.cs:53) bails early if the lock file exists → restarting Live won't re-initialize recording, producing a continuous demo across the restart
  • _backUpManagement.Setup() cvar (mp_backup_round_file) is not reset

This gap already exists for the Paused → Warmup path, so this PR doesn't regress anything, but the new transitions widen the surface. Options:

  1. Leave as-is — admin restart keeps one continuous demo (current behavior)
  2. Stop demo on Warmup/Knife entry from active states — produces a fresh demo file per restart
  3. Handle at a different layer (server-side tv_stoprecord + file rotation)

Happy to implement (2) in this PR or a follow-up if that's what you want.

Admins can need to go back to warmup or restart the knife round mid-match
(via match_state or API-driven Init). The strict transition table rejected
these, forcing a Paused detour. Allow Live and Overtime to transition to
Warmup/Knife directly, and Knife to transition to Warmup.
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.

2 participants