Adds new functions to IComponentManager that can efficiently query for all entities with a set of components.

This commit is contained in:
Acruid
2020-07-29 15:48:32 -07:00
parent 0bf451d5d4
commit 350e05c152
10 changed files with 135 additions and 12 deletions

View File

@@ -98,7 +98,7 @@ namespace Robust.Client.Debugging
var drawing = new PhysDrawingAdapter(worldHandle);
var viewport = _eyeManager.GetWorldViewport();
foreach (var boundingBox in _componentManager.GetAllComponents<ICollidableComponent>())
foreach (var boundingBox in _componentManager.EntityQuery<ICollidableComponent>())
{
var physBody = (IPhysBody)boundingBox;

View File

@@ -31,7 +31,7 @@ namespace Robust.Client.GameStates
{
var worldHandle = (DrawingHandleWorld) handle;
var viewport = _eyeManager.GetWorldViewport();
foreach (var boundingBox in _componentManager.GetAllComponents<ICollidableComponent>())
foreach (var boundingBox in _componentManager.EntityQuery<ICollidableComponent>())
{
// all entities have a TransformComponent
var transform = ((IComponent)boundingBox).Owner.Transform;

View File

@@ -38,7 +38,7 @@ namespace Robust.Client.Physics
private List<ICollidableComponent> ActuallyRelevant()
{
var relevant = _componentManager.GetAllComponents<ICollidableComponent>().Where(p => p.Predict)
var relevant = _componentManager.EntityQuery<ICollidableComponent>().Where(p => p.Predict)
.ToList();
return relevant;
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using Robust.Shared.Exceptions;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
@@ -453,8 +454,10 @@ namespace Robust.Shared.GameObjects
}
}
#region Join Functions
/// <inheritdoc />
public IEnumerable<T> GetAllComponents<T>()
public IEnumerable<T> EntityQuery<T>()
{
var comps = _entTraitDict[typeof(T)];
foreach (var comp in comps.Values)
@@ -465,6 +468,87 @@ namespace Robust.Shared.GameObjects
}
}
/// <inheritdoc />
public IEnumerable<(TComp1, TComp2)> EntityQuery<TComp1, TComp2>()
where TComp1 : IComponent
where TComp2 : IComponent
{
// this would prob be faster if trait1 was a list (or an array of structs hue).
var trait1 = _entTraitDict[typeof(TComp1)];
var trait2 = _entTraitDict[typeof(TComp2)];
// you really want trait1 to be the smaller set of components
foreach (var kvComp in trait1)
{
var uid = kvComp.Key;
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
yield return ((TComp1) (object) kvComp.Value, (TComp2) (object) t2Comp);
}
}
/// <inheritdoc />
public IEnumerable<(TComp1, TComp2, TComp3)> EntityQuery<TComp1, TComp2, TComp3>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
{
var trait1 = _entTraitDict[typeof(TComp1)];
var trait2 = _entTraitDict[typeof(TComp2)];
var trait3 = _entTraitDict[typeof(TComp3)];
foreach (var kvComp in trait1)
{
var uid = kvComp.Key;
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
continue;
yield return ((TComp1) (object) kvComp.Value,
(TComp2) (object) t2Comp,
(TComp3) (object) t3Comp);
}
}
/// <inheritdoc />
public IEnumerable<(TComp1, TComp2, TComp3, TComp4)> EntityQuery<TComp1, TComp2, TComp3, TComp4>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent
{
var trait1 = _entTraitDict[typeof(TComp1)];
var trait2 = _entTraitDict[typeof(TComp2)];
var trait3 = _entTraitDict[typeof(TComp3)];
var trait4 = _entTraitDict[typeof(TComp4)];
foreach (var kvComp in trait1)
{
var uid = kvComp.Key;
if (!trait2.TryGetValue(uid, out var t2Comp) || t2Comp.Deleted)
continue;
if (!trait3.TryGetValue(uid, out var t3Comp) || t3Comp.Deleted)
continue;
if (!trait4.TryGetValue(uid, out var t4Comp) || t4Comp.Deleted)
continue;
yield return ((TComp1) (object) kvComp.Value,
(TComp2) (object) t2Comp,
(TComp3) (object) t3Comp,
(TComp4) (object) t4Comp);
}
}
#endregion
/// <inheritdoc />
public IEnumerable<IComponent> GetAllComponents(Type type)
{

View File

@@ -98,7 +98,7 @@ namespace Robust.Shared.GameObjects
public IEnumerable<IEntity> Match(IEntityManager entityMan)
{
return entityMan.ComponentManager.GetAllComponents<T>().Select(component => component.Owner);
return entityMan.ComponentManager.EntityQuery<T>().Select(component => component.Owner);
}
}
@@ -176,5 +176,4 @@ namespace Robust.Shared.GameObjects
return entityMan.GetEntities(new TypeEntityQuery(ComponentTypes.First())).Where(entity => Match(entity));
}
}
}

View File

@@ -21,10 +21,14 @@ namespace Robust.Shared.GameObjects.Systems
public abstract class EntitySystem : IEntitySystem
{
[Dependency] protected readonly IEntityManager EntityManager = default!;
[Dependency] protected readonly IComponentManager ComponentManager = default!;
[Dependency] protected readonly IEntitySystemManager EntitySystemManager = default!;
[Dependency] protected readonly IEntityNetworkManager EntityNetworkManager = default!;
[Obsolete("You need to create and store the query yourself in a field.")]
protected IEntityQuery? EntityQuery;
[Obsolete("You need to use `EntityManager.GetEntities(EntityQuery)`, or store a query yourself.")]
protected IEnumerable<IEntity> RelevantEntities => EntityQuery != null ? EntityManager.GetEntities(EntityQuery) : EntityManager.GetEntities();
protected internal List<Type> UpdatesAfter { get; } = new List<Type>();

View File

@@ -201,7 +201,43 @@ namespace Robust.Shared.Interfaces.GameObjects
/// </summary>
/// <typeparam name="T">A trait or type of a component to retrieve.</typeparam>
/// <returns>All components that have the specified type.</returns>
IEnumerable<T> GetAllComponents<T>();
IEnumerable<T> EntityQuery<T>();
/// <summary>
/// Returns the relevant components from all entities that contain the two required components.
/// </summary>
/// <typeparam name="TComp1">First required component.</typeparam>
/// <typeparam name="TComp2">Second required component.</typeparam>
/// <returns>The pairs of components from each entity that has the two required components.</returns>
IEnumerable<(TComp1, TComp2)> EntityQuery<TComp1, TComp2>()
where TComp1 : IComponent
where TComp2 : IComponent;
/// <summary>
/// Returns the relevant components from all entities that contain the three required components.
/// </summary>
/// <typeparam name="TComp1">First required component.</typeparam>
/// <typeparam name="TComp2">Second required component.</typeparam>
/// <typeparam name="TComp3">Third required component.</typeparam>
/// <returns>The pairs of components from each entity that has the three required components.</returns>
IEnumerable<(TComp1, TComp2, TComp3)> EntityQuery<TComp1, TComp2, TComp3>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent;
/// <summary>
/// Returns the relevant components from all entities that contain the four required components.
/// </summary>
/// <typeparam name="TComp1">First required component.</typeparam>
/// <typeparam name="TComp2">Second required component.</typeparam>
/// <typeparam name="TComp3">Third required component.</typeparam>
/// <typeparam name="TComp4">Fourth required component.</typeparam>
/// <returns>The pairs of components from each entity that has the four required components.</returns>
IEnumerable<(TComp1, TComp2, TComp3, TComp4)> EntityQuery<TComp1, TComp2, TComp3, TComp4>()
where TComp1 : IComponent
where TComp2 : IComponent
where TComp3 : IComponent
where TComp4 : IComponent;
/// <summary>
/// Returns ALL component instances of a specified type.

View File

@@ -209,7 +209,7 @@ namespace Robust.Shared.Map
// locate the entity that represents this map that was just sent to us
IEntity? sharedMapEntity = null;
var mapComps = _entityManager.ComponentManager.GetAllComponents<IMapComponent>();
var mapComps = _entityManager.ComponentManager.EntityQuery<IMapComponent>();
foreach (var mapComp in mapComps)
{
if (!mapComp.Owner.Uid.IsClientSide() && mapComp.WorldMap == mapId)
@@ -259,7 +259,7 @@ namespace Robust.Shared.Map
cGridComp.ClearGridId();
cEntity.Delete(); // normal entities are already parented to the shared comp, client comp has no children
var gridComps = _entityManager.ComponentManager.GetAllComponents<IMapGridComponent>();
var gridComps = _entityManager.ComponentManager.EntityQuery<IMapGridComponent>();
foreach (var gridComp in gridComps)
{
if (gridComp.GridIndex == kvNewGrid.Key)

View File

@@ -245,7 +245,7 @@ namespace Robust.Shared.Map
if (actualID != MapId.Nullspace) // nullspace isn't bound to an entity
{
var mapComps = _entityManager.ComponentManager.GetAllComponents<IMapComponent>();
var mapComps = _entityManager.ComponentManager.EntityQuery<IMapComponent>();
IMapComponent? result = null;
foreach (var mapComp in mapComps)
@@ -446,7 +446,7 @@ namespace Robust.Shared.Map
{
// the entity may already exist from map deserialization
IMapGridComponent? result = null;
foreach (var comp in _entityManager.ComponentManager.GetAllComponents<IMapGridComponent>())
foreach (var comp in _entityManager.ComponentManager.EntityQuery<IMapGridComponent>())
{
if (comp.GridIndex != actualID)
continue;

View File

@@ -208,7 +208,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
manager.AddComponent(entity, component);
// Act
var result = manager.GetAllComponents<DummyComponent>();
var result = manager.EntityQuery<DummyComponent>();
// Assert
var list = result.ToList();