mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-05-19 21:51:56 +00:00
1.7.7-alpha
- Fixed steamid only bans - Added missing multiservermode - Better caching
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
UPDATE `sa_players_ips` SET `address` = INET_ATON(address);
|
UPDATE `sa_players_ips` SET `address` = INET_ATON(address);
|
||||||
ALTER TABLE `sa_players_ips` CHANGE `address` `address` INT UNSIGNED NOT NULL;
|
ALTER TABLE `sa_players_ips` CHANGE `address` `address` INT UNSIGNED NOT NULL;
|
||||||
ALTER TABLE `sa_players_ips` ADD `name` VARCHAR(64) NULL DEFAULT NULL AFTER `steamid`;
|
ALTER TABLE `sa_players_ips` ADD `name` VARCHAR(64) NULL DEFAULT NULL AFTER `steamid`;
|
||||||
|
ALTER TABLE `sa_players_ips` ADD INDEX(`used_at`);
|
||||||
|
|||||||
@@ -137,7 +137,10 @@ public partial class CS2_SimpleAdmin
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.LogCritical("[OnClientConnect]");
|
Logger.LogCritical("[OnClientConnect]");
|
||||||
#endif
|
#endif
|
||||||
if (Config.OtherSettings.BanType == 1 && Instance.CacheManager != null && !Instance.CacheManager.IsPlayerBanned(null, ipaddress.Split(":")[0]))
|
if (Config.OtherSettings.BanType == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Instance.CacheManager != null && !Instance.CacheManager.IsPlayerBanned(null, ipaddress.Split(":")[0]))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Server.NextFrame((() =>
|
Server.NextFrame((() =>
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ namespace CS2_SimpleAdmin.Managers;
|
|||||||
internal class CacheManager: IDisposable
|
internal class CacheManager: IDisposable
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<int, BanRecord> _banCache = [];
|
private readonly ConcurrentDictionary<int, BanRecord> _banCache = [];
|
||||||
|
private readonly ConcurrentDictionary<string, List<BanRecord>> _steamIdIndex = [];
|
||||||
|
private readonly ConcurrentDictionary<uint, List<BanRecord>> _ipIndex = [];
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<ulong, HashSet<IpRecord>> _playerIpsCache = [];
|
private readonly ConcurrentDictionary<ulong, HashSet<IpRecord>> _playerIpsCache = [];
|
||||||
private HashSet<uint> _cachedIgnoredIps = [];
|
private HashSet<uint> _cachedIgnoredIps = [];
|
||||||
|
|
||||||
@@ -29,24 +32,34 @@ internal class CacheManager: IDisposable
|
|||||||
.Select(IpHelper.IpToUint));
|
.Select(IpHelper.IpToUint));
|
||||||
|
|
||||||
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
||||||
var bans = await connection.QueryAsync<BanRecord>(
|
List<BanRecord> bans;
|
||||||
"""
|
|
||||||
SELECT
|
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||||
|
{
|
||||||
|
bans = (await connection.QueryAsync<BanRecord>(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
id AS Id,
|
id AS Id,
|
||||||
player_name AS PlayerName,
|
|
||||||
player_steamid AS PlayerSteamId,
|
player_steamid AS PlayerSteamId,
|
||||||
player_ip AS PlayerIp,
|
player_ip AS PlayerIp,
|
||||||
admin_steamid AS AdminSteamId,
|
status AS Status
|
||||||
admin_name AS AdminName,
|
FROM sa_bans
|
||||||
reason AS Reason,
|
""")).ToList();
|
||||||
duration AS Duration,
|
}
|
||||||
ends AS Ends,
|
else
|
||||||
created AS Created,
|
{
|
||||||
server_id AS ServerId,
|
bans = (await connection.QueryAsync<BanRecord>(
|
||||||
status AS Status,
|
"""
|
||||||
updated_at AS UpdatedAt
|
SELECT
|
||||||
FROM sa_bans
|
id AS Id,
|
||||||
""");
|
player_steamid AS PlayerSteamId,
|
||||||
|
player_ip AS PlayerIp,
|
||||||
|
status AS Status
|
||||||
|
FROM sa_bans
|
||||||
|
WHERE server_id = @serverId
|
||||||
|
""", new {serverId = CS2_SimpleAdmin.ServerId})).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
var ipHistory =
|
var ipHistory =
|
||||||
await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>(
|
await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>(
|
||||||
"SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC");
|
"SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC");
|
||||||
@@ -90,6 +103,8 @@ internal class CacheManager: IDisposable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RebuildIndexes();
|
||||||
|
|
||||||
_lastUpdateTime = DateTime.Now.AddSeconds(-1);
|
_lastUpdateTime = DateTime.Now.AddSeconds(-1);
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
}
|
}
|
||||||
@@ -119,10 +134,61 @@ internal class CacheManager: IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
await using var connection = await CS2_SimpleAdmin.Database.GetConnectionAsync();
|
||||||
var updatedBans = (await connection.QueryAsync<BanRecord>(
|
List<BanRecord> updatedBans;
|
||||||
"SELECT * FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC",
|
|
||||||
new { lastUpdate = _lastUpdateTime }
|
var allIds = (await connection.QueryAsync<int>("SELECT id FROM sa_bans")).ToHashSet();
|
||||||
)).ToList();
|
|
||||||
|
if (CS2_SimpleAdmin.Instance.Config.MultiServerMode)
|
||||||
|
{
|
||||||
|
updatedBans = (await connection.QueryAsync<BanRecord>(
|
||||||
|
"""
|
||||||
|
SELECT id AS Id,
|
||||||
|
player_steamid AS PlayerSteamId,
|
||||||
|
player_ip AS PlayerIp,
|
||||||
|
status AS Status
|
||||||
|
FROM `sa_bans` WHERE updated_at > @lastUpdate OR created > @lastUpdate ORDER BY updated_at DESC
|
||||||
|
""",
|
||||||
|
new { lastUpdate = _lastUpdateTime }
|
||||||
|
)).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updatedBans = (await connection.QueryAsync<BanRecord>(
|
||||||
|
"""
|
||||||
|
SELECT id AS Id,
|
||||||
|
player_steamid AS PlayerSteamId,
|
||||||
|
player_ip AS PlayerIp,
|
||||||
|
status AS Status
|
||||||
|
FROM `sa_bans` WHERE (updated_at > @lastUpdate OR created > @lastUpdate) AND server_id = @serverId ORDER BY updated_at DESC
|
||||||
|
""",
|
||||||
|
new { lastUpdate = _lastUpdateTime, serverId = CS2_SimpleAdmin.ServerId }
|
||||||
|
)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var id in _banCache.Keys)
|
||||||
|
{
|
||||||
|
if (allIds.Contains(id) || !_banCache.TryRemove(id, out var ban)) continue;
|
||||||
|
|
||||||
|
// Remove from steamIdIndex
|
||||||
|
if (!string.IsNullOrWhiteSpace(ban.PlayerSteamId) &&
|
||||||
|
_steamIdIndex.TryGetValue(ban.PlayerSteamId, out var steamBans))
|
||||||
|
{
|
||||||
|
steamBans.RemoveAll(b => b.Id == id);
|
||||||
|
if (steamBans.Count == 0)
|
||||||
|
_steamIdIndex.TryRemove(ban.PlayerSteamId, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from ipIndex
|
||||||
|
if (!string.IsNullOrWhiteSpace(ban.PlayerIp) &&
|
||||||
|
IpHelper.TryConvertIpToUint(ban.PlayerIp, out var ipUInt) &&
|
||||||
|
_ipIndex.TryGetValue(ipUInt, out var ipBans))
|
||||||
|
{
|
||||||
|
ipBans.RemoveAll(b => b.Id == id);
|
||||||
|
if (ipBans.Count == 0)
|
||||||
|
_ipIndex.TryRemove(ipUInt, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ipHistory = (await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>(
|
var ipHistory = (await connection.QueryAsync<(ulong steamid, string? name, uint address, DateTime used_at)>(
|
||||||
"SELECT steamid, name, address, used_at FROM sa_players_ips WHERE used_at >= @lastUpdate ORDER BY used_at DESC LIMIT 300", new {lastUpdate = _lastUpdateTime})).ToList();
|
"SELECT steamid, name, address, used_at FROM sa_players_ips WHERE used_at >= @lastUpdate ORDER BY used_at DESC LIMIT 300", new {lastUpdate = _lastUpdateTime})).ToList();
|
||||||
|
|
||||||
@@ -167,6 +233,7 @@ internal class CacheManager: IDisposable
|
|||||||
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
_banCache.AddOrUpdate(ban.Id, ban, (_, _) => ban);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RebuildIndexes();
|
||||||
_lastUpdateTime = DateTime.Now.AddSeconds(-1);
|
_lastUpdateTime = DateTime.Now.AddSeconds(-1);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -175,9 +242,47 @@ internal class CacheManager: IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RebuildIndexes()
|
||||||
|
{
|
||||||
|
_steamIdIndex.Clear();
|
||||||
|
_ipIndex.Clear();
|
||||||
|
|
||||||
|
foreach (var ban in _banCache.Values)
|
||||||
|
{
|
||||||
|
if (ban.Status != "ACTIVE")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(ban.PlayerSteamId))
|
||||||
|
{
|
||||||
|
var steamId = ban.PlayerSteamId;
|
||||||
|
_steamIdIndex.AddOrUpdate(
|
||||||
|
steamId,
|
||||||
|
key => [ban],
|
||||||
|
(key, list) =>
|
||||||
|
{
|
||||||
|
list.Add(ban);
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ban.PlayerIp != null &&
|
||||||
|
IpHelper.TryConvertIpToUint(ban.PlayerIp, out var ipUInt))
|
||||||
|
{
|
||||||
|
_ipIndex.AddOrUpdate(
|
||||||
|
ipUInt,
|
||||||
|
key => [ban],
|
||||||
|
(key, list) =>
|
||||||
|
{
|
||||||
|
list.Add(ban);
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<BanRecord> GetAllBans() => _banCache.Values.ToList();
|
public List<BanRecord> GetAllBans() => _banCache.Values.ToList();
|
||||||
public List<BanRecord> GetActiveBans() => _banCache.Values.Where(b => b.Status == "ACTIVE").ToList();
|
public List<BanRecord> GetActiveBans() => _banCache.Values.Where(b => b.Status == "ACTIVE").ToList();
|
||||||
public List<BanRecord> GetPlayerBansBySteamId(string steamId) => _banCache.Values.Where(b => b.PlayerSteamId == steamId).ToList();
|
public List<BanRecord> GetPlayerBansBySteamId(string steamId) => _steamIdIndex.TryGetValue(steamId, out var bans) ? bans : [];
|
||||||
public List<(ulong SteamId, DateTime UsedAt, string PlayerName)> GetAccountsByIp(string ipAddress)
|
public List<(ulong SteamId, DateTime UsedAt, string PlayerName)> GetAccountsByIp(string ipAddress)
|
||||||
{
|
{
|
||||||
var ipAsUint = IpHelper.IpToUint(ipAddress);
|
var ipAsUint = IpHelper.IpToUint(ipAddress);
|
||||||
@@ -191,49 +296,37 @@ internal class CacheManager: IDisposable
|
|||||||
|
|
||||||
private bool IsIpBanned(string ipAddress)
|
private bool IsIpBanned(string ipAddress)
|
||||||
{
|
{
|
||||||
|
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0) return false;
|
||||||
var ipUInt = IpHelper.IpToUint(ipAddress);
|
var ipUInt = IpHelper.IpToUint(ipAddress);
|
||||||
|
return !_cachedIgnoredIps.Contains(ipUInt) && _ipIndex.ContainsKey(ipUInt);
|
||||||
return _banCache.Values.Any(b =>
|
|
||||||
b is { Status: "ACTIVE", PlayerIp: not null } &&
|
|
||||||
IpHelper.IpToUint(b.PlayerIp) == ipUInt &&
|
|
||||||
!_cachedIgnoredIps.Contains(ipUInt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool IsPlayerBanned(string? steamId, string? ipAddress)
|
public bool IsPlayerBanned(string? steamId, string? ipAddress)
|
||||||
{
|
{
|
||||||
|
if (steamId != null && _steamIdIndex.ContainsKey(steamId))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0) return false;
|
||||||
|
|
||||||
if (ipAddress == null)
|
if (ipAddress == null)
|
||||||
return _banCache.Values.Any(b =>
|
return false;
|
||||||
b.Status == "ACTIVE" &&
|
|
||||||
steamId != null &&
|
|
||||||
b.PlayerSteamId != null &&
|
|
||||||
b.PlayerSteamId.Equals(steamId, StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
if (!IpHelper.TryConvertIpToUint(ipAddress, out var ipUInt))
|
if (!IpHelper.TryConvertIpToUint(ipAddress, out var ipUInt))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return _banCache.Values.Any(b =>
|
return !_cachedIgnoredIps.Contains(ipUInt) &&
|
||||||
b is { Status: "ACTIVE", PlayerIp: not null } &&
|
_ipIndex.ContainsKey(ipUInt);
|
||||||
(
|
|
||||||
(steamId != null &&
|
|
||||||
b.PlayerSteamId != null &&
|
|
||||||
b.PlayerSteamId.Equals(steamId, StringComparison.OrdinalIgnoreCase))
|
|
||||||
||
|
|
||||||
(IpHelper.TryConvertIpToUint(b.PlayerIp, out var bIpUint) &&
|
|
||||||
bIpUint == ipUInt &&
|
|
||||||
!_cachedIgnoredIps.Contains(ipUInt))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsPlayerOrAnyIpBanned(ulong steamId, string? ipAddress)
|
public bool IsPlayerOrAnyIpBanned(ulong steamId, string? ipAddress)
|
||||||
{
|
{
|
||||||
var steamIdStr = steamId.ToString();
|
var steamIdStr = steamId.ToString();
|
||||||
if (_banCache.Values.Any(b =>
|
|
||||||
b.Status == "ACTIVE" &&
|
if (_steamIdIndex.ContainsKey(steamIdStr))
|
||||||
b.PlayerSteamId?.Equals(steamIdStr, StringComparison.OrdinalIgnoreCase) == true))
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
if (CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType == 0) return false;
|
||||||
|
|
||||||
if (!_playerIpsCache.TryGetValue(steamId, out var ipData))
|
if (!_playerIpsCache.TryGetValue(steamId, out var ipData))
|
||||||
return false;
|
return false;
|
||||||
@@ -245,21 +338,26 @@ internal class CacheManager: IDisposable
|
|||||||
{
|
{
|
||||||
var ipAsUint = IpHelper.IpToUint(ipAddress);
|
var ipAsUint = IpHelper.IpToUint(ipAddress);
|
||||||
|
|
||||||
ipData.Add(new IpRecord(
|
if (!_cachedIgnoredIps.Contains(ipAsUint))
|
||||||
ipAsUint,
|
{
|
||||||
now.AddSeconds(-2),
|
ipData.Add(new IpRecord(
|
||||||
CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown"
|
ipAsUint,
|
||||||
));
|
now.AddSeconds(-2), // artificially recent
|
||||||
|
CS2_SimpleAdmin._localizer?["sa_unknown"] ?? "Unknown"
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ipData.Any(x =>
|
foreach (var ipRecord in ipData)
|
||||||
x.UsedAt >= cutoff &&
|
{
|
||||||
!_cachedIgnoredIps.Contains(x.Ip) &&
|
if (ipRecord.UsedAt < cutoff || _cachedIgnoredIps.Contains(ipRecord.Ip))
|
||||||
_banCache.Values.Any(b =>
|
continue;
|
||||||
b is { Status: "ACTIVE", PlayerIp: not null } &&
|
|
||||||
IpHelper.TryConvertIpToUint(b.PlayerIp, out var banIpUint) &&
|
if (_ipIndex.ContainsKey(ipRecord.Ip))
|
||||||
banIpUint == x.Ip
|
return true;
|
||||||
));
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasIpForPlayer(ulong steamId, string ipAddress)
|
public bool HasIpForPlayer(ulong steamId, string ipAddress)
|
||||||
@@ -273,6 +371,9 @@ internal class CacheManager: IDisposable
|
|||||||
|
|
||||||
private void Clear()
|
private void Clear()
|
||||||
{
|
{
|
||||||
|
_steamIdIndex.Clear();
|
||||||
|
_ipIndex.Clear();
|
||||||
|
|
||||||
_banCache.Clear();
|
_banCache.Clear();
|
||||||
_playerIpsCache.Clear();
|
_playerIpsCache.Clear();
|
||||||
_cachedIgnoredIps.Clear();
|
_cachedIgnoredIps.Clear();
|
||||||
|
|||||||
@@ -313,9 +313,8 @@ public class PlayerManager
|
|||||||
return CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
return CS2_SimpleAdmin.Instance.CacheManager != null && CS2_SimpleAdmin.Instance.Config.OtherSettings.BanType switch
|
||||||
{
|
{
|
||||||
0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), null),
|
0 => CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), null),
|
||||||
_ => CS2_SimpleAdmin.Instance.Config.OtherSettings.CheckMultiAccountsByIp
|
_ =>
|
||||||
? CS2_SimpleAdmin.Instance.CacheManager.IsPlayerOrAnyIpBanned(player.SteamID, player.IpAddress?.Split(":")[0])
|
CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), player.IpAddress?.Split(":")[0])
|
||||||
: CS2_SimpleAdmin.Instance.CacheManager.IsPlayerBanned(player.SteamID.ToString(), player.IpAddress?.Split(":")[0])
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|||||||
@@ -2,44 +2,17 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
|
|
||||||
namespace CS2_SimpleAdmin.Models;
|
namespace CS2_SimpleAdmin.Models;
|
||||||
|
|
||||||
public record struct BanRecord
|
public record BanRecord
|
||||||
{
|
{
|
||||||
[Column("id")]
|
[Column("id")]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
[Column("player_name")]
|
|
||||||
public string PlayerName { get; set; }
|
|
||||||
|
|
||||||
[Column("player_steamid")]
|
[Column("player_steamid")]
|
||||||
public string? PlayerSteamId { get; set; }
|
public string? PlayerSteamId { get; set; }
|
||||||
|
|
||||||
[Column("player_ip")]
|
[Column("player_ip")]
|
||||||
public string? PlayerIp { get; set; }
|
public string? PlayerIp { get; set; }
|
||||||
|
|
||||||
[Column("admin_steamid")]
|
|
||||||
public string AdminSteamId { get; set; }
|
|
||||||
|
|
||||||
[Column("admin_name")]
|
|
||||||
public string AdminName { get; set; }
|
|
||||||
|
|
||||||
[Column("reason")]
|
|
||||||
public string Reason { get; set; }
|
|
||||||
|
|
||||||
[Column("duration")]
|
|
||||||
public int Duration { get; set; }
|
|
||||||
|
|
||||||
[Column("ends")]
|
|
||||||
public DateTime? Ends { get; set; }
|
|
||||||
|
|
||||||
[Column("created")]
|
|
||||||
public DateTime Created { get; set; }
|
|
||||||
|
|
||||||
[Column("server_id")]
|
|
||||||
public int? ServerId { get; set; }
|
|
||||||
|
|
||||||
[Column("status")]
|
[Column("status")]
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
|
|
||||||
[Column("updated_at")]
|
|
||||||
public DateTime UpdatedAt { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user