From 5bf966f9cd0a120220cc169c34469e64bcf3ef0e Mon Sep 17 00:00:00 2001 From: Dawid Bepierszcz <41084667+daffyyyy@users.noreply.github.com> Date: Wed, 21 Feb 2024 13:14:46 +0100 Subject: [PATCH] 1.3.3a - Fixed godmode - Added logging commands to simpleadmin logs file - Fixed votes? - Added updating player_ip and player_name after connect with ban issued by css_addban --- CS2-SimpleAdmin.cs | 5 ++- CS2-SimpleAdmin.csproj | 2 +- Commands/basebans.cs | 9 +++++ Commands/basechat.cs | 10 ++++++ Commands/basecommands.cs | 37 +++++++++++++++------ Commands/basecomms.cs | 18 ++++++++++ Commands/basevotes.cs | 18 ++++++---- Commands/funcommands.cs | 6 ++++ Commands/playercommands.cs | 42 +++++++++++++++++++----- Events.cs | 67 +++++++++++++++++--------------------- Helper.cs | 41 +++++++++++++++++++---- Managers/BanManager.cs | 20 ++++++++++-- Managers/MuteManager.cs | 4 +-- README.md | 2 +- lang/pt-BR.json | 8 ++--- lang/ru.json | 10 +++--- 16 files changed, 212 insertions(+), 87 deletions(-) diff --git a/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin.cs index 2d8fdb0..44148a7 100644 --- a/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin.cs @@ -12,14 +12,13 @@ namespace CS2_SimpleAdmin; -[MinimumApiVersion(163)] +[MinimumApiVersion(168)] public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig { public static CS2_SimpleAdmin Instance { get; private set; } = new(); public static IStringLocalizer? _localizer; public static Dictionary voteAnswers = new Dictionary(); - public static HashSet votePlayers = new HashSet(); public static ConcurrentBag godPlayers = new ConcurrentBag(); public static ConcurrentBag silentPlayers = new ConcurrentBag(); public static ConcurrentBag bannedPlayers = new ConcurrentBag(); @@ -39,7 +38,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig "CS2-SimpleAdmin"; public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)"; public override string ModuleAuthor => "daffyy & Dliix66"; - public override string ModuleVersion => "1.3.2b"; + public override string ModuleVersion => "1.3.3a"; public CS2_SimpleAdminConfig Config { get; set; } = new(); diff --git a/CS2-SimpleAdmin.csproj b/CS2-SimpleAdmin.csproj index 35ac26b..f4ee3ba 100644 --- a/CS2-SimpleAdmin.csproj +++ b/CS2-SimpleAdmin.csproj @@ -10,7 +10,7 @@ - + diff --git a/Commands/basebans.cs b/Commands/basebans.cs index 74fc251..994892f 100644 --- a/Commands/basebans.cs +++ b/Commands/basebans.cs @@ -58,6 +58,7 @@ public void OnBanCommand(CCSPlayerController? caller, CommandInfo command) internal void Ban(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, BanManager? banManager = null) { if (_database == null) return; + callerName ??= caller == null ? "Console" : caller.PlayerName; banManager ??= new BanManager(_database, Config); @@ -80,6 +81,8 @@ internal void Ban(CCSPlayerController? caller, CCSPlayerController player, int t IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, $"css_ban {player?.SteamID} {time} {reason}"); + Task.Run(async () => { await banManager.BanPlayer(playerInfo, adminInfo, reason, time); @@ -177,6 +180,8 @@ public void OnAddBanCommand(CCSPlayerController? caller, CommandInfo command) IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, command); + List matches = Helper.GetPlayerFromSteamid64(steamid); if (matches.Count == 1) { @@ -281,6 +286,8 @@ public void OnBanIp(CCSPlayerController? caller, CommandInfo command) IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, command); + int.TryParse(command.GetArg(2), out int time); if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) @@ -375,6 +382,8 @@ public void OnUnbanCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + string pattern = command.GetArg(1); Database database = new Database(dbConnectionString); diff --git a/Commands/basechat.cs b/Commands/basechat.cs index 1690274..ffa81b7 100644 --- a/Commands/basechat.cs +++ b/Commands/basechat.cs @@ -27,6 +27,8 @@ public void OnAdminToAdminSayCommand(CCSPlayerController? caller, CommandInfo co _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]); string utf8String = Encoding.UTF8.GetString(utf8BytesString); @@ -58,6 +60,8 @@ public void OnAdminSayCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) @@ -78,6 +82,8 @@ public void OnAdminPrivateSayCommand(CCSPlayerController? caller, CommandInfo co if (targets == null) return; List playersToTarget = targets!.Players.Where(player => player != null && player.IsValid && player.SteamID.ToString().Length == 17 && !player.IsHLTV).ToList(); + Helper.LogCommand(caller, command); + int range = command.GetArg(0).Length + command.GetArg(1).Length + 2; string message = command.GetCommandString[range..]; @@ -107,6 +113,8 @@ public void OnAdminCenterSayCommand(CCSPlayerController? caller, CommandInfo com _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + Helper.PrintToCenterAll(Helper.ReplaceTags(utf8String)); } @@ -125,6 +133,8 @@ public void OnAdminHudSayCommand(CCSPlayerController? caller, CommandInfo comman _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + VirtualFunctions.ClientPrintAll( HudDestination.Alert, Helper.ReplaceTags(utf8String), diff --git a/Commands/basecommands.cs b/Commands/basecommands.cs index 715bdf7..24f7de9 100644 --- a/Commands/basecommands.cs +++ b/Commands/basecommands.cs @@ -116,6 +116,8 @@ public void AddAdmin(CCSPlayerController? caller, string steamid, string name, s AdminSQLManager _adminManager = new(_database); _ = _adminManager.AddAdminBySteamId(steamid, name, flags, immunity, time, globalAdmin); + Helper.LogCommand(caller, $"css_addadmin {steamid} {name} {flags} {immunity} {time}"); + string msg = $"Added '{flags}' flags to '{name}' ({steamid})"; if (command != null) command.ReplyToCommand(msg); @@ -171,6 +173,8 @@ public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool global } }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + Helper.LogCommand(caller, $"css_deladmin {steamid}"); + string msg = $"Removed flags from '{steamid}'"; if (command != null) command.ReplyToCommand(msg); @@ -195,6 +199,7 @@ public void OnRelAdminCommand(CCSPlayerController? caller, CommandInfo command) public void ReloadAdmins() { if (_database == null) return; + foreach (SteamID steamId in AdminSQLManager._adminCache.Keys.ToList()) { if (AdminSQLManager._adminCache.TryRemove(steamId, out _)) @@ -216,6 +221,8 @@ public void OnHideCommand(CCSPlayerController? caller, CommandInfo command) { if (caller == null) return; + Helper.LogCommand(caller, command); + if (silentPlayers.Contains(caller.Slot)) { RemoveFromConcurrentBag(silentPlayers, caller.Slot); @@ -226,16 +233,14 @@ public void OnHideCommand(CCSPlayerController? caller, CommandInfo command) { silentPlayers.Add(caller.Slot); Server.ExecuteCommand("sv_disable_teamselect_menu 1"); - Server.NextFrame(() => - { - if (caller.PlayerPawn.Value != null && caller.PawnIsAlive) - caller.PlayerPawn.Value.CommitSuicide(true, false); - AddTimer(1.0f, () => { caller.ChangeTeam(CsTeam.Spectator); }, 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!"); - AddTimer(1.22f, () => { Server.ExecuteCommand("sv_disable_teamselect_menu 0"); }); - }); + if (caller.PlayerPawn.Value != null && caller.PawnIsAlive) + caller.PlayerPawn.Value.CommitSuicide(true, false); + + AddTimer(1.0f, () => { Server.NextFrame(() => caller.ChangeTeam(CsTeam.Spectator)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + AddTimer(1.4f, () => { Server.NextFrame(() => caller.ChangeTeam(CsTeam.None)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + caller.PrintToChat($"You are hidden now!"); + AddTimer(2.0f, () => { Server.NextFrame(() => Server.ExecuteCommand("sv_disable_teamselect_menu 0")); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); } } @@ -390,6 +395,8 @@ public void Kick(CCSPlayerController? caller, CCSPlayerController player, string player.Pawn.Value!.Freeze(); } + Helper.LogCommand(caller, $"css_kick {player.PlayerName} {reason}"); + if (string.IsNullOrEmpty(reason) == false) { if (!player.IsBot && !player.IsHLTV) @@ -450,6 +457,8 @@ public void ChangeMap(CCSPlayerController? caller, string map, CommandInfo? comm string commandName = command?.GetCommandString ?? "css_changemap"; _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", commandName])); } + if (command is not null) + Helper.LogCommand(caller, command); AddTimer(2.0f, () => { @@ -537,6 +546,8 @@ public void ChangeWorkshopMap(CCSPlayerController? caller, string map, CommandIn string commandName = command?.GetCommandString ?? "css_changewsmap"; _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", commandName])); } + if (command is not null) + Helper.LogCommand(caller, command); AddTimer(2.0f, () => { @@ -570,6 +581,8 @@ public void OnCvarCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + var value = command.GetArg(2); Server.ExecuteCommand($"{cvar.Name} {value}"); @@ -591,6 +604,8 @@ public void OnRconCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + Server.ExecuteCommand(command.ArgString); command.ReplyToCommand($"{callerName} executed command {command.ArgString}."); Logger.LogInformation($"{callerName} executed command ({command.ArgString})."); @@ -609,9 +624,11 @@ public void OnRestartCommand(CCSPlayerController? caller, CommandInfo command) public static void RestartGame(CCSPlayerController? admin) { + Helper.LogCommand(admin, "css_restartgame"); + // TODO: Localize var name = admin == null ? "Console" : admin.PlayerName; - Server.PrintToChatAll($"[SimpleAdmin] {name}: Restarting game..."); + Server.PrintToChatAll($"[SA] {name}: Restarting game..."); Server.ExecuteCommand("mp_restartgame 2"); } } diff --git a/Commands/basecomms.cs b/Commands/basecomms.cs index 51196cd..9481749 100644 --- a/Commands/basecomms.cs +++ b/Commands/basecomms.cs @@ -76,6 +76,8 @@ internal void Gag(CCSPlayerController? caller, CCSPlayerController player, int t IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, $"css_gag {player?.SteamID} {time} {reason}"); + Task.Run(async () => { await muteManager.MutePlayer(playerInfo, adminInfo, reason, time); @@ -179,6 +181,8 @@ public void OnAddGagCommand(CCSPlayerController? caller, CommandInfo command) IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, command); + List matches = Helper.GetPlayerFromSteamid64(steamid); if (matches.Count == 1) { @@ -264,6 +268,8 @@ public void OnUngagCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + bool found = false; string pattern = command.GetArg(1); @@ -405,6 +411,8 @@ internal void Mute(CCSPlayerController? caller, CCSPlayerController player, int IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, $"css_mute {player?.SteamID} {time} {reason}"); + player!.VoiceFlags = VoiceFlags.Muted; Task.Run(async () => @@ -483,6 +491,8 @@ public void OnAddMuteCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + int time = 0; string reason = "Unknown"; @@ -581,6 +591,8 @@ public void OnUnmuteCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + string pattern = command.GetArg(1); bool found = false; MuteManager _muteManager = new(_database); @@ -711,6 +723,8 @@ internal void Silence(CCSPlayerController? caller, CCSPlayerController player, i IpAddress = caller?.IpAddress?.Split(":")[0] }; + Helper.LogCommand(caller, $"css_silence {player?.SteamID} {time} {reason}"); + Task.Run(async () => { await muteManager.MutePlayer(playerInfo, adminInfo, reason, time, 2); @@ -797,6 +811,8 @@ public void OnAddSilenceCommand(CCSPlayerController? caller, CommandInfo command _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + int time = 0; string reason = "Unknown"; @@ -898,6 +914,8 @@ public void OnUnsilenceCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + string pattern = command.GetArg(1); bool found = false; MuteManager _muteManager = new(_database); diff --git a/Commands/basevotes.cs b/Commands/basevotes.cs index ed27152..2cff60d 100644 --- a/Commands/basevotes.cs +++ b/Commands/basevotes.cs @@ -26,6 +26,8 @@ public void OnVoteCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + voteAnswers.Clear(); string question = command.GetArg(1); @@ -33,25 +35,30 @@ public void OnVoteCommand(CCSPlayerController? caller, CommandInfo command) if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { - ChatMenu voteMenu = new(_localizer!["sa_admin_vote_menu_title", question]); - for (int i = 2; i <= answersCount - 1; i++) { voteAnswers.Add(command.GetArg(i), 0); - voteMenu.AddMenuOption(command.GetArg(i), Helper.HandleVotes); } foreach (CCSPlayerController _player in Helper.GetValidPlayers()) { using (new WithTemporaryCulture(_player.GetLanguage())) { + ChatMenu voteMenu = new(_localizer!["sa_admin_vote_menu_title", question]); + + for (int i = 2; i <= answersCount - 1; i++) + { + voteMenu.AddMenuOption(command.GetArg(i), Helper.HandleVotes); + } + + voteMenu.PostSelectAction = PostSelectAction.Close; + MenuManager.OpenChatMenu(_player, voteMenu); + 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); } voteInProgress = true; @@ -84,7 +91,6 @@ public void OnVoteCommand(CCSPlayerController? caller, CommandInfo command) } } voteAnswers.Clear(); - votePlayers.Clear(); voteInProgress = false; }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); } diff --git a/Commands/funcommands.cs b/Commands/funcommands.cs index 321ff15..906dfa2 100644 --- a/Commands/funcommands.cs +++ b/Commands/funcommands.cs @@ -41,6 +41,8 @@ public void NoClip(CCSPlayerController? caller, CCSPlayerController player, stri callerName ??= caller == null ? "Console" : caller.PlayerName; player!.Pawn.Value!.ToggleNoclip(); + Helper.LogCommand(caller, $"css_noclip {player?.PlayerName}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -90,6 +92,8 @@ public void Freeze(CCSPlayerController? caller, CCSPlayerController player, int player!.Pawn.Value!.Freeze(); + Helper.LogCommand(caller, $"css_freeze {player?.PlayerName}"); + if (time > 0) AddTimer(time, () => player.Pawn.Value!.Unfreeze(), CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); @@ -138,6 +142,8 @@ public void Unfreeze(CCSPlayerController? caller, CCSPlayerController player, st player!.Pawn.Value!.Unfreeze(); + Helper.LogCommand(caller, $"css_unfreeze {player?.PlayerName}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) diff --git a/Commands/playercommands.cs b/Commands/playercommands.cs index 3a67f15..d7c0eaa 100644 --- a/Commands/playercommands.cs +++ b/Commands/playercommands.cs @@ -8,7 +8,6 @@ using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; -using System.Collections.Concurrent; using System.Text; namespace CS2_SimpleAdmin @@ -47,6 +46,8 @@ public void Slay(CCSPlayerController? caller, CCSPlayerController player, string player.CommitSuicide(false, true); + Helper.LogCommand(caller, $"css_slay {player?.PlayerName}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -114,14 +115,18 @@ public void OnGiveCommand(CCSPlayerController? caller, CommandInfo command) public void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, CsItem weapon, string? callerName = null) { - player.GiveNamedItem(weapon); - SubGiveWeapon(caller, player, weapon.ToString(), callerName); + Helper.LogCommand(caller, $"css_give {player?.PlayerName} {weapon.ToString()}"); + + player?.GiveNamedItem(weapon); + SubGiveWeapon(caller, player!, weapon.ToString(), callerName); } public void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null) { - player.GiveNamedItem(weaponName); - SubGiveWeapon(caller, player, weaponName, callerName); + Helper.LogCommand(caller, $"css_give {player?.PlayerName} {weaponName}"); + + player?.GiveNamedItem(weaponName); + SubGiveWeapon(caller, player!, weaponName, callerName); } public void SubGiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null) @@ -177,6 +182,8 @@ public void StripWeapons(CCSPlayerController? caller, CCSPlayerController player player.RemoveWeapons(); + Helper.LogCommand(caller, $"css_strip {player?.PlayerName}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -229,6 +236,8 @@ public void SetHp(CCSPlayerController? caller, CCSPlayerController player, int h player.SetHp(health); + Helper.LogCommand(caller, $"css_hp {player?.PlayerName} {health}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -281,6 +290,8 @@ public void SetSpeed(CCSPlayerController? caller, CCSPlayerController player, do player.SetSpeed((float)speed); + Helper.LogCommand(caller, $"css_speed {player?.PlayerName} {speed}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -288,7 +299,7 @@ public void SetSpeed(CCSPlayerController? caller, CCSPlayerController player, do using (new WithTemporaryCulture(_player.GetLanguage())) { StringBuilder sb = new(_localizer!["sa_prefix"]); - sb.Append(_localizer["sa_admin_speed_message", callerName, player.PlayerName]); + sb.Append(_localizer["sa_admin_speed_message", callerName, player!.PlayerName]); _player.PrintToChat(sb.ToString()); } } @@ -330,13 +341,15 @@ public void God(CCSPlayerController? caller, CCSPlayerController player, string? if (player != null) { + Helper.LogCommand(caller, $"css_god {player.PlayerName}"); + if (!godPlayers.Contains(player.Slot)) { godPlayers.Add(player.Slot); } else { - godPlayers = new ConcurrentBag(godPlayers.Where(item => item != player.Slot)); + RemoveFromConcurrentBag(godPlayers, player.Slot); } if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) @@ -395,6 +408,8 @@ public void Slap(CCSPlayerController? caller, CCSPlayerController player, int da callerName ??= caller == null ? "Console" : caller.PlayerName; player!.Pawn.Value!.Slap(damage); + Helper.LogCommand(caller, $"css_slap {player?.PlayerName} {damage}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -456,9 +471,12 @@ public void OnTeamCommand(CCSPlayerController? caller, CommandInfo command) } bool kill = command.GetArg(3).ToLower().Equals("-k"); + + Helper.LogCommand(caller, command); + playersToTarget.ForEach(player => { - ChangeTeam(caller, player, _teamName.ToLower(), teamNum, kill, callerName); + ChangeTeam(caller, player, _teamName, teamNum, kill, callerName); }); } @@ -527,6 +545,8 @@ public void OnRenameCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + playersToTarget.ForEach(player => { if (!player.IsBot && player.SteamID.ToString().Length != 17) @@ -591,6 +611,8 @@ public void Respawn(CCSPlayerController? caller, CCSPlayerController player, str VirtualFunction.CreateVoid(player.Handle, GameData.GetOffset("CCSPlayerController_Respawn"))(player); + Helper.LogCommand(caller, $"css_respawn {player.PlayerName}"); + if (caller == null || caller != null && !silentPlayers.Contains(caller.Slot)) { foreach (CCSPlayerController _player in Helper.GetValidPlayers()) @@ -629,6 +651,8 @@ public void OnGotoCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + playersToTarget.ForEach(player => { if (!player.IsBot && player.SteamID.ToString().Length != 17 || !player.PawnIsAlive) @@ -683,6 +707,8 @@ public void OnBringCommand(CCSPlayerController? caller, CommandInfo command) _discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(_localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); } + Helper.LogCommand(caller, command); + playersToTarget.ForEach(player => { if (!player.IsBot && player.SteamID.ToString().Length != 17 || !player.PawnIsAlive) diff --git a/Events.cs b/Events.cs index 3128cce..2a6c4ec 100644 --- a/Events.cs +++ b/Events.cs @@ -206,7 +206,6 @@ public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo PlayerPenaltyManager playerPenaltyManager = new PlayerPenaltyManager(); playerPenaltyManager.RemoveAllPenalties(player.Slot); - //RemoveFromConcurrentBag(gaggedPlayers, player.Slot); RemoveFromConcurrentBag(silentPlayers, player.Slot); RemoveFromConcurrentBag(godPlayers, player.Slot); @@ -226,7 +225,6 @@ public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo private void OnMapStart(string mapName) { Random random = new Random(); - //gaggedPlayers.Clear(); godPlayers.Clear(); silentPlayers.Clear(); @@ -290,7 +288,7 @@ private void OnMapStart(string mapName) TagsDetected = true; } - AddTimer(2.0f, async () => + AddTimer(3.0f, async () => { string? address = $"{ConVar.Find("ip")!.StringValue}:{ConVar.Find("hostport")!.GetPrimitiveValue()}"; string? hostname = ConVar.Find("hostname")!.StringValue; @@ -300,68 +298,63 @@ await Task.Run(async () => AdminSQLManager _adminManager = new(_database); try { - await using (var connection = await _database.GetConnectionAsync()) - { - bool addressExists = await connection.ExecuteScalarAsync( - "SELECT COUNT(*) FROM sa_servers WHERE address = @address", - new { address }); + await using var connection = await _database.GetConnectionAsync(); + bool addressExists = await connection.ExecuteScalarAsync( + "SELECT COUNT(*) FROM sa_servers WHERE address = @address", + new { 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 }); - } + 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 }); + } - int? serverId = await connection.ExecuteScalarAsync( - "SELECT `id` FROM `sa_servers` WHERE `address` = @address", - new { address }); + int? serverId = await connection.ExecuteScalarAsync( + "SELECT `id` FROM `sa_servers` WHERE `address` = @address", + new { address }); - ServerId = serverId; - } + ServerId = serverId; } catch (Exception) { - if (_logger != null) - _logger.LogCritical("Unable to create or get server_id"); + _logger?.LogCritical("Unable to create or get server_id"); } + await _adminManager.GiveAllFlags(); }); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); - AddTimer(2.0f, () => + AddTimer(3.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] - private HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) + public HookResult OnPlayerHurt(EventPlayerHurt @event, GameEventInfo info) { CCSPlayerController? player = @event.Userid; - 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) + if (player is null || @event.Attacker is null || (LifeState_t)player.LifeState != LifeState_t.LIFE_ALIVE || player.PlayerPawn.Value == null + || player.Connected != PlayerConnectedState.PlayerConnected) return HookResult.Continue; - if (godPlayers.Contains(player.Slot) && player.PawnIsAlive) + if (godPlayers.Contains(player.Slot)) { - player.Health = 100; - player.PlayerPawn.Value.Health = 100; + player.PlayerPawn.Value.Health = player.PlayerPawn.Value.MaxHealth; + player.PlayerPawn.Value.ArmorValue = 100; } return HookResult.Continue; diff --git a/Helper.cs b/Helper.cs index f898e8b..2fdce99 100644 --- a/Helper.cs +++ b/Helper.cs @@ -1,12 +1,14 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Cvars; using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Utils; using Discord; +using Microsoft.Extensions.Logging; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; @@ -135,12 +137,37 @@ internal static string ReplaceTags(string message) internal static void HandleVotes(CCSPlayerController player, ChatMenuOption option) { - if (CS2_SimpleAdmin.voteInProgress && !CS2_SimpleAdmin.votePlayers.Contains(player.Slot)) - { - option.Disabled = true; - CS2_SimpleAdmin.votePlayers.Add(player.Slot); - CS2_SimpleAdmin.voteAnswers[option.Text]++; - } + if (!CS2_SimpleAdmin.voteInProgress) + return; + + option.Disabled = true; + CS2_SimpleAdmin.voteAnswers[option.Text]++; + } + + internal static void LogCommand(CCSPlayerController? caller, CommandInfo command) + { + if (CS2_SimpleAdmin.Instance == null || CS2_SimpleAdmin._localizer == null) + return; + + string playerName = caller?.PlayerName ?? "Console"; + + string? hostname = ConVar.Find("hostname")!.StringValue ?? "Unknown"; + + CS2_SimpleAdmin.Instance.Logger.LogInformation($"{CS2_SimpleAdmin._localizer["sa_discord_log_command", + playerName, command.GetCommandString]}".Replace("HOSTNAME", hostname).Replace("**", "")); + } + + internal static void LogCommand(CCSPlayerController? caller, string command) + { + if (CS2_SimpleAdmin.Instance == null || CS2_SimpleAdmin._localizer == null) + return; + + string playerName = caller?.PlayerName ?? "Console"; + + string? hostname = ConVar.Find("hostname")!.StringValue ?? "Unknown"; + + CS2_SimpleAdmin.Instance.Logger.LogInformation($"{CS2_SimpleAdmin._localizer["sa_discord_log_command", + playerName, command]}".Replace("HOSTNAME", hostname).Replace("**", "")); } public static IEnumerable GenerateEmbedsDiscord(string title, string description, string thumbnailUrl, Color color, string[] fieldNames, string[] fieldValues, bool[] inlineFlags) @@ -206,7 +233,7 @@ public unsafe void Set(string str) private static byte[] GetStringBytes(string str) { - return Encoding.ASCII.GetBytes(str); + return Encoding.UTF8.GetBytes(str); } } } \ No newline at end of file diff --git a/Managers/BanManager.cs b/Managers/BanManager.cs index 0a317ad..a460ac4 100644 --- a/Managers/BanManager.cs +++ b/Managers/BanManager.cs @@ -101,19 +101,33 @@ public async Task IsPlayerBanned(PlayerInfo player) 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; + DateTime currentTime = DateTime.Now; + try { + string sql = @" + UPDATE sa_bans + SET player_ip = CASE WHEN player_ip IS NULL THEN @PlayerIP ELSE player_ip END, + player_name = CASE WHEN player_name IS NULL THEN @PlayerName ELSE player_name END + WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) + AND status = 'ACTIVE' + AND (duration = 0 OR ends > @CurrentTime); + + SELECT COUNT(*) FROM sa_bans + WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) + AND status = 'ACTIVE' + AND (duration = 0 OR ends > @CurrentTime);"; + await using var connection = await _database.GetConnectionAsync(); var parameters = new { PlayerSteamID = player.SteamId, PlayerIP = !string.IsNullOrEmpty(player.IpAddress) ? player.IpAddress : (object)DBNull.Value, - CurrentTime = currentTimeUtc + PlayerName = !string.IsNullOrEmpty(player.Name) ? player.Name : string.Empty, + CurrentTime = currentTime }; banCount = await connection.ExecuteScalarAsync(sql, parameters); diff --git a/Managers/MuteManager.cs b/Managers/MuteManager.cs index 85ed992..b384cf4 100644 --- a/Managers/MuteManager.cs +++ b/Managers/MuteManager.cs @@ -93,10 +93,10 @@ public async Task> IsPlayerMuted(string steamId) try { await using var connection = await _database.GetConnectionAsync(); - DateTime currentTimeUtc = DateTime.UtcNow; + DateTime currentTime = DateTime.Now; 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 parameters = new { PlayerSteamID = steamId, CurrentTime = currentTime }; var activeMutes = (await connection.QueryAsync(sql, parameters)).ToList(); return activeMutes; } diff --git a/README.md b/README.md index b819d36..4dc8bbd 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Manage your Counter-Strike 2 server by simple commands :) ``` ### Requirments -- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp/) **tested on v166** +- [CounterStrikeSharp](https://github.com/roflmuffin/CounterStrikeSharp/) **tested on v168** - MySQL **tested on MySQL (MariaDB) Server version: 10.11.4-MariaDB-1~deb12u1 Debian 12** diff --git a/lang/pt-BR.json b/lang/pt-BR.json index 2442ed1..722fe3a 100644 --- a/lang/pt-BR.json +++ b/lang/pt-BR.json @@ -1,6 +1,6 @@ { "sa_prefix": "{lightred}[SA] {default}", - "sa_adminhelp": "{GREEN}[ CS2-SimpleAdmin HELP ]{DEFAULT}\n- css_who <#userid or name> - Mostrar inpormações sobre o player\n- css_players - Mostrar a lista de players\n- css_ban <#userid or name> [time in minutos/0 perm] [reason] - Ban player\n- css_addban [time in minutos/0 perm] [reason] - Banir o player através do steamid64\n- css_banip [time in minutos/0 perm] [reason] - Banir o player através do endereço IP\n- css_unban - Desbanir o player\n- css_kick <#userid or name> [reason] - Kikar player\n- css_gag <#userid or name> [time in minutos/0 perm] [reason] - Mutar pelo chat o player\n- css_addgag [time in minutos/0 perm] [reason] - Mutar pelo chat o player pelo steamid64\n- css_unmute - Desmutar pelo chat o player\n- css_mute <#userid or name> [time in minutos/0 perm] [reason] - Mutar na voice o player\n- css_addmute [time in minutos/0 perm] [reason] - Mutar na voice o player pelo steamid64\n- css_give <#userid or name> - Dar arma a um player\n- css_strip <#userid or name> - Tirar arma de um player\n- css_hp <#userid or name> [health] - Setar vida de um player\n- css_god <#userid or name> - Alternar god no player\n- css_slay <#userid or name> - Matar player\n- css_slap <#userid or name> [damage] - Dâ uns tapa no player\n- css_vote <'Question?'> ['Answer1'] ['Answer2'] ... - Criar votação (pool)\n- css_map - Mudar mapa\n- css_wsmap - Mudar mapa da workshop\n- css_asay - Mandar mensagem para todos os Admins\n- css_say - Manda uma mensagem em modo adm no chat\n- css_psay <#userid or name> - Manda uma mensagem privada para um player\n- css_csay - Manda uma mensagem em modo admin de centro\n- css_hsay - Manda uma mensagem em modo admin no HUD\n- css_noclip <#userid or name> - Alternar Noclip em player\n- css_freeze <#userid or name> [duration] - Congela um player\n- css_unfreeze <#userid or name> - Descongela um player\n- css_respawn <#userid or name> - Respawna um player\n- css_cvar - Muda valor de cvar\n- css_rcon - Executar comando como servidor", + "sa_adminhelp": "{GREEN}[ CS2-SimpleAdmin HELP ]{DEFAULT}\n- css_who <#userid or name> - Mostrar inpormações sobre o player\n- css_players - Mostrar a lista de players\n- css_ban <#userid or name> [time in minutos/0 perm] [reason] - Ban player\n- css_addban [time in minutos/0 perm] [reason] - Banir o player através do steamid64\n- css_banip [time in minutos/0 perm] [reason] - Banir o player através do endereço IP\n- css_unban - Desbanir o player\n- css_kick <#userid or name> [reason] - Kikar player\n- css_gag <#userid or name> [time in minutos/0 perm] [reason] - Mutar pelo chat o player\n- css_addgag [time in minutos/0 perm] [reason] - Mutar pelo chat o player pelo steamid64\n- css_unmute - Desmutar pelo chat o player\n- css_mute <#userid or name> [time in minutos/0 perm] [reason] - Mutar na voice o player\n- css_addmute [time in minutos/0 perm] [reason] - Mutar na voice o player pelo steamid64\n- css_give <#userid or name> - Dar arma a um player\n- css_strip <#userid or name> - Tirar arma de um player\n- css_hp <#userid or name> [health] - Setar vida de um player\n- css_god <#userid or name> - Alternar god no player\n- css_slay <#userid or name> - Matar player\n- css_slap <#userid or name> [damage] - Dâ uns tapa no player\n-<'Question?'> [ 'Answer1' ] ['Answer2'] ... - Criar votação (pool)\n- css_map - Mudar mapa\n- css_wsmap - Mudar mapa da workshop\n- css_asay - Mandar mensagem para todos os Admins\n- css_say - Manda uma mensagem em modo adm no chat\n- css_psay <#userid or name> - Manda uma mensagem privada para um player\n- css_csay - Manda uma mensagem em modo admin de centro\n- css_hsay - Manda uma mensagem em modo admin no HUD\n- css_noclip <#userid or name> - Alternar Noclip em player\n- css_freeze <#userid or name> [duration] - Congela um player\n- css_unfreeze <#userid or name> - Descongela um player\n- css_respawn <#userid or name> - Respawna um player\n- css_cvar - Muda valor de cvar\n- css_rcon - Executar comando como servidor", "sa_player_ban_message_time": "Você foi banido por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!", "sa_player_ban_message_perm": "Você foi banido permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!", "sa_player_kick_message": "Você foi kikado por {lightred}{0}{default} por {lightred}{1}{default}!", @@ -9,7 +9,7 @@ "sa_player_mute_message_time": "Você foi mutado na voice por {lightred}{0}{default} por {lightred}{1}{default} minutos por {lightred}{2}{default}!", "sa_player_mute_message_perm": "Você foi mutado na voice permanentemente por {lightred}{0}{default} por {lightred}{1}{default}!", "sa_player_silence_message_time": "Você foi silenciado por {lightred}{0}{default} por {lightred}{1}{default} minutos pelo {green}Admin {lightred}{2}{default}!", - "sa_player_silence_message_perm": "Você foi sileciado permanentemente por {lightred}{0}{default} pelo {green}Admin {lightred}{1}{default}!", + "sa_player_silence_message_perm": "Você foi sileciado permanentemente por {lightred}{0}{default} pelo {green}Admin {lightred}{1}{default}!", "sa_admin_ban_message_time": "Admin {lightred}{0}{default} baniu {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!", "sa_admin_ban_message_perm": "Admin {lightred}{0}{default} baniu {lightred}{1}{default} permanentemente por {lightred}{2}{default}!", "sa_admin_kick_message": "Admin {lightred}{0}{default} kikou {lightred}{1}{default} por {lightred}{2}{default}!", @@ -18,7 +18,7 @@ "sa_admin_mute_message_time": "Admin {lightred}{0}{default} mutou na voice {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!", "sa_admin_mute_message_perm": "Admin {lightred}{0}{default} mutou na voice {lightred}{1}{default} permanentemente por {lightred}{2}{default}!", "sa_admin_silence_message_time": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} por {lightred}{2}{default} por {lightred}{3}{default} minutos!", - "sa_admin_silence_message_perm": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} permanentemente por {lightred}{2}{default}!", + "sa_admin_silence_message_perm": "Admin {lightred}{0}{default} silenciou {lightred}{1}{default} permanentemente por {lightred}{2}{default}!", "sa_admin_give_message": "Admin {lightred}{0}{default} deu a arma {lightred}{1}{default} para {lightred}{2}{default}!", "sa_admin_strip_message": "Admin {lightred}{0}{default} {lightred}removeu {default}a arma do player {lightred}{1}{default}!", "sa_admin_hp_message": "Admin {lightred}{0}{default} mudou a {lightred}quantidade de HP {default}de {lightred}{1}{default}!", @@ -30,7 +30,7 @@ "sa_admin_noclip_message": "Admin {lightred}{0}{default} alternou o {lightred}noclip {default}em {lightred}{1}{default}!", "sa_admin_freeze_message": "Admin {lightred}{0}{default} congelou {lightred}{1}{default}!", "sa_admin_unfreeze_message": "Admin {lightred}{0}{default} descongelou {lightred}{1}{default}!", - "sa_admin_rename_message": "Admin {lightred}{0}{default} mudou o nickname de {lightred}{1}{default} para {lightred}{2}{default}!", + "sa_admin_rename_message": "Admin {lightred}{0}{default} mudou o nickname de {lightred}{1}{default} para {lightred}{2}{default}!", "sa_admin_respawn_message": "Admin {lightred}{0}{default} respawnou {lightred}{1}{default}!", "sa_admin_tp_message": "Admin {lightred}{0}{default} teleleportou para {lightred}{1}{default}!", "sa_admin_bring_message": "Admin {lightred}{0}{default} teleportou para si {lightred}{1}{default}!", diff --git a/lang/ru.json b/lang/ru.json index 91b3622..3840997 100644 --- a/lang/ru.json +++ b/lang/ru.json @@ -8,8 +8,8 @@ "sa_player_gag_message_perm": "Администратор {lightred}{1}{default} выдал вам мут чата навсегда по причине {lightred}{0}{default}!", "sa_player_mute_message_time": "Администратор {lightred}{2}{default} выдал вам мут голоса по причине {lightred}{0}{default} на {lightred}{1}{default} минут!", "sa_player_mute_message_perm": "Администратор {lightred}{1}{default} выдал вам мут голоса навсегда по причине {lightred}{0}{default}!", - "sa_player_silence_message_time": "Вы были замьючены на {lightred}{0}{default} на {lightred}{1}{default} минут {lightred}{2}{default}!", - "sa_player_silence_message_perm": "Вы были замьючены навсегда для {lightred}{0}{default} по причине {lightred}{1}{default}!", + "sa_player_silence_message_time": "Вы были замьючены на {lightred}{0}{default} на {lightred}{1}{default} минут {lightred}{2}{default}!", + "sa_player_silence_message_perm": "Вы были замьючены навсегда для {lightred}{0}{default} по причине {lightred}{1}{default}!", "sa_admin_ban_message_time": "Администратор {lightred}{0}{default} забанил {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут!", "sa_admin_ban_message_perm": "Администратор {lightred}{0}{default} забанил {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!", "sa_admin_kick_message": "Администратор {lightred}{0}{default} кикнул {lightred}{1}{default} по причине {lightred}{2}{default}!", @@ -18,7 +18,7 @@ "sa_admin_mute_message_time": "Администратор {lightred}{0}{default} выдал бан чата {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут!", "sa_admin_mute_message_perm": "Администратор {lightred}{0}{default} выдал бан чата {lightred}{1}{default} навсегда игроку {lightred}{2}{default}!", "sa_admin_silence_message_time": "Администратор {lightred}{0}{default} заглушил {lightred}{1}{default} по причине {lightred}{2}{default} на {lightred}{3}{default} минут", - "sa_admin_silence_message_perm": "Администратор {lightred}{0}{default} заглушил {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!", + "sa_admin_silence_message_perm": "Администратор {lightred}{0}{default} заглушил {lightred}{1}{default} навсегда по причине {lightred}{2}{default}!", "sa_admin_give_message": "Администратор {lightred}{0}{default} присвоил {lightred}{1}{default} значение {lightred}{2}{default}!", "sa_admin_strip_message": "Администратор {lightred}{0}{default} забрал у игрока {lightred}{1}{default} всё оружие!", "sa_admin_hp_message": "Администратор {lightred}{0}{default} измененил {lightred}{1}{default} количество здоровья{default}!", @@ -30,7 +30,7 @@ "sa_admin_noclip_message": "Администратор {lightred}{0}{default} переключил режим полета для {lightred}{1}{default}!", "sa_admin_freeze_message": "Администратор {lightred}{0}{default} заморозил {lightred}{1}{default}!", "sa_admin_unfreeze_message": "Администратор {lightred}{0}{default} разморозил {lightred}{1}{default}!", - "sa_admin_rename_message": "Администратор {lightred}{0}{default} изменил ник {lightred}{1}{default} на {lightred}{2}{default}!", + "sa_admin_rename_message": "Администратор {lightred}{0}{default} изменил ник {lightred}{1}{default} на {lightred}{2}{default}!", "sa_admin_respawn_message": "Администратор {lightred}{0}{default} заспавнил {lightred}{1}{default}!", "sa_admin_team_message": "Администратор {lightred}{0}{default} переместил {lightred}{1}{default} в {lightred}{2}{default}!", "sa_admin_vote_menu_title": "{lime}ГОЛОСУЙ ЗА {gold}{0}", @@ -40,7 +40,7 @@ "sa_adminsay_prefix": "{RED}ADMIN: {lightred}{0}{default}", "sa_adminchat_template_admin": "{LIME}(ADMIN) {lightred}{0}{default}: {lightred}{1}{default}", "sa_admin_tp_message": "Администратор {lightred}{0}{default} телепортировался к {lightred}{1}{default}!", - "sa_admin_bring_message": "Администратор {lightred}{0}{default} телепортировал к себе {lightred}{1}{default}!", + "sa_admin_bring_message": "Администратор {lightred}{0}{default} телепортировал к себе {lightred}{1}{default}!", "sa_adminchat_template_player": "{SILVER}(PLAYER) {lightred}{0}{default}: {lightred}{1}{default}", "sa_discord_log_command": "**{0}** отправил команду `{1}` на сервере `HOSTNAME`" } \ No newline at end of file