mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-14 23:14:45 +01:00
TriggerOnUserInteractHand and TriggerOnUserInteractUsing (#41843)
* init * handle check * oops * cleanup * fix resolve --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Trigger;
|
||||
using Content.Shared.Trigger.Components.Effects;
|
||||
|
||||
@@ -31,7 +32,10 @@ public sealed class FireStackOnTriggerSystem : EntitySystem
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
_flame.AdjustFireStacks(target.Value, ent.Comp.FireStacks, ignite: ent.Comp.DoIgnite);
|
||||
if (!TryComp<FlammableComponent>(target.Value, out var flammable))
|
||||
return;
|
||||
|
||||
_flame.AdjustFireStacks(target.Value, ent.Comp.FireStacks, ignite: ent.Comp.DoIgnite, flammable: flammable);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -46,7 +50,10 @@ public sealed class FireStackOnTriggerSystem : EntitySystem
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
_flame.Extinguish(target.Value);
|
||||
if (!TryComp<FlammableComponent>(target.Value, out var flammable))
|
||||
return;
|
||||
|
||||
_flame.Extinguish(target.Value, flammable: flammable);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -1,54 +1,75 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Interaction
|
||||
namespace Content.Shared.Interaction;
|
||||
|
||||
public sealed class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs
|
||||
{
|
||||
public sealed class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs
|
||||
public InteractHandEventArgs(EntityUid user, EntityUid target)
|
||||
{
|
||||
public InteractHandEventArgs(EntityUid user, EntityUid target)
|
||||
{
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public EntityUid User { get; }
|
||||
public EntityUid Target { get; }
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public EntityUid User { get; }
|
||||
public EntityUid Target { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on a target entity when it is interacted with by a user with an empty hand.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class InteractHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised directed on a target entity when it is interacted with by a user with an empty hand.
|
||||
/// Entity that triggered the interaction.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class InteractHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity that triggered the interaction.
|
||||
/// </summary>
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that was interacted on.
|
||||
/// </summary>
|
||||
public EntityUid Target { get; }
|
||||
|
||||
public InteractHandEvent(EntityUid user, EntityUid target)
|
||||
{
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the user before interacting on an entity with bare hand.
|
||||
/// Interaction is cancelled if this event is handled, so set it to true if you do custom interaction logic.
|
||||
/// Entity that was interacted on.
|
||||
/// </summary>
|
||||
public sealed class BeforeInteractHandEvent : HandledEntityEventArgs
|
||||
{
|
||||
public EntityUid Target { get; }
|
||||
public EntityUid Target { get; }
|
||||
|
||||
public BeforeInteractHandEvent(EntityUid target)
|
||||
{
|
||||
Target = target;
|
||||
}
|
||||
public InteractHandEvent(EntityUid user, EntityUid target)
|
||||
{
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed on the user when they interact with an entity with an empty hand.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class UserInteractHandEvent : HandledEntityEventArgs, ITargetedInteractEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity that triggered the interaction.
|
||||
/// </summary>
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that was interacted on.
|
||||
/// </summary>
|
||||
public EntityUid Target { get; }
|
||||
|
||||
public UserInteractHandEvent(EntityUid user, EntityUid target)
|
||||
{
|
||||
User = user;
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the user before interacting on an entity with bare hand.
|
||||
/// Interaction is cancelled if this event is handled, so set it to true if you do custom interaction logic.
|
||||
/// </summary>
|
||||
public sealed class BeforeInteractHandEvent : HandledEntityEventArgs
|
||||
{
|
||||
public EntityUid Target { get; }
|
||||
|
||||
public BeforeInteractHandEvent(EntityUid target)
|
||||
{
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,45 +2,85 @@ using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Interaction
|
||||
namespace Content.Shared.Interaction;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a target entity is interacted with by a user while holding an object in their hand.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class InteractUsingEvent : HandledEntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised when a target entity is interacted with by a user while holding an object in their hand.
|
||||
/// Entity that triggered the interaction.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class InteractUsingEvent : HandledEntityEventArgs
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that the user used to interact.
|
||||
/// </summary>
|
||||
public EntityUid Used { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that was interacted on.
|
||||
/// </summary>
|
||||
public EntityUid Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The original location that was clicked by the user.
|
||||
/// </summary>
|
||||
public EntityCoordinates ClickLocation { get; }
|
||||
|
||||
public InteractUsingEvent(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation)
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity that triggered the interaction.
|
||||
/// </summary>
|
||||
public EntityUid User { get; }
|
||||
// Interact using should not have the same used and target.
|
||||
// That should be a use-in-hand event instead.
|
||||
// If this is not the case, can lead to bugs (e.g., attempting to merge a item stack into itself).
|
||||
DebugTools.Assert(used != target);
|
||||
|
||||
/// <summary>
|
||||
/// Entity that the user used to interact.
|
||||
/// </summary>
|
||||
public EntityUid Used { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that was interacted on.
|
||||
/// </summary>
|
||||
public EntityUid Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The original location that was clicked by the user.
|
||||
/// </summary>
|
||||
public EntityCoordinates ClickLocation { get; }
|
||||
|
||||
public InteractUsingEvent(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation)
|
||||
{
|
||||
// Interact using should not have the same used and target.
|
||||
// That should be a use-in-hand event instead.
|
||||
// If this is not the case, can lead to bugs (e.g., attempting to merge a item stack into itself).
|
||||
DebugTools.Assert(used != target);
|
||||
|
||||
User = user;
|
||||
Used = used;
|
||||
Target = target;
|
||||
ClickLocation = clickLocation;
|
||||
}
|
||||
User = user;
|
||||
Used = used;
|
||||
Target = target;
|
||||
ClickLocation = clickLocation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a user entity interacts with a target while holding an object in their hand.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class UserInteractUsingEvent : HandledEntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity that triggered the interaction.
|
||||
/// </summary>
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that the user used to interact.
|
||||
/// </summary>
|
||||
public EntityUid Used { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entity that was interacted on.
|
||||
/// </summary>
|
||||
public EntityUid Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The original location that was clicked by the user.
|
||||
/// </summary>
|
||||
public EntityCoordinates ClickLocation { get; }
|
||||
|
||||
public UserInteractUsingEvent(EntityUid user, EntityUid used, EntityUid target, EntityCoordinates clickLocation)
|
||||
{
|
||||
// Interact using should not have the same used and target.
|
||||
// That should be a use-in-hand event instead.
|
||||
// If this is not the case, can lead to bugs (e.g., attempting to merge a item stack into itself).
|
||||
DebugTools.Assert(used != target);
|
||||
|
||||
User = user;
|
||||
Used = used;
|
||||
Target = target;
|
||||
ClickLocation = clickLocation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -523,12 +523,16 @@ namespace Content.Shared.Interaction
|
||||
}
|
||||
|
||||
DebugTools.Assert(!IsDeleted(user) && !IsDeleted(target));
|
||||
|
||||
// all interactions should only happen when in range / unobstructed, so no range check is needed
|
||||
var message = new InteractHandEvent(user, target);
|
||||
RaiseLocalEvent(target, message, true);
|
||||
var userMessage = new UserInteractHandEvent(user, target);
|
||||
RaiseLocalEvent(user, userMessage, true);
|
||||
|
||||
_adminLogger.Add(LogType.InteractHand, LogImpact.Low, $"{user} interacted with {target}");
|
||||
DoContactInteraction(user, target, message);
|
||||
if (message.Handled)
|
||||
if (message.Handled || userMessage.Handled)
|
||||
return;
|
||||
|
||||
DebugTools.Assert(!IsDeleted(user) && !IsDeleted(target));
|
||||
@@ -1061,10 +1065,14 @@ namespace Content.Shared.Interaction
|
||||
// all interactions should only happen when in range / unobstructed, so no range check is needed
|
||||
var interactUsingEvent = new InteractUsingEvent(user, used, target, clickLocation);
|
||||
RaiseLocalEvent(target, interactUsingEvent, true);
|
||||
|
||||
var userInteractUsingEvent = new UserInteractUsingEvent(user, used, target, clickLocation);
|
||||
RaiseLocalEvent(user, userInteractUsingEvent, true);
|
||||
|
||||
DoContactInteraction(user, used, interactUsingEvent);
|
||||
DoContactInteraction(user, target, interactUsingEvent);
|
||||
// Contact interactions are currently only used for forensics, so we don't raise used -> target
|
||||
if (interactUsingEvent.Handled)
|
||||
if (interactUsingEvent.Handled || userInteractUsingEvent.Handled)
|
||||
return true;
|
||||
|
||||
if (InteractDoAfter(user, used, target, clickLocation, canReach: true, checkDeletion: false))
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Trigger.Components.Triggers;
|
||||
|
||||
/// <summary>
|
||||
/// Trigger on <see cref="UserInteractHandEvent"/>, aka when owner clicks on an entity with an empty hand.
|
||||
/// The trigger user is the entity that got interacted with.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class TriggerOnUserInteractHandComponent : BaseTriggerOnXComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the interaction should be marked as handled after it happens.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Handle = true;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Trigger.Components.Triggers;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers when the owner uses another entity to interact with another entity (<see cref="UserInteractUsingEvent"/>).
|
||||
/// The trigger user is the interacted entity or the item used, depending on the TargetUsed datafield.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class TriggerOnUserInteractUsingComponent : BaseTriggerOnXComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Whitelist of entities that can be used to trigger this component.
|
||||
/// </summary>
|
||||
/// <remarks>No whitelist check when null.</remarks>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
/// <summary>
|
||||
/// Blacklist of entities that cannot be used to trigger this component.
|
||||
/// </summary>
|
||||
/// <remarks>No blacklist check when null.</remarks>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityWhitelist? Blacklist;
|
||||
|
||||
/// <summary>
|
||||
/// If false, the trigger user will be the entity that got interacted with.
|
||||
/// If true, the trigger user will the entity that was used to interact.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool TargetUsed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the interaction should be marked as handled after it happens.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Handle = true;
|
||||
}
|
||||
@@ -16,7 +16,9 @@ public sealed partial class TriggerSystem
|
||||
SubscribeLocalEvent<TriggerOnActivateComponent, ActivateInWorldEvent>(OnActivate);
|
||||
SubscribeLocalEvent<TriggerOnUseComponent, UseInHandEvent>(OnUse);
|
||||
SubscribeLocalEvent<TriggerOnInteractHandComponent, InteractHandEvent>(OnInteractHand);
|
||||
SubscribeLocalEvent<TriggerOnUserInteractHandComponent, UserInteractHandEvent>(OnUserInteractHand);
|
||||
SubscribeLocalEvent<TriggerOnInteractUsingComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<TriggerOnUserInteractUsingComponent, UserInteractUsingEvent>(OnUserInteractUsing);
|
||||
|
||||
SubscribeLocalEvent<TriggerOnThrowComponent, ThrowEvent>(OnThrow);
|
||||
SubscribeLocalEvent<TriggerOnThrownComponent, ThrownEvent>(OnThrown);
|
||||
@@ -64,6 +66,17 @@ public sealed partial class TriggerSystem
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnUserInteractHand(Entity<TriggerOnUserInteractHandComponent> ent, ref UserInteractHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
Trigger(ent.Owner, args.Target, ent.Comp.KeyOut);
|
||||
|
||||
if (ent.Comp.Handle)
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnInteractUsing(Entity<TriggerOnInteractUsingComponent> ent, ref InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
@@ -76,6 +89,20 @@ public sealed partial class TriggerSystem
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnUserInteractUsing(Entity<TriggerOnUserInteractUsingComponent> ent, ref UserInteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!_whitelist.CheckBoth(args.Used, ent.Comp.Blacklist, ent.Comp.Whitelist))
|
||||
return;
|
||||
|
||||
Trigger(ent.Owner, ent.Comp.TargetUsed ? args.Used : args.Target, ent.Comp.KeyOut);
|
||||
|
||||
if (ent.Comp.Handle)
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnThrow(Entity<TriggerOnThrowComponent> ent, ref ThrowEvent args)
|
||||
{
|
||||
Trigger(ent.Owner, args.Thrown, ent.Comp.KeyOut);
|
||||
|
||||
Reference in New Issue
Block a user