Decouple interactions from hands, cleanup old events, add new fears (#28393)
* ok basic shit * second part * pretend it isn't real it can't hurt you. * 👁️ 👁️ * shadowcommander review
This commit is contained in:
@@ -76,6 +76,7 @@ namespace Content.Shared.Interaction
|
||||
private EntityQuery<WallMountComponent> _wallMountQuery;
|
||||
private EntityQuery<UseDelayComponent> _delayQuery;
|
||||
private EntityQuery<ActivatableUIComponent> _uiQuery;
|
||||
private EntityQuery<ComplexInteractionComponent> _complexInteractionQuery;
|
||||
|
||||
private const CollisionGroup InRangeUnobstructedMask = CollisionGroup.Impassable | CollisionGroup.InteractImpassable;
|
||||
|
||||
@@ -98,6 +99,7 @@ namespace Content.Shared.Interaction
|
||||
_wallMountQuery = GetEntityQuery<WallMountComponent>();
|
||||
_delayQuery = GetEntityQuery<UseDelayComponent>();
|
||||
_uiQuery = GetEntityQuery<ActivatableUIComponent>();
|
||||
_complexInteractionQuery = GetEntityQuery<ComplexInteractionComponent>();
|
||||
|
||||
SubscribeLocalEvent<BoundUserInterfaceCheckRangeEvent>(HandleUserInterfaceRangeCheck);
|
||||
SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
|
||||
@@ -360,8 +362,13 @@ namespace Content.Shared.Interaction
|
||||
// TODO this needs to be handled better. This probably bypasses many complex can-interact checks in weird roundabout ways.
|
||||
if (_actionBlockerSystem.CanInteract(user, target))
|
||||
{
|
||||
UserInteraction(relay.RelayEntity.Value, coordinates, target, altInteract, checkCanInteract,
|
||||
checkAccess, checkCanUse);
|
||||
UserInteraction(relay.RelayEntity.Value,
|
||||
coordinates,
|
||||
target,
|
||||
altInteract,
|
||||
checkCanInteract,
|
||||
checkAccess,
|
||||
checkCanUse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -398,25 +405,10 @@ namespace Content.Shared.Interaction
|
||||
? !checkAccess || InRangeUnobstructed(user, coordinates)
|
||||
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
||||
|
||||
// Does the user have hands?
|
||||
if (!_handsQuery.TryComp(user, out var hands) || hands.ActiveHand == null)
|
||||
{
|
||||
var ev = new InteractNoHandEvent(user, target, coordinates);
|
||||
RaiseLocalEvent(user, ev);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
var interactedEv = new InteractedNoHandEvent(target.Value, user, coordinates);
|
||||
RaiseLocalEvent(target.Value, interactedEv);
|
||||
DoContactInteraction(user, target.Value, ev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// empty-hand interactions
|
||||
// combat mode hand interactions will always be true here -- since
|
||||
// they check this earlier before returning in
|
||||
if (hands.ActiveHandEntity is not { } held)
|
||||
if (!TryGetUsedEntity(user, out var used, checkCanUse))
|
||||
{
|
||||
if (inRangeUnobstructed && target != null)
|
||||
InteractHand(user, target.Value);
|
||||
@@ -424,11 +416,7 @@ namespace Content.Shared.Interaction
|
||||
return;
|
||||
}
|
||||
|
||||
// Can the user use the held entity?
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user))
|
||||
return;
|
||||
|
||||
if (target == held)
|
||||
if (target == used)
|
||||
{
|
||||
UseInHandInteraction(user, target.Value, checkCanUse: false, checkCanInteract: false);
|
||||
return;
|
||||
@@ -438,7 +426,7 @@ namespace Content.Shared.Interaction
|
||||
{
|
||||
InteractUsing(
|
||||
user,
|
||||
held,
|
||||
used.Value,
|
||||
target.Value,
|
||||
coordinates,
|
||||
checkCanInteract: false,
|
||||
@@ -449,7 +437,7 @@ namespace Content.Shared.Interaction
|
||||
|
||||
InteractUsingRanged(
|
||||
user,
|
||||
held,
|
||||
used.Value,
|
||||
target,
|
||||
coordinates,
|
||||
inRangeUnobstructed);
|
||||
@@ -457,6 +445,18 @@ namespace Content.Shared.Interaction
|
||||
|
||||
public void InteractHand(EntityUid user, EntityUid target)
|
||||
{
|
||||
var complexInteractions = SupportsComplexInteractions(user);
|
||||
if (!complexInteractions)
|
||||
{
|
||||
InteractionActivate(user,
|
||||
target,
|
||||
checkCanInteract: false,
|
||||
checkUseDelay: true,
|
||||
checkAccess: false,
|
||||
complexInteractions: complexInteractions);
|
||||
return;
|
||||
}
|
||||
|
||||
// allow for special logic before main interaction
|
||||
var ev = new BeforeInteractHandEvent(target);
|
||||
RaiseLocalEvent(user, ev);
|
||||
@@ -475,10 +475,12 @@ namespace Content.Shared.Interaction
|
||||
return;
|
||||
|
||||
// Else we run Activate.
|
||||
InteractionActivate(user, target,
|
||||
InteractionActivate(user,
|
||||
target,
|
||||
checkCanInteract: false,
|
||||
checkUseDelay: true,
|
||||
checkAccess: false);
|
||||
checkAccess: false,
|
||||
complexInteractions: complexInteractions);
|
||||
}
|
||||
|
||||
public void InteractUsingRanged(EntityUid user, EntityUid used, EntityUid? target,
|
||||
@@ -921,7 +923,7 @@ namespace Content.Shared.Interaction
|
||||
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
|
||||
return;
|
||||
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user))
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user, used))
|
||||
return;
|
||||
|
||||
if (RangedInteractDoBefore(user, used, target, clickLocation, true))
|
||||
@@ -1001,7 +1003,8 @@ namespace Content.Shared.Interaction
|
||||
EntityUid used,
|
||||
bool checkCanInteract = true,
|
||||
bool checkUseDelay = true,
|
||||
bool checkAccess = true)
|
||||
bool checkAccess = true,
|
||||
bool? complexInteractions = null)
|
||||
{
|
||||
_delayQuery.TryComp(used, out var delayComponent);
|
||||
if (checkUseDelay && delayComponent != null && _useDelay.IsDelayed((used, delayComponent)))
|
||||
@@ -1018,13 +1021,12 @@ namespace Content.Shared.Interaction
|
||||
if (checkAccess && !IsAccessible(user, used))
|
||||
return false;
|
||||
|
||||
// Does the user have hands?
|
||||
if (!_handsQuery.HasComp(user))
|
||||
return false;
|
||||
|
||||
var activateMsg = new ActivateInWorldEvent(user, used);
|
||||
complexInteractions ??= SupportsComplexInteractions(user);
|
||||
var activateMsg = new ActivateInWorldEvent(user, used, complexInteractions.Value);
|
||||
RaiseLocalEvent(used, activateMsg, true);
|
||||
if (!activateMsg.Handled)
|
||||
var userEv = new UserActivateInWorldEvent(user, used, complexInteractions.Value);
|
||||
RaiseLocalEvent(user, userEv, true);
|
||||
if (!activateMsg.Handled && !userEv.Handled)
|
||||
return false;
|
||||
|
||||
DoContactInteraction(user, used, activateMsg);
|
||||
@@ -1059,7 +1061,7 @@ namespace Content.Shared.Interaction
|
||||
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
||||
return false;
|
||||
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user))
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user, used))
|
||||
return false;
|
||||
|
||||
var useMsg = new UseInHandEvent(user);
|
||||
@@ -1259,6 +1261,39 @@ namespace Content.Shared.Interaction
|
||||
? BoundUserInterfaceRangeResult.Pass
|
||||
: BoundUserInterfaceRangeResult.Fail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity that is currently being "used" for the interaction.
|
||||
/// In most cases, this refers to the entity in the character's active hand.
|
||||
/// </summary>
|
||||
/// <returns>If there is an entity being used.</returns>
|
||||
public bool TryGetUsedEntity(EntityUid user, [NotNullWhen(true)] out EntityUid? used, bool checkCanUse = true)
|
||||
{
|
||||
var ev = new GetUsedEntityEvent();
|
||||
RaiseLocalEvent(user, ref ev);
|
||||
|
||||
used = ev.Used;
|
||||
if (!ev.Handled)
|
||||
return false;
|
||||
|
||||
// Can the user use the held entity?
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user, ev.Used!.Value))
|
||||
{
|
||||
used = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ev.Handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given entity is able to do specific complex interactions.
|
||||
/// This is used to gate manipulation to general humanoids. If a mouse shouldn't be able to do something, then it's complex.
|
||||
/// </summary>
|
||||
public bool SupportsComplexInteractions(EntityUid user)
|
||||
{
|
||||
return _complexInteractionQuery.HasComp(user);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1284,6 +1319,24 @@ namespace Content.Shared.Interaction
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed by-ref on an entity to determine what item will be used in interactions.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct GetUsedEntityEvent()
|
||||
{
|
||||
public EntityUid? Used = null;
|
||||
|
||||
public bool Handled => Used != null;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed by-ref on an item and a user to determine if interactions can occur.
|
||||
/// </summary>
|
||||
/// <param name="Cancelled">Whether the hand interaction should be cancelled.</param>
|
||||
[ByRefEvent]
|
||||
public record struct AttemptUseInteractEvent(EntityUid User, EntityUid Used, bool Cancelled = false);
|
||||
|
||||
/// <summary>
|
||||
/// Raised directed by-ref on an item to determine if hand interactions should go through.
|
||||
/// Defaults to allowing hand interactions to go through. Cancel to force the item to be attacked instead.
|
||||
|
||||
Reference in New Issue
Block a user