mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-02-18 10:43:23 +00:00
Compare commits
2 Commits
0dded66e5d
...
9723a4faee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9723a4faee | ||
|
|
4865b76262 |
@@ -21,13 +21,12 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
|
|||||||
|
|
||||||
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
|
||||||
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
|
||||||
public override string ModuleAuthor => "daffyy & Dliix66";
|
public override string ModuleAuthor => "daffyy";
|
||||||
public override string ModuleVersion => "1.7.8-beta-5";
|
public override string ModuleVersion => "1.7.8-beta-6";
|
||||||
|
|
||||||
public override void Load(bool hotReload)
|
public override void Load(bool hotReload)
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
if (hotReload)
|
if (hotReload)
|
||||||
{
|
{
|
||||||
ServerLoaded = false;
|
ServerLoaded = false;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class MySqlDatabaseProvider(string connectionString) : IDatabaseProvider
|
|||||||
cmd.CommandText = "SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci';";
|
cmd.CommandText = "SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci';";
|
||||||
await cmd.ExecuteNonQueryAsync();
|
await cmd.ExecuteNonQueryAsync();
|
||||||
|
|
||||||
cmd.CommandText = "SET time_zone = '+00:00';";
|
// cmd.CommandText = "SET time_zone = '+00:00';";
|
||||||
await cmd.ExecuteNonQueryAsync();
|
await cmd.ExecuteNonQueryAsync();
|
||||||
|
|
||||||
return connection;
|
return connection;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public partial class CS2_SimpleAdmin
|
|||||||
{
|
{
|
||||||
RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
RegisterListener<Listeners.OnMapStart>(OnMapStart);
|
||||||
// RegisterListener<Listeners.OnClientConnect>(OnClientConnect);
|
// RegisterListener<Listeners.OnClientConnect>(OnClientConnect);
|
||||||
RegisterListener<Listeners.OnClientConnect>(OnClientConnect);
|
// RegisterListener<Listeners.OnClientConnect>(OnClientConnect);
|
||||||
RegisterListener<Listeners.OnClientConnected>(OnClientConnected);
|
RegisterListener<Listeners.OnClientConnected>(OnClientConnected);
|
||||||
RegisterListener<Listeners.OnGameServerSteamAPIActivated>(OnGameServerSteamAPIActivated);
|
RegisterListener<Listeners.OnGameServerSteamAPIActivated>(OnGameServerSteamAPIActivated);
|
||||||
if (Config.OtherSettings.UserMessageGagChatType)
|
if (Config.OtherSettings.UserMessageGagChatType)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Collections.Concurrent;
|
|||||||
using CS2_SimpleAdmin.Database;
|
using CS2_SimpleAdmin.Database;
|
||||||
using CS2_SimpleAdmin.Models;
|
using CS2_SimpleAdmin.Models;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using ZLinq;
|
using ZLinq;
|
||||||
|
|
||||||
namespace CS2_SimpleAdmin.Managers;
|
namespace CS2_SimpleAdmin.Managers;
|
||||||
@@ -16,6 +17,7 @@ internal class CacheManager: IDisposable
|
|||||||
private HashSet<uint> _cachedIgnoredIps = [];
|
private HashSet<uint> _cachedIgnoredIps = [];
|
||||||
|
|
||||||
private DateTime _lastUpdateTime = DateTime.MinValue;
|
private DateTime _lastUpdateTime = DateTime.MinValue;
|
||||||
|
private DateTime? _lastDatabaseTime = null; // Track actual time from database
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -156,13 +158,20 @@ internal class CacheManager: IDisposable
|
|||||||
await using var connection = await CS2_SimpleAdmin.DatabaseProvider.CreateConnectionAsync();
|
await using var connection = await CS2_SimpleAdmin.DatabaseProvider.CreateConnectionAsync();
|
||||||
IEnumerable<BanRecord> updatedBans;
|
IEnumerable<BanRecord> updatedBans;
|
||||||
|
|
||||||
|
// Get current time from database in local timezone (CURRENT_TIMESTAMP uses session timezone, not UTC)
|
||||||
|
var currentDatabaseTime = await connection.QueryFirstAsync<DateTime>("SELECT CURRENT_TIMESTAMP");
|
||||||
|
|
||||||
// Optimization: Only get IDs for comparison if we need to check for deletions
|
// Optimization: Only get IDs for comparison if we need to check for deletions
|
||||||
// Most of the time bans are just added/updated, not deleted
|
// Most of the time bans are just added/updated, not deleted
|
||||||
HashSet<int>? allIds = null;
|
HashSet<int>? allIds = null;
|
||||||
|
|
||||||
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||||
{
|
{
|
||||||
updatedBans = (await connection.QueryAsync<BanRecord>(
|
// Use previous database time or start from far past if first run
|
||||||
|
var lastCheckTime = _lastDatabaseTime ?? DateTime.MinValue;
|
||||||
|
|
||||||
|
// Get recently updated bans by timestamp (using database time to avoid timezone issues)
|
||||||
|
var updatedBans_Query = (await connection.QueryAsync<BanRecord>(
|
||||||
"""
|
"""
|
||||||
SELECT id AS Id,
|
SELECT id AS Id,
|
||||||
player_name AS PlayerName,
|
player_name AS PlayerName,
|
||||||
@@ -171,33 +180,68 @@ internal class CacheManager: IDisposable
|
|||||||
status AS Status
|
status AS Status
|
||||||
FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC
|
FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC
|
||||||
""",
|
""",
|
||||||
new { lastUpdate = _lastUpdateTime }
|
new { lastUpdate = lastCheckTime }
|
||||||
));
|
)).ToList();
|
||||||
|
|
||||||
|
// Detect changes: new bans or status changes
|
||||||
|
var updatedList = new List<BanRecord>();
|
||||||
|
foreach (var ban in updatedBans_Query)
|
||||||
|
{
|
||||||
|
if (!_banCache.TryGetValue(ban.Id, out var cachedBan))
|
||||||
|
{
|
||||||
|
// New ban
|
||||||
|
updatedList.Add(ban);
|
||||||
|
}
|
||||||
|
else if (cachedBan.Status != ban.Status)
|
||||||
|
{
|
||||||
|
// Status changed
|
||||||
|
updatedList.Add(ban);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Optimization: Only fetch all IDs if there were updates
|
|
||||||
var updatedList = updatedBans.ToList();
|
|
||||||
if (updatedList.Count > 0)
|
if (updatedList.Count > 0)
|
||||||
{
|
{
|
||||||
allIds = (await connection.QueryAsync<int>("SELECT id FROM sa_bans")).ToHashSet();
|
allIds = (await connection.QueryAsync<int>("SELECT id FROM sa_bans")).ToHashSet();
|
||||||
}
|
}
|
||||||
updatedBans = updatedList;
|
updatedBans = updatedList;
|
||||||
|
|
||||||
|
// Update last check time to current database time
|
||||||
|
_lastDatabaseTime = currentDatabaseTime;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
updatedBans = (await connection.QueryAsync<BanRecord>(
|
// Use previous database time or start from far past if first run
|
||||||
|
var lastCheckTime = _lastDatabaseTime ?? DateTime.MinValue;
|
||||||
|
|
||||||
|
// Get recently updated bans for this server by timestamp (using database time to avoid timezone issues)
|
||||||
|
var updatedBans_Query = (await connection.QueryAsync<BanRecord>(
|
||||||
"""
|
"""
|
||||||
SELECT id AS Id,
|
SELECT id AS Id,
|
||||||
player_name AS PlayerName,
|
player_name AS PlayerName,
|
||||||
player_steamid AS PlayerSteamId,
|
player_steamid AS PlayerSteamId,
|
||||||
player_ip AS PlayerIp,
|
player_ip AS PlayerIp,
|
||||||
status AS Status
|
status AS Status
|
||||||
FROM `sa_bans` WHERE (updated_at > @lastUpdate OR created > @lastUpdate) AND server_id = @serverId ORDER BY updated_at DESC
|
FROM `sa_bans` WHERE server_id = @serverId AND (updated_at > @lastUpdate OR created > @lastUpdate) ORDER BY updated_at DESC
|
||||||
""",
|
""",
|
||||||
new { lastUpdate = _lastUpdateTime, serverId = CS2_SimpleAdmin.ServerId }
|
new { serverId = CS2_SimpleAdmin.ServerId, lastUpdate = lastCheckTime }
|
||||||
));
|
)).ToList();
|
||||||
|
|
||||||
|
// Detect changes: new bans or status changes
|
||||||
|
var updatedList = new List<BanRecord>();
|
||||||
|
foreach (var ban in updatedBans_Query)
|
||||||
|
{
|
||||||
|
if (!_banCache.TryGetValue(ban.Id, out var cachedBan))
|
||||||
|
{
|
||||||
|
// New ban
|
||||||
|
updatedList.Add(ban);
|
||||||
|
}
|
||||||
|
else if (cachedBan.Status != ban.Status)
|
||||||
|
{
|
||||||
|
// Status changed
|
||||||
|
updatedList.Add(ban);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Optimization: Only fetch all IDs if there were updates
|
|
||||||
var updatedList = updatedBans.ToList();
|
|
||||||
if (updatedList.Count > 0)
|
if (updatedList.Count > 0)
|
||||||
{
|
{
|
||||||
allIds = (await connection.QueryAsync<int>(
|
allIds = (await connection.QueryAsync<int>(
|
||||||
@@ -206,6 +250,9 @@ internal class CacheManager: IDisposable
|
|||||||
)).ToHashSet();
|
)).ToHashSet();
|
||||||
}
|
}
|
||||||
updatedBans = updatedList;
|
updatedBans = updatedList;
|
||||||
|
|
||||||
|
// Update last check time to current database time
|
||||||
|
_lastDatabaseTime = currentDatabaseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimization: Only process deletions if we have the full ID list
|
// Optimization: Only process deletions if we have the full ID list
|
||||||
@@ -276,16 +323,13 @@ internal class CacheManager: IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update cache with new/modified bans
|
// Update cache with new/modified bans
|
||||||
var hasUpdates = false;
|
|
||||||
foreach (var ban in updatedBans)
|
foreach (var ban in updatedBans)
|
||||||
{
|
{
|
||||||
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
||||||
hasUpdates = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always rebuild indexes if there were any updates
|
// Rebuild indexes if there were updates
|
||||||
// This ensures status changes (ACTIVE -> UNBANNED) are reflected
|
if (updatedBans.Any())
|
||||||
if (hasUpdates)
|
|
||||||
{
|
{
|
||||||
RebuildIndexes();
|
RebuildIndexes();
|
||||||
}
|
}
|
||||||
@@ -446,7 +490,7 @@ internal class CacheManager: IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0)
|
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0 || string.IsNullOrEmpty(ipAddress))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ipAddress) ||
|
if (string.IsNullOrEmpty(ipAddress) ||
|
||||||
@@ -547,14 +591,14 @@ internal class CacheManager: IDisposable
|
|||||||
var activeBan = steamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
|
var activeBan = steamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
|
||||||
if (activeBan != null)
|
if (activeBan != null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(activeBan.PlayerName) || string.IsNullOrEmpty(activeBan.PlayerIp))
|
if (string.IsNullOrEmpty(activeBan.PlayerName) || string.IsNullOrEmpty(activeBan.PlayerIp) && !string.IsNullOrEmpty(ipAddress))
|
||||||
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0)
|
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0 || string.IsNullOrEmpty(ipAddress))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_playerIpsCache.TryGetValue(steamId, out var ipData))
|
if (!_playerIpsCache.TryGetValue(steamId, out var ipData))
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace CS2_SimpleAdmin.Managers;
|
|||||||
|
|
||||||
internal class PlayerManager
|
internal class PlayerManager
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _loadPlayerSemaphore = new(5);
|
private readonly SemaphoreSlim _loadPlayerSemaphore = new(10);
|
||||||
private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config;
|
private readonly CS2_SimpleAdminConfig _config = CS2_SimpleAdmin.Instance.Config;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -51,7 +51,6 @@ internal class PlayerManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _loadPlayerSemaphore.WaitAsync();
|
await _loadPlayerSemaphore.WaitAsync();
|
||||||
|
|
||||||
if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(steamId))
|
if (!CS2_SimpleAdmin.PlayersInfo.ContainsKey(steamId))
|
||||||
{
|
{
|
||||||
var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
var isBanned = CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
||||||
@@ -287,9 +286,6 @@ internal class PlayerManager
|
|||||||
|
|
||||||
// Optimization: Get players once and avoid allocating anonymous types
|
// Optimization: Get players once and avoid allocating anonymous types
|
||||||
var validPlayers = Helper.GetValidPlayers();
|
var validPlayers = Helper.GetValidPlayers();
|
||||||
if (validPlayers.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Use ValueTuple instead of anonymous type - better performance and less allocations
|
// Use ValueTuple instead of anonymous type - better performance and less allocations
|
||||||
var tempPlayers = new List<(string PlayerName, ulong SteamID, string? IpAddress, int? UserId, int Slot)>(validPlayers.Count);
|
var tempPlayers = new List<(string PlayerName, ulong SteamID, string? IpAddress, int? UserId, int Slot)>(validPlayers.Count);
|
||||||
foreach (var p in validPlayers)
|
foreach (var p in validPlayers)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.7.8-beta-5
|
1.7.8-beta-6
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.340" />
|
<PackageReference Include="CounterStrikeSharp.API" Version="1.0.346" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user