]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Improve IsBlockedTurf (#15133)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Fri, 21 Apr 2023 05:06:10 +0000 (17:06 +1200)
committerGitHub <noreply@github.com>
Fri, 21 Apr 2023 05:06:10 +0000 (15:06 +1000)
Content.Shared/Maps/TurfHelpers.cs
Content.Shared/Maps/TurfSystem.cs [new file with mode: 0644]

index 3f14e6ed471ffd34fdb2e9efce41884cc88cf038..5d1d1aa60c3459946fba23dda1e367af3230ccce 100644 (file)
@@ -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
     {
         /// <summary>
@@ -90,6 +93,7 @@ namespace Content.Shared.Maps
         ///     Helper that returns all entities in a turf.
         /// </summary>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [Obsolete("Use the lookup system")]
         public static IEnumerable<EntityUid> GetEntitiesInTile(this TileRef turf, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
         {
             lookupSystem ??= EntitySystem.Get<EntityLookupSystem>();
@@ -103,6 +107,7 @@ namespace Content.Shared.Maps
         /// <summary>
         ///     Helper that returns all entities in a turf.
         /// </summary>
+        [Obsolete("Use the lookup system")]
         public static IEnumerable<EntityUid> GetEntitiesInTile(this EntityCoordinates coordinates, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null)
         {
             var turf = coordinates.GetTileRef();
@@ -116,6 +121,7 @@ namespace Content.Shared.Maps
         /// <summary>
         ///     Helper that returns all entities in a turf.
         /// </summary>
+        [Obsolete("Use the lookup system")]
         public static IEnumerable<EntityUid> 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
         /// <summary>
         /// Checks if a turf has something dense on it.
         /// </summary>
-        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<EntityLookupSystem>();
-            }
-
-            if (!GetWorldTileBox(turf, out var worldBox))
-                return false;
-
-            var entManager = IoCManager.Resolve<IEntityManager>();
-            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<IEntitySystemManager>().GetEntitySystem<TurfSystem>().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 (file)
index 0000000..eac61cd
--- /dev/null
@@ -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;
+
+/// <summary>
+///     This system provides various useful helper methods for turfs & tiles. Replacement for <see cref="TurfHelpers"/>
+/// </summary>
+public sealed class TurfSystem : EntitySystem
+{
+    [Dependency] private readonly IMapManager _mapMan = default!;
+    [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
+    [Dependency] private readonly SharedTransformSystem _transform = default!;
+
+    /// <summary>
+    ///     Returns true if a given tile is blocked by physics-enabled entities.
+    /// </summary>
+    public bool IsTileBlocked(TileRef turf, CollisionGroup mask, float minIntersectionArea = 0.1f)
+        => IsTileBlocked(turf.GridUid, turf.GridIndices, mask, minIntersectionArea: minIntersectionArea);
+
+    /// <summary>
+    ///     Returns true if a given tile is blocked by physics-enabled entities.
+    /// </summary>
+    /// <param name="gridUid">The grid that owns the tile</param>
+    /// <param name="indices">The tile indices</param>
+    /// <param name="mask">Collision layers to check</param>
+    /// <param name="grid">Grid component</param>
+    /// <param name="gridXform">Grid's transform</param>
+    /// <param name="minIntersectionArea">Minimum area that must be covered for a tile to be considered blocked</param>
+    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<TransformComponent>();
+        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<FixturesComponent>();
+        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;
+    }
+}