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:
parent
b97426313b
commit
5701455de0
111 changed files with 5387 additions and 2871 deletions
|
|
@ -1,89 +1,99 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CS2_SimpleAdmin;
|
||||
|
||||
public static class RegisterCommands
|
||||
{
|
||||
internal static readonly Dictionary<string, IList<CommandDefinition>> _commandDefinitions =
|
||||
new(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
private delegate void CommandCallback(CCSPlayerController? caller, CommandInfo.CommandCallback callback);
|
||||
|
||||
private static readonly string CommandsPath = Path.Combine(CS2_SimpleAdmin.ConfigDirectory, "Commands.json");
|
||||
private static readonly List<CommandMapping> CommandMappings =
|
||||
[
|
||||
new CommandMapping("css_ban", CS2_SimpleAdmin.Instance.OnBanCommand),
|
||||
new CommandMapping("css_addban", CS2_SimpleAdmin.Instance.OnAddBanCommand),
|
||||
new CommandMapping("css_banip", CS2_SimpleAdmin.Instance.OnBanIpCommand),
|
||||
new CommandMapping("css_unban", CS2_SimpleAdmin.Instance.OnUnbanCommand),
|
||||
new CommandMapping("css_warn", CS2_SimpleAdmin.Instance.OnWarnCommand),
|
||||
new CommandMapping("css_unwarn", CS2_SimpleAdmin.Instance.OnUnwarnCommand),
|
||||
new("css_ban", CS2_SimpleAdmin.Instance.OnBanCommand),
|
||||
new("css_addban", CS2_SimpleAdmin.Instance.OnAddBanCommand),
|
||||
new("css_banip", CS2_SimpleAdmin.Instance.OnBanIpCommand),
|
||||
new("css_unban", CS2_SimpleAdmin.Instance.OnUnbanCommand),
|
||||
new("css_warn", CS2_SimpleAdmin.Instance.OnWarnCommand),
|
||||
new("css_unwarn", CS2_SimpleAdmin.Instance.OnUnwarnCommand),
|
||||
|
||||
new CommandMapping("css_asay", CS2_SimpleAdmin.Instance.OnAdminToAdminSayCommand),
|
||||
new CommandMapping("css_cssay", CS2_SimpleAdmin.Instance.OnAdminCustomSayCommand),
|
||||
new CommandMapping("css_say", CS2_SimpleAdmin.Instance.OnAdminSayCommand),
|
||||
new CommandMapping("css_psay", CS2_SimpleAdmin.Instance.OnAdminPrivateSayCommand),
|
||||
new CommandMapping("css_csay", CS2_SimpleAdmin.Instance.OnAdminCenterSayCommand),
|
||||
new CommandMapping("css_hsay", CS2_SimpleAdmin.Instance.OnAdminHudSayCommand),
|
||||
new("css_asay", CS2_SimpleAdmin.Instance.OnAdminToAdminSayCommand),
|
||||
new("css_cssay", CS2_SimpleAdmin.Instance.OnAdminCustomSayCommand),
|
||||
new("css_say", CS2_SimpleAdmin.Instance.OnAdminSayCommand),
|
||||
new("css_psay", CS2_SimpleAdmin.Instance.OnAdminPrivateSayCommand),
|
||||
new("css_csay", CS2_SimpleAdmin.Instance.OnAdminCenterSayCommand),
|
||||
new("css_hsay", CS2_SimpleAdmin.Instance.OnAdminHudSayCommand),
|
||||
|
||||
new CommandMapping("css_penalties", CS2_SimpleAdmin.Instance.OnPenaltiesCommand),
|
||||
new CommandMapping("css_admin", CS2_SimpleAdmin.Instance.OnAdminCommand),
|
||||
new CommandMapping("css_adminhelp", CS2_SimpleAdmin.Instance.OnAdminHelpCommand),
|
||||
new CommandMapping("css_addadmin", CS2_SimpleAdmin.Instance.OnAddAdminCommand),
|
||||
new CommandMapping("css_deladmin", CS2_SimpleAdmin.Instance.OnDelAdminCommand),
|
||||
new CommandMapping("css_addgroup", CS2_SimpleAdmin.Instance.OnAddGroup),
|
||||
new CommandMapping("css_delgroup", CS2_SimpleAdmin.Instance.OnDelGroupCommand),
|
||||
new CommandMapping("css_reloadadmins", CS2_SimpleAdmin.Instance.OnRelAdminCommand),
|
||||
new CommandMapping("css_reloadbans", CS2_SimpleAdmin.Instance.OnRelBans),
|
||||
new CommandMapping("css_hide", CS2_SimpleAdmin.Instance.OnHideCommand),
|
||||
new CommandMapping("css_hidecomms", CS2_SimpleAdmin.Instance.OnHideCommsCommand),
|
||||
new CommandMapping("css_who", CS2_SimpleAdmin.Instance.OnWhoCommand),
|
||||
new CommandMapping("css_disconnected", CS2_SimpleAdmin.Instance.OnDisconnectedCommand),
|
||||
new CommandMapping("css_warns", CS2_SimpleAdmin.Instance.OnWarnsCommand),
|
||||
new CommandMapping("css_players", CS2_SimpleAdmin.Instance.OnPlayersCommand),
|
||||
new CommandMapping("css_kick", CS2_SimpleAdmin.Instance.OnKickCommand),
|
||||
new CommandMapping("css_map", CS2_SimpleAdmin.Instance.OnMapCommand),
|
||||
new CommandMapping("css_wsmap", CS2_SimpleAdmin.Instance.OnWorkshopMapCommand),
|
||||
new CommandMapping("css_cvar", CS2_SimpleAdmin.Instance.OnCvarCommand),
|
||||
new CommandMapping("css_rcon", CS2_SimpleAdmin.Instance.OnRconCommand),
|
||||
new CommandMapping("css_rr", CS2_SimpleAdmin.Instance.OnRestartCommand),
|
||||
new("css_penalties", CS2_SimpleAdmin.Instance.OnPenaltiesCommand),
|
||||
new("css_admin", CS2_SimpleAdmin.Instance.OnAdminCommand),
|
||||
new("css_adminhelp", CS2_SimpleAdmin.Instance.OnAdminHelpCommand),
|
||||
new("css_addadmin", CS2_SimpleAdmin.Instance.OnAddAdminCommand),
|
||||
new("css_deladmin", CS2_SimpleAdmin.Instance.OnDelAdminCommand),
|
||||
new("css_addgroup", CS2_SimpleAdmin.Instance.OnAddGroup),
|
||||
new("css_delgroup", CS2_SimpleAdmin.Instance.OnDelGroupCommand),
|
||||
new("css_reloadadmins", CS2_SimpleAdmin.Instance.OnRelAdminCommand),
|
||||
new("css_reloadbans", CS2_SimpleAdmin.Instance.OnRelBans),
|
||||
new("css_hide", CS2_SimpleAdmin.Instance.OnHideCommand),
|
||||
new("css_hidecomms", CS2_SimpleAdmin.Instance.OnHideCommsCommand),
|
||||
new("css_who", CS2_SimpleAdmin.Instance.OnWhoCommand),
|
||||
new("css_disconnected", CS2_SimpleAdmin.Instance.OnDisconnectedCommand),
|
||||
new("css_warns", CS2_SimpleAdmin.Instance.OnWarnsCommand),
|
||||
new("css_players", CS2_SimpleAdmin.Instance.OnPlayersCommand),
|
||||
new("css_kick", CS2_SimpleAdmin.Instance.OnKickCommand),
|
||||
new("css_map", CS2_SimpleAdmin.Instance.OnMapCommand),
|
||||
new("css_wsmap", CS2_SimpleAdmin.Instance.OnWorkshopMapCommand),
|
||||
new("css_cvar", CS2_SimpleAdmin.Instance.OnCvarCommand),
|
||||
new("css_rcon", CS2_SimpleAdmin.Instance.OnRconCommand),
|
||||
new("css_rr", CS2_SimpleAdmin.Instance.OnRestartCommand),
|
||||
|
||||
new CommandMapping("css_gag", CS2_SimpleAdmin.Instance.OnGagCommand),
|
||||
new CommandMapping("css_addgag", CS2_SimpleAdmin.Instance.OnAddGagCommand),
|
||||
new CommandMapping("css_ungag", CS2_SimpleAdmin.Instance.OnUngagCommand),
|
||||
new CommandMapping("css_mute", CS2_SimpleAdmin.Instance.OnMuteCommand),
|
||||
new CommandMapping("css_addmute", CS2_SimpleAdmin.Instance.OnAddMuteCommand),
|
||||
new CommandMapping("css_unmute", CS2_SimpleAdmin.Instance.OnUnmuteCommand),
|
||||
new CommandMapping("css_silence", CS2_SimpleAdmin.Instance.OnSilenceCommand),
|
||||
new CommandMapping("css_addsilence", CS2_SimpleAdmin.Instance.OnAddSilenceCommand),
|
||||
new CommandMapping("css_unsilence", CS2_SimpleAdmin.Instance.OnUnsilenceCommand),
|
||||
new("css_gag", CS2_SimpleAdmin.Instance.OnGagCommand),
|
||||
new("css_addgag", CS2_SimpleAdmin.Instance.OnAddGagCommand),
|
||||
new("css_ungag", CS2_SimpleAdmin.Instance.OnUngagCommand),
|
||||
new("css_mute", CS2_SimpleAdmin.Instance.OnMuteCommand),
|
||||
new("css_addmute", CS2_SimpleAdmin.Instance.OnAddMuteCommand),
|
||||
new("css_unmute", CS2_SimpleAdmin.Instance.OnUnmuteCommand),
|
||||
new("css_silence", CS2_SimpleAdmin.Instance.OnSilenceCommand),
|
||||
new("css_addsilence", CS2_SimpleAdmin.Instance.OnAddSilenceCommand),
|
||||
new("css_unsilence", CS2_SimpleAdmin.Instance.OnUnsilenceCommand),
|
||||
|
||||
new CommandMapping("css_vote", CS2_SimpleAdmin.Instance.OnVoteCommand),
|
||||
new("css_vote", CS2_SimpleAdmin.Instance.OnVoteCommand),
|
||||
|
||||
new CommandMapping("css_noclip", CS2_SimpleAdmin.Instance.OnNoclipCommand),
|
||||
new CommandMapping("css_freeze", CS2_SimpleAdmin.Instance.OnFreezeCommand),
|
||||
new CommandMapping("css_unfreeze", CS2_SimpleAdmin.Instance.OnUnfreezeCommand),
|
||||
new CommandMapping("css_godmode", CS2_SimpleAdmin.Instance.OnGodCommand),
|
||||
new("css_noclip", CS2_SimpleAdmin.Instance.OnNoclipCommand),
|
||||
new("css_freeze", CS2_SimpleAdmin.Instance.OnFreezeCommand),
|
||||
new("css_unfreeze", CS2_SimpleAdmin.Instance.OnUnfreezeCommand),
|
||||
new("css_godmode", CS2_SimpleAdmin.Instance.OnGodCommand),
|
||||
|
||||
new CommandMapping("css_slay", CS2_SimpleAdmin.Instance.OnSlayCommand),
|
||||
new CommandMapping("css_slap", CS2_SimpleAdmin.Instance.OnSlapCommand),
|
||||
new CommandMapping("css_give", CS2_SimpleAdmin.Instance.OnGiveCommand),
|
||||
new CommandMapping("css_strip", CS2_SimpleAdmin.Instance.OnStripCommand),
|
||||
new CommandMapping("css_hp", CS2_SimpleAdmin.Instance.OnHpCommand),
|
||||
new CommandMapping("css_speed", CS2_SimpleAdmin.Instance.OnSpeedCommand),
|
||||
new CommandMapping("css_gravity", CS2_SimpleAdmin.Instance.OnGravityCommand),
|
||||
new CommandMapping("css_resize", CS2_SimpleAdmin.Instance.OnResizeCommand),
|
||||
new CommandMapping("css_money", CS2_SimpleAdmin.Instance.OnMoneyCommand),
|
||||
new CommandMapping("css_team", CS2_SimpleAdmin.Instance.OnTeamCommand),
|
||||
new CommandMapping("css_rename", CS2_SimpleAdmin.Instance.OnRenameCommand),
|
||||
new CommandMapping("css_prename", CS2_SimpleAdmin.Instance.OnPrenameCommand),
|
||||
new CommandMapping("css_respawn", CS2_SimpleAdmin.Instance.OnRespawnCommand),
|
||||
new CommandMapping("css_tp", CS2_SimpleAdmin.Instance.OnGotoCommand),
|
||||
new CommandMapping("css_bring", CS2_SimpleAdmin.Instance.OnBringCommand),
|
||||
new CommandMapping("css_pluginsmanager", CS2_SimpleAdmin.Instance.OnPluginManagerCommand),
|
||||
new CommandMapping("css_adminvoice", CS2_SimpleAdmin.Instance.OnAdminVoiceCommand)
|
||||
new("css_slay", CS2_SimpleAdmin.Instance.OnSlayCommand),
|
||||
new("css_slap", CS2_SimpleAdmin.Instance.OnSlapCommand),
|
||||
new("css_give", CS2_SimpleAdmin.Instance.OnGiveCommand),
|
||||
new("css_strip", CS2_SimpleAdmin.Instance.OnStripCommand),
|
||||
new("css_hp", CS2_SimpleAdmin.Instance.OnHpCommand),
|
||||
new("css_speed", CS2_SimpleAdmin.Instance.OnSpeedCommand),
|
||||
new("css_gravity", CS2_SimpleAdmin.Instance.OnGravityCommand),
|
||||
new("css_resize", CS2_SimpleAdmin.Instance.OnResizeCommand),
|
||||
new("css_money", CS2_SimpleAdmin.Instance.OnMoneyCommand),
|
||||
new("css_team", CS2_SimpleAdmin.Instance.OnTeamCommand),
|
||||
new("css_rename", CS2_SimpleAdmin.Instance.OnRenameCommand),
|
||||
new("css_prename", CS2_SimpleAdmin.Instance.OnPrenameCommand),
|
||||
new("css_respawn", CS2_SimpleAdmin.Instance.OnRespawnCommand),
|
||||
new("css_tp", CS2_SimpleAdmin.Instance.OnGotoCommand),
|
||||
new("css_bring", CS2_SimpleAdmin.Instance.OnBringCommand),
|
||||
new("css_pluginsmanager", CS2_SimpleAdmin.Instance.OnPluginManagerCommand),
|
||||
new("css_adminvoice", CS2_SimpleAdmin.Instance.OnAdminVoiceCommand)
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Initializes command registration.
|
||||
/// If the commands config file does not exist, creates it and then recurses to register commands.
|
||||
/// Otherwise, directly registers commands from the configuration.
|
||||
/// </summary>
|
||||
public static void InitializeCommands()
|
||||
{
|
||||
if (!File.Exists(CommandsPath))
|
||||
|
|
@ -97,6 +107,10 @@ public static class RegisterCommands
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the default commands configuration JSON file with built-in commands and aliases.
|
||||
/// </summary>
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||
private static void CreateConfig()
|
||||
{
|
||||
var commands = new CommandsConfig
|
||||
|
|
@ -170,14 +184,26 @@ public static class RegisterCommands
|
|||
}
|
||||
};
|
||||
|
||||
var json = JsonConvert.SerializeObject(commands, Formatting.Indented);
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(commands, options);
|
||||
File.WriteAllText(CommandsPath, json);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the command configuration JSON file and registers all commands and their aliases with their callbacks.
|
||||
/// Also registers any custom commands previously stored.
|
||||
/// </summary>
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||
private static void Register()
|
||||
{
|
||||
var json = File.ReadAllText(CommandsPath);
|
||||
var commandsConfig = JsonConvert.DeserializeObject<CommandsConfig>(json);
|
||||
var commandsConfig = JsonSerializer.Deserialize<CommandsConfig>(json,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
|
||||
if (commandsConfig?.Commands == null) return;
|
||||
|
||||
|
|
@ -195,19 +221,37 @@ public static class RegisterCommands
|
|||
{
|
||||
CS2_SimpleAdmin.Instance.AddCommand(alias, "", mapping.Callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (name, definitions) in RegisterCommands._commandDefinitions)
|
||||
{
|
||||
foreach (var definition in definitions)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogInformation($"Registering custom command: `{name}`");
|
||||
CS2_SimpleAdmin.Instance.AddCommand(name, definition.Description, definition.Callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the JSON configuration structure for commands.
|
||||
/// </summary>
|
||||
private class CommandsConfig
|
||||
{
|
||||
public Dictionary<string, Command>? Commands { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a command definition containing a list of aliases.
|
||||
/// </summary>
|
||||
private class Command
|
||||
{
|
||||
public string[]? Aliases { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a command key to its respective command callback handler.
|
||||
/// </summary>
|
||||
private class CommandMapping(string commandKey, CommandInfo.CommandCallback callback)
|
||||
{
|
||||
public string CommandKey { get; } = commandKey;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,11 @@ namespace CS2_SimpleAdmin;
|
|||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the 'ban' command, allowing admins to ban one or more valid connected players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the ban command, or null for console.</param>
|
||||
/// <param name="command">The command information including arguments.</param>
|
||||
[RequiresPermissions("@css/ban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnBanCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -51,9 +56,20 @@ public partial class CS2_SimpleAdmin
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core logic to ban a specific player, scheduling database updates, notifications, and kicks.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the ban, or null for console.</param>
|
||||
/// <param name="player">The player to be banned.</param>
|
||||
/// <param name="time">Ban duration in minutes; 0 means permanent.</param>
|
||||
/// <param name="reason">Reason for the ban.</param>
|
||||
/// <param name="callerName">Optional caller name string. If null, defaults to player name or console.</param>
|
||||
/// <param name="banManager">Optional BanManager to handle ban persistence.</param>
|
||||
/// <param name="command">Optional command info object for logging.</param>
|
||||
/// <param name="silent">If true, suppresses command logging.</param>
|
||||
internal void Ban(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, BanManager? banManager = null, CommandInfo? command = null, bool silent = false)
|
||||
{
|
||||
if (Database == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (DatabaseProvider == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
if (!CheckValidBan(caller, time)) return;
|
||||
|
||||
|
|
@ -63,14 +79,17 @@ public partial class CS2_SimpleAdmin
|
|||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
// Get player and admin information
|
||||
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;
|
||||
|
||||
// Asynchronously handle banning logic
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await BanManager.BanPlayer(playerInfo, adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Ban, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Ban, reason, time, penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
// Determine message keys and arguments based on ban time
|
||||
|
|
@ -114,6 +133,14 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Ban, _localizer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a ban for a player by their SteamID, including offline bans.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the ban command.</param>
|
||||
/// <param name="steamid">SteamID of the player to ban.</param>
|
||||
/// <param name="time">Ban duration in minutes (0 means permanent).</param>
|
||||
/// <param name="reason">Reason for banning.</param>
|
||||
/// <param name="banManager">Optional ban manager for database operations.</param>
|
||||
internal void AddBan(CCSPlayerController? caller, SteamID steamid, int time, string reason, BanManager? banManager = null)
|
||||
{
|
||||
// Set default caller name if not provided
|
||||
|
|
@ -121,15 +148,12 @@ public partial class CS2_SimpleAdmin
|
|||
? caller.PlayerName
|
||||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64);
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
if (!caller.CanTarget(player))
|
||||
return;
|
||||
|
||||
Ban(caller, player, time, reason, callerName, silent: true);
|
||||
//command.ReplyToCommand($"Banned player {player.PlayerName}.");
|
||||
}
|
||||
|
|
@ -137,23 +161,31 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
if (!caller.CanTarget(steamid))
|
||||
return;
|
||||
|
||||
// Asynchronous ban operation if player is not online or not found
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await BanManager.AddBanBySteamid(steamid.SteamId64.ToString(), adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Ban, reason, time, penaltyId);
|
||||
int? penaltyId = await BanManager.AddBanBySteamid(steamid.SteamId64, adminInfo, reason, time);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Ban, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.SteamId64.ToString(), reason, time, PenaltyType.Ban, _localizer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles banning a player by specifying their SteamID via command.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command, or null if console.</param>
|
||||
/// <param name="command">Command information including arguments (SteamID, time, reason).</param>
|
||||
[RequiresPermissions("@css/ban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnAddBanCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
var callerName = caller?.PlayerName ?? _localizer?["sa_console"] ?? "Console";
|
||||
if (command.ArgCount < 2 || string.IsNullOrEmpty(command.GetArg(1))) return;
|
||||
if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null)
|
||||
|
|
@ -162,7 +194,7 @@ public partial class CS2_SimpleAdmin
|
|||
return;
|
||||
}
|
||||
|
||||
var steamid = steamId.SteamId64.ToString();
|
||||
var steamid = steamId.SteamId64;
|
||||
var reason = command.ArgCount >= 3
|
||||
? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
|
||||
: _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
|
@ -170,15 +202,13 @@ public partial class CS2_SimpleAdmin
|
|||
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
|
||||
|
||||
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
|
||||
|
||||
if (!CheckValidBan(caller, time)) return;
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue
|
||||
? PlayersInfo[caller.UserId.Value]
|
||||
? PlayersInfo[caller.SteamID]
|
||||
: null;
|
||||
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
if (!caller.CanTarget(player))
|
||||
|
|
@ -196,10 +226,14 @@ public partial class CS2_SimpleAdmin
|
|||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await BanManager.AddBanBySteamid(steamid, adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Ban, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Ban, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Ban, _localizer);
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.ToString(), reason, time, PenaltyType.Ban, _localizer);
|
||||
|
||||
command.ReplyToCommand($"Player with steamid {steamid} is not online. Ban has been added offline.");
|
||||
}
|
||||
|
|
@ -210,11 +244,16 @@ public partial class CS2_SimpleAdmin
|
|||
Server.ExecuteCommand($"banid 1 {steamId.SteamId3}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles banning a player by their IP address, supporting offline banning if player is not online.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the ban command.</param>
|
||||
/// <param name="command">The command containing the IP, time, and reason arguments.</param>
|
||||
[RequiresPermissions("@css/ban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<ip> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnBanIpCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
var callerName = caller?.PlayerName ?? _localizer?["sa_console"] ?? "Console";
|
||||
if (command.ArgCount < 2 || string.IsNullOrEmpty(command.GetArg(1))) return;
|
||||
var ipAddress = command.GetArg(1);
|
||||
|
|
@ -236,17 +275,20 @@ public partial class CS2_SimpleAdmin
|
|||
if (!CheckValidBan(caller, time)) return;
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue
|
||||
? PlayersInfo[caller.UserId.Value]
|
||||
? PlayersInfo[caller.SteamID]
|
||||
: null;
|
||||
|
||||
var player = Helper.GetPlayerFromIp(ipAddress);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
var players = Helper.GetPlayerFromIp(ipAddress);
|
||||
if (players.Count >= 1)
|
||||
{
|
||||
if (!caller.CanTarget(player))
|
||||
return;
|
||||
foreach (var player in players)
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
if (!caller.CanTarget(player))
|
||||
return;
|
||||
|
||||
Ban(caller, player, time, reason, callerName, silent: true);
|
||||
Ban(caller, player, time, reason, callerName, silent: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -262,6 +304,12 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the ban duration is valid based on the caller's permissions and configured limits.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the ban command.</param>
|
||||
/// <param name="duration">Requested ban duration in minutes.</param>
|
||||
/// <returns>True if ban duration is valid; otherwise, false.</returns>
|
||||
private bool CheckValidBan(CCSPlayerController? caller, int duration)
|
||||
{
|
||||
if (caller == null) return true;
|
||||
|
|
@ -280,14 +328,17 @@ public partial class CS2_SimpleAdmin
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles unbanning players by pattern (steamid, name, or IP).
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the unban command.</param>
|
||||
/// <param name="command">Command containing target pattern and optional reason.</param>
|
||||
[RequiresPermissions("@css/unban")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid or name or ip> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnUnbanCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
|
||||
if (DatabaseProvider == null) return;
|
||||
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
|
||||
|
||||
if (command.GetArg(1).Length <= 1)
|
||||
{
|
||||
command.ReplyToCommand($"Too short pattern to search.");
|
||||
|
|
@ -300,19 +351,21 @@ public partial class CS2_SimpleAdmin
|
|||
: _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
||||
reason = string.IsNullOrWhiteSpace(reason) ? _localizer?["sa_unknown"] ?? "Unknown" : reason;
|
||||
|
||||
Task.Run(async () => await BanManager.UnbanPlayer(pattern, callerSteamId, reason));
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
command.ReplyToCommand($"Unbanned player with pattern {pattern}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles warning players, supporting multiple targets and warning durations.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the warn command.</param>
|
||||
/// <param name="command">The command containing target, time, and reason parameters.</param>
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnWarnCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null)
|
||||
if (DatabaseProvider == null)
|
||||
return;
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
if (command.ArgCount < 2)
|
||||
|
|
@ -327,8 +380,6 @@ public partial class CS2_SimpleAdmin
|
|||
return;
|
||||
}
|
||||
|
||||
WarnManager warnManager = new(Database);
|
||||
|
||||
var time = Math.Max(0, Helper.ParsePenaltyTime(command.GetArg(2)));
|
||||
var reason = command.ArgCount >= 3
|
||||
? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
|
||||
|
|
@ -340,14 +391,23 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
if (caller!.CanTarget(player))
|
||||
{
|
||||
Warn(caller, player, time, reason, callerName, warnManager, command);
|
||||
Warn(caller, player, time, reason, callerName, command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void Warn(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, WarnManager? warnManager = null, CommandInfo? command = null)
|
||||
/// <summary>
|
||||
/// Issues a warning penalty to a specific player with optional duration and reason.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the warning.</param>
|
||||
/// <param name="player">The player to warn.</param>
|
||||
/// <param name="time">Duration of the warning in minutes.</param>
|
||||
/// <param name="reason">Reason for the warning.</param>
|
||||
/// <param name="callerName">Optional display name of the caller.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal void Warn(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (Database == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (DatabaseProvider == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
if (!CheckValidBan(caller, time)) return;
|
||||
|
||||
|
|
@ -364,18 +424,21 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
|
||||
// Get player and admin information
|
||||
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;
|
||||
|
||||
// Asynchronously handle warning logic
|
||||
Task.Run(async () =>
|
||||
{
|
||||
warnManager ??= new WarnManager(Database);
|
||||
int? penaltyId = await warnManager.WarnPlayer(playerInfo, adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Warn, reason, time, penaltyId);
|
||||
int? penaltyId = await WarnManager.WarnPlayer(playerInfo, adminInfo, reason, time);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Warn, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
|
||||
// Check for warn thresholds and execute punish command if applicable
|
||||
var totalWarns = await warnManager.GetPlayerWarnsCount(player.SteamID.ToString());
|
||||
var totalWarns = await WarnManager.GetPlayerWarnsCount(player.SteamID);
|
||||
if (Config.WarnThreshold.Count > 0)
|
||||
{
|
||||
string? punishCommand = null;
|
||||
|
|
@ -388,7 +451,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
if (!string.IsNullOrEmpty(punishCommand))
|
||||
{
|
||||
await Server.NextFrameAsync(() =>
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
Server.ExecuteCommand(punishCommand.Replace("USERID", playerInfo.UserId.ToString()).Replace("STEAMID64", playerInfo.SteamId?.ToString()));
|
||||
});
|
||||
|
|
@ -424,6 +487,14 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Warn, _localizer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a warning to a player by their SteamID, including support for offline players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the warn command.</param>
|
||||
/// <param name="steamid">SteamID of the player to warn.</param>
|
||||
/// <param name="time">Warning duration in minutes.</param>
|
||||
/// <param name="reason">Reason for the warning.</param>
|
||||
/// <param name="warnManager">Optional warn manager instance.</param>
|
||||
internal void AddWarn(CCSPlayerController? caller, SteamID steamid, int time, string reason, WarnManager? warnManager = null)
|
||||
{
|
||||
// Set default caller name if not provided
|
||||
|
|
@ -431,9 +502,9 @@ public partial class CS2_SimpleAdmin
|
|||
? caller.PlayerName
|
||||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -451,11 +522,15 @@ public partial class CS2_SimpleAdmin
|
|||
// Asynchronous ban operation if player is not online or not found
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await WarnManager.AddWarnBySteamid(steamid.SteamId64.ToString(), adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Warn, reason, time, penaltyId);
|
||||
int? penaltyId = await WarnManager.AddWarnBySteamid(steamid.SteamId64, adminInfo, reason, time);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Warn, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
|
||||
// Check for warn thresholds and execute punish command if applicable
|
||||
var totalWarns = await WarnManager.GetPlayerWarnsCount(steamid.SteamId64.ToString());
|
||||
var totalWarns = await WarnManager.GetPlayerWarnsCount(steamid.SteamId64);
|
||||
if (Config.WarnThreshold.Count > 0)
|
||||
{
|
||||
string? punishCommand = null;
|
||||
|
|
@ -468,7 +543,7 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
if (!string.IsNullOrEmpty(punishCommand))
|
||||
{
|
||||
await Server.NextFrameAsync(() =>
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
Server.ExecuteCommand(punishCommand.Replace("STEAMID64", steamid.SteamId64.ToString()));
|
||||
});
|
||||
|
|
@ -480,11 +555,16 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles removing a warning (unwarn) by a pattern string.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the unwarn command.</param>
|
||||
/// <param name="command">The command containing target pattern.</param>
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid or name or ip>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnUnwarnCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
if (command.GetArg(1).Length <= 1)
|
||||
{
|
||||
|
|
@ -493,9 +573,7 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
|
||||
var pattern = command.GetArg(1);
|
||||
|
||||
Task.Run(async () => await WarnManager.UnwarnPlayer(pattern));
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
command.ReplyToCommand($"Unwarned player with pattern {pattern}.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ namespace CS2_SimpleAdmin;
|
|||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
/// <summary>
|
||||
/// Sends a chat message only to admins that have chat permission.
|
||||
/// The message is encoded properly to handle UTF-8 characters.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin player sending the message, or null for console.</param>
|
||||
/// <param name="command">The command input containing the message.</param>
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminToAdminSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -30,6 +36,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a custom chat message to all players with color tags processed.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin or console sending the message.</param>
|
||||
/// <param name="command">The command input containing the message.</param>
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminCustomSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -47,6 +58,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a chat message to all players with localization prefix and color tags handled.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin or console sending the message.</param>
|
||||
/// <param name="command">The command input containing the message.</param>
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -57,7 +73,6 @@ public partial class CS2_SimpleAdmin
|
|||
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
|
||||
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
foreach (var player in Helper.GetValidPlayers())
|
||||
{
|
||||
player.SendLocalizedMessage(_localizer,
|
||||
|
|
@ -66,6 +81,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a private chat message from the caller to the specified target player(s).
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin or console sending the private message.</param>
|
||||
/// <param name="command">The command input containing target and message.</param>
|
||||
[CommandHelper(2, "<#userid or name> <message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminPrivateSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -92,6 +112,11 @@ public partial class CS2_SimpleAdmin
|
|||
command.ReplyToCommand($" Private message sent!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcasts a center-screen message to all players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin or console sending the message.</param>
|
||||
/// <param name="command">The command input containing the message.</param>
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminCenterSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -103,6 +128,11 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.PrintToCenterAll(utf8String.ReplaceColorTags());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a HUD alert message to all players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin or console sending the message.</param>
|
||||
/// <param name="command">The command input containing the message.</param>
|
||||
[CommandHelper(1, "<message>")]
|
||||
[RequiresPermissions("@css/chat")]
|
||||
public void OnAdminHudSayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -115,6 +145,6 @@ public partial class CS2_SimpleAdmin
|
|||
VirtualFunctions.ClientPrintAll(
|
||||
HudDestination.Alert,
|
||||
utf8String.ReplaceColorTags(),
|
||||
0, 0, 0, 0);
|
||||
0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -11,11 +11,16 @@ namespace CS2_SimpleAdmin;
|
|||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes the 'gag' command, applying a muted penalty to target players with optional time and reason.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the gag command or null for console.</param>
|
||||
/// <param name="command">The command input containing targets, time, and reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGagCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
|
|
@ -49,9 +54,19 @@ public partial class CS2_SimpleAdmin
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the gag penalty logic to an individual player, performing permission checks, notification, and logging.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the gag.</param>
|
||||
/// <param name="player">The player to gag.</param>
|
||||
/// <param name="time">Duration of the gag in minutes, 0 is permanent.</param>
|
||||
/// <param name="reason">Reason for the gag.</param>
|
||||
/// <param name="callerName">Optional caller name for notifications.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
/// <param name="silent">If true, suppresses logging notifications.</param>
|
||||
internal void Gag(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, CommandInfo? command = null, bool silent = false)
|
||||
{
|
||||
if (Database == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (DatabaseProvider == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
if (!CheckValidMute(caller, time)) return;
|
||||
|
||||
|
|
@ -59,14 +74,18 @@ public partial class CS2_SimpleAdmin
|
|||
callerName ??= caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
// Get player and admin information
|
||||
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;
|
||||
|
||||
// Asynchronously handle gag logic
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Gag, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Gag, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
// Add penalty to the player's penalty manager
|
||||
|
|
@ -91,7 +110,7 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
|
||||
// Increment the player's total gags count
|
||||
PlayersInfo[player.UserId.Value].TotalGags++;
|
||||
PlayersInfo[player.SteamID].TotalGags++;
|
||||
|
||||
// Log the gag command and send Discord notification
|
||||
if (!silent)
|
||||
|
|
@ -105,16 +124,23 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Gag, _localizer);
|
||||
}
|
||||
|
||||
internal void AddGag(CCSPlayerController? caller, SteamID steamid, int time, string reason, MuteManager? muteManager = null)
|
||||
/// <summary>
|
||||
/// Adds a gag penalty to a player identified by SteamID, supporting offline players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command or null for console.</param>
|
||||
/// <param name="steamid">SteamID of the target player.</param>
|
||||
/// <param name="time">Duration in minutes (0 for permanent).</param>
|
||||
/// <param name="reason">Reason for the gag.</param>
|
||||
internal void AddGag(CCSPlayerController? caller, SteamID steamid, int time, string reason)
|
||||
{
|
||||
// Set default caller name if not provided
|
||||
var callerName = !string.IsNullOrEmpty(caller?.PlayerName)
|
||||
? caller.PlayerName
|
||||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -131,19 +157,28 @@ public partial class CS2_SimpleAdmin
|
|||
// Asynchronous ban operation if player is not online or not found
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid.SteamId64.ToString(), adminInfo, reason, time, 3);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Gag, reason, time, penaltyId);
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid.SteamId64, adminInfo, reason, time, 3);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Gag, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.SteamId64.ToString(), reason, time, PenaltyType.Gag, _localizer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the 'addgag' command, which adds a gag penalty to a player specified by SteamID.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command or null for console.</param>
|
||||
/// <param name="command">Command input that includes SteamID, optional time, and reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnAddGagCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
// Set caller name
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
|
@ -158,7 +193,7 @@ public partial class CS2_SimpleAdmin
|
|||
return;
|
||||
}
|
||||
|
||||
var steamid = steamId.SteamId64.ToString();
|
||||
var steamid = steamId.SteamId64;
|
||||
var reason = command.ArgCount >= 3
|
||||
? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
|
||||
: _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
|
@ -169,7 +204,7 @@ public partial class CS2_SimpleAdmin
|
|||
if (!CheckValidMute(caller, time)) return;
|
||||
|
||||
// Get player and admin info
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
// Attempt to match player based on SteamID
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
|
@ -191,10 +226,14 @@ public partial class CS2_SimpleAdmin
|
|||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Gag, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Gag, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Gag, _localizer);
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.ToString(), reason, time, PenaltyType.Gag, _localizer);
|
||||
|
||||
command.ReplyToCommand($"Player with steamid {steamid} is not online. Gag has been added offline.");
|
||||
}
|
||||
|
|
@ -203,11 +242,16 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles removing a gag penalty ('ungag') of a player, either by SteamID or pattern match.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the ungag command or null for console.</param>
|
||||
/// <param name="command">Command input containing SteamID or player name and optional reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid or name> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnUngagCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
|
||||
var pattern = command.GetArg(1);
|
||||
|
|
@ -228,7 +272,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Check if pattern is a valid SteamID64
|
||||
if (Helper.ValidateSteamId(pattern, out var steamId) && steamId != null)
|
||||
{
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -252,8 +296,8 @@ public partial class CS2_SimpleAdmin
|
|||
{
|
||||
PlayerPenaltyManager.RemovePenaltiesByType(namePlayer.Slot, PenaltyType.Gag);
|
||||
|
||||
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalGags > 0)
|
||||
PlayersInfo[namePlayer.UserId.Value].TotalGags--;
|
||||
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.SteamID].TotalGags > 0)
|
||||
PlayersInfo[namePlayer.SteamID].TotalGags--;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
|
@ -273,11 +317,16 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the 'mute' command, applying a voice mute penalty to target players with optional time and reason.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the mute command or null for console.</param>
|
||||
/// <param name="command">The command input containing targets, time, and reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnMuteCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
|
|
@ -311,9 +360,19 @@ public partial class CS2_SimpleAdmin
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the mute penalty logic to an individual player, handling permissions, notifications, logging, and countdown timers.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the mute.</param>
|
||||
/// <param name="player">The player to mute.</param>
|
||||
/// <param name="time">Duration in minutes, 0 indicates permanent mute.</param>
|
||||
/// <param name="reason">Reason for the mute.</param>
|
||||
/// <param name="callerName">Optional caller name for notification messages.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
/// <param name="silent">If true, suppresses some logging.</param>
|
||||
internal void Mute(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, CommandInfo? command = null, bool silent = false)
|
||||
{
|
||||
if (Database == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (DatabaseProvider == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
if (!CheckValidMute(caller, time)) return;
|
||||
|
||||
|
|
@ -321,8 +380,8 @@ public partial class CS2_SimpleAdmin
|
|||
callerName ??= caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
// Get player and admin information
|
||||
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;
|
||||
|
||||
// Set player's voice flags to muted
|
||||
player.VoiceFlags = VoiceFlags.Muted;
|
||||
|
|
@ -331,7 +390,11 @@ public partial class CS2_SimpleAdmin
|
|||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 1);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Mute, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Mute, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
// Add penalty to the player's penalty manager
|
||||
|
|
@ -356,7 +419,7 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
|
||||
// Increment the player's total mutes count
|
||||
PlayersInfo[player.UserId.Value].TotalMutes++;
|
||||
PlayersInfo[player.SteamID].TotalMutes++;
|
||||
|
||||
// Log the mute command and send Discord notification
|
||||
if (!silent)
|
||||
|
|
@ -370,11 +433,16 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Mute, _localizer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the 'addmute' command that adds a mute penalty to a player specified by SteamID.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command or null for console.</param>
|
||||
/// <param name="command">Command input includes SteamID, optional time, and reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnAddMuteCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
// Set caller name
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
|
@ -389,7 +457,7 @@ public partial class CS2_SimpleAdmin
|
|||
return;
|
||||
}
|
||||
|
||||
var steamid = steamId.SteamId64.ToString();
|
||||
var steamid = steamId.SteamId64;
|
||||
var reason = command.ArgCount >= 3
|
||||
? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
|
||||
: _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
|
@ -400,7 +468,7 @@ public partial class CS2_SimpleAdmin
|
|||
if (!CheckValidMute(caller, time)) return;
|
||||
|
||||
// Get player and admin info
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
// Attempt to match player based on SteamID
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
|
@ -422,10 +490,14 @@ public partial class CS2_SimpleAdmin
|
|||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 1);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Mute, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Mute, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Mute, _localizer);
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.ToString(), reason, time, PenaltyType.Mute, _localizer);
|
||||
|
||||
command.ReplyToCommand($"Player with steamid {steamid} is not online. Mute has been added offline.");
|
||||
}
|
||||
|
|
@ -434,6 +506,14 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously adds a mute penalty to a player by Steam ID. Handles both online and offline players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin/player issuing the mute.</param>
|
||||
/// <param name="steamid">The Steam ID of the player to mute.</param>
|
||||
/// <param name="time">Duration of the mute in minutes.</param>
|
||||
/// <param name="reason">Reason for the mute.</param>
|
||||
/// <param name="muteManager">Optional mute manager instance for handling database ops.</param>
|
||||
internal void AddMute(CCSPlayerController? caller, SteamID steamid, int time, string reason, MuteManager? muteManager = null)
|
||||
{
|
||||
// Set default caller name if not provided
|
||||
|
|
@ -441,9 +521,9 @@ public partial class CS2_SimpleAdmin
|
|||
? caller.PlayerName
|
||||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -460,19 +540,29 @@ public partial class CS2_SimpleAdmin
|
|||
// Asynchronous ban operation if player is not online or not found
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid.SteamId64.ToString(), adminInfo, reason, time, 1);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Mute, reason, time, penaltyId);
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid.SteamId64, adminInfo, reason, time, 1);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Mute, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.SteamId64.ToString(), reason, time, PenaltyType.Mute, _localizer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the unmute command - removes mute penalty from player identified by SteamID or name.
|
||||
/// Can target both online and offline players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin/player issuing the unmute.</param>
|
||||
/// <param name="command">The command arguments including target identifier and optional reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnUnmuteCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
|
||||
var pattern = command.GetArg(1);
|
||||
|
|
@ -493,7 +583,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Check if pattern is a valid SteamID64
|
||||
if (Helper.ValidateSteamId(pattern, out var steamId) && steamId != null)
|
||||
{
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -519,8 +609,8 @@ public partial class CS2_SimpleAdmin
|
|||
PlayerPenaltyManager.RemovePenaltiesByType(namePlayer.Slot, PenaltyType.Mute);
|
||||
namePlayer.VoiceFlags = VoiceFlags.Normal;
|
||||
|
||||
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalMutes > 0)
|
||||
PlayersInfo[namePlayer.UserId.Value].TotalMutes--;
|
||||
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.SteamID].TotalMutes > 0)
|
||||
PlayersInfo[namePlayer.SteamID].TotalMutes--;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
|
@ -540,11 +630,17 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issue a 'silence' penalty to a player - disables voice communication.
|
||||
/// Handles online and offline players, with duration and reason specified.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin/player issuing the silence.</param>
|
||||
/// <param name="command">Command containing target, duration, and optional reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSilenceCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
|
|
@ -578,9 +674,19 @@ public partial class CS2_SimpleAdmin
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies silence logical processing for a player - updates database and notifies.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin/player applying the silence.</param>
|
||||
/// <param name="player">Target player.</param>
|
||||
/// <param name="time">Duration of silence.</param>
|
||||
/// <param name="reason">Reason for silence.</param>
|
||||
/// <param name="callerName">Optional name of silent admin or console.</param>
|
||||
/// <param name="command">Optional command details for logging.</param>
|
||||
/// <param name="silent">If true, suppresses logging notifications.</param>
|
||||
internal void Silence(CCSPlayerController? caller, CCSPlayerController player, int time, string reason, string? callerName = null, CommandInfo? command = null, bool silent = false)
|
||||
{
|
||||
if (Database == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (DatabaseProvider == null || !player.IsValid || !player.UserId.HasValue) return;
|
||||
if (!caller.CanTarget(player)) return;
|
||||
if (!CheckValidMute(caller, time)) return;
|
||||
|
||||
|
|
@ -588,14 +694,18 @@ public partial class CS2_SimpleAdmin
|
|||
callerName ??= caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
||||
// Get player and admin information
|
||||
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;
|
||||
|
||||
// Asynchronously handle silence logic
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 2); // Assuming 2 is the type for silence
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Silence, reason, time, penaltyId);
|
||||
int? penaltyId = await MuteManager.MutePlayer(playerInfo, adminInfo, reason, time, 2);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedEvent(playerInfo, adminInfo, PenaltyType.Silence, reason, time,
|
||||
penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
// Add penalty to the player's penalty manager
|
||||
|
|
@ -621,7 +731,7 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
|
||||
// Increment the player's total silences count
|
||||
PlayersInfo[player.UserId.Value].TotalSilences++;
|
||||
PlayersInfo[player.SteamID].TotalSilences++;
|
||||
|
||||
// Log the silence command and send Discord notification
|
||||
if (!silent)
|
||||
|
|
@ -635,11 +745,17 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.SendDiscordPenaltyMessage(caller, player, reason, time, PenaltyType.Silence, _localizer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the 'AddSilence' command, applying a silence penalty to a player specified by SteamID,
|
||||
/// with support for offline player penalties.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin issuing the command.</param>
|
||||
/// <param name="command">The command input containing SteamID, optional time, and reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [time in minutes/0 perm] [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnAddSilenceCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
// Set caller name
|
||||
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
|
||||
|
|
@ -654,7 +770,7 @@ public partial class CS2_SimpleAdmin
|
|||
return;
|
||||
}
|
||||
|
||||
var steamid = steamId.SteamId64.ToString();
|
||||
var steamid = steamId.SteamId64;
|
||||
var reason = command.ArgCount >= 3
|
||||
? string.Join(" ", Enumerable.Range(3, command.ArgCount - 3).Select(command.GetArg)).Trim()
|
||||
: _localizer?["sa_unknown"] ?? "Unknown";
|
||||
|
|
@ -665,7 +781,7 @@ public partial class CS2_SimpleAdmin
|
|||
if (!CheckValidMute(caller, time)) return;
|
||||
|
||||
// Get player and admin info
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
// Attempt to match player based on SteamID
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid);
|
||||
|
|
@ -687,10 +803,14 @@ public partial class CS2_SimpleAdmin
|
|||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid, adminInfo, reason, time, 2);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Silence, reason, time, penaltyId);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamId, adminInfo, PenaltyType.Silence, reason,
|
||||
time, penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid, reason, time, PenaltyType.Silence, _localizer);
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.ToString(), reason, time, PenaltyType.Silence, _localizer);
|
||||
|
||||
command.ReplyToCommand($"Player with steamid {steamid} is not online. Silence has been added offline.");
|
||||
}
|
||||
|
|
@ -699,6 +819,14 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a silence penalty to a player by Steam ID. Manages both online and offline player cases.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin/player initiating the silence.</param>
|
||||
/// <param name="steamid">Steam ID of player.</param>
|
||||
/// <param name="time">Duration of silence.</param>
|
||||
/// <param name="reason">Reason for the penalty.</param>
|
||||
/// <param name="muteManager">Optional mute manager for DB operations.</param>
|
||||
internal void AddSilence(CCSPlayerController? caller, SteamID steamid, int time, string reason, MuteManager? muteManager = null)
|
||||
{
|
||||
// Set default caller name if not provided
|
||||
|
|
@ -706,9 +834,9 @@ public partial class CS2_SimpleAdmin
|
|||
? caller.PlayerName
|
||||
: (_localizer?["sa_console"] ?? "Console");
|
||||
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.UserId.Value] : null;
|
||||
var adminInfo = caller != null && caller.UserId.HasValue ? PlayersInfo[caller.SteamID] : null;
|
||||
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamid.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -725,19 +853,29 @@ public partial class CS2_SimpleAdmin
|
|||
// Asynchronous ban operation if player is not online or not found
|
||||
Task.Run(async () =>
|
||||
{
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid.SteamId64.ToString(), adminInfo, reason, time, 2);
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Silence, reason, time, penaltyId);
|
||||
int? penaltyId = await MuteManager.AddMuteBySteamid(steamid.SteamId64, adminInfo, reason, time, 2);
|
||||
await Server.NextWorldUpdateAsync(() =>
|
||||
{
|
||||
SimpleAdminApi?.OnPlayerPenaltiedAddedEvent(steamid, adminInfo, PenaltyType.Silence, reason,
|
||||
time, penaltyId);
|
||||
});
|
||||
});
|
||||
|
||||
Helper.SendDiscordPenaltyMessage(caller, steamid.SteamId64.ToString(), reason, time, PenaltyType.Silence, _localizer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the silence penalty from a player, either by SteamID, name, or offline pattern.
|
||||
/// Resets voice settings and updates notices accordingly.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin/player issuing the unsilence.</param>
|
||||
/// <param name="command">Command arguments with target pattern and optional reason.</param>
|
||||
[RequiresPermissions("@css/chat")]
|
||||
[CommandHelper(minArgs: 1, usage: "<steamid or name> [reason]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnUnsilenceCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
if (Database == null) return;
|
||||
if (DatabaseProvider == null) return;
|
||||
|
||||
var callerSteamId = caller?.SteamID.ToString() ?? _localizer?["sa_console"] ?? "Console";
|
||||
var pattern = command.GetArg(1);
|
||||
|
|
@ -758,7 +896,7 @@ public partial class CS2_SimpleAdmin
|
|||
// Check if pattern is a valid SteamID64
|
||||
if (Helper.ValidateSteamId(pattern, out var steamId) && steamId != null)
|
||||
{
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64.ToString());
|
||||
var player = Helper.GetPlayerFromSteamid64(steamId.SteamId64);
|
||||
|
||||
if (player != null && player.IsValid)
|
||||
{
|
||||
|
|
@ -788,8 +926,8 @@ public partial class CS2_SimpleAdmin
|
|||
// Reset voice flags to normal
|
||||
namePlayer.VoiceFlags = VoiceFlags.Normal;
|
||||
|
||||
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalSilences > 0)
|
||||
PlayersInfo[namePlayer.UserId.Value].TotalSilences--;
|
||||
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.SteamID].TotalSilences > 0)
|
||||
PlayersInfo[namePlayer.SteamID].TotalSilences--;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
|
|
@ -809,6 +947,12 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates mute penalty duration based on admin privileges and configured max duration.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin/player issuing the mute.</param>
|
||||
/// <param name="duration">Requested duration in minutes.</param>
|
||||
/// <returns>True if mute penalty duration is allowed; false otherwise.</returns>
|
||||
private bool CheckValidMute(CCSPlayerController? caller, int duration)
|
||||
{
|
||||
if (caller == null) return true;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ namespace CS2_SimpleAdmin;
|
|||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the vote command, creates voting menu for players, and collects answers.
|
||||
/// Displays results after timeout and resets voting state.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin who initiated the vote, or null for console.</param>
|
||||
/// <param name="command">Command object containing question and options.</param>
|
||||
[RequiresPermissions("@css/generic")]
|
||||
[CommandHelper(minArgs: 2, usage: "<question> [... options ...]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnVoteCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@ namespace CS2_SimpleAdmin;
|
|||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables or disables no-clip mode for specified player(s).
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command input containing targets.</param>
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
public void OnNoclipCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -31,6 +36,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles no-clip mode for a player and shows admin activity messages.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin toggling no-clip.</param>
|
||||
/// <param name="player">The target player whose no-clip state changes.</param>
|
||||
/// <param name="callerName">Optional caller name for messages.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void NoClip(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
|
|
@ -58,6 +70,12 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, $"css_noclip {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables god mode for specified player(s).
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the command.</param>
|
||||
/// <param name="command">The command input containing targets.</param>
|
||||
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGodCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -82,6 +100,12 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles god mode for a player and notifies admins.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin toggling god mode.</param>
|
||||
/// <param name="player">The target player whose god mode changes.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void God(CCSPlayerController? caller, CCSPlayerController player, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -111,6 +135,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes target player(s) for an optional specified duration.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the freeze command.</param>
|
||||
/// <param name="command">The command input containing targets and duration.</param>
|
||||
[CommandHelper(1, "<#userid or name> [duration]")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
public void OnFreezeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -133,6 +162,11 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes the target player(s) models to a specified scale.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the resize command.</param>
|
||||
/// <param name="command">The command input containing targets and scale factor.</param>
|
||||
[CommandHelper(1, "<#userid or name> [size]")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
public void OnResizeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -153,8 +187,8 @@ public partial class CS2_SimpleAdmin
|
|||
|
||||
sceneNode.GetSkeletonInstance().Scale = size;
|
||||
player.PlayerPawn.Value.AcceptInput("SetScale", null, null, size.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
Server.NextFrame(() =>
|
||||
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
Utilities.SetStateChanged(player.PlayerPawn.Value, "CBaseEntity", "m_CBodyComponent");
|
||||
});
|
||||
|
|
@ -173,6 +207,14 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes a single player and optionally schedules automatic unfreeze after a duration.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin freezing the player.</param>
|
||||
/// <param name="player">The player to freeze.</param>
|
||||
/// <param name="time">Duration of freeze in seconds.</param>
|
||||
/// <param name="callerName">Optional name for notifications.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void Freeze(CCSPlayerController? caller, CCSPlayerController player, int time, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
|
|
@ -206,6 +248,11 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, $"css_freeze {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {time}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfreezes target player(s).
|
||||
/// </summary>
|
||||
/// <param name="caller">The player issuing the unfreeze command.</param>
|
||||
/// <param name="command">The command input with targets.</param>
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/slay")]
|
||||
public void OnUnfreezeCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -224,6 +271,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfreezes a single player and notifies admins.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin unfreezing the player.</param>
|
||||
/// <param name="player">The player to unfreeze.</param>
|
||||
/// <param name="callerName">Optional name for notifications.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void Unfreeze(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,15 @@ namespace CS2_SimpleAdmin;
|
|||
|
||||
public partial class CS2_SimpleAdmin
|
||||
{
|
||||
internal static readonly Dictionary<int, float> SpeedPlayers = [];
|
||||
internal static readonly Dictionary<CCSPlayerController, float> SpeedPlayers = [];
|
||||
internal static readonly Dictionary<CCSPlayerController, float> GravityPlayers = [];
|
||||
|
||||
/// <summary>
|
||||
/// Executes the 'slay' command, forcing the targeted players to commit suicide.
|
||||
/// Checks player validity and permissions.
|
||||
/// </summary>
|
||||
/// <param name="caller">Player or console issuing the command.</param>
|
||||
/// <param name="command">Command details, including targets.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSlayCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -32,6 +38,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the actual slay action on a player, with notification and logging.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console issuing the slay.</param>
|
||||
/// <param name="player">Target player to slay.</param>
|
||||
/// <param name="callerName">Optional name to display as the slayer.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void Slay(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected) return;
|
||||
|
|
@ -59,6 +72,12 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, $"css_slay {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the 'give' command to provide a specified weapon to targeted players.
|
||||
/// Enforces server rules for prohibited weapons.
|
||||
/// </summary>
|
||||
/// <param name="caller">Player or console issuing the command.</param>
|
||||
/// <param name="command">Command details, including targets and weapon name.</param>
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
[CommandHelper(minArgs: 2, usage: "<#userid or name> <weapon>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGiveCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -70,13 +89,6 @@ public partial class CS2_SimpleAdmin
|
|||
var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList();
|
||||
var weaponName = command.GetArg(2);
|
||||
|
||||
// check if item is typed
|
||||
// if (weaponName.Length < 2)
|
||||
// {
|
||||
// command.ReplyToCommand($"No weapon typed.");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// check if weapon is knife
|
||||
if (weaponName.Contains("_knife") || weaponName.Contains("bayonet"))
|
||||
{
|
||||
|
|
@ -98,6 +110,15 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gives a weapon identified by name to a player, handling ambiguous matches and logging.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin issuing the command.</param>
|
||||
/// <param name="player">Target player to receive the weapon.</param>
|
||||
/// <param name="weaponName">Weapon name or partial name.</param>
|
||||
/// <param name="callerName">Optional name to display in notifications.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
private static void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -137,6 +158,14 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives a specific weapon to a player, with notifications and logging.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin issuing the command.</param>
|
||||
/// <param name="player">Target player.</param>
|
||||
/// <param name="weapon">Weapon item object.</param>
|
||||
/// <param name="callerName">Optional caller name for notifications.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
internal static void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, CsItem weapon, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -163,6 +192,12 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the 'strip' command, removing all weapons from targeted players.
|
||||
/// Checks player validity and permissions.
|
||||
/// </summary>
|
||||
/// <param name="caller">Player or console issuing the command.</param>
|
||||
/// <param name="command">Command details including targets.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnStripCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -184,6 +219,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all weapons from a player, with notifications and logging.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console issuing the strip command.</param>
|
||||
/// <param name="player">Target player.</param>
|
||||
/// <param name="callerName">Optional caller name.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void StripWeapons(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -214,6 +256,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets health value on targeted players.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console issuing the command.</param>
|
||||
/// <param name="command">Command details including targets and health value.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <health>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnHpCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -236,6 +283,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes health of a player and logs the action.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console calling the method.</param>
|
||||
/// <param name="player">Target player.</param>
|
||||
/// <param name="health">Health value to set.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
internal static void SetHp(CCSPlayerController? caller, CCSPlayerController player, int health, CommandInfo? command = null)
|
||||
{
|
||||
if (!player.IsValid || player.IsHLTV) return;
|
||||
|
|
@ -263,6 +317,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets movement speed on targeted players.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console issuing the command.</param>
|
||||
/// <param name="command">Command details including targets and speed.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <speed>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSpeedCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -288,6 +347,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes speed of a player and logs the action.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console calling the method.</param>
|
||||
/// <param name="player">Target player.</param>
|
||||
/// <param name="speed">Speed value to set.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
internal static void SetSpeed(CCSPlayerController? caller, CCSPlayerController player, float speed, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -299,9 +365,9 @@ public partial class CS2_SimpleAdmin
|
|||
player.SetSpeed(speed);
|
||||
|
||||
if (speed == 1f)
|
||||
SpeedPlayers.Remove(player.Slot);
|
||||
SpeedPlayers.Remove(player);
|
||||
else
|
||||
SpeedPlayers[player.Slot] = speed;
|
||||
SpeedPlayers[player] = speed;
|
||||
|
||||
// Log the command
|
||||
if (command == null)
|
||||
|
|
@ -319,6 +385,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets gravity on targeted players.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console issuing the command.</param>
|
||||
/// <param name="command">Command details including targets and gravity value.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <gravity>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnGravityCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -344,6 +415,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes gravity of a player and logs the action.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or console calling the method.</param>
|
||||
/// <param name="player">Target player.</param>
|
||||
/// <param name="gravity">Gravity value to set.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
internal static void SetGravity(CCSPlayerController? caller, CCSPlayerController player, float gravity, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -375,6 +453,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the money amount for the targeted players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin executing the command.</param>
|
||||
/// <param name="command">The command containing target player and money value.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> <money>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnMoneyCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -401,6 +484,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies money value to a single targeted player and logs the operation.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin setting the money.</param>
|
||||
/// <param name="player">The player whose money will be set.</param>
|
||||
/// <param name="money">The value of money to set.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void SetMoney(CCSPlayerController? caller, CCSPlayerController player, int money, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -427,6 +517,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies damage as a slap effect to the targeted players.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin executing the slap command.</param>
|
||||
/// <param name="command">The command including targets and optional damage value.</param>
|
||||
[RequiresPermissions("@css/slay")]
|
||||
[CommandHelper(minArgs: 1, usage: "<#userid or name> [damage]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSlapCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -457,6 +552,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies slap damage to a specific player with notifications and logging.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin applying the slap effect.</param>
|
||||
/// <param name="player">The target player to slap.</param>
|
||||
/// <param name="damage">The damage amount to apply.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void Slap(CCSPlayerController? caller, CCSPlayerController player, int damage, CommandInfo? command = null)
|
||||
{
|
||||
if (!caller.CanTarget(player)) return;
|
||||
|
|
@ -485,6 +587,11 @@ public partial class CS2_SimpleAdmin
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the team of targeted players with optional kill on switch.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin issuing the command.</param>
|
||||
/// <param name="command">The command containing targets, team info, and optional kill flag.</param>
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 2, usage: "<#userid or name> [<ct/tt/spec>] [-k]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnTeamCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -534,6 +641,15 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the team of a player with various conditions and logs the operation.
|
||||
/// </summary>
|
||||
/// <param name="caller">The player/admin issuing the change.</param>
|
||||
/// <param name="player">The target player.</param>
|
||||
/// <param name="teamName">Team name string.</param>
|
||||
/// <param name="teamNum">Team enumeration value.</param>
|
||||
/// <param name="kill">If true, kills player on team change.</param>
|
||||
/// <param name="command">Optional command info for logging.</param>
|
||||
internal static void ChangeTeam(CCSPlayerController? caller, CCSPlayerController player, string teamName, CsTeam teamNum, bool kill, CommandInfo? command = null)
|
||||
{
|
||||
// Check if the player is valid and connected
|
||||
|
|
@ -581,6 +697,11 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renames targeted players to a new name.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin issuing the rename command.</param>
|
||||
/// <param name="command">The command including targets and new name.</param>
|
||||
[CommandHelper(1, "<#userid or name> <new name>")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnRenameCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -626,6 +747,11 @@ public partial class CS2_SimpleAdmin
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renames permamently targeted players to a new name.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin issuing the pre-rename command.</param>
|
||||
/// <param name="command">The command containing targets and new alias.</param>
|
||||
[CommandHelper(1, "<#userid or name> <new name>")]
|
||||
[RequiresPermissions("@css/ban")]
|
||||
public void OnPrenameCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -676,6 +802,11 @@ public partial class CS2_SimpleAdmin
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Respawns targeted players, restoring their state.
|
||||
/// </summary>
|
||||
/// <param name="caller">The admin or player issuing respawn.</param>
|
||||
/// <param name="command">The command including target players.</param>
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
[RequiresPermissions("@css/cheats")]
|
||||
public void OnRespawnCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
|
|
@ -700,6 +831,13 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.LogCommand(caller, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Respawns a specified player and updates admin notifications.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin or player executing respawn.</param>
|
||||
/// <param name="player">Player to respawn.</param>
|
||||
/// <param name="callerName">Optional admin name.</param>
|
||||
/// <param name="command">Optional command info.</param>
|
||||
internal static void Respawn(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null)
|
||||
{
|
||||
// Check if the caller can target the player
|
||||
|
|
@ -715,8 +853,8 @@ public partial class CS2_SimpleAdmin
|
|||
var playerPawn = player.PlayerPawn.Value;
|
||||
_cBasePlayerControllerSetPawnFunc.Invoke(player, playerPawn, true, false);
|
||||
VirtualFunction.CreateVoid<CCSPlayerController>(player.Handle, GameData.GetOffset("CCSPlayerController_Respawn"))(player);
|
||||
|
||||
if (player.UserId.HasValue && PlayersInfo.TryGetValue(player.UserId.Value, out var value) && value.DiePosition != null)
|
||||
|
||||
if (player.UserId.HasValue && PlayersInfo.TryGetValue(player.SteamID, out var value) && value.DiePosition != null)
|
||||
playerPawn.Teleport(value.DiePosition?.Position, value.DiePosition?.Angle);
|
||||
|
||||
// Log the command
|
||||
|
|
@ -733,146 +871,270 @@ public partial class CS2_SimpleAdmin
|
|||
Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs);
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
/// <summary>
|
||||
/// Teleports targeted player(s) to another player's location.
|
||||
/// </summary>
|
||||
/// <param name="caller">Admin issuing teleport command.</param>
|
||||
/// <param name="command">Command containing teleport targets and destination.</param>
|
||||
[CommandHelper(1, "<#userid or name> [#userid or name]")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnGotoCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
// Check if the caller is valid and has a live pawn
|
||||
if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE) return;
|
||||
IEnumerable<CCSPlayerController> playersToTeleport;
|
||||
CCSPlayerController? destinationPlayer;
|
||||
|
||||
// Get the target players
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null || targets.Count() > 1) return;
|
||||
|
||||
var playersToTarget = targets.Players
|
||||
.Where(player => player is { IsValid: true, IsHLTV: false })
|
||||
.ToList();
|
||||
if (command.ArgCount < 3)
|
||||
{
|
||||
if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
// Log the command
|
||||
if (targets == null || targets.Count() != 1)
|
||||
return;
|
||||
|
||||
destinationPlayer = targets.Players.FirstOrDefault(p =>
|
||||
p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
||||
|
||||
if (destinationPlayer == null || !caller.CanTarget(destinationPlayer) || caller.PlayerPawn.Value == null)
|
||||
return;
|
||||
|
||||
playersToTeleport = [caller];
|
||||
}
|
||||
else
|
||||
{
|
||||
var destination = GetTarget(command, 2);
|
||||
if (targets == null || destination == null || destination.Count() != 1)
|
||||
return;
|
||||
|
||||
destinationPlayer = destination.Players.FirstOrDefault(p =>
|
||||
p is { IsValid: true, IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
||||
|
||||
if (destinationPlayer == null)
|
||||
return;
|
||||
|
||||
playersToTeleport = targets.Players
|
||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller.CanTarget(p))
|
||||
.ToList();
|
||||
|
||||
if (!playersToTeleport.Any())
|
||||
return;
|
||||
}
|
||||
|
||||
// Log command
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Process each player to teleport
|
||||
foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).Where(caller.CanTarget))
|
||||
foreach (var player in playersToTeleport)
|
||||
{
|
||||
if (caller.PlayerPawn.Value == null || player.PlayerPawn.Value == null)
|
||||
if (player.PlayerPawn?.Value == null || destinationPlayer?.PlayerPawn?.Value == null)
|
||||
continue;
|
||||
|
||||
// Teleport the caller to the player and toggle noclip
|
||||
caller.TeleportPlayer(player);
|
||||
// caller.PlayerPawn.Value.ToggleNoclip();
|
||||
player.TeleportPlayer(destinationPlayer);
|
||||
|
||||
caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
caller.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
|
||||
Utilities.SetStateChanged(caller, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(caller, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
|
||||
Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
// Set a timer to toggle collision back after 4 seconds
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
Utilities.SetStateChanged(destinationPlayer, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(destinationPlayer, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
AddTimer(4, () =>
|
||||
{
|
||||
if (!caller.IsValid || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
caller.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
|
||||
Utilities.SetStateChanged(caller, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(caller, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
|
||||
Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
if (player is { IsValid: true, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE })
|
||||
{
|
||||
player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
}
|
||||
|
||||
if (destinationPlayer.IsValid && destinationPlayer.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
Utilities.SetStateChanged(destinationPlayer, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(destinationPlayer, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
}
|
||||
});
|
||||
|
||||
// Prepare message key and arguments for the teleport notification
|
||||
var activityMessageKey = "sa_admin_tp_message";
|
||||
var adminActivityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
|
||||
// Show admin activity
|
||||
if (!SilentPlayers.Contains(caller.Slot) && _localizer != null)
|
||||
if (caller != null && !SilentPlayers.Contains(caller.Slot) && _localizer != null)
|
||||
{
|
||||
Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, false, adminActivityArgs);
|
||||
Helper.ShowAdminActivity("sa_admin_tp_message", player.PlayerName, false, "CALLER", destinationPlayer.PlayerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHelper(1, "<#userid or name>")]
|
||||
|
||||
/// <summary>
|
||||
/// Brings targeted player(s) to the caller or specified destination player's location.
|
||||
/// </summary>
|
||||
/// <param name="caller">Player issuing the bring command.</param>
|
||||
/// <param name="command">Command containing the destination and targets.</param>
|
||||
[CommandHelper(1, "<#destination or name> [#userid or name...]")]
|
||||
[RequiresPermissions("@css/kick")]
|
||||
public void OnBringCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
{
|
||||
// Check if the caller is valid and has a live pawn
|
||||
if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
IEnumerable<CCSPlayerController> playersToTeleport;
|
||||
CCSPlayerController? destinationPlayer;
|
||||
|
||||
if (command.ArgCount < 3)
|
||||
{
|
||||
if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null || !targets.Any())
|
||||
return;
|
||||
|
||||
destinationPlayer = caller;
|
||||
|
||||
playersToTeleport = targets.Players
|
||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller.CanTarget(p))
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
var destination = GetTarget(command);
|
||||
if (destination == null || destination.Count() != 1)
|
||||
return;
|
||||
|
||||
destinationPlayer = destination.Players.FirstOrDefault(p =>
|
||||
p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE });
|
||||
|
||||
if (destinationPlayer == null)
|
||||
return;
|
||||
|
||||
// Rest args = targets to teleport
|
||||
var targets = GetTarget(command, 2);
|
||||
if (targets == null || !targets.Any())
|
||||
return;
|
||||
|
||||
playersToTeleport = targets.Players
|
||||
.Where(p => p is { IsValid: true, IsHLTV: false, Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE } && caller!.CanTarget(p))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (destinationPlayer == null || !playersToTeleport.Any())
|
||||
return;
|
||||
|
||||
// Get the target players
|
||||
var targets = GetTarget(command);
|
||||
if (targets == null || targets.Count() > 1) return;
|
||||
|
||||
var playersToTarget = targets.Players
|
||||
.Where(player => player is { IsValid: true, IsHLTV: false })
|
||||
.ToList();
|
||||
|
||||
// Log the command
|
||||
// Log command
|
||||
Helper.LogCommand(caller, command);
|
||||
|
||||
// Process each player to teleport
|
||||
foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).Where(caller.CanTarget))
|
||||
foreach (var player in playersToTeleport)
|
||||
{
|
||||
if (caller.PlayerPawn.Value == null || player.PlayerPawn.Value == null)
|
||||
if (player.PlayerPawn?.Value == null || destinationPlayer.PlayerPawn?.Value == null)
|
||||
continue;
|
||||
|
||||
// Teleport the player to the caller and toggle noclip
|
||||
player.TeleportPlayer(caller);
|
||||
// caller.PlayerPawn.Value.ToggleNoclip();
|
||||
|
||||
caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
caller.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
|
||||
Utilities.SetStateChanged(caller, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(caller, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
// Teleport
|
||||
player.TeleportPlayer(destinationPlayer);
|
||||
|
||||
player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
|
||||
Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
// Set a timer to toggle collision back after 4 seconds
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
Utilities.SetStateChanged(destinationPlayer, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(destinationPlayer, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
AddTimer(4, () =>
|
||||
{
|
||||
if (!player.IsValid || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
return;
|
||||
|
||||
caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
caller.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
|
||||
Utilities.SetStateChanged(caller, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(caller, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
|
||||
player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
|
||||
Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
if (player is { IsValid: true, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE })
|
||||
{
|
||||
player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
}
|
||||
|
||||
if (destinationPlayer.IsValid && destinationPlayer.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE)
|
||||
{
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
destinationPlayer.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
Utilities.SetStateChanged(destinationPlayer, "CCollisionProperty", "m_CollisionGroup");
|
||||
Utilities.SetStateChanged(destinationPlayer, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
}
|
||||
});
|
||||
|
||||
// Prepare message key and arguments for the bring notification
|
||||
var activityMessageKey = "sa_admin_bring_message";
|
||||
var adminActivityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
|
||||
// Show admin activity
|
||||
if (!SilentPlayers.Contains(caller.Slot) && _localizer != null)
|
||||
if (caller != null && !SilentPlayers.Contains(caller.Slot) && _localizer != null)
|
||||
{
|
||||
Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, false, adminActivityArgs);
|
||||
Helper.ShowAdminActivity("sa_admin_bring_message", player.PlayerName, false, "CALLER", destinationPlayer.PlayerName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [CommandHelper(1, "<#userid or name> [#userid or name]")]
|
||||
// [RequiresPermissions("@css/kick")]
|
||||
// public void OnBringCommand(CCSPlayerController? caller, CommandInfo command)
|
||||
// {
|
||||
// // Check if the caller is valid and has a live pawn
|
||||
// if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
// return;
|
||||
//
|
||||
// // Get the target players
|
||||
// var targets = GetTarget(command);
|
||||
// if (targets == null || targets.Count() > 1) return;
|
||||
//
|
||||
// var playersToTarget = targets.Players
|
||||
// .Where(player => player is { IsValid: true, IsHLTV: false })
|
||||
// .ToList();
|
||||
//
|
||||
// // Log the command
|
||||
// Helper.LogCommand(caller, command);
|
||||
//
|
||||
// // Process each player to teleport
|
||||
// foreach (var player in playersToTarget.Where(player => player is { Connected: PlayerConnectedState.PlayerConnected, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).Where(caller.CanTarget))
|
||||
// {
|
||||
// if (caller.PlayerPawn.Value == null || player.PlayerPawn.Value == null)
|
||||
// continue;
|
||||
//
|
||||
// // Teleport the player to the caller and toggle noclip
|
||||
// player.TeleportPlayer(caller);
|
||||
// // caller.PlayerPawn.Value.ToggleNoclip();
|
||||
//
|
||||
// caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
// caller.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
//
|
||||
// Utilities.SetStateChanged(caller, "CCollisionProperty", "m_CollisionGroup");
|
||||
// Utilities.SetStateChanged(caller, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
//
|
||||
// player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
// player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_DISSOLVING;
|
||||
//
|
||||
// Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
// Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
//
|
||||
// // Set a timer to toggle collision back after 4 seconds
|
||||
// AddTimer(4, () =>
|
||||
// {
|
||||
// if (!player.IsValid || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
// return;
|
||||
//
|
||||
// caller.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
// caller.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
//
|
||||
// Utilities.SetStateChanged(caller, "CCollisionProperty", "m_CollisionGroup");
|
||||
// Utilities.SetStateChanged(caller, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
//
|
||||
// player.PlayerPawn.Value.Collision.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
// player.PlayerPawn.Value.Collision.CollisionAttribute.CollisionGroup = (byte)CollisionGroup.COLLISION_GROUP_PLAYER;
|
||||
//
|
||||
// Utilities.SetStateChanged(player, "CCollisionProperty", "m_CollisionGroup");
|
||||
// Utilities.SetStateChanged(player, "VPhysicsCollisionAttribute_t", "m_nCollisionGroup");
|
||||
// });
|
||||
//
|
||||
// // Prepare message key and arguments for the bring notification
|
||||
// var activityMessageKey = "sa_admin_bring_message";
|
||||
// var adminActivityArgs = new object[] { "CALLER", player.PlayerName };
|
||||
//
|
||||
// // Show admin activity
|
||||
// if (!SilentPlayers.Contains(caller.Slot) && _localizer != null)
|
||||
// {
|
||||
// Helper.ShowAdminActivity(activityMessageKey, caller.PlayerName, false, adminActivityArgs);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue