Enable verbs for items in storage and prevent orphaned nested UIs (#5512)
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -10,6 +13,8 @@ namespace Content.Shared.Verbs
|
||||
public abstract class SharedVerbSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
|
||||
@@ -19,30 +24,61 @@ namespace Content.Shared.Verbs
|
||||
{
|
||||
Dictionary<VerbType, SortedSet<Verb>> verbs = new();
|
||||
|
||||
// accessibility checks
|
||||
bool canAccess = false;
|
||||
if (force || target == user)
|
||||
canAccess = true;
|
||||
else if (_interactionSystem.InRangeUnobstructed(user, target, ignoreInsideBlocker: true))
|
||||
{
|
||||
if (user.IsInSameOrParentContainer(target))
|
||||
canAccess = true;
|
||||
else
|
||||
// the item might be in a backpack that the user has open
|
||||
canAccess = _interactionSystem.CanAccessViaStorage(user.Uid, target.Uid);
|
||||
}
|
||||
|
||||
// A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
|
||||
// call ActionBlocker checks, just cache it for the verb request.
|
||||
var canInteract = force || _actionBlockerSystem.CanInteract(user.Uid);
|
||||
|
||||
IEntity? @using = null;
|
||||
if (user.TryGetComponent(out SharedHandsComponent? hands) && (force || _actionBlockerSystem.CanUse(user.Uid)))
|
||||
{
|
||||
hands.TryGetActiveHeldEntity(out @using);
|
||||
|
||||
// Check whether the "Held" entity is a virtual pull entity. If yes, set that as the entity being "Used".
|
||||
// This allows you to do things like buckle a dragged person onto a surgery table, without click-dragging
|
||||
// their sprite.
|
||||
if (@using != null && @using.TryGetComponent<HandVirtualItemComponent>(out var pull))
|
||||
{
|
||||
@using = IoCManager.Resolve<IEntityManager>().GetEntity(pull.BlockingEntity);
|
||||
}
|
||||
}
|
||||
|
||||
if ((verbTypes & VerbType.Interaction) == VerbType.Interaction)
|
||||
{
|
||||
GetInteractionVerbsEvent getVerbEvent = new(user, target, force);
|
||||
GetInteractionVerbsEvent getVerbEvent = new(user, target, @using, hands, canInteract, canAccess);
|
||||
RaiseLocalEvent(target.Uid, getVerbEvent);
|
||||
verbs.Add(VerbType.Interaction, getVerbEvent.Verbs);
|
||||
}
|
||||
|
||||
if ((verbTypes & VerbType.Activation) == VerbType.Activation)
|
||||
{
|
||||
GetActivationVerbsEvent getVerbEvent = new(user, target, force);
|
||||
GetActivationVerbsEvent getVerbEvent = new(user, target, @using, hands, canInteract, canAccess);
|
||||
RaiseLocalEvent(target.Uid, getVerbEvent);
|
||||
verbs.Add(VerbType.Activation, getVerbEvent.Verbs);
|
||||
}
|
||||
|
||||
if ((verbTypes & VerbType.Alternative) == VerbType.Alternative)
|
||||
{
|
||||
GetAlternativeVerbsEvent getVerbEvent = new(user, target, force);
|
||||
GetAlternativeVerbsEvent getVerbEvent = new(user, target, @using, hands, canInteract, canAccess);
|
||||
RaiseLocalEvent(target.Uid, getVerbEvent);
|
||||
verbs.Add(VerbType.Alternative, getVerbEvent.Verbs);
|
||||
}
|
||||
|
||||
if ((verbTypes & VerbType.Other) == VerbType.Other)
|
||||
{
|
||||
GetOtherVerbsEvent getVerbEvent = new(user, target, force);
|
||||
GetOtherVerbsEvent getVerbEvent = new(user, target, @using, hands, canInteract, canAccess);
|
||||
RaiseLocalEvent(target.Uid, getVerbEvent);
|
||||
verbs.Add(VerbType.Other, getVerbEvent.Verbs);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ using Content.Shared.Hands.Components;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.IoC;
|
||||
using Content.Shared.Interaction;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Content.Shared.Verbs
|
||||
{
|
||||
@@ -17,10 +15,18 @@ namespace Content.Shared.Verbs
|
||||
public readonly EntityUid EntityUid;
|
||||
public readonly VerbType Type;
|
||||
|
||||
public RequestServerVerbsEvent(EntityUid entityUid, VerbType type)
|
||||
/// <summary>
|
||||
/// If the target item is inside of some storage (e.g., backpack), this is the entity that owns that item
|
||||
/// slot. Needed for validating that the user can access the target item.
|
||||
/// </summary>
|
||||
public readonly EntityUid? SlotOwner;
|
||||
|
||||
|
||||
public RequestServerVerbsEvent(EntityUid entityUid, VerbType type, EntityUid? slotOwner = null)
|
||||
{
|
||||
EntityUid = entityUid;
|
||||
Type = type;
|
||||
SlotOwner = slotOwner;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +81,9 @@ namespace Content.Shared.Verbs
|
||||
/// </remarks>
|
||||
public class GetInteractionVerbsEvent : GetVerbsEvent
|
||||
{
|
||||
public GetInteractionVerbsEvent(IEntity user, IEntity target, bool force=false) : base(user, target, force) { }
|
||||
public GetInteractionVerbsEvent(IEntity user, IEntity target, IEntity? @using, SharedHandsComponent? hands,
|
||||
bool canInteract, bool canAccess) : base(user, target, @using, hands, canInteract, canAccess) { }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,7 +97,8 @@ namespace Content.Shared.Verbs
|
||||
/// </remarks>
|
||||
public class GetActivationVerbsEvent : GetVerbsEvent
|
||||
{
|
||||
public GetActivationVerbsEvent(IEntity user, IEntity target, bool force=false) : base(user, target, force) { }
|
||||
public GetActivationVerbsEvent(IEntity user, IEntity target, IEntity? @using, SharedHandsComponent? hands,
|
||||
bool canInteract, bool canAccess) : base(user, target, @using, hands, canInteract, canAccess) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,7 +110,8 @@ namespace Content.Shared.Verbs
|
||||
/// </remarks>
|
||||
public class GetAlternativeVerbsEvent : GetVerbsEvent
|
||||
{
|
||||
public GetAlternativeVerbsEvent(IEntity user, IEntity target, bool force=false) : base(user, target, force) { }
|
||||
public GetAlternativeVerbsEvent(IEntity user, IEntity target, IEntity? @using, SharedHandsComponent? hands,
|
||||
bool canInteract, bool canAccess) : base(user, target, @using, hands, canInteract, canAccess) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,7 +123,8 @@ namespace Content.Shared.Verbs
|
||||
/// </remarks>
|
||||
public class GetOtherVerbsEvent : GetVerbsEvent
|
||||
{
|
||||
public GetOtherVerbsEvent(IEntity user, IEntity target, bool force=false) : base(user, target, force) { }
|
||||
public GetOtherVerbsEvent(IEntity user, IEntity target, IEntity? @using, SharedHandsComponent? hands,
|
||||
bool canInteract, bool canAccess) : base(user, target, @using, hands, canInteract, canAccess) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -124,7 +135,7 @@ namespace Content.Shared.Verbs
|
||||
/// <summary>
|
||||
/// Event output. Set of verbs that can be executed.
|
||||
/// </summary>
|
||||
public SortedSet<Verb> Verbs = new();
|
||||
public readonly SortedSet<Verb> Verbs = new();
|
||||
|
||||
/// <summary>
|
||||
/// Can the user physically access the target?
|
||||
@@ -133,17 +144,17 @@ namespace Content.Shared.Verbs
|
||||
/// This is a combination of <see cref="ContainerHelpers.IsInSameOrParentContainer"/> and
|
||||
/// <see cref="SharedInteractionSystem.InRangeUnobstructed"/>.
|
||||
/// </remarks>
|
||||
public bool CanAccess;
|
||||
public readonly bool CanAccess = false;
|
||||
|
||||
/// <summary>
|
||||
/// The entity being targeted for the verb.
|
||||
/// </summary>
|
||||
public IEntity Target;
|
||||
public readonly IEntity Target;
|
||||
|
||||
/// <summary>
|
||||
/// The entity that will be "performing" the verb.
|
||||
/// </summary>
|
||||
public IEntity User;
|
||||
public readonly IEntity User;
|
||||
|
||||
/// <summary>
|
||||
/// Can the user physically interact?
|
||||
@@ -153,7 +164,7 @@ namespace Content.Shared.Verbs
|
||||
/// to check this, it prevents it from having to be repeatedly called by each individual system that might
|
||||
/// contribute a verb.
|
||||
/// </remarks>
|
||||
public bool CanInteract;
|
||||
public readonly bool CanInteract;
|
||||
|
||||
/// <summary>
|
||||
/// The User's hand component.
|
||||
@@ -161,7 +172,7 @@ namespace Content.Shared.Verbs
|
||||
/// <remarks>
|
||||
/// This may be null if the user has no hands.
|
||||
/// </remarks>
|
||||
public SharedHandsComponent? Hands;
|
||||
public readonly SharedHandsComponent? Hands;
|
||||
|
||||
/// <summary>
|
||||
/// The entity currently being held by the active hand.
|
||||
@@ -170,34 +181,21 @@ namespace Content.Shared.Verbs
|
||||
/// This is only ever not null when <see cref="ActionBlockerSystem.CanUse(EntityUid)"/> is true and the user
|
||||
/// has hands.
|
||||
/// </remarks>
|
||||
public IEntity? Using;
|
||||
public readonly IEntity? Using;
|
||||
|
||||
public GetVerbsEvent(IEntity user, IEntity target, bool force=false)
|
||||
// for eventual removal of IEntity.
|
||||
public EntityUid UserUid => User.Uid;
|
||||
public EntityUid TargetUid => Target.Uid;
|
||||
public EntityUid? UsingUid => Using?.Uid;
|
||||
|
||||
public GetVerbsEvent(IEntity user, IEntity target, IEntity? @using, SharedHandsComponent? hands, bool canInteract, bool canAccess)
|
||||
{
|
||||
User = user;
|
||||
Target = target;
|
||||
|
||||
CanAccess = force || (Target == User) || user.IsInSameOrParentContainer(target) &&
|
||||
EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(user, target, ignoreInsideBlocker: true);
|
||||
|
||||
// A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
|
||||
// call ActionBlocker checks, just cache it for the verb request.
|
||||
var actionBlockerSystem = EntitySystem.Get<ActionBlockerSystem>();
|
||||
CanInteract = force || actionBlockerSystem.CanInteract(user.Uid);
|
||||
|
||||
if (!user.TryGetComponent(out Hands) ||
|
||||
!actionBlockerSystem.CanUse(user.Uid))
|
||||
return;
|
||||
|
||||
Hands.TryGetActiveHeldEntity(out Using);
|
||||
|
||||
// Check whether the "Held" entity is a virtual pull entity. If yes, set that as the entity being "Used".
|
||||
// This allows you to do things like buckle a dragged person onto a surgery table, without click-dragging
|
||||
// their sprite.
|
||||
if (Using != null && Using.TryGetComponent<HandVirtualItemComponent>(out var pull))
|
||||
{
|
||||
Using = IoCManager.Resolve<IEntityManager>().GetEntity(pull.BlockingEntity);
|
||||
}
|
||||
Using = @using;
|
||||
Hands = hands;
|
||||
CanAccess = canAccess;
|
||||
CanInteract = canInteract;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user