Prevent players from getting into the game without a team when both teams are full - #1168
Merged
Merged
Conversation
PlayerRespawnThink only applied the UNASSIGNED/SPECTATOR check to observers, so a non-observer player stuck at the team select menu (both teams full) with mp_forcerespawn > 0 and mp_auto_join_team 1 got a pending respawn and spawned while on TEAM_UNASSIGNED. Fixes rehlds#929 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HandleMenu_ChooseTeam with MENU_SLOT_TEAM_RANDOM fell through with team == UNASSIGNED when SelectDefaultTeam() found both teams full and no bot could be vacated: TeamFull(UNASSIGNED) and TeamStacked() pass, so the player joined UNASSIGNED and got into the game, spawning via GetIntoGame() since FPlayerCanRespawn() always passes with mp_forcerespawn > 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #929
Fixes #932
What
Players could get into the game with
m_iTeam == UNASSIGNEDwhen both teams are full — a teamless "player" that can move, shoot and pick up weapons, shows no team on the radar/scoreboard and is hostile to everyone. Reproducible withmp_auto_join_team 1+mp_forcerespawn 1on a server where bots fill both teams (bot_auto_vacate 0), and the same fall-through is reachable in the vanilla menu flow via "Auto-select" (slot 5).Why (Root cause)
Two independent paths lead to spawning a player without a team:
HandleMenu_ChooseTeam()withMENU_SLOT_TEAM_RANDOM: whenSelectDefaultTeam()returnsUNASSIGNED(both teams full) and no bot can be vacated, the function falls through —TeamFull(UNASSIGNED)andTeamStacked(UNASSIGNED, ...)both returnFALSE— so it assignsm_iTeam = UNASSIGNEDand returnsTRUE. The comment "If the code gets this far, the team is not TEAM_UNASSIGNED" does not hold on this path. The player then goes through the normal joining flow (HandleMenu_ChooseAppearance()→GetIntoGame()), whereFPlayerCanRespawn()always passes withmp_forcerespawn > 0, resulting in an immediateSpawn()with no team.PlayerRespawnThink(): the guardGetObserverMode() != OBS_NONE && (m_iTeam == UNASSIGNED || m_iTeam == SPECTATOR)does not protect a player sitting at the team select menu (Menu_ChooseTeam/PICKINGTEAM,deadflag == DEAD_DEADsinceClientPutInServer(), observer modeOBS_NONE): the menu check on the next line only coversMenu_ChooseAppearance/SHOWTEAMSELECT, somp_forcerespawnschedules and executes a respawn for a teamless player anyway.How it works
HandleMenu_ChooseTeam(): deny auto-select (return FALSE) when the team is stillUNASSIGNEDafter the vacate attempt — the player stays at the team select menu, consistent with explicitly picking a full team (slots 1/2 are already denied by theTeamFull()check) and with the bot path, which already refuses to add a bot in this case ("Could not add bot to the game: Team is full"). Guarded byREGAMEDLL_FIXESsince the fall-through exists in the vanilla code.PlayerRespawnThink(): never force-respawn players without a team (UNASSIGNED/SPECTATOR) regardless of observer mode. UnlikePlayerDeathThink()(which is gated bym_iJoiningState != JOINED), this function is reached fromPreThink()for players in any joining state, hence the stronger guard.Edge cases
jointeamconsole command,mp_auto_join_team) go throughHandleMenu_ChooseTeam(), so the fix covers them all.RoundRespawn()) already skips teamless players, and the bot add path already deniesUNASSIGNED— behavior is now consistent everywhere.PlayerRespawnThink()isREGAMEDLL_ADD-only and theHandleMenu_ChooseTeam()change is underREGAMEDLL_FIXES.Tested
On a 24-slot Windows server (cs_office, 10+10 spawn points),
bot_quota 32; bot_stop 1; bot_join_after_player 0; bot_auto_vacate 0; mp_forcerespawn 1; mp_auto_join_team 1; humans_join_team any: bots fill both teams; without the fix a connecting player spawns into the world with no team (immediately via auto-join, or aftermp_forcerespawnseconds when left at the team menu); with the fix the player stays at the team select menu. Manually choosing T/CT/Spectator, team changes and bot vacating (bot_auto_vacate 1) behave as before.