using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; using CounterStrikeSharp.API.Modules.Entities; using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.ValveConstants.Protobuf; using CS2_SimpleAdminApi; using Dapper; using Microsoft.Extensions.Logging; using ZLinq; namespace CS2_SimpleAdmin.Managers; public class PlayerManager { private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config; public void LoadPlayerData(CCSPlayerController player, bool fullConnect = false) { if (player.IsBot || string.IsNullOrEmpty(player.IpAddress) || player.IpAddress.Contains("127.0.0.1")) return; if (!player.UserId.HasValue) { Helper.KickPlayer(player, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_INVALIDCONNECTION); 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); // if (!player.UserId.HasValue) // { // Helper.KickPlayer(player, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_INVALIDCONNECTION); // return; // } var userId = player.UserId.Value; if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(userId)) { Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_INVALIDCONNECTION); } var steamId64 = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64; var steamId = steamId64.ToString(); if (CS2_SimpleAdmin.Database == null) return; // Perform asynchronous database operations within a single method Task.Run(async () => { var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch { 0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(steamId, null), _ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(steamId64) : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(steamId, ipAddress) }; if (isBanned) { // Kick the player if banned await Server.NextFrameAsync(() => { if (!player.UserId.HasValue) return; Helper.KickPlayer(userId, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED); }); return; } if (_config.OtherSettings.CheckMultiAccountsByIp && ipAddress != null) { try { if (CS2_SimpleAdmin.Instance.CacheManager.HasIpForPlayer( CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, ipAddress)) { await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); const string updateQuery = """ UPDATE `sa_players_ips` SET used_at = CURRENT_TIMESTAMP WHERE steamid = @SteamID AND address = @IPAddress; """; await connection.ExecuteAsync(updateQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, IPAddress = ipAddress }); } else { await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync(); const string selectQuery = "SELECT COUNT(*) FROM `sa_players_ips` WHERE steamid = @SteamID AND address = @IPAddress;"; var recordExists = await connection.ExecuteScalarAsync(selectQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, IPAddress = ipAddress }); if (recordExists > 0) { const string updateQuery = """ UPDATE `sa_players_ips` SET used_at = CURRENT_TIMESTAMP WHERE steamid = @SteamID AND address = @IPAddress; """; await connection.ExecuteAsync(updateQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, IPAddress = ipAddress }); } else { const string insertQuery = """ INSERT INTO `sa_players_ips` (steamid, address, used_at) VALUES (@SteamID, @IPAddress, CURRENT_TIMESTAMP); """; await connection.ExecuteAsync(insertQuery, new { SteamID = CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64, IPAddress = ipAddress }); } } } catch (Exception ex) { CS2_SimpleAdmin._logger?.LogError( $"Unable to save ip address for {CS2_SimpleAdmin.PlayersInfo[userId].Name} ({ipAddress}) {ex.Message}"); } // Get all accounts associated to the player (ip address) CS2_SimpleAdmin.PlayersInfo[userId].AccountsAssociated = CS2_SimpleAdmin.Instance.CacheManager.GetAccountsByIp(ipAddress); } try { // var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0 // ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned( // CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString(), null) // : CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp // ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(CS2_SimpleAdmin // .PlayersInfo[userId].SteamId.SteamId64) // : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString(), ipAddress); if (fullConnect || !fullConnect) // Temp skip { var warns = await CS2_SimpleAdmin.Instance.WarnManager.GetPlayerWarns(CS2_SimpleAdmin.PlayersInfo[userId], false); var (totalMutes, totalGags, totalSilences) = await CS2_SimpleAdmin.Instance.MuteManager.GetPlayerMutes(CS2_SimpleAdmin.PlayersInfo[userId]); CS2_SimpleAdmin.PlayersInfo[userId].TotalBans = CS2_SimpleAdmin.Instance.CacheManager.GetPlayerBansBySteamId(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()).Count; CS2_SimpleAdmin.PlayersInfo[userId].TotalMutes = totalMutes; CS2_SimpleAdmin.PlayersInfo[userId].TotalGags = totalGags; CS2_SimpleAdmin.PlayersInfo[userId].TotalSilences = totalSilences; CS2_SimpleAdmin.PlayersInfo[userId].TotalWarns = warns.Count; // Check if the player is muted var activeMutes = await CS2_SimpleAdmin.Instance.MuteManager.IsPlayerMuted(CS2_SimpleAdmin.PlayersInfo[userId].SteamId.SteamId64.ToString()); 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.Instance.Config.OtherSettings.NotifyPenaltiesToAdminOnConnect && fullConnect) { var associatedAcccountsChunks = CS2_SimpleAdmin.PlayersInfo[userId].AccountsAssociated.ChunkBy(5).ToList(); await Server.NextFrameAsync(() => { foreach (var admin in Helper.GetValidPlayers() .Where(p => (AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/kick") || AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/ban")) && p.Connected == PlayerConnectedState.PlayerConnected && !CS2_SimpleAdmin.AdminDisabledJoinComms.Contains(p.SteamID))) { 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 ); foreach (var chunk in associatedAcccountsChunks) { admin.SendLocalizedMessage(CS2_SimpleAdmin._localizer, "sa_admin_associated_accounts", player.PlayerName, string.Join(", ", chunk.Select(a => $"{a.PlayerName} ({a.SteamId})")) ); } } } }); } } catch (Exception ex) { CS2_SimpleAdmin._logger?.LogError("Error processing player connection: {exception}", ex.Message); } }); if (CS2_SimpleAdmin.RenamedPlayers.TryGetValue(player.SteamID, out var name)) { player.Rename(name); } } public void CheckPlayersTimer() { CS2_SimpleAdmin.Instance.AddTimer(0.1f, () => { if (CS2_SimpleAdmin.GravityPlayers.Count <= 0) return; foreach (var value in CS2_SimpleAdmin.GravityPlayers.Where(value => value.Key is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected } || value.Key.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE)) { value.Key.SetGravity(value.Value); } }, TimerFlags.REPEAT); CS2_SimpleAdmin.Instance.AddTimer(61.0f, () => { #if DEBUG CS2_SimpleAdmin._logger?.LogCritical("[OnMapStart] Expired check"); #endif if (CS2_SimpleAdmin.Database == null) return; var players = Helper.GetValidPlayers().ToList(); var bannedPlayers = players.AsValueEnumerable() .Where(player => { return CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch { 0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), null), _ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp ? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(player.SteamID) : CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), player.IpAddress) }; }) .ToList(); foreach (var player in bannedPlayers) { Helper.KickPlayer(player, NetworkDisconnectionReason.NETWORK_DISCONNECT_REJECT_BANNED); players.Remove(player); } var onlinePlayers = players.AsValueEnumerable().Select(player => (player.SteamID, player.UserId, player.Slot)).ToList(); try { var expireTasks = new[] { CS2_SimpleAdmin.Instance.BanManager.ExpireOldBans(), CS2_SimpleAdmin.Instance.MuteManager.ExpireOldMutes(), CS2_SimpleAdmin.Instance.WarnManager.ExpireOldWarns(), CS2_SimpleAdmin.Instance.CacheManager.RefreshCacheAsync(), CS2_SimpleAdmin.Instance.PermissionManager.DeleteOldAdmins() }; Task.WhenAll(expireTasks).ContinueWith(t => { if (t is not { IsFaulted: true, Exception: not null }) return; foreach (var ex in t.Exception.InnerExceptions) { CS2_SimpleAdmin._logger?.LogError($"Error processing players timer tasks: {ex.Message}"); } }); } catch (Exception ex) { CS2_SimpleAdmin._logger?.LogError("Unexpected error: {exception}", ex.Message); } if (players.Count == 0 || onlinePlayers.Count == 0) return; try { Task.Run(async () => { // await CS2_SimpleAdmin.Instance.BanManager.CheckOnlinePlayers(onlinePlayers); if (_config.OtherSettings.TimeMode == 0) { await CS2_SimpleAdmin.Instance.MuteManager.CheckOnlineModeMutes(onlinePlayers); } }).ContinueWith(t => { if (t is not { IsFaulted: true, Exception: not null }) return; foreach (var ex in t.Exception.InnerExceptions) { CS2_SimpleAdmin._logger?.LogError($"Error checking online players: {ex.Message}"); } }); } catch (Exception ex) { CS2_SimpleAdmin._logger?.LogError($"Unexpected error: {ex.Message}"); } try { var penalizedSlots = players .Where(player => PlayerPenaltyManager.IsSlotInPenalties(player.Slot)) .Select(player => new { Player = player, IsMuted = PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Mute, out _), IsSilenced = PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Silence, out _), IsGagged = PlayerPenaltyManager.IsPenalized(player.Slot, PenaltyType.Gag, out _) }); foreach (var entry in penalizedSlots) { // If the player is not muted or silenced, set voice flags to normal if (!entry.IsMuted && !entry.IsSilenced) { entry.Player.VoiceFlags = VoiceFlags.Normal; } } PlayerPenaltyManager.RemoveExpiredPenalties(); } catch (Exception ex) { CS2_SimpleAdmin._logger?.LogError($"Unable to remove old penalties: {ex.Message}"); } }, TimerFlags.REPEAT); } }