Improve IsBlockedTurf (#15133)
This commit is contained in:
@@ -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>();
|
||||
}
|
||||
CollisionGroup mask = filterMobs
|
||||
? CollisionGroup.MobMask
|
||||
: CollisionGroup.Impassable;
|
||||
|
||||
if (!GetWorldTileBox(turf, out var worldBox))
|
||||
return false;
|
||||
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var query = physics.GetEntitiesIntersecting(turf.GridUid, worldBox);
|
||||
|
||||
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)
|
||||
|
||||
88
Content.Shared/Maps/TurfSystem.cs
Normal file
88
Content.Shared/Maps/TurfSystem.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user