AdminStealth 0.3.14: a team pick closes the team screen for hidden admins

Telling only their client they joined spectators left the screen open, so the
admin had to unhide to get out. Move them to spectators and back to no team,
as css_hide does, with sv_disable_teamselect_menu on around it.
This commit is contained in:
Astra 2026-10-03 00:20:33 +01:00
parent 0446fe49e8
commit 7eba09905a
2 changed files with 36 additions and 12 deletions

View file

@ -23,7 +23,7 @@ namespace AdminStealth;
public class AdminStealth : BasePlugin
{
public override string ModuleName => "AdminStealth";
public override string ModuleVersion => "0.3.13";
public override string ModuleVersion => "0.3.14";
public override string ModuleAuthor => "astra";
public override string ModuleDescription => "Makes CS2-SimpleAdmin's css_hide look like leaving, and keeps it";
@ -80,6 +80,7 @@ public class AdminStealth : BasePlugin
_hideTyped.Clear();
_restoreScheduled.Clear();
_restoring.Clear();
_closingTeamScreen.Clear();
});
}
@ -136,20 +137,42 @@ public class AdminStealth : BasePlugin
player!.PrintToChat($" You're hidden, so you can't join a team. Type {ChatAlias()} to show yourself.");
// M opens the team screen on the client, where the server can't block it, and a player with
// no team (as hidden admins are) can't close it without picking. Answer the pick by telling
// only their client they joined spectators, with the team screen disabled around it, so
// nobody else ever sees them on a team.
CloseTeamScreen(player);
return HookResult.Stop;
}
// M opens the team screen on the client, where the server can't block it, and a player with no
// team (as hidden admins are) can't close it without picking. Telling only their client they
// joined spectators doesn't close it (tried live), so do what css_hide does: really move them
// to spectators and back to no team, with the team screen disabled around it. Their team
// events aren't broadcast while hidden (OnPlayerTeam), and our SimpleAdmin fork doesn't unhide
// for spectators.
private readonly HashSet<int> _closingTeamScreen = [];
private void CloseTeamScreen(CCSPlayerController player)
{
var slot = player.Slot;
if (!_closingTeamScreen.Add(slot))
return;
Server.ExecuteCommand("sv_disable_teamselect_menu 1");
AddTimer(0.3f, () =>
Server.NextFrame(() =>
{
var p = Utilities.GetPlayerFromSlot(slot);
if (p is { IsValid: true } && IsHidden(p))
SendTeamEvent(p, (int)CsTeam.Spectator, p.TeamNum);
if (p is { IsValid: true } && IsHidden(p) && p.TeamNum == (byte)CsTeam.None)
p.ChangeTeam(CsTeam.Spectator);
});
AddTimer(0.15f, () =>
{
var p = Utilities.GetPlayerFromSlot(slot);
if (p is { IsValid: true } && IsHidden(p) && p.TeamNum == (byte)CsTeam.Spectator)
p.ChangeTeam(CsTeam.None);
}, TimerFlags.STOP_ON_MAPCHANGE);
AddTimer(0.5f, () =>
{
_closingTeamScreen.Remove(slot);
Server.ExecuteCommand("sv_disable_teamselect_menu 0");
}, TimerFlags.STOP_ON_MAPCHANGE);
AddTimer(0.6f, () => Server.ExecuteCommand("sv_disable_teamselect_menu 0"), TimerFlags.STOP_ON_MAPCHANGE);
return HookResult.Stop;
}
private HookResult OnTeamMenu(CCSPlayerController? player, CommandInfo command)