diff --git a/.gitignore b/.gitignore index 8359a57..4284741 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ obj/ .vs/ .git .vscode/ -.idea/ \ No newline at end of file +.idea/ +*.sln \ No newline at end of file diff --git a/CS2-SimpleAdmin.sln b/CS2-SimpleAdmin.sln index e59a911..3cdfc2b 100644 --- a/CS2-SimpleAdmin.sln +++ b/CS2-SimpleAdmin.sln @@ -1,11 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.8.34309.116 +VisualStudioVersion = 17.5.002.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CS2-SimpleAdmin", "CS2-SimpleAdmin\CS2-SimpleAdmin.csproj", "{CC7C3B4D-26C9-4DE7-B4E1-0864350468D0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CS2-SimpleAdmin", "CS2-SimpleAdmin\CS2-SimpleAdmin.csproj", "{10611B4A-49BC-4556-A000-C1F922C4979D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CS2-SimpleAdminApi", "CS2-SimpleAdminApi\CS2-SimpleAdminApi.csproj", "{8BEF0C35-7E4E-4BAF-B632-8584FAFCA922}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CS2-SimpleAdminApi", "CS2-SimpleAdminApi\CS2-SimpleAdminApi.csproj", "{2A46E7D8-A0AC-4EB2-BCEA-BBC9049A83DB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{264FAD58-0947-4A02-86C6-39FF99B8EA51}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CS2-SimpleAdmin_ExampleModule", "Modules\CS2-SimpleAdmin_ExampleModule\CS2-SimpleAdmin_ExampleModule.csproj", "{FD770842-F4CE-468A-A0DC-7A3A30A0CED6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,19 +17,26 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CC7C3B4D-26C9-4DE7-B4E1-0864350468D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC7C3B4D-26C9-4DE7-B4E1-0864350468D0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC7C3B4D-26C9-4DE7-B4E1-0864350468D0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC7C3B4D-26C9-4DE7-B4E1-0864350468D0}.Release|Any CPU.Build.0 = Release|Any CPU - {8BEF0C35-7E4E-4BAF-B632-8584FAFCA922}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BEF0C35-7E4E-4BAF-B632-8584FAFCA922}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BEF0C35-7E4E-4BAF-B632-8584FAFCA922}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BEF0C35-7E4E-4BAF-B632-8584FAFCA922}.Release|Any CPU.Build.0 = Release|Any CPU + {10611B4A-49BC-4556-A000-C1F922C4979D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10611B4A-49BC-4556-A000-C1F922C4979D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10611B4A-49BC-4556-A000-C1F922C4979D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10611B4A-49BC-4556-A000-C1F922C4979D}.Release|Any CPU.Build.0 = Release|Any CPU + {2A46E7D8-A0AC-4EB2-BCEA-BBC9049A83DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A46E7D8-A0AC-4EB2-BCEA-BBC9049A83DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A46E7D8-A0AC-4EB2-BCEA-BBC9049A83DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A46E7D8-A0AC-4EB2-BCEA-BBC9049A83DB}.Release|Any CPU.Build.0 = Release|Any CPU + {FD770842-F4CE-468A-A0DC-7A3A30A0CED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD770842-F4CE-468A-A0DC-7A3A30A0CED6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD770842-F4CE-468A-A0DC-7A3A30A0CED6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD770842-F4CE-468A-A0DC-7A3A30A0CED6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {FD770842-F4CE-468A-A0DC-7A3A30A0CED6} = {264FAD58-0947-4A02-86C6-39FF99B8EA51} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {86114444-059F-4DB8-9A55-E6D1BB76238D} + SolutionGuid = {27D147C9-0BD5-467F-8602-83A82E4792D6} EndGlobalSection EndGlobal diff --git a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs index e67a1b4..206fc16 100644 --- a/CS2-SimpleAdmin/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin/CS2-SimpleAdmin.cs @@ -51,6 +51,8 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig SimpleAdminApi); new PlayerManager().CheckPlayersTimer(); + + ChatManager = new ChatManager(); } public override void OnAllPluginsLoaded(bool hotReload) diff --git a/CS2-SimpleAdmin/Commands/basebans.cs b/CS2-SimpleAdmin/Commands/basebans.cs index 7c2f6cd..bb60f57 100644 --- a/CS2-SimpleAdmin/Commands/basebans.cs +++ b/CS2-SimpleAdmin/Commands/basebans.cs @@ -111,7 +111,7 @@ public partial class CS2_SimpleAdmin } // Execute ban command if necessary - if (UnlockedCommands) + if (UnlockedCommands && Config.BanIDBan) { Server.ExecuteCommand($"banid 1 {new SteamID(player.SteamID).SteamId3}"); } @@ -177,7 +177,7 @@ public partial class CS2_SimpleAdmin Helper.LogCommand(caller, command); - if (UnlockedCommands) + if (UnlockedCommands && Config.BanIDBan) Server.ExecuteCommand($"banid 1 {steamId.SteamId3}"); SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Ban, reason, time); diff --git a/CS2-SimpleAdmin/Commands/basecommands.cs b/CS2-SimpleAdmin/Commands/basecommands.cs index 7447c3e..622eaea 100644 --- a/CS2-SimpleAdmin/Commands/basecommands.cs +++ b/CS2-SimpleAdmin/Commands/basecommands.cs @@ -365,27 +365,29 @@ public partial class CS2_SimpleAdmin AdminManager.RemovePlayerAdminData(steamId); } - Task.Run(async () => + if(!Config.IsCSSPanel) { - await PermissionManager.CrateGroupsJsonFile(); - await PermissionManager.CreateAdminsJsonFile(); - - var adminsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/admins.json"); - var groupsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/groups.json"); - - await Server.NextFrameAsync(() => + Task.Run(async () => { - if (!string.IsNullOrEmpty(adminsFile)) - AddTimer(0.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json")); - if (!string.IsNullOrEmpty(groupsFile)) - AddTimer(1.0f, () => AdminManager.LoadAdminGroups(ModuleDirectory + "/data/groups.json")); - if (!string.IsNullOrEmpty(adminsFile)) - AddTimer(1.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json")); - }); - }); + await PermissionManager.CreateGroupsJsonFile(); + await PermissionManager.CreateAdminsJsonFile(); - //_ = _adminManager.GiveAllGroupsFlags(); - //_ = _adminManager.GiveAllFlags(); + var adminsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/admins.json"); + var groupsFile = await File.ReadAllTextAsync(Instance.ModuleDirectory + "/data/groups.json"); + + await Server.NextFrameAsync(() => + { + if (!string.IsNullOrEmpty(adminsFile)) + AddTimer(0.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json")); + if (!string.IsNullOrEmpty(groupsFile)) + AddTimer(1.0f, () => AdminManager.LoadAdminGroups(ModuleDirectory + "/data/groups.json")); + if (!string.IsNullOrEmpty(adminsFile)) + AddTimer(1.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json")); + }); + }); + } + else + _ = PermissionManager.GiveAllFlags(); } [CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)] @@ -761,6 +763,8 @@ public partial class CS2_SimpleAdmin var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; map = map.ToLower(); + var wsMaps = Config.WorkshopMaps; + if (map.StartsWith("ws:")) { var issuedCommand = long.TryParse(map.Replace("ws:", ""), out var mapId) @@ -776,14 +780,21 @@ public partial class CS2_SimpleAdmin { if (!Server.IsMapValid(map)) { - var msg = $"Map {map} not found."; - if (command != null) - command.ReplyToCommand(msg); - else if (caller != null && caller.IsValid) - caller.PrintToChat(msg); + if(wsMaps.ContainsKey(map)) + { + map = wsMaps.Where(m => m.Key == map).FirstOrDefault().Key; + } else - Server.PrintToConsole(msg); - return; + { + var msg = $"Map {map} not found."; + if (command != null) + command.ReplyToCommand(msg); + else if (caller != null && caller.IsValid) + caller.PrintToChat(msg); + else + Server.PrintToConsole(msg); + return; + } } AddTimer(3.0f, () => diff --git a/CS2-SimpleAdmin/Commands/basecomms.cs b/CS2-SimpleAdmin/Commands/basecomms.cs index 4aa3f3d..a3bf321 100644 --- a/CS2-SimpleAdmin/Commands/basecomms.cs +++ b/CS2-SimpleAdmin/Commands/basecomms.cs @@ -273,7 +273,8 @@ public partial class CS2_SimpleAdmin var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; // Set player's voice flags to muted - player.VoiceFlags = VoiceFlags.Muted; + if (!player.VoiceFlags.HasFlag(VoiceFlags.Muted)) + player.VoiceFlags |= VoiceFlags.Muted; // Asynchronously handle mute logic Task.Run(async () => @@ -402,7 +403,8 @@ public partial class CS2_SimpleAdmin if (player != null && player.IsValid) { PlayerPenaltyManager.RemovePenaltiesByType(player.Slot, PenaltyType.Mute); - player.VoiceFlags = VoiceFlags.Normal; + if (player.VoiceFlags.HasFlag(VoiceFlags.Muted)) + player.VoiceFlags &= ~VoiceFlags.Muted; Task.Run(async () => { @@ -421,7 +423,8 @@ public partial class CS2_SimpleAdmin if (namePlayer != null && namePlayer.IsValid) { PlayerPenaltyManager.RemovePenaltiesByType(namePlayer.Slot, PenaltyType.Mute); - namePlayer.VoiceFlags = VoiceFlags.Normal; + if (namePlayer.VoiceFlags.HasFlag(VoiceFlags.Muted)) + namePlayer.VoiceFlags &= ~VoiceFlags.Muted; if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalMutes > 0) PlayersInfo[namePlayer.UserId.Value].TotalMutes--; @@ -491,6 +494,10 @@ public partial class CS2_SimpleAdmin var playerInfo = PlayersInfo[player.UserId.Value]; var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null; + // Set player's voice flags to muted + if (!player.VoiceFlags.HasFlag(VoiceFlags.Muted)) + player.VoiceFlags |= VoiceFlags.Muted; + // Asynchronously handle silence logic Task.Run(async () => { @@ -620,7 +627,8 @@ public partial class CS2_SimpleAdmin PlayerPenaltyManager.RemovePenaltiesByType(player.Slot, PenaltyType.Silence); // Reset voice flags to normal - player.VoiceFlags = VoiceFlags.Normal; + if (player.VoiceFlags.HasFlag(VoiceFlags.Muted)) + player.VoiceFlags &= ~VoiceFlags.Muted; Task.Run(async () => { @@ -641,7 +649,8 @@ public partial class CS2_SimpleAdmin PlayerPenaltyManager.RemovePenaltiesByType(namePlayer.Slot, PenaltyType.Silence); // Reset voice flags to normal - namePlayer.VoiceFlags = VoiceFlags.Normal; + if (namePlayer.VoiceFlags.HasFlag(VoiceFlags.Muted)) + namePlayer.VoiceFlags &= ~VoiceFlags.Muted; if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalSilences > 0) PlayersInfo[namePlayer.UserId.Value].TotalSilences--; diff --git a/CS2-SimpleAdmin/Commands/panelcommands.cs b/CS2-SimpleAdmin/Commands/panelcommands.cs new file mode 100644 index 0000000..5b72af9 --- /dev/null +++ b/CS2-SimpleAdmin/Commands/panelcommands.cs @@ -0,0 +1,136 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Core.Translations; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Cvars; +using CounterStrikeSharp.API.Modules.Entities; +using CounterStrikeSharp.API.Modules.Menu; +using CounterStrikeSharp.API.Modules.Utils; +using CS2_SimpleAdmin.Managers; +using CS2_SimpleAdmin.Menus; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System.Globalization; +using System.Text; + +namespace CS2_SimpleAdmin; +public partial class CS2_SimpleAdmin +{ + [ConsoleCommand("css_panel_say", "Say to all players from the panel.")] + [CommandHelper(1, "")] + [RequiresPermissions("@css/root")] + public void OnPanelSayCommand(CCSPlayerController? caller, CommandInfo command) + { + if (!Config.IsCSSPanel) return; + if (command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0) return; + + byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]); + string utf8String = Encoding.UTF8.GetString(utf8BytesString); + + foreach (CCSPlayerController player in Utilities.GetPlayers().Where(p => !p.IsBot && !p.IsHLTV)) + { + player.PrintToChat(StringExtensions.ReplaceColorTags(utf8String)); + } + } + + /** + * Prints the server info and a list of players to the console + */ + [ConsoleCommand("css_query")] + [CommandHelper(whoCanExecute: CommandUsage.SERVER_ONLY)] + [RequiresPermissions("@css/root")] + public void OnQueryCommand(CCSPlayerController? caller, CommandInfo command) + { + if (!Config.IsCSSPanel) return; + + List playersToTarget = Utilities.GetPlayers().Where(player => caller!.CanTarget(player) && !player.IsHLTV).ToList(); + + string Map = Server.MapName; + int Players = playersToTarget.Count; + int MaxPlayers = Server.MaxPlayers; + string[] Maps; + + MaxPlayers = ConVar.Find("sv_visiblemaxplayers")?.GetPrimitiveValue() ?? -1; + MaxPlayers = MaxPlayers <= -1 ? Server.MaxPlayers : MaxPlayers; + + try + { + Maps = Server.GetMapList(); + } + catch (Exception) + { + Maps = Array.Empty(); // return an empty array + } + + var server = new + { + map = Map, + p = Players, + mP = MaxPlayers, + // maps = Maps, + pr = ModuleVersion + }; + + List> playerTasks = playersToTarget + .FindAll(player => !player.IsBot && !player.IsHLTV && player.PlayerName != "") + .Select(player => + { + string deaths = player.ActionTrackingServices!.MatchStats.Deaths.ToString(); + string headshots = player.ActionTrackingServices!.MatchStats.HeadShotKills.ToString(); + string assists = player.ActionTrackingServices!.MatchStats.Assists.ToString(); + string damage = player.ActionTrackingServices!.MatchStats.Damage.ToString(); + string kills = player.ActionTrackingServices!.MatchStats.Kills.ToString(); + string time = player.ActionTrackingServices!.MatchStats.LiveTime.ToString(); + var user = new + { + id = player.UserId, + // playerName = player.PlayerName, + // ipAddress = player.IpAddress?.Split(":")[0], + // accountId = player.AuthorizedSteamID?.AccountId.ToString(), + // steamId2 = player.AuthorizedSteamID?.SteamId2, + // steamId3 = player.AuthorizedSteamID?.SteamId3, + s64 = player.AuthorizedSteamID?.SteamId64.ToString(), + // ping = player.Ping, + t = player.Team, + // clanName = player.ClanName, + k = kills, + d = deaths, + // assists, + // headshots, + // damage, + s = player.Score, + // roundScore = player.RoundScore, + // roundsWon = player.RoundsWon, + // mvps = player.MVPs, + // time, // ? Fix this, it's not the time the player has been connected + // avatar = player.AuthorizedSteamID != null ? await GetProfilePictureAsync(player.AuthorizedSteamID.SteamId64.ToString(), true) : "" + }; + return Task.FromResult((object)user); + }).ToList(); + + List players = new List(); + try + { + players = Task.WhenAll(playerTasks).Result.ToList(); + } + catch (AggregateException ex) + { + foreach (var innerEx in ex.InnerExceptions) + { + Logger.LogError(innerEx, "Error while querying players"); + } + } + + string jsonString = JsonConvert.SerializeObject( + new + { + server, + players + } + ); + + Server.PrintToConsole(jsonString); + } +} \ No newline at end of file diff --git a/CS2-SimpleAdmin/Commands/playercommands.cs b/CS2-SimpleAdmin/Commands/playercommands.cs index 5debea2..0d5b471 100644 --- a/CS2-SimpleAdmin/Commands/playercommands.cs +++ b/CS2-SimpleAdmin/Commands/playercommands.cs @@ -307,7 +307,6 @@ public partial class CS2_SimpleAdmin } } - [ConsoleCommand("css_gravity")] [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name> ", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnGravityCommand(CCSPlayerController? caller, CommandInfo command) diff --git a/CS2-SimpleAdmin/Config.cs b/CS2-SimpleAdmin/Config.cs index f523734..5e7cc30 100644 --- a/CS2-SimpleAdmin/Config.cs +++ b/CS2-SimpleAdmin/Config.cs @@ -91,6 +91,21 @@ public class Discord ]; } +public class ChatLog +{ + [JsonPropertyName("ChatLog_Enable")] + public bool ChatLog_Enable { get; set; } = true; + + [JsonPropertyName("ChatLog_ExcludeMessageContains")] + public string ExcludeMessageContains { get; set; } = "!./"; + + [JsonPropertyName("ChatLog_ExcludeMessageContainsLessThanXLetters")] + public int ExcludeMessageContainsLessThanXLetters { get; set; } = 0; + + [JsonPropertyName("ChatLog_ExcludeMessageDuplicate")] + public bool ExcludeMessageDuplicate { get; set; } = false; +} + public class CustomServerCommandData { [JsonPropertyName("Flag")] @@ -273,4 +288,16 @@ public class CS2_SimpleAdminConfig : BasePluginConfig [JsonPropertyName("MenuConfig")] public MenuConfig MenuConfigs { get; set; } = new(); + + [JsonPropertyName("ChatLog")] + public ChatLog ChatLog { get; set; } = new ChatLog(); + + [JsonPropertyName("Statistics_Enable")] + public bool Statistics_Enable { get; set; } = true; + + [JsonPropertyName("IsCSSPanel")] + public bool IsCSSPanel { get; set; } = false; + + [JsonPropertyName("BanIDBan")] + public bool BanIDBan { get; set; } = true; } \ No newline at end of file diff --git a/CS2-SimpleAdmin/Database/Migrations/001_CreateTables.sql b/CS2-SimpleAdmin/Database/Migrations/001_CreateTables.sql index fb8292f..a30e1b7 100644 --- a/CS2-SimpleAdmin/Database/Migrations/001_CreateTables.sql +++ b/CS2-SimpleAdmin/Database/Migrations/001_CreateTables.sql @@ -45,6 +45,36 @@ CREATE TABLE IF NOT EXISTS `sa_servers` ( `id` int(11) NOT NULL AUTO_INCREMENT, `hostname` varchar(128) NOT NULL, `address` varchar(64) NOT NULL, + `rcon` varchar(64) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `address` (`address`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `sa_chatlogs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `serverId` varchar(64) NOT NULL, + `playerSteam64` varchar(64) NOT NULL, + `playerName` varchar(64) NOT NULL, + `message` TEXT, + `team` BOOLEAN NOT NULL, + `created` timestamp NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `sa_statistics` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `serverId` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `playerId` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `playerName` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `playerIP` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `connectDate` timestamp DEFAULT CURRENT_TIMESTAMP, + `connectTime` INT(20) NOT NULL, + `disconnectDate` timestamp NULL DEFAULT NULL, + `disconnectTime` INT(20) NULL DEFAULT NULL, + `duration` INT(20) NULL DEFAULT NULL, + `kills` INT(10) NULL DEFAULT NULL, + `flags` TEXT COLLATE 'utf8mb4_general_ci', + `map` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE, + INDEX `playerId` (`playerId`) USING BTREE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/CS2-SimpleAdmin/Database/Migrations/011_CSSPanelSupport.sql b/CS2-SimpleAdmin/Database/Migrations/011_CSSPanelSupport.sql new file mode 100644 index 0000000..5fce9a0 --- /dev/null +++ b/CS2-SimpleAdmin/Database/Migrations/011_CSSPanelSupport.sql @@ -0,0 +1,30 @@ +ALTER TABLE `sa_servers` ADD `rcon` varchar(64) NOT NULL AFTER `address`; + +CREATE TABLE IF NOT EXISTS `sa_chatlogs` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `serverId` varchar(64) NOT NULL, + `playerSteam64` varchar(64) NOT NULL, + `playerName` varchar(64) NOT NULL, + `message` TEXT, + `team` BOOLEAN NOT NULL, + `created` timestamp NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `sa_statistics` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `serverId` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `playerId` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `playerName` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `playerIP` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + `connectDate` timestamp DEFAULT CURRENT_TIMESTAMP, + `connectTime` INT(20) NOT NULL, + `disconnectDate` timestamp NULL DEFAULT NULL, + `disconnectTime` INT(20) NULL DEFAULT NULL, + `duration` INT(20) NULL DEFAULT NULL, + `kills` INT(10) NULL DEFAULT NULL, + `flags` TEXT COLLATE 'utf8mb4_general_ci', + `map` VARCHAR(64) NOT NULL COLLATE 'utf8mb4_general_ci', + PRIMARY KEY (`id`) USING BTREE, + INDEX `playerId` (`playerId`) USING BTREE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/CS2-SimpleAdmin/Events.cs b/CS2-SimpleAdmin/Events.cs index e92329f..5ced95a 100644 --- a/CS2-SimpleAdmin/Events.cs +++ b/CS2-SimpleAdmin/Events.cs @@ -117,7 +117,13 @@ public partial class CS2_SimpleAdmin if (player == null || !player.IsValid || player.IsBot) return HookResult.Continue; - new PlayerManager().LoadPlayerData(player); + AddTimer(1.25f, () => + { + if(player == null || !player.IsValid) + return; + + new PlayerManager().LoadPlayerData(player); + }); return HookResult.Continue; } @@ -164,7 +170,8 @@ public partial class CS2_SimpleAdmin if (!command.Contains("say")) return HookResult.Continue; - if (info.GetArg(1).StartsWith($"/") + if (string.IsNullOrWhiteSpace(info.GetArg(1)) + || info.GetArg(1).StartsWith($"/") || info.GetArg(1).StartsWith($"!")) return HookResult.Continue; @@ -180,6 +187,36 @@ public partial class CS2_SimpleAdmin player.ExecuteClientCommandFromServer($"css_say {info.GetArg(1).Remove(0, 1)}"); return HookResult.Stop; } + + if ((command == "say" || command == "say_team") && Config.IsCSSPanel) + { + var message = info.GetArg(1); + + string trimmedMessage1 = message.TrimStart(); + string trimmedMessage = trimmedMessage1.TrimEnd(); + + //Console.WriteLine($"{IsStringValid(trimmedMessage)} | {Config.ChatLog.ExcludeMessageContainsLessThanXLetters} | {CountLetters(trimmedMessage)}"); + + if (IsStringValid(trimmedMessage) && (Config.ChatLog.ExcludeMessageContainsLessThanXLetters <= 0 || CountLetters(trimmedMessage) > Config.ChatLog.ExcludeMessageContainsLessThanXLetters)) + { + var vplayername = player.PlayerName; + var steamId64 = (player.AuthorizedSteamID != null) ? player.AuthorizedSteamID.SteamId64.ToString() : "InvalidSteamID"; + + secondMessage = firstMessage; + firstMessage = trimmedMessage; + + if (!Config.ChatLog.ExcludeMessageDuplicate || secondMessage != firstMessage) + { + // Add to db + ChatManager.AddChatMessageDB( + steamId64, + vplayername, + trimmedMessage, + command.Contains("say_team") + ); + } + } + } if (command != "say_team" || !info.GetArg(1).StartsWith($"@")) return HookResult.Continue; diff --git a/CS2-SimpleAdmin/Events_Statistics.cs b/CS2-SimpleAdmin/Events_Statistics.cs new file mode 100644 index 0000000..750078b --- /dev/null +++ b/CS2-SimpleAdmin/Events_Statistics.cs @@ -0,0 +1,130 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Entities; +using CounterStrikeSharp.API.Modules.Utils; +using CS2_SimpleAdmin.Managers; +using CS2_SimpleAdmin.Models; +using Microsoft.Extensions.Logging; +using System.Text; +using CounterStrikeSharp.API.Modules.Admin; +using Dapper; + +namespace CS2_SimpleAdmin; + +public partial class CS2_SimpleAdmin +{ + [GameEventHandler] + public HookResult OnPlayerConnectStatistics(EventPlayerConnectFull @event, GameEventInfo info) + { + if (!Config.IsCSSPanel) return HookResult.Continue; + if (Config.Statistics_Enable == false) return HookResult.Continue; + + CCSPlayerController? player = @event.Userid; + + if (player == null || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1") + || player.IsBot || player.IsHLTV || !player.UserId.HasValue || player.AuthorizedSteamID == null) + { + + return HookResult.Continue; + } + + + if (Database == null) return HookResult.Continue; + + SteamID authorizedSteamID = player.AuthorizedSteamID!; + string ipAddress = player.IpAddress!.Split(":")[0]; + string playerId = authorizedSteamID.SteamId64.ToString(); + string playerName = player.PlayerName; + + // Unix timestamp + long Time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + + string Map = Server.MapName; + + if (ServerId == null) + return HookResult.Continue; + + Task.Run(async () => + { + try + { + await using var connection = await Database.GetConnectionAsync(); + + string sql = "INSERT INTO `sa_statistics` (`serverId`, `playerId`, `playerName`, `playerIP`, `connectTime`, `flags`, `map`) " + + "VALUES (@serverId, @playerId, @playerName, @playerIP, @connectTime, @flags, @map)"; + + List adminFlags = await PermissionManager.GetAdminFlagsAsString(playerId); + + await connection.ExecuteAsync(sql, new + { + serverId = ServerId, + playerId, + playerName, + playerIP = ipAddress, + connectTime = Time, + flags = adminFlags.Count > 0 ? string.Join(",", adminFlags) : null, + map = Map + }); + } + catch (Exception ex) + { + Logger.LogError($"An error occurred in OnPlayerConnect: {ex.Message}"); + } + }); + + return HookResult.Continue; + } + + [GameEventHandler] + public HookResult OnClientDisconnectStatistics(EventPlayerDisconnect @event, GameEventInfo info) + { + if (!Config.IsCSSPanel) return HookResult.Continue; + if (Config.Statistics_Enable == false) return HookResult.Continue; + + CCSPlayerController? player = @event.Userid; + + if (player == null || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1") + || player.IsBot || player.IsHLTV || !player.UserId.HasValue || player.AuthorizedSteamID == null) + return HookResult.Continue; + + if (Database == null) return HookResult.Continue; + + SteamID authorizedSteamID = player.AuthorizedSteamID!; + string ipAddress = player.IpAddress!.Split(":")[0]; + string playerId = authorizedSteamID.SteamId64.ToString(); + string playerName = player.PlayerName; + DateTime now = DateTime.Now; + + // Unix timestamp + long Time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + string kills = player.ActionTrackingServices!.MatchStats.Kills.ToString(); + + Task.Run(async () => + { + try + { + await using var connection = await Database.GetConnectionAsync(); + + string sql = "UPDATE `sa_statistics` SET `disconnectTime` = @disconnectTime, `disconnectDate` = @disconnectDate, `kills` = @kills, `duration` = @disconnectTime - `connectTime` " + + "WHERE `playerId` = @playerId AND `disconnectTime` IS NULL"; + + await connection.ExecuteAsync(sql, new + { + disconnectTime = Time, + disconnectDate = now, + kills, + playerId, + }); + } + catch (Exception ex) + { + Logger.LogError($"An error occurred in OnClientDisconnectStatistics: {ex.Message}"); + } + }); + + return HookResult.Continue; + + } +} \ No newline at end of file diff --git a/CS2-SimpleAdmin/Helper.cs b/CS2-SimpleAdmin/Helper.cs index ce6f797..3872992 100644 --- a/CS2-SimpleAdmin/Helper.cs +++ b/CS2-SimpleAdmin/Helper.cs @@ -22,6 +22,33 @@ using CS2_SimpleAdmin.Managers; namespace CS2_SimpleAdmin; +public partial class CS2_SimpleAdmin +{ + bool IsStringValid(string input) + { + if (!string.IsNullOrEmpty(input) && (string.IsNullOrEmpty(Config.ChatLog.ExcludeMessageContains) || !input.Any(c => Config.ChatLog.ExcludeMessageContains.Contains(c))) && !char.IsWhiteSpace(input.Last())) + { + return true; + } + return false; + } + + static int CountLetters(string input) + { + int count = 0; + + foreach (char c in input) + { + if (char.IsLetter(c)) + { + count++; + } + } + + return count; + } +} + internal static class Helper { private static readonly string AssemblyName = Assembly.GetExecutingAssembly().GetName().Name ?? ""; diff --git a/CS2-SimpleAdmin/Managers/ChatManager.cs b/CS2-SimpleAdmin/Managers/ChatManager.cs new file mode 100644 index 0000000..ad11aae --- /dev/null +++ b/CS2-SimpleAdmin/Managers/ChatManager.cs @@ -0,0 +1,40 @@ +using Dapper; +using Microsoft.Extensions.Logging; + +namespace CS2_SimpleAdmin.Managers; + +public class ChatManager +{ + public void AddChatMessageDB(string playerSteam64, string playerName, string message, bool? team) + { + if (CS2_SimpleAdmin.Database == null) return; + + Task.Run(async () => + { + try + { + await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); + + var sql = "INSERT INTO `sa_chatlogs` (`playerSteam64`, `playerName`, `message`, `team`, `created`, `serverId`) " + + "VALUES (@playerSteam64, @playerName, @message, @team, @created, @serverId)"; + int? serverId = CS2_SimpleAdmin.ServerId; + if (serverId == null) + return; + DateTime now = DateTime.Now; + await connection.ExecuteAsync(sql, new + { + playerSteam64, + playerName, + message, + team = team ?? null, + created = now, + serverid = serverId + }); + } + catch (Exception e) + { + CS2_SimpleAdmin._logger?.LogError(e.Message); + } + }); + } +} \ No newline at end of file diff --git a/CS2-SimpleAdmin/Managers/PermissionManager.cs b/CS2-SimpleAdmin/Managers/PermissionManager.cs index 4ac21b0..8c56510 100644 --- a/CS2-SimpleAdmin/Managers/PermissionManager.cs +++ b/CS2-SimpleAdmin/Managers/PermissionManager.cs @@ -1,4 +1,5 @@ using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Entities; using Dapper; using Microsoft.Extensions.Logging; @@ -14,22 +15,77 @@ public class PermissionManager(Database.Database? database) //public static readonly ConcurrentDictionary> _adminCache = new ConcurrentDictionary>(); public static readonly ConcurrentDictionary AdminCache = new(); - /* - public async Task, int)>> GetAdminFlags(string steamId) + // Get the relevant server groups from the sa_servers_groups table by searching if the serverId is in the servers set column + public async Task> GetServerGroups() { - DateTime now = Time.ActualDateTime(); + if (database == null) return []; + + await using MySqlConnection connection = await database.GetConnectionAsync(); - await using MySqlConnection connection = await _database.GetConnectionAsync(); + string sql = "SELECT id FROM sa_servers_groups WHERE FIND_IN_SET(@ServerId, servers)"; + List? serverGroups = (await connection.QueryAsync(sql, new { ServerId = CS2_SimpleAdmin.ServerId }))?.ToList(); + + if (serverGroups == null) + { + return new List(); + } + + List serverGroupsList = new List(); + + foreach (dynamic serverGroup in serverGroups) + { + if (serverGroup is not IDictionary serverGroupDict) + { + Console.WriteLine("[GetServerGroups] Failed to parse server group."); + continue; + } + + if (!serverGroupDict.TryGetValue("id", out var idObj)) + { + Console.WriteLine("[GetServerGroups] Failed to get server group id."); + continue; + } + + if (idObj is not string id) + { + // Convert to string and add it to the list + // Console.WriteLine("[GetServerGroups] Failed to parse server group id."); + serverGroupsList.Add(idObj.ToString()!); + + continue; + } + + serverGroupsList.Add(id); + } + + Console.WriteLine($"[GetServerGroups] Server Groups List: {string.Join(", ", serverGroupsList)}"); + return serverGroupsList; + } + + public async Task> GetAdminFlagsAsString(string steamId) + { + if (database == null) return []; + + DateTime now = DateTime.UtcNow.ToLocalTime(); + + await using MySqlConnection connection = await database.GetConnectionAsync(); + + // string sql = "SELECT flags, immunity, ends FROM sa_admins WHERE player_steamid = @PlayerSteamID AND (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR FIND_IN_SET(@serverid, server_id) > 0)"; + // string sql = "SELECT player_steamid, flags, immunity, ends FROM sa_admins WHERE (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR FIND_IN_SET(@serverid, server_id) > 0)"; + List serverGroups = await GetServerGroups(); + string serverGroupsCondition = string.Join(" OR ", serverGroups.Select(g => $"FIND_IN_SET({g}, servers_groups) > 0")); + + string GroupCheck = serverGroups.Count > 0 ? $"AND (((server_id IS NULL AND servers_groups IS NULL) OR FIND_IN_SET(@serverid, server_id) > 0) OR (servers_groups IS NULL OR {serverGroupsCondition}))" : "AND ((server_id IS NULL AND servers_groups IS NULL) OR FIND_IN_SET(@serverid, server_id) > 0)"; + string sql = $"SELECT flags, immunity, ends FROM sa_admins WHERE player_steamid = @PlayerSteamID AND (ends IS NULL OR ends > @CurrentTime) {GroupCheck}"; - string sql = "SELECT flags, immunity, ends FROM sa_admins WHERE player_steamid = @PlayerSteamID AND (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR server_id = @serverid)"; List? activeFlags = (await connection.QueryAsync(sql, new { PlayerSteamID = steamId, CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId }))?.ToList(); if (activeFlags == null) { - return new List<(List, int)>(); + return new List(); } - List<(List, int)> filteredFlagsWithImmunity = []; + List flagsList = new List(); foreach (dynamic flags in activeFlags) { @@ -38,26 +94,160 @@ public class PermissionManager(Database.Database? database) continue; } - if (!flagsDict.TryGetValue("flags", out var flagsValueObj) || !flagsDict.TryGetValue("immunity", out var immunityValueObj)) + if (!flagsDict.TryGetValue("flags", out var flagsValueObj)) { continue; } - if (!(flagsValueObj is string flagsValue) || !int.TryParse(immunityValueObj.ToString(), out var immunityValue)) + if (!(flagsValueObj is string flagsValue)) { continue; } - //Console.WriteLine($"Flags: {flagsValue}, Immunity: {immunityValue}"); + // If flags start with '#', fetch flags from sa_admins_groups + if (flagsValue.StartsWith("#")) + { + string groupSql = "SELECT flags FROM sa_admins_groups WHERE id = @GroupId"; + var group = await connection.QueryFirstOrDefaultAsync(groupSql, new { GroupId = flagsValue }); - filteredFlagsWithImmunity.Add((flagsValue.Split(',').ToList(), immunityValue)); + if (group != null) + { + flagsValue = group.flags; + } + } + + flagsList.AddRange(flagsValue.Split(',')); } - return filteredFlagsWithImmunity; + return flagsList; } - */ - private async Task, int, DateTime?)>> GetAllPlayersFlags() + public async Task, int, DateTime?)>> GetAllPlayersFlags() + { + if (database == null) return []; + + DateTime now = DateTime.UtcNow.ToLocalTime(); + + try + { + await using MySqlConnection connection = await database.GetConnectionAsync(); + + // string sql = "SELECT player_steamid, flags, immunity, ends FROM sa_admins WHERE (ends IS NULL OR ends > @CurrentTime) AND (server_id IS NULL OR FIND_IN_SET(@serverid, server_id) > 0)"; + List serverGroups = await GetServerGroups(); + string serverGroupsCondition = string.Join(" OR ", serverGroups.Select(g => $"FIND_IN_SET({g}, servers_groups) > 0")); + + string GroupCheck = serverGroups.Count > 0 ? $"AND (((server_id IS NULL AND servers_groups IS NULL) OR FIND_IN_SET(@serverid, server_id) > 0) OR (servers_groups IS NULL OR {serverGroupsCondition}))" : "AND ((server_id IS NULL AND servers_groups IS NULL) OR FIND_IN_SET(@serverid, server_id) > 0)"; + string sql = $"SELECT player_steamid, flags, immunity, ends FROM sa_admins WHERE (ends IS NULL OR ends > @CurrentTime) {GroupCheck}"; + + List? activeFlags = (await connection.QueryAsync(sql, new { CurrentTime = now, serverid = CS2_SimpleAdmin.ServerId }))?.ToList(); + + if (activeFlags == null) + { + return new List<(string, List, int, DateTime?)>(); + } + + List<(string, List, int, DateTime?)> filteredFlagsWithImmunity = new List<(string, List, int, DateTime?)>(); + + foreach (dynamic flags in activeFlags) + { + if (flags is not IDictionary flagsDict) + { + continue; + } + + if (!flagsDict.TryGetValue("player_steamid", out var steamIdObj) || + !flagsDict.TryGetValue("flags", out var flagsValueObj) || + !flagsDict.TryGetValue("immunity", out var immunityValueObj) || + !flagsDict.TryGetValue("ends", out var endsObj)) + { + //Console.WriteLine("One or more required keys are missing."); + continue; + } + + DateTime? ends = null; + + if (endsObj != null) // Check if "ends" is not null + { + if (!DateTime.TryParse(endsObj.ToString(), out var parsedEnds)) + { + //Console.WriteLine("Failed to parse 'ends' value."); + continue; + } + + ends = parsedEnds; + } + + if (!(steamIdObj is string steamId) || + !(flagsValueObj is string flagsValue) || + !int.TryParse(immunityValueObj.ToString(), out var immunityValue)) + { + //Console.WriteLine("Failed to parse one or more values."); + continue; + } + + // + if (flagsValue.StartsWith("#")) + { + string groupSql = "SELECT flags, immunity FROM sa_admins_groups WHERE id = @GroupId"; + var group = await connection.QueryFirstOrDefaultAsync(groupSql, new { GroupId = flagsValue }); + + if (group != null) + { + flagsValue = group.flags; + if (int.TryParse(group.immunity.ToString(), out int immunityGroupValue)) + { + filteredFlagsWithImmunity.Add((steamId, flagsValue.Split(',').ToList(), immunityGroupValue, ends)); + // Console.WriteLine($"Flags Check (Group): SteamId {steamId} Flags: {flagsValue}, Immunity: {immunityValue}"); + + continue; + } + else + { + Console.WriteLine($"Failed to parse immunity: {group.immunity}"); + } + } + } + + filteredFlagsWithImmunity.Add((steamId, flagsValue.Split(',').ToList(), immunityValue, ends)); + } + + return filteredFlagsWithImmunity; + } + catch (Exception e) + { + Console.WriteLine($"Error: {e.Message}"); + return new List<(string, List, int, DateTime?)>(); + } + } + + public async Task GiveAllFlags() + { + List<(string, List, int, DateTime?)> allPlayers = await GetAllPlayersFlags(); + + foreach (var record in allPlayers) + { + string steamIdStr = record.Item1; + List flags = record.Item2; + int immunity = record.Item3; + + DateTime? ends = record.Item4; + + if (!string.IsNullOrEmpty(steamIdStr) && SteamID.TryParse(steamIdStr, out var steamId) && steamId != null) + { + if (!AdminCache.ContainsKey(steamId)) + { + AdminCache.TryAdd(steamId, ends); + //_adminCacheTimestamps.Add(steamId, ends); + } + + Helper.GivePlayerFlags(steamId, flags, (uint)immunity); + // Often need to call 2 times + Helper.GivePlayerFlags(steamId, flags, (uint)immunity); + } + } + } + + private async Task, int, DateTime?)>> GetAllPlayersFlagsSA() { if (database == null) return []; @@ -111,71 +301,6 @@ public class PermissionManager(Database.Database? database) } } - /* - public async Task, List>, int>>> GetAllGroupsFlags() - { - try - { - await using MySqlConnection connection = await _database.GetConnectionAsync(); - - string sql = "SELECT group_id FROM sa_groups_servers WHERE server_id = @serverid"; - var groupIds = connection.Query(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList(); - - sql = @" - SELECT g.group_id, f.flag - FROM sa_groups_flags f - JOIN sa_groups_servers g ON f.group_id = g.group_id - WHERE g.server_id = @serverid"; - - var groupFlagData = connection.Query(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList(); - - if (groupIds.Count == 0 || groupFlagData.Count == 0) - { - return []; - } - - var groupInfoDictionary = new Dictionary, List>, int>>(); - - foreach (var groupId in groupIds) - { - groupInfoDictionary[groupId] = new Tuple, List>, int>([], [], 0); - } - - foreach (var row in groupFlagData) - { - var groupId = (int)row.group_id; - var flag = (string)row.flag; - - groupInfoDictionary[groupId].Item1.Add(flag); - } - - sql = @" - SELECT a.group_id, a.player_steamid, a.ends, g.immunity, g.name - FROM sa_admins a - JOIN sa_groups g ON a.group_id = g.id - WHERE a.group_id IN @groupIds"; - - var playerData = (await connection.QueryAsync(sql, new { groupIds })).ToList(); - - foreach (var row in playerData) - { - var groupId = (int)row.group_id; - var playerSteamid = (string)row.player_steamid; - var ends = row.ends as DateTime?; - var immunity = (int)row.immunity; - - groupInfoDictionary[groupId].Item2.Add(new Tuple(playerSteamid, ends)); - groupInfoDictionary[groupId] = new Tuple, List>, int>(groupInfoDictionary[groupId].Item1, groupInfoDictionary[groupId].Item2, immunity); - } - - return groupInfoDictionary; - } - catch { } - - return []; - } - */ - private async Task, int)>> GetAllGroupsData() { if (database == null) return []; @@ -184,6 +309,7 @@ public class PermissionManager(Database.Database? database) try { var sql = "SELECT group_id FROM sa_groups_servers WHERE (server_id = @serverid OR server_id IS NULL)"; + var groupDataSql = connection.Query(sql, new { serverid = CS2_SimpleAdmin.ServerId }).ToList(); sql = """ @@ -230,7 +356,7 @@ public class PermissionManager(Database.Database? database) return []; } - public async Task CrateGroupsJsonFile() + public async Task CreateGroupsJsonFile() { var groupsData = await GetAllGroupsData(); @@ -252,69 +378,9 @@ public class PermissionManager(Database.Database? database) await File.WriteAllTextAsync(filePath, json); } - /* - public async Task GiveAllGroupsFlags() - { - Dictionary, List>, int>> groupFlags = await GetAllGroupsFlags(); - - foreach (var kvp in groupFlags) - { - var flags = kvp.Value.Item1; - var players = kvp.Value.Item2; - int immunity = kvp.Value.Item3; - - foreach (var playerTuple in players) - { - var steamIdStr = playerTuple.Item1; - var ends = playerTuple.Item2; - - if (!string.IsNullOrEmpty(steamIdStr) && SteamID.TryParse(steamIdStr, out var steamId) && steamId != null) - { - if (!_adminCache.ContainsKey(steamId)) - { - _adminCache.TryAdd(steamId, ends); - } - - Helper.GivePlayerFlags(steamId, flags, (uint)immunity); - // Often need to call 2 times - Helper.GivePlayerFlags(steamId, flags, (uint)immunity); - } - } - } - } - */ - /* - public async Task GiveAllFlags() - { - List<(string, string, List, int, DateTime?)> allPlayers = await GetAllPlayersFlags(); - - foreach (var record in allPlayers) - { - string steamIdStr = record.Item1; - List flags = record.Item2; - int immunity = record.Item3; - - DateTime? ends = record.Item4; - - if (!string.IsNullOrEmpty(steamIdStr) && SteamID.TryParse(steamIdStr, out var steamId) && steamId != null) - { - if (!_adminCache.ContainsKey(steamId)) - { - _adminCache.TryAdd(steamId, ends); - //_adminCacheTimestamps.Add(steamId, ends); - } - - Helper.GivePlayerFlags(steamId, flags, (uint)immunity); - // Often need to call 2 times - Helper.GivePlayerFlags(steamId, flags, (uint)immunity); - } - } - } - */ - public async Task CreateAdminsJsonFile() { - List<(string identity, string name, List flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlags(); + List<(string identity, string name, List flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlagsSA(); var validPlayers = allPlayers .Where(player => SteamID.TryParse(player.identity, out _)) // Filter invalid SteamID .ToList(); diff --git a/CS2-SimpleAdmin/Managers/PlayerManager.cs b/CS2-SimpleAdmin/Managers/PlayerManager.cs index d4138ed..8250005 100644 --- a/CS2-SimpleAdmin/Managers/PlayerManager.cs +++ b/CS2-SimpleAdmin/Managers/PlayerManager.cs @@ -109,7 +109,7 @@ public class PlayerManager if (victim?.UserId == null) return; - if (CS2_SimpleAdmin.UnlockedCommands) + if (CS2_SimpleAdmin.UnlockedCommands && _config.BanIDBan) Server.ExecuteCommand($"banid 1 {userId}"); Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED); @@ -178,7 +178,9 @@ public class PlayerManager AdminManager.PlayerHasPermissions(p, "@css/ban")) && p.Connected == PlayerConnectedState.PlayerConnected && !CS2_SimpleAdmin.AdminDisabledJoinComms.Contains(p.SteamID))) { - if (CS2_SimpleAdmin._localizer != null && admin != player) + if (CS2_SimpleAdmin._localizer != null && admin != player + && (CS2_SimpleAdmin.PlayersInfo[userId].TotalBans > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalGags > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences > 0 || CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns > 0) + ) admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_penalty_info", player.PlayerName, CS2_SimpleAdmin.PlayersInfo[userId].TotalBans, @@ -253,13 +255,14 @@ public class PlayerManager { foreach (var player in players.Where(player => PlayerPenaltyManager.IsSlotInPenalties(player.Slot))) { - if (!PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) && !PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence)) - player.VoiceFlags = VoiceFlags.Normal; + if (!PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) && !PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence) && player.VoiceFlags.HasFlag(VoiceFlags.Muted)) + player.VoiceFlags &= ~VoiceFlags.Muted; if (PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence) || PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) || PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag)) continue; - player.VoiceFlags = VoiceFlags.Normal; + if (player.VoiceFlags.HasFlag(VoiceFlags.Muted)) + player.VoiceFlags &= ~VoiceFlags.Muted; } PlayerPenaltyManager.RemoveExpiredPenalties(); diff --git a/CS2-SimpleAdmin/Managers/ServerManager.cs b/CS2-SimpleAdmin/Managers/ServerManager.cs index 3e59976..952eaf8 100644 --- a/CS2-SimpleAdmin/Managers/ServerManager.cs +++ b/CS2-SimpleAdmin/Managers/ServerManager.cs @@ -34,6 +34,7 @@ public class ServerManager var address = $"{ipAddress}:{ConVar.Find("hostport")?.GetPrimitiveValue()}"; var hostname = ConVar.Find("hostname")!.StringValue; + var rcon = ConVar.Find("rcon_password")!.StringValue; CS2_SimpleAdmin.IpAddress = address; Task.Run(async () => @@ -48,14 +49,14 @@ public class ServerManager if (!addressExists) { await connection.ExecuteAsync( - "INSERT INTO sa_servers (address, hostname) VALUES (@address, @hostname)", - new { address, hostname }); + "INSERT INTO sa_servers (address, hostname, rcon) VALUES (@address, @hostname, @rcon)", + new { address, hostname, rcon }); } else { await connection.ExecuteAsync( - "UPDATE `sa_servers` SET `hostname` = @hostname, `id` = `id` WHERE `address` = @address", - new { address, hostname }); + "UPDATE `sa_servers` SET `hostname` = @hostname, rcon = @rcon, `id` = `id` WHERE `address` = @address", + new { address, rcon, hostname }); } int? serverId = await connection.ExecuteScalarAsync( diff --git a/CS2-SimpleAdmin/Variables.cs b/CS2-SimpleAdmin/Variables.cs index db1d6d9..34b8c24 100644 --- a/CS2-SimpleAdmin/Variables.cs +++ b/CS2-SimpleAdmin/Variables.cs @@ -69,4 +69,8 @@ public partial class CS2_SimpleAdmin internal BanManager BanManager = new(Database); internal MuteManager MuteManager = new(Database); internal WarnManager WarnManager = new(Database); + internal ChatManager ChatManager = new(); + + static string firstMessage = ""; + static string secondMessage = ""; } \ No newline at end of file diff --git a/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdminApi.dll b/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdminApi.dll index c2dbdee..577b46d 100644 Binary files a/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdminApi.dll and b/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdminApi.dll differ diff --git a/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdmin_ExampleModule.sln b/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdmin_ExampleModule.sln deleted file mode 100644 index 34bbc15..0000000 --- a/Modules/CS2-SimpleAdmin_ExampleModule/CS2-SimpleAdmin_ExampleModule.sln +++ /dev/null @@ -1,16 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS2-SimpleAdmin_ExampleModule", "CS2-SimpleAdmin_ExampleModule.csproj", "{D940F3E9-0E3F-467A-B336-149E3A624FB6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D940F3E9-0E3F-467A-B336-149E3A624FB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D940F3E9-0E3F-467A-B336-149E3A624FB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D940F3E9-0E3F-467A-B336-149E3A624FB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D940F3E9-0E3F-467A-B336-149E3A624FB6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal