cs2-SimpleAdmin/CS2-SimpleAdmin/CS2-SimpleAdmin.cs
Dawid Bepierszcz eea700bfb4 Version bump and multi-account/IP ban fixes
Bump version to 1.7.9a and update package references (CounterStrikeSharp.API, Dapper, System.Linq.Async, ZLinq). Replace usages of PlayerConnectedState.PlayerConnected with PlayerConnectedState.Connected across commands, events, and helpers. Add DB method GetExpireOldPlayerIpsQuery (MySQL/SQLite) and call it to purge old player IP records during ban expiration. Improve CacheManager multi-account/ip ban detection (direct IP bans, cross-account IP checks) and adjust ban logic to respect expiration window. In PlayerManager: reduce semaphore, save player IP to DB before performing ban checks (add SavePlayerIpAddress), and always perform ban checks on connect. Simplify config upgrade logic in Helper.UpdateConfig to update the JSON file Version via JsonNode. Misc: adjust ban sound volume, minor exception catch cleanup, and add module folder to .gitignore.
2026-04-23 22:15:44 +02:00

271 lines
No EOL
9.4 KiB
C#

using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Commands.Targeting;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CS2_SimpleAdmin.Database;
using CS2_SimpleAdmin.Managers;
using CS2_SimpleAdmin.Menus;
using CS2_SimpleAdminApi;
using Microsoft.Extensions.Logging;
using MySqlConnector;
namespace CS2_SimpleAdmin;
[MinimumApiVersion(300)]
public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdminConfig>
{
internal static CS2_SimpleAdmin Instance { get; private set; } = new();
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
public override string ModuleAuthor => "daffyy";
public override string ModuleVersion => "1.7.9a";
public override void Load(bool hotReload)
{
Instance = this;
if (hotReload)
{
ServerLoaded = false;
_serverLoading = false;
CacheManager?.Dispose();
CacheManager = new CacheManager();
// OnGameServerSteamAPIActivated();
OnMapStart(string.Empty);
AddTimer(6.0f, () =>
{
if (DatabaseProvider == null) return;
PlayersInfo.Clear();
CachedPlayers.Clear();
BotPlayers.Clear();
foreach (var player in Utilities.GetPlayers().Where(p => p.IsValid && p is { Connected: PlayerConnectedState.Connected, IsHLTV: false }).ToArray())
{
if (!player.IsBot)
PlayerManager.LoadPlayerData(player, true);
else
BotPlayers.Add(player);
};
});
PlayersTimer?.Kill();
PlayersTimer = null;
}
_cBasePlayerControllerSetPawnFunc = new MemoryFunctionVoid<CBasePlayerController, CCSPlayerPawn, bool, bool>(GameData.GetSignature("CBasePlayerController_SetPawn"));
SimpleAdminApi = new Api.CS2_SimpleAdminApi();
Capabilities.RegisterPluginCapability(ICS2_SimpleAdminApi.PluginCapability, () => SimpleAdminApi);
PlayersTimer?.Kill();
PlayersTimer = null;
PlayerManager.CheckPlayersTimer();
Menus.MenuManager.Instance.InitializeDefaultCategories();
BasicMenu.Initialize();
}
public override void OnAllPluginsLoaded(bool hotReload)
{
try
{
MenuApi = MenuCapability.Get();
}
catch (Exception ex)
{
Logger.LogError("Unable to load required plugins ... \n{exception}", ex.Message);
Unload(false);
}
RegisterEvents();
AddTimer(0.5f, RegisterCommands.InitializeCommands);
AddTimer(3.0f, () => ReloadAdmins(null));
if (!CoreConfig.UnlockConCommands)
{
_logger?.LogError(
$"⚠️ Warning: 'UnlockConCommands' is disabled in core.json. " +
$"Players will not be automatically banned when kicked and will be able " +
$"to rejoin the server for 60 seconds. " +
$"To enable instant banning, set 'UnlockConCommands': true"
);
_logger?.LogError(
$"⚠️ Warning: 'UnlockConCommands' is disabled in core.json. " +
$"Players will not be automatically banned when kicked and will be able " +
$"to rejoin the server for 60 seconds. " +
$"To enable instant banning, set 'UnlockConCommands': true"
);
}
}
public void OnConfigParsed(CS2_SimpleAdminConfig config)
{
if (System.Diagnostics.Debugger.IsAttached)
Environment.FailFast(":(!");
Helper.UpdateConfig(config);
_logger = Logger;
Config = config;
bool missing = false;
var cssPath = Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp");
var pluginsPath = Path.Combine(cssPath, "plugins");
var sharedPath = Path.Combine(cssPath, "shared");
foreach (var plugin in _requiredPlugins)
{
var pluginDirPath = Path.Combine(pluginsPath, plugin);
var pluginDllPath = Path.Combine(pluginDirPath, $"{plugin}.dll");
if (!Directory.Exists(pluginDirPath))
{
_logger?.LogError(
$"❌ Plugin directory '{plugin}' missing at: {pluginDirPath}"
);
missing = true;
}
if (!File.Exists(pluginDllPath))
{
_logger?.LogError(
$"❌ Plugin DLL '{plugin}.dll' missing at: {pluginDllPath}"
);
missing = true;
}
}
foreach (var shared in _requiredShared)
{
var sharedDirPath = Path.Combine(sharedPath, shared);
var sharedDllPath = Path.Combine(sharedDirPath, $"{shared}.dll");
if (!Directory.Exists(sharedDirPath))
{
_logger?.LogError(
$"❌ Shared library directory '{shared}' missing at: {sharedDirPath}"
);
missing = true;
}
if (!File.Exists(sharedDllPath))
{
_logger?.LogError(
$"❌ Shared library DLL '{shared}.dll' missing at: {sharedDllPath}"
);
missing = true;
}
}
if (missing)
Server.ExecuteCommand($"css_plugins unload {ModuleName}");
Instance = this;
if (Config.DatabaseConfig.DatabaseType.Contains("mysql", StringComparison.CurrentCultureIgnoreCase))
{
if (string.IsNullOrWhiteSpace(config.DatabaseConfig.DatabaseHost) ||
string.IsNullOrWhiteSpace(config.DatabaseConfig.DatabaseName) ||
string.IsNullOrWhiteSpace(config.DatabaseConfig.DatabaseUser))
{
throw new Exception("[CS2-SimpleAdmin] You need to setup MySQL credentials in config!");
}
var builder = new MySqlConnectionStringBuilder()
{
Server = config.DatabaseConfig.DatabaseHost,
Database = config.DatabaseConfig.DatabaseName,
UserID = config.DatabaseConfig.DatabaseUser,
Password = config.DatabaseConfig.DatabasePassword,
Port = (uint)config.DatabaseConfig.DatabasePort,
SslMode = Enum.TryParse(config.DatabaseConfig.DatabaseSSlMode, true, out MySqlSslMode sslMode)
? sslMode
: MySqlSslMode.Preferred,
Pooling = true,
};
DbConnectionString = builder.ConnectionString;
DatabaseProvider = new MySqlDatabaseProvider(DbConnectionString);
}
else
{
if (string.IsNullOrWhiteSpace(config.DatabaseConfig.SqliteFilePath))
{
throw new Exception("[CS2-SimpleAdmin] You need to specify SQLite file path in config!");
}
DatabaseProvider = new SqliteDatabaseProvider(ModuleDirectory + "/" + config.DatabaseConfig.SqliteFilePath);
}
var (success, exception) = Task.Run(() => DatabaseProvider.CheckConnectionAsync()).GetAwaiter().GetResult();
if (!success)
{
if (exception != null)
Logger.LogError("Problem with database connection! \n{exception}", exception);
Unload(false);
return;
}
Task.Run(() => DatabaseProvider.DatabaseMigrationAsync());
if (!Directory.Exists(ModuleDirectory + "/data"))
{
Directory.CreateDirectory(ModuleDirectory + "/data");
}
_localizer = Localizer;
if (!string.IsNullOrEmpty(Config.Discord.DiscordLogWebhook))
DiscordWebhookClientLog = new DiscordManager(Config.Discord.DiscordLogWebhook);
if (Config.EnableUpdateCheck)
Task.Run(async () => await PluginInfo.CheckVersion(ModuleVersion, Logger));
PermissionManager = new PermissionManager(DatabaseProvider);
BanManager = new BanManager(DatabaseProvider);
MuteManager = new MuteManager(DatabaseProvider);
WarnManager = new WarnManager(DatabaseProvider);
}
internal static TargetResult? GetTarget(CommandInfo command, int argument = 1)
{
var matches = command.GetArgTargetResult(argument);
if (!matches.Any())
{
command.ReplyToCommand($"Target {command.GetArg(argument)} not found.");
return null;
}
if (command.GetArg(argument).StartsWith('@'))
return matches;
if (matches.Count() == 1)
return matches;
command.ReplyToCommand($"Multiple targets found for \"{command.GetArg(argument)}\".");
return null;
}
public override void Unload(bool hotReload)
{
CacheManager?.Dispose();
CacheManager = null;
PlayersTimer?.Kill();
PlayersTimer = null;
UnregisterEvents();
if (hotReload)
PlayersInfo.Clear();
else
Server.ExecuteCommand($"css_plugins unload {ModuleDirectory}");
}
}