├── .gitignore ├── MiniAdmin (For CSSharp Flags) ├── AdminChat.cs ├── Admins.cs ├── BanUser.cs ├── BaseAdmin.cs ├── BaseAdmin.csproj ├── Database.cs ├── Menu.cs └── MuteUser.cs ├── MiniAdmin ├── AdminChat.cs ├── Admins.cs ├── BanUser.cs ├── BaseAdmin.cs ├── BaseAdmin.csproj ├── Database.cs ├── Menu.cs ├── MuteUser.cs └── Utils.cs ├── Old ├── MiniAdmin.cs └── MiniAdmin.csproj └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /contentModel.xml 7 | /projectSettingsUpdater.xml 8 | /.idea.LRMini.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | *.user 15 | *.cache 16 | *.editorconfig 17 | *.dll 18 | *.json 19 | *.pdb 20 | *.CopyComplete 21 | *.txt 22 | *.xml 23 | Old 24 | MiniAdmin/BaseAdmin/bin 25 | MiniAdmin/BaseAdmin/obj 26 | MiniAdmin/BaseAdmin/.idea 27 | 28 | MiniAdmin/BaseAdminApi/bin 29 | MiniAdmin/BaseAdminApi/obj 30 | MiniAdmin/BaseAdminApi/.idea 31 | MiniAdmin/Modules 32 | MiniAdmin/.idea 33 | -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/AdminChat.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | 5 | namespace BaseAdmin; 6 | 7 | public class AdminChat 8 | { 9 | public void SendToAdminChat(CCSPlayerController player, string message) 10 | { 11 | player.PrintToChat( 12 | $"[{ChatColors.Blue} AdminChat {ChatColors.Default}]{message}"); 13 | } 14 | 15 | public void SendToAdminChatFromPlayer(CCSPlayerController player, string message) 16 | { 17 | player.PrintToChat( 18 | $"[{ChatColors.Blue} From Players {ChatColors.Default}]{message}"); 19 | } 20 | 21 | public void SendToAllFromAdmin(string message) 22 | { 23 | Server.PrintToChatAll( 24 | $"[{ChatColors.Blue}ALL{ChatColors.Default}] {ChatColors.Blue}ADMIN{ChatColors.Default}: {message}"); 25 | } 26 | } -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/Admins.cs: -------------------------------------------------------------------------------- 1 | namespace BaseAdmin; 2 | 3 | public class Admins 4 | { 5 | public required string username { get; set; } 6 | public required string steamid { get; set; } 7 | public int start_time { get; set; } 8 | public int end_time { get; set; } 9 | public int immunity { get; set; } 10 | public required string flags { get; set; } 11 | } -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/BanUser.cs: -------------------------------------------------------------------------------- 1 | namespace BaseAdmin; 2 | 3 | public class User 4 | { 5 | public required string admin_username { get; set; } 6 | public required string admin_steamid { get; set; } 7 | public required string username { get; set; } 8 | public ulong steamid64 { get; set; } 9 | public required string steamid { get; set; } 10 | public required string reason { get; set; } 11 | public required string unban_reason { get; set; } 12 | public required string admin_unlocked_username { get; set; } 13 | public required string admin_unlocked_steamid { get; set; } 14 | public int start_ban_time { get; set; } 15 | public int end_ban_time { get; set; } 16 | public bool ban_active { get; set; } 17 | } -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/BaseAdmin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text.Json; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | using CounterStrikeSharp.API; 9 | using CounterStrikeSharp.API.Core; 10 | using CounterStrikeSharp.API.Core.Attributes.Registration; 11 | using CounterStrikeSharp.API.Modules.Commands; 12 | using CounterStrikeSharp.API.Modules.Entities; 13 | using CounterStrikeSharp.API.Modules.Memory; 14 | using CounterStrikeSharp.API.Modules.Timers; 15 | using CounterStrikeSharp.API.Modules.Utils; 16 | using Dapper; 17 | using Microsoft.Extensions.Logging; 18 | using MySqlConnector; 19 | 20 | namespace BaseAdmin; 21 | 22 | public class BaseAdmin : BasePlugin 23 | { 24 | public override string ModuleAuthor => "thesamefabius"; 25 | public override string ModuleName => "Mini Admin (Fork CSSharp Flags)"; 26 | public override string ModuleVersion => "v1.0.5"; 27 | 28 | private static string _dbConnectionString = string.Empty; 29 | 30 | //MENU 31 | public readonly string Prefix = "[\x0C Admin Menu \x01]"; 32 | 33 | private readonly DateTime[] _playerPlayTime = new DateTime[65]; 34 | private readonly MuteUserLocal?[] _muteUsers = new MuteUserLocal[65]; 35 | private readonly Admins?[] _adminUsers = new Admins[65]; 36 | 37 | public Database Database = null!; 38 | private AdminChat _adminChat = null!; 39 | 40 | public enum MuteType 41 | { 42 | Micro = 0, 43 | Chat, 44 | All 45 | } 46 | 47 | public enum AdminFlag 48 | { 49 | Reservation = 'a', 50 | Generic = 'b', 51 | Kick = 'c', 52 | Ban = 'd', 53 | Unban = 'e', 54 | Slay = 'f', 55 | Changemap = 'g', 56 | Cvar = 'h', 57 | Config = 'i', 58 | Chat = 'j', 59 | Vote = 'k', 60 | Password = 'l', 61 | Rcon = 'm', 62 | Cheats = 'n', 63 | Vip = 'o', 64 | Root = 'z' 65 | } 66 | 67 | public override void Load(bool hotReload) 68 | { 69 | _dbConnectionString = BuildConnectionString(); 70 | Database = new Database(this, _dbConnectionString); 71 | _adminChat = new AdminChat(); 72 | new Menu(this).CreateMenu(); 73 | 74 | Task.Run(Database.CreateTable); 75 | Task.Run(Database.CreateAdminsTable); 76 | Task.Run(Database.CreateMuteTable); 77 | 78 | RegisterListener((slot, id) => 79 | { 80 | OnClientConnectedAsync(slot, Utilities.GetPlayerFromSlot(slot), id); 81 | OnClientAuthorizedAsync(slot, id); 82 | }); 83 | 84 | RegisterListener(slot => 85 | { 86 | _muteUsers[slot + 1] = null; 87 | _adminUsers[slot + 1] = null; 88 | _playerPlayTime[slot + 1] = DateTime.MinValue; 89 | }); 90 | 91 | AddCommandListener("say", CommandListener_Say); 92 | AddCommandListener("say_team", CommandListener_SayTeam); 93 | 94 | AddTimer(300, () => Task.Run(Database.DeleteExpiredAdminsAsync), TimerFlags.REPEAT); 95 | AddTimer(60, () => 96 | { 97 | foreach (var player in Utilities.GetPlayers().Where(u => !u.IsBot)) 98 | { 99 | var user = _muteUsers[player.Index]; 100 | 101 | if (user == null) continue; 102 | 103 | var endTime = DateTimeOffset.FromUnixTimeSeconds(user.EndMuteTime).UtcDateTime; 104 | 105 | if (endTime <= DateTime.UtcNow) 106 | { 107 | if (user.MuteType is (int)MuteType.Micro or (int)MuteType.All) 108 | player.VoiceFlags = VoiceFlags.Normal; 109 | 110 | _muteUsers[player.Index] = null; 111 | } 112 | } 113 | }, TimerFlags.REPEAT); 114 | } 115 | 116 | private HookResult ProcessChatMessage(CCSPlayerController? controller, CommandInfo info, bool sendToAllAdmins) 117 | { 118 | if (controller == null) return HookResult.Continue; 119 | 120 | var msg = GetTextInsideQuotes(info.ArgString); 121 | var entityIndex = controller.Index; 122 | 123 | if (msg.StartsWith('@')) 124 | { 125 | if (CheckingForAdminAndFlag(controller, AdminFlag.Chat)) 126 | { 127 | if (sendToAllAdmins) 128 | { 129 | _adminChat.SendToAllFromAdmin(msg.Trim('@')); 130 | return HookResult.Handled; 131 | } 132 | 133 | foreach (var player in Utilities.GetPlayers()) 134 | { 135 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Chat)) continue; 136 | 137 | _adminChat.SendToAdminChat(player, 138 | $" {ChatColors.Blue}{controller.PlayerName}{ChatColors.Default}: {msg.Trim('@')}"); 139 | return HookResult.Handled; 140 | } 141 | } 142 | else 143 | { 144 | if (!IsUserMute(entityIndex)) 145 | { 146 | foreach (var player in Utilities.GetPlayers()) 147 | { 148 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Chat)) continue; 149 | 150 | _adminChat.SendToAdminChatFromPlayer(player, 151 | $" {ChatColors.Blue}{controller.PlayerName}{ChatColors.Default}: {msg.Trim('@')}"); 152 | return HookResult.Handled; 153 | } 154 | } 155 | } 156 | } 157 | 158 | if (IsUserMute(entityIndex)) 159 | return CheckMuteStatus(controller, MuteType.Chat) ? HookResult.Handled : HookResult.Continue; 160 | 161 | return HookResult.Continue; 162 | } 163 | 164 | private HookResult CommandListener_SayTeam(CCSPlayerController? controller, CommandInfo info) 165 | { 166 | return ProcessChatMessage(controller, info, sendToAllAdmins: false); 167 | } 168 | 169 | private HookResult CommandListener_Say(CCSPlayerController? controller, CommandInfo info) 170 | { 171 | return ProcessChatMessage(controller, info, sendToAllAdmins: true); 172 | } 173 | 174 | // private bool CheckMute(CCSPlayerController controller) 175 | // { 176 | // return CheckMuteStatus(controller, MuteType.Chat, "You cannot write a message because you have chat disabled. End via: "); 177 | // } 178 | // 179 | // private bool CheckMicrophoneMute(CCSPlayerController controller) 180 | // { 181 | // return CheckMuteStatus(controller, MuteType.Micro, "You cannot use the microphone because it is muted. End via: "); 182 | // } 183 | 184 | private bool CheckMuteStatus(CCSPlayerController controller, MuteType requiredMuteType) 185 | { 186 | var user = _muteUsers[controller.Index]; 187 | 188 | if (user == null) return false; 189 | 190 | if (user.MuteType != (int)MuteType.All && user.MuteType != (int)requiredMuteType) return false; 191 | 192 | var endTime = DateTimeOffset.FromUnixTimeSeconds(user.EndMuteTime).UtcDateTime; 193 | var timeEnd = endTime - DateTime.UtcNow; 194 | 195 | var message = requiredMuteType == MuteType.Chat 196 | ? "You cannot write a message because you have chat disabled. End via: " 197 | : "You cannot use the microphone because it is muted. End via: "; 198 | var time = 199 | $"{(timeEnd.Days == 0 ? "" : $"{timeEnd.Days}d, ")}{timeEnd.Hours:00}:{timeEnd.Minutes:00}:{timeEnd.Seconds:00}"; 200 | PrintToChat(controller, message + time); 201 | return true; 202 | } 203 | 204 | private async Task OnClientAuthorizedAsync(int playerSlot, SteamID steamId) 205 | { 206 | var userAdmin = await Database.IsUserAdmin(steamId.SteamId2); 207 | 208 | if (userAdmin != null) 209 | { 210 | _adminUsers[playerSlot + 1] = new Admins 211 | { 212 | username = userAdmin.username, 213 | steamid = userAdmin.steamid, 214 | start_time = userAdmin.start_time, 215 | end_time = userAdmin.end_time, 216 | immunity = userAdmin.immunity, 217 | flags = userAdmin.flags 218 | }; 219 | 220 | //Server.NextFrame(() => Utilities.GetPlayerFromSlot(playerSlot).Clan = "[Admin]"); 221 | } 222 | 223 | var userMuted = await Database.GetActiveMuteAsync(steamId.SteamId2); 224 | 225 | if (userMuted != null) 226 | { 227 | _muteUsers[playerSlot + 1] = new MuteUserLocal 228 | { 229 | MuteType = userMuted.mute_type, 230 | SteamId = userMuted.steamid, 231 | EndMuteTime = userMuted.end_mute_time, 232 | MuteActive = userMuted.mute_active 233 | }; 234 | 235 | if (userMuted.mute_type == (int)MuteType.Micro) 236 | { 237 | Server.NextFrame(() => Utilities.GetPlayerFromSlot(playerSlot).VoiceFlags = VoiceFlags.Muted); 238 | } 239 | } 240 | } 241 | 242 | private async Task OnClientConnectedAsync(int slot, CCSPlayerController player, SteamID steamId) 243 | { 244 | try 245 | { 246 | await using var connection = new MySqlConnection(_dbConnectionString); 247 | 248 | var unbanUsers = await connection.QueryAsync( 249 | "SELECT * FROM miniadmin_bans WHERE end_ban_time <= @CurrentTime AND ban_active = 1 AND end_ban_time != 0", 250 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }); 251 | 252 | foreach (var user in unbanUsers) 253 | { 254 | PrintLogInfo("Unban: {steamid}", user.steamid); 255 | await Database.UnbanUser("Console", "Console", user.steamid, "The deadline has passed"); 256 | } 257 | 258 | var unmuteUsers = await connection.QueryAsync( 259 | "SELECT * FROM miniadmin_mute WHERE end_mute_time <= @CurrentTime AND mute_active = 1 AND end_mute_time != 0", 260 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }); 261 | 262 | foreach (var user in unmuteUsers) 263 | { 264 | PrintLogInfo("Unmute: {steamid}", user.steamid); 265 | await Database.UnmuteUser(-1, "Console", "Console", user.steamid, "The deadline has passed"); 266 | Server.NextFrame(() => player.VoiceFlags = VoiceFlags.Normal); 267 | } 268 | 269 | await Database.DeleteExpiredAdminsAsync(); 270 | 271 | var banUser = await connection.QueryFirstOrDefaultAsync( 272 | "SELECT * FROM miniadmin_bans WHERE steamid64 = @SteamId64 AND ban_active = 1", 273 | new { steamId.SteamId64 }); 274 | 275 | if (banUser != null) 276 | Server.NextFrame(() => Server.ExecuteCommand($"kickid {player.UserId}")); 277 | else 278 | _playerPlayTime[slot + 1] = DateTime.Now; 279 | } 280 | catch (Exception e) 281 | { 282 | PrintLogError(e.ToString()); 283 | } 284 | } 285 | 286 | [CommandHelper(0, "<#userid or username>", CommandUsage.CLIENT_ONLY)] 287 | [ConsoleCommand("css_noclip")] 288 | public void OnCmdNoclip(CCSPlayerController? controller, CommandInfo command) 289 | { 290 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Root)) return; 291 | 292 | var msg = GetTextInsideQuotes(command.ArgString); 293 | if (msg.StartsWith('#')) 294 | { 295 | GiveNoclip(controller, GetPlayerFromUserIdOrName(msg)); 296 | return; 297 | } 298 | 299 | GiveNoclip(controller); 300 | } 301 | 302 | private void GiveNoclip(CCSPlayerController player, CCSPlayerController? target = null) 303 | { 304 | var playerPawn = target == null ? player.PlayerPawn.Value : target.PlayerPawn.Value; 305 | if (playerPawn != null) 306 | playerPawn.MoveType = playerPawn.MoveType switch 307 | { 308 | MoveType_t.MOVETYPE_NOCLIP => MoveType_t.MOVETYPE_WALK, 309 | MoveType_t.MOVETYPE_WALK => MoveType_t.MOVETYPE_NOCLIP, 310 | _ => playerPawn.MoveType 311 | }; 312 | 313 | PrintToChatAll( 314 | $"Admin '{player.PlayerName}' has issued a noclip to player '{(target == null ? $"{player.PlayerName}" : $"{target.PlayerName}")}'"); 315 | } 316 | 317 | [CommandHelper(1, "", CommandUsage.CLIENT_ONLY)] 318 | [ConsoleCommand("css_rcon")] 319 | public void OnCmdRcon(CCSPlayerController? controller, CommandInfo command) 320 | { 321 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Rcon)) return; 322 | 323 | Server.ExecuteCommand(command.ArgString); 324 | } 325 | 326 | [CommandHelper(1, "<#userid or username> [damage]", CommandUsage.CLIENT_ONLY)] 327 | [ConsoleCommand("css_slap")] 328 | public void OnCmdSlap(CCSPlayerController? controller, CommandInfo command) 329 | { 330 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Slay)) return; 331 | 332 | var player = GetPlayerFromUserIdOrName(command.GetArg(1)); 333 | 334 | var damage = 0; 335 | if (command.ArgCount >= 3) 336 | damage = int.Parse(command.GetArg(2)); 337 | 338 | if (!IsPlayerValid(controller, player, true)) return; 339 | 340 | if (player != null) 341 | { 342 | var playerPawn = player.PlayerPawn.Value; 343 | 344 | if (playerPawn == null) return; 345 | 346 | playerPawn.AbsVelocity.X += Random.Shared.Next(100, 200); 347 | playerPawn.AbsVelocity.Y += Random.Shared.Next(100, 200); 348 | playerPawn.AbsVelocity.Z += Random.Shared.Next(200, 300); 349 | playerPawn.Health -= damage; 350 | 351 | var random = Random.Shared.Next(3); 352 | 353 | player.ExecuteClientCommand($"play {GetMusicChoice(random)}"); 354 | 355 | if (playerPawn.Health <= 0) playerPawn.CommitSuicide(true, true); 356 | } 357 | } 358 | 359 | private string GetMusicChoice(int randomNumber) 360 | { 361 | return randomNumber switch 362 | { 363 | 0 => "sounds/player/damage1.vsnd", 364 | 1 => "sounds/player/damage2.vsnd", 365 | 2 => "sounds/player/damage3.vsnd", 366 | _ => string.Empty 367 | }; 368 | } 369 | 370 | [ConsoleCommand("css_who")] 371 | public void OnCmdWho(CCSPlayerController? controller, CommandInfo command) 372 | { 373 | if (controller != null) 374 | if (!IsAdmin(controller.Index)) 375 | { 376 | PrintToChat(controller, "you do not have access to this command"); 377 | return; 378 | } 379 | 380 | var maxNameLength = 0; 381 | 382 | var id = 0; 383 | foreach (var client in Utilities.GetPlayers() 384 | .Where(u => u.PlayerPawn.Value != null && u.PlayerPawn.Value.IsValid)) 385 | { 386 | var playerName = !string.IsNullOrWhiteSpace(client.PlayerName) ? client.PlayerName : "unknown"; 387 | var playerNameLength = playerName.Length; 388 | maxNameLength = Math.Max(maxNameLength, playerNameLength); 389 | 390 | var adminStatus = IsAdmin(client.Index) ? "admin " : "player"; 391 | 392 | var index = client.Index; 393 | var playTime = DateTime.Now - _playerPlayTime[index]; 394 | 395 | id ++; 396 | var formattedOutput = 397 | $"{id,-1} - {playerName,-15} || UserId: {client.UserId,-2} || {adminStatus,-6} || Playtime: {playTime.Hours:D2}:{playTime.Minutes:D2}:{playTime.Seconds:D2} | {(client.AuthorizedSteamID == null ? "none" : client.AuthorizedSteamID)}"; 398 | 399 | if (controller == null) 400 | { 401 | Console.ForegroundColor = Random.Shared.Next(2) == 1 ? ConsoleColor.Cyan : ConsoleColor.DarkMagenta; 402 | Console.WriteLine(formattedOutput); 403 | Console.ResetColor(); 404 | } 405 | else 406 | PrintToConsole(controller, formattedOutput); 407 | 408 | // PrintLogInfo("{id} - {playerName} | {adminStatus} | Playtime: {playTime} | {SteamID}", 409 | // $"{id,-1}", $"{playerName,-15}", $"{adminStatus,-6}", 410 | // $"{playTime.Hours:D2}:{playTime.Minutes:D2}:{playTime.Seconds:D2}", $"{new SteamID(client.SteamID)}"); 411 | } 412 | } 413 | 414 | [CommandHelper(1, "")] 415 | [ConsoleCommand("css_map", "change map")] 416 | public void OnCmdChangeMap(CCSPlayerController? controller, CommandInfo command) 417 | { 418 | if (controller == null) return; 419 | 420 | var cmdArg = command.ArgString; 421 | 422 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Changemap )) return; 423 | 424 | foreach (var t in GetMapFromMaps()) 425 | { 426 | var isWorkshopMap = t.Trim().StartsWith("ws:", StringComparison.OrdinalIgnoreCase); 427 | 428 | if (!t.Trim().Contains(cmdArg.Trim(), StringComparison.OrdinalIgnoreCase)) continue; 429 | 430 | var map = t.StartsWith("ws:") ? t.Split("ws:")[1] : t; 431 | PrintToChatAll($"{controller.PlayerName}: changing the map to {map}"); 432 | AddTimer(3.0f, () => ChangeMap(map, isWorkshopMap)); 433 | return; 434 | } 435 | 436 | PrintToChat(controller, "This map doesn't exist"); 437 | } 438 | 439 | [CommandHelper(1, "<#userid or username>")] 440 | [ConsoleCommand("css_slay", "kill a player")] 441 | public void OnCmdSlay(CCSPlayerController? controller, CommandInfo command) 442 | { 443 | var cmdArg = command.ArgString; 444 | 445 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Slay)) return; 446 | 447 | ExtractValueInQuotes(cmdArg); 448 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 449 | 450 | if (!IsPlayerValid(controller, target, true)) return; 451 | 452 | if (target.PlayerPawn.Value != null) target.PlayerPawn.Value.CommitSuicide(true, true); 453 | 454 | if (controller == null) 455 | PrintToChatAll($"Console: Player '{target.PlayerName}' has been killed"); 456 | 457 | ReplyToCommand(controller, 458 | $"{(controller != null ? controller.PlayerName : "Console")}: Player '{target.PlayerName}' has been killed"); 459 | } 460 | 461 | [CommandHelper(1, "<#userid or username>")] 462 | [ConsoleCommand("css_kick", "Kick a player")] 463 | public void OnCmdKick(CCSPlayerController? controller, CommandInfo command) 464 | { 465 | var cmdArg = command.ArgString; 466 | 467 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Kick)) return; 468 | 469 | var target = GetPlayerFromUserIdOrName(ExtractValueInQuotes(cmdArg)); 470 | 471 | if (!IsPlayerValid(controller, target)) return; 472 | 473 | if (controller != null) 474 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 475 | { 476 | ReplyToCommand(controller, "You can't ban this player"); 477 | return; 478 | } 479 | 480 | KickClient($"{target.UserId}"); 481 | 482 | var msg = 483 | $"{(controller != null ? controller.PlayerName : "Console")}: Player '{target.PlayerName}' kicked by admin"; 484 | ReplyToCommand(controller, msg); 485 | } 486 | 487 | [CommandHelper(2, "<#userid or username> [reason]")] 488 | [ConsoleCommand("css_ban", "ban")] 489 | public void OnCmdBan(CCSPlayerController? controller, CommandInfo command) 490 | { 491 | var cmdArg = command.ArgString; 492 | 493 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Ban)) return; 494 | 495 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 496 | 497 | if (!IsPlayerValid(controller, target)) return; 498 | 499 | if (controller != null) 500 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 501 | { 502 | ReplyToCommand(controller, "You can't ban this player"); 503 | return; 504 | } 505 | 506 | var endBanTime = Convert.ToInt32(command.GetArg(2)); 507 | 508 | var startBanTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 509 | var endBanTimeUnix = DateTime.UtcNow.AddSeconds(endBanTime).GetUnixEpoch(); 510 | 511 | var reason = "none"; 512 | if (command.ArgCount > 3) 513 | reason = command.GetArg(3); 514 | 515 | Server.NextFrame(() => 516 | { 517 | var msg = Database.AddBan(new User 518 | { 519 | admin_username = controller != null ? controller.PlayerName : "Console", 520 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 521 | username = target.PlayerName, 522 | steamid64 = target.SteamID, 523 | steamid = new SteamID(target.SteamID).SteamId2, 524 | reason = reason, 525 | unban_reason = "", 526 | admin_unlocked_username = "", 527 | admin_unlocked_steamid = "", 528 | start_ban_time = startBanTimeUnix, 529 | end_ban_time = endBanTime == 0 ? 0 : endBanTimeUnix, 530 | ban_active = true 531 | }).Result; 532 | KickClient($"{target.UserId}"); 533 | 534 | ReplyToCommand(controller, msg); 535 | }); 536 | } 537 | 538 | [CommandHelper(2, "<#userid or username> [reason]")] 539 | [ConsoleCommand("css_mute", "mute")] 540 | public void OnCmdMute(CCSPlayerController? controller, CommandInfo command) 541 | { 542 | var cmdArg = command.ArgString; 543 | 544 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Generic)) return; 545 | 546 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 547 | 548 | if (!IsPlayerValid(controller, target)) return; 549 | 550 | if (controller != null) 551 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 552 | { 553 | ReplyToCommand(controller, "You can't ban this player"); 554 | return; 555 | } 556 | 557 | var endMuteTime = Convert.ToInt32(command.GetArg(2)); 558 | 559 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 560 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(endMuteTime).GetUnixEpoch(); 561 | 562 | if (target.VoiceFlags.HasFlag(VoiceFlags.Muted)) 563 | { 564 | ReplyToCommand(controller, $"Player \x02'{target.PlayerName}'\x08 has already had his microphone cut off"); 565 | return; 566 | } 567 | 568 | var reason = "none"; 569 | if (command.ArgCount > 3) 570 | reason = command.GetArg(3); 571 | 572 | Server.NextFrame(() => 573 | { 574 | Database.AddMute(new MuteUser 575 | { 576 | mute_type = (int)MuteType.Micro, 577 | admin_username = controller != null ? controller.PlayerName : "Console", 578 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 579 | username = target.PlayerName, 580 | steamid64 = target.SteamID, 581 | steamid = new SteamID(target.SteamID).SteamId2, 582 | reason = reason, 583 | unmute_reason = "", 584 | admin_unlocked_username = "", 585 | admin_unlocked_steamid = "", 586 | start_mute_time = startMuteTimeUnix, 587 | end_mute_time = endMuteTime == 0 ? 0 : endMuteTimeUnix, 588 | mute_active = true 589 | }, controller == null ? null : controller); 590 | }); 591 | target.VoiceFlags = VoiceFlags.Muted; 592 | 593 | UpdateUserMuteLocal(target, endMuteTime, endMuteTimeUnix, (int)MuteType.Micro); 594 | } 595 | 596 | [CommandHelper(1, " [reason]")] 597 | [ConsoleCommand("css_unmute", "unmute")] 598 | public void OnCmdUnmute(CCSPlayerController? controller, CommandInfo command) 599 | { 600 | var cmdArg = command.ArgString; 601 | 602 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 603 | 604 | var arg1 = command.GetArg(1); 605 | var steamId = arg1; 606 | CCSPlayerController? player = null; 607 | 608 | if (arg1.StartsWith('#')) 609 | { 610 | player = GetPlayerFromUserIdOrName(arg1); 611 | } 612 | 613 | var reason = "none"; 614 | if (command.ArgCount > 2) 615 | reason = command.GetArg(2); 616 | 617 | Server.NextFrame(() => 618 | { 619 | var msg = Database.UnmuteUser((int)MuteType.Micro, 620 | controller != null ? controller.PlayerName : "Console", 621 | controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 622 | player == null ? steamId : new SteamID(player.SteamID).SteamId2, reason).Result; 623 | 624 | ReplyToCommand(controller, msg); 625 | }); 626 | 627 | //var player = Utilities.GetPlayers().FirstOrDefault(u => new SteamID(u.SteamID).SteamId2 == steamId); 628 | if (player != null) 629 | { 630 | UpdateUserMuteLocal(player, isAdded: false); 631 | player.VoiceFlags = VoiceFlags.Normal; 632 | } 633 | } 634 | 635 | [CommandHelper(2, "<#userid or username> [reason]")] 636 | [ConsoleCommand("css_gag", "mute")] 637 | public void OnCmdGag(CCSPlayerController? controller, CommandInfo command) 638 | { 639 | var cmdArg = command.ArgString; 640 | 641 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Generic)) return; 642 | 643 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 644 | 645 | if (!IsPlayerValid(controller, target)) return; 646 | 647 | if (target == null) 648 | { 649 | ReplyToCommand(controller, "Player not found"); 650 | return; 651 | } 652 | 653 | if (controller != null) 654 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 655 | { 656 | ReplyToCommand(controller, "You can't ban this player"); 657 | return; 658 | } 659 | 660 | var endMuteTime = Convert.ToInt32(command.GetArg(2)); 661 | 662 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 663 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(endMuteTime).GetUnixEpoch(); 664 | 665 | var reason = "none"; 666 | if (command.ArgCount > 3) 667 | reason = command.GetArg(3); 668 | 669 | Server.NextFrame(() => 670 | { 671 | Database.AddMute(new MuteUser 672 | { 673 | mute_type = (int)MuteType.Chat, 674 | admin_username = controller != null ? controller.PlayerName : "Console", 675 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 676 | username = target.PlayerName, 677 | steamid64 = target.SteamID, 678 | steamid = new SteamID(target.SteamID).SteamId2, 679 | reason = reason, 680 | unmute_reason = "", 681 | admin_unlocked_username = "", 682 | admin_unlocked_steamid = "", 683 | start_mute_time = startMuteTimeUnix, 684 | end_mute_time = endMuteTime == 0 ? 0 : endMuteTimeUnix, 685 | mute_active = true 686 | }, controller == null ? null : controller); 687 | }); 688 | 689 | UpdateUserMuteLocal(target, endMuteTime, endMuteTimeUnix, (int)MuteType.Chat); 690 | } 691 | 692 | [CommandHelper(1, " [reason]")] 693 | [ConsoleCommand("css_ungag", "ungag")] 694 | public void OnCmdUngag(CCSPlayerController? controller, CommandInfo command) 695 | { 696 | var cmdArg = command.ArgString; 697 | 698 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 699 | 700 | var arg1 = command.GetArg(1); 701 | var steamId = arg1; 702 | CCSPlayerController? player = null; 703 | 704 | if (arg1.StartsWith('#')) 705 | { 706 | player = GetPlayerFromUserIdOrName(arg1); 707 | } 708 | 709 | var reason = "none"; 710 | if (command.ArgCount > 2) 711 | reason = command.GetArg(2); 712 | 713 | Server.NextFrame(() => 714 | { 715 | var msg = Database.UnmuteUser((int)MuteType.Chat, 716 | controller != null ? controller.PlayerName : "Console", 717 | controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 718 | player == null ? steamId : new SteamID(player.SteamID).SteamId2, reason).Result; 719 | 720 | ReplyToCommand(controller, msg); 721 | }); 722 | 723 | if (player != null) 724 | UpdateUserMuteLocal(player, isAdded: false); 725 | } 726 | 727 | public void UpdateUserMuteLocal(CCSPlayerController? player = null, int endTime = -1, int endTimeUnix = -1, 728 | int type = -1, 729 | bool isAdded = true) 730 | { 731 | if (player != null) 732 | { 733 | var entityIndex = player.Index; 734 | var user = _muteUsers[entityIndex]; 735 | 736 | if (isAdded) 737 | { 738 | _muteUsers[entityIndex] = new MuteUserLocal 739 | { 740 | MuteType = user == null ? type : (int)MuteType.All, 741 | SteamId = new SteamID(player.SteamID).SteamId2, 742 | EndMuteTime = endTime == 0 ? 0 : endTimeUnix, 743 | MuteActive = true 744 | }; 745 | } 746 | else _muteUsers[entityIndex] = null; 747 | } 748 | } 749 | 750 | [CommandHelper(5, " ", CommandUsage.SERVER_ONLY)] 751 | [ConsoleCommand("css_addadmin")] 752 | public void OnCmdAddAdmin(CCSPlayerController? controller, CommandInfo command) 753 | { 754 | if (controller != null) return; 755 | 756 | var cmdArg = command.ArgString; 757 | 758 | var splitCmdArgs = ParseCommandArguments(cmdArg); 759 | 760 | var endTime = Convert.ToInt32(ExtractValueInQuotes(splitCmdArgs[4])); 761 | var startTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 762 | var endTimeUnix = DateTime.UtcNow.AddSeconds(endTime).GetUnixEpoch(); 763 | 764 | Server.NextFrame(() => 765 | { 766 | Database.AddAdmin(new Admins 767 | { 768 | username = ExtractValueInQuotes(splitCmdArgs[0]), 769 | steamid = ExtractValueInQuotes(splitCmdArgs[1]), 770 | start_time = startTimeUnix, 771 | end_time = endTime == 0 ? 0 : endTimeUnix, 772 | immunity = int.Parse(ExtractValueInQuotes(splitCmdArgs[2])), 773 | flags = ExtractValueInQuotes(splitCmdArgs[3]) 774 | }, controller); 775 | }); 776 | } 777 | 778 | [CommandHelper(1, " [reason]")] 779 | [ConsoleCommand("css_unban", "unban")] 780 | public void OnCmdUnban(CCSPlayerController? controller, CommandInfo command) 781 | { 782 | var cmdArg = command.ArgString; 783 | 784 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 785 | 786 | var steamId = command.GetArg(1); 787 | 788 | var reason = "none"; 789 | if (command.ArgCount > 2) 790 | reason = command.GetArg(2); 791 | 792 | Server.NextFrame(() => 793 | { 794 | var msg = Database.UnbanUser( 795 | controller != null ? controller.PlayerName : "Console", 796 | controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 797 | steamId, reason).Result; 798 | 799 | ReplyToCommand(controller, msg); 800 | }); 801 | } 802 | 803 | [CommandHelper(1, "", CommandUsage.SERVER_ONLY)] 804 | [ConsoleCommand("css_deleteadmin", "delete admin")] 805 | public void OnCmdDeleteAdmin(CCSPlayerController? controller, CommandInfo command) 806 | { 807 | if (controller != null) return; 808 | 809 | var cmdArg = command.ArgString; 810 | 811 | var steamId = ExtractValueInQuotes(cmdArg); 812 | 813 | Task.Run(() => Database.DeleteAdminAsync(steamId)); 814 | } 815 | 816 | private CCSPlayerController? GetPlayerFromUserIdOrName(string player, bool isSteamId = false) 817 | { 818 | if (player.StartsWith('#') && int.TryParse(player.Trim('#'), out var index)) 819 | return Utilities.GetPlayerFromUserid(index); 820 | 821 | return Utilities.GetPlayers().FirstOrDefault(u => u.PlayerName == player); 822 | } 823 | 824 | public bool CheckingForAdminAndFlag(CCSPlayerController? controller, AdminFlag flag) 825 | { 826 | if (controller == null) return true; 827 | var entityIndex = controller.Index; 828 | 829 | if (IsAdmin(entityIndex) && HasLetterInUserFlags(entityIndex, (char)flag)) return true; 830 | 831 | PrintToChat(controller, "you do not have access to this command"); 832 | return false; 833 | } 834 | 835 | private string GetTextInsideQuotes(string input) 836 | { 837 | var startIndex = input.IndexOf('"'); 838 | var endIndex = input.LastIndexOf('"'); 839 | 840 | if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) 841 | { 842 | return input.Substring(startIndex + 1, endIndex - startIndex - 1); 843 | } 844 | 845 | return string.Empty; 846 | } 847 | 848 | private string[] ParseCommandArguments(string argString) 849 | { 850 | var parse = Regex.Matches(argString, @"[\""].+?[\""]|[^ ]+") 851 | .Select(m => m.Value.Trim('"')) 852 | .ToArray(); 853 | 854 | return parse; 855 | } 856 | 857 | private bool IsPlayerValid(CCSPlayerController? player, CCSPlayerController? target, bool isKickOrSlap = false) 858 | { 859 | if (target == null || !target.IsValid) 860 | { 861 | ReplyToCommand(player, "Player not found"); 862 | return false; 863 | } 864 | 865 | if (isKickOrSlap) 866 | { 867 | if (!target.PawnIsAlive) 868 | { 869 | ReplyToCommand(player, "The player is invalid"); 870 | return false; 871 | } 872 | } 873 | 874 | return true; 875 | } 876 | 877 | private string BuildConnectionString() 878 | { 879 | var dbConfig = LoadConfig(); 880 | 881 | Console.WriteLine("Building connection string"); 882 | var builder = new MySqlConnectionStringBuilder 883 | { 884 | Database = dbConfig.Connection.Database, 885 | UserID = dbConfig.Connection.User, 886 | Password = dbConfig.Connection.Password, 887 | Server = dbConfig.Connection.Host, 888 | Port = 3306, 889 | }; 890 | 891 | Console.WriteLine("OK!"); 892 | return builder.ConnectionString; 893 | } 894 | 895 | private Config LoadConfig() 896 | { 897 | var configPath = Path.Combine(ModuleDirectory, "database.json"); 898 | if (!File.Exists(configPath)) return CreateConfig(configPath); 899 | 900 | var config = JsonSerializer.Deserialize(File.ReadAllText(configPath))!; 901 | 902 | return config; 903 | } 904 | 905 | private Config CreateConfig(string configPath) 906 | { 907 | var config = new Config 908 | { 909 | Connection = new BaseAdminDb 910 | { 911 | Host = "", 912 | Database = "", 913 | User = "", 914 | Password = "" 915 | } 916 | }; 917 | 918 | var mapsConfig = Path.Combine(ModuleDirectory, "maps.txt"); 919 | if (!File.Exists(mapsConfig)) 920 | File.WriteAllLines(mapsConfig, new[] { "de_dust2", "de_mirage" }); 921 | 922 | File.WriteAllText(configPath, 923 | JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true })); 924 | return config; 925 | } 926 | 927 | public IEnumerable ReadAllBanReasons() 928 | { 929 | var path = Path.Combine(ModuleDirectory, "admin/ban_reasons.txt"); 930 | 931 | if (!File.Exists(path)) 932 | File.WriteAllLines(path, new[] { "Aim", "Wallhack", "Violation" }); 933 | 934 | return File.ReadAllLines(path); 935 | } 936 | 937 | public IEnumerable ReadAllMuteReasons() 938 | { 939 | var path = Path.Combine(ModuleDirectory, "admin/mute_reasons.txt"); 940 | 941 | if (!File.Exists(path)) 942 | File.WriteAllLines(path, new[] { "Spam Mic/Chat", "Inappropriate behavior", "16+" }); 943 | 944 | return File.ReadAllLines(path); 945 | } 946 | 947 | public IEnumerable ReadAllTime() 948 | { 949 | var path = Path.Combine(ModuleDirectory, "admin/times.txt"); 950 | 951 | if (!File.Exists(path)) 952 | File.WriteAllLines(path, new[] { "permanently:0", "1 hours:3600", "1 day:86400", "1 week:604800" }); 953 | 954 | return File.ReadAllLines(path); 955 | } 956 | 957 | public string[] GetMapFromMaps() 958 | { 959 | var mapText = File.ReadAllText(Path.Combine(ModuleDirectory, "maps.txt")); 960 | var mapList = mapText.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) 961 | .Select(s => s.Trim()).ToArray(); 962 | 963 | return mapList; 964 | } 965 | 966 | public IEnumerable ReadAllImmunity() 967 | { 968 | var path = Path.Combine(ModuleDirectory, "admin/immunity.txt"); 969 | 970 | if (!File.Exists(path)) 971 | File.WriteAllLines(path, new[] { "1", "10", "20", "30" }); 972 | 973 | return File.ReadAllLines(path); 974 | } 975 | 976 | public bool HasLetterInUserFlags(uint index, char letter) 977 | { 978 | if (_adminUsers[index] == null) return false; 979 | 980 | var adminUser = _adminUsers[index]!.flags; 981 | 982 | if (adminUser.Contains((char)AdminFlag.Root)) return true; 983 | 984 | return !string.IsNullOrEmpty(adminUser) && adminUser.Contains(letter); 985 | } 986 | 987 | private bool PlayerImmunityComparison(CCSPlayerController player, CCSPlayerController target) 988 | { 989 | if (_adminUsers[target.Index] == null) return false; 990 | 991 | return _adminUsers[player.Index]!.immunity >= _adminUsers[target.Index]!.immunity; 992 | } 993 | 994 | public bool IsAdmin(uint index) 995 | { 996 | var user = _adminUsers[index]; 997 | if (user == null) return false; 998 | 999 | if (user.end_time != 0 && DateTime.UtcNow.GetUnixEpoch() > user.end_time) return false; 1000 | 1001 | return user.end_time == 0 || DateTime.UtcNow.GetUnixEpoch() < user.end_time; 1002 | } 1003 | 1004 | private bool IsUserMute(uint index) 1005 | { 1006 | var user = _muteUsers[index]; 1007 | if (user == null) return false; 1008 | 1009 | if (DateTime.UtcNow.GetUnixEpoch() > user.EndMuteTime) return false; 1010 | 1011 | return user.EndMuteTime == 0 || DateTime.UtcNow.GetUnixEpoch() < user.EndMuteTime; 1012 | } 1013 | 1014 | public string ExtractValueInQuotes(string input) 1015 | { 1016 | var match = Regex.Match(input, @"""([^""]*)"""); 1017 | 1018 | return match.Success ? match.Groups[1].Value : input; 1019 | } 1020 | 1021 | public void ReplyToCommand(CCSPlayerController? controller, string message, params object?[] args) 1022 | { 1023 | if (controller != null) 1024 | PrintToChat(controller, message); 1025 | else 1026 | PrintLogInfo(message, args); 1027 | } 1028 | 1029 | public void ChangeMap(string mapName, bool isWorkshop = false) 1030 | { 1031 | Server.ExecuteCommand($"{(isWorkshop ? "ds_workshop_changelevel" : "map")} {mapName}"); 1032 | } 1033 | 1034 | public void KickClient(string userId) 1035 | { 1036 | Server.ExecuteCommand($"kickid {userId}"); 1037 | } 1038 | 1039 | public void PrintToChat(CCSPlayerController controller, string msg) 1040 | { 1041 | controller.PrintToChat($"\x08[\x0C Admin \x08] {msg}"); 1042 | } 1043 | 1044 | public void PrintToChatAll(string msg) 1045 | { 1046 | Server.PrintToChatAll($"\x08[\x0C Admin \x08] {msg}"); 1047 | } 1048 | 1049 | private void PrintToConsole(CCSPlayerController client, string msg) 1050 | { 1051 | VirtualFunctions.ClientPrint(client.Handle, HudDestination.Console, msg, 0, 0, 0, 0); 1052 | } 1053 | 1054 | public void PrintLogInfo(string? message, params object?[] args) 1055 | { 1056 | Logger.LogInformation($"{message}", args); 1057 | } 1058 | 1059 | public void PrintLogError(string? message, params object?[] args) 1060 | { 1061 | Logger.LogError($"{message}", args); 1062 | } 1063 | } 1064 | 1065 | public static class GetUnixTime 1066 | { 1067 | public static int GetUnixEpoch(this DateTime dateTime) 1068 | { 1069 | var unixTime = dateTime.ToUniversalTime() - 1070 | new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 1071 | 1072 | return (int)unixTime.TotalSeconds; 1073 | } 1074 | } 1075 | 1076 | public class Config 1077 | { 1078 | public BaseAdminDb Connection { get; set; } = null!; 1079 | } 1080 | 1081 | public class BaseAdminDb 1082 | { 1083 | public required string Host { get; init; } 1084 | public required string Database { get; init; } 1085 | public required string User { get; init; } 1086 | public required string Password { get; init; } 1087 | } 1088 | 1089 | public class AdminData 1090 | { 1091 | public ulong SteamId { get; set; } 1092 | public bool TagEnabled { get; set; } 1093 | } -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/BaseAdmin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | AnyCPU;x86 6 | true 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | CounterStrikeSharp.API.dll 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/Database.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using CounterStrikeSharp.API; 5 | using CounterStrikeSharp.API.Core; 6 | using CounterStrikeSharp.API.Modules.Entities; 7 | using Dapper; 8 | using MySqlConnector; 9 | 10 | namespace BaseAdmin; 11 | 12 | public class Database 13 | { 14 | private readonly string _dbConnectionString; 15 | private readonly BaseAdmin _baseAdmin; 16 | 17 | public Database(BaseAdmin baseAdmin, string dbConnectionString) 18 | { 19 | _baseAdmin = baseAdmin; 20 | _dbConnectionString = dbConnectionString; 21 | } 22 | 23 | public async Task CreateTable() 24 | { 25 | try 26 | { 27 | await using var dbConnection = new MySqlConnection(_dbConnectionString); 28 | dbConnection.Open(); 29 | 30 | var createBansTable = @" 31 | CREATE TABLE IF NOT EXISTS `miniadmin_bans` ( 32 | `id` INT AUTO_INCREMENT PRIMARY KEY, 33 | `admin_username` VARCHAR(255) NOT NULL, 34 | `admin_steamid` VARCHAR(255) NOT NULL, 35 | `username` VARCHAR(255) NOT NULL, 36 | `steamid64` BIGINT NOT NULL, 37 | `steamid` VARCHAR(255) NOT NULL, 38 | `reason` VARCHAR(255) NOT NULL, 39 | `unban_reason` VARCHAR(255) NOT NULL, 40 | `admin_unlocked_username` VARCHAR(255) NOT NULL, 41 | `admin_unlocked_steamid` VARCHAR(255) NOT NULL, 42 | `start_ban_time` BIGINT NOT NULL, 43 | `end_ban_time` BIGINT NOT NULL, 44 | `ban_active` BOOLEAN NOT NULL 45 | );"; 46 | 47 | await dbConnection.ExecuteAsync(createBansTable); 48 | } 49 | catch (Exception e) 50 | { 51 | Console.WriteLine(e); 52 | } 53 | } 54 | 55 | public async Task CreateAdminsTable() 56 | { 57 | try 58 | { 59 | await using var connection = new MySqlConnection(_dbConnectionString); 60 | 61 | connection.Open(); 62 | 63 | var createAdminsTable = @" 64 | CREATE TABLE IF NOT EXISTS `miniadmin_admins` ( 65 | `id` INT AUTO_INCREMENT PRIMARY KEY, 66 | `username` VARCHAR(255) NOT NULL, 67 | `steamid` VARCHAR(255) NOT NULL, 68 | `start_time` BIGINT NOT NULL, 69 | `end_time` BIGINT NOT NULL, 70 | `immunity` INT NOT NULL, 71 | `flags` VARCHAR(255) NOT NULL 72 | );"; 73 | 74 | await connection.ExecuteAsync(createAdminsTable); 75 | } 76 | catch (Exception e) 77 | { 78 | Console.WriteLine(e); 79 | } 80 | } 81 | 82 | public async Task CreateMuteTable() 83 | { 84 | try 85 | { 86 | await using var connection = new MySqlConnection(_dbConnectionString); 87 | 88 | connection.Open(); 89 | 90 | var createMuteTable = @" 91 | CREATE TABLE IF NOT EXISTS `miniadmin_mute` ( 92 | `id` INT AUTO_INCREMENT PRIMARY KEY, 93 | `mute_type` INT NOT NULL, 94 | `admin_username` VARCHAR(255) NOT NULL, 95 | `admin_steamid` VARCHAR(255) NOT NULL, 96 | `username` VARCHAR(255) NOT NULL, 97 | `steamid64` BIGINT NOT NULL, 98 | `steamid` VARCHAR(255) NOT NULL, 99 | `reason` VARCHAR(255) NOT NULL, 100 | `unmute_reason` VARCHAR(255) NOT NULL, 101 | `admin_unlocked_username` VARCHAR(255) NOT NULL, 102 | `admin_unlocked_steamid` VARCHAR(255) NOT NULL, 103 | `start_mute_time` BIGINT NOT NULL, 104 | `end_mute_time` BIGINT NOT NULL, 105 | `mute_active` BOOLEAN NOT NULL 106 | );"; 107 | 108 | await connection.ExecuteAsync(createMuteTable); 109 | } 110 | catch (Exception e) 111 | { 112 | Console.WriteLine(e); 113 | } 114 | } 115 | 116 | public async Task AddBan(User user) 117 | { 118 | try 119 | { 120 | var isUserBanned = await IsUserBanned(user.steamid); 121 | if (isUserBanned) 122 | return $"The user with the SteamId identifier {user.steamid} has already been banned."; 123 | 124 | await using var connection = new MySqlConnection(_dbConnectionString); 125 | 126 | await connection.ExecuteAsync(@" 127 | INSERT INTO miniadmin_bans (admin_username, admin_steamid, username, steamid64, steamid, reason, unban_reason, admin_unlocked_username, admin_unlocked_steamid, start_ban_time, end_ban_time, ban_active) 128 | VALUES (@admin_username, @admin_steamid, @username, @steamid64, @steamid, @reason, @unban_reason, @admin_unlocked_username, @admin_unlocked_steamid, @start_ban_time, @end_ban_time, @ban_active); 129 | ", user); 130 | 131 | return $"Player '{user.username} | [{user.steamid}]' is banned"; 132 | } 133 | catch (Exception e) 134 | { 135 | Console.WriteLine(e); 136 | } 137 | 138 | return string.Empty; 139 | } 140 | 141 | public async Task AddMute(MuteUser user, CCSPlayerController? controller) 142 | { 143 | try 144 | { 145 | await using var connection = new MySqlConnection(_dbConnectionString); 146 | 147 | var activeUserMute = await GetActiveMuteAsync(user.steamid); 148 | 149 | if (activeUserMute != null) 150 | { 151 | if (activeUserMute.mute_type == user.mute_type) 152 | { 153 | Server.NextFrame(() => 154 | _baseAdmin.ReplyToCommand(controller, "The user already has sound or chat disabled")); 155 | return; 156 | } 157 | 158 | if (activeUserMute.mute_type == 2 || user.mute_type == 2) 159 | { 160 | Server.NextFrame(() => _baseAdmin.ReplyToCommand(controller, 161 | $"The user with the SteamId identifier {user.steamid} has already been muted in all channels.")); 162 | return; 163 | } 164 | 165 | if (activeUserMute.mute_type is 1 or 0 && user.mute_type is 1 or 0) 166 | user.mute_type = 2; 167 | 168 | await connection.ExecuteAsync(@" 169 | UPDATE miniadmin_mute 170 | SET mute_type = @mute_type, 171 | admin_username = @admin_username, 172 | admin_steamid = @admin_steamid, 173 | username = @username, 174 | steamid64 = @steamid64, 175 | steamid = @steamid, 176 | reason = @reason, 177 | unmute_reason = @unmute_reason, 178 | admin_unlocked_username = @admin_unlocked_username, 179 | admin_unlocked_steamid = @admin_unlocked_steamid, 180 | start_mute_time = @start_mute_time, 181 | end_mute_time = @end_mute_time, 182 | mute_active = @mute_active 183 | WHERE steamid = @steamid and mute_active = 1; 184 | ", user); 185 | 186 | Server.NextFrame(() => _baseAdmin.ReplyToCommand(controller, 187 | $"Player '{user.username} | [{user.steamid}]' mute has been updated.")); 188 | return; 189 | } 190 | 191 | await connection.ExecuteAsync(@" 192 | INSERT INTO miniadmin_mute (mute_type, admin_username, admin_steamid, username, steamid64, steamid, reason, unmute_reason, admin_unlocked_username, admin_unlocked_steamid, start_mute_time, end_mute_time, mute_active) 193 | VALUES (@mute_type, @admin_username, @admin_steamid, @username, @steamid64, @steamid, @reason, @unmute_reason, @admin_unlocked_username, @admin_unlocked_steamid, @start_mute_time, @end_mute_time, @mute_active); 194 | ", user); 195 | 196 | Server.NextFrame(() => 197 | _baseAdmin.ReplyToCommand(controller, $"Player '{user.username} | [{user.steamid}]' is muted.")); 198 | } 199 | catch (Exception e) 200 | { 201 | Console.WriteLine(e); 202 | } 203 | } 204 | 205 | public async Task AddAdmin(Admins admin, CCSPlayerController? player = null, bool fromMenu = false) 206 | { 207 | try 208 | { 209 | var isAdminExist = await IsUserAdmin(admin.steamid); 210 | if (isAdminExist != null) 211 | { 212 | _baseAdmin.PrintLogError("An administrator with the SteamId identifier {steamid} already exists.", 213 | admin.steamid); 214 | 215 | if (fromMenu) 216 | { 217 | if(player != null) 218 | _baseAdmin.PrintToChat(player, $"An administrator with the SteamId identifier {admin.steamid} already exists."); 219 | } 220 | return; 221 | } 222 | 223 | await using var connection = new MySqlConnection(_dbConnectionString); 224 | 225 | await connection.ExecuteAsync(@" 226 | INSERT INTO 227 | miniadmin_admins (username, steamid, start_time, end_time, immunity, flags) 228 | VALUES 229 | (@username, @steamid, @start_time, @end_time, @immunity, @flags);", admin); 230 | 231 | _baseAdmin.PrintLogInfo("Admin '{username}[{steamid}]' successfully added", 232 | admin.username, admin.steamid); 233 | if (fromMenu) 234 | { 235 | if (player != null) 236 | _baseAdmin.PrintToChat(player, $"Admin '{admin.username}[{admin.steamid}]' successfully added"); 237 | } 238 | } 239 | catch (Exception e) 240 | { 241 | Console.WriteLine(e); 242 | } 243 | } 244 | 245 | public async Task DeleteExpiredAdminsAsync() 246 | { 247 | try 248 | { 249 | await using var connection = new MySqlConnection(_dbConnectionString); 250 | 251 | var deleteAdmins = await connection.QueryAsync( 252 | "SELECT * FROM miniadmin_admins WHERE end_time <= @CurrentTime AND end_time > 0", 253 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }); 254 | 255 | var adminsEnumerable = deleteAdmins.ToList(); 256 | if (adminsEnumerable.Any()) 257 | { 258 | foreach (var deleteAdmin in adminsEnumerable) 259 | { 260 | await connection.ExecuteAsync(@"DELETE FROM miniadmin_admins WHERE steamid = @SteamId;", 261 | new { SteamId = deleteAdmin.steamid }); 262 | 263 | _baseAdmin.PrintLogInfo("Admin {steamid} successfully deleted", 264 | deleteAdmin.steamid); 265 | } 266 | 267 | _baseAdmin.PrintLogInfo("Expired admins successfully deleted"); 268 | } 269 | } 270 | catch (Exception e) 271 | { 272 | Console.WriteLine(e); 273 | } 274 | 275 | return string.Empty; 276 | } 277 | 278 | public async Task DeleteAdminAsync(string steamId) 279 | { 280 | try 281 | { 282 | await using var connection = new MySqlConnection(_dbConnectionString); 283 | 284 | await connection.ExecuteAsync(@"DELETE FROM miniadmin_admins WHERE steamid = @SteamId;", 285 | new { SteamId = steamId }); 286 | 287 | _baseAdmin.PrintLogInfo("Admin {steamId} successfully deleted", steamId); 288 | } 289 | catch (Exception e) 290 | { 291 | Console.WriteLine(e); 292 | } 293 | 294 | return string.Empty; 295 | } 296 | 297 | public async Task UnbanUser(string adminName, string adminSteamId, string steamId, string reason) 298 | { 299 | try 300 | { 301 | await using var connection = new MySqlConnection(_dbConnectionString); 302 | 303 | var user = await connection.QueryFirstOrDefaultAsync( 304 | "SELECT * FROM miniadmin_bans WHERE steamid = @SteamId AND ban_active = 1", 305 | new { SteamId = steamId }); 306 | 307 | if (user == null) return "User not found or not currently banned"; 308 | 309 | user.unban_reason = reason; 310 | user.admin_unlocked_username = adminName; 311 | user.admin_unlocked_steamid = adminSteamId; 312 | user.ban_active = false; 313 | 314 | await connection.ExecuteAsync(@" 315 | UPDATE miniadmin_bans 316 | SET unban_reason = @unban_reason, admin_unlocked_username = @admin_unlocked_username, 317 | admin_unlocked_steamid = @admin_unlocked_steamid, ban_active = @ban_active 318 | WHERE steamid = @SteamId AND ban_active = 1 319 | ", user); 320 | 321 | return $"Player {steamId} has been successfully unblocked with reason: {reason}"; 322 | } 323 | catch (Exception e) 324 | { 325 | Console.WriteLine(e); 326 | } 327 | 328 | return string.Empty; 329 | } 330 | 331 | public async Task UnmuteUser(int unmuteType, string adminName, string adminSteamId, string steamId, 332 | string reason) 333 | { 334 | try 335 | { 336 | await using var connection = new MySqlConnection(_dbConnectionString); 337 | 338 | var user = await connection.QueryFirstOrDefaultAsync( 339 | "SELECT * FROM miniadmin_mute WHERE steamid = @SteamId AND mute_active = 1", 340 | new { SteamId = steamId }); 341 | 342 | if (user == null) return "User not found or not currently muted"; 343 | 344 | user.unmute_reason = reason; 345 | user.admin_unlocked_username = adminName; 346 | user.admin_unlocked_steamid = adminSteamId; 347 | 348 | if (unmuteType != -1) 349 | { 350 | if (user.mute_type is 2 && unmuteType is 0) 351 | user.mute_type = 1; 352 | else if (user.mute_type is 2 && unmuteType is 1) 353 | user.mute_type = 0; 354 | else if (user.mute_type == unmuteType) 355 | user.mute_active = false; 356 | } 357 | else 358 | user.mute_active = false; 359 | 360 | await connection.ExecuteAsync(@" 361 | UPDATE miniadmin_mute 362 | SET 363 | mute_type = @mute_type, 364 | unmute_reason = @unmute_reason, 365 | admin_unlocked_username = @admin_unlocked_username, 366 | admin_unlocked_steamid = @admin_unlocked_steamid, 367 | mute_active = @mute_active 368 | WHERE 369 | steamid = @SteamId 370 | AND 371 | mute_active = 1 372 | ", user); 373 | 374 | return $"Player {steamId} has been successfully unmuted with reason: {reason}"; 375 | } 376 | catch (Exception e) 377 | { 378 | Console.WriteLine(e); 379 | } 380 | 381 | return string.Empty; 382 | } 383 | 384 | public async Task GetActiveMuteAsync(string steamId) 385 | { 386 | try 387 | { 388 | await using var connection = new MySqlConnection(_dbConnectionString); 389 | 390 | var muteData = await connection.QueryFirstOrDefaultAsync(@" 391 | SELECT * FROM miniadmin_mute 392 | WHERE steamid = @SteamId AND mute_active = 1; 393 | ", new { SteamId = steamId }); 394 | 395 | return muteData; 396 | } 397 | catch (Exception e) 398 | { 399 | Console.WriteLine(e); 400 | return null; 401 | } 402 | } 403 | 404 | private async Task IsUserBanned(string steamId) 405 | { 406 | await using var connection = new MySqlConnection(_dbConnectionString); 407 | 408 | var existingBan = connection.QueryFirstOrDefaultAsync( 409 | "SELECT * FROM miniadmin_bans WHERE steamid = @SteamId AND ban_active = 1", 410 | new { SteamId = steamId }).Result; 411 | 412 | return existingBan != null; 413 | } 414 | 415 | public async Task IsUserMuted(string steamId) 416 | { 417 | await using var connection = new MySqlConnection(_dbConnectionString); 418 | 419 | var existingMute = connection.QueryFirstOrDefaultAsync( 420 | "SELECT * FROM miniadmin_mute WHERE steamid = @SteamId AND mute_active = 1", 421 | new { SteamId = steamId }).Result; 422 | 423 | return existingMute != null; 424 | } 425 | 426 | public async Task IsUserAdmin(string steamId) 427 | { 428 | await using var connection = new MySqlConnection(_dbConnectionString); 429 | 430 | var existingAdmin = connection.QueryFirstOrDefaultAsync( 431 | "SELECT * FROM miniadmin_admins WHERE steamid = @SteamId", 432 | new { SteamId = steamId }).Result; 433 | 434 | return existingAdmin; 435 | } 436 | 437 | // private async Task IsAdminExist(string steamId) 438 | // { 439 | // await using var connection = new MySqlConnection(_dbConnectionString); 440 | // 441 | // var existingAdmin = connection.QueryFirstOrDefaultAsync( 442 | // "SELECT * FROM miniadmin_admins WHERE steamid = @SteamId", 443 | // new { SteamId = steamId }).Result; 444 | // 445 | // return existingAdmin != null; 446 | // } 447 | } -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/Menu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using CounterStrikeSharp.API; 5 | using CounterStrikeSharp.API.Core; 6 | using CounterStrikeSharp.API.Modules.Entities; 7 | using CounterStrikeSharp.API.Modules.Menu; 8 | 9 | namespace BaseAdmin; 10 | 11 | public class Menu 12 | { 13 | private readonly BaseAdmin _baseAdmin; 14 | private readonly ChatMenu _slayMenu; 15 | private readonly ChatMenu _kickMenu; 16 | private readonly ChatMenu _muteMenu; 17 | private readonly ChatMenu _banMenu; 18 | private readonly ChatMenu _changeMapMenu; 19 | private readonly ChatMenu _addAdminMenu; 20 | 21 | public Menu(BaseAdmin baseAdmin) 22 | { 23 | _baseAdmin = baseAdmin; 24 | 25 | _slayMenu = new ChatMenu(baseAdmin.Prefix); 26 | _kickMenu = new ChatMenu(baseAdmin.Prefix); 27 | _muteMenu = new ChatMenu(baseAdmin.Prefix); 28 | _banMenu = new ChatMenu(baseAdmin.Prefix); 29 | _changeMapMenu = new ChatMenu(baseAdmin.Prefix); 30 | _addAdminMenu = new ChatMenu(baseAdmin.Prefix); 31 | } 32 | 33 | public void CreateMenu() 34 | { 35 | var adminMenu = new ChatMenu(_baseAdmin.Prefix); 36 | adminMenu.AddMenuOption("Slay players", (player, _) => 37 | { 38 | if (_baseAdmin.CheckingForAdminAndFlag(player, BaseAdmin.AdminFlag.Slay)) 39 | { 40 | CreateSlayMenu(); 41 | ChatMenus.OpenMenu(player, _slayMenu); 42 | } 43 | else 44 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 45 | }); 46 | adminMenu.AddMenuOption("Kick players", (player, _) => 47 | { 48 | if (_baseAdmin.CheckingForAdminAndFlag(player, BaseAdmin.AdminFlag.Kick)) 49 | { 50 | CreateKickMenu(); 51 | ChatMenus.OpenMenu(player, _kickMenu); 52 | } 53 | else 54 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 55 | }); 56 | adminMenu.AddMenuOption("Mute players", (player, _) => 57 | { 58 | if (_baseAdmin.CheckingForAdminAndFlag(player, BaseAdmin.AdminFlag.Generic)) 59 | { 60 | CreateMuteMenu(); 61 | ChatMenus.OpenMenu(player, _muteMenu); 62 | } 63 | else 64 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 65 | }); 66 | adminMenu.AddMenuOption("Ban players", (player, _) => 67 | { 68 | if (_baseAdmin.CheckingForAdminAndFlag(player, BaseAdmin.AdminFlag.Ban)) 69 | { 70 | CreateBanMenu(); 71 | ChatMenus.OpenMenu(player, _banMenu); 72 | } 73 | else 74 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 75 | }); 76 | adminMenu.AddMenuOption("Change map", (player, _) => 77 | { 78 | if (_baseAdmin.CheckingForAdminAndFlag(player, BaseAdmin.AdminFlag.Changemap)) 79 | { 80 | CreateChangeMapMenu(); 81 | ChatMenus.OpenMenu(player, _changeMapMenu); 82 | } 83 | else 84 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 85 | }); 86 | adminMenu.AddMenuOption("Add Admin", (player, _) => 87 | { 88 | if (_baseAdmin.CheckingForAdminAndFlag(player, BaseAdmin.AdminFlag.Root)) 89 | { 90 | CreateAddAdminMenu(); 91 | ChatMenus.OpenMenu(player, _addAdminMenu); 92 | } 93 | else 94 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 95 | }); 96 | 97 | _baseAdmin.AddCommand("css_admin", "admin menu", (player, info) => 98 | { 99 | if (player == null) return; 100 | if (!_baseAdmin.IsAdmin(player.Index)) 101 | { 102 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 103 | return; 104 | } 105 | 106 | ChatMenus.OpenMenu(player, adminMenu); 107 | }); 108 | } 109 | 110 | private void CreateSlayMenu() 111 | { 112 | var playerEntities = 113 | Utilities.GetPlayers().Where(u => u.PlayerPawn.Value != null && u.PlayerPawn.Value.IsValid); 114 | _slayMenu.MenuOptions.Clear(); 115 | _slayMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 116 | _slayMenu.AddMenuOption("All", (controller, option) => 117 | { 118 | foreach (var player in playerEntities) 119 | if (player.PlayerPawn.Value != null) 120 | player.PlayerPawn.Value.CommitSuicide(true, true); 121 | }); 122 | foreach (var player in playerEntities) 123 | { 124 | if (!player.PawnIsAlive) continue; 125 | 126 | _slayMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 127 | { 128 | var parts = option.Text.Split('[', ']'); 129 | if (parts.Length < 2) return; 130 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 131 | 132 | if (!target.PawnIsAlive) 133 | { 134 | _baseAdmin.PrintToChat(controller, "The player is already dead"); 135 | return; 136 | } 137 | 138 | if (target.PlayerPawn.Value != null) 139 | target.PlayerPawn.Value.CommitSuicide(true, true); 140 | 141 | _baseAdmin.PrintToChatAll($"{controller.PlayerName}: Player '{target.PlayerName}' has been killed"); 142 | }); 143 | } 144 | } 145 | 146 | private void CreateKickMenu() 147 | { 148 | _kickMenu.MenuOptions.Clear(); 149 | _kickMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 150 | foreach (var player in Utilities.GetPlayers()) 151 | { 152 | _kickMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 153 | { 154 | var parts = option.Text.Split('[', ']'); 155 | if (parts.Length < 2) return; 156 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 157 | 158 | if (!target.IsValid) 159 | { 160 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 161 | return; 162 | } 163 | 164 | _baseAdmin.KickClient($"{target.UserId}"); 165 | 166 | _baseAdmin.PrintToChatAll($"{controller.PlayerName}: Player '{target.PlayerName}' has been kicked"); 167 | }); 168 | } 169 | } 170 | 171 | private void CreateBanMenu() 172 | { 173 | _banMenu.MenuOptions.Clear(); 174 | _banMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 175 | foreach (var player in Utilities.GetPlayers()) 176 | { 177 | _banMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 178 | { 179 | var parts = option.Text.Split('[', ']'); 180 | if (parts.Length < 2) return; 181 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 182 | 183 | if (!target.IsValid) 184 | { 185 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 186 | return; 187 | } 188 | 189 | SelectionReasonsForBanning(controller, target); 190 | }); 191 | } 192 | } 193 | 194 | private void SelectionReasonsForBanning(CCSPlayerController player, CCSPlayerController target) 195 | { 196 | var reasonMenu = new ChatMenu(_baseAdmin.Prefix); 197 | reasonMenu.AddMenuOption("Pick a reason", (_, _) => { }, true); 198 | foreach (var reason in _baseAdmin.ReadAllBanReasons()) 199 | { 200 | reasonMenu.AddMenuOption(reason, (controller, option) => 201 | { 202 | var timeMenu = new ChatMenu(_baseAdmin.Prefix); 203 | timeMenu.AddMenuOption("Select a time", (_, _) => { }, true); 204 | foreach (var time in _baseAdmin.ReadAllTime()) 205 | { 206 | var split = time.Split(':'); 207 | timeMenu.AddMenuOption(split[0], 208 | (playerController, _) => 209 | { 210 | Task.Run(() => AddBanFromMenu(playerController, target, option.Text, int.Parse(split[1]))); 211 | }); 212 | } 213 | 214 | ChatMenus.OpenMenu(controller, timeMenu); 215 | }); 216 | } 217 | 218 | ChatMenus.OpenMenu(player, reasonMenu); 219 | } 220 | 221 | private async Task AddBanFromMenu(CCSPlayerController controller, CCSPlayerController target, string reason, 222 | int time) 223 | { 224 | var startBanTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 225 | var endBanTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 226 | 227 | Server.NextFrame(() => 228 | { 229 | var msg = _baseAdmin.Database.AddBan(new User 230 | { 231 | admin_username = controller.PlayerName, 232 | admin_steamid = new SteamID(controller.SteamID).SteamId2, 233 | username = target.PlayerName, 234 | steamid64 = target.SteamID, 235 | steamid = new SteamID(target.SteamID).SteamId2, 236 | reason = reason, 237 | unban_reason = string.Empty, 238 | admin_unlocked_username = string.Empty, 239 | admin_unlocked_steamid = string.Empty, 240 | start_ban_time = startBanTimeUnix, 241 | end_ban_time = time == 0 ? time : endBanTimeUnix, 242 | ban_active = true 243 | }).Result; 244 | _baseAdmin.KickClient($"{target.UserId}"); 245 | _baseAdmin.PrintToChatAll(msg); 246 | }); 247 | } 248 | 249 | private void CreateMuteMenu() 250 | { 251 | _muteMenu.MenuOptions.Clear(); 252 | _muteMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 253 | foreach (var player in Utilities.GetPlayers()) 254 | { 255 | _muteMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 256 | { 257 | var parts = option.Text.Split('[', ']'); 258 | if (parts.Length < 2) return; 259 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 260 | 261 | if (!target.IsValid) 262 | { 263 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 264 | return; 265 | } 266 | 267 | SelectionTypeMute(controller, target); 268 | }); 269 | } 270 | } 271 | 272 | private void SelectionTypeMute(CCSPlayerController player, CCSPlayerController target) 273 | { 274 | var reasonMenu = new ChatMenu(_baseAdmin.Prefix); 275 | reasonMenu.AddMenuOption("Pick a type", (_, _) => { }, true); 276 | reasonMenu.AddMenuOption("All", (_, _) => { SelectionReasonsForMute(player, target, BaseAdmin.MuteType.All); }); 277 | reasonMenu.AddMenuOption("Mute", 278 | (_, _) => { SelectionReasonsForMute(player, target, BaseAdmin.MuteType.Micro); }); 279 | reasonMenu.AddMenuOption("Gag", 280 | (_, _) => { SelectionReasonsForMute(player, target, BaseAdmin.MuteType.Chat); }); 281 | ChatMenus.OpenMenu(player, reasonMenu); 282 | } 283 | 284 | private void SelectionReasonsForMute(CCSPlayerController player, CCSPlayerController target, 285 | BaseAdmin.MuteType muteType) 286 | { 287 | var reasonMenu = new ChatMenu(_baseAdmin.Prefix); 288 | reasonMenu.AddMenuOption("Pick a reason", (_, _) => { }, true); 289 | foreach (var reason in _baseAdmin.ReadAllMuteReasons()) 290 | { 291 | reasonMenu.AddMenuOption(reason, (controller, option) => 292 | { 293 | var timeMenu = new ChatMenu(_baseAdmin.Prefix); 294 | timeMenu.AddMenuOption("Select a time", (_, _) => { }, true); 295 | foreach (var time in _baseAdmin.ReadAllTime()) 296 | { 297 | var split = time.Split(':'); 298 | timeMenu.AddMenuOption(split[0], 299 | (playerController, _) => 300 | { 301 | Task.Run(() => 302 | AddMuteFromMenu(playerController, target, option.Text, int.Parse(split[1]), muteType)); 303 | }); 304 | } 305 | 306 | ChatMenus.OpenMenu(controller, timeMenu); 307 | }); 308 | } 309 | 310 | ChatMenus.OpenMenu(player, reasonMenu); 311 | } 312 | 313 | private async Task AddMuteFromMenu(CCSPlayerController controller, CCSPlayerController target, string reason, 314 | int time, BaseAdmin.MuteType muteType) 315 | { 316 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 317 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 318 | 319 | Server.NextFrame(() => 320 | { 321 | _baseAdmin.Database.AddMute(new MuteUser 322 | { 323 | mute_type = (int)muteType, 324 | admin_username = controller != null ? controller.PlayerName : "Console", 325 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 326 | username = target.PlayerName, 327 | steamid64 = target.SteamID, 328 | steamid = new SteamID(target.SteamID).SteamId2, 329 | reason = reason, 330 | unmute_reason = "", 331 | admin_unlocked_username = "", 332 | admin_unlocked_steamid = "", 333 | start_mute_time = startMuteTimeUnix, 334 | end_mute_time = endMuteTimeUnix == 0 ? 0 : endMuteTimeUnix, 335 | mute_active = true 336 | }, controller == null ? null : controller); 337 | 338 | if (muteType is BaseAdmin.MuteType.Micro or BaseAdmin.MuteType.All) 339 | target.VoiceFlags = VoiceFlags.Muted; 340 | }); 341 | 342 | _baseAdmin.UpdateUserMuteLocal(target, time, endMuteTimeUnix, (int)muteType); 343 | } 344 | 345 | private void CreateChangeMapMenu() 346 | { 347 | _changeMapMenu.MenuOptions.Clear(); 348 | _changeMapMenu.AddMenuOption("Pick a map", (_, _) => { }, true); 349 | foreach (var map in _baseAdmin.GetMapFromMaps()) 350 | { 351 | var mapsStarts = map.StartsWith("ws:"); 352 | var mapName = mapsStarts ? map.Trim('w', 's', ':') : map; 353 | _changeMapMenu.AddMenuOption($"{mapName}", 354 | (controller, option) => 355 | { 356 | _baseAdmin.PrintToChatAll($"{controller.PlayerName}: changing the map to {mapName}"); 357 | _baseAdmin.AddTimer(3.0f, () => _baseAdmin.ChangeMap(mapName, mapsStarts)); 358 | }); 359 | } 360 | } 361 | 362 | private void CreateAddAdminMenu() 363 | { 364 | _addAdminMenu.MenuOptions.Clear(); 365 | _addAdminMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 366 | foreach (var player in Utilities.GetPlayers()) 367 | { 368 | if (_baseAdmin.IsAdmin(player.Index)) continue; 369 | 370 | _addAdminMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", 371 | (controller, option) => 372 | { 373 | var parts = option.Text.Split('[', ']'); 374 | if (parts.Length < 2) return; 375 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 376 | 377 | if (!target.IsValid) 378 | { 379 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 380 | return; 381 | } 382 | 383 | SelectionTimeAndImmunityForAddAdmin(controller, target); 384 | }); 385 | } 386 | } 387 | 388 | private void SelectionTimeAndImmunityForAddAdmin(CCSPlayerController player, CCSPlayerController target) 389 | { 390 | var timeMenu = new ChatMenu(_baseAdmin.Prefix); 391 | timeMenu.AddMenuOption("Select a time", (_, _) => { }, true); 392 | foreach (var time in _baseAdmin.ReadAllTime()) 393 | { 394 | var split = time.Split(':'); 395 | timeMenu.AddMenuOption(split[0], (playerController, _) => 396 | { 397 | var immunityMenu = new ChatMenu(_baseAdmin.Prefix); 398 | immunityMenu.AddMenuOption("Choice of immunity", (_, _) => { }, true); 399 | foreach (var immunity in _baseAdmin.ReadAllImmunity()) 400 | { 401 | immunityMenu.AddMenuOption(immunity, 402 | (client, _) => 403 | { 404 | Task.Run(() => AddAdminFromMenu(client, target, int.Parse(immunity), int.Parse(split[1]))); 405 | }); 406 | } 407 | 408 | ChatMenus.OpenMenu(playerController, immunityMenu); 409 | }); 410 | } 411 | 412 | ChatMenus.OpenMenu(player, timeMenu); 413 | } 414 | 415 | private async void AddAdminFromMenu(CCSPlayerController client, CCSPlayerController target, 416 | int immunity, int time) 417 | { 418 | var startTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 419 | var endTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 420 | 421 | await _baseAdmin.Database.AddAdmin(new Admins 422 | { 423 | username = target.PlayerName, 424 | steamid = new SteamID(target.SteamID).SteamId2, 425 | start_time = startTimeUnix, 426 | end_time = time == 0 ? time : endTimeUnix, 427 | immunity = immunity, 428 | flags = "s" 429 | }, client, true); 430 | } 431 | } -------------------------------------------------------------------------------- /MiniAdmin (For CSSharp Flags)/MuteUser.cs: -------------------------------------------------------------------------------- 1 | namespace BaseAdmin; 2 | 3 | public class MuteUser 4 | { 5 | public int mute_type { get; set; } 6 | public required string admin_username { get; set; } 7 | public required string admin_steamid { get; set; } 8 | public required string username { get; set; } 9 | public ulong steamid64 { get; set; } 10 | public required string steamid { get; set; } 11 | public required string reason { get; set; } 12 | public required string unmute_reason { get; set; } 13 | public required string admin_unlocked_username { get; set; } 14 | public required string admin_unlocked_steamid { get; set; } 15 | public int start_mute_time { get; set; } 16 | public int end_mute_time { get; set; } 17 | public bool mute_active { get; set; } 18 | } 19 | 20 | public class MuteUserLocal 21 | { 22 | public int MuteType { get; set; } 23 | public required string SteamId { get; set; } 24 | public int EndMuteTime { get; set; } 25 | public bool MuteActive { get; set; } 26 | } -------------------------------------------------------------------------------- /MiniAdmin/AdminChat.cs: -------------------------------------------------------------------------------- 1 | using CounterStrikeSharp.API; 2 | using CounterStrikeSharp.API.Core; 3 | using CounterStrikeSharp.API.Modules.Utils; 4 | 5 | namespace BaseAdmin; 6 | 7 | public class AdminChat 8 | { 9 | public void SendToAdminChat(CCSPlayerController player, string message) 10 | { 11 | player.PrintToChat( 12 | $"[{ChatColors.Blue} AdminChat {ChatColors.Default}]{message}"); 13 | } 14 | 15 | public void SendToAdminChatFromPlayer(CCSPlayerController player, string message) 16 | { 17 | player.PrintToChat( 18 | $"[{ChatColors.Blue} From Players {ChatColors.Default}]{message}"); 19 | } 20 | 21 | public void SendToAllFromAdmin(string message) 22 | { 23 | Server.PrintToChatAll( 24 | $"[{ChatColors.Blue}ALL{ChatColors.Default}] {ChatColors.Blue}ADMIN{ChatColors.Default}: {message}"); 25 | } 26 | } -------------------------------------------------------------------------------- /MiniAdmin/Admins.cs: -------------------------------------------------------------------------------- 1 | namespace BaseAdmin; 2 | 3 | public class Admins 4 | { 5 | public required string username { get; set; } 6 | public required string steamid { get; set; } 7 | public int start_time { get; set; } 8 | public int end_time { get; set; } 9 | public int immunity { get; set; } 10 | public required string flags { get; set; } 11 | } -------------------------------------------------------------------------------- /MiniAdmin/BanUser.cs: -------------------------------------------------------------------------------- 1 | namespace BaseAdmin; 2 | 3 | public class User 4 | { 5 | public required string admin_username { get; set; } 6 | public required string admin_steamid { get; set; } 7 | public required string username { get; set; } 8 | public ulong steamid64 { get; set; } 9 | public required string steamid { get; set; } 10 | public required string reason { get; set; } 11 | public required string unban_reason { get; set; } 12 | public required string admin_unlocked_username { get; set; } 13 | public required string admin_unlocked_steamid { get; set; } 14 | public int start_ban_time { get; set; } 15 | public int end_ban_time { get; set; } 16 | public bool ban_active { get; set; } 17 | } -------------------------------------------------------------------------------- /MiniAdmin/BaseAdmin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using System.Text.Json; 7 | using System.Text.RegularExpressions; 8 | using System.Threading.Tasks; 9 | using CounterStrikeSharp.API; 10 | using CounterStrikeSharp.API.Core; 11 | using CounterStrikeSharp.API.Core.Attributes.Registration; 12 | using CounterStrikeSharp.API.Modules.Commands; 13 | using CounterStrikeSharp.API.Modules.Cvars; 14 | using CounterStrikeSharp.API.Modules.Entities; 15 | using CounterStrikeSharp.API.Modules.Memory; 16 | using CounterStrikeSharp.API.Modules.Timers; 17 | using CounterStrikeSharp.API.Modules.Utils; 18 | using Dapper; 19 | using Microsoft.Extensions.Logging; 20 | using MySqlConnector; 21 | 22 | namespace BaseAdmin; 23 | 24 | public class BaseAdmin : BasePlugin 25 | { 26 | public override string ModuleAuthor => "thesamefabius"; 27 | public override string ModuleName => "Mini Admin"; 28 | public override string ModuleVersion => "v1.0.5"; 29 | 30 | private static string _dbConnectionString = string.Empty; 31 | 32 | //MENU 33 | public readonly string Prefix = "[\x0C Admin Menu \x01]"; 34 | 35 | private readonly DateTime[] _playerPlayTime = new DateTime[65]; 36 | private readonly MuteUserLocal?[] _muteUsers = new MuteUserLocal[65]; 37 | private readonly Admins?[] _adminUsers = new Admins[65]; 38 | 39 | public Database Database = null!; 40 | private AdminChat _adminChat = null!; 41 | private Config _config; 42 | 43 | public enum MuteType 44 | { 45 | Micro = 0, 46 | Chat, 47 | All 48 | } 49 | 50 | public enum AdminFlag 51 | { 52 | Reservation = 'a', 53 | Generic = 'b', 54 | Kick = 'c', 55 | Ban = 'd', 56 | Unban = 'e', 57 | Slay = 'f', 58 | Changemap = 'g', 59 | Cvar = 'h', 60 | Config = 'i', 61 | Chat = 'j', 62 | Vote = 'k', 63 | Password = 'l', 64 | Rcon = 'm', 65 | Cheats = 'n', 66 | Vip = 'o', 67 | Root = 'z' 68 | } 69 | 70 | public override void Load(bool hotReload) 71 | { 72 | _config = LoadConfig(); 73 | _dbConnectionString = BuildConnectionString(); 74 | Database = new Database(this, _dbConnectionString); 75 | _adminChat = new AdminChat(); 76 | new Menu(this).CreateMenu(); 77 | 78 | Task.Run(Database.CreateTable); 79 | Task.Run(Database.CreateAdminsTable); 80 | Task.Run(Database.CreateMuteTable); 81 | 82 | RegisterListener((slot, id) => 83 | { 84 | OnClientConnectedAsync(slot, Utilities.GetPlayerFromSlot(slot), id); 85 | OnClientAuthorizedAsync(slot, id); 86 | }); 87 | 88 | RegisterListener(slot => 89 | { 90 | _muteUsers[slot + 1] = null; 91 | _adminUsers[slot + 1] = null; 92 | _playerPlayTime[slot + 1] = DateTime.MinValue; 93 | }); 94 | 95 | AddCommandListener("say", CommandListener_Say); 96 | AddCommandListener("say_team", CommandListener_SayTeam); 97 | 98 | AddTimer(300, () => Task.Run(Database.DeleteExpiredAdminsAsync), TimerFlags.REPEAT); 99 | AddTimer(60, () => 100 | { 101 | foreach (var player in Utilities.GetPlayers().Where(u => !u.IsBot)) 102 | { 103 | var user = _muteUsers[player.Index]; 104 | 105 | if (user == null) continue; 106 | 107 | var endTime = DateTimeOffset.FromUnixTimeSeconds(user.EndMuteTime).UtcDateTime; 108 | 109 | if (endTime <= DateTime.UtcNow) 110 | { 111 | if (user.MuteType is (int)MuteType.Micro or (int)MuteType.All) 112 | player.VoiceFlags = VoiceFlags.Normal; 113 | 114 | _muteUsers[player.Index] = null; 115 | } 116 | } 117 | }, TimerFlags.REPEAT); 118 | } 119 | 120 | private HookResult ProcessChatMessage(CCSPlayerController? controller, CommandInfo info, bool sendToAllAdmins) 121 | { 122 | if (controller == null) return HookResult.Continue; 123 | 124 | var msg = GetTextInsideQuotes(info.ArgString); 125 | var entityIndex = controller.Index; 126 | 127 | if (msg.StartsWith('@')) 128 | { 129 | if (CheckingForAdminAndFlag(controller, AdminFlag.Chat)) 130 | { 131 | if (sendToAllAdmins) 132 | { 133 | _adminChat.SendToAllFromAdmin(msg.Trim('@')); 134 | return HookResult.Handled; 135 | } 136 | 137 | foreach (var player in Utilities.GetPlayers() 138 | .Where(player => CheckingForAdminAndFlag(player, AdminFlag.Chat))) 139 | { 140 | _adminChat.SendToAdminChat(player, 141 | $" {ChatColors.Blue}{controller.PlayerName}{ChatColors.Default}: {msg.Trim('@')}"); 142 | } 143 | 144 | return HookResult.Handled; 145 | } 146 | else 147 | { 148 | if (!IsUserMute(entityIndex)) 149 | { 150 | foreach (var player in Utilities.GetPlayers()) 151 | { 152 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Chat)) continue; 153 | 154 | _adminChat.SendToAdminChatFromPlayer(player, 155 | $" {ChatColors.Blue}{controller.PlayerName}{ChatColors.Default}: {msg.Trim('@')}"); 156 | return HookResult.Handled; 157 | } 158 | } 159 | } 160 | } 161 | 162 | if (IsUserMute(entityIndex)) 163 | return CheckMuteStatus(controller, MuteType.Chat) ? HookResult.Handled : HookResult.Continue; 164 | 165 | return HookResult.Continue; 166 | } 167 | 168 | private HookResult CommandListener_SayTeam(CCSPlayerController? controller, CommandInfo info) 169 | { 170 | return ProcessChatMessage(controller, info, sendToAllAdmins: false); 171 | } 172 | 173 | private HookResult CommandListener_Say(CCSPlayerController? controller, CommandInfo info) 174 | { 175 | return ProcessChatMessage(controller, info, sendToAllAdmins: true); 176 | } 177 | 178 | // private bool CheckMute(CCSPlayerController controller) 179 | // { 180 | // return CheckMuteStatus(controller, MuteType.Chat, "You cannot write a message because you have chat disabled. End via: "); 181 | // } 182 | // 183 | // private bool CheckMicrophoneMute(CCSPlayerController controller) 184 | // { 185 | // return CheckMuteStatus(controller, MuteType.Micro, "You cannot use the microphone because it is muted. End via: "); 186 | // } 187 | 188 | private bool CheckMuteStatus(CCSPlayerController controller, MuteType requiredMuteType) 189 | { 190 | var user = _muteUsers[controller.Index]; 191 | 192 | if (user == null) return false; 193 | 194 | if (user.MuteType != (int)MuteType.All && user.MuteType != (int)requiredMuteType) return false; 195 | 196 | var endTime = DateTimeOffset.FromUnixTimeSeconds(user.EndMuteTime).UtcDateTime; 197 | var timeEnd = endTime - DateTime.UtcNow; 198 | 199 | var message = requiredMuteType == MuteType.Chat 200 | ? "You cannot write a message because you have chat disabled. End via: " 201 | : "You cannot use the microphone because it is muted. End via: "; 202 | var time = 203 | $"{(timeEnd.Days == 0 ? "" : $"{timeEnd.Days}d, ")}{timeEnd.Hours:00}:{timeEnd.Minutes:00}:{timeEnd.Seconds:00}"; 204 | PrintToChat(controller, message + time); 205 | return true; 206 | } 207 | 208 | private async Task OnClientAuthorizedAsync(int playerSlot, SteamID steamId) 209 | { 210 | await LoadAdminUserAsync(steamId, playerSlot); 211 | 212 | var userMuted = await Database.GetActiveMuteAsync(steamId.SteamId2); 213 | 214 | if (userMuted != null) 215 | { 216 | _muteUsers[playerSlot + 1] = new MuteUserLocal 217 | { 218 | MuteType = userMuted.mute_type, 219 | SteamId = userMuted.steamid, 220 | EndMuteTime = userMuted.end_mute_time, 221 | MuteActive = userMuted.mute_active 222 | }; 223 | 224 | if (userMuted.mute_type is (int)MuteType.Micro or (int)MuteType.All) 225 | { 226 | Server.NextFrame(() => Utilities.GetPlayerFromSlot(playerSlot).VoiceFlags = VoiceFlags.Muted); 227 | } 228 | } 229 | } 230 | 231 | public async Task LoadAdminUserAsync(SteamID steamId, int playerSlot) 232 | { 233 | var userAdmin = await Database.GetAdminFromDb(steamId.SteamId2); 234 | 235 | if (userAdmin != null) 236 | { 237 | _adminUsers[playerSlot + 1] = new Admins 238 | { 239 | username = userAdmin.username, 240 | steamid = userAdmin.steamid, 241 | start_time = userAdmin.start_time, 242 | end_time = userAdmin.end_time, 243 | immunity = userAdmin.immunity, 244 | flags = userAdmin.flags 245 | }; 246 | } 247 | } 248 | 249 | private async Task OnClientConnectedAsync(int slot, CCSPlayerController player, SteamID steamId) 250 | { 251 | try 252 | { 253 | await using var connection = new MySqlConnection(_dbConnectionString); 254 | 255 | var unbanUsers = await connection.QueryFirstOrDefaultAsync( 256 | "SELECT * FROM miniadmin_bans WHERE steamid64 = @SteamId64 AND end_ban_time <= @CurrentTime AND ban_active = 1 AND end_ban_time != 0", 257 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), steamId.SteamId64 }); 258 | 259 | if (unbanUsers != null) 260 | { 261 | PrintLogInfo("Unban: {steamid}", unbanUsers.steamid); 262 | await Database.UnbanUser(_config.BanFromConsoleName, _config.BanFromConsoleName, unbanUsers.steamid, "The deadline has passed"); 263 | } 264 | 265 | var unmuteUsers = await connection.QueryFirstOrDefaultAsync( 266 | "SELECT * FROM miniadmin_mute WHERE steamid64 = @SteamId64 AND end_mute_time <= @CurrentTime AND mute_active = 1 AND end_mute_time != 0", 267 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), steamId.SteamId64 }); 268 | 269 | if (unmuteUsers != null) 270 | { 271 | PrintLogInfo("Unmute: {steamid}", unmuteUsers.steamid); 272 | await Database.UnmuteUser(-1, _config.BanFromConsoleName, _config.BanFromConsoleName, unmuteUsers.steamid, "The deadline has passed"); 273 | 274 | if (unmuteUsers.mute_type is (int)MuteType.All or (int)MuteType.Micro) 275 | Server.NextFrame(() => player.VoiceFlags = VoiceFlags.Normal); 276 | } 277 | 278 | await Database.DeleteExpiredAdminsAsync(); 279 | 280 | var banUser = await connection.QueryFirstOrDefaultAsync( 281 | "SELECT * FROM miniadmin_bans WHERE steamid64 = @SteamId64 AND ban_active = 1", 282 | new { steamId.SteamId64 }); 283 | 284 | if (banUser != null) 285 | player.Kick("Ban"); 286 | else 287 | _playerPlayTime[slot + 1] = DateTime.Now; 288 | } 289 | catch (Exception e) 290 | { 291 | PrintLogError(e.ToString()); 292 | } 293 | } 294 | 295 | [CommandHelper(0, "<#userid or username>", CommandUsage.CLIENT_ONLY)] 296 | [ConsoleCommand("css_noclip")] 297 | public void OnCmdNoclip(CCSPlayerController? controller, CommandInfo command) 298 | { 299 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Cheats)) return; 300 | 301 | var msg = GetTextInsideQuotes(command.ArgString); 302 | if (msg.StartsWith('#')) 303 | { 304 | GiveNoclip(controller, GetPlayerFromUserIdOrName(msg)); 305 | return; 306 | } 307 | 308 | GiveNoclip(controller); 309 | } 310 | 311 | private void GiveNoclip(CCSPlayerController player, CCSPlayerController? target = null) 312 | { 313 | var playerPawn = target == null ? player.PlayerPawn.Value : target.PlayerPawn.Value; 314 | if (playerPawn != null) 315 | playerPawn.MoveType = playerPawn.MoveType switch 316 | { 317 | MoveType_t.MOVETYPE_NOCLIP => MoveType_t.MOVETYPE_WALK, 318 | MoveType_t.MOVETYPE_WALK => MoveType_t.MOVETYPE_NOCLIP, 319 | _ => playerPawn.MoveType 320 | }; 321 | 322 | PrintToChatAll( 323 | $"Admin '{player.PlayerName}' has issued a noclip to player '{(target == null ? $"{player.PlayerName}" : $"{target.PlayerName}")}'"); 324 | } 325 | 326 | // [ConsoleCommand("css_refresh_admins")] 327 | // public void OnCmdRefreshAdmins(CCSPlayerController? controller, CommandInfo command) 328 | // { 329 | // if (controller != null && !CheckingForAdminAndFlag(controller, AdminFlag.Root)) return; 330 | // 331 | // foreach (var players in Utilities.GetPlayers() 332 | // .Where(u => u.AuthorizedSteamID != null && u.PlayerPawn.Value != null)) 333 | // { 334 | // Server.NextFrame(() => LoadAdminUserAsync(players.AuthorizedSteamID, players.Slot)); 335 | // } 336 | // 337 | // const string msg = "The list of administrators has been successfully reloaded"; 338 | // 339 | // ReplyToCommand(controller, msg); 340 | // } 341 | // 342 | // [CommandHelper(1, "")] 343 | // [ConsoleCommand("css_reload_infractions")] 344 | // public void OnCmdReloadInfractions(CCSPlayerController? controller, CommandInfo command) 345 | // { 346 | // if (controller == null) return; 347 | // var target = GetPlayerFromSteamId(command.GetArg(1)); 348 | // 349 | // if (target == null) return; 350 | // 351 | // Server.NextFrame(() => LoadAdminUserAsync(target.AuthorizedSteamID, target.Slot)); 352 | // 353 | // const string msg = "The list of administrators has been successfully reloaded"; 354 | // 355 | // ReplyToCommand(controller, msg); 356 | // } 357 | 358 | [CommandHelper(1, "<#userid or username> [-k]", CommandUsage.CLIENT_ONLY)] 359 | [ConsoleCommand("css_team")] 360 | public void OnCmdChangeTeam(CCSPlayerController? controller, CommandInfo command) 361 | { 362 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Kick)) return; 363 | 364 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 365 | 366 | if (target == null) 367 | { 368 | ReplyToCommand(controller, "Player not found"); 369 | return; 370 | } 371 | 372 | if (command.ArgCount >= 3) 373 | { 374 | var team = GetTeam(command.GetArg(2)); 375 | 376 | if (command.ArgCount is 4) 377 | target.ChangeTeam(team); 378 | else 379 | target.SwitchTeam(team); 380 | 381 | PrintToChatAll($"An administrator has moved a player {target.PlayerName} to another team"); 382 | } 383 | } 384 | 385 | private CsTeam GetTeam(string name) 386 | { 387 | return name switch 388 | { 389 | "ct" => CsTeam.CounterTerrorist, 390 | "t" => CsTeam.Terrorist, 391 | "tt" => CsTeam.Terrorist, 392 | "none" => CsTeam.None, 393 | _ => CsTeam.Spectator 394 | }; 395 | } 396 | 397 | [CommandHelper(1, "", CommandUsage.CLIENT_ONLY)] 398 | [ConsoleCommand("css_say")] 399 | public void OnCmdSay(CCSPlayerController? controller, CommandInfo command) 400 | { 401 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Chat)) return; 402 | 403 | PrintToChatAll($"{ChatColors.Blue}Admin\x01: {command.ArgString}"); 404 | } 405 | 406 | [CommandHelper(1, "<#userid or username> ", CommandUsage.CLIENT_ONLY)] 407 | [ConsoleCommand("css_psay")] 408 | public void OnCmdPSay(CCSPlayerController? controller, CommandInfo command) 409 | { 410 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Chat)) return; 411 | 412 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 413 | 414 | if (target == null) 415 | { 416 | ReplyToCommand(controller, "Player not found"); 417 | return; 418 | } 419 | 420 | PrintToChat(target, 421 | $"Private message from - {ChatColors.Blue}{(controller == null ? _config.BanFromConsoleName : controller.PlayerName)}\x01: {command.ArgString}"); 422 | ReplyToCommand(controller, 423 | $"Private message from - {ChatColors.Blue}{(controller == null ? _config.BanFromConsoleName : controller.PlayerName)}\x01: {command.ArgString}"); 424 | } 425 | 426 | 427 | [CommandHelper(1, "", CommandUsage.CLIENT_ONLY)] 428 | [ConsoleCommand("css_csay")] 429 | public void OnCmdCSay(CCSPlayerController? controller, CommandInfo command) 430 | { 431 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Chat)) return; 432 | 433 | PrintToCenterAll($"{command.ArgString}"); 434 | } 435 | 436 | [CommandHelper(usage: "[#userid or name]", whoCanExecute: CommandUsage.CLIENT_ONLY)] 437 | [ConsoleCommand("css_god")] 438 | public void OnCmdGod(CCSPlayerController? controller, CommandInfo command) 439 | { 440 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Cheats)) return; 441 | 442 | if (command.ArgCount >= 2) 443 | { 444 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 445 | 446 | if (target == null) 447 | { 448 | ReplyToCommand(controller, "Player not found"); 449 | return; 450 | } 451 | 452 | var targetPawn = target.PlayerPawn.Value; 453 | if (targetPawn == null) return; 454 | 455 | targetPawn.TakesDamage ^= true; 456 | PrintToChat(target, "The administrator has given you immortality"); 457 | } 458 | else 459 | { 460 | var playerPawn = controller.PlayerPawn.Value; 461 | if (playerPawn == null) return; 462 | playerPawn.TakesDamage ^= true; 463 | PrintToChat(controller, "You've established immortality"); 464 | } 465 | } 466 | 467 | [CommandHelper(2, " ")] 468 | [ConsoleCommand("css_cvar")] 469 | public void OnCmdCvar(CCSPlayerController? controller, CommandInfo command) 470 | { 471 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Cvar)) return; 472 | 473 | var cvar = command.GetArg(1); 474 | var value = command.GetArg(2); 475 | 476 | var conVar = ConVar.Find(cvar); 477 | 478 | if (conVar == null) 479 | { 480 | ReplyToCommand(controller, $"ConVar: {cvar} not found"); 481 | return; 482 | } 483 | 484 | conVar.SetValue(value); 485 | } 486 | 487 | [CommandHelper(1, "", CommandUsage.CLIENT_ONLY)] 488 | [ConsoleCommand("css_rcon")] 489 | public void OnCmdRcon(CCSPlayerController? controller, CommandInfo command) 490 | { 491 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Rcon)) return; 492 | 493 | Server.ExecuteCommand(command.ArgString); 494 | } 495 | 496 | [CommandHelper(1, "<#userid or username> [damage]", CommandUsage.CLIENT_ONLY)] 497 | [ConsoleCommand("css_slap")] 498 | public void OnCmdSlap(CCSPlayerController? controller, CommandInfo command) 499 | { 500 | if (controller == null || !CheckingForAdminAndFlag(controller, AdminFlag.Slay)) return; 501 | 502 | var player = GetPlayerFromUserIdOrName(command.GetArg(1)); 503 | 504 | var damage = 0; 505 | if (command.ArgCount >= 3) 506 | damage = int.Parse(command.GetArg(2)); 507 | 508 | if (!IsPlayerValid(controller, player, true)) return; 509 | 510 | if (player != null) 511 | { 512 | var playerPawn = player.PlayerPawn.Value; 513 | 514 | if (playerPawn == null) return; 515 | 516 | playerPawn.AbsVelocity.X += Random.Shared.Next(100, 200); 517 | playerPawn.AbsVelocity.Y += Random.Shared.Next(100, 200); 518 | playerPawn.AbsVelocity.Z += Random.Shared.Next(200, 300); 519 | playerPawn.Health -= damage; 520 | 521 | var random = Random.Shared.Next(3); 522 | 523 | player.ExecuteClientCommand($"play {GetMusicChoice(random)}"); 524 | 525 | if (playerPawn.Health <= 0) playerPawn.CommitSuicide(true, true); 526 | } 527 | } 528 | 529 | private string GetMusicChoice(int randomNumber) 530 | { 531 | return randomNumber switch 532 | { 533 | 0 => "sounds/player/damage1.vsnd", 534 | 1 => "sounds/player/damage2.vsnd", 535 | 2 => "sounds/player/damage3.vsnd", 536 | _ => string.Empty 537 | }; 538 | } 539 | 540 | [ConsoleCommand("css_who")] 541 | public void OnCmdWho(CCSPlayerController? controller, CommandInfo command) 542 | { 543 | if (controller != null) 544 | if (!IsAdmin(controller.Index)) 545 | { 546 | PrintToChat(controller, "you do not have access to this command"); 547 | return; 548 | } 549 | 550 | var maxNameLength = 0; 551 | 552 | var id = 0; 553 | foreach (var client in Utilities.GetPlayers() 554 | .Where(u => u.PlayerPawn.Value != null && u.PlayerPawn.Value.IsValid)) 555 | { 556 | var playerName = !string.IsNullOrWhiteSpace(client.PlayerName) ? client.PlayerName : "unknown"; 557 | var playerNameLength = playerName.Length; 558 | maxNameLength = Math.Max(maxNameLength, playerNameLength); 559 | 560 | var adminStatus = IsAdmin(client.Index) ? "admin " : "player"; 561 | 562 | var index = client.Index; 563 | var playTime = DateTime.Now - _playerPlayTime[index]; 564 | 565 | id ++; 566 | var formattedOutput = 567 | $"{id,-1} - {playerName,-15} || UserId: {client.UserId,-2} || {adminStatus,-6} || Playtime: {playTime.Hours:D2}:{playTime.Minutes:D2}:{playTime.Seconds:D2} | {(client.AuthorizedSteamID == null ? "none" : client.AuthorizedSteamID)}"; 568 | 569 | if (controller == null) 570 | { 571 | Console.ForegroundColor = Random.Shared.Next(2) == 1 ? ConsoleColor.Cyan : ConsoleColor.DarkMagenta; 572 | Console.WriteLine(formattedOutput); 573 | Console.ResetColor(); 574 | } 575 | else 576 | PrintToConsole(controller, formattedOutput); 577 | 578 | // PrintLogInfo("{id} - {playerName} | {adminStatus} | Playtime: {playTime} | {SteamID}", 579 | // $"{id,-1}", $"{playerName,-15}", $"{adminStatus,-6}", 580 | // $"{playTime.Hours:D2}:{playTime.Minutes:D2}:{playTime.Seconds:D2}", $"{new SteamID(client.SteamID)}"); 581 | } 582 | } 583 | 584 | [CommandHelper(1, "")] 585 | [ConsoleCommand("css_map", "change map")] 586 | public void OnCmdChangeMap(CCSPlayerController? controller, CommandInfo command) 587 | { 588 | if (controller == null) return; 589 | 590 | var cmdArg = command.ArgString; 591 | 592 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Changemap)) return; 593 | 594 | foreach (var t in GetMapFromMaps()) 595 | { 596 | var isWorkshopMap = t.Trim().StartsWith("ws:", StringComparison.OrdinalIgnoreCase); 597 | 598 | if (!t.Trim().Contains(cmdArg.Trim(), StringComparison.OrdinalIgnoreCase)) continue; 599 | 600 | var map = t.StartsWith("ws:") ? t.Split("ws:")[1] : t; 601 | PrintToChatAll($"{controller.PlayerName}: changing the map to {map}"); 602 | AddTimer(3.0f, () => ChangeMap(map, isWorkshopMap)); 603 | return; 604 | } 605 | 606 | PrintToChat(controller, "This map doesn't exist"); 607 | } 608 | 609 | [CommandHelper(1, "<#userid or username>")] 610 | [ConsoleCommand("css_slay", "kill a player")] 611 | public void OnCmdSlay(CCSPlayerController? controller, CommandInfo command) 612 | { 613 | var cmdArg = command.ArgString; 614 | 615 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Slay)) return; 616 | 617 | ExtractValueInQuotes(cmdArg); 618 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 619 | 620 | if (!IsPlayerValid(controller, target, true)) return; 621 | 622 | if (target.PlayerPawn.Value != null) target.PlayerPawn.Value.CommitSuicide(true, true); 623 | 624 | if (controller == null) 625 | PrintToChatAll($"Console: Player '{target.PlayerName}' has been killed"); 626 | 627 | ReplyToCommand(controller, 628 | $"{(controller != null ? controller.PlayerName : _config.BanFromConsoleName)}: Player '{target.PlayerName}' has been killed"); 629 | } 630 | 631 | [CommandHelper(1, "<#userid or username>")] 632 | [ConsoleCommand("css_kick", "Kick a player")] 633 | public void OnCmdKick(CCSPlayerController? controller, CommandInfo command) 634 | { 635 | var cmdArg = command.ArgString; 636 | 637 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Kick)) return; 638 | 639 | var target = GetPlayerFromUserIdOrName(ExtractValueInQuotes(cmdArg)); 640 | 641 | if (!IsPlayerValid(controller, target)) return; 642 | 643 | if (controller != null) 644 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 645 | { 646 | ReplyToCommand(controller, "You can't ban this player"); 647 | return; 648 | } 649 | 650 | target.Kick("Test"); 651 | 652 | var msg = 653 | $"{(controller != null ? controller.PlayerName : _config.BanFromConsoleName)}: Player '{target.PlayerName}' kicked by admin"; 654 | ReplyToCommand(controller, msg); 655 | } 656 | 657 | [CommandHelper(2, "<#userid or username> [reason]")] 658 | [ConsoleCommand("css_ban", "ban")] 659 | public void OnCmdBan(CCSPlayerController? controller, CommandInfo command) 660 | { 661 | var cmdArg = command.ArgString; 662 | 663 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Ban)) return; 664 | 665 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 666 | 667 | if (!IsPlayerValid(controller, target)) return; 668 | 669 | if (controller != null) 670 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 671 | { 672 | ReplyToCommand(controller, "You can't ban this player"); 673 | return; 674 | } 675 | 676 | var endBanTime = Convert.ToInt32(command.GetArg(2)); 677 | 678 | var startBanTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 679 | var endBanTimeUnix = DateTime.UtcNow.AddSeconds(endBanTime).GetUnixEpoch(); 680 | 681 | var reason = "none"; 682 | if (command.ArgCount > 3) 683 | reason = command.GetArg(3); 684 | 685 | Server.NextFrame(() => 686 | { 687 | var msg = Database.AddBan(new User 688 | { 689 | admin_username = controller != null ? controller.PlayerName : _config.BanFromConsoleName, 690 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 691 | username = target.PlayerName, 692 | steamid64 = target.SteamID, 693 | steamid = new SteamID(target.SteamID).SteamId2, 694 | reason = reason, 695 | unban_reason = "", 696 | admin_unlocked_username = "", 697 | admin_unlocked_steamid = "", 698 | start_ban_time = startBanTimeUnix, 699 | end_ban_time = endBanTime == 0 ? 0 : endBanTimeUnix, 700 | ban_active = true 701 | }).Result; 702 | //KickClient($"{target.UserId}"); 703 | target.Kick("Ban"); 704 | 705 | ReplyToCommand(controller, msg); 706 | }); 707 | } 708 | 709 | [CommandHelper(2, "<#userid or username> [reason]")] 710 | [ConsoleCommand("css_mute", "mute")] 711 | public void OnCmdMute(CCSPlayerController? controller, CommandInfo command) 712 | { 713 | var cmdArg = command.ArgString; 714 | 715 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Generic)) return; 716 | 717 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 718 | 719 | if (!IsPlayerValid(controller, target)) return; 720 | 721 | if (controller != null) 722 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 723 | { 724 | ReplyToCommand(controller, "You can't ban this player"); 725 | return; 726 | } 727 | 728 | var endMuteTime = Convert.ToInt32(command.GetArg(2)); 729 | 730 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 731 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(endMuteTime).GetUnixEpoch(); 732 | 733 | if (target.VoiceFlags.HasFlag(VoiceFlags.Muted)) 734 | { 735 | ReplyToCommand(controller, $"Player \x02'{target.PlayerName}'\x01 has already had his microphone cut off"); 736 | return; 737 | } 738 | 739 | var reason = "none"; 740 | if (command.ArgCount > 3) 741 | reason = command.GetArg(3); 742 | 743 | Server.NextFrame(() => 744 | { 745 | Database.AddMute(new MuteUser 746 | { 747 | mute_type = (int)MuteType.Micro, 748 | admin_username = controller != null ? controller.PlayerName : _config.BanFromConsoleName, 749 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 750 | username = target.PlayerName, 751 | steamid64 = target.SteamID, 752 | steamid = new SteamID(target.SteamID).SteamId2, 753 | reason = reason, 754 | unmute_reason = "", 755 | admin_unlocked_username = "", 756 | admin_unlocked_steamid = "", 757 | start_mute_time = startMuteTimeUnix, 758 | end_mute_time = endMuteTime == 0 ? 0 : endMuteTimeUnix, 759 | mute_active = true 760 | }, controller == null ? null : controller); 761 | }); 762 | target.VoiceFlags = VoiceFlags.Muted; 763 | 764 | UpdateUserMuteLocal(target, endMuteTime, endMuteTimeUnix, (int)MuteType.Micro); 765 | } 766 | 767 | [CommandHelper(1, " [reason]")] 768 | [ConsoleCommand("css_unmute", "unmute")] 769 | public void OnCmdUnmute(CCSPlayerController? controller, CommandInfo command) 770 | { 771 | var cmdArg = command.ArgString; 772 | 773 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 774 | 775 | var arg1 = command.GetArg(1); 776 | var steamId = arg1; 777 | CCSPlayerController? player = null; 778 | 779 | if (arg1.StartsWith('#')) 780 | { 781 | player = GetPlayerFromUserIdOrName(arg1); 782 | } 783 | 784 | var reason = "none"; 785 | if (command.ArgCount > 2) 786 | reason = command.GetArg(2); 787 | 788 | Server.NextFrame(() => 789 | { 790 | var msg = Database.UnmuteUser((int)MuteType.Micro, 791 | controller != null ? controller.PlayerName : _config.BanFromConsoleName, 792 | controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 793 | player == null ? steamId : new SteamID(player.SteamID).SteamId2, reason).Result; 794 | 795 | ReplyToCommand(controller, msg); 796 | }); 797 | 798 | //var player = Utilities.GetPlayers().FirstOrDefault(u => new SteamID(u.SteamID).SteamId2 == steamId); 799 | if (player != null) 800 | { 801 | UpdateUserMuteLocal(player, isAdded: false); 802 | player.VoiceFlags = VoiceFlags.Normal; 803 | } 804 | } 805 | 806 | [CommandHelper(2, "<#userid or username> [reason]")] 807 | [ConsoleCommand("css_gag", "mute")] 808 | public void OnCmdGag(CCSPlayerController? controller, CommandInfo command) 809 | { 810 | var cmdArg = command.ArgString; 811 | 812 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Generic)) return; 813 | 814 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 815 | 816 | if (!IsPlayerValid(controller, target)) return; 817 | 818 | if (target == null) 819 | { 820 | ReplyToCommand(controller, "Player not found"); 821 | return; 822 | } 823 | 824 | if (controller != null) 825 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 826 | { 827 | ReplyToCommand(controller, "You can't ban this player"); 828 | return; 829 | } 830 | 831 | var endMuteTime = Convert.ToInt32(command.GetArg(2)); 832 | 833 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 834 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(endMuteTime).GetUnixEpoch(); 835 | 836 | var reason = "none"; 837 | if (command.ArgCount > 3) 838 | reason = command.GetArg(3); 839 | 840 | Server.NextFrame(() => 841 | { 842 | Database.AddMute(new MuteUser 843 | { 844 | mute_type = (int)MuteType.Chat, 845 | admin_username = controller != null ? controller.PlayerName : _config.BanFromConsoleName, 846 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 847 | username = target.PlayerName, 848 | steamid64 = target.SteamID, 849 | steamid = new SteamID(target.SteamID).SteamId2, 850 | reason = reason, 851 | unmute_reason = "", 852 | admin_unlocked_username = "", 853 | admin_unlocked_steamid = "", 854 | start_mute_time = startMuteTimeUnix, 855 | end_mute_time = endMuteTime == 0 ? 0 : endMuteTimeUnix, 856 | mute_active = true 857 | }, controller == null ? null : controller); 858 | }); 859 | 860 | UpdateUserMuteLocal(target, endMuteTime, endMuteTimeUnix, (int)MuteType.Chat); 861 | } 862 | 863 | [CommandHelper(1, " [reason]")] 864 | [ConsoleCommand("css_ungag", "ungag")] 865 | public void OnCmdUngag(CCSPlayerController? controller, CommandInfo command) 866 | { 867 | var cmdArg = command.ArgString; 868 | 869 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 870 | 871 | var arg1 = command.GetArg(1); 872 | var steamId = arg1; 873 | CCSPlayerController? player = null; 874 | 875 | if (arg1.StartsWith('#')) 876 | { 877 | player = GetPlayerFromUserIdOrName(arg1); 878 | } 879 | 880 | var reason = "none"; 881 | if (command.ArgCount > 2) 882 | reason = command.GetArg(2); 883 | 884 | Server.NextFrame(() => 885 | { 886 | var msg = Database.UnmuteUser((int)MuteType.Chat, 887 | controller != null ? controller.PlayerName : _config.BanFromConsoleName, 888 | controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 889 | player == null ? steamId : new SteamID(player.SteamID).SteamId2, reason).Result; 890 | 891 | ReplyToCommand(controller, msg); 892 | }); 893 | 894 | if (player != null) 895 | UpdateUserMuteLocal(player, isAdded: false); 896 | } 897 | 898 | public void UpdateUserMuteLocal(CCSPlayerController? player = null, int endTime = -1, int endTimeUnix = -1, 899 | int type = -1, 900 | bool isAdded = true) 901 | { 902 | if (player != null) 903 | { 904 | var entityIndex = player.Index; 905 | var user = _muteUsers[entityIndex]; 906 | 907 | if (isAdded) 908 | { 909 | _muteUsers[entityIndex] = new MuteUserLocal 910 | { 911 | MuteType = user == null ? type : (int)MuteType.All, 912 | SteamId = new SteamID(player.SteamID).SteamId2, 913 | EndMuteTime = endTime == 0 ? 0 : endTimeUnix, 914 | MuteActive = true 915 | }; 916 | } 917 | else _muteUsers[entityIndex] = null; 918 | } 919 | } 920 | 921 | [CommandHelper(1, " [username] [immunity] [flags] [time_seconds]\nif you don't want to update something, don't leave it blank, write `-` or `-s`\nExample of updating flags: css_updateadmin \"STEAM_0:0:123456\" -s -s bcd -s", CommandUsage.SERVER_ONLY)] 922 | [ConsoleCommand("css_updateadmin")] 923 | public void OnCmdUpdateAdmin(CCSPlayerController? controller, CommandInfo command) 924 | { 925 | Database.UpdateAdmin(new Admins 926 | { 927 | username = command.GetArg(2), 928 | steamid = command.GetArg(1), 929 | start_time = -1, 930 | end_time = int.TryParse(command.GetArg(5), out var time) ? time : -1, 931 | immunity = int.TryParse(command.GetArg(3), out var i) ? i : -1, 932 | flags = command.GetArg(4) 933 | }); 934 | } 935 | 936 | [CommandHelper(5, " ", CommandUsage.SERVER_ONLY)] 937 | [ConsoleCommand("css_addadmin")] 938 | public void OnCmdAddAdmin(CCSPlayerController? controller, CommandInfo command) 939 | { 940 | var username = command.GetArg(1); 941 | var steamId = command.GetArg(2); 942 | var immunity = command.GetArg(3); 943 | var flags = command.GetArg(4); 944 | 945 | var time = int.TryParse(command.GetArg(5), out var endTime) ? endTime : 3600; 946 | var startTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 947 | var endTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 948 | 949 | Server.NextFrame(() => 950 | { 951 | Database.AddAdmin(new Admins 952 | { 953 | username = username, 954 | steamid = steamId, 955 | start_time = startTimeUnix, 956 | end_time = time == 0 ? 0 : endTimeUnix, 957 | immunity = int.TryParse(immunity, out var i) ? i : 10, 958 | flags = flags 959 | }, controller); 960 | }); 961 | } 962 | 963 | [CommandHelper(1, " [reason]")] 964 | [ConsoleCommand("css_unban", "unban")] 965 | public void OnCmdUnban(CCSPlayerController? controller, CommandInfo command) 966 | { 967 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 968 | 969 | var steamId = command.GetArg(1); 970 | 971 | var reason = "none"; 972 | if (command.ArgCount > 2) 973 | reason = command.GetArg(2); 974 | 975 | Server.NextFrame(() => 976 | { 977 | var msg = Database.UnbanUser( 978 | controller != null ? controller.PlayerName : _config.BanFromConsoleName, 979 | controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 980 | steamId, reason).Result; 981 | 982 | ReplyToCommand(controller, msg); 983 | }); 984 | } 985 | 986 | [CommandHelper(1, "", CommandUsage.SERVER_ONLY)] 987 | [ConsoleCommand("css_deleteadmin", "delete admin")] 988 | public void OnCmdDeleteAdmin(CCSPlayerController? controller, CommandInfo command) 989 | { 990 | if (controller != null) return; 991 | 992 | var cmdArg = command.ArgString; 993 | 994 | var steamId = ExtractValueInQuotes(cmdArg); 995 | 996 | Task.Run(() => Database.DeleteAdminAsync(steamId)); 997 | } 998 | 999 | [CommandHelper(2, "<#userid or username> [reason]")] 1000 | [ConsoleCommand("css_silence")] 1001 | public void OnCmdSilence(CCSPlayerController? controller, CommandInfo command) 1002 | { 1003 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Generic)) return; 1004 | 1005 | var target = GetPlayerFromUserIdOrName(command.GetArg(1)); 1006 | 1007 | if (!IsPlayerValid(controller, target)) return; 1008 | 1009 | if (controller != null) 1010 | if (IsAdmin(target.Index) && !PlayerImmunityComparison(controller, target)) 1011 | { 1012 | ReplyToCommand(controller, "You can't ban this player"); 1013 | return; 1014 | } 1015 | 1016 | var endMuteTime = Convert.ToInt32(command.GetArg(2)); 1017 | 1018 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 1019 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(endMuteTime).GetUnixEpoch(); 1020 | 1021 | if (target.VoiceFlags.HasFlag(VoiceFlags.All)) 1022 | { 1023 | ReplyToCommand(controller, $"Player \x02'{target.PlayerName}'\x01 has already had all chat disabled"); 1024 | return; 1025 | } 1026 | 1027 | var reason = "none"; 1028 | if (command.ArgCount > 3) 1029 | reason = command.GetArg(3); 1030 | 1031 | Server.NextFrame(() => 1032 | { 1033 | Database.AddMute(new MuteUser 1034 | { 1035 | mute_type = (int)MuteType.All, 1036 | admin_username = controller != null ? controller.PlayerName : _config.BanFromConsoleName, 1037 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 1038 | username = target.PlayerName, 1039 | steamid64 = target.SteamID, 1040 | steamid = new SteamID(target.SteamID).SteamId2, 1041 | reason = reason, 1042 | unmute_reason = "", 1043 | admin_unlocked_username = "", 1044 | admin_unlocked_steamid = "", 1045 | start_mute_time = startMuteTimeUnix, 1046 | end_mute_time = endMuteTime == 0 ? 0 : endMuteTimeUnix, 1047 | mute_active = true 1048 | }, controller); 1049 | }); 1050 | target.VoiceFlags = VoiceFlags.Muted; 1051 | 1052 | UpdateUserMuteLocal(target, endMuteTime, endMuteTimeUnix, (int)MuteType.All); 1053 | } 1054 | 1055 | [CommandHelper(1, "<#userid or steamid> [reason]")] 1056 | [ConsoleCommand("css_unsilence", "unmute")] 1057 | public void OnCmdUnSilence(CCSPlayerController? controller, CommandInfo command) 1058 | { 1059 | if (!CheckingForAdminAndFlag(controller, AdminFlag.Unban)) return; 1060 | 1061 | var arg1 = command.GetArg(1); 1062 | var steamId = arg1; 1063 | CCSPlayerController? player = null; 1064 | 1065 | if (arg1.StartsWith('#')) 1066 | { 1067 | player = GetPlayerFromUserIdOrName(arg1); 1068 | } 1069 | 1070 | var reason = "none"; 1071 | if (command.ArgCount > 2) 1072 | reason = command.GetArg(2); 1073 | 1074 | Server.NextFrame(() => 1075 | { 1076 | var msg = Database.UnmuteUser((int)MuteType.All, 1077 | controller != null ? controller.PlayerName : _config.BanFromConsoleName, 1078 | controller != null ? new SteamID(controller.SteamID).SteamId2 : _config.BanFromConsoleName, 1079 | player == null ? steamId : new SteamID(player.SteamID).SteamId2, reason).Result; 1080 | 1081 | ReplyToCommand(controller, msg); 1082 | }); 1083 | 1084 | //var player = Utilities.GetPlayers().FirstOrDefault(u => new SteamID(u.SteamID).SteamId2 == steamId); 1085 | if (player != null) 1086 | { 1087 | UpdateUserMuteLocal(player, isAdded: false); 1088 | player.VoiceFlags = VoiceFlags.Normal; 1089 | } 1090 | } 1091 | 1092 | private CCSPlayerController? GetPlayerFromUserIdOrName(string player) 1093 | { 1094 | if (player.StartsWith('#') && int.TryParse(player.Trim('#'), out var index)) 1095 | return Utilities.GetPlayerFromUserid(index); 1096 | 1097 | return Utilities.GetPlayers().FirstOrDefault(u => u.PlayerName.Contains(player)); 1098 | } 1099 | 1100 | public bool CheckingForAdminAndFlag(CCSPlayerController? controller, AdminFlag flag) 1101 | { 1102 | if (controller == null) return true; 1103 | var entityIndex = controller.Index; 1104 | 1105 | if (IsAdmin(entityIndex) && HasLetterInUserFlags(entityIndex, (char)flag)) return true; 1106 | 1107 | PrintToChat(controller, "you do not have access to this command"); 1108 | return false; 1109 | } 1110 | 1111 | private string GetTextInsideQuotes(string input) 1112 | { 1113 | var startIndex = input.IndexOf('"'); 1114 | var endIndex = input.LastIndexOf('"'); 1115 | 1116 | if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) 1117 | { 1118 | return input.Substring(startIndex + 1, endIndex - startIndex - 1); 1119 | } 1120 | 1121 | return string.Empty; 1122 | } 1123 | 1124 | private string[] ParseCommandArguments(string argString) 1125 | { 1126 | var parse = Regex.Matches(argString, @"[\""].+?[\""]|[^ ]+") 1127 | .Select(m => m.Value.Trim('"')) 1128 | .ToArray(); 1129 | 1130 | return parse; 1131 | } 1132 | 1133 | private bool IsPlayerValid(CCSPlayerController? player, CCSPlayerController? target, bool isKickOrSlap = false) 1134 | { 1135 | if (target == null || !target.IsValid) 1136 | { 1137 | ReplyToCommand(player, "Player not found"); 1138 | return false; 1139 | } 1140 | 1141 | if (isKickOrSlap) 1142 | { 1143 | if (!target.PawnIsAlive) 1144 | { 1145 | ReplyToCommand(player, "The player is invalid"); 1146 | return false; 1147 | } 1148 | } 1149 | 1150 | return true; 1151 | } 1152 | 1153 | private string BuildConnectionString() 1154 | { 1155 | var dbConfig = _config.Connection; 1156 | 1157 | Console.WriteLine("Building connection string"); 1158 | var builder = new MySqlConnectionStringBuilder 1159 | { 1160 | Database = dbConfig.Database, 1161 | UserID = dbConfig.User, 1162 | Password = dbConfig.Password, 1163 | Server = dbConfig.Host, 1164 | Port = (uint)dbConfig.Port, 1165 | }; 1166 | 1167 | Console.WriteLine("OK!"); 1168 | return builder.ConnectionString; 1169 | } 1170 | 1171 | private static CCSPlayerController? GetPlayerFromSteamId(string steamId) 1172 | { 1173 | return Utilities.GetPlayers().FirstOrDefault(u => 1174 | u.AuthorizedSteamID != null && 1175 | (u.AuthorizedSteamID.SteamId2.ToString().Equals(steamId, StringComparison.OrdinalIgnoreCase) || 1176 | u.AuthorizedSteamID.SteamId64.ToString().Equals(steamId, StringComparison.OrdinalIgnoreCase))); 1177 | } 1178 | 1179 | private Config LoadConfig() 1180 | { 1181 | var configPath = Path.Combine(ModuleDirectory, "database.json"); 1182 | if (!File.Exists(configPath)) return CreateConfig(configPath); 1183 | 1184 | var config = JsonSerializer.Deserialize(File.ReadAllText(configPath))!; 1185 | 1186 | return config; 1187 | } 1188 | 1189 | private Config CreateConfig(string configPath) 1190 | { 1191 | var config = new Config 1192 | { 1193 | BanFromConsoleName = "Console", 1194 | Connection = new BaseAdminDb 1195 | { 1196 | Host = "", 1197 | Database = "", 1198 | User = "", 1199 | Password = "", 1200 | Port = 3306 1201 | } 1202 | }; 1203 | 1204 | var mapsConfig = Path.Combine(ModuleDirectory, "maps.txt"); 1205 | if (!File.Exists(mapsConfig)) 1206 | File.WriteAllLines(mapsConfig, new[] { "de_dust2", "ws:awp_lego_2" }); 1207 | 1208 | File.WriteAllText(configPath, 1209 | JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true })); 1210 | return config; 1211 | } 1212 | 1213 | public IEnumerable ReadAllBanReasons() 1214 | { 1215 | var path = Path.Combine(ModuleDirectory, "admin/ban_reasons.txt"); 1216 | 1217 | if (!File.Exists(path)) 1218 | File.WriteAllLines(path, new[] { "Aim", "Wallhack", "Violation" }); 1219 | 1220 | return File.ReadAllLines(path); 1221 | } 1222 | 1223 | public IEnumerable ReadAllMuteReasons() 1224 | { 1225 | var path = Path.Combine(ModuleDirectory, "admin/mute_reasons.txt"); 1226 | 1227 | if (!File.Exists(path)) 1228 | File.WriteAllLines(path, new[] { "Spam Mic/Chat", "Inappropriate behavior", "16+" }); 1229 | 1230 | return File.ReadAllLines(path); 1231 | } 1232 | 1233 | public IEnumerable ReadAllTime() 1234 | { 1235 | var path = Path.Combine(ModuleDirectory, "admin/times.txt"); 1236 | 1237 | if (!File.Exists(path)) 1238 | File.WriteAllLines(path, new[] { "permanently:0", "1 hours:3600", "1 day:86400", "1 week:604800" }); 1239 | 1240 | return File.ReadAllLines(path); 1241 | } 1242 | 1243 | public string[] GetMapFromMaps() 1244 | { 1245 | var mapText = File.ReadAllText(Path.Combine(ModuleDirectory, "maps.txt")); 1246 | var mapList = mapText.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) 1247 | .Select(s => s.Trim()).ToArray(); 1248 | 1249 | return mapList; 1250 | } 1251 | 1252 | public IEnumerable ReadAllImmunity() 1253 | { 1254 | var path = Path.Combine(ModuleDirectory, "admin/immunity.txt"); 1255 | 1256 | if (!File.Exists(path)) 1257 | File.WriteAllLines(path, new[] { "1", "10", "20", "30" }); 1258 | 1259 | return File.ReadAllLines(path); 1260 | } 1261 | 1262 | public bool HasLetterInUserFlags(uint index, char letter) 1263 | { 1264 | if (_adminUsers[index] == null) return false; 1265 | 1266 | var adminUser = _adminUsers[index]!.flags; 1267 | 1268 | if (adminUser.Contains((char)AdminFlag.Root)) return true; 1269 | 1270 | return !string.IsNullOrEmpty(adminUser) && adminUser.Contains(letter); 1271 | } 1272 | 1273 | private bool PlayerImmunityComparison(CCSPlayerController player, CCSPlayerController target) 1274 | { 1275 | if (_adminUsers[target.Index] == null) return false; 1276 | 1277 | return _adminUsers[player.Index]!.immunity >= _adminUsers[target.Index]!.immunity; 1278 | } 1279 | 1280 | public bool IsAdmin(uint index) 1281 | { 1282 | var user = _adminUsers[index]; 1283 | if (user == null) return false; 1284 | 1285 | if (user.end_time != 0 && DateTime.UtcNow.GetUnixEpoch() > user.end_time) return false; 1286 | 1287 | return user.end_time == 0 || DateTime.UtcNow.GetUnixEpoch() < user.end_time; 1288 | } 1289 | 1290 | private bool IsUserMute(uint index) 1291 | { 1292 | var user = _muteUsers[index]; 1293 | if (user == null) return false; 1294 | 1295 | if (DateTime.UtcNow.GetUnixEpoch() > user.EndMuteTime) return false; 1296 | 1297 | return user.EndMuteTime == 0 || DateTime.UtcNow.GetUnixEpoch() < user.EndMuteTime; 1298 | } 1299 | 1300 | public string ExtractValueInQuotes(string input) 1301 | { 1302 | var match = Regex.Match(input, @"""([^""]*)"""); 1303 | 1304 | return match.Success ? match.Groups[1].Value : input; 1305 | } 1306 | 1307 | public void ReplyToCommand(CCSPlayerController? controller, string message, params object?[] args) 1308 | { 1309 | if (controller != null) 1310 | PrintToChat(controller, message); 1311 | else 1312 | PrintLogInfo(message, args); 1313 | } 1314 | 1315 | public void ChangeMap(string mapName, bool isWorkshop = false) 1316 | { 1317 | Server.ExecuteCommand($"{(isWorkshop ? "ds_workshop_changelevel" : "map")} {mapName}"); 1318 | } 1319 | 1320 | public void PrintToChat(CCSPlayerController controller, string msg) 1321 | { 1322 | controller.PrintToChat($"[ {ChatColors.Blue}Admin \x01] {msg}"); 1323 | } 1324 | 1325 | public void PrintToCenterAll(string msg) 1326 | { 1327 | VirtualFunctions.ClientPrintAll(HudDestination.Center, $"Admin: {msg}", 0, 0, 0, 0); 1328 | } 1329 | 1330 | public void PrintToChatAll(string msg) 1331 | { 1332 | Server.PrintToChatAll($"[ {ChatColors.Blue}Admin \x01] {msg}"); 1333 | } 1334 | 1335 | private void PrintToConsole(CCSPlayerController client, string msg) 1336 | { 1337 | VirtualFunctions.ClientPrint(client.Handle, HudDestination.Console, msg, 0, 0, 0, 0); 1338 | } 1339 | 1340 | public void PrintLogInfo(string? message, params object?[] args) 1341 | { 1342 | Logger.LogInformation($"{message}", args); 1343 | } 1344 | 1345 | public void PrintLogError(string? message, params object?[] args) 1346 | { 1347 | Logger.LogError($"{message}", args); 1348 | } 1349 | } 1350 | 1351 | public class Config 1352 | { 1353 | public string BanFromConsoleName { get; init; } = "Console"; 1354 | public BaseAdminDb Connection { get; init; } = null!; 1355 | } 1356 | 1357 | public class BaseAdminDb 1358 | { 1359 | public required string Host { get; init; } 1360 | public required string Database { get; init; } 1361 | public required string User { get; init; } 1362 | public required string Password { get; init; } 1363 | public int Port { get; init; } 1364 | } 1365 | 1366 | public class AdminData 1367 | { 1368 | public ulong SteamId { get; set; } 1369 | public bool TagEnabled { get; set; } 1370 | } -------------------------------------------------------------------------------- /MiniAdmin/BaseAdmin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | AnyCPU;x86 6 | true 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ..\CounterStrikeSharp.API.dll 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /MiniAdmin/Database.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using CounterStrikeSharp.API; 5 | using CounterStrikeSharp.API.Core; 6 | using CounterStrikeSharp.API.Modules.Entities; 7 | using Dapper; 8 | using MySqlConnector; 9 | 10 | namespace BaseAdmin; 11 | 12 | public class Database 13 | { 14 | private readonly string _dbConnectionString; 15 | private readonly BaseAdmin _baseAdmin; 16 | 17 | public Database(BaseAdmin baseAdmin, string dbConnectionString) 18 | { 19 | _baseAdmin = baseAdmin; 20 | _dbConnectionString = dbConnectionString; 21 | } 22 | 23 | public async Task CreateTable() 24 | { 25 | try 26 | { 27 | await using var dbConnection = new MySqlConnection(_dbConnectionString); 28 | dbConnection.Open(); 29 | 30 | var createBansTable = @" 31 | CREATE TABLE IF NOT EXISTS `miniadmin_bans` ( 32 | `id` INT AUTO_INCREMENT PRIMARY KEY, 33 | `admin_username` VARCHAR(255) NOT NULL, 34 | `admin_steamid` VARCHAR(255) NOT NULL, 35 | `username` VARCHAR(255) NOT NULL, 36 | `steamid64` BIGINT NOT NULL, 37 | `steamid` VARCHAR(255) NOT NULL, 38 | `reason` VARCHAR(255) NOT NULL, 39 | `unban_reason` VARCHAR(255) NOT NULL, 40 | `admin_unlocked_username` VARCHAR(255) NOT NULL, 41 | `admin_unlocked_steamid` VARCHAR(255) NOT NULL, 42 | `start_ban_time` BIGINT NOT NULL, 43 | `end_ban_time` BIGINT NOT NULL, 44 | `ban_active` BOOLEAN NOT NULL 45 | );"; 46 | 47 | await dbConnection.ExecuteAsync(createBansTable); 48 | } 49 | catch (Exception e) 50 | { 51 | Console.WriteLine(e); 52 | } 53 | } 54 | 55 | public async Task CreateAdminsTable() 56 | { 57 | try 58 | { 59 | await using var connection = new MySqlConnection(_dbConnectionString); 60 | 61 | connection.Open(); 62 | 63 | var createAdminsTable = @" 64 | CREATE TABLE IF NOT EXISTS `miniadmin_admins` ( 65 | `id` INT AUTO_INCREMENT PRIMARY KEY, 66 | `username` VARCHAR(255) NOT NULL, 67 | `steamid` VARCHAR(255) NOT NULL, 68 | `start_time` BIGINT NOT NULL, 69 | `end_time` BIGINT NOT NULL, 70 | `immunity` INT NOT NULL, 71 | `flags` VARCHAR(255) NOT NULL 72 | );"; 73 | 74 | await connection.ExecuteAsync(createAdminsTable); 75 | } 76 | catch (Exception e) 77 | { 78 | Console.WriteLine(e); 79 | } 80 | } 81 | 82 | public async Task CreateMuteTable() 83 | { 84 | try 85 | { 86 | await using var connection = new MySqlConnection(_dbConnectionString); 87 | 88 | connection.Open(); 89 | 90 | var createMuteTable = @" 91 | CREATE TABLE IF NOT EXISTS `miniadmin_mute` ( 92 | `id` INT AUTO_INCREMENT PRIMARY KEY, 93 | `mute_type` INT NOT NULL, 94 | `admin_username` VARCHAR(255) NOT NULL, 95 | `admin_steamid` VARCHAR(255) NOT NULL, 96 | `username` VARCHAR(255) NOT NULL, 97 | `steamid64` BIGINT NOT NULL, 98 | `steamid` VARCHAR(255) NOT NULL, 99 | `reason` VARCHAR(255) NOT NULL, 100 | `unmute_reason` VARCHAR(255) NOT NULL, 101 | `admin_unlocked_username` VARCHAR(255) NOT NULL, 102 | `admin_unlocked_steamid` VARCHAR(255) NOT NULL, 103 | `start_mute_time` BIGINT NOT NULL, 104 | `end_mute_time` BIGINT NOT NULL, 105 | `mute_active` BOOLEAN NOT NULL 106 | );"; 107 | 108 | await connection.ExecuteAsync(createMuteTable); 109 | } 110 | catch (Exception e) 111 | { 112 | Console.WriteLine(e); 113 | } 114 | } 115 | 116 | public async Task AddBan(User user) 117 | { 118 | try 119 | { 120 | var isUserBanned = await IsUserBanned(user.steamid); 121 | if (isUserBanned) 122 | return $"The user with the SteamId identifier {user.steamid} has already been banned."; 123 | 124 | await using var connection = new MySqlConnection(_dbConnectionString); 125 | 126 | await connection.ExecuteAsync(@" 127 | INSERT INTO miniadmin_bans (admin_username, admin_steamid, username, steamid64, steamid, reason, unban_reason, admin_unlocked_username, admin_unlocked_steamid, start_ban_time, end_ban_time, ban_active) 128 | VALUES (@admin_username, @admin_steamid, @username, @steamid64, @steamid, @reason, @unban_reason, @admin_unlocked_username, @admin_unlocked_steamid, @start_ban_time, @end_ban_time, @ban_active); 129 | ", user); 130 | 131 | return $"Player '{user.username} | [{user.steamid}]' is banned"; 132 | } 133 | catch (Exception e) 134 | { 135 | Console.WriteLine(e); 136 | } 137 | 138 | return string.Empty; 139 | } 140 | 141 | public async Task AddMute(MuteUser user, CCSPlayerController? controller) 142 | { 143 | try 144 | { 145 | await using var connection = new MySqlConnection(_dbConnectionString); 146 | 147 | var activeUserMute = await GetActiveMuteAsync(user.steamid); 148 | 149 | if (activeUserMute != null) 150 | { 151 | if (activeUserMute.mute_type == user.mute_type) 152 | { 153 | Server.NextFrame(() => 154 | _baseAdmin.ReplyToCommand(controller, "The user already has sound or chat disabled")); 155 | return; 156 | } 157 | 158 | if (activeUserMute.mute_type == 2 || user.mute_type == 2) 159 | { 160 | Server.NextFrame(() => _baseAdmin.ReplyToCommand(controller, 161 | $"The user with the SteamId identifier {user.steamid} has already been muted in all channels.")); 162 | return; 163 | } 164 | 165 | if (activeUserMute.mute_type is 1 or 0 && user.mute_type is 1 or 0) 166 | user.mute_type = 2; 167 | 168 | await connection.ExecuteAsync(@" 169 | UPDATE miniadmin_mute 170 | SET mute_type = @mute_type, 171 | admin_username = @admin_username, 172 | admin_steamid = @admin_steamid, 173 | username = @username, 174 | steamid64 = @steamid64, 175 | steamid = @steamid, 176 | reason = @reason, 177 | unmute_reason = @unmute_reason, 178 | admin_unlocked_username = @admin_unlocked_username, 179 | admin_unlocked_steamid = @admin_unlocked_steamid, 180 | start_mute_time = @start_mute_time, 181 | end_mute_time = @end_mute_time, 182 | mute_active = @mute_active 183 | WHERE steamid = @steamid and mute_active = 1; 184 | ", user); 185 | 186 | Server.NextFrame(() => _baseAdmin.ReplyToCommand(controller, 187 | $"Player '{user.username} | [{user.steamid}]' mute has been updated.")); 188 | return; 189 | } 190 | 191 | await connection.ExecuteAsync(@" 192 | INSERT INTO miniadmin_mute (mute_type, admin_username, admin_steamid, username, steamid64, steamid, reason, unmute_reason, admin_unlocked_username, admin_unlocked_steamid, start_mute_time, end_mute_time, mute_active) 193 | VALUES (@mute_type, @admin_username, @admin_steamid, @username, @steamid64, @steamid, @reason, @unmute_reason, @admin_unlocked_username, @admin_unlocked_steamid, @start_mute_time, @end_mute_time, @mute_active); 194 | ", user); 195 | 196 | Server.NextFrame(() => 197 | _baseAdmin.ReplyToCommand(controller, $"Player '{user.username} | [{user.steamid}]' is muted.")); 198 | } 199 | catch (Exception e) 200 | { 201 | Console.WriteLine(e); 202 | } 203 | } 204 | 205 | public async Task AddAdmin(Admins admin, CCSPlayerController? player = null, bool fromMenu = false) 206 | { 207 | try 208 | { 209 | var isAdminExist = await GetAdminFromDb(admin.steamid); 210 | if (isAdminExist != null) 211 | { 212 | _baseAdmin.PrintLogError("An administrator with the SteamId identifier {steamid} already exists.", 213 | admin.steamid); 214 | 215 | if (fromMenu) 216 | { 217 | if (player != null) 218 | Server.NextFrame(() => _baseAdmin.PrintToChat(player, 219 | $"An administrator with the SteamId identifier {admin.steamid} already exists.")); 220 | } 221 | 222 | return; 223 | } 224 | 225 | await using var connection = new MySqlConnection(_dbConnectionString); 226 | 227 | await connection.ExecuteAsync(@" 228 | INSERT INTO 229 | miniadmin_admins (username, steamid, start_time, end_time, immunity, flags) 230 | VALUES 231 | (@username, @steamid, @start_time, @end_time, @immunity, @flags);", admin); 232 | 233 | _baseAdmin.PrintLogInfo("Admin '{username}[{steamid}]' successfully added", 234 | admin.username, admin.steamid); 235 | if (fromMenu) 236 | { 237 | if (player != null) 238 | { 239 | Server.NextFrame(() => 240 | _baseAdmin.PrintToChat(player, 241 | $"Admin '{admin.username}[{admin.steamid}]' successfully added")); 242 | } 243 | } 244 | } 245 | catch (Exception e) 246 | { 247 | Console.WriteLine(e); 248 | } 249 | } 250 | 251 | public async Task UpdateAdmin(Admins admin) 252 | { 253 | try 254 | { 255 | var existingAdmin = await GetAdminFromDb(admin.steamid); 256 | if (existingAdmin == null) 257 | { 258 | _baseAdmin.PrintLogError("Administrator with SteamId {steamid} does not exist.", admin.steamid); 259 | return; 260 | } 261 | 262 | var hasChanges = false; 263 | 264 | if (existingAdmin.username != admin.username && admin.username is not ("-" or "-s")) 265 | { 266 | existingAdmin.username = admin.username; 267 | hasChanges = true; 268 | } 269 | 270 | if (existingAdmin.end_time != admin.end_time && admin.end_time is not -1) 271 | { 272 | existingAdmin.end_time = admin.end_time; 273 | hasChanges = true; 274 | } 275 | 276 | if (existingAdmin.immunity != admin.immunity && admin.immunity is not -1) 277 | { 278 | existingAdmin.immunity = admin.immunity; 279 | hasChanges = true; 280 | } 281 | 282 | if (existingAdmin.flags != admin.flags && admin.flags is not ("-" or "-s")) 283 | { 284 | existingAdmin.flags = admin.flags; 285 | hasChanges = true; 286 | } 287 | 288 | if (!hasChanges) 289 | { 290 | _baseAdmin.PrintLogInfo("No changes detected for administrator '{username}[{steamid}]'", 291 | existingAdmin.username, existingAdmin.steamid); 292 | return; 293 | } 294 | 295 | await using var connection = new MySqlConnection(_dbConnectionString); 296 | 297 | await connection.ExecuteAsync(@" 298 | UPDATE miniadmin_admins 299 | SET 300 | username = @username, 301 | end_time = @end_time, 302 | immunity = @immunity, 303 | flags = @flags 304 | WHERE 305 | steamid = @steamid;", existingAdmin); 306 | 307 | _baseAdmin.PrintLogInfo("Administrator '{username}[{steamid}]' successfully updated", 308 | existingAdmin.username, existingAdmin.steamid); 309 | } 310 | catch (Exception e) 311 | { 312 | Console.WriteLine(e); 313 | } 314 | } 315 | 316 | 317 | public async Task DeleteExpiredAdminsAsync() 318 | { 319 | try 320 | { 321 | await using var connection = new MySqlConnection(_dbConnectionString); 322 | 323 | var deleteAdmins = await connection.QueryAsync( 324 | "SELECT * FROM miniadmin_admins WHERE end_time <= @CurrentTime AND end_time > 0", 325 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }); 326 | 327 | var adminsEnumerable = deleteAdmins.ToList(); 328 | if (adminsEnumerable.Any()) 329 | { 330 | foreach (var deleteAdmin in adminsEnumerable) 331 | { 332 | await connection.ExecuteAsync(@"DELETE FROM miniadmin_admins WHERE steamid = @SteamId;", 333 | new { SteamId = deleteAdmin.steamid }); 334 | 335 | _baseAdmin.PrintLogInfo("Admin {steamid} successfully deleted", 336 | deleteAdmin.steamid); 337 | } 338 | 339 | _baseAdmin.PrintLogInfo("Expired admins successfully deleted"); 340 | } 341 | } 342 | catch (Exception e) 343 | { 344 | Console.WriteLine(e); 345 | } 346 | 347 | return string.Empty; 348 | } 349 | 350 | public async Task DeleteAdminAsync(string steamId) 351 | { 352 | try 353 | { 354 | await using var connection = new MySqlConnection(_dbConnectionString); 355 | 356 | await connection.ExecuteAsync(@"DELETE FROM miniadmin_admins WHERE steamid = @SteamId;", 357 | new { SteamId = steamId }); 358 | 359 | _baseAdmin.PrintLogInfo("Admin {steamId} successfully deleted", steamId); 360 | } 361 | catch (Exception e) 362 | { 363 | Console.WriteLine(e); 364 | } 365 | 366 | return string.Empty; 367 | } 368 | 369 | public async Task UnbanUser(string adminName, string adminSteamId, string steamId, string reason) 370 | { 371 | try 372 | { 373 | await using var connection = new MySqlConnection(_dbConnectionString); 374 | 375 | var user = await connection.QueryFirstOrDefaultAsync( 376 | "SELECT * FROM miniadmin_bans WHERE steamid = @SteamId AND ban_active = 1", 377 | new { SteamId = steamId }); 378 | 379 | if (user == null) return "User not found or not currently banned"; 380 | 381 | user.unban_reason = reason; 382 | user.admin_unlocked_username = adminName; 383 | user.admin_unlocked_steamid = adminSteamId; 384 | user.ban_active = false; 385 | 386 | await connection.ExecuteAsync(@" 387 | UPDATE miniadmin_bans 388 | SET unban_reason = @unban_reason, admin_unlocked_username = @admin_unlocked_username, 389 | admin_unlocked_steamid = @admin_unlocked_steamid, ban_active = @ban_active 390 | WHERE steamid = @SteamId AND ban_active = 1 391 | ", user); 392 | 393 | return $"Player {steamId} has been successfully unblocked with reason: {reason}"; 394 | } 395 | catch (Exception e) 396 | { 397 | Console.WriteLine(e); 398 | } 399 | 400 | return string.Empty; 401 | } 402 | 403 | public async Task UnmuteUser(int unmuteType, string adminName, string adminSteamId, string steamId, 404 | string reason) 405 | { 406 | try 407 | { 408 | await using var connection = new MySqlConnection(_dbConnectionString); 409 | 410 | var user = await connection.QueryFirstOrDefaultAsync( 411 | "SELECT * FROM miniadmin_mute WHERE steamid = @SteamId AND mute_active = 1", 412 | new { SteamId = steamId }); 413 | 414 | if (user == null) return "User not found or not currently muted"; 415 | 416 | user.unmute_reason = reason; 417 | user.admin_unlocked_username = adminName; 418 | user.admin_unlocked_steamid = adminSteamId; 419 | 420 | if (unmuteType != -1) 421 | { 422 | if (user.mute_type is 2 && unmuteType is 0) 423 | user.mute_type = 1; 424 | else if (user.mute_type is 2 && unmuteType is 1) 425 | user.mute_type = 0; 426 | else if (user.mute_type == unmuteType) 427 | user.mute_active = false; 428 | } 429 | else 430 | user.mute_active = false; 431 | 432 | await connection.ExecuteAsync(@" 433 | UPDATE miniadmin_mute 434 | SET 435 | mute_type = @mute_type, 436 | unmute_reason = @unmute_reason, 437 | admin_unlocked_username = @admin_unlocked_username, 438 | admin_unlocked_steamid = @admin_unlocked_steamid, 439 | mute_active = @mute_active 440 | WHERE 441 | steamid = @SteamId 442 | AND 443 | mute_active = 1 444 | ", user); 445 | 446 | return $"Player {steamId} has been successfully unmuted with reason: {reason}"; 447 | } 448 | catch (Exception e) 449 | { 450 | Console.WriteLine(e); 451 | } 452 | 453 | return string.Empty; 454 | } 455 | 456 | public async Task GetActiveMuteAsync(string steamId) 457 | { 458 | try 459 | { 460 | await using var connection = new MySqlConnection(_dbConnectionString); 461 | 462 | var muteData = await connection.QueryFirstOrDefaultAsync(@" 463 | SELECT * FROM miniadmin_mute 464 | WHERE steamid = @SteamId AND mute_active = 1; 465 | ", new { SteamId = steamId }); 466 | 467 | return muteData; 468 | } 469 | catch (Exception e) 470 | { 471 | Console.WriteLine(e); 472 | return null; 473 | } 474 | } 475 | 476 | private async Task IsUserBanned(string steamId) 477 | { 478 | await using var connection = new MySqlConnection(_dbConnectionString); 479 | 480 | var existingBan = connection.QueryFirstOrDefaultAsync( 481 | "SELECT * FROM miniadmin_bans WHERE steamid = @SteamId AND ban_active = 1", 482 | new { SteamId = steamId }).Result; 483 | 484 | return existingBan != null; 485 | } 486 | 487 | public async Task IsUserMuted(string steamId) 488 | { 489 | await using var connection = new MySqlConnection(_dbConnectionString); 490 | 491 | var existingMute = connection.QueryFirstOrDefaultAsync( 492 | "SELECT * FROM miniadmin_mute WHERE steamid = @SteamId AND mute_active = 1", 493 | new { SteamId = steamId }).Result; 494 | 495 | return existingMute != null; 496 | } 497 | 498 | public async Task GetAdminFromDb(string steamId) 499 | { 500 | await using var connection = new MySqlConnection(_dbConnectionString); 501 | 502 | var existingAdmin = connection.QueryFirstOrDefaultAsync( 503 | "SELECT * FROM miniadmin_admins WHERE steamid = @SteamId", 504 | new { SteamId = steamId }).Result; 505 | 506 | return existingAdmin; 507 | } 508 | 509 | // private async Task IsAdminExist(string steamId) 510 | // { 511 | // await using var connection = new MySqlConnection(_dbConnectionString); 512 | // 513 | // var existingAdmin = connection.QueryFirstOrDefaultAsync( 514 | // "SELECT * FROM miniadmin_admins WHERE steamid = @SteamId", 515 | // new { SteamId = steamId }).Result; 516 | // 517 | // return existingAdmin != null; 518 | // } 519 | } -------------------------------------------------------------------------------- /MiniAdmin/Menu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using CounterStrikeSharp.API; 5 | using CounterStrikeSharp.API.Core; 6 | using CounterStrikeSharp.API.Modules.Entities; 7 | using CounterStrikeSharp.API.Modules.Menu; 8 | using static BaseAdmin.BaseAdmin; 9 | 10 | namespace BaseAdmin; 11 | 12 | public class Menu 13 | { 14 | private readonly BaseAdmin _baseAdmin; 15 | private readonly ChatMenu _slayMenu; 16 | private readonly ChatMenu _kickMenu; 17 | private readonly ChatMenu _muteMenu; 18 | private readonly ChatMenu _banMenu; 19 | private readonly ChatMenu _changeMapMenu; 20 | private readonly ChatMenu _addAdminMenu; 21 | 22 | public Menu(BaseAdmin baseAdmin) 23 | { 24 | _baseAdmin = baseAdmin; 25 | 26 | _slayMenu = new ChatMenu(baseAdmin.Prefix); 27 | _kickMenu = new ChatMenu(baseAdmin.Prefix); 28 | _muteMenu = new ChatMenu(baseAdmin.Prefix); 29 | _banMenu = new ChatMenu(baseAdmin.Prefix); 30 | _changeMapMenu = new ChatMenu(baseAdmin.Prefix); 31 | _addAdminMenu = new ChatMenu(baseAdmin.Prefix); 32 | } 33 | 34 | public void CreateMenu() 35 | { 36 | var adminMenu = new ChatMenu(_baseAdmin.Prefix); 37 | adminMenu.AddMenuOption("Slay players", (player, _) => 38 | { 39 | if (_baseAdmin.CheckingForAdminAndFlag(player, AdminFlag.Slay)) 40 | { 41 | CreateSlayMenu(); 42 | ChatMenus.OpenMenu(player, _slayMenu); 43 | } 44 | }); 45 | adminMenu.AddMenuOption("Kick players", (player, _) => 46 | { 47 | if (_baseAdmin.CheckingForAdminAndFlag(player, AdminFlag.Kick)) 48 | { 49 | CreateKickMenu(); 50 | ChatMenus.OpenMenu(player, _kickMenu); 51 | } 52 | }); 53 | adminMenu.AddMenuOption("Mute players", (player, _) => 54 | { 55 | if (_baseAdmin.CheckingForAdminAndFlag(player, AdminFlag.Generic)) 56 | { 57 | CreateMuteMenu(); 58 | ChatMenus.OpenMenu(player, _muteMenu); 59 | } 60 | }); 61 | adminMenu.AddMenuOption("Ban players", (player, _) => 62 | { 63 | if (_baseAdmin.CheckingForAdminAndFlag(player, AdminFlag.Ban)) 64 | { 65 | CreateBanMenu(); 66 | ChatMenus.OpenMenu(player, _banMenu); 67 | } 68 | }); 69 | adminMenu.AddMenuOption("Change map", (player, _) => 70 | { 71 | if (_baseAdmin.CheckingForAdminAndFlag(player, AdminFlag.Changemap)) 72 | { 73 | CreateChangeMapMenu(); 74 | ChatMenus.OpenMenu(player, _changeMapMenu); 75 | } 76 | }); 77 | adminMenu.AddMenuOption("Add Admin", (player, _) => 78 | { 79 | if (_baseAdmin.CheckingForAdminAndFlag(player, AdminFlag.Root)) 80 | { 81 | CreateAddAdminMenu(); 82 | ChatMenus.OpenMenu(player, _addAdminMenu); 83 | } 84 | }); 85 | 86 | _baseAdmin.AddCommand("css_admin", "admin menu", (player, info) => 87 | { 88 | if (player == null) return; 89 | if (!_baseAdmin.IsAdmin(player.Index)) 90 | { 91 | _baseAdmin.PrintToChat(player, "you do not have access to this command"); 92 | return; 93 | } 94 | 95 | ChatMenus.OpenMenu(player, adminMenu); 96 | }); 97 | } 98 | 99 | private void CreateSlayMenu() 100 | { 101 | var playerEntities = 102 | Utilities.GetPlayers().Where(u => u.PlayerPawn.Value != null && u.PlayerPawn.Value.IsValid); 103 | _slayMenu.MenuOptions.Clear(); 104 | _slayMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 105 | _slayMenu.AddMenuOption("All", (controller, option) => 106 | { 107 | foreach (var player in playerEntities) 108 | if (player.PlayerPawn.Value != null) 109 | player.PlayerPawn.Value.CommitSuicide(true, true); 110 | }); 111 | foreach (var player in playerEntities) 112 | { 113 | if (!player.PawnIsAlive) continue; 114 | 115 | _slayMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 116 | { 117 | var parts = option.Text.Split('[', ']'); 118 | if (parts.Length < 2) return; 119 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 120 | 121 | if (!target.PawnIsAlive) 122 | { 123 | _baseAdmin.PrintToChat(controller, "The player is already dead"); 124 | return; 125 | } 126 | 127 | if (target.PlayerPawn.Value != null) 128 | target.PlayerPawn.Value.CommitSuicide(true, true); 129 | 130 | _baseAdmin.PrintToChatAll($"{controller.PlayerName}: Player '{target.PlayerName}' has been killed"); 131 | }); 132 | } 133 | } 134 | 135 | private void CreateKickMenu() 136 | { 137 | _kickMenu.MenuOptions.Clear(); 138 | _kickMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 139 | foreach (var player in Utilities.GetPlayers()) 140 | { 141 | _kickMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 142 | { 143 | var parts = option.Text.Split('[', ']'); 144 | if (parts.Length < 2) return; 145 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 146 | 147 | if (!target.IsValid) 148 | { 149 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 150 | return; 151 | } 152 | 153 | //_baseAdmin.KickClient($"{target.UserId}"); 154 | target.Kick("Kick"); 155 | 156 | _baseAdmin.PrintToChatAll($"{controller.PlayerName}: Player '{target.PlayerName}' has been kicked"); 157 | }); 158 | } 159 | } 160 | 161 | private void CreateBanMenu() 162 | { 163 | _banMenu.MenuOptions.Clear(); 164 | _banMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 165 | foreach (var player in Utilities.GetPlayers()) 166 | { 167 | _banMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 168 | { 169 | var parts = option.Text.Split('[', ']'); 170 | if (parts.Length < 2) return; 171 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 172 | 173 | if (!target.IsValid) 174 | { 175 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 176 | return; 177 | } 178 | 179 | SelectionReasonsForBanning(controller, target); 180 | }); 181 | } 182 | } 183 | 184 | private void SelectionReasonsForBanning(CCSPlayerController player, CCSPlayerController target) 185 | { 186 | var reasonMenu = new ChatMenu(_baseAdmin.Prefix); 187 | reasonMenu.AddMenuOption("Pick a reason", (_, _) => { }, true); 188 | foreach (var reason in _baseAdmin.ReadAllBanReasons()) 189 | { 190 | reasonMenu.AddMenuOption(reason, (controller, option) => 191 | { 192 | var timeMenu = new ChatMenu(_baseAdmin.Prefix); 193 | timeMenu.AddMenuOption("Select a time", (_, _) => { }, true); 194 | foreach (var time in _baseAdmin.ReadAllTime()) 195 | { 196 | var split = time.Split(':'); 197 | timeMenu.AddMenuOption(split[0], 198 | (playerController, _) => 199 | { 200 | AddBanFromMenu(playerController, target, option.Text, int.Parse(split[1])); 201 | }); 202 | } 203 | 204 | ChatMenus.OpenMenu(controller, timeMenu); 205 | }); 206 | } 207 | 208 | ChatMenus.OpenMenu(player, reasonMenu); 209 | } 210 | 211 | private void AddBanFromMenu(CCSPlayerController controller, CCSPlayerController target, string reason, 212 | int time) 213 | { 214 | var startBanTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 215 | var endBanTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 216 | 217 | var msg = _baseAdmin.Database.AddBan(new User 218 | { 219 | admin_username = controller.PlayerName, 220 | admin_steamid = new SteamID(controller.SteamID).SteamId2, 221 | username = target.PlayerName, 222 | steamid64 = target.SteamID, 223 | steamid = new SteamID(target.SteamID).SteamId2, 224 | reason = reason, 225 | unban_reason = string.Empty, 226 | admin_unlocked_username = string.Empty, 227 | admin_unlocked_steamid = string.Empty, 228 | start_ban_time = startBanTimeUnix, 229 | end_ban_time = time == 0 ? time : endBanTimeUnix, 230 | ban_active = true 231 | }).Result; 232 | //_baseAdmin.KickClient($"{target.UserId}"); 233 | target.Kick("Ban"); 234 | _baseAdmin.PrintToChatAll(msg); 235 | } 236 | 237 | private void CreateMuteMenu() 238 | { 239 | _muteMenu.MenuOptions.Clear(); 240 | _muteMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 241 | foreach (var player in Utilities.GetPlayers()) 242 | { 243 | _muteMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", (controller, option) => 244 | { 245 | var parts = option.Text.Split('[', ']'); 246 | if (parts.Length < 2) return; 247 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 248 | 249 | if (!target.IsValid) 250 | { 251 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 252 | return; 253 | } 254 | 255 | SelectionTypeMute(controller, target); 256 | }); 257 | } 258 | } 259 | 260 | private void SelectionTypeMute(CCSPlayerController player, CCSPlayerController target) 261 | { 262 | var reasonMenu = new ChatMenu(_baseAdmin.Prefix); 263 | reasonMenu.AddMenuOption("Pick a type", (_, _) => { }, true); 264 | reasonMenu.AddMenuOption("All", (_, _) => { SelectionReasonsForMute(player, target, MuteType.All); }); 265 | reasonMenu.AddMenuOption("Mute", 266 | (_, _) => { SelectionReasonsForMute(player, target, MuteType.Micro); }); 267 | reasonMenu.AddMenuOption("Gag", 268 | (_, _) => { SelectionReasonsForMute(player, target, MuteType.Chat); }); 269 | ChatMenus.OpenMenu(player, reasonMenu); 270 | } 271 | 272 | private void SelectionReasonsForMute(CCSPlayerController player, CCSPlayerController target, 273 | MuteType muteType) 274 | { 275 | var reasonMenu = new ChatMenu(_baseAdmin.Prefix); 276 | reasonMenu.AddMenuOption("Pick a reason", (_, _) => { }, true); 277 | foreach (var reason in _baseAdmin.ReadAllMuteReasons()) 278 | { 279 | reasonMenu.AddMenuOption(reason, (controller, option) => 280 | { 281 | var timeMenu = new ChatMenu(_baseAdmin.Prefix); 282 | timeMenu.AddMenuOption("Select a time", (_, _) => { }, true); 283 | foreach (var time in _baseAdmin.ReadAllTime()) 284 | { 285 | var split = time.Split(':'); 286 | timeMenu.AddMenuOption(split[0], 287 | (playerController, _) => 288 | { 289 | AddMuteFromMenu(playerController, target, option.Text, int.Parse(split[1]), muteType); 290 | }); 291 | } 292 | 293 | ChatMenus.OpenMenu(controller, timeMenu); 294 | }); 295 | } 296 | 297 | ChatMenus.OpenMenu(player, reasonMenu); 298 | } 299 | 300 | private void AddMuteFromMenu(CCSPlayerController controller, CCSPlayerController target, string reason, 301 | int time, MuteType muteType) 302 | { 303 | var startMuteTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 304 | var endMuteTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 305 | 306 | Server.NextFrame(() => 307 | { 308 | _baseAdmin.Database.AddMute(new MuteUser 309 | { 310 | mute_type = (int)muteType, 311 | admin_username = controller != null ? controller.PlayerName : "Console", 312 | admin_steamid = controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 313 | username = target.PlayerName, 314 | steamid64 = target.SteamID, 315 | steamid = new SteamID(target.SteamID).SteamId2, 316 | reason = reason, 317 | unmute_reason = "", 318 | admin_unlocked_username = "", 319 | admin_unlocked_steamid = "", 320 | start_mute_time = startMuteTimeUnix, 321 | end_mute_time = endMuteTimeUnix == 0 ? 0 : endMuteTimeUnix, 322 | mute_active = true 323 | }, controller == null ? null : controller); 324 | 325 | if (muteType is MuteType.Micro or MuteType.All) 326 | target.VoiceFlags = VoiceFlags.Muted; 327 | }); 328 | 329 | _baseAdmin.UpdateUserMuteLocal(target, time, endMuteTimeUnix, (int)muteType); 330 | } 331 | 332 | private void CreateChangeMapMenu() 333 | { 334 | _changeMapMenu.MenuOptions.Clear(); 335 | _changeMapMenu.AddMenuOption("Pick a map", (_, _) => { }, true); 336 | foreach (var map in _baseAdmin.GetMapFromMaps()) 337 | { 338 | var mapsStarts = map.StartsWith("ws:"); 339 | var mapName = mapsStarts ? map.Trim('w', 's', ':') : map; 340 | _changeMapMenu.AddMenuOption($"{mapName}", 341 | (controller, option) => 342 | { 343 | _baseAdmin.PrintToChatAll($"{controller.PlayerName}: changing the map to {mapName}"); 344 | _baseAdmin.AddTimer(3.0f, () => _baseAdmin.ChangeMap(mapName, mapsStarts)); 345 | }); 346 | } 347 | } 348 | 349 | private void CreateAddAdminMenu() 350 | { 351 | _addAdminMenu.MenuOptions.Clear(); 352 | _addAdminMenu.AddMenuOption("Pick a player", (_, _) => { }, true); 353 | foreach (var player in Utilities.GetPlayers()) 354 | { 355 | if (_baseAdmin.IsAdmin(player.Index)) continue; 356 | 357 | _addAdminMenu.AddMenuOption($"{player.PlayerName} [{player.Index}]", 358 | (controller, option) => 359 | { 360 | var parts = option.Text.Split('[', ']'); 361 | if (parts.Length < 2) return; 362 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 363 | 364 | if (!target.IsValid) 365 | { 366 | _baseAdmin.PrintToChat(controller, "This player is invalid"); 367 | return; 368 | } 369 | 370 | SelectionTimeAndImmunityForAddAdmin(controller, target); 371 | }); 372 | } 373 | } 374 | 375 | private void SelectionTimeAndImmunityForAddAdmin(CCSPlayerController player, CCSPlayerController target) 376 | { 377 | var timeMenu = new ChatMenu(_baseAdmin.Prefix); 378 | timeMenu.AddMenuOption("Select a time", (_, _) => { }, true); 379 | foreach (var time in _baseAdmin.ReadAllTime()) 380 | { 381 | var split = time.Split(':'); 382 | timeMenu.AddMenuOption(split[0], (playerController, _) => 383 | { 384 | var immunityMenu = new ChatMenu(_baseAdmin.Prefix); 385 | immunityMenu.AddMenuOption("Choice of immunity", (_, _) => { }, true); 386 | foreach (var immunity in _baseAdmin.ReadAllImmunity()) 387 | { 388 | immunityMenu.AddMenuOption(immunity, 389 | (client, _) => 390 | { 391 | AddAdminFromMenu(client, target, int.Parse(immunity), int.Parse(split[1])); 392 | }); 393 | } 394 | 395 | ChatMenus.OpenMenu(playerController, immunityMenu); 396 | }); 397 | } 398 | 399 | ChatMenus.OpenMenu(player, timeMenu); 400 | } 401 | 402 | private void AddAdminFromMenu(CCSPlayerController client, CCSPlayerController target, 403 | int immunity, int time) 404 | { 405 | var startTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 406 | var endTimeUnix = DateTime.UtcNow.AddSeconds(time).GetUnixEpoch(); 407 | 408 | _baseAdmin.Database.AddAdmin(new Admins 409 | { 410 | username = target.PlayerName, 411 | steamid = new SteamID(target.SteamID).SteamId2, 412 | start_time = startTimeUnix, 413 | end_time = time == 0 ? time : endTimeUnix, 414 | immunity = immunity, 415 | flags = "s" 416 | }, client, true); 417 | } 418 | } -------------------------------------------------------------------------------- /MiniAdmin/MuteUser.cs: -------------------------------------------------------------------------------- 1 | namespace BaseAdmin; 2 | 3 | public class MuteUser 4 | { 5 | public int mute_type { get; set; } 6 | public required string admin_username { get; set; } 7 | public required string admin_steamid { get; set; } 8 | public required string username { get; set; } 9 | public ulong steamid64 { get; set; } 10 | public required string steamid { get; set; } 11 | public required string reason { get; set; } 12 | public required string unmute_reason { get; set; } 13 | public required string admin_unlocked_username { get; set; } 14 | public required string admin_unlocked_steamid { get; set; } 15 | public int start_mute_time { get; set; } 16 | public int end_mute_time { get; set; } 17 | public bool mute_active { get; set; } 18 | } 19 | 20 | public class MuteUserLocal 21 | { 22 | public int MuteType { get; set; } 23 | public required string SteamId { get; set; } 24 | public int EndMuteTime { get; set; } 25 | public bool MuteActive { get; set; } 26 | } -------------------------------------------------------------------------------- /MiniAdmin/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using CounterStrikeSharp.API; 4 | using CounterStrikeSharp.API.Core; 5 | 6 | namespace BaseAdmin; 7 | 8 | public static class Utils 9 | { 10 | public static void Kick(this CCSPlayerController? player, string reason) 11 | { 12 | if (player == null) 13 | { 14 | Console.WriteLine("player is null"); 15 | return; 16 | } 17 | 18 | Server.ExecuteCommand(string.Create(CultureInfo.InvariantCulture, $"kickid {player.UserId!.Value} \"{reason}\"")); 19 | } 20 | 21 | public static int GetUnixEpoch(this DateTime dateTime) 22 | { 23 | var unixTime = dateTime.ToUniversalTime() - 24 | new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 25 | 26 | return (int)unixTime.TotalSeconds; 27 | } 28 | } -------------------------------------------------------------------------------- /Old/MiniAdmin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text.Json; 6 | using System.Text.RegularExpressions; 7 | using System.Threading.Tasks; 8 | using CounterStrikeSharp.API; 9 | using CounterStrikeSharp.API.Core; 10 | using CounterStrikeSharp.API.Core.Attributes.Registration; 11 | using CounterStrikeSharp.API.Modules.Commands; 12 | using CounterStrikeSharp.API.Modules.Entities; 13 | using CounterStrikeSharp.API.Modules.Menu; 14 | using CounterStrikeSharp.API.Modules.Timers; 15 | using Dapper; 16 | using MySqlConnector; 17 | 18 | namespace MiniAdmin; 19 | 20 | public class MiniAdmin : BasePlugin 21 | { 22 | public override string ModuleAuthor => "thesamefabius"; 23 | public override string ModuleName => "Mini Admin"; 24 | public override string ModuleVersion => "v1.0.4"; 25 | 26 | private string _dbConnectionString = string.Empty; 27 | 28 | private DateTime[] _playerPlayTime = new DateTime[Server.MaxPlayers]; 29 | 30 | private static readonly string Prefix = "[\x0C Admin Menu \x01]"; 31 | private readonly ChatMenu _slayMenu = new(Prefix + " Slay"); 32 | 33 | public override void Load(bool hotReload) 34 | { 35 | _dbConnectionString = BuildConnectionString(); 36 | Task.Run(() => CreateTable(_dbConnectionString)); 37 | Task.Run(() => CreateAdminsTable(_dbConnectionString)); 38 | 39 | var path = Path.Combine(ModuleDirectory, "maps.txt"); 40 | if(!File.Exists(path)) 41 | File.WriteAllLines(path, new []{ "de_dust2" }); 42 | 43 | RegisterListener(slot => 44 | { 45 | var entity = NativeAPI.GetEntityFromIndex(slot + 1); 46 | 47 | if (entity == IntPtr.Zero) return; 48 | 49 | var player = new CCSPlayerController(entity); 50 | 51 | Task.Run(() => OnClientConnectedAsync(slot, player, new SteamID(player.SteamID))); 52 | }); 53 | 54 | RegisterListener(slot => { _playerPlayTime[slot + 1] = DateTime.MinValue; }); 55 | 56 | AddTimer(300, () => 57 | { 58 | Task.Run(Timer_DeleteAdminAsync); 59 | }, TimerFlags.REPEAT); 60 | CreateMenu(); 61 | } 62 | 63 | private async Task Timer_DeleteAdminAsync() 64 | { 65 | await using var connection = new MySqlConnection(_dbConnectionString); 66 | 67 | var deleteAdmins = await connection.QueryAsync( 68 | "SELECT * FROM miniadmin_admins WHERE EndTime <= @CurrentTime AND EndTime > 0", 69 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }); 70 | 71 | var adminsEnumerable = deleteAdmins.ToList(); 72 | if (adminsEnumerable.Any()) 73 | { 74 | foreach (var result in adminsEnumerable.Select(deleteAdmin => DeleteAdmin(deleteAdmin.SteamId))) 75 | PrintToServer(await result, ConsoleColor.DarkMagenta); 76 | } 77 | } 78 | 79 | private async Task OnClientConnectedAsync(int slot, CCSPlayerController player, SteamID steamId) 80 | { 81 | try 82 | { 83 | await using var connection = new MySqlConnection(_dbConnectionString); 84 | 85 | var unbanUsers = await connection.QueryAsync( 86 | "SELECT * FROM miniadmin_bans WHERE EndBanTime <= @CurrentTime AND BanActive = 1 AND EndBanTime > 0", 87 | new { CurrentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() }); 88 | 89 | foreach (var user in unbanUsers) 90 | { 91 | PrintToServer($"Unban: {user.SteamId}", ConsoleColor.DarkMagenta); 92 | await UnbanUser("Console", "Console", user.SteamId, "The deadline has passed"); 93 | } 94 | 95 | await Timer_DeleteAdminAsync(); 96 | 97 | var banUser = await connection.QueryFirstOrDefaultAsync( 98 | "SELECT * FROM miniadmin_bans WHERE SteamId64 = @SteamId64 AND BanActive = 1", 99 | new { steamId.SteamId64 }); 100 | 101 | if (banUser != null) Server.ExecuteCommand($"kick {player.PlayerName}"); 102 | else 103 | _playerPlayTime[slot + 1] = DateTime.Now; 104 | } 105 | catch (Exception e) 106 | { 107 | Console.WriteLine(e); 108 | } 109 | } 110 | 111 | private void CreateMenu() 112 | { 113 | var adminMenu = new ChatMenu(Prefix); 114 | adminMenu.AddMenuOption("Slay players", (player, option) => 115 | { 116 | if (!IsAdmin(player)) 117 | { 118 | PrintToChat(player, "you do not have access to this command"); 119 | return; 120 | } 121 | 122 | CreateSlayMenu(); 123 | ChatMenus.OpenMenu(player, _slayMenu); 124 | }); 125 | 126 | AddCommand("css_admin", "admin menu", (player, info) => 127 | { 128 | if (player == null) return; 129 | if (!IsAdmin(player)) 130 | { 131 | PrintToChat(player, "you do not have access to this command"); 132 | return; 133 | } 134 | 135 | ChatMenus.OpenMenu(player, adminMenu); 136 | }); 137 | } 138 | 139 | private void CreateSlayMenu() 140 | { 141 | var playerEntities = Utilities.GetPlayers(); 142 | _slayMenu.MenuOptions.Clear(); 143 | _slayMenu.AddMenuOption("All", (controller, option) => 144 | { 145 | foreach (var player in playerEntities) player.PlayerPawn.Value.CommitSuicide(true, true); 146 | }); 147 | foreach (var player in playerEntities) 148 | { 149 | if(!player.PawnIsAlive) continue; 150 | 151 | _slayMenu.AddMenuOption($"{player.PlayerName} [{player.EntityIndex!.Value.Value}]", (controller, option) => 152 | { 153 | var parts = option.Text.Split('[', ']'); 154 | if (parts.Length < 2) return; 155 | var target = Utilities.GetPlayerFromIndex(int.Parse(parts[1])); 156 | 157 | if (!target.PawnIsAlive) 158 | { 159 | PrintToChat(controller, "The player is already dead"); 160 | return; 161 | } 162 | 163 | target.PlayerPawn.Value.CommitSuicide(true, true); 164 | 165 | PrintToChatAll($"{controller.PlayerName}: Player '{target.PlayerName}' has been killed"); 166 | }); 167 | } 168 | } 169 | 170 | static async Task CreateTable(string connectionString) 171 | { 172 | try 173 | { 174 | await using var dbConnection = new MySqlConnection(connectionString); 175 | dbConnection.Open(); 176 | 177 | var createBansTable = @" 178 | CREATE TABLE IF NOT EXISTS `miniadmin_bans` ( 179 | `Id` INT AUTO_INCREMENT PRIMARY KEY, 180 | `AdminUsername` VARCHAR(255) NOT NULL, 181 | `AdminSteamId` VARCHAR(255) NOT NULL, 182 | `Username` VARCHAR(255) NOT NULL, 183 | `SteamId64` BIGINT NOT NULL, 184 | `SteamId` VARCHAR(255) NOT NULL, 185 | `Reason` VARCHAR(255) NOT NULL, 186 | `UnbanReason` VARCHAR(255) NOT NULL, 187 | `AdminUnlockedUsername` VARCHAR(255) NOT NULL, 188 | `AdminUnlockedSteamId` VARCHAR(255) NOT NULL, 189 | `StartBanTime` BIGINT NOT NULL, 190 | `EndBanTime` BIGINT NOT NULL, 191 | `BanActive` BOOLEAN NOT NULL 192 | );"; 193 | 194 | await dbConnection.ExecuteAsync(createBansTable); 195 | } 196 | catch (Exception e) 197 | { 198 | Console.WriteLine(e); 199 | } 200 | } 201 | 202 | static async Task CreateAdminsTable(string connectionString) 203 | { 204 | try 205 | { 206 | await using var connection = new MySqlConnection(connectionString); 207 | 208 | connection.Open(); 209 | 210 | var createAdminsTable = @" 211 | CREATE TABLE IF NOT EXISTS `miniadmin_admins` ( 212 | `Id` INT AUTO_INCREMENT PRIMARY KEY, 213 | `Username` VARCHAR(255) NOT NULL, 214 | `SteamId` VARCHAR(255) NOT NULL, 215 | `StartTime` BIGINT NOT NULL, 216 | `EndTime` BIGINT NOT NULL 217 | );"; 218 | 219 | await connection.ExecuteAsync(createAdminsTable); 220 | } 221 | catch (Exception e) 222 | { 223 | Console.WriteLine(e); 224 | } 225 | } 226 | 227 | [ConsoleCommand("css_who")] 228 | public void OnCmdWho(CCSPlayerController? controller, CommandInfo command) 229 | { 230 | if (controller != null) return; 231 | 232 | var maxNameLength = 0; 233 | 234 | var id = 0; 235 | foreach (var client in Utilities.GetPlayers()) 236 | { 237 | var playerName = !string.IsNullOrWhiteSpace(client.PlayerName) ? client.PlayerName : "unknown"; 238 | var playerNameLength = playerName.Length; 239 | maxNameLength = Math.Max(maxNameLength, playerNameLength); 240 | 241 | var adminStatus = IsAdmin(client) ? "admin " : "player"; 242 | 243 | var index = client.EntityIndex!.Value.Value; 244 | var playTime = DateTime.Now - _playerPlayTime[index]; 245 | 246 | id++; 247 | var formattedOutput = 248 | $"{id,-1} - {playerName,-15} | {adminStatus,-6} | Playtime: {playTime.Hours:D2}:{playTime.Minutes:D2}:{playTime.Seconds:D2}"; 249 | 250 | PrintToServer(formattedOutput, ConsoleColor.Magenta); 251 | } 252 | } 253 | 254 | [ConsoleCommand("css_map", "change map")] 255 | public void OnCmdChangeMap(CCSPlayerController? controller, CommandInfo command) 256 | { 257 | if (controller == null) return; 258 | 259 | var cmdArg = command.ArgString; 260 | 261 | if (!IsAdmin(controller)) 262 | { 263 | PrintToChat(controller, "you do not have access to this command"); 264 | return; 265 | } 266 | 267 | var mapText = File.ReadAllText(Path.Combine(ModuleDirectory, "maps.txt")); 268 | var mapList = mapText.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) 269 | .Select(s => s.Trim()).ToArray(); 270 | 271 | foreach (var t in mapList) 272 | { 273 | if (t.Trim().Contains(cmdArg.Trim(), StringComparison.OrdinalIgnoreCase)) 274 | { 275 | PrintToChatAll($"{controller.PlayerName}: changing the map to {t}"); 276 | AddTimer(3.0f, () => ChangeMap(t)); 277 | return; 278 | } 279 | } 280 | 281 | PrintToChat(controller, "This map doesn't exist"); 282 | } 283 | 284 | 285 | [ConsoleCommand("css_slay", "kill a player")] 286 | public void OnCmdSlay(CCSPlayerController? controller, CommandInfo command) 287 | { 288 | var cmdArg = command.ArgString; 289 | 290 | if (controller != null) 291 | if (!IsAdmin(controller)) 292 | { 293 | PrintToChat(controller, "you do not have access to this command"); 294 | return; 295 | } 296 | 297 | if (command.ArgCount is < 2 or > 2) 298 | { 299 | ReplyToCommand(controller, "Using: css_slay "); 300 | return; 301 | } 302 | 303 | var target = Utilities.GetPlayerFromUserid(Convert.ToInt32(cmdArg)); 304 | 305 | if (!target.IsValid) 306 | { 307 | ReplyToCommand(controller, "Player not found"); 308 | return; 309 | } 310 | 311 | target.PlayerPawn.Value.CommitSuicide(true, true); 312 | 313 | if (controller == null) 314 | PrintToChatAll($"Console: Player '{target.PlayerName}' has been killed"); 315 | 316 | ReplyToCommand(controller, 317 | $"{(controller != null ? controller.PlayerName : "Console")}: Player '{target.PlayerName}' has been killed"); 318 | } 319 | 320 | [ConsoleCommand("css_kick", "Kick a player")] 321 | public void OnCmdKick(CCSPlayerController? controller, CommandInfo command) 322 | { 323 | var cmdArg = command.ArgString; 324 | 325 | if (controller != null) 326 | if (!IsAdmin(controller)) 327 | { 328 | PrintToChat(controller, "you do not have access to this command"); 329 | return; 330 | } 331 | 332 | if (command.ArgCount is < 2 or > 2) 333 | { 334 | ReplyToCommand(controller, "Using: css_kick "); 335 | return; 336 | } 337 | 338 | var convertCmdArg = Convert.ToInt32(cmdArg); 339 | 340 | var target = Utilities.GetPlayerFromUserid(convertCmdArg); 341 | //var userId = NativeAPI.GetUseridFromIndex(convertCmdArg + 1); 342 | 343 | if (!target.IsValid) 344 | { 345 | ReplyToCommand(controller, "Player not found"); 346 | return; 347 | } 348 | 349 | KickClient($"{convertCmdArg}"); 350 | 351 | var msg = 352 | $"{(controller != null ? controller.PlayerName : "Console")}: Player '{target.PlayerName}' kicked by admin"; 353 | ReplyToCommand(controller, msg); 354 | } 355 | 356 | [ConsoleCommand("css_ban", "ban")] 357 | public void OnCmdBan(CCSPlayerController? controller, CommandInfo command) 358 | { 359 | var cmdArg = command.ArgString; 360 | 361 | if (controller != null) 362 | if (!IsAdmin(controller)) 363 | { 364 | PrintToChat(controller, "you do not have access to this command"); 365 | return; 366 | } 367 | 368 | if (command.ArgCount is < 4 or > 4) 369 | { 370 | ReplyToCommand(controller, "Using: css_ban "); 371 | return; 372 | } 373 | 374 | var splitCmdArgs = Regex.Matches(cmdArg, @"[\""].+?[\""]|[^ ]+") 375 | .Select(m => m.Value) 376 | .ToArray(); 377 | 378 | var convertCmdArg = Convert.ToInt32(ExtractValueInQuotes(splitCmdArgs[0])); 379 | 380 | var target = Utilities.GetPlayerFromUserid(convertCmdArg); 381 | //var userId = NativeAPI.GetUseridFromIndex(convertCmdArg + 1); 382 | 383 | if (!target.IsValid) 384 | { 385 | ReplyToCommand(controller, "Player not found"); 386 | return; 387 | } 388 | 389 | var endBanTime = Convert.ToInt32(ExtractValueInQuotes(splitCmdArgs[1])); 390 | var reason = ExtractValueInQuotes(splitCmdArgs[2]); 391 | 392 | Console.WriteLine($"ExtractValue: {endBanTime}"); 393 | Console.WriteLine($"Split: {splitCmdArgs[0]} + {splitCmdArgs[1]} + {splitCmdArgs[2]}"); 394 | 395 | var startBanTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 396 | var endBanTimeUnix = DateTime.UtcNow.AddSeconds(endBanTime).GetUnixEpoch(); 397 | 398 | var msg = Task.Run(() => AddBan(new User 399 | { 400 | AdminUsername = controller != null ? controller.PlayerName : "Console", 401 | AdminSteamId = controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 402 | Username = target.PlayerName, 403 | SteamId64 = target.SteamID, 404 | SteamId = new SteamID(target.SteamID).SteamId2, 405 | Reason = reason, 406 | UnbanReason = "", 407 | AdminUnlockedUsername = "", 408 | AdminUnlockedSteamId = "", 409 | StartBanTime = startBanTimeUnix, 410 | EndBanTime = endBanTime == 0 ? 0 : endBanTimeUnix, 411 | BanActive = true 412 | })).Result; 413 | 414 | KickClient($"{convertCmdArg}"); 415 | 416 | ReplyToCommand(controller, msg); 417 | } 418 | 419 | [ConsoleCommand("css_addadmin")] 420 | public void OnCmdAddAdmin(CCSPlayerController? controller, CommandInfo command) 421 | { 422 | if(controller != null) return; 423 | 424 | var cmdArg = command.ArgString; 425 | 426 | if (command.ArgCount is < 4 or > 4) 427 | { 428 | PrintToServer("Using: css_addadmin ", ConsoleColor.Red); 429 | return; 430 | } 431 | 432 | var splitCmdArgs = Regex.Matches(cmdArg, @"[\""].+?[\""]|[^ ]+") 433 | .Select(m => m.Value) 434 | .ToArray(); 435 | 436 | var username = ExtractValueInQuotes(splitCmdArgs[0]); 437 | var steamId = ExtractValueInQuotes(splitCmdArgs[1]); 438 | var endTime = Convert.ToInt32(ExtractValueInQuotes(splitCmdArgs[2])); 439 | 440 | var startTimeUnix = DateTime.UtcNow.GetUnixEpoch(); 441 | var endTimeUnix = DateTime.UtcNow.AddSeconds(endTime).GetUnixEpoch(); 442 | 443 | var msg = Task.Run(() => AddAdmin(new Admins 444 | { 445 | Username = username, 446 | SteamId = steamId, 447 | StartTime = startTimeUnix, 448 | EndTime = endTime == 0 ? 0 : endTimeUnix 449 | })).Result; 450 | 451 | PrintToServer(msg, ConsoleColor.Green); 452 | } 453 | 454 | private async Task AddBan(User user) 455 | { 456 | try 457 | { 458 | if (IsUserBanned(user.SteamId)) 459 | return $"The user with the SteamId identifier {user.SteamId} has already been banned."; 460 | 461 | await using var connection = new MySqlConnection(_dbConnectionString); 462 | 463 | await connection.ExecuteAsync(@" 464 | INSERT INTO miniadmin_bans (AdminUsername, AdminSteamId, Username, SteamId64, SteamId, Reason, UnbanReason, AdminUnlockedUsername, AdminUnlockedSteamId, StartBanTime, EndBanTime, BanActive) 465 | VALUES (@AdminUsername, @AdminSteamId, @Username, @SteamId64, @SteamId, @Reason, @UnbanReason, @AdminUnlockedUsername, @AdminUnlockedSteamId, @StartBanTime, @EndBanTime, @BanActive); 466 | ", user); 467 | 468 | return $"Player '{user.Username} | [{user.SteamId}]' is banned"; 469 | } 470 | catch (Exception e) 471 | { 472 | Console.WriteLine(e); 473 | } 474 | 475 | return string.Empty; 476 | } 477 | 478 | private async Task AddAdmin(Admins admin) 479 | { 480 | try 481 | { 482 | if (IsAdminExist(admin.SteamId)) 483 | return $"An administrator with the SteamId identifier {admin.SteamId} already exists."; 484 | 485 | await using var connection = new MySqlConnection(_dbConnectionString); 486 | 487 | await connection.ExecuteAsync(@"INSERT INTO miniadmin_admins (Username, SteamId, StartTime, EndTime) 488 | VALUES (@Username, @SteamId, @StartTime, @EndTime);", admin); 489 | 490 | return $"Admin '{admin.Username}[{admin.SteamId}]' successfully added"; 491 | } 492 | catch (Exception e) 493 | { 494 | Console.WriteLine(e); 495 | } 496 | 497 | return string.Empty; 498 | } 499 | 500 | [ConsoleCommand("css_unban", "unban")] 501 | public void OnCmdUnban(CCSPlayerController? controller, CommandInfo command) 502 | { 503 | var cmdArg = command.ArgString; 504 | 505 | if (controller != null && !IsAdmin(controller)) 506 | { 507 | PrintToChat(controller, "you do not have access to this command"); 508 | return; 509 | } 510 | 511 | if (command.ArgCount is < 3 or > 3) 512 | { 513 | ReplyToCommand(controller, "Using: css_unban "); 514 | return; 515 | } 516 | 517 | var splitCmdArgs = Regex.Matches(cmdArg, @"[\""].+?[\""]|[^ ]+") 518 | .Select(m => m.Value) 519 | .ToArray(); 520 | 521 | var steamId = ExtractValueInQuotes(splitCmdArgs[0]); 522 | var reason = ExtractValueInQuotes(splitCmdArgs[1]); 523 | 524 | var msg = Task.Run(() => UnbanUser( 525 | controller != null ? controller.PlayerName : "Console", 526 | controller != null ? new SteamID(controller.SteamID).SteamId2 : "Console", 527 | steamId, reason)).Result; 528 | 529 | ReplyToCommand(controller, msg); 530 | } 531 | 532 | [ConsoleCommand("css_deleteadmin", "delete admin")] 533 | public void OnCmdDeleteAdmin(CCSPlayerController? controller, CommandInfo command) 534 | { 535 | if (controller != null) return; 536 | 537 | var cmdArg = command.ArgString; 538 | 539 | if (command.ArgCount is < 2 or > 2) 540 | { 541 | PrintToServer("Using: css_deleteadmin ", ConsoleColor.Red); 542 | return; 543 | } 544 | 545 | var steamId = ExtractValueInQuotes(cmdArg); 546 | 547 | var msg = Task.Run(() => DeleteAdmin(steamId)).Result; 548 | 549 | PrintToServer(msg, ConsoleColor.Green); 550 | } 551 | 552 | private async Task DeleteAdmin(string steamId) 553 | { 554 | try 555 | { 556 | await using var connection = new MySqlConnection(_dbConnectionString); 557 | 558 | await connection.ExecuteAsync(@"DELETE FROM miniadmin_admins WHERE SteamId = @SteamId;", 559 | new { SteamId = steamId }); 560 | 561 | return $"Admin {steamId} successfully deleted"; 562 | } 563 | catch (Exception e) 564 | { 565 | Console.WriteLine(e); 566 | } 567 | 568 | return string.Empty; 569 | } 570 | 571 | private async Task UnbanUser(string adminName, string adminSteamId, string steamId, string reason) 572 | { 573 | try 574 | { 575 | await using var connection = new MySqlConnection(_dbConnectionString); 576 | 577 | var user = await connection.QueryFirstOrDefaultAsync( 578 | "SELECT * FROM miniadmin_bans WHERE SteamId = @SteamId AND BanActive = 1", 579 | new { SteamId = steamId }); 580 | 581 | if (user == null) return "User not found or not currently banned"; 582 | 583 | user.UnbanReason = reason; 584 | user.AdminUnlockedUsername = adminName; 585 | user.AdminUnlockedSteamId = adminSteamId; 586 | user.BanActive = false; 587 | 588 | await connection.ExecuteAsync(@" 589 | UPDATE miniadmin_bans 590 | SET UnbanReason = @UnbanReason, AdminUnlockedUsername = @AdminUnlockedUsername, 591 | AdminUnlockedSteamId = @AdminUnlockedSteamId, BanActive = @BanActive 592 | WHERE SteamId = @SteamId AND BanActive = 1 593 | ", user); 594 | 595 | return $"Player {steamId} has been successfully unblocked with reason: {reason}"; 596 | } 597 | catch (Exception e) 598 | { 599 | Console.WriteLine(e); 600 | } 601 | 602 | return string.Empty; 603 | } 604 | 605 | private Config LoadConfig() 606 | { 607 | var configPath = Path.Combine(ModuleDirectory, "database.json"); 608 | if (!File.Exists(configPath)) return CreateConfig(configPath); 609 | 610 | var config = JsonSerializer.Deserialize(File.ReadAllText(configPath))!; 611 | 612 | return config; 613 | } 614 | 615 | private string BuildConnectionString() 616 | { 617 | var dbConfig = LoadConfig(); 618 | 619 | Console.WriteLine("Building connection string"); 620 | var builder = new MySqlConnectionStringBuilder 621 | { 622 | Database = dbConfig.Connection.Database, 623 | UserID = dbConfig.Connection.User, 624 | Password = dbConfig.Connection.Password, 625 | Server = dbConfig.Connection.Host, 626 | Port = 3306, 627 | }; 628 | 629 | Console.WriteLine("OK!"); 630 | return builder.ConnectionString; 631 | } 632 | 633 | private Config CreateConfig(string configPath) 634 | { 635 | var config = new Config 636 | { 637 | Connection = new MiniAdminDb 638 | { 639 | Host = "", 640 | Database = "", 641 | User = "", 642 | Password = "" 643 | } 644 | }; 645 | 646 | File.WriteAllText(configPath, 647 | JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true })); 648 | return config; 649 | } 650 | 651 | private string ExtractValueInQuotes(string input) 652 | { 653 | var match = Regex.Match(input, @"""([^""]*)"""); 654 | 655 | return match.Success ? match.Groups[1].Value : input; 656 | } 657 | 658 | private void ReplyToCommand(CCSPlayerController? controller, string msg) 659 | { 660 | if (controller != null) 661 | PrintToChat(controller, msg); 662 | else 663 | PrintToServer(msg, ConsoleColor.DarkMagenta); 664 | } 665 | 666 | private void ChangeMap(string mapName) 667 | { 668 | Server.ExecuteCommand($"map {mapName}"); 669 | } 670 | 671 | private void KickClient(string userId) 672 | { 673 | Server.ExecuteCommand($"kickid {userId}"); 674 | } 675 | 676 | private void PrintToChat(CCSPlayerController controller, string msg) 677 | { 678 | controller.PrintToChat($"\x08[ \x0CMiniAdmin \x08] {msg}"); 679 | } 680 | 681 | private void PrintToChatAll(string msg) 682 | { 683 | Server.PrintToChatAll($"\x08[ \x0CMiniAdmin \x08] {msg}"); 684 | } 685 | 686 | private void PrintToConsole(CCSPlayerController client, string msg) 687 | { 688 | client.PrintToConsole(msg); 689 | } 690 | 691 | private void PrintToServer(string msg, ConsoleColor color) 692 | { 693 | Console.ForegroundColor = color; 694 | Console.WriteLine($"[ MiniAdmin ] {msg}"); 695 | Console.ResetColor(); 696 | } 697 | 698 | private bool IsAdmin(CCSPlayerController controller) 699 | { 700 | var steamId = new SteamID(controller.SteamID).SteamId2; 701 | 702 | using var connection = new MySqlConnection(_dbConnectionString); 703 | 704 | var admin = connection.QueryFirstOrDefault( 705 | "SELECT * FROM miniadmin_admins WHERE SteamId = @SteamId", 706 | new { SteamId = steamId }); 707 | 708 | return admin != null; 709 | } 710 | 711 | private bool IsUserBanned(string steamId) 712 | { 713 | using var connection = new MySqlConnection(_dbConnectionString); 714 | 715 | var existingBan = connection.QueryFirstOrDefault( 716 | "SELECT * FROM miniadmin_bans WHERE SteamId = @SteamId AND BanActive = 1", 717 | new { SteamId = steamId }); 718 | 719 | return existingBan != null; 720 | } 721 | 722 | private bool IsAdminExist(string steamId) 723 | { 724 | using var connection = new MySqlConnection(_dbConnectionString); 725 | 726 | var existingAdmin = connection.QueryFirstOrDefault( 727 | "SELECT * FROM miniadmin_admins WHERE SteamId = @SteamId", 728 | new { SteamId = steamId }); 729 | 730 | return existingAdmin != null; 731 | } 732 | } 733 | 734 | public static class GetUnixTime 735 | { 736 | public static int GetUnixEpoch(this DateTime dateTime) 737 | { 738 | var unixTime = dateTime.ToUniversalTime() - 739 | new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 740 | 741 | return (int)unixTime.TotalSeconds; 742 | } 743 | } 744 | 745 | public class Config 746 | { 747 | public MiniAdminDb Connection { get; set; } = null!; 748 | } 749 | 750 | public class MiniAdminDb 751 | { 752 | public required string Host { get; init; } 753 | public required string Database { get; init; } 754 | public required string User { get; init; } 755 | public required string Password { get; init; } 756 | } 757 | 758 | public class User 759 | { 760 | public required string AdminUsername { get; set; } 761 | public required string AdminSteamId { get; set; } 762 | public required string Username { get; set; } 763 | public ulong SteamId64 { get; set; } 764 | public required string SteamId { get; set; } 765 | public required string Reason { get; set; } 766 | public required string UnbanReason { get; set; } 767 | public required string AdminUnlockedUsername { get; set; } 768 | public required string AdminUnlockedSteamId { get; set; } 769 | public int StartBanTime { get; set; } 770 | public int EndBanTime { get; set; } 771 | public bool BanActive { get; set; } 772 | } 773 | 774 | public class Admins 775 | { 776 | public required string Username { get; set; } 777 | public required string SteamId { get; set; } 778 | public int StartTime { get; set; } 779 | public int EndTime { get; set; } 780 | } -------------------------------------------------------------------------------- /Old/MiniAdmin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | AnyCPU;x86 6 | true 7 | enable 8 | 9 | 10 | 11 | 12 | ..\CounterStrikeSharp.API.dll 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IF YOU FIND A BUG, PLEASE TEXT ME AT DISCORD: thesamefabius 2 | 3 | # cs2-MiniAdmin 4 | Adds basic administrator functions 5 | 6 | # Installation 7 | 1. Install [CounterStrike Sharp](https://github.com/roflmuffin/CounterStrikeSharp) and [Metamod:Source](https://www.sourcemm.net/downloads.php/?branch=master) 8 | 3. Download [MiniAdmin](https://github.com/partiusfabaa/cs2-MiniAdmin/releases/tag/v1.0.0) 9 | 4. Unzip the archive and upload it to the game server 10 | 11 | # Commands 12 | ## For administrators: 13 | | Command | Description | Admin Flag | 14 | |---------|-------------|------------| 15 | | `css_admin`, `!admin` | opens the admin menu | - | 16 | | `css_ban "#userid or username" "time_minutes or 0 - permanently" [reason]` | Bans a player | Ban | 17 | | `css_unban "steamid" "reason"`, `!unban "steamid" [reason]` | Unbans the player | Unban | 18 | | `css_mute <#userid or username> [reason]` | Turns off player voice chat | Generic | 19 | | `css_unmute [reason]` | Enables voice chat for the player | Unban | 20 | | `css_gag <#userid or username> [reason]` | Disables player chat | Generic | 21 | | `css_ungag [reason]` | Enables player chat | Unban | 22 | | `css_slay "#userid or username"`, `!slay "userid"` | Allows you to kill a player | Slay | 23 | | `css_kick "#userid or username"`, `!kick "userid"` | Allows you to kick a player from the server | Kick | 24 | | `css_map "name_map"`, `!map "name_map"` | Allows you to change the map on the server | ChangeMap | 25 | | `css_team <#userid or username> [-k]` | Allows you to transfer a player for another team, if you write `-k` to the team the player will die | Kick | 26 | | `css_say ` | Allows you to send a message to the chat room | Chat | 27 | | `css_csay ` | Allows you to send a message to the CENTER | Chat | 28 | | `css_psay <#userid or username> ` | Allows you to send a private message | Chat | 29 | | `css_cvar ` | Change cvar value | Cvar | 30 | | `css_god [#userid or username]` | Allows you to grant immortality, if you don't write userid or name, it will be granted to the one who wrote it. | Cheats | 31 | | `css_rcon ` | Changes cvar with rcon | Rcon | 32 | | `css_slap <#userid or username> [damage]` | Slap a player | Slay | 33 | | `css_who`, `!who` | Shows all players, admin, and game time | - | 34 | 35 | To write to admin chat, you need to open Team chat and write @MYTEXT 36 | 37 | ## A LOT OF THESE FLAGS DON'T WORK. THEY HAVE BEEN ADDED FOR THE FUTURE. 38 | ### FLAGS: 39 | Reservation = a (doesn't work) 40 | Generic = b 41 | Kick = c 42 | Ban = d 43 | Unban = e 44 | Slay = f 45 | Changemap = g 46 | Cvar = h 47 | Config = i (doesn't work) 48 | Chat = j 49 | Vote = k (doesn't work) 50 | Password = l (doesn't work) 51 | Rcon = m 52 | Cheats = n 53 | Vip = o (doesn't work) 54 | Root = z 55 | 56 | (example SteamId: STEAM_0:1:123456) 57 | 58 | ## For chief administrators: 59 | `css_addadmin "username" "steamid" "immunity" "flags" "time_minutes or 0 - permanently"`, - Adds an administrator(server console only) 60 | 61 | `css_deleteadmin "steamid"` - Removes the administrator(server console only) 62 | 63 | (example SteamId: STEAM_0:1:123456) 64 | 65 | # Configs 66 | The configuration is generated automatically next to the plugin dll 67 | ``` 68 | database.json 69 | { 70 | "Connection": { 71 | "Host": "HOST", 72 | "Database": "NAME_DATABASE", 73 | "User": "NAME_USER", 74 | "Password": "PASSWORD", 75 | "Port": 3306 76 | } 77 | } 78 | 79 | maps.txt 80 | You just put the name of your maps here. 81 | ``` 82 | --------------------------------------------------------------------------------