zio fork 1.8.2b-zio11: reloading admins removes deleted and demoted admins
CSS's admin loaders only add, and the per-admin cleanup in CreateAdminsJsonFile reset AdminCache once per admin, so it only ever tracked the last one and a reload never took anyone else out of memory. ReloadAdmins now removes every admin it loaded last time and loads the new set in one tick. admins.json is keyed by SteamID instead of name, so admins sharing a name aren't merged, and a failed admins query keeps the loaded admins instead of removing them.
This commit is contained in:
parent
f46ccf18ce
commit
d042aab1c0
3 changed files with 63 additions and 103 deletions
|
|
@ -17,8 +17,8 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
|||
/// <summary>
|
||||
/// Retrieves all players' flags and associated data asynchronously.
|
||||
/// </summary>
|
||||
/// <returns>A list of tuples containing player SteamID, name, flags, immunity, and expiration time.</returns>
|
||||
private async Task<List<(ulong, string ,List<string>, int, DateTime?)>> GetAllPlayersFlags()
|
||||
/// <returns>A list of tuples containing player SteamID, name, flags, immunity, and expiration time, or null if the database query failed.</returns>
|
||||
private async Task<List<(ulong, string ,List<string>, int, DateTime?)>?> GetAllPlayersFlags()
|
||||
{
|
||||
if (databaseProvider == null)
|
||||
return new List<(ulong, string, List<string>, int, DateTime?)>();
|
||||
|
|
@ -68,7 +68,8 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
|||
catch (Exception ex)
|
||||
{
|
||||
CS2_SimpleAdmin._logger?.LogError("Unable to load admins from database! {exception}", ex.Message);
|
||||
return [];
|
||||
// zio: null rather than empty, so ReloadAdmins keeps the loaded admins instead of removing them all.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,96 +151,50 @@ public class PermissionManager(IDatabaseProvider? databaseProvider)
|
|||
/// <summary>
|
||||
/// Creates a JSON file containing admins data asynchronously.
|
||||
/// </summary>
|
||||
/// <returns>zio: every admin row loaded, for ReloadAdmins to rebuild AdminCache from, or null if the database query failed (the file is then left alone).</returns>
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||
public async Task CreateAdminsJsonFile()
|
||||
public async Task<List<(SteamID SteamId, DateTime? Ends, List<string> Flags)>?> CreateAdminsJsonFile()
|
||||
{
|
||||
List<(ulong identity, string name, List<string> flags, int immunity, DateTime? ends)> allPlayers = await GetAllPlayersFlags();
|
||||
var allPlayers = await GetAllPlayersFlags();
|
||||
if (allPlayers == null) return null;
|
||||
|
||||
var validPlayers = allPlayers
|
||||
.Where(player => SteamID.TryParse(player.identity.ToString(), out _))
|
||||
.Select(player => (player, steamId: SteamID.TryParse(player.Item1.ToString(), out var steamId) ? steamId : null))
|
||||
.Where(p => p.steamId != null)
|
||||
.ToList();
|
||||
|
||||
var jsonData = validPlayers
|
||||
.GroupBy(player => player.name)
|
||||
.ToDictionary(
|
||||
group => group.Key,
|
||||
object (group) =>
|
||||
{
|
||||
var consolidatedData = group.Aggregate(
|
||||
new
|
||||
{
|
||||
identity = string.Empty,
|
||||
immunity = 0,
|
||||
flags = new List<string>(),
|
||||
groups = new List<string>()
|
||||
},
|
||||
(acc, player) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(acc.identity) && !string.IsNullOrEmpty(player.identity.ToString()))
|
||||
{
|
||||
acc = acc with { identity = player.identity.ToString() };
|
||||
}
|
||||
// zio: keyed by SteamID, not name: CSS ignores the key, and two admins with the same name were
|
||||
// merged into one entry under the first one's SteamID. Upstream also cleared and refilled
|
||||
// AdminCache here once per admin, so it only ever kept the last admin and a reload never
|
||||
// removed anyone else; ReloadAdmins now does that once, from the list returned here.
|
||||
var jsonData = validPlayers
|
||||
.GroupBy(p => p.steamId!.SteamId64)
|
||||
.ToDictionary(
|
||||
group => group.Key.ToString(),
|
||||
object (group) =>
|
||||
{
|
||||
var rows = group.Select(p => p.player).ToList();
|
||||
var flags = rows.SelectMany(r => r.Item3).Distinct().ToList();
|
||||
return new
|
||||
{
|
||||
identity = group.Key.ToString(),
|
||||
immunity = rows.Max(r => r.Item4),
|
||||
flags = flags.Where(flag => flag.StartsWith($"@")).ToList(),
|
||||
groups = flags.Where(flag => flag.StartsWith($"#")).ToList()
|
||||
};
|
||||
});
|
||||
|
||||
acc = acc with { immunity = Math.Max(acc.immunity, player.immunity) };
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
acc = acc with
|
||||
{
|
||||
flags = acc.flags.Concat(player.flags.Where(flag => flag.StartsWith($"@"))).Distinct().ToList(),
|
||||
groups = acc.groups.Concat(player.flags.Where(flag => flag.StartsWith($"#"))).Distinct().ToList()
|
||||
};
|
||||
|
||||
return acc;
|
||||
});
|
||||
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
var keysToRemove = new List<SteamID>();
|
||||
|
||||
foreach (var steamId in AdminCache.Keys.ToList())
|
||||
{
|
||||
var data = AdminManager.GetPlayerAdminData(steamId);
|
||||
if (data != null)
|
||||
{
|
||||
var flagsArray = AdminCache[steamId].Flags.ToArray();
|
||||
AdminManager.RemovePlayerPermissions(steamId, flagsArray);
|
||||
AdminManager.RemovePlayerFromGroup(steamId, true, flagsArray);
|
||||
}
|
||||
|
||||
keysToRemove.Add(steamId);
|
||||
}
|
||||
|
||||
foreach (var steamId in keysToRemove)
|
||||
{
|
||||
if (!AdminCache.TryRemove(steamId, out _)) continue;
|
||||
|
||||
var data = AdminManager.GetPlayerAdminData(steamId);
|
||||
if (data == null) continue;
|
||||
if (data.Flags.Count != 0 && data.Groups.Count != 0) continue;
|
||||
|
||||
AdminManager.ClearPlayerPermissions(steamId);
|
||||
AdminManager.RemovePlayerAdminData(steamId);
|
||||
}
|
||||
|
||||
foreach (var player in group)
|
||||
{
|
||||
if (SteamID.TryParse(player.identity.ToString(), out var steamId) && steamId != null)
|
||||
{
|
||||
AdminCache.TryAdd(steamId, (player.ends, player.flags));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return consolidatedData;
|
||||
});
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(jsonData, options);
|
||||
var json = JsonSerializer.Serialize(jsonData, options);
|
||||
var filePath = Path.Combine(CS2_SimpleAdmin.Instance.ModuleDirectory, "data", "admins.json");
|
||||
await File.WriteAllTextAsync(filePath, json);
|
||||
|
||||
return validPlayers.Select(p => (p.steamId!, p.player.Item5, p.player.Item3)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue