Merge upstream to 1.7.2a

This commit is contained in:
Sachin 2025-01-15 17:36:19 +05:30
commit 75b36a0a98
24 changed files with 660 additions and 280 deletions

Binary file not shown.

View file

@ -25,14 +25,14 @@ public class CS2_SimpleAdminApi : ICS2_SimpleAdminApi
return PlayerPenaltyManager.GetAllPlayerPenalties(player.Slot); return PlayerPenaltyManager.GetAllPlayerPenalties(player.Slot);
} }
public event Action<PlayerInfo, PlayerInfo?, PenaltyType, string, int, int?>? OnPlayerPenaltied; public event Action<PlayerInfo, PlayerInfo?, PenaltyType, string, int, int?, int?>? OnPlayerPenaltied;
public event Action<SteamID, PlayerInfo?, PenaltyType, string, int, int?>? OnPlayerPenaltiedAdded; public event Action<SteamID, PlayerInfo?, PenaltyType, string, int, int?, int?>? OnPlayerPenaltiedAdded;
public void OnPlayerPenaltiedEvent(PlayerInfo player, PlayerInfo? admin, PenaltyType penaltyType, string reason, 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, 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) public void IssuePenalty(CCSPlayerController player, CCSPlayerController? admin, PenaltyType penaltyType, string reason, int duration = -1)
{ {

View file

@ -19,7 +19,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)"); public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)"; public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
public override string ModuleAuthor => "daffyy & Dliix66"; public override string ModuleAuthor => "daffyy & Dliix66";
public override string ModuleVersion => "1.7.0a"; public override string ModuleVersion => "1.7.2a";
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
@ -58,6 +58,8 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
public override void OnAllPluginsLoaded(bool hotReload) public override void OnAllPluginsLoaded(bool hotReload)
{ {
new ServerManager().CheckHibernationStatus();
AddTimer(3.0f, () => ReloadAdmins(null)); AddTimer(3.0f, () => ReloadAdmins(null));
try try

View file

@ -78,7 +78,8 @@ public static class RegisterCommands
new CommandMapping("css_respawn", CS2_SimpleAdmin.Instance.OnRespawnCommand), new CommandMapping("css_respawn", CS2_SimpleAdmin.Instance.OnRespawnCommand),
new CommandMapping("css_tp", CS2_SimpleAdmin.Instance.OnGotoCommand), new CommandMapping("css_tp", CS2_SimpleAdmin.Instance.OnGotoCommand),
new CommandMapping("css_bring", CS2_SimpleAdmin.Instance.OnBringCommand), 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() public static void InitializeCommands()
@ -160,7 +161,8 @@ public static class RegisterCommands
{ "css_respawn", new Command { Aliases = ["css_respawn"] } }, { "css_respawn", new Command { Aliases = ["css_respawn"] } },
{ "css_tp", new Command { Aliases = ["css_tp", "css_tpto", "css_goto"] } }, { "css_tp", new Command { Aliases = ["css_tp", "css_tpto", "css_goto"] } },
{ "css_bring", new Command { Aliases = ["css_bring", "css_tphere"] } }, { "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"] } }
} }
}; };

View file

@ -20,8 +20,6 @@ public partial class CS2_SimpleAdmin
if (command.ArgCount < 2) if (command.ArgCount < 2)
return; return;
var reason = _localizer?["sa_unknown"] ?? "Unknown";
var targets = GetTarget(command); var targets = GetTarget(command);
if (targets == null) return; if (targets == null) return;
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, IsHLTV: false }).ToList(); var playersToTarget = targets.Players.Where(player => player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected, IsHLTV: false }).ToList();
@ -31,14 +29,20 @@ public partial class CS2_SimpleAdmin
return; return;
} }
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) var reason = command.ArgCount >= 3
reason = command.GetArg(3); ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Helper.ParsePenaltyTime(command.GetArg(2));
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!caller.CanTarget(player)) return; 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, DurationMenu.OpenMenu(caller, $"{_localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player,
ManagePlayersMenu.BanMenu); ManagePlayersMenu.BanMenu);
@ -60,12 +64,6 @@ public partial class CS2_SimpleAdmin
? caller.PlayerName ? caller.PlayerName
: (_localizer?["sa_console"] ?? "Console"); : (_localizer?["sa_console"] ?? "Console");
// Freeze player pawn if alive
if (player.PawnIsAlive)
{
player.Pawn.Value?.Freeze();
}
// Get player and admin information // Get player and admin information
var playerInfo = PlayersInfo[player.UserId.Value]; var playerInfo = PlayersInfo[player.UserId.Value];
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
@ -73,7 +71,8 @@ public partial class CS2_SimpleAdmin
// Asynchronously handle banning logic // Asynchronously handle banning logic
Task.Run(async () => 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 // Update banned players list
@ -103,13 +102,7 @@ public partial class CS2_SimpleAdmin
// Schedule a kick timer // Schedule a kick timer
if (player.UserId.HasValue) if (player.UserId.HasValue)
{ {
AddTimer(Config.OtherSettings.KickTime, () => Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKBANADDED, 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);
} }
// Execute ban command if necessary // Execute ban command if necessary
@ -127,7 +120,6 @@ public partial class CS2_SimpleAdmin
} }
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Ban, _localizer); Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Ban, _localizer);
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Ban, reason, time);
} }
[RequiresPermissions("@css/ban")] [RequiresPermissions("@css/ban")]
@ -144,11 +136,14 @@ public partial class CS2_SimpleAdmin
} }
var steamid = steamId.SteamId64.ToString(); var steamid = steamId.SteamId64.ToString();
var reason = command.ArgCount >= 3 && !string.IsNullOrEmpty(command.GetArg(3)) var reason = command.ArgCount >= 3
? command.GetArg(3) ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown"; : _localizer?["sa_unknown"] ?? "Unknown";
int.TryParse(command.GetArg(2), out var time); reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
if (!CheckValidBan(caller, time)) return; if (!CheckValidBan(caller, time)) return;
var adminInfo = caller != null && caller.UserId.HasValue var adminInfo = caller != null && caller.UserId.HasValue
@ -168,10 +163,14 @@ public partial class CS2_SimpleAdmin
} }
else else
{ {
if (!caller.CanTarget(new SteamID(steamId.SteamId64)))
return;
// Asynchronous ban operation if player is not online or not found // Asynchronous ban operation if player is not online or not found
Task.Run(async () => 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); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Ban, _localizer);
@ -183,8 +182,6 @@ public partial class CS2_SimpleAdmin
if (UnlockedCommands && Config.BanIDBan) if (UnlockedCommands && Config.BanIDBan)
Server.ExecuteCommand($"banid 1 {steamId.SteamId3}"); Server.ExecuteCommand($"banid 1 {steamId.SteamId3}");
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Ban, reason, time);
} }
[RequiresPermissions("@css/ban")] [RequiresPermissions("@css/ban")]
@ -202,11 +199,14 @@ public partial class CS2_SimpleAdmin
return; return;
} }
var reason = command.ArgCount >= 3 && !string.IsNullOrEmpty(command.GetArg(3)) var reason = command.ArgCount >= 3
? command.GetArg(3) ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown"; : _localizer?["sa_unknown"] ?? "Unknown";
int.TryParse(command.GetArg(2), out var time); reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
if (!CheckValidBan(caller, time)) return; if (!CheckValidBan(caller, time)) return;
var adminInfo = caller != null && caller.UserId.HasValue var adminInfo = caller != null && caller.UserId.HasValue
@ -270,7 +270,11 @@ public partial class CS2_SimpleAdmin
} }
var pattern = command.GetArg(1); 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)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
Task.Run(async () => await BanManager.UnbanPlayer(pattern, callerSteamId, reason)); Task.Run(async () => await BanManager.UnbanPlayer(pattern, callerSteamId, reason));
@ -289,8 +293,6 @@ public partial class CS2_SimpleAdmin
if (command.ArgCount < 2) if (command.ArgCount < 2)
return; return;
var reason = _localizer?["sa_unknown"] ?? "Unknown";
var targets = GetTarget(command); var targets = GetTarget(command);
if (targets == null) return; if (targets == null) return;
var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList(); var playersToTarget = targets.Players.Where(player => player.IsValid && player.Connected == PlayerConnectedState.PlayerConnected && !player.IsHLTV).ToList();
@ -302,10 +304,12 @@ public partial class CS2_SimpleAdmin
WarnManager warnManager = new(Database); WarnManager warnManager = new(Database);
int.TryParse(command.GetArg(2), out var time); 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)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
reason = command.GetArg(3);
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
@ -342,7 +346,8 @@ public partial class CS2_SimpleAdmin
Task.Run(async () => Task.Run(async () =>
{ {
warnManager ??= new WarnManager(Database); 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 // Check for warn thresholds and execute punish command if applicable
var totalWarns = await warnManager.GetPlayerWarnsCount(player.SteamID.ToString()); var totalWarns = await warnManager.GetPlayerWarnsCount(player.SteamID.ToString());
@ -392,7 +397,6 @@ public partial class CS2_SimpleAdmin
// Send Discord notification for the warning // Send Discord notification for the warning
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Warn, _localizer); Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Warn, _localizer);
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Warn, reason, time);
} }
[RequiresPermissions("@css/kick")] [RequiresPermissions("@css/kick")]

