mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-02-24 20:26:51 +00:00
Refactor player cache and ban checks, update version
Improves player cache handling and ban status checks for race condition safety. Removes unused GodPlayers logic and related event handler. Refactors event handlers for disconnect and team changes, and fixes warn reason field naming. Updates version to 1.7.8-beta-7.
This commit is contained in:
@@ -22,7 +22,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
||||||
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
||||||
public override string ModuleAuthor => "daffyy";
|
public override string ModuleAuthor => "daffyy";
|
||||||
public override string ModuleVersion => "1.7.8-beta-6";
|
public override string ModuleVersion => "1.7.8-beta-7";
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
{
|
{
|
||||||
@@ -46,7 +46,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
CachedPlayers.Clear();
|
CachedPlayers.Clear();
|
||||||
BotPlayers.Clear();
|
BotPlayers.Clear();
|
||||||
|
|
||||||
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && !p.IsHLTV).ToArray())
|
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsHLTV).ToArray())
|
||||||
{
|
{
|
||||||
if (!player.IsBot)
|
if (!player.IsBot)
|
||||||
PlayerManager.LoadPlayerData(player, true);
|
PlayerManager.LoadPlayerData(player, true);
|
||||||
@@ -260,6 +260,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
CacheManager = null;
|
CacheManager = null;
|
||||||
PlayersTimer?.Kill();
|
PlayersTimer?.Kill();
|
||||||
PlayersTimer = null;
|
PlayersTimer = null;
|
||||||
|
|
||||||
UnregisterEvents();
|
UnregisterEvents();
|
||||||
|
|
||||||
if (hotReload)
|
if (hotReload)
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
new ServerManager().LoadServerData();
|
new ServerManager().LoadServerData();
|
||||||
}
|
}
|
||||||
|
|
||||||
[GameEventHandler(HookMode.Pre)]
|
[GameEventHandler]
|
||||||
public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
|
public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
|
||||||
{
|
{
|
||||||
if (@event.Reason is 149 or 6)
|
if (@event.Reason is 149 or 6)
|
||||||
@@ -91,14 +91,15 @@ public partial class CS2_SimpleAdmin
|
|||||||
|
|
||||||
if (player == null || !player.IsValid || player.IsHLTV)
|
if (player == null || !player.IsValid || player.IsHLTV)
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
|
|
||||||
BotPlayers.Remove(player);
|
|
||||||
CachedPlayers.Remove(player);
|
|
||||||
|
|
||||||
|
CachedPlayers.Remove(player);
|
||||||
|
BotPlayers.Remove(player);
|
||||||
SilentPlayers.Remove(player.Slot);
|
SilentPlayers.Remove(player.Slot);
|
||||||
|
|
||||||
if (player.IsBot)
|
if (player.IsBot)
|
||||||
|
{
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.LogCritical("[OnClientDisconnect] After Check");
|
Logger.LogCritical("[OnClientDisconnect] After Check");
|
||||||
@@ -176,6 +177,9 @@ public partial class CS2_SimpleAdmin
|
|||||||
if (player == null || !player.IsValid || player.IsBot)
|
if (player == null || !player.IsValid || player.IsBot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!CachedPlayers.Contains(player))
|
||||||
|
CachedPlayers.Add(player);
|
||||||
|
|
||||||
PlayerManager.LoadPlayerData(player);
|
PlayerManager.LoadPlayerData(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,28 +462,11 @@ public partial class CS2_SimpleAdmin
|
|||||||
// OnGameServerSteamAPIActivated();
|
// OnGameServerSteamAPIActivated();
|
||||||
// });
|
// });
|
||||||
|
|
||||||
GodPlayers.Clear();
|
|
||||||
SilentPlayers.Clear();
|
SilentPlayers.Clear();
|
||||||
|
|
||||||
PlayerPenaltyManager.RemoveAllPenalties();
|
PlayerPenaltyManager.RemoveAllPenalties();
|
||||||
}
|
}
|
||||||
|
|
||||||
[GameEventHandler]
|
|
||||||
public HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info)
|
|
||||||
{
|
|
||||||
var player = @event.Userid;
|
|
||||||
|
|
||||||
if (player is null || @event.Attacker is null || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE || player.PlayerPawn.Value == null)
|
|
||||||
return HookResult.Continue;
|
|
||||||
|
|
||||||
if (!GodPlayers.Contains(player.Slot)) return HookResult.Continue;
|
|
||||||
|
|
||||||
player.PlayerPawn.Value.Health = player.PlayerPawn.Value.MaxHealth;
|
|
||||||
player.PlayerPawn.Value.ArmorValue = 100;
|
|
||||||
|
|
||||||
return HookResult.Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
[GameEventHandler]
|
[GameEventHandler]
|
||||||
public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
|
public HookResult OnPlayerDeath(EventPlayerDeath @event, GameEventInfo info)
|
||||||
{
|
{
|
||||||
@@ -512,17 +499,13 @@ public partial class CS2_SimpleAdmin
|
|||||||
public HookResult OnPlayerTeam(EventPlayerTeam @event, GameEventInfo info)
|
public HookResult OnPlayerTeam(EventPlayerTeam @event, GameEventInfo info)
|
||||||
{
|
{
|
||||||
var player = @event.Userid;
|
var player = @event.Userid;
|
||||||
if (player == null || !player.IsValid || player.IsBot)
|
if (player == null || !player.IsValid || player.IsBot || !SilentPlayers.Contains(player.Slot))
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
|
|
||||||
if (!SilentPlayers.Contains(player.Slot))
|
if (@event is not { Oldteam: <= 1, Team: >= 1 }) return HookResult.Continue;
|
||||||
return HookResult.Continue;
|
|
||||||
|
SilentPlayers.Remove(player.Slot);
|
||||||
if (@event is { Oldteam: <= 1, Team: >= 1 })
|
SimpleAdminApi?.OnAdminToggleSilentEvent(player.Slot, false);
|
||||||
{
|
|
||||||
SilentPlayers.Remove(player.Slot);
|
|
||||||
SimpleAdminApi?.OnAdminToggleSilentEvent(player.Slot, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HookResult.Continue;
|
return HookResult.Continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ internal static class Helper
|
|||||||
|
|
||||||
public static List<CCSPlayerController> GetValidPlayers()
|
public static List<CCSPlayerController> GetValidPlayers()
|
||||||
{
|
{
|
||||||
return CS2_SimpleAdmin.CachedPlayers.AsValueEnumerable().Where(p => p.Connected == PlayerConnectedState.PlayerConnected).ToList();
|
return CS2_SimpleAdmin.CachedPlayers.AsValueEnumerable().Where(p => p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<CCSPlayerController> GetValidPlayersWithBots()
|
public static List<CCSPlayerController> GetValidPlayersWithBots()
|
||||||
|
|||||||
@@ -323,13 +323,19 @@ internal class CacheManager: IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update cache with new/modified bans
|
// Update cache with new/modified bans
|
||||||
|
var needsRebuild = false;
|
||||||
foreach (var ban in updatedBans)
|
foreach (var ban in updatedBans)
|
||||||
{
|
{
|
||||||
|
if (_banCache.TryGetValue(ban.Id, out var oldBan) && oldBan.Status != ban.Status)
|
||||||
|
{
|
||||||
|
// Ban status changed (e.g., ACTIVE -> EXPIRED/UNBANNED), need to rebuild indexes
|
||||||
|
needsRebuild = true;
|
||||||
|
}
|
||||||
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild indexes if there were updates
|
// Rebuild indexes if there were updates or status changes
|
||||||
if (updatedBans.Any())
|
if (updatedBans.Any() || needsRebuild)
|
||||||
{
|
{
|
||||||
RebuildIndexes();
|
RebuildIndexes();
|
||||||
}
|
}
|
||||||
@@ -480,13 +486,17 @@ internal class CacheManager: IDisposable
|
|||||||
record = steamRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
record = steamRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
||||||
if (record != null)
|
if (record != null)
|
||||||
{
|
{
|
||||||
if ((string.IsNullOrEmpty(record.PlayerIp) && !string.IsNullOrEmpty(ipAddress)) ||
|
// Double-check the ban is still active in cache (handle race conditions)
|
||||||
(!record.PlayerSteamId.HasValue))
|
if (_banCache.TryGetValue(record.Id, out var cachedBan) && cachedBan.StatusEnum == BanStatus.ACTIVE)
|
||||||
{
|
{
|
||||||
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
if ((string.IsNullOrEmpty(record.PlayerIp) && !string.IsNullOrEmpty(ipAddress)) ||
|
||||||
}
|
(!record.PlayerSteamId.HasValue))
|
||||||
|
{
|
||||||
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,15 +507,20 @@ internal class CacheManager: IDisposable
|
|||||||
!IpHelper.TryConvertIpToUint(ipAddress, out var ipUInt) ||
|
!IpHelper.TryConvertIpToUint(ipAddress, out var ipUInt) ||
|
||||||
_cachedIgnoredIps.Contains(ipUInt) ||
|
_cachedIgnoredIps.Contains(ipUInt) ||
|
||||||
!_ipIndex.TryGetValue(ipUInt, out var ipRecords)) return false;
|
!_ipIndex.TryGetValue(ipUInt, out var ipRecords)) return false;
|
||||||
|
|
||||||
record = ipRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
record = ipRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
||||||
if (record == null) return false;
|
if (record == null) return false;
|
||||||
|
|
||||||
|
// Double-check the ban is still active in cache (handle race conditions)
|
||||||
|
if (!_banCache.TryGetValue(record.Id, out var cachedBanIp) || cachedBanIp.StatusEnum != BanStatus.ACTIVE)
|
||||||
|
return false;
|
||||||
|
|
||||||
if ((string.IsNullOrEmpty(record.PlayerIp) && !string.IsNullOrEmpty(ipAddress)) ||
|
if ((string.IsNullOrEmpty(record.PlayerIp) && !string.IsNullOrEmpty(ipAddress)) ||
|
||||||
(!record.PlayerSteamId.HasValue && steamId.HasValue))
|
(!record.PlayerSteamId.HasValue && steamId.HasValue))
|
||||||
{
|
{
|
||||||
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,10 +606,14 @@ internal class CacheManager: IDisposable
|
|||||||
var activeBan = steamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
|
var activeBan = steamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
|
||||||
if (activeBan != null)
|
if (activeBan != null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(activeBan.PlayerName) || string.IsNullOrEmpty(activeBan.PlayerIp) && !string.IsNullOrEmpty(ipAddress))
|
// Double-check the ban is still active in cache (handle race conditions)
|
||||||
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
if (_banCache.TryGetValue(activeBan.Id, out var cachedBan) && cachedBan.StatusEnum == BanStatus.ACTIVE)
|
||||||
|
{
|
||||||
return true;
|
if (string.IsNullOrEmpty(activeBan.PlayerName) || string.IsNullOrEmpty(activeBan.PlayerIp) && !string.IsNullOrEmpty(ipAddress))
|
||||||
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,16 +639,20 @@ internal class CacheManager: IDisposable
|
|||||||
if (ipRecord.UsedAt < cutoff || _cachedIgnoredIps.Contains(ipRecord.Ip))
|
if (ipRecord.UsedAt < cutoff || _cachedIgnoredIps.Contains(ipRecord.Ip))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_ipIndex.TryGetValue(ipRecord.Ip, out var banRecords))
|
if (!_ipIndex.TryGetValue(ipRecord.Ip, out var banRecords))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var activeBan = banRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
var activeBan = banRecords.FirstOrDefault(r => r.StatusEnum == BanStatus.ACTIVE);
|
||||||
if (activeBan == null)
|
if (activeBan == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Double-check the ban is still active in cache (handle race conditions)
|
||||||
|
if (!_banCache.TryGetValue(activeBan.Id, out var cachedBan) || cachedBan.StatusEnum != BanStatus.ACTIVE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(activeBan.PlayerName))
|
if (string.IsNullOrEmpty(activeBan.PlayerName))
|
||||||
activeBan.PlayerName = unknownName;
|
activeBan.PlayerName = unknownName;
|
||||||
|
|
||||||
activeBan.PlayerSteamId ??= steamId;
|
activeBan.PlayerSteamId ??= steamId;
|
||||||
|
|
||||||
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
|||||||
@@ -80,13 +80,7 @@ internal class PlayerManager
|
|||||||
{
|
{
|
||||||
var playerInfo = new PlayerInfo(userId, slot, new SteamID(steamId), playerName, ipAddress);
|
var playerInfo = new PlayerInfo(userId, slot, new SteamID(steamId), playerName, ipAddress);
|
||||||
CS2_SimpleAdmin.PlayersInfo[steamId] = playerInfo;
|
CS2_SimpleAdmin.PlayersInfo[steamId] = playerInfo;
|
||||||
|
|
||||||
await Server.NextWorldUpdateAsync(() =>
|
|
||||||
{
|
|
||||||
if (!CS2_SimpleAdmin.CachedPlayers.Contains(player))
|
|
||||||
CS2_SimpleAdmin.CachedPlayers.Add(player);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (_config.OtherSettings.CheckMultiAccountsByIp && ipAddress != null &&
|
if (_config.OtherSettings.CheckMultiAccountsByIp && ipAddress != null &&
|
||||||
CS2_SimpleAdmin.PlayersInfo[steamId] != null)
|
CS2_SimpleAdmin.PlayersInfo[steamId] != null)
|
||||||
{
|
{
|
||||||
@@ -253,6 +247,7 @@ internal class PlayerManager
|
|||||||
_loadPlayerSemaphore.Release();
|
_loadPlayerSemaphore.Release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (CS2_SimpleAdmin.RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
if (CS2_SimpleAdmin.RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
||||||
{
|
{
|
||||||
player.Rename(name);
|
player.Rename(name);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ internal class WarnManager(IDatabaseProvider? databaseProvider)
|
|||||||
playerName = player.Name,
|
playerName = player.Name,
|
||||||
adminSteamid = issuer?.SteamId.SteamId64 ?? 0,
|
adminSteamid = issuer?.SteamId.SteamId64 ?? 0,
|
||||||
adminName = issuer?.Name ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
|
adminName = issuer?.Name ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
|
||||||
muteReason = reason,
|
warnReason = reason,
|
||||||
duration = time,
|
duration = time,
|
||||||
ends = futureTime,
|
ends = futureTime,
|
||||||
created = now,
|
created = now,
|
||||||
@@ -42,7 +42,7 @@ internal class WarnManager(IDatabaseProvider? databaseProvider)
|
|||||||
|
|
||||||
return warnId;
|
return warnId;
|
||||||
}
|
}
|
||||||
catch
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ internal class WarnManager(IDatabaseProvider? databaseProvider)
|
|||||||
playerSteamid = playerSteamId,
|
playerSteamid = playerSteamId,
|
||||||
adminSteamid = issuer?.SteamId.SteamId64 ?? 0,
|
adminSteamid = issuer?.SteamId.SteamId64 ?? 0,
|
||||||
adminName = issuer?.Name ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
|
adminName = issuer?.Name ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
|
||||||
muteReason = reason,
|
warnReason = reason,
|
||||||
duration = time,
|
duration = time,
|
||||||
ends = futureTime,
|
ends = futureTime,
|
||||||
created = now,
|
created = now,
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.7.8-beta-6
|
1.7.8-beta-7
|
||||||
@@ -40,7 +40,6 @@ public partial class CS2_SimpleAdmin
|
|||||||
internal static readonly HashSet<ulong> AdminDisabledJoinComms = [];
|
internal static readonly HashSet<ulong> AdminDisabledJoinComms = [];
|
||||||
|
|
||||||
// Player Management
|
// Player Management
|
||||||
private static readonly HashSet<int> GodPlayers = [];
|
|
||||||
internal static readonly HashSet<int> SilentPlayers = [];
|
internal static readonly HashSet<int> SilentPlayers = [];
|
||||||
internal static readonly Dictionary<ulong, string> RenamedPlayers = [];
|
internal static readonly Dictionary<ulong, string> RenamedPlayers = [];
|
||||||
internal static readonly ConcurrentDictionary<ulong, PlayerInfo> PlayersInfo = [];
|
internal static readonly ConcurrentDictionary<ulong, PlayerInfo> PlayersInfo = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user