diff --git a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs index d974dbc..2a9a98e 100644 --- a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs @@ -31,6 +31,8 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig diff --git a/CS2-SimpleAdmin/Helper.cs b/CS2-SimpleAdmin/Helper.cs index 479fcf9..a17ec62 100644 --- a/CS2-SimpleAdmin/Helper.cs +++ b/CS2-SimpleAdmin/Helper.cs @@ -62,14 +62,14 @@ internal static class Helper return GetValidPlayers().FirstOrDefault(x => x.IpAddress != null && x.IpAddress.Split(":")[0].Equals(ipAddress)); } - public static IReadOnlyList GetValidPlayers() + public static List GetValidPlayers() { return Utilities.GetPlayers().AsValueEnumerable() .Where(p => p is { IsValid: true, IsBot: false, Connected: PlayerConnectedState.PlayerConnected }) .ToList(); } - public static IReadOnlyList GetValidPlayersWithBots() + public static List GetValidPlayersWithBots() { return Utilities.GetPlayers().AsValueEnumerable() .Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected }).ToList(); @@ -970,3 +970,35 @@ public static class WeaponHelper return filteredWeapons; // Return all relevant matches for the partial input } } + +public static class IpHelper +{ + public static uint IpToUint(string ipAddress) + { + return (uint)BitConverter.ToInt32(System.Net.IPAddress.Parse(ipAddress).GetAddressBytes().Reverse().ToArray(), + 0); + } + + public static bool TryConvertIpToUint(string ipString, out uint ipUint) + { + ipUint = 0; + if (string.IsNullOrWhiteSpace(ipString)) + return false; + + if (!System.Net.IPAddress.TryParse(ipString, out var ipAddress)) + return false; + + var bytes = ipAddress.GetAddressBytes(); + if (bytes.Length != 4) + return false; + + ipUint = IpToUint(ipString); + return true; + } + + public static string UintToIp(uint ipAddress) + { + var bytes = BitConverter.GetBytes(ipAddress).Reverse().ToArray(); + return new System.Net.IPAddress(bytes).ToString(); + } +} diff --git a/CS2-SimpleAdmin/Managers/CacheManager.cs b/CS2-SimpleAdmin/Managers/CacheManager.cs index 194d02e..11fb12e 100644 --- a/CS2-SimpleAdmin/Managers/CacheManager.cs +++ b/CS2-SimpleAdmin/Managers/CacheManager.cs @@ -5,25 +5,29 @@ using ZLinq; namespace CS2_SimpleAdmin.Managers; -internal class CacheManager +internal class CacheManager: IDisposable { - private readonly ConcurrentDictionary _banCache = new(); - private readonly ConcurrentDictionary ips, DateTime usedAt, string playerName)> _playerIpsCache = new(); - private HashSet _cachedIgnoredIps; + private readonly ConcurrentDictionary _banCache = []; + private readonly ConcurrentDictionary> _playerIpsCache = []; + private HashSet _cachedIgnoredIps = []; private DateTime _lastUpdateTime = DateTime.MinValue; private bool _isInitialized; + private bool _disposed; public async Task InitializeCacheAsync() { if (CS2_SimpleAdmin.Database == null) return; if (!CS2_SimpleAdmin.ServerLoaded) return; if (_isInitialized) return; - - _cachedIgnoredIps = [..CS2_SimpleAdmin.Instance.Config.OtherSettings.IgnoredIps]; - + try { + Clear(); + _cachedIgnoredIps = new HashSet( + CS2_SimpleAdmin.Instance.Config.OtherSettings.IgnoredIps + .Select(IpHelper.IpToUint)); + await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); var bans = await connection.QueryAsync( """ @@ -44,26 +48,49 @@ internal class CacheManager FROM sa_bans """); var ipHistory = - await connection.QueryAsync<(ulong steamid, string? name, string address, DateTime used_at)>( + await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>( "SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC"); - foreach (var ban in bans) { _banCache.TryAdd(ban.Id, ban); } - foreach (var group in ipHistory.GroupBy(x => x.steamid)) + foreach (var group in ipHistory.AsValueEnumerable().GroupBy(x => x.steamid)) { - var ips = new HashSet(group.Select(x => x.address)); - var lastUsed = group.Max(x => x.used_at); - var playerName = group.FirstOrDefault(x => !string.IsNullOrEmpty(x.name)).name - ?? CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown"; + var ipSet = new HashSet( + group + .GroupBy(x => x.address) + .Select(g => + { + var latest = g.MaxBy(x => x.used_at); + return new IpRecord( + g.Key, + latest.used_at, + !string.IsNullOrEmpty(latest.name) + ? latest.name + : CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown" + ); + }), + new IpRecordComparer() + ); - _playerIpsCache[group.Key] = (ips, lastUsed, playerName); + _playerIpsCache.AddOrUpdate( + group.Key, + _ => ipSet, + (_, existingSet) => + { + foreach (var ip in ipSet) + { + existingSet.Remove(ip); + existingSet.Add(ip); + } + + return existingSet; + }); } - _lastUpdateTime = DateTime.Now; + _lastUpdateTime = DateTime.Now.AddSeconds(-1); _isInitialized = true; } catch (Exception e) @@ -95,53 +122,44 @@ internal class CacheManager var updatedBans = (await connection.QueryAsync( "SELECT * FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC", new { lastUpdate = _lastUpdateTime } - )).ToList().AsValueEnumerable(); - var ipHistory = (await connection.QueryAsync<(ulong steamid, string? name, string address, DateTime used_at)>( - "SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC LIMIT 500")).ToList(); + )).ToList(); + var ipHistory = (await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>( + "SELECT steamid, name, address, used_at FROM sa_players_ips WHERE used_at >= @lastUpdate ORDER BY used_at DESC LIMIT 300", new {lastUpdate = _lastUpdateTime})).ToList(); - // foreach (var group in ipHistory.GroupBy(x => x.steamid)) - // { - // var ips = new HashSet(group.Select(x => x.address)); - // var lastUsed = group.Max(x => x.used_at); - // _playerIpsCache[group.Key] = (ips, lastUsed); - // } - - var groupedData = ipHistory.AsValueEnumerable() - .GroupBy(x => x.steamid) - .ToList(); - - groupedData.ForEach(group => + foreach (var group in ipHistory.AsValueEnumerable().GroupBy(x => x.steamid)) { - var ips = new HashSet( - group.Select(x => x.address), - StringComparer.OrdinalIgnoreCase + var ipSet = new HashSet( + group + .GroupBy(x => x.address) + .Select(g => + { + var latest = g.MaxBy(x => x.used_at); + return new IpRecord( + g.Key, + latest.used_at, + !string.IsNullOrEmpty(latest.name) + ? latest.name + : CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown" + ); + }), + new IpRecordComparer() ); - - var lastUsed = group.Max(x => x.used_at); - var playerName = group - .OrderByDescending(x => x.used_at) // Prefer newer records - .Select(x => x.name) - .FirstOrDefault(name => !string.IsNullOrEmpty(name)) - ?? CS2_SimpleAdmin._localizer?["sa_unknown"] - ?? "Unknown"; _playerIpsCache.AddOrUpdate( group.Key, - // Add new entry - _ => (ips, lastUsed, playerName), - // Update existing - (_, existing) => + _ => ipSet, + (_, existingSet) => { - existing.ips.UnionWith(ips); - return ( - existing.ips, - lastUsed > existing.usedAt ? lastUsed : existing.usedAt, - string.IsNullOrEmpty(existing.playerName) ? playerName : existing.playerName - ); + foreach (var newEntry in ipSet) + { + existingSet.Remove(newEntry); + existingSet.Add(newEntry); + } + return existingSet; }); - }); - - if (updatedBans.Count() == 0) + } + + if (updatedBans.Count == 0) return; foreach (var ban in updatedBans) @@ -149,7 +167,7 @@ internal class CacheManager _banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban); } - _lastUpdateTime = DateTime.Now; + _lastUpdateTime = DateTime.Now.AddSeconds(-1); } catch (Exception e) { @@ -160,52 +178,119 @@ internal class CacheManager public List GetAllBans() => _banCache.Values.ToList(); public List GetActiveBans() => _banCache.Values.Where(b => b.Status == "ACTIVE").ToList(); public List GetPlayerBansBySteamId(string steamId) => _banCache.Values.Where(b => b.PlayerSteamId == steamId).ToList(); - public List<(ulong SteamId, string PlayerName)> GetAccountsByIp(string ipAddress) + public List<(ulong SteamId, DateTime UsedAt, string PlayerName)> GetAccountsByIp(string ipAddress) { + var ipAsUint = IpHelper.IpToUint(ipAddress); + return _playerIpsCache.AsValueEnumerable() - .Where(kvp => kvp.Value.ips.Contains(ipAddress)) - .Select(kvp => (kvp.Key, kvp.Value.playerName)) + .SelectMany(kvp => kvp.Value + .Where(entry => entry.Ip == ipAsUint) + .Select(entry => (kvp.Key, entry.UsedAt, entry.PlayerName))) .ToList(); } private bool IsIpBanned(string ipAddress) { - return _banCache.Values.Any(b => - b.Status == "ACTIVE" && - !string.IsNullOrEmpty(b.PlayerIp) && - b.PlayerIp.Equals(ipAddress, StringComparison.OrdinalIgnoreCase) && - !_cachedIgnoredIps.Contains(ipAddress)); + var ipUInt = IpHelper.IpToUint(ipAddress); + + return _banCache.Values.Any(b => + b is { Status: "ACTIVE", PlayerIp: not null } && + IpHelper.IpToUint(b.PlayerIp) == ipUInt && + !_cachedIgnoredIps.Contains(ipUInt)); } - public bool IsPlayerBanned(string? steamId, string? ipAddress) => - _banCache.Values.Any(b => - b.Status == "ACTIVE" && ( - (steamId != null && - b.PlayerSteamId != null && - b.PlayerSteamId.Equals(steamId, StringComparison.OrdinalIgnoreCase)) || - (ipAddress != null && - b.PlayerIp != null && - b.PlayerIp.Equals(ipAddress, StringComparison.OrdinalIgnoreCase) && - !_cachedIgnoredIps.Contains(ipAddress)) - )); + public bool IsPlayerBanned(string? steamId, string? ipAddress) + { + if (ipAddress == null) + return _banCache.Values.Any(b => + b.Status == "ACTIVE" && + steamId != null && + b.PlayerSteamId != null && + b.PlayerSteamId.Equals(steamId, StringComparison.OrdinalIgnoreCase)); + + if (!IpHelper.TryConvertIpToUint(ipAddress, out var ipUInt)) + return false; + + return _banCache.Values.Any(b => + b is { Status: "ACTIVE", PlayerIp: not null } && + ( + (steamId != null && + b.PlayerSteamId != null && + b.PlayerSteamId.Equals(steamId, StringComparison.OrdinalIgnoreCase)) + || + (IpHelper.TryConvertIpToUint(b.PlayerIp, out var bIpUint) && + bIpUint == ipUInt && + !_cachedIgnoredIps.Contains(ipUInt)) + ) + ); + } - public bool IsPlayerOrAnyIpBanned(ulong steamId) + public bool IsPlayerOrAnyIpBanned(ulong steamId, string? ipAddress) { var steamIdStr = steamId.ToString(); - if (_banCache.Values.Any(b => + if (_banCache.Values.Any(b => b.Status == "ACTIVE" && b.PlayerSteamId?.Equals(steamIdStr, StringComparison.OrdinalIgnoreCase) == true)) { return true; } - - return _playerIpsCache.TryGetValue(steamId, out var ipList) && ipList.ips.Any(ip => - !_cachedIgnoredIps.Contains(ip) && IsIpBanned(ip)); + + if (!_playerIpsCache.TryGetValue(steamId, out var ipData)) + return false; + + var now = DateTime.Now; + var cutoff = now.AddDays(-7); + + if (ipAddress != null) + { + var ipAsUint = IpHelper.IpToUint(ipAddress); + + ipData.Add(new IpRecord( + ipAsUint, + now.AddSeconds(-2), + CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown" + )); + } + + return ipData.Any(x => + x.UsedAt >= cutoff && + !_cachedIgnoredIps.Contains(x.Ip) && + _banCache.Values.Any(b => + b is { Status: "ACTIVE", PlayerIp: not null } && + IpHelper.TryConvertIpToUint(b.PlayerIp, out var banIpUint) && + banIpUint == x.Ip + )); } public bool HasIpForPlayer(ulong steamId, string ipAddress) { - return _playerIpsCache.TryGetValue(steamId, out var ipList) - && ipList.ips.Contains(ipAddress); + if (string.IsNullOrWhiteSpace(ipAddress)) + return false; + + return _playerIpsCache.TryGetValue(steamId, out var ipData) + && ipData.Any(x => x.Ip == IpHelper.IpToUint(ipAddress)); } + + private void Clear() + { + _banCache.Clear(); + _playerIpsCache.Clear(); + _cachedIgnoredIps.Clear(); + } + + public void Dispose() + { + if (_disposed) return; + Clear(); + _disposed = true; + } +} + +public class IpRecordComparer : IEqualityComparer +{ + public bool Equals(IpRecord x, IpRecord y) + => x.Ip == y.Ip; + + public int GetHashCode(IpRecord obj) + => obj.Ip.GetHashCode(); } \ No newline at end of file diff --git a/CS2-SimpleAdmin/Managers/PlayerManager.cs b/CS2-SimpleAdmin/Managers/PlayerManager.cs index d3d0c16..95f85fe 100644 --- a/CS2-SimpleAdmin/Managers/PlayerManager.cs +++ b/CS2-SimpleAdmin/Managers/PlayerManager.cs @@ -27,7 +27,6 @@ public class PlayerManager } var ipAddress = player.IpAddress?.Split(":")[0]; - CS2_SimpleAdmin.PlayersInfo[player.UserId.Value] = new PlayerInfo(player.UserId.Value, player.Slot, new SteamID(player.SteamID), player.PlayerName, ipAddress); @@ -52,11 +51,11 @@ public class PlayerManager // Perform asynchronous database operations within a single method Task.Run(async () => { - var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch + var isBanned = CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch { 0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(steamId, null), _ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp - ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(steamId64) + ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(steamId64, ipAddress) : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(steamId, ipAddress) }; @@ -76,7 +75,7 @@ public class PlayerManager { try { - if (CS2_SimpleAdmin.Instance.CacheManager.HasIpForPlayer( + if (CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.CacheManager.HasIpForPlayer( CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, ipAddress)) { await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); @@ -89,7 +88,7 @@ public class PlayerManager await connection.ExecuteAsync(updateQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, - IPAddress = ipAddress + IPAddress = IpHelper.IpToUint(ipAddress) }); } else @@ -101,7 +100,7 @@ public class PlayerManager var recordExists = await connection.ExecuteScalarAsync(selectQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, - IPAddress = ipAddress + IPAddress = IpHelper.IpToUint(ipAddress) }); if (recordExists > 0) @@ -114,7 +113,7 @@ public class PlayerManager await connection.ExecuteAsync(updateQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, - IPAddress = ipAddress + IPAddress = IpHelper.IpToUint(ipAddress) }); } else @@ -126,7 +125,7 @@ public class PlayerManager await connection.ExecuteAsync(insertQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, - IPAddress = ipAddress + IPAddress = IpHelper.IpToUint(ipAddress) }); } } @@ -139,10 +138,10 @@ public class PlayerManager // Get all accounts associated to the player (ip address) CS2_SimpleAdmin.PlayersInfo[userId].AccountsAssociated = - CS2_SimpleAdmin.Instance.CacheManager.GetAccountsByIp(ipAddress); + CS2_SimpleAdmin.Instance.CacheManager?.GetAccountsByIp(ipAddress).AsValueEnumerable().Select(x => (x.SteamId, x.PlayerName)).ToList() ?? []; } - try + try { // var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0 // ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned( @@ -158,7 +157,7 @@ public class PlayerManager var (totalMutes, totalGags, totalSilences) = await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]); - CS2_SimpleAdmin.PlayersInfo[userId].TotalBans = CS2_SimpleAdmin.Instance.CacheManager.GetPlayerBansBySteamId(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()).Count; + CS2_SimpleAdmin.PlayersInfo[userId].TotalBans = CS2_SimpleAdmin.Instance.CacheManager?.GetPlayerBansBySteamId(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()).Count ?? 0; CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = totalMutes; CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = totalGags; CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences = totalSilences; @@ -273,85 +272,71 @@ public class PlayerManager if (CS2_SimpleAdmin.Database == null) return; - var players = Helper.GetValidPlayers().ToList(); - - var bannedPlayers = players.AsValueEnumerable() - .Where(player => + var tempPlayers = Helper.GetValidPlayers() + .Select(p => new { - return CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch - { - 0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), null), - _ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp - ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(player.SteamID) - : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), player.IpAddress) - }; + p.SteamID, p.IpAddress, p.UserId, p.Slot, }) .ToList(); - - foreach (var player in bannedPlayers) - { - Helper.KickPlayer(player, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED); - players.Remove(player); - } - var onlinePlayers = players.AsValueEnumerable().Select(player => (player.SteamID, player.UserId, player.Slot)).ToList(); - - try + _ = Task.Run(async () => { - var expireTasks = new[] + try { - CS2_SimpleAdmin.Instance.BanManager.ExpireOldBans(), - CS2_SimpleAdmin.Instance.MuteManager.ExpireOldMutes(), - CS2_SimpleAdmin.Instance.WarnManager.ExpireOldWarns(), - CS2_SimpleAdmin.Instance.CacheManager.RefreshCacheAsync(), - CS2_SimpleAdmin.Instance.PermissionManager.DeleteOldAdmins() - }; - - Task.WhenAll(expireTasks).ContinueWith(t => - { - if (t is not { IsFaulted: true, Exception: not null }) return; - - foreach (var ex in t.Exception.InnerExceptions) + var expireTasks = new Task[] { - CS2_SimpleAdmin._logger?.LogError($"Error processing players timer tasks: {ex.Message}"); - } - }); + CS2_SimpleAdmin.Instance.BanManager.ExpireOldBans(), + CS2_SimpleAdmin.Instance.MuteManager.ExpireOldMutes(), + CS2_SimpleAdmin.Instance.WarnManager.ExpireOldWarns(), + CS2_SimpleAdmin.Instance.CacheManager?.RefreshCacheAsync() ?? Task.CompletedTask, + CS2_SimpleAdmin.Instance.PermissionManager.DeleteOldAdmins() + }; - } - catch (Exception ex) - { - CS2_SimpleAdmin._logger?.LogError("Unexpected error: {exception}", ex.Message); - } + await Task.WhenAll(expireTasks); + } + catch (Exception ex) + { + CS2_SimpleAdmin._logger?.LogError($"Error processing players timer tasks: {ex.Message}"); + + if (ex is AggregateException aggregate) + { + foreach (var inner in aggregate.InnerExceptions) + { + CS2_SimpleAdmin._logger?.LogError($"Inner exception: {inner.Message}"); + } + } + } + + var bannedPlayers = tempPlayers.AsValueEnumerable() + .Where(player => + { + return CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch + { + 0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), null), + _ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp + ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(player.SteamID, player.IpAddress?.Split(":")[0]) + : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), player.IpAddress?.Split(":")[0]) + }; + }) + .ToList(); + + foreach (var player in bannedPlayers) + { + if (player.UserId.HasValue) + await Server.NextFrameAsync(() => Helper.KickPlayer((int)player.UserId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED)); + } + + var onlinePlayers = tempPlayers.AsValueEnumerable().Select(player => (player.SteamID, player.UserId, player.Slot)).ToList(); + if (tempPlayers.Count == 0 || onlinePlayers.Count == 0) return; + if (_config.OtherSettings.TimeMode == 0) + { + await CS2_SimpleAdmin.Instance.MuteManager.CheckOnlineModeMutes(onlinePlayers); + } + }); - if (players.Count == 0 || onlinePlayers.Count == 0) return; - - try - { - Task.Run(async () => - { - // await CS2_SimpleAdmin.Instance.BanManager.CheckOnlinePlayers(onlinePlayers); - - if (_config.OtherSettings.TimeMode == 0) - { - await CS2_SimpleAdmin.Instance.MuteManager.CheckOnlineModeMutes(onlinePlayers); - } - }).ContinueWith(t => - { - if (t is not { IsFaulted: true, Exception: not null }) return; - - foreach (var ex in t.Exception.InnerExceptions) - { - CS2_SimpleAdmin._logger?.LogError($"Error checking online players: {ex.Message}"); - } - }); - } - catch (Exception ex) - { - CS2_SimpleAdmin._logger?.LogError($"Unexpected error: {ex.Message}"); - } - try { + var players = Helper.GetValidPlayers(); var penalizedSlots = players .Where(player => PlayerPenaltyManager.IsSlotInPenalties(player.Slot)) .Select(player => new diff --git a/CS2-SimpleAdmin/Managers/ServerManager.cs b/CS2-SimpleAdmin/Managers/ServerManager.cs index c1988ce..66131a0 100644 --- a/CS2-SimpleAdmin/Managers/ServerManager.cs +++ b/CS2-SimpleAdmin/Managers/ServerManager.cs @@ -88,8 +88,8 @@ public class ServerManager } CS2_SimpleAdmin.ServerLoaded = true; - - await CS2_SimpleAdmin.Instance.CacheManager.InitializeCacheAsync(); + if (CS2_SimpleAdmin.Instance.CacheManager != null) + await CS2_SimpleAdmin.Instance.CacheManager.InitializeCacheAsync(); } catch (Exception ex) { diff --git a/CS2-SimpleAdmin/Models/BanRecord.cs b/CS2-SimpleAdmin/Models/BanRecord.cs index 818745b..dd7712a 100644 --- a/CS2-SimpleAdmin/Models/BanRecord.cs +++ b/CS2-SimpleAdmin/Models/BanRecord.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace CS2_SimpleAdmin.Models; -public record BanRecord +public record struct BanRecord { [Column("id")] public int Id { get; set; } diff --git a/CS2-SimpleAdmin/Models/IpRecord.cs b/CS2-SimpleAdmin/Models/IpRecord.cs new file mode 100644 index 0000000..af9ef95 --- /dev/null +++ b/CS2-SimpleAdmin/Models/IpRecord.cs @@ -0,0 +1,3 @@ +namespace CS2_SimpleAdmin.Models; + +public readonly record struct IpRecord(uint Ip, DateTime UsedAt, string PlayerName); diff --git a/CS2-SimpleAdmin/Variables.cs b/CS2-SimpleAdmin/Variables.cs index c12cbc0..39c53a3 100644 --- a/CS2-SimpleAdmin/Variables.cs +++ b/CS2-SimpleAdmin/Variables.cs @@ -68,5 +68,5 @@ public partial class CS2_SimpleAdmin internal BanManager BanManager = new(Database); internal MuteManager MuteManager = new(Database); internal WarnManager WarnManager = new(Database); - internal readonly CacheManager CacheManager = new(); + internal CacheManager? CacheManager = new(); } \ No newline at end of file