Refactor Context Menus and make them use XAML & stylesheets (#4768)
* XAML verb menu * fix ghost FOV * spacing * rename missed "ContextMenu"->"EntityMenu" instances * move visibility checks to verb system * update comment * Remove CanSeeContainerCheck * use ScrollContainer measure option * MaxWidth / texxt line wrapping * verb category default Now when you click on a verb category, it should default to running the first member of that category. This makes it much more convenient to eject/insert when there is only a single option * only apply style to first verb category entry * Use new visibility flags * FoV -> Fov * Revert "only apply style to first verb category entry" This reverts commit 9a6a17dba600e3ae0421caed59fcab145c260c99. * make all entity menu visibility checks clientside * Fix empty unbuckle category * fix merge
This commit is contained in:
@@ -1,79 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Shared.Verbs
|
||||
{
|
||||
public class SharedVerbSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEntityLookup _lookup = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Get all of the entities in an area for displaying on the context menu.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Whether we should slightly extend the entity search area.</param>
|
||||
public bool TryGetContextEntities(IEntity player, MapCoordinates targetPos,
|
||||
[NotNullWhen(true)] out List<IEntity>? contextEntities, bool buffer = false, bool ignoreVisibility = false)
|
||||
{
|
||||
contextEntities = null;
|
||||
|
||||
// Check if we have LOS to the clicked-location.
|
||||
if (!ignoreVisibility && !player.InRangeUnOccluded(targetPos, range: ExamineSystemShared.ExamineRange))
|
||||
return false;
|
||||
|
||||
// Get entities
|
||||
var length = buffer ? 1.0f : 0.5f;
|
||||
var entities = _lookup.GetEntitiesIntersecting(
|
||||
targetPos.MapId,
|
||||
Box2.CenteredAround(targetPos.Position, (length, length)))
|
||||
.ToList();
|
||||
|
||||
if (entities.Count == 0) return false;
|
||||
|
||||
if (ignoreVisibility)
|
||||
{
|
||||
contextEntities = entities;
|
||||
return true;
|
||||
}
|
||||
|
||||
// perform visibility checks
|
||||
var playerPos = player.Transform.MapPosition;
|
||||
foreach (var entity in entities.ToList())
|
||||
{
|
||||
if (entity.HasTag("HideContextMenu"))
|
||||
{
|
||||
entities.Remove(entity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ExamineSystemShared.InRangeUnOccluded(
|
||||
playerPos,
|
||||
entity.Transform.MapPosition,
|
||||
ExamineSystemShared.ExamineRange,
|
||||
null) )
|
||||
{
|
||||
entities.Remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (entities.Count == 0)
|
||||
return false;
|
||||
|
||||
contextEntities = entities;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a number of events in order to get all verbs of the given type(s)
|
||||
/// </summary>
|
||||
public Dictionary<VerbType, SortedSet<Verb>> GetVerbs(IEntity target, IEntity user, VerbType verbTypes)
|
||||
public virtual Dictionary<VerbType, SortedSet<Verb>> GetLocalVerbs(IEntity target, IEntity user, VerbType verbTypes)
|
||||
{
|
||||
Dictionary<VerbType, SortedSet<Verb>> verbs = new();
|
||||
|
||||
@@ -109,41 +45,24 @@ namespace Content.Shared.Verbs
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute actions associated with the given verb.
|
||||
/// Execute the provided verb.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will try to call delegates and raise any events for the given verb.
|
||||
/// This will try to call the action delegates and raise the local events for the given verb.
|
||||
/// </remarks>
|
||||
public bool TryExecuteVerb(Verb verb)
|
||||
public void ExecuteVerb(Verb verb)
|
||||
{
|
||||
var executed = false;
|
||||
|
||||
// Maybe run a delegate
|
||||
if (verb.Act != null)
|
||||
{
|
||||
executed = true;
|
||||
verb.Act.Invoke();
|
||||
}
|
||||
|
||||
verb.Act?.Invoke();
|
||||
|
||||
// Maybe raise a local event
|
||||
if (verb.LocalVerbEventArgs != null)
|
||||
if (verb.ExecutionEventArgs != null)
|
||||
{
|
||||
executed = true;
|
||||
if (verb.LocalEventTarget.IsValid())
|
||||
RaiseLocalEvent(verb.LocalEventTarget, verb.LocalVerbEventArgs);
|
||||
if (verb.EventTarget.IsValid())
|
||||
RaiseLocalEvent(verb.EventTarget, verb.ExecutionEventArgs);
|
||||
else
|
||||
RaiseLocalEvent(verb.LocalVerbEventArgs);
|
||||
RaiseLocalEvent(verb.ExecutionEventArgs);
|
||||
}
|
||||
|
||||
// maybe raise a network event
|
||||
if (verb.NetworkVerbEventArgs != null)
|
||||
{
|
||||
executed = true;
|
||||
RaiseNetworkEvent(verb.NetworkVerbEventArgs);
|
||||
}
|
||||
|
||||
// return false if all of these were null
|
||||
return executed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,38 +28,38 @@ namespace Content.Shared.Verbs
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This delegate probably just points to some function in the system assembling this verb. This delegate
|
||||
/// will be run regardless of whether <see cref="LocalVerbEventArgs"/> or <see cref="NetworkVerbEventArgs"/>
|
||||
/// are defined.
|
||||
/// will be run regardless of whether <see cref="ExecutionEventArgs"/> is defined.
|
||||
/// </remarks>
|
||||
[NonSerialized]
|
||||
public Action? Act;
|
||||
|
||||
/// <summary>
|
||||
/// This is local event that will be raised when the verb is executed.
|
||||
/// This is a general local event that will be raised when the verb is executed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event will be raised regardless of whether <see cref="NetworkVerbEventArgs"/> or <see cref="Act"/>
|
||||
/// are defined.
|
||||
/// If not null, this event will be raised regardless of whether <see cref="Act"/> was run. If this event
|
||||
/// exists purely to call a specific system method, then <see cref="Act"/> should probably be used instead (method
|
||||
/// events are a no-go).
|
||||
/// </remarks>
|
||||
[NonSerialized]
|
||||
public object? LocalVerbEventArgs;
|
||||
public object? ExecutionEventArgs;
|
||||
|
||||
/// <summary>
|
||||
/// Where do direct the local event.
|
||||
/// Where do direct the local event. If invalid, the event is not raised directed at any entity.
|
||||
/// </summary>
|
||||
[NonSerialized]
|
||||
public EntityUid LocalEventTarget = EntityUid.Invalid;
|
||||
public EntityUid EventTarget = EntityUid.Invalid;
|
||||
|
||||
/// <summary>
|
||||
/// This is networked event that will be raised when the verb is executed.
|
||||
/// If a verb is only defined client-side, this should be set to true.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event will be raised regardless of whether <see cref="LocalVerbEventArgs"/> or <see cref="Act"/>
|
||||
/// are defined.
|
||||
/// If true, the client will not also ask the server to run this verb when executed locally. This just
|
||||
/// prevents unnecessary network events and "404-verb-not-found" log entries.
|
||||
/// </remarks>
|
||||
[NonSerialized]
|
||||
public EntityEventArgs? NetworkVerbEventArgs;
|
||||
|
||||
public bool ClientExclusive;
|
||||
|
||||
/// <summary>
|
||||
/// The text that the user sees on the verb button.
|
||||
/// </summary>
|
||||
@@ -74,6 +74,7 @@ namespace Content.Shared.Verbs
|
||||
IconTexture == null ? null : new SpriteSpecifier.Texture(new ResourcePath(IconTexture));
|
||||
set => _icon = value;
|
||||
}
|
||||
[NonSerialized]
|
||||
private SpriteSpecifier? _icon;
|
||||
|
||||
/// <summary>
|
||||
@@ -86,18 +87,20 @@ namespace Content.Shared.Verbs
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Disabled verbs are shown in the context menu with a slightly darker background color, and cannot be
|
||||
/// executed. It is recommended that a <see cref="Tooltip"/> message be provided outlining why this verb is
|
||||
/// executed. It is recommended that a <see cref="Message"/> message be provided outlining why this verb is
|
||||
/// disabled.
|
||||
/// </remarks>
|
||||
public bool Disabled;
|
||||
|
||||
/// <summary>
|
||||
/// Optional tooltip to show when hovering over this verb.
|
||||
/// Optional informative message.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Useful for disabled verbs as a replacement for informative pop-up messages.
|
||||
/// This will be shown as a tooltip when hovering over this verb in the context menu. Additionally, iF a
|
||||
/// <see cref="Disabled"/> verb is executed, this message will also be shown as a pop-up message. Useful for
|
||||
/// disabled verbs to inform users about why they cannot perform a given action.
|
||||
/// </remarks>
|
||||
public string? Tooltip;
|
||||
public string? Message;
|
||||
|
||||
/// <summary>
|
||||
/// Determines the priority of the verb. This affects both how the verb is displayed in the context menu
|
||||
@@ -109,7 +112,7 @@ namespace Content.Shared.Verbs
|
||||
public int Priority;
|
||||
|
||||
/// <summary>
|
||||
/// Raw texture path used to load the <see cref="Icon"/>.
|
||||
/// Raw texture path used to load the <see cref="Icon"/> for displaying on the client.
|
||||
/// </summary>
|
||||
public string? IconTexture;
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@ namespace Content.Shared.Verbs
|
||||
public readonly SpriteSpecifier? Icon;
|
||||
|
||||
/// <summary>
|
||||
/// If true, this verb category is shown in the context menu as a row of icons without any text.
|
||||
/// If true, the members of this verb category will be shown in the context menu as a row of icons without
|
||||
/// any text.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, the 'Rotate' category simply shows two icons for rotating left and right.
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Content.Shared.Verbs
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class TryExecuteVerbEvent : EntityEventArgs
|
||||
public class ExecuteVerbEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Target;
|
||||
public readonly Verb RequestedVerb;
|
||||
@@ -56,7 +56,7 @@ namespace Content.Shared.Verbs
|
||||
/// </summary>
|
||||
public readonly VerbType Type;
|
||||
|
||||
public TryExecuteVerbEvent(EntityUid target, Verb requestedVerb, VerbType type)
|
||||
public ExecuteVerbEvent(EntityUid target, Verb requestedVerb, VerbType type)
|
||||
{
|
||||
Target = target;
|
||||
RequestedVerb = requestedVerb;
|
||||
@@ -64,15 +64,6 @@ namespace Content.Shared.Verbs
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event used to toggle visibility of all context menu entities.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public class SetSeeAllContextEvent : EntityEventArgs
|
||||
{
|
||||
public bool CanSeeAllContext = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request primary interaction verbs. This includes both use-in-hand and interacting with external entities.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user