diff --git a/Content.Client/Clickable/ClickableComponent.cs b/Content.Client/Clickable/ClickableComponent.cs
index 080fa89b2b..44734ce92f 100644
--- a/Content.Client/Clickable/ClickableComponent.cs
+++ b/Content.Client/Clickable/ClickableComponent.cs
@@ -21,9 +21,9 @@ namespace Content.Client.Clickable
/// The draw depth for the sprite that captured the click.
///
/// True if the click worked, false otherwise.
- public bool CheckClick(SpriteComponent sprite, EntityQuery xformQuery, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom)
+ public bool CheckClick(SpriteComponent sprite, TransformComponent transform, EntityQuery xformQuery, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom)
{
- if (!sprite.Visible || !xformQuery.TryGetComponent(sprite.Owner, out var transform))
+ if (!sprite.Visible)
{
drawDepth = default;
renderOrder = default;
diff --git a/Content.Client/DragDrop/DragDropSystem.cs b/Content.Client/DragDrop/DragDropSystem.cs
index 488fc87eb6..1e12d53ba5 100644
--- a/Content.Client/DragDrop/DragDropSystem.cs
+++ b/Content.Client/DragDrop/DragDropSystem.cs
@@ -20,6 +20,7 @@ using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
+using System.Linq;
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
namespace Content.Client.DragDrop
@@ -306,7 +307,7 @@ namespace Content.Client.DragDrop
if (_stateManager.CurrentState is GameplayState screen)
{
- entities = screen.GetEntitiesUnderPosition(args.Coordinates);
+ entities = screen.GetClickableEntities(args.Coordinates).ToList();
}
else
{
diff --git a/Content.Client/Gameplay/GameplayStateBase.cs b/Content.Client/Gameplay/GameplayStateBase.cs
index 727eb2b299..e1ca614f91 100644
--- a/Content.Client/Gameplay/GameplayStateBase.cs
+++ b/Content.Client/Gameplay/GameplayStateBase.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Content.Client.Clickable;
using Content.Client.ContextMenu.UI;
+using Robust.Client.ComponentTrees;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
@@ -49,7 +50,7 @@ namespace Content.Client.Gameplay
EntityUid? uid = null;
if (UserInterfaceManager.CurrentlyHovered is IViewportControl vp && _inputManager.MouseScreenPosition.IsValid)
- uid = GetEntityUnderPosition(vp.ScreenToMap(_inputManager.MouseScreenPosition.Position));
+ uid = GetClickedEntity(vp.ScreenToMap(_inputManager.MouseScreenPosition.Position));
else if (UserInterfaceManager.CurrentlyHovered is EntityMenuElement element)
uid = element.Entity;
@@ -74,48 +75,47 @@ namespace Content.Client.Gameplay
_inputManager.KeyBindStateChanged -= OnKeyBindStateChanged;
}
- public EntityUid? GetEntityUnderPosition(MapCoordinates coordinates)
+ public EntityUid? GetClickedEntity(MapCoordinates coordinates)
{
- var entitiesUnderPosition = GetEntitiesUnderPosition(coordinates);
- return entitiesUnderPosition.Count > 0 ? entitiesUnderPosition[0] : null;
+ var first = GetClickableEntities(coordinates).FirstOrDefault();
+ return first.IsValid() ? first : null;
}
- public IList GetEntitiesUnderPosition(EntityCoordinates coordinates)
+ public IEnumerable GetClickableEntities(EntityCoordinates coordinates)
{
- return GetEntitiesUnderPosition(coordinates.ToMap(_entityManager));
+ return GetClickableEntities(coordinates.ToMap(_entityManager));
}
- public IList GetEntitiesUnderPosition(MapCoordinates coordinates)
+ public IEnumerable GetClickableEntities(MapCoordinates coordinates)
{
// Find all the entities intersecting our click
- var entities = _entityManager.EntitySysManager.GetEntitySystem().GetEntitiesIntersecting(coordinates.MapId,
- Box2.CenteredAround(coordinates.Position, (1, 1)), LookupFlags.Uncontained | LookupFlags.Approximate);
+ var spriteTree = _entityManager.EntitySysManager.GetEntitySystem();
+ var entities = spriteTree.QueryAabb(coordinates.MapId, Box2.CenteredAround(coordinates.Position, (1, 1)), true);
// Check the entities against whether or not we can click them
- var foundEntities = new List<(EntityUid clicked, int drawDepth, uint renderOrder, float bottom)>();
+ var foundEntities = new List<(EntityUid, int, uint, float)>(entities.Count);
var clickQuery = _entityManager.GetEntityQuery();
- var metaQuery = _entityManager.GetEntityQuery();
- var spriteQuery = _entityManager.GetEntityQuery();
var xformQuery = _entityManager.GetEntityQuery();
+
// TODO: Smelly
var eye = _eyeManager.CurrentEye;
foreach (var entity in entities)
{
- if (clickQuery.TryGetComponent(entity, out var component) &&
- spriteQuery.TryGetComponent(entity, out var sprite) &&
- component.CheckClick(sprite, xformQuery, coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom))
+ if (clickQuery.TryGetComponent(entity.Uid, out var component) &&
+ component.CheckClick(entity.Component, entity.Transform, xformQuery, coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom))
{
- foundEntities.Add((entity, drawDepthClicked, renderOrder, bottom));
+ foundEntities.Add((entity.Uid, drawDepthClicked, renderOrder, bottom));
}
}
if (foundEntities.Count == 0)
return Array.Empty();
+ // Do drawdepth & y-sorting. First index is the top-most sprite (opposite of normal render order).
foundEntities.Sort(_comparer);
- // 0 is the top element.
- return foundEntities.Select(a => a.clicked).ToList();
+
+ return foundEntities.Select(a => a.Item1);
}
private sealed class ClickableEntityComparer : IComparer<(EntityUid clicked, int depth, uint renderOrder, float bottom)>
@@ -166,7 +166,7 @@ namespace Content.Client.Gameplay
if (args.Viewport is IViewportControl vp)
{
var mousePosWorld = vp.ScreenToMap(kArgs.PointerLocation.Position);
- entityToClick = GetEntityUnderPosition(mousePosWorld);
+ entityToClick = GetClickedEntity(mousePosWorld);
coordinates = _mapManager.TryFindGridAt(mousePosWorld, out var grid) ? grid.MapToGrid(mousePosWorld) :
EntityCoordinates.FromMap(_mapManager, mousePosWorld);
diff --git a/Content.Client/Outline/InteractionOutlineSystem.cs b/Content.Client/Outline/InteractionOutlineSystem.cs
index ec5f4c6e46..26128fef50 100644
--- a/Content.Client/Outline/InteractionOutlineSystem.cs
+++ b/Content.Client/Outline/InteractionOutlineSystem.cs
@@ -118,7 +118,7 @@ public sealed class InteractionOutlineSystem : EntitySystem
&& _inputManager.MouseScreenPosition.IsValid)
{
var mousePosWorld = vp.ScreenToMap(_inputManager.MouseScreenPosition.Position);
- entityToClick = screen.GetEntityUnderPosition(mousePosWorld);
+ entityToClick = screen.GetClickedEntity(mousePosWorld);
if (vp is ScalingViewport svp)
{
diff --git a/Content.Client/Verbs/VerbSystem.cs b/Content.Client/Verbs/VerbSystem.cs
index f62f13d37a..8a0b69d774 100644
--- a/Content.Client/Verbs/VerbSystem.cs
+++ b/Content.Client/Verbs/VerbSystem.cs
@@ -109,7 +109,7 @@ namespace Content.Client.Verbs
// Do we have to do FoV checks?
if ((visibility & MenuVisibility.NoFov) == 0)
{
- var entitiesUnderMouse = gameScreenBase.GetEntitiesUnderPosition(targetPos);
+ var entitiesUnderMouse = gameScreenBase.GetClickableEntities(targetPos).ToHashSet();
bool Predicate(EntityUid e) => e == player || entitiesUnderMouse.Contains(e);
// first check the general location.
diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
index f3ba6edaa2..dad14c3ac5 100644
--- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
+++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
@@ -112,7 +112,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
if (_stateManager.CurrentState is GameplayStateBase screen)
{
- target = screen.GetEntityUnderPosition(mousePos);
+ target = screen.GetClickedEntity(mousePos);
}
EntityManager.RaisePredictiveEvent(new DisarmAttackEvent(target, coordinates));
@@ -191,7 +191,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
// TODO: UI Refactor update I assume
if (_stateManager.CurrentState is GameplayStateBase screen)
{
- target = screen.GetEntityUnderPosition(mousePos);
+ target = screen.GetClickedEntity(mousePos);
}
RaisePredictiveEvent(new LightAttackEvent(target, weapon.Owner, coordinates));
diff --git a/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs b/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs
index 9b56fdd8d7..482643076b 100644
--- a/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs
+++ b/Content.Client/Weapons/Ranged/Systems/TetherGunSystem.cs
@@ -84,7 +84,7 @@ public sealed class TetherGunSystem : SharedTetherGunSystem
if (gameState is GameplayState game)
{
- var uid = game.GetEntityUnderPosition(mousePos);
+ var uid = game.GetClickedEntity(mousePos);
if (uid != null)
StartDragging(uid.Value, mousePos);
diff --git a/Content.IntegrationTests/Tests/ClickableTest.cs b/Content.IntegrationTests/Tests/ClickableTest.cs
index 390771ce8f..dcaf06829e 100644
--- a/Content.IntegrationTests/Tests/ClickableTest.cs
+++ b/Content.IntegrationTests/Tests/ClickableTest.cs
@@ -81,7 +81,7 @@ namespace Content.IntegrationTests.Tests
var pos = clientEntManager.GetComponent(entity).WorldPosition;
var clickable = clientEntManager.GetComponent(entity);
- hit = clickable.CheckClick(sprite, xformQuery, (clickPosX, clickPosY) + pos, eye, out _, out _, out _);
+ hit = clickable.CheckClick(sprite, xformQuery.GetComponent(entity), xformQuery, (clickPosX, clickPosY) + pos, eye, out _, out _, out _);
});
await server.WaitPost(() =>