fix: add state machine validation and fix vote/captain disconnect handling#136
fix: add state machine validation and fix vote/captain disconnect handling#136
Conversation
… 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.
| new HashSet<eMapStatus> { eMapStatus.Live, eMapStatus.Paused } | ||
| }, | ||
| { | ||
| eMapStatus.Live, |
There was a problem hiding this comment.
sometimes we may need to restart go bk to warmup / restart knife round.
There was a problem hiding this comment.
Good catch. Added restart transitions in abbd6d3:
Live→Warmup/Knife(restart from live)Overtime→Warmup/Knife/Live(full or knife restart during OT, or roll OT back to regulation)Knife→Warmup(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.
There was a problem hiding this comment.
Heads-up on a related concern the reviewer flagged (pre-existing, not introduced here but worth your call):
When going Live/Overtime/Knife → Warmup (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:
- Leave as-is — admin restart keeps one continuous demo (current behavior)
- Stop demo on
Warmup/Knifeentry from active states — produces a fresh demo file per restart - 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.
Summary
_allowedTransitionsdictionary toMatchManagerthat defines legaleMapStatustransitions.UpdateMapStatusnow rejects and logs illegal transitions (e.g.Finished -> Live,Paused -> Kniferound skip) instead of silently accepting any status change.CaptainSystem.RemoveCaptaincondition from!match.IsWarmup()to!(match.IsWarmup() || match.IsKnife())so captains can be properly removed/reassigned during the knife round.2inVoteSystem.CheckVotescaptain-only path with the dynamicexpectedVoteCountfromGetExpectedVoteCount(). When a captain disconnects and only 1 remains, a single captain's vote now resolves the vote instead of deadlocking. Also remove a stray extra semicolon inGetExpectedVoteCount.Test plan