```diff
+ `Refactored Code`: Improved code structure for better maintainability.
+ `Player Penalties Command`: Introduced the `css_penalties` command to display player penalties.
+ `Admin Penalties Information`: Added functionality to provide information for admins regarding penalties of connecting players.
+ `Disconnected Players Command`: Added the `css_disconnected` command to show a list of disconnected players.
+ `Colorful Messages`: Implemented the `css_cssay` command to send colorful messages, e.g., `css_cssay {lightgreen}Test`.
+ `Respawn Functionality`: Updated the `css_respawn` command to respawn players at their death location.
+ `Menu Type Management`: Introduced the `css_menus` command to change the menu type via `MenuManagerCS2`.
+ `Dynamic Menu Control`: Enhanced menu interaction with dynamic controls using WASD + ER keys.
+ `Language File Updates`: Updated language files for better localization.
+ `API Integration`: Added a simple API for external interaction.
+ `Configurable Timezone`: Introduced timezone settings in the configuration.
+ `Admin Activity Display Options`: Added configurable settings for displaying admin activity:
+ `0`: Do not show
+ `1`: Hide admin name
+ `2`: Show admin name
+ `Discord Notification Customization`: Made Discord duration notifications customizable with `{relative}` and `{normal}` placeholders.
+ Improved command logging
+
`Configuration Options:`
+ `Timezone`
+ `Other Settings`
+ `Disconnected Players History Count`
+ `Show Activity Type`
```
320 lines
No EOL
14 KiB
C#
320 lines
No EOL
14 KiB
C#
using CounterStrikeSharp.API;
|
|
using CounterStrikeSharp.API.Core;
|
|
using CounterStrikeSharp.API.Modules.Admin;
|
|
using CounterStrikeSharp.API.Modules.Entities;
|
|
using CounterStrikeSharp.API.ValveConstants.Protobuf;
|
|
using CS2_SimpleAdminApi;
|
|
using Dapper;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace CS2_SimpleAdmin.Managers;
|
|
|
|
public class PlayerManager
|
|
{
|
|
private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config;
|
|
|
|
public void LoadPlayerData(CCSPlayerController player)
|
|
{
|
|
if (player.IsBot || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1")
|
|
|| !player.UserId.HasValue)
|
|
return;
|
|
|
|
var ipAddress = player.IpAddress?.Split(":")[0];
|
|
|
|
CS2_SimpleAdmin.PlayersInfo[player.UserId.Value] =
|
|
new PlayerInfo(player.UserId.Value, player.Slot, new SteamID(player.SteamID), player.PlayerName, ipAddress);
|
|
|
|
var userId = player.UserId.Value;
|
|
|
|
// Check if the player's IP or SteamID is in the bannedPlayers list
|
|
if (_config.OtherSettings.BanType > 0 && CS2_SimpleAdmin.BannedPlayers.Contains(ipAddress) || CS2_SimpleAdmin.BannedPlayers.Contains(player.SteamID.ToString()))
|
|
{
|
|
// Kick the player if banned
|
|
if (player.UserId.HasValue)
|
|
Helper.KickPlayer(player.UserId.Value, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
|
|
|
return;
|
|
}
|
|
|
|
if (CS2_SimpleAdmin.Database == null) return;
|
|
|
|
// Perform asynchronous database operations within a single method
|
|
Task.Run(async () =>
|
|
{
|
|
// Initialize managers
|
|
BanManager banManager = new(CS2_SimpleAdmin.Database, _config);
|
|
MuteManager muteManager = new(CS2_SimpleAdmin.Database);
|
|
WarnManager warnManager = new(CS2_SimpleAdmin.Database);
|
|
|
|
try
|
|
{
|
|
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
|
|
|
const string query = """
|
|
INSERT INTO `sa_players_ips` (steamid, address)
|
|
VALUES (@SteamID, @IPAddress) ON DUPLICATE KEY UPDATE `used_at` = CURRENT_TIMESTAMP
|
|
""";
|
|
|
|
await connection.ExecuteAsync(query, new
|
|
{
|
|
SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId,
|
|
IPAddress = ipAddress,
|
|
});
|
|
}
|
|
catch { }
|
|
|
|
try
|
|
{
|
|
// Check if the player is banned
|
|
bool isBanned = await banManager.IsPlayerBanned(CS2_SimpleAdmin.PlayersInfo[userId]);
|
|
|
|
if (isBanned)
|
|
{
|
|
// Add player's IP and SteamID to bannedPlayers list if not already present
|
|
if (_config.OtherSettings.BanType > 0 && ipAddress != null &&
|
|
!CS2_SimpleAdmin.BannedPlayers.Contains(ipAddress))
|
|
{
|
|
CS2_SimpleAdmin.BannedPlayers.Add(ipAddress);
|
|
}
|
|
|
|
if (!CS2_SimpleAdmin.BannedPlayers.Contains(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()))
|
|
{
|
|
CS2_SimpleAdmin.BannedPlayers.Add(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString());
|
|
}
|
|
|
|
// Kick the player if banned
|
|
await Server.NextFrameAsync(() =>
|
|
{
|
|
var victim = Utilities.GetPlayerFromUserid(userId);
|
|
|
|
if (victim?.UserId == null) return;
|
|
|
|
if (CS2_SimpleAdmin.UnlockedCommands)
|
|
Server.ExecuteCommand($"banid 1 {userId}");
|
|
|
|
Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED);
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
var warns = await warnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false);
|
|
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans =
|
|
await banManager.GetPlayerBans(CS2_SimpleAdmin.PlayersInfo[userId]);
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes =
|
|
await muteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId], 1);
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalGags =
|
|
await muteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId], 0);
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences =
|
|
await muteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId], 2);
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns = warns.Count;
|
|
|
|
|
|
// Check if the player is muted
|
|
var activeMutes = await muteManager.IsPlayerMuted(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString());
|
|
|
|
/*
|
|
Dictionary<PenaltyType, List<string>> mutesList = new()
|
|
{
|
|
{ PenaltyType.Gag, [] },
|
|
{ PenaltyType.Mute, [] },
|
|
{ PenaltyType.Silence, [] }
|
|
};
|
|
|
|
List<string> warnsList = [];
|
|
|
|
bool found = false;
|
|
foreach (var warn in warns.TakeWhile(warn => (string)warn.status == "ACTIVE"))
|
|
{
|
|
DateTime ends = warn.ends;
|
|
if (CS2_SimpleAdmin._localizer == null) continue;
|
|
|
|
Console.WriteLine(ends.ToLocalTime().ToString(CultureInfo.CurrentCulture));
|
|
|
|
warnsList.Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_warn", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture), (string)warn.reason]);
|
|
found = true;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
if (CS2_SimpleAdmin._localizer != null)
|
|
warnsList.Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_no_active_warn"]);
|
|
}
|
|
*/
|
|
|
|
if (activeMutes.Count > 0)
|
|
{
|
|
foreach (var mute in activeMutes)
|
|
{
|
|
string muteType = mute.type;
|
|
DateTime ends = mute.ends;
|
|
int duration = mute.duration;
|
|
switch (muteType)
|
|
{
|
|
// Apply mute penalty based on mute type
|
|
case "GAG":
|
|
PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Gag, ends, duration);
|
|
// if (CS2_SimpleAdmin._localizer != null)
|
|
// mutesList[PenaltyType.Gag].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_gag", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture)]);
|
|
break;
|
|
case "MUTE":
|
|
PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Mute, ends, duration);
|
|
await Server.NextFrameAsync(() =>
|
|
{
|
|
player.VoiceFlags = VoiceFlags.Muted;
|
|
});
|
|
// if (CS2_SimpleAdmin._localizer != null)
|
|
// mutesList[PenaltyType.Mute].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_mute", ends.ToLocalTime().ToString(CultureInfo.InvariantCulture)]);
|
|
break;
|
|
default:
|
|
PlayerPenaltyManager.AddPenalty(CS2_SimpleAdmin.PlayersInfo[userId].Slot, PenaltyType.Silence, ends, duration);
|
|
await Server.NextFrameAsync(() =>
|
|
{
|
|
player.VoiceFlags = VoiceFlags.Muted;
|
|
});
|
|
// if (CS2_SimpleAdmin._localizer != null)
|
|
// mutesList[PenaltyType.Silence].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_active_silence", ends.ToLocalTime().ToString(CultureInfo.CurrentCulture)]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (CS2_SimpleAdmin._localizer != null)
|
|
{
|
|
if (mutesList[PenaltyType.Gag].Count == 0)
|
|
mutesList[PenaltyType.Gag].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_no_active_gag"]);
|
|
if (mutesList[PenaltyType.Mute].Count == 0)
|
|
mutesList[PenaltyType.Mute].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_no_active_mute"]);
|
|
if (mutesList[PenaltyType.Silence].Count == 0)
|
|
mutesList[PenaltyType.Silence].Add(CS2_SimpleAdmin._localizer["sa_player_penalty_info_no_active_silence"]);
|
|
}
|
|
*/
|
|
|
|
/*
|
|
await Server.NextFrameAsync(() =>
|
|
{
|
|
CS2_SimpleAdmin.Instance.AddTimer(3.0f, () =>
|
|
{
|
|
player.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_player_penalty_info",
|
|
[
|
|
player.PlayerName,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalGags,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns,
|
|
string.Join("\n", mutesList.SelectMany(kvp => kvp.Value)),
|
|
string.Join("\n", warnsList)
|
|
]);
|
|
});
|
|
*/
|
|
|
|
await Server.NextFrameAsync(() =>
|
|
{
|
|
foreach (var admin in Helper.GetValidPlayers()
|
|
.Where(p => (AdminManager.PlayerHasPermissions(p, "@css/kick") ||
|
|
AdminManager.PlayerHasPermissions(p, "@css/ban")) &&
|
|
p.Connected == PlayerConnectedState.PlayerConnected))
|
|
{
|
|
if (CS2_SimpleAdmin._localizer != null && admin != player)
|
|
admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_penalty_info",
|
|
player.PlayerName,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalBans,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalGags,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences,
|
|
CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns
|
|
);
|
|
}
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
CS2_SimpleAdmin._logger?.LogError($"Error processing player connection: {ex}");
|
|
}
|
|
});
|
|
|
|
if (CS2_SimpleAdmin.RenamedPlayers.TryGetValue(player.SteamID, out var name))
|
|
{
|
|
player.Rename(name);
|
|
}
|
|
}
|
|
|
|
public void CheckPlayersTimer()
|
|
{
|
|
CS2_SimpleAdmin.Database = new Database.Database(CS2_SimpleAdmin.Instance.DbConnectionString);
|
|
|
|
CS2_SimpleAdmin.Instance.AddTimer(61.0f, () =>
|
|
{
|
|
#if DEBUG
|
|
CS2_SimpleAdmin._logger?.LogCritical("[OnMapStart] Expired check");
|
|
#endif
|
|
|
|
var players = Helper.GetValidPlayers();
|
|
var onlinePlayers = players
|
|
.Where(player => player.IpAddress != null)
|
|
.Select(player => (player.IpAddress, player.SteamID, player.UserId, player.Slot))
|
|
.ToList();
|
|
|
|
Task.Run(async () =>
|
|
{
|
|
PermissionManager adminManager = new(CS2_SimpleAdmin.Database);
|
|
BanManager banManager = new(CS2_SimpleAdmin.Database, _config);
|
|
MuteManager muteManager = new(CS2_SimpleAdmin.Database);
|
|
WarnManager warnManager = new(CS2_SimpleAdmin.Database);
|
|
|
|
await muteManager.ExpireOldMutes();
|
|
await banManager.ExpireOldBans();
|
|
await warnManager.ExpireOldWarns();
|
|
await adminManager.DeleteOldAdmins();
|
|
|
|
CS2_SimpleAdmin.BannedPlayers.Clear();
|
|
|
|
if (onlinePlayers.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
await banManager.CheckOnlinePlayers(onlinePlayers);
|
|
|
|
if (_config.OtherSettings.TimeMode == 0)
|
|
{
|
|
await muteManager.CheckOnlineModeMutes(onlinePlayers);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
CS2_SimpleAdmin._logger?.LogError("Unable to check bans for online players");
|
|
}
|
|
}
|
|
|
|
await Server.NextFrameAsync(() =>
|
|
{
|
|
if (onlinePlayers.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
foreach (var player in players.Where(player => PlayerPenaltyManager.IsSlotInPenalties(player.Slot)))
|
|
{
|
|
if (!PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) && !PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence))
|
|
player.VoiceFlags = VoiceFlags.Normal;
|
|
|
|
if (PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence) ||
|
|
PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute) ||
|
|
PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag)) continue;
|
|
player.VoiceFlags = VoiceFlags.Normal;
|
|
}
|
|
|
|
PlayerPenaltyManager.RemoveExpiredPenalties();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
CS2_SimpleAdmin._logger?.LogError("Unable to remove old penalties");
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}, CounterStrikeSharp.API.Modules.Timers.TimerFlags.REPEAT | CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE);
|
|
}
|
|
} |