zio fork 1.8.2b-zio3: ban reasons on join, @css/bypassipban, spectators keep hidden
Some checks failed
Build and Publish / build (push) Has been cancelled
Build and Publish / publish (push) Has been cancelled

Banned players are let in long enough to be told the ban's reason and time left, then kicked
after KickTime, instead of only seeing "Your client is not allowed to join this server"; they
can't chat, talk or join a team meanwhile. New permission @css/bypassipban (players or groups,
implied by @css/root) skips IP and shared-IP bans, leaving only bans on their own SteamID, on
join and in the periodic check. Moving to spectators no longer unhides a hidden admin; only
joining T or CT does.
This commit is contained in:
Astra 2026-09-28 11:23:11 +01:00
parent 6171162ae9
commit 2069c1a690
8 changed files with 142 additions and 25 deletions

View file

@ -478,8 +478,12 @@ internal class CacheManager: IDisposable
/// <param name="steamId">Optional 64-bit Steam ID of the player.</param>
/// <param name="ipAddress">Optional IP address of the player.</param>
/// <returns>True if the player is banned, otherwise false.</returns>
public bool IsPlayerBanned(string playerName, ulong? steamId, string? ipAddress)
public bool IsPlayerBanned(string playerName, ulong? steamId, string? ipAddress) => IsPlayerBanned(playerName, steamId, ipAddress, out _);
// zio: also returns the ban that matched, so the player can be told why.
public bool IsPlayerBanned(string playerName, ulong? steamId, string? ipAddress, out BanRecord? ban)
{
ban = null;
BanRecord? record;
if (steamId.HasValue && _steamIdIndex.TryGetValue(steamId.Value, out var steamRecords))
{
@ -495,6 +499,7 @@ internal class CacheManager: IDisposable
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
}
ban = record;
return true;
}
}
@ -521,6 +526,7 @@ internal class CacheManager: IDisposable
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
}
ban = record;
return true;
}
@ -599,8 +605,12 @@ internal class CacheManager: IDisposable
/// <param name="steamId">64-bit Steam ID of the player.</param>
/// <param name="ipAddress">Current IP address of the player (optional).</param>
/// <returns>True if the player or their known IPs are banned, otherwise false.</returns>
public bool IsPlayerOrAnyIpBanned(string playerName, ulong steamId, string? ipAddress)
public bool IsPlayerOrAnyIpBanned(string playerName, ulong steamId, string? ipAddress) => IsPlayerOrAnyIpBanned(playerName, steamId, ipAddress, out _);
// zio: also returns the ban that matched, so the player can be told why.
public bool IsPlayerOrAnyIpBanned(string playerName, ulong steamId, string? ipAddress, out BanRecord? ban)
{
ban = null;
if (_steamIdIndex.TryGetValue(steamId, out var steamBans))
{
var activeBan = steamBans.FirstOrDefault(b => b.StatusEnum == BanStatus.ACTIVE);
@ -612,6 +622,7 @@ internal class CacheManager: IDisposable
if (string.IsNullOrEmpty(activeBan.PlayerName) || string.IsNullOrEmpty(activeBan.PlayerIp) && !string.IsNullOrEmpty(ipAddress))
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
ban = activeBan;
return true;
}
}
@ -639,6 +650,7 @@ internal class CacheManager: IDisposable
ipBan.PlayerName = playerName;
ipBan.PlayerSteamId ??= steamId;
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
ban = ipBan;
return true;
}
}
@ -661,6 +673,7 @@ internal class CacheManager: IDisposable
if (activeBan == null || !_banCache.TryGetValue(activeBan.Id, out var cachedBan) ||
cachedBan.StatusEnum != BanStatus.ACTIVE) continue;
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
ban = activeBan;
return true;
}
}
@ -696,6 +709,7 @@ internal class CacheManager: IDisposable
continue;
_ = Task.Run(() => UpdatePlayerData(playerName, steamId, ipAddress));
ban = activeBan;
return true;
}
}