View file

@ -15,6 +15,7 @@ using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Globalization; using System.Globalization;
using System.Reflection; using System.Reflection;
using CounterStrikeSharp.API.ValveConstants.Protobuf;
using MenuManager; using MenuManager;
namespace CS2_SimpleAdmin; namespace CS2_SimpleAdmin;
@ -40,7 +41,7 @@ public partial class CS2_SimpleAdmin
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!player.UserId.HasValue) return; if (!player.UserId.HasValue) return;
if (!caller!.CanTarget(player)) return; if (!caller.CanTarget(player)) return;
userId = player.UserId.Value; 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")] [RequiresPermissions("@css/generic")]
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
public void OnAdminCommand(CCSPlayerController? caller, CommandInfo command) 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") || var globalAdmin = command.GetArg(4).ToLower().Equals("-g") || command.GetArg(5).ToLower().Equals("-g") ||
command.GetArg(6).ToLower().Equals("-g"); command.GetArg(6).ToLower().Equals("-g");
int.TryParse(command.GetArg(4), out var immunity); 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); AddAdmin(caller, steamid, name, flags, immunity, time, globalAdmin, command);
} }
@ -514,6 +547,23 @@ public partial class CS2_SimpleAdmin
ReasonMenu.OpenMenu(caller, PenaltyType.Ban, _localizer["sa_reason"], player, (_, _, reason) => ReasonMenu.OpenMenu(caller, PenaltyType.Ban, _localizer["sa_reason"], player, (_, _, reason) =>
{ {
caller.ExecuteClientCommandFromServer($"css_addban {player.SteamId.SteamId64} {duration} \"{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"], (_, _) => disconnectedMenuAction?.AddMenuOption(_localizer["sa_mute"], (_, _) =>
@ -522,6 +572,23 @@ public partial class CS2_SimpleAdmin
ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) => ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) =>
{ {
caller.ExecuteClientCommandFromServer($"css_addmute {player.SteamId.SteamId64} {duration} \"{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"], (_, _) => disconnectedMenuAction?.AddMenuOption(_localizer["sa_gag"], (_, _) =>
@ -530,6 +597,23 @@ public partial class CS2_SimpleAdmin
ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) => ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) =>
{ {
caller.ExecuteClientCommandFromServer($"css_addgag {player.SteamId.SteamId64} {duration} \"{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"], (_, _) => disconnectedMenuAction?.AddMenuOption(_localizer["sa_silence"], (_, _) =>
@ -538,6 +622,23 @@ public partial class CS2_SimpleAdmin
ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) => ReasonMenu.OpenMenu(caller, PenaltyType.Mute, _localizer["sa_reason"], player, (_, _, reason) =>
{ {
caller.ExecuteClientCommandFromServer($"css_addsilence {player.SteamId.SteamId64} {duration} \"{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);
})); }));
}); });
@ -567,7 +668,7 @@ public partial class CS2_SimpleAdmin
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!player.UserId.HasValue) return; if (!player.UserId.HasValue) return;
if (!caller!.CanTarget(player)) return; if (!caller.CanTarget(player)) return;
var userId = player.UserId.Value; var userId = player.UserId.Value;
@ -617,27 +718,27 @@ public partial class CS2_SimpleAdmin
{ {
if (caller != null) if (caller != null)
{ {
caller.PrintToConsole($"--------- PLAYER LIST ---------"); caller.PrintToConsole("--------- PLAYER LIST ---------");
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
caller.PrintToConsole( caller.PrintToConsole(
$"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{(AdminManager.PlayerHasPermissions(caller, "@css/showip") ? player.IpAddress?.Split(":")[0] : "Unknown")}\" SteamID64: \"{player.SteamID}\")"); $"• [#{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 else
{ {
Server.PrintToConsole($"--------- PLAYER LIST ---------"); Server.PrintToConsole("--------- PLAYER LIST ---------");
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
Server.PrintToConsole($"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")"); 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 else
{ {
var playersJson = JsonConvert.SerializeObject(playersToTarget.Select((CCSPlayerController player) => var playersJson = JsonConvert.SerializeObject(playersToTarget.Select(player =>
{ {
var matchStats = player.ActionTrackingServices?.MatchStats; var matchStats = player.ActionTrackingServices?.MatchStats;
@ -671,7 +772,6 @@ public partial class CS2_SimpleAdmin
public void OnKickCommand(CCSPlayerController? caller, CommandInfo command) public void OnKickCommand(CCSPlayerController? caller, CommandInfo command)
{ {
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
var reason = _localizer?["sa_unknown"] ?? "Unknown";
var targets = GetTarget(command); var targets = GetTarget(command);
@ -684,8 +784,11 @@ public partial class CS2_SimpleAdmin
return; return;
} }
if (command.ArgCount >= 2 && command.GetArg(2).Length > 0) var reason = command.ArgCount >= 2
reason = command.GetArg(2); ? string.Join(" ", Enumerable.Range(2, command.ArgCount - 2).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
@ -712,12 +815,6 @@ public partial class CS2_SimpleAdmin
var playerInfo = PlayersInfo[player.UserId.Value]; var playerInfo = PlayersInfo[player.UserId.Value];
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; 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 // Determine message keys and arguments for the kick notification
var (messageKey, activityMessageKey, centerArgs, adminActivityArgs) = var (messageKey, activityMessageKey, centerArgs, adminActivityArgs) =
("sa_player_kick_message", "sa_admin_kick_message", ("sa_player_kick_message", "sa_admin_kick_message",
@ -736,13 +833,7 @@ public partial class CS2_SimpleAdmin
// Schedule the kick for the player // Schedule the kick for the player
if (player.UserId.HasValue) if (player.UserId.HasValue)
{ {
AddTimer(Config.OtherSettings.KickTime, () => Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_KICKED, Config.OtherSettings.KickTime);
{
if (player.IsValid)
{
Helper.KickPlayer(player.UserId.Value);
}
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
} }
// Log the command and send Discord notification // Log the command and send Discord notification
@ -751,7 +842,7 @@ public partial class CS2_SimpleAdmin
else else
Helper.LogCommand(caller, command); Helper.LogCommand(caller, command);
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Kick, reason); SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Kick, reason, -1, null);
} }
[RequiresPermissions("@css/changemap")] [RequiresPermissions("@css/changemap")]

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Entities;
using CS2_SimpleAdmin.Managers; using CS2_SimpleAdmin.Managers;
using CS2_SimpleAdmin.Menus; using CS2_SimpleAdmin.Menus;
using CS2_SimpleAdminApi; using CS2_SimpleAdminApi;
@ -17,8 +18,6 @@ public partial class CS2_SimpleAdmin
if (Database == null) return; if (Database == null) return;
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
var reason = _localizer?["sa_unknown"] ?? "Unknown";
var targets = GetTarget(command); var targets = GetTarget(command);
if (targets == null) return; if (targets == null) return;
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
@ -28,13 +27,18 @@ public partial class CS2_SimpleAdmin
return; return;
} }
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) var reason = command.ArgCount >= 3
reason = command.GetArg(3); ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Helper.ParsePenaltyTime(command.GetArg(2));
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!caller!.CanTarget(player)) return; 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, DurationMenu.OpenMenu(caller, $"{_localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player,
ManagePlayersMenu.GagMenu); ManagePlayersMenu.GagMenu);
@ -61,7 +65,8 @@ public partial class CS2_SimpleAdmin
// Asynchronously handle gag logic // Asynchronously handle gag logic
Task.Run(async () => 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 // Add penalty to the player's penalty manager
@ -98,7 +103,6 @@ public partial class CS2_SimpleAdmin
} }
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Gag, _localizer); Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Gag, _localizer);
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Gag, reason, time);
} }
[RequiresPermissions("@css/chat")] [RequiresPermissions("@css/chat")]
@ -121,11 +125,13 @@ public partial class CS2_SimpleAdmin
} }
var steamid = steamId.SteamId64.ToString(); var steamid = steamId.SteamId64.ToString();
var reason = command.ArgCount >= 3 && command.GetArg(3).Length > 0 var reason = command.ArgCount >= 3
? command.GetArg(3) ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: (_localizer?["sa_unknown"] ?? "Unknown"); : _localizer?["sa_unknown"] ?? "Unknown";
int.TryParse(command.GetArg(2), out var time); reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
if (!CheckValidMute(caller, time)) return; if (!CheckValidMute(caller, time)) return;
// Get player and admin info // Get player and admin info
@ -145,10 +151,14 @@ public partial class CS2_SimpleAdmin
} }
else else
{ {
if (!caller.CanTarget(new SteamID(steamId.SteamId64)))
return;
// Asynchronous gag operation for offline players // Asynchronous gag operation for offline players
Task.Run(async () => 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); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Gag, _localizer);
@ -158,7 +168,6 @@ public partial class CS2_SimpleAdmin
// Log the gag command and respond to the command // Log the gag command and respond to the command
Helper.LogCommand(caller, command); Helper.LogCommand(caller, command);
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Gag, reason, time);
} }
[RequiresPermissions("@css/chat")] [RequiresPermissions("@css/chat")]
@ -169,7 +178,11 @@ public partial class CS2_SimpleAdmin
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
var pattern = command.GetArg(1); 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)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
if (pattern.Length <= 1) if (pattern.Length <= 1)
{ {
@ -235,8 +248,6 @@ public partial class CS2_SimpleAdmin
if (Database == null) return; if (Database == null) return;
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
var reason = _localizer?["sa_unknown"] ?? "Unknown";
var targets = GetTarget(command); var targets = GetTarget(command);
if (targets == null) return; if (targets == null) return;
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
@ -246,13 +257,18 @@ public partial class CS2_SimpleAdmin
return; return;
} }
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) var reason = command.ArgCount >= 3
reason = command.GetArg(3); ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Helper.ParsePenaltyTime(command.GetArg(2));
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!caller!.CanTarget(player)) return; 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, DurationMenu.OpenMenu(caller, $"{_localizer?["sa_mute"] ?? "Mute"}: {player.PlayerName}", player,
ManagePlayersMenu.MuteMenu); ManagePlayersMenu.MuteMenu);
@ -283,7 +299,8 @@ public partial class CS2_SimpleAdmin
// Asynchronously handle mute logic // Asynchronously handle mute logic
Task.Run(async () => 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 // Add penalty to the player's penalty manager
@ -320,7 +337,6 @@ public partial class CS2_SimpleAdmin
} }
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Mute, _localizer); Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Mute, _localizer);
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Mute, reason, time);
} }
[RequiresPermissions("@css/chat")] [RequiresPermissions("@css/chat")]
@ -343,11 +359,13 @@ public partial class CS2_SimpleAdmin
} }
var steamid = steamId.SteamId64.ToString(); var steamid = steamId.SteamId64.ToString();
var reason = command.ArgCount >= 3 && command.GetArg(3).Length > 0 var reason = command.ArgCount >= 3
? command.GetArg(3) ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: (_localizer?["sa_unknown"] ?? "Unknown"); : _localizer?["sa_unknown"] ?? "Unknown";
int.TryParse(command.GetArg(2), out var time); reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
if (!CheckValidMute(caller, time)) return; if (!CheckValidMute(caller, time)) return;
// Get player and admin info // Get player and admin info
@ -367,10 +385,14 @@ public partial class CS2_SimpleAdmin
} }
else else
{ {
if (!caller.CanTarget(new SteamID(steamId.SteamId64)))
return;
// Asynchronous mute operation for offline players // Asynchronous mute operation for offline players
Task.Run(async () => 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); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Mute, _localizer);
@ -380,7 +402,6 @@ public partial class CS2_SimpleAdmin
// Log the mute command and respond to the command // Log the mute command and respond to the command
Helper.LogCommand(caller, command); Helper.LogCommand(caller, command);
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Mute, reason, time);
} }
[RequiresPermissions("@css/chat")] [RequiresPermissions("@css/chat")]
@ -391,7 +412,11 @@ public partial class CS2_SimpleAdmin
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
var pattern = command.GetArg(1); 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)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
if (pattern.Length <= 1) if (pattern.Length <= 1)
{ {
@ -461,8 +486,6 @@ public partial class CS2_SimpleAdmin
if (Database == null) return; if (Database == null) return;
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
var reason = _localizer?["sa_unknown"] ?? "Unknown";
var targets = GetTarget(command); var targets = GetTarget(command);
if (targets == null) return; if (targets == null) return;
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
@ -472,13 +495,18 @@ public partial class CS2_SimpleAdmin
return; return;
} }
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) var reason = command.ArgCount >= 3
reason = command.GetArg(3); ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Helper.ParsePenaltyTime(command.GetArg(2));
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!caller!.CanTarget(player)) return; 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, DurationMenu.OpenMenu(caller, $"{_localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player,
ManagePlayersMenu.SilenceMenu); ManagePlayersMenu.SilenceMenu);
@ -509,7 +537,8 @@ public partial class CS2_SimpleAdmin
// Asynchronously handle silence logic // Asynchronously handle silence logic
Task.Run(async () => 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 // Add penalty to the player's penalty manager
@ -547,7 +576,6 @@ public partial class CS2_SimpleAdmin
} }
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Silence, _localizer); Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Silence, _localizer);
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Silence, reason, time);
} }
[RequiresPermissions("@css/chat")] [RequiresPermissions("@css/chat")]
@ -570,11 +598,13 @@ public partial class CS2_SimpleAdmin
} }
var steamid = steamId.SteamId64.ToString(); var steamid = steamId.SteamId64.ToString();
var reason = command.ArgCount >= 3 && command.GetArg(3).Length > 0 var reason = command.ArgCount >= 3
? command.GetArg(3) ? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
: (_localizer?["sa_unknown"] ?? "Unknown"); : _localizer?["sa_unknown"] ?? "Unknown";
int.TryParse(command.GetArg(2), out var time); reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
if (!CheckValidMute(caller, time)) return; if (!CheckValidMute(caller, time)) return;
// Get player and admin info // Get player and admin info
@ -594,10 +624,14 @@ public partial class CS2_SimpleAdmin
} }
else else
{ {
if (!caller.CanTarget(new SteamID(steamId.SteamId64)))
return;
// Asynchronous silence operation for offline players // Asynchronous silence operation for offline players
Task.Run(async () => 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); Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Silence, _localizer);
@ -607,7 +641,6 @@ public partial class CS2_SimpleAdmin
// Log the silence command and respond to the command // Log the silence command and respond to the command
Helper.LogCommand(caller, command); Helper.LogCommand(caller, command);
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Silence, reason, time);
} }
[RequiresPermissions("@css/chat")] [RequiresPermissions("@css/chat")]
@ -618,7 +651,11 @@ public partial class CS2_SimpleAdmin
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console"; var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
var pattern = command.GetArg(1); 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)).Trim()
: _localizer?["sa_unknown"] ?? "Unknown";
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
if (pattern.Length <= 1) if (pattern.Length <= 1)
{ {

View file

@ -0,0 +1 @@
ALTER TABLE `sa_servers` ADD `rcon_password` varchar(128) NULL AFTER `hostname`;

View file

@ -59,7 +59,7 @@ public partial class CS2_SimpleAdmin
new ServerManager().LoadServerData(); new ServerManager().LoadServerData();
} }
[GameEventHandler] [GameEventHandler(HookMode.Pre)]
public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info) public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
{ {
var player = @event.Userid; var player = @event.Userid;
@ -103,7 +103,12 @@ public partial class CS2_SimpleAdmin
GravityPlayers.Remove(player); GravityPlayers.Remove(player);
if (player.UserId.HasValue) if (player.UserId.HasValue)
{
if (@event.Reason == 149)
info.DontBroadcast = true;
PlayersInfo.TryRemove(player.UserId.Value, out _); PlayersInfo.TryRemove(player.UserId.Value, out _);
}
var authorizedSteamId = player.AuthorizedSteamID; var authorizedSteamId = player.AuthorizedSteamID;
if (authorizedSteamId == null || !PermissionManager.AdminCache.TryGetValue(authorizedSteamId, if (authorizedSteamId == null || !PermissionManager.AdminCache.TryGetValue(authorizedSteamId,
@ -151,7 +156,11 @@ public partial class CS2_SimpleAdmin
if (player == null || !player.IsValid || player.IsBot) if (player == null || !player.IsValid || player.IsBot)
return HookResult.Continue; return HookResult.Continue;
new PlayerManager().LoadPlayerData(player); if (player.UserId.HasValue && PlayersInfo.TryGetValue(player.UserId.Value, out PlayerInfo? value) &&
value.WaitingForKick)
return HookResult.Continue;
new PlayerManager().LoadPlayerData(player, true);
return HookResult.Continue; return HookResult.Continue;
} }

View file

@ -36,6 +36,14 @@ public static class PlayerExtensions
AdminManager.GetPlayerImmunity(controller) >= AdminManager.GetPlayerImmunity(target); 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) public static void SetSpeed(this CCSPlayerController? controller, float speed)
{ {
var playerPawnValue = controller?.PlayerPawn.Value; var playerPawnValue = controller?.PlayerPawn.Value;

View file

@ -106,11 +106,11 @@ internal static class Helper
); );
} }
public static bool IsValidSteamId64(string input) // public static bool IsValidSteamId64(string input)
{ // {
const string pattern = @"^\d{17}$"; // const string pattern = @"^\d{17}$";
return Regex.IsMatch(input, pattern); // return Regex.IsMatch(input, pattern);
} // }
public static bool ValidateSteamId(string input, out SteamID? steamId) public static bool ValidateSteamId(string input, out SteamID? steamId)
{ {
@ -164,14 +164,39 @@ 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); var player = Utilities.GetPlayerFromUserid(userId);
if (player == null || !player.IsValid || player.IsHLTV) if (player == null || !player.IsValid || player.IsHLTV)
return; return;
player.Disconnect(reason); 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;
Server.ExecuteCommand($"kickid {player.UserId}");
// player.Disconnect(reason); Broken after last update
});
}
else
{
Server.ExecuteCommand($"kickid {player.UserId}");
player.Disconnect(reason); // Broken after last update
}
if (CS2_SimpleAdmin.UnlockedCommands && reason == NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED)
Server.ExecuteCommand($"banid 1 {new SteamID(player.SteamID).SteamId3}");
// if (!string.IsNullOrEmpty(reason)) // if (!string.IsNullOrEmpty(reason))
// { // {
@ -186,9 +211,46 @@ internal static class Helper
// Server.ExecuteCommand($"kickid {userId} {reason}"); // 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;
// if (!string.IsNullOrEmpty(reason))
// {
// var escapeChars = reason.IndexOfAny([';', '|']);
//
// if (escapeChars != -1)
// {
// reason = reason[..escapeChars];
// }
// }
//
Server.ExecuteCommand($"kickid {player.UserId}");
// player.Disconnect(reason); // Broken after last update
});
}
else
{
Server.ExecuteCommand($"kickid {player.UserId}");
// player.Disconnect(reason); // Broken after last update
}
if (CS2_SimpleAdmin.UnlockedCommands && reason == NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED)
Server.ExecuteCommand($"banid 1 {new SteamID(player.SteamID).SteamId3}");
// if (!string.IsNullOrEmpty(reason)) // if (!string.IsNullOrEmpty(reason))
// { // {
@ -203,6 +265,57 @@ internal static class Helper
// Server.ExecuteCommand($"kickid {userId} {reason}"); // Server.ExecuteCommand($"kickid {userId} {reason}");
} }
public static int ParsePenaltyTime(string time)
{
if (string.IsNullOrWhiteSpace(time) || !time.Any(char.IsDigit))
{
// CS2_SimpleAdmin._logger?.LogError("Time string cannot be null or empty.");
return -1;
}
if (time.Equals($"0"))
return 0;
var timeUnits = new Dictionary<string, int>
{
{ "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 > 0 ? totalMinutes : -1;
}
public static void PrintToCenterAll(string message) public static void PrintToCenterAll(string message)
{ {
Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false }).ToList().ForEach(controller => Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false }).ToList().ForEach(controller =>
@ -659,28 +772,28 @@ internal static class Helper
commandString])); commandString]));
} }
public static IMenu? CreateMenu(string title) public static IMenu? CreateMenu(string title, Action<CCSPlayerController>? backAction = null)
{ {
var menuType = CS2_SimpleAdmin.Instance.Config.MenuConfigs.MenuType.ToLower(); var menuType = CS2_SimpleAdmin.Instance.Config.MenuConfigs.MenuType.ToLower();
var menu = menuType switch var menu = menuType switch
{ {
_ when menuType.Equals("selectable", StringComparison.CurrentCultureIgnoreCase) => _ when menuType.Equals("selectable", StringComparison.CurrentCultureIgnoreCase) =>
CS2_SimpleAdmin.MenuApi?.NewMenu(title), CS2_SimpleAdmin.MenuApi?.GetMenu(title),
_ when menuType.Equals("dynamic", StringComparison.CurrentCultureIgnoreCase) => _ 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) => _ 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) => _ 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) => _ 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; return menu;

View file

@ -10,9 +10,9 @@ namespace CS2_SimpleAdmin.Managers;
internal class BanManager(Database.Database? database) internal class BanManager(Database.Database? database)
{ {
public async Task BanPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0) public async Task<int?> BanPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0)
{ {
if (database == null) return; if (database == null) return null;
DateTime now = Time.ActualDateTime(); DateTime now = Time.ActualDateTime();
DateTime futureTime = now.AddMinutes(time); DateTime futureTime = now.AddMinutes(time);
@ -20,11 +20,16 @@ internal class BanManager(Database.Database? database)
await using MySqlConnection connection = await database.GetConnectionAsync(); await using MySqlConnection connection = await database.GetConnectionAsync();
try try
{ {
const string sql = 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)";
await connection.ExecuteAsync(sql, new 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();
""";
var banId = await connection.ExecuteScalarAsync<int?>(sql, new
{ {
playerSteamid = player.SteamId.SteamId64.ToString(), playerSteamid = player.SteamId.SteamId64.ToString(),
playerName = player.Name, playerName = player.Name,
@ -37,15 +42,19 @@ internal class BanManager(Database.Database? database)
created = now, created = now,
serverid = CS2_SimpleAdmin.ServerId serverid = CS2_SimpleAdmin.ServerId
}); });
}
catch { }
}
public async Task AddBanBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0) return banId;
}
catch
{ {
if (database == null) return; return null;
}
}
if (string.IsNullOrEmpty(playerSteamId)) return; public async Task<int?> AddBanBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0)
{
if (database == null) return null;
if (string.IsNullOrEmpty(playerSteamId)) return null;
DateTime now = Time.ActualDateTime(); DateTime now = Time.ActualDateTime();
DateTime futureTime = now.AddMinutes(time); DateTime futureTime = now.AddMinutes(time);
@ -54,10 +63,16 @@ internal class BanManager(Database.Database? database)
{ {
await using MySqlConnection connection = await database.GetConnectionAsync(); 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`) " + const string sql = """
"VALUES (@playerSteamid, @adminSteamid, @adminName, @banReason, @duration, @ends, @created, @serverid)";
await connection.ExecuteAsync(sql, new 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();
""";
var banId = await connection.ExecuteScalarAsync<int?>(sql, new
{ {
playerSteamid = playerSteamId, playerSteamid = playerSteamId,
adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
@ -68,8 +83,13 @@ internal class BanManager(Database.Database? database)
created = now, created = now,
serverid = CS2_SimpleAdmin.ServerId serverid = CS2_SimpleAdmin.ServerId
}); });
return banId;
}
catch (Exception)
{
return null;
} }
catch { }
} }
public async Task AddBanByIp(string playerIp, PlayerInfo? issuer, string reason, int time = 0) 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) || foreach (var player in filteredPlayers.Where(player => bannedSteamIds.Contains(player.SteamID) ||
(checkIpBans && bannedIps.Contains(player.IpAddress ?? "")))) (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(() => await Server.NextFrameAsync(() =>
{ {

View file

@ -6,9 +6,9 @@ namespace CS2_SimpleAdmin.Managers;
internal class MuteManager(Database.Database? database) 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<int?> 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 now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@ -23,11 +23,16 @@ internal class MuteManager(Database.Database? database)
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
const string sql = 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)";
await connection.ExecuteAsync(sql, new 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();
""";
var muteId = await connection.ExecuteScalarAsync<int?>(sql, new
{ {
playerSteamid = player.SteamId.SteamId64.ToString(), playerSteamid = player.SteamId.SteamId64.ToString(),
playerName = player.Name, playerName = player.Name,
@ -40,19 +45,20 @@ internal class MuteManager(Database.Database? database)
type = muteType, type = muteType,
serverid = CS2_SimpleAdmin.ServerId serverid = CS2_SimpleAdmin.ServerId
}); });
return muteId;
} }
catch (Exception ex) catch (Exception ex)
{ {
CS2_SimpleAdmin._logger?.LogError(ex.Message); 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<int?> AddMuteBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0, int type = 0)
{ {
if (database == null) return; if (database == null) return null;
if (string.IsNullOrEmpty(playerSteamId)) return null;
if (string.IsNullOrEmpty(playerSteamId)) return;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@ -67,10 +73,16 @@ internal class MuteManager(Database.Database? database)
try try
{ {
await using var connection = await database.GetConnectionAsync(); 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`) " + const string sql = """
"VALUES (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @type, @serverid)";
await connection.ExecuteAsync(sql, new 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();
""";
var muteId = await connection.ExecuteScalarAsync<int?>(sql, new
{ {
playerSteamid = playerSteamId, playerSteamid = playerSteamId,
adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
@ -82,8 +94,13 @@ internal class MuteManager(Database.Database? database)
type = muteType, type = muteType,
serverid = CS2_SimpleAdmin.ServerId serverid = CS2_SimpleAdmin.ServerId
}); });
return muteId;
}
catch
{
return null;
} }
catch { };
} }
public async Task<List<dynamic>> IsPlayerMuted(string steamId) public async Task<List<dynamic>> IsPlayerMuted(string steamId)

View file

@ -381,53 +381,72 @@ public class PermissionManager(Database.Database? database)
{ {
List<(string identity, string name, List<string> flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlagsSA(); List<(string identity, string name, List<string> flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlagsSA();
var validPlayers = allPlayers var validPlayers = allPlayers
.Where(player => SteamID.TryParse(player.identity, out _)) // Filter invalid SteamID .Where(player => SteamID.TryParse(player.identity, out _))
.ToList(); .ToList();
/* // foreach (var player in allPlayers)
foreach (var player in allPlayers) // {
{ // var (steamId, name, flags, immunity, ends) = player;
var (steamId, name, flags, immunity, ends) = player; //
// Console.WriteLine($"Player SteamID: {steamId}");
// Print or process each item // Console.WriteLine($"Player Name: {name}");
Console.WriteLine($"Player SteamID: {steamId}"); // Console.WriteLine($"Flags: {string.Join(", ", flags)}");
Console.WriteLine($"Player Name: {name}"); // Console.WriteLine($"Immunity: {immunity}");
Console.WriteLine($"Flags: {string.Join(", ", flags)}"); // Console.WriteLine($"Ends: {(ends.HasValue ? ends.Value.ToString("yyyy-MM-dd HH:mm:ss") : "Never")}");
Console.WriteLine($"Immunity: {immunity}"); // Console.WriteLine();
Console.WriteLine($"Ends: {(ends.HasValue ? ends.Value.ToString("yyyy-MM-dd HH:mm:ss") : "Never")}"); // }
Console.WriteLine(); // New line for better readability
}
*/
var jsonData = validPlayers var jsonData = validPlayers
.Select(player => .GroupBy(player => player.name) // Group by player name
.ToDictionary(
group => group.Key, // Use the player name as the key
group =>
{
// Consolidate data for players with the same name
var consolidatedData = group.Aggregate(
new
{
identity = string.Empty,
immunity = 0,
flags = new List<string>(),
groups = new List<string>()
},
(acc, player) =>
{
// Merge identities and use the latest or first non-null identity
if (string.IsNullOrEmpty(acc.identity) && !string.IsNullOrEmpty(player.identity))
{
acc = acc with { identity = player.identity };
}
// Combine immunities by taking the maximum value
acc = acc with { immunity = Math.Max(acc.immunity, player.immunity) };
// Combine flags and groups, ensuring no duplicates
acc = acc with
{
flags = acc.flags.Concat(player.flags.Where(flag => flag.StartsWith($"@"))).Distinct().ToList(),
groups = acc.groups.Concat(player.flags.Where(flag => flag.StartsWith($"#"))).Distinct().ToList()
};
return acc;
});
foreach (var player in group)
{ {
SteamID.TryParse(player.identity, out var steamId); SteamID.TryParse(player.identity, out var steamId);
// Update cache if SteamID is valid and not already cached
if (steamId != null && !AdminCache.ContainsKey(steamId)) if (steamId != null && !AdminCache.ContainsKey(steamId))
{ {
AdminCache.TryAdd(steamId, player.ends); AdminCache.TryAdd(steamId, player.ends);
} }
// Create an anonymous object with player data
return new
{
playerName = player.name,
playerData = new
{
player.identity,
player.immunity,
flags = player.flags.Where(flag => flag.StartsWith("@")).ToList(),
groups = player.flags.Where(flag => flag.StartsWith("#")).ToList()
} }
};
}) return (object)consolidatedData;
.ToDictionary(item => item.playerName, item => (object)item.playerData); });
var json = JsonConvert.SerializeObject(jsonData, Formatting.Indented); var json = JsonConvert.SerializeObject(jsonData, Formatting.Indented);
var filePath = Path.Combine(CS2_SimpleAdmin.Instance.ModuleDirectory, "data", "admins.json"); var filePath = Path.Combine(CS2_SimpleAdmin.Instance.ModuleDirectory, "data", "admins.json");
await File.WriteAllTextAsync(filePath, json); await File.WriteAllTextAsync(filePath, json);
//await File.WriteAllTextAsync(CS2_SimpleAdmin.Instance.ModuleDirectory + "/data/admins.json", json); //await File.WriteAllTextAsync(CS2_SimpleAdmin.Instance.ModuleDirectory + "/data/admins.json", json);

View file

@ -14,7 +14,7 @@ public class PlayerManager
{ {
private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config; 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")) if (player.IsBot || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1"))
return; return;
@ -134,6 +134,8 @@ public class PlayerManager
return; return;
} }
if (fullConnect)
{
var warns = await CS2_SimpleAdmin.Instance.WarnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false); var warns = await CS2_SimpleAdmin.Instance.WarnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false);
var (totalMutes, totalGags, totalSilences) = var (totalMutes, totalGags, totalSilences) =
await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]); await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]);
@ -184,8 +186,9 @@ public class PlayerManager
} }
} }
} }
}
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect) if (CS2_SimpleAdmin.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect && fullConnect)
{ {
await Server.NextFrameAsync(() => await Server.NextFrameAsync(() =>
{ {

View file

@ -9,6 +9,16 @@ public class ServerManager
{ {
private int _getIpTryCount; private int _getIpTryCount;
public void CheckHibernationStatus()
{
ConVar? convar = ConVar.Find("sv_hibernate_when_empty");
if (convar == null || !convar.GetPrimitiveValue<bool>())
return;
CS2_SimpleAdmin._logger?.LogError("Detected setting \"sv_hibernate_when_empty true\", set false to make plugin work properly");
}
public void LoadServerData() public void LoadServerData()
{ {
CS2_SimpleAdmin.Instance.AddTimer(1.2f, () => CS2_SimpleAdmin.Instance.AddTimer(1.2f, () =>

View file

@ -6,9 +6,9 @@ namespace CS2_SimpleAdmin.Managers;
internal class WarnManager(Database.Database? database) internal class WarnManager(Database.Database? database)
{ {
public async Task WarnPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0) public async Task<int?> WarnPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0)
{ {
if (database == null) return; if (database == null) return null;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@ -16,11 +16,16 @@ internal class WarnManager(Database.Database? database)
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
const string sql = 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)";
await connection.ExecuteAsync(sql, new 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();
""";
var warnId = await connection.ExecuteScalarAsync<int?>(sql, new
{ {
playerSteamid = player.SteamId.SteamId64.ToString(), playerSteamid = player.SteamId.SteamId64.ToString(),
playerName = player.Name, playerName = player.Name,
@ -32,14 +37,19 @@ internal class WarnManager(Database.Database? database)
created = now, created = now,
serverid = CS2_SimpleAdmin.ServerId 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<int?> AddWarnBySteamid(string playerSteamId, PlayerInfo? issuer, string reason, int time = 0)
{ {
if (database == null) return; if (database == null) return null;
if (string.IsNullOrEmpty(playerSteamId)) return; if (string.IsNullOrEmpty(playerSteamId)) return null;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@ -47,10 +57,16 @@ internal class WarnManager(Database.Database? database)
try try
{ {
await using var connection = await database.GetConnectionAsync(); 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`) " + const string sql = """
"VALUES (@playerSteamid, @adminSteamid, @adminName, @muteReason, @duration, @ends, @created, @serverid)";
await connection.ExecuteAsync(sql, new 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();
""";
var warnId = await connection.ExecuteScalarAsync<int?>(sql, new
{ {
playerSteamid = playerSteamId, playerSteamid = playerSteamId,
adminSteamid = issuer?.SteamId.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", adminSteamid = issuer?.SteamId.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
@ -61,8 +77,13 @@ internal class WarnManager(Database.Database? database)
created = now, created = now,
serverid = CS2_SimpleAdmin.ServerId serverid = CS2_SimpleAdmin.ServerId
}); });
return warnId;
}
catch
{
return null;
} }
catch { };
} }
public async Task<List<dynamic>> GetPlayerWarns(PlayerInfo player, bool active = true) public async Task<List<dynamic>> GetPlayerWarns(PlayerInfo player, bool active = true)
@ -153,14 +174,32 @@ internal class WarnManager(Database.Database? database)
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
? "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND player_steamid = @steamid AND id = (SELECT MAX(id) FROM sa_warns WHERE player_steamid = @steamid AND status = 'ACTIVE')" ? """
: "UPDATE sa_warns SET status = 'EXPIRED' WHERE status = 'ACTIVE' AND player_steamid = @steamid AND id = (SELECT MAX(id) FROM sa_warns WHERE player_steamid = @steamid AND status = 'ACTIVE' AND server_id = @serverid)"; UPDATE sa_warns
JOIN (
SELECT MAX(id) AS max_id
FROM sa_warns
WHERE player_steamid = @steamid AND status = 'ACTIVE'
) AS subquery ON sa_warns.id = subquery.max_id
SET sa_warns.status = 'EXPIRED'
WHERE sa_warns.status = 'ACTIVE' AND sa_warns.player_steamid = @steamid;
"""
: """
UPDATE sa_warns
JOIN (
SELECT MAX(id) AS max_id
FROM sa_warns
WHERE player_steamid = @steamid AND status = 'ACTIVE' AND server_id = @serverid
) AS subquery ON sa_warns.id = subquery.max_id
SET sa_warns.status = 'EXPIRED'
WHERE sa_warns.status = 'ACTIVE' AND sa_warns.player_steamid = @steamid AND sa_warns.server_id = @serverid;
""";
await connection.ExecuteAsync(sql, new { steamid = playerPattern, serverid = CS2_SimpleAdmin.ServerId }); await connection.ExecuteAsync(sql, new { steamid = playerPattern, serverid = CS2_SimpleAdmin.ServerId });
} }
catch (Exception ex) catch (Exception ex)
{ {
CS2_SimpleAdmin._logger?.LogCritical($"Unable to remove last warn + {ex}"); CS2_SimpleAdmin._logger?.LogCritical("Unable to remove last warn {exception}", ex.Message);
} }
} }

View file

@ -6,9 +6,9 @@ namespace CS2_SimpleAdmin.Menus;
public static class AdminMenu public static class AdminMenu
{ {
public static IMenu? CreateMenu(string title) public static IMenu? CreateMenu(string title, Action<CCSPlayerController>? 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); // return CS2_SimpleAdmin.Instance.Config.UseChatMenu ? new ChatMenu(title) : new CenterHtmlMenu(title, CS2_SimpleAdmin.Instance);
} }

View file

@ -1 +1 @@
1.7.0a 1.7.2a

View file

@ -17,8 +17,8 @@ public interface ICS2_SimpleAdminApi
public Dictionary<PenaltyType, List<(DateTime EndDateTime, int Duration, bool Passed)>> GetPlayerMuteStatus(CCSPlayerController player); public Dictionary<PenaltyType, List<(DateTime EndDateTime, int Duration, bool Passed)>> GetPlayerMuteStatus(CCSPlayerController player);
public event Action<PlayerInfo, PlayerInfo?, PenaltyType, string, int, int?>? OnPlayerPenaltied; public event Action<PlayerInfo, PlayerInfo?, PenaltyType, string, int, int?, int?>? OnPlayerPenaltied;
public event Action<SteamID, PlayerInfo?, PenaltyType, string, int, int?>? OnPlayerPenaltiedAdded; public event Action<SteamID, PlayerInfo?, PenaltyType, string, int, int?, int?>? OnPlayerPenaltiedAdded;
public void IssuePenalty(CCSPlayerController player, CCSPlayerController? admin, PenaltyType penaltyType, string reason, int duration = -1); public void IssuePenalty(CCSPlayerController player, CCSPlayerController? admin, PenaltyType penaltyType, string reason, int duration = -1);
public void LogCommand(CCSPlayerController? caller, string command); public void LogCommand(CCSPlayerController? caller, string command);

View file

@ -25,6 +25,7 @@ public class PlayerInfo(
public int TotalGags { get; set; } = totalGags; public int TotalGags { get; set; } = totalGags;
public int TotalSilences { get; set; } = totalSilences; public int TotalSilences { get; set; } = totalSilences;
public int TotalWarns { get; set; } = totalWarns; public int TotalWarns { get; set; } = totalWarns;
public bool WaitingForKick { get; set; } = false;
public DiePosition? DiePosition { get; set; } public DiePosition? DiePosition { get; set; }
} }

View file

@ -70,7 +70,7 @@ public class CS2_SimpleAdmin_ExampleModule: BasePlugin
} }
private void OnPlayerPenaltied(PlayerInfo player, PlayerInfo? admin, PenaltyType penaltyType, private void OnPlayerPenaltied(PlayerInfo player, PlayerInfo? admin, PenaltyType penaltyType,
string reason, int duration, int? serverId) string reason, int duration, int? penaltyId, int? serverId)
{ {
if (penaltyType == PenaltyType.Ban) if (penaltyType == PenaltyType.Ban)
{ {
@ -82,6 +82,7 @@ public class CS2_SimpleAdmin_ExampleModule: BasePlugin
case PenaltyType.Ban: case PenaltyType.Ban:
{ {
Logger.LogInformation("Ban issued"); Logger.LogInformation("Ban issued");
Logger.LogInformation($"Id = {penaltyId}");
break; break;
} }
case PenaltyType.Kick: case PenaltyType.Kick:
@ -92,6 +93,7 @@ public class CS2_SimpleAdmin_ExampleModule: BasePlugin
case PenaltyType.Gag: case PenaltyType.Gag:
{ {
Logger.LogInformation("Gag issued"); Logger.LogInformation("Gag issued");
Logger.LogInformation($"Id = {penaltyId}");
break; break;
} }
case PenaltyType.Mute: case PenaltyType.Mute:
@ -120,13 +122,14 @@ public class CS2_SimpleAdmin_ExampleModule: BasePlugin
} }
private void OnPlayerPenaltiedAdded(SteamID steamId, PlayerInfo? admin, PenaltyType penaltyType, private void OnPlayerPenaltiedAdded(SteamID steamId, PlayerInfo? admin, PenaltyType penaltyType,
string reason, int duration, int? serverId) string reason, int duration, int? penaltyId, int? serverId)
{ {
switch (penaltyType) switch (penaltyType)
{ {
case PenaltyType.Ban: case PenaltyType.Ban:
{ {
Logger.LogInformation("Ban added"); Logger.LogInformation("Ban added");
Logger.LogInformation($"Id = {penaltyId}");
break; break;
} }
case PenaltyType.Kick: case PenaltyType.Kick:
@ -137,6 +140,7 @@ public class CS2_SimpleAdmin_ExampleModule: BasePlugin
case PenaltyType.Gag: case PenaltyType.Gag:
{ {
Logger.LogInformation("Gag added"); Logger.LogInformation("Gag added");
Logger.LogInformation($"Id = {penaltyId}");
break; break;
} }
case PenaltyType.Mute: case PenaltyType.Mute: