Skip to content

Prevent players from getting into the game without a team when both teams are full - #1168

Merged
s1lentq merged 2 commits into
rehlds:masterfrom
belomaxorka:fix/unassigned-forcerespawn
Jul 9, 2026
Merged

Prevent players from getting into the game without a team when both teams are full#1168
s1lentq merged 2 commits into
rehlds:masterfrom
belomaxorka:fix/unassigned-forcerespawn

Conversation

@belomaxorka

Copy link
Copy Markdown
Contributor

Fixes #929
Fixes #932

What

Players could get into the game with m_iTeam == UNASSIGNED when 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 with mp_auto_join_team 1 + mp_forcerespawn 1 on 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:

  1. HandleMenu_ChooseTeam() with MENU_SLOT_TEAM_RANDOM: when SelectDefaultTeam() returns UNASSIGNED (both teams full) and no bot can be vacated, the function falls through — TeamFull(UNASSIGNED) and TeamStacked(UNASSIGNED, ...) both return FALSE — so it assigns m_iTeam = UNASSIGNED and returns TRUE. 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()), where FPlayerCanRespawn() always passes with mp_forcerespawn > 0, resulting in an immediate Spawn() with no team.

  2. PlayerRespawnThink(): the guard GetObserverMode() != OBS_NONE && (m_iTeam == UNASSIGNED || m_iTeam == SPECTATOR) does not protect a player sitting at the team select menu (Menu_ChooseTeam / PICKINGTEAM, deadflag == DEAD_DEAD since ClientPutInServer(), observer mode OBS_NONE): the menu check on the next line only covers Menu_ChooseAppearance / SHOWTEAMSELECT, so mp_forcerespawn schedules and executes a respawn for a teamless player anyway.

How it works

  • HandleMenu_ChooseTeam(): deny auto-select (return FALSE) when the team is still UNASSIGNED after 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 the TeamFull() 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 by REGAMEDLL_FIXES since the fall-through exists in the vanilla code.
  • PlayerRespawnThink(): never force-respawn players without a team (UNASSIGNED/SPECTATOR) regardless of observer mode. Unlike PlayerDeathThink() (which is gated by m_iJoiningState != JOINED), this function is reached from PreThink() for players in any joining state, hence the stronger guard.

Edge cases

  • All human join paths (VGUI menu, jointeam console command, mp_auto_join_team) go through HandleMenu_ChooseTeam(), so the fix covers them all.
  • Round restart (RoundRespawn()) already skips teamless players, and the bot add path already denies UNASSIGNED — behavior is now consistent everywhere.
  • Vanilla builds are unaffected: PlayerRespawnThink() is REGAMEDLL_ADD-only and the HandleMenu_ChooseTeam() change is under REGAMEDLL_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 after mp_forcerespawn seconds 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.

belomaxorka and others added 2 commits July 6, 2026 02:57
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>
@s1lentq
s1lentq merged commit 8a23353 into rehlds:master Jul 9, 2026
4 checks passed
@belomaxorka
belomaxorka deleted the fix/unassigned-forcerespawn branch July 10, 2026 07:07
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.

mp_auto_join_team "1" fix pls Players can be spawned while on the UNASSIGNED team

2 participants