using System.Globalization; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Entities.Constants; using CounterStrikeSharp.API.Modules.Memory; using CounterStrikeSharp.API.Modules.Utils; namespace CS2_SimpleAdmin; public partial class CS2_SimpleAdmin { internal static readonly Dictionary SpeedPlayers = []; internal static readonly Dictionary GravityPlayers = []; /// /// Executes the 'slay' command, forcing the targeted players to commit suicide. /// Checks player validity and permissions. /// /// Player or console issuing the command. /// Command details, including targets. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnSlayCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is {IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); playersToTarget.ForEach(player => { Slay(caller, player, callerName, command); }); Helper.LogCommand(caller, command); } /// /// Performs the actual slay action on a player, with notification and logging. /// /// Admin or console issuing the slay. /// Target player to slay. /// Optional name to display as the slayer. /// Optional command info for logging. internal static void Slay(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null) { if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected) return; if (!caller.CanTarget(player)) return; // Set default caller name if not provided callerName ??= caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Make the player commit suicide player.CommitSuicide(false, true); // Determine message keys and arguments for the slay notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_slay_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } // Log the command and send Discord notification if (command == null) Helper.LogCommand(caller, $"css_slay {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}"); } /// /// Executes the 'give' command to provide a specified weapon to targeted players. /// Enforces server rules for prohibited weapons. /// /// Player or console issuing the command. /// Command details, including targets and weapon name. [RequiresPermissions("@css/cheats")] [CommandHelper(minArgs: 2, usage: "<#userid or name> ", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnGiveCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var targets = GetTarget(command); if (targets == null) return; 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 weapon is knife if (weaponName.Contains("_knife") || weaponName.Contains("bayonet")) { if (CoreConfig.FollowCS2ServerGuidelines) { command.ReplyToCommand($"Cannot Give {weaponName} because it's illegal to be given."); return; } } playersToTarget.ForEach(player => { if (player.Connected != PlayerConnectedState.PlayerConnected) return; GiveWeapon(caller, player, weaponName, callerName, command); }); Helper.LogCommand(caller, command); } /// /// Gives a weapon identified by name to a player, handling ambiguous matches and logging. /// /// Admin issuing the command. /// Target player to receive the weapon. /// Weapon name or partial name. /// Optional name to display in notifications. /// Optional command info for logging. private static void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, string weaponName, string? callerName = null, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided callerName ??= caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; var weapons = WeaponHelper.GetWeaponsByPartialName(weaponName); switch (weapons.Count) { case 0: return; case > 1: { var weaponList = string.Join(", ", weapons.Select(w => w.EnumMemberValue)); command?.ReplyToCommand($"Found weapons with a similar name: {weaponList}"); return; } } // Give weapon to the player player.GiveNamedItem(weapons.First().EnumValue); // Log the command if (command == null) Helper.LogCommand(caller, $"css_giveweapon {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {weaponName}"); // Determine message keys and arguments for the weapon give notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_give_message", new object[] { "CALLER", player.PlayerName, weaponName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Gives a specific weapon to a player, with notifications and logging. /// /// Admin issuing the command. /// Target player. /// Weapon item object. /// Optional caller name for notifications. /// Optional command info. internal static void GiveWeapon(CCSPlayerController? caller, CCSPlayerController player, CsItem weapon, string? callerName = null, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided callerName ??= caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Give weapon to the player player.GiveNamedItem(weapon); // Log the command if (command == null) Helper.LogCommand(caller, $"css_giveweapon {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {weapon.ToString()}"); // Determine message keys and arguments for the weapon give notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_give_message", new object[] { "CALLER", player.PlayerName, weapon.ToString() }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Executes the 'strip' command, removing all weapons from targeted players. /// Checks player validity and permissions. /// /// Player or console issuing the command. /// Command details including targets. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name>", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnStripCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); playersToTarget.ForEach(player => { if (caller!.CanTarget(player)) { StripWeapons(caller, player, callerName, command); } }); Helper.LogCommand(caller, command); } /// /// Removes all weapons from a player, with notifications and logging. /// /// Admin or console issuing the strip command. /// Target player. /// Optional caller name. /// Optional command info for logging. internal static void StripWeapons(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided callerName ??= caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Check if player is valid, alive, and connected if (!player.IsValid || player.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE || player.Connected != PlayerConnectedState.PlayerConnected) return; // Strip weapons from the player player.RemoveWeapons(); // Log the command if (command == null) Helper.LogCommand(caller, $"css_strip {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}"); // Determine message keys and arguments for the weapon strip notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_strip_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Sets health value on targeted players. /// /// Admin or console issuing the command. /// Command details including targets and health value. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name> ", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnHpCommand(CCSPlayerController? caller, CommandInfo command) { int.TryParse(command.GetArg(2), out var health); var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); playersToTarget.ForEach(player => { if (caller!.CanTarget(player)) { SetHp(caller, player, health, command); } }); Helper.LogCommand(caller, command); } /// /// Changes health of a player and logs the action. /// /// Admin or console calling the method. /// Target player. /// Health value to set. /// Optional command info. internal static void SetHp(CCSPlayerController? caller, CCSPlayerController player, int health, CommandInfo? command = null) { if (!player.IsValid || player.IsHLTV) return; if (!caller.CanTarget(player)) return; // Set default caller name if not provided var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Set player's health player.SetHp(health); // Log the command if (command == null) Helper.LogCommand(caller, $"css_hp {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {health}"); // Determine message keys and arguments for the HP set notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_hp_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Sets movement speed on targeted players. /// /// Admin or console issuing the command. /// Command details including targets and speed. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name> ", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnSpeedCommand(CCSPlayerController? caller, CommandInfo command) { float.TryParse(command.GetArg(2), NumberStyles.Float, CultureInfo.InvariantCulture, out var speed); var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); playersToTarget.ForEach(player => { if (player.Connected != PlayerConnectedState.PlayerConnected) return; if (caller!.CanTarget(player)) { SetSpeed(caller, player, speed, command); } }); Helper.LogCommand(caller, command); } /// /// Changes speed of a player and logs the action. /// /// Admin or console calling the method. /// Target player. /// Speed value to set. /// Optional command info. internal static void SetSpeed(CCSPlayerController? caller, CCSPlayerController player, float speed, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Set player's speed player.SetSpeed(speed); if (speed == 1f) SpeedPlayers.Remove(player); else SpeedPlayers[player] = speed; // Log the command if (command == null) Helper.LogCommand(caller, $"css_speed {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {speed}"); // Determine message keys and arguments for the speed set notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_speed_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Sets gravity on targeted players. /// /// Admin or console issuing the command. /// Command details including targets and gravity value. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name> ", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnGravityCommand(CCSPlayerController? caller, CommandInfo command) { float.TryParse(command.GetArg(2), NumberStyles.Float, CultureInfo.InvariantCulture, out var gravity); var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); playersToTarget.ForEach(player => { if (player.Connected != PlayerConnectedState.PlayerConnected) return; if (caller!.CanTarget(player)) { SetGravity(caller, player, gravity, command); } }); Helper.LogCommand(caller, command); } /// /// Changes gravity of a player and logs the action. /// /// Admin or console calling the method. /// Target player. /// Gravity value to set. /// Optional command info. internal static void SetGravity(CCSPlayerController? caller, CCSPlayerController player, float gravity, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Set player's gravity player.SetGravity(gravity); if (gravity == 1f) GravityPlayers.Remove(player); else GravityPlayers[player] = gravity; // Log the command if (command == null) Helper.LogCommand(caller, $"css_gravity {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {gravity}"); // Determine message keys and arguments for the gravity set notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_gravity_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Sets the money amount for the targeted players. /// /// The player/admin executing the command. /// The command containing target player and money value. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name> ", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnMoneyCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; int.TryParse(command.GetArg(2), out var money); var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); playersToTarget.ForEach(player => { if (player.Connected != PlayerConnectedState.PlayerConnected) return; if (caller!.CanTarget(player)) { SetMoney(caller, player, money, command); } }); Helper.LogCommand(caller, command); } /// /// Applies money value to a single targeted player and logs the operation. /// /// The player/admin setting the money. /// The player whose money will be set. /// The value of money to set. /// Optional command info for logging. internal static void SetMoney(CCSPlayerController? caller, CCSPlayerController player, int money, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Set player's money player.SetMoney(money); // Log the command if (command == null) Helper.LogCommand(caller, $"css_money {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {money}"); // Determine message keys and arguments for the money set notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_money_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller == null || !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Applies damage as a slap effect to the targeted players. /// /// The player/admin executing the slap command. /// The command including targets and optional damage value. [RequiresPermissions("@css/slay")] [CommandHelper(minArgs: 1, usage: "<#userid or name> [damage]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnSlapCommand(CCSPlayerController? caller, CommandInfo command) { var damage = 0; var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player.IsValid && player is { IsHLTV: false, PlayerPawn.Value.LifeState: (int)LifeState_t.LIFE_ALIVE }).ToList(); if (command.ArgCount >= 2) { int.TryParse(command.GetArg(2), out damage); } playersToTarget.ForEach(player => { if (player.Connected != PlayerConnectedState.PlayerConnected) return; if (caller!.CanTarget(player)) { Slap(caller, player, damage, command); } }); Helper.LogCommand(caller, command); } /// /// Applies slap damage to a specific player with notifications and logging. /// /// The player/admin applying the slap effect. /// The target player to slap. /// The damage amount to apply. /// Optional command info for logging. internal static void Slap(CCSPlayerController? caller, CCSPlayerController player, int damage, CommandInfo? command = null) { if (!caller.CanTarget(player)) return; // Set default caller name if not provided var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Apply slap damage to the player player.Pawn.Value?.Slap(damage); // Log the command if (command == null) Helper.LogCommand(caller, $"css_slap {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)} {damage}"); // Determine message key and arguments for the slap notification var (activityMessageKey, adminActivityArgs) = ("sa_admin_slap_message", new object[] { "CALLER", player.PlayerName }); // Display admin activity message to other players if (caller != null && SilentPlayers.Contains(caller.Slot)) return; if (_localizer != null) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } } /// /// Changes the team of targeted players with optional kill on switch. /// /// The player/admin issuing the command. /// The command containing targets, team info, and optional kill flag. [RequiresPermissions("@css/kick")] [CommandHelper(minArgs: 2, usage: "<#userid or name> [] [-k]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] public void OnTeamCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var teamName = command.GetArg(2).ToLower(); string _teamName; var teamNum = CsTeam.Spectator; var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); switch (teamName) { case "ct": case "counterterrorist": teamNum = CsTeam.CounterTerrorist; _teamName = "CT"; break; case "t": case "tt": case "terrorist": teamNum = CsTeam.Terrorist; _teamName = "TT"; break; case "swap": _teamName = "SWAP"; break; default: teamNum = CsTeam.Spectator; _teamName = "SPEC"; break; } var kill = command.GetArg(3).ToLower().Equals("-k"); playersToTarget.ForEach(player => { ChangeTeam(caller, player, _teamName, teamNum, kill, command); }); Helper.LogCommand(caller, command); } /// /// Changes the team of a player with various conditions and logs the operation. /// /// The player/admin issuing the change. /// The target player. /// Team name string. /// Team enumeration value. /// If true, kills player on team change. /// Optional command info for logging. 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 if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected) return; // Ensure the caller can target the player if (!caller.CanTarget(player)) return; // Set default caller name if not provided var callerName = caller != null ? caller.PlayerName : _localizer?["sa_console"] ?? "Console"; // Change team based on the provided teamName and conditions if (!teamName.Equals("swap", StringComparison.OrdinalIgnoreCase)) { if (player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && teamNum != CsTeam.Spectator && !kill && Instance.Config.OtherSettings.TeamSwitchType == 1) player.SwitchTeam(teamNum); else player.ChangeTeam(teamNum); } else { if (player.TeamNum != (byte)CsTeam.Spectator) { var _teamNum = (CsTeam)player.TeamNum == CsTeam.Terrorist ? CsTeam.CounterTerrorist : CsTeam.Terrorist; teamName = _teamNum == CsTeam.Terrorist ? "TT" : "CT"; if (player.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE && !kill && Instance.Config.OtherSettings.TeamSwitchType == 1) player.SwitchTeam(_teamNum); else player.ChangeTeam(_teamNum); } } // Log the command if (command == null) Helper.LogCommand(caller, $"css_team {player.PlayerName} {teamName}"); // Determine message key and arguments for the team change notification var activityMessageKey = "sa_admin_team_message"; var adminActivityArgs = new object[] { "CALLER", player.PlayerName, teamName }; // Display admin activity message to other players if (caller != null && SilentPlayers.Contains(caller.Slot)) return; Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } /// /// Renames targeted players to a new name. /// /// The admin issuing the rename command. /// The command including targets and new name. [CommandHelper(1, "<#userid or name> ")] [RequiresPermissions("@css/kick")] public void OnRenameCommand(CCSPlayerController? caller, CommandInfo command) { // Set default caller name if not provided var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; // Get the new name from the command arguments var newName = command.GetArg(2); // Check if the new name is valid if (string.IsNullOrEmpty(newName)) return; // Retrieve the targets based on the command var targets = GetTarget(command); if (targets == null) return; // Filter out valid players from the targets var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); // Log the command Helper.LogCommand(caller, command); // Process each player to rename playersToTarget.ForEach(player => { // Check if the player is connected and can be targeted if (player.Connected != PlayerConnectedState.PlayerConnected || !caller!.CanTarget(player)) return; // Determine message key and arguments for the rename notification var activityMessageKey = "sa_admin_rename_message"; var adminActivityArgs = new object[] { "CALLER", player.PlayerName, newName }; // Display admin activity message to other players if (caller != null && SilentPlayers.Contains(caller.Slot)) return; Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); // Rename the player player.Rename(newName); }); } /// /// Renames permamently targeted players to a new name. /// /// The admin issuing the pre-rename command. /// The command containing targets and new alias. [CommandHelper(1, "<#userid or name> ")] [RequiresPermissions("@css/ban")] public void OnPrenameCommand(CCSPlayerController? caller, CommandInfo command) { // Set default caller name if not provided var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; // Get the new name from the command arguments var newName = command.GetArg(2); // Retrieve the targets based on the command var targets = GetTarget(command); if (targets == null) return; // Filter out valid players from the targets var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); // Log the command Helper.LogCommand(caller, command); // Process each player to rename playersToTarget.ForEach(player => { // Check if the player is connected and can be targeted if (player.Connected != PlayerConnectedState.PlayerConnected || !caller!.CanTarget(player)) return; // Determine message key and arguments for the rename notification var activityMessageKey = "sa_admin_rename_message"; var adminActivityArgs = new object[] { "CALLER", player.PlayerName, newName }; // Display admin activity message to other players if (caller != null && !SilentPlayers.Contains(caller.Slot)) { Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } // Determine if the new name is valid and update the renamed players list if (!string.IsNullOrEmpty(newName)) { RenamedPlayers[player.SteamID] = newName; player.Rename(newName); } else { RenamedPlayers.Remove(player.SteamID); } }); } /// /// Respawns targeted players, restoring their state. /// /// The admin or player issuing respawn. /// The command including target players. [CommandHelper(1, "<#userid or name>")] [RequiresPermissions("@css/cheats")] public void OnRespawnCommand(CCSPlayerController? caller, CommandInfo command) { var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; var targets = GetTarget(command); if (targets == null) return; var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList(); playersToTarget.ForEach(player => { if (player.Connected != PlayerConnectedState.PlayerConnected) return; if (caller!.CanTarget(player)) { Respawn(caller, player, callerName, command); } }); Helper.LogCommand(caller, command); } /// /// Respawns a specified player and updates admin notifications. /// /// Admin or player executing respawn. /// Player to respawn. /// Optional admin name. /// Optional command info. internal static void Respawn(CCSPlayerController? caller, CCSPlayerController player, string? callerName = null, CommandInfo? command = null) { // Check if the caller can target the player if (!caller.CanTarget(player)) return; // Set default caller name if not provided callerName ??= caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName; // Ensure the player's pawn is valid before attempting to respawn if (_cBasePlayerControllerSetPawnFunc == null || player.PlayerPawn.Value == null || !player.PlayerPawn.IsValid) return; // Perform the respawn operation var playerPawn = player.PlayerPawn.Value; _cBasePlayerControllerSetPawnFunc.Invoke(player, playerPawn, true, false); VirtualFunction.CreateVoid(player.Handle, GameData.GetOffset("CCSPlayerController_Respawn"))(player); 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 if (command == null) Helper.LogCommand(caller, $"css_respawn {(string.IsNullOrEmpty(player.PlayerName) ? player.SteamID.ToString() : player.PlayerName)}"); // Determine message key and arguments for the respawn notification var activityMessageKey = "sa_admin_respawn_message"; var adminActivityArgs = new object[] { "CALLER", player.PlayerName }; // Display admin activity message to other players if (caller != null && SilentPlayers.Contains(caller.Slot)) return; Helper.ShowAdminActivity(activityMessageKey, callerName, false, adminActivityArgs); } /// /// Teleports targeted player(s) to another player's location. /// /// Admin issuing teleport command. /// Command containing teleport targets and destination. [CommandHelper(1, "<#userid or name> [#userid or name]")] [RequiresPermissions("@css/kick")] public void OnGotoCommand(CCSPlayerController? caller, CommandInfo command) { IEnumerable playersToTeleport; CCSPlayerController? destinationPlayer; var targets = GetTarget(command); if (command.ArgCount < 3) { if (caller == null || caller.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE) return; 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); foreach (var player in playersToTeleport) { if (player.PlayerPawn?.Value == null || destinationPlayer?.PlayerPawn?.Value == null) continue; 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"); 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 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"); } }); if (caller != null && !SilentPlayers.Contains(caller.Slot) && _localizer != null) { Helper.ShowAdminActivity("sa_admin_tp_message", player.PlayerName, false, "CALLER", destinationPlayer.PlayerName); } } } /// /// Brings targeted player(s) to the caller or specified destination player's location. /// /// Player issuing the bring command. /// Command containing the destination and targets. [CommandHelper(1, "<#destination or name> [#userid or name...]")] [RequiresPermissions("@css/kick")] public void OnBringCommand(CCSPlayerController? caller, CommandInfo command) { IEnumerable 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; // Log command Helper.LogCommand(caller, command); foreach (var player in playersToTeleport) { if (player.PlayerPawn?.Value == null || destinationPlayer.PlayerPawn?.Value == null) continue; // 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"); 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 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"); } }); if (caller != null && !SilentPlayers.Contains(caller.Slot) && _localizer != null) { 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); // } // } // } }