Files
CS2-SimpleAdmin/CS2-SimpleAdmin-docs/docs/developer/api/penalties.md
Dawid Bepierszcz b0d8696756 Add CS2-SimpleAdmin documentation site
Introduces a new documentation site for CS2-SimpleAdmin using Docusaurus, including developer API references, tutorials, user guides, and module documentation. Removes the CleanModule example and updates FunCommands and ExampleModule. Also updates main plugin and API files to support new documentation and module structure.
2025-10-20 01:27:01 +02:00

611 lines
13 KiB
Markdown

---
sidebar_position: 4
---
# Penalties API
Complete reference for issuing and managing player penalties.
## Penalty Types
```csharp
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.
```csharp
void IssuePenalty(
CCSPlayerController player,
CCSPlayerController? admin,
PenaltyType penaltyType,
string reason,
int duration = -1
)
```
**Parameters:**
- `player` - Target player controller
- `admin` - Admin issuing penalty (null for console)
- `penaltyType` - Type of penalty
- `reason` - Reason for penalty
- `duration` - Duration in minutes (0 = permanent, -1 = default)
**Example:**
```csharp
// 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).
```csharp
void IssuePenalty(
SteamID steamid,
CCSPlayerController? admin,
PenaltyType penaltyType,
string reason,
int duration = -1
)
```
**Parameters:**
- `steamid` - Target player's SteamID
- `admin` - Admin issuing penalty (null for console)
- `penaltyType` - Type of penalty
- `reason` - Reason for penalty
- `duration` - Duration in minutes (0 = permanent, -1 = default)
**Example:**
```csharp
// 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:**
```csharp
// 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.
```csharp
PlayerInfo GetPlayerInfo(CCSPlayerController player)
```
**Returns:** `PlayerInfo` object containing:
- `PlayerName` - Player's name
- `SteamId` - Steam ID (ulong)
- `IpAddress` - Player's IP address
- `Warnings` - Warning count
- `Bans` - Ban count
- `Mutes` - Mute count
- `Gags` - Gag count
**Example:**
```csharp
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.
```csharp
Dictionary<PenaltyType, List<(DateTime EndDateTime, int Duration, bool Passed)>> GetPlayerMuteStatus(
CCSPlayerController player
)
```
**Returns:** Dictionary mapping penalty types to lists of active penalties
**Example:**
```csharp
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.
```csharp
string GetConnectionString()
```
**Example:**
```csharp
var connectionString = _api!.GetConnectionString();
// Use for custom database operations
```
---
### GetServerAddress
Get the server's IP address and port.
```csharp
string GetServerAddress()
```
**Example:**
```csharp
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.
```csharp
int? GetServerId()
```
**Returns:**
- `int` - Server ID if multi-server mode enabled
- `null` - If single-server mode
**Example:**
```csharp
var serverId = _api!.GetServerId();
if (serverId.HasValue)
{
Console.WriteLine($"Server ID: {serverId.Value}");
}
else
{
Console.WriteLine("Single-server mode");
}
```
---
## Complete Examples
### Ban with Validation
```csharp
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
```csharp
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
```csharp
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
```csharp
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
```csharp
[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
```csharp
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
```csharp
// ✅ 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
```csharp
_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
```csharp
// 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
```csharp
// 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
```csharp
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
```csharp
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
```csharp
try
{
var playerInfo = _api!.GetPlayerInfo(player);
// Use playerInfo...
}
catch (KeyNotFoundException)
{
Logger.LogError($"Player info not found for {player?.PlayerName}");
return;
}
```
### Validate SteamID
```csharp
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](commands)** - Issue penalties from commands
- **[Menus API](menus)** - Issue penalties from menus
- **[Events API](events)** - React to penalty events
- **[Utilities API](utilities)** - Helper functions