Stop admin verb pop-in (#27450)

This commit is contained in:
Leon Friedrich
2024-04-29 15:24:10 +12:00
committed by GitHub
parent a466b35b27
commit 1eb81427d3
6 changed files with 68 additions and 33 deletions

View File

@@ -1,3 +1,6 @@
using Content.Shared.Administration;
using Content.Shared.Administration.Managers;
using Content.Shared.Mind.Components;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using Robust.Client.Console; using Robust.Client.Console;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -11,10 +14,12 @@ namespace Content.Client.Administration.Systems
{ {
[Dependency] private readonly IClientConGroupController _clientConGroupController = default!; [Dependency] private readonly IClientConGroupController _clientConGroupController = default!;
[Dependency] private readonly IClientConsoleHost _clientConsoleHost = default!; [Dependency] private readonly IClientConsoleHost _clientConsoleHost = default!;
[Dependency] private readonly ISharedAdminManager _admin = default!;
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<GetVerbsEvent<Verb>>(AddAdminVerbs); SubscribeLocalEvent<GetVerbsEvent<Verb>>(AddAdminVerbs);
} }
private void AddAdminVerbs(GetVerbsEvent<Verb> args) private void AddAdminVerbs(GetVerbsEvent<Verb> args)
@@ -33,6 +38,24 @@ namespace Content.Client.Administration.Systems
}; };
args.Verbs.Add(verb); args.Verbs.Add(verb);
} }
if (!_admin.IsAdmin(args.User))
return;
if (_admin.HasAdminFlag(args.User, AdminFlags.Admin))
args.ExtraCategories.Add(VerbCategory.Admin);
if (_admin.HasAdminFlag(args.User, AdminFlags.Fun) && HasComp<MindContainerComponent>(args.Target))
args.ExtraCategories.Add(VerbCategory.Antag);
if (_admin.HasAdminFlag(args.User, AdminFlags.Debug))
args.ExtraCategories.Add(VerbCategory.Debug);
if (_admin.HasAdminFlag(args.User, AdminFlags.Fun))
args.ExtraCategories.Add(VerbCategory.Smite);
if (_admin.HasAdminFlag(args.User, AdminFlags.Admin))
args.ExtraCategories.Add(VerbCategory.Tricks);
} }
} }
} }

View File

@@ -31,6 +31,7 @@ namespace Content.Client.Verbs.UI
public NetEntity CurrentTarget; public NetEntity CurrentTarget;
public SortedSet<Verb> CurrentVerbs = new(); public SortedSet<Verb> CurrentVerbs = new();
public List<VerbCategory> ExtraCategories = new();
/// <summary> /// <summary>
/// Separate from <see cref="ContextMenuUIController.RootMenu"/>, since we can open a verb menu as a submenu /// Separate from <see cref="ContextMenuUIController.RootMenu"/>, since we can open a verb menu as a submenu
@@ -91,19 +92,12 @@ namespace Content.Client.Verbs.UI
menu.MenuBody.DisposeAllChildren(); menu.MenuBody.DisposeAllChildren();
CurrentTarget = target; CurrentTarget = target;
CurrentVerbs = _verbSystem.GetVerbs(target, user, Verb.VerbTypes, force); CurrentVerbs = _verbSystem.GetVerbs(target, user, Verb.VerbTypes, out ExtraCategories, force);
OpenMenu = menu; OpenMenu = menu;
// Fill in client-side verbs. // Fill in client-side verbs.
FillVerbPopup(menu); FillVerbPopup(menu);
// Add indicator that some verbs may be missing.
// I long for the day when verbs will all be predicted and this becomes unnecessary.
if (!target.IsClientSide())
{
_context.AddElement(menu, new ContextMenuElement(Loc.GetString("verb-system-waiting-on-server-text")));
}
// if popup isn't null (ie we are opening out of an entity menu element), // if popup isn't null (ie we are opening out of an entity menu element),
// assume that that is going to handle opening the submenu properly // assume that that is going to handle opening the submenu properly
if (popup != null) if (popup != null)
@@ -128,11 +122,19 @@ namespace Content.Client.Verbs.UI
var element = new VerbMenuElement(verb); var element = new VerbMenuElement(verb);
_context.AddElement(popup, element); _context.AddElement(popup, element);
} }
else if (listedCategories.Add(verb.Category.Text)) else if (listedCategories.Add(verb.Category.Text))
AddVerbCategory(verb.Category, popup); AddVerbCategory(verb.Category, popup);
} }
if (ExtraCategories != null)
{
foreach (var category in ExtraCategories)
{
if (listedCategories.Add(category.Text))
AddVerbCategory(category, popup);
}
}
popup.InvalidateMeasure(); popup.InvalidateMeasure();
} }
@@ -153,10 +155,11 @@ namespace Content.Client.Verbs.UI
} }
} }
if (verbsInCategory.Count == 0) if (verbsInCategory.Count == 0 && !ExtraCategories.Contains(category))
return; return;
var element = new VerbMenuElement(category, verbsInCategory[0].TextStyleClass); var style = verbsInCategory.FirstOrDefault()?.TextStyleClass ?? Verb.DefaultTextStyleClass;
var element = new VerbMenuElement(category, style);
_context.AddElement(popup, element); _context.AddElement(popup, element);
// Create the pop-up that appears when hovering over this element // Create the pop-up that appears when hovering over this element

View File

@@ -165,29 +165,23 @@ namespace Content.Client.Verbs
return true; return true;
} }
/// <summary>
/// Asks the server to send back a list of server-side verbs, for the given verb type.
/// </summary>
public SortedSet<Verb> GetVerbs(EntityUid target, EntityUid user, Type type, bool force = false)
{
return GetVerbs(GetNetEntity(target), user, new List<Type>() { type }, force);
}
/// <summary> /// <summary>
/// Ask the server to send back a list of server-side verbs, and for now return an incomplete list of verbs /// Ask the server to send back a list of server-side verbs, and for now return an incomplete list of verbs
/// (only those defined locally). /// (only those defined locally).
/// </summary> /// </summary>
public SortedSet<Verb> GetVerbs(NetEntity target, EntityUid user, List<Type> verbTypes, public SortedSet<Verb> GetVerbs(NetEntity target, EntityUid user, List<Type> verbTypes, out List<VerbCategory> extraCategories, bool force = false)
bool force = false)
{ {
if (!target.IsClientSide()) if (!target.IsClientSide())
RaiseNetworkEvent(new RequestServerVerbsEvent(target, verbTypes, adminRequest: force)); RaiseNetworkEvent(new RequestServerVerbsEvent(target, verbTypes, adminRequest: force));
// Some admin menu interactions will try get verbs for entities that have not yet been sent to the player. // Some admin menu interactions will try get verbs for entities that have not yet been sent to the player.
if (!TryGetEntity(target, out var local)) if (!TryGetEntity(target, out var local))
{
extraCategories = new();
return new(); return new();
}
return GetLocalVerbs(local.Value, user, verbTypes, force); return GetLocalVerbs(local.Value, user, verbTypes, out extraCategories, force);
} }

View File

@@ -55,13 +55,21 @@ namespace Content.Shared.Verbs
return GetLocalVerbs(target, user, new List<Type>() { type }, force); return GetLocalVerbs(target, user, new List<Type>() { type }, force);
} }
/// <inheritdoc cref="GetLocalVerbs(Robust.Shared.GameObjects.EntityUid,Robust.Shared.GameObjects.EntityUid,System.Type,bool)"/>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types, bool force = false)
{
return GetLocalVerbs(target, user, types, out _, force);
}
/// <summary> /// <summary>
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This /// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
/// does not request verbs from the server. /// does not request verbs from the server.
/// </summary> /// </summary>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types, bool force = false) public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types,
out List<VerbCategory> extraCategories, bool force = false)
{ {
SortedSet<Verb> verbs = new(); SortedSet<Verb> verbs = new();
extraCategories = new();
// accessibility checks // accessibility checks
bool canAccess = false; bool canAccess = false;
@@ -108,7 +116,7 @@ namespace Content.Shared.Verbs
// TODO: fix this garbage and use proper generics or reflection or something else, not this. // TODO: fix this garbage and use proper generics or reflection or something else, not this.
if (types.Contains(typeof(InteractionVerb))) if (types.Contains(typeof(InteractionVerb)))
{ {
var verbEvent = new GetVerbsEvent<InteractionVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<InteractionVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true); RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
@@ -117,35 +125,35 @@ namespace Content.Shared.Verbs
&& @using != null && @using != null
&& @using != target) && @using != target)
{ {
var verbEvent = new GetVerbsEvent<UtilityVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<UtilityVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(@using.Value, verbEvent, true); // directed at used, not at target RaiseLocalEvent(@using.Value, verbEvent, true); // directed at used, not at target
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
if (types.Contains(typeof(InnateVerb))) if (types.Contains(typeof(InnateVerb)))
{ {
var verbEvent = new GetVerbsEvent<InnateVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<InnateVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(user, verbEvent, true); RaiseLocalEvent(user, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
if (types.Contains(typeof(AlternativeVerb))) if (types.Contains(typeof(AlternativeVerb)))
{ {
var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true); RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
if (types.Contains(typeof(ActivationVerb))) if (types.Contains(typeof(ActivationVerb)))
{ {
var verbEvent = new GetVerbsEvent<ActivationVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<ActivationVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true); RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
if (types.Contains(typeof(ExamineVerb))) if (types.Contains(typeof(ExamineVerb)))
{ {
var verbEvent = new GetVerbsEvent<ExamineVerb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<ExamineVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true); RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
@@ -153,7 +161,7 @@ namespace Content.Shared.Verbs
// generic verbs // generic verbs
if (types.Contains(typeof(Verb))) if (types.Contains(typeof(Verb)))
{ {
var verbEvent = new GetVerbsEvent<Verb>(user, target, @using, hands, canInteract, canAccess); var verbEvent = new GetVerbsEvent<Verb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true); RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }
@@ -161,7 +169,7 @@ namespace Content.Shared.Verbs
if (types.Contains(typeof(EquipmentVerb))) if (types.Contains(typeof(EquipmentVerb)))
{ {
var access = canAccess || _interactionSystem.CanAccessEquipment(user, target); var access = canAccess || _interactionSystem.CanAccessEquipment(user, target);
var verbEvent = new GetVerbsEvent<EquipmentVerb>(user, target, @using, hands, canInteract, access); var verbEvent = new GetVerbsEvent<EquipmentVerb>(user, target, @using, hands, canInteract, access, extraCategories);
RaiseLocalEvent(target, verbEvent); RaiseLocalEvent(target, verbEvent);
verbs.UnionWith(verbEvent.Verbs); verbs.UnionWith(verbEvent.Verbs);
} }

View File

@@ -77,6 +77,13 @@ namespace Content.Shared.Verbs
/// </summary> /// </summary>
public readonly SortedSet<TVerb> Verbs = new(); public readonly SortedSet<TVerb> Verbs = new();
/// <summary>
/// Additional verb categories to show in the pop-up menu, even if there are no verbs currently associated
/// with that category. This is mainly useful to prevent verb menu pop-in. E.g., admins will get admin/debug
/// related verbs on entities, even though most of those verbs are all defined server-side.
/// </summary>
public readonly List<VerbCategory> ExtraCategories;
/// <summary> /// <summary>
/// Can the user physically access the target? /// Can the user physically access the target?
/// </summary> /// </summary>
@@ -123,7 +130,7 @@ namespace Content.Shared.Verbs
/// </remarks> /// </remarks>
public readonly EntityUid? Using; public readonly EntityUid? Using;
public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsComponent? hands, bool canInteract, bool canAccess) public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsComponent? hands, bool canInteract, bool canAccess, List<VerbCategory> extraCategories)
{ {
User = user; User = user;
Target = target; Target = target;
@@ -131,6 +138,7 @@ namespace Content.Shared.Verbs
Hands = hands; Hands = hands;
CanAccess = canAccess; CanAccess = canAccess;
CanInteract = canInteract; CanInteract = canInteract;
ExtraCategories = extraCategories;
} }
} }
} }

View File

@@ -1,4 +1,3 @@
verb-system-waiting-on-server-text = Waiting on Server...
verb-system-null-server-response = Entity not in view. You should not see this. verb-system-null-server-response = Entity not in view. You should not see this.