Entity Iteration Rework #1
|
@ -10,11 +10,18 @@ internal class ComponentDepot
|
||||||
|
|
||||||
private Dictionary<int, HashSet<Type>> entityComponentMap = new Dictionary<int, HashSet<Type>>();
|
private Dictionary<int, HashSet<Type>> entityComponentMap = new Dictionary<int, HashSet<Type>>();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private Dictionary<Type, Filter> singleComponentFilters = new Dictionary<Type, Filter>();
|
||||||
|
#endif
|
||||||
|
|
||||||
internal void Register<TComponent>() where TComponent : struct
|
internal void Register<TComponent>() where TComponent : struct
|
||||||
{
|
{
|
||||||
if (!storages.ContainsKey(typeof(TComponent)))
|
if (!storages.ContainsKey(typeof(TComponent)))
|
||||||
{
|
{
|
||||||
storages.Add(typeof(TComponent), new ComponentStorage<TComponent>());
|
storages.Add(typeof(TComponent), new ComponentStorage<TComponent>());
|
||||||
|
#if DEBUG
|
||||||
|
singleComponentFilters.Add(typeof(TComponent), CreateFilter(new HashSet<Type>() { typeof(TComponent) }, new HashSet<Type>()));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,14 +86,9 @@ internal class ComponentDepot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref readonly Entity GetEntity<TComponent>() where TComponent : struct
|
public Entity GetSingletonEntity<TComponent>() where TComponent : struct
|
||||||
{
|
{
|
||||||
return ref Lookup<TComponent>().FirstEntity();
|
return Lookup<TComponent>().FirstEntity();
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlySpan<Entity> ReadEntities<TComponent>() where TComponent : struct
|
|
||||||
{
|
|
||||||
return Lookup<TComponent>().AllEntities();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
|
public ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
|
||||||
|
@ -226,8 +228,7 @@ internal class ComponentDepot
|
||||||
filterSignatureToEntityIDs[filterSignature].Add(entityID);
|
filterSignatureToEntityIDs[filterSignature].Add(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug use only!
|
#if DEBUG
|
||||||
|
|
||||||
public IEnumerable<object> Debug_GetAllComponents(int entityID)
|
public IEnumerable<object> Debug_GetAllComponents(int entityID)
|
||||||
{
|
{
|
||||||
foreach (var (type, storage) in storages)
|
foreach (var (type, storage) in storages)
|
||||||
|
@ -239,9 +240,9 @@ internal class ComponentDepot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<Entity> Debug_GetEntities(Type componentType)
|
public IEnumerable<Entity> Debug_GetEntities(Type componentType)
|
||||||
{
|
{
|
||||||
return Lookup(componentType).AllEntities();
|
return singleComponentFilters[componentType].Entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Type> Debug_SearchComponentType(string typeString)
|
public IEnumerable<Type> Debug_SearchComponentType(string typeString)
|
||||||
|
@ -254,4 +255,5 @@ internal class ComponentDepot
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@ internal abstract class ComponentStorage
|
||||||
{
|
{
|
||||||
public abstract bool Has(int entityID);
|
public abstract bool Has(int entityID);
|
||||||
public abstract void Remove(int entityID);
|
public abstract void Remove(int entityID);
|
||||||
public abstract ReadOnlySpan<Entity> AllEntities();
|
|
||||||
|
|
||||||
public abstract object Debug_Get(int entityID);
|
public abstract object Debug_Get(int entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,10 +11,9 @@ internal abstract class ComponentStorage
|
||||||
internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : struct
|
internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : struct
|
||||||
{
|
{
|
||||||
private int nextID;
|
private int nextID;
|
||||||
private IDStorage idStorage = new IDStorage();
|
private readonly Dictionary<int, int> entityIDToStorageIndex = new Dictionary<int, int>(16);
|
||||||
private readonly Dictionary<int, int> entityIDToStorageIndex = new Dictionary<int, int>();
|
private int[] entityIDs = new int[16];
|
||||||
private Entity[] storageIndexToEntities = new Entity[64];
|
private TComponent[] components = new TComponent[16];
|
||||||
private TComponent[] components = new TComponent[64];
|
|
||||||
|
|
||||||
public bool Any()
|
public bool Any()
|
||||||
{
|
{
|
||||||
|
@ -59,11 +56,11 @@ internal class ComponentStorage<TComponent> : ComponentStorage where TComponent
|
||||||
if (index >= components.Length)
|
if (index >= components.Length)
|
||||||
{
|
{
|
||||||
Array.Resize(ref components, components.Length * 2);
|
Array.Resize(ref components, components.Length * 2);
|
||||||
Array.Resize(ref storageIndexToEntities, storageIndexToEntities.Length * 2);
|
Array.Resize(ref entityIDs, entityIDs.Length * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
entityIDToStorageIndex[entityID] = index;
|
entityIDToStorageIndex[entityID] = index;
|
||||||
storageIndexToEntities[index] = new Entity(entityID);
|
entityIDs[index] = entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
components[entityIDToStorageIndex[entityID]] = component;
|
components[entityIDToStorageIndex[entityID]] = component;
|
||||||
|
@ -79,13 +76,12 @@ internal class ComponentStorage<TComponent> : ComponentStorage where TComponent
|
||||||
var lastElementIndex = nextID - 1;
|
var lastElementIndex = nextID - 1;
|
||||||
|
|
||||||
// move a component into the hole to maintain contiguous memory
|
// move a component into the hole to maintain contiguous memory
|
||||||
if (entityIDToStorageIndex.Count > 0 && storageIndex != lastElementIndex)
|
if (lastElementIndex != storageIndex)
|
||||||
{
|
{
|
||||||
var lastEntity = storageIndexToEntities[lastElementIndex];
|
var lastEntityID = entityIDs[lastElementIndex];
|
||||||
|
entityIDToStorageIndex[lastEntityID] = storageIndex;
|
||||||
entityIDToStorageIndex[lastEntity.ID] = storageIndex;
|
|
||||||
storageIndexToEntities[storageIndex] = lastEntity;
|
|
||||||
components[storageIndex] = components[lastElementIndex];
|
components[storageIndex] = components[lastElementIndex];
|
||||||
|
entityIDs[storageIndex] = lastEntityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextID -= 1;
|
nextID -= 1;
|
||||||
|
@ -98,18 +94,13 @@ internal class ComponentStorage<TComponent> : ComponentStorage where TComponent
|
||||||
entityIDToStorageIndex.Clear();
|
entityIDToStorageIndex.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ReadOnlySpan<Entity> AllEntities()
|
|
||||||
{
|
|
||||||
return new ReadOnlySpan<Entity>(storageIndexToEntities, 0, nextID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlySpan<TComponent> AllComponents()
|
public ReadOnlySpan<TComponent> AllComponents()
|
||||||
{
|
{
|
||||||
return new ReadOnlySpan<TComponent>(components, 0, nextID);
|
return new ReadOnlySpan<TComponent>(components, 0, nextID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref readonly Entity FirstEntity()
|
public Entity FirstEntity()
|
||||||
{
|
{
|
||||||
return ref storageIndexToEntities[0];
|
return new Entity(entityIDs[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// NOTE: these methods are very inefficient
|
// NOTE: these methods are very inefficient
|
||||||
// this class should only be used in debugging contexts!!
|
// this class should only be used in debugging contexts!!
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
public abstract class DebugSystem : System
|
public abstract class DebugSystem : System
|
||||||
|
@ -13,7 +15,7 @@ namespace MoonTools.ECS
|
||||||
return ComponentDepot.Debug_GetAllComponents(entity.ID);
|
return ComponentDepot.Debug_GetAllComponents(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ReadOnlySpan<Entity> Debug_GetEntities(Type componentType)
|
protected IEnumerable<Entity> Debug_GetEntities(Type componentType)
|
||||||
{
|
{
|
||||||
return ComponentDepot.Debug_GetEntities(componentType);
|
return ComponentDepot.Debug_GetEntities(componentType);
|
||||||
}
|
}
|
||||||
|
@ -24,3 +26,4 @@ namespace MoonTools.ECS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -16,12 +16,6 @@ public abstract class EntityComponentReader
|
||||||
ComponentDepot = componentDepot;
|
ComponentDepot = componentDepot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is this faster or slower than a single-component Filter?
|
|
||||||
protected ReadOnlySpan<Entity> ReadEntities<TComponent>() where TComponent : struct
|
|
||||||
{
|
|
||||||
return ComponentDepot.ReadEntities<TComponent>();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
|
protected ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
|
||||||
{
|
{
|
||||||
return ComponentDepot.ReadComponents<TComponent>();
|
return ComponentDepot.ReadComponents<TComponent>();
|
||||||
|
@ -47,9 +41,9 @@ public abstract class EntityComponentReader
|
||||||
return ref ComponentDepot.Get<TComponent>();
|
return ref ComponentDepot.Get<TComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ref readonly Entity GetEntity<TComponent>() where TComponent : struct
|
protected Entity GetSingletonEntity<TComponent>() where TComponent : struct
|
||||||
{
|
{
|
||||||
return ref ComponentDepot.GetEntity<TComponent>();
|
return ComponentDepot.GetSingletonEntity<TComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool Exists(in Entity entity)
|
protected bool Exists(in Entity entity)
|
||||||
|
|
Loading…
Reference in New Issue