diff --git a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs index e9ff215..a99c4ce 100644 --- a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs @@ -19,7 +19,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)"); public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)"; public override string ModuleAuthor => "daffyy & Dliix66"; - public override string ModuleVersion => "1.7.1a"; + public override string ModuleVersion => "1.7.2a"; public override void Load(bool hotReload) { @@ -56,6 +56,8 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig ReloadAdmins(null)); try diff --git a/CS2-SimpleAdmin/Commands/basebans.cs b/CS2-SimpleAdmin/Commands/basebans.cs index 21a3112..fcb432d 100644 --- a/CS2-SimpleAdmin/Commands/basebans.cs +++ b/CS2-SimpleAdmin/Commands/basebans.cs @@ -30,9 +30,12 @@ public partial class CS2_SimpleAdmin } var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + + var time = Helper.ParsePenaltyTime(command.GetArg(2)); playersToTarget.ForEach(player => @@ -134,8 +137,10 @@ public partial class CS2_SimpleAdmin var steamid = steamId.SteamId64.ToString(); var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); @@ -195,8 +200,10 @@ public partial class CS2_SimpleAdmin } var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); @@ -264,8 +271,10 @@ public partial class CS2_SimpleAdmin var pattern = command.GetArg(1); var reason = command.ArgCount >= 2 - ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; Task.Run(async () => await BanManager.UnbanPlayer(pattern, callerSteamId, reason)); @@ -297,8 +306,10 @@ public partial class CS2_SimpleAdmin var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; playersToTarget.ForEach(player => { diff --git a/CS2-SimpleAdmin/Commands/basecommands.cs b/CS2-SimpleAdmin/Commands/basecommands.cs index d85bb57..77d48e1 100644 --- a/CS2-SimpleAdmin/Commands/basecommands.cs +++ b/CS2-SimpleAdmin/Commands/basecommands.cs @@ -782,10 +782,12 @@ public partial class CS2_SimpleAdmin return; } - var reason = command.ArgCount >= 2 - ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + var reason = command.ArgCount >= 2 + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + playersToTarget.ForEach(player => { if (!player.IsValid) diff --git a/CS2-SimpleAdmin/Commands/basecomms.cs b/CS2-SimpleAdmin/Commands/basecomms.cs index 66ac4ee..7ac183e 100644 --- a/CS2-SimpleAdmin/Commands/basecomms.cs +++ b/CS2-SimpleAdmin/Commands/basecomms.cs @@ -28,9 +28,11 @@ public partial class CS2_SimpleAdmin } var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + var time = Helper.ParsePenaltyTime(command.GetArg(2)); playersToTarget.ForEach(player => @@ -124,8 +126,10 @@ public partial class CS2_SimpleAdmin var steamid = steamId.SteamId64.ToString(); var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); if (!CheckValidMute(caller, time)) return; @@ -175,9 +179,11 @@ public partial class CS2_SimpleAdmin var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var pattern = command.GetArg(1); var reason = command.ArgCount >= 2 - ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + if (pattern.Length <= 1) { command.ReplyToCommand($"Too short pattern to search."); @@ -252,9 +258,11 @@ public partial class CS2_SimpleAdmin } var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + var time = Helper.ParsePenaltyTime(command.GetArg(2)); playersToTarget.ForEach(player => @@ -351,8 +359,10 @@ public partial class CS2_SimpleAdmin var steamid = steamId.SteamId64.ToString(); var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); if (!CheckValidMute(caller, time)) return; @@ -402,9 +412,11 @@ public partial class CS2_SimpleAdmin var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var pattern = command.GetArg(1); var reason = command.ArgCount >= 2 - ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + if (pattern.Length <= 1) { command.ReplyToCommand("Too short pattern to search."); @@ -481,8 +493,10 @@ public partial class CS2_SimpleAdmin } var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; var time = Helper.ParsePenaltyTime(command.GetArg(2)); @@ -578,8 +592,10 @@ public partial class CS2_SimpleAdmin var steamid = steamId.SteamId64.ToString(); var reason = command.ArgCount >= 3 - ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); if (!CheckValidMute(caller, time)) return; @@ -629,9 +645,11 @@ public partial class CS2_SimpleAdmin var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var pattern = command.GetArg(1); var reason = command.ArgCount >= 2 - ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)).Trim() : _localizer?["sa_unknown"] ?? "Unknown"; + reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason; + if (pattern.Length <= 1) { command.ReplyToCommand("Too short pattern to search."); diff --git a/CS2-SimpleAdmin/Helper.cs b/CS2-SimpleAdmin/Helper.cs index 2c5030b..3057dc4 100644 --- a/CS2-SimpleAdmin/Helper.cs +++ b/CS2-SimpleAdmin/Helper.cs @@ -156,12 +156,16 @@ internal static class Helper if (!player.IsValid || player.IsHLTV) return; - player.Disconnect(reason); + Server.ExecuteCommand($"kickid {player.UserId}"); + + // player.Disconnect(reason); Broken after last update }); } else { - player.Disconnect(reason); + Server.ExecuteCommand($"kickid {player.UserId}"); + + player.Disconnect(reason); // Broken after last update } if (CS2_SimpleAdmin.UnlockedCommands && reason == NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED) @@ -196,13 +200,26 @@ internal static class Helper { if (!player.IsValid || player.IsHLTV) return; - - player.Disconnect(reason); + + // if (!string.IsNullOrEmpty(reason)) + // { + // var escapeChars = reason.IndexOfAny([';', '|']); + // + // if (escapeChars != -1) + // { + // reason = reason[..escapeChars]; + // } + // } + // + Server.ExecuteCommand($"kickid {player.UserId}"); + // player.Disconnect(reason); // Broken after last update }); } else { - player.Disconnect(reason); + Server.ExecuteCommand($"kickid {player.UserId}"); + + // player.Disconnect(reason); // Broken after last update } if (CS2_SimpleAdmin.UnlockedCommands && reason == NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED) @@ -223,12 +240,15 @@ internal static class Helper public static int ParsePenaltyTime(string time) { - if (string.IsNullOrWhiteSpace(time)) + if (string.IsNullOrWhiteSpace(time) || !time.Any(char.IsDigit)) { - CS2_SimpleAdmin._logger?.LogError("Time string cannot be null or empty."); + // CS2_SimpleAdmin._logger?.LogError("Time string cannot be null or empty."); return -1; } + if (time.Equals($"0")) + return 0; + var timeUnits = new Dictionary { { "m", 1 }, // Minute @@ -265,8 +285,8 @@ internal static class Helper throw new ArgumentException($"Invalid time unit '{unit}' in time string.", nameof(time)); } } - - return totalMinutes; + + return totalMinutes > 0 ? totalMinutes : -1; } public static void PrintToCenterAll(string message) diff --git a/CS2-SimpleAdmin/Managers/PermissionManager.cs b/CS2-SimpleAdmin/Managers/PermissionManager.cs index d641857..8019d99 100644 --- a/CS2-SimpleAdmin/Managers/PermissionManager.cs +++ b/CS2-SimpleAdmin/Managers/PermissionManager.cs @@ -315,53 +315,72 @@ public class PermissionManager(Database.Database? database) { List<(string identity, string name, List flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlags(); var validPlayers = allPlayers - .Where(player => SteamID.TryParse(player.identity, out _)) // Filter invalid SteamID + .Where(player => SteamID.TryParse(player.identity, out _)) .ToList(); - /* - foreach (var player in allPlayers) - { - var (steamId, name, flags, immunity, ends) = player; - - // Print or process each item - Console.WriteLine($"Player SteamID: {steamId}"); - Console.WriteLine($"Player Name: {name}"); - Console.WriteLine($"Flags: {string.Join(", ", flags)}"); - Console.WriteLine($"Immunity: {immunity}"); - Console.WriteLine($"Ends: {(ends.HasValue ? ends.Value.ToString("yyyy-MM-dd HH:mm:ss") : "Never")}"); - Console.WriteLine(); // New line for better readability - } - */ + // foreach (var player in allPlayers) + // { + // var (steamId, name, flags, immunity, ends) = player; + // + // Console.WriteLine($"Player SteamID: {steamId}"); + // Console.WriteLine($"Player Name: {name}"); + // Console.WriteLine($"Flags: {string.Join(", ", flags)}"); + // Console.WriteLine($"Immunity: {immunity}"); + // Console.WriteLine($"Ends: {(ends.HasValue ? ends.Value.ToString("yyyy-MM-dd HH:mm:ss") : "Never")}"); + // Console.WriteLine(); + // } - var jsonData = validPlayers - .Select(player => - { - SteamID.TryParse(player.identity, out var steamId); + var jsonData = validPlayers + .GroupBy(player => player.name) // Group by player name + .ToDictionary( + group => group.Key, // Use the player name as the key + group => + { + // Consolidate data for players with the same name + var consolidatedData = group.Aggregate( + new + { + identity = string.Empty, + immunity = 0, + flags = new List(), + groups = new List() + }, + (acc, player) => + { + // Merge identities and use the latest or first non-null identity + if (string.IsNullOrEmpty(acc.identity) && !string.IsNullOrEmpty(player.identity)) + { + acc = acc with { identity = player.identity }; + } - // Update cache if SteamID is valid and not already cached - if (steamId != null && !AdminCache.ContainsKey(steamId)) - { - AdminCache.TryAdd(steamId, player.ends); - } + // Combine immunities by taking the maximum value + acc = acc with { immunity = Math.Max(acc.immunity, player.immunity) }; - // Create an anonymous object with player data - return new - { - playerName = player.name, - playerData = new - { - player.identity, - player.immunity, - flags = player.flags.Where(flag => flag.StartsWith("@")).ToList(), - groups = player.flags.Where(flag => flag.StartsWith("#")).ToList() - } - }; - }) - .ToDictionary(item => item.playerName, item => (object)item.playerData); + // Combine flags and groups, ensuring no duplicates + acc = acc with + { + flags = acc.flags.Concat(player.flags.Where(flag => flag.StartsWith($"@"))).Distinct().ToList(), + groups = acc.groups.Concat(player.flags.Where(flag => flag.StartsWith($"#"))).Distinct().ToList() + }; + return acc; + }); + + foreach (var player in group) + { + SteamID.TryParse(player.identity, out var steamId); + if (steamId != null && !AdminCache.ContainsKey(steamId)) + { + AdminCache.TryAdd(steamId, player.ends); + } + } + + return (object)consolidatedData; + }); + var json = JsonConvert.SerializeObject(jsonData, Formatting.Indented); - var filePath = Path.Combine(CS2_SimpleAdmin.Instance.ModuleDirectory, "data", "admins.json"); + await File.WriteAllTextAsync(filePath, json); //await File.WriteAllTextAsync(CS2_SimpleAdmin.Instance.ModuleDirectory + "/data/admins.json", json); diff --git a/CS2-SimpleAdmin/Managers/ServerManager.cs b/CS2-SimpleAdmin/Managers/ServerManager.cs index 48fe1e7..52ec75e 100644 --- a/CS2-SimpleAdmin/Managers/ServerManager.cs +++ b/CS2-SimpleAdmin/Managers/ServerManager.cs @@ -9,6 +9,16 @@ public class ServerManager { private int _getIpTryCount; + public void CheckHibernationStatus() + { + ConVar? convar = ConVar.Find("sv_hibernate_when_empty"); + + if (convar == null || !convar.GetPrimitiveValue()) + return; + + CS2_SimpleAdmin._logger?.LogError("Detected setting \"sv_hibernate_when_empty true\", set false to make plugin work properly"); + } + public void LoadServerData() { CS2_SimpleAdmin.Instance.AddTimer(1.2f, () => diff --git a/CS2-SimpleAdmin/Managers/WarnManager.cs b/CS2-SimpleAdmin/Managers/WarnManager.cs index ad88cb9..60c7dde 100644 --- a/CS2-SimpleAdmin/Managers/WarnManager.cs +++ b/CS2-SimpleAdmin/Managers/WarnManager.cs @@ -174,14 +174,32 @@ internal class WarnManager(Database.Database? database) await using var connection = await database.GetConnectionAsync(); var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode - ? "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND player_steamid = @steamid AND id = (SELECT MAX(id) FROM sa_warns WHERE player_steamid = @steamid AND status = 'ACTIVE')" - : "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND player_steamid = @steamid AND id = (SELECT MAX(id) FROM sa_warns WHERE player_steamid = @steamid AND status = 'ACTIVE' AND server_id = @serverid)"; + ? """ + UPDATE sa_warns + JOIN ( + SELECT MAX(id) AS max_id + FROM sa_warns + WHERE player_steamid = @steamid AND status = 'ACTIVE' + ) AS subquery ON sa_warns.id = subquery.max_id + SET sa_warns.status = 'EXPIRED' + WHERE sa_warns.status = 'ACTIVE' AND sa_warns.player_steamid = @steamid; + """ + : """ + UPDATE sa_warns + JOIN ( + SELECT MAX(id) AS max_id + FROM sa_warns + WHERE player_steamid = @steamid AND status = 'ACTIVE' AND server_id = @serverid + ) AS subquery ON sa_warns.id = subquery.max_id + SET sa_warns.status = 'EXPIRED' + WHERE sa_warns.status = 'ACTIVE' AND sa_warns.player_steamid = @steamid AND sa_warns.server_id = @serverid; + """; await connection.ExecuteAsync(sql, new { steamid = playerPattern, serverid = CS2_SimpleAdmin.ServerId }); } catch (Exception ex) { - CS2_SimpleAdmin._logger?.LogCritical($"Unable to remove last warn + {ex}"); + CS2_SimpleAdmin._logger?.LogCritical("Unable to remove last warn {exception}", ex.Message); } } diff --git a/CS2-SimpleAdmin/VERSION b/CS2-SimpleAdmin/VERSION index 6d8ff6d..c22096b 100644 --- a/CS2-SimpleAdmin/VERSION +++ b/CS2-SimpleAdmin/VERSION @@ -1 +1 @@ -1.7.1a \ No newline at end of file +1.7.2a \ No newline at end of file