Antag Rolebans (#35966)

Co-authored-by: beck-thompson <beck314159@hotmail.com>
Co-authored-by: Hannah Giovanna Dawson <karakkaraz@gmail.com>
This commit is contained in:
Errant
2025-09-17 23:59:07 +02:00
committed by GitHub
parent e1ba33814b
commit b692b6e33e
33 changed files with 898 additions and 283 deletions

View File

@@ -1,6 +1,8 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
using Content.Server.EUI;
using Content.Server.GameTicking.Events;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Ghost.Roles.Events;
using Content.Shared.Ghost.Roles.Raffles;
@@ -32,13 +34,16 @@ using Content.Server.Popups;
using Content.Shared.Verbs;
using Robust.Shared.Collections;
using Content.Shared.Ghost.Roles.Components;
using Content.Shared.Roles.Components;
namespace Content.Server.Ghost.Roles;
[UsedImplicitly]
public sealed class GhostRoleSystem : EntitySystem
{
[Dependency] private readonly IBanManager _ban = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IEntityManager _ent = default!;
[Dependency] private readonly EuiManager _euiManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
@@ -459,6 +464,23 @@ public sealed class GhostRoleSystem : EntitySystem
if (!_ghostRoles.TryGetValue(identifier, out var roleEnt))
return;
TryPrototypes(roleEnt, out var antags, out var jobs);
// Check role bans
if (_ban.IsRoleBanned(player, antags) || _ban.IsRoleBanned(player, jobs))
{
Log.Warning($"Server rejected ghost role request '{roleEnt.Comp.RoleName}' for '{player.Name}' - client missed ban?");
return;
}
// Check role requirements
if (!IsRoleAllowed(player, jobs, antags))
{
Log.Warning($"Server rejected ghost role request '{roleEnt.Comp.RoleName}' for '{player.Name}' - client missed requirement check?");
return;
}
// Decide to do a raffle or not
if (roleEnt.Comp.RaffleConfig is not null)
{
JoinRaffle(player, identifier);
@@ -469,6 +491,78 @@ public sealed class GhostRoleSystem : EntitySystem
}
}
/// <summary>
/// Collect all role prototypes on the Ghostrole.
/// </summary>
/// <returns>
/// Returns true if at least on role prototype could be found.
/// </returns>
private bool TryPrototypes(
Entity<GhostRoleComponent> roleEnt,
out List<ProtoId<AntagPrototype>> antags,
out List<ProtoId<JobPrototype>> jobs)
{
antags = [];
jobs = [];
// If there is a mind already, check its mind roles.
// Not sure if this can ever actually happen.
if (TryComp<MindContainerComponent>(roleEnt, out var mindCont)
&& TryComp<MindComponent>(mindCont.Mind, out var mind))
{
foreach (var role in mind.MindRoleContainer.ContainedEntities)
{
if(!TryComp<MindRoleComponent>(role, out var comp))
continue;
if (comp.JobPrototype is not null)
jobs.Add(comp.JobPrototype.Value);
else if (comp.AntagPrototype is not null)
antags.Add(comp.AntagPrototype.Value);
}
return antags.Count > 0 || jobs.Count > 0;
}
if (roleEnt.Comp.JobProto is not null)
jobs.Add(roleEnt.Comp.JobProto.Value);
// If there is no mind, check the mindRole prototypes
foreach (var proto in roleEnt.Comp.MindRoles)
{
if (!_prototype.TryIndex(proto, out var indexed)
|| !indexed.TryGetComponent<MindRoleComponent>(out var comp, _ent.ComponentFactory))
continue;
var roleComp = (MindRoleComponent)comp;
if (roleComp.JobPrototype is not null)
jobs.Add(roleComp.JobPrototype.Value);
else if (roleComp.AntagPrototype is not null)
antags.Add(roleComp.AntagPrototype.Value);
else
Log.Debug($"Mind role '{proto}' of '{roleEnt.Comp.RoleName}' has neither a job or antag prototype specified");
}
return antags.Count > 0 || jobs.Count > 0;
}
/// <summary>
/// Checks if the player passes the requirements for the supplied roles.
/// Returns false if any role fails the check.
/// </summary>
private bool IsRoleAllowed(
ICommonSession player,
List<ProtoId<JobPrototype>>? jobIds,
List<ProtoId<AntagPrototype>>? antagIds)
{
var ev = new IsRoleAllowedEvent(player, jobIds, antagIds);
RaiseLocalEvent(ref ev);
return !ev.Cancelled;
}
/// <summary>
/// Attempts having the player take over the ghost role with the corresponding ID. Does not start a raffle.
/// </summary>
@@ -571,13 +665,15 @@ public sealed class GhostRoleSystem : EntitySystem
? _timing.CurTime.Add(raffle.Countdown)
: TimeSpan.MinValue;
TryPrototypes((uid, role), out var antags, out var jobs);
roles.Add(new GhostRoleInfo
{
Identifier = id,
Name = role.RoleName,
Description = role.RoleDescription,
Rules = role.RoleRules,
Requirements = role.Requirements,
RolePrototypes = (jobs, antags),
Kind = kind,
RafflePlayerCount = rafflePlayerCount,
RaffleEndTime = raffleEndTime