diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index ee72406..4528cca 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -6,82 +6,23 @@ namespace Encompass { internal class ComponentStore { - interface IComponentStore + private Dictionary Stores = new Dictionary(); + + public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable() { - T All() where T : struct, IComponent; - } - - abstract class TypedComponentStore - { - public abstract int Count { get; } - public abstract bool Has(Entity entity); - public abstract bool Remove(Entity entity); - public abstract void Clear(); - } - - class TypedComponentStore : TypedComponentStore where TComponent : struct, IComponent - { - private readonly Dictionary store = new Dictionary(); - private readonly Dictionary priorities = new Dictionary(); - - public override int Count { get => store.Count; } - - public TComponent Get(Entity entity) + foreach (var entry in Stores) { - return store[entity]; - } - - public void Set(Entity entity, TComponent component) - { - store[entity] = component; - } - - public void Set(Entity entity, TComponent component, int priority) - { - if (!priorities.ContainsKey(entity) || priority < priorities[entity]) { - store[entity] = component; - } - } - - public override bool Has(Entity entity) - { - return store.ContainsKey(entity); - } - - public override void Clear() - { - store.Clear(); - } - - public IEnumerable<(Entity, TComponent)> All() - { - return store.Select(kvp => (kvp.Key, kvp.Value)); - } - - // public override IEnumerable All() - // { - // return store.Values.Cast(); - // } - - public override bool Remove(Entity entity) - { - throw new NotImplementedException(); + yield return (entry.Key, entry.Value); } } - private readonly Dictionary Stores = new Dictionary(); - - public void RegisterComponentType() where TComponent : struct, IComponent + private TypedComponentStore Lookup() where TComponent : struct, IComponent { if (!Stores.ContainsKey(typeof(TComponent))) { var store = new TypedComponentStore(); Stores.Add(typeof(TComponent), store); } - } - - private TypedComponentStore Lookup() where TComponent : struct, IComponent - { return Stores[typeof(TComponent)] as TypedComponentStore; } @@ -105,9 +46,9 @@ namespace Encompass Lookup().Set(entity, component); } - public void Set(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + public bool Set(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - Lookup().Set(entity, component, priority); + return Lookup().Set(entity, component, priority); } public void Remove(Entity entity) where TComponent : struct, IComponent @@ -133,6 +74,17 @@ namespace Encompass // return Lookup().All(); // } + public IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped() + { + foreach (var store in Stores.Values) + { + foreach (var thing in store.AllInterfaceTyped()) + { + yield return thing; + } + } + } + public IEnumerable<(Entity, TComponent)> All() where TComponent : struct, IComponent { return Lookup().All(); @@ -150,5 +102,10 @@ namespace Encompass store.Clear(); } } + + public void SwapWith(ComponentStore other) + { + (Stores, other.Stores) = (other.Stores, Stores); + } } } diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs new file mode 100644 index 0000000..6392739 --- /dev/null +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Encompass +{ + internal abstract class TypedComponentStore + { + public abstract int Count { get; } + public abstract IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped(); + public abstract bool Has(Entity entity); + public abstract void Remove(Entity entity); + public abstract void Clear(); + } + + internal class TypedComponentStore : TypedComponentStore where TComponent : struct, IComponent + { + private readonly Dictionary store = new Dictionary(); + private readonly Dictionary priorities = new Dictionary(); + + public override int Count { get => store.Count; } + + public TComponent Get(Entity entity) + { + return store[entity]; + } + + public void Set(Entity entity, TComponent component) + { + store[entity] = component; + } + + public bool Set(Entity entity, TComponent component, int priority) + { + if (!priorities.ContainsKey(entity) || priority < priorities[entity]) { + store[entity] = component; + return true; + } + + return false; + } + + public override bool Has(Entity entity) + { + return store.ContainsKey(entity); + } + + public override void Clear() + { + store.Clear(); + } + + public IEnumerable<(Entity, TComponent)> All() + { + return store.Select(kvp => (kvp.Key, kvp.Value)); + } + + public override IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped() + { + return store.Select(kvp => (kvp.Key, typeof(TComponent), (IComponent)kvp.Value)); + } + + // public override IEnumerable All() + // { + // return store.Values.Cast(); + // } + + public override void Remove(Entity entity) + { + store.Remove(entity); + priorities.Remove(entity); + } + } +} diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 6ea8a00..3459991 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -9,41 +9,25 @@ namespace Encompass internal class ComponentManager { private readonly DrawLayerManager drawLayerManager; + private readonly ComponentMessageManager componentMessageManager; private readonly ComponentStore componentStore = new ComponentStore(); - - private readonly Dictionary<(Entity, Type), IComponent> componentWriteData = new Dictionary<(Entity, Type), IComponent>(); - private readonly Dictionary<(Entity, Type), int> componentWritePriorities = new Dictionary<(Entity, Type), int>(); private readonly HashSet entitiesMarkedForRemoval = new HashSet(); - public ComponentManager(DrawLayerManager drawLayerManager) + public ComponentManager(DrawLayerManager drawLayerManager, ComponentMessageManager componentMessageManager) { this.drawLayerManager = drawLayerManager; + this.componentMessageManager = componentMessageManager; } - internal void MarkComponentForWrite(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + internal void SetComponentStore(ComponentStore componentStore) { - componentStore.RegisterComponentType(); - - if (componentWriteData.ContainsKey((entity, typeof(TComponent)))) - { - var currentPriority = componentWritePriorities[(entity, typeof(TComponent))]; - if (priority < currentPriority) - { - componentWriteData[(entity, typeof(TComponent))] = component; - componentWritePriorities[(entity, typeof(TComponent))] = priority; - } - } - else - { - componentWriteData.Add((entity, typeof(TComponent)), component); - componentWritePriorities[(entity, typeof(TComponent))] = priority; - } + this.componentStore.SwapWith(componentStore); } - internal void RegisterDrawableComponent(Guid componentID, TComponent component) where TComponent : IDrawableComponent + internal void RegisterDrawableComponent(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent { - drawLayerManager.RegisterComponentWithLayer(componentID, component.Layer); + drawLayerManager.RegisterComponentWithLayer(entity, component, layer); } internal void AddComponent(Entity entity, TComponent component) where TComponent : struct, IComponent @@ -53,16 +37,12 @@ namespace Encompass internal void WriteComponents() { - foreach (var keyValuePair in componentWriteData) - { - var (entity, type) = keyValuePair.Key; - var component = keyValuePair.Value; + componentStore.SwapWith(componentMessageManager.ComponentStore); + } - AddComponent(entity, component); - } - - componentWriteData.Clear(); - componentWritePriorities.Clear(); + internal IEnumerable<(TComponent, Entity)> GetComponentsIncludingEntity() where TComponent : struct, IComponent + { + return componentStore.All().Select(pair => (pair.Item2, pair.Item1)); } internal IEnumerable GetComponentsByType() where TComponent : struct, IComponent @@ -95,7 +75,7 @@ namespace Encompass foreach (var entity in entitiesMarkedForRemoval) { componentStore.Remove(entity); - drawLayerManager.UnRegisterComponentWithLayer(entity); + drawLayerManager.UnRegisterEntityWithLayer(entity); } entitiesMarkedForRemoval.Clear(); diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 15da58d..5747795 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -14,6 +14,8 @@ namespace Encompass private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(); + public ComponentStore ComponentStore { get => componentStore; } + internal void ClearMessages() { componentStore.ClearAll(); @@ -35,9 +37,10 @@ namespace Encompass internal void AddPendingComponentMessage(PendingComponentMessage pendingComponentMessage) where TComponent : struct, IComponent { - RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.component); - - pendingComponentStore.Set(pendingComponentMessage.entity, pendingComponentMessage.component, pendingComponentMessage.priority); + if (pendingComponentStore.Set(pendingComponentMessage.entity, pendingComponentMessage.component, pendingComponentMessage.priority)) + { + RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.component); + } } private void RegisterExistingOrPendingComponentMessage(Entity entity, TComponent component) where TComponent : struct, IComponent diff --git a/encompass-cs/DrawLayerManager.cs b/encompass-cs/DrawLayerManager.cs index a00e669..aab17b2 100644 --- a/encompass-cs/DrawLayerManager.cs +++ b/encompass-cs/DrawLayerManager.cs @@ -7,11 +7,12 @@ namespace Encompass internal class DrawLayerManager { private readonly SortedList layerOrder = new SortedList(); + private readonly ComponentStore componentStore = new ComponentStore(); - private readonly Dictionary> layerIndexToComponentIDs = new Dictionary>(); + private readonly Dictionary layerIndexToComponentStore = new Dictionary(); private readonly Dictionary> layerIndexToGeneralRenderers = new Dictionary>(); - private readonly Dictionary componentIDToLayerIndex = new Dictionary(); + private readonly Dictionary> typeToEntityToLayer = new Dictionary>(); public IEnumerable LayerOrder { get { return layerOrder.Values; } } @@ -49,23 +50,23 @@ namespace Encompass RegisterGeneralRendererWithLayer(renderer, newLayer); } - public void RegisterComponentWithLayer(Guid id, int layer) + public void RegisterComponentWithLayer(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent { - if (componentIDToLayerIndex.ContainsKey(id)) { UnRegisterComponentWithLayer(id); } + if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { UnRegisterComponentWithLayer(entity, component); } - if (layerIndexToComponentIDs.ContainsKey(layer)) + if (layerIndexToComponentStore.ContainsKey(layer)) { - var set = layerIndexToComponentIDs[layer]; - set.Add(id); + var set = layerIndexToComponentStore[layer]; + set.Set(entity, component); } else { - var set = new HashSet(); - layerIndexToComponentIDs.Add(layer, set); - set.Add(id); + var set = new ComponentStore(); + layerIndexToComponentStore.Add(layer, set); + set.Set(entity, component); } - componentIDToLayerIndex[id] = layer; + typeToEntityToLayer[typeof(TComponent)].Add(entity, layer); if (!layerOrder.ContainsKey(layer)) { @@ -73,21 +74,19 @@ namespace Encompass } } - public void UnRegisterComponentWithLayer(Entity entity) + public void UnRegisterComponentWithLayer(Entity entity, TComponent component) where TComponent : struct, IComponent { - if (componentIDToLayerIndex.ContainsKey(id)) + if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { - var layer = componentIDToLayerIndex[id]; - layerIndexToComponentIDs[layer].Remove(id); + var layer = typeToEntityToLayer[typeof(TComponent)][entity]; + layerIndexToComponentStore[layer].Remove(entity); } - componentIDToLayerIndex.Remove(id); + typeToEntityToLayer[typeof(TComponent)].Remove(entity); } - public IEnumerable ComponentIDsByLayer(int layer) + public void UnRegisterEntityWithLayer(Entity entity) { - return layerIndexToComponentIDs.ContainsKey(layer) ? - layerIndexToComponentIDs[layer] : - Enumerable.Empty(); + componentStore.Remove(entity); } public IEnumerable GeneralRenderersByLayer(int layer) @@ -96,5 +95,10 @@ namespace Encompass layerIndexToGeneralRenderers[layer] : Enumerable.Empty(); } + + public IEnumerable<(Entity, Type, IComponent)> AllInLayer(int layer) + { + return layerIndexToComponentStore[layer].AllInterfaceTyped(); + } } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index eb9a1b4..a910a52 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -215,6 +215,11 @@ namespace Encompass return ReadComponentsHelper().Select((tuple) => (tuple.Item2, tuple.Item1)); } + internal IEnumerable<(TComponent, Entity)> InternalRead() where TComponent : struct, IComponent + { + return componentManager.GetComponentsIncludingEntity(); + } + private (Entity, TComponent) ReadComponentHelper() where TComponent : struct, IComponent { var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); @@ -397,8 +402,6 @@ namespace Encompass { var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0; - componentManager.MarkComponentForWrite(entity, component, priority); - if (!sendTypes.Contains(typeof(ComponentWriteMessage))) { throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name); @@ -415,7 +418,7 @@ namespace Encompass if (component is IDrawableComponent drawableComponent) { - componentManager.RegisterDrawableComponent(componentID, drawableComponent); + componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); } } @@ -519,22 +522,13 @@ namespace Encompass return ReadMessages().Any(); } - /// - /// Destroys the Entity with the specified ID. This also removes all of the Components associated with the Entity. - /// Entity destruction takes place after all the Engines have been processed by World Update. - /// - internal void Destroy(Guid entityID) - { - entityManager.MarkForDestroy(entityID); - } - /// /// Destroys the specified Entity. This also removes all of the Components associated with the Entity. /// Entity destruction takes place after all the Engines have been processed by World Update. /// protected void Destroy(Entity entity) { - entityManager.MarkForDestroy(entity.ID); + entityManager.MarkForDestroy(entity); } /// diff --git a/encompass-cs/Engines/ComponentMessageEmitter.cs b/encompass-cs/Engines/ComponentMessageEmitter.cs index 4d12515..d6bee6a 100644 --- a/encompass-cs/Engines/ComponentMessageEmitter.cs +++ b/encompass-cs/Engines/ComponentMessageEmitter.cs @@ -9,7 +9,7 @@ namespace Encompass public override void Update(double dt) { - foreach (var (component, entity) in ReadComponentsIncludingEntity()) + foreach (var (component, entity) in InternalRead()) { ComponentMessage componentMessage; componentMessage.entity = entity; diff --git a/encompass-cs/RenderManager.cs b/encompass-cs/RenderManager.cs index 839c5fd..07d4a46 100644 --- a/encompass-cs/RenderManager.cs +++ b/encompass-cs/RenderManager.cs @@ -37,16 +37,10 @@ namespace Encompass { foreach (var layer in drawLayerManager.LayerOrder) { - var componentIDSet = drawLayerManager.ComponentIDsByLayer(layer); var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(layer); - foreach (var componentID in componentIDSet) + foreach (var (entity, componentType, component) in drawLayerManager.AllInLayer(layer)) { - var componentType = componentManager.GetComponentTypeByID(componentID); - var component = componentManager.GetComponentByID(componentType, componentID); - var entityID = componentManager.GetEntityIDByComponentID(componentID); - var entity = entityManager.GetEntity(entityID); - if (drawComponentTypeToOrderedRenderer.ContainsKey(componentType)) { var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType]; diff --git a/encompass-cs/Renderer.cs b/encompass-cs/Renderer.cs index cb30820..e14a8c8 100644 --- a/encompass-cs/Renderer.cs +++ b/encompass-cs/Renderer.cs @@ -19,11 +19,6 @@ namespace Encompass this.componentManager = componentManager; } - internal Guid GetEntityIDByComponentID(Guid componentID) - { - return componentManager.GetEntityIDByComponentID(componentID); - } - internal Entity GetEntity(Guid entityID) { return entityManager.GetEntity(entityID); @@ -41,12 +36,12 @@ namespace Encompass protected IEnumerable ReadComponents() where TComponent : struct, IComponent { - return componentManager.GetComponentsByType().Select(tuple => tuple.Item2); + return componentManager.GetComponentsByType(); } protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity() where TComponent : struct, IComponent { - return componentManager.GetComponentsByType().Select(tuple => (tuple.Item2, GetEntity(GetEntityIDByComponentID(tuple.Item1)))); + return componentManager.GetComponentsIncludingEntity(); } protected TComponent ReadComponent() where TComponent : struct, IComponent @@ -61,7 +56,7 @@ namespace Encompass protected TComponent GetComponent(Entity entity) where TComponent : struct, IComponent { - return componentManager.GetComponentByEntityAndType(entity).Item2; + return componentManager.GetComponentByEntityAndType(entity); } protected bool HasComponent(Entity entity) where TComponent : struct, IComponent diff --git a/encompass-cs/World.cs b/encompass-cs/World.cs index 2a3a099..783e251 100644 --- a/encompass-cs/World.cs +++ b/encompass-cs/World.cs @@ -56,11 +56,12 @@ namespace Encompass } messageManager.ClearMessages(); - componentMessageManager.ClearMessages(); entityManager.DestroyMarkedEntities(); - componentManager.RemoveMarkedComponents(); componentManager.WriteComponents(); + componentManager.RemoveMarkedComponents(); + + componentMessageManager.ClearMessages(); } /// diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 491e6da..a12d53a 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -20,6 +20,7 @@ namespace Encompass { private readonly List engines = new List(); private readonly DirectedGraph engineGraph = GraphBuilder.DirectedGraph(); + private readonly ComponentStore componentStore = new ComponentStore(); private readonly ComponentManager componentManager; private readonly EntityManager entityManager; @@ -39,9 +40,9 @@ namespace Encompass { drawLayerManager = new DrawLayerManager(); timeManager = new TimeManager(); - componentManager = new ComponentManager(drawLayerManager); - messageManager = new MessageManager(timeManager); componentMessageManager = new ComponentMessageManager(); + componentManager = new ComponentManager(drawLayerManager, componentMessageManager); + messageManager = new MessageManager(timeManager); entityManager = new EntityManager(componentManager); renderManager = new RenderManager(componentManager, drawLayerManager, entityManager); } @@ -73,12 +74,13 @@ namespace Encompass /// /// Sets Component data for the specified Component Type on the specified Entity. /// - public void SetComponent(Entity entity, TComponent component, int priority = 0) where TComponent : struct, IComponent + public void SetComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentManager.MarkComponentForWrite(entity, component, priority); + componentStore.Set(entity, component); + if (component is IDrawableComponent drawableComponent) { - componentManager.RegisterDrawableComponent(componentID, drawableComponent); + componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); } } @@ -346,8 +348,7 @@ namespace Encompass renderManager ); - componentManager.RemoveMarkedComponents(); - componentManager.WriteComponents(); + componentManager.SetComponentStore(componentStore); return world; } diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index 3c6d061..957ac91 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -89,16 +89,16 @@ namespace Tests worldBuilder.AddEngine(new ReadMockComponentEngine()); var entity = worldBuilder.CreateEntity(); - worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" }, 2); - worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" }, 0); - worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" }, 1); + worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" }); + worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" }); + worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" }); var world = worldBuilder.Build(); world.Update(0.01); - Assert.That(gottenMockComponent.myInt, Is.EqualTo(50)); - Assert.That(gottenMockComponent.myString, Is.EqualTo("hi")); + Assert.That(gottenMockComponent.myInt, Is.EqualTo(40)); + Assert.That(gottenMockComponent.myString, Is.EqualTo("wassup")); } [Reads(typeof(MockComponent))] diff --git a/test/EngineTest.cs b/test/EngineTest.cs index a9dbbb4..1edd31f 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -557,7 +557,7 @@ namespace Tests world.Update(0.01); Assert.That(results, Does.Not.Contain((mockComponent, entity))); - Assert.That(results, Does.Not.Contain((mockComponent, entity))); + Assert.That(results, Does.Not.Contain((mockComponent, entityB))); Assert.That(results, Does.Contain((mockComponent, entityC))); }