From 3f1b6b3bf74ab974e777f9495edf20a24c847764 Mon Sep 17 00:00:00 2001 From: Dawid Bepierszcz <41084667+daffyyyy@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:24:47 +0100 Subject: [PATCH] 1.7.1a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【UPDATE 1.7.1a】 :new: What's new and what's changed: - Fixed 2x player lock text - Added immunity check when using css_addX - MenuManagerCS2 has been updated - Added return of lock ID by api (check example_module) - Fixed reasons for locks, no longer need to use `“”` if there is a space in them - Improved handling of lock times, from now on you can use: -- 1mo - 1 month -- 1w - 1 week -- 1d - 1 day -- 1h - 1 hour -- 1m - 1 minute -- 1 - 1 minute You can also combine it, e.g: 10d5h - 10 days and 5 hours 2w3d - 2 weeks and 3 days 1w1d1h1 - 1 week, 1 day and 1 minute So for example css_ban player 10d5h Super reason for my ban - Added a `rcon_password` column in the `sa_servers` table that populates with the rcon password - Fixed `banid` and banning - Fixed too fast kick (it was caused by checking players online) :warning: **Remember to update all files + api** --- .../3rd_party/MenuManagerApi — old.dll | Bin 0 -> 4608 bytes CS2-SimpleAdmin/3rd_party/MenuManagerApi.dll | Bin 4608 -> 4608 bytes CS2-SimpleAdmin/Api/CS2_SimpleAdminApi.cs | 8 +- CS2-SimpleAdmin/CS2-SimpleAdmin.cs | 2 +- CS2-SimpleAdmin/Commands/RegisterCommands.cs | 6 +- CS2-SimpleAdmin/Commands/basebans.cs | 75 +++++---- CS2-SimpleAdmin/Commands/basecommands.cs | 143 ++++++++++++++---- CS2-SimpleAdmin/Commands/basecomms.cs | 111 ++++++++------ .../011_AddRconColumnToServersTable.sql | 1 + CS2-SimpleAdmin/Events.cs | 15 +- .../Extensions/PlayerExtensions.cs | 8 + CS2-SimpleAdmin/Helper.cs | 127 +++++++++++++--- CS2-SimpleAdmin/Managers/BanManager.cs | 54 ++++--- CS2-SimpleAdmin/Managers/MuteManager.cs | 49 ++++-- CS2-SimpleAdmin/Managers/PlayerManager.cs | 92 +++++------ CS2-SimpleAdmin/Managers/ServerManager.cs | 24 +-- CS2-SimpleAdmin/Managers/WarnManager.cs | 49 ++++-- CS2-SimpleAdmin/Menus/AdminMenu.cs | 4 +- CS2-SimpleAdmin/Menus/ReasonMenu.cs | 2 +- CS2-SimpleAdmin/VERSION | 2 +- CS2-SimpleAdminApi/ICS2-SimpleAdminApi.cs | 4 +- CS2-SimpleAdminApi/PlayerInfo.cs | 1 + .../CS2-SimpleAdminApi.dll | Bin 8192 -> 8192 bytes .../CS2-SimpleAdminApi.dll | Bin 8192 -> 8192 bytes .../CS2-SimpleAdmin_ExampleModule.cs | 8 +- 25 files changed, 532 insertions(+), 253 deletions(-) create mode 100644 CS2-SimpleAdmin/3rd_party/MenuManagerApi — old.dll create mode 100644 CS2-SimpleAdmin/Database/Migrations/011_AddRconColumnToServersTable.sql diff --git a/CS2-SimpleAdmin/3rd_party/MenuManagerApi — old.dll b/CS2-SimpleAdmin/3rd_party/MenuManagerApi — old.dll new file mode 100644 index 0000000000000000000000000000000000000000..c4f723a28a8c29c879d5badd5bcfebd3cd325d01 GIT binary patch literal 4608 zcmeHKU2Ggz75-+{yV*F7Ydb$msGt)ZX!#r2`D>Cksn=^eafmm@yKxI_v1ixU>#1jF zmYG>6egLcrgv3(>s1ia#LKP1Pit@uSfO)%{QWtRJuMe&fh3Uwq(xNKyw`s&$NI>4qq+fEz*+0@P(_> z6MX-jyv4wV$GxB?#ss=Bp8p`QTbO?t$8j);eUPjyr?iihj4A2bbl#F5#}fW&B)R5r z-dHnp_@TxdsGE=B6`JJmBmBz9;f8UP+Fcs|0z$v3@fWn@+nWBU9(#?r7r!-Mqm6++ z(&Oe5{p>UQ^pw)p5~YFfGrzwYrz8paF_23*WloaLBA5F(p2hse56tI?Ga12u(Dd6H z-z84qcD655-zEM8{z!ZrcZr|D+r&j=Y5!?0FB2D; z&DAZ#&@E1q%>`buK_SAV4gSH>5P#Shs zl~{fCbxr80Agrrc1n=z7 zE(W2(gsQb04X5U*Ld*$k?O34@MXFiz)+;j8mbl`C4HZxE*j3kpaCJ-3v7d51HLt>m z`8=qc_LqaO=}5AU_fV^1;4iz4cBt*PoXn}^va`%==2)R7{y|F)^pZXD7l1z=cy1a zEr4B*gRnDv!gU&c5XEji>WI>u*a=cbwwwyr+`5X=u3-4=NzE=hZ7+UUBPER+*%DQf zAT9kU@RXJmy&y`c@pc>sej-%T;|aOq=;rM-uHG8IzjV6t<6pi!{%Yy9k?PTx+vu?j zBcHKgWJwGT3fnIzo4@(o!dC`=*L$|-K0(f5^vG`O;pu`NIit*6K9d{l+hdtSXZjBe zoim0Cd#w!V!M=nOmqUe|WeoNW74k;9fj=bYWyL)BeCV`Ffj@b@u3FN*m6b5K78$hL zCG+5%fkSp_vLgGb&}w}$UHo%vr|l6s=-y63p31=DQ=Z!ypzbV%Yzj6{B7{eY3A%TC~{`EIt%*;ySU*dC%_laBjqm}3-S~+|b_cql!7hJ5E_N6Byf6mbljct0o_T`QJj%RP%wrOBq^5Z< zDUqKho=R@r_<7G?{+)cMrF#XEcjs;+XGWJ>Z84#(=HVcuAD4GZMV~&F5orBUedDW8 z>rfg|?;xgKKrVrsJykk27*k9um-5Ctcsi|ZMwoZmB>G`gt za;dV+*U4MBq+=`Ub3ZPqOAiXN=@qw7Axd$57+<9AkVt7hQsQ0iOY>O}O+ i?>?hnXJ!u{BlUidftCDUbThdMzsG`qKivPf0{;ORA)K55 literal 0 HcmV?d00001 diff --git a/CS2-SimpleAdmin/3rd_party/MenuManagerApi.dll b/CS2-SimpleAdmin/3rd_party/MenuManagerApi.dll index c4f723a28a8c29c879d5badd5bcfebd3cd325d01..3a47c6aa2f05c955957067f1c4009a546aae1ebe 100644 GIT binary patch delta 1251 zcmYL}T}&KR6vzMf&d%%y%XU8mrM7mqps*EbfuurO3>7R=#e%d=n;PT74(*1OA;@F4pY`pe!ovb7ke$BAG-w+Q=swmLSY1sgY^?UG8XthBf-Ev##n z;mI9XV~T~J@km&xh!Y&$r}+>{`?Oxr{9H$d_1qicc2R~Pj0a2-*iW68^IT|^+QLD( zU+)~!+X`lU#)nAADMpnic%EaJlEc(~Sk^wgh*PECdH^++Fs|t8RL6#}RI5=JqEU%MG8#27q>r~1QAh1! zy2LDV44vcK&f)(552(~dJ$X?Eah>IkkrtZB5K?3motnLxM>K~u$28Aqrb&S;*?=qL zP6YT%A&wwAsKR8NkD+uiif(p~p@*Rc9eM(N)JdK6v}PySinI7gbnsq$LN9?&$tQ7- zY{q@^S(qH{MiY4mE#v??$yaoIob1Om4vPUyVnLL&_LX4Q-h(QrG9RCxH+^q+b@P)>!J9VU@E@O;b8}9ivTA-P%)B$laF74*!CE3-b1tX}dMSJJ zRt{A9XBT9r3OQ?iU9IUKnu-=iQ7wKj&m@cP4kyo^tc{M0#@iLOP$ZC*8Ma(}nCr zHkU12Y`16Jf*#K}?>ISk*6HA-G}YBcK}F%1v3x@f6cx`Y*ynMxPAiv%6$ zVz&t)f}o^}4n|>xe?YBWbmL9Yost(4ND@L8UG&blit{nQdERHPNhm}NR*%tyUu z#Sf5rL9tso_m$qM#*VU)2)AL5Pf-$sgLF0Tqlui{q1Lpi1sU}{rtPn=QgUS^chZ1T zUQ1eouJ6JDgrZORVWP<-`BmvP#bx4pNoWpJ4UO4|f`~M$(@P_vedk^39@e8e^s3un zD1u>dWUIxCsFULiIi{o&QhtbA(Zw0kh&o(E8}f+;_9<2pio{)^7Lj`Av4E@AR zSm^U29aaQLITQ`-C7nTANk^t~vQY*W(jfD=Q+T-+mi@sPM1--yLnCRSpN zSObmnk1Ib&tg4|?8Z0F$FLrBLpwP0#$U(V^WY*%Q?*znc?UY#6+NZnqYfLPfm-3pz zqmAK#VU_fyp}h6w$MNdPrm4bC-}tatvE&HDny=g4JiQ`Sgsrn;(B>@0@5HA&V2v&E zzh9?1Ll0ucy19_r9j!)321@8%l-R_3+YV#C>_P0`;K|yXTBX(X&T~#I*)A6)&9FIX z%DGE^ZSQr79|=qDGHxW_m7M*N)b6+^i^l@uiT%>F+sI?nsgA!U{? OnPlayerPenaltied; - public event Action? OnPlayerPenaltiedAdded; + public event Action? OnPlayerPenaltied; + public event Action? OnPlayerPenaltiedAdded; public void OnPlayerPenaltiedEvent(PlayerInfo player, PlayerInfo? admin, PenaltyType penaltyType, string reason, - int duration = -1) => OnPlayerPenaltied?.Invoke(player, admin, penaltyType, reason, duration, CS2_SimpleAdmin.ServerId); + int duration, int? penaltyId) => OnPlayerPenaltied?.Invoke(player, admin, penaltyType, reason, duration, penaltyId, CS2_SimpleAdmin.ServerId); public void OnPlayerPenaltiedAddedEvent(SteamID player, PlayerInfo? admin, PenaltyType penaltyType, string reason, - int duration) => OnPlayerPenaltiedAdded?.Invoke(player, admin, penaltyType, reason, duration, CS2_SimpleAdmin.ServerId); + int duration, int? penaltyId) => OnPlayerPenaltiedAdded?.Invoke(player, admin, penaltyType, reason, duration, penaltyId, CS2_SimpleAdmin.ServerId); public void IssuePenalty(CCSPlayerController player, CCSPlayerController? admin, PenaltyType penaltyType, string reason, int duration = -1) { diff --git a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs index 4d069ed..e9ff215 100644 --- a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs @@ -19,7 +19,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)"); public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)"; public override string ModuleAuthor => "daffyy & Dliix66"; - public override string ModuleVersion => "1.7.0a"; + public override string ModuleVersion => "1.7.1a"; public override void Load(bool hotReload) { diff --git a/CS2-SimpleAdmin/Commands/RegisterCommands.cs b/CS2-SimpleAdmin/Commands/RegisterCommands.cs index 6ef9b48..0712c00 100644 --- a/CS2-SimpleAdmin/Commands/RegisterCommands.cs +++ b/CS2-SimpleAdmin/Commands/RegisterCommands.cs @@ -78,7 +78,8 @@ public static class RegisterCommands new CommandMapping("css_respawn", CS2_SimpleAdmin.Instance.OnRespawnCommand), new CommandMapping("css_tp", CS2_SimpleAdmin.Instance.OnGotoCommand), new CommandMapping("css_bring", CS2_SimpleAdmin.Instance.OnBringCommand), - new CommandMapping("css_pluginsmanager", CS2_SimpleAdmin.Instance.OnPluginManagerCommand) + new CommandMapping("css_pluginsmanager", CS2_SimpleAdmin.Instance.OnPluginManagerCommand), + new CommandMapping("css_adminvoice", CS2_SimpleAdmin.Instance.OnAdminVoiceCommand) ]; public static void InitializeCommands() @@ -160,7 +161,8 @@ public static class RegisterCommands { "css_respawn", new Command { Aliases = ["css_respawn"] } }, { "css_tp", new Command { Aliases = ["css_tp", "css_tpto", "css_goto"] } }, { "css_bring", new Command { Aliases = ["css_bring", "css_tphere"] } }, - { "css_pluginsmanager", new Command { Aliases = ["css_pluginsmanager", "css_pluginmanager"] } } + { "css_pluginsmanager", new Command { Aliases = ["css_pluginsmanager", "css_pluginmanager"] } }, + { "css_adminvoice", new Command { Aliases = ["css_adminvoice", "css_listenall"] } } } }; diff --git a/CS2-SimpleAdmin/Commands/basebans.cs b/CS2-SimpleAdmin/Commands/basebans.cs index 2e7a514..21a3112 100644 --- a/CS2-SimpleAdmin/Commands/basebans.cs +++ b/CS2-SimpleAdmin/Commands/basebans.cs @@ -19,9 +19,7 @@ public partial class CS2_SimpleAdmin var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; if (command.ArgCount < 2) return; - - var reason = _localizer?["sa_unknown"] ?? "Unknown"; - + var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, IsHLTV: false }).ToList(); @@ -31,14 +29,17 @@ public partial class CS2_SimpleAdmin return; } - if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) - reason = command.GetArg(3); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; + + var time = Helper.ParsePenaltyTime(command.GetArg(2)); playersToTarget.ForEach(player => { if (!caller.CanTarget(player)) return; - if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) + if (time < 0 && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) { DurationMenu.OpenMenu(caller, $"{_localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player, ManagePlayersMenu.BanMenu); @@ -59,13 +60,7 @@ public partial class CS2_SimpleAdmin callerName = !string.IsNullOrEmpty(caller?.PlayerName) ? caller.PlayerName : (_localizer?["sa_console"] ?? "Console"); - - // Freeze player pawn if alive - if (player.PawnIsAlive) - { - player.Pawn.Value?.Freeze(); - } - + // Get player and admin information var playerInfo = PlayersInfo[player.UserId.Value]; var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; @@ -73,7 +68,8 @@ public partial class CS2_SimpleAdmin // Asynchronously handle banning logic Task.Run(async () => { - await BanManager.BanPlayer(playerInfo, adminInfo, reason, time); + int? penaltyId = await BanManager.BanPlayer(playerInfo, adminInfo, reason, time); + SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Ban, reason, time, penaltyId); }); // Update banned players list @@ -103,13 +99,7 @@ public partial class CS2_SimpleAdmin // Schedule a kick timer if (player.UserId.HasValue) { - AddTimer(Config.OtherSettings.KickTime, () => - { - if (player is { IsValid: true, UserId: not null }) - { - Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKBANADDED); - } - }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKBANADDED, Config.OtherSettings.KickTime); } // Execute ban command if necessary @@ -127,7 +117,6 @@ public partial class CS2_SimpleAdmin } Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Ban, _localizer); - SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Ban, reason, time); } [RequiresPermissions("@css/ban")] @@ -144,11 +133,12 @@ public partial class CS2_SimpleAdmin } var steamid = steamId.SteamId64.ToString(); - var reason = command.ArgCount >= 3 && !string.IsNullOrEmpty(command.GetArg(3)) - ? command.GetArg(3) + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) : _localizer?["sa_unknown"] ?? "Unknown"; - int.TryParse(command.GetArg(2), out var time); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); + if (!CheckValidBan(caller, time)) return; var adminInfo = caller != null && caller.UserId.HasValue @@ -168,10 +158,14 @@ public partial class CS2_SimpleAdmin } else { + if (!caller.CanTarget(new SteamID(steamId.SteamId64))) + return; + // Asynchronous ban operation if player is not online or not found Task.Run(async () => { - await BanManager.AddBanBySteamid(steamid, adminInfo, reason, time); + int? penaltyId = await BanManager.AddBanBySteamid(steamid, adminInfo, reason, time); + SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Ban, reason, time, penaltyId); }); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Ban, _localizer); @@ -183,8 +177,6 @@ public partial class CS2_SimpleAdmin if (UnlockedCommands) Server.ExecuteCommand($"banid 1 {steamId.SteamId3}"); - - SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Ban, reason, time); } [RequiresPermissions("@css/ban")] @@ -202,11 +194,12 @@ public partial class CS2_SimpleAdmin return; } - var reason = command.ArgCount >= 3 && !string.IsNullOrEmpty(command.GetArg(3)) - ? command.GetArg(3) + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) : _localizer?["sa_unknown"] ?? "Unknown"; - int.TryParse(command.GetArg(2), out var time); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); + if (!CheckValidBan(caller, time)) return; var adminInfo = caller != null && caller.UserId.HasValue @@ -270,7 +263,9 @@ public partial class CS2_SimpleAdmin } var pattern = command.GetArg(1); - var reason = command.GetArg(2); + var reason = command.ArgCount >= 2 + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; Task.Run(async () => await BanManager.UnbanPlayer(pattern, callerSteamId, reason)); @@ -288,9 +283,7 @@ public partial class CS2_SimpleAdmin var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; if (command.ArgCount < 2) return; - - var reason = _localizer?["sa_unknown"] ?? "Unknown"; - + var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList(); @@ -302,10 +295,10 @@ public partial class CS2_SimpleAdmin WarnManager warnManager = new(Database); - int.TryParse(command.GetArg(2), out var time); - - if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) - reason = command.GetArg(3); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; playersToTarget.ForEach(player => { @@ -342,7 +335,8 @@ public partial class CS2_SimpleAdmin Task.Run(async () => { warnManager ??= new WarnManager(Database); - await warnManager.WarnPlayer(playerInfo, adminInfo, reason, time); + int? penaltyId = await warnManager.WarnPlayer(playerInfo, adminInfo, reason, time); + SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Warn, reason, time, penaltyId); // Check for warn thresholds and execute punish command if applicable var totalWarns = await warnManager.GetPlayerWarnsCount(player.SteamID.ToString()); @@ -392,7 +386,6 @@ public partial class CS2_SimpleAdmin // Send Discord notification for the warning Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Warn, _localizer); - SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Warn, reason, time); } [RequiresPermissions("@css/kick")] diff --git a/CS2-SimpleAdmin/Commands/basecommands.cs b/CS2-SimpleAdmin/Commands/basecommands.cs index bf46d26..d85bb57 100644 --- a/CS2-SimpleAdmin/Commands/basecommands.cs +++ b/CS2-SimpleAdmin/Commands/basecommands.cs @@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.Globalization; using System.Reflection; +using CounterStrikeSharp.API.ValveConstants.Protobuf; using MenuManager; namespace CS2_SimpleAdmin; @@ -40,7 +41,7 @@ public partial class CS2_SimpleAdmin playersToTarget.ForEach(player => { if (!player.UserId.HasValue) return; - if (!caller!.CanTarget(player)) return; + if (!caller.CanTarget(player)) return; userId = player.UserId.Value; }); @@ -140,6 +141,38 @@ public partial class CS2_SimpleAdmin }); } + [RequiresPermissions("@css/chat")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] + public void OnAdminVoiceCommand(CCSPlayerController? caller, CommandInfo command) + { + if (caller == null || caller.IsValid == false) + return; + + if (command.ArgCount > 1) + { + if (command.GetArg(2).ToLower().Equals("muteAll")) + { + foreach (var player in Helper.GetValidPlayers().Where(p => p != caller && !AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/chat"))) + { + player.VoiceFlags = VoiceFlags.Muted; + } + } + + if (command.GetArg(2).ToLower().Equals("unmuteAll")) + { + foreach (var player in Helper.GetValidPlayers().Where(p => p != caller)) + { + if (PlayerPenaltyManager.GetPlayerPenalties(player.Slot, PenaltyType.Mute).Count == 0) + player.VoiceFlags = VoiceFlags.Normal; + } + } + + return; + } + + caller.VoiceFlags = caller.VoiceFlags == VoiceFlags.All ? VoiceFlags.Normal : VoiceFlags.All; + } + [RequiresPermissions("@css/generic")] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] public void OnAdminCommand(CCSPlayerController? caller, CommandInfo command) @@ -192,7 +225,7 @@ public partial class CS2_SimpleAdmin var globalAdmin = command.GetArg(4).ToLower().Equals("-g") || command.GetArg(5).ToLower().Equals("-g") || command.GetArg(6).ToLower().Equals("-g"); int.TryParse(command.GetArg(4), out var immunity); - int.TryParse(command.GetArg(5), out var time); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(5))); AddAdmin(caller, steamid, name, flags, immunity, time, globalAdmin, command); } @@ -512,6 +545,23 @@ public partial class CS2_SimpleAdmin ReasonMenu.OpenMenu(caller, PenaltyType.Ban, _localizer["sa_reason"], player, (_, _, reason) => { caller.ExecuteClientCommandFromServer($"css_addban {player.SteamId.SteamId64} {duration} \"{reason}\""); + + // Determine message keys and arguments based on ban time + var (_, activityMessageKey, _, adminActivityArgs) = duration == 0 + ? ("sa_player_ban_message_perm", "sa_admin_ban_message_perm", + [reason, "CALLER"], + ["CALLER", player.Name, reason]) + : ("sa_player_ban_message_time", "sa_admin_ban_message_time", + new object[] { reason, duration, "CALLER" }, + new object[] { "CALLER", player.Name, reason, duration }); + + // Display admin activity message if necessary + if (!SilentPlayers.Contains(caller.Slot)) + { + Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, adminActivityArgs); + } + + MenuApi?.CloseMenu(caller); })); }); disconnectedMenuAction?.AddMenuOption(_localizer["sa_mute"], (_, _) => @@ -520,6 +570,23 @@ public partial class CS2_SimpleAdmin ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) => { caller.ExecuteClientCommandFromServer($"css_addmute {player.SteamId.SteamId64} {duration} \"{reason}\""); + + // Determine message keys and arguments based on mute time (permanent or timed) + var (_, activityMessageKey, _, adminActivityArgs) = duration == 0 + ? ("sa_player_mute_message_perm", "sa_admin_mute_message_perm", + [reason, "CALLER"], + ["CALLER", player.Name, reason]) + : ("sa_player_mute_message_time", "sa_admin_mute_message_time", + new object[] { reason, duration, "CALLER" }, + new object[] { "CALLER", player.Name, reason, duration }); + + // Display admin activity message to other players + if (!SilentPlayers.Contains(caller.Slot)) + { + Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, adminActivityArgs); + } + + MenuApi?.CloseMenu(caller); })); }); disconnectedMenuAction?.AddMenuOption(_localizer["sa_gag"], (_, _) => @@ -528,6 +595,23 @@ public partial class CS2_SimpleAdmin ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) => { caller.ExecuteClientCommandFromServer($"css_addgag {player.SteamId.SteamId64} {duration} \"{reason}\""); + + // Determine message keys and arguments based on gag time (permanent or timed) + var (_, activityMessageKey, _, adminActivityArgs) = duration == 0 + ? ("sa_player_gag_message_perm", "sa_admin_gag_message_perm", + [reason, "CALLER"], + ["CALLER", player.Name, reason]) + : ("sa_player_gag_message_time", "sa_admin_gag_message_time", + new object[] { reason, duration, "CALLER" }, + new object[] { "CALLER", player.Name, reason, duration}); + + // Display admin activity message to other players + if (!SilentPlayers.Contains(caller.Slot)) + { + Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, adminActivityArgs); + } + + MenuApi?.CloseMenu(caller); })); }); disconnectedMenuAction?.AddMenuOption(_localizer["sa_silence"], (_, _) => @@ -536,6 +620,23 @@ public partial class CS2_SimpleAdmin ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) => { caller.ExecuteClientCommandFromServer($"css_addsilence {player.SteamId.SteamId64} {duration} \"{reason}\""); + + // Determine message keys and arguments based on silence time (permanent or timed) + var (_, activityMessageKey, _, adminActivityArgs) = duration == 0 + ? ("sa_player_silence_message_perm", "sa_admin_silence_message_perm", + [reason, "CALLER"], + ["CALLER", player.Name, reason]) + : ("sa_player_silence_message_time", "sa_admin_silence_message_time", + new object[] { reason, duration, "CALLER" }, + new object[] { "CALLER", player.Name, reason, duration }); + + // Display admin activity message to other players + if (!SilentPlayers.Contains(caller.Slot)) + { + Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, adminActivityArgs); + } + + MenuApi?.CloseMenu(caller); })); }); @@ -565,7 +666,7 @@ public partial class CS2_SimpleAdmin playersToTarget.ForEach(player => { if (!player.UserId.HasValue) return; - if (!caller!.CanTarget(player)) return; + if (!caller.CanTarget(player)) return; var userId = player.UserId.Value; @@ -615,30 +716,30 @@ public partial class CS2_SimpleAdmin { if (caller != null) { - caller.PrintToConsole($"--------- PLAYER LIST ---------"); + caller.PrintToConsole("--------- PLAYER LIST ---------"); playersToTarget.ForEach(player => { caller.PrintToConsole( $"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{(AdminManager.PlayerHasPermissions(caller, "@css/showip") ? player.IpAddress?.Split(":")[0] : "Unknown")}\" SteamID64: \"{player.SteamID}\")"); }); - caller.PrintToConsole($"--------- END PLAYER LIST ---------"); + caller.PrintToConsole("--------- END PLAYER LIST ---------"); } else { - Server.PrintToConsole($"--------- PLAYER LIST ---------"); + Server.PrintToConsole("--------- PLAYER LIST ---------"); playersToTarget.ForEach(player => { Server.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")"); }); - Server.PrintToConsole($"--------- END PLAYER LIST ---------"); + Server.PrintToConsole("--------- END PLAYER LIST ---------"); } } else { - var playersJson = JsonConvert.SerializeObject(playersToTarget.Select((CCSPlayerController player) => + var playersJson = JsonConvert.SerializeObject(playersToTarget.Select(player => { var matchStats = player.ActionTrackingServices?.MatchStats; - + return new { player.UserId, @@ -669,7 +770,6 @@ public partial class CS2_SimpleAdmin public void OnKickCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; - var reason = _localizer?["sa_unknown"] ?? "Unknown"; var targets = GetTarget(command); @@ -682,8 +782,9 @@ public partial class CS2_SimpleAdmin return; } - if (command.ArgCount >= 2 && command.GetArg(2).Length > 0) - reason = command.GetArg(2); + var reason = command.ArgCount >= 2 + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; playersToTarget.ForEach(player => { @@ -709,13 +810,7 @@ public partial class CS2_SimpleAdmin var playerInfo = PlayersInfo[player.UserId.Value]; var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; - - // Freeze player pawn if alive - if (player.PawnIsAlive) - { - player.Pawn.Value?.Freeze(); - } - + // Determine message keys and arguments for the kick notification var (messageKey, activityMessageKey, centerArgs, adminActivityArgs) = ("sa_player_kick_message", "sa_admin_kick_message", @@ -734,13 +829,7 @@ public partial class CS2_SimpleAdmin // Schedule the kick for the player if (player.UserId.HasValue) { - AddTimer(Config.OtherSettings.KickTime, () => - { - if (player.IsValid) - { - Helper.KickPlayer(player.UserId.Value); - } - }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED, Config.OtherSettings.KickTime); } // Log the command and send Discord notification @@ -749,7 +838,7 @@ public partial class CS2_SimpleAdmin else Helper.LogCommand(caller, command); - SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Kick, reason); + SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Kick, reason, -1, null); } [RequiresPermissions("@css/changemap")] diff --git a/CS2-SimpleAdmin/Commands/basecomms.cs b/CS2-SimpleAdmin/Commands/basecomms.cs index 16c73de..66ac4ee 100644 --- a/CS2-SimpleAdmin/Commands/basecomms.cs +++ b/CS2-SimpleAdmin/Commands/basecomms.cs @@ -2,6 +2,7 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Entities; using CS2_SimpleAdmin.Managers; using CS2_SimpleAdmin.Menus; using CS2_SimpleAdminApi; @@ -16,9 +17,7 @@ public partial class CS2_SimpleAdmin { if (Database == null) return; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; - - var reason = _localizer?["sa_unknown"] ?? "Unknown"; - + var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); @@ -28,13 +27,16 @@ public partial class CS2_SimpleAdmin return; } - if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) - reason = command.GetArg(3); - + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; + + var time = Helper.ParsePenaltyTime(command.GetArg(2)); + playersToTarget.ForEach(player => { if (!caller!.CanTarget(player)) return; - if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) + if (time < 0 && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) { DurationMenu.OpenMenu(caller, $"{_localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player, ManagePlayersMenu.GagMenu); @@ -61,7 +63,8 @@ public partial class CS2_SimpleAdmin // Asynchronously handle gag logic Task.Run(async () => { - await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time); + int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time); + SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Gag, reason, time, penaltyId); }); // Add penalty to the player's penalty manager @@ -98,7 +101,6 @@ public partial class CS2_SimpleAdmin } Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Gag, _localizer); - SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Gag, reason, time); } [RequiresPermissions("@css/chat")] @@ -121,11 +123,11 @@ public partial class CS2_SimpleAdmin } var steamid = steamId.SteamId64.ToString(); - var reason = command.ArgCount >= 3 && command.GetArg(3).Length > 0 - ? command.GetArg(3) - : (_localizer?["sa_unknown"] ?? "Unknown"); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; - int.TryParse(command.GetArg(2), out var time); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); if (!CheckValidMute(caller, time)) return; // Get player and admin info @@ -145,10 +147,14 @@ public partial class CS2_SimpleAdmin } else { + if (!caller.CanTarget(new SteamID(steamId.SteamId64))) + return; + // Asynchronous gag operation for offline players Task.Run(async () => { - await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time); + int? penaltyId = await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time); + SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Gag, reason, time, penaltyId); }); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Gag, _localizer); @@ -158,7 +164,6 @@ public partial class CS2_SimpleAdmin // Log the gag command and respond to the command Helper.LogCommand(caller, command); - SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Gag, reason, time); } [RequiresPermissions("@css/chat")] @@ -169,7 +174,9 @@ public partial class CS2_SimpleAdmin var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var pattern = command.GetArg(1); - var reason = command.GetArg(2); + var reason = command.ArgCount >= 2 + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; if (pattern.Length <= 1) { @@ -235,8 +242,6 @@ public partial class CS2_SimpleAdmin if (Database == null) return; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; - var reason = _localizer?["sa_unknown"] ?? "Unknown"; - var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); @@ -246,13 +251,16 @@ public partial class CS2_SimpleAdmin return; } - if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) - reason = command.GetArg(3); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; + + var time = Helper.ParsePenaltyTime(command.GetArg(2)); playersToTarget.ForEach(player => { if (!caller!.CanTarget(player)) return; - if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) + if (time < 0 && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) { DurationMenu.OpenMenu(caller, $"{_localizer?["sa_mute"] ?? "Mute"}: {player.PlayerName}", player, ManagePlayersMenu.MuteMenu); @@ -282,7 +290,8 @@ public partial class CS2_SimpleAdmin // Asynchronously handle mute logic Task.Run(async () => { - await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 1); + int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 1); + SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Mute, reason, time, penaltyId); }); // Add penalty to the player's penalty manager @@ -319,7 +328,6 @@ public partial class CS2_SimpleAdmin } Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Mute, _localizer); - SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Mute, reason, time); } [RequiresPermissions("@css/chat")] @@ -342,11 +350,11 @@ public partial class CS2_SimpleAdmin } var steamid = steamId.SteamId64.ToString(); - var reason = command.ArgCount >= 3 && command.GetArg(3).Length > 0 - ? command.GetArg(3) - : (_localizer?["sa_unknown"] ?? "Unknown"); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; - int.TryParse(command.GetArg(2), out var time); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); if (!CheckValidMute(caller, time)) return; // Get player and admin info @@ -366,10 +374,14 @@ public partial class CS2_SimpleAdmin } else { + if (!caller.CanTarget(new SteamID(steamId.SteamId64))) + return; + // Asynchronous mute operation for offline players Task.Run(async () => { - await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 1); + int? penaltyId = await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 1); + SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Mute, reason, time, penaltyId); }); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Mute, _localizer); @@ -379,7 +391,6 @@ public partial class CS2_SimpleAdmin // Log the mute command and respond to the command Helper.LogCommand(caller, command); - SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Mute, reason, time); } [RequiresPermissions("@css/chat")] @@ -390,7 +401,9 @@ public partial class CS2_SimpleAdmin var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var pattern = command.GetArg(1); - var reason = command.GetArg(2); + var reason = command.ArgCount >= 2 + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; if (pattern.Length <= 1) { @@ -457,9 +470,7 @@ public partial class CS2_SimpleAdmin { if (Database == null) return; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; - - var reason = _localizer?["sa_unknown"] ?? "Unknown"; - + var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); @@ -469,13 +480,16 @@ public partial class CS2_SimpleAdmin return; } - if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) - reason = command.GetArg(3); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; + var time = Helper.ParsePenaltyTime(command.GetArg(2)); + playersToTarget.ForEach(player => { if (!caller!.CanTarget(player)) return; - if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) + if (time < 0 && caller != null && caller.IsValid && Config.OtherSettings.ShowBanMenuIfNoTime) { DurationMenu.OpenMenu(caller, $"{_localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player, ManagePlayersMenu.SilenceMenu); @@ -502,7 +516,8 @@ public partial class CS2_SimpleAdmin // Asynchronously handle silence logic Task.Run(async () => { - await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 2); // Assuming 2 is the type for silence + int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 2); // Assuming 2 is the type for silence + SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Silence, reason, time, penaltyId); }); // Add penalty to the player's penalty manager @@ -540,7 +555,6 @@ public partial class CS2_SimpleAdmin } Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Silence, _localizer); - SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Silence, reason, time); } [RequiresPermissions("@css/chat")] @@ -563,11 +577,11 @@ public partial class CS2_SimpleAdmin } var steamid = steamId.SteamId64.ToString(); - var reason = command.ArgCount >= 3 && command.GetArg(3).Length > 0 - ? command.GetArg(3) - : (_localizer?["sa_unknown"] ?? "Unknown"); + var reason = command.ArgCount >= 3 + ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; - int.TryParse(command.GetArg(2), out var time); + var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2))); if (!CheckValidMute(caller, time)) return; // Get player and admin info @@ -587,10 +601,14 @@ public partial class CS2_SimpleAdmin } else { + if (!caller.CanTarget(new SteamID(steamId.SteamId64))) + return; + // Asynchronous silence operation for offline players Task.Run(async () => { - await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 2); + int? penaltyId = await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 2); + SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Silence, reason, time, penaltyId); }); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Silence, _localizer); @@ -600,7 +618,6 @@ public partial class CS2_SimpleAdmin // Log the silence command and respond to the command Helper.LogCommand(caller, command); - SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Silence, reason, time); } [RequiresPermissions("@css/chat")] @@ -611,14 +628,16 @@ public partial class CS2_SimpleAdmin var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var pattern = command.GetArg(1); - var reason = command.GetArg(2); + var reason = command.ArgCount >= 2 + ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)) + : _localizer?["sa_unknown"] ?? "Unknown"; if (pattern.Length <= 1) { command.ReplyToCommand("Too short pattern to search."); return; } - + Helper.LogCommand(caller, command); // Check if pattern is a valid SteamID64 diff --git a/CS2-SimpleAdmin/Database/Migrations/011_AddRconColumnToServersTable.sql b/CS2-SimpleAdmin/Database/Migrations/011_AddRconColumnToServersTable.sql new file mode 100644 index 0000000..656cc1a --- /dev/null +++ b/CS2-SimpleAdmin/Database/Migrations/011_AddRconColumnToServersTable.sql @@ -0,0 +1 @@ +ALTER TABLE `sa_servers` ADD `rcon_password` varchar(128) NULL AFTER `hostname`; diff --git a/CS2-SimpleAdmin/Events.cs b/CS2-SimpleAdmin/Events.cs index 9ee641e..65d9d7a 100644 --- a/CS2-SimpleAdmin/Events.cs +++ b/CS2-SimpleAdmin/Events.cs @@ -59,7 +59,7 @@ public partial class CS2_SimpleAdmin new ServerManager().LoadServerData(); } - [GameEventHandler] + [GameEventHandler(HookMode.Pre)] public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info) { var player = @event.Userid; @@ -101,9 +101,14 @@ public partial class CS2_SimpleAdmin GodPlayers.Remove(player.Slot); SpeedPlayers.Remove(player.Slot); GravityPlayers.Remove(player); - + if (player.UserId.HasValue) + { + if (@event.Reason == 149) + info.DontBroadcast = true; + PlayersInfo.TryRemove(player.UserId.Value, out _); + } var authorizedSteamId = player.AuthorizedSteamID; if (authorizedSteamId == null || !PermissionManager.AdminCache.TryGetValue(authorizedSteamId, @@ -150,8 +155,12 @@ public partial class CS2_SimpleAdmin if (player == null || !player.IsValid || player.IsBot) return HookResult.Continue; + + if (player.UserId.HasValue && PlayersInfo.TryGetValue(player.UserId.Value, out PlayerInfo? value) && +value.WaitingForKick) + return HookResult.Continue; - new PlayerManager().LoadPlayerData(player); + new PlayerManager().LoadPlayerData(player, true); return HookResult.Continue; } diff --git a/CS2-SimpleAdmin/Extensions/PlayerExtensions.cs b/CS2-SimpleAdmin/Extensions/PlayerExtensions.cs index de488d5..c4ac802 100644 --- a/CS2-SimpleAdmin/Extensions/PlayerExtensions.cs +++ b/CS2-SimpleAdmin/Extensions/PlayerExtensions.cs @@ -36,6 +36,14 @@ public static class PlayerExtensions AdminManager.GetPlayerImmunity(controller) >= AdminManager.GetPlayerImmunity(target); } + public static bool CanTarget(this CCSPlayerController? controller, SteamID steamId) + { + if (controller is null) return true; + + return AdminManager.CanPlayerTarget(new SteamID(controller.SteamID), steamId) || + AdminManager.GetPlayerImmunity(controller) >= AdminManager.GetPlayerImmunity(steamId); + } + public static void SetSpeed(this CCSPlayerController? controller, float speed) { var playerPawnValue = controller?.PlayerPawn.Value; diff --git a/CS2-SimpleAdmin/Helper.cs b/CS2-SimpleAdmin/Helper.cs index 2b1d8f5..2c5030b 100644 --- a/CS2-SimpleAdmin/Helper.cs +++ b/CS2-SimpleAdmin/Helper.cs @@ -79,11 +79,11 @@ internal static class Helper ); } - public static bool IsValidSteamId64(string input) - { - const string pattern = @"^\d{17}$"; - return Regex.IsMatch(input, pattern); - } + // public static bool IsValidSteamId64(string input) + // { + // const string pattern = @"^\d{17}$"; + // return Regex.IsMatch(input, pattern); + // } public static bool ValidateSteamId(string input, out SteamID? steamId) { @@ -93,7 +93,7 @@ internal static class Helper { return false; } - + if (!SteamID.TryParse(input, out var parsedSteamId)) return false; steamId = parsedSteamId; @@ -137,14 +137,35 @@ internal static class Helper } } - public static void KickPlayer(int userId, NetworkDisconnectionReason reason = NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED) + public static void KickPlayer(int userId, NetworkDisconnectionReason reason = NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED, int delay = 0) { var player = Utilities.GetPlayerFromUserid(userId); if (player == null || !player.IsValid || player.IsHLTV) return; + + if (player.UserId.HasValue) + CS2_SimpleAdmin.PlayersInfo[player.UserId.Value].WaitingForKick = true; - player.Disconnect(reason); + player.CommitSuicide(true, true); + + if (delay > 0) + { + CS2_SimpleAdmin.Instance.AddTimer(delay, () => + { + if (!player.IsValid || player.IsHLTV) + return; + + player.Disconnect(reason); + }); + } + else + { + player.Disconnect(reason); + } + + if (CS2_SimpleAdmin.UnlockedCommands && reason == NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED) + Server.ExecuteCommand($"banid 1 {new SteamID(player.SteamID).SteamId3}"); // if (!string.IsNullOrEmpty(reason)) // { @@ -159,9 +180,33 @@ internal static class Helper // Server.ExecuteCommand($"kickid {userId} {reason}"); } - public static void KickPlayer(CCSPlayerController player, NetworkDisconnectionReason reason = NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED) + public static void KickPlayer(CCSPlayerController player, NetworkDisconnectionReason reason = NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED, int delay = 0) { - player.Disconnect(reason); + if (!player.IsValid || player.IsHLTV) + return; + + if (player.UserId.HasValue) + CS2_SimpleAdmin.PlayersInfo[player.UserId.Value].WaitingForKick = true; + + player.CommitSuicide(true, true); + + if (delay > 0) + { + CS2_SimpleAdmin.Instance.AddTimer(delay, () => + { + if (!player.IsValid || player.IsHLTV) + return; + + player.Disconnect(reason); + }); + } + else + { + player.Disconnect(reason); + } + + if (CS2_SimpleAdmin.UnlockedCommands && reason == NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED) + Server.ExecuteCommand($"banid 1 {new SteamID(player.SteamID).SteamId3}"); // if (!string.IsNullOrEmpty(reason)) // { @@ -176,6 +221,54 @@ internal static class Helper // Server.ExecuteCommand($"kickid {userId} {reason}"); } + public static int ParsePenaltyTime(string time) + { + if (string.IsNullOrWhiteSpace(time)) + { + CS2_SimpleAdmin._logger?.LogError("Time string cannot be null or empty."); + return -1; + } + + var timeUnits = new Dictionary + { + { "m", 1 }, // Minute + { "h", 60 }, // Hour + { "d", 1440 }, // Day (24 * 60) + { "w", 10080 }, // Week (7 * 24 * 60) + { "mo", 43200 }, // Month (30 * 24 * 60) + { "y", 525600 } // Year (365 * 24 * 60) + }; + + + // Check if the input is purely numeric (e.g., "10" for 10 minutes) + if (int.TryParse(time, out var numericMinutes)) + { + return numericMinutes; + } + + int totalMinutes = 0; + + var regex = new Regex(@"(\d+)([a-z]+)"); + var matches = regex.Matches(time); + + foreach (Match match in matches) + { + var value = int.Parse(match.Groups[1].Value); // Numeric part + var unit = match.Groups[2].Value; // Unit part + + if (timeUnits.TryGetValue(unit, out var minutesPerUnit)) + { + totalMinutes += value * minutesPerUnit; + } + else + { + throw new ArgumentException($"Invalid time unit '{unit}' in time string.", nameof(time)); + } + } + + return totalMinutes; + } + public static void PrintToCenterAll(string message) { Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false }).ToList().ForEach(controller => @@ -632,28 +725,28 @@ internal static class Helper commandString])); } - public static IMenu? CreateMenu(string title) + public static IMenu? CreateMenu(string title, Action? backAction = null) { var menuType = CS2_SimpleAdmin.Instance.Config.MenuConfigs.MenuType.ToLower(); var menu = menuType switch { _ when menuType.Equals("selectable", StringComparison.CurrentCultureIgnoreCase) => - CS2_SimpleAdmin.MenuApi?.NewMenu(title), + CS2_SimpleAdmin.MenuApi?.GetMenu(title), _ when menuType.Equals("dynamic", StringComparison.CurrentCultureIgnoreCase) => - CS2_SimpleAdmin.MenuApi?.NewMenuForcetype(title, MenuType.ButtonMenu), + CS2_SimpleAdmin.MenuApi?.GetMenuForcetype(title, MenuType.ButtonMenu), _ when menuType.Equals("center", StringComparison.CurrentCultureIgnoreCase) => - CS2_SimpleAdmin.MenuApi?.NewMenuForcetype(title, MenuType.CenterMenu), + CS2_SimpleAdmin.MenuApi?.GetMenuForcetype(title, MenuType.CenterMenu), _ when menuType.Equals("chat", StringComparison.CurrentCultureIgnoreCase) => - CS2_SimpleAdmin.MenuApi?.NewMenuForcetype(title, MenuType.ChatMenu), + CS2_SimpleAdmin.MenuApi?.GetMenuForcetype(title, MenuType.ChatMenu), _ when menuType.Equals("console", StringComparison.CurrentCultureIgnoreCase) => - CS2_SimpleAdmin.MenuApi?.NewMenuForcetype(title, MenuType.ConsoleMenu), + CS2_SimpleAdmin.MenuApi?.GetMenuForcetype(title, MenuType.ConsoleMenu), - _ => CS2_SimpleAdmin.MenuApi?.NewMenu(title) + _ => CS2_SimpleAdmin.MenuApi?.GetMenu(title) }; return menu; diff --git a/CS2-SimpleAdmin/Managers/BanManager.cs b/CS2-SimpleAdmin/Managers/BanManager.cs index 1cda794..1f01c5f 100644 --- a/CS2-SimpleAdmin/Managers/BanManager.cs +++ b/CS2-SimpleAdmin/Managers/BanManager.cs @@ -10,21 +10,26 @@ namespace CS2_SimpleAdmin.Managers; internal class BanManager(Database.Database? database) { - public async Task BanPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0) + public async Task BanPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0) { - if (database == null) return; - + if (database == null) return null; + DateTime now = Time.ActualDateTime(); DateTime futureTime = now.AddMinutes(time); await using MySqlConnection connection = await database.GetConnectionAsync(); try { - const string 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)"; + const string 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); + SELECT LAST_INSERT_ID(); + """; - await connection.ExecuteAsync(sql, new + var banId = await connection.ExecuteScalarAsync(sql, new { playerSteamid = player.SteamId.SteamId64.ToString(), playerName = player.Name, @@ -37,15 +42,19 @@ internal class BanManager(Database.Database? database) created = now, serverid = CS2_SimpleAdmin.ServerId }); + + return banId; + } + catch + { + return null; } - catch { } } - public async Task AddBanBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0) + public async Task AddBanBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0) { - if (database == null) return; - - if (string.IsNullOrEmpty(playerSteamId)) return; + if (database == null) return null; + if (string.IsNullOrEmpty(playerSteamId)) return null; DateTime now = Time.ActualDateTime(); DateTime futureTime = now.AddMinutes(time); @@ -54,10 +63,16 @@ internal class BanManager(Database.Database? database) { await using MySqlConnection 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)"; + const string 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); + SELECT LAST_INSERT_ID(); + """; - await connection.ExecuteAsync(sql, new + var banId = await connection.ExecuteScalarAsync(sql, new { playerSteamid = playerSteamId, adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", @@ -68,8 +83,13 @@ internal class BanManager(Database.Database? database) created = now, serverid = CS2_SimpleAdmin.ServerId }); + + return banId; + } + catch (Exception) + { + return null; } - catch { } } public async Task AddBanByIp(string playerIp, PlayerInfo? issuer, string reason, int time = 0) @@ -383,7 +403,7 @@ internal class BanManager(Database.Database? database) foreach (var player in filteredPlayers.Where(player => bannedSteamIds.Contains(player.SteamID) || (checkIpBans && bannedIps.Contains(player.IpAddress ?? "")))) { - if (!player.UserId.HasValue) continue; + if (!player.UserId.HasValue || CS2_SimpleAdmin.PlayersInfo[player.UserId.Value].WaitingForKick) continue; await Server.NextFrameAsync(() => { diff --git a/CS2-SimpleAdmin/Managers/MuteManager.cs b/CS2-SimpleAdmin/Managers/MuteManager.cs index 3a5637a..be3e9bf 100644 --- a/CS2-SimpleAdmin/Managers/MuteManager.cs +++ b/CS2-SimpleAdmin/Managers/MuteManager.cs @@ -6,9 +6,9 @@ namespace CS2_SimpleAdmin.Managers; internal class MuteManager(Database.Database? database) { - public async Task MutePlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0, int type = 0) + public async Task MutePlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0, int type = 0) { - if (database == null) return; + if (database == null) return null; var now = Time.ActualDateTime(); var futureTime = now.AddMinutes(time); @@ -23,11 +23,16 @@ internal class MuteManager(Database.Database? database) try { await using var connection = await database.GetConnectionAsync(); - const string 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, @muteReason, @duration, @ends, @created, @type, @serverid)"; + const string 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, @muteReason, @duration, @ends, @created, @type, @serverid); + SELECT LAST_INSERT_ID(); + """; - await connection.ExecuteAsync(sql, new + var muteId = await connection.ExecuteScalarAsync(sql, new { playerSteamid = player.SteamId.SteamId64.ToString(), playerName = player.Name, @@ -40,19 +45,20 @@ internal class MuteManager(Database.Database? database) type = muteType, serverid = CS2_SimpleAdmin.ServerId }); + + return muteId; } catch (Exception ex) { CS2_SimpleAdmin._logger?.LogError(ex.Message); - }; + return null; + } } - public async Task AddMuteBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0, int type = 0) + public async Task AddMuteBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0, int type = 0) { - if (database == null) return; - - if (string.IsNullOrEmpty(playerSteamId)) return; - + if (database == null) return null; + if (string.IsNullOrEmpty(playerSteamId)) return null; var now = Time.ActualDateTime(); var futureTime = now.AddMinutes(time); @@ -67,10 +73,16 @@ internal class MuteManager(Database.Database? database) try { await using var connection = await database.GetConnectionAsync(); - const string sql = "INSERT INTO `sa_mutes` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `type`, `server_id`) " + - "VALUES (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @type, @serverid)"; + const string sql = """ + + INSERT INTO `sa_mutes` + (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `type`, `server_id`) + VALUES + (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @type, @serverid); + SELECT LAST_INSERT_ID(); + """; - await connection.ExecuteAsync(sql, new + var muteId = await connection.ExecuteScalarAsync(sql, new { playerSteamid = playerSteamId, adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", @@ -82,8 +94,13 @@ internal class MuteManager(Database.Database? database) type = muteType, serverid = CS2_SimpleAdmin.ServerId }); + + return muteId; + } + catch + { + return null; } - catch { }; } public async Task> IsPlayerMuted(string steamId) diff --git a/CS2-SimpleAdmin/Managers/PlayerManager.cs b/CS2-SimpleAdmin/Managers/PlayerManager.cs index 49218da..ab1492f 100644 --- a/CS2-SimpleAdmin/Managers/PlayerManager.cs +++ b/CS2-SimpleAdmin/Managers/PlayerManager.cs @@ -14,7 +14,7 @@ public class PlayerManager { private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config; - public void LoadPlayerData(CCSPlayerController player) + public void LoadPlayerData(CCSPlayerController player, bool fullConnect = false) { if (player.IsBot || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1")) return; @@ -125,67 +125,67 @@ public class PlayerManager if (victim == null || !victim.UserId.HasValue) return; - if (CS2_SimpleAdmin.UnlockedCommands) - Server.ExecuteCommand($"banid 1 {userId}"); - Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED); }); return; } - var warns = await CS2_SimpleAdmin.Instance.WarnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false); - var (totalMutes, totalGags, totalSilences) = - await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]); + if (fullConnect) + { + var warns = await CS2_SimpleAdmin.Instance.WarnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false); + var (totalMutes, totalGags, totalSilences) = + await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]); - CS2_SimpleAdmin.PlayersInfo[userId].TotalBans = - await CS2_SimpleAdmin.Instance.BanManager.GetPlayerBans(CS2_SimpleAdmin.PlayersInfo[userId]); - CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = totalMutes; - CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = totalGags; - CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences = totalSilences; - CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns = warns.Count; + CS2_SimpleAdmin.PlayersInfo[userId].TotalBans = + await CS2_SimpleAdmin.Instance.BanManager.GetPlayerBans(CS2_SimpleAdmin.PlayersInfo[userId]); + CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = totalMutes; + CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = totalGags; + CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences = totalSilences; + CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns = warns.Count; // Check if the player is muted - var activeMutes = await CS2_SimpleAdmin.Instance.MuteManager.IsPlayerMuted(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()); + var activeMutes = await CS2_SimpleAdmin.Instance.MuteManager.IsPlayerMuted(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()); - if (activeMutes.Count > 0) - { - foreach (var mute in activeMutes) + if (activeMutes.Count > 0) { - string muteType = mute.type; - DateTime ends = mute.ends; - int duration = mute.duration; - switch (muteType) + foreach (var mute in activeMutes) { - // Apply mute penalty based on mute type - case "GAG": - PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Gag, ends, duration); - // if (CS2_SimpleAdmin._localizer != null) - // mutesList[PenaltyType.Gag].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_gag", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture)]); - break; - case "MUTE": - PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Mute, ends, duration); - await Server.NextFrameAsync(() => - { - player.VoiceFlags = VoiceFlags.Muted; - }); - // if (CS2_SimpleAdmin._localizer != null) - // mutesList[PenaltyType.Mute].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_mute", ends.ToLocalTime().ToString(CultureInfo.InvariantCulture)]); - break; - default: - PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Silence, ends, duration); - await Server.NextFrameAsync(() => - { - player.VoiceFlags = VoiceFlags.Muted; - }); - // if (CS2_SimpleAdmin._localizer != null) - // mutesList[PenaltyType.Silence].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_silence", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture)]); - break; + string muteType = mute.type; + DateTime ends = mute.ends; + int duration = mute.duration; + switch (muteType) + { + // Apply mute penalty based on mute type + case "GAG": + PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Gag, ends, duration); + // if (CS2_SimpleAdmin._localizer != null) + // mutesList[PenaltyType.Gag].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_gag", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture)]); + break; + case "MUTE": + PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Mute, ends, duration); + await Server.NextFrameAsync(() => + { + player.VoiceFlags = VoiceFlags.Muted; + }); + // if (CS2_SimpleAdmin._localizer != null) + // mutesList[PenaltyType.Mute].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_mute", ends.ToLocalTime().ToString(CultureInfo.InvariantCulture)]); + break; + default: + PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Silence, ends, duration); + await Server.NextFrameAsync(() => + { + player.VoiceFlags = VoiceFlags.Muted; + }); + // if (CS2_SimpleAdmin._localizer != null) + // mutesList[PenaltyType.Silence].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_silence", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture)]); + break; + } } } } - if (CS2_SimpleAdmin.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect) + if (CS2_SimpleAdmin.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect && fullConnect) { await Server.NextFrameAsync(() => { diff --git a/CS2-SimpleAdmin/Managers/ServerManager.cs b/CS2-SimpleAdmin/Managers/ServerManager.cs index ee54d0f..48fe1e7 100644 --- a/CS2-SimpleAdmin/Managers/ServerManager.cs +++ b/CS2-SimpleAdmin/Managers/ServerManager.cs @@ -38,6 +38,7 @@ public class ServerManager var address = $"{ipAddress}:{ConVar.Find("hostport")?.GetPrimitiveValue()}"; var hostname = ConVar.Find("hostname")!.StringValue; + var rconPassword = ConVar.Find("rcon_password")!.StringValue; CS2_SimpleAdmin.IpAddress = address; CS2_SimpleAdmin._logger?.LogInformation("Loaded server with ip {ip}", ipAddress); @@ -47,27 +48,28 @@ public class ServerManager try { await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); - var addressExists = await connection.ExecuteScalarAsync( - "SELECT COUNT(*) FROM sa_servers WHERE address = @address", + + int? serverId = await connection.ExecuteScalarAsync( + "SELECT id FROM sa_servers WHERE address = @address", new { address }); - if (!addressExists) + if (serverId == null) { await connection.ExecuteAsync( - "INSERT INTO sa_servers (address, hostname) VALUES (@address, @hostname)", - new { address, hostname }); + "INSERT INTO sa_servers (address, hostname, rcon_password) VALUES (@address, @hostname, @rconPassword)", + new { address, hostname, rconPassword }); + + serverId = await connection.ExecuteScalarAsync( + "SELECT id FROM sa_servers WHERE address = @address", + new { address }); } else { await connection.ExecuteAsync( - "UPDATE `sa_servers` SET `hostname` = @hostname WHERE `address` = @address", - new { address, hostname }); + "UPDATE sa_servers SET hostname = @hostname, rcon_password = @rconPassword WHERE address = @address", + new { address, hostname, rconPassword }); } - int? serverId = await connection.ExecuteScalarAsync( - "SELECT `id` FROM `sa_servers` WHERE `address` = @address", - new { address }); - CS2_SimpleAdmin.ServerId = serverId; if (CS2_SimpleAdmin.ServerId != null) diff --git a/CS2-SimpleAdmin/Managers/WarnManager.cs b/CS2-SimpleAdmin/Managers/WarnManager.cs index 82b9e2d..ad88cb9 100644 --- a/CS2-SimpleAdmin/Managers/WarnManager.cs +++ b/CS2-SimpleAdmin/Managers/WarnManager.cs @@ -6,9 +6,9 @@ namespace CS2_SimpleAdmin.Managers; internal class WarnManager(Database.Database? database) { - public async Task WarnPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0) + public async Task WarnPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0) { - if (database == null) return; + if (database == null) return null; var now = Time.ActualDateTime(); var futureTime = now.AddMinutes(time); @@ -16,11 +16,16 @@ internal class WarnManager(Database.Database? database) try { await using var connection = await database.GetConnectionAsync(); - const string sql = - "INSERT INTO `sa_warns` (`player_steamid`, `player_name`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " + - "VALUES (@playerSteamid, @playerName, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid)"; + const string sql = """ + + INSERT INTO `sa_warns` + (`player_steamid`, `player_name`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) + VALUES + (@playerSteamid, @playerName, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid); + SELECT LAST_INSERT_ID(); + """; - await connection.ExecuteAsync(sql, new + var warnId = await connection.ExecuteScalarAsync(sql, new { playerSteamid = player.SteamId.SteamId64.ToString(), playerName = player.Name, @@ -32,14 +37,19 @@ internal class WarnManager(Database.Database? database) created = now, serverid = CS2_SimpleAdmin.ServerId }); + + return warnId; + } + catch + { + return null; } - catch { }; } - public async Task AddWarnBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0) + public async Task AddWarnBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0) { - if (database == null) return; - if (string.IsNullOrEmpty(playerSteamId)) return; + if (database == null) return null; + if (string.IsNullOrEmpty(playerSteamId)) return null; var now = Time.ActualDateTime(); var futureTime = now.AddMinutes(time); @@ -47,10 +57,16 @@ internal class WarnManager(Database.Database? database) try { await using var connection = await database.GetConnectionAsync(); - const string sql = "INSERT INTO `sa_warns` (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) " + - "VALUES (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid)"; + const string sql = """ + + INSERT INTO `sa_warns` + (`player_steamid`, `admin_steamid`, `admin_name`, `reason`, `duration`, `ends`, `created`, `server_id`) + VALUES + (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid); + SELECT LAST_INSERT_ID(); + """; - await connection.ExecuteAsync(sql, new + var warnId = await connection.ExecuteScalarAsync(sql, new { playerSteamid = playerSteamId, adminSteamid = issuer?.SteamId.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", @@ -61,8 +77,13 @@ internal class WarnManager(Database.Database? database) created = now, serverid = CS2_SimpleAdmin.ServerId }); + + return warnId; + } + catch + { + return null; } - catch { }; } public async Task> GetPlayerWarns(PlayerInfo player, bool active = true) diff --git a/CS2-SimpleAdmin/Menus/AdminMenu.cs b/CS2-SimpleAdmin/Menus/AdminMenu.cs index 8757351..cec6b13 100644 --- a/CS2-SimpleAdmin/Menus/AdminMenu.cs +++ b/CS2-SimpleAdmin/Menus/AdminMenu.cs @@ -6,9 +6,9 @@ namespace CS2_SimpleAdmin.Menus; public static class AdminMenu { - public static IMenu? CreateMenu(string title) + public static IMenu? CreateMenu(string title, Action? backAction = null) { - return Helper.CreateMenu(title); + return Helper.CreateMenu(title, backAction); // return CS2_SimpleAdmin.Instance.Config.UseChatMenu ? new ChatMenu(title) : new CenterHtmlMenu(title, CS2_SimpleAdmin.Instance); } diff --git a/CS2-SimpleAdmin/Menus/ReasonMenu.cs b/CS2-SimpleAdmin/Menus/ReasonMenu.cs index 026edf1..5a1d6a2 100644 --- a/CS2-SimpleAdmin/Menus/ReasonMenu.cs +++ b/CS2-SimpleAdmin/Menus/ReasonMenu.cs @@ -46,7 +46,7 @@ public static class ReasonMenu { menu?.AddMenuOption(reason, (_, _) => onSelectAction(admin, player, reason)); } - + if (menu != null) AdminMenu.OpenMenu(admin, menu); } } \ No newline at end of file diff --git a/CS2-SimpleAdmin/VERSION b/CS2-SimpleAdmin/VERSION index 48c2394..6d8ff6d 100644 --- a/CS2-SimpleAdmin/VERSION +++ b/CS2-SimpleAdmin/VERSION @@ -1 +1 @@ -1.7.0a \ No newline at end of file +1.7.1a \ No newline at end of file diff --git a/CS2-SimpleAdminApi/ICS2-SimpleAdminApi.cs b/CS2-SimpleAdminApi/ICS2-SimpleAdminApi.cs index a1e627d..6447f90 100644 --- a/CS2-SimpleAdminApi/ICS2-SimpleAdminApi.cs +++ b/CS2-SimpleAdminApi/ICS2-SimpleAdminApi.cs @@ -17,8 +17,8 @@ public interface ICS2_SimpleAdminApi public Dictionary> GetPlayerMuteStatus(CCSPlayerController player); - public event Action? OnPlayerPenaltied; - public event Action? OnPlayerPenaltiedAdded; + public event Action? OnPlayerPenaltied; + public event Action? OnPlayerPenaltiedAdded; public void IssuePenalty(CCSPlayerController player, CCSPlayerController? admin, PenaltyType penaltyType, string reason, int duration = -1); public void LogCommand(CCSPlayerController? caller, string command); diff --git a/CS2-SimpleAdminApi/PlayerInfo.cs b/CS2-SimpleAdminApi/PlayerInfo.cs index 7e04841..f367ed7 100644 --- a/CS2-SimpleAdminApi/PlayerInfo.cs +++ b/CS2-SimpleAdminApi/PlayerInfo.cs @@ -25,6 +25,7 @@ public class PlayerInfo( public int TotalGags { get; set; } = totalGags; public int TotalSilences { get; set; } = totalSilences; public int TotalWarns { get; set; } = totalWarns; + public bool WaitingForKick { get; set; } = false; public DiePosition? DiePosition { get; set; } } diff --git a/Modules/CS2-SimpleAdmin_CleanModule/CS2-SimpleAdminApi.dll b/Modules/CS2-SimpleAdmin_CleanModule/CS2-SimpleAdminApi.dll index b7283c2ce01b88b33c2ac23f9b052051fb11fdbe..2e65ca9b809719986101d4696d311dee4bd4f524 100644 GIT binary patch delta 3130 zcmZ{meQ*_58OEP;_U_(INW#50x%q$u?j?mpP$mhv32CRATfQ0)2%pMF2QEo~5J(FF zhlt?@C`DVw64okK>ktVeRi<@F2S%rZDPl$|&QxVa|3FP3vP__P?*7; zIluEh&w0<;v%6={Zf|36Wk;+Yy@(s z2kL;8UR;0FTcaxUAB(($YJbTkW}D+l77ZIG;!KVL${Q`N_nLK3MZ8bzEh^s|(#Pjc z()$X4!1O8F>XG2%4456zfu2Iszyu>DK>`}mV0uUZ?|Ez5hyM_8AyT7f_W2$^`ns;0TD3#jjSH?4|vjLK%=pr~M(#*)usu5=NLV$pud zV?B|@Vllp{flk}RfP+s4jyVo~Dok0cobkBs82=mA?SO-GfdSjWzbwNG!mHLmnqs>& z91*KTIv*D9vCMFdILsVHW@9-f1hYB4zd6~M=1jF5R5LS=lkP?yr`*kx&64~-Ytw5! zN63clY~?sdZR4zR4K2%zw#4ZRrnB*;?hA5`9LQWnlL1es(9b(oYbSVfj8eSFTq|Mk z;N2Kc9YTSVuy-PhDoceh#>_p4q8xSD>mGsQ?8J*$-P>m$C)i}t8`Pj&1Tbue zoeOj_$FQAiUzCSw^srs!UPRhFTXPKC-^Zo<8k6qZAFA9BFp5AX5yQDrH7aXH`sEJe zectxWF`PR}6}+qLFSt>~Whuw7-LK;+_dZpr#;5Pe^=_34qd8`bzTyQ=or<7U)N{p2 z=TWN58ReegL`!kSSKHjhsuWj!^(8E$y5_6j=!?u8^Hnjgw-oRC>U_}jOTXvK%R$A) z|M=<&HkQGTgU563GPac=&sQC6n}kANb+c^}Cj08U&SEtg6~4OUC`?9`uWqql46}Xp zU-pY3nfB$A_G%SJldsmK%K7nu4{y8nL%hwPY0U%q~@qF2C)({aG~?`+W67 zJ5BZMU8N7JX*lYupXukRfV9G+cOM=Xiis8e#7F%wnpTaM_(oVL;maSuKkZP+#@FcZ zN~QHI7u17sW=yjrHM+PMESzK}J3MSE z|8I(aC| zOYjrY5hu#M!NjF>LKqd_ zeeW!eDSj{A6XXeeogCHuWT|WTw-)E1YM%Xcfp?^1wHnESLw1i>_`e43hzaU2;%F5jy{Qlm&dXvL)F`w^x;fz+7D z9%fU_XI#b}W}}NTp3EL*^D1H-XAgxbq~_1YM8;D|%`b8p;|el{daOiqpx3;}_aAY- zs&~H)#$Si`2(!Ud#4M^L#Niq4!-h_14~~1%c<7)e>?xH-meQ{m4(sB0Cs-*RT&ogppc0XJ4DwjC zn`sCa7`NM?$6H(Yoyys%&9kc#b+c+xZJVmA8d%r2B^s*Q5{cTDhU(gy>b696Z9{8~ z_pzdmVxXgW+Zm|E&F1Mo&2p!XrPzC|sL-)^%=-Z62kFJ7oG)q7`(R}bb* zsI!*NMhcrT8&yc~&ukWIsN1lKdv6tY{*11tlc1`SI)Pg5eGSa0Wp=fACT`$%T;q9V Qd-PcSV0h9k)mIh#A3*FBu>b%7 delta 2917 zcmZ{me{hsX9mb#C_uls|M{;@ZxVt1I9Csu_q=@-JE{Sbt5=$(hGC*mQVnuREfJR0T zAsy0AxTFZ;7-mRc#@bFti9u8>okFIgh}Bd(*Ku?d9mY}YA0eRTk5)$QgsD!|XTN#T zIvqE&pZz}1es|w}-`jWdjZ`qP#jQRG}Y{F);m&nzKTiDv?;UGpK1F4-@=}s*M(~1&ux?;gtlF<7Y%5qT zR^yu%D78%tI9ML2cO0A$He2&{DULYCKWM!iAOjt?gDaNd3E?@bBTw;B>DVsTEz3;t zs7&#I#BEr?97TrlATB#$EXLF1>-ImigCH{_Sb-rfxR`X%DEU9rW>ght2;;0>#5q4? z8)rUf=DB4z1jBe|1xl1embKI_OF8PRo}-2 z>67~}*t5Y)|4l9V7p{PhKuVz`p{~ddF|trnz#sUK7fPYzI#uwFva3RW2REUVf<3Ao zWp<1yMwO^iY)%_BUOs0hR22PbnCl-apS3F}Uz5&bp>J_*mH4@@-VLr+mALAwQ>deQ z!&k59^US>It4qAYO1$Z-ZW;HsuXY9%``-1{4QI8gf}Mf6{;|+s9fc}HD2*!Sz@1xH5~r97EUt`puij(uLoV%!2vP|MTSsI7GcnF-7sF{ z*7*NRk;Ub?QrA@&=OQ$|D;K`A>LSeYXo->zkDXb*w;v>3)C*gM?ZQss7U4Ewj#L;R z6WC8K;j2AsuftDCN1OzI@>x6Y;<{KN9v`3J?sc()jH90{=L8|9?IqJVK-S|BxlJ;+ z3vH5cM&ef`o)KOb-V`6&%&dfIVMf>{ zY|l&6qs@AIB+hAb;he-H!cpOA;e_yv zc(=rp5+Ah>&_8Y;A}{3iunO@&)!cYNQlpfwScrcCIz^=EvB{|P$LMKppG9OGC0tN~ z)JSriLK&&KZKI4UNR1`TH7DO<##PKUhgpJgin->1+Ehl7VY0$ zV8pz`?=3fYwA?x6jlTs~`PwdI#l1_#m4Pi74tm#$H>&JZZApikIuYqoQ*V`yEAN^c z_MVT9O?Afpro9b`4||6aHSUgMznFYyY1_IB)hkNwdc1hddm)idMH8`motPVQqs5U> zBHFG(3r>eP-rI>!7F$j%&N|3CHlmOn>C%WG2rK7Zpo~mCPH8bwnZ| zQ>-*Xfiz+r263CS#p1!VR}`= zl=;GVNGH3!C(53!?Qg8h^|jRH8ncZ%Tbpvbvb_!2#$0n>YeTN7KHHLO$hGvf^wzEQ z?k?Yx{O0c#{|IX1X7ix;vCcKImU%xcPdeTFxa=c}FN~c^k z6svP_3>9sI2szpZka{OA) RTRNz(W~ZX5TWY*6_;2WDktVeRi<@F2S%rZDPl$|&QxVa|3FP3vP__P?*7; zIluEh&w0<;v%6={Zf|36Wk;+Yy@(s z2kL;8UR;0FTcaxUAB(($YJbTkW}D+l77ZIG;!KVL${Q`N_nLK3MZ8bzEh^s|(#Pjc z()$X4!1O8F>XG2%4456zfu2Iszyu>DK>`}mV0uUZ?|Ez5hyM_8AyT7f_W2$^`ns;0TD3#jjSH?4|vjLK%=pr~M(#*)usu5=NLV$pud zV?B|@Vllp{flk}RfP+s4jyVo~Dok0cobkBs82=mA?SO-GfdSjWzbwNG!mHLmnqs>& z91*KTIv*D9vCMFdILsVHW@9-f1hYB4zd6~M=1jF5R5LS=lkP?yr`*kx&64~-Ytw5! zN63clY~?sdZR4zR4K2%zw#4ZRrnB*;?hA5`9LQWnlL1es(9b(oYbSVfj8eSFTq|Mk z;N2Kc9YTSVuy-PhDoceh#>_p4q8xSD>mGsQ?8J*$-P>m$C)i}t8`Pj&1Tbue zoeOj_$FQAiUzCSw^srs!UPRhFTXPKC-^Zo<8k6qZAFA9BFp5AX5yQDrH7aXH`sEJe zectxWF`PR}6}+qLFSt>~Whuw7-LK;+_dZpr#;5Pe^=_34qd8`bzTyQ=or<7U)N{p2 z=TWN58ReegL`!kSSKHjhsuWj!^(8E$y5_6j=!?u8^Hnjgw-oRC>U_}jOTXvK%R$A) z|M=<&HkQGTgU563GPac=&sQC6n}kANb+c^}Cj08U&SEtg6~4OUC`?9`uWqql46}Xp zU-pY3nfB$A_G%SJldsmK%K7nu4{y8nL%hwPY0U%q~@qF2C)({aG~?`+W67 zJ5BZMU8N7JX*lYupXukRfV9G+cOM=Xiis8e#7F%wnpTaM_(oVL;maSuKkZP+#@FcZ zN~QHI7u17sW=yjrHM+PMESzK}J3MSE z|8I(aC| zOYjrY5hu#M!NjF>LKqd_ zeeW!eDSj{A6XXeeogCHuWT|WTw-)E1YM%Xcfp?^1wHnESLw1i>_`e43hzaU2;%F5jy{Qlm&dXvL)F`w^x;fz+7D z9%fU_XI#b}W}}NTp3EL*^D1H-XAgxbq~_1YM8;D|%`b8p;|el{daOiqpx3;}_aAY- zs&~H)#$Si`2(!Ud#4M^L#Niq4!-h_14~~1%c<7)e>?xH-meQ{m4(sB0Cs-*RT&ogppc0XJ4DwjC zn`sCa7`NM?$6H(Yoyys%&9kc#b+c+xZJVmA8d%r2B^s*Q5{cTDhU(gy>b696Z9{8~ z_pzdmVxXgW+Zm|E&F1Mo&2p!XrPzC|sL-)^%=-Z62kFJ7oG)q7`(R}bb* zsI!*NMhcrT8&yc~&ukWIsN1lKdv6tY{*11tlc1`SI)Pg5eGSa0Wp=fACT`$%T;q9V Qd-PcSV0h9k)mIh#A3*FBu>b%7 delta 2917 zcmZ{me{hsX9mb#C_uls|M{;@ZxVt1I9Csu_q=@-JE{Sbt5=$(hGC*mQVnuREfJR0T zAsy0AxTFZ;7-mRc#@bFti9u8>okFIgh}Bd(*Ku?d9mY}YA0eRTk5)$QgsD!|XTN#T zIvqE&pZz}1es|w}-`jWdjZ`qP#jQRG}Y{F);m&nzKTiDv?;UGpK1F4-@=}s*M(~1&ux?;gtlF<7Y%5qT zR^yu%D78%tI9ML2cO0A$He2&{DULYCKWM!iAOjt?gDaNd3E?@bBTw;B>DVsTEz3;t zs7&#I#BEr?97TrlATB#$EXLF1>-ImigCH{_Sb-rfxR`X%DEU9rW>ght2;;0>#5q4? z8)rUf=DB4z1jBe|1xl1embKI_OF8PRo}-2 z>67~}*t5Y)|4l9V7p{PhKuVz`p{~ddF|trnz#sUK7fPYzI#uwFva3RW2REUVf<3Ao zWp<1yMwO^iY)%_BUOs0hR22PbnCl-apS3F}Uz5&bp>J_*mH4@@-VLr+mALAwQ>deQ z!&k59^US>It4qAYO1$Z-ZW;HsuXY9%``-1{4QI8gf}Mf6{;|+s9fc}HD2*!Sz@1xH5~r97EUt`puij(uLoV%!2vP|MTSsI7GcnF-7sF{ z*7*NRk;Ub?QrA@&=OQ$|D;K`A>LSeYXo->zkDXb*w;v>3)C*gM?ZQss7U4Ewj#L;R z6WC8K;j2AsuftDCN1OzI@>x6Y;<{KN9v`3J?sc()jH90{=L8|9?IqJVK-S|BxlJ;+ z3vH5cM&ef`o)KOb-V`6&%&dfIVMf>{ zY|l&6qs@AIB+hAb;he-H!cpOA;e_yv zc(=rp5+Ah>&_8Y;A}{3iunO@&)!cYNQlpfwScrcCIz^=EvB{|P$LMKppG9OGC0tN~ z)JSriLK&&KZKI4UNR1`TH7DO<##PKUhgpJgin->1+Ehl7VY0$ zV8pz`?=3fYwA?x6jlTs~`PwdI#l1_#m4Pi74tm#$H>&JZZApikIuYqoQ*V`yEAN^c z_MVT9O?Afpro9b`4||6aHSUgMznFYyY1_IB)hkNwdc1hddm)idMH8`motPVQqs5U> zBHFG(3r>eP-rI>!7F$j%&N|3CHlmOn>C%WG2rK7Zpo~mCPH8bwnZ| zQ>-*Xfiz+r263CS#p1!VR}`= zl=;GVNGH3!C(53!?Qg8h^|jRH8ncZ%Tbpvbvb_!2#$0n>YeTN7KHHLO$hGvf^wzEQ z?k?Yx{O0c#{|IX1X7ix;vCcKImU%xcPdeTFxa=c}FN~c^k z6svP_3>9sI2szpZka{OA) RTRNz(W~ZX5TWY*6_;2WD