Make clickmap lookups use the sprite tree (#13275)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -21,9 +21,9 @@ namespace Content.Client.Clickable
|
|||||||
/// The draw depth for the sprite that captured the click.
|
/// The draw depth for the sprite that captured the click.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>True if the click worked, false otherwise.</returns>
|
/// <returns>True if the click worked, false otherwise.</returns>
|
||||||
public bool CheckClick(SpriteComponent sprite, EntityQuery<TransformComponent> xformQuery, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom)
|
public bool CheckClick(SpriteComponent sprite, TransformComponent transform, EntityQuery<TransformComponent> 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;
|
drawDepth = default;
|
||||||
renderOrder = default;
|
renderOrder = default;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ using Robust.Shared.Input;
|
|||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using System.Linq;
|
||||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||||
|
|
||||||
namespace Content.Client.DragDrop
|
namespace Content.Client.DragDrop
|
||||||
@@ -306,7 +307,7 @@ namespace Content.Client.DragDrop
|
|||||||
|
|
||||||
if (_stateManager.CurrentState is GameplayState screen)
|
if (_stateManager.CurrentState is GameplayState screen)
|
||||||
{
|
{
|
||||||
entities = screen.GetEntitiesUnderPosition(args.Coordinates);
|
entities = screen.GetClickableEntities(args.Coordinates).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Client.Clickable;
|
using Content.Client.Clickable;
|
||||||
using Content.Client.ContextMenu.UI;
|
using Content.Client.ContextMenu.UI;
|
||||||
|
using Robust.Client.ComponentTrees;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Input;
|
using Robust.Client.Input;
|
||||||
@@ -49,7 +50,7 @@ namespace Content.Client.Gameplay
|
|||||||
|
|
||||||
EntityUid? uid = null;
|
EntityUid? uid = null;
|
||||||
if (UserInterfaceManager.CurrentlyHovered is IViewportControl vp && _inputManager.MouseScreenPosition.IsValid)
|
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)
|
else if (UserInterfaceManager.CurrentlyHovered is EntityMenuElement element)
|
||||||
uid = element.Entity;
|
uid = element.Entity;
|
||||||
|
|
||||||
@@ -74,48 +75,47 @@ namespace Content.Client.Gameplay
|
|||||||
_inputManager.KeyBindStateChanged -= OnKeyBindStateChanged;
|
_inputManager.KeyBindStateChanged -= OnKeyBindStateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityUid? GetEntityUnderPosition(MapCoordinates coordinates)
|
public EntityUid? GetClickedEntity(MapCoordinates coordinates)
|
||||||
{
|
{
|
||||||
var entitiesUnderPosition = GetEntitiesUnderPosition(coordinates);
|
var first = GetClickableEntities(coordinates).FirstOrDefault();
|
||||||
return entitiesUnderPosition.Count > 0 ? entitiesUnderPosition[0] : null;
|
return first.IsValid() ? first : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<EntityUid> GetEntitiesUnderPosition(EntityCoordinates coordinates)
|
public IEnumerable<EntityUid> GetClickableEntities(EntityCoordinates coordinates)
|
||||||
{
|
{
|
||||||
return GetEntitiesUnderPosition(coordinates.ToMap(_entityManager));
|
return GetClickableEntities(coordinates.ToMap(_entityManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<EntityUid> GetEntitiesUnderPosition(MapCoordinates coordinates)
|
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates)
|
||||||
{
|
{
|
||||||
// Find all the entities intersecting our click
|
// Find all the entities intersecting our click
|
||||||
var entities = _entityManager.EntitySysManager.GetEntitySystem<EntityLookupSystem>().GetEntitiesIntersecting(coordinates.MapId,
|
var spriteTree = _entityManager.EntitySysManager.GetEntitySystem<SpriteTreeSystem>();
|
||||||
Box2.CenteredAround(coordinates.Position, (1, 1)), LookupFlags.Uncontained | LookupFlags.Approximate);
|
var entities = spriteTree.QueryAabb(coordinates.MapId, Box2.CenteredAround(coordinates.Position, (1, 1)), true);
|
||||||
|
|
||||||
// Check the entities against whether or not we can click them
|
// 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<ClickableComponent>();
|
var clickQuery = _entityManager.GetEntityQuery<ClickableComponent>();
|
||||||
var metaQuery = _entityManager.GetEntityQuery<MetaDataComponent>();
|
|
||||||
var spriteQuery = _entityManager.GetEntityQuery<SpriteComponent>();
|
|
||||||
var xformQuery = _entityManager.GetEntityQuery<TransformComponent>();
|
var xformQuery = _entityManager.GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
// TODO: Smelly
|
// TODO: Smelly
|
||||||
var eye = _eyeManager.CurrentEye;
|
var eye = _eyeManager.CurrentEye;
|
||||||
|
|
||||||
foreach (var entity in entities)
|
foreach (var entity in entities)
|
||||||
{
|
{
|
||||||
if (clickQuery.TryGetComponent(entity, out var component) &&
|
if (clickQuery.TryGetComponent(entity.Uid, out var component) &&
|
||||||
spriteQuery.TryGetComponent(entity, out var sprite) &&
|
component.CheckClick(entity.Component, entity.Transform, xformQuery, coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom))
|
||||||
component.CheckClick(sprite, 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)
|
if (foundEntities.Count == 0)
|
||||||
return Array.Empty<EntityUid>();
|
return Array.Empty<EntityUid>();
|
||||||
|
|
||||||
|
// Do drawdepth & y-sorting. First index is the top-most sprite (opposite of normal render order).
|
||||||
foundEntities.Sort(_comparer);
|
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)>
|
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)
|
if (args.Viewport is IViewportControl vp)
|
||||||
{
|
{
|
||||||
var mousePosWorld = vp.ScreenToMap(kArgs.PointerLocation.Position);
|
var mousePosWorld = vp.ScreenToMap(kArgs.PointerLocation.Position);
|
||||||
entityToClick = GetEntityUnderPosition(mousePosWorld);
|
entityToClick = GetClickedEntity(mousePosWorld);
|
||||||
|
|
||||||
coordinates = _mapManager.TryFindGridAt(mousePosWorld, out var grid) ? grid.MapToGrid(mousePosWorld) :
|
coordinates = _mapManager.TryFindGridAt(mousePosWorld, out var grid) ? grid.MapToGrid(mousePosWorld) :
|
||||||
EntityCoordinates.FromMap(_mapManager, mousePosWorld);
|
EntityCoordinates.FromMap(_mapManager, mousePosWorld);
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public sealed class InteractionOutlineSystem : EntitySystem
|
|||||||
&& _inputManager.MouseScreenPosition.IsValid)
|
&& _inputManager.MouseScreenPosition.IsValid)
|
||||||
{
|
{
|
||||||
var mousePosWorld = vp.ScreenToMap(_inputManager.MouseScreenPosition.Position);
|
var mousePosWorld = vp.ScreenToMap(_inputManager.MouseScreenPosition.Position);
|
||||||
entityToClick = screen.GetEntityUnderPosition(mousePosWorld);
|
entityToClick = screen.GetClickedEntity(mousePosWorld);
|
||||||
|
|
||||||
if (vp is ScalingViewport svp)
|
if (vp is ScalingViewport svp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ namespace Content.Client.Verbs
|
|||||||
// Do we have to do FoV checks?
|
// Do we have to do FoV checks?
|
||||||
if ((visibility & MenuVisibility.NoFov) == 0)
|
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);
|
bool Predicate(EntityUid e) => e == player || entitiesUnderMouse.Contains(e);
|
||||||
|
|
||||||
// first check the general location.
|
// first check the general location.
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
|
|
||||||
if (_stateManager.CurrentState is GameplayStateBase screen)
|
if (_stateManager.CurrentState is GameplayStateBase screen)
|
||||||
{
|
{
|
||||||
target = screen.GetEntityUnderPosition(mousePos);
|
target = screen.GetClickedEntity(mousePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.RaisePredictiveEvent(new DisarmAttackEvent(target, coordinates));
|
EntityManager.RaisePredictiveEvent(new DisarmAttackEvent(target, coordinates));
|
||||||
@@ -191,7 +191,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
// TODO: UI Refactor update I assume
|
// TODO: UI Refactor update I assume
|
||||||
if (_stateManager.CurrentState is GameplayStateBase screen)
|
if (_stateManager.CurrentState is GameplayStateBase screen)
|
||||||
{
|
{
|
||||||
target = screen.GetEntityUnderPosition(mousePos);
|
target = screen.GetClickedEntity(mousePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
RaisePredictiveEvent(new LightAttackEvent(target, weapon.Owner, coordinates));
|
RaisePredictiveEvent(new LightAttackEvent(target, weapon.Owner, coordinates));
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ public sealed class TetherGunSystem : SharedTetherGunSystem
|
|||||||
|
|
||||||
if (gameState is GameplayState game)
|
if (gameState is GameplayState game)
|
||||||
{
|
{
|
||||||
var uid = game.GetEntityUnderPosition(mousePos);
|
var uid = game.GetClickedEntity(mousePos);
|
||||||
|
|
||||||
if (uid != null)
|
if (uid != null)
|
||||||
StartDragging(uid.Value, mousePos);
|
StartDragging(uid.Value, mousePos);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
var pos = clientEntManager.GetComponent<TransformComponent>(entity).WorldPosition;
|
var pos = clientEntManager.GetComponent<TransformComponent>(entity).WorldPosition;
|
||||||
var clickable = clientEntManager.GetComponent<ClickableComponent>(entity);
|
var clickable = clientEntManager.GetComponent<ClickableComponent>(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(() =>
|
await server.WaitPost(() =>
|
||||||
|
|||||||
Reference in New Issue
Block a user