diff --git a/Content.Client/GameObjects/EntitySystems/VerbSystem.cs b/Content.Client/GameObjects/EntitySystems/VerbSystem.cs index fb9c2c441d..7f26504431 100644 --- a/Content.Client/GameObjects/EntitySystems/VerbSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/VerbSystem.cs @@ -7,13 +7,16 @@ using Content.Client.State; using Content.Client.UserInterface; using Content.Client.Utility; using Content.Shared.GameObjects.EntitySystemMessages; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.Verbs; using Content.Shared.Input; +using Content.Shared.Physics; using JetBrains.Annotations; using Robust.Client.GameObjects.EntitySystems; using Robust.Client.Graphics; using Robust.Client.Graphics.Drawing; using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Client.Interfaces.Graphics.ClientEye; using Robust.Client.Interfaces.Input; using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.Interfaces.State; @@ -29,6 +32,7 @@ using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Physics; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -40,7 +44,7 @@ using Timer = Robust.Shared.Timers.Timer; namespace Content.Client.GameObjects.EntitySystems { [UsedImplicitly] - public sealed class VerbSystem : EntitySystem + public sealed class VerbSystem : SharedVerbSystem { [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; @@ -63,7 +67,7 @@ namespace Content.Client.GameObjects.EntitySystems public override void Initialize() { base.Initialize(); - + SubscribeNetworkEvent(FillEntityPopup); IoCManager.InjectDependencies(this); @@ -114,12 +118,11 @@ namespace Content.Client.GameObjects.EntitySystems { return false; } - + var mapCoordinates = args.Coordinates.ToMap(_mapManager); - var entities = _entityManager.GetEntitiesIntersecting(mapCoordinates.MapId, - Box2.CenteredAround(mapCoordinates.Position, (0.5f, 0.5f))).ToList(); - - if (entities.Count == 0) + var playerEntity = _playerManager.LocalPlayer?.ControlledEntity; + + if (playerEntity == null || !TryGetContextEntities(playerEntity, mapCoordinates, out var entities)) { return false; } diff --git a/Content.Server/GameObjects/EntitySystems/VerbSystem.cs b/Content.Server/GameObjects/EntitySystems/VerbSystem.cs index 6b625cdf25..c48909ad1d 100644 --- a/Content.Server/GameObjects/EntitySystems/VerbSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/VerbSystem.cs @@ -12,7 +12,7 @@ using static Content.Shared.GameObjects.EntitySystemMessages.VerbSystemMessages; namespace Content.Server.GameObjects.EntitySystems { - public class VerbSystem : EntitySystem + public class VerbSystem : SharedVerbSystem { [Dependency] private readonly IEntityManager _entityManager = default!; @@ -93,6 +93,11 @@ namespace Content.Server.GameObjects.EntitySystems return; } + if (!TryGetContextEntities(userEntity, entity.Transform.MapPosition, out var entities, true) || !entities.Contains(entity)) + { + return; + } + var data = new List(); //Get verbs, component dependent. foreach (var (component, verb) in VerbUtility.GetVerbs(entity)) diff --git a/Content.Shared/GameObjects/Verbs/SharedVerbSystem.cs b/Content.Shared/GameObjects/Verbs/SharedVerbSystem.cs new file mode 100644 index 0000000000..51714a1198 --- /dev/null +++ b/Content.Shared/GameObjects/Verbs/SharedVerbSystem.cs @@ -0,0 +1,71 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Physics; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Maths; + +namespace Content.Shared.GameObjects.Verbs +{ + public class SharedVerbSystem : EntitySystem + { + private SharedInteractionSystem _interactionSystem = null!; + + public override void Initialize() + { + base.Initialize(); + _interactionSystem = Get(); + } + + /// + /// Get all of the entities relevant for the contextmenu + /// + /// + /// + /// + /// Whether we should slightly extend out the ignored range for the ray predicated + /// + protected bool TryGetContextEntities(IEntity player, MapCoordinates targetPos, [NotNullWhen(true)] out List? contextEntities, bool buffer = false) + { + contextEntities = null; + var length = buffer ? 1.0f: 0.5f; + + var entities = EntityManager.GetEntitiesIntersecting(targetPos.MapId, + Box2.CenteredAround(targetPos.Position, (length, length))).ToList(); + + if (entities.Count == 0) + { + return false; + } + + // Check if we have LOS to the clicked-location, otherwise no popup. + var vectorDiff = player.Transform.MapPosition.Position - targetPos.Position; + var distance = vectorDiff.Length + 0.01f; + Func ignored = entity => entities.Contains(entity) || + entity == player || + !entity.TryGetComponent(out OccluderComponent? occluder) || + !occluder.Enabled; + + var result = _interactionSystem.InRangeUnobstructed( + player.Transform.MapPosition, + targetPos, + distance, + (int) CollisionGroup.Opaque, + ignored); + + if (!result) + { + return false; + } + + contextEntities = entities; + return true; + } + } +} \ No newline at end of file