From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Fri, 21 Apr 2023 05:06:10 +0000 (+1200) Subject: Improve IsBlockedTurf (#15133) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=857c1462be7fef4757cf31f5caf83bdfb1731286;p=space-station-14.git Improve IsBlockedTurf (#15133) --- 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; + } +}