mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-03-01 05:46:24 +00:00
Refactor database layer and add module/plugin improvements
Reworked the database layer to support both MySQL and SQLite via new provider classes and migration scripts for each backend. Updated the build workflow to support building and packaging additional modules, including StealthModule and BanSoundModule, and improved artifact handling. Refactored command registration to allow dynamic registration/unregistration and improved API event handling. Updated dependencies, project structure, and configuration checks for better reliability and extensibility. Added new language files, updated versioning, and removed obsolete files.
**⚠️ Warning: SQLite support is currently experimental.
Using this version requires reconfiguration of your database settings!
Plugin now uses UTC time. Please adjust your configurations accordingly!
**
This commit is contained in:
@@ -12,23 +12,32 @@ using CS2_SimpleAdmin.Managers;
|
||||
using CS2_SimpleAdmin.Menus;
|
||||
using CS2_SimpleAdminApi;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using CounterStrikeSharp.API.ValveConstants.Protobuf;
|
||||
using CS2_SimpleAdmin.Models;
|
||||
using MenuManager;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the command that shows active penalties and warns for the caller or specified player.
|
||||
/// Queries warnings and mute status, formats them locally, and sends the result to caller's chat.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing this command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(usage: "[#userid or name]", whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
public void OnPenaltiesCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (caller == null || caller.IsValid == false || !caller.UserId.HasValue || Database == null)
|
||||
if (caller == null || caller.IsValid == false || !caller.UserId.HasValue || DatabaseProvider == null)
|
||||
return;
|
||||
|
||||
var userId = caller.UserId.Value;
|
||||
var steamId = caller.SteamID;
|
||||
|
||||
if (!string.IsNullOrEmpty(command.GetArg(1)) && AdminManager.PlayerHasPermissions(new SteamID(caller.SteamID), "@css/kick"))
|
||||
{
|
||||
@@ -51,10 +60,10 @@ public partial class CS2_SimpleAdmin
|
||||
{
|
||||
try
|
||||
{
|
||||
var warns = await WarnManager.GetPlayerWarns(PlayersInfo[userId], false);
|
||||
var warns = await WarnManager.GetPlayerWarns(PlayersInfo[steamId], false);
|
||||
|
||||
// Check if the player is muted
|
||||
var activeMutes = await MuteManager.IsPlayerMuted(PlayersInfo[userId].SteamId.SteamId64.ToString());
|
||||
var activeMutes = await MuteManager.IsPlayerMuted(PlayersInfo[steamId].SteamId.SteamId64.ToString());
|
||||
|
||||
Dictionary<PenaltyType, List<string>> mutesList = new()
|
||||
{
|
||||
@@ -119,16 +128,16 @@ public partial class CS2_SimpleAdmin
|
||||
mutesList[PenaltyType.Silence].Add(_localizer["sa_player_penalty_info_no_active_silence"]);
|
||||
}
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
caller.SendLocalizedMessage(_localizer, "sa_player_penalty_info",
|
||||
[
|
||||
PlayersInfo[userId].Name,
|
||||
PlayersInfo[userId].TotalBans,
|
||||
PlayersInfo[userId].TotalGags,
|
||||
PlayersInfo[userId].TotalMutes,
|
||||
PlayersInfo[userId].TotalSilences,
|
||||
PlayersInfo[userId].TotalWarns,
|
||||
PlayersInfo[steamId].Name,
|
||||
PlayersInfo[steamId].TotalBans,
|
||||
PlayersInfo[steamId].TotalGags,
|
||||
PlayersInfo[steamId].TotalMutes,
|
||||
PlayersInfo[steamId].TotalSilences,
|
||||
PlayersInfo[steamId].TotalWarns,
|
||||
string.Join("\n", mutesList.SelectMany(kvp => kvp.Value)),
|
||||
string.Join("\n", warnsList)
|
||||
]);
|
||||
@@ -141,6 +150,12 @@ public partial class CS2_SimpleAdmin
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the admin voice listening mode or mutes/unmutes all players' voice.
|
||||
/// Sends confirmation messages accordingly.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing this command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
public void OnAdminVoiceCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -152,6 +167,7 @@ public partial class CS2_SimpleAdmin
|
||||
{
|
||||
if (command.GetArg(2).ToLower().Equals("muteAll"))
|
||||
{
|
||||
caller.SendLocalizedMessage(_localizer, "sa_admin_voice_mute_all");
|
||||
foreach (var player in Helper.GetValidPlayers().Where(p => p != caller && !AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/chat")))
|
||||
{
|
||||
player.VoiceFlags = VoiceFlags.Muted;
|
||||
@@ -160,19 +176,31 @@ public partial class CS2_SimpleAdmin
|
||||
|
||||
if (command.GetArg(2).ToLower().Equals("unmuteAll"))
|
||||
{
|
||||
caller.SendLocalizedMessage(_localizer, "sa_admin_voice_unmute_all");
|
||||
foreach (var player in Helper.GetValidPlayers().Where(p => p != caller))
|
||||
{
|
||||
if (PlayerPenaltyManager.GetPlayerPenalties(player.Slot, PenaltyType.Mute).Count == 0)
|
||||
if (PlayerPenaltyManager.GetPlayerPenalties(player.Slot, [PenaltyType.Silence, PenaltyType.Mute]).Count == 0)
|
||||
player.VoiceFlags = VoiceFlags.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
caller.VoiceFlags = caller.VoiceFlags == VoiceFlags.All ? VoiceFlags.Normal : VoiceFlags.All;
|
||||
|
||||
var enabled = caller.VoiceFlags.HasFlag(VoiceFlags.ListenAll);
|
||||
var messageKey = enabled
|
||||
? "sa_admin_voice_unlisten_all"
|
||||
: "sa_admin_voice_listen_all";
|
||||
|
||||
caller.SendLocalizedMessage(_localizer, messageKey);
|
||||
caller.VoiceFlags ^= VoiceFlags.ListenAll;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the admin menu for the caller.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
public void OnAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -183,6 +211,12 @@ public partial class CS2_SimpleAdmin
|
||||
AdminMenu.OpenMenu(caller);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays admin help text read from a file.
|
||||
/// Outputs lines one at a time as replies to the command.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[RequiresPermissions("@css/generic")]
|
||||
public void OnAdminHelpCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
@@ -194,12 +228,16 @@ public partial class CS2_SimpleAdmin
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles adding a new admin with specified SteamID, name, flags, immunity, and duration.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(minArgs: 4, usage: "<steamid> <name> <flags/groups> <immunity> <duration>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnAddAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null)
|
||||
{
|
||||
@@ -230,9 +268,20 @@ public partial class CS2_SimpleAdmin
|
||||
AddAdmin(caller, steamid, name, flags, immunity, time, globalAdmin, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds admin permissions and groups for a player.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="steamid">SteamID as string identifying the player.</param>
|
||||
/// <param name="name">Player's name.</param>
|
||||
/// <param name="flags">Comma-separated admin flags/groups.</param>
|
||||
/// <param name="immunity">Admin immunity level.</param>
|
||||
/// <param name="time">Duration of permission (default 0 = permanent).</param>
|
||||
/// <param name="globalAdmin">Whether admin is global.</param>
|
||||
/// <param name="command">Optional command info for confirmation messages.</param>
|
||||
public static void AddAdmin(CCSPlayerController? caller, string steamid, string name, string flags, int immunity, int time = 0, bool globalAdmin = false, CommandInfo? command = null)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
var flagsList = flags.Split(',').Select(flag => flag.Trim()).ToList();
|
||||
_ = Instance.PermissionManager.AddAdminBySteamId(steamid, name, flagsList, immunity, time, globalAdmin);
|
||||
@@ -248,11 +297,16 @@ public partial class CS2_SimpleAdmin
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles removing an admin's flags and groups by SteamID.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnDelAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null)
|
||||
{
|
||||
@@ -265,9 +319,16 @@ public partial class CS2_SimpleAdmin
|
||||
RemoveAdmin(caller, steamId.SteamId64.ToString(), globalDelete, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes admin permissions and groups for a player.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="steamid">SteamID as string identifying the player.</param>
|
||||
/// <param name="globalDelete">Whether to delete globally.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
public void RemoveAdmin(CCSPlayerController? caller, string steamid, bool globalDelete = false, CommandInfo? command = null)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
_ = PermissionManager.DeleteAdminBySteamId(steamid, globalDelete);
|
||||
|
||||
AddTimer(2, () =>
|
||||
@@ -294,11 +355,16 @@ public partial class CS2_SimpleAdmin
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new admin group with specified flags and immunity settings.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(minArgs: 3, usage: "<group_name> <flags> <immunity>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnAddGroup(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
if (!command.GetArg(1).StartsWith("#"))
|
||||
{
|
||||
@@ -320,9 +386,18 @@ public partial class CS2_SimpleAdmin
|
||||
AddGroup(caller, groupName, flags, immunity, globalGroup, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new admin group with specified flags and immunity level.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="name">Group name (prefix with #).</param>
|
||||
/// <param name="flags">Comma-separated flags/groups string.</param>
|
||||
/// <param name="immunity">Immunity level.</param>
|
||||
/// <param name="globalGroup">Whether group is global.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
private static void AddGroup(CCSPlayerController? caller, string name, string flags, int immunity, bool globalGroup, CommandInfo? command = null)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
var flagsList = flags.Split(',').Select(flag => flag.Trim()).ToList();
|
||||
_ = Instance.PermissionManager.AddGroup(name, flagsList, immunity, globalGroup);
|
||||
@@ -338,11 +413,16 @@ public partial class CS2_SimpleAdmin
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles removing a group by name.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(minArgs: 1, usage: "<group_name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnDelGroupCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
if (!command.GetArg(1).StartsWith($"#"))
|
||||
{
|
||||
@@ -355,9 +435,15 @@ public partial class CS2_SimpleAdmin
|
||||
RemoveGroup(caller, groupName, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a group.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="name">The group name to remove.</param>
|
||||
/// <param name="command">Optional command info for confirmation.</param>
|
||||
private void RemoveGroup(CCSPlayerController? caller, string name, CommandInfo? command = null)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
_ = PermissionManager.DeleteGroup(name);
|
||||
|
||||
AddTimer(2, () =>
|
||||
@@ -376,30 +462,42 @@ public partial class CS2_SimpleAdmin
|
||||
Server.PrintToConsole(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads admin and group data from database and json files.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the reload command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnRelAdminCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
|
||||
if (DatabaseProvider == null) return;
|
||||
ReloadAdmins(caller);
|
||||
|
||||
command.ReplyToCommand("Reloaded sql admins and groups");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads bans cache.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the reload command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/root")]
|
||||
public void OnRelBans(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
_ = Instance.CacheManager?.ForceReInitializeCacheAsync();
|
||||
command.ReplyToCommand("Reloaded bans");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reloads admin data asynchronously and updates admin caches.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the reload command.</param>
|
||||
public void ReloadAdmins(CCSPlayerController? caller)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
@@ -411,14 +509,17 @@ public partial class CS2_SimpleAdmin
|
||||
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(1.3f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
if (!string.IsNullOrEmpty(groupsFile))
|
||||
AddTimer(2.5f, () => AdminManager.LoadAdminGroups(ModuleDirectory + "/data/groups.json"));
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(3.5f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
AddTimer(1, () =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(2.0f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
if (!string.IsNullOrEmpty(groupsFile))
|
||||
AddTimer(3.0f, () => AdminManager.LoadAdminGroups(ModuleDirectory + "/data/groups.json"));
|
||||
if (!string.IsNullOrEmpty(adminsFile))
|
||||
AddTimer(4.0f, () => AdminManager.LoadAdminData(ModuleDirectory + "/data/admins.json"));
|
||||
|
||||
_logger?.LogInformation("Loaded admins!");
|
||||
_logger?.LogInformation("Loaded admins!");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -426,6 +527,11 @@ public partial class CS2_SimpleAdmin
|
||||
//_ = _adminManager.GiveAllFlags();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles player visibility on the server, hiding or revealing them.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the hide command.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnHideCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -438,7 +544,9 @@ public partial class CS2_SimpleAdmin
|
||||
{
|
||||
SilentPlayers.Remove(caller.Slot);
|
||||
caller.PrintToChat($"You aren't hidden now!");
|
||||
caller.ChangeTeam(CsTeam.Spectator);
|
||||
if (caller.TeamNum <= 1)
|
||||
caller.ChangeTeam(CsTeam.Spectator);
|
||||
SimpleAdminApi?.OnAdminToggleSilentEvent(caller.Slot, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -447,13 +555,20 @@ public partial class CS2_SimpleAdmin
|
||||
if (caller.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
caller.PlayerPawn.Value?.CommitSuicide(true, false);
|
||||
|
||||
AddTimer(1.0f, () => { Server.NextFrame(() => caller.ChangeTeam(CsTeam.Spectator)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
AddTimer(1.4f, () => { Server.NextFrame(() => caller.ChangeTeam(CsTeam.None)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
caller.PrintToChat($"You are hidden now!");
|
||||
AddTimer(2.0f, () => { Server.NextFrame(() => Server.ExecuteCommand("sv_disable_teamselect_menu 0")); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
if (caller.TeamNum > 1)
|
||||
AddTimer(0.15f, () => { Server.NextWorldUpdate(() => caller.ChangeTeam(CsTeam.Spectator)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
AddTimer(0.26f, () => { Server.NextWorldUpdate(() => caller.ChangeTeam(CsTeam.None)); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
AddTimer(0.50f, () => { Server.NextWorldUpdate(() => Server.ExecuteCommand("sv_disable_teamselect_menu 0")); }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
||||
SimpleAdminApi?.OnAdminToggleSilentEvent(caller.Slot, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles penalty notification visibility to admins.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player toggling notification visibility.</param>
|
||||
/// <param name="command">Command input parameters.</param>
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnHideCommsCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -473,11 +588,16 @@ public partial class CS2_SimpleAdmin
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays detailed information about target players, including admin groups, permissions, and penalties.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">Command input parameters including targets.</param>
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
public void OnWhoCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
@@ -491,39 +611,41 @@ public partial class CS2_SimpleAdmin
|
||||
if (!player.UserId.HasValue) return;
|
||||
if (!caller!.CanTarget(player)) return;
|
||||
|
||||
var playerInfo = PlayersInfo[player.UserId.Value];
|
||||
var playerInfo = PlayersInfo[player.SteamID];
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Server.NextFrameAsync(() =>
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
Action<string> printMethod = caller == null ? Server.PrintToConsole : caller.PrintToConsole;
|
||||
|
||||
|
||||
var adminData = AdminManager.GetPlayerAdminData(new SteamID(player.SteamID));
|
||||
|
||||
printMethod($"--------- INFO ABOUT \"{playerInfo.Name}\" ---------");
|
||||
|
||||
printMethod($"• Clan: \"{player.Clan}\" Name: \"{playerInfo.Name}\"");
|
||||
printMethod($"• UserID: \"{playerInfo.UserId}\"");
|
||||
printMethod($"• SteamID64: \"{playerInfo.SteamId.SteamId64}\"");
|
||||
if (player.Connected == PlayerConnectedState.PlayerConnected)
|
||||
if (adminData != null)
|
||||
{
|
||||
printMethod($"• SteamID2: \"{playerInfo.SteamId.SteamId2}\"");
|
||||
printMethod($"• Community link: \"{playerInfo.SteamId.ToCommunityUrl()}\"");
|
||||
var flags = string.Join(",", adminData._flags);
|
||||
var groups = string.Join(",", adminData.Groups);
|
||||
|
||||
printMethod($"• Groups/Flags: \"{groups}{flags}\"");
|
||||
}
|
||||
printMethod($"• SteamID2: \"{playerInfo.SteamId.SteamId2}\"");
|
||||
printMethod($"• Community link: \"{playerInfo.SteamId.ToCommunityUrl()}\"");
|
||||
if (playerInfo.IpAddress != null && AdminManager.PlayerHasPermissions(new SteamID(caller!.SteamID), "@css/showip"))
|
||||
printMethod($"• IP Address: \"{playerInfo.IpAddress}\"");
|
||||
printMethod($"• Ping: \"{player.Ping}\"");
|
||||
if (player.Connected == PlayerConnectedState.PlayerConnected)
|
||||
{
|
||||
printMethod($"• Total Bans: \"{playerInfo.TotalBans}\"");
|
||||
printMethod($"• Total Gags: \"{playerInfo.TotalGags}\"");
|
||||
printMethod($"• Total Mutes: \"{playerInfo.TotalMutes}\"");
|
||||
printMethod($"• Total Silences: \"{playerInfo.TotalSilences}\"");
|
||||
printMethod($"• Total Warns: \"{playerInfo.TotalWarns}\"");
|
||||
printMethod($"• Total Bans: \"{playerInfo.TotalBans}\"");
|
||||
printMethod($"• Total Gags: \"{playerInfo.TotalGags}\"");
|
||||
printMethod($"• Total Mutes: \"{playerInfo.TotalMutes}\"");
|
||||
printMethod($"• Total Silences: \"{playerInfo.TotalSilences}\"");
|
||||
printMethod($"• Total Warns: \"{playerInfo.TotalWarns}\"");
|
||||
|
||||
var chunkedAccounts = playerInfo.AccountsAssociated.ChunkBy(3).ToList();
|
||||
foreach (var chunk in chunkedAccounts)
|
||||
printMethod($"• Associated Accounts: \"{string.Join(", ", chunk.Select(a => $"{a.PlayerName} ({a.SteamId})"))}\"");
|
||||
}
|
||||
var chunkedAccounts = playerInfo.AccountsAssociated.ChunkBy(3).ToList();
|
||||
foreach (var chunk in chunkedAccounts)
|
||||
printMethod($"• Associated Accounts: \"{string.Join(", ", chunk.Select(a => $"{a.PlayerName} ({a.SteamId})"))}\"");
|
||||
|
||||
printMethod($"--------- END INFO ABOUT \"{player.PlayerName}\" ---------");
|
||||
});
|
||||
@@ -531,6 +653,11 @@ public partial class CS2_SimpleAdmin
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a menu with disconnected players, allowing the caller to apply penalties like ban, mute, gag, or silence.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command containing parameters.</param>
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnDisconnectedCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -652,11 +779,17 @@ public partial class CS2_SimpleAdmin
|
||||
disconnectedMenu?.Open(caller);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays the warning menu for a player specified by a command argument,
|
||||
/// showing active and past warns with options to remove them.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command containing target player identifier.</param>
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnWarnsCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null || _localizer == null || caller == null) return;
|
||||
if (DatabaseProvider == null || _localizer == null || caller == null) return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null) return;
|
||||
@@ -673,12 +806,13 @@ public partial class CS2_SimpleAdmin
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
||||
var userId = player.UserId.Value;
|
||||
var steamId = player.SteamID;
|
||||
|
||||
IMenu? warnsMenu = Helper.CreateMenu(_localizer["sa_admin_warns_menu_title", player.PlayerName]);
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var warnsList = await WarnManager.GetPlayerWarns(PlayersInfo[userId], false);
|
||||
var warnsList = await WarnManager.GetPlayerWarns(PlayersInfo[steamId], false);
|
||||
var sortedWarns = warnsList
|
||||
.OrderBy(warn => (string)warn.status == "ACTIVE" ? 0 : 1)
|
||||
.ThenByDescending(warn => (int)warn.id)
|
||||
@@ -689,12 +823,12 @@ public partial class CS2_SimpleAdmin
|
||||
warnsMenu?.AddMenuOption($"[{((string)w.status == "ACTIVE" ? $"{ChatColors.LightRed}X" : $"{ChatColors.Lime}✔️")}{ChatColors.Default}] {(string)w.reason}",
|
||||
(controller, option) =>
|
||||
{
|
||||
_ = WarnManager.UnwarnPlayer(PlayersInfo[userId], (int)w.id);
|
||||
_ = WarnManager.UnwarnPlayer(PlayersInfo[steamId], (int)w.id);
|
||||
player.PrintToChat(_localizer["sa_admin_warns_unwarn", player.PlayerName, (string)w.reason]);
|
||||
});
|
||||
});
|
||||
|
||||
await Server.NextFrameAsync(() =>
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
warnsMenu?.Open(caller);
|
||||
});
|
||||
@@ -702,8 +836,14 @@ public partial class CS2_SimpleAdmin
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lists players currently connected to the server with options to output JSON or filter duplicate IPs.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command or null for console.</param>
|
||||
/// <param name="command">The command containing output options.</param>
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||
public void OnPlayersCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var isJson = command.GetArg(1).ToLower().Equals("-json");
|
||||
@@ -740,27 +880,39 @@ public partial class CS2_SimpleAdmin
|
||||
}
|
||||
else
|
||||
{
|
||||
var playersJson = JsonConvert.SerializeObject(playersToTarget.Select(player =>
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
var matchStats = player.ActionTrackingServices?.MatchStats;
|
||||
|
||||
return new
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
var playerDtos = playersToTarget
|
||||
.Where(player => player.UserId.HasValue)
|
||||
.Select(player =>
|
||||
{
|
||||
player.UserId,
|
||||
Name = player.PlayerName,
|
||||
SteamId = player.SteamID.ToString(),
|
||||
IpAddress = AdminManager.PlayerHasPermissions(new SteamID(caller!.SteamID), "@css/showip") ? player.IpAddress?.Split(":")[0] ?? "Unknown" : "Unknown",
|
||||
player.Ping,
|
||||
IsAdmin = AdminManager.PlayerHasPermissions(new SteamID(player.SteamID), "@css/ban") || AdminManager.PlayerHasPermissions(new SteamID(player.SteamID), "@css/generic"),
|
||||
Stats = new
|
||||
{
|
||||
player.Score,
|
||||
Kills = matchStats?.Kills ?? 0,
|
||||
Deaths = matchStats?.Deaths ?? 0,
|
||||
player.MVPs
|
||||
}
|
||||
};
|
||||
}));
|
||||
var matchStats = player.ActionTrackingServices?.MatchStats;
|
||||
|
||||
return new PlayerDto(
|
||||
player.UserId.GetValueOrDefault(0),
|
||||
player.PlayerName,
|
||||
player.SteamID.ToString(),
|
||||
AdminManager.PlayerHasPermissions(new SteamID(caller!.SteamID), "@css/showip")
|
||||
? player.IpAddress?.Split(":")[0] ?? "Unknown"
|
||||
: "Unknown",
|
||||
player.Ping,
|
||||
AdminManager.PlayerHasPermissions(new SteamID(player.SteamID), "@css/ban")
|
||||
|| AdminManager.PlayerHasPermissions(new SteamID(player.SteamID), "@css/generic"),
|
||||
new PlayerStats(
|
||||
player.Score,
|
||||
matchStats?.Kills ?? 0,
|
||||
matchStats?.Deaths ?? 0,
|
||||
player.MVPs
|
||||
)
|
||||
);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var playersJson = JsonSerializer.Serialize(playerDtos, options);
|
||||
|
||||
if (caller != null)
|
||||
caller.PrintToConsole(playersJson);
|
||||
@@ -769,6 +921,11 @@ public partial class CS2_SimpleAdmin
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues a kick to one or multiple players specified in the command arguments.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the kick command.</param>
|
||||
/// <param name="command">The command with target player(s) and optional reason.</param>
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnKickCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -806,6 +963,15 @@ public partial class CS2_SimpleAdmin
|
||||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Kicks a specified player immediately with reason, notifying the server and logging the action.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the kick.</param>
|
||||
/// <param name="player">The player to be kicked.</param>
|
||||
/// <param name="reason">The reason for the kick.</param>
|
||||
/// <param name="callerName">Optional name of the kick issuer for notifications.</param>
|
||||
/// <param name="command">Optional command for logging.</param>
|
||||
public void Kick(CCSPlayerController? caller, CCSPlayerController player, string? reason = "Unknown", string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
@@ -816,8 +982,8 @@ public partial class CS2_SimpleAdmin
|
||||
callerName ??= caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console";
|
||||
reason ??= _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
var playerInfo = PlayersInfo[player.UserId.Value];
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var playerInfo = PlayersInfo[player.SteamID];
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
// Determine message keys and arguments for the kick notification
|
||||
var (messageKey, activityMessageKey, centerArgs, adminActivityArgs) =
|
||||
@@ -847,6 +1013,11 @@ public partial class CS2_SimpleAdmin
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Kick, reason, -1, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current map to the specified map name or workshop map ID.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the map change.</param>
|
||||
/// <param name="command">The command containing the map name or ID.</param>
|
||||
[RequiresPermissions("@css/changemap")]
|
||||
[CommandHelper(minArgs: 1, usage: "<mapname>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnMapCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -855,6 +1026,12 @@ public partial class CS2_SimpleAdmin
|
||||
ChangeMap(caller, map, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes to a specified map, validating it or handling workshop maps, and notifying the server and admins.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the change.</param>
|
||||
/// <param name="map">The map name or identifier.</param>
|
||||
/// <param name="command">Optional command object for logging and replies.</param>
|
||||
public void ChangeMap(CCSPlayerController? caller, string map, CommandInfo? command = null)
|
||||
{
|
||||
var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console";
|
||||
@@ -904,6 +1081,11 @@ public partial class CS2_SimpleAdmin
|
||||
Helper.LogCommand(caller, command?.GetCommandString ?? $"css_map {map}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current map to a workshop map specified by name or ID.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command containing the workshop map identifier.</param>
|
||||
[CommandHelper(1, "<name or id>")]
|
||||
[RequiresPermissions("@css/changemap")]
|
||||
public void OnWorkshopMapCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -912,6 +1094,12 @@ public partial class CS2_SimpleAdmin
|
||||
ChangeWorkshopMap(caller, map, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes to a specified workshop map by name or ID and notifies admins.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="map">The workshop map identifier.</param>
|
||||
/// <param name="command">Optional command for logging.</param>
|
||||
public void ChangeWorkshopMap(CCSPlayerController? caller, string map, CommandInfo? command = null)
|
||||
{
|
||||
map = map.ToLower();
|
||||
@@ -941,6 +1129,11 @@ public partial class CS2_SimpleAdmin
|
||||
Helper.LogCommand(caller, command?.GetCommandString ?? $"css_wsmap {map}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows changing a console variable's value.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command with cvar name and value.</param>
|
||||
[CommandHelper(2, "<cvar> <value>")]
|
||||
[RequiresPermissions("@css/cvar")]
|
||||
public void OnCvarCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -961,28 +1154,33 @@ public partial class CS2_SimpleAdmin
|
||||
}
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
var value = command.GetArg(2);
|
||||
|
||||
Server.ExecuteCommand($"{cvar.Name} {value}");
|
||||
|
||||
command.ReplyToCommand($"{callerName} changed cvar {cvar.Name} to {value}.");
|
||||
Logger.LogInformation($"{callerName} changed cvar {cvar.Name} to {value}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an RCON command on the server.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command string to execute via RCON.</param>
|
||||
[CommandHelper(1, "<command>")]
|
||||
[RequiresPermissions("@css/rcon")]
|
||||
public void OnRconCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
Server.ExecuteCommand(command.ArgString);
|
||||
command.ReplyToCommand($"{callerName} executed command {command.ArgString}.");
|
||||
Logger.LogInformation($"{callerName} executed command ({command.ArgString}).");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restarts the game.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player or console initiating the restart.</param>
|
||||
/// <param name="command">The restart command info.</param>
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[CommandHelper(minArgs: 0, usage: "", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnRestartCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
@@ -990,6 +1188,11 @@ public partial class CS2_SimpleAdmin
|
||||
RestartGame(caller);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens plugin manager menu for the caller with options to load or unload plugins.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player opening the plugin manager.</param>
|
||||
/// <param name="commandInfo">The command parameters.</param>
|
||||
[RequiresPermissions("@css/root")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_ONLY)]
|
||||
public void OnPluginManagerCommand(CCSPlayerController? caller, CommandInfo commandInfo)
|
||||
@@ -1060,6 +1263,10 @@ public partial class CS2_SimpleAdmin
|
||||
pluginsMenu?.Open(caller);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restarts the game process by issuing the restart game command to the server and logging the action.
|
||||
/// </summary>
|
||||
/// <param name="admin">The admin or console requesting the restart.</param>
|
||||
public static void RestartGame(CCSPlayerController? admin)
|
||||
{
|
||||
Helper.LogCommand(admin, "css_restartgame");
|
||||
|
||||
Reference in New Issue
Block a user