```diff
+ Added duration and reason menu when admin try to ban/mute without specific time
+ Added `NotifyPenaltiesToAdminOnConnect` config setting to disable notifications globally
+ Added immunity check when using game vote to kick player

- Removed `Discord.Net.Webhook` package (too heavy)
```
This commit is contained in:
Dawid Bepierszcz
2024-10-05 11:45:09 +02:00
parent bd817d6652
commit 6847da2af0
20 changed files with 532 additions and 328 deletions

View File

@@ -1,19 +1,17 @@
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes; using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Capabilities; using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Core.Commands;
using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Commands.Targeting; using CounterStrikeSharp.API.Modules.Commands.Targeting;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CS2_SimpleAdmin.Managers; using CS2_SimpleAdmin.Managers;
using CS2_SimpleAdminApi; using CS2_SimpleAdminApi;
using Discord.Webhook;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MySqlConnector; using MySqlConnector;
namespace CS2_SimpleAdmin; namespace CS2_SimpleAdmin;
[MinimumApiVersion(260)] [MinimumApiVersion(271)]
public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdminConfig> public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdminConfig>
{ {
internal static CS2_SimpleAdmin Instance { get; private set; } = new(); internal static CS2_SimpleAdmin Instance { get; private set; } = new();
@@ -21,10 +19,8 @@ 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.6.1b"; public override string ModuleVersion => "1.6.2a";
public CS2_SimpleAdminConfig Config { get; set; } = new();
public override void Load(bool hotReload) public override void Load(bool hotReload)
{ {
Instance = this; Instance = this;
@@ -98,6 +94,11 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
} }
Task.Run(() => Database.DatabaseMigration()); Task.Run(() => Database.DatabaseMigration());
PermissionManager = new PermissionManager(Database);
BanManager = new BanManager(Database);
MuteManager = new MuteManager(Database);
WarnManager = new WarnManager(Database);
Config = config; Config = config;
Helper.UpdateConfig(config); Helper.UpdateConfig(config);
@@ -110,7 +111,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
_localizer = Localizer; _localizer = Localizer;
if (!string.IsNullOrEmpty(Config.Discord.DiscordLogWebhook)) if (!string.IsNullOrEmpty(Config.Discord.DiscordLogWebhook))
DiscordWebhookClientLog = new DiscordWebhookClient(Config.Discord.DiscordLogWebhook); DiscordWebhookClientLog = new DiscordManager(Config.Discord.DiscordLogWebhook);
PluginInfo.ShowAd(ModuleVersion); PluginInfo.ShowAd(ModuleVersion);
if (Config.EnableUpdateCheck) if (Config.EnableUpdateCheck)

View File

@@ -12,7 +12,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.266" /> <PackageReference Include="CounterStrikeSharp.API" Version="1.0.266" />
<PackageReference Include="Dapper" Version="2.1.35" /> <PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Discord.Net.Webhook" Version="3.16.0" />
<PackageReference Include="MySqlConnector" Version="2.3.7" /> <PackageReference Include="MySqlConnector" Version="2.3.7" />
<PackageReference Include="Newtonsoft.Json" Version="*" /> <PackageReference Include="Newtonsoft.Json" Version="*" />
</ItemGroup> </ItemGroup>

View File

@@ -1,11 +1,11 @@
using CounterStrikeSharp.API; using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes.Registration;
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 CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.ValveConstants.Protobuf; using CounterStrikeSharp.API.ValveConstants.Protobuf;
using CS2_SimpleAdmin.Managers; using CS2_SimpleAdmin.Managers;
using CS2_SimpleAdmin.Menus;
using CS2_SimpleAdminApi; using CS2_SimpleAdminApi;
namespace CS2_SimpleAdmin; namespace CS2_SimpleAdmin;
@@ -30,21 +30,22 @@ public partial class CS2_SimpleAdmin
{ {
return; return;
} }
Database.Database database = new(DbConnectionString);
BanManager banManager = new(database, Config);
int.TryParse(command.GetArg(2), out var time);
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
reason = command.GetArg(3); reason = command.GetArg(3);
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (caller!.CanTarget(player)) if (!caller.CanTarget(player)) return;
if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid)
{ {
Ban(caller, player, time, reason, callerName, banManager, command); DurationMenu.OpenMenu(caller, $"{_localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player,
ManagePlayersMenu.BanMenu);
return;
} }
Ban(caller, player, time, reason, callerName, BanManager, command);
}); });
} }
@@ -70,7 +71,7 @@ public partial class CS2_SimpleAdmin
// Asynchronously handle banning logic // Asynchronously handle banning logic
Task.Run(async () => Task.Run(async () =>
{ {
await (banManager ??= new BanManager(Database, Config)).BanPlayer(playerInfo, adminInfo, reason, time); await BanManager.BanPlayer(playerInfo, adminInfo, reason, time);
}); });
// Update banned players list // Update banned players list
@@ -168,8 +169,7 @@ public partial class CS2_SimpleAdmin
// 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 () =>
{ {
var banManager = new BanManager(Database, Config); await BanManager.AddBanBySteamid(steamid, adminInfo, reason, time);
await banManager.AddBanBySteamid(steamid, adminInfo, reason, time);
}); });
command.ReplyToCommand($"Player with steamid {steamid} is not online. Ban has been added offline."); command.ReplyToCommand($"Player with steamid {steamid} is not online. Ban has been added offline.");
@@ -224,8 +224,7 @@ public partial class CS2_SimpleAdmin
// 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 () =>
{ {
var banManager = new BanManager(Database, Config); await BanManager.AddBanByIp(ipAddress, adminInfo, reason, time);
await banManager.AddBanByIp(ipAddress, adminInfo, reason, time);
}); });
command.ReplyToCommand($"Player with ip {ipAddress} is not online. Ban has been added offline."); command.ReplyToCommand($"Player with ip {ipAddress} is not online. Ban has been added offline.");
@@ -269,8 +268,7 @@ public partial class CS2_SimpleAdmin
var pattern = command.GetArg(1); var pattern = command.GetArg(1);
var reason = command.GetArg(2); var reason = command.GetArg(2);
BanManager banManager = new(Database, Config); Task.Run(async () => await BanManager.UnbanPlayer(pattern, callerSteamId, reason));
Task.Run(async () => await banManager.UnbanPlayer(pattern, callerSteamId, reason));
Helper.LogCommand(caller, command); Helper.LogCommand(caller, command);
@@ -406,8 +404,7 @@ public partial class CS2_SimpleAdmin
var pattern = command.GetArg(1); var pattern = command.GetArg(1);
WarnManager warnManager = new(Database); Task.Run(async () => await WarnManager.UnwarnPlayer(pattern));
Task.Run(async () => await warnManager.UnwarnPlayer(pattern));
Helper.LogCommand(caller, command); Helper.LogCommand(caller, command);
command.ReplyToCommand($"Unwarned player with pattern {pattern}."); command.ReplyToCommand($"Unwarned player with pattern {pattern}.");

View File

@@ -29,16 +29,12 @@ public partial class CS2_SimpleAdmin
Task.Run(async () => Task.Run(async () =>
{ {
// Initialize managers
MuteManager muteManager = new(Database);
WarnManager warnManager = new(Database);
try try
{ {
var warns = await warnManager.GetPlayerWarns(PlayersInfo[userId], false); var warns = await WarnManager.GetPlayerWarns(PlayersInfo[userId], false);
// Check if the player is muted // Check if the player is muted
var activeMutes = await muteManager.IsPlayerMuted(PlayersInfo[userId].SteamId.SteamId64.ToString()); var activeMutes = await MuteManager.IsPlayerMuted(PlayersInfo[userId].SteamId.SteamId64.ToString());
Dictionary<PenaltyType, List<string>> mutesList = new() Dictionary<PenaltyType, List<string>> mutesList = new()
{ {
@@ -221,8 +217,7 @@ public partial class CS2_SimpleAdmin
public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool globalDelete = false, CommandInfo? command = null) public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool globalDelete = false, CommandInfo? command = null)
{ {
if (Database == null) return; if (Database == null) return;
PermissionManager adminManager = new(Database); _ = PermissionManager.DeleteAdminBySteamId(steamid, globalDelete);
_ = adminManager.DeleteAdminBySteamId(steamid, globalDelete);
AddTimer(2, () => AddTimer(2, () =>
{ {
@@ -313,8 +308,7 @@ public partial class CS2_SimpleAdmin
private void RemoveGroup(CCSPlayerController? caller, string name, CommandInfo? command = null) private void RemoveGroup(CCSPlayerController? caller, string name, CommandInfo? command = null)
{ {
if (Database == null) return; if (Database == null) return;
PermissionManager adminManager = new(Database); _ = PermissionManager.DeleteGroup(name);
_ = adminManager.DeleteGroup(name);
AddTimer(2, () => AddTimer(2, () =>
{ {
@@ -551,9 +545,6 @@ public partial class CS2_SimpleAdmin
if (playersToTarget.Count > 1) if (playersToTarget.Count > 1)
return; return;
Database.Database database = new(DbConnectionString);
WarnManager warnManager = new(database);
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (!player.UserId.HasValue) return; if (!player.UserId.HasValue) return;
@@ -565,7 +556,7 @@ public partial class CS2_SimpleAdmin
Task.Run(async () => Task.Run(async () =>
{ {
var warnsList = await warnManager.GetPlayerWarns(PlayersInfo[userId], false); var warnsList = await WarnManager.GetPlayerWarns(PlayersInfo[userId], false);
var sortedWarns = warnsList var sortedWarns = warnsList
.OrderBy(warn => (string)warn.status == "ACTIVE" ? 0 : 1) .OrderBy(warn => (string)warn.status == "ACTIVE" ? 0 : 1)
.ThenByDescending(warn => (int)warn.id) .ThenByDescending(warn => (int)warn.id)
@@ -576,7 +567,7 @@ public partial class CS2_SimpleAdmin
warnsMenu?.AddMenuOption($"[{((string)w.status == "ACTIVE" ? $"{ChatColors.LightRed}X" : $"{ChatColors.Lime}")}{ChatColors.Default}] {(string)w.reason}", warnsMenu?.AddMenuOption($"[{((string)w.status == "ACTIVE" ? $"{ChatColors.LightRed}X" : $"{ChatColors.Lime}")}{ChatColors.Default}] {(string)w.reason}",
(controller, option) => (controller, option) =>
{ {
_ = warnManager.UnwarnPlayer(PlayersInfo[userId], (int)w.id); _ = WarnManager.UnwarnPlayer(PlayersInfo[userId], (int)w.id);
player.PrintToChat(_localizer["sa_admin_warns_unwarn", player.PlayerName, (string)w.reason]); player.PrintToChat(_localizer["sa_admin_warns_unwarn", player.PlayerName, (string)w.reason]);
}); });
}); });

View File

@@ -4,6 +4,7 @@ using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Commands;
using CS2_SimpleAdmin.Managers; using CS2_SimpleAdmin.Managers;
using CS2_SimpleAdmin.Menus;
using CS2_SimpleAdminApi; using CS2_SimpleAdminApi;
namespace CS2_SimpleAdmin; namespace CS2_SimpleAdmin;
@@ -27,20 +28,21 @@ public partial class CS2_SimpleAdmin
{ {
return; return;
} }
int.TryParse(command.GetArg(2), out var time);
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
reason = command.GetArg(3); reason = command.GetArg(3);
MuteManager muteManager = new(Database);
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (caller!.CanTarget(player)) if (!caller!.CanTarget(player)) return;
if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid)
{ {
Gag(caller, player, time, reason, callerName, muteManager, command); DurationMenu.OpenMenu(caller, $"{_localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player,
ManagePlayersMenu.GagMenu);
return;
} }
Gag(caller, player, time, reason, callerName, MuteManager, command);
}); });
} }
@@ -124,7 +126,6 @@ public partial class CS2_SimpleAdmin
? command.GetArg(3) ? command.GetArg(3)
: (_localizer?["sa_unknown"] ?? "Unknown"); : (_localizer?["sa_unknown"] ?? "Unknown");
MuteManager muteManager = new(Database);
int.TryParse(command.GetArg(2), out var time); int.TryParse(command.GetArg(2), out var time);
// Get player and admin info // Get player and admin info
@@ -140,14 +141,14 @@ public partial class CS2_SimpleAdmin
if (!caller.CanTarget(player)) return; if (!caller.CanTarget(player)) return;
// Perform the gag for an online player // Perform the gag for an online player
Gag(caller, player, time, reason, callerName, muteManager, silent: true); Gag(caller, player, time, reason, callerName, MuteManager, silent: true);
} }
else else
{ {
// 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); await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time);
}); });
command.ReplyToCommand($"Player with steamid {steamid} is not online. Gag has been added offline."); command.ReplyToCommand($"Player with steamid {steamid} is not online. Gag has been added offline.");
@@ -244,19 +245,20 @@ public partial class CS2_SimpleAdmin
return; return;
} }
int.TryParse(command.GetArg(2), out var time);
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
reason = command.GetArg(3); reason = command.GetArg(3);
MuteManager muteManager = new(Database);
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (caller!.CanTarget(player)) if (!caller!.CanTarget(player)) return;
if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid)
{ {
Mute(caller, player, time, reason, callerName, muteManager, command); DurationMenu.OpenMenu(caller, $"{_localizer?["sa_mute"] ?? "Mute"}: {player.PlayerName}", player,
ManagePlayersMenu.MuteMenu);
return;
} }
Mute(caller, player, time, reason, callerName, MuteManager, command);
}); });
} }
@@ -343,7 +345,6 @@ public partial class CS2_SimpleAdmin
? command.GetArg(3) ? command.GetArg(3)
: (_localizer?["sa_unknown"] ?? "Unknown"); : (_localizer?["sa_unknown"] ?? "Unknown");
MuteManager muteManager = new(Database);
int.TryParse(command.GetArg(2), out var time); int.TryParse(command.GetArg(2), out var time);
// Get player and admin info // Get player and admin info
@@ -359,14 +360,14 @@ public partial class CS2_SimpleAdmin
if (!caller.CanTarget(player)) return; if (!caller.CanTarget(player)) return;
// Perform the mute for an online player // Perform the mute for an online player
Mute(caller, player, time, reason, callerName, muteManager, silent: true); Mute(caller, player, time, reason, callerName, MuteManager, silent: true);
} }
else else
{ {
// 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); await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 1);
}); });
command.ReplyToCommand($"Player with steamid {steamid} is not online. Mute has been added offline."); command.ReplyToCommand($"Player with steamid {steamid} is not online. Mute has been added offline.");
@@ -464,20 +465,21 @@ public partial class CS2_SimpleAdmin
{ {
return; return;
} }
int.TryParse(command.GetArg(2), out var time);
if (command.ArgCount >= 3 && command.GetArg(3).Length > 0) if (command.ArgCount >= 3 && command.GetArg(3).Length > 0)
reason = command.GetArg(3); reason = command.GetArg(3);
MuteManager muteManager = new(Database);
playersToTarget.ForEach(player => playersToTarget.ForEach(player =>
{ {
if (caller!.CanTarget(player)) if (!caller!.CanTarget(player)) return;
if (!int.TryParse(command.GetArg(2), out var time) && caller != null && caller.IsValid)
{ {
Silence(caller, player, time, reason, callerName, muteManager, command); DurationMenu.OpenMenu(caller, $"{_localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player,
ManagePlayersMenu.SilenceMenu);
return;
} }
Silence(caller, player, time, reason, callerName, MuteManager, command);
}); });
} }
@@ -562,7 +564,6 @@ public partial class CS2_SimpleAdmin
: (_localizer?["sa_unknown"] ?? "Unknown"); : (_localizer?["sa_unknown"] ?? "Unknown");
int.TryParse(command.GetArg(2), out var time); int.TryParse(command.GetArg(2), out var time);
MuteManager muteManager = new(Database);
// Get player and admin info // Get player and admin info
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
@@ -577,14 +578,14 @@ public partial class CS2_SimpleAdmin
if (!caller.CanTarget(player)) return; if (!caller.CanTarget(player)) return;
// Perform the silence for an online player // Perform the silence for an online player
Silence(caller, player, time, reason, callerName, muteManager, silent: true); Silence(caller, player, time, reason, callerName, MuteManager, silent: true);
} }
else else
{ {
// 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); await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 2);
}); });
command.ReplyToCommand($"Player with steamid {steamid} is not online. Silence has been added offline."); command.ReplyToCommand($"Player with steamid {steamid} is not online. Silence has been added offline.");

View File

@@ -27,7 +27,7 @@ public class DiscordPenaltySetting
public required string Name { get; set; } public required string Name { get; set; }
[JsonPropertyName("value")] [JsonPropertyName("value")]
public string Value { get; set; } = ""; public string? Value { get; set; } = "";
} }
public class Discord public class Discord
@@ -210,6 +210,9 @@ public class OtherSettings
[JsonPropertyName("DisconnectedPlayersHistoryCount")] [JsonPropertyName("DisconnectedPlayersHistoryCount")]
public int DisconnectedPlayersHistoryCount { get; set; } = 10; public int DisconnectedPlayersHistoryCount { get; set; } = 10;
[JsonPropertyName("NotifyPenaltiesToAdminOnConnect")]
public bool NotifyPenaltiesToAdminOnConnect { get; set; } = true;
} }
public class CS2_SimpleAdminConfig : BasePluginConfig public class CS2_SimpleAdminConfig : BasePluginConfig

View File

@@ -6,7 +6,7 @@ CREATE TABLE IF NOT EXISTS `sa_warns` (
`admin_name` varchar(128) NOT NULL, `admin_name` varchar(128) NOT NULL,
`reason` varchar(255) NOT NULL, `reason` varchar(255) NOT NULL,
`duration` int(11) NOT NULL, `duration` int(11) NOT NULL,
`ends` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `ends` timestamp NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`server_id` int(11) DEFAULT NULL, `server_id` int(11) DEFAULT NULL,
`status` enum('ACTIVE','EXPIRED','') NOT NULL DEFAULT 'ACTIVE', `status` enum('ACTIVE','EXPIRED','') NOT NULL DEFAULT 'ACTIVE',

View File

@@ -21,10 +21,27 @@ public partial class CS2_SimpleAdmin
RegisterListener<Listeners.OnMapStart>(OnMapStart); RegisterListener<Listeners.OnMapStart>(OnMapStart);
RegisterListener<Listeners.OnGameServerSteamAPIActivated>(OnGameServerSteamAPIActivated); RegisterListener<Listeners.OnGameServerSteamAPIActivated>(OnGameServerSteamAPIActivated);
AddCommandListener(null, OnCommandSayNew); AddCommandListener(null, OnCommandSayNew);
AddCommandListener("callvote", OnCommandCallVote);
// AddCommandListener("say", OnCommandSay); // AddCommandListener("say", OnCommandSay);
// AddCommandListener("say_team", OnCommandTeamSay); // AddCommandListener("say_team", OnCommandTeamSay);
} }
private HookResult OnCommandCallVote(CCSPlayerController? caller, CommandInfo commandinfo)
{
var voteType = commandinfo.GetArg(1).ToLower();
if (voteType != "kick")
return HookResult.Continue;
var target = int.TryParse(commandinfo.GetArg(2), out var userId)
? Utilities.GetPlayerFromUserid(userId)
: null;
if (target == null || !target.IsValid || target.Connected != PlayerConnectedState.PlayerConnected)
return HookResult.Continue;
return !CounterStrikeSharp.API.Modules.Admin.AdminManager.CanPlayerTarget(caller, target) ? HookResult.Stop : HookResult.Continue;
}
private void OnGameServerSteamAPIActivated() private void OnGameServerSteamAPIActivated()
{ {
new ServerManager().LoadServerData(); new ServerManager().LoadServerData();
@@ -79,8 +96,8 @@ public partial class CS2_SimpleAdmin
out var expirationTime) out var expirationTime)
|| !(expirationTime <= Time.ActualDateTime())) return HookResult.Continue; || !(expirationTime <= Time.ActualDateTime())) return HookResult.Continue;
AdminManager.ClearPlayerPermissions(authorizedSteamId); CounterStrikeSharp.API.Modules.Admin.AdminManager.ClearPlayerPermissions(authorizedSteamId);
AdminManager.RemovePlayerAdminData(authorizedSteamId); CounterStrikeSharp.API.Modules.Admin.AdminManager.RemovePlayerAdminData(authorizedSteamId);
return HookResult.Continue; return HookResult.Continue;
} }
@@ -160,10 +177,10 @@ public partial class CS2_SimpleAdmin
StringBuilder sb = new(); StringBuilder sb = new();
if (AdminManager.PlayerHasPermissions(player, "@css/chat")) if (CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(player, "@css/chat"))
{ {
sb.Append(_localizer!["sa_adminchat_template_admin", player.PlayerName, info.GetArg(1).Remove(0, 1)]); sb.Append(_localizer!["sa_adminchat_template_admin", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p is { IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(p, "@css/chat"))) foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p is { IsBot: false, IsHLTV: false } && CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(p, "@css/chat")))
{ {
p.PrintToChat(sb.ToString()); p.PrintToChat(sb.ToString());
} }
@@ -172,7 +189,7 @@ public partial class CS2_SimpleAdmin
{ {
sb.Append(_localizer!["sa_adminchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]); sb.Append(_localizer!["sa_adminchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
player.PrintToChat(sb.ToString()); player.PrintToChat(sb.ToString());
foreach (var p in Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(p, "@css/chat"))) foreach (var p in Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false } && CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(p, "@css/chat")))
{ {
p.PrintToChat(sb.ToString()); p.PrintToChat(sb.ToString());
} }
@@ -218,10 +235,10 @@ public partial class CS2_SimpleAdmin
StringBuilder sb = new(); StringBuilder sb = new();
if (AdminManager.PlayerHasPermissions(player, "@css/chat")) if (CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(player, "@css/chat"))
{ {
sb.Append(_localizer!["sa_adminchat_template_admin", player.PlayerName, info.GetArg(1).Remove(0, 1)]); sb.Append(_localizer!["sa_adminchat_template_admin", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p is { IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(p, "@css/chat"))) foreach (var p in Utilities.GetPlayers().Where(p => p.IsValid && p is { IsBot: false, IsHLTV: false } && CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(p, "@css/chat")))
{ {
p.PrintToChat(sb.ToString()); p.PrintToChat(sb.ToString());
} }
@@ -230,7 +247,7 @@ public partial class CS2_SimpleAdmin
{ {
sb.Append(_localizer!["sa_adminchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]); sb.Append(_localizer!["sa_adminchat_template_player", player.PlayerName, info.GetArg(1).Remove(0, 1)]);
player.PrintToChat(sb.ToString()); player.PrintToChat(sb.ToString());
foreach (var p in Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false } && AdminManager.PlayerHasPermissions(p, "@css/chat"))) foreach (var p in Utilities.GetPlayers().Where(p => p is { IsValid: true, IsBot: false, IsHLTV: false } && CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(p, "@css/chat")))
{ {
p.PrintToChat(sb.ToString()); p.PrintToChat(sb.ToString());
} }

View File

@@ -1,4 +1,5 @@
using CounterStrikeSharp.API; using System.Globalization;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Translations; using CounterStrikeSharp.API.Core.Translations;
using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Admin;
@@ -9,18 +10,15 @@ using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Menu; using CounterStrikeSharp.API.Modules.Menu;
using CounterStrikeSharp.API.ValveConstants.Protobuf; using CounterStrikeSharp.API.ValveConstants.Protobuf;
using CS2_SimpleAdminApi; using CS2_SimpleAdminApi;
using Discord;
using Discord.Webhook;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Drawing;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Color = Discord.Color; using CS2_SimpleAdmin.Managers;
namespace CS2_SimpleAdmin; namespace CS2_SimpleAdmin;
@@ -188,7 +186,7 @@ internal static class Helper
"sa_discord_log_command", "sa_discord_log_command",
playerName, command.GetCommandString]}".Replace("HOSTNAME", hostname).Replace("**", "")); playerName, command.GetCommandString]}".Replace("HOSTNAME", hostname).Replace("**", ""));
SendDiscordLogMessage(caller, command, CS2_SimpleAdmin.DiscordWebhookClientLog, CS2_SimpleAdmin._localizer); SendDiscordLogMessage(caller, command, CS2_SimpleAdmin._localizer);
} }
internal static void LogCommand(CCSPlayerController? caller, string command) internal static void LogCommand(CCSPlayerController? caller, string command)
@@ -204,7 +202,7 @@ internal static class Helper
CS2_SimpleAdmin.Instance.Logger.LogInformation($"{CS2_SimpleAdmin._localizer["sa_discord_log_command", CS2_SimpleAdmin.Instance.Logger.LogInformation($"{CS2_SimpleAdmin._localizer["sa_discord_log_command",
playerName, command]}".Replace("HOSTNAME", hostname).Replace("**", "")); playerName, command]}".Replace("HOSTNAME", hostname).Replace("**", ""));
SendDiscordLogMessage(caller, command, CS2_SimpleAdmin.DiscordWebhookClientLog, CS2_SimpleAdmin._localizer); SendDiscordLogMessage(caller, command, CS2_SimpleAdmin._localizer);
} }
/*public static IEnumerable<Embed> GenerateEmbedsDiscord(string title, string description, string thumbnailUrl, Color color, string[] fieldNames, string[] fieldValues, bool[] inlineFlags) /*public static IEnumerable<Embed> GenerateEmbedsDiscord(string title, string description, string thumbnailUrl, Color color, string[] fieldNames, string[] fieldValues, bool[] inlineFlags)
@@ -239,22 +237,22 @@ internal static class Helper
return new List<Embed> { embed.Build() }; return new List<Embed> { embed.Build() };
}*/ }*/
private static void SendDiscordLogMessage(CCSPlayerController? caller, CommandInfo command, DiscordWebhookClient? discordWebhookClientLog, IStringLocalizer? localizer) private static void SendDiscordLogMessage(CCSPlayerController? caller, CommandInfo command, IStringLocalizer? localizer)
{ {
if (discordWebhookClientLog == null || localizer == null) return; if (CS2_SimpleAdmin.DiscordWebhookClientLog == null || localizer == null) return;
var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>"; var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
var callerName = caller != null ? caller.PlayerName : CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console"; var callerName = caller != null ? caller.PlayerName : CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console";
discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); _ = CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString]));
} }
private static void SendDiscordLogMessage(CCSPlayerController? caller, string command, DiscordWebhookClient? discordWebhookClientLog, IStringLocalizer? localizer) private static void SendDiscordLogMessage(CCSPlayerController? caller, string command, IStringLocalizer? localizer)
{ {
if (discordWebhookClientLog == null || localizer == null) return; if (CS2_SimpleAdmin.DiscordWebhookClientLog == null || localizer == null) return;
var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>"; var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
var callerName = caller != null ? caller.PlayerName : CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console"; var callerName = caller != null ? caller.PlayerName : CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console";
discordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command])); _ = CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command]));
} }
public static void ShowAdminActivity(string messageKey, string? callerName = null, params object[] messageArgs) public static void ShowAdminActivity(string messageKey, string? callerName = null, params object[] messageArgs)
@@ -343,7 +341,7 @@ internal static class Helper
public static void SendDiscordPenaltyMessage(CCSPlayerController? caller, CCSPlayerController? target, string reason, int duration, PenaltyType penalty, IStringLocalizer? localizer) public static void SendDiscordPenaltyMessage(CCSPlayerController? caller, CCSPlayerController? target, string reason, int duration, PenaltyType penalty, IStringLocalizer? localizer)
{ {
if (localizer == null) return; if (localizer == null) return;
var penaltySetting = penalty switch var penaltySetting = penalty switch
{ {
PenaltyType.Ban => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltyBanSettings, PenaltyType.Ban => CS2_SimpleAdmin.Instance.Config.Discord.DiscordPenaltyBanSettings,
@@ -357,11 +355,13 @@ internal static class Helper
var webhookUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("Webhook"))?.Value; var webhookUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("Webhook"))?.Value;
if (string.IsNullOrEmpty(webhookUrl)) return; if (string.IsNullOrEmpty(webhookUrl)) return;
const string defaultCommunityUrl = "<https://steamcommunity.com/profiles/0>";
var callerCommunityUrl = caller != null ? $"<{new SteamID(caller.SteamID).ToCommunityUrl()}>" : defaultCommunityUrl;
var targetCommunityUrl = target != null ? $"<{new SteamID(target.SteamID).ToCommunityUrl()}>" : defaultCommunityUrl;
var callerCommunityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>"; var callerName = caller?.PlayerName ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console";
var targetCommunityUrl = target != null ? "<" + new SteamID(target.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>"; var targetName = target?.PlayerName ?? localizer["sa_unknown"];
var callerName = caller != null ? caller.PlayerName : CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console";
var targetName = target != null ? target.PlayerName : localizer["sa_unknown"];
var targetSteamId = target != null ? new SteamID(target.SteamID).SteamId64.ToString() : localizer["sa_unknown"]; var targetSteamId = target != null ? new SteamID(target.SteamID).SteamId64.ToString() : localizer["sa_unknown"];
var futureTime = Time.ActualDateTime().AddMinutes(duration); var futureTime = Time.ActualDateTime().AddMinutes(duration);
@@ -385,16 +385,14 @@ internal static class Helper
$"[{targetName}]({targetCommunityUrl})", $"||{targetSteamId}||", time, reason, $"[{targetName}]({targetCommunityUrl})", $"||{targetSteamId}||", time, reason,
$"[{callerName}]({callerCommunityUrl})" $"[{callerName}]({callerCommunityUrl})"
]; ];
bool[] inlineFlags = [true, true, true, false, false]; bool[] inlineFlags = [true, true, true, false, false];
var hostname = ConVar.Find("hostname")?.StringValue ?? localizer["sa_unknown"]; var hostname = ConVar.Find("hostname")?.StringValue ?? localizer["sa_unknown"];
var colorHex = penaltySetting.FirstOrDefault(s => s.Name.Equals("Color"))?.Value ?? "#FFFFFF"; var colorHex = penaltySetting.FirstOrDefault(s => s.Name.Equals("Color"))?.Value ?? "#FFFFFF";
var color = ColorTranslator.FromHtml(colorHex);
var embed = new EmbedBuilder var embed = new Embed
{ {
Color = new Color(color.R, color.G, color.B), Color = DiscordManager.ColorFromHex(colorHex),
Title = penalty switch Title = penalty switch
{ {
PenaltyType.Ban => localizer["sa_discord_penalty_ban"], PenaltyType.Ban => localizer["sa_discord_penalty_ban"],
@@ -404,14 +402,15 @@ internal static class Helper
PenaltyType.Warn => localizer["sa_discord_penalty_warn"], PenaltyType.Warn => localizer["sa_discord_penalty_warn"],
_ => throw new ArgumentOutOfRangeException(nameof(penalty), penalty, null) _ => throw new ArgumentOutOfRangeException(nameof(penalty), penalty, null)
}, },
Description = $"{hostname}",
ThumbnailUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("ThumbnailUrl"))?.Value, ThumbnailUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("ThumbnailUrl"))?.Value,
ImageUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("ImageUrl"))?.Value, ImageUrl = penaltySetting.FirstOrDefault(s => s.Name.Equals("ImageUrl"))?.Value,
Footer = new EmbedFooterBuilder Footer = new Footer
{ {
Text = penaltySetting.FirstOrDefault(s => s.Name.Equals("Footer"))?.Value, Text = penaltySetting.FirstOrDefault(s => s.Name.Equals("Footer"))?.Value
}, },
Description = $"{hostname}",
Timestamp = DateTimeOffset.Now, Timestamp = Time.ActualDateTime().ToUniversalTime().ToString("o"),
}; };
for (var i = 0; i < fieldNames.Length; i++) for (var i = 0; i < fieldNames.Length; i++)
@@ -421,7 +420,15 @@ internal static class Helper
Task.Run(async () => Task.Run(async () =>
{ {
await new DiscordWebhookClient(webhookUrl).SendMessageAsync(embeds: [embed.Build()]); try
{
await new DiscordManager(webhookUrl).SendEmbedAsync(embed);
}
catch (Exception ex)
{
// Log or handle the exception
Console.WriteLine(ex);
}
}); });
} }
@@ -470,7 +477,6 @@ internal static class Helper
} }
} }
public static void UpdateConfig<T>(T config) where T : BasePluginConfig, new() public static void UpdateConfig<T>(T config) where T : BasePluginConfig, new()
{ {
// get newest config version // get newest config version
@@ -505,7 +511,7 @@ internal static class Helper
var communityUrl = caller != null var communityUrl = caller != null
? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">"
: "<https://steamcommunity.com/profiles/0>"; : "<https://steamcommunity.com/profiles/0>";
CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord( _ = CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord(
CS2_SimpleAdmin._localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", CS2_SimpleAdmin._localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})",
commandString])); commandString]));
} }
@@ -513,20 +519,21 @@ internal static class Helper
public static class PluginInfo public static class PluginInfo
{ {
internal static async Task CheckVersion(string version, ILogger logger) internal static async Task CheckVersion(string localVersion, ILogger logger)
{ {
using HttpClient client = new(); const string versionUrl = "https://raw.githubusercontent.com/daffyyyy/CS2-SimpleAdmin/main/CS2-SimpleAdmin/VERSION";
var client = CS2_SimpleAdmin.HttpClient;
try try
{ {
var response = await client.GetAsync("https://raw.githubusercontent.com/daffyyyy/CS2-SimpleAdmin/main/CS2-SimpleAdmin/VERSION"); var response = await client.GetAsync(versionUrl);
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
var remoteVersion = await response.Content.ReadAsStringAsync(); var remoteVersion = await response.Content.ReadAsStringAsync();
remoteVersion = remoteVersion.Trim(); remoteVersion = remoteVersion.Trim();
var comparisonResult = string.CompareOrdinal(version, remoteVersion); var comparisonResult = string.CompareOrdinal(localVersion, remoteVersion);
switch (comparisonResult) switch (comparisonResult)
{ {
@@ -543,7 +550,7 @@ public static class PluginInfo
} }
else else
{ {
logger.LogWarning("Failed to check version"); logger.LogWarning($"Failed to check version. Status Code: {response.StatusCode}");
} }
} }
catch (HttpRequestException ex) catch (HttpRequestException ex)
@@ -555,7 +562,7 @@ public static class PluginInfo
logger.LogError(ex, "An error occurred while checking version."); logger.LogError(ex, "An error occurred while checking version.");
} }
} }
internal static void ShowAd(string moduleVersion) internal static void ShowAd(string moduleVersion)
{ {
Console.WriteLine(" "); Console.WriteLine(" ");

View File

@@ -8,10 +8,12 @@ using System.Text;
namespace CS2_SimpleAdmin.Managers; namespace CS2_SimpleAdmin.Managers;
internal class BanManager(Database.Database database, CS2_SimpleAdminConfig config) 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;
DateTime now = Time.ActualDateTime(); DateTime now = Time.ActualDateTime();
DateTime futureTime = now.AddMinutes(time); DateTime futureTime = now.AddMinutes(time);
@@ -26,7 +28,7 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
{ {
playerSteamid = player.SteamId.SteamId64.ToString(), playerSteamid = player.SteamId.SteamId64.ToString(),
playerName = player.Name, playerName = player.Name,
playerIp = config.OtherSettings.BanType == 1 ? player.IpAddress : null, playerIp = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 1 ? player.IpAddress : null,
adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", adminSteamid = issuer?.SteamId.SteamId64.ToString() ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
adminName = issuer?.Name ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console", adminName = issuer?.Name ?? CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console",
banReason = reason, banReason = reason,
@@ -41,6 +43,8 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
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 (string.IsNullOrEmpty(playerSteamId)) return;
DateTime now = Time.ActualDateTime(); DateTime now = Time.ActualDateTime();
@@ -70,6 +74,8 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
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)
{ {
if (database == null) return;
if (string.IsNullOrEmpty(playerIp)) return; if (string.IsNullOrEmpty(playerIp)) return;
DateTime now = Time.ActualDateTime(); DateTime now = Time.ActualDateTime();
@@ -99,6 +105,8 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
public async Task<bool> IsPlayerBanned(PlayerInfo player) public async Task<bool> IsPlayerBanned(PlayerInfo player)
{ {
if (database == null) return false;
if (player.IpAddress == null) if (player.IpAddress == null)
{ {
return false; return false;
@@ -115,62 +123,58 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
try try
{ {
var sql = config.MultiServerMode ? """ var sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode ? """
UPDATE sa_bans SELECT COALESCE((
SET player_ip = CASE WHEN player_ip IS NULL THEN @PlayerIP ELSE player_ip END, SELECT COUNT(*)
player_name = CASE WHEN player_name IS NULL THEN @PlayerName ELSE player_name END FROM sa_bans
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
AND status = 'ACTIVE' AND status = 'ACTIVE'
AND (duration = 0 OR ends > @CurrentTime); AND (duration = 0 OR ends > @CurrentTime)
), 0) AS BanCount
SELECT COUNT(*) FROM sa_bans + COALESCE((
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) SELECT COUNT(*)
AND status = 'ACTIVE' FROM sa_bans
AND (duration = 0 OR ends > @CurrentTime); JOIN sa_players_ips ON sa_bans.player_steamid = sa_players_ips.steamid
""" : @" WHERE sa_bans.status = 'ACTIVE'
UPDATE sa_bans AND sa_players_ips.address = @PlayerIP
SET player_ip = CASE WHEN player_ip IS NULL THEN @PlayerIP ELSE player_ip END, AND (SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
player_name = CASE WHEN player_name IS NULL THEN @PlayerName ELSE player_name END AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime)) = 0
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) ), 0) AS TotalBanCount;
AND status = 'ACTIVE' """ : """
AND (duration = 0 OR ends > @CurrentTime) AND server_id = @serverid; SELECT COALESCE((
SELECT COUNT(*)
SELECT COUNT(*) FROM sa_bans FROM sa_bans
WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
AND status = 'ACTIVE' AND status = 'ACTIVE'
AND (duration = 0 OR ends > @CurrentTime) AND server_id = @serverid;"; AND (duration = 0 OR ends > @CurrentTime)
AND server_id = @ServerId
), 0) AS BanCount
+ COALESCE((
SELECT COUNT(*)
FROM sa_bans
JOIN sa_players_ips ON sa_bans.player_steamid = sa_players_ips.steamid
WHERE sa_bans.status = 'ACTIVE'
AND sa_players_ips.address = @PlayerIP
AND (SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)
AND status = 'ACTIVE' AND (duration = 0 OR ends > @CurrentTime) AND server_id = @ServerId) = 0
), 0) AS TotalBanCount;
""";
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
var parameters = new var parameters = new
{ {
PlayerSteamID = player.SteamId.SteamId64.ToString(), PlayerSteamID = player.SteamId.SteamId64.ToString(),
PlayerIP = config.OtherSettings.BanType == 0 || string.IsNullOrEmpty(player.IpAddress) ? null : player.IpAddress, PlayerIP = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0 ||
string.IsNullOrEmpty(player.IpAddress)
? null
: player.IpAddress,
PlayerName = !string.IsNullOrEmpty(player.Name) ? player.Name : string.Empty, PlayerName = !string.IsNullOrEmpty(player.Name) ? player.Name : string.Empty,
CurrentTime = currentTime, CurrentTime = currentTime,
serverid = CS2_SimpleAdmin.ServerId CS2_SimpleAdmin.ServerId
}; };
banCount = await connection.ExecuteScalarAsync<int>(sql, parameters); banCount = await connection.ExecuteScalarAsync<int>(sql, parameters);
if (config.OtherSettings.BanType == 1 && banCount == 0)
{
sql = """
SELECT
COUNT(*)
FROM
sa_bans
JOIN sa_players_ips ON sa_bans.player_steamid = sa_players_ips.steamid
WHERE
sa_bans.status = 'ACTIVE'
AND sa_players_ips.address = @PlayerIP;
""";
banCount = await connection.ExecuteScalarAsync<int>(sql, new
{
PlayerIP = player.IpAddress
});
}
} }
catch (Exception) catch (Exception)
{ {
@@ -182,11 +186,13 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
public async Task<int> GetPlayerBans(PlayerInfo player) public async Task<int> GetPlayerBans(PlayerInfo player)
{ {
if (database == null) return 0;
try try
{ {
var sql = ""; string sql;
sql = config.MultiServerMode sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode
? "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)" ? "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP)"
: "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) AND server_id = @serverid"; : "SELECT COUNT(*) FROM sa_bans WHERE (player_steamid = @PlayerSteamID OR player_ip = @PlayerIP) AND server_id = @serverid";
@@ -194,7 +200,7 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
if (config.OtherSettings.BanType > 0 && !string.IsNullOrEmpty(player.IpAddress)) if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType > 0 && !string.IsNullOrEmpty(player.IpAddress))
{ {
banCount = await connection.ExecuteScalarAsync<int>(sql, banCount = await connection.ExecuteScalarAsync<int>(sql,
new new
@@ -224,6 +230,8 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
public async Task UnbanPlayer(string playerPattern, string adminSteamId, string reason) public async Task UnbanPlayer(string playerPattern, string adminSteamId, string reason)
{ {
if (database == null) return;
if (playerPattern is not { Length: > 1 }) if (playerPattern is not { Length: > 1 })
{ {
return; return;
@@ -232,7 +240,7 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
var sqlRetrieveBans = config.MultiServerMode var sqlRetrieveBans = CS2_SimpleAdmin.Instance.Config.MultiServerMode
? "SELECT id FROM sa_bans WHERE (player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern) AND status = 'ACTIVE'" ? "SELECT id FROM sa_bans WHERE (player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern) AND status = 'ACTIVE'"
: "SELECT id FROM sa_bans WHERE (player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern) AND status = 'ACTIVE' AND server_id = @serverid"; : "SELECT id FROM sa_bans WHERE (player_steamid = @pattern OR player_name = @pattern OR player_ip = @pattern) AND status = 'ACTIVE' AND server_id = @serverid";
@@ -273,10 +281,12 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
public async Task CheckOnlinePlayers(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players) public async Task CheckOnlinePlayers(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players)
{ {
if (database == null) return;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
bool checkIpBans = config.OtherSettings.BanType > 0; bool checkIpBans = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType > 0;
var filteredPlayers = players.Where(p => p.UserId.HasValue).ToList(); var filteredPlayers = players.Where(p => p.UserId.HasValue).ToList();
@@ -290,7 +300,7 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
var sql = new StringBuilder(); var sql = new StringBuilder();
sql.Append("SELECT `player_steamid`, `player_ip` FROM `sa_bans` WHERE `status` = 'ACTIVE' "); sql.Append("SELECT `player_steamid`, `player_ip` FROM `sa_bans` WHERE `status` = 'ACTIVE' ");
if (config.MultiServerMode) if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
{ {
sql.Append("AND (player_steamid IN @SteamIDs "); sql.Append("AND (player_steamid IN @SteamIDs ");
if (checkIpBans && ipAddresses.Count != 0) if (checkIpBans && ipAddresses.Count != 0)
@@ -341,6 +351,7 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
public async Task ExpireOldBans() public async Task ExpireOldBans()
{ {
if (database == null) return;
var currentTime = Time.ActualDateTime(); var currentTime = Time.ActualDateTime();
try try
@@ -354,58 +365,58 @@ internal class BanManager(Database.Database database, CS2_SimpleAdminConfig conf
await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.UtcNow }); await connection.ExecuteAsync(sql, new { CurrentTime = DateTime.UtcNow });
*/ */
var sql = ""; string sql;
sql = config.MultiServerMode ? """ sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode ? """
UPDATE sa_bans UPDATE sa_bans
SET SET
status = 'EXPIRED' status = 'EXPIRED'
WHERE WHERE
status = 'ACTIVE' status = 'ACTIVE'
AND AND
`duration` > 0 `duration` > 0
AND AND
ends <= @currentTime ends <= @currentTime
""" : """ """ : """
UPDATE sa_bans UPDATE sa_bans
SET SET
status = 'EXPIRED' status = 'EXPIRED'
WHERE WHERE
status = 'ACTIVE' status = 'ACTIVE'
AND AND
`duration` > 0 `duration` > 0
AND AND
ends <= @currentTime ends <= @currentTime
AND server_id = @serverid AND server_id = @serverid
"""; """;
await connection.ExecuteAsync(sql, new { currentTime, serverid = CS2_SimpleAdmin.ServerId }); await connection.ExecuteAsync(sql, new { currentTime, serverid = CS2_SimpleAdmin.ServerId });
if (config.OtherSettings.ExpireOldIpBans > 0) if (CS2_SimpleAdmin.Instance.Config.OtherSettings.ExpireOldIpBans > 0)
{ {
var ipBansTime = currentTime.AddDays(-config.OtherSettings.ExpireOldIpBans); var ipBansTime = currentTime.AddDays(-CS2_SimpleAdmin.Instance.Config.OtherSettings.ExpireOldIpBans);
sql = config.MultiServerMode ? """ sql = CS2_SimpleAdmin.Instance.Config.MultiServerMode ? """
UPDATE sa_bans UPDATE sa_bans
SET SET
player_ip = NULL player_ip = NULL
WHERE WHERE
status = 'ACTIVE' status = 'ACTIVE'
AND AND
ends <= @ipBansTime ends <= @ipBansTime
""" : """ """ : """
UPDATE sa_bans UPDATE sa_bans
SET SET
player_ip = NULL player_ip = NULL
WHERE WHERE
status = 'ACTIVE' status = 'ACTIVE'
AND AND
ends <= @ipBansTime ends <= @ipBansTime
AND server_id = @serverid AND server_id = @serverid
"""; """;
await connection.ExecuteAsync(sql, new { ipBansTime, CS2_SimpleAdmin.ServerId }); await connection.ExecuteAsync(sql, new { ipBansTime, CS2_SimpleAdmin.ServerId });
} }

View File

@@ -0,0 +1,124 @@
using System.Text;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace CS2_SimpleAdmin.Managers;
public class DiscordManager(string webhookUrl)
{
public async Task SendMessageAsync(string message)
{
var client = CS2_SimpleAdmin.HttpClient;
var payload = new
{
content = message
};
var json = JsonConvert.SerializeObject(payload);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
var response = await client.PostAsync(webhookUrl, content);
if (!response.IsSuccessStatusCode)
{
CS2_SimpleAdmin._logger?.LogError(
$"Failed to send discord message. Status Code: {response.StatusCode}, Reason: {response.ReasonPhrase}");
}
}
catch (HttpRequestException e)
{
CS2_SimpleAdmin._logger?.LogError($"Error sending discord message: {e.Message}");
}
}
public async Task SendEmbedAsync(Embed embed)
{
var httpClient = CS2_SimpleAdmin.HttpClient;
var payload = new
{
embeds = new[]
{
new
{
color = embed.Color,
title = !string.IsNullOrEmpty(embed.Title) ? embed.Title : null,
description = !string.IsNullOrEmpty(embed.Description) ? embed.Description : null,
thumbnail = !string.IsNullOrEmpty(embed.ThumbnailUrl) ? new { url = embed.ThumbnailUrl } : null,
image = !string.IsNullOrEmpty(embed.ImageUrl) ? new { url = embed.ImageUrl } : null,
footer = !string.IsNullOrEmpty(embed.Footer?.Text) ? new { text = embed.Footer.Text, icon_url = embed.Footer.IconUrl } : null,
timestamp = embed.Timestamp,
fields = embed.Fields.Count > 0 ? embed.Fields.Select(field => new
{
name = field.Name,
value = field.Value,
inline = field.Inline
}).ToArray() : null
}
}
};
var jsonPayload = JsonConvert.SerializeObject(payload);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(webhookUrl, content);
if (!response.IsSuccessStatusCode)
{
var errorMessage = await response.Content.ReadAsStringAsync();
CS2_SimpleAdmin._logger?.LogError($"Failed to send embed: {response.StatusCode} - {errorMessage}");
}
}
public static int ColorFromHex(string hex)
{
if (hex.StartsWith($"#"))
{
hex = hex[1..];
}
return int.Parse(hex, System.Globalization.NumberStyles.HexNumber);
}
}
public class Embed
{
public int Color { get; init; }
public string? Title { get; init; }
public string? Description { get; init; }
public string? ImageUrl { get; init; }
public string? ThumbnailUrl { get; init; }
public Footer? Footer { get; init; }
public string? Timestamp { get; init; }
public List<EmbedField> Fields { get; } = [];
public void AddField(string name, string value, bool inline)
{
var field = new EmbedField
{
Name = name,
Value = value,
Inline = inline
};
Fields.Add(field);
}
}
public class Footer
{
public string? Text { get; init; }
public string? IconUrl { get; set; }
}
public class EmbedField
{
public string? Name { get; init; }
public string? Value { get; init; }
public bool Inline { get; init; }
}

View File

@@ -4,10 +4,12 @@ using Microsoft.Extensions.Logging;
namespace CS2_SimpleAdmin.Managers; 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 MutePlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0, int type = 0)
{ {
if (database == null) return;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@@ -47,6 +49,8 @@ internal class MuteManager(Database.Database database)
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 (string.IsNullOrEmpty(playerSteamId)) return;
@@ -84,6 +88,8 @@ internal class MuteManager(Database.Database database)
public async Task<List<dynamic>> IsPlayerMuted(string steamId) public async Task<List<dynamic>> IsPlayerMuted(string steamId)
{ {
if (database == null) return [];
if (string.IsNullOrEmpty(steamId)) if (string.IsNullOrEmpty(steamId))
{ {
return []; return [];
@@ -124,34 +130,50 @@ internal class MuteManager(Database.Database database)
} }
} }
public async Task<int> GetPlayerMutes(PlayerInfo playerInfo, int type = 0) public async Task<(int TotalMutes, int TotalGags, int TotalSilences)> GetPlayerMutes(PlayerInfo playerInfo)
{ {
if (database == null) return (0,0,0);
try try
{ {
var muteType = type switch
{
1 => "MUTE",
2 => "SILENCE",
_ => "GAG"
};
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
? "SELECT COUNT(*) FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND type = @MuteType" ? """
: "SELECT COUNT(*) FROM sa_mutes WHERE player_steamid = @PlayerSteamID AND server_id = @serverid AND type = @MuteType"; SELECT
COUNT(CASE WHEN type = 'MUTE' THEN 1 END) AS TotalMutes,
COUNT(CASE WHEN type = 'GAG' THEN 1 END) AS TotalGags,
COUNT(CASE WHEN type = 'SILENCE' THEN 1 END) AS TotalSilences
FROM sa_mutes
WHERE player_steamid = @PlayerSteamID;
"""
: """
SELECT
COUNT(CASE WHEN type = 'MUTE' THEN 1 END) AS TotalMutes,
COUNT(CASE WHEN type = 'GAG' THEN 1 END) AS TotalGags,
COUNT(CASE WHEN type = 'SILENCE' THEN 1 END) AS TotalSilences
FROM sa_mutes
WHERE player_steamid = @PlayerSteamID AND server_id = @ServerId;
""";
var muteCount = await connection.ExecuteScalarAsync<int>(sql, new { PlayerSteamID = playerInfo.SteamId.SteamId64.ToString(), serverid = CS2_SimpleAdmin.ServerId, MuteType = muteType }); var result = await connection.QuerySingleAsync<(int TotalMutes, int TotalGags, int TotalSilences)>(sql, new
return muteCount; {
PlayerSteamID = playerInfo.SteamId.SteamId64.ToString(),
CS2_SimpleAdmin.ServerId
});
return result;
} }
catch (Exception) catch (Exception)
{ {
return 0; return (0, 0, 0);
} }
} }
public async Task CheckOnlineModeMutes(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players) public async Task CheckOnlineModeMutes(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players)
{ {
if (database == null) return;
try try
{ {
int batchSize = 10; int batchSize = 10;
@@ -196,6 +218,8 @@ internal class MuteManager(Database.Database database)
public async Task UnmutePlayer(string playerPattern, string adminSteamId, string reason, int type = 0) public async Task UnmutePlayer(string playerPattern, string adminSteamId, string reason, int type = 0)
{ {
if (database == null) return;
if (playerPattern.Length <= 1) if (playerPattern.Length <= 1)
{ {
return; return;
@@ -266,6 +290,8 @@ internal class MuteManager(Database.Database database)
public async Task ExpireOldMutes() public async Task ExpireOldMutes()
{ {
if (database == null) return;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();

View File

@@ -8,7 +8,7 @@ using System.Collections.Concurrent;
namespace CS2_SimpleAdmin.Managers; namespace CS2_SimpleAdmin.Managers;
public class PermissionManager(Database.Database database) public class PermissionManager(Database.Database? database)
{ {
// Unused for now // Unused for now
//public static readonly ConcurrentDictionary<string, ConcurrentBag<string>> _adminCache = new ConcurrentDictionary<string, ConcurrentBag<string>>(); //public static readonly ConcurrentDictionary<string, ConcurrentBag<string>> _adminCache = new ConcurrentDictionary<string, ConcurrentBag<string>>();
@@ -59,6 +59,8 @@ public class PermissionManager(Database.Database database)
private async Task<List<(string, string, List<string>, int, DateTime?)>> GetAllPlayersFlags() private async Task<List<(string, string, List<string>, int, DateTime?)>> GetAllPlayersFlags()
{ {
if (database == null) return [];
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
try try
@@ -176,6 +178,8 @@ public class PermissionManager(Database.Database database)
private async Task<Dictionary<string, (List<string>, int)>> GetAllGroupsData() private async Task<Dictionary<string, (List<string>, int)>> GetAllGroupsData()
{ {
if (database == null) return [];
await using MySqlConnection connection = await database.GetConnectionAsync(); await using MySqlConnection connection = await database.GetConnectionAsync();
try try
{ {
@@ -366,6 +370,8 @@ public class PermissionManager(Database.Database database)
public async Task DeleteAdminBySteamId(string playerSteamId, bool globalDelete = false) public async Task DeleteAdminBySteamId(string playerSteamId, bool globalDelete = false)
{ {
if (database == null) return;
if (string.IsNullOrEmpty(playerSteamId)) return; if (string.IsNullOrEmpty(playerSteamId)) return;
//_adminCache.TryRemove(playerSteamId, out _); //_adminCache.TryRemove(playerSteamId, out _);
@@ -388,6 +394,8 @@ public class PermissionManager(Database.Database database)
public async Task AddAdminBySteamId(string playerSteamId, string playerName, List<string> flagsList, int immunity = 0, int time = 0, bool globalAdmin = false) public async Task AddAdminBySteamId(string playerSteamId, string playerName, List<string> flagsList, int immunity = 0, int time = 0, bool globalAdmin = false)
{ {
if (database == null) return;
if (string.IsNullOrEmpty(playerSteamId) || flagsList.Count == 0) return; if (string.IsNullOrEmpty(playerSteamId) || flagsList.Count == 0) return;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
@@ -458,6 +466,8 @@ public class PermissionManager(Database.Database database)
public async Task AddGroup(string groupName, List<string> flagsList, int immunity = 0, bool globalGroup = false) public async Task AddGroup(string groupName, List<string> flagsList, int immunity = 0, bool globalGroup = false)
{ {
if (database == null) return;
if (string.IsNullOrEmpty(groupName) || flagsList.Count == 0) return; if (string.IsNullOrEmpty(groupName) || flagsList.Count == 0) return;
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
@@ -504,6 +514,8 @@ public class PermissionManager(Database.Database database)
public async Task DeleteGroup(string groupName) public async Task DeleteGroup(string groupName)
{ {
if (database == null) return;
if (string.IsNullOrEmpty(groupName)) return; if (string.IsNullOrEmpty(groupName)) return;
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
@@ -520,6 +532,8 @@ public class PermissionManager(Database.Database database)
public async Task DeleteOldAdmins() public async Task DeleteOldAdmins()
{ {
if (database == null) return;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();

View File

@@ -27,12 +27,12 @@ public class PlayerManager
var userId = player.UserId.Value; var userId = player.UserId.Value;
// Check if the player's IP or SteamID is in the bannedPlayers list // Check if the player's IP or SteamID is in the bannedPlayers list
if (_config.OtherSettings.BanType > 0 && CS2_SimpleAdmin.BannedPlayers.Contains(ipAddress) || CS2_SimpleAdmin.BannedPlayers.Contains(player.SteamID.ToString())) if (_config.OtherSettings.BanType > 0 && CS2_SimpleAdmin.BannedPlayers.Contains(ipAddress) ||
CS2_SimpleAdmin.BannedPlayers.Contains(player.SteamID.ToString()))
{ {
// Kick the player if banned // Kick the player if banned
if (player.UserId.HasValue) if (player.UserId.HasValue)
Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED); Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
return; return;
} }
@@ -41,32 +41,52 @@ public class PlayerManager
// Perform asynchronous database operations within a single method // Perform asynchronous database operations within a single method
Task.Run(async () => Task.Run(async () =>
{ {
// Initialize managers
BanManager banManager = new(CS2_SimpleAdmin.Database, _config);
MuteManager muteManager = new(CS2_SimpleAdmin.Database);
WarnManager warnManager = new(CS2_SimpleAdmin.Database);
try try
{ {
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
const string selectQuery = "SELECT COUNT(*) FROM `sa_players_ips` WHERE steamid = @SteamID AND address = @IPAddress;";
const string query = """ var recordExists = await connection.ExecuteScalarAsync<int>(selectQuery, new
INSERT INTO `sa_players_ips` (steamid, address)
VALUES (@SteamID, @IPAddress) ON DUPLICATE KEY UPDATE `used_at` = CURRENT_TIMESTAMP
""";
await connection.ExecuteAsync(query, new
{ {
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId, SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
IPAddress = ipAddress, IPAddress = ipAddress
}); });
if (recordExists > 0)
{
const string updateQuery = """
UPDATE `sa_players_ips`
SET used_at = CURRENT_TIMESTAMP
WHERE steamid = @SteamID AND address = @IPAddress;
""";
await connection.ExecuteAsync(updateQuery, new
{
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
IPAddress = ipAddress
});
}
else
{
const string insertQuery = """
INSERT INTO `sa_players_ips` (steamid, address, used_at)
VALUES (@SteamID, @IPAddress, CURRENT_TIMESTAMP);
""";
await connection.ExecuteAsync(insertQuery, new
{
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64,
IPAddress = ipAddress
});
}
}
catch (Exception ex)
{
CS2_SimpleAdmin._logger?.LogError(
$"Unable to save ip address for {CS2_SimpleAdmin.PlayersInfo[userId].Name} ({ipAddress}) {ex.Message}");
} }
catch { }
try try
{ {
// Check if the player is banned // Check if the player is banned
bool isBanned = await banManager.IsPlayerBanned(CS2_SimpleAdmin.PlayersInfo[userId]); bool isBanned = await CS2_SimpleAdmin.Instance.BanManager.IsPlayerBanned(CS2_SimpleAdmin.PlayersInfo[userId]);
if (isBanned) if (isBanned)
{ {
@@ -98,50 +118,19 @@ public class PlayerManager
return; return;
} }
var warns = await warnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false); 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 = CS2_SimpleAdmin.PlayersInfo[userId].TotalBans =
await banManager.GetPlayerBans(CS2_SimpleAdmin.PlayersInfo[userId]); await CS2_SimpleAdmin.Instance.BanManager.GetPlayerBans(CS2_SimpleAdmin.PlayersInfo[userId]);
CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = totalMutes;
await muteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId], 1); CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = totalGags;
CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences = totalSilences;
await muteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId], 0);
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences =
await muteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId], 2);
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns = warns.Count; CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns = warns.Count;
// Check if the player is muted // Check if the player is muted
var activeMutes = await muteManager.IsPlayerMuted(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()); var activeMutes = await CS2_SimpleAdmin.Instance.MuteManager.IsPlayerMuted(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString());
/*
Dictionary<PenaltyType, List<string>> mutesList = new()
{
{ PenaltyType.Gag, [] },
{ PenaltyType.Mute, [] },
{ PenaltyType.Silence, [] }
};
List<string> warnsList = [];
bool found = false;
foreach (var warn in warns.TakeWhile(warn => (string)warn.status == "ACTIVE"))
{
DateTime ends = warn.ends;
if (CS2_SimpleAdmin._localizer == null) continue;
Console.WriteLine(ends.ToLocalTime().ToString(CultureInfo.CurrentCulture));
warnsList.Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_warn", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture), (string)warn.reason]);
found = true;
}
if (!found)
{
if (CS2_SimpleAdmin._localizer != null)
warnsList.Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_no_active_warn"]);
}
*/
if (activeMutes.Count > 0) if (activeMutes.Count > 0)
{ {
@@ -180,24 +169,27 @@ public class PlayerManager
} }
} }
await Server.NextFrameAsync(() => if (CS2_SimpleAdmin.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect)
{ {
foreach (var admin in Helper.GetValidPlayers() await Server.NextFrameAsync(() =>
.Where(p => (AdminManager.PlayerHasPermissions(p, "@css/kick") ||
AdminManager.PlayerHasPermissions(p, "@css/ban")) &&
p.Connected == PlayerConnectedState.PlayerConnected && !CS2_SimpleAdmin.AdminDisabledJoinComms.Contains(p.SteamID)))
{ {
if (CS2_SimpleAdmin._localizer != null && admin != player) foreach (var admin in Helper.GetValidPlayers()
admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_penalty_info", .Where(p => (AdminManager.PlayerHasPermissions(p, "@css/kick") ||
player.PlayerName, AdminManager.PlayerHasPermissions(p, "@css/ban")) &&
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans, p.Connected == PlayerConnectedState.PlayerConnected && !CS2_SimpleAdmin.AdminDisabledJoinComms.Contains(p.SteamID)))
CS2_SimpleAdmin.PlayersInfo[userId].TotalGags, {
CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes, if (CS2_SimpleAdmin._localizer != null && admin != player)
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences, admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_penalty_info",
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns player.PlayerName,
); CS2_SimpleAdmin.PlayersInfo[userId].TotalBans,
} CS2_SimpleAdmin.PlayersInfo[userId].TotalGags,
}); CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes,
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences,
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns
);
}
});
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -229,15 +221,10 @@ public class PlayerManager
Task.Run(async () => Task.Run(async () =>
{ {
PermissionManager adminManager = new(CS2_SimpleAdmin.Database); await CS2_SimpleAdmin.Instance.MuteManager.ExpireOldMutes();
BanManager banManager = new(CS2_SimpleAdmin.Database, _config); await CS2_SimpleAdmin.Instance.BanManager.ExpireOldBans();
MuteManager muteManager = new(CS2_SimpleAdmin.Database); await CS2_SimpleAdmin.Instance.WarnManager.ExpireOldWarns();
WarnManager warnManager = new(CS2_SimpleAdmin.Database); await CS2_SimpleAdmin.Instance.PermissionManager.DeleteOldAdmins();
await muteManager.ExpireOldMutes();
await banManager.ExpireOldBans();
await warnManager.ExpireOldWarns();
await adminManager.DeleteOldAdmins();
CS2_SimpleAdmin.BannedPlayers.Clear(); CS2_SimpleAdmin.BannedPlayers.Clear();
@@ -245,11 +232,11 @@ public class PlayerManager
{ {
try try
{ {
await banManager.CheckOnlinePlayers(onlinePlayers); await CS2_SimpleAdmin.Instance.BanManager.CheckOnlinePlayers(onlinePlayers);
if (_config.OtherSettings.TimeMode == 0) if (_config.OtherSettings.TimeMode == 0)
{ {
await muteManager.CheckOnlineModeMutes(onlinePlayers); await CS2_SimpleAdmin.Instance.MuteManager.CheckOnlineModeMutes(onlinePlayers);
} }
} }
catch (Exception) catch (Exception)

View File

@@ -79,7 +79,7 @@ public class ServerManager
if (CS2_SimpleAdmin.Instance.Config.EnableMetrics) if (CS2_SimpleAdmin.Instance.Config.EnableMetrics)
{ {
var queryString = $"?address={address}&hostname={hostname}"; var queryString = $"?address={address}&hostname={hostname}";
using HttpClient client = new(); var client = CS2_SimpleAdmin.HttpClient;
try try
{ {

View File

@@ -4,10 +4,12 @@ using Microsoft.Extensions.Logging;
namespace CS2_SimpleAdmin.Managers; 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 WarnPlayer(PlayerInfo player, PlayerInfo? issuer, string reason, int time = 0)
{ {
if (database == null) return;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@@ -36,9 +38,9 @@ internal class WarnManager(Database.Database database)
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 (string.IsNullOrEmpty(playerSteamId)) return;
var now = Time.ActualDateTime(); var now = Time.ActualDateTime();
var futureTime = now.AddMinutes(time); var futureTime = now.AddMinutes(time);
@@ -65,6 +67,8 @@ internal class WarnManager(Database.Database database)
public async Task<List<dynamic>> GetPlayerWarns(PlayerInfo player, bool active = true) public async Task<List<dynamic>> GetPlayerWarns(PlayerInfo player, bool active = true)
{ {
if (database == null) return [];
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
@@ -97,6 +101,8 @@ internal class WarnManager(Database.Database database)
public async Task<int> GetPlayerWarnsCount(string steamId, bool active = true) public async Task<int> GetPlayerWarnsCount(string steamId, bool active = true)
{ {
if (database == null) return 0;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
@@ -120,6 +126,8 @@ internal class WarnManager(Database.Database database)
public async Task UnwarnPlayer(PlayerInfo player, int warnId) public async Task UnwarnPlayer(PlayerInfo player, int warnId)
{ {
if (database == null) return;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
@@ -138,6 +146,8 @@ internal class WarnManager(Database.Database database)
public async Task UnwarnPlayer(string playerPattern) public async Task UnwarnPlayer(string playerPattern)
{ {
if (database == null) return;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();
@@ -156,6 +166,8 @@ internal class WarnManager(Database.Database database)
public async Task ExpireOldWarns() public async Task ExpireOldWarns()
{ {
if (database == null) return;
try try
{ {
await using var connection = await database.GetConnectionAsync(); await using var connection = await database.GetConnectionAsync();

View File

@@ -151,7 +151,7 @@ public static class ManagePlayersMenu
CS2_SimpleAdmin.Instance.Kick(admin, player, reason); CS2_SimpleAdmin.Instance.Kick(admin, player, reason);
} }
private static void BanMenu(CCSPlayerController admin, CCSPlayerController player, int duration) internal static void BanMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{ {
ReasonMenu.OpenMenu(admin, PenaltyType.Ban, ReasonMenu.OpenMenu(admin, PenaltyType.Ban,
$"{CS2_SimpleAdmin._localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player, (_, _, reason) => $"{CS2_SimpleAdmin._localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player, (_, _, reason) =>
@@ -211,7 +211,7 @@ public static class ManagePlayersMenu
CS2_SimpleAdmin.Instance.Warn(admin, player, duration, reason); CS2_SimpleAdmin.Instance.Warn(admin, player, duration, reason);
} }
private static void GagMenu(CCSPlayerController admin, CCSPlayerController player, int duration) internal static void GagMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{ {
ReasonMenu.OpenMenu(admin, PenaltyType.Gag, ReasonMenu.OpenMenu(admin, PenaltyType.Gag,
$"{CS2_SimpleAdmin._localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player, (_, _, reason) => $"{CS2_SimpleAdmin._localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player, (_, _, reason) =>
@@ -241,7 +241,7 @@ public static class ManagePlayersMenu
CS2_SimpleAdmin.Instance.Gag(admin, player, duration, reason); CS2_SimpleAdmin.Instance.Gag(admin, player, duration, reason);
} }
private static void MuteMenu(CCSPlayerController admin, CCSPlayerController player, int duration) internal static void MuteMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{ {
ReasonMenu.OpenMenu(admin, PenaltyType.Mute, ReasonMenu.OpenMenu(admin, PenaltyType.Mute,
$"{CS2_SimpleAdmin._localizer?["sa_mute"] ?? "mute"}: {player.PlayerName}", player, (_, _, reason) => $"{CS2_SimpleAdmin._localizer?["sa_mute"] ?? "mute"}: {player.PlayerName}", player, (_, _, reason) =>
@@ -272,7 +272,7 @@ public static class ManagePlayersMenu
CS2_SimpleAdmin.Instance.Mute(admin, player, duration, reason); CS2_SimpleAdmin.Instance.Mute(admin, player, duration, reason);
} }
private static void SilenceMenu(CCSPlayerController admin, CCSPlayerController player, int duration) internal static void SilenceMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{ {
ReasonMenu.OpenMenu(admin, PenaltyType.Silence, ReasonMenu.OpenMenu(admin, PenaltyType.Silence,
$"{CS2_SimpleAdmin._localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player, (_, _, reason) => $"{CS2_SimpleAdmin._localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player, (_, _, reason) =>

View File

@@ -16,6 +16,8 @@ public static class ReasonMenu
PenaltyType.Kick => CS2_SimpleAdmin.Instance.Config.MenuConfigs.KickReasons, PenaltyType.Kick => CS2_SimpleAdmin.Instance.Config.MenuConfigs.KickReasons,
PenaltyType.Mute => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons, PenaltyType.Mute => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
PenaltyType.Warn => CS2_SimpleAdmin.Instance.Config.MenuConfigs.WarnReasons, PenaltyType.Warn => CS2_SimpleAdmin.Instance.Config.MenuConfigs.WarnReasons,
PenaltyType.Gag => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
PenaltyType.Silence => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
_ => CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons _ => CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons
}; };

View File

@@ -1 +1 @@
1.6.1b 1.6.2a

View File

@@ -3,18 +3,24 @@ using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions; using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CS2_SimpleAdmin.Models; using CS2_SimpleAdmin.Models;
using CS2_SimpleAdminApi; using CS2_SimpleAdminApi;
using Discord.Webhook;
using MenuManager; using MenuManager;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using CS2_SimpleAdmin.Managers;
namespace CS2_SimpleAdmin; namespace CS2_SimpleAdmin;
public partial class CS2_SimpleAdmin public partial class CS2_SimpleAdmin
{ {
// Config
public CS2_SimpleAdminConfig Config { get; set; } = new();
// HttpClient
internal static readonly HttpClient HttpClient = new();
// Paths // Paths
internal static string ConfigDirectory = Path.Combine(Application.RootDirectory, "configs/plugins/CS2-SimpleAdmin"); internal static readonly string ConfigDirectory = Path.Combine(Application.RootDirectory, "configs/plugins/CS2-SimpleAdmin");
// Localization // Localization
public static IStringLocalizer? _localizer; public static IStringLocalizer? _localizer;
@@ -39,7 +45,7 @@ public partial class CS2_SimpleAdmin
private static readonly List<DisconnectedPlayer> DisconnectedPlayers = []; private static readonly List<DisconnectedPlayer> DisconnectedPlayers = [];
// Discord Integration // Discord Integration
internal static DiscordWebhookClient? DiscordWebhookClientLog; internal static DiscordManager? DiscordWebhookClientLog;
// Database Settings // Database Settings
internal string DbConnectionString = string.Empty; internal string DbConnectionString = string.Empty;
@@ -57,4 +63,10 @@ public partial class CS2_SimpleAdmin
// Shared API // Shared API
private Api.CS2_SimpleAdminApi? SimpleAdminApi { get; set; } private Api.CS2_SimpleAdminApi? SimpleAdminApi { get; set; }
// Managers
internal PermissionManager PermissionManager = new(Database);
internal BanManager BanManager = new(Database);
internal MuteManager MuteManager = new(Database);
internal WarnManager WarnManager = new(Database);
} }