Adjust interaction ordering & interaction conditions (#6387)

This commit is contained in:
Leon Friedrich
2022-02-05 15:39:01 +13:00
committed by GitHub
parent 442d7dbf8e
commit dd61fb46ea
28 changed files with 88 additions and 167 deletions

View File

@@ -31,8 +31,7 @@ namespace Content.Shared.Interaction
public EntityCoordinates ClickLocation { get; }
/// <summary>
/// Is the click location close enough to reach by the player? This does not check for obstructions, just that the target is within
/// reach radius around the user.
/// Is the click location in range and unobstructed?
/// </summary>
public bool CanReach { get; }

View File

@@ -403,24 +403,6 @@ namespace Content.Shared.Interaction.Helpers
{
return SharedInteractionSystem.InRangeUnobstructed(args.User, args.Target, range, collisionMask, predicate, ignoreInsideBlocker, popup);
}
public static bool InRangeUnobstructed(
this AfterInteractEventArgs args,
float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored? predicate = null,
bool ignoreInsideBlocker = false,
bool popup = false)
{
var user = args.User;
var target = args.Target;
if (target == null)
return SharedInteractionSystem.InRangeUnobstructed(user, args.ClickLocation, range, collisionMask, predicate, ignoreInsideBlocker, popup);
else
return SharedInteractionSystem.InRangeUnobstructed(user, target.Value, range, collisionMask, predicate, ignoreInsideBlocker, popup);
}
#endregion
#region EntityEventArgs
@@ -444,23 +426,6 @@ namespace Content.Shared.Interaction.Helpers
return true;
}
public static bool InRangeUnobstructed(
this AfterInteractEvent args,
float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored? predicate = null,
bool ignoreInsideBlocker = false,
bool popup = false)
{
var user = args.User;
var target = args.Target;
if (target == null)
return SharedInteractionSystem.InRangeUnobstructed(user, args.ClickLocation, range, collisionMask, predicate, ignoreInsideBlocker, popup);
else
return SharedInteractionSystem.InRangeUnobstructed(user, target.Value, range, collisionMask, predicate, ignoreInsideBlocker, popup);
}
#endregion
}
}

View File

@@ -45,11 +45,8 @@ namespace Content.Shared.Interaction
}
}
/// <summary>
/// Raised directed on the used object when clicking on another object and no attack event was handled.
/// </summary>
[PublicAPI]
public class AfterInteractEvent : HandledEntityEventArgs
public abstract class InteractEvent : HandledEntityEventArgs
{
/// <summary>
/// Entity that triggered the interaction.
@@ -62,7 +59,7 @@ namespace Content.Shared.Interaction
public EntityUid Used { get; }
/// <summary>
/// Entity that was interacted on. This can be null if the attack did not click on an entity.
/// Entity that was interacted on. This can be null if there was no target (e.g., clicking on tiles).
/// </summary>
public EntityUid? Target { get; }
@@ -72,12 +69,11 @@ namespace Content.Shared.Interaction
public EntityCoordinates ClickLocation { get; }
/// <summary>
/// Is the click location close enough to reach by the player? This does not check for obstructions, just that the target is within
/// reach radius around the user.
/// Is the click location in range without obstructions?
/// </summary>
public bool CanReach { get; }
public AfterInteractEvent(EntityUid user, EntityUid used, EntityUid? target,
public InteractEvent(EntityUid user, EntityUid used, EntityUid? target,
EntityCoordinates clickLocation, bool canReach)
{
User = user;
@@ -87,4 +83,26 @@ namespace Content.Shared.Interaction
CanReach = canReach;
}
}
/// <summary>
/// Raised directed on the used object when clicking on another object and no standard interaction occurred.
/// Used for low-priority interactions facilitated by the used entity.
/// </summary>
public sealed class AfterInteractEvent : InteractEvent
{
public AfterInteractEvent(EntityUid user, EntityUid used, EntityUid? target,
EntityCoordinates clickLocation, bool canReach) : base(user, used, target, clickLocation, canReach)
{ }
}
/// <summary>
/// Raised directed on the target when clicking on another object and no standard interaction occurred. Used for
/// low-priority interactions facilitated by the target entity.
/// </summary>
public sealed class AfterInteractUsingEvent : InteractEvent
{
public AfterInteractUsingEvent(EntityUid user, EntityUid used, EntityUid? target,
EntityCoordinates clickLocation, bool canReach) : base(user, used, target, clickLocation, canReach)
{ }
}
}

View File

@@ -26,6 +26,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.Player;
#pragma warning disable 618
@@ -42,6 +43,7 @@ namespace Content.Shared.Interaction
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
[Dependency] private readonly SharedAdminLogSystem _adminLogSystem = default!;
[Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
public const float InteractionRange = 2;
@@ -166,14 +168,16 @@ namespace Content.Shared.Interaction
var inRangeUnobstructed = user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true);
if (target == null || !inRangeUnobstructed)
{
if (!hands.TryGetActiveHeldEntity(out var heldEntity))
if (!hands.TryGetActiveHeldEntity(out var heldEntity) || !_actionBlockerSystem.CanUse(user))
return;
if (!await InteractUsingRanged(user, heldEntity.Value, target, coordinates, inRangeUnobstructed) &&
!inRangeUnobstructed)
if (await InteractUsingRanged(user, heldEntity.Value, target, coordinates, inRangeUnobstructed))
return;
// Generate popup only if user actually tried to click on something.
if (!inRangeUnobstructed && target != null)
{
var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
user.PopupMessage(message);
_popupSystem.PopupCursor(Loc.GetString("interaction-system-user-interaction-cannot-reach"), Filter.Entities(user));
}
return;
@@ -188,15 +192,15 @@ namespace Content.Shared.Interaction
else if (!hands.TryGetActiveHeldEntity(out var heldEntity))
{
// Since our hand is empty we will use InteractHand/Activate
InteractHand(user, target.Value);
InteractHand(user, target.Value, checkActionBlocker: false);
}
else if (heldEntity != target)
else if (heldEntity != target && _actionBlockerSystem.CanUse(user))
{
await InteractUsing(user, heldEntity.Value, target.Value, coordinates);
await InteractUsing(user, heldEntity.Value, target.Value, coordinates, checkActionBlocker: false);
}
}
public virtual void InteractHand(EntityUid user, EntityUid target)
public virtual void InteractHand(EntityUid user, EntityUid target, bool checkActionBlocker = true)
{
// TODO PREDICTION move server-side interaction logic into the shared system for interaction prediction.
}
@@ -561,9 +565,9 @@ namespace Content.Shared.Interaction
/// Finds components with the InteractUsing interface and calls their function
/// NOTE: Does not have an InRangeUnobstructed check
/// </summary>
public async Task InteractUsing(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation, bool predicted = false)
public async Task InteractUsing(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation, bool predicted = false, bool checkActionBlocker = true)
{
if (!_actionBlockerSystem.CanInteract(user))
if (checkActionBlocker && (!_actionBlockerSystem.CanInteract(user) || !_actionBlockerSystem.CanUse(user)))
return;
if (InteractDoBefore(user, used, target, clickLocation, true))
@@ -585,12 +589,11 @@ namespace Content.Shared.Interaction
return;
}
// If we aren't directly interacting with the nearby object, lets see if our item has an after interact we can do
await InteractDoAfter(user, used, target, clickLocation, true);
}
/// <summary>
/// We didn't click on any entity, try doing an AfterInteract on the click location
/// Used when clicking on an entity resulted in no other interaction. Used for low-priority interactions.
/// </summary>
public async Task<bool> InteractDoAfter(EntityUid user, EntityUid used, EntityUid? target, EntityCoordinates clickLocation, bool canReach)
{
@@ -611,7 +614,12 @@ namespace Content.Shared.Interaction
return true;
}
return false;
if (target == null)
return false;
var afterInteractUsingEvent = new AfterInteractUsingEvent(user, used, target, clickLocation, canReach);
RaiseLocalEvent(target.Value, afterInteractUsingEvent, false);
return afterInteractEvent.Handled;
}
#region ActivateItemInWorld