From a484771e94ce02ab232bbb7b570b37ba658703df Mon Sep 17 00:00:00 2001 From: Luke Policinski Date: Thu, 1 Oct 2026 17:17:13 -0400 Subject: [PATCH] bug: count connected players without a pawn on SwiftlyS2 --- .../src/PlayerManagementPlugin.cs | 18 +++++++++++++++++- .../test/PlayerRosterTests.cs | 10 ++++++++++ .../dotnet/FiveStack.Utilities/PlayerRoster.cs | 6 ++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/player-management-sw/src/PlayerManagementPlugin.cs b/apps/player-management-sw/src/PlayerManagementPlugin.cs index fe8c45ae..233419f5 100644 --- a/apps/player-management-sw/src/PlayerManagementPlugin.cs +++ b/apps/player-management-sw/src/PlayerManagementPlugin.cs @@ -13,6 +13,7 @@ using SwiftlyS2.Shared.Misc; using SwiftlyS2.Shared.Players; using SwiftlyS2.Shared.Plugins; +using SwiftlyS2.Shared.SchemaDefinitions; using SwiftlyS2.Shared.ProtobufDefinitions; using SwiftlyS2.Shared.Translation; @@ -555,9 +556,24 @@ private static List Observed(List humans) .ToList(); } + // Not IPlayer.IsValid: that also wants a pawn, and a player without one + // is still on the server, so the roster ended their session and a gag + // stopped applying until they had one again. private static bool IsHuman(IPlayer player) { - return player.IsValid && !player.IsFakeClient && SteamIdOf(player) != 0; + CCSPlayerController controller = player.Controller; + + if (!controller.IsValid) + { + return false; + } + + return PlayerRoster.IsConnectedHuman( + controller.IsHLTV, + controller.Connected == PlayerConnectedState.Connected, + player.IsFakeClient, + SteamIdOf(player) + ); } // Before Steam verifies a player only the id they claim is known. Enforcing diff --git a/apps/player-management-sw/test/PlayerRosterTests.cs b/apps/player-management-sw/test/PlayerRosterTests.cs index db60c72b..89f6e927 100644 --- a/apps/player-management-sw/test/PlayerRosterTests.cs +++ b/apps/player-management-sw/test/PlayerRosterTests.cs @@ -837,4 +837,14 @@ bool expected ) ); } + + [Fact] + public void CountsEveryConnectedHumanAndNothingElse() + { + Assert.True(PlayerRoster.IsConnectedHuman(false, true, false, 76561198000000001)); + Assert.False(PlayerRoster.IsConnectedHuman(false, false, false, 76561198000000001)); + Assert.False(PlayerRoster.IsConnectedHuman(true, true, false, 76561198000000001)); + Assert.False(PlayerRoster.IsConnectedHuman(false, true, true, 76561198000000001)); + Assert.False(PlayerRoster.IsConnectedHuman(false, true, false, 0)); + } } diff --git a/shared/dotnet/FiveStack.Utilities/PlayerRoster.cs b/shared/dotnet/FiveStack.Utilities/PlayerRoster.cs index f90887c2..841feed8 100644 --- a/shared/dotnet/FiveStack.Utilities/PlayerRoster.cs +++ b/shared/dotnet/FiveStack.Utilities/PlayerRoster.cs @@ -274,6 +274,12 @@ public static string Name(string? raw) return address.ToString(); } + // A connected controller is on the server whether or not it has a pawn. + public static bool IsConnectedHuman(bool isHltv, bool connected, bool isBot, ulong steamId) + { + return !isHltv && connected && !isBot && steamId != 0; + } + // Identified by slot, not Steam id: an unverified victim can claim the // attacker's id. public static bool CountsAsKill(