diff --git a/CS2-SimpleAdmin.cs b/CS2-SimpleAdmin.cs index 092719d..20f7999 100644 --- a/CS2-SimpleAdmin.cs +++ b/CS2-SimpleAdmin.cs @@ -37,7 +37,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)"); public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)"; public override string ModuleAuthor => "daffyy & Dliix66"; - public override string ModuleVersion => "1.4.5a"; + public override string ModuleVersion => "1.4.6a"; public CS2_SimpleAdminConfig Config { get; set; } = new(); @@ -63,7 +63,7 @@ public override void Unload(bool hotReload) RemoveCommandListener("say", OnCommandSay, HookMode.Post); RemoveCommandListener("say_team", OnCommandTeamSay, HookMode.Post); } - + public override void OnAllPluginsLoaded(bool hotReload) { AddTimer(3.0f, () => ReloadAdmins(null)); @@ -119,7 +119,8 @@ public void OnConfigParsed(CS2_SimpleAdminConfig config) DiscordWebhookClientPenalty = new DiscordWebhookClient(Config.Discord.DiscordPenaltyWebhook); PluginInfo.ShowAd(ModuleVersion); - _ = PluginInfo.CheckVersion(ModuleVersion, _logger); + if (Config.EnableUpdateCheck) + Task.Run(async () => await PluginInfo.CheckVersion(ModuleVersion, _logger)); } private static TargetResult? GetTarget(CommandInfo command) diff --git a/CS2-SimpleAdmin.csproj b/CS2-SimpleAdmin.csproj index b95061d..28a7898 100644 --- a/CS2-SimpleAdmin.csproj +++ b/CS2-SimpleAdmin.csproj @@ -10,9 +10,9 @@ - + - + diff --git a/Commands/basecommands.cs b/Commands/basecommands.cs index e52e0be..e592a46 100644 --- a/Commands/basecommands.cs +++ b/Commands/basecommands.cs @@ -97,8 +97,8 @@ public void OnAdminHelpCommand(CCSPlayerController? caller, CommandInfo command) public void OnAddAdminCommand(CCSPlayerController? caller, CommandInfo command) { if (_database == null) return; - - + + if (!Helper.ValidateSteamId(command.GetArg(1), out var steamId) || steamId == null) { command.ReplyToCommand($"Invalid SteamID64."); @@ -106,7 +106,7 @@ public void OnAddAdminCommand(CCSPlayerController? caller, CommandInfo command) } var steamid = steamId.SteamId64.ToString(); - + if (command.GetArg(2).Length <= 0) { command.ReplyToCommand($"Invalid player name."); @@ -161,7 +161,7 @@ public void OnDelAdminCommand(CCSPlayerController? caller, CommandInfo command) command.ReplyToCommand($"Invalid SteamID64."); return; } - + var globalDelete = command.GetArg(2).ToLower().Equals("-g"); RemoveAdmin(caller, steamId.SteamId64.ToString(), globalDelete, command); @@ -318,7 +318,7 @@ public void ReloadAdmins(CCSPlayerController? caller) Task.Run(async () => { - + await adminManager.CrateGroupsJsonFile(); await adminManager.CreateAdminsJsonFile(); @@ -415,7 +415,7 @@ await Server.NextFrameAsync(() => printMethod($"• SteamID2: \"{player.SteamID}\""); printMethod($"• Community link: \"{new SteamID(player.SteamID).ToCommunityUrl()}\""); } - if (playerInfo.IpAddress != null) + if (playerInfo.IpAddress != null && AdminManager.PlayerHasPermissions(caller, "@css/showip")) printMethod($"• IP Address: \"{playerInfo.IpAddress}\""); printMethod($"• Ping: \"{player.Ping}\""); if (player.SteamID.ToString().Length == 17) @@ -453,7 +453,7 @@ public void OnPlayersCommand(CCSPlayerController? caller, CommandInfo command) playersToTarget.ForEach(player => { caller.PrintToConsole( - $"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{player.IpAddress?.Split(":")[0]}\" SteamID64: \"{player.SteamID}\")"); + $"• [#{player.UserId}] \"{player.PlayerName}\" (IP Address: \"{(AdminManager.PlayerHasPermissions(caller, "@css/showip") ? player.IpAddress?.Split(":")[0] : "Unknown")}\" SteamID64: \"{player.SteamID}\")"); }); caller.PrintToConsole($"--------- END PLAYER LIST ---------"); } @@ -475,18 +475,18 @@ public void OnPlayersCommand(CCSPlayerController? caller, CommandInfo command) return new { - UserId = player.UserId, + player.UserId, Name = player.PlayerName, SteamId = player.SteamID.ToString(), - IpAddress = player.IpAddress?.Split(":")[0] ?? "Unknown", - Ping = player.Ping, + IpAddress = AdminManager.PlayerHasPermissions(caller, "@css/showip") ? player.IpAddress?.Split(":")[0] ?? "Unknown" : "Unknown", + player.Ping, IsAdmin = AdminManager.PlayerHasPermissions(player, "@css/ban") || AdminManager.PlayerHasPermissions(player, "@css/generic"), Stats = new { - Score = player.Score, + player.Score, Kills = matchStats?.Kills ?? 0, Deaths = matchStats?.Deaths ?? 0, - MVPs = player.MVPs + player.MVPs } }; })); @@ -537,10 +537,10 @@ public void OnKickCommand(CCSPlayerController? caller, CommandInfo command) public void Kick(CCSPlayerController? caller, CCSPlayerController? player, string? reason = "Unknown", string? callerName = null, CommandInfo? command = null) { if (player == null || !player.IsValid) return; - + callerName ??= caller == null ? "Console" : caller.PlayerName; reason ??= _localizer?["sa_unknown"] ?? "Unknown"; - + player.Pawn.Value!.Freeze(); if (command != null) diff --git a/Config.cs b/Config.cs index 7f274ab..509f49b 100644 --- a/Config.cs +++ b/Config.cs @@ -102,6 +102,7 @@ public class MenuConfig new AdminFlag { Name = "Ban", Flag = "@css/ban" }, new AdminFlag { Name = "Perm Ban", Flag = "@css/permban" }, new AdminFlag { Name = "Unban", Flag = "@css/unban" }, + new AdminFlag { Name = "Show IP", Flag = "@css/showip" }, new AdminFlag { Name = "Cvar", Flag = "@css/cvar" }, new AdminFlag { Name = "Rcon", Flag = "@css/rcon" }, new AdminFlag { Name = "Root (all flags)", Flag = "@css/root" } @@ -110,7 +111,7 @@ public class MenuConfig public class CS2_SimpleAdminConfig : BasePluginConfig { - [JsonPropertyName("ConfigVersion")] public override int Version { get; set; } = 14; + [JsonPropertyName("ConfigVersion")] public override int Version { get; set; } = 15; [JsonPropertyName("DatabaseHost")] public string DatabaseHost { get; set; } = ""; @@ -129,7 +130,10 @@ public class CS2_SimpleAdminConfig : BasePluginConfig [JsonPropertyName("EnableMetrics")] public bool EnableMetrics { get; set; } = true; - + + [JsonPropertyName("EnableUpdateCheck")] + public bool EnableUpdateCheck { get; set; } = true; + [JsonPropertyName("ReloadAdminsEveryMapChange")] public bool ReloadAdminsEveryMapChange { get; set; } = false; @@ -141,15 +145,15 @@ public class CS2_SimpleAdminConfig : BasePluginConfig [JsonPropertyName("DisableDangerousCommands")] public bool DisableDangerousCommands { get; set; } = true; - + [JsonPropertyName("BanType")] public int BanType { get; set; } = 1; - + [JsonPropertyName("TimeMode")] public int TimeMode { get; set; } = 1; - + [JsonPropertyName("MaxBanDuration")] - public int MaxBanDuration { get; set; } = 60 * 24 * 7; // 7 days + public int MaxBanDuration { get; set; } = 60 * 24 * 7; [JsonPropertyName("MultiServerMode")] public bool MultiServerMode { get; set; } = true; diff --git a/Events.cs b/Events.cs index f6cee71..f497db4 100644 --- a/Events.cs +++ b/Events.cs @@ -15,12 +15,10 @@ public partial class CS2_SimpleAdmin private void RegisterEvents() { RegisterListener(OnMapStart); - //RegisterListener(OnClientConnected); - //RegisterListener(OnClientDisconnect); AddCommandListener("say", OnCommandSay); AddCommandListener("say_team", OnCommandTeamSay); } - + [GameEventHandler] public HookResult OnClientDisconnect(EventPlayerDisconnect @event, GameEventInfo info) { @@ -209,7 +207,7 @@ public HookResult OnCommandSay(CCSPlayerController? player, CommandInfo info) return HookResult.Continue; if (info.GetArg(1).StartsWith($"/") - || info.GetArg(1).StartsWith($"!")) + || info.GetArg(1).StartsWith($"!")) return HookResult.Continue; if (info.GetArg(1).Length == 0) @@ -223,11 +221,11 @@ public HookResult OnCommandSay(CCSPlayerController? player, CommandInfo info) public HookResult OnCommandTeamSay(CCSPlayerController? player, CommandInfo info) { - if (player is null || !player.IsValid || player.IsBot || player.IsHLTV ) + if (player is null || !player.IsValid || player.IsBot || player.IsHLTV) return HookResult.Continue; - + if (info.GetArg(1).StartsWith($"/") - || info.GetArg(1).StartsWith($"!")) + || info.GetArg(1).StartsWith($"!")) return HookResult.Continue; if (info.GetArg(1).Length == 0) @@ -265,7 +263,7 @@ public void OnMapStart(string mapName) { if (Config.ReloadAdminsEveryMapChange) AddTimer(3.0f, () => ReloadAdmins(null)); - + var path = Path.GetDirectoryName(ModuleDirectory); if (Directory.Exists(path + "/CS2-Tags")) { @@ -279,13 +277,15 @@ public void OnMapStart(string mapName) _database = new Database.Database(_dbConnectionString); - AddTimer(2.0f, () => + AddTimer(2.5f, () => { var ipAddress = ConVar.Find("ip")?.StringValue; if (string.IsNullOrEmpty(ipAddress) || ipAddress.StartsWith("0.0.0")) { + ipAddress = Helper.GetServerIp(); Logger.LogError("Unable to get server ip, Check that you have added the correct start parameter \"-ip \""); + Logger.LogError($"Using alternative method... Server IP {ipAddress}"); } var address = $"{ipAddress}:{ConVar.Find("hostport")?.GetPrimitiveValue()}"; @@ -341,7 +341,7 @@ await connection.ExecuteAsync( } } }); - }, CounterStrikeSharp.API.Modules.Timers.TimerFlags.STOP_ON_MAPCHANGE); + }); AddTimer(61.0f, () => { @@ -363,9 +363,9 @@ await connection.ExecuteAsync( await banManager.ExpireOldBans(); await adminManager.DeleteOldAdmins(); - + BannedPlayers.Clear(); - + if (onlinePlayers.Count > 0) { try @@ -380,7 +380,7 @@ await connection.ExecuteAsync( } await muteManager.ExpireOldMutes(); - + await Server.NextFrameAsync(() => { try diff --git a/Helper.cs b/Helper.cs index bdc3765..f190498 100644 --- a/Helper.cs +++ b/Helper.cs @@ -12,6 +12,7 @@ using Microsoft.Extensions.Logging; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; @@ -23,20 +24,23 @@ internal class Helper private static readonly string AssemblyName = Assembly.GetExecutingAssembly().GetName().Name ?? ""; private static readonly string CfgPath = $"{Server.GameDirectory}/csgo/addons/counterstrikesharp/configs/plugins/{AssemblyName}/{AssemblyName}.json"; + public delegate nint CNetworkSystem_UpdatePublicIp(nint a1); + public static CNetworkSystem_UpdatePublicIp? _networkSystemUpdatePublicIp; + internal static CS2_SimpleAdminConfig? Config { get; set; } public static bool IsDebugBuild { get { - #if DEBUG +#if DEBUG return true; - #else - return false; - #endif +#else + return false; +#endif } } - + public static List GetPlayerFromName(string name) { return Utilities.GetPlayers().FindAll(x => x.PlayerName.Equals(name, StringComparison.OrdinalIgnoreCase)); @@ -60,7 +64,7 @@ public static List GetPlayerFromIp(string ipAddress) public static List GetValidPlayers() { return Utilities.GetPlayers().FindAll(p => p is - { IsBot: false, IsHLTV: false }); + { IsBot: false, IsHLTV: false }); } public static IEnumerable GetValidPlayersWithBots() @@ -75,7 +79,7 @@ public static bool IsValidSteamId64(string input) const string pattern = @"^\d{17}$"; return Regex.IsMatch(input, pattern); } - + public static bool ValidateSteamId(string input, out SteamID? steamId) { steamId = null; @@ -86,7 +90,7 @@ public static bool ValidateSteamId(string input, out SteamID? steamId) } if (!SteamID.TryParse(input, out var parsedSteamId)) return false; - + steamId = parsedSteamId; return true; } @@ -222,7 +226,7 @@ public static IEnumerable GenerateEmbedsDiscord(string title, string desc public static void SendDiscordLogMessage(CCSPlayerController? caller, CommandInfo command, DiscordWebhookClient? discordWebhookClientLog, IStringLocalizer? localizer) { if (discordWebhookClientLog == null || localizer == null) return; - + var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : ""; var callerName = caller != null ? caller.PlayerName : "Console"; discordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString])); @@ -246,7 +250,7 @@ private static string ConvertMinutesToTime(int minutes) public static void SendDiscordPenaltyMessage(CCSPlayerController? caller, CCSPlayerController? target, string reason, int duration, PenaltyType penalty, DiscordWebhookClient? discordWebhookClientPenalty, IStringLocalizer? localizer) { if (discordWebhookClientPenalty == null || localizer == null) return; - + var callerCommunityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : ""; var targetCommunityUrl = target != null ? "<" + new SteamID(target.SteamID).ToCommunityUrl() + ">" : ""; var callerName = caller != null ? caller.PlayerName : "Console"; @@ -310,6 +314,33 @@ private static string GenerateMessageDiscord(string message) return message; } + public static string GetServerIp() + { + var network_system = NativeAPI.GetValveInterface(0, "NetworkSystemVersion001"); + + unsafe + { + if (_networkSystemUpdatePublicIp == null) + { + var funcPtr = *(nint*)(*(nint*)(network_system) + 256); + _networkSystemUpdatePublicIp = Marshal.GetDelegateForFunctionPointer(funcPtr); + } + /* + struct netadr_t + { + uint32_t type + uint8_t ip[4] + uint16_t port + } + */ + // + 4 to skip type, because the size of uint32_t is 4 bytes + var ipBytes = (byte*)(_networkSystemUpdatePublicIp(network_system) + 4); + // port is always 0, use the one from convar "hostport" + return $"{ipBytes[0]}.{ipBytes[1]}.{ipBytes[2]}.{ipBytes[3]}"; + } + } + + public static void UpdateConfig(T config) where T : BasePluginConfig, new() { // get newest config version diff --git a/Managers/BanManager.cs b/Managers/BanManager.cs index cc24ef8..073b768 100644 --- a/Managers/BanManager.cs +++ b/Managers/BanManager.cs @@ -1,7 +1,9 @@ -using CounterStrikeSharp.API; +using System.Text; +using CounterStrikeSharp.API; using Dapper; using Microsoft.Extensions.Logging; using MySqlConnector; +using Serilog.Core; namespace CS2_SimpleAdmin; @@ -256,6 +258,7 @@ public async Task UnbanPlayer(string playerPattern, string adminSteamId, string catch { } } + /* public async Task CheckOnlinePlayers(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players) { try @@ -294,6 +297,75 @@ await Server.NextFrameAsync(() => } catch { } } + */ + + public async Task CheckOnlinePlayers(List<(string? IpAddress, ulong SteamID, int? UserId, int Slot)> players) + { + try + { + await using var connection = await database.GetConnectionAsync(); + bool checkIpBans = config.BanType > 0; + + var filteredPlayers = players.Where(p => p.UserId.HasValue).ToList(); + + var steamIds = filteredPlayers.Select(p => p.SteamID).Distinct().ToList(); + var ipAddresses = filteredPlayers + .Where(p => !string.IsNullOrEmpty(p.IpAddress)) + .Select(p => p.IpAddress) + .Distinct() + .ToList(); + + var sql = new StringBuilder(); + sql.Append("SELECT `player_steamid`, `player_ip` FROM `sa_bans` WHERE `status` = 'ACTIVE' "); + + if (config.MultiServerMode) + { + sql.Append("AND (player_steamid IN @SteamIDs "); + if (checkIpBans && ipAddresses.Count != 0) + { + sql.Append("OR player_ip IN @IpAddresses"); + } + sql.Append(')'); + } + else + { + sql.Append("AND server_id = @ServerId AND (player_steamid IN @SteamIDs "); + if (checkIpBans && ipAddresses.Count != 0) + { + sql.Append("OR player_ip IN @IpAddresses"); + } + sql.Append(')'); + } + + var bannedPlayers = await connection.QueryAsync<(ulong PlayerSteamID, string PlayerIP)>( + sql.ToString(), + new + { + SteamIDs = steamIds, + IpAddresses = checkIpBans ? ipAddresses : [], + ServerId = CS2_SimpleAdmin.ServerId + }); + + var valueTuples = bannedPlayers.ToList(); + var bannedSteamIds = valueTuples.Select(b => b.PlayerSteamID).ToHashSet(); + var bannedIps = valueTuples.Select(b => b.PlayerIP).ToHashSet(); + + foreach (var player in filteredPlayers.Where(player => bannedSteamIds.Contains(player.SteamID) || + (checkIpBans && bannedIps.Contains(player.IpAddress ?? "")))) + { + if (!player.UserId.HasValue) continue; + + await Server.NextFrameAsync(() => + { + Helper.KickPlayer(player.UserId.Value, "Banned"); + }); + } + } + catch (Exception ex) + { + CS2_SimpleAdmin._logger?.LogError($"Error checking online players: {ex.Message}"); + } + } public async Task ExpireOldBans() { diff --git a/VERSION b/VERSION index 63221b0..a87f057 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.5a \ No newline at end of file +1.4.6a \ No newline at end of file