From d7e795309ff7eebde7cb0ce13f58837cb8e70ae0 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Sun, 3 Apr 2022 21:46:52 +0000 Subject: [PATCH] Entity Iteration Rework (#1) Filters are now the canonical way to look up Entities. The only exception is the new GetSingletonEntity. --- src/ComponentDepot.cs | 24 +++++++++++++----------- src/ComponentStorage.cs | 31 +++++++++++-------------------- src/DebugSystem.cs | 5 ++++- src/EntityComponentReader.cs | 10 ++-------- 4 files changed, 30 insertions(+), 40 deletions(-) diff --git a/src/ComponentDepot.cs b/src/ComponentDepot.cs index 275a48f..dae13fb 100644 --- a/src/ComponentDepot.cs +++ b/src/ComponentDepot.cs @@ -10,11 +10,18 @@ internal class ComponentDepot private Dictionary> entityComponentMap = new Dictionary>(); + #if DEBUG + private Dictionary singleComponentFilters = new Dictionary(); + #endif + internal void Register() where TComponent : struct { if (!storages.ContainsKey(typeof(TComponent))) { storages.Add(typeof(TComponent), new ComponentStorage()); + #if DEBUG + singleComponentFilters.Add(typeof(TComponent), CreateFilter(new HashSet() { typeof(TComponent) }, new HashSet())); + #endif } } @@ -79,14 +86,9 @@ internal class ComponentDepot } } - public ref readonly Entity GetEntity() where TComponent : struct + public Entity GetSingletonEntity() where TComponent : struct { - return ref Lookup().FirstEntity(); - } - - public ReadOnlySpan ReadEntities() where TComponent : struct - { - return Lookup().AllEntities(); + return Lookup().FirstEntity(); } public ReadOnlySpan ReadComponents() where TComponent : struct @@ -226,8 +228,7 @@ internal class ComponentDepot filterSignatureToEntityIDs[filterSignature].Add(entityID); } - // debug use only! - + #if DEBUG public IEnumerable Debug_GetAllComponents(int entityID) { foreach (var (type, storage) in storages) @@ -239,9 +240,9 @@ internal class ComponentDepot } } - public ReadOnlySpan Debug_GetEntities(Type componentType) + public IEnumerable Debug_GetEntities(Type componentType) { - return Lookup(componentType).AllEntities(); + return singleComponentFilters[componentType].Entities; } public IEnumerable Debug_SearchComponentType(string typeString) @@ -254,4 +255,5 @@ internal class ComponentDepot } } } + #endif } diff --git a/src/ComponentStorage.cs b/src/ComponentStorage.cs index c5d86a2..a777494 100644 --- a/src/ComponentStorage.cs +++ b/src/ComponentStorage.cs @@ -4,8 +4,6 @@ internal abstract class ComponentStorage { public abstract bool Has(int entityID); public abstract void Remove(int entityID); - public abstract ReadOnlySpan AllEntities(); - public abstract object Debug_Get(int entityID); } @@ -13,10 +11,9 @@ internal abstract class ComponentStorage internal class ComponentStorage : ComponentStorage where TComponent : struct { private int nextID; - private IDStorage idStorage = new IDStorage(); - private readonly Dictionary entityIDToStorageIndex = new Dictionary(); - private Entity[] storageIndexToEntities = new Entity[64]; - private TComponent[] components = new TComponent[64]; + private readonly Dictionary entityIDToStorageIndex = new Dictionary(16); + private int[] entityIDs = new int[16]; + private TComponent[] components = new TComponent[16]; public bool Any() { @@ -59,11 +56,11 @@ internal class ComponentStorage : ComponentStorage where TComponent if (index >= components.Length) { Array.Resize(ref components, components.Length * 2); - Array.Resize(ref storageIndexToEntities, storageIndexToEntities.Length * 2); + Array.Resize(ref entityIDs, entityIDs.Length * 2); } entityIDToStorageIndex[entityID] = index; - storageIndexToEntities[index] = new Entity(entityID); + entityIDs[index] = entityID; } components[entityIDToStorageIndex[entityID]] = component; @@ -79,13 +76,12 @@ internal class ComponentStorage : ComponentStorage where TComponent var lastElementIndex = nextID - 1; // move a component into the hole to maintain contiguous memory - if (entityIDToStorageIndex.Count > 0 && storageIndex != lastElementIndex) + if (lastElementIndex != storageIndex) { - var lastEntity = storageIndexToEntities[lastElementIndex]; - - entityIDToStorageIndex[lastEntity.ID] = storageIndex; - storageIndexToEntities[storageIndex] = lastEntity; + var lastEntityID = entityIDs[lastElementIndex]; + entityIDToStorageIndex[lastEntityID] = storageIndex; components[storageIndex] = components[lastElementIndex]; + entityIDs[storageIndex] = lastEntityID; } nextID -= 1; @@ -98,18 +94,13 @@ internal class ComponentStorage : ComponentStorage where TComponent entityIDToStorageIndex.Clear(); } - public override ReadOnlySpan AllEntities() - { - return new ReadOnlySpan(storageIndexToEntities, 0, nextID); - } - public ReadOnlySpan AllComponents() { return new ReadOnlySpan(components, 0, nextID); } - public ref readonly Entity FirstEntity() + public Entity FirstEntity() { - return ref storageIndexToEntities[0]; + return new Entity(entityIDs[0]); } } diff --git a/src/DebugSystem.cs b/src/DebugSystem.cs index 0697800..6db9882 100644 --- a/src/DebugSystem.cs +++ b/src/DebugSystem.cs @@ -1,5 +1,7 @@ // NOTE: these methods are very inefficient // this class should only be used in debugging contexts!! + +#if DEBUG namespace MoonTools.ECS { public abstract class DebugSystem : System @@ -13,7 +15,7 @@ namespace MoonTools.ECS return ComponentDepot.Debug_GetAllComponents(entity.ID); } - protected ReadOnlySpan Debug_GetEntities(Type componentType) + protected IEnumerable Debug_GetEntities(Type componentType) { return ComponentDepot.Debug_GetEntities(componentType); } @@ -24,3 +26,4 @@ namespace MoonTools.ECS } } } +#endif diff --git a/src/EntityComponentReader.cs b/src/EntityComponentReader.cs index 6ef1469..4146d94 100644 --- a/src/EntityComponentReader.cs +++ b/src/EntityComponentReader.cs @@ -16,12 +16,6 @@ public abstract class EntityComponentReader ComponentDepot = componentDepot; } - // TODO: is this faster or slower than a single-component Filter? - protected ReadOnlySpan ReadEntities() where TComponent : struct - { - return ComponentDepot.ReadEntities(); - } - protected ReadOnlySpan ReadComponents() where TComponent : struct { return ComponentDepot.ReadComponents(); @@ -47,9 +41,9 @@ public abstract class EntityComponentReader return ref ComponentDepot.Get(); } - protected ref readonly Entity GetEntity() where TComponent : struct + protected Entity GetSingletonEntity() where TComponent : struct { - return ref ComponentDepot.GetEntity(); + return ComponentDepot.GetSingletonEntity(); } protected bool Exists(in Entity entity)