diff --git a/AdminSQLManager.cs b/AdminSQLManager.cs index 17f2906..608f9e5 100644 --- a/AdminSQLManager.cs +++ b/AdminSQLManager.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API.Modules.Entities; using Dapper; +using Microsoft.Extensions.Logging; using System.Collections.Concurrent; namespace CS2_SimpleAdmin @@ -50,7 +51,7 @@ namespace CS2_SimpleAdmin { DateTime now = DateTime.Now; - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); string sql = "SELECT flags, immunity, ends FROM sa_admins WHERE player_steamid = @PlayerSteamID AND (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR server_id = @serverid)"; List? activeFlags = (await connection.QueryAsync(sql, new { PlayerSteamID = steamId, CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId }))?.ToList(); @@ -148,59 +149,66 @@ namespace CS2_SimpleAdmin { DateTime now = DateTime.Now; - await using var connection = _database.GetConnection(); - - string sql = "SELECT player_steamid, flags, immunity, ends FROM sa_admins WHERE (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR server_id = @serverid)"; - List? activeFlags = (await connection.QueryAsync(sql, new { CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId }))?.ToList(); - - if (activeFlags == null) + try { - return new List<(string, List, int, DateTime?)>(); - } + await using var connection = await _database.GetConnectionAsync(); - List<(string, List, int, DateTime?)> filteredFlagsWithImmunity = new List<(string, List, int, DateTime?)>(); + string sql = "SELECT player_steamid, flags, immunity, ends FROM sa_admins WHERE (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR server_id = @serverid)"; + List? activeFlags = (await connection.QueryAsync(sql, new { CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId }))?.ToList(); - foreach (dynamic flags in activeFlags) - { - if (flags is not IDictionary flagsDict) + if (activeFlags == null) { - continue; + return new List<(string, List, int, DateTime?)>(); } - if (!flagsDict.TryGetValue("player_steamid", out var steamIdObj) || - !flagsDict.TryGetValue("flags", out var flagsValueObj) || - !flagsDict.TryGetValue("immunity", out var immunityValueObj) || - !flagsDict.TryGetValue("ends", out var endsObj)) - { - //Console.WriteLine("One or more required keys are missing."); - continue; - } + List<(string, List, int, DateTime?)> filteredFlagsWithImmunity = new List<(string, List, int, DateTime?)>(); - DateTime? ends = null; - - if (endsObj != null) // Check if "ends" is not null + foreach (dynamic flags in activeFlags) { - if (!DateTime.TryParse(endsObj.ToString(), out var parsedEnds)) + if (flags is not IDictionary flagsDict) { - //Console.WriteLine("Failed to parse 'ends' value."); continue; } - ends = parsedEnds; + if (!flagsDict.TryGetValue("player_steamid", out var steamIdObj) || + !flagsDict.TryGetValue("flags", out var flagsValueObj) || + !flagsDict.TryGetValue("immunity", out var immunityValueObj) || + !flagsDict.TryGetValue("ends", out var endsObj)) + { + //Console.WriteLine("One or more required keys are missing."); + continue; + } + + DateTime? ends = null; + + if (endsObj != null) // Check if "ends" is not null + { + if (!DateTime.TryParse(endsObj.ToString(), out var parsedEnds)) + { + //Console.WriteLine("Failed to parse 'ends' value."); + continue; + } + + ends = parsedEnds; + } + + if (!(steamIdObj is string steamId) || + !(flagsValueObj is string flagsValue) || + !int.TryParse(immunityValueObj.ToString(), out var immunityValue)) + { + //Console.WriteLine("Failed to parse one or more values."); + continue; + } + + filteredFlagsWithImmunity.Add((steamId, flagsValue.Split(',').ToList(), immunityValue, ends)); } - if (!(steamIdObj is string steamId) || - !(flagsValueObj is string flagsValue) || - !int.TryParse(immunityValueObj.ToString(), out var immunityValue)) - { - //Console.WriteLine("Failed to parse one or more values."); - continue; - } - - filteredFlagsWithImmunity.Add((steamId, flagsValue.Split(',').ToList(), immunityValue, ends)); + return filteredFlagsWithImmunity; + } + catch (Exception) + { + return new List<(string, List, int, DateTime?)>(); } - - return filteredFlagsWithImmunity; } public async Task GiveAllFlags() @@ -236,7 +244,7 @@ namespace CS2_SimpleAdmin //_adminCache.TryRemove(playerSteamId, out _); - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); string sql = ""; @@ -265,7 +273,7 @@ namespace CS2_SimpleAdmin else futureTime = null; - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); var sql = "INSERT INTO `sa_admins` (`player_steamid`, `player_name`, `flags`, `immunity`, `ends`, `created`, `server_id`) " + "VALUES (@playerSteamid, @playerName, @flags, @immunity, @ends, @created, @serverid)"; @@ -286,10 +294,19 @@ namespace CS2_SimpleAdmin public async Task DeleteOldAdmins() { - await using var connection = _database.GetConnection(); + try + { + await using var connection = await _database.GetConnectionAsync(); + + string sql = "DELETE FROM sa_admins WHERE ends IS NOT NULL AND ends <= @CurrentTime"; + await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.Now }); + } + catch (Exception) + { + if (CS2_SimpleAdmin._logger != null) + CS2_SimpleAdmin._logger.LogCritical("Unable to remove expired admins"); + } - string sql = "DELETE FROM sa_admins WHERE ends IS NOT NULL AND ends <= @CurrentTime"; - await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.Now }); } } } \ No newline at end of file diff --git a/BanManager.cs b/BanManager.cs index 3a62b43..0a317ad 100644 --- a/BanManager.cs +++ b/BanManager.cs @@ -1,4 +1,5 @@ using Dapper; +using Microsoft.Extensions.Logging; namespace CS2_SimpleAdmin { @@ -18,7 +19,7 @@ namespace CS2_SimpleAdmin DateTime now = DateTime.Now; DateTime futureTime = now.AddMinutes(time); - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); var sql = "INSERT INTO `sa_bans` (`player_steamid`, `player_name`, `player_ip`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " + "VALUES (@playerSteamid, @playerName, @playerIp, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)"; @@ -45,7 +46,7 @@ namespace CS2_SimpleAdmin DateTime now = DateTime.Now; DateTime futureTime = now.AddMinutes(time); - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); var sql = "INSERT INTO `sa_bans` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " + "VALUES (@playerSteamid, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)"; @@ -70,7 +71,7 @@ namespace CS2_SimpleAdmin DateTime now = DateTime.Now; DateTime futureTime = now.AddMinutes(time); - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); var sql = "INSERT INTO `sa_bans` (`player_ip`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " + "VALUES (@playerIp, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)"; @@ -90,18 +91,23 @@ namespace CS2_SimpleAdmin public async Task IsPlayerBanned(PlayerInfo player) { - if (player == null) + if (player.SteamId == null && player.IpAddress == null) { return false; } +#if DEBUG + if (CS2_SimpleAdmin._logger != null) + CS2_SimpleAdmin._logger.LogCritical($"IsPlayerBanned for {player.Name}"); +#endif + DateTime currentTimeUtc = DateTime.UtcNow; string sql = "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime)"; int banCount = 0; try { - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); var parameters = new { @@ -119,12 +125,13 @@ namespace CS2_SimpleAdmin return banCount > 0; } + public async Task GetPlayerBans(PlayerInfo player) { string sql = "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)"; int banCount; - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); if (!string.IsNullOrEmpty(player.IpAddress)) { @@ -145,7 +152,7 @@ namespace CS2_SimpleAdmin return; } - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); string sqlUnban = "UPDATE sa_bans SET status = 'UNBANNED' WHERE player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern AND status = 'ACTIVE'"; await connection.ExecuteAsync(sqlUnban, new { pattern = playerPattern }); @@ -153,10 +160,18 @@ namespace CS2_SimpleAdmin public async Task ExpireOldBans() { - await using var connection = _database.GetConnection(); + try + { + await using var connection = await _database.GetConnectionAsync(); - string sql = "UPDATE sa_bans SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime"; - await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.Now }); + string sql = "UPDATE sa_bans SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime"; + await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.Now }); + } + catch (Exception) + { + if (CS2_SimpleAdmin._logger != null) + CS2_SimpleAdmin._logger.LogCritical("Unable to remove expired bans"); + } } } } \ No newline at end of file diff --git a/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin.cs index 38048a6..4046031 100644 --- a/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin.cs @@ -18,16 +18,16 @@ using Microsoft.Extensions.Logging; using MySqlConnector; using Newtonsoft.Json; using System.Collections.Concurrent; -using System.Runtime.InteropServices; using System.Text; using CS2_SimpleAdmin.Menus; namespace CS2_SimpleAdmin; -[MinimumApiVersion(159)] -public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig +[MinimumApiVersion(163)] +public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig { public static CS2_SimpleAdmin Instance { get; private set; } = null; + public static BasePlugin? _plugin = null; public static IStringLocalizer? _localizer; //public static ConcurrentBag mutedPlayers = new ConcurrentBag(); @@ -44,8 +44,9 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig CBasePlayerController_SetPawnFunc = new(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x89\\xF3\\x48\\x81\\xEC\\xC8\\x00\\x00\\x00" : "\\x44\\x88\\x4C\\x24\\x2A\\x55\\x57"); + internal static ILogger? _logger; + public static MemoryFunctionVoid? CBasePlayerController_SetPawnFunc = null; public override string ModuleName => "CS2-SimpleAdmin"; public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)"; public override string ModuleAuthor => "daffyy"; @@ -56,6 +57,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig + { + try + { + using (var connection = await _database.GetConnectionAsync()) + { + var commandText = "ALTER TABLE `sa_mutes` CHANGE `type` `type` ENUM('GAG','MUTE', 'SILENCE', '') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'GAG';"; + + using (var command = connection.CreateCommand()) + { + command.CommandText = commandText; + await command.ExecuteNonQueryAsync(); + } + } + } + catch (Exception ex) + { + Logger.LogError($"{ex.Message}"); + } + }); + } + [ConsoleCommand("css_adminhelp")] [RequiresPermissions("@css/generic")] public void OnAdminHelpCommand(CCSPlayerController? caller, CommandInfo command) { - if (caller == null || !caller.IsValid) - return; + if (caller == null || !caller.IsValid) return; using (new WithTemporaryCulture(caller.GetLanguage())) { @@ -208,8 +185,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig(silentPlayers.Where(item => item != caller.Slot)); + RemoveFromConcurrentBag(silentPlayers, caller.Slot); caller.PrintToChat($"You aren't hidden now!"); caller.ChangeTeam(CsTeam.Spectator); - if (Config.DiscordWebhook.Length > 0 && _localizer != null) + if (Config.DiscordWebhook.Length > 0) _ = SendWebhookMessage($"{caller.PlayerName} isn't hidden now."); } else @@ -332,12 +305,12 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { caller.ChangeTeam(CsTeam.Spectator); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); - AddTimer(1.05f, () => { caller.ChangeTeam(CsTeam.None); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(1.15f, () => { caller.ChangeTeam(CsTeam.None); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); caller.PrintToChat($"You are hidden now!"); - if (Config.DiscordWebhook.Length > 0 && _localizer != null) + if (Config.DiscordWebhook.Length > 0) _ = SendWebhookMessage($"{caller.PlayerName} is hidden now."); + AddTimer(1.22f, () => { Server.ExecuteCommand("sv_disable_teamselect_menu 0"); }); }); - Server.NextFrame(() => { AddTimer(1.1f, () => { Server.ExecuteCommand("sv_disable_teamselect_menu 0"); }); }); } } @@ -346,13 +319,11 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && !player.IsBot && !player.IsHLTV).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); Database database = new Database(dbConnectionString); BanManager _banManager = new(database, Config); @@ -376,7 +347,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { Action printMethod = caller == null ? Server.PrintToConsole : caller.PrintToConsole; + printMethod($"--------- INFO ABOUT \"{playerInfo.Name}\" ---------"); printMethod($"• Clan: \"{player!.Clan}\" Name: \"{playerInfo.Name}\""); printMethod($"• UserID: \"{playerInfo.UserId}\""); if (playerInfo.SteamId != null) printMethod($"• SteamID64: \"{playerInfo.SteamId}\""); - if (player.AuthorizedSteamID != null) + if (player.SteamID.ToString().Length == 17) { - printMethod($"• SteamID2: \"{player.AuthorizedSteamID.SteamId2}\""); - printMethod($"• Community link: \"{player.AuthorizedSteamID.ToCommunityUrl()}\""); + printMethod($"• SteamID2: \"{player.SteamID}\""); + printMethod($"• Community link: \"{new SteamID(player.SteamID).ToCommunityUrl()}\""); } - if (playerInfo.IpAddress != null) printMethod($"• IP Address: \"{playerInfo.IpAddress}\""); printMethod($"• Ping: \"{player.Ping}\""); - if (player.AuthorizedSteamID != null) + if (player.SteamID.ToString().Length == 17) { printMethod($"• Total Bans: \"{totalBans}\""); printMethod($"• Total Mutes: \"{totalMutes}\""); @@ -423,21 +394,24 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList(); + List playersToTarget = Helper.GetValidPlayers(); if (caller != null) { caller!.PrintToConsole($"--------- PLAYER LIST ---------"); - playersToTarget.ForEach(player => { caller!.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.AuthorizedSteamID?.SteamId64}\")"); }); + playersToTarget.ForEach(player => + { + caller!.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")"); + }); caller!.PrintToConsole($"--------- END PLAYER LIST ---------"); } else { Server.PrintToConsole($"--------- PLAYER LIST ---------"); - playersToTarget.ForEach(player => { Server.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.AuthorizedSteamID?.SteamId64}\")"); }); + playersToTarget.ForEach(player => + { + Server.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")"); + }); Server.PrintToConsole($"--------- END PLAYER LIST ---------"); } } @@ -447,12 +421,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnKickCommand(CCSPlayerController? caller, CommandInfo command) { - string reason = null; + string reason = "Unknown"; TargetResult? targets = GetTarget(command); + if (targets == null) return; - List playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && !player.IsHLTV).ToList(); if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) { @@ -464,6 +440,9 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (caller!.CanTarget(player)) { Kick(caller, player, reason); @@ -478,14 +457,16 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig Helper.KickPlayer((ushort)player.UserId!, reason), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); @@ -497,7 +478,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -520,16 +501,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnGagCommand(CCSPlayerController? caller, CommandInfo command) { - if (_database == null) - return; + if (_database == null) return; int time = 0; - string reason = null; + string reason = "Unknown"; TargetResult? targets = GetTarget(command); - if (targets == null) - return; - List playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) { @@ -542,6 +521,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { @@ -559,78 +539,85 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { await muteManager.MutePlayer(playerInfo, adminInfo, reason, time); }); - - if (TagsDetected) - NativeAPI.IssueServerCommand($"css_tag_mute {player!.SteamID}"); - - if (player != null && !gaggedPlayers.Contains(player.Slot)) - gaggedPlayers.Add(player.Slot); - - if (time == 0) - { - using (new WithTemporaryCulture(player.GetLanguage())) - { - player!.PrintToCenter(_localizer!["sa_player_gag_message_perm", reason, caller == null ? "Console" : caller.PlayerName]); - } - - if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) - { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + PlayerInfo adminInfo = new PlayerInfo { - using (new WithTemporaryCulture(_player.GetLanguage())) + SteamId = caller?.SteamID.ToString(), + Name = caller?.PlayerName, + IpAddress = caller?.IpAddress?.Split(":")[0] + }; + + Task.Run(async () => + { + await _muteManager.MutePlayer(playerInfo, adminInfo, reason, time); + }); + + if (TagsDetected) + Server.ExecuteCommand($"css_tag_mute {player!.SteamID}"); + + playerPenaltyManager.AddPenalty(player!.Slot, PenaltyType.Gag, DateTime.Now.AddMinutes(time), time); + + if (time == 0) + { + if (!player!.IsBot && !player.IsHLTV) { - StringBuilder sb = new(_localizer!["sa_prefix"]); - sb.Append(_localizer["sa_admin_gag_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]); - _player.PrintToChat(sb.ToString()); + using (new WithTemporaryCulture(player.GetLanguage())) + { + player.PrintToCenter(_localizer!["sa_player_gag_message_perm", reason, caller == null ? "Console" : caller.PlayerName]); + } + } + + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_gag_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_gag_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } } } - - if (Config.DiscordWebhook.Length > 0 && _localizer != null) + else { - LocalizedString localizedMessage = _localizer["sa_admin_gag_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; - _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); - } - } - } - else - { - using (new WithTemporaryCulture(player.GetLanguage())) - { - player!.PrintToCenter(_localizer!["sa_player_gag_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]); - } - - if (caller == null || caller != null && caller != null && !silentPlayers.Contains(caller.Slot)) - { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) - { - using (new WithTemporaryCulture(_player.GetLanguage())) + if (!player!.IsBot && !player.IsHLTV) { - StringBuilder sb = new(_localizer!["sa_prefix"]); - sb.Append(_localizer["sa_admin_gag_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]); - _player.PrintToChat(sb.ToString()); + using (new WithTemporaryCulture(player.GetLanguage())) + { + player!.PrintToCenter(_localizer!["sa_player_gag_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]); + } + } + + if (caller == null || caller != null && caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_gag_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_gag_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } } } - - if (Config.DiscordWebhook.Length > 0 && _localizer != null) - { - LocalizedString localizedMessage = _localizer["sa_admin_gag_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; - _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); - } - } - } + } [ConsoleCommand("css_addgag")] @@ -638,12 +625,9 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnAddGagCommand(CCSPlayerController? caller, CommandInfo command) { - if (_database == null) - return; - if (command.ArgCount < 2) - return; - if (string.IsNullOrEmpty(command.GetArg(1))) - return; + if (_database == null) return; + if (command.ArgCount < 2) return; + if (string.IsNullOrEmpty(command.GetArg(1))) return; string steamid = command.GetArg(1); @@ -657,6 +641,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -710,14 +696,15 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -726,7 +713,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_gag_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; @@ -736,13 +722,11 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnUngagCommand(CCSPlayerController? caller, CommandInfo command) { - if (_database == null) - return; + if (_database == null) return; if (command.GetArg(1).Length <= 1) { @@ -766,6 +749,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig matches = Helper.GetPlayerFromSteamid64(pattern); @@ -774,13 +759,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig(gaggedPlayers.Where(item => item != player.Slot)); - } + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Gag); if (TagsDetected) - NativeAPI.IssueServerCommand($"css_tag_unmute {player!.SteamID}"); + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); found = true; } @@ -794,15 +776,12 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig(gaggedPlayers.Where(item => item != player.Slot)); - } + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Gag); if (TagsDetected) - NativeAPI.IssueServerCommand($"css_tag_unmute {player!.SteamID.ToString()}"); + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID.ToString()}"); - pattern = player!.AuthorizedSteamID!.SteamId64.ToString(); + pattern = player!.SteamID.ToString(); found = true; } @@ -817,9 +796,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) { @@ -830,16 +808,13 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { - if (player != null && gaggedPlayers.Contains(player.Slot)) - { - gaggedPlayers = new ConcurrentBag(gaggedPlayers.Where(item => item != player.Slot)); - } + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Gag); - if (player!.AuthorizedSteamID != null) - _ = _muteManager.UnmutePlayer(player.AuthorizedSteamID.SteamId64.ToString(), 0); // Unmute by type 0 (gag) + if (player!.SteamID.ToString().Length == 17) + _ = _muteManager.UnmutePlayer(player.SteamID.ToString(), 0); // Unmute by type 0 (gag) if (TagsDetected) - NativeAPI.IssueServerCommand($"css_tag_unmute {player!.SteamID}"); + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); }); command.ReplyToCommand($"Ungaged player with pattern {pattern}."); @@ -854,16 +829,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnMuteCommand(CCSPlayerController? caller, CommandInfo command) { - if (_database == null) - return; + if (_database == null) return; int time = 0; string reason = "Unknown"; TargetResult? targets = GetTarget(command); - if (targets == null) - return; - List playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) { @@ -876,6 +849,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { @@ -893,79 +867,78 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { await muteManager.MutePlayer(playerInfo, adminInfo, reason, time, 1); }); - - if (time == 0) - { - using (new WithTemporaryCulture(player.GetLanguage())) - { - player!.PrintToCenter(_localizer!["sa_player_mute_message_perm", reason, caller == null ? "Console" : caller.PlayerName]); - } - - if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) - { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + PlayerInfo adminInfo = new PlayerInfo { - using (new WithTemporaryCulture(_player.GetLanguage())) + SteamId = caller?.SteamID.ToString(), + Name = caller?.PlayerName, + IpAddress = caller?.IpAddress?.Split(":")[0] + }; + + player!.VoiceFlags = VoiceFlags.Muted; + + Task.Run(async () => + { + await _muteManager.MutePlayer(playerInfo, adminInfo, reason, time, 1); + }); + + playerPenaltyManager.AddPenalty(player!.Slot, PenaltyType.Mute, DateTime.Now.AddMinutes(time), time); + + if (time == 0) + { + if (!player.IsBot && !player.IsHLTV) + using (new WithTemporaryCulture(player.GetLanguage())) + { + player!.PrintToCenter(_localizer!["sa_player_mute_message_perm", reason, caller == null ? "Console" : caller.PlayerName]); + } + + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - StringBuilder sb = new(_localizer!["sa_prefix"]); - sb.Append(_localizer["sa_admin_mute_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]); - _player.PrintToChat(sb.ToString()); + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_mute_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_mute_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } } } - - if (Config.DiscordWebhook.Length > 0 && _localizer != null) + else { - LocalizedString localizedMessage = _localizer["sa_admin_mute_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; - _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); - } - } - } - else - { - using (new WithTemporaryCulture(player.GetLanguage())) - { - player!.PrintToCenter(_localizer!["sa_player_mute_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]); - } - - if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) - { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) - { - using (new WithTemporaryCulture(_player.GetLanguage())) + if (!player.IsBot && !player.IsHLTV) + using (new WithTemporaryCulture(player.GetLanguage())) + { + player!.PrintToCenter(_localizer!["sa_player_mute_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]); + } + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - StringBuilder sb = new(_localizer!["sa_prefix"]); - sb.Append(_localizer["sa_admin_mute_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]); - _player.PrintToChat(sb.ToString()); + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_mute_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_mute_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } } } - - if (Config.DiscordWebhook.Length > 0 && _localizer != null) - { - LocalizedString localizedMessage = _localizer["sa_admin_mute_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; - _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); - } - } - } } [ConsoleCommand("css_addmute")] @@ -973,13 +946,9 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnAddMuteCommand(CCSPlayerController? caller, CommandInfo command) { - if (_database == null) - return; - - if (command.ArgCount < 2) - return; - if (string.IsNullOrEmpty(command.GetArg(1))) - return; + if (_database == null) return; + if (command.ArgCount < 2) return; + if (string.IsNullOrEmpty(command.GetArg(1))) return; string steamid = command.GetArg(1); @@ -993,6 +962,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1046,14 +1018,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1070,11 +1042,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnUnmuteCommand(CCSPlayerController? caller, CommandInfo command) { - if (_database == null) - return; + if (_database == null) return; if (command.GetArg(1).Length <= 1) { @@ -1099,6 +1065,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) { @@ -1167,19 +1116,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { - /* - if (mutedPlayers.Contains((int)player.Index)) - { - if (mutedPlayers.TryTake(out int removedItem) && removedItem != (int)player.Index) - { - mutedPlayers.Add(removedItem); - } - } - */ - - if (player.AuthorizedSteamID != null) - _ = _muteManager.UnmutePlayer(player.AuthorizedSteamID.SteamId64.ToString(), 1); // Unmute by type 1 (mute) + if (player.SteamID.ToString().Length == 17) + _ = _muteManager.UnmutePlayer(player.SteamID.ToString(), 1); // Unmute by type 1 (mute) + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Mute); player.VoiceFlags = VoiceFlags.Normal; }); @@ -1190,6 +1130,321 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] + public void OnSilenceCommand(CCSPlayerController? caller, CommandInfo command) + { + if (_database == null) return; + + int time = 0; + string reason = "Unknown"; + + TargetResult? targets = GetTarget(command); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); + + if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) + { + return; + } + + int.TryParse(command.GetArg(2), out time); + + if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) + reason = command.GetArg(3); + + MuteManager _muteManager = new(_database); + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + + playersToTarget.ForEach(player => + { + if (caller!.CanTarget(player)) + { + PlayerInfo playerInfo = new PlayerInfo + { + SteamId = player?.SteamID.ToString(), + Name = player?.PlayerName, + IpAddress = player?.IpAddress?.Split(":")[0] + }; + + PlayerInfo adminInfo = new PlayerInfo + { + SteamId = caller?.SteamID.ToString(), + Name = caller?.PlayerName, + IpAddress = caller?.IpAddress?.Split(":")[0] + }; + + Task.Run(async () => + { + await _muteManager.MutePlayer(playerInfo, adminInfo, reason, time, 2); + }); + + if (TagsDetected) + Server.ExecuteCommand($"css_tag_mute {player!.SteamID}"); + + playerPenaltyManager.AddPenalty(player!.Slot, PenaltyType.Silence, DateTime.Now.AddMinutes(time), time); + + if (time == 0) + { + if (!player!.IsBot && !player.IsHLTV) + { + using (new WithTemporaryCulture(player.GetLanguage())) + { + player.PrintToCenter(_localizer!["sa_player_silence_message_perm", reason, caller == null ? "Console" : caller.PlayerName]); + } + } + + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_silence_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_silence_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } + } + } + else + { + if (!player!.IsBot && !player.IsHLTV) + { + using (new WithTemporaryCulture(player.GetLanguage())) + { + player!.PrintToCenter(_localizer!["sa_player_silence_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]); + } + } + + if (caller == null || caller != null && caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_silence_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_silence_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } + } + } + } + }); + } + + [ConsoleCommand("css_addsilence")] + [RequiresPermissions("@css/chat")] + [CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] + public void OnAddSilenceCommand(CCSPlayerController? caller, CommandInfo command) + { + if (_database == null) return; + + if (command.ArgCount < 2) + return; + if (string.IsNullOrEmpty(command.GetArg(1))) return; + + string steamid = command.GetArg(1); + + if (!Helper.IsValidSteamID64(steamid)) + { + command.ReplyToCommand($"Invalid SteamID64."); + return; + } + + int time = 0; + string reason = "Unknown"; + + MuteManager _muteManager = new(_database); + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + + int.TryParse(command.GetArg(2), out time); + + if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) + reason = command.GetArg(3); + + PlayerInfo adminInfo = new PlayerInfo + { + SteamId = caller?.SteamID.ToString(), + Name = caller?.PlayerName, + IpAddress = caller?.IpAddress?.Split(":")[0] + }; + + List matches = Helper.GetPlayerFromSteamid64(steamid); + if (matches.Count == 1) + { + CCSPlayerController? player = matches.FirstOrDefault(); + if (player != null && player.IsValid) + { + if (!caller!.CanTarget(player)) + { + command.ReplyToCommand($"{player.PlayerName} is more powerful than you!"); + return; + } + + if (TagsDetected) + Server.ExecuteCommand($"css_tag_mute {player!.SteamID}"); + + playerPenaltyManager.AddPenalty(player!.Slot, PenaltyType.Silence, DateTime.Now.AddMinutes(time), time); + + if (time == 0) + { + if (!player.IsBot && !player.IsHLTV) + using (new WithTemporaryCulture(player.GetLanguage())) + { + player!.PrintToCenter(_localizer!["sa_player_silence_message_perm", reason, caller == null ? "Console" : caller.PlayerName]); + } + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_silence_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_silence_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } + } + } + else + { + if (!player.IsBot && !player.IsHLTV) + using (new WithTemporaryCulture(player.GetLanguage())) + { + player!.PrintToCenter(_localizer!["sa_player_silence_message_time", reason, time, caller == null ? "Console" : caller.PlayerName]); + } + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_silence_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]); + _player.PrintToChat(sb.ToString()); + } + } + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_silence_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } + } + } + } + } + _ = _muteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 2); + command.ReplyToCommand($"Silenced player with steamid {steamid}."); + } + + [ConsoleCommand("css_unsilence")] + [RequiresPermissions("@css/chat")] + [CommandHelper(minArgs: 1, usage: "", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] + public void OnUnsilenceCommand(CCSPlayerController? caller, CommandInfo command) + { + if (_database == null) return; + + if (command.GetArg(1).Length <= 1) + { + command.ReplyToCommand($"Too short pattern to search."); + return; + } + + string pattern = command.GetArg(1); + bool found = false; + MuteManager _muteManager = new(_database); + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + + if (Helper.IsValidSteamID64(pattern)) + { + List matches = Helper.GetPlayerFromSteamid64(pattern); + if (matches.Count == 1) + { + CCSPlayerController? player = matches.FirstOrDefault(); + if (player != null && player.IsValid) + { + if (TagsDetected) + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); + + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Silence); + player.VoiceFlags = VoiceFlags.Normal; + found = true; + } + } + } + else + { + List matches = Helper.GetPlayerFromName(pattern); + if (matches.Count == 1) + { + CCSPlayerController? player = matches.FirstOrDefault(); + if (player != null && player.IsValid) + { + if (TagsDetected) + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); + + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Silence); + player.VoiceFlags = VoiceFlags.Normal; + pattern = player.SteamID.ToString(); + found = true; + } + } + } + + if (found) + { + _ = _muteManager.UnmutePlayer(pattern, 2); // Unmute by type 2 (silence) + command.ReplyToCommand($"Unsilenced player with pattern {pattern}."); + return; + } + + TargetResult? targets = GetTarget(command); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); + + if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) + { + return; + } + + if (playersToTarget.Count > 1) + { + playersToTarget.ForEach(player => + { + if (player.SteamID.ToString().Length == 17) + _ = _muteManager.UnmutePlayer(player.SteamID.ToString(), 2); // Unmute by type 2 (silence) + + if (TagsDetected) + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); + + playerPenaltyManager.RemovePenaltiesByType(player!.Slot, PenaltyType.Silence); + player.VoiceFlags = VoiceFlags.Normal; + }); + + command.ReplyToCommand($"Unsilenced player with pattern {pattern}."); + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + _ = SendWebhookMessage($"Unsilenced player with pattern {pattern}."); + return; + } + } + [ConsoleCommand("css_ban")] [RequiresPermissions("@css/ban")] [CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] @@ -1202,9 +1457,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); if (playersToTarget.Count > 1 && Config.DisableDangerousCommands || playersToTarget.Count == 0) { @@ -1237,24 +1491,26 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { await banManager.BanPlayer(playerInfo, adminInfo, reason, time); }); + Task.Run(async () => + { + await _banManager.BanPlayer(playerInfo, adminInfo, reason, time); + }); AddTimer(Config.KickTime, () => Helper.KickPlayer((ushort)player!.UserId!), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); @@ -1265,14 +1521,15 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1281,7 +1538,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_ban_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; @@ -1291,14 +1547,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1307,7 +1563,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_ban_message_time", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason, time]; @@ -1324,8 +1579,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1387,7 +1641,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_ban_message_perm", caller == null ? "Console" : caller.PlayerName, player.PlayerName, reason]; @@ -1397,14 +1650,15 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1440,10 +1694,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnBanIp(CCSPlayerController? caller, CommandInfo command) { - if (command.ArgCount < 2) - return; - if (string.IsNullOrEmpty(command.GetArg(1))) - return; + if (command.ArgCount < 2) return; + if (string.IsNullOrEmpty(command.GetArg(1))) return; string ipAddress = command.GetArg(1); @@ -1458,7 +1710,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1510,14 +1763,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1580,9 +1833,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { Slay(caller, player); }); } @@ -1593,16 +1845,16 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { + StringBuilder sb = new(_localizer!["sa_prefix"]); sb.Append(_localizer["sa_admin_slay_message", caller == null ? "Console" : caller.PlayerName, player.PlayerName]); _player.PrintToChat(sb.ToString()); } } - if (Config.DiscordWebhook.Length > 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_slay_message", caller == null ? "Console" : caller.PlayerName, player.PlayerName]; @@ -1617,9 +1869,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); + string weaponName = command.GetArg(2); @@ -1649,11 +1902,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + player.GiveNamedItem(weaponName); if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1678,20 +1934,22 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { if (caller!.CanTarget(player)) { - player.RemoveWeapons(); + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + player.RemoveWeapons(); if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1720,20 +1978,21 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { if (caller!.CanTarget(player)) { - player.SetHp(health); + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + player.SetHp(health); if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1762,12 +2021,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (caller!.CanTarget(player)) { /* @@ -1779,7 +2040,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1805,12 +2066,14 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (caller!.CanTarget(player)) { if (player != null) @@ -1827,7 +2090,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1856,9 +2119,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); if (command.ArgCount >= 2) { @@ -1867,6 +2129,9 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (caller!.CanTarget(player)) { Slap(caller, player, damage); @@ -1880,7 +2145,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -1889,7 +2154,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_slap_message", caller == null ? "Console" : caller.PlayerName, player.PlayerName]; @@ -1908,9 +2172,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && !player.IsHLTV).ToList(); switch (teamName) { @@ -1941,6 +2204,9 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (!teamName.Equals("swap")) { if (player.PawnIsAlive && teamNum != CsTeam.Spectator && !command.GetArg(3).ToLower().Equals("-k") && Config.TeamSwitchType == 1) @@ -1967,7 +2233,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2006,23 +2272,21 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { + using (new WithTemporaryCulture(_player.GetLanguage())) { - MenuManager.OpenChatMenu(_player, voteMenu); - for (int i = 2; i <= answersCount - 1; i++) - { - voteMenu.AddMenuOption(command.GetArg(i), Helper.handleVotes); - } - Helper.PrintToCenterAll(_localizer!["sa_admin_vote_message", caller == null ? "Console" : caller.PlayerName, question]); StringBuilder sb = new(_localizer!["sa_prefix"]); sb.Append(_localizer["sa_admin_vote_message", caller == null ? "Console" : caller.PlayerName, question]); _player.PrintToChat(sb.ToString()); } + + MenuManager.OpenChatMenu(_player, voteMenu); } if (Config.DiscordWebhook.Length > 0 && _localizer != null) @@ -2038,7 +2302,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2056,7 +2320,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig kvp in voteAnswers) { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2100,7 +2364,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { Server.ExecuteCommand(_command); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(2.0f, () => + { + Server.ExecuteCommand(_command); + }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); } else { @@ -2113,7 +2380,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2132,7 +2399,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { Server.ExecuteCommand($"changelevel {map}"); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(2.0f, () => + { + Server.ExecuteCommand($"changelevel {map}"); + }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); } } @@ -2157,7 +2427,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2174,7 +2444,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig { Server.ExecuteCommand(_command); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(2.0f, () => + { + Server.ExecuteCommand(_command); + }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); } [ConsoleCommand("css_asay", "Say to all admins.")] @@ -2182,13 +2455,12 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV && AdminManager.PlayerHasPermissions(p, "@css/chat"))) + foreach (CCSPlayerController _player in Helper.GetValidPlayers().Where(p => AdminManager.PlayerHasPermissions(p, "@css/chat"))) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2207,13 +2479,12 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2233,9 +2504,8 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => player != null && player.IsValid).ToList(); + if (targets == null) return; + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); int range = command.GetArg(0).Length + command.GetArg(1).Length + 2; string message = command.GetCommandString[range..]; @@ -2274,9 +2544,10 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) _ = SendWebhookMessage($"HSAY: {caller!.PlayerName}: {utf8String}"); @@ -2288,7 +2559,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { @@ -2298,7 +2569,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2327,10 +2598,13 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (caller!.CanTarget(player)) { player!.Pawn.Value!.Freeze(); @@ -2340,7 +2614,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2349,7 +2623,6 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig 0 && _localizer != null) { LocalizedString localizedMessage = _localizer["sa_admin_freeze_message", caller == null ? "Console" : caller.PlayerName, player.PlayerName]; @@ -2366,15 +2639,18 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid && player.PawnIsAlive).ToList(); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.PawnIsAlive && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + player!.Pawn.Value!.Unfreeze(); if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2393,29 +2669,75 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig ")] + [RequiresPermissions("@css/kick")] + public void OnRenameCommand(CCSPlayerController? caller, CommandInfo command) + { + string? newName = command.GetArg(2); + + if (string.IsNullOrEmpty(newName)) + return; + + TargetResult? targets = GetTarget(command); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && !player.IsHLTV).ToList(); + + playersToTarget.ForEach(player => + { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + + if (caller!.CanTarget(player)) + { + player.Rename(newName); + + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) + { + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) + { + using (new WithTemporaryCulture(_player.GetLanguage())) + { + StringBuilder sb = new(_localizer!["sa_prefix"]); + sb.Append(_localizer["sa_admin_rename_message", caller == null ? "Console" : caller.PlayerName, player.PlayerName, newName]); + _player.PrintToChat(sb.ToString()); + } + } + } + + if (Config.DiscordWebhook.Length > 0 && _localizer != null) + { + LocalizedString localizedMessage = _localizer["sa_admin_rename_message", caller == null ? "Console" : caller.PlayerName, player.PlayerName, newName]; + _ = SendWebhookMessage(localizedMessage.ToString().Replace("", "").Replace("", "")); + } + } + }); + } + [ConsoleCommand("css_respawn", "Respawn a dead player.")] [CommandHelper(1, "<#userid or name>")] [RequiresPermissions("@css/cheats")] public void OnRespawnCommand(CCSPlayerController? caller, CommandInfo command) { TargetResult? targets = GetTarget(command); - List playersToTarget = targets!.Players.Where(player => caller!.CanTarget(player) && player != null && player.IsValid).ToList(); + List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && !player.IsHLTV).ToList(); playersToTarget.ForEach(player => { + if (!player.IsBot && player.SteamID.ToString().Length != 17) + return; + if (caller!.CanTarget(player)) { - if (CBasePlayerController_SetPawnFunc == null || player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) - return; + if (CBasePlayerController_SetPawnFunc == null || player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) return; - CCSPlayerPawn? playerPawn = player.PlayerPawn.Value; + var playerPawn = player.PlayerPawn.Value; CBasePlayerController_SetPawnFunc.Invoke(player, playerPawn, true, false); VirtualFunction.CreateVoid(player.Handle, - GameData.GetOffset("CCSPlayerController_Respawn"))(player); + GameData.GetOffset("CCSPlayerController_Respawn"))(player); if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - foreach (CCSPlayerController _player in Utilities.GetPlayers().Where(p => p != null && p.IsValid && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV)) + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { @@ -2440,7 +2762,7 @@ public partial class CS2_SimpleAdmin: BasePlugin, IPluginConfig bag, int value) + { + if (bag.Count > 0) + { + if (bag.Contains(value)) + { + bag = new ConcurrentBag(bag.Where(item => item != value)); + } + } + } + } diff --git a/CS2-SimpleAdmin.csproj b/CS2-SimpleAdmin.csproj index 127d09a..c1d5959 100644 --- a/CS2-SimpleAdmin.csproj +++ b/CS2-SimpleAdmin.csproj @@ -6,10 +6,11 @@ enable enable true + true - + @@ -17,6 +18,10 @@ + + + + diff --git a/Database.cs b/Database.cs index b701af9..87a3c59 100644 --- a/Database.cs +++ b/Database.cs @@ -1,19 +1,31 @@ -using MySqlConnector; +using Microsoft.Extensions.Logging; +using MySqlConnector; -namespace CS2_SimpleAdmin; -public class Database +namespace CS2_SimpleAdmin { - private readonly string _dbConnectionString; - - public Database(string dbConnectionString) + public class Database { - _dbConnectionString = dbConnectionString; - } + private readonly string _dbConnectionString; - public MySqlConnection GetConnection() - { - var connection = new MySqlConnection(_dbConnectionString); - connection.Open(); - return connection; + public Database(string dbConnectionString) + { + _dbConnectionString = dbConnectionString; + } + + public async Task GetConnectionAsync() + { + try + { + var connection = new MySqlConnection(_dbConnectionString); + await connection.OpenAsync(); + return connection; + } + catch (Exception) + { + if (CS2_SimpleAdmin._logger != null) + CS2_SimpleAdmin._logger.LogCritical("Unable to connect to database"); + throw; + } + } } -} +} \ No newline at end of file diff --git a/Events.cs b/Events.cs index 13ac8ae..af0d300 100644 --- a/Events.cs +++ b/Events.cs @@ -6,10 +6,8 @@ using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Cvars; using Dapper; using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; using System.Data; using System.Text; -using static CounterStrikeSharp.API.Core.Listeners; namespace CS2_SimpleAdmin; @@ -17,44 +15,12 @@ public partial class CS2_SimpleAdmin { private void registerEvents() { - //RegisterListener(OnClientAuthorized); - //RegisterListener(OnClientConnect); - //RegisterListener(OnClientPutInServer); - //RegisterListener(OnClientDisconnect); - //RegisterEventHandler(OnPlayerFullConnect); - RegisterListener(OnMapStart); - //RegisterEventHandler(OnPlayerHurt); - //RegisterEventHandler(OnRoundStart); + RegisterListener(OnClientPutInServer); + RegisterListener(OnMapStart); AddCommandListener("say", OnCommandSay); AddCommandListener("say_team", OnCommandTeamSay); } - /*private HookResult OnPlayerFullConnect(EventPlayerConnectFull @event, GameEventInfo info) - { - CCSPlayerController? player = @event.Userid; - - if (player is null || player.IsBot || player.IsHLTV) return HookResult.Continue; - - PlayerInfo playerInfo = new PlayerInfo - { - UserId = player.UserId, - Index = (ushort)player.UserId, - SteamId = player?.AuthorizedSteamID?.SteamId64.ToString(), - Name = player?.PlayerName, - IpAddress = player?.IpAddress?.Split(":")[0] - }; - - Task.Run(async () => - { - Server.NextFrame(() => - { - if (player is null) return; - }); - }); - return HookResult.Continue; - } - */ - [GameEventHandler] private HookResult OnRoundEnd(EventRoundEnd @event, GameEventInfo info) { @@ -69,10 +35,10 @@ public partial class CS2_SimpleAdmin { if (player is null || !player.IsValid || player.IsBot || player.IsHLTV || info.GetArg(1).Length == 0) return HookResult.Continue; - if (player != null && gaggedPlayers.Contains(player.Slot)) - { + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + + if (playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) || playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence)) return HookResult.Handled; - } return HookResult.Continue; } @@ -81,10 +47,10 @@ public partial class CS2_SimpleAdmin { if (player is null || !player.IsValid || player.IsBot || player.IsHLTV || info.GetArg(1).Length == 0) return HookResult.Continue; - if (player != null && gaggedPlayers.Contains(player.Slot)) - { + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + + if (playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) || playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence)) return HookResult.Handled; - } if (info.GetArg(1).StartsWith("@")) { @@ -114,23 +80,17 @@ public partial class CS2_SimpleAdmin return HookResult.Continue; } - [GameEventHandler] - public HookResult OnPlayerConnect(EventPlayerConnectFull @event, GameEventInfo info) + public void OnClientPutInServer(int playerSlot) { - if (!@event.Userid.IsValid || !@event.Userid.PlayerPawn.IsValid) - return HookResult.Continue; - - CCSPlayerController? player = @event.Userid; + CCSPlayerController? player = Utilities.GetPlayerFromSlot(playerSlot); #if DEBUG Logger.LogCritical("[OnPlayerConnect] Before check"); -#endif - if (_database == null || player is null || !player.IsValid || player.IsBot || player.IsHLTV) - return HookResult.Continue; +#endif + if (player is null || !player.IsValid || player.IsBot || player.IsHLTV) return; #if DEBUG Logger.LogCritical("[OnPlayerConnect] After Check"); #endif - string? ipAddress = !string.IsNullOrEmpty(player.IpAddress) ? player.IpAddress.Split(":")[0] : null; if ( @@ -138,13 +98,13 @@ public partial class CS2_SimpleAdmin bannedPlayers.Contains(player.SteamID.ToString()) ) { - Server.NextFrame(() => - { - Helper.KickPlayer((ushort)player.UserId!, "Banned"); - }); - return HookResult.Continue; + Helper.KickPlayer((ushort)player.UserId!, "Banned"); + return; } + if (_database == null) + return; + PlayerInfo playerInfo = new PlayerInfo { UserId = player.UserId, @@ -155,19 +115,18 @@ public partial class CS2_SimpleAdmin IpAddress = ipAddress }; + BanManager _banManager = new(_database, Config); + MuteManager _muteManager = new(_database); + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + Task.Run(async () => { - BanManager _banManager = new(_database, Config); - - MuteManager _muteManager = new(_database); - List activeMutes = await _muteManager.IsPlayerMuted(playerInfo.SteamId); - if (await _banManager.IsPlayerBanned(playerInfo)) { if (playerInfo.IpAddress != null && !bannedPlayers.Contains(playerInfo.IpAddress)) bannedPlayers.Add(playerInfo.IpAddress); - if (!bannedPlayers.Contains(playerInfo.SteamId)) + if (playerInfo.SteamId != null && !bannedPlayers.Contains(playerInfo.SteamId)) bannedPlayers.Add(playerInfo.SteamId); Server.NextFrame(() => @@ -179,113 +138,151 @@ public partial class CS2_SimpleAdmin return; } + List activeMutes = await _muteManager.IsPlayerMuted(playerInfo.SteamId); + if (activeMutes.Count > 0) { - foreach (var mute in activeMutes) + foreach (dynamic mute in activeMutes) { string muteType = mute.type; + DateTime ends = mute.ends; + int duration = mute.duration; if (muteType == "GAG") { - // Chat mute - if (playerInfo.Slot.HasValue && !gaggedPlayers.Contains(playerInfo.Slot.Value)) - gaggedPlayers.Add(playerInfo.Slot.Value); - - if (TagsDetected) + playerPenaltyManager.AddPenalty(playerInfo.Slot, PenaltyType.Gag, ends, duration); + Server.NextFrame(() => { - Server.NextFrame(() => + if (TagsDetected) { Server.ExecuteCommand($"css_tag_mute {playerInfo.SteamId}"); - }); - } + } + }); } else if (muteType == "MUTE") { - // Voice mute + playerPenaltyManager.AddPenalty(playerInfo.Slot, PenaltyType.Mute, ends, duration); Server.NextFrame(() => { player.VoiceFlags = VoiceFlags.Muted; }); + + } + else + { + playerPenaltyManager.AddPenalty(playerInfo.Slot, PenaltyType.Silence, ends, duration); + Server.NextFrame(() => + { + player.VoiceFlags = VoiceFlags.Muted; + if (TagsDetected) + { + Server.ExecuteCommand($"css_tag_mute {playerInfo.SteamId}"); + } + }); } } } }); - return HookResult.Continue; + return; } [GameEventHandler] public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info) { - if (!@event.Userid.IsValid || @event.Userid.IsBot) + if (@event.Userid is null || !@event.Userid.IsValid) return HookResult.Continue; CCSPlayerController? player = @event.Userid; + #if DEBUG Logger.LogCritical("[OnClientDisconnect] Before"); #endif - if (player is null || !player.IsValid || player.IsBot || player.IsHLTV) - return HookResult.Continue; + if (player.IsBot || player.IsHLTV) return HookResult.Continue; - if (player.Connected == PlayerConnectedState.PlayerConnecting) - return HookResult.Continue; #if DEBUG Logger.LogCritical("[OnClientDisconnect] After Check"); #endif - if (gaggedPlayers.Contains(player.Slot)) - { - gaggedPlayers = new ConcurrentBag(gaggedPlayers.Where(item => item != player.Slot)); - } + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + playerPenaltyManager.RemoveAllPenalties(player.Slot); + //RemoveFromConcurrentBag(gaggedPlayers, player.Slot); + RemoveFromConcurrentBag(silentPlayers, player.Slot); + RemoveFromConcurrentBag(godPlayers, player.Slot); - if (silentPlayers.Contains(player.Slot)) + if (player.AuthorizedSteamID != null && AdminSQLManager._adminCache.TryGetValue(player.AuthorizedSteamID, out DateTime? expirationTime) + && expirationTime <= DateTime.Now) { - silentPlayers = new ConcurrentBag(silentPlayers.Where(item => item != player.Slot)); - } - - if (godPlayers.Contains(player.Slot)) - { - godPlayers = new ConcurrentBag(godPlayers.Where(item => item != player.Slot)); - } - - if (player.AuthorizedSteamID != null && AdminSQLManager._adminCache.ContainsKey(player.AuthorizedSteamID)) - { - if (AdminSQLManager._adminCache.TryGetValue(player.AuthorizedSteamID, out DateTime? expirationTime) && - expirationTime <= DateTime.Now) - { - AdminManager.ClearPlayerPermissions(player.AuthorizedSteamID); - AdminManager.RemovePlayerAdminData(player.AuthorizedSteamID); - } + AdminManager.ClearPlayerPermissions(player.AuthorizedSteamID); + AdminManager.RemovePlayerAdminData(player.AuthorizedSteamID); } if (TagsDetected) - NativeAPI.IssueServerCommand($"css_tag_unmute {player!.SteamID}"); + Server.ExecuteCommand($"css_tag_unmute {player.SteamID}"); return HookResult.Continue; } private void OnMapStart(string mapName) { - gaggedPlayers.Clear(); + Random random = new Random(); + //gaggedPlayers.Clear(); godPlayers.Clear(); silentPlayers.Clear(); + PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); + playerPenaltyManager.RemoveAllPenalties(); + + _database = new(dbConnectionString); + if (_database == null) return; - AdminSQLManager _adminManager = new(_database); - - AddTimer(60.0f, bannedPlayers.Clear, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT | CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); - AddTimer(120.0f, async () => + AddTimer(random.Next(60, 80), async () => { +#if DEBUG + Logger.LogCritical("[OnMapStart] Expired check"); +#endif + AdminSQLManager _adminManager = new(_database); BanManager _banManager = new(_database, Config); MuteManager _muteManager = new(_database); await _banManager.ExpireOldBans(); await _muteManager.ExpireOldMutes(); await _adminManager.DeleteOldAdmins(); -#if DEBUG - Logger.LogCritical("[OnMapStart] Expired check"); -#endif + + bannedPlayers.Clear(); + + Server.NextFrame(() => + { + foreach (CCSPlayerController player in Helper.GetValidPlayers()) + { + if (playerPenaltyManager.IsSlotInPenalties(player.Slot)) + { + if (!playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) && !playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence)) + player.VoiceFlags = VoiceFlags.Normal; + + if (!playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) && !playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence)) + { + if (TagsDetected) + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); + } + + if ( + !playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence) && + !playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) && + !playerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag) + ) + { + player.VoiceFlags = VoiceFlags.Normal; + + if (TagsDetected) + Server.ExecuteCommand($"css_tag_unmute {player!.SteamID}"); + } + } + } + }); + + playerPenaltyManager.RemoveExpiredPenalties(); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT | CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); @@ -302,23 +299,56 @@ public partial class CS2_SimpleAdmin await Task.Run(async () => { - using (var connection = _database.GetConnection()) + AdminSQLManager _adminManager = new(_database); + try { - await connection.ExecuteAsync( - "INSERT INTO `sa_servers` (address, hostname) VALUES (@address, @hostname) " + - "ON DUPLICATE KEY UPDATE hostname = @hostname", - new { address = $"{address}", hostname }); + await using (var connection = await _database.GetConnectionAsync()) + { + bool addressExists = await connection.ExecuteScalarAsync( + "SELECT COUNT(*) FROM sa_servers WHERE address = @address", + new { address }); - int? serverId = await connection.ExecuteScalarAsync( - "SELECT `id` FROM `sa_servers` WHERE `address` = @address", - new { address = $"{address}" }); + if (!addressExists) + { + await connection.ExecuteAsync( + "INSERT INTO sa_servers (address, hostname) VALUES (@address, @hostname)", + new { address, hostname }); + } + else + { + await connection.ExecuteAsync( + "UPDATE `sa_servers` SET hostname = @hostname WHERE address = @address", + new { address, hostname }); + } - ServerId = serverId; + int? serverId = await connection.ExecuteScalarAsync( + "SELECT `id` FROM `sa_servers` WHERE `address` = @address", + new { address }); - await _adminManager.GiveAllFlags(); + ServerId = serverId; + } } + catch (Exception) + { + if (_logger != null) + _logger.LogCritical("Unable to create or get server_id"); + } + await _adminManager.GiveAllFlags(); }); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + + + AddTimer(2.0f, () => + { + ConVar? botQuota = ConVar.Find("bot_quota"); + + if (botQuota != null && botQuota.GetPrimitiveValue() > 0) + { + Logger.LogInformation("Due to bugs with bots (game bug), consider disabling bots by setting `bot_quota 0` in the gamemode config if your server crashes after a map change."); + Logger.LogWarning("Due to bugs with bots (game bug), consider disabling bots by setting `bot_quota 0` in the gamemode config if your server crashes after a map change."); + Logger.LogCritical("Due to bugs with bots (game bug), consider disabling bots by setting `bot_quota 0` in the gamemode config if your server crashes after a map change."); + } + }); } [GameEventHandler] @@ -326,7 +356,9 @@ public partial class CS2_SimpleAdmin { CCSPlayerController? player = @event.Userid; - if (player is null || !player.IsValid || !player.PlayerPawn.IsValid || player.PlayerPawn.Value == null || player.IsBot || player.IsHLTV || player.PlayerPawn.IsValid || player.Connected == PlayerConnectedState.PlayerDisconnecting) + if (player is null || @event.Attacker == null || !player.IsValid || !player.PlayerPawn.IsValid || player.PlayerPawn.Value == null + || player.IsBot || player.IsHLTV || player.PlayerPawn.IsValid || player.Connected == PlayerConnectedState.PlayerDisconnecting + || @event.Attacker.Connected == PlayerConnectedState.PlayerDisconnecting) return HookResult.Continue; if (godPlayers.Contains(player.Slot) && player.PawnIsAlive) @@ -337,4 +369,5 @@ public partial class CS2_SimpleAdmin return HookResult.Continue; } + } \ No newline at end of file diff --git a/Helper.cs b/Helper.cs index e2be60c..c545fea 100644 --- a/Helper.cs +++ b/Helper.cs @@ -2,9 +2,12 @@ using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Entities; +using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Utils; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; using System.Text.RegularExpressions; namespace CS2_SimpleAdmin @@ -20,20 +23,25 @@ namespace CS2_SimpleAdmin public static List GetPlayerFromSteamid64(string steamid) { - return Utilities.GetPlayers().FindAll(x => - x.AuthorizedSteamID != null && - x.AuthorizedSteamID.SteamId64.ToString().Equals(steamid, StringComparison.OrdinalIgnoreCase) + return GetValidPlayers().FindAll(x => + x.SteamID.ToString().Equals(steamid, StringComparison.OrdinalIgnoreCase) ); } public static List GetPlayerFromIp(string ipAddress) { - return Utilities.GetPlayers().FindAll(x => + return GetValidPlayers().FindAll(x => x.IpAddress != null && x.IpAddress.Split(":")[0].Equals(ipAddress) ); } + public static List GetValidPlayers() + { + return Utilities.GetPlayers().FindAll(p => p != null && p.IsValid && p.SteamID.ToString().Length == 17 && p.Connected == PlayerConnectedState.PlayerConnected && !p.IsBot && !p.IsHLTV); + } + + public static bool IsValidSteamID64(string input) { string pattern = @"^\d{17}$"; @@ -60,7 +68,6 @@ namespace CS2_SimpleAdmin //Console.WriteLine($"Setting immunity for SteamID {steamid} to {immunity}"); - if (flags != null) { //Console.WriteLine($"Applying flags to SteamID {steamid}:"); @@ -150,10 +157,33 @@ namespace CS2_SimpleAdmin { if (CS2_SimpleAdmin.voteInProgress && !CS2_SimpleAdmin.votePlayers.Contains(player.Slot)) { + option.Disabled = true; CS2_SimpleAdmin.votePlayers.Add(player.Slot); CS2_SimpleAdmin.voteAnswers[option.Text]++; - option.Disabled = true; } } } + + public class SchemaString : NativeObject where SchemaClass : NativeObject + { + public SchemaString(SchemaClass instance, string member) : base(Schema.GetSchemaValue(instance.Handle, typeof(SchemaClass).Name!, member)) + { } + + public unsafe void Set(string str) + { + byte[] bytes = this.GetStringBytes(str); + + for (int i = 0; i < bytes.Length; i++) + { + Unsafe.Write((void*)(this.Handle.ToInt64() + i), bytes[i]); + } + + Unsafe.Write((void*)(this.Handle.ToInt64() + bytes.Length), 0); + } + + private byte[] GetStringBytes(string str) + { + return Encoding.ASCII.GetBytes(str); + } + } } \ No newline at end of file diff --git a/MuteManager.cs b/MuteManager.cs index 90585f5..85ed992 100644 --- a/MuteManager.cs +++ b/MuteManager.cs @@ -1,5 +1,6 @@ using CounterStrikeSharp.API.Core; using Dapper; +using Microsoft.Extensions.Logging; namespace CS2_SimpleAdmin { @@ -16,7 +17,7 @@ namespace CS2_SimpleAdmin { if (player == null || player.SteamId == null) return; - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); DateTime now = DateTime.Now; DateTime futureTime = now.AddMinutes(time); @@ -24,6 +25,8 @@ namespace CS2_SimpleAdmin string muteType = "GAG"; if (type == 1) muteType = "MUTE"; + else if (type == 2) + muteType = "SILENCE"; var sql = "INSERT INTO `sa_mutes` (`player_steamid`, `player_name`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `type`, `server_id`) " + "VALUES (@playerSteamid, @playerName, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @type, @serverid)"; @@ -47,7 +50,7 @@ namespace CS2_SimpleAdmin { if (string.IsNullOrEmpty(playerSteamId)) return; - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); DateTime now = DateTime.Now; DateTime futureTime = now.AddMinutes(time); @@ -55,6 +58,8 @@ namespace CS2_SimpleAdmin string muteType = "GAG"; if (type == 1) muteType = "MUTE"; + else if (type == 2) + muteType = "SILENCE"; var sql = "INSERT INTO `sa_mutes` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `type`, `server_id`) " + "VALUES (@playerSteamid, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @type, @serverid)"; @@ -80,12 +85,17 @@ namespace CS2_SimpleAdmin return new List(); } - await using var connection = _database.GetConnection(); - DateTime currentTimeUtc = DateTime.UtcNow; - string sql = "SELECT * FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime)"; +#if DEBUG + if (CS2_SimpleAdmin._logger != null) + CS2_SimpleAdmin._logger.LogCritical($"IsPlayerMuted for {steamId}"); +#endif try { + await using var connection = await _database.GetConnectionAsync(); + DateTime currentTimeUtc = DateTime.UtcNow; + string sql = "SELECT * FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime)"; + var parameters = new { PlayerSteamID = steamId, CurrentTime = currentTimeUtc }; var activeMutes = (await connection.QueryAsync(sql, parameters)).ToList(); return activeMutes; @@ -98,7 +108,7 @@ namespace CS2_SimpleAdmin public async Task GetPlayerMutes(string steamId) { - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); int muteCount; string sql = "SELECT COUNT(*) FROM sa_mutes WHERE player_steamid = @PlayerSteamID"; @@ -115,7 +125,7 @@ namespace CS2_SimpleAdmin return; } - await using var connection = _database.GetConnection(); + await using var connection = await _database.GetConnectionAsync(); if (type == 2) { @@ -130,6 +140,8 @@ namespace CS2_SimpleAdmin { muteType = "MUTE"; } + else if (type == 2) + muteType = "SILENCE"; string sqlUnban = "UPDATE sa_mutes SET status = 'UNMUTED' WHERE (player_steamid = @pattern OR player_name = @pattern) AND type = @muteType AND status = 'ACTIVE'"; await connection.ExecuteAsync(sqlUnban, new { pattern = playerPattern, muteType }); @@ -137,10 +149,18 @@ namespace CS2_SimpleAdmin public async Task ExpireOldMutes() { - await using var connection = _database.GetConnection(); + try + { + await using var connection = await _database.GetConnectionAsync(); - string sql = "UPDATE sa_mutes SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime"; - await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.Now }); + string sql = "UPDATE sa_mutes SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND `duration` > 0 AND ends <= @CurrentTime"; + await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.Now }); + } + catch (Exception) + { + if (CS2_SimpleAdmin._logger != null) + CS2_SimpleAdmin._logger.LogCritical("Unable to remove expired mutes"); + } } public async Task CheckMute(PlayerInfo player) @@ -160,11 +180,6 @@ namespace CS2_SimpleAdmin if (muteType == "GAG") { - if (player.Slot.HasValue && !CS2_SimpleAdmin.gaggedPlayers.Contains(player.Slot.Value)) - { - CS2_SimpleAdmin.gaggedPlayers.Add(player.Slot.Value); - } - if (CS2_SimpleAdmin.TagsDetected) NativeAPI.IssueServerCommand($"css_tag_mute {player!.SteamId}"); diff --git a/PlayerInfo.cs b/PlayerInfo.cs index de7c85d..4d472c0 100644 --- a/PlayerInfo.cs +++ b/PlayerInfo.cs @@ -4,7 +4,7 @@ { public int? Index { get; set; } public int? UserId { get; set; } - public int? Slot { get; set; } + public int Slot { get; set; } public string? SteamId { get; set; } public string? Name { get; set; } public string? IpAddress { get; set; } diff --git a/PlayerPenaltyManager.cs b/PlayerPenaltyManager.cs new file mode 100644 index 0000000..d8cae04 --- /dev/null +++ b/PlayerPenaltyManager.cs @@ -0,0 +1,139 @@ +using System.Collections.Concurrent; + +namespace CS2_SimpleAdmin +{ + public enum PenaltyType + { + Mute, + Gag, + Silence + } + + public class PlayerPenaltyManager + { + private static ConcurrentDictionary>> penalties = + new ConcurrentDictionary>>(); + + // Add a penalty for a player + public void AddPenalty(int slot, PenaltyType penaltyType, DateTime endDateTime, int durationSeconds) + { + if (!penalties.ContainsKey(slot)) + { + penalties[slot] = new Dictionary>(); + } + + if (!penalties[slot].ContainsKey(penaltyType)) + { + penalties[slot][penaltyType] = new List<(DateTime, int)>(); + } + + penalties[slot][penaltyType].Add((endDateTime, durationSeconds)); + } + + public bool IsPenalized(int slot, PenaltyType penaltyType) + { + //Console.WriteLine($"Checking penalties for player with slot {slot} and penalty type {penaltyType}"); + + if (penalties.TryGetValue(slot, out var penaltyDict) && penaltyDict.TryGetValue(penaltyType, out var penaltiesList)) + { + //Console.WriteLine($"Found penalties for player with slot {slot} and penalty type {penaltyType}"); + + DateTime now = DateTime.Now; + + // Check if any active penalties exist + foreach (var penalty in penaltiesList.ToList()) + { + // Check if the penalty is still active + if (penalty.Duration > 0 && now >= penalty.EndDateTime.AddSeconds(penalty.Duration)) + { + //Console.WriteLine($"Removing expired penalty for player with slot {slot} and penalty type {penaltyType}"); + penaltiesList.Remove(penalty); // Remove expired penalty + if (penaltiesList.Count == 0) + { + //Console.WriteLine($"No more penalties of type {penaltyType} for player with slot {slot}. Removing penalty type."); + penaltyDict.Remove(penaltyType); // Remove penalty type if no more penalties exist + } + } + else if (penalty.Duration == 0 || now < penalty.EndDateTime) + { + //Console.WriteLine($"Player with slot {slot} is penalized for type {penaltyType}"); + // Return true if there's an active penalty + return true; + } + } + + // Return false if no active penalties are found + //Console.WriteLine($"Player with slot {slot} is not penalized for type {penaltyType}"); + return false; + } + + // Return false if no penalties of the specified type were found for the player + //Console.WriteLine($"No penalties found for player with slot {slot} and penalty type {penaltyType}"); + return false; + } + + // Get the end datetime and duration of penalties for a player and penalty type + public List<(DateTime EndDateTime, int Duration)> GetPlayerPenalties(int slot, PenaltyType penaltyType) + { + if (penalties.TryGetValue(slot, out Dictionary>? penaltyDict) && + penaltyDict.TryGetValue(penaltyType, out List<(DateTime EndDateTime, int Duration)>? penaltiesList) && penaltiesList != null) + { + return penaltiesList; + } + return new List<(DateTime EndDateTime, int Duration)>(); + } + + public bool IsSlotInPenalties(int slot) + { + return penalties.ContainsKey(slot); + } + + // Remove all penalties for a player slot + public void RemoveAllPenalties(int slot) + { + if (penalties.ContainsKey(slot)) + { + penalties.TryRemove(slot, out _); + } + } + + // Remove all penalties + public void RemoveAllPenalties() + { + penalties.Clear(); + } + + // Remove all penalties of a selected type from a specific player + public void RemovePenaltiesByType(int slot, PenaltyType penaltyType) + { + if (penalties.TryGetValue(slot, out Dictionary>? penaltyDict) && + penaltyDict.ContainsKey(penaltyType)) + { + penaltyDict.Remove(penaltyType); + } + } + + // Remove all expired penalties for all players and penalty types + public void RemoveExpiredPenalties() + { + DateTime now = DateTime.Now; + foreach (var kvp in penalties.ToList()) // Use ToList to avoid modification while iterating + { + var playerSlot = kvp.Key; + var penaltyDict = kvp.Value; + + // Remove expired penalties for the player + foreach (var penaltiesList in penaltyDict.Values) + { + penaltiesList.RemoveAll(p => p.Duration > 0 && now >= p.EndDateTime.AddSeconds(p.Duration)); + } + + // Remove player slot if no penalties left + if (penaltyDict.Count == 0) + { + penalties.TryRemove(playerSlot, out _); + } + } + } + } +} \ No newline at end of file diff --git a/PlayerUtils.cs b/PlayerUtils.cs index 4fd61e8..d167562 100644 --- a/PlayerUtils.cs +++ b/PlayerUtils.cs @@ -1,5 +1,8 @@ -using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Entities; +using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; using System.Text; using CounterStrikeSharp.API; @@ -23,7 +26,9 @@ public static class PlayerUtils public static bool CanTarget(this CCSPlayerController controller, CCSPlayerController target) { if (target.IsBot) return true; - return AdminManager.CanPlayerTarget(controller, target); + if (controller is null) return true; + + return AdminManager.CanPlayerTarget(controller, target) || AdminManager.CanPlayerTarget(new SteamID(controller.SteamID), new SteamID(target.SteamID)); } public static void SetSpeed(this CCSPlayerController controller, float speed) @@ -81,19 +86,56 @@ public static class PlayerUtils public static void Freeze(this CBasePlayerPawn pawn) { pawn.MoveType = MoveType_t.MOVETYPE_OBSOLETE; + Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 1); // obsolete + Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType"); } public static void Unfreeze(this CBasePlayerPawn pawn) { pawn.MoveType = MoveType_t.MOVETYPE_WALK; + Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk + Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType"); } public static void ToggleNoclip(this CBasePlayerPawn pawn) { if (pawn.MoveType == MoveType_t.MOVETYPE_NOCLIP) + { pawn.MoveType = MoveType_t.MOVETYPE_WALK; + Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 2); // walk + Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType"); + } else + { pawn.MoveType = MoveType_t.MOVETYPE_NOCLIP; + Schema.SetSchemaValue(pawn.Handle, "CBaseEntity", "m_nActualMoveType", 8); // noclip + Utilities.SetStateChanged(pawn, "CBaseEntity", "m_MoveType"); + } + } + + public static void Rename(this CCSPlayerController controller, string newName = "Unknown") + { + if (CS2_SimpleAdmin._plugin == null) + return; + + SchemaString playerName = new SchemaString(controller, "m_iszPlayerName"); + playerName.Set(newName + " "); + + CS2_SimpleAdmin._plugin.AddTimer(0.25f, () => + { + Utilities.SetStateChanged(controller, "CCSPlayerController", "m_szClan"); + Utilities.SetStateChanged(controller, "CBasePlayerController", "m_iszPlayerName"); + }); + + CS2_SimpleAdmin._plugin.AddTimer(0.3f, () => + { + playerName.Set(newName); + }); + + CS2_SimpleAdmin._plugin.AddTimer(0.4f, () => + { + Utilities.SetStateChanged(controller, "CBasePlayerController", "m_iszPlayerName"); + }); } private static void PerformSlap(CBasePlayerPawn pawn, int damage = 0) diff --git a/README.md b/README.md index 17164f2..b63471e 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ Manage your Counter-Strike 2 server by simple commands :) - css_mute <#userid or name> [time in minutes/0 perm] [reason] - Mute player // @css/chat - css_addmute [time in minutes/0 perm] [reason] - Mute player via steamid64 // @css/chat - css_unmute - Unmute player // @css/chat +- css_silence <#userid or name> [time in minutes/0 perm] [reason] - Silence player // @css/chat +- css_addsilence [time in minutes/0 perm] [reason] - Silence player via steamid64 // @css/chat +- css_unsilence - Unsilence player // @css/chat - css_give <#userid or name> - Give weapon to player // @css/cheats - css_strip <#userid or name> - Takes all of the player weapons // @css/slay - css_hp <#userid or name> [health] - Set player health // @css/slay @@ -49,6 +52,7 @@ Manage your Counter-Strike 2 server by simple commands :) - css_noclip <#userid or name> - Toggle noclip for player // @css/cheats - css_freeze <#userid or name> [duration] - Freeze player // @css/slay - css_unfreeze <#userid or name> - Unfreeze player // @css/slay +- css_rename <#userid or name> - Rename player // @css/kick - css_respawn <#userid or name> - Respawn player // @css/cheats - css_cvar - Change cvar value // @css/cvar - css_rcon - Run command as server // @css/rcon @@ -58,7 +62,7 @@ Manage your Counter-Strike 2 server by simple commands :) ``` ### Requirments -- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp/) **tested on v159** +- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp/) **tested on v163** - MySQL **tested on MySQL (MariaDB) Server version: 10.11.4-MariaDB-1~deb12u1 Debian 12** diff --git a/database_setup.sql b/database_setup.sql new file mode 100644 index 0000000..b3dcdb0 --- /dev/null +++ b/database_setup.sql @@ -0,0 +1,50 @@ +CREATE TABLE IF NOT EXISTS `sa_bans` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `player_steamid` VARCHAR(64), + `player_name` VARCHAR(128), + `player_ip` VARCHAR(128), + `admin_steamid` VARCHAR(64) NOT NULL, + `admin_name` VARCHAR(128) NOT NULL, + `reason` VARCHAR(255) NOT NULL, + `duration` INT NOT NULL, + `ends` TIMESTAMP NOT NULL, + `created` TIMESTAMP NOT NULL, + `server_id` INT NULL, + `status` ENUM('ACTIVE', 'UNBANNED', 'EXPIRED', '') NOT NULL DEFAULT 'ACTIVE' + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `sa_mutes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `player_steamid` varchar(64) NOT NULL, + `player_name` varchar(128) NULL, + `admin_steamid` varchar(64) NOT NULL, + `admin_name` varchar(128) NOT NULL, + `reason` varchar(255) NOT NULL, + `duration` int(11) NOT NULL, + `ends` timestamp NOT NULL, + `created` timestamp NOT NULL, + `type` enum('GAG','MUTE','SILENCE','') NOT NULL DEFAULT 'GAG', + `server_id` INT NULL, + `status` enum('ACTIVE','UNMUTED','EXPIRED','') NOT NULL DEFAULT 'ACTIVE', + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `sa_admins` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `player_steamid` varchar(64) NOT NULL, + `player_name` varchar(128) NOT NULL, + `flags` TEXT NOT NULL, + `immunity` varchar(64) NOT NULL DEFAULT '0', + `server_id` INT NULL, + `ends` timestamp NULL, + `created` timestamp NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `sa_servers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `address` varchar(64) NOT NULL, + `hostname` varchar(64) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `address` (`address`) + ) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index f49baed..099961d 100644 --- a/lang/en.json +++ b/lang/en.json @@ -8,6 +8,8 @@ "sa_player_gag_message_perm": "You have been gagged permanently for {lightred}{0}{default} by {lightred}{1}{default}!", "sa_player_mute_message_time": "You have been muted for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!", "sa_player_mute_message_perm": "You have been muted permanently for {lightred}{0}{default} by {lightred}{1}{default}!", + "sa_player_silence_message_time": "You have been silenced for {lightred}{0}{default} for {lightred}{1}{default} minutes by {lightred}{2}{default}!", + "sa_player_silence_message_perm": "You have been silenced permanently for {lightred}{0}{default} by {lightred}{1}{default}!", "sa_admin_ban_message_time": "Admin {lightred}{0}{default} banned {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!", "sa_admin_ban_message_perm": "Admin {lightred}{0}{default} banned {lightred}{1}{default} permanently for {lightred}{2}{default}!", "sa_admin_kick_message": "Admin {lightred}{0}{default} kicked {lightred}{1}{default} for {lightred}{2}{default}!", @@ -15,6 +17,8 @@ "sa_admin_gag_message_perm": "Admin {lightred}{0}{default} gagged {lightred}{1}{default} permanently for {lightred}{2}{default}!", "sa_admin_mute_message_time": "Admin {lightred}{0}{default} muted {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!", "sa_admin_mute_message_perm": "Admin {lightred}{0}{default} muted {lightred}{1}{default} permanently for {lightred}{2}{default}!", + "sa_admin_silence_message_time": "Admin {lightred}{0}{default} silenced {lightred}{1}{default} for {lightred}{2}{default} for {lightred}{3}{default} minutes!", + "sa_admin_silence_message_perm": "Admin {lightred}{0}{default} silenced {lightred}{1}{default} permanently for {lightred}{2}{default}!", "sa_admin_give_message": "Admin {lightred}{0}{default} gave {lightred}{1}{default} a {lightred}{2}{default}!", "sa_admin_strip_message": "Admin {lightred}{0}{default} took all of player {lightred}{1}{default} weapons!", "sa_admin_hp_message": "Admin {lightred}{0}{default} changed {lightred}{1}{default} hp amount{default}!", @@ -26,6 +30,7 @@ "sa_admin_noclip_message": "Admin {lightred}{0}{default} toggled noclip for {lightred}{1}{default}!", "sa_admin_freeze_message": "Admin {lightred}{0}{default} freezed {lightred}{1}{default}!", "sa_admin_unfreeze_message": "Admin {lightred}{0}{default} umfreezed {lightred}{1}{default}!", + "sa_admin_rename_message": "Admin {lightred}{0}{default} changed {lightred}{1}{default} nickname to {lightred}{2}{default}!", "sa_admin_respawn_message": "Admin {lightred}{0}{default} respawned {lightred}{1}{default}!", "sa_admin_team_message": "Admin {lightred}{0}{default} transfered {lightred}{1}{default} to {lightred}{2}{default}!", "sa_admin_vote_menu_title": "{lime}VOTING FOR {gold}{0}", diff --git a/lang/es.json b/lang/es.json index 32bc1c8..9c8d680 100644 --- a/lang/es.json +++ b/lang/es.json @@ -8,6 +8,8 @@ "sa_player_gag_message_perm": "Has sido silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}.", "sa_player_mute_message_time": "Has sido silenciado por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}.", "sa_player_mute_message_perm": "Has sido silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}.", + "sa_player_silence_message_time": "Has sido silenciado por {lightred}{0}{default} durante {lightred}{1}{default} minutos por {lightred}{2}{default}.", + "sa_player_silence_message_perm": "Has sido silenciado permanentemente por {lightred}{0}{default} por {lightred}{1}{default}.", "sa_admin_ban_message_time": "El administrador {lightred}{0}{default} ha baneado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos.", "sa_admin_ban_message_perm": "El administrador {lightred}{0}{default} ha baneado a {lightred}{1}{default} permanentemente por {lightred}{2}{default}.", "sa_admin_kick_message": "El administrador {lightred}{0}{default} ha expulsado a {lightred}{1}{default} por {lightred}{2}{default}.", @@ -15,6 +17,8 @@ "sa_admin_gag_message_perm": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} permanentemente por {lightred}{2}{default}.", "sa_admin_mute_message_time": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos.", "sa_admin_mute_message_perm": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} permanentemente por {lightred}{2}{default}.", + "sa_admin_silence_message_time": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} por {lightred}{2}{default} durante {lightred}{3}{default} minutos.", + "sa_admin_silence_message_perm": "El administrador {lightred}{0}{default} ha silenciado a {lightred}{1}{default} permanentemente por {lightred}{2}{default}.", "sa_admin_give_message": "El administrador {lightred}{0}{default} le ha dado a {lightred}{1}{default} un {lightred}{2}{default}.", "sa_admin_strip_message": "El administrador {lightred}{0}{default} le ha quitado todas las armas al jugador {lightred}{1}{default}.", "sa_admin_hp_message": "El administrador {lightred}{0}{default} ha cambiado la cantidad de salud de {lightred}{1}{default}{default}.", @@ -26,6 +30,7 @@ "sa_admin_noclip_message": "El administrador {lightred}{0}{default} ha activado noclip para {lightred}{1}{default}.", "sa_admin_freeze_message": "El administrador {lightred}{0}{default} ha congelado a {lightred}{1}{default}.", "sa_admin_unfreeze_message": "El administrador {lightred}{0}{default} ha descongelado a {lightred}{1}{default}.", + "sa_admin_rename_message": "El administrador {lightred}{0}{default} ha cambiado el nombre de {lightred}{1}{default} a {lightred}{2}{default}." "sa_admin_respawn_message": "El administrador {lightred}{0}{default} ha respawnado a {lightred}{1}{default}.", "sa_admin_team_message": "El administrador {lightred}{0}{default} ha transferido a {lightred}{1}{default} a {lightred}{2}{default}.", "sa_admin_vote_menu_title": "{lime}VOTACIÓN PARA {gold}{0}", @@ -35,4 +40,4 @@ "sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}", "sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}", "sa_adminchat_template_player": "{SILVER}(JUGADOR) {lightred}{0}{default}: {lightred}{1}{default}" -} \ No newline at end of file +} diff --git a/lang/pl.json b/lang/pl.json index 048017c..f2823f1 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -8,6 +8,8 @@ "sa_player_gag_message_perm": "Zostałeś zakneblowany na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!", "sa_player_mute_message_time": "Zostałeś uciszony za {lightred}{0}{default} na {lightred}{1}{default} minute przez {lightred}{2}{default}!", "sa_player_mute_message_perm": "Zostałeś uciszony na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!", + "sa_player_silence_message_time": "Zostałeś wyciszony za {lightred}{0}{default} na {lightred}{1}{default} minut przez {lightred}{2}{default}!", + "sa_player_silence_message_perm": "Zostałeś wyciszony na zawsze za {lightred}{0}{default} przez {lightred}{1}{default}!", "sa_admin_ban_message_time": "Admin {lightred}{0}{default} zbanował {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!", "sa_admin_ban_message_perm": "Admin {lightred}{0}{default} zbanował {lightred}{1}{default} na zawsze za {lightred}{2}{default}!", "sa_admin_kick_message": "Admin {lightred}{0}{default} wyrzucił {lightred}{1}{default} za {lightred}{2}{default}!", @@ -15,6 +17,8 @@ "sa_admin_gag_message_perm": "Admin {lightred}{0}{default} zakneblował {lightred}{1}{default} na zawsze za {lightred}{2}{default}!", "sa_admin_mute_message_time": "Admin {lightred}{0}{default} uciszył {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!", "sa_admin_mute_message_perm": "Admin {lightred}{0}{default} uciszył {lightred}{1}{default} na zawsze za {lightred}{2}{default}!", + "sa_admin_silence_message_time": "Admin {lightred}{0}{default} wyciszył {lightred}{1}{default} za {lightred}{2}{default} na {lightred}{3}{default} minut!", + "sa_admin_silence_message_perm": "Admin {lightred}{0}{default} wyciszył {lightred}{1}{default} na zawsze za {lightred}{2}{default}!", "sa_admin_give_message": "Admin {lightred}{0}{default} dał {lightred}{1}{default} przedmiot {lightred}{2}{default}!", "sa_admin_strip_message": "Admin {lightred}{0}{default} zabrał wszystkie bronie {lightred}{1}{default}!", "sa_admin_hp_message": "Admin {lightred}{0}{default} zmienił ilość hp dla {lightred}{1}{default}!", @@ -26,6 +30,7 @@ "sa_admin_noclip_message": "Admin {lightred}{0}{default} ustawił latanie dla {lightred}{1}{default}!", "sa_admin_freeze_message": "Admin {lightred}{0}{default} zamroził {lightred}{1}{default}!", "sa_admin_unfreeze_message": "Admin {lightred}{0}{default} odmroził {lightred}{1}{default}!", + "sa_admin_rename_message": "Admin {lightred}{0}{default} zmienił nick gracza {lightred}{1}{default} na {lightred}{2}{default}!", "sa_admin_respawn_message": "Admin {lightred}{0}{default} odrodził {lightred}{1}{default}!", "sa_admin_team_message": "Admin {lightred}{0}{default} przerzucił {lightred}{1}{default} do {lightred}{2}{default}!", "sa_admin_vote_menu_title": "{lime}GŁOSOWANIE NA {gold}{0}",