Remove ignore-inside-blocker (#6692)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -1,20 +1,14 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Content.Shared.Construction;
|
using Content.Shared.Construction;
|
||||||
using Content.Shared.Construction.Prototypes;
|
using Content.Shared.Construction.Prototypes;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Input;
|
using Robust.Shared.Input;
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Construction
|
namespace Content.Client.Construction
|
||||||
@@ -27,6 +21,7 @@ namespace Content.Client.Construction
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
private readonly Dictionary<int, ConstructionGhostComponent> _ghosts = new();
|
private readonly Dictionary<int, ConstructionGhostComponent> _ghosts = new();
|
||||||
private readonly Dictionary<string, ConstructionGuide> _guideCache = new();
|
private readonly Dictionary<string, ConstructionGuide> _guideCache = new();
|
||||||
@@ -162,8 +157,12 @@ namespace Content.Client.Construction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GhostPresent(loc)) return;
|
||||||
|
|
||||||
// This InRangeUnobstructed should probably be replaced with "is there something blocking us in that tile?"
|
// This InRangeUnobstructed should probably be replaced with "is there something blocking us in that tile?"
|
||||||
if (GhostPresent(loc) || !user.InRangeUnobstructed(loc, 20f, ignoreInsideBlocker: prototype.CanBuildInImpassable)) return;
|
var predicate = GetPredicate(prototype.CanBuildInImpassable, loc.ToMap(EntityManager));
|
||||||
|
if (!_interactionSystem.InRangeUnobstructed(user, loc, 20f, predicate: predicate))
|
||||||
|
return;
|
||||||
|
|
||||||
foreach (var condition in prototype.Conditions)
|
foreach (var condition in prototype.Conditions)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -297,19 +297,6 @@ namespace Content.Client.DragDrop
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now when ending the drag, we will not replay the click because
|
|
||||||
// by this time we've determined the input was actually a drag attempt
|
|
||||||
var range = (args.Coordinates.ToMapPos(EntityManager) - EntityManager.GetComponent<TransformComponent>(_dragger).MapPosition.Position).Length + 0.01f;
|
|
||||||
// tell the server we are dropping if we are over a valid drop target in range.
|
|
||||||
// We don't use args.EntityUid here because drag interactions generally should
|
|
||||||
// work even if there's something "on top" of the drop target
|
|
||||||
if (!_interactionSystem.InRangeUnobstructed(_dragger,
|
|
||||||
args.Coordinates, range, ignoreInsideBlocker: true))
|
|
||||||
{
|
|
||||||
_dragDropHelper.EndDrag();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IList<EntityUid> entities;
|
IList<EntityUid> entities;
|
||||||
|
|
||||||
if (_stateManager.CurrentState is GameScreen screen)
|
if (_stateManager.CurrentState is GameScreen screen)
|
||||||
@@ -333,7 +320,8 @@ namespace Content.Client.DragDrop
|
|||||||
// TODO: Cache valid CanDragDrops
|
// TODO: Cache valid CanDragDrops
|
||||||
if (ValidDragDrop(dropArgs) != true) continue;
|
if (ValidDragDrop(dropArgs) != true) continue;
|
||||||
|
|
||||||
if (!dropArgs.InRangeUnobstructed(ignoreInsideBlocker: true))
|
if (!_interactionSystem.InRangeUnobstructed(dropArgs.User, dropArgs.Target)
|
||||||
|
|| !_interactionSystem.InRangeUnobstructed(dropArgs.User, dropArgs.Dragged))
|
||||||
{
|
{
|
||||||
outOfRange = true;
|
outOfRange = true;
|
||||||
continue;
|
continue;
|
||||||
@@ -401,7 +389,8 @@ namespace Content.Client.DragDrop
|
|||||||
// We'll do a final check given server-side does this before any dragdrop can take place.
|
// We'll do a final check given server-side does this before any dragdrop can take place.
|
||||||
if (valid.Value)
|
if (valid.Value)
|
||||||
{
|
{
|
||||||
valid = dropArgs.InRangeUnobstructed(ignoreInsideBlocker: true);
|
valid = _interactionSystem.InRangeUnobstructed(dropArgs.Target, dropArgs.Dragged)
|
||||||
|
&& _interactionSystem.InRangeUnobstructed(dropArgs.Target, dropArgs.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// highlight depending on whether its in or out of range
|
// highlight depending on whether its in or out of range
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Client.Interactable;
|
using Content.Client.Interactable;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Robust.Client.Audio.Midi;
|
using Robust.Client.Audio.Midi;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
@@ -151,8 +152,7 @@ namespace Content.Client.Instruments.UI
|
|||||||
|| conMan.Owner != localPlayer.ControlledEntity))) return false;
|
|| conMan.Owner != localPlayer.ControlledEntity))) return false;
|
||||||
|
|
||||||
// We check that we're in range unobstructed just in case.
|
// We check that we're in range unobstructed just in case.
|
||||||
return localPlayer.InRangeUnobstructed(instrumentEnt.Value,
|
return EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(localPlayer.ControlledEntity.Value, instrumentEnt.Value);
|
||||||
predicate: (e) => e == instrumentEnt || e == localPlayer.ControlledEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MidiStopButtonOnPressed(ButtonEventArgs? obj)
|
private void MidiStopButtonOnPressed(ButtonEventArgs? obj)
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Physics;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using static Content.Shared.Interaction.SharedInteractionSystem;
|
|
||||||
|
|
||||||
namespace Content.Client.Interactable
|
|
||||||
{
|
|
||||||
public static class UnobstructedExtensions
|
|
||||||
{
|
|
||||||
private static SharedInteractionSystem SharedInteractionSystem => EntitySystem.Get<SharedInteractionSystem>();
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this LocalPlayer origin,
|
|
||||||
EntityUid other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other).MapPosition;
|
|
||||||
|
|
||||||
return origin.InRangeUnobstructed(otherPosition, range, collisionMask, predicate, ignoreInsideBlocker,
|
|
||||||
popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this LocalPlayer origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
return origin.InRangeUnobstructed(other.Owner, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this LocalPlayer origin,
|
|
||||||
IContainer other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
return origin.InRangeUnobstructed(other.Owner, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this LocalPlayer origin,
|
|
||||||
EntityCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
var otherPosition = other.ToMap(entityManager);
|
|
||||||
|
|
||||||
return origin.InRangeUnobstructed(otherPosition, range, collisionMask, predicate, ignoreInsideBlocker,
|
|
||||||
popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this LocalPlayer origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.ControlledEntity;
|
|
||||||
if (originEntity == null)
|
|
||||||
{
|
|
||||||
// TODO: Take into account the player's camera position?
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity.Value, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared.Climbing;
|
using Content.Shared.Climbing;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
@@ -19,7 +20,10 @@ namespace Content.Client.Movement.Components
|
|||||||
var dragged = eventArgs.Dragged;
|
var dragged = eventArgs.Dragged;
|
||||||
bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged;
|
bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged;
|
||||||
|
|
||||||
return user.InRangeUnobstructed(target, Range, predicate: Ignored) && user.InRangeUnobstructed(dragged, Range, predicate: Ignored);
|
var sys = EntitySystem.Get<SharedInteractionSystem>();
|
||||||
|
|
||||||
|
return sys.InRangeUnobstructed(user, target, Range, predicate: Ignored)
|
||||||
|
&& sys.InRangeUnobstructed(user, dragged, Range, predicate: Ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool DragDropOn(DragDropEvent eventArgs)
|
public override bool DragDropOn(DragDropEvent eventArgs)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Client.Interactable;
|
|||||||
using Content.Client.Interactable.Components;
|
using Content.Client.Interactable.Components;
|
||||||
using Content.Client.Viewport;
|
using Content.Client.Viewport;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Input;
|
using Robust.Client.Input;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
@@ -10,8 +11,6 @@ using Robust.Client.State;
|
|||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Client.Outline;
|
namespace Content.Client.Outline;
|
||||||
|
|
||||||
@@ -23,6 +22,7 @@ public sealed class InteractionOutlineSystem : EntitySystem
|
|||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public bool Enabled = true;
|
public bool Enabled = true;
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public sealed class InteractionOutlineSystem : EntitySystem
|
|||||||
var inRange = false;
|
var inRange = false;
|
||||||
if (localPlayer.ControlledEntity != null && entityToClick != null)
|
if (localPlayer.ControlledEntity != null && entityToClick != null)
|
||||||
{
|
{
|
||||||
inRange = localPlayer.InRangeUnobstructed(entityToClick.Value, ignoreInsideBlocker: true);
|
inRange = _interactionSystem.InRangeUnobstructed(localPlayer.ControlledEntity.Value, entityToClick.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractionOutlineComponent? outline;
|
InteractionOutlineComponent? outline;
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Client.Interactable;
|
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
|
|
||||||
@@ -13,8 +10,6 @@ namespace Content.IntegrationTests.Tests.Interaction
|
|||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[TestOf(typeof(SharedInteractionSystem))]
|
[TestOf(typeof(SharedInteractionSystem))]
|
||||||
[TestOf(typeof(SharedUnobstructedExtensions))]
|
|
||||||
[TestOf(typeof(UnobstructedExtensions))]
|
|
||||||
public sealed class InRangeUnobstructed : ContentIntegrationTest
|
public sealed class InRangeUnobstructed : ContentIntegrationTest
|
||||||
{
|
{
|
||||||
private const string HumanId = "MobHumanBase";
|
private const string HumanId = "MobHumanBase";
|
||||||
@@ -59,98 +54,50 @@ namespace Content.IntegrationTests.Tests.Interaction
|
|||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var interactionSys = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<SharedInteractionSystem>();
|
||||||
|
|
||||||
server.Assert(() =>
|
server.Assert(() =>
|
||||||
{
|
{
|
||||||
// Entity <-> Entity
|
// Entity <-> Entity
|
||||||
Assert.True(origin.InRangeUnobstructed(other));
|
Assert.True(interactionSys.InRangeUnobstructed(origin, other));
|
||||||
Assert.True(other.InRangeUnobstructed(origin));
|
Assert.True(interactionSys.InRangeUnobstructed(other, origin));
|
||||||
|
|
||||||
// Entity <-> Component
|
|
||||||
Assert.True(origin.InRangeUnobstructed(component));
|
|
||||||
Assert.True(component.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> Container
|
|
||||||
Assert.True(origin.InRangeUnobstructed(container));
|
|
||||||
Assert.True(container.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> EntityCoordinates
|
|
||||||
Assert.True(origin.InRangeUnobstructed(entityCoordinates));
|
|
||||||
Assert.True(entityCoordinates.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> MapCoordinates
|
// Entity <-> MapCoordinates
|
||||||
Assert.True(origin.InRangeUnobstructed(mapCoordinates));
|
Assert.True(interactionSys.InRangeUnobstructed(origin, mapCoordinates));
|
||||||
Assert.True(mapCoordinates.InRangeUnobstructed(origin));
|
Assert.True(interactionSys.InRangeUnobstructed(mapCoordinates, origin));
|
||||||
|
|
||||||
|
|
||||||
// Move them slightly apart
|
// Move them slightly apart
|
||||||
sEntities.GetComponent<TransformComponent>(origin).LocalPosition += _interactionRangeDivided15X;
|
sEntities.GetComponent<TransformComponent>(origin).LocalPosition += _interactionRangeDivided15X;
|
||||||
|
|
||||||
// Entity <-> Entity
|
// Entity <-> Entity
|
||||||
Assert.True(origin.InRangeUnobstructed(other));
|
// Entity <-> Entity
|
||||||
Assert.True(other.InRangeUnobstructed(origin));
|
Assert.True(interactionSys.InRangeUnobstructed(origin, other));
|
||||||
|
Assert.True(interactionSys.InRangeUnobstructed(other, origin));
|
||||||
// Entity <-> Component
|
|
||||||
Assert.True(origin.InRangeUnobstructed(component));
|
|
||||||
Assert.True(component.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> Container
|
|
||||||
Assert.True(origin.InRangeUnobstructed(container));
|
|
||||||
Assert.True(container.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> EntityCoordinates
|
|
||||||
Assert.True(origin.InRangeUnobstructed(entityCoordinates));
|
|
||||||
Assert.True(entityCoordinates.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> MapCoordinates
|
// Entity <-> MapCoordinates
|
||||||
Assert.True(origin.InRangeUnobstructed(mapCoordinates));
|
Assert.True(interactionSys.InRangeUnobstructed(origin, mapCoordinates));
|
||||||
Assert.True(mapCoordinates.InRangeUnobstructed(origin));
|
Assert.True(interactionSys.InRangeUnobstructed(mapCoordinates, origin));
|
||||||
|
|
||||||
|
|
||||||
// Move them out of range
|
// Move them out of range
|
||||||
sEntities.GetComponent<TransformComponent>(origin).LocalPosition += _interactionRangeDivided15X;
|
sEntities.GetComponent<TransformComponent>(origin).LocalPosition += _interactionRangeDivided15X;
|
||||||
|
|
||||||
// Entity <-> Entity
|
// Entity <-> Entity
|
||||||
Assert.False(origin.InRangeUnobstructed(other));
|
Assert.False(interactionSys.InRangeUnobstructed(origin, other));
|
||||||
Assert.False(other.InRangeUnobstructed(origin));
|
Assert.False(interactionSys.InRangeUnobstructed(other, origin));
|
||||||
|
|
||||||
// Entity <-> Component
|
|
||||||
Assert.False(origin.InRangeUnobstructed(component));
|
|
||||||
Assert.False(component.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> Container
|
|
||||||
Assert.False(origin.InRangeUnobstructed(container));
|
|
||||||
Assert.False(container.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> EntityCoordinates
|
|
||||||
Assert.False(origin.InRangeUnobstructed(entityCoordinates));
|
|
||||||
Assert.False(entityCoordinates.InRangeUnobstructed(origin));
|
|
||||||
|
|
||||||
// Entity <-> MapCoordinates
|
// Entity <-> MapCoordinates
|
||||||
Assert.False(origin.InRangeUnobstructed(mapCoordinates));
|
Assert.False(interactionSys.InRangeUnobstructed(origin, mapCoordinates));
|
||||||
Assert.False(mapCoordinates.InRangeUnobstructed(origin));
|
Assert.False(interactionSys.InRangeUnobstructed(mapCoordinates, origin));
|
||||||
|
|
||||||
|
|
||||||
// Checks with increased range
|
// Checks with increased range
|
||||||
|
|
||||||
// Entity <-> Entity
|
// Entity <-> Entity
|
||||||
Assert.True(origin.InRangeUnobstructed(other, InteractionRangeDivided15Times3));
|
Assert.True(interactionSys.InRangeUnobstructed(origin, other, InteractionRangeDivided15Times3));
|
||||||
Assert.True(other.InRangeUnobstructed(origin, InteractionRangeDivided15Times3));
|
Assert.True(interactionSys.InRangeUnobstructed(other, origin, InteractionRangeDivided15Times3));
|
||||||
|
|
||||||
// Entity <-> Component
|
|
||||||
Assert.True(origin.InRangeUnobstructed(component, InteractionRangeDivided15Times3));
|
|
||||||
Assert.True(component.InRangeUnobstructed(origin, InteractionRangeDivided15Times3));
|
|
||||||
|
|
||||||
// Entity <-> Container
|
|
||||||
Assert.True(origin.InRangeUnobstructed(container, InteractionRangeDivided15Times3));
|
|
||||||
Assert.True(container.InRangeUnobstructed(origin, InteractionRangeDivided15Times3));
|
|
||||||
|
|
||||||
// Entity <-> EntityCoordinates
|
|
||||||
Assert.True(origin.InRangeUnobstructed(entityCoordinates, InteractionRangeDivided15Times3));
|
|
||||||
Assert.True(entityCoordinates.InRangeUnobstructed(origin, InteractionRangeDivided15Times3));
|
|
||||||
|
|
||||||
// Entity <-> MapCoordinates
|
// Entity <-> MapCoordinates
|
||||||
Assert.True(origin.InRangeUnobstructed(mapCoordinates, InteractionRangeDivided15Times3));
|
Assert.True(interactionSys.InRangeUnobstructed(origin, mapCoordinates, InteractionRangeDivided15Times3));
|
||||||
Assert.True(mapCoordinates.InRangeUnobstructed(origin, InteractionRangeDivided15Times3));
|
Assert.True(interactionSys.InRangeUnobstructed(mapCoordinates, origin, InteractionRangeDivided15Times3));
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.AI.Utility;
|
using Content.Server.AI.Utility;
|
||||||
using Content.Server.AI.WorldState.States.Inventory;
|
using Content.Server.AI.WorldState.States.Inventory;
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
@@ -54,7 +54,7 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
|
|
||||||
public override Outcome Execute(float frameTime)
|
public override Outcome Execute(float frameTime)
|
||||||
{
|
{
|
||||||
if (_target == default || !_owner.InRangeUnobstructed(_target, popup: true))
|
if (_target == default || !EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(_owner, _target, popup: true))
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.CombatMode;
|
using Content.Server.CombatMode;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -34,7 +35,9 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_owner.InRangeUnobstructed(_useTarget, popup: true))
|
var interactionSystem = EntitySystem.Get<InteractionSystem>();
|
||||||
|
|
||||||
|
if (!interactionSystem.InRangeUnobstructed(_owner, _useTarget, popup: true))
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
@@ -45,7 +48,6 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Click on da thing
|
// Click on da thing
|
||||||
var interactionSystem = EntitySystem.Get<InteractionSystem>();
|
|
||||||
interactionSystem.AiUseInteraction(_owner, targetTransform.Coordinates, _useTarget);
|
interactionSystem.AiUseInteraction(_owner, targetTransform.Coordinates, _useTarget);
|
||||||
|
|
||||||
return Outcome.Success;
|
return Outcome.Success;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.AI.Utility;
|
using Content.Server.AI.Utility;
|
||||||
using Content.Server.AI.WorldState.States.Inventory;
|
using Content.Server.AI.WorldState.States.Inventory;
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
@@ -30,7 +30,7 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
return Outcome.Success;
|
return Outcome.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_owner.InRangeUnobstructed(container, popup: true))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(_owner, container.Owner, popup: true))
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
@@ -27,7 +28,7 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
if (entMan.Deleted(_target)
|
if (entMan.Deleted(_target)
|
||||||
|| !entMan.HasComponent<SharedItemComponent>(_target)
|
|| !entMan.HasComponent<SharedItemComponent>(_target)
|
||||||
|| _target.IsInContainer()
|
|| _target.IsInContainer()
|
||||||
|| !_owner.InRangeUnobstructed(_target, popup: true))
|
|| !EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(_owner, _target, popup: true))
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Content.Server.AI.Pathfinding.Pathfinders;
|
|||||||
using Content.Server.CPUJob.JobQueues;
|
using Content.Server.CPUJob.JobQueues;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -28,6 +29,7 @@ namespace Content.Server.AI.Steering
|
|||||||
[Dependency] private readonly IPauseManager _pauseManager = default!;
|
[Dependency] private readonly IPauseManager _pauseManager = default!;
|
||||||
[Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
|
[Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
|
||||||
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether we try to avoid non-blocking physics objects
|
/// Whether we try to avoid non-blocking physics objects
|
||||||
@@ -283,7 +285,7 @@ namespace Content.Server.AI.Steering
|
|||||||
if (targetDistance <= steeringRequest.ArrivalDistance && steeringRequest.TimeUntilInteractionCheck <= 0.0f)
|
if (targetDistance <= steeringRequest.ArrivalDistance && steeringRequest.TimeUntilInteractionCheck <= 0.0f)
|
||||||
{
|
{
|
||||||
if (!steeringRequest.RequiresInRangeUnobstructed ||
|
if (!steeringRequest.RequiresInRangeUnobstructed ||
|
||||||
entity.InRangeUnobstructed(steeringRequest.TargetMap, steeringRequest.ArrivalDistance, popup: true))
|
_interactionSystem.InRangeUnobstructed(entity, steeringRequest.TargetMap, steeringRequest.ArrivalDistance, popup: true))
|
||||||
{
|
{
|
||||||
// TODO: Need cruder LOS checks for ranged weaps
|
// TODO: Need cruder LOS checks for ranged weaps
|
||||||
controller.VelocityDir = Vector2.Zero;
|
controller.VelocityDir = Vector2.Zero;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using Content.Shared.Actions.Components;
|
|||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.Cooldown;
|
using Content.Shared.Cooldown;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -56,7 +55,9 @@ namespace Content.Server.Actions.Actions
|
|||||||
if (attemptEvent.Cancelled)
|
if (attemptEvent.Cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!args.Performer.InRangeUnobstructed(args.Target)) return;
|
var sys = EntitySystem.Get<InteractionSystem>();
|
||||||
|
|
||||||
|
if (!sys.InRangeUnobstructed(args.Performer, args.Target)) return;
|
||||||
|
|
||||||
if (disarmedActs.Length == 0)
|
if (disarmedActs.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -66,7 +67,7 @@ namespace Content.Server.Actions.Actions
|
|||||||
var player = actor.PlayerSession;
|
var player = actor.PlayerSession;
|
||||||
var coordinates = entMan.GetComponent<TransformComponent>(args.Target).Coordinates;
|
var coordinates = entMan.GetComponent<TransformComponent>(args.Target).Coordinates;
|
||||||
var target = args.Target;
|
var target = args.Target;
|
||||||
EntitySystem.Get<InteractionSystem>().HandleUseInteraction(player, coordinates, target);
|
sys.HandleUseInteraction(player, coordinates, target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -252,9 +252,6 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
|||||||
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
|
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!args.User.InRangeUnobstructed(canister, SharedInteractionSystem.InteractionRange, popup: true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!hands.Drop(args.Used, container))
|
if (!hands.Drop(args.Used, container))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Pulling;
|
using Content.Server.Pulling;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Buckle.Components;
|
using Content.Shared.Buckle.Components;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Pulling.Components;
|
using Content.Shared.Pulling.Components;
|
||||||
@@ -14,14 +13,8 @@ using Content.Shared.Stunnable;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.Buckle.Components
|
namespace Content.Server.Buckle.Components
|
||||||
{
|
{
|
||||||
@@ -146,7 +139,7 @@ namespace Content.Server.Buckle.Components
|
|||||||
var strapUid = strap.Owner;
|
var strapUid = strap.Owner;
|
||||||
bool Ignored(EntityUid entity) => entity == Owner || entity == user || entity == strapUid;
|
bool Ignored(EntityUid entity) => entity == Owner || entity == user || entity == strapUid;
|
||||||
|
|
||||||
if (!Owner.InRangeUnobstructed(strapUid, Range, predicate: Ignored, popup: true))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(Owner, strapUid, Range, predicate: Ignored, popup: true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -288,7 +281,7 @@ namespace Content.Server.Buckle.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(oldBuckledTo.Owner, Range, popup: true))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(user, oldBuckledTo.Owner, Range, popup: true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
@@ -6,17 +5,10 @@ using Content.Shared.Body.Components;
|
|||||||
using Content.Shared.Body.Part;
|
using Content.Shared.Body.Part;
|
||||||
using Content.Shared.Climbing;
|
using Content.Shared.Climbing;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.Climbing.Components
|
namespace Content.Server.Climbing.Components
|
||||||
{
|
{
|
||||||
@@ -91,7 +83,7 @@ namespace Content.Server.Climbing.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(target, Range))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(user, target, Range))
|
||||||
{
|
{
|
||||||
reason = Loc.GetString("comp-climbable-cant-reach");
|
reason = Loc.GetString("comp-climbable-cant-reach");
|
||||||
return false;
|
return false;
|
||||||
@@ -135,8 +127,9 @@ namespace Content.Server.Climbing.Components
|
|||||||
|
|
||||||
bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged;
|
bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged;
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(target, Range, predicate: Ignored) ||
|
var sys = EntitySystem.Get<SharedInteractionSystem>();
|
||||||
!user.InRangeUnobstructed(dragged, Range, predicate: Ignored))
|
if (!sys.InRangeUnobstructed(user, target, Range, predicate: Ignored) ||
|
||||||
|
!sys.InRangeUnobstructed(user, dragged, Range, predicate: Ignored))
|
||||||
{
|
{
|
||||||
reason = Loc.GetString("comp-climbable-cant-reach");
|
reason = Loc.GetString("comp-climbable-cant-reach");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -11,15 +10,10 @@ using Content.Shared.Construction;
|
|||||||
using Content.Shared.Construction.Prototypes;
|
using Content.Shared.Construction.Prototypes;
|
||||||
using Content.Shared.Construction.Steps;
|
using Content.Shared.Construction.Steps;
|
||||||
using Content.Shared.Coordinates;
|
using Content.Shared.Coordinates;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Item;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
@@ -29,6 +23,8 @@ namespace Content.Server.Construction
|
|||||||
{
|
{
|
||||||
|
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
|
|
||||||
// --- WARNING! LEGACY CODE AHEAD! ---
|
// --- WARNING! LEGACY CODE AHEAD! ---
|
||||||
// This entire file contains the legacy code for initial construction.
|
// This entire file contains the legacy code for initial construction.
|
||||||
@@ -399,15 +395,23 @@ namespace Content.Server.Construction
|
|||||||
_beingBuilt[args.SenderSession].Remove(ev.Ack);
|
_beingBuilt[args.SenderSession].Remove(ev.Ack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Get<ActionBlockerSystem>().CanInteract(user, null)
|
if (!_actionBlocker.CanInteract(user, null)
|
||||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.GetActiveHandItem == null
|
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.GetActiveHandItem == null)
|
||||||
|| !user.InRangeUnobstructed(ev.Location, ignoreInsideBlocker:constructionPrototype.CanBuildInImpassable))
|
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pathFind == null)
|
var mapPos = ev.Location.ToMap(EntityManager);
|
||||||
|
var predicate = GetPredicate(constructionPrototype.CanBuildInImpassable, mapPos);
|
||||||
|
|
||||||
|
if (!_interactionSystem.InRangeUnobstructed(user, mapPos, predicate: predicate))
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathFind == null)
|
||||||
throw new InvalidDataException($"Can't find path from starting node to target node in construction! Recipe: {ev.PrototypeName}");
|
throw new InvalidDataException($"Can't find path from starting node to target node in construction! Recipe: {ev.PrototypeName}");
|
||||||
|
|
||||||
var edge = startNode.GetEdge(pathFind[0].Name);
|
var edge = startNode.GetEdge(pathFind[0].Name);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Server.DoAfter;
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Cuffs.Components;
|
using Content.Shared.Cuffs.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -96,7 +97,7 @@ namespace Content.Server.Cuffs.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handcuff.InRangeUnobstructed(Owner))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(handcuff, Owner))
|
||||||
{
|
{
|
||||||
Logger.Warning("Handcuffs being applied to player are obstructed or too far away! This should not happen!");
|
Logger.Warning("Handcuffs being applied to player are obstructed or too far away! This should not happen!");
|
||||||
return true;
|
return true;
|
||||||
@@ -210,7 +211,7 @@ namespace Content.Server.Cuffs.Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOwner && !user.InRangeUnobstructed(Owner))
|
if (!isOwner && !EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(user, Owner))
|
||||||
{
|
{
|
||||||
user.PopupMessage(Loc.GetString("cuffable-component-cannot-remove-cuffs-too-far-message"));
|
user.PopupMessage(Loc.GetString("cuffable-component-cannot-remove-cuffs-too-far-message"));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Engineering.Components;
|
using Content.Server.Engineering.Components;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
@@ -10,6 +11,8 @@ namespace Content.Server.Engineering.EntitySystems
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class DisassembleOnAltVerbSystem : EntitySystem
|
public sealed class DisassembleOnAltVerbSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -18,7 +21,7 @@ namespace Content.Server.Engineering.EntitySystems
|
|||||||
}
|
}
|
||||||
private void AddDisassembleVerb(EntityUid uid, DisassembleOnAltVerbComponent component, GetVerbsEvent<AlternativeVerb> args)
|
private void AddDisassembleVerb(EntityUid uid, DisassembleOnAltVerbComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
if (!args.CanInteract)
|
if (!args.CanInteract || !args.CanAccess)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AlternativeVerb verb = new()
|
AlternativeVerb verb = new()
|
||||||
@@ -39,8 +42,6 @@ namespace Content.Server.Engineering.EntitySystems
|
|||||||
return;
|
return;
|
||||||
if (string.IsNullOrEmpty(component.Prototype))
|
if (string.IsNullOrEmpty(component.Prototype))
|
||||||
return;
|
return;
|
||||||
if (!user.InRangeUnobstructed(target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (component.DoAfterTime > 0 && TryGet<DoAfterSystem>(out var doAfterSystem))
|
if (component.DoAfterTime > 0 && TryGet<DoAfterSystem>(out var doAfterSystem))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Content.Server.Engineering.EntitySystems
|
|||||||
|
|
||||||
bool IsTileClear()
|
bool IsTileClear()
|
||||||
{
|
{
|
||||||
return tileRef.Tile.IsEmpty == false && args.User.InRangeUnobstructed(args.ClickLocation, popup: true);
|
return tileRef.Tile.IsEmpty == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsTileClear())
|
if (!IsTileClear())
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Server.Explosion.Components;
|
|||||||
using Content.Shared.Acts;
|
using Content.Shared.Acts;
|
||||||
using Content.Shared.Camera;
|
using Content.Shared.Camera;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
@@ -27,6 +28,8 @@ namespace Content.Server.Explosion.EntitySystems
|
|||||||
{
|
{
|
||||||
public sealed class ExplosionSystem : EntitySystem
|
public sealed class ExplosionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Distance used for camera shake when distance from explosion is (0.0, 0.0).
|
/// Distance used for camera shake when distance from explosion is (0.0, 0.0).
|
||||||
/// Avoids getting NaN values down the line from doing math on (0.0, 0.0).
|
/// Avoids getting NaN values down the line from doing math on (0.0, 0.0).
|
||||||
@@ -174,7 +177,7 @@ namespace Content.Server.Explosion.EntitySystems
|
|||||||
var epicenterMapPos = epicenter.ToMap(EntityManager);
|
var epicenterMapPos = epicenter.ToMap(EntityManager);
|
||||||
foreach (var (entity, distance) in impassableEntities)
|
foreach (var (entity, distance) in impassableEntities)
|
||||||
{
|
{
|
||||||
if (!entity.InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: true, predicate: IgnoreExplosivePassable))
|
if (!_interactionSystem.InRangeUnobstructed(epicenterMapPos, entity, maxRange, predicate: IgnoreExplosivePassable))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -186,7 +189,7 @@ namespace Content.Server.Explosion.EntitySystems
|
|||||||
// there are probably more ExplosivePassable entities around
|
// there are probably more ExplosivePassable entities around
|
||||||
foreach (var (entity, distance) in nonImpassableEntities)
|
foreach (var (entity, distance) in nonImpassableEntities)
|
||||||
{
|
{
|
||||||
if (!entity.InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: true, predicate: IgnoreExplosivePassable))
|
if (!_interactionSystem.InRangeUnobstructed(epicenterMapPos, entity, maxRange, predicate: IgnoreExplosivePassable))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -235,7 +238,7 @@ namespace Content.Server.Explosion.EntitySystems
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tileLoc.ToMap(EntityManager).InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: false, predicate: IgnoreExplosivePassable))
|
if (!_interactionSystem.InRangeUnobstructed(tileLoc.ToMap(EntityManager), epicenterMapPos, maxRange, predicate: IgnoreExplosivePassable))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Content.Server.Flash
|
|||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly StunSystem _stunSystem = default!;
|
[Dependency] private readonly StunSystem _stunSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -153,7 +154,7 @@ namespace Content.Server.Flash
|
|||||||
foreach (var entity in flashableEntities)
|
foreach (var entity in flashableEntities)
|
||||||
{
|
{
|
||||||
// Check for unobstructed entities while ignoring the mobs with flashable components.
|
// Check for unobstructed entities while ignoring the mobs with flashable components.
|
||||||
if (!transform.InRangeUnobstructed(entity, range, CollisionGroup.Opaque, (e) => flashableEntities.Contains(e)))
|
if (!_interactionSystem.InRangeUnobstructed(entity, transform.MapPosition, range, CollisionGroup.Opaque, (e) => flashableEntities.Contains(e)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Flash(entity, user, source, duration, slowTo, displayPopup);
|
Flash(entity, user, source, duration, slowTo, displayPopup);
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace Content.Server.Fluids.Components
|
|||||||
_currentlyUsing.Remove(eventArgs.Using);
|
_currentlyUsing.Remove(eventArgs.Using);
|
||||||
|
|
||||||
if (result == DoAfterStatus.Cancelled || _entMan.Deleted(Owner) || mopComponent.Deleted ||
|
if (result == DoAfterStatus.Cancelled || _entMan.Deleted(Owner) || mopComponent.Deleted ||
|
||||||
CurrentVolume <= 0 || !Owner.InRangeUnobstructed(mopComponent.Owner))
|
CurrentVolume <= 0 || !EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(Owner, mopComponent.Owner))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//Checks if the mop is empty
|
//Checks if the mop is empty
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ namespace Content.Server.Interaction
|
|||||||
|
|
||||||
// must be in range of both the target and the object they are drag / dropping
|
// must be in range of both the target and the object they are drag / dropping
|
||||||
// Client also does this check but ya know we gotta validate it.
|
// Client also does this check but ya know we gotta validate it.
|
||||||
if (!interactionArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
|
if (!InRangeUnobstructed(interactionArgs.User, interactionArgs.Dragged, popup: true)
|
||||||
|
|| !InRangeUnobstructed(interactionArgs.User, interactionArgs.Target, popup: true))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// trigger dragdrops on the dropped entity
|
// trigger dragdrops on the dropped entity
|
||||||
@@ -311,7 +312,11 @@ namespace Content.Server.Interaction
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with body attack range when we get something like arm length or telekinesis or something.
|
// TODO: Replace with body attack range when we get something like arm length or telekinesis or something.
|
||||||
if (!user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true))
|
var unobstructed = (target == null)
|
||||||
|
? InRangeUnobstructed(user, coordinates)
|
||||||
|
: InRangeUnobstructed(user, target.Value);
|
||||||
|
|
||||||
|
if (!unobstructed)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
@@ -125,7 +125,6 @@ namespace Content.Server.MachineLinking.System
|
|||||||
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
||||||
!hands.TryGetActiveHeldEntity(out var heldEntity) ||
|
!hands.TryGetActiveHeldEntity(out var heldEntity) ||
|
||||||
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent) ||
|
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent) ||
|
||||||
!_interaction.InRangeUnobstructed(attached, component.Owner, ignoreInsideBlocker: true) ||
|
|
||||||
!signalLinkerComponent.Port.HasValue ||
|
!signalLinkerComponent.Port.HasValue ||
|
||||||
!signalLinkerComponent.Port.Value.transmitter.Outputs.ContainsPort(signalLinkerComponent.Port
|
!signalLinkerComponent.Port.Value.transmitter.Outputs.ContainsPort(signalLinkerComponent.Port
|
||||||
.Value.port) || !component.Inputs.ContainsPort(portSelected.Port))
|
.Value.port) || !component.Inputs.ContainsPort(portSelected.Port))
|
||||||
@@ -167,8 +166,7 @@ namespace Content.Server.MachineLinking.System
|
|||||||
if (msg.Session.AttachedEntity == default ||
|
if (msg.Session.AttachedEntity == default ||
|
||||||
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
||||||
!hands.TryGetActiveHeldEntity(out var heldEntity) ||
|
!hands.TryGetActiveHeldEntity(out var heldEntity) ||
|
||||||
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent) ||
|
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent))
|
||||||
!_interaction.InRangeUnobstructed(attached, component.Owner, ignoreInsideBlocker: true))
|
|
||||||
return;
|
return;
|
||||||
LinkerSaveInteraction(attached, signalLinkerComponent, component,
|
LinkerSaveInteraction(attached, signalLinkerComponent, component,
|
||||||
portSelected.Port);
|
portSelected.Port);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public sealed class HealingSystem : EntitySystem
|
|||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||||
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly StackSystem _stacks = default!;
|
[Dependency] private readonly StackSystem _stacks = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -87,7 +88,7 @@ public sealed class HealingSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (user != target &&
|
if (user != target &&
|
||||||
!user.InRangeUnobstructed(target, ignoreInsideBlocker: true, popup: true))
|
!_interactionSystem.InRangeUnobstructed(user, target, popup: true))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace Content.Server.Morgue.Components
|
|||||||
|
|
||||||
public override bool CanOpen(EntityUid user, bool silent = false)
|
public override bool CanOpen(EntityUid user, bool silent = false)
|
||||||
{
|
{
|
||||||
if (!Owner.InRangeUnobstructed(
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(Owner,
|
||||||
_entMan.GetComponent<TransformComponent>(Owner).Coordinates.Offset(_entMan.GetComponent<TransformComponent>(Owner).LocalRotation.GetCardinalDir()),
|
_entMan.GetComponent<TransformComponent>(Owner).Coordinates.Offset(_entMan.GetComponent<TransformComponent>(Owner).LocalRotation.GetCardinalDir()),
|
||||||
collisionMask: CollisionGroup.Impassable | CollisionGroup.VaultImpassable
|
collisionMask: CollisionGroup.Impassable | CollisionGroup.VaultImpassable
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
||||||
[Dependency] private readonly SpillableSystem _spillableSystem = default!;
|
[Dependency] private readonly SpillableSystem _spillableSystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -212,7 +213,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (_foodSystem.IsMouthBlocked(target, user))
|
if (_foodSystem.IsMouthBlocked(target, user))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(drink.Owner, popup: true))
|
if (!_interactionSystem.InRangeUnobstructed(user, drink.Owner, popup: true))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var forceDrink = user != target;
|
var forceDrink = user != target;
|
||||||
|
|||||||
@@ -14,13 +14,9 @@ using Content.Shared.Chemistry.Reagent;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
@@ -41,6 +37,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -111,7 +108,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
if (!TryGetRequiredUtensils(user, food, out var utensils))
|
if (!TryGetRequiredUtensils(user, food, out var utensils))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(food.Owner, popup: true))
|
if (!_interactionSystem.InRangeUnobstructed(user, food.Owner, popup: true))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var forceFeed = user != target;
|
var forceFeed = user != target;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly FoodSystem _foodSystem = default!;
|
[Dependency] private readonly FoodSystem _foodSystem = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -51,7 +52,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(target, popup: true))
|
if (!_interactionSystem.InRangeUnobstructed(user, target, popup: true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return _foodSystem.TryFeed(user, target, food);
|
return _foodSystem.TryFeed(user, target, food);
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ namespace Content.Server.RCD.Systems
|
|||||||
|
|
||||||
var coordinates = mapGrid.ToCoordinates(tile.GridIndices);
|
var coordinates = mapGrid.ToCoordinates(tile.GridIndices);
|
||||||
if (coordinates == EntityCoordinates.Invalid ||
|
if (coordinates == EntityCoordinates.Invalid ||
|
||||||
!_interactionSystem.InRangeUnobstructed(eventArgs.User, coordinates, ignoreInsideBlocker: true, popup: true))
|
!_interactionSystem.InRangeUnobstructed(eventArgs.User, coordinates, popup: true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace Content.Server.Radio.Components
|
|||||||
public bool CanListen(string message, EntityUid source)
|
public bool CanListen(string message, EntityUid source)
|
||||||
{
|
{
|
||||||
return RadioOn &&
|
return RadioOn &&
|
||||||
Owner.InRangeUnobstructed(IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(source).Coordinates, range: ListenRange);
|
EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(Owner, source, range: ListenRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(string message, int channel, EntityUid speaker)
|
public void Receive(string message, int channel, EntityUid speaker)
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ namespace Content.Server.Storage.Components
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.InRangeUnobstructed(Owner, popup: true))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(player, Owner, popup: true))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Content.Server.Tools;
|
|||||||
|
|
||||||
public sealed partial class ToolSystem
|
public sealed partial class ToolSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
private void InitializeTilePrying()
|
private void InitializeTilePrying()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<TilePryingComponent, AfterInteractEvent>(OnTilePryingAfterInteract);
|
SubscribeLocalEvent<TilePryingComponent, AfterInteractEvent>(OnTilePryingAfterInteract);
|
||||||
@@ -50,7 +52,7 @@ public sealed partial class ToolSystem
|
|||||||
|
|
||||||
var coordinates = mapGrid.GridTileToLocal(tile.GridIndices);
|
var coordinates = mapGrid.GridTileToLocal(tile.GridIndices);
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(coordinates, popup: false))
|
if (!_interactionSystem.InRangeUnobstructed(user, coordinates, popup: false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
|
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ namespace Content.Server.WireHacking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(Owner))
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(user, Owner))
|
||||||
{
|
{
|
||||||
Owner.PopupMessage(user, Loc.GetString("wires-component-ui-on-receive-message-cannot-reach"));
|
Owner.PopupMessage(user, Loc.GetString("wires-component-ui-on-receive-message-cannot-reach"));
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
|
||||||
using Content.Shared.ActionBlocker;
|
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
|
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
|
||||||
|
|
||||||
@@ -21,8 +17,6 @@ public sealed class ArtifactInteractionTriggerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
if (!args.InRangeUnobstructed())
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Handled = _artifactSystem.TryActivateArtifact(uid, args.User);
|
args.Handled = _artifactSystem.TryActivateArtifact(uid, args.User);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
@@ -34,7 +35,7 @@ namespace Content.Shared.Buckle.Components
|
|||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(eventArgs.Dragged, out SharedBuckleComponent? buckleComponent)) return false;
|
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(eventArgs.Dragged, out SharedBuckleComponent? buckleComponent)) return false;
|
||||||
bool Ignored(EntityUid entity) => entity == eventArgs.User || entity == eventArgs.Dragged || entity == eventArgs.Target;
|
bool Ignored(EntityUid entity) => entity == eventArgs.User || entity == eventArgs.Dragged || entity == eventArgs.Target;
|
||||||
|
|
||||||
return eventArgs.Target.InRangeUnobstructed(eventArgs.Dragged, buckleComponent.Range, predicate: Ignored);
|
return EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.Target, eventArgs.Dragged, buckleComponent.Range, predicate: Ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract bool DragDropOn(DragDropEvent eventArgs);
|
public abstract bool DragDropOn(DragDropEvent eventArgs);
|
||||||
|
|||||||
@@ -1,13 +1,29 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
using static Content.Shared.Interaction.SharedInteractionSystem;
|
||||||
|
|
||||||
namespace Content.Shared.Construction
|
namespace Content.Shared.Construction
|
||||||
{
|
{
|
||||||
public abstract class SharedConstructionSystem : EntitySystem
|
public abstract class SharedConstructionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get predicate for construction obstruction checks.
|
||||||
|
/// </summary>
|
||||||
|
public Ignored? GetPredicate(bool canBuildInImpassable, MapCoordinates coords)
|
||||||
|
{
|
||||||
|
if (!canBuildInImpassable)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!_mapManager.TryFindGridAt(coords, out var grid))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var ignored = grid.GetAnchoredEntities(coords).ToHashSet();
|
||||||
|
return e => ignored.Contains(e);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sent client -> server to to tell the server that we started building
|
/// Sent client -> server to to tell the server that we started building
|
||||||
/// a structure-construction.
|
/// a structure-construction.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ namespace Content.Shared.Examine
|
|||||||
if (EntityManager.TryGetComponent(examiner, out MobStateComponent mobState) && mobState.IsIncapacitated())
|
if (EntityManager.TryGetComponent(examiner, out MobStateComponent mobState) && mobState.IsIncapacitated())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_interactionSystem.InRangeUnobstructed(examiner, entity, ExamineDetailsRange, ignoreInsideBlocker: true))
|
if (!_interactionSystem.InRangeUnobstructed(examiner, entity, ExamineDetailsRange))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Is the target hidden in a opaque locker or something? Currently this check allows players to examine
|
// Is the target hidden in a opaque locker or something? Currently this check allows players to examine
|
||||||
|
|||||||
@@ -387,7 +387,8 @@ namespace Content.Shared.Hands.Components
|
|||||||
target = new MapCoordinates(origin.Position + dropVector, target.MapId);
|
target = new MapCoordinates(origin.Position + dropVector, target.MapId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dropLength = EntitySystem.Get<SharedInteractionSystem>().UnobstructedDistance(origin, target, ignoredEnt: Owner);
|
|
||||||
|
var dropLength = EntitySystem.Get<SharedInteractionSystem>().UnobstructedDistance(origin, target, predicate: e => e == Owner);
|
||||||
|
|
||||||
if (dropLength < requestedDropDistance)
|
if (dropLength < requestedDropDistance)
|
||||||
return origin.Position + dropVector.Normalized * dropLength;
|
return origin.Position + dropVector.Normalized * dropLength;
|
||||||
|
|||||||
@@ -1,431 +0,0 @@
|
|||||||
using Content.Shared.DragDrop;
|
|
||||||
using Content.Shared.Physics;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using static Content.Shared.Interaction.SharedInteractionSystem;
|
|
||||||
|
|
||||||
namespace Content.Shared.Interaction.Helpers
|
|
||||||
{
|
|
||||||
// TODO: Kill these with fire.
|
|
||||||
public static class SharedUnobstructedExtensions
|
|
||||||
{
|
|
||||||
private static SharedInteractionSystem SharedInteractionSystem => EntitySystem.Get<SharedInteractionSystem>();
|
|
||||||
|
|
||||||
#region Entities
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityUid origin,
|
|
||||||
EntityUid other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false,
|
|
||||||
IEntityManager? entityManager = null)
|
|
||||||
{
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, other, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityUid origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityUid origin,
|
|
||||||
IContainer other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var otherEntity = other.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, otherEntity, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityUid origin,
|
|
||||||
EntityCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityUid origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Components
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IComponent origin,
|
|
||||||
EntityUid other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IComponent origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IComponent origin,
|
|
||||||
IContainer other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
var otherEntity = other.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, otherEntity, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IComponent origin,
|
|
||||||
EntityCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IComponent origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Containers
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IContainer origin,
|
|
||||||
EntityUid other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IContainer origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IContainer origin,
|
|
||||||
IContainer other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
var otherEntity = other.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, otherEntity, range, collisionMask,
|
|
||||||
predicate, ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IContainer origin,
|
|
||||||
EntityCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this IContainer origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var originEntity = origin.Owner;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originEntity, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region EntityCoordinates
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityCoordinates origin,
|
|
||||||
EntityUid other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var originPosition = origin.ToMap(IoCManager.Resolve<IEntityManager>());
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other).MapPosition;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originPosition, otherPosition, range, collisionMask,
|
|
||||||
predicate, ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityCoordinates origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var originPosition = origin.ToMap(IoCManager.Resolve<IEntityManager>());
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other.Owner).MapPosition;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originPosition, otherPosition, range, collisionMask,
|
|
||||||
predicate, ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityCoordinates origin,
|
|
||||||
IContainer other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var originPosition = origin.ToMap(IoCManager.Resolve<IEntityManager>());
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other.Owner).MapPosition;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originPosition, otherPosition, range, collisionMask,
|
|
||||||
predicate, ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityCoordinates origin,
|
|
||||||
EntityCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
IEntityManager? entityManager = null)
|
|
||||||
{
|
|
||||||
entityManager ??= IoCManager.Resolve<IEntityManager>();
|
|
||||||
|
|
||||||
var originPosition = origin.ToMap(entityManager);
|
|
||||||
var otherPosition = other.ToMap(entityManager);
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originPosition, otherPosition, range, collisionMask,
|
|
||||||
predicate, ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this EntityCoordinates origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
IEntityManager? entityManager = null)
|
|
||||||
{
|
|
||||||
entityManager ??= IoCManager.Resolve<IEntityManager>();
|
|
||||||
|
|
||||||
var originPosition = origin.ToMap(entityManager);
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(originPosition, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region MapCoordinates
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this MapCoordinates origin,
|
|
||||||
EntityUid other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other).MapPosition;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, otherPosition, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this MapCoordinates origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other.Owner).MapPosition;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, otherPosition, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this MapCoordinates origin,
|
|
||||||
IContainer other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
var otherPosition = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(other.Owner).MapPosition;
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, otherPosition, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this MapCoordinates origin,
|
|
||||||
EntityCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
IEntityManager? entityManager = null)
|
|
||||||
{
|
|
||||||
entityManager ??= IoCManager.Resolve<IEntityManager>();
|
|
||||||
|
|
||||||
var otherPosition = other.ToMap(entityManager);
|
|
||||||
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, otherPosition, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this MapCoordinates origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(origin, other, range, collisionMask, predicate,
|
|
||||||
ignoreInsideBlocker);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region EventArgs
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this ITargetedInteractEventArgs args,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
return SharedInteractionSystem.InRangeUnobstructed(args.User, args.Target, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region EntityEventArgs
|
|
||||||
public static bool InRangeUnobstructed(
|
|
||||||
this DragDropEvent args,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
|
||||||
var user = args.User;
|
|
||||||
var dropped = args.Dragged;
|
|
||||||
var target = args.Target;
|
|
||||||
|
|
||||||
if (!SharedInteractionSystem.InRangeUnobstructed(user, target, range, collisionMask, predicate, ignoreInsideBlocker, popup))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!SharedInteractionSystem.InRangeUnobstructed(user, dropped, range, collisionMask, predicate, ignoreInsideBlocker, popup))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ using Content.Shared.CombatMode;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
@@ -16,16 +15,13 @@ using Content.Shared.Timing;
|
|||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
using Content.Shared.Wall;
|
||||||
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
@@ -38,6 +34,7 @@ namespace Content.Shared.Interaction
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public abstract class SharedInteractionSystem : EntitySystem
|
public abstract class SharedInteractionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _sharedBroadphaseSystem = default!;
|
[Dependency] private readonly SharedPhysicsSystem _sharedBroadphaseSystem = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
|
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
|
||||||
@@ -87,7 +84,7 @@ namespace Content.Shared.Interaction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!InRangeUnobstructed(user, ev.Target, ignoreInsideBlocker: true))
|
if (!InRangeUnobstructed(user, ev.Target))
|
||||||
{
|
{
|
||||||
ev.Cancel();
|
ev.Cancel();
|
||||||
return;
|
return;
|
||||||
@@ -190,12 +187,9 @@ namespace Content.Shared.Interaction
|
|||||||
if (!TryComp(user, out SharedHandsComponent? hands) || !hands.TryGetActiveHand(out hand))
|
if (!TryComp(user, out SharedHandsComponent? hands) || !hands.TryGetActiveHand(out hand))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// ^ In future, things like looking at a UI & opening doors (i.e., Activate interactions) shouldn't neccesarily require hands.
|
var inRangeUnobstructed = target == null
|
||||||
// But that would first involve some work with BUIs & making sure other activate-interactions check hands if they are required.
|
? !checkAccess || InRangeUnobstructed(user, coordinates)
|
||||||
|
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
||||||
// Check range
|
|
||||||
// TODO: Replace with body interaction range when we get something like arm length or telekinesis or something.
|
|
||||||
var inRangeUnobstructed = !checkAccess || user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true);
|
|
||||||
|
|
||||||
// empty-hand interactions
|
// empty-hand interactions
|
||||||
if (hand.HeldEntity == null)
|
if (hand.HeldEntity == null)
|
||||||
@@ -289,30 +283,6 @@ namespace Content.Shared.Interaction
|
|||||||
return (rayResults[0].HitPos - origin.Position).Length;
|
return (rayResults[0].HitPos - origin.Position).Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Traces a ray from coords to otherCoords and returns the length
|
|
||||||
/// of the vector between coords and the ray's first hit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="origin">Set of coordinates to use.</param>
|
|
||||||
/// <param name="other">Other set of coordinates to use.</param>
|
|
||||||
/// <param name="collisionMask">The mask to check for collisions</param>
|
|
||||||
/// <param name="ignoredEnt">
|
|
||||||
/// The entity to be ignored when checking for collisions.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>Length of resulting ray.</returns>
|
|
||||||
public float UnobstructedDistance(
|
|
||||||
MapCoordinates origin,
|
|
||||||
MapCoordinates other,
|
|
||||||
int collisionMask = (int) CollisionGroup.Impassable,
|
|
||||||
EntityUid? ignoredEnt = null)
|
|
||||||
{
|
|
||||||
var predicate = ignoredEnt == null
|
|
||||||
? null
|
|
||||||
: (Ignored) (e => e == ignoredEnt);
|
|
||||||
|
|
||||||
return UnobstructedDistance(origin, other, collisionMask, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks that these coordinates are within a certain distance without any
|
/// Checks that these coordinates are within a certain distance without any
|
||||||
/// entity that matches the collision mask obstructing them.
|
/// entity that matches the collision mask obstructing them.
|
||||||
@@ -330,14 +300,6 @@ namespace Content.Shared.Interaction
|
|||||||
/// A predicate to check whether to ignore an entity or not.
|
/// A predicate to check whether to ignore an entity or not.
|
||||||
/// If it returns true, it will be ignored.
|
/// If it returns true, it will be ignored.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="ignoreInsideBlocker">
|
|
||||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
|
||||||
/// the obstruction, ignores the obstruction and considers the interaction
|
|
||||||
/// unobstructed.
|
|
||||||
/// Therefore, setting this to true makes this check more permissive,
|
|
||||||
/// such as allowing an interaction to occur inside something impassable
|
|
||||||
/// (like a wall). The default, false, makes the check more restrictive.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// True if the two points are within a given range without being obstructed.
|
/// True if the two points are within a given range without being obstructed.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
@@ -346,8 +308,7 @@ namespace Content.Shared.Interaction
|
|||||||
MapCoordinates other,
|
MapCoordinates other,
|
||||||
float range = InteractionRange,
|
float range = InteractionRange,
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||||
Ignored? predicate = null,
|
Ignored? predicate = null)
|
||||||
bool ignoreInsideBlocker = false)
|
|
||||||
{
|
{
|
||||||
// Have to be on same map regardless.
|
// Have to be on same map regardless.
|
||||||
if (other.MapId != origin.MapId) return false;
|
if (other.MapId != origin.MapId) return false;
|
||||||
@@ -371,29 +332,7 @@ namespace Content.Shared.Interaction
|
|||||||
var ray = new CollisionRay(origin.Position, dir.Normalized, (int) collisionMask);
|
var ray = new CollisionRay(origin.Position, dir.Normalized, (int) collisionMask);
|
||||||
var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, length, predicate.Invoke, false).ToList();
|
var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, length, predicate.Invoke, false).ToList();
|
||||||
|
|
||||||
if (rayResults.Count == 0) return true;
|
return rayResults.Count == 0;
|
||||||
|
|
||||||
// TODO: Wot? This should just be in the predicate.
|
|
||||||
if (!ignoreInsideBlocker) return false;
|
|
||||||
|
|
||||||
foreach (var result in rayResults)
|
|
||||||
{
|
|
||||||
if (!TryComp(result.HitEntity, out IPhysBody? p))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var bBox = p.GetWorldAABB();
|
|
||||||
|
|
||||||
if (bBox.Contains(other.Position))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -401,6 +340,8 @@ namespace Content.Shared.Interaction
|
|||||||
/// entity that matches the collision mask obstructing them.
|
/// entity that matches the collision mask obstructing them.
|
||||||
/// If the <paramref name="range"/> is zero or negative,
|
/// If the <paramref name="range"/> is zero or negative,
|
||||||
/// this method will only check if nothing obstructs the two entities.
|
/// this method will only check if nothing obstructs the two entities.
|
||||||
|
/// This function will also check whether the other entity is a wall-mounted entity. If it is, it will
|
||||||
|
/// automatically ignore some obstructions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="origin">The first entity to use.</param>
|
/// <param name="origin">The first entity to use.</param>
|
||||||
/// <param name="other">Other entity to use.</param>
|
/// <param name="other">Other entity to use.</param>
|
||||||
@@ -412,14 +353,6 @@ namespace Content.Shared.Interaction
|
|||||||
/// A predicate to check whether to ignore an entity or not.
|
/// A predicate to check whether to ignore an entity or not.
|
||||||
/// If it returns true, it will be ignored.
|
/// If it returns true, it will be ignored.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="ignoreInsideBlocker">
|
|
||||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
|
||||||
/// the obstruction, ignores the obstruction and considers the interaction
|
|
||||||
/// unobstructed.
|
|
||||||
/// Therefore, setting this to true makes this check more permissive,
|
|
||||||
/// such as allowing an interaction to occur inside something impassable
|
|
||||||
/// (like a wall). The default, false, makes the check more restrictive.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="popup">
|
/// <param name="popup">
|
||||||
/// Whether or not to popup a feedback message on the origin entity for
|
/// Whether or not to popup a feedback message on the origin entity for
|
||||||
/// it to see.
|
/// it to see.
|
||||||
@@ -433,55 +366,92 @@ namespace Content.Shared.Interaction
|
|||||||
float range = InteractionRange,
|
float range = InteractionRange,
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||||
Ignored? predicate = null,
|
Ignored? predicate = null,
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
bool popup = false)
|
||||||
{
|
{
|
||||||
predicate ??= e => e == origin || e == other;
|
var originPosition = Transform(origin).MapPosition;
|
||||||
return InRangeUnobstructed(origin, Transform(other).MapPosition, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
var transform = Transform(other);
|
||||||
|
var (position, rotation) = transform.GetWorldPositionRotation();
|
||||||
|
var mapPos = new MapCoordinates(position, transform.MapID);
|
||||||
|
var wallPredicate = AddAnchoredPredicate(other, mapPos, rotation, originPosition);
|
||||||
|
|
||||||
|
Ignored combinedPredicate = e =>
|
||||||
|
{
|
||||||
|
return e == origin
|
||||||
|
|| e == other
|
||||||
|
|| (predicate?.Invoke(e) ?? false)
|
||||||
|
|| (wallPredicate?.Invoke(e) ?? false);
|
||||||
|
};
|
||||||
|
|
||||||
|
var inRange = InRangeUnobstructed(origin, mapPos, range, collisionMask, combinedPredicate, popup);
|
||||||
|
|
||||||
|
if (!inRange && popup)
|
||||||
|
{
|
||||||
|
var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
|
||||||
|
_popupSystem.PopupEntity(message, origin, Filter.Entities(origin));
|
||||||
|
}
|
||||||
|
|
||||||
|
return inRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InRangeUnobstructed(
|
||||||
|
MapCoordinates origin,
|
||||||
|
EntityUid target,
|
||||||
|
float range = InteractionRange,
|
||||||
|
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||||
|
Ignored? predicate = null)
|
||||||
|
{
|
||||||
|
var transform = Transform(target);
|
||||||
|
var (position, rotation) = transform.GetWorldPositionRotation();
|
||||||
|
var mapPos = new MapCoordinates(position, transform.MapID);
|
||||||
|
|
||||||
|
var wallPredicate = AddAnchoredPredicate(target, mapPos, rotation, origin);
|
||||||
|
Ignored combinedPredicate = e =>
|
||||||
|
{
|
||||||
|
return e == target
|
||||||
|
|| (predicate?.Invoke(e) ?? false)
|
||||||
|
|| (wallPredicate?.Invoke(e) ?? false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return InRangeUnobstructed(origin, mapPos, range, collisionMask, combinedPredicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks that an entity and a component are within a certain
|
/// If the target entity is either an item or a wall-mounted object, this will add a predicate to ignore any
|
||||||
/// distance without any entity that matches the collision mask
|
/// anchored entities on that tile.
|
||||||
/// obstructing them.
|
|
||||||
/// If the <paramref name="range"/> is zero or negative,
|
|
||||||
/// this method will only check if nothing obstructs the entity and component.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="origin">The entity to use.</param>
|
public Ignored? AddAnchoredPredicate(
|
||||||
/// <param name="other">The component to use.</param>
|
EntityUid target,
|
||||||
/// <param name="range">
|
MapCoordinates targetPosition,
|
||||||
/// Maximum distance between the entity and component.
|
Angle targetRotation,
|
||||||
/// </param>
|
MapCoordinates origin)
|
||||||
/// <param name="collisionMask">The mask to check for collisions.</param>
|
|
||||||
/// <param name="predicate">
|
|
||||||
/// A predicate to check whether to ignore an entity or not.
|
|
||||||
/// If it returns true, it will be ignored.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="ignoreInsideBlocker">
|
|
||||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
|
||||||
/// the obstruction, ignores the obstruction and considers the interaction
|
|
||||||
/// unobstructed.
|
|
||||||
/// Therefore, setting this to true makes this check more permissive,
|
|
||||||
/// such as allowing an interaction to occur inside something impassable
|
|
||||||
/// (like a wall). The default, false, makes the check more restrictive.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="popup">
|
|
||||||
/// Whether or not to popup a feedback message on the origin entity for
|
|
||||||
/// it to see.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>
|
|
||||||
/// True if the two points are within a given range without being obstructed.
|
|
||||||
/// </returns>
|
|
||||||
public bool InRangeUnobstructed(
|
|
||||||
EntityUid origin,
|
|
||||||
IComponent other,
|
|
||||||
float range = InteractionRange,
|
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
|
||||||
Ignored? predicate = null,
|
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
|
||||||
{
|
{
|
||||||
return InRangeUnobstructed(origin, other.Owner, range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
if (!_mapManager.TryFindGridAt(targetPosition, out var grid))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (HasComp<SharedItemComponent>(target))
|
||||||
|
{
|
||||||
|
// Ignore anchored entities on that tile.
|
||||||
|
var colliding = new HashSet<EntityUid>(grid.GetAnchoredEntities(targetPosition));
|
||||||
|
return e => colliding.Contains(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryComp(target, out WallMountComponent? wallMount))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// wall-mount exemptions may be restricted to a specific angle range.
|
||||||
|
if (wallMount.Arc < 360)
|
||||||
|
{
|
||||||
|
var angle = Angle.FromWorldVec(origin.Position - targetPosition.Position);
|
||||||
|
var angleDelta = (wallMount.Direction + targetRotation - angle).Reduced().FlipPositive();
|
||||||
|
var inArc = angleDelta < wallMount.Arc / 2 || Math.Tau - angleDelta < wallMount.Arc / 2;
|
||||||
|
|
||||||
|
if (!inArc)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore anchored entities on that tile.
|
||||||
|
var ignored = new HashSet<EntityUid>(grid.GetAnchoredEntities(targetPosition));
|
||||||
|
return e => ignored.Contains(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -501,14 +471,6 @@ namespace Content.Shared.Interaction
|
|||||||
/// A predicate to check whether to ignore an entity or not.
|
/// A predicate to check whether to ignore an entity or not.
|
||||||
/// If it returns true, it will be ignored.
|
/// If it returns true, it will be ignored.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="ignoreInsideBlocker">
|
|
||||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
|
||||||
/// the obstruction, ignores the obstruction and considers the interaction
|
|
||||||
/// unobstructed.
|
|
||||||
/// Therefore, setting this to true makes this check more permissive,
|
|
||||||
/// such as allowing an interaction to occur inside something impassable
|
|
||||||
/// (like a wall). The default, false, makes the check more restrictive.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="popup">
|
/// <param name="popup">
|
||||||
/// Whether or not to popup a feedback message on the origin entity for
|
/// Whether or not to popup a feedback message on the origin entity for
|
||||||
/// it to see.
|
/// it to see.
|
||||||
@@ -522,10 +484,9 @@ namespace Content.Shared.Interaction
|
|||||||
float range = InteractionRange,
|
float range = InteractionRange,
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||||
Ignored? predicate = null,
|
Ignored? predicate = null,
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
bool popup = false)
|
||||||
{
|
{
|
||||||
return InRangeUnobstructed(origin, other.ToMap(EntityManager), range, collisionMask, predicate, ignoreInsideBlocker, popup);
|
return InRangeUnobstructed(origin, other.ToMap(EntityManager), range, collisionMask, predicate, popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -545,14 +506,6 @@ namespace Content.Shared.Interaction
|
|||||||
/// A predicate to check whether to ignore an entity or not.
|
/// A predicate to check whether to ignore an entity or not.
|
||||||
/// If it returns true, it will be ignored.
|
/// If it returns true, it will be ignored.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="ignoreInsideBlocker">
|
|
||||||
/// If true and <see cref="origin"/> or <see cref="other"/> are inside
|
|
||||||
/// the obstruction, ignores the obstruction and considers the interaction
|
|
||||||
/// unobstructed.
|
|
||||||
/// Therefore, setting this to true makes this check more permissive,
|
|
||||||
/// such as allowing an interaction to occur inside something impassable
|
|
||||||
/// (like a wall). The default, false, makes the check more restrictive.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="popup">
|
/// <param name="popup">
|
||||||
/// Whether or not to popup a feedback message on the origin entity for
|
/// Whether or not to popup a feedback message on the origin entity for
|
||||||
/// it to see.
|
/// it to see.
|
||||||
@@ -566,18 +519,16 @@ namespace Content.Shared.Interaction
|
|||||||
float range = InteractionRange,
|
float range = InteractionRange,
|
||||||
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
CollisionGroup collisionMask = CollisionGroup.Impassable,
|
||||||
Ignored? predicate = null,
|
Ignored? predicate = null,
|
||||||
bool ignoreInsideBlocker = false,
|
|
||||||
bool popup = false)
|
bool popup = false)
|
||||||
{
|
{
|
||||||
|
Ignored combinedPredicatre = e => e == origin || (predicate?.Invoke(e) ?? false);
|
||||||
var originPosition = Transform(origin).MapPosition;
|
var originPosition = Transform(origin).MapPosition;
|
||||||
predicate ??= e => e == origin;
|
var inRange = InRangeUnobstructed(originPosition, other, range, collisionMask, combinedPredicatre);
|
||||||
|
|
||||||
var inRange = InRangeUnobstructed(originPosition, other, range, collisionMask, predicate, ignoreInsideBlocker);
|
|
||||||
|
|
||||||
if (!inRange && popup)
|
if (!inRange && popup)
|
||||||
{
|
{
|
||||||
var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
|
var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
|
||||||
origin.PopupMessage(message);
|
_popupSystem.PopupEntity(message, origin, Filter.Entities(origin));
|
||||||
}
|
}
|
||||||
|
|
||||||
return inRange;
|
return inRange;
|
||||||
@@ -690,9 +641,7 @@ namespace Content.Shared.Interaction
|
|||||||
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (checkAccess && !InRangeUnobstructed(user, used, popup: true))
|
||||||
// all activates should only fire when in range / unobstructed
|
|
||||||
if (checkAccess && !InRangeUnobstructed(user, used, ignoreInsideBlocker: true, popup: true))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
|
// Check if interacted entity is in the same container, the direct child, or direct parent of the user.
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ public abstract partial class InventorySystem
|
|||||||
public bool CanAccess(EntityUid actor, EntityUid target, EntityUid itemUid)
|
public bool CanAccess(EntityUid actor, EntityUid target, EntityUid itemUid)
|
||||||
{
|
{
|
||||||
// Can the actor reach the target?
|
// Can the actor reach the target?
|
||||||
if (actor != target && !( actor.InRangeUnobstructed(target) && _containerSystem.IsInSameOrParentContainer(actor, target)))
|
if (actor != target && !(_interactionSystem.InRangeUnobstructed(actor, target) && _containerSystem.IsInSameOrParentContainer(actor, target)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Can the actor reach the item?
|
// Can the actor reach the item?
|
||||||
|
|||||||
@@ -101,9 +101,6 @@ namespace Content.Shared.Item
|
|||||||
{
|
{
|
||||||
var user = eventArgs.User;
|
var user = eventArgs.User;
|
||||||
|
|
||||||
if (!user.InRangeUnobstructed(Owner, ignoreInsideBlocker: true))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!_entMan.TryGetComponent(user, out SharedHandsComponent hands))
|
if (!_entMan.TryGetComponent(user, out SharedHandsComponent hands))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
using System;
|
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Ghost;
|
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.MobState.Components;
|
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
@@ -15,6 +10,7 @@ namespace Content.Shared.Tabletop
|
|||||||
public abstract class SharedTabletopSystem : EntitySystem
|
public abstract class SharedTabletopSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] protected readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] protected readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class TabletopDraggableComponentState : ComponentState
|
public sealed class TabletopDraggableComponentState : ComponentState
|
||||||
@@ -49,7 +45,7 @@ namespace Content.Shared.Tabletop
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return playerEntity.InRangeUnobstructed(table.Value) && _actionBlockerSystem.CanInteract(playerEntity, table);
|
return _interactionSystem.InRangeUnobstructed(playerEntity, table.Value) && _actionBlockerSystem.CanInteract(playerEntity, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool StunnedOrNoHands(EntityUid playerEntity)
|
protected bool StunnedOrNoHands(EntityUid playerEntity)
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ namespace Content.Shared.Verbs
|
|||||||
bool canAccess = false;
|
bool canAccess = false;
|
||||||
if (force || target == user)
|
if (force || target == user)
|
||||||
canAccess = true;
|
canAccess = true;
|
||||||
else if (EntityManager.EntityExists(target) && _interactionSystem.InRangeUnobstructed(user, target, ignoreInsideBlocker: true))
|
else if (EntityManager.EntityExists(target) && _interactionSystem.InRangeUnobstructed(user, target))
|
||||||
{
|
{
|
||||||
if (ContainerSystem.IsInSameOrParentContainer(user, target))
|
if (ContainerSystem.IsInSameOrParentContainer(user, target))
|
||||||
canAccess = true;
|
canAccess = true;
|
||||||
|
|||||||
26
Content.Shared/Wall/WallMountComponent.cs
Normal file
26
Content.Shared/Wall/WallMountComponent.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace Content.Shared.Wall;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component enables an entity to ignore some obstructions for interaction checks.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This will only exempt anchored entities that intersect the wall-mount. Additionally, this exemption will apply
|
||||||
|
/// in a limited arc, providing basic functionality for directional wall mounts.
|
||||||
|
/// </remarks>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class WallMountComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Range of angles in which the exemption applies. Bigger is more permissive.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("arc")]
|
||||||
|
public float Arc = MathF.PI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The direction in which the exemption arc is facing, relative to the entity's rotation. Defaults to south.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("direction")]
|
||||||
|
public Angle Direction = Angle.Zero;
|
||||||
|
}
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Power/wall_recharger.rsi
|
sprite: Structures/Power/wall_recharger.rsi
|
||||||
state: empty
|
state: empty
|
||||||
|
- type: WallMount
|
||||||
- type: Charger
|
- type: Charger
|
||||||
transferEfficiency: 0.95
|
transferEfficiency: 0.95
|
||||||
chargerSlot:
|
chargerSlot:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
parent: BaseAPC
|
parent: BaseAPC
|
||||||
id: SalternAPC
|
id: SalternAPC
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: Battery
|
- type: Battery
|
||||||
maxCharge: 12000
|
maxCharge: 12000
|
||||||
startingCharge: 2000
|
startingCharge: 2000
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
id: PlaqueAtmos
|
id: PlaqueAtmos
|
||||||
name: atmos plaque
|
name: atmos plaque
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: Physics
|
- type: Physics
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
parent: BaseStructure
|
parent: BaseStructure
|
||||||
name: bar sign
|
name: bar sign
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: Physics
|
- type: Physics
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
placement:
|
placement:
|
||||||
mode: SnapgridCenter
|
mode: SnapgridCenter
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Rotatable
|
- type: Rotatable
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
id: PosterBase
|
id: PosterBase
|
||||||
abstract: true
|
abstract: true
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
drawdepth: WallTops
|
drawdepth: WallTops
|
||||||
sprite: Structures/Wallmounts/posters.rsi
|
sprite: Structures/Wallmounts/posters.rsi
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
name: air alarm
|
name: air alarm
|
||||||
description: An air alarm. Alarms... air?
|
description: An air alarm. Alarms... air?
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: DeviceNetworkComponent
|
- type: DeviceNetworkComponent
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
name: extinguisher cabinet
|
name: extinguisher cabinet
|
||||||
description: A small wall mounted cabinet designed to hold a fire extinguisher.
|
description: A small wall mounted cabinet designed to hold a fire extinguisher.
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360
|
||||||
- type: Transform
|
- type: Transform
|
||||||
anchored: true
|
anchored: true
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
name: fire alarm
|
name: fire alarm
|
||||||
description: A fire alarm. Spicy!
|
description: A fire alarm. Spicy!
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: DeviceNetworkComponent
|
- type: DeviceNetworkComponent
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
name: fire axe cabinet
|
name: fire axe cabinet
|
||||||
description: There is a small label that reads \"For Emergency use only\" along with details for safe use of the axe. As if.
|
description: There is a small label that reads \"For Emergency use only\" along with details for safe use of the axe. As if.
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
name: mirror
|
name: mirror
|
||||||
description: 'Mirror mirror on the wall , who''s the most robust of them all?'
|
description: 'Mirror mirror on the wall , who''s the most robust of them all?'
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Wallmounts/mirror.rsi
|
sprite: Structures/Wallmounts/mirror.rsi
|
||||||
state: mirror
|
state: mirror
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
name: "signal switch"
|
name: "signal switch"
|
||||||
description: "Its a switch for toggling power to things."
|
description: "Its a switch for toggling power to things."
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Physics
|
- type: Physics
|
||||||
@@ -30,6 +32,8 @@
|
|||||||
name: "signal button"
|
name: "signal button"
|
||||||
description: "It's a button for activating something."
|
description: "It's a button for activating something."
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Physics
|
- type: Physics
|
||||||
@@ -51,6 +55,8 @@
|
|||||||
name: apc net switch
|
name: apc net switch
|
||||||
description: Its a switch for toggling lights that are connected to the same apc.
|
description: Its a switch for toggling lights that are connected to the same apc.
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Physics
|
- type: Physics
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
snap:
|
snap:
|
||||||
- Window
|
- Window
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360 # interact despite grilles
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- RCDDeconstructWhitelist
|
- RCDDeconstructWhitelist
|
||||||
@@ -92,6 +94,8 @@
|
|||||||
snap:
|
snap:
|
||||||
- Window
|
- Window
|
||||||
components:
|
components:
|
||||||
|
- type: WallMount
|
||||||
|
arc: 360 # interact despite grilles
|
||||||
# Attention! If adding tags here:
|
# Attention! If adding tags here:
|
||||||
# Keep WindowTintedDirectional in mind
|
# Keep WindowTintedDirectional in mind
|
||||||
- type: Tag
|
- type: Tag
|
||||||
|
|||||||
Reference in New Issue
Block a user