advanced query system
parent
728109bfc6
commit
50974c181a
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
|
@ -6,7 +7,12 @@ namespace Encompass
|
||||||
internal class ComponentStore
|
internal class ComponentStore
|
||||||
{
|
{
|
||||||
private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512);
|
private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512);
|
||||||
private ComponentBitSet componentBitSet = new ComponentBitSet();
|
private ComponentBitSet componentBitSet;
|
||||||
|
|
||||||
|
public ComponentStore(Dictionary<Type, int> typeToIndex)
|
||||||
|
{
|
||||||
|
componentBitSet = new ComponentBitSet(typeToIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
|
public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
|
||||||
{
|
{
|
||||||
|
@ -22,7 +28,6 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
var store = new TypedComponentStore<TComponent>();
|
var store = new TypedComponentStore<TComponent>();
|
||||||
Stores.Add(typeof(TComponent), store);
|
Stores.Add(typeof(TComponent), store);
|
||||||
componentBitSet.RegisterType<TComponent>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +52,9 @@ namespace Encompass
|
||||||
return Stores.ContainsKey(type) && Stores[type].Has(entity);
|
return Stores.ContainsKey(type) && Stores[type].Has(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> EntitiesWithComponents(IEnumerable<Type> types)
|
public BitArray EntityBitArray(Entity entity)
|
||||||
{
|
{
|
||||||
return componentBitSet.EntitiesWithComponents(types);
|
return componentBitSet.EntityBitArray(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent
|
public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
|
|
@ -8,21 +8,25 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
BitArrayPool bitArrayPool = new BitArrayPool(32768); // todo: set entity cap
|
BitArrayPool bitArrayPool = new BitArrayPool(32768); // todo: set entity cap
|
||||||
Dictionary<Entity, BitArray> entities = new Dictionary<Entity, BitArray>();
|
Dictionary<Entity, BitArray> entities = new Dictionary<Entity, BitArray>();
|
||||||
Dictionary<Type, int> typeToIndex = new Dictionary<Type, int>();
|
Dictionary<Type, int> TypeToIndex { get; set; }
|
||||||
BitArray queryArray;
|
BitArray withQueryArray;
|
||||||
|
BitArray withoutQueryArray;
|
||||||
|
BitArray emptyArray;
|
||||||
|
|
||||||
public void RegisterType<TComponent>() where TComponent : struct, IComponent
|
public ComponentBitSet(Dictionary<Type, int> typeToIndex)
|
||||||
{
|
{
|
||||||
typeToIndex.Add(typeof(TComponent), typeToIndex.Count);
|
TypeToIndex = typeToIndex;
|
||||||
foreach (var kvp in entities)
|
|
||||||
{
|
|
||||||
kvp.Value.Length = typeToIndex.Count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FinishRegistering()
|
public void FinishRegistering()
|
||||||
{
|
{
|
||||||
queryArray = new BitArray(typeToIndex.Count);
|
withQueryArray = new BitArray(TypeToIndex.Count);
|
||||||
|
withoutQueryArray = new BitArray(TypeToIndex.Count);
|
||||||
|
emptyArray = new BitArray(TypeToIndex.Count);
|
||||||
|
foreach (var kvp in entities)
|
||||||
|
{
|
||||||
|
kvp.Value.Length = TypeToIndex.Count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
|
@ -36,19 +40,19 @@ namespace Encompass
|
||||||
|
|
||||||
public void AddEntity(Entity entity)
|
public void AddEntity(Entity entity)
|
||||||
{
|
{
|
||||||
var bitArray = bitArrayPool.Obtain(typeToIndex.Count);
|
var bitArray = bitArrayPool.Obtain(TypeToIndex.Count);
|
||||||
entities.Add(entity, bitArray);
|
entities.Add(entity, bitArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set<TComponent>(Entity entity) where TComponent : struct, IComponent
|
public void Set<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (!entities.ContainsKey(entity)) { AddEntity(entity); }
|
if (!entities.ContainsKey(entity)) { AddEntity(entity); }
|
||||||
entities[entity].Set(typeToIndex[typeof(TComponent)], true);
|
entities[entity].Set(TypeToIndex[typeof(TComponent)], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
public void RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
entities[entity].Set(typeToIndex[typeof(TComponent)], false);
|
entities[entity].Set(TypeToIndex[typeof(TComponent)], false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveEntity(Entity entity)
|
public void RemoveEntity(Entity entity)
|
||||||
|
@ -60,26 +64,9 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> EntitiesWithComponents(IEnumerable<Type> types)
|
public BitArray EntityBitArray(Entity entity)
|
||||||
{
|
{
|
||||||
foreach (var kvp in entities)
|
return entities.ContainsKey(entity) ? entities[entity] : emptyArray;
|
||||||
{
|
|
||||||
queryArray.SetAll(false);
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
queryArray.Set(typeToIndex[type], true);
|
|
||||||
}
|
|
||||||
queryArray.And(kvp.Value);
|
|
||||||
var hasComponents = true;
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
if (!queryArray.Get(typeToIndex[type])) {
|
|
||||||
hasComponents = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasComponents) { yield return kvp.Key; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,14 @@ namespace Encompass
|
||||||
private readonly DrawLayerManager drawLayerManager;
|
private readonly DrawLayerManager drawLayerManager;
|
||||||
private readonly ComponentUpdateManager componentUpdateManager;
|
private readonly ComponentUpdateManager componentUpdateManager;
|
||||||
|
|
||||||
private readonly ComponentStore componentStore = new ComponentStore();
|
private readonly ComponentStore componentStore;
|
||||||
private readonly HashSet<Entity> entitiesMarkedForRemoval = new HashSet<Entity>();
|
private readonly HashSet<Entity> entitiesMarkedForRemoval = new HashSet<Entity>();
|
||||||
|
|
||||||
public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager)
|
public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager, Dictionary<Type, int> typeToIndex)
|
||||||
{
|
{
|
||||||
this.drawLayerManager = drawLayerManager;
|
this.drawLayerManager = drawLayerManager;
|
||||||
this.componentUpdateManager = componentUpdateManager;
|
this.componentUpdateManager = componentUpdateManager;
|
||||||
|
componentStore = new ComponentStore(typeToIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -96,10 +97,5 @@ namespace Encompass
|
||||||
componentUpdateManager.Remove<TComponent>(entity);
|
componentUpdateManager.Remove<TComponent>(entity);
|
||||||
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity);
|
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> EntitiesWithComponents(IEnumerable<Type> types)
|
|
||||||
{
|
|
||||||
return componentStore.EntitiesWithComponents(types);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,27 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
internal class ComponentUpdateManager
|
internal class ComponentUpdateManager
|
||||||
{
|
{
|
||||||
private readonly ComponentStore existingAndPendingComponentStore = new ComponentStore();
|
private readonly ComponentStore existingAndPendingComponentStore;
|
||||||
private readonly ComponentStore existingComponentStore = new ComponentStore();
|
private readonly ComponentStore existingComponentStore;
|
||||||
private readonly ComponentStore pendingComponentStore = new ComponentStore();
|
private readonly ComponentStore pendingComponentStore;
|
||||||
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
||||||
|
private Dictionary<Type, int> typeToIndex;
|
||||||
|
public ComponentStore UpToDateComponentStore { get; private set; }
|
||||||
|
|
||||||
public ComponentStore UpToDateComponentStore { get; private set; } = new ComponentStore();
|
public ComponentUpdateManager(Dictionary<Type, int> typeToIndex)
|
||||||
|
{
|
||||||
|
existingAndPendingComponentStore = new ComponentStore(typeToIndex);
|
||||||
|
existingComponentStore = new ComponentStore(typeToIndex);
|
||||||
|
pendingComponentStore = new ComponentStore(typeToIndex);
|
||||||
|
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
||||||
|
this.typeToIndex = typeToIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
@ -183,5 +194,63 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
UpToDateComponentStore.Remove<TComponent>(entity);
|
UpToDateComponentStore.Remove<TComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal IEnumerable<Entity> QueryEntities(IEnumerable<Entity> entities, HashSet<Type> readTypes, HashSet<Type> readPendingTypes, IEnumerable<Type> withTypes, IEnumerable<Type> withoutTypes)
|
||||||
|
{
|
||||||
|
var pendingMask = new BitArray(typeToIndex.Count);
|
||||||
|
foreach (var type in readPendingTypes)
|
||||||
|
{
|
||||||
|
pendingMask.Set(typeToIndex[type], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var readMask = new BitArray(typeToIndex.Count);
|
||||||
|
foreach (var type in readTypes)
|
||||||
|
{
|
||||||
|
readMask.Set(typeToIndex[type], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var withMask = new BitArray(typeToIndex.Count);
|
||||||
|
foreach (var type in withTypes)
|
||||||
|
{
|
||||||
|
withMask.Set(typeToIndex[type], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var withoutMask = new BitArray(typeToIndex.Count);
|
||||||
|
foreach (var type in withoutTypes)
|
||||||
|
{
|
||||||
|
withoutMask.Set(typeToIndex[type], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entity in entities)
|
||||||
|
{
|
||||||
|
var pendingEntity = pendingComponentStore.EntityBitArray(entity);
|
||||||
|
var existingEntity = existingComponentStore.EntityBitArray(entity);
|
||||||
|
|
||||||
|
if (VerifyTypes(pendingEntity, existingEntity, readMask, pendingMask, withMask, withoutMask)) { yield return entity; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool VerifyTypes(BitArray pendingEntity, BitArray existingEntity, BitArray readMask, BitArray pendingMask, BitArray withMask, BitArray withoutMask)
|
||||||
|
{
|
||||||
|
var arrayA = new BitArray(typeToIndex.Count);
|
||||||
|
var arrayB = new BitArray(typeToIndex.Count);
|
||||||
|
var arrayC = new BitArray(typeToIndex.Count);
|
||||||
|
|
||||||
|
var notWithMask = new BitArray(typeToIndex.Count);
|
||||||
|
notWithMask.Or(withMask).Not();
|
||||||
|
|
||||||
|
arrayA.Or(pendingMask).And(withMask).And(pendingEntity);
|
||||||
|
arrayB.Or(readMask).And(withMask).And(existingEntity);
|
||||||
|
arrayA.Or(arrayB).Or(notWithMask);
|
||||||
|
|
||||||
|
arrayB.SetAll(false);
|
||||||
|
arrayB.Or(pendingMask).And(withoutMask).And(pendingEntity).Not();
|
||||||
|
arrayC.Or(readMask).And(withoutMask).And(existingEntity).Not();
|
||||||
|
arrayB.And(arrayC);
|
||||||
|
|
||||||
|
arrayA.And(arrayB);
|
||||||
|
|
||||||
|
return !arrayA.Cast<bool>().Contains(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,12 @@ namespace Encompass
|
||||||
private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512);
|
private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512);
|
||||||
|
|
||||||
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToLayer = new Dictionary<Type, Dictionary<Entity, int>>(512);
|
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToLayer = new Dictionary<Type, Dictionary<Entity, int>>(512);
|
||||||
|
private Dictionary<Type, int> typeToIndex;
|
||||||
public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } }
|
public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } }
|
||||||
|
|
||||||
public DrawLayerManager()
|
public DrawLayerManager(Dictionary<Type, int> typeToIndex)
|
||||||
{
|
{
|
||||||
|
this.typeToIndex = typeToIndex;
|
||||||
RegisterDrawLayer(0);
|
RegisterDrawLayer(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +28,15 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
layerOrder.Add(layer, layer);
|
layerOrder.Add(layer, layer);
|
||||||
layerIndexToGeneralRenderers.Add(layer, new HashSet<GeneralRenderer>());
|
layerIndexToGeneralRenderers.Add(layer, new HashSet<GeneralRenderer>());
|
||||||
layerIndexToComponentStore.Add(layer, new ComponentStore());
|
layerIndexToComponentStore.Add(layer, new ComponentStore(typeToIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishRegistering()
|
||||||
|
{
|
||||||
|
foreach (var store in layerIndexToComponentStore.Values)
|
||||||
|
{
|
||||||
|
store.FinishRegistering();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -612,9 +612,12 @@ namespace Encompass
|
||||||
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
|
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria.
|
||||||
|
/// </summary>
|
||||||
protected EntitySetQuery QueryEntities()
|
protected EntitySetQuery QueryEntities()
|
||||||
{
|
{
|
||||||
return new EntitySetQuery(componentManager);
|
return new EntitySetQuery(entityManager, componentUpdateManager, readTypes, readPendingTypes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,17 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
private readonly int entityCapacity;
|
private readonly int entityCapacity;
|
||||||
private readonly IDManager idManager = new IDManager();
|
private readonly IDManager idManager = new IDManager();
|
||||||
private readonly HashSet<int> IDs = new HashSet<int>();
|
private readonly Dictionary<int, Entity> IDs = new Dictionary<int, Entity>(32768);
|
||||||
|
|
||||||
private readonly HashSet<Entity> entitiesMarkedForDestroy = new HashSet<Entity>();
|
private readonly HashSet<Entity> entitiesMarkedForDestroy = new HashSet<Entity>();
|
||||||
|
|
||||||
private readonly ComponentManager componentManager;
|
private readonly ComponentManager componentManager;
|
||||||
|
|
||||||
|
public IEnumerable<Entity> Entities
|
||||||
|
{
|
||||||
|
get { return IDs.Values; }
|
||||||
|
}
|
||||||
|
|
||||||
public EntityManager(ComponentManager componentManager, int entityCapacity)
|
public EntityManager(ComponentManager componentManager, int entityCapacity)
|
||||||
{
|
{
|
||||||
this.componentManager = componentManager;
|
this.componentManager = componentManager;
|
||||||
|
@ -30,7 +35,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
var id = NextID();
|
var id = NextID();
|
||||||
var entity = new Entity(id);
|
var entity = new Entity(id);
|
||||||
IDs.Add(id);
|
IDs.Add(id, entity);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -41,7 +46,7 @@ namespace Encompass
|
||||||
|
|
||||||
public bool EntityExists(int id)
|
public bool EntityExists(int id)
|
||||||
{
|
{
|
||||||
return IDs.Contains(id);
|
return IDs.ContainsKey(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkForDestroy(Entity entity)
|
public void MarkForDestroy(Entity entity)
|
||||||
|
|
|
@ -5,39 +5,57 @@ using System.Collections.Immutable;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EntitySetQuery is used to efficiently obtain a set of Entities that have all required Components and do not have any forbidden Components.
|
||||||
|
/// </summary>
|
||||||
public struct EntitySetQuery : IEnumerable<Entity>
|
public struct EntitySetQuery : IEnumerable<Entity>
|
||||||
{
|
{
|
||||||
private EntitySetQuery(ComponentManager componentManager, ImmutableArray<Type> includes, ImmutableArray<Type> excludes)
|
private EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, HashSet<Type> readTypes, HashSet<Type> readPendingTypes, ImmutableArray<Type> includes, ImmutableArray<Type> excludes)
|
||||||
{
|
{
|
||||||
ComponentManager = componentManager;
|
EntityManager = entityManager;
|
||||||
|
ComponentUpdateManager = componentUpdateManager;
|
||||||
|
ReadTypes = readTypes;
|
||||||
|
ReadPendingTypes = readPendingTypes;
|
||||||
Includes = includes;
|
Includes = includes;
|
||||||
Excludes = excludes;
|
Excludes = excludes;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal EntitySetQuery(ComponentManager componentManager)
|
internal EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, HashSet<Type> readTypes, HashSet<Type> readPendingTypes)
|
||||||
{
|
{
|
||||||
ComponentManager = componentManager;
|
EntityManager = entityManager;
|
||||||
|
ComponentUpdateManager = componentUpdateManager;
|
||||||
|
ReadTypes = readTypes;
|
||||||
|
ReadPendingTypes = readPendingTypes;
|
||||||
Includes = ImmutableArray.Create<Type>();
|
Includes = ImmutableArray.Create<Type>();
|
||||||
Excludes = ImmutableArray.Create<Type>();
|
Excludes = ImmutableArray.Create<Type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ComponentManager ComponentManager { get; }
|
private EntityManager EntityManager { get; }
|
||||||
|
private ComponentUpdateManager ComponentUpdateManager { get; }
|
||||||
|
private HashSet<Type> ReadTypes { get; }
|
||||||
|
private HashSet<Type> ReadPendingTypes { get; }
|
||||||
private ImmutableArray<Type> Includes { get; }
|
private ImmutableArray<Type> Includes { get; }
|
||||||
private ImmutableArray<Type> Excludes { get; }
|
private ImmutableArray<Type> Excludes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Designates that the given component type is required.
|
||||||
|
/// </summary>
|
||||||
public EntitySetQuery With<TComponent>() where TComponent : struct, IComponent
|
public EntitySetQuery With<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return new EntitySetQuery(ComponentManager, Includes.Add(typeof(TComponent)), Excludes);
|
return new EntitySetQuery(EntityManager, ComponentUpdateManager, ReadTypes, ReadPendingTypes, Includes.Add(typeof(TComponent)), Excludes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Designates that the given component type is forbidden.
|
||||||
|
/// </summary>
|
||||||
public EntitySetQuery Without<TComponent>() where TComponent : struct, IComponent
|
public EntitySetQuery Without<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return new EntitySetQuery(ComponentManager, Includes, Excludes.Add(typeof(TComponent)));
|
return new EntitySetQuery(EntityManager, ComponentUpdateManager, ReadTypes, ReadPendingTypes, Includes, Excludes.Add(typeof(TComponent)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<Entity> GetEnumerator()
|
public IEnumerator<Entity> GetEnumerator()
|
||||||
{
|
{
|
||||||
return ComponentManager.EntitiesWithComponents(Includes).GetEnumerator();
|
return ComponentUpdateManager.QueryEntities(EntityManager.Entities, ReadTypes, ReadPendingTypes, Includes, Excludes).GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
|
|
@ -21,8 +21,8 @@ namespace Encompass
|
||||||
private readonly int entityCapacity;
|
private readonly int entityCapacity;
|
||||||
private readonly List<Engine> engines = new List<Engine>();
|
private readonly List<Engine> engines = new List<Engine>();
|
||||||
private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<Engine>();
|
private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<Engine>();
|
||||||
private readonly ComponentStore startingComponentStoreForComponentManager = new ComponentStore();
|
private readonly ComponentStore startingComponentStoreForComponentManager;
|
||||||
private readonly ComponentStore startingComponentStoreForComponentUpdateManager = new ComponentStore();
|
private readonly ComponentStore startingComponentStoreForComponentUpdateManager;
|
||||||
|
|
||||||
private readonly ComponentManager componentManager;
|
private readonly ComponentManager componentManager;
|
||||||
private readonly EntityManager entityManager;
|
private readonly EntityManager entityManager;
|
||||||
|
@ -40,16 +40,21 @@ namespace Encompass
|
||||||
|
|
||||||
private readonly HashSet<Type> messageTypes = new HashSet<Type>();
|
private readonly HashSet<Type> messageTypes = new HashSet<Type>();
|
||||||
|
|
||||||
|
private readonly Dictionary<Type, int> typeToIndex = new Dictionary<Type, int>();
|
||||||
|
|
||||||
public WorldBuilder(int entityCapacity = 32768)
|
public WorldBuilder(int entityCapacity = 32768)
|
||||||
{
|
{
|
||||||
this.entityCapacity = entityCapacity;
|
this.entityCapacity = entityCapacity;
|
||||||
drawLayerManager = new DrawLayerManager();
|
drawLayerManager = new DrawLayerManager(typeToIndex);
|
||||||
timeManager = new TimeManager();
|
timeManager = new TimeManager();
|
||||||
componentUpdateManager = new ComponentUpdateManager();
|
componentUpdateManager = new ComponentUpdateManager(typeToIndex);
|
||||||
componentManager = new ComponentManager(drawLayerManager, componentUpdateManager);
|
componentManager = new ComponentManager(drawLayerManager, componentUpdateManager, typeToIndex);
|
||||||
messageManager = new MessageManager(timeManager);
|
messageManager = new MessageManager(timeManager);
|
||||||
entityManager = new EntityManager(componentManager, entityCapacity);
|
entityManager = new EntityManager(componentManager, entityCapacity);
|
||||||
renderManager = new RenderManager(drawLayerManager);
|
renderManager = new RenderManager(drawLayerManager);
|
||||||
|
|
||||||
|
startingComponentStoreForComponentManager = new ComponentStore(typeToIndex);
|
||||||
|
startingComponentStoreForComponentUpdateManager = new ComponentStore(typeToIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -84,7 +89,9 @@ namespace Encompass
|
||||||
RegisterComponentType<TComponent>();
|
RegisterComponentType<TComponent>();
|
||||||
componentTypesToRegister.Add(typeof(TComponent));
|
componentTypesToRegister.Add(typeof(TComponent));
|
||||||
|
|
||||||
|
startingComponentStoreForComponentManager.FinishRegistering();
|
||||||
startingComponentStoreForComponentManager.Set(entity, component);
|
startingComponentStoreForComponentManager.Set(entity, component);
|
||||||
|
startingComponentStoreForComponentUpdateManager.FinishRegistering();
|
||||||
startingComponentStoreForComponentUpdateManager.Set(entity, component);
|
startingComponentStoreForComponentUpdateManager.Set(entity, component);
|
||||||
|
|
||||||
if (component is IDrawableComponent drawableComponent)
|
if (component is IDrawableComponent drawableComponent)
|
||||||
|
@ -96,10 +103,14 @@ namespace Encompass
|
||||||
|
|
||||||
internal void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
internal void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
componentManager.RegisterComponentType<TComponent>();
|
if (!typeToIndex.ContainsKey(typeof(TComponent)))
|
||||||
componentUpdateManager.RegisterComponentType<TComponent>();
|
{
|
||||||
startingComponentStoreForComponentManager.RegisterComponentType<TComponent>();
|
typeToIndex.Add(typeof(TComponent), typeToIndex.Count);
|
||||||
startingComponentStoreForComponentUpdateManager.RegisterComponentType<TComponent>();
|
componentManager.RegisterComponentType<TComponent>();
|
||||||
|
componentUpdateManager.RegisterComponentType<TComponent>();
|
||||||
|
startingComponentStoreForComponentManager.RegisterComponentType<TComponent>();
|
||||||
|
startingComponentStoreForComponentUpdateManager.RegisterComponentType<TComponent>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterMessageTypes(IEnumerable<Type> types)
|
internal void RegisterMessageTypes(IEnumerable<Type> types)
|
||||||
|
@ -363,13 +374,14 @@ namespace Encompass
|
||||||
engineOrder.Add(emitterEngine);
|
engineOrder.Add(emitterEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreloadJIT(componentTypesToRegister, messageTypes);
|
|
||||||
|
|
||||||
componentManager.FinishRegistering();
|
componentManager.FinishRegistering();
|
||||||
componentUpdateManager.FinishRegistering();
|
componentUpdateManager.FinishRegistering();
|
||||||
|
drawLayerManager.FinishRegistering();
|
||||||
startingComponentStoreForComponentManager.FinishRegistering();
|
startingComponentStoreForComponentManager.FinishRegistering();
|
||||||
startingComponentStoreForComponentUpdateManager.FinishRegistering();
|
startingComponentStoreForComponentUpdateManager.FinishRegistering();
|
||||||
|
|
||||||
|
PreloadJIT(componentTypesToRegister, messageTypes);
|
||||||
|
|
||||||
foreach (var engine in engineGraph.TopologicalSort())
|
foreach (var engine in engineGraph.TopologicalSort())
|
||||||
{
|
{
|
||||||
engineOrder.Add(engine);
|
engineOrder.Add(engine);
|
||||||
|
@ -401,9 +413,9 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
var dummyTimeManager = new TimeManager();
|
var dummyTimeManager = new TimeManager();
|
||||||
var dummyMessageManager = new MessageManager(dummyTimeManager);
|
var dummyMessageManager = new MessageManager(dummyTimeManager);
|
||||||
var dummyDrawLayerManager = new DrawLayerManager();
|
var dummyDrawLayerManager = new DrawLayerManager(typeToIndex);
|
||||||
var dummyComponentUpdateManager = new ComponentUpdateManager();
|
var dummyComponentUpdateManager = new ComponentUpdateManager(typeToIndex);
|
||||||
var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, dummyComponentUpdateManager);
|
var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, dummyComponentUpdateManager, typeToIndex);
|
||||||
var dummyEntityManager = new EntityManager(dummyComponentManager, entityCapacity);
|
var dummyEntityManager = new EntityManager(dummyComponentManager, entityCapacity);
|
||||||
var dummyRenderManager = new RenderManager(dummyDrawLayerManager);
|
var dummyRenderManager = new RenderManager(dummyDrawLayerManager);
|
||||||
|
|
||||||
|
|
|
@ -1088,42 +1088,156 @@ namespace Tests
|
||||||
undilatedDeltaTime.Should().Be(0.5);
|
undilatedDeltaTime.Should().Be(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MockComponentB : IComponent { }
|
public class QueryTests
|
||||||
|
|
||||||
static Entity[] queriedEntities;
|
|
||||||
|
|
||||||
class EntityQueryEngine : Engine
|
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
struct MockComponentB : IComponent { }
|
||||||
|
struct MockComponentC : IComponent { }
|
||||||
|
struct MockComponentD : IComponent { }
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent), typeof(MockComponentB))]
|
||||||
|
class EntityQueryWithComponentsEngine : Engine
|
||||||
{
|
{
|
||||||
queriedEntities = QueryEntities().With<MockComponent>().With<MockComponentB>().ToArray();
|
private List<Entity> entities;
|
||||||
|
|
||||||
|
public EntityQueryWithComponentsEngine(List<Entity> entities)
|
||||||
|
{
|
||||||
|
this.entities = entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
entities.Clear();
|
||||||
|
|
||||||
|
entities.AddRange(QueryEntities().With<MockComponent>().With<MockComponentB>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void EntitiesWithComponents()
|
public void EntitiesWithComponents()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
var entityB = worldBuilder.CreateEntity();
|
var entityB = worldBuilder.CreateEntity();
|
||||||
var entityC = worldBuilder.CreateEntity();
|
var entityC = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
worldBuilder.SetComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
worldBuilder.SetComponent(entity, new MockComponentB());
|
worldBuilder.SetComponent(entity, new MockComponentB());
|
||||||
|
|
||||||
worldBuilder.SetComponent(entityB, new MockComponent());
|
worldBuilder.SetComponent(entityB, new MockComponent());
|
||||||
worldBuilder.SetComponent(entityB, new MockComponentB());
|
worldBuilder.SetComponent(entityB, new MockComponentB());
|
||||||
|
|
||||||
worldBuilder.SetComponent(entityC, new MockComponentB());
|
worldBuilder.SetComponent(entityC, new MockComponentB());
|
||||||
|
|
||||||
worldBuilder.AddEngine(new EntityQueryEngine());
|
var queriedEntities = new List<Entity>();
|
||||||
|
worldBuilder.AddEngine(new EntityQueryWithComponentsEngine(queriedEntities));
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
world.Update(0.01);
|
world.Update(0.01);
|
||||||
|
|
||||||
queriedEntities.Should().BeEquivalentTo(new Entity[] { entity, entityB });
|
queriedEntities.Should().BeEquivalentTo(new Entity[] { entity, entityB });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
|
class EntityQueryWithoutComponentsEngine : Engine
|
||||||
|
{
|
||||||
|
private List<Entity> entities;
|
||||||
|
|
||||||
|
public EntityQueryWithoutComponentsEngine(List<Entity> entities)
|
||||||
|
{
|
||||||
|
this.entities = entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
entities.Clear();
|
||||||
|
|
||||||
|
entities.AddRange(QueryEntities().Without<MockComponent>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EntitiesWithoutComponents()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
|
||||||
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
var entityB = worldBuilder.CreateEntity();
|
||||||
|
var entityC = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponentB());
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entityB, new MockComponent());
|
||||||
|
worldBuilder.SetComponent(entityB, new MockComponentB());
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entityC, new MockComponentB());
|
||||||
|
|
||||||
|
var queriedEntities = new List<Entity>();
|
||||||
|
worldBuilder.AddEngine(new EntityQueryWithoutComponentsEngine(queriedEntities));
|
||||||
|
|
||||||
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
|
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityC });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent), typeof(MockComponentB), typeof(MockComponentD))]
|
||||||
|
class EntityQueryWithandWithoutComponentsEngine : Engine
|
||||||
|
{
|
||||||
|
private List<Entity> entities;
|
||||||
|
|
||||||
|
public EntityQueryWithandWithoutComponentsEngine(List<Entity> entities)
|
||||||
|
{
|
||||||
|
this.entities = entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
entities.Clear();
|
||||||
|
|
||||||
|
entities.AddRange(QueryEntities().With<MockComponent>()
|
||||||
|
.With<MockComponentB>()
|
||||||
|
.Without<MockComponentD>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EntitiesWithAndWithoutComponents()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
|
||||||
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
var entityB = worldBuilder.CreateEntity();
|
||||||
|
var entityC = worldBuilder.CreateEntity();
|
||||||
|
var entityD = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponentB());
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponentD());
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entityB, new MockComponent());
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entityC, new MockComponent());
|
||||||
|
worldBuilder.SetComponent(entityC, new MockComponentB());
|
||||||
|
worldBuilder.SetComponent(entityC, new MockComponentC());
|
||||||
|
worldBuilder.SetComponent(entityC, new MockComponentD());
|
||||||
|
|
||||||
|
worldBuilder.SetComponent(entityD, new MockComponent());
|
||||||
|
worldBuilder.SetComponent(entityD, new MockComponentB());
|
||||||
|
worldBuilder.SetComponent(entityD, new MockComponentC());
|
||||||
|
|
||||||
|
var queriedEntities = new List<Entity>();
|
||||||
|
worldBuilder.AddEngine(new EntityQueryWithandWithoutComponentsEngine(queriedEntities));
|
||||||
|
|
||||||
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
|
queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityD });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue