Penalties API
Complete reference for issuing and managing player penalties.
Penalty Types
public enum PenaltyType
{
Ban, // Ban player from server
Kick, // Kick player from server
Gag, // Block text chat
Mute, // Block voice chat
Silence, // Block both text and voice
Warn // Issue warning
}
Issue Penalties
IssuePenalty (Online Player)
Issue a penalty to a currently connected player.
void IssuePenalty(
CCSPlayerController player,
CCSPlayerController? admin,
PenaltyType penaltyType,
string reason,
int duration = -1
)
Parameters:
player- Target player controlleradmin- Admin issuing penalty (null for console)penaltyType- Type of penaltyreason- Reason for penaltyduration- Duration in minutes (0 = permanent, -1 = default)
Example:
// Ban player for 1 day
_api!.IssuePenalty(
player,
admin,
PenaltyType.Ban,
"Cheating",
1440 // 24 hours in minutes
);
// Permanent ban
_api.IssuePenalty(
player,
admin,
PenaltyType.Ban,
"Severe rule violation",
0
);
// Kick player
_api.IssuePenalty(
player,
admin,
PenaltyType.Kick,
"AFK"
);
// Gag for 30 minutes
_api.IssuePenalty(
player,
admin,
PenaltyType.Gag,
"Chat spam",
30
);
IssuePenalty (Offline Player)
Issue a penalty to a player by SteamID (even if offline).
void IssuePenalty(
SteamID steamid,
CCSPlayerController? admin,
PenaltyType penaltyType,
string reason,
int duration = -1
)
Parameters:
steamid- Target player's SteamIDadmin- Admin issuing penalty (null for console)penaltyType- Type of penaltyreason- Reason for penaltyduration- Duration in minutes (0 = permanent, -1 = default)
Example:
// Ban offline player
var steamId = new SteamID(76561198012345678);
_api!.IssuePenalty(
steamId,
admin,
PenaltyType.Ban,
"Ban evasion",
10080 // 7 days
);
// Mute offline player
_api.IssuePenalty(
steamId,
admin,
PenaltyType.Mute,
"Voice abuse",
1440
);
Supported SteamID Formats:
// SteamID64
new SteamID(76561198012345678)
// Also works with SteamID string parsing
SteamID.FromString("STEAM_1:0:12345678")
SteamID.FromString("[U:1:12345678]")
Get Player Information
GetPlayerInfo
Get detailed player information including penalty counts.
PlayerInfo GetPlayerInfo(CCSPlayerController player)
Returns: PlayerInfo object containing:
PlayerName- Player's nameSteamId- Steam ID (ulong)IpAddress- Player's IP addressWarnings- Warning countBans- Ban countMutes- Mute countGags- Gag count
Example:
var playerInfo = _api!.GetPlayerInfo(player);
Console.WriteLine($"Player: {playerInfo.PlayerName}");
Console.WriteLine($"SteamID: {playerInfo.SteamId}");
Console.WriteLine($"Warnings: {playerInfo.Warnings}");
Console.WriteLine($"Total Bans: {playerInfo.Bans}");
// Check if player has penalties
if (playerInfo.Warnings >= 3)
{
_api.IssuePenalty(player, null, PenaltyType.Ban, "Too many warnings", 1440);
}
Throws:
KeyNotFoundException- If player doesn't have a valid UserId
GetPlayerMuteStatus
Get current mute/gag/silence status for a player.
Dictionary<PenaltyType, List<(DateTime EndDateTime, int Duration, bool Passed)>> GetPlayerMuteStatus(
CCSPlayerController player
)
Returns: Dictionary mapping penalty types to lists of active penalties
Example:
var muteStatus = _api!.GetPlayerMuteStatus(player);
// Check if player is gagged
if (muteStatus.ContainsKey(PenaltyType.Gag))
{
var gagPenalties = muteStatus[PenaltyType.Gag];
foreach (var (endTime, duration, passed) in gagPenalties)
{
if (!passed)
{
var remaining = endTime - DateTime.UtcNow;
Console.WriteLine($"Gagged for {remaining.TotalMinutes:F0} more minutes");
}
}
}
// Check if player is muted
if (muteStatus.ContainsKey(PenaltyType.Mute))
{
Console.WriteLine("Player is currently muted");
}
// Check if player is silenced
if (muteStatus.ContainsKey(PenaltyType.Silence))
{
Console.WriteLine("Player is silenced (gag + mute)");
}
Server Information
GetConnectionString
Get the database connection string.
string GetConnectionString()
Example:
var connectionString = _api!.GetConnectionString();
// Use for custom database operations
GetServerAddress
Get the server's IP address and port.
string GetServerAddress()
Example:
var serverAddress = _api!.GetServerAddress();
Console.WriteLine($"Server: {serverAddress}");
// Example output: "192.168.1.100:27015"
GetServerId
Get the server's unique ID in the database.
int? GetServerId()
Returns:
int- Server ID if multi-server mode enablednull- If single-server mode
Example:
var serverId = _api!.GetServerId();
if (serverId.HasValue)
{
Console.WriteLine($"Server ID: {serverId.Value}");
}
else
{
Console.WriteLine("Single-server mode");
}
Complete Examples
Ban with Validation
private void BanPlayer(CCSPlayerController? admin, CCSPlayerController target, int duration, string reason)
{
// Validate player
if (!target.IsValid)
{
admin?.PrintToChat("Invalid player!");
return;
}
// Check immunity
if (admin != null && !admin.CanTarget(target))
{
admin.PrintToChat($"You cannot ban {target.PlayerName} (higher immunity)!");
return;
}
// Get player info to check history
var playerInfo = _api!.GetPlayerInfo(target);
Logger.LogInformation(
$"{admin?.PlayerName ?? "Console"} banning {playerInfo.PlayerName} " +
$"(SteamID: {playerInfo.SteamId}, Previous bans: {playerInfo.Bans})"
);
// Issue ban
_api.IssuePenalty(target, admin, PenaltyType.Ban, reason, duration);
// Show activity
if (admin == null || !_api.IsAdminSilent(admin))
{
var durationText = duration == 0 ? "permanently" : $"for {duration} minutes";
Server.PrintToChatAll($"{admin?.PlayerName ?? "Console"} banned {target.PlayerName} {durationText}: {reason}");
}
}
Progressive Punishment System
private void HandlePlayerOffense(CCSPlayerController? admin, CCSPlayerController target, string reason)
{
var playerInfo = _api!.GetPlayerInfo(target);
// Progressive punishment based on warning count
if (playerInfo.Warnings == 0)
{
// First offense - warning
_api.IssuePenalty(target, admin, PenaltyType.Warn, reason);
target.PrintToChat("This is your first warning!");
}
else if (playerInfo.Warnings == 1)
{
// Second offense - gag for 30 minutes
_api.IssuePenalty(target, admin, PenaltyType.Gag, $"Second offense: {reason}", 30);
target.PrintToChat("Second warning! You are gagged for 30 minutes.");
}
else if (playerInfo.Warnings == 2)
{
// Third offense - 1 day ban
_api.IssuePenalty(target, admin, PenaltyType.Ban, $"Third offense: {reason}", 1440);
target.PrintToChat("Third offense! You are banned for 1 day.");
}
else
{
// More than 3 warnings - permanent ban
_api.IssuePenalty(target, admin, PenaltyType.Ban, $"Multiple offenses: {reason}", 0);
}
}
Check Active Penalties Before Action
private void AllowPlayerToChat(CCSPlayerController player)
{
var muteStatus = _api!.GetPlayerMuteStatus(player);
// Check if player is gagged
if (muteStatus.ContainsKey(PenaltyType.Gag))
{
player.PrintToChat("You are currently gagged and cannot use chat!");
return;
}
// Check if player is silenced (includes gag)
if (muteStatus.ContainsKey(PenaltyType.Silence))
{
player.PrintToChat("You are silenced and cannot communicate!");
return;
}
// Player can chat
ProcessChatMessage(player);
}
Offline Player Ban
private void BanOfflinePlayer(CCSPlayerController? admin, string steamIdString, int duration, string reason)
{
// Parse SteamID
if (!ulong.TryParse(steamIdString, out ulong steamId64))
{
admin?.PrintToChat("Invalid SteamID format!");
return;
}
var steamId = new SteamID(steamId64);
// Issue offline ban
_api!.IssuePenalty(steamId, admin, PenaltyType.Ban, reason, duration);
Logger.LogInformation(
$"{admin?.PlayerName ?? "Console"} banned offline player " +
$"(SteamID: {steamId64}) for {duration} minutes: {reason}"
);
admin?.PrintToChat($"Offline ban issued to SteamID {steamId64}");
}
Multi-Account Detection
[GameEventHandler]
public HookResult OnPlayerConnect(EventPlayerConnectFull @event, GameEventInfo info)
{
var player = @event.Userid;
if (player == null || !player.IsValid) return HookResult.Continue;
var playerInfo = _api!.GetPlayerInfo(player);
// Check if player has multiple accounts
if (playerInfo.Bans > 0)
{
// Notify admins
var admins = Utilities.GetPlayers()
.Where(p => AdminManager.PlayerHasPermissions(p, "@css/ban"));
foreach (var admin in admins)
{
admin.PrintToChat(
$"⚠ {player.PlayerName} has {playerInfo.Bans} previous ban(s)!"
);
}
}
return HookResult.Continue;
}
Best Practices
1. Always Validate Players
if (!target.IsValid || !target.PawnIsAlive)
{
return;
}
// Check immunity
if (admin != null && !admin.CanTarget(target))
{
admin.PrintToChat("Cannot target this player!");
return;
}
2. Provide Clear Reasons
// ✅ Good - Specific reason
_api.IssuePenalty(player, admin, PenaltyType.Ban, "Aimbot detected in Round 12", 10080);
// ❌ Bad - Vague reason
_api.IssuePenalty(player, admin, PenaltyType.Ban, "cheating", 10080);
3. Log Penalty Actions
_api.IssuePenalty(player, admin, PenaltyType.Ban, reason, duration);
Logger.LogInformation(
$"Penalty issued: {admin?.PlayerName ?? "Console"} -> {player.PlayerName} " +
$"| Type: {PenaltyType.Ban} | Duration: {duration}m | Reason: {reason}"
);
4. Handle Kick Separately
// Kick doesn't need duration
_api.IssuePenalty(player, admin, PenaltyType.Kick, reason);
// NOT:
_api.IssuePenalty(player, admin, PenaltyType.Kick, reason, 0);
5. Check Active Penalties
// Before issuing new penalty, check existing ones
var muteStatus = _api.GetPlayerMuteStatus(player);
if (muteStatus.ContainsKey(PenaltyType.Gag))
{
admin?.PrintToChat($"{player.PlayerName} is already gagged!");
return;
}
Common Patterns
Duration Helpers
public static class PenaltyDurations
{
public const int OneHour = 60;
public const int OneDay = 1440;
public const int OneWeek = 10080;
public const int TwoWeeks = 20160;
public const int OneMonth = 43200;
public const int Permanent = 0;
}
// Usage
_api.IssuePenalty(player, admin, PenaltyType.Ban, reason, PenaltyDurations.OneWeek);
Penalty History Display
private void ShowPlayerHistory(CCSPlayerController admin, CCSPlayerController target)
{
var info = _api!.GetPlayerInfo(target);
admin.PrintToChat($"=== {info.PlayerName} History ===");
admin.PrintToChat($"Warnings: {info.Warnings}");
admin.PrintToChat($"Bans: {info.Bans}");
admin.PrintToChat($"Mutes: {info.Mutes}");
admin.PrintToChat($"Gags: {info.Gags}");
var muteStatus = _api.GetPlayerMuteStatus(target);
if (muteStatus.ContainsKey(PenaltyType.Gag))
admin.PrintToChat("Currently: GAGGED");
if (muteStatus.ContainsKey(PenaltyType.Mute))
admin.PrintToChat("Currently: MUTED");
if (muteStatus.ContainsKey(PenaltyType.Silence))
admin.PrintToChat("Currently: SILENCED");
}
Error Handling
Handle Invalid Players
try
{
var playerInfo = _api!.GetPlayerInfo(player);
// Use playerInfo...
}
catch (KeyNotFoundException)
{
Logger.LogError($"Player info not found for {player?.PlayerName}");
return;
}
Validate SteamID
private bool TryParseSteamId(string input, out SteamID steamId)
{
steamId = default;
if (ulong.TryParse(input, out ulong steamId64))
{
steamId = new SteamID(steamId64);
return true;
}
return false;
}
Related APIs
- Commands API - Issue penalties from commands
- Menus API - Issue penalties from menus
- Events API - React to penalty events
- Utilities API - Helper functions