started system for efficiently doing entity queries
parent
664f08c446
commit
494a583240
|
@ -6,6 +6,7 @@ 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();
|
||||||
|
|
||||||
public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
|
public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
|
||||||
{
|
{
|
||||||
|
@ -19,12 +20,17 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
if (!Stores.ContainsKey(typeof(TComponent)))
|
if (!Stores.ContainsKey(typeof(TComponent)))
|
||||||
{
|
{
|
||||||
System.Console.WriteLine("register component type in component store");
|
|
||||||
var store = new TypedComponentStore<TComponent>();
|
var store = new TypedComponentStore<TComponent>();
|
||||||
Stores.Add(typeof(TComponent), store);
|
Stores.Add(typeof(TComponent), store);
|
||||||
|
componentBitSet.RegisterType<TComponent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FinishRegistering()
|
||||||
|
{
|
||||||
|
componentBitSet.FinishRegistering();
|
||||||
|
}
|
||||||
|
|
||||||
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
//RegisterComponentType<TComponent>();
|
//RegisterComponentType<TComponent>();
|
||||||
|
@ -41,6 +47,11 @@ 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)
|
||||||
|
{
|
||||||
|
return componentBitSet.EntitiesWithComponents(types);
|
||||||
|
}
|
||||||
|
|
||||||
public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent
|
public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return Lookup<TComponent>().Get(entity);
|
return Lookup<TComponent>().Get(entity);
|
||||||
|
@ -49,15 +60,18 @@ namespace Encompass
|
||||||
public void Set<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
public void Set<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
Lookup<TComponent>().Set(entity, component);
|
Lookup<TComponent>().Set(entity, component);
|
||||||
|
componentBitSet.Set<TComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
componentBitSet.Set<TComponent>(entity);
|
||||||
return Lookup<TComponent>().Set(entity, component, priority);
|
return Lookup<TComponent>().Set(entity, component, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
componentBitSet.RemoveComponent<TComponent>(entity);
|
||||||
Lookup<TComponent>().Remove(entity);
|
Lookup<TComponent>().Remove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +81,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
entry.Remove(entity);
|
entry.Remove(entity);
|
||||||
}
|
}
|
||||||
|
componentBitSet.DestroyEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Any<TComponent>() where TComponent : struct, IComponent
|
public bool Any<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -97,6 +112,7 @@ namespace Encompass
|
||||||
|
|
||||||
public void ClearAll()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
|
componentBitSet.Clear();
|
||||||
foreach (var store in Stores.Values)
|
foreach (var store in Stores.Values)
|
||||||
{
|
{
|
||||||
store.Clear();
|
store.Clear();
|
||||||
|
@ -106,6 +122,7 @@ namespace Encompass
|
||||||
public void SwapWith(ComponentStore other)
|
public void SwapWith(ComponentStore other)
|
||||||
{
|
{
|
||||||
(Stores, other.Stores) = (other.Stores, Stores);
|
(Stores, other.Stores) = (other.Stores, Stores);
|
||||||
|
(componentBitSet, other.componentBitSet) = (other.componentBitSet, componentBitSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
internal class ComponentBitSet
|
||||||
|
{
|
||||||
|
Dictionary<Entity, BitArray> entities = new Dictionary<Entity, BitArray>();
|
||||||
|
Dictionary<Type, int> typeToIndex = new Dictionary<Type, int>();
|
||||||
|
BitArray queryArray;
|
||||||
|
|
||||||
|
public void RegisterType<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
typeToIndex.Add(typeof(TComponent), typeToIndex.Count);
|
||||||
|
foreach (var kvp in entities)
|
||||||
|
{
|
||||||
|
kvp.Value.Length = typeToIndex.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FinishRegistering()
|
||||||
|
{
|
||||||
|
queryArray = new BitArray(typeToIndex.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
entities.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEntity(Entity entity)
|
||||||
|
{
|
||||||
|
var bitArray = new BitArray(typeToIndex.Count);
|
||||||
|
entities.Add(entity, bitArray); // this is gonna create garbage!! fuck!!
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
if (!entities.ContainsKey(entity)) { AddEntity(entity); }
|
||||||
|
entities[entity].Set(typeToIndex[typeof(TComponent)], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
entities[entity].Set(typeToIndex[typeof(TComponent)], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DestroyEntity(Entity entity)
|
||||||
|
{
|
||||||
|
entities.Remove(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Entity> EntitiesWithComponents(IEnumerable<Type> types)
|
||||||
|
{
|
||||||
|
foreach (var kvp in entities)
|
||||||
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
|
@ -21,6 +22,11 @@ namespace Encompass
|
||||||
componentStore.RegisterComponentType<TComponent>();
|
componentStore.RegisterComponentType<TComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FinishRegistering()
|
||||||
|
{
|
||||||
|
componentStore.FinishRegistering();
|
||||||
|
}
|
||||||
|
|
||||||
internal void SetComponentStore(ComponentStore componentStore)
|
internal void SetComponentStore(ComponentStore componentStore)
|
||||||
{
|
{
|
||||||
this.componentStore.SwapWith(componentStore);
|
this.componentStore.SwapWith(componentStore);
|
||||||
|
@ -90,5 +96,10 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,14 @@ namespace Encompass
|
||||||
UpToDateComponentStore.RegisterComponentType<TComponent>();
|
UpToDateComponentStore.RegisterComponentType<TComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FinishRegistering()
|
||||||
|
{
|
||||||
|
existingAndPendingComponentStore.FinishRegistering();
|
||||||
|
existingComponentStore.FinishRegistering();
|
||||||
|
pendingComponentStore.FinishRegistering();
|
||||||
|
UpToDateComponentStore.FinishRegistering();
|
||||||
|
}
|
||||||
|
|
||||||
internal void Clear()
|
internal void Clear()
|
||||||
{
|
{
|
||||||
existingAndPendingComponentStore.ClearAll();
|
existingAndPendingComponentStore.ClearAll();
|
||||||
|
|
|
@ -611,5 +611,10 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
|
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Entity> EntitiesWithComponents(IEnumerable<Type> types)
|
||||||
|
{
|
||||||
|
return componentManager.EntitiesWithComponents(types);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,6 +363,11 @@ namespace Encompass
|
||||||
|
|
||||||
PreloadJIT(componentTypesToRegister, messageTypes);
|
PreloadJIT(componentTypesToRegister, messageTypes);
|
||||||
|
|
||||||
|
componentManager.FinishRegistering();
|
||||||
|
componentUpdateManager.FinishRegistering();
|
||||||
|
startingComponentStoreForComponentManager.FinishRegistering();
|
||||||
|
startingComponentStoreForComponentUpdateManager.FinishRegistering();
|
||||||
|
|
||||||
foreach (var engine in engineGraph.TopologicalSort())
|
foreach (var engine in engineGraph.TopologicalSort())
|
||||||
{
|
{
|
||||||
engineOrder.Add(engine);
|
engineOrder.Add(engine);
|
||||||
|
|
|
@ -1087,5 +1087,43 @@ namespace Tests
|
||||||
|
|
||||||
undilatedDeltaTime.Should().Be(0.5);
|
undilatedDeltaTime.Should().Be(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MockComponentB : IComponent { }
|
||||||
|
|
||||||
|
static Entity[] queriedEntities;
|
||||||
|
|
||||||
|
class EntityQueryEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
queriedEntities = EntitiesWithComponents(new Type[] { typeof(MockComponent), typeof(MockComponentB) }).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EntitiesWithComponents()
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
|
||||||
|
worldBuilder.AddEngine(new EntityQueryEngine());
|
||||||
|
|
||||||
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
|
queriedEntities.Should().BeEquivalentTo(new Entity[] { entity, entityB });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue