From 857c1462be7fef4757cf31f5caf83bdfb1731286 Mon Sep 17 00:00:00 2001
From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Date: Fri, 21 Apr 2023 17:06:10 +1200
Subject: [PATCH] Improve IsBlockedTurf (#15133)
---
Content.Shared/Maps/TurfHelpers.cs | 39 ++++---------
Content.Shared/Maps/TurfSystem.cs | 88 ++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+), 27 deletions(-)
create mode 100644 Content.Shared/Maps/TurfSystem.cs
diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs
index 3f14e6ed47..5d1d1aa60c 100644
--- a/Content.Shared/Maps/TurfHelpers.cs
+++ b/Content.Shared/Maps/TurfHelpers.cs
@@ -4,11 +4,14 @@ using System.Diagnostics.CodeAnalysis;
using Content.Shared.Decals;
using Content.Shared.Physics;
using Robust.Shared.Map;
+using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
namespace Content.Shared.Maps
{
+ // TODO move all these methods to LookupSystem or TurfSystem
+ // That, or make the interface arguments non-optional so people stop failing to pass them in.
public static class TurfHelpers
{
///
@@ -90,6 +93,7 @@ namespace Content.Shared.Maps
/// Helper that returns all entities in a turf.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [Obsolete("Use the lookup system")]
public static IEnumerable GetEntitiesInTile(this TileRef turf, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
{
lookupSystem ??= EntitySystem.Get();
@@ -103,6 +107,7 @@ namespace Content.Shared.Maps
///
/// Helper that returns all entities in a turf.
///
+ [Obsolete("Use the lookup system")]
public static IEnumerable GetEntitiesInTile(this EntityCoordinates coordinates, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
{
var turf = coordinates.GetTileRef();
@@ -116,6 +121,7 @@ namespace Content.Shared.Maps
///
/// Helper that returns all entities in a turf.
///
+ [Obsolete("Use the lookup system")]
public static IEnumerable GetEntitiesInTile(this Vector2i indices, EntityUid gridId, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
{
return GetEntitiesInTile(indices.GetTileRef(gridId), flags, lookupSystem);
@@ -124,35 +130,14 @@ namespace Content.Shared.Maps
///
/// Checks if a turf has something dense on it.
///
- public static bool IsBlockedTurf(this TileRef turf, bool filterMobs, EntityLookupSystem? physics = null, IEntitySystemManager? entSysMan = null)
+ [Obsolete("Use turf system")]
+ public static bool IsBlockedTurf(this TileRef turf, bool filterMobs, EntityLookupSystem? physics = null)
{
- // TODO: Deprecate this with entitylookup.
- if (physics == null)
- {
- IoCManager.Resolve(ref entSysMan);
- physics = entSysMan.GetEntitySystem();
- }
-
- if (!GetWorldTileBox(turf, out var worldBox))
- return false;
-
- var entManager = IoCManager.Resolve();
- var query = physics.GetEntitiesIntersecting(turf.GridUid, worldBox);
+ CollisionGroup mask = filterMobs
+ ? CollisionGroup.MobMask
+ : CollisionGroup.Impassable;
- foreach (var ent in query)
- {
- // Yes, this can fail. Welp!
- if (!entManager.TryGetComponent(ent, out PhysicsComponent? body))
- continue;
-
- if (body.CanCollide && body.Hard && (body.CollisionLayer & (int) CollisionGroup.Impassable) != 0)
- return true;
-
- if (filterMobs && (body.CollisionLayer & (int) CollisionGroup.MobMask) != 0)
- return true;
- }
-
- return false;
+ return IoCManager.Resolve().GetEntitySystem().IsTileBlocked(turf, mask);
}
public static EntityCoordinates GridPosition(this TileRef turf, IMapManager? mapManager = null)
diff --git a/Content.Shared/Maps/TurfSystem.cs b/Content.Shared/Maps/TurfSystem.cs
new file mode 100644
index 0000000000..eac61cd778
--- /dev/null
+++ b/Content.Shared/Maps/TurfSystem.cs
@@ -0,0 +1,88 @@
+using Content.Shared.Physics;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Physics;
+
+namespace Content.Shared.Maps;
+
+///
+/// This system provides various useful helper methods for turfs & tiles. Replacement for
+///
+public sealed class TurfSystem : EntitySystem
+{
+ [Dependency] private readonly IMapManager _mapMan = default!;
+ [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+
+ ///
+ /// Returns true if a given tile is blocked by physics-enabled entities.
+ ///
+ public bool IsTileBlocked(TileRef turf, CollisionGroup mask, float minIntersectionArea = 0.1f)
+ => IsTileBlocked(turf.GridUid, turf.GridIndices, mask, minIntersectionArea: minIntersectionArea);
+
+ ///
+ /// Returns true if a given tile is blocked by physics-enabled entities.
+ ///
+ /// The grid that owns the tile
+ /// The tile indices
+ /// Collision layers to check
+ /// Grid component
+ /// Grid's transform
+ /// Minimum area that must be covered for a tile to be considered blocked
+ public bool IsTileBlocked(EntityUid gridUid,
+ Vector2i indices,
+ CollisionGroup mask,
+ MapGridComponent? grid = null,
+ TransformComponent? gridXform = null,
+ float minIntersectionArea = 0.1f)
+ {
+ if (!Resolve(gridUid, ref grid, ref gridXform))
+ return false;
+
+ var xformQuery = GetEntityQuery();
+ var (gridPos, gridRot, matrix) = _transform.GetWorldPositionRotationMatrix(gridXform, xformQuery);
+
+ var size = grid.TileSize;
+ var localPos = new Vector2(indices.X * size + (size / 2f), indices.Y * size + (size / 2f));
+ var worldPos = matrix.Transform(localPos);
+
+ // This is scaled to 95 % so it doesn't encompass walls on other tiles.
+ var tileAabb = Box2.UnitCentered.Scale(0.95f * size);
+ var worldBox = new Box2Rotated(tileAabb.Translated(worldPos), gridRot, worldPos);
+ tileAabb = tileAabb.Translated(localPos);
+
+ var intersectionArea = 0f;
+ var fixtureQuery = GetEntityQuery();
+ foreach (var ent in _entityLookup.GetEntitiesIntersecting(gridUid, worldBox, LookupFlags.Dynamic | LookupFlags.Static))
+ {
+ if (!fixtureQuery.TryGetComponent(ent, out var fixtures))
+ continue;
+
+ // get grid local coordinates
+ var (pos, rot) = _transform.GetWorldPositionRotation(xformQuery.GetComponent(ent), xformQuery);
+ rot -= gridRot;
+ pos = (-gridRot).RotateVec(pos - gridPos);
+
+ var xform = new Transform(pos, (float) rot.Theta);
+
+ foreach (var fixture in fixtures.Fixtures.Values)
+ {
+ if (!fixture.Hard)
+ continue;
+
+ if ((fixture.CollisionLayer & (int) mask) == 0)
+ continue;
+
+ for (var i = 0; i < fixture.Shape.ChildCount; i++)
+ {
+ var intersection = fixture.Shape.ComputeAABB(xform, i).Intersect(tileAabb);
+ intersectionArea += intersection.Width * intersection.Height;
+ if (intersectionArea > minIntersectionArea)
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
--
2.51.2