mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-01 17:47:24 +02:00
* Move MapManager queries to SharedMapSystem Moves all variants of FindGridsIntersecting/TryFindGridAt to SharedMapSystem Hollows out the MapManager methods and converts them into relays to SharedMapSystem * Move CreateGrid to SharedMapSystem Moves the functionality for CreateGrid and its variants to SharedMapSystem Hollows out the MapManager methods and converts them into relays for the SharedMapSystem methods Obsoletes them too Also moves over the GetAllMapGrids and GetAllGrids methods * Move RaiseOnTileChanged to SharedMapSystem Also moves the SuppressOnTileChanged flag member to SharedMapSystem Hollows out and obsoletes the MapManager versions * Move default value constants to SharedMapSystem * Converts map pausing events into LocalizedEntityCommands * Move MapManager related delegates/structs to SharedMapSystem Moves the GridCreationOptions struct to the same namespace as SharedMapSystem and converts it into a record struct Move the GridCallback delegates to the same namespace as SharedMapSystem * Move CullDeletionHistory to SharedMapSystem Well, that was less painful than I thought it would be * Actually obsolete the NetworkedMapManager method * Rename file * Doc comments for new SharedMapSystem methods * Doc comment * Doc comments * Fix access * Purge all references to IMapManagerInternal * Cull easy IMapManager references * The rest * Purge IMapManager * Private internal FindGridsIntersecting method * please die * 41 * notes --------- Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
879 lines
30 KiB
C#
879 lines
30 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using Robust.Shared.Collections;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Physics.Collision;
|
|
using Robust.Shared.Physics.Collision.Shapes;
|
|
using Robust.Shared.Physics.Dynamics;
|
|
using Robust.Shared.Physics.Shapes;
|
|
using Robust.Shared.Physics.Systems;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Robust.Shared.GameObjects;
|
|
|
|
public sealed partial class EntityLookupSystem
|
|
{
|
|
#region Private
|
|
|
|
private void RecursiveAdd<T>(EntityUid uid, ref ValueList<Entity<T>> toAdd, EntityQuery<T> query) where T : IComponent
|
|
{
|
|
var xform = _xformQuery.GetComponent(uid);
|
|
foreach (var child in xform._children)
|
|
{
|
|
if (query.TryGetComponent(child, out var compies))
|
|
{
|
|
toAdd.Add((child, compies));
|
|
}
|
|
|
|
RecursiveAdd(child, ref toAdd, query);
|
|
}
|
|
}
|
|
|
|
private void AddContained<T>(HashSet<Entity<T>> intersecting, LookupFlags flags, EntityQuery<T> query) where T : IComponent
|
|
{
|
|
if ((flags & LookupFlags.Contained) == 0x0) return;
|
|
|
|
var toAdd = new ValueList<Entity<T>>();
|
|
|
|
foreach (var comp in intersecting)
|
|
{
|
|
if (!_containerQuery.TryGetComponent(comp, out var conManager)) continue;
|
|
|
|
foreach (var con in _container.GetAllContainers(comp, conManager))
|
|
{
|
|
foreach (var contained in con.ContainedEntities)
|
|
{
|
|
if (query.TryGetComponent(contained, out var compies))
|
|
{
|
|
toAdd.Add((contained, compies));
|
|
}
|
|
|
|
RecursiveAdd(contained, ref toAdd, query);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var uid in toAdd.Span)
|
|
{
|
|
intersecting.Add(uid);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Common method to determine if an entity overlaps the specified shape.
|
|
/// </summary>
|
|
private bool IsIntersecting<TShape>(MapId mapId, EntityUid uid, TransformComponent xform, TShape shape, Transform shapeTransform, Box2 worldAABB, LookupFlags flags) where TShape : IPhysShape
|
|
{
|
|
var (entPos, entRot) = _transform.GetWorldPositionRotation(xform);
|
|
|
|
if (xform.MapID != mapId ||
|
|
!worldAABB.Contains(entPos) ||
|
|
((flags & LookupFlags.Contained) == 0x0 &&
|
|
_container.IsEntityOrParentInContainer(uid, _metaQuery.GetComponent(uid), xform)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_fixturesQuery.TryGetComponent(uid, out var fixtures))
|
|
{
|
|
var transform = new Transform(entPos, entRot);
|
|
bool anyFixture = false;
|
|
var sensors = (flags & LookupFlags.Sensors) != 0x0;
|
|
|
|
foreach (var fixture in fixtures.Fixtures.Values)
|
|
{
|
|
if (!sensors && !fixture.Hard)
|
|
continue;
|
|
|
|
anyFixture = true;
|
|
for (var i = 0; i < fixture.Shape.ChildCount; i++)
|
|
{
|
|
if (_manifoldManager.TestOverlap(shape, 0, fixture.Shape, i, shapeTransform, transform))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (anyFixture)
|
|
return false;
|
|
}
|
|
|
|
if (!_fixtures.TestPoint(shape, shapeTransform, entPos))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
private void AddLocalEntitiesIntersecting<T>(
|
|
EntityUid lookupUid,
|
|
HashSet<Entity<T>> intersecting,
|
|
Box2 localAABB,
|
|
LookupFlags flags,
|
|
EntityQuery<T> query,
|
|
BroadphaseComponent? lookup = null) where T : IComponent
|
|
{
|
|
if (!_broadQuery.Resolve(lookupUid, ref lookup))
|
|
return;
|
|
|
|
var polygon = new SlimPolygon(localAABB);
|
|
AddEntitiesIntersecting(lookupUid, intersecting, polygon, localAABB, Physics.Transform.Empty, flags, query, lookup);
|
|
}
|
|
|
|
private void AddEntitiesIntersecting<T, TShape>(
|
|
EntityUid lookupUid,
|
|
HashSet<Entity<T>> intersecting,
|
|
TShape shape,
|
|
Box2 localAABB,
|
|
Transform localTransform,
|
|
LookupFlags flags,
|
|
EntityQuery<T> query,
|
|
BroadphaseComponent? lookup = null)
|
|
where T : IComponent
|
|
where TShape : IPhysShape
|
|
{
|
|
if (!_broadQuery.Resolve(lookupUid, ref lookup))
|
|
return;
|
|
|
|
var state = new QueryState<T, TShape>(
|
|
intersecting,
|
|
shape,
|
|
localTransform,
|
|
_fixtures,
|
|
_physics,
|
|
_manifoldManager,
|
|
query,
|
|
_fixturesQuery,
|
|
(flags & LookupFlags.Sensors) != 0,
|
|
(flags & LookupFlags.Approximate) != 0x0
|
|
);
|
|
|
|
if ((flags & LookupFlags.Dynamic) != 0x0)
|
|
{
|
|
lookup.DynamicTree.QueryAabb(ref state, PhysicsQuery, localAABB, true);
|
|
}
|
|
|
|
if ((flags & LookupFlags.Static) != 0x0)
|
|
{
|
|
lookup.StaticTree.QueryAabb(ref state, PhysicsQuery, localAABB, true);
|
|
}
|
|
|
|
if ((flags & LookupFlags.StaticSundries) == LookupFlags.StaticSundries)
|
|
{
|
|
lookup.StaticSundriesTree.QueryAabb(ref state, SundriesQuery, localAABB, true);
|
|
}
|
|
|
|
if ((flags & LookupFlags.Sundries) != 0x0)
|
|
{
|
|
lookup.SundriesTree.QueryAabb(ref state, SundriesQuery, localAABB, true);
|
|
}
|
|
|
|
return;
|
|
|
|
static bool PhysicsQuery(ref QueryState<T, TShape> state, in FixtureProxy value)
|
|
{
|
|
if (!state.Sensors && !value.Fixture.Hard)
|
|
return true;
|
|
|
|
if (!state.Query.TryGetComponent(value.Entity, out var comp))
|
|
return true;
|
|
|
|
if (!state.Approximate)
|
|
{
|
|
var intersectingTransform = state.Physics.GetLocalPhysicsTransform(value.Entity);
|
|
if (!state.Manifolds.TestOverlap(state.Shape, 0, value.Fixture.Shape, value.ChildIndex, state.Transform, intersectingTransform))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
state.Intersecting.Add((value.Entity, comp));
|
|
return true;
|
|
}
|
|
|
|
static bool SundriesQuery(ref QueryState<T, TShape> state, in EntityUid value)
|
|
{
|
|
if (!state.Query.TryGetComponent(value, out var comp))
|
|
return true;
|
|
|
|
if (state.Approximate)
|
|
{
|
|
state.Intersecting.Add((value, comp));
|
|
return true;
|
|
}
|
|
|
|
var intersectingTransform = state.Physics.GetLocalPhysicsTransform(value);
|
|
|
|
if (state.FixturesQuery.TryGetComponent(value, out var fixtures))
|
|
{
|
|
bool anyFixture = false;
|
|
foreach (var fixture in fixtures.Fixtures.Values)
|
|
{
|
|
if (!state.Sensors && !fixture.Hard)
|
|
continue;
|
|
|
|
anyFixture = true;
|
|
for (var i = 0; i < fixture.Shape.ChildCount; i++)
|
|
{
|
|
if (state.Manifolds.TestOverlap(state.Shape, 0, fixture.Shape, i, state.Transform,
|
|
intersectingTransform))
|
|
{
|
|
state.Intersecting.Add((value, comp));
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (anyFixture)
|
|
return true;
|
|
}
|
|
|
|
if (state.Fixtures.TestPoint(state.Shape, state.Transform, intersectingTransform.Position))
|
|
state.Intersecting.Add((value, comp));
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private bool AnyLocalComponentsIntersecting<T>(
|
|
EntityUid lookupUid,
|
|
Box2 localAABB,
|
|
LookupFlags flags,
|
|
EntityQuery<T> query,
|
|
EntityUid? ignored = null,
|
|
BroadphaseComponent? lookup = null) where T : IComponent
|
|
{
|
|
if (!_broadQuery.Resolve(lookupUid, ref lookup))
|
|
return false;
|
|
|
|
var polygon = new SlimPolygon(localAABB);
|
|
var (lookupPos, lookupRot) = _transform.GetWorldPositionRotation(lookupUid);
|
|
var transform = new Transform(lookupPos, lookupRot);
|
|
var result = AnyComponentsIntersecting(lookupUid, polygon, localAABB, transform, flags, query, ignored, lookup);
|
|
|
|
return result;
|
|
}
|
|
|
|
private bool AnyComponentsIntersecting<T, TShape>(
|
|
EntityUid lookupUid,
|
|
TShape shape,
|
|
Box2 localAABB,
|
|
Transform shapeTransform,
|
|
LookupFlags flags,
|
|
EntityQuery<T> query,
|
|
EntityUid? ignored = null,
|
|
BroadphaseComponent? lookup = null)
|
|
where T : IComponent
|
|
where TShape : IPhysShape
|
|
{
|
|
/*
|
|
* Unfortunately this is split from the other query as we can short-circuit here, hence the code duplication.
|
|
* Alternatively you can make them both use callbacks.
|
|
*/
|
|
|
|
if (!_broadQuery.Resolve(lookupUid, ref lookup))
|
|
return false;
|
|
|
|
var state = new AnyQueryState<T, TShape>(false,
|
|
ignored,
|
|
shape,
|
|
shapeTransform,
|
|
_fixtures,
|
|
_physics,
|
|
_manifoldManager,
|
|
query,
|
|
_fixturesQuery,
|
|
flags);
|
|
|
|
if ((flags & LookupFlags.Dynamic) != 0x0)
|
|
{
|
|
lookup.DynamicTree.QueryAabb(ref state, PhysicsQuery, localAABB, true);
|
|
|
|
if (state.Found)
|
|
return true;
|
|
}
|
|
|
|
if ((flags & LookupFlags.Static) != 0x0)
|
|
{
|
|
lookup.StaticTree.QueryAabb(ref state, PhysicsQuery, localAABB, true);
|
|
|
|
if (state.Found)
|
|
return true;
|
|
}
|
|
|
|
if ((flags & LookupFlags.StaticSundries) == LookupFlags.StaticSundries)
|
|
{
|
|
lookup.StaticSundriesTree.QueryAabb(ref state, SundriesQuery, localAABB, true);
|
|
|
|
if (state.Found)
|
|
return true;
|
|
}
|
|
|
|
if ((flags & LookupFlags.Sundries) != 0x0)
|
|
{
|
|
lookup.SundriesTree.QueryAabb(ref state, SundriesQuery, localAABB, true);
|
|
}
|
|
|
|
return state.Found;
|
|
|
|
static bool PhysicsQuery(ref AnyQueryState<T, TShape> state, in FixtureProxy value)
|
|
{
|
|
if (value.Entity == state.Ignored)
|
|
return true;
|
|
|
|
if (!state.Query.HasComponent(value.Entity))
|
|
return true;
|
|
|
|
var approx = (state.Flags & LookupFlags.Approximate) != 0x0;
|
|
|
|
if (!approx)
|
|
{
|
|
var intersectingTransform = state.Physics.GetPhysicsTransform(value.Entity);
|
|
|
|
if (!state.Manifolds.TestOverlap(state.Shape, 0, value.Fixture.Shape, value.ChildIndex,
|
|
state.Transform, intersectingTransform))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
state.Found = true;
|
|
return false;
|
|
}
|
|
|
|
static bool SundriesQuery(ref AnyQueryState<T, TShape> state, in EntityUid value)
|
|
{
|
|
if (state.Ignored == value)
|
|
return true;
|
|
|
|
if (!state.Query.HasComponent(value))
|
|
return true;
|
|
|
|
var approx = (state.Flags & LookupFlags.Approximate) != 0x0;
|
|
|
|
if (approx)
|
|
{
|
|
state.Found = true;
|
|
return false;
|
|
}
|
|
|
|
var intersectingTransform = state.Physics.GetPhysicsTransform(value);
|
|
|
|
if (state.FixturesQuery.TryGetComponent(value, out var fixtures))
|
|
{
|
|
var sensors = (state.Flags & LookupFlags.Sensors) != 0x0;
|
|
bool anyFixture = false;
|
|
foreach (var fixture in fixtures.Fixtures.Values)
|
|
{
|
|
if (!sensors && !fixture.Hard)
|
|
continue;
|
|
|
|
anyFixture = true;
|
|
for (var i = 0; i < fixture.Shape.ChildCount; i++)
|
|
{
|
|
if (state.Manifolds.TestOverlap(state.Shape, 0, fixture.Shape, i, state.Transform,
|
|
intersectingTransform))
|
|
{
|
|
state.Found = true;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (anyFixture)
|
|
return true;
|
|
}
|
|
|
|
if (state.Fixtures.TestPoint(state.Shape, state.Transform, intersectingTransform.Position))
|
|
{
|
|
state.Found = true;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should we just iterate every component and check position or do bounds checks.
|
|
/// </summary>
|
|
private bool UseBoundsQuery(Type type, float area)
|
|
{
|
|
return Count(type) > area;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should we just iterate every component and check position or do bounds checks.
|
|
/// </summary>
|
|
private bool UseBoundsQuery<T>(float area) where T : IComponent
|
|
{
|
|
// If the component has a low count we'll just do an estimate if it's faster to iterate every comp directly
|
|
// Might be useful to have some way to expose this to content?
|
|
// For now we'll assume 1 entity per metre.
|
|
return Count<T>() > area;
|
|
}
|
|
|
|
#endregion
|
|
|
|
// Like .Queries but works with components
|
|
#region Box2
|
|
|
|
public bool AnyComponentsIntersecting(Type type, MapId mapId, Box2 worldAABB, EntityUid? ignored = null, LookupFlags flags = DefaultFlags)
|
|
{
|
|
var polygon = new SlimPolygon(worldAABB);
|
|
var transform = Physics.Transform.Empty;
|
|
var result = AnyComponentsIntersecting(type, mapId, polygon, transform, ignored, flags);
|
|
return result;
|
|
}
|
|
|
|
public bool AnyComponentsIntersecting<T>(Type type, MapId mapId, T shape, Transform shapeTransform, EntityUid? ignored = null, LookupFlags flags = DefaultFlags) where T : IPhysShape
|
|
{
|
|
DebugTools.Assert(typeof(IComponent).IsAssignableFrom(type));
|
|
if (mapId == MapId.Nullspace)
|
|
return false;
|
|
|
|
var worldAABB = shape.ComputeAABB(shapeTransform, 0);
|
|
|
|
if (!UseBoundsQuery(type, worldAABB.Height * worldAABB.Width))
|
|
{
|
|
foreach (var (uid, comp) in EntityManager.GetAllComponents(type, true))
|
|
{
|
|
var xform = _xformQuery.GetComponent(uid);
|
|
|
|
if (!IsIntersecting(mapId, uid, xform, shape, shapeTransform, worldAABB, flags))
|
|
continue;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var query = EntityManager.GetEntityQuery(type);
|
|
|
|
// Get grid entities
|
|
var state = (this, worldAABB, flags, query, ignored, found: false);
|
|
|
|
_map.FindGridsIntersecting(mapId, worldAABB, ref state,
|
|
static (EntityUid uid, MapGridComponent grid, ref
|
|
(EntityLookupSystem system,
|
|
Box2 worldAABB,
|
|
LookupFlags flags,
|
|
EntityQuery<IComponent> query,
|
|
EntityUid? ignored,
|
|
bool found) tuple) =>
|
|
{
|
|
if (!tuple.system.AnyLocalComponentsIntersecting(uid, tuple.worldAABB, tuple.flags, tuple.query, tuple.ignored))
|
|
return true;
|
|
|
|
tuple.found = true;
|
|
return false;
|
|
}, approx: true, includeMap: false);
|
|
|
|
if (state.found)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Get map entities
|
|
var mapUid = _map.GetMapOrInvalid(mapId);
|
|
AnyLocalComponentsIntersecting(mapUid, worldAABB, flags, query, ignored);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void GetEntitiesIntersecting(Type type, MapId mapId, Box2 worldAABB, HashSet<Entity<IComponent>> intersecting, LookupFlags flags = DefaultFlags)
|
|
{
|
|
DebugTools.Assert(typeof(IComponent).IsAssignableFrom(type));
|
|
if (mapId == MapId.Nullspace)
|
|
return;
|
|
|
|
var polygon = new SlimPolygon(worldAABB);
|
|
var transform = Physics.Transform.Empty;
|
|
|
|
GetEntitiesIntersecting(type, mapId, polygon, transform, intersecting, flags);
|
|
}
|
|
|
|
public void GetEntitiesIntersecting<T>(MapId mapId, Box2Rotated worldBounds, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
if (mapId == MapId.Nullspace) return;
|
|
|
|
var polygon = new SlimPolygon(worldBounds);
|
|
var shapeTransform = Physics.Transform.Empty;
|
|
|
|
GetEntitiesIntersecting(mapId, polygon, shapeTransform, entities, flags);
|
|
}
|
|
|
|
public void GetEntitiesIntersecting<T>(MapId mapId, Box2 worldAABB, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
if (mapId == MapId.Nullspace) return;
|
|
|
|
var polygon = new SlimPolygon(worldAABB);
|
|
var shapeTransform = Physics.Transform.Empty;
|
|
|
|
GetEntitiesIntersecting(mapId, polygon, shapeTransform, entities, flags);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IPhysShape
|
|
|
|
public void GetEntitiesIntersecting<T>(Type type, MapId mapId, T shape, Transform shapeTransform, HashSet<Entity<IComponent>> intersecting, LookupFlags flags = DefaultFlags) where T : IPhysShape
|
|
{
|
|
DebugTools.Assert(typeof(IComponent).IsAssignableFrom(type));
|
|
if (mapId == MapId.Nullspace)
|
|
return;
|
|
|
|
var worldAABB = shape.ComputeAABB(shapeTransform, 0);
|
|
|
|
if (!UseBoundsQuery(type, worldAABB.Height * worldAABB.Width))
|
|
{
|
|
foreach (var (uid, comp) in EntityManager.GetAllComponents(type, true))
|
|
{
|
|
var xform = _xformQuery.GetComponent(uid);
|
|
|
|
if (!IsIntersecting(mapId, uid, xform, shape, shapeTransform, worldAABB, flags))
|
|
continue;
|
|
|
|
intersecting.Add((uid, comp));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var query = EntityManager.GetEntityQuery(type);
|
|
|
|
// Get grid entities
|
|
var state = new GridQueryState<IComponent, T>(intersecting, shape, shapeTransform, this, _physics, flags, query);
|
|
|
|
_map.FindGridsIntersecting(mapId, worldAABB, ref state,
|
|
static (EntityUid uid, MapGridComponent grid, ref GridQueryState<IComponent, T> state) =>
|
|
{
|
|
var localTransform = state.Physics.GetRelativePhysicsTransform(state.Transform, uid);
|
|
var localAabb = state.Shape.ComputeAABB(localTransform, 0);
|
|
state.Lookup.AddEntitiesIntersecting(uid, state.Intersecting, state.Shape, localAabb, localTransform, state.Flags, state.Query);
|
|
return true;
|
|
}, approx: true, includeMap: false);
|
|
|
|
var mapUid = _map.GetMapOrInvalid(mapId);
|
|
var localTransform = state.Physics.GetRelativePhysicsTransform(state.Transform, mapUid);
|
|
var localAabb = state.Shape.ComputeAABB(localTransform, 0);
|
|
|
|
AddEntitiesIntersecting(mapUid, intersecting, shape, localAabb, localTransform, flags, query);
|
|
|
|
AddContained(intersecting, flags, query);
|
|
}
|
|
}
|
|
|
|
public void GetEntitiesIntersecting<T, TShape>(MapId mapId, TShape shape, Transform shapeTransform, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags)
|
|
where T : IComponent
|
|
where TShape : IPhysShape
|
|
{
|
|
if (mapId == MapId.Nullspace) return;
|
|
|
|
var worldAABB = shape.ComputeAABB(shapeTransform, 0);
|
|
|
|
if (!UseBoundsQuery<T>(worldAABB.Height * worldAABB.Width))
|
|
{
|
|
var query = AllEntityQuery<T, TransformComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp, out var xform))
|
|
{
|
|
if (!IsIntersecting(mapId, uid, xform, shape, shapeTransform, worldAABB, flags))
|
|
continue;
|
|
|
|
entities.Add((uid, comp));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var query = GetEntityQuery<T>();
|
|
|
|
// Get grid entities
|
|
var state = new GridQueryState<T, TShape>(entities, shape, shapeTransform, this, _physics, flags, query);
|
|
|
|
_map.FindGridsIntersecting(mapId, worldAABB, ref state,
|
|
static (EntityUid uid, MapGridComponent grid, ref GridQueryState<T, TShape> state) =>
|
|
{
|
|
var localTransform = state.Physics.GetRelativePhysicsTransform(state.Transform, uid);
|
|
var localAabb = state.Shape.ComputeAABB(localTransform, 0);
|
|
state.Lookup.AddEntitiesIntersecting(uid, state.Intersecting, state.Shape, localAabb, localTransform, state.Flags, state.Query);
|
|
return true;
|
|
}, approx: true, includeMap: false);
|
|
|
|
// Get map entities
|
|
var mapUid = _map.GetMapOrInvalid(mapId);
|
|
var localTransform = state.Physics.GetRelativePhysicsTransform(state.Transform, mapUid);
|
|
var localAabb = state.Shape.ComputeAABB(localTransform, 0);
|
|
|
|
AddEntitiesIntersecting(mapUid, entities, shape, localAabb, localTransform, flags, query);
|
|
AddContained(entities, flags, query);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EntityCoordinates
|
|
|
|
public void GetEntitiesInRange<T>(EntityCoordinates coordinates, float range, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
var mapPos = _transform.ToMapCoordinates(coordinates);
|
|
GetEntitiesInRange(mapPos, range, entities, flags);
|
|
}
|
|
|
|
public HashSet<Entity<T>> GetEntitiesInRange<T>(EntityCoordinates coordinates, float range, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
var entities = new HashSet<Entity<T>>();
|
|
GetEntitiesInRange(coordinates, range, entities, flags);
|
|
return entities;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MapCoordinates
|
|
|
|
public HashSet<Entity<IComponent>> GetEntitiesInRange(Type type, MapCoordinates coordinates, float range)
|
|
{
|
|
var entities = new HashSet<Entity<IComponent>>();
|
|
GetEntitiesInRange(type, coordinates, range, entities);
|
|
return entities;
|
|
}
|
|
|
|
public void GetEntitiesInRange(Type type, MapCoordinates coordinates, float range, HashSet<Entity<IComponent>> entities, LookupFlags flags = DefaultFlags)
|
|
{
|
|
DebugTools.Assert(typeof(IComponent).IsAssignableFrom(type));
|
|
GetEntitiesInRange(type, coordinates.MapId, coordinates.Position, range, entities, flags);
|
|
}
|
|
|
|
public void GetEntitiesInRange<T>(MapCoordinates coordinates, float range, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
GetEntitiesInRange(coordinates.MapId, coordinates.Position, range, entities, flags);
|
|
}
|
|
|
|
public HashSet<Entity<T>> GetEntitiesInRange<T>(MapCoordinates coordinates, float range, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
var entities = new HashSet<Entity<T>>();
|
|
GetEntitiesInRange(coordinates.MapId, coordinates.Position, range, entities, flags);
|
|
return entities;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MapId
|
|
|
|
public void GetEntitiesInRange(Type type, MapId mapId, Vector2 worldPos, float range, HashSet<Entity<IComponent>> entities, LookupFlags flags = DefaultFlags)
|
|
{
|
|
DebugTools.Assert(typeof(IComponent).IsAssignableFrom(type));
|
|
DebugTools.Assert(range > 0, "Range must be a positive float");
|
|
|
|
if (mapId == MapId.Nullspace) return;
|
|
|
|
var circle = new PhysShapeCircle(range);
|
|
var transform = new Transform(worldPos, 0f);
|
|
GetEntitiesIntersecting(type, mapId, circle, transform, entities, flags);
|
|
}
|
|
|
|
public void GetEntitiesInRange<T>(MapId mapId, Vector2 worldPos, float range, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
var shape = new PhysShapeCircle(range, worldPos);
|
|
var transform = Physics.Transform.Empty;
|
|
|
|
GetEntitiesInRange(mapId, shape, transform, entities, flags);
|
|
}
|
|
|
|
public void GetEntitiesInRange<T, TShape>(MapId mapId, TShape shape, Transform transform, HashSet<Entity<T>> entities, LookupFlags flags = DefaultFlags)
|
|
where T : IComponent
|
|
where TShape : IPhysShape
|
|
{
|
|
DebugTools.Assert(shape.Radius > 0, "Range must be a positive float");
|
|
|
|
if (mapId == MapId.Nullspace) return;
|
|
|
|
GetEntitiesIntersecting(mapId, shape, transform, entities, flags);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets entities with the specified component with the specified map.
|
|
/// </summary>
|
|
public void GetEntitiesOnMap<TComp1>(MapId mapId, HashSet<Entity<TComp1>> entities) where TComp1 : IComponent
|
|
{
|
|
var query = AllEntityQuery<TComp1, TransformComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp, out var xform))
|
|
{
|
|
if (xform.MapID != mapId)
|
|
continue;
|
|
|
|
entities.Add((uid, comp));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets entities with the specified component with the specified parent.
|
|
/// </summary>
|
|
public void GetEntitiesOnMap<TComp1, TComp2>(MapId mapId, HashSet<Entity<TComp1, TComp2>> entities)
|
|
where TComp1 : IComponent
|
|
where TComp2 : IComponent
|
|
{
|
|
var query = AllEntityQuery<TComp1, TComp2, TransformComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp, out var comp2, out var xform))
|
|
{
|
|
if (xform.MapID != mapId)
|
|
continue;
|
|
|
|
entities.Add((uid, comp, comp2));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Local
|
|
|
|
/// <summary>
|
|
/// Gets the entities intersecting the specified broadphase entity using a local AABB.
|
|
/// </summary>
|
|
public void GetLocalEntitiesIntersecting<T>(
|
|
EntityUid gridUid,
|
|
Vector2i localTile,
|
|
HashSet<Entity<T>> intersecting,
|
|
float enlargement = TileEnlargementRadius,
|
|
LookupFlags flags = DefaultFlags,
|
|
MapGridComponent? gridComp = null) where T : IComponent
|
|
{
|
|
ushort tileSize = 1;
|
|
|
|
if (_gridQuery.Resolve(gridUid, ref gridComp))
|
|
{
|
|
tileSize = gridComp.TileSize;
|
|
}
|
|
|
|
var localAABB = GetLocalBounds(localTile, tileSize);
|
|
localAABB = localAABB.Enlarged(enlargement);
|
|
GetLocalEntitiesIntersecting(gridUid, localAABB, intersecting, flags);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the entities intersecting the specified broadphase entity using a local AABB.
|
|
/// </summary>
|
|
public void GetLocalEntitiesIntersecting<T>(
|
|
EntityUid gridUid,
|
|
Box2 localAABB,
|
|
HashSet<Entity<T>> intersecting,
|
|
LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
var query = GetEntityQuery<T>();
|
|
AddLocalEntitiesIntersecting(gridUid, intersecting, localAABB, flags, query);
|
|
AddContained(intersecting, flags, query);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the entities intersecting the specified broadphase entity using a local AABB.
|
|
/// </summary>
|
|
public void GetLocalEntitiesIntersecting<T>(
|
|
Entity<BroadphaseComponent> grid,
|
|
Box2 localAABB,
|
|
HashSet<Entity<T>> intersecting,
|
|
EntityQuery<T> query,
|
|
LookupFlags flags = DefaultFlags) where T : IComponent
|
|
{
|
|
AddLocalEntitiesIntersecting(grid, intersecting, localAABB, flags, query, grid.Comp);
|
|
AddContained(intersecting, flags, query);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Gets entities with the specified component with the specified grid.
|
|
/// </summary>
|
|
public void GetGridEntities<TComp1>(EntityUid gridUid, HashSet<Entity<TComp1>> entities) where TComp1 : IComponent
|
|
{
|
|
var query = AllEntityQuery<TComp1, TransformComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp, out var xform))
|
|
{
|
|
if (xform.GridUid != gridUid)
|
|
continue;
|
|
|
|
entities.Add((uid, comp));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets entities with the specified component with the specified parent.
|
|
/// </summary>
|
|
public void GetChildEntities<TComp1>(EntityUid parentUid, HashSet<Entity<TComp1>> entities) where TComp1 : IComponent
|
|
{
|
|
var query = AllEntityQuery<TComp1, TransformComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp, out var xform))
|
|
{
|
|
if (xform.ParentUid != parentUid)
|
|
continue;
|
|
|
|
entities.Add((uid, comp));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets entities with the specified component with the specified parent.
|
|
/// </summary>
|
|
public void GetChildEntities<TComp1, TComp2>(EntityUid parentUid, HashSet<Entity<TComp1, TComp2>> entities)
|
|
where TComp1 : IComponent
|
|
where TComp2 : IComponent
|
|
{
|
|
var query = AllEntityQuery<TComp1, TComp2, TransformComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp, out var comp2, out var xform))
|
|
{
|
|
if (xform.ParentUid != parentUid)
|
|
continue;
|
|
|
|
entities.Add((uid, comp, comp2));
|
|
}
|
|
}
|
|
|
|
private readonly record struct GridQueryState<T, TShape>(
|
|
HashSet<Entity<T>> Intersecting,
|
|
TShape Shape,
|
|
Transform Transform,
|
|
EntityLookupSystem Lookup,
|
|
SharedPhysicsSystem Physics,
|
|
LookupFlags Flags,
|
|
EntityQuery<T> Query
|
|
) where T : IComponent
|
|
where TShape : IPhysShape;
|
|
|
|
private record struct AnyQueryState<T, TShape>(
|
|
bool Found,
|
|
EntityUid? Ignored,
|
|
TShape Shape,
|
|
Transform Transform,
|
|
FixtureSystem Fixtures,
|
|
SharedPhysicsSystem Physics,
|
|
IManifoldManager Manifolds,
|
|
EntityQuery<T> Query,
|
|
EntityQuery<FixturesComponent> FixturesQuery,
|
|
LookupFlags Flags
|
|
) where T : IComponent
|
|
where TShape : IPhysShape;
|
|
|
|
private readonly record struct QueryState<T, TShape>(
|
|
HashSet<Entity<T>> Intersecting,
|
|
TShape Shape,
|
|
Transform Transform,
|
|
FixtureSystem Fixtures,
|
|
SharedPhysicsSystem Physics,
|
|
IManifoldManager Manifolds,
|
|
EntityQuery<T> Query,
|
|
EntityQuery<FixturesComponent> FixturesQuery,
|
|
bool Sensors,
|
|
bool Approximate
|
|
) where T : IComponent
|
|
where TShape : IPhysShape;
|
|
}
|