started system for efficiently doing entity queries
parent
664f08c446
commit
494a583240
|
@ -6,6 +6,7 @@ namespace Encompass
|
|||
internal class ComponentStore
|
||||
{
|
||||
private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512);
|
||||
private ComponentBitSet componentBitSet = new ComponentBitSet();
|
||||
|
||||
public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
|
||||
{
|
||||
|
@ -19,12 +20,17 @@ namespace Encompass
|
|||
{
|
||||
if (!Stores.ContainsKey(typeof(TComponent)))
|
||||
{
|
||||
System.Console.WriteLine("register component type in component store");
|
||||
var store = new TypedComponentStore<TComponent>();
|
||||
Stores.Add(typeof(TComponent), store);
|
||||
componentBitSet.RegisterType<TComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
public void FinishRegistering()
|
||||
{
|
||||
componentBitSet.FinishRegistering();
|
||||
}
|
||||
|
||||
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
//RegisterComponentType<TComponent>();
|
||||
|
@ -41,6 +47,11 @@ namespace Encompass
|
|||
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
|
||||
{
|
||||
return Lookup<TComponent>().Get(entity);
|
||||
|
@ -49,15 +60,18 @@ namespace Encompass
|
|||
public void Set<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
Lookup<TComponent>().Set(entity, component);
|
||||
componentBitSet.Set<TComponent>(entity);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
componentBitSet.RemoveComponent<TComponent>(entity);
|
||||
Lookup<TComponent>().Remove(entity);
|
||||
}
|
||||
|
||||
|
@ -67,6 +81,7 @@ namespace Encompass
|
|||
{
|
||||
entry.Remove(entity);
|
||||
}
|
||||
componentBitSet.DestroyEntity(entity);
|
||||
}
|
||||
|
||||
public bool Any<TComponent>() where TComponent : struct, IComponent
|
||||
|
@ -97,6 +112,7 @@ namespace Encompass
|
|||
|
||||
public void ClearAll()
|
||||
{
|
||||
componentBitSet.Clear();
|
||||
foreach (var store in Stores.Values)
|
||||
{
|
||||
store.Clear();
|
||||
|
@ -106,6 +122,7 @@ namespace Encompass
|
|||
public void SwapWith(ComponentStore other)
|
||||
{
|
||||
(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;
|
||||
|
||||
namespace Encompass
|
||||
|
@ -21,6 +22,11 @@ namespace Encompass
|
|||
componentStore.RegisterComponentType<TComponent>();
|
||||
}
|
||||
|
||||
public void FinishRegistering()
|
||||
{
|
||||
componentStore.FinishRegistering();
|
||||
}
|
||||
|
||||
internal void SetComponentStore(ComponentStore componentStore)
|
||||
{
|
||||
this.componentStore.SwapWith(componentStore);
|
||||
|
@ -90,5 +96,10 @@ namespace Encompass
|
|||
componentUpdateManager.Remove<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>();
|
||||
}
|
||||
|
||||
public void FinishRegistering()
|
||||
{
|
||||
existingAndPendingComponentStore.FinishRegistering();
|
||||
existingComponentStore.FinishRegistering();
|
||||
pendingComponentStore.FinishRegistering();
|
||||
UpToDateComponentStore.FinishRegistering();
|
||||
}
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
existingAndPendingComponentStore.ClearAll();
|
||||
|
|
|
@ -611,5 +611,10 @@ namespace Encompass
|
|||
{
|
||||
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);
|
||||
|
||||
componentManager.FinishRegistering();
|
||||
componentUpdateManager.FinishRegistering();
|
||||
startingComponentStoreForComponentManager.FinishRegistering();
|
||||
startingComponentStoreForComponentUpdateManager.FinishRegistering();
|
||||
|
||||
foreach (var engine in engineGraph.TopologicalSort())
|
||||
{
|
||||
engineOrder.Add(engine);
|
||||
|
@ -387,7 +392,7 @@ namespace Encompass
|
|||
/// <summary>
|
||||
/// This is necessary because Encompass heavily uses generic methods with value types,
|
||||
/// so the first time any code path runs the JIT gets smashed. This method warms up the runtime.
|
||||
/// It does so by grabbing all component and message types known to the WorldBuilder and
|
||||
/// It does so by grabbing all component and message types known to the WorldBuilder and
|
||||
/// executing every possible generic method that could be executed with those types.
|
||||
/// </summary>
|
||||
private void PreloadJIT(IEnumerable<Type> componentTypes, IEnumerable<Type> messageTypes)
|
||||
|
|
|
@ -1087,5 +1087,43 @@ namespace Tests
|
|||
|
||||
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