upstream to 1.7.7-alpha-10

This commit is contained in:
Sachin 2025-10-03 17:18:24 +05:30
commit 2de2924cef
106 changed files with 5897 additions and 3306 deletions

View file

@ -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
if (!player.VoiceFlags.HasFlag(VoiceFlags.Muted))
@ -332,7 +391,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
@ -357,7 +420,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)
@ -371,11 +434,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;
@ -390,7 +458,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";
@ -401,7 +469,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);
@ -423,10 +491,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.");
}
@ -435,6 +507,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
@ -442,9 +522,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)
{
@ -461,19 +541,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);
@ -494,7 +584,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)
{
@ -522,8 +612,8 @@ public partial class CS2_SimpleAdmin
if (namePlayer.VoiceFlags.HasFlag(VoiceFlags.Muted))
namePlayer.VoiceFlags &= ~VoiceFlags.Muted;
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalMutes > 0)
PlayersInfo[namePlayer.UserId.Value].TotalMutes--;
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.SteamID].TotalMutes > 0)
PlayersInfo[namePlayer.SteamID].TotalMutes--;
Task.Run(async () =>
{
@ -543,11 +633,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);
@ -581,9 +677,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;
@ -591,8 +697,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
if (!player.VoiceFlags.HasFlag(VoiceFlags.Muted))
@ -601,8 +707,12 @@ public partial class CS2_SimpleAdmin
// 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
@ -628,7 +738,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)
@ -642,11 +752,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;
@ -661,7 +777,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";
@ -672,7 +788,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);
@ -694,10 +810,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.");
}
@ -706,6 +826,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
@ -713,9 +841,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)
{
@ -732,19 +860,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);
@ -765,7 +903,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)
{
@ -797,8 +935,8 @@ public partial class CS2_SimpleAdmin
if (namePlayer.VoiceFlags.HasFlag(VoiceFlags.Muted))
namePlayer.VoiceFlags &= ~VoiceFlags.Muted;
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.UserId.Value].TotalSilences > 0)
PlayersInfo[namePlayer.UserId.Value].TotalSilences--;
if (namePlayer.UserId.HasValue && PlayersInfo[namePlayer.SteamID].TotalSilences > 0)
PlayersInfo[namePlayer.SteamID].TotalSilences--;
Task.Run(async () =>
{
@ -818,6 +956,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;