From 506aee8c37e146b57a7a021a3262d85e1f537b38 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Wed, 4 Dec 2019 20:50:08 -0800 Subject: [PATCH 01/24] started rewriting managers to not reference interfaces --- encompass-cs/Collections/ComponentStore.cs | 61 +++++++++ encompass-cs/ComponentManager.cs | 14 +-- encompass-cs/ComponentMessageManager.cs | 137 ++++++++------------- encompass-cs/Engine.cs | 57 +-------- encompass-cs/EntityManager.cs | 6 +- encompass-cs/MessageManager.cs | 2 +- encompass-cs/TimeManager.cs | 2 +- encompass-cs/WorldBuilder.cs | 2 +- encompass-cs/encompass-cs.csproj | 8 +- test/ComponentTest.cs | 39 ------ 10 files changed, 131 insertions(+), 197 deletions(-) create mode 100644 encompass-cs/Collections/ComponentStore.cs diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs new file mode 100644 index 0000000..5d857b1 --- /dev/null +++ b/encompass-cs/Collections/ComponentStore.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace Encompass +{ + internal class ComponentStore + { + private readonly Dictionary Stores = new Dictionary(); + private readonly Dictionary ClearMethods = new Dictionary(); + + private Dictionary Lookup() where TComponent : struct, IComponent + { + if (!Stores.ContainsKey(typeof(TComponent))) + { + var dictionary = new Dictionary(); + Stores.Add(typeof(TComponent), dictionary); + ClearMethods.Add(typeof(TComponent), dictionary.Clear); + } + + return Stores[typeof(TComponent)] as Dictionary; + } + + public bool Has(Guid id) where TComponent : struct, IComponent + { + return Lookup().ContainsKey(id); + } + + public TComponent Get(Guid id) where TComponent : struct, IComponent + { + return Lookup()[id]; + } + + public void Set(Type type, Guid id, IComponent component) + { + (Stores[type] as Dictionary)[id] = component; + } + + public void Set(Guid id, TComponent component) where TComponent : struct, IComponent + { + Lookup()[id] = component; + } + + public void Remove(Guid id) where TComponent : struct, IComponent + { + Lookup().Remove(id); + } + + public void Clear() where TComponent : struct, IComponent + { + Lookup().Clear(); + } + + public void ClearAll() + { + foreach (var type in Stores.Keys) + { + ClearMethods[type](); + } + } + } +} diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index f76d76e..08340f4 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -11,7 +11,7 @@ namespace Encompass private readonly DrawLayerManager drawLayerManager; private readonly Dictionary componentIDToType = new Dictionary(); - private readonly Dictionary IDToComponent = new Dictionary(); + private readonly ComponentStore IDToComponent = new ComponentStore(); private readonly Dictionary> entityIDToComponentIDs = new Dictionary>(); private readonly Dictionary componentIDToEntityID = new Dictionary(); @@ -79,7 +79,7 @@ namespace Encompass internal void AddComponent(Entity entity, Type type, Guid componentID, IComponent component) { - IDToComponent[componentID] = component; + IDToComponent.Set(type, componentID, component); componentIDToEntityID[componentID] = entity.ID; componentIDToType[componentID] = type; entityIDToComponentTypeToComponentID[entity.ID][type] = componentID; @@ -133,7 +133,7 @@ namespace Encompass { if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { - return idSet.Select(id => (id, (TComponent)IDToComponent[id])); + return idSet.Select(id => (id, IDToComponent.Get(id))); } return Enumerable.Empty<(Guid, TComponent)>(); } @@ -142,7 +142,7 @@ namespace Encompass { if (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].TryGetValue(typeof(TComponent), out Guid id)) { - return (id, (TComponent)IDToComponent[id]); + return (id, IDToComponent.Get(id)); } throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); @@ -165,7 +165,7 @@ namespace Encompass internal IComponent GetComponentByID(Guid componentID) { - if (IDToComponent.ContainsKey(componentID)) + if (IDToComponent.Has(componentID)) { return IDToComponent[componentID]; } @@ -230,7 +230,7 @@ namespace Encompass componentsMarkedForRemoval.Clear(); } - private void Remove(Guid componentID) + private void Remove(Guid componentID) where TComponent : struct, IComponent { var type = componentIDToType[componentID]; @@ -245,7 +245,7 @@ namespace Encompass entityIDToComponentTypeToComponentID[entityID].Remove(type); } - IDToComponent.Remove(componentID); + IDToComponent.Remove(componentID); componentIDToType.Remove(componentID); componentIDToEntityID.Remove(componentID); typeToComponentIDs[type].Remove(componentID); diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 8541880..d9d6d59 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using Collections.Pooled; using Encompass.Exceptions; namespace Encompass { class ComponentMessageManager { - private readonly Dictionary componentIDToComponent = new Dictionary(); + private readonly ComponentStore componentIDToComponent = new ComponentStore(); private readonly Dictionary componentIDToType = new Dictionary(); private readonly Dictionary componentIDToEntityID = new Dictionary(); @@ -17,38 +16,15 @@ namespace Encompass private readonly Dictionary> componentMessageTypeToPendingComponentIDs = new Dictionary>(); private readonly Dictionary> componentMessageTypeToComponentIDs = new Dictionary>(); - private readonly Dictionary> entityToTypeToExistingComponentID = new Dictionary>(); - private readonly Dictionary> entityToTypeToPendingComponentID = new Dictionary>(); - private readonly Dictionary> entityToTypeToComponentID = new Dictionary>(); + private readonly Dictionary> typeToEntityToExistingComponentID = new Dictionary>(); + private readonly Dictionary> typeToEntityToPendingComponentID = new Dictionary>(); + private readonly Dictionary> typeToEntityToComponentID = new Dictionary>(); - private readonly Dictionary> entityToTypeToPendingComponentPriority = new Dictionary>(); - - internal void RegisterEntity(Entity entity) - { - entityToTypeToComponentID[entity] = new PooledDictionary(); - entityToTypeToPendingComponentID[entity] = new PooledDictionary(); - entityToTypeToPendingComponentPriority[entity] = new PooledDictionary(); - entityToTypeToExistingComponentID[entity] = new PooledDictionary(); - } - - internal void RegisterDestroyedEntity(Entity entity) - { - entityToTypeToComponentID[entity].Dispose(); - entityToTypeToComponentID.Remove(entity); - - entityToTypeToPendingComponentID[entity].Dispose(); - entityToTypeToPendingComponentID.Remove(entity); - - entityToTypeToPendingComponentPriority[entity].Dispose(); - entityToTypeToPendingComponentPriority.Remove(entity); - - entityToTypeToExistingComponentID[entity].Dispose(); - entityToTypeToExistingComponentID.Remove(entity); - } + private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(); internal void ClearMessages() { - componentIDToComponent.Clear(); + componentIDToComponent.ClearAll(); componentIDToType.Clear(); componentIDToEntityID.Clear(); @@ -67,22 +43,22 @@ namespace Encompass set.Clear(); } - foreach (var dictionary in entityToTypeToExistingComponentID.Values) + foreach (var dictionary in typeToEntityToExistingComponentID.Values) { dictionary.Clear(); } - foreach (var dictionary in entityToTypeToPendingComponentID.Values) + foreach (var dictionary in typeToEntityToPendingComponentID.Values) { dictionary.Clear(); } - foreach (var dictionary in entityToTypeToComponentID.Values) + foreach (var dictionary in typeToEntityToComponentID.Values) { dictionary.Clear(); } - foreach (var dictionary in entityToTypeToPendingComponentPriority.Values) + foreach (var dictionary in typeToEntityToPendingComponentPriority.Values) { dictionary.Clear(); } @@ -99,9 +75,14 @@ namespace Encompass componentMessageTypeToExistingComponentIDs[typeof(TComponent)].Add(componentMessage.componentID); - if (!entityToTypeToExistingComponentID[componentMessage.entity].ContainsKey(typeof(TComponent))) + if (!typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent))) { - entityToTypeToExistingComponentID[componentMessage.entity].Add(typeof(TComponent), componentMessage.componentID); + typeToEntityToExistingComponentID.Add(typeof(TComponent), new Dictionary()); + } + + if (!typeToEntityToExistingComponentID[typeof(TComponent)].ContainsKey(componentMessage.entity)) + { + typeToEntityToExistingComponentID[typeof(TComponent)].Add(componentMessage.entity, componentMessage.componentID); } else { @@ -118,19 +99,25 @@ namespace Encompass componentMessageTypeToPendingComponentIDs.Add(typeof(TComponent), new HashSet()); } - if (!entityToTypeToPendingComponentID[pendingComponentMessage.entity].ContainsKey(typeof(TComponent))) + if (!typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent))) { - entityToTypeToPendingComponentID[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.componentID); - entityToTypeToPendingComponentPriority[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.priority); + typeToEntityToPendingComponentID.Add(typeof(TComponent), new Dictionary()); + typeToEntityToPendingComponentPriority.Add(typeof(TComponent), new Dictionary()); + } + + if (!typeToEntityToPendingComponentID[typeof(TComponent)].ContainsKey(pendingComponentMessage.entity)) + { + typeToEntityToPendingComponentID[typeof(TComponent)].Add(pendingComponentMessage.entity, pendingComponentMessage.componentID); + typeToEntityToPendingComponentPriority[typeof(TComponent)].Add(pendingComponentMessage.entity, pendingComponentMessage.priority); componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID); } else { - if (pendingComponentMessage.priority < entityToTypeToPendingComponentPriority[pendingComponentMessage.entity][typeof(TComponent)]) + if (pendingComponentMessage.priority < typeToEntityToPendingComponentPriority[typeof(TComponent)][pendingComponentMessage.entity]) { - componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Remove(entityToTypeToPendingComponentID[pendingComponentMessage.entity][typeof(TComponent)]); - entityToTypeToPendingComponentID[pendingComponentMessage.entity][typeof(TComponent)] = pendingComponentMessage.componentID; - entityToTypeToPendingComponentPriority[pendingComponentMessage.entity][typeof(TComponent)] = pendingComponentMessage.priority; + componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Remove(typeToEntityToPendingComponentID[typeof(TComponent)][pendingComponentMessage.entity]); + typeToEntityToPendingComponentID[typeof(TComponent)][pendingComponentMessage.entity] = pendingComponentMessage.componentID; + typeToEntityToPendingComponentPriority[typeof(TComponent)][pendingComponentMessage.entity] = pendingComponentMessage.priority; componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID); } } @@ -138,7 +125,7 @@ namespace Encompass private void RegisterExistingOrPendingComponentMessage(Entity entity, Guid componentID, TComponent component) where TComponent : struct, IComponent { - componentIDToComponent[componentID] = component; + componentIDToComponent.Set(componentID, component); componentIDToEntityID[componentID] = entity.ID; componentIDToType[componentID] = typeof(TComponent); @@ -148,7 +135,11 @@ namespace Encompass } componentMessageTypeToComponentIDs[typeof(TComponent)].Add(componentID); - entityToTypeToComponentID[entity][typeof(TComponent)] = componentID; + if (!typeToEntityToComponentID.ContainsKey(typeof(TComponent))) + { + typeToEntityToComponentID.Add(typeof(TComponent), new Dictionary()); + } + typeToEntityToComponentID[typeof(TComponent)][entity] = componentID; } // general component reads by type @@ -157,7 +148,7 @@ namespace Encompass { if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { - return idSet.Select(id => (id, (TComponent)componentIDToComponent[id])); + return idSet.Select(id => (id, componentIDToComponent.Get(id))); } return Enumerable.Empty<(Guid, TComponent)>(); @@ -167,7 +158,7 @@ namespace Encompass { if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { - return idSet.Select(id => (id, (TComponent)componentIDToComponent[id])); + return idSet.Select(id => (id, componentIDToComponent.Get(id))); } return Enumerable.Empty<(Guid, TComponent)>(); @@ -177,7 +168,7 @@ namespace Encompass { if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { - return idSet.Select(id => (id, (TComponent)componentIDToComponent[id])); + return idSet.Select(id => (id, componentIDToComponent.Get(id))); } return Enumerable.Empty<(Guid, TComponent)>(); @@ -239,9 +230,9 @@ namespace Encompass internal (Guid, TComponent) ReadExistingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { - if (entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id)) + if (typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToExistingComponentID[typeof(TComponent)].TryGetValue(entity, out Guid id)) { - return (id, (TComponent)componentIDToComponent[id]); + return (id, componentIDToComponent.Get(id)); } else { @@ -249,23 +240,11 @@ namespace Encompass } } - internal (Guid, IComponent) ReadExistingComponentByEntityAndType(Entity entity, Type type) - { - if (entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].TryGetValue(type, out Guid id)) - { - return (id, componentIDToComponent[id]); - } - else - { - throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID); - } - } - internal (Guid, TComponent) ReadPendingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { - if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id)) + if (typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToPendingComponentID[typeof(TComponent)].TryGetValue(entity, out Guid id)) { - return (id, (TComponent)componentIDToComponent[id]); + return (id, componentIDToComponent.Get(id)); } else { @@ -273,55 +252,43 @@ namespace Encompass } } - internal (Guid, IComponent) ReadPendingComponentByEntityAndType(Entity entity, Type type) - { - if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(type, out Guid id)) - { - return (id, componentIDToComponent[id]); - } - else - { - throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID); - } - } - // check if entity has component of type internal bool HasExistingOrPendingComponent(Entity entity) where TComponent : struct, IComponent { - return entityToTypeToComponentID.ContainsKey(entity) && entityToTypeToComponentID[entity].ContainsKey(typeof(TComponent)); + return typeToEntityToComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToComponentID[typeof(TComponent)].ContainsKey(entity); } internal bool HasExistingOrPendingComponent(Entity entity, Type type) { - return entityToTypeToComponentID.ContainsKey(entity) && entityToTypeToComponentID[entity].ContainsKey(type); + return typeToEntityToComponentID.ContainsKey(type) && typeToEntityToComponentID[type].ContainsKey(entity); } internal bool HasExistingComponent(Entity entity) where TComponent : struct, IComponent { - return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(typeof(TComponent)); + return typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToExistingComponentID[typeof(TComponent)].ContainsKey(entity); } internal bool HasExistingComponent(Entity entity, Type type) { - return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(type); + return typeToEntityToExistingComponentID.ContainsKey(type) && typeToEntityToExistingComponentID[type].ContainsKey(entity); } internal bool HasPendingComponent(Entity entity) where TComponent : struct, IComponent { - return entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].ContainsKey(typeof(TComponent)); + return typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToPendingComponentID[typeof(TComponent)].ContainsKey(entity); } internal bool HasPendingComponent(Entity entity, Type type) { - return entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].ContainsKey(type); + return typeToEntityToPendingComponentID.ContainsKey(type) && typeToEntityToPendingComponentID[type].ContainsKey(entity); } - internal IComponent GetComponentByID(Guid componentID) + internal TComponent GetComponentByID(Guid componentID) where TComponent : struct, IComponent { - if (componentIDToComponent.ContainsKey(componentID)) + if (componentIDToComponent.Has(componentID)) { - return componentIDToComponent[componentID]; + return componentIDToComponent.Get(componentID); } else { diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 1ca83d5..fcf6288 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -183,7 +183,7 @@ namespace Encompass /// protected Entity ReadEntity() where TComponent : struct, IComponent { - var (id, component) = ReadComponentHelper(); + var (id, _) = ReadComponentHelper(); return GetEntityByComponentID(id); } @@ -216,7 +216,7 @@ namespace Encompass throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentMessageManager.GetComponentTypeByID(componentID).Name); } - return (TComponent)componentMessageManager.GetComponentByID(componentID); + return componentMessageManager.GetComponentByID(componentID); } // these next two are for the ComponentMessageEmitter only @@ -380,57 +380,6 @@ namespace Encompass return GetComponentHelper(entity).Item2; } - private (Guid, IComponent) GetComponentHelper(Entity entity, Type type) - { - var pending = typeof(PendingComponentMessage<>).MakeGenericType(type); - var existing = typeof(ComponentMessage<>).MakeGenericType(type); - - var pendingRead = receiveTypes.Contains(pending); - var existingRead = receiveTypes.Contains(existing); - - if (existingRead && pendingRead) - { - if (componentMessageManager.HasPendingComponent(entity, pending)) - { - return componentMessageManager.ReadPendingComponentByEntityAndType(entity, pending); - } - else if (componentMessageManager.HasExistingComponent(entity, existing)) - { - return componentMessageManager.ReadExistingComponentByEntityAndType(entity, existing); - } - else - { - throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID); - } - } - else if (existingRead) - { - return componentMessageManager.ReadExistingComponentByEntityAndType(entity, existing); - } - else if (pendingRead) - { - return componentMessageManager.ReadPendingComponentByEntityAndType(entity, pending); - } - else - { - throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, type.Name); - } - } - - /// - /// Returns a Component with the specified Type that exists on the Entity. - /// - /// - /// Thrown when the Entity does not have a Component of the specified Type - /// - /// - /// Thrown when the Engine does not declare that it reads the given Component Type. - /// - protected IComponent GetComponent(Entity entity, Type type) - { - return GetComponentHelper(entity, type).Item2; - } - /// /// Returns true if the Entity has a Component of the given Type. /// @@ -673,7 +622,7 @@ namespace Encompass { if (!HasComponent(entity)) { return false; } - var (componentID, component) = GetComponentHelper(entity); + var (componentID, _) = GetComponentHelper(entity); RemoveComponent(componentID); diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs index 6a6e525..466b7da 100644 --- a/encompass-cs/EntityManager.cs +++ b/encompass-cs/EntityManager.cs @@ -12,12 +12,10 @@ namespace Encompass private readonly HashSet entitiesMarkedForDestroy = new HashSet(); private readonly ComponentManager componentManager; - private readonly ComponentMessageManager componentMessageManager; - public EntityManager(ComponentManager componentManager, ComponentMessageManager componentMessageManager) + public EntityManager(ComponentManager componentManager) { this.componentManager = componentManager; - this.componentMessageManager = componentMessageManager; } public Entity CreateEntity() @@ -26,7 +24,6 @@ namespace Encompass var entity = new Entity(id); IDToEntity[id] = entity; componentManager.RegisterEntity(id); - componentMessageManager.RegisterEntity(entity); return entity; } @@ -56,7 +53,6 @@ namespace Encompass { foreach (var entityID in entitiesMarkedForDestroy) { - componentMessageManager.RegisterDestroyedEntity(GetEntity(entityID)); componentManager.MarkAllComponentsOnEntityForRemoval(entityID); IDToEntity.Remove(entityID); componentManager.RegisterDestroyedEntity(entityID); diff --git a/encompass-cs/MessageManager.cs b/encompass-cs/MessageManager.cs index 7846092..c967d67 100644 --- a/encompass-cs/MessageManager.cs +++ b/encompass-cs/MessageManager.cs @@ -6,7 +6,7 @@ namespace Encompass { internal class MessageManager { - private TimeManager timeManager; + private readonly TimeManager timeManager; private readonly Dictionary> messageTypeToMessages = new Dictionary>(); diff --git a/encompass-cs/TimeManager.cs b/encompass-cs/TimeManager.cs index 4c23dee..79cfe8f 100644 --- a/encompass-cs/TimeManager.cs +++ b/encompass-cs/TimeManager.cs @@ -5,7 +5,7 @@ namespace Encompass { internal class TimeManager { - private List timeDilationDatas = new List(); + private readonly List timeDilationDatas = new List(32); private double Linear(double t, double b, double c, double d) { diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 77802de..65b9c28 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -42,7 +42,7 @@ namespace Encompass componentManager = new ComponentManager(drawLayerManager); messageManager = new MessageManager(timeManager); componentMessageManager = new ComponentMessageManager(); - entityManager = new EntityManager(componentManager, componentMessageManager); + entityManager = new EntityManager(componentManager); renderManager = new RenderManager(componentManager, drawLayerManager, entityManager); } diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 30aae01..52f3410 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -9,7 +9,7 @@ Moonside Games Encompass ECS https://github.com/encompass-ecs - + Evan Hemsley 2019 Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations. true @@ -19,11 +19,11 @@ True - + - - + + diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index e7c5c54..3c6d061 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -267,45 +267,6 @@ namespace Tests Assert.AreEqual(mockComponent, gottenMockComponent); } - - [Receives(typeof(EntityMessage))] - [Reads(typeof(MockComponent))] - class GetMockComponentByRuntimeType : Engine - { - public override void Update(double dt) - { - foreach (var entityMessage in ReadMessages()) - { - gottenMockComponent = (MockComponent)GetComponent(entityMessage.entity, typeof(MockComponent)); - } - } - } - - [Test] - public void GetComponentByRuntimeType() - { - var worldBuilder = new WorldBuilder(); - worldBuilder.AddEngine(new GetMockComponentEngine()); - - var entity = worldBuilder.CreateEntity(); - - MockComponent mockComponent; - mockComponent.myInt = 3; - mockComponent.myString = "hello"; - - worldBuilder.SetComponent(entity, mockComponent); - - EntityMessage entityMessage; - entityMessage.entity = entity; - worldBuilder.SendMessage(entityMessage); - - var world = worldBuilder.Build(); - - world.Update(0.01); - - Assert.AreEqual(mockComponent, gottenMockComponent); - } - struct HasComponentTestMessage : IMessage { public Entity entity; From a4c30402396fa3e269b3f9589c50def63edc9184 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 12:10:33 -0800 Subject: [PATCH 02/24] start removing component ID system --- encompass-cs/Collections/ComponentStore.cs | 133 ++++++++-- encompass-cs/ComponentManager.cs | 205 ++------------- encompass-cs/ComponentMessageManager.cs | 245 +++--------------- encompass-cs/DrawLayerManager.cs | 2 +- encompass-cs/Engine.cs | 92 +------ .../Engines/ComponentMessageEmitter.cs | 7 +- encompass-cs/EntityManager.cs | 14 +- encompass-cs/Messages/ComponentMessage.cs | 5 +- .../Messages/PendingComponentMessage.cs | 5 +- encompass-cs/RenderManager.cs | 2 +- encompass-cs/WorldBuilder.cs | 2 +- 11 files changed, 201 insertions(+), 511 deletions(-) diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index 5d857b1..ee72406 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -1,48 +1,141 @@ using System; using System.Collections.Generic; +using System.Linq; namespace Encompass { internal class ComponentStore { - private readonly Dictionary Stores = new Dictionary(); - private readonly Dictionary ClearMethods = new Dictionary(); + interface IComponentStore + { + T All() where T : struct, IComponent; + } - private Dictionary Lookup() where TComponent : 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) + { + 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(); + } + } + + private readonly Dictionary Stores = new Dictionary(); + + public void RegisterComponentType() where TComponent : struct, IComponent { if (!Stores.ContainsKey(typeof(TComponent))) { - var dictionary = new Dictionary(); - Stores.Add(typeof(TComponent), dictionary); - ClearMethods.Add(typeof(TComponent), dictionary.Clear); + var store = new TypedComponentStore(); + Stores.Add(typeof(TComponent), store); } - - return Stores[typeof(TComponent)] as Dictionary; } - public bool Has(Guid id) where TComponent : struct, IComponent + private TypedComponentStore Lookup() where TComponent : struct, IComponent { - return Lookup().ContainsKey(id); + return Stores[typeof(TComponent)] as TypedComponentStore; } - public TComponent Get(Guid id) where TComponent : struct, IComponent + public bool Has(Entity entity) where TComponent : struct, IComponent { - return Lookup()[id]; + return Lookup().Has(entity); } - public void Set(Type type, Guid id, IComponent component) + public bool Has(Type type, Entity entity) { - (Stores[type] as Dictionary)[id] = component; + return Stores[type].Has(entity); } - public void Set(Guid id, TComponent component) where TComponent : struct, IComponent + public TComponent Get(Entity entity) where TComponent : struct, IComponent { - Lookup()[id] = component; + return Lookup().Get(entity); } - public void Remove(Guid id) where TComponent : struct, IComponent + public void Set(Entity entity, TComponent component) where TComponent : struct, IComponent { - Lookup().Remove(id); + Lookup().Set(entity, component); + } + + public void Set(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + { + Lookup().Set(entity, component, priority); + } + + public void Remove(Entity entity) where TComponent : struct, IComponent + { + Lookup().Remove(entity); + } + + public void Remove(Entity entity) + { + foreach (var entry in Stores.Values) + { + entry.Remove(entity); + } + } + + public bool Any() where TComponent : struct, IComponent + { + return Lookup().Count > 0; + } + + // public IEnumerable All() where TComponent : struct, IComponent + // { + // return Lookup().All(); + // } + + public IEnumerable<(Entity, TComponent)> All() where TComponent : struct, IComponent + { + return Lookup().All(); } public void Clear() where TComponent : struct, IComponent @@ -52,9 +145,9 @@ namespace Encompass public void ClearAll() { - foreach (var type in Stores.Keys) + foreach (var store in Stores.Values) { - ClearMethods[type](); + store.Clear(); } } } diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 08340f4..6ea8a00 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -10,66 +10,35 @@ namespace Encompass { private readonly DrawLayerManager drawLayerManager; - private readonly Dictionary componentIDToType = new Dictionary(); - private readonly ComponentStore IDToComponent = new ComponentStore(); - private readonly Dictionary> entityIDToComponentIDs = new Dictionary>(); - private readonly Dictionary componentIDToEntityID = new Dictionary(); + private readonly ComponentStore componentStore = new ComponentStore(); - private readonly Dictionary> entityIDToComponentTypeToComponentID = new Dictionary>(); - - private readonly Dictionary> typeToComponentIDs = new Dictionary>(); - - private readonly Dictionary<(Entity, Type), (Guid, IComponent)> componentWriteData = new Dictionary<(Entity, Type), (Guid, IComponent)>(); + 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 componentIDsMarkedForWrite = new HashSet(); - private readonly HashSet componentsMarkedForRemoval = new HashSet(); + private readonly HashSet entitiesMarkedForRemoval = new HashSet(); public ComponentManager(DrawLayerManager drawLayerManager) { this.drawLayerManager = drawLayerManager; } - internal void RegisterEntity(Guid entityID) + internal void MarkComponentForWrite(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - entityIDToComponentIDs.Add(entityID, new PooledSet()); - entityIDToComponentTypeToComponentID.Add(entityID, new PooledDictionary()); - } - - private Guid NextID() - { - return Guid.NewGuid(); - } - - internal Guid MarkComponentForWrite(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent - { - Guid id; - if (EntityHasComponentOfType(entity)) - { - id = GetComponentByEntityAndType(entity).Item1; - } - else - { - id = NextID(); - } + componentStore.RegisterComponentType(); if (componentWriteData.ContainsKey((entity, typeof(TComponent)))) { var currentPriority = componentWritePriorities[(entity, typeof(TComponent))]; if (priority < currentPriority) { - componentWriteData[(entity, typeof(TComponent))] = (id, component); + componentWriteData[(entity, typeof(TComponent))] = component; componentWritePriorities[(entity, typeof(TComponent))] = priority; - componentIDsMarkedForWrite.Add(id); } } else { - componentWriteData.Add((entity, typeof(TComponent)), (id, component)); + componentWriteData.Add((entity, typeof(TComponent)), component); componentWritePriorities[(entity, typeof(TComponent))] = priority; - componentIDsMarkedForWrite.Add(id); } - - return id; } internal void RegisterDrawableComponent(Guid componentID, TComponent component) where TComponent : IDrawableComponent @@ -77,23 +46,9 @@ namespace Encompass drawLayerManager.RegisterComponentWithLayer(componentID, component.Layer); } - internal void AddComponent(Entity entity, Type type, Guid componentID, IComponent component) + internal void AddComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - IDToComponent.Set(type, componentID, component); - componentIDToEntityID[componentID] = entity.ID; - componentIDToType[componentID] = type; - entityIDToComponentTypeToComponentID[entity.ID][type] = componentID; - if (!typeToComponentIDs.ContainsKey(type)) - { - typeToComponentIDs.Add(type, new HashSet()); - } - typeToComponentIDs[type].Add(componentID); - entityIDToComponentIDs[entity.ID].Add(componentID); - } - - internal void UpdateComponent(Guid componentID, IComponent component) - { - IDToComponent[componentID] = component; + componentStore.Set(entity, component); } internal void WriteComponents() @@ -101,165 +56,59 @@ namespace Encompass foreach (var keyValuePair in componentWriteData) { var (entity, type) = keyValuePair.Key; - var (componentID, component) = keyValuePair.Value; + var component = keyValuePair.Value; - if (!componentIDsMarkedForWrite.Contains(componentID) || !entityIDToComponentTypeToComponentID.ContainsKey(entity.ID)) { continue; } - - if (entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(type)) - { - UpdateComponent(componentID, component); - } - else - { - AddComponent(entity, type, componentID, component); - } + AddComponent(entity, component); } componentWriteData.Clear(); - componentIDsMarkedForWrite.Clear(); componentWritePriorities.Clear(); } - internal IEnumerable GetComponentIDsByEntityID(Guid entityID) + internal IEnumerable GetComponentsByType() where TComponent : struct, IComponent { - if (entityIDToComponentIDs.TryGetValue(entityID, out PooledSet idSet)) - { - return idSet; - } - return Enumerable.Empty(); + return componentStore.All().Select(pair => pair.Item2); } - internal IEnumerable<(Guid, TComponent)> GetComponentsByType() where TComponent : struct, IComponent + internal TComponent GetComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { - if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Select(id => (id, IDToComponent.Get(id))); - } - return Enumerable.Empty<(Guid, TComponent)>(); - } - - internal (Guid, TComponent) GetComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent - { - if (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].TryGetValue(typeof(TComponent), out Guid id)) - { - return (id, IDToComponent.Get(id)); - } - - throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); + return componentStore.Get(entity); } internal bool EntityHasComponentOfType(Entity entity) where TComponent : struct, IComponent { - return (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(typeof(TComponent))); + return componentStore.Has(entity); } internal bool ComponentOfTypeExists() where TComponent : struct, IComponent { - if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Count > 0; - } - - return false; + return componentStore.Any(); } - internal IComponent GetComponentByID(Guid componentID) + internal void MarkAllComponentsOnEntityForRemoval(Entity entity) { - if (IDToComponent.Has(componentID)) - { - return IDToComponent[componentID]; - } - else - { - throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID); - } - } - - internal Type GetComponentTypeByID(Guid componentID) - { - if (componentIDToType.ContainsKey(componentID)) - { - return componentIDToType[componentID]; - } - else - { - throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID); - } - } - - internal Guid GetEntityIDByComponentID(Guid componentID) - { - if (componentIDToEntityID.ContainsKey(componentID)) - { - return componentIDToEntityID[componentID]; - } - else - { - throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID); - } - } - - internal void MarkAllComponentsOnEntityForRemoval(Guid entityID) - { - foreach (var componentID in GetComponentIDsByEntityID(entityID)) - { - MarkForRemoval(componentID); - } - } - - internal void MarkForRemoval(Guid componentID) - { - componentsMarkedForRemoval.Add(componentID); + entitiesMarkedForRemoval.Add(entity); } internal void RemoveMarkedComponents() { - foreach (var componentID in componentsMarkedForRemoval) + foreach (var entity in entitiesMarkedForRemoval) { - if (componentIDsMarkedForWrite.Contains(componentID)) - { - componentIDsMarkedForWrite.Remove(componentID); - } - - if (IDToComponent.ContainsKey(componentID)) - { - Remove(componentID); - } + componentStore.Remove(entity); + drawLayerManager.UnRegisterComponentWithLayer(entity); } - componentsMarkedForRemoval.Clear(); + entitiesMarkedForRemoval.Clear(); } - private void Remove(Guid componentID) where TComponent : struct, IComponent + public void Remove(Entity entity) where TComponent : struct, IComponent { - var type = componentIDToType[componentID]; - - var entityID = componentIDToEntityID[componentID]; - if (entityIDToComponentIDs.ContainsKey(entityID)) - { - entityIDToComponentIDs[entityID].Remove(componentID); - } - - if (entityIDToComponentTypeToComponentID.ContainsKey(entityID)) - { - entityIDToComponentTypeToComponentID[entityID].Remove(type); - } - - IDToComponent.Remove(componentID); - componentIDToType.Remove(componentID); - componentIDToEntityID.Remove(componentID); - typeToComponentIDs[type].Remove(componentID); - - drawLayerManager.UnRegisterComponentWithLayer(componentID); + componentStore.Remove(entity); } - public void RegisterDestroyedEntity(Guid entityID) + private void Remove(Entity entity) { - entityIDToComponentIDs[entityID].Dispose(); - entityIDToComponentIDs.Remove(entityID); - - entityIDToComponentTypeToComponentID[entityID].Dispose(); - entityIDToComponentTypeToComponentID.Remove(entityID); + componentStore.Remove(entity); } } } diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index d9d6d59..15da58d 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -7,56 +7,18 @@ namespace Encompass { class ComponentMessageManager { - private readonly ComponentStore componentIDToComponent = new ComponentStore(); - private readonly Dictionary componentIDToType = new Dictionary(); + private readonly ComponentStore componentStore = new ComponentStore(); - private readonly Dictionary componentIDToEntityID = new Dictionary(); - - private readonly Dictionary> componentMessageTypeToExistingComponentIDs = new Dictionary>(); - private readonly Dictionary> componentMessageTypeToPendingComponentIDs = new Dictionary>(); - private readonly Dictionary> componentMessageTypeToComponentIDs = new Dictionary>(); - - private readonly Dictionary> typeToEntityToExistingComponentID = new Dictionary>(); - private readonly Dictionary> typeToEntityToPendingComponentID = new Dictionary>(); - private readonly Dictionary> typeToEntityToComponentID = new Dictionary>(); + private readonly ComponentStore existingComponentStore = new ComponentStore(); + private readonly ComponentStore pendingComponentStore = new ComponentStore(); private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(); internal void ClearMessages() { - componentIDToComponent.ClearAll(); - componentIDToType.Clear(); - componentIDToEntityID.Clear(); - - foreach (var set in componentMessageTypeToExistingComponentIDs.Values) - { - set.Clear(); - } - - foreach (var set in componentMessageTypeToPendingComponentIDs.Values) - { - set.Clear(); - } - - foreach (var set in componentMessageTypeToComponentIDs.Values) - { - set.Clear(); - } - - foreach (var dictionary in typeToEntityToExistingComponentID.Values) - { - dictionary.Clear(); - } - - foreach (var dictionary in typeToEntityToPendingComponentID.Values) - { - dictionary.Clear(); - } - - foreach (var dictionary in typeToEntityToComponentID.Values) - { - dictionary.Clear(); - } + componentStore.ClearAll(); + existingComponentStore.ClearAll(); + pendingComponentStore.ClearAll(); foreach (var dictionary in typeToEntityToPendingComponentPriority.Values) { @@ -66,129 +28,55 @@ namespace Encompass internal void AddExistingComponentMessage(ComponentMessage componentMessage) where TComponent : struct, IComponent { - RegisterExistingOrPendingComponentMessage(componentMessage.entity, componentMessage.componentID, componentMessage.component); + RegisterExistingOrPendingComponentMessage(componentMessage.entity, componentMessage.component); - if (!componentMessageTypeToExistingComponentIDs.ContainsKey(typeof(TComponent))) - { - componentMessageTypeToExistingComponentIDs.Add(typeof(TComponent), new HashSet()); - } - - componentMessageTypeToExistingComponentIDs[typeof(TComponent)].Add(componentMessage.componentID); - - if (!typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent))) - { - typeToEntityToExistingComponentID.Add(typeof(TComponent), new Dictionary()); - } - - if (!typeToEntityToExistingComponentID[typeof(TComponent)].ContainsKey(componentMessage.entity)) - { - typeToEntityToExistingComponentID[typeof(TComponent)].Add(componentMessage.entity, componentMessage.componentID); - } - else - { - throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", componentMessage.entity.ID, typeof(TComponent).Name); - } + existingComponentStore.Set(componentMessage.entity, componentMessage.component); } internal void AddPendingComponentMessage(PendingComponentMessage pendingComponentMessage) where TComponent : struct, IComponent { - RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.componentID, pendingComponentMessage.component); + RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.component); - if (!componentMessageTypeToPendingComponentIDs.ContainsKey(typeof(TComponent))) - { - componentMessageTypeToPendingComponentIDs.Add(typeof(TComponent), new HashSet()); - } - - if (!typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent))) - { - typeToEntityToPendingComponentID.Add(typeof(TComponent), new Dictionary()); - typeToEntityToPendingComponentPriority.Add(typeof(TComponent), new Dictionary()); - } - - if (!typeToEntityToPendingComponentID[typeof(TComponent)].ContainsKey(pendingComponentMessage.entity)) - { - typeToEntityToPendingComponentID[typeof(TComponent)].Add(pendingComponentMessage.entity, pendingComponentMessage.componentID); - typeToEntityToPendingComponentPriority[typeof(TComponent)].Add(pendingComponentMessage.entity, pendingComponentMessage.priority); - componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID); - } - else - { - if (pendingComponentMessage.priority < typeToEntityToPendingComponentPriority[typeof(TComponent)][pendingComponentMessage.entity]) - { - componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Remove(typeToEntityToPendingComponentID[typeof(TComponent)][pendingComponentMessage.entity]); - typeToEntityToPendingComponentID[typeof(TComponent)][pendingComponentMessage.entity] = pendingComponentMessage.componentID; - typeToEntityToPendingComponentPriority[typeof(TComponent)][pendingComponentMessage.entity] = pendingComponentMessage.priority; - componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID); - } - } + pendingComponentStore.Set(pendingComponentMessage.entity, pendingComponentMessage.component, pendingComponentMessage.priority); } - private void RegisterExistingOrPendingComponentMessage(Entity entity, Guid componentID, TComponent component) where TComponent : struct, IComponent + private void RegisterExistingOrPendingComponentMessage(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentIDToComponent.Set(componentID, component); - componentIDToEntityID[componentID] = entity.ID; - componentIDToType[componentID] = typeof(TComponent); - - if (!componentMessageTypeToComponentIDs.ContainsKey(typeof(TComponent))) - { - componentMessageTypeToComponentIDs.Add(typeof(TComponent), new HashSet()); - } - componentMessageTypeToComponentIDs[typeof(TComponent)].Add(componentID); - - if (!typeToEntityToComponentID.ContainsKey(typeof(TComponent))) - { - typeToEntityToComponentID.Add(typeof(TComponent), new Dictionary()); - } - typeToEntityToComponentID[typeof(TComponent)][entity] = componentID; + componentStore.Set(entity, component); } // general component reads by type - internal IEnumerable<(Guid, TComponent)> ReadExistingAndPendingComponentsByType() where TComponent : struct, IComponent + internal IEnumerable<(Entity, TComponent)> ReadExistingAndPendingComponentsByType() where TComponent : struct, IComponent { - if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Select(id => (id, componentIDToComponent.Get(id))); - } - - return Enumerable.Empty<(Guid, TComponent)>(); + return componentStore.All(); } - internal IEnumerable<(Guid, TComponent)> ReadExistingComponentsByType() where TComponent : struct, IComponent + internal IEnumerable<(Entity, TComponent)> ReadExistingComponentsByType() where TComponent : struct, IComponent { - if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Select(id => (id, componentIDToComponent.Get(id))); - } - - return Enumerable.Empty<(Guid, TComponent)>(); + return existingComponentStore.All(); } - internal IEnumerable<(Guid, TComponent)> ReadPendingComponentsByType() where TComponent : struct, IComponent + internal IEnumerable<(Entity, TComponent)> ReadPendingComponentsByType() where TComponent : struct, IComponent { - if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Select(id => (id, componentIDToComponent.Get(id))); - } - - return Enumerable.Empty<(Guid, TComponent)>(); + return pendingComponentStore.All(); } // singular component reads by type - internal (Guid, TComponent) ReadFirstExistingOrPendingComponentByType() where TComponent : struct, IComponent + internal (Entity, TComponent) ReadFirstExistingOrPendingComponentByType() where TComponent : struct, IComponent { if (!SomeExistingOrPendingComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } return ReadExistingAndPendingComponentsByType().First(); } - internal (Guid, TComponent) ReadFirstExistingComponentByType() where TComponent : struct, IComponent + internal (Entity, TComponent) ReadFirstExistingComponentByType() where TComponent : struct, IComponent { if (!SomeExistingComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } return ReadExistingComponentsByType().First(); } - internal (Guid, TComponent) ReadFirstPendingComponentByType() where TComponent : struct, IComponent + internal (Entity, TComponent) ReadFirstPendingComponentByType() where TComponent : struct, IComponent { if (!SomeExistingComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } return ReadPendingComponentsByType().First(); @@ -198,126 +86,61 @@ namespace Encompass internal bool SomeExistingOrPendingComponent() where TComponent : struct, IComponent { - if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Count > 0; - } - - return false; + return componentStore.Any(); } internal bool SomeExistingComponent() where TComponent : struct, IComponent { - if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Count > 0; - } - - return false; + return existingComponentStore.Any(); } internal bool SomePendingComponent() where TComponent : struct, IComponent { - if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) - { - return idSet.Count > 0; - } - - return false; + return pendingComponentStore.Any(); } // read components by entity and type - internal (Guid, TComponent) ReadExistingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent + internal TComponent ReadExistingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { - if (typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToExistingComponentID[typeof(TComponent)].TryGetValue(entity, out Guid id)) - { - return (id, componentIDToComponent.Get(id)); - } - else - { - throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); - } + return existingComponentStore.Get(entity); } - internal (Guid, TComponent) ReadPendingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent + internal TComponent ReadPendingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { - if (typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToPendingComponentID[typeof(TComponent)].TryGetValue(entity, out Guid id)) - { - return (id, componentIDToComponent.Get(id)); - } - else - { - throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); - } + return pendingComponentStore.Get(entity); } // check if entity has component of type internal bool HasExistingOrPendingComponent(Entity entity) where TComponent : struct, IComponent { - return typeToEntityToComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToComponentID[typeof(TComponent)].ContainsKey(entity); + return componentStore.Has(entity); } internal bool HasExistingOrPendingComponent(Entity entity, Type type) { - return typeToEntityToComponentID.ContainsKey(type) && typeToEntityToComponentID[type].ContainsKey(entity); + return componentStore.Has(type, entity); } internal bool HasExistingComponent(Entity entity) where TComponent : struct, IComponent { - return typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToExistingComponentID[typeof(TComponent)].ContainsKey(entity); + return existingComponentStore.Has(entity); } internal bool HasExistingComponent(Entity entity, Type type) { - return typeToEntityToExistingComponentID.ContainsKey(type) && typeToEntityToExistingComponentID[type].ContainsKey(entity); + return existingComponentStore.Has(type, entity); } internal bool HasPendingComponent(Entity entity) where TComponent : struct, IComponent { - return typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToPendingComponentID[typeof(TComponent)].ContainsKey(entity); + return pendingComponentStore.Has(entity); } internal bool HasPendingComponent(Entity entity, Type type) { - return typeToEntityToPendingComponentID.ContainsKey(type) && typeToEntityToPendingComponentID[type].ContainsKey(entity); - } - - internal TComponent GetComponentByID(Guid componentID) where TComponent : struct, IComponent - { - if (componentIDToComponent.Has(componentID)) - { - return componentIDToComponent.Get(componentID); - } - else - { - throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID); - } - } - - internal Type GetComponentTypeByID(Guid componentID) - { - if (componentIDToType.ContainsKey(componentID)) - { - return componentIDToType[componentID]; - } - else - { - throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID); - } - } - - internal Guid GetEntityIDByComponentID(Guid componentID) - { - if (componentIDToEntityID.ContainsKey(componentID)) - { - return componentIDToEntityID[componentID]; - } - else - { - throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID); - } + return pendingComponentStore.Has(type, entity); } } } diff --git a/encompass-cs/DrawLayerManager.cs b/encompass-cs/DrawLayerManager.cs index 926be6f..a00e669 100644 --- a/encompass-cs/DrawLayerManager.cs +++ b/encompass-cs/DrawLayerManager.cs @@ -73,7 +73,7 @@ namespace Encompass } } - public void UnRegisterComponentWithLayer(Guid id) + public void UnRegisterComponentWithLayer(Entity entity) { if (componentIDToLayerIndex.ContainsKey(id)) { diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index fcf6288..eb9a1b4 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -20,7 +20,7 @@ namespace Encompass internal readonly Dictionary writePriorities = new Dictionary(); /// - /// If false, the Engine will ignore time dilation. + /// If false, the Engine will ignore time dilation. /// internal bool usesTimeDilation = true; public bool TimeDilationActive { get => usesTimeDilation && timeManager.TimeDilationActive; } @@ -154,37 +154,12 @@ namespace Encompass return entityManager.GetEntity(entityID); } - /// - /// Returns the Entity ID associated with the specified Component Type and ID. - /// - private Guid GetEntityIDByComponentID(Guid componentID) where TComponent : struct, IComponent - { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); - - if (!pendingRead && !existingRead) - { - throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name); - } - - return componentMessageManager.GetEntityIDByComponentID(componentID); - } - - /// - /// Returns the Entity associated with the specified Component Type and ID. - /// - private Entity GetEntityByComponentID(Guid componentID) where TComponent : struct, IComponent - { - return GetEntity(GetEntityIDByComponentID(componentID)); - } - /// /// Returns an Entity containing the specified Component type. /// protected Entity ReadEntity() where TComponent : struct, IComponent { - var (id, _) = ReadComponentHelper(); - return GetEntityByComponentID(id); + return ReadComponentHelper().Item1; } /// @@ -192,46 +167,17 @@ namespace Encompass /// protected IEnumerable ReadEntities() where TComponent : struct, IComponent { - foreach (var (id, _) in ReadComponentsHelper()) - { - yield return GetEntityByComponentID(id); - } - } - - /// - /// Returns the Component struct with the specified Component Type and ID. - /// - internal TComponent GetComponentByID(Guid componentID) where TComponent : struct, IComponent - { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); - - if (!pendingRead && !existingRead) - { - throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name); - } - - if (componentMessageManager.GetComponentTypeByID(componentID) != typeof(TComponent)) - { - throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentMessageManager.GetComponentTypeByID(componentID).Name); - } - - return componentMessageManager.GetComponentByID(componentID); + return ReadComponentsHelper().Select(pair => pair.Item1); } // these next two are for the ComponentMessageEmitter only - internal IEnumerable<(Guid, TComponent)> ReadComponentsFromWorld() where TComponent : struct, IComponent + internal IEnumerable ReadComponentsFromWorld() where TComponent : struct, IComponent { return componentManager.GetComponentsByType(); } - internal Entity ReadEntityFromWorld(Guid componentID) - { - return GetEntity(componentManager.GetEntityIDByComponentID(componentID)); - } - - private IEnumerable<(Guid, TComponent)> ReadComponentsHelper() where TComponent : struct, IComponent + private IEnumerable<(Entity, TComponent)> ReadComponentsHelper() where TComponent : struct, IComponent { var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); @@ -266,10 +212,10 @@ namespace Encompass /// protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity() where TComponent : struct, IComponent { - return ReadComponentsHelper().Select((tuple) => (tuple.Item2, GetEntityByComponentID(tuple.Item1))); + return ReadComponentsHelper().Select((tuple) => (tuple.Item2, tuple.Item1)); } - private (Guid, TComponent) ReadComponentHelper() where TComponent : struct, IComponent + private (Entity, TComponent) ReadComponentHelper() where TComponent : struct, IComponent { var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); @@ -304,8 +250,8 @@ namespace Encompass /// protected (TComponent, Entity) ReadComponentIncludingEntity() where TComponent : struct, IComponent { - var (id, component) = ReadComponentHelper(); - return (component, GetEntityByComponentID(id)); + var (entity, component) = ReadComponentHelper(); + return (component, entity); } /// @@ -333,7 +279,7 @@ namespace Encompass } } - private (Guid, TComponent) GetComponentHelper(Entity entity) where TComponent : struct, IComponent + private TComponent GetComponentHelper(Entity entity) where TComponent : struct, IComponent { var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); @@ -377,7 +323,7 @@ namespace Encompass /// protected TComponent GetComponent(Entity entity) where TComponent : struct, IComponent { - return GetComponentHelper(entity).Item2; + return GetComponentHelper(entity); } /// @@ -451,7 +397,7 @@ namespace Encompass { var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0; - var componentID = componentManager.MarkComponentForWrite(entity, component, priority); + componentManager.MarkComponentForWrite(entity, component, priority); if (!sendTypes.Contains(typeof(ComponentWriteMessage))) { @@ -462,7 +408,6 @@ namespace Encompass { PendingComponentMessage newComponentMessage; newComponentMessage.entity = entity; - newComponentMessage.componentID = componentID; newComponentMessage.component = component; newComponentMessage.priority = priority; SendPendingComponentMessage(newComponentMessage); @@ -622,21 +567,10 @@ namespace Encompass { if (!HasComponent(entity)) { return false; } - var (componentID, _) = GetComponentHelper(entity); - - RemoveComponent(componentID); - + componentManager.Remove(entity); return true; } - /// - /// Removes the Component with the specified ID from its Entity. - /// - private void RemoveComponent(Guid componentID) - { - componentManager.MarkForRemoval(componentID); - } - /// /// Activates the Encompass time dilation system. /// Engines that have the IgnoresTimeDilation property will ignore all time dilation. diff --git a/encompass-cs/Engines/ComponentMessageEmitter.cs b/encompass-cs/Engines/ComponentMessageEmitter.cs index 5addc68..4d12515 100644 --- a/encompass-cs/Engines/ComponentMessageEmitter.cs +++ b/encompass-cs/Engines/ComponentMessageEmitter.cs @@ -9,15 +9,14 @@ namespace Encompass public override void Update(double dt) { - foreach (var (componentID, component) in ReadComponentsFromWorld()) + foreach (var (component, entity) in ReadComponentsIncludingEntity()) { ComponentMessage componentMessage; - componentMessage.entity = ReadEntityFromWorld(componentID); - componentMessage.componentID = componentID; + componentMessage.entity = entity; componentMessage.component = component; SendMessage(componentMessage); SendExistingComponentMessage(componentMessage); } } } -} \ No newline at end of file +} diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs index 466b7da..fa96910 100644 --- a/encompass-cs/EntityManager.cs +++ b/encompass-cs/EntityManager.cs @@ -9,7 +9,7 @@ namespace Encompass { private readonly Dictionary IDToEntity = new Dictionary(); - private readonly HashSet entitiesMarkedForDestroy = new HashSet(); + private readonly HashSet entitiesMarkedForDestroy = new HashSet(); private readonly ComponentManager componentManager; @@ -23,7 +23,6 @@ namespace Encompass var id = NextID(); var entity = new Entity(id); IDToEntity[id] = entity; - componentManager.RegisterEntity(id); return entity; } @@ -44,18 +43,17 @@ namespace Encompass } } - public void MarkForDestroy(Guid entityID) + public void MarkForDestroy(Entity entity) { - entitiesMarkedForDestroy.Add(entityID); + entitiesMarkedForDestroy.Add(entity); } public void DestroyMarkedEntities() { - foreach (var entityID in entitiesMarkedForDestroy) + foreach (var entity in entitiesMarkedForDestroy) { - componentManager.MarkAllComponentsOnEntityForRemoval(entityID); - IDToEntity.Remove(entityID); - componentManager.RegisterDestroyedEntity(entityID); + componentManager.MarkAllComponentsOnEntityForRemoval(entity); + IDToEntity.Remove(entity.ID); } entitiesMarkedForDestroy.Clear(); diff --git a/encompass-cs/Messages/ComponentMessage.cs b/encompass-cs/Messages/ComponentMessage.cs index c1b74ee..1153815 100644 --- a/encompass-cs/Messages/ComponentMessage.cs +++ b/encompass-cs/Messages/ComponentMessage.cs @@ -1,11 +1,8 @@ -using System; - namespace Encompass { internal struct ComponentMessage : IMessage where TComponent : struct, IComponent { public Entity entity; - public Guid componentID; public TComponent component; } -} \ No newline at end of file +} diff --git a/encompass-cs/Messages/PendingComponentMessage.cs b/encompass-cs/Messages/PendingComponentMessage.cs index 4a051b4..8dfcc36 100644 --- a/encompass-cs/Messages/PendingComponentMessage.cs +++ b/encompass-cs/Messages/PendingComponentMessage.cs @@ -1,12 +1,9 @@ -using System; - namespace Encompass { internal struct PendingComponentMessage : IMessage where TComponent : struct, IComponent { public Entity entity; - public Guid componentID; public TComponent component; public int priority; } -} \ No newline at end of file +} diff --git a/encompass-cs/RenderManager.cs b/encompass-cs/RenderManager.cs index 35c2405..839c5fd 100644 --- a/encompass-cs/RenderManager.cs +++ b/encompass-cs/RenderManager.cs @@ -42,8 +42,8 @@ namespace Encompass foreach (var componentID in componentIDSet) { - var component = componentManager.GetComponentByID(componentID); var componentType = componentManager.GetComponentTypeByID(componentID); + var component = componentManager.GetComponentByID(componentType, componentID); var entityID = componentManager.GetEntityIDByComponentID(componentID); var entity = entityManager.GetEntity(entityID); diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 65b9c28..491e6da 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -75,7 +75,7 @@ namespace Encompass /// public void SetComponent(Entity entity, TComponent component, int priority = 0) where TComponent : struct, IComponent { - var componentID = componentManager.MarkComponentForWrite(entity, component, priority); + componentManager.MarkComponentForWrite(entity, component, priority); if (component is IDrawableComponent drawableComponent) { componentManager.RegisterDrawableComponent(componentID, drawableComponent); From 5513402573b72bbd41ddd1f4f5f02eb0f97b48e1 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 14:59:55 -0800 Subject: [PATCH 03/24] removed all component ID stuff --- encompass-cs/Collections/ComponentStore.cs | 91 +++++-------------- .../Collections/TypedComponentStore.cs | 74 +++++++++++++++ encompass-cs/ComponentManager.cs | 46 +++------- encompass-cs/ComponentMessageManager.cs | 9 +- encompass-cs/DrawLayerManager.cs | 44 +++++---- encompass-cs/Engine.cs | 20 ++-- .../Engines/ComponentMessageEmitter.cs | 2 +- encompass-cs/RenderManager.cs | 8 +- encompass-cs/Renderer.cs | 11 +-- encompass-cs/World.cs | 5 +- encompass-cs/WorldBuilder.cs | 15 +-- test/ComponentTest.cs | 10 +- test/EngineTest.cs | 2 +- 13 files changed, 170 insertions(+), 167 deletions(-) create mode 100644 encompass-cs/Collections/TypedComponentStore.cs 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))); } From 02932636847e54d9c988722db4a8a328e8041c67 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 15:14:28 -0800 Subject: [PATCH 04/24] fix component updates --- encompass-cs/ComponentManager.cs | 5 +++-- encompass-cs/ComponentMessageManager.cs | 15 ++++++++++++++- encompass-cs/Engine.cs | 4 ++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 3459991..6ffb8a6 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -37,7 +37,7 @@ namespace Encompass internal void WriteComponents() { - componentStore.SwapWith(componentMessageManager.ComponentStore); + componentStore.SwapWith(componentMessageManager.UpToDateComponentStore); } internal IEnumerable<(TComponent, Entity)> GetComponentsIncludingEntity() where TComponent : struct, IComponent @@ -83,7 +83,8 @@ namespace Encompass public void Remove(Entity entity) where TComponent : struct, IComponent { - componentStore.Remove(entity); + //componentStore.Remove(entity); + componentMessageManager.Remove(entity); } private void Remove(Entity entity) diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 5747795..06137b9 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -11,16 +11,18 @@ namespace Encompass private readonly ComponentStore existingComponentStore = new ComponentStore(); private readonly ComponentStore pendingComponentStore = new ComponentStore(); + private readonly ComponentStore upToDateComponentStore = new ComponentStore(); private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(); - public ComponentStore ComponentStore { get => componentStore; } + public ComponentStore UpToDateComponentStore { get => upToDateComponentStore; } internal void ClearMessages() { componentStore.ClearAll(); existingComponentStore.ClearAll(); pendingComponentStore.ClearAll(); + upToDateComponentStore.ClearAll(); foreach (var dictionary in typeToEntityToPendingComponentPriority.Values) { @@ -46,6 +48,12 @@ namespace Encompass private void RegisterExistingOrPendingComponentMessage(Entity entity, TComponent component) where TComponent : struct, IComponent { componentStore.Set(entity, component); + upToDateComponentStore.Set(entity, component); + } + + public void UpdateComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + { + upToDateComponentStore.Set(entity, component, priority); } // general component reads by type @@ -145,5 +153,10 @@ namespace Encompass { return pendingComponentStore.Has(type, entity); } + + internal void Remove(Entity entity) where TComponent : struct, IComponent + { + upToDateComponentStore.Remove(entity); + } } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index a910a52..8387b4d 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -415,6 +415,10 @@ namespace Encompass newComponentMessage.priority = priority; SendPendingComponentMessage(newComponentMessage); } + else + { + componentMessageManager.UpdateComponent(entity, component, priority); + } if (component is IDrawableComponent drawableComponent) { From 571310e5798163e4876743caea04ab53c1046b2f Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 16:00:00 -0800 Subject: [PATCH 05/24] fixed world initialization and draw component removal issues --- encompass-cs/ComponentManager.cs | 1 + encompass-cs/ComponentMessageManager.cs | 7 ++++++- encompass-cs/DrawLayerManager.cs | 21 ++++++++++++++++----- encompass-cs/WorldBuilder.cs | 9 ++++++--- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 6ffb8a6..5db7d12 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -85,6 +85,7 @@ namespace Encompass { //componentStore.Remove(entity); componentMessageManager.Remove(entity); + drawLayerManager.UnRegisterComponentWithLayer(entity); } private void Remove(Entity entity) diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 06137b9..9c37d0b 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -11,7 +11,7 @@ namespace Encompass private readonly ComponentStore existingComponentStore = new ComponentStore(); private readonly ComponentStore pendingComponentStore = new ComponentStore(); - private readonly ComponentStore upToDateComponentStore = new ComponentStore(); + private ComponentStore upToDateComponentStore = new ComponentStore(); private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(); @@ -30,6 +30,11 @@ namespace Encompass } } + internal void SetStartingComponentStore(ComponentStore componentStore) + { + upToDateComponentStore = componentStore; + } + internal void AddExistingComponentMessage(ComponentMessage componentMessage) where TComponent : struct, IComponent { RegisterExistingOrPendingComponentMessage(componentMessage.entity, componentMessage.component); diff --git a/encompass-cs/DrawLayerManager.cs b/encompass-cs/DrawLayerManager.cs index aab17b2..c116bb7 100644 --- a/encompass-cs/DrawLayerManager.cs +++ b/encompass-cs/DrawLayerManager.cs @@ -7,7 +7,6 @@ namespace Encompass internal class DrawLayerManager { private readonly SortedList layerOrder = new SortedList(); - private readonly ComponentStore componentStore = new ComponentStore(); private readonly Dictionary layerIndexToComponentStore = new Dictionary(); private readonly Dictionary> layerIndexToGeneralRenderers = new Dictionary>(); @@ -52,7 +51,12 @@ namespace Encompass public void RegisterComponentWithLayer(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent { - if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { UnRegisterComponentWithLayer(entity, component); } + if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) + { + typeToEntityToLayer.Add(typeof(TComponent), new Dictionary()); + } + + if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { UnRegisterComponentWithLayer(entity); } if (layerIndexToComponentStore.ContainsKey(layer)) { @@ -74,8 +78,10 @@ namespace Encompass } } - public void UnRegisterComponentWithLayer(Entity entity, TComponent component) where TComponent : struct, IComponent + public void UnRegisterComponentWithLayer(Entity entity) where TComponent : struct, IComponent { + if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; } + if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { var layer = typeToEntityToLayer[typeof(TComponent)][entity]; @@ -86,7 +92,10 @@ namespace Encompass public void UnRegisterEntityWithLayer(Entity entity) { - componentStore.Remove(entity); + foreach (var store in layerIndexToComponentStore.Values) + { + store.Remove(entity); + } } public IEnumerable GeneralRenderersByLayer(int layer) @@ -98,7 +107,9 @@ namespace Encompass public IEnumerable<(Entity, Type, IComponent)> AllInLayer(int layer) { - return layerIndexToComponentStore[layer].AllInterfaceTyped(); + return layerIndexToComponentStore.ContainsKey(layer) ? + layerIndexToComponentStore[layer].AllInterfaceTyped() : + Enumerable.Empty<(Entity, Type, IComponent)>(); } } } diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index a12d53a..a64e97e 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -20,7 +20,8 @@ namespace Encompass { private readonly List engines = new List(); private readonly DirectedGraph engineGraph = GraphBuilder.DirectedGraph(); - private readonly ComponentStore componentStore = new ComponentStore(); + private readonly ComponentStore startingComponentStoreForComponentManager = new ComponentStore(); + private readonly ComponentStore startingComponentStoreForComponentMessageManager = new ComponentStore(); private readonly ComponentManager componentManager; private readonly EntityManager entityManager; @@ -76,7 +77,8 @@ namespace Encompass /// public void SetComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentStore.Set(entity, component); + startingComponentStoreForComponentManager.Set(entity, component); + startingComponentStoreForComponentMessageManager.Set(entity, component); if (component is IDrawableComponent drawableComponent) { @@ -348,7 +350,8 @@ namespace Encompass renderManager ); - componentManager.SetComponentStore(componentStore); + componentManager.SetComponentStore(startingComponentStoreForComponentManager); + componentMessageManager.SetStartingComponentStore(startingComponentStoreForComponentMessageManager); return world; } From 2a62adee51487fdd5f6ee9fd7aaa083affc0cb80 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 16:01:09 -0800 Subject: [PATCH 06/24] 0.18.0-preview1 --- encompass-cs/encompass-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 52f3410..470c597 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.17.0 + 0.18.0-preview1 Evan Hemsley true Moonside Games From bdac3d85418d02444f3c1fe5f8bd3f6e4ef3fe84 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 16:19:35 -0800 Subject: [PATCH 07/24] fix panic when using runtime HasComponent --- encompass-cs/Collections/ComponentStore.cs | 2 +- test/ComponentTest.cs | 25 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index 4528cca..b081f99 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -33,7 +33,7 @@ namespace Encompass public bool Has(Type type, Entity entity) { - return Stores[type].Has(entity); + return Stores.ContainsKey(type) && Stores[type].Has(entity); } public TComponent Get(Entity entity) where TComponent : struct, IComponent diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index 957ac91..a27ecf6 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -308,6 +308,8 @@ namespace Tests world.Update(0.01); } + static bool hasComponentRuntimeTypeResult; + [Receives(typeof(HasComponentTestMessage))] [Reads(typeof(MockComponent))] class HasComponentWithRuntimeTypeEngine : Engine @@ -316,7 +318,7 @@ namespace Tests { foreach (var hasComponentTestEngine in ReadMessages()) { - Assert.IsTrue(HasComponent(hasComponentTestEngine.entity, typeof(MockComponent))); + hasComponentRuntimeTypeResult = HasComponent(hasComponentTestEngine.entity, typeof(MockComponent)); } } } @@ -342,6 +344,27 @@ namespace Tests var world = worldBuilder.Build(); world.Update(0.01); + + Assert.IsTrue(hasComponentRuntimeTypeResult); + } + + [Test] + public void HasComponentWithRuntimeTypeFalseWhenNoneHaveBeenCreated() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(new HasComponentWithRuntimeTypeEngine()); + + var entity = worldBuilder.CreateEntity(); + + HasComponentTestMessage hasComponentTestMessage; + hasComponentTestMessage.entity = entity; + worldBuilder.SendMessage(hasComponentTestMessage); + + var world = worldBuilder.Build(); + + world.Update(0.01); + + Assert.IsFalse(hasComponentRuntimeTypeResult); } struct RemoveComponentTestMessage : IMessage From 23b3241f60316bedf6398da85fa2e419312e7ed3 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 16:19:54 -0800 Subject: [PATCH 08/24] 0.18.0-preview2 --- encompass-cs/encompass-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 470c597..39d2173 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview1 + 0.18.0-preview2 Evan Hemsley true Moonside Games From 65e5ea2ec028707e626b44480895951ed745dcd3 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 16:23:39 -0800 Subject: [PATCH 09/24] remove Collections.Pooled --- encompass-cs/ComponentManager.cs | 3 --- encompass-cs/encompass-cs.csproj | 11 +++++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 5db7d12..a860cf3 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -1,8 +1,5 @@ -using System; using System.Collections.Generic; using System.Linq; -using Encompass.Exceptions; -using Collections.Pooled; namespace Encompass { diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 39d2173..f860bab 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 Encompass @@ -9,7 +9,7 @@ Moonside Games Encompass ECS https://github.com/encompass-ecs - + Evan Hemsley 2019 Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations. true @@ -19,11 +19,10 @@ True - + - - + - + \ No newline at end of file From c11b5720b78205f840586591ece3ff05e6902fee Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 17:07:06 -0800 Subject: [PATCH 10/24] adding default capacities to avoid lots of initial runtime resizing --- encompass-cs/Collections/ComponentStore.cs | 2 +- encompass-cs/Collections/TypedComponentStore.cs | 4 ++-- encompass-cs/ComponentMessageManager.cs | 2 +- encompass-cs/DrawLayerManager.cs | 6 +++--- encompass-cs/EntityManager.cs | 4 ++-- encompass-cs/RenderManager.cs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index b081f99..60396ea 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -6,7 +6,7 @@ namespace Encompass { internal class ComponentStore { - private Dictionary Stores = new Dictionary(); + private Dictionary Stores = new Dictionary(512); public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable() { diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index 6392739..cb84a6d 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -15,8 +15,8 @@ namespace Encompass internal class TypedComponentStore : TypedComponentStore where TComponent : struct, IComponent { - private readonly Dictionary store = new Dictionary(); - private readonly Dictionary priorities = new Dictionary(); + private readonly Dictionary store = new Dictionary(128); + private readonly Dictionary priorities = new Dictionary(128); public override int Count { get => store.Count; } diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 9c37d0b..2d93a1a 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -13,7 +13,7 @@ namespace Encompass private readonly ComponentStore pendingComponentStore = new ComponentStore(); private ComponentStore upToDateComponentStore = new ComponentStore(); - private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(); + private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(128); public ComponentStore UpToDateComponentStore { get => upToDateComponentStore; } diff --git a/encompass-cs/DrawLayerManager.cs b/encompass-cs/DrawLayerManager.cs index c116bb7..9785987 100644 --- a/encompass-cs/DrawLayerManager.cs +++ b/encompass-cs/DrawLayerManager.cs @@ -8,10 +8,10 @@ namespace Encompass { private readonly SortedList layerOrder = new SortedList(); - private readonly Dictionary layerIndexToComponentStore = new Dictionary(); - private readonly Dictionary> layerIndexToGeneralRenderers = new Dictionary>(); + private readonly Dictionary layerIndexToComponentStore = new Dictionary(512); + private readonly Dictionary> layerIndexToGeneralRenderers = new Dictionary>(512); - private readonly Dictionary> typeToEntityToLayer = new Dictionary>(); + private readonly Dictionary> typeToEntityToLayer = new Dictionary>(512); public IEnumerable LayerOrder { get { return layerOrder.Values; } } diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs index fa96910..2d33f31 100644 --- a/encompass-cs/EntityManager.cs +++ b/encompass-cs/EntityManager.cs @@ -7,9 +7,9 @@ namespace Encompass { internal class EntityManager { - private readonly Dictionary IDToEntity = new Dictionary(); + private readonly Dictionary IDToEntity = new Dictionary(1024); - private readonly HashSet entitiesMarkedForDestroy = new HashSet(); + private readonly HashSet entitiesMarkedForDestroy = new HashSet(256); private readonly ComponentManager componentManager; diff --git a/encompass-cs/RenderManager.cs b/encompass-cs/RenderManager.cs index 07d4a46..bb271e9 100644 --- a/encompass-cs/RenderManager.cs +++ b/encompass-cs/RenderManager.cs @@ -10,7 +10,7 @@ namespace Encompass private readonly DrawLayerManager drawLayerManager; private readonly EntityManager entityManager; - private readonly Dictionary> drawComponentTypeToOrderedRenderer = new Dictionary>(); + private readonly Dictionary> drawComponentTypeToOrderedRenderer = new Dictionary>(256); public RenderManager( ComponentManager componentManager, From 8a676b3e4bc1374a99344fc5ad8840aff73f07ba Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 17:07:54 -0800 Subject: [PATCH 11/24] hashsets cant set capacity lol --- encompass-cs/EntityManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs index 2d33f31..0d89fa3 100644 --- a/encompass-cs/EntityManager.cs +++ b/encompass-cs/EntityManager.cs @@ -9,7 +9,7 @@ namespace Encompass { private readonly Dictionary IDToEntity = new Dictionary(1024); - private readonly HashSet entitiesMarkedForDestroy = new HashSet(256); + private readonly HashSet entitiesMarkedForDestroy = new HashSet(); private readonly ComponentManager componentManager; From ec191c69d89b6b6b29a3136de8ad2ac631496ceb Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 17:50:05 -0800 Subject: [PATCH 12/24] fix issue where components would not be readable by renderers if they were not updated the previous frame --- encompass-cs/ComponentMessageManager.cs | 1 - encompass-cs/RenderManager.cs | 1 - test/GeneralRendererTest.cs | 5 +++++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 2d93a1a..7c4b58a 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -22,7 +22,6 @@ namespace Encompass componentStore.ClearAll(); existingComponentStore.ClearAll(); pendingComponentStore.ClearAll(); - upToDateComponentStore.ClearAll(); foreach (var dictionary in typeToEntityToPendingComponentPriority.Values) { diff --git a/encompass-cs/RenderManager.cs b/encompass-cs/RenderManager.cs index bb271e9..bcf07eb 100644 --- a/encompass-cs/RenderManager.cs +++ b/encompass-cs/RenderManager.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection; using System.Collections.Generic; namespace Encompass diff --git a/test/GeneralRendererTest.cs b/test/GeneralRendererTest.cs index 8fa01d5..bc1aedc 100644 --- a/test/GeneralRendererTest.cs +++ b/test/GeneralRendererTest.cs @@ -35,6 +35,9 @@ namespace Tests world.Update(0.01f); world.Draw(); + world.Update(0.01); + world.Draw(); + Assert.That(result, Is.EqualTo((aComponent, entity))); } @@ -55,7 +58,9 @@ namespace Tests var world = worldBuilder.Build(); world.Update(0.01f); + world.Draw(); + world.Update(0.01f); world.Draw(); Assert.That(result, Is.EqualTo((aComponent, entity)).Or.EqualTo((aComponentTwo, entityB))); From d4c6b9416d341cda6166886f563d810d7f23ae36 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 5 Dec 2019 17:50:40 -0800 Subject: [PATCH 13/24] 0.18.0-preview3 --- encompass-cs/encompass-cs.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index f860bab..729eb03 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview2 + 0.18.0-preview3 Evan Hemsley true Moonside Games @@ -25,4 +25,4 @@ - \ No newline at end of file + From 005405512eb1e2bd050e82b51dfad9235a23c101 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 19:55:17 -0800 Subject: [PATCH 14/24] remove component messages --- encompass-cs/Attributes/Reads.cs | 2 +- encompass-cs/Attributes/ReadsPending.cs | 2 +- encompass-cs/Attributes/Writes.cs | 6 +- encompass-cs/Attributes/WritesPending.cs | 2 +- encompass-cs/ComponentManager.cs | 5 -- encompass-cs/ComponentMessageManager.cs | 13 ++-- encompass-cs/Engine.cs | 64 ++++++++--------- encompass-cs/Engines/ComponentEmitter.cs | 18 +++++ .../Engines/ComponentMessageEmitter.cs | 22 ------ encompass-cs/Messages/ComponentMessage.cs | 8 --- .../Messages/ComponentWriteMessage.cs | 10 --- .../Messages/PendingComponentMessage.cs | 9 --- encompass-cs/WorldBuilder.cs | 72 ++++++++----------- encompass-cs/encompass-cs.csproj | 6 +- test/ComponentTest.cs | 12 +++- 15 files changed, 105 insertions(+), 146 deletions(-) create mode 100644 encompass-cs/Engines/ComponentEmitter.cs delete mode 100644 encompass-cs/Engines/ComponentMessageEmitter.cs delete mode 100644 encompass-cs/Messages/ComponentMessage.cs delete mode 100644 encompass-cs/Messages/ComponentWriteMessage.cs delete mode 100644 encompass-cs/Messages/PendingComponentMessage.cs diff --git a/encompass-cs/Attributes/Reads.cs b/encompass-cs/Attributes/Reads.cs index a8892dc..b35e81f 100644 --- a/encompass-cs/Attributes/Reads.cs +++ b/encompass-cs/Attributes/Reads.cs @@ -21,7 +21,7 @@ namespace Encompass throw new IllegalReadTypeException("{0} must be a Component", readType.Name); } - this.readTypes.Add(typeof(ComponentMessage<>).MakeGenericType(readType)); + this.readTypes.Add(readType); } } } diff --git a/encompass-cs/Attributes/ReadsPending.cs b/encompass-cs/Attributes/ReadsPending.cs index f1798f8..e7e8653 100644 --- a/encompass-cs/Attributes/ReadsPending.cs +++ b/encompass-cs/Attributes/ReadsPending.cs @@ -21,7 +21,7 @@ namespace Encompass throw new IllegalReadTypeException("{0} must be a Component", readPendingType.Name); } - this.readPendingTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(readPendingType)); + this.readPendingTypes.Add(readPendingType); } } } diff --git a/encompass-cs/Attributes/Writes.cs b/encompass-cs/Attributes/Writes.cs index b6edfe1..ee73ded 100644 --- a/encompass-cs/Attributes/Writes.cs +++ b/encompass-cs/Attributes/Writes.cs @@ -21,7 +21,7 @@ namespace Encompass throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name); } - this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType)); + this.writeTypes.Add(writeType); } } @@ -33,8 +33,8 @@ namespace Encompass throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name); } - this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType)); - this.priorities.Add(writeType, priority); + writeTypes.Add(writeType); + priorities.Add(writeType, priority); } } } diff --git a/encompass-cs/Attributes/WritesPending.cs b/encompass-cs/Attributes/WritesPending.cs index 0983aab..ea5a370 100644 --- a/encompass-cs/Attributes/WritesPending.cs +++ b/encompass-cs/Attributes/WritesPending.cs @@ -19,7 +19,7 @@ namespace Encompass throw new IllegalWritePendingTypeException("{0} must be a Component", writePendingType.Name); } - this.writePendingTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(writePendingType)); + this.writePendingTypes.Add(writePendingType); } } } diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index a860cf3..bcd07be 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -84,10 +84,5 @@ namespace Encompass componentMessageManager.Remove(entity); drawLayerManager.UnRegisterComponentWithLayer(entity); } - - private void Remove(Entity entity) - { - componentStore.Remove(entity); - } } } diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 7c4b58a..ab93fec 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -22,6 +22,7 @@ namespace Encompass componentStore.ClearAll(); existingComponentStore.ClearAll(); pendingComponentStore.ClearAll(); + UpToDateComponentStore.ClearAll(); foreach (var dictionary in typeToEntityToPendingComponentPriority.Values) { @@ -34,18 +35,18 @@ namespace Encompass upToDateComponentStore = componentStore; } - internal void AddExistingComponentMessage(ComponentMessage componentMessage) where TComponent : struct, IComponent + internal void AddExistingComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - RegisterExistingOrPendingComponentMessage(componentMessage.entity, componentMessage.component); + RegisterExistingOrPendingComponentMessage(entity, component); - existingComponentStore.Set(componentMessage.entity, componentMessage.component); + existingComponentStore.Set(entity, component); } - internal void AddPendingComponentMessage(PendingComponentMessage pendingComponentMessage) where TComponent : struct, IComponent + internal void AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - if (pendingComponentStore.Set(pendingComponentMessage.entity, pendingComponentMessage.component, pendingComponentMessage.priority)) + if (pendingComponentStore.Set(entity, component, priority)) { - RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.component); + RegisterExistingOrPendingComponentMessage(entity, component); } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 8387b4d..ea22c3f 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -15,8 +15,12 @@ namespace Encompass { internal Guid ID; + internal readonly HashSet readTypes = new HashSet(); + internal readonly HashSet readPendingTypes = new HashSet(); internal readonly HashSet sendTypes = new HashSet(); internal readonly HashSet receiveTypes = new HashSet(); + internal readonly HashSet writeTypes = new HashSet(); + internal readonly HashSet writePendingTypes = new HashSet(); internal readonly Dictionary writePriorities = new Dictionary(); /// @@ -47,13 +51,12 @@ namespace Encompass var activatesAttribute = GetType().GetCustomAttribute(false); if (activatesAttribute != null) { - sendTypes.UnionWith(activatesAttribute.writePendingTypes); + writePendingTypes = activatesAttribute.writePendingTypes; } - var writesAttributes = GetType().GetCustomAttributes(false); - foreach (var writesAttribute in writesAttributes) + foreach (var writesAttribute in GetType().GetCustomAttributes(false)) { - sendTypes.UnionWith(writesAttribute.writeTypes); + writeTypes.UnionWith(writesAttribute.writeTypes); writePriorities = new Dictionary[2] { writePriorities, writesAttribute.priorities }.SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value); } @@ -66,13 +69,13 @@ namespace Encompass var readsAttribute = GetType().GetCustomAttribute(false); if (readsAttribute != null) { - receiveTypes.UnionWith(readsAttribute.readTypes); + readTypes = readsAttribute.readTypes; } var readsPendingAttribute = GetType().GetCustomAttribute(false); if (readsPendingAttribute != null) { - receiveTypes.UnionWith(readsPendingAttribute.readPendingTypes); + readPendingTypes = readsPendingAttribute.readPendingTypes; } } @@ -179,8 +182,8 @@ namespace Encompass private IEnumerable<(Entity, TComponent)> ReadComponentsHelper() where TComponent : struct, IComponent { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); + var pendingRead = readPendingTypes.Contains(typeof(TComponent)); + var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { return componentMessageManager.ReadExistingAndPendingComponentsByType(); @@ -222,8 +225,8 @@ namespace Encompass private (Entity, TComponent) ReadComponentHelper() where TComponent : struct, IComponent { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); + var pendingRead = readPendingTypes.Contains(typeof(TComponent)); + var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { return componentMessageManager.ReadFirstExistingOrPendingComponentByType(); @@ -264,8 +267,8 @@ namespace Encompass /// protected bool SomeComponent() where TComponent : struct, IComponent { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); + var pendingRead = readPendingTypes.Contains(typeof(TComponent)); + var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { return componentMessageManager.SomeExistingOrPendingComponent(); @@ -286,8 +289,8 @@ namespace Encompass private TComponent GetComponentHelper(Entity entity) where TComponent : struct, IComponent { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); + var pendingRead = readPendingTypes.Contains(typeof(TComponent)); + var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { if (componentMessageManager.HasPendingComponent(entity)) @@ -339,8 +342,8 @@ namespace Encompass /// protected bool HasComponent(Entity entity) where TComponent : struct, IComponent { - var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage)); - var existingRead = receiveTypes.Contains(typeof(ComponentMessage)); + var pendingRead = readPendingTypes.Contains(typeof(TComponent)); + var existingRead = readTypes.Contains(typeof(TComponent)); if (pendingRead && existingRead) { @@ -368,11 +371,8 @@ namespace Encompass /// protected bool HasComponent(Entity entity, Type type) { - var pending = typeof(PendingComponentMessage<>).MakeGenericType(type); - var existing = typeof(ComponentMessage<>).MakeGenericType(type); - - var pendingRead = receiveTypes.Contains(pending); - var existingRead = receiveTypes.Contains(existing); + var pendingRead = readPendingTypes.Contains(type); + var existingRead = readTypes.Contains(type); if (pendingRead && existingRead) { @@ -402,27 +402,23 @@ namespace Encompass { var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0; - if (!sendTypes.Contains(typeof(ComponentWriteMessage))) + if (!writeTypes.Contains(typeof(TComponent))) { throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name); } - if (sendTypes.Contains(typeof(PendingComponentMessage))) + if (writePendingTypes.Contains(typeof(TComponent))) { - PendingComponentMessage newComponentMessage; - newComponentMessage.entity = entity; - newComponentMessage.component = component; - newComponentMessage.priority = priority; - SendPendingComponentMessage(newComponentMessage); + AddPendingComponent(entity, component, priority); } else { - componentMessageManager.UpdateComponent(entity, component, priority); + componentMessageManager.UpdateComponent(entity, component, priority); } if (component is IDrawableComponent drawableComponent) { - componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); + componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); } } @@ -473,14 +469,14 @@ namespace Encompass messageManager.AddMessage(message); } - internal void SendExistingComponentMessage(ComponentMessage message) where TComponent : struct, IComponent + internal void AddExistingComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentMessageManager.AddExistingComponentMessage(message); + componentMessageManager.AddExistingComponent(entity, component); } - internal void SendPendingComponentMessage(PendingComponentMessage message) where TComponent : struct, IComponent + internal void AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - componentMessageManager.AddPendingComponentMessage(message); + componentMessageManager.AddPendingComponent(entity, component, priority); } /// diff --git a/encompass-cs/Engines/ComponentEmitter.cs b/encompass-cs/Engines/ComponentEmitter.cs new file mode 100644 index 0000000..b1f7f64 --- /dev/null +++ b/encompass-cs/Engines/ComponentEmitter.cs @@ -0,0 +1,18 @@ +namespace Encompass +{ + internal class ComponentEmitter : Engine where TComponent : struct, IComponent + { + public ComponentEmitter() + { + sendTypes.Add(typeof(TComponent)); + } + + public override void Update(double dt) + { + foreach (var (component, entity) in InternalRead()) + { + AddExistingComponent(entity, component); + } + } + } +} diff --git a/encompass-cs/Engines/ComponentMessageEmitter.cs b/encompass-cs/Engines/ComponentMessageEmitter.cs deleted file mode 100644 index d6bee6a..0000000 --- a/encompass-cs/Engines/ComponentMessageEmitter.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Encompass -{ - internal class ComponentMessageEmitter : Engine where TComponent : struct, IComponent - { - public ComponentMessageEmitter() : base() - { - sendTypes.Add(typeof(ComponentMessage)); - } - - public override void Update(double dt) - { - foreach (var (component, entity) in InternalRead()) - { - ComponentMessage componentMessage; - componentMessage.entity = entity; - componentMessage.component = component; - SendMessage(componentMessage); - SendExistingComponentMessage(componentMessage); - } - } - } -} diff --git a/encompass-cs/Messages/ComponentMessage.cs b/encompass-cs/Messages/ComponentMessage.cs deleted file mode 100644 index 1153815..0000000 --- a/encompass-cs/Messages/ComponentMessage.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Encompass -{ - internal struct ComponentMessage : IMessage where TComponent : struct, IComponent - { - public Entity entity; - public TComponent component; - } -} diff --git a/encompass-cs/Messages/ComponentWriteMessage.cs b/encompass-cs/Messages/ComponentWriteMessage.cs deleted file mode 100644 index 424fa7b..0000000 --- a/encompass-cs/Messages/ComponentWriteMessage.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Encompass -{ - internal struct ComponentWriteMessage : IMessage where TComponent : struct, IComponent - { - public Guid componentID; - public TComponent component; - } -} \ No newline at end of file diff --git a/encompass-cs/Messages/PendingComponentMessage.cs b/encompass-cs/Messages/PendingComponentMessage.cs deleted file mode 100644 index 8dfcc36..0000000 --- a/encompass-cs/Messages/PendingComponentMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Encompass -{ - internal struct PendingComponentMessage : IMessage where TComponent : struct, IComponent - { - public Entity entity; - public TComponent component; - public int priority; - } -} diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index a64e97e..dda5ee2 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -89,7 +89,7 @@ namespace Encompass internal void RegisterComponent(Type componentType) { registeredComponentTypes.Add(componentType); - AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType))); + AddEngine((Engine)Activator.CreateInstance(typeof(ComponentEmitter<>).MakeGenericType(componentType))); } /// @@ -115,37 +115,31 @@ namespace Encompass messageManager.RegisterMessageType(messageType); } + foreach (var writePendingType in engine.writePendingTypes.Intersect(engine.readPendingTypes)) + { + throw new EngineSelfCycleException("Engine {0} both writes and reads pending Component {1}", engine.GetType().Name, writePendingType.Name); + } + foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes)) { - if ((messageType.IsGenericType && messageType.GetGenericTypeDefinition() == typeof(PendingComponentMessage<>))) - { - var componentType = messageType.GetGenericArguments().Single(); - throw new EngineSelfCycleException("Engine {0} both activates and reads pending Component {1}", engine.GetType().Name, componentType.Name); - } - throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name); } - if (messageSendTypes.Any()) + if (messageSendTypes.Count > 0 || engine.writePendingTypes.Count > 0) { senders.Add(engine); } - foreach (var receiveType in engine.receiveTypes) + foreach (var readTypes in engine.readTypes) { - if (receiveType.IsGenericType) + if (!registeredComponentTypes.Contains(readTypes)) { - var genericTypeDefinition = receiveType.GetGenericTypeDefinition(); - if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(PendingComponentMessage<>)) - { - var componentType = receiveType.GetGenericArguments().Single(); - if (!registeredComponentTypes.Contains(componentType)) - { - RegisterComponent(componentType); - } - } + RegisterComponent(readTypes); } + } + foreach (var receiveType in engine.receiveTypes.Union(engine.readPendingTypes).Union(engine.readTypes)) + { if (!typeToReaders.ContainsKey(receiveType)) { typeToReaders.Add(receiveType, new HashSet()); @@ -188,7 +182,7 @@ namespace Encompass { foreach (var senderEngine in senders) { - foreach (var messageType in senderEngine.sendTypes) + foreach (var messageType in senderEngine.sendTypes.Union(senderEngine.writePendingTypes)) { if (typeToReaders.ContainsKey(messageType)) { @@ -247,16 +241,12 @@ namespace Encompass var defaultWritePriorityAttribute = engine.GetType().GetCustomAttribute(false); - var writeTypes = engine.sendTypes.Where((type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ComponentWriteMessage<>)); - - foreach (var writeType in writeTypes) + foreach (var writeType in engine.writeTypes) { - var componentType = writeType.GetGenericArguments()[0]; - int? priority = null; - if (engine.writePriorities.ContainsKey(componentType)) + if (engine.writePriorities.ContainsKey(writeType)) { - priority = engine.writePriorities[componentType]; + priority = engine.writePriorities[writeType]; } else if (defaultWritePriorityAttribute != null) { @@ -265,44 +255,44 @@ namespace Encompass if (priority.HasValue) { - writtenComponentTypesWithPriority.Add(componentType); + writtenComponentTypesWithPriority.Add(writeType); - if (!writePriorities.ContainsKey(componentType)) + if (!writePriorities.ContainsKey(writeType)) { - writePriorities[componentType] = new HashSet(); + writePriorities[writeType] = new HashSet(); } - if (writePriorities[componentType].Contains(priority.Value)) + if (writePriorities[writeType].Contains(priority.Value)) { - duplicateWritesWithSamePriority.Add(componentType); + duplicateWritesWithSamePriority.Add(writeType); } - else if (writtenComponentTypesWithoutPriority.Contains(componentType)) + else if (writtenComponentTypesWithoutPriority.Contains(writeType)) { - duplicateWritesWithoutPriority.Add(componentType); + duplicateWritesWithoutPriority.Add(writeType); } else { - writePriorities[componentType].Add(priority.Value); + writePriorities[writeType].Add(priority.Value); } } else { - if (writtenComponentTypesWithoutPriority.Contains(componentType) || writtenComponentTypesWithPriority.Contains(componentType)) + if (writtenComponentTypesWithoutPriority.Contains(writeType) || writtenComponentTypesWithPriority.Contains(writeType)) { - duplicateWritesWithoutPriority.Add(componentType); + duplicateWritesWithoutPriority.Add(writeType); } else { - writtenComponentTypesWithoutPriority.Add(componentType); + writtenComponentTypesWithoutPriority.Add(writeType); } } - if (!writeMessageToEngines.ContainsKey(componentType)) + if (!writeMessageToEngines.ContainsKey(writeType)) { - writeMessageToEngines[componentType] = new List(); + writeMessageToEngines[writeType] = new List(); } - writeMessageToEngines[componentType].Add(engine); + writeMessageToEngines[writeType].Add(engine); } } diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 729eb03..e10181e 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -9,7 +9,7 @@ Moonside Games Encompass ECS https://github.com/encompass-ecs - + Evan Hemsley 2019 Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations. true @@ -19,10 +19,10 @@ True - + - + diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index a27ecf6..ef3e9f8 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -415,6 +415,8 @@ namespace Tests } } + static bool hasComponentResult; + [Receives(typeof(CheckHasMockComponentMessage))] [Reads(typeof(MockComponent))] class CheckHasMockComponentEngine : Engine @@ -423,13 +425,13 @@ namespace Tests { foreach (var checkHasMockComponentMessage in ReadMessages()) { - Assert.IsTrue(HasComponent(checkHasMockComponentMessage.entity)); + hasComponentResult = HasComponent(checkHasMockComponentMessage.entity); } } } [Test] - public void RemoveComponent() + public void RemovedComponentShouldStillExistOnSameFrame() { var worldBuilder = new WorldBuilder(); var entity = worldBuilder.CreateEntity(); @@ -451,6 +453,12 @@ namespace Tests var world = worldBuilder.Build(); world.Update(0.01f); + + hasComponentResult.Should().BeTrue(); + + world.Update(0.01f); + + hasComponentResult.Should().BeFalse(); } struct CheckHasMockComponentMessage : IMessage From 8218ada6d1b47a01c448af3bb7a6b50caa16c8ce Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 22:32:09 -0800 Subject: [PATCH 15/24] fix emitters not being generated for certain component types +rename component message manager --- encompass-cs/Collections/ComponentStore.cs | 6 -- encompass-cs/ComponentManager.cs | 13 ++-- ...geManager.cs => ComponentUpdateManager.cs} | 32 +++++----- encompass-cs/Engine.cs | 61 +++++++++---------- encompass-cs/Entity.cs | 6 +- encompass-cs/RenderManager.cs | 10 +-- encompass-cs/TimeDilationData.cs | 10 ++- encompass-cs/TimeManager.cs | 2 +- encompass-cs/World.cs | 8 +-- encompass-cs/WorldBuilder.cs | 26 ++++---- test/ComponentTest.cs | 5 -- 11 files changed, 76 insertions(+), 103 deletions(-) rename encompass-cs/{ComponentMessageManager.cs => ComponentUpdateManager.cs} (86%) diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index 60396ea..ffb4eda 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace Encompass { @@ -69,11 +68,6 @@ namespace Encompass return Lookup().Count > 0; } - // public IEnumerable All() where TComponent : struct, IComponent - // { - // return Lookup().All(); - // } - public IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped() { foreach (var store in Stores.Values) diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index bcd07be..c0d53e3 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -6,15 +6,15 @@ namespace Encompass internal class ComponentManager { private readonly DrawLayerManager drawLayerManager; - private readonly ComponentMessageManager componentMessageManager; + private readonly ComponentUpdateManager componentUpdateManager; private readonly ComponentStore componentStore = new ComponentStore(); private readonly HashSet entitiesMarkedForRemoval = new HashSet(); - public ComponentManager(DrawLayerManager drawLayerManager, ComponentMessageManager componentMessageManager) + public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager) { this.drawLayerManager = drawLayerManager; - this.componentMessageManager = componentMessageManager; + this.componentUpdateManager = componentUpdateManager; } internal void SetComponentStore(ComponentStore componentStore) @@ -29,12 +29,12 @@ namespace Encompass internal void AddComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentStore.Set(entity, component); + componentStore.Set(entity, component); } internal void WriteComponents() { - componentStore.SwapWith(componentMessageManager.UpToDateComponentStore); + componentStore.SwapWith(componentUpdateManager.UpToDateComponentStore); } internal IEnumerable<(TComponent, Entity)> GetComponentsIncludingEntity() where TComponent : struct, IComponent @@ -80,8 +80,7 @@ namespace Encompass public void Remove(Entity entity) where TComponent : struct, IComponent { - //componentStore.Remove(entity); - componentMessageManager.Remove(entity); + componentUpdateManager.Remove(entity); drawLayerManager.UnRegisterComponentWithLayer(entity); } } diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentUpdateManager.cs similarity index 86% rename from encompass-cs/ComponentMessageManager.cs rename to encompass-cs/ComponentUpdateManager.cs index ab93fec..3f27029 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentUpdateManager.cs @@ -1,25 +1,21 @@ using System; using System.Collections.Generic; using System.Linq; -using Encompass.Exceptions; namespace Encompass { - class ComponentMessageManager + internal class ComponentUpdateManager { - private readonly ComponentStore componentStore = new ComponentStore(); - + private readonly ComponentStore existingAndPendingComponentStore = new ComponentStore(); private readonly ComponentStore existingComponentStore = new ComponentStore(); private readonly ComponentStore pendingComponentStore = new ComponentStore(); - private ComponentStore upToDateComponentStore = new ComponentStore(); - private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(128); - public ComponentStore UpToDateComponentStore { get => upToDateComponentStore; } + public ComponentStore UpToDateComponentStore { get; private set; } = new ComponentStore(); - internal void ClearMessages() + internal void Clear() { - componentStore.ClearAll(); + existingAndPendingComponentStore.ClearAll(); existingComponentStore.ClearAll(); pendingComponentStore.ClearAll(); UpToDateComponentStore.ClearAll(); @@ -32,7 +28,7 @@ namespace Encompass internal void SetStartingComponentStore(ComponentStore componentStore) { - upToDateComponentStore = componentStore; + UpToDateComponentStore = componentStore; } internal void AddExistingComponent(Entity entity, TComponent component) where TComponent : struct, IComponent @@ -52,20 +48,20 @@ namespace Encompass private void RegisterExistingOrPendingComponentMessage(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentStore.Set(entity, component); - upToDateComponentStore.Set(entity, component); + existingAndPendingComponentStore.Set(entity, component); + UpToDateComponentStore.Set(entity, component); } public void UpdateComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - upToDateComponentStore.Set(entity, component, priority); + UpToDateComponentStore.Set(entity, component, priority); } // general component reads by type internal IEnumerable<(Entity, TComponent)> ReadExistingAndPendingComponentsByType() where TComponent : struct, IComponent { - return componentStore.All(); + return existingAndPendingComponentStore.All(); } internal IEnumerable<(Entity, TComponent)> ReadExistingComponentsByType() where TComponent : struct, IComponent @@ -102,7 +98,7 @@ namespace Encompass internal bool SomeExistingOrPendingComponent() where TComponent : struct, IComponent { - return componentStore.Any(); + return existingAndPendingComponentStore.Any(); } internal bool SomeExistingComponent() where TComponent : struct, IComponent @@ -131,12 +127,12 @@ namespace Encompass internal bool HasExistingOrPendingComponent(Entity entity) where TComponent : struct, IComponent { - return componentStore.Has(entity); + return existingAndPendingComponentStore.Has(entity); } internal bool HasExistingOrPendingComponent(Entity entity, Type type) { - return componentStore.Has(type, entity); + return existingAndPendingComponentStore.Has(type, entity); } internal bool HasExistingComponent(Entity entity) where TComponent : struct, IComponent @@ -161,7 +157,7 @@ namespace Encompass internal void Remove(Entity entity) where TComponent : struct, IComponent { - upToDateComponentStore.Remove(entity); + UpToDateComponentStore.Remove(entity); } } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index ea22c3f..268be45 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -28,14 +28,11 @@ namespace Encompass /// internal bool usesTimeDilation = true; public bool TimeDilationActive { get => usesTimeDilation && timeManager.TimeDilationActive; } - /// - /// Used when activating time dilation. Lower priority overrides higher priority. - /// private EntityManager entityManager; private MessageManager messageManager; private ComponentManager componentManager; - private ComponentMessageManager componentMessageManager; + private ComponentUpdateManager componentUpdateManager; private TimeManager timeManager; protected Engine() @@ -81,9 +78,9 @@ namespace Encompass public override bool Equals(object obj) { - if (obj is Engine) + if (obj is Engine engine) { - return this.Equals((Engine)obj); + return Equals(engine); } return false; @@ -114,9 +111,9 @@ namespace Encompass this.messageManager = messageManager; } - internal void AssignComponentMessageManager(ComponentMessageManager componentMessageManager) + internal void AssignComponentUpdateManager(ComponentUpdateManager componentUpdateManager) { - this.componentMessageManager = componentMessageManager; + this.componentUpdateManager = componentUpdateManager; } internal void AssignTimeManager(TimeManager timeManager) @@ -186,15 +183,15 @@ namespace Encompass var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { - return componentMessageManager.ReadExistingAndPendingComponentsByType(); + return componentUpdateManager.ReadExistingAndPendingComponentsByType(); } else if (existingRead) { - return componentMessageManager.ReadExistingComponentsByType(); + return componentUpdateManager.ReadExistingComponentsByType(); } else if (pendingRead) { - return componentMessageManager.ReadPendingComponentsByType(); + return componentUpdateManager.ReadPendingComponentsByType(); } else { @@ -229,15 +226,15 @@ namespace Encompass var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { - return componentMessageManager.ReadFirstExistingOrPendingComponentByType(); + return componentUpdateManager.ReadFirstExistingOrPendingComponentByType(); } else if (existingRead) { - return componentMessageManager.ReadFirstExistingComponentByType(); + return componentUpdateManager.ReadFirstExistingComponentByType(); } else if (pendingRead) { - return componentMessageManager.ReadFirstPendingComponentByType(); + return componentUpdateManager.ReadFirstPendingComponentByType(); } else { @@ -271,15 +268,15 @@ namespace Encompass var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { - return componentMessageManager.SomeExistingOrPendingComponent(); + return componentUpdateManager.SomeExistingOrPendingComponent(); } else if (existingRead) { - return componentMessageManager.SomeExistingComponent(); + return componentUpdateManager.SomeExistingComponent(); } else if (pendingRead) { - return componentMessageManager.SomePendingComponent(); + return componentUpdateManager.SomePendingComponent(); } else { @@ -293,13 +290,13 @@ namespace Encompass var existingRead = readTypes.Contains(typeof(TComponent)); if (existingRead && pendingRead) { - if (componentMessageManager.HasPendingComponent(entity)) + if (componentUpdateManager.HasPendingComponent(entity)) { - return componentMessageManager.ReadPendingComponentByEntityAndType(entity); + return componentUpdateManager.ReadPendingComponentByEntityAndType(entity); } - else if (componentMessageManager.HasExistingComponent(entity)) + else if (componentUpdateManager.HasExistingComponent(entity)) { - return componentMessageManager.ReadExistingComponentByEntityAndType(entity); + return componentUpdateManager.ReadExistingComponentByEntityAndType(entity); } else { @@ -308,11 +305,11 @@ namespace Encompass } else if (existingRead) { - return componentMessageManager.ReadExistingComponentByEntityAndType(entity); + return componentUpdateManager.ReadExistingComponentByEntityAndType(entity); } else if (pendingRead) { - return componentMessageManager.ReadPendingComponentByEntityAndType(entity); + return componentUpdateManager.ReadPendingComponentByEntityAndType(entity); } else { @@ -347,15 +344,15 @@ namespace Encompass if (pendingRead && existingRead) { - return componentMessageManager.HasExistingOrPendingComponent(entity); + return componentUpdateManager.HasExistingOrPendingComponent(entity); } else if (existingRead) { - return componentMessageManager.HasExistingComponent(entity); + return componentUpdateManager.HasExistingComponent(entity); } else if (pendingRead) { - return componentMessageManager.HasPendingComponent(entity); + return componentUpdateManager.HasPendingComponent(entity); } else { @@ -376,15 +373,15 @@ namespace Encompass if (pendingRead && existingRead) { - return componentMessageManager.HasExistingOrPendingComponent(entity, type); + return componentUpdateManager.HasExistingOrPendingComponent(entity, type); } else if (existingRead) { - return componentMessageManager.HasExistingComponent(entity, type); + return componentUpdateManager.HasExistingComponent(entity, type); } else if (pendingRead) { - return componentMessageManager.HasPendingComponent(entity, type); + return componentUpdateManager.HasPendingComponent(entity, type); } else { @@ -413,7 +410,7 @@ namespace Encompass } else { - componentMessageManager.UpdateComponent(entity, component, priority); + componentUpdateManager.UpdateComponent(entity, component, priority); } if (component is IDrawableComponent drawableComponent) @@ -471,12 +468,12 @@ namespace Encompass internal void AddExistingComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - componentMessageManager.AddExistingComponent(entity, component); + componentUpdateManager.AddExistingComponent(entity, component); } internal void AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - componentMessageManager.AddPendingComponent(entity, component, priority); + componentUpdateManager.AddPendingComponent(entity, component, priority); } /// diff --git a/encompass-cs/Entity.cs b/encompass-cs/Entity.cs index fa584e3..a08954c 100644 --- a/encompass-cs/Entity.cs +++ b/encompass-cs/Entity.cs @@ -12,14 +12,14 @@ namespace Encompass internal Entity(Guid id) { - this.ID = id; + ID = id; } public override bool Equals(object obj) { - if (obj is Entity) + if (obj is Entity entity) { - return this.Equals((Entity)obj); + return Equals(entity); } return false; diff --git a/encompass-cs/RenderManager.cs b/encompass-cs/RenderManager.cs index bcf07eb..cea10c0 100644 --- a/encompass-cs/RenderManager.cs +++ b/encompass-cs/RenderManager.cs @@ -5,21 +5,13 @@ namespace Encompass { internal class RenderManager { - private readonly ComponentManager componentManager; private readonly DrawLayerManager drawLayerManager; - private readonly EntityManager entityManager; private readonly Dictionary> drawComponentTypeToOrderedRenderer = new Dictionary>(256); - public RenderManager( - ComponentManager componentManager, - DrawLayerManager drawLayerManager, - EntityManager entityManager - ) + public RenderManager(DrawLayerManager drawLayerManager) { - this.componentManager = componentManager; this.drawLayerManager = drawLayerManager; - this.entityManager = entityManager; } public void RegisterOrderedRenderer(Action renderAction) where TComponent : struct, IComponent diff --git a/encompass-cs/TimeDilationData.cs b/encompass-cs/TimeDilationData.cs index 4939f43..b344589 100644 --- a/encompass-cs/TimeDilationData.cs +++ b/encompass-cs/TimeDilationData.cs @@ -14,23 +14,21 @@ namespace Encompass { get { - double calculatedFactor = 1; - if (elapsedTime < easeInTime) { - calculatedFactor = easeInFunction(elapsedTime, 1, factor - 1, easeInTime); + return easeInFunction(elapsedTime, 1, factor - 1, easeInTime); } else if (elapsedTime < easeInTime + activeTime) { - calculatedFactor = factor; + return factor; } else if (elapsedTime < easeInTime + activeTime + easeOutTime) { var elapsedOutTime = elapsedTime - easeInTime - activeTime; - calculatedFactor = easeOutFunction(elapsedOutTime, factor, 1 - factor, easeOutTime); + return easeOutFunction(elapsedOutTime, factor, 1 - factor, easeOutTime); } - return calculatedFactor; + return 1; } } } diff --git a/encompass-cs/TimeManager.cs b/encompass-cs/TimeManager.cs index 79cfe8f..d29ac10 100644 --- a/encompass-cs/TimeManager.cs +++ b/encompass-cs/TimeManager.cs @@ -9,7 +9,7 @@ namespace Encompass private double Linear(double t, double b, double c, double d) { - return c * t / d + b; + return (c * t / d) + b; } public double TimeDilationFactor diff --git a/encompass-cs/World.cs b/encompass-cs/World.cs index 783e251..1154ca3 100644 --- a/encompass-cs/World.cs +++ b/encompass-cs/World.cs @@ -11,7 +11,7 @@ namespace Encompass private readonly EntityManager entityManager; private readonly ComponentManager componentManager; private readonly MessageManager messageManager; - private readonly ComponentMessageManager componentMessageManager; + private readonly ComponentUpdateManager componentUpdateManager; private readonly TimeManager timeManager; private readonly RenderManager renderManager; @@ -20,7 +20,7 @@ namespace Encompass EntityManager entityManager, ComponentManager componentManager, MessageManager messageManager, - ComponentMessageManager componentMessageManager, + ComponentUpdateManager componentUpdateManager, TimeManager timeManager, RenderManager renderManager ) @@ -29,7 +29,7 @@ namespace Encompass this.entityManager = entityManager; this.componentManager = componentManager; this.messageManager = messageManager; - this.componentMessageManager = componentMessageManager; + this.componentUpdateManager = componentUpdateManager; this.timeManager = timeManager; this.renderManager = renderManager; } @@ -61,7 +61,7 @@ namespace Encompass componentManager.WriteComponents(); componentManager.RemoveMarkedComponents(); - componentMessageManager.ClearMessages(); + componentUpdateManager.Clear(); } /// diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index dda5ee2..d8e678e 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -21,12 +21,12 @@ namespace Encompass private readonly List engines = new List(); private readonly DirectedGraph engineGraph = GraphBuilder.DirectedGraph(); private readonly ComponentStore startingComponentStoreForComponentManager = new ComponentStore(); - private readonly ComponentStore startingComponentStoreForComponentMessageManager = new ComponentStore(); + private readonly ComponentStore startingComponentStoreForComponentUpdateManager = new ComponentStore(); private readonly ComponentManager componentManager; private readonly EntityManager entityManager; private readonly MessageManager messageManager; - private readonly ComponentMessageManager componentMessageManager; + private readonly ComponentUpdateManager componentUpdateManager; private readonly TimeManager timeManager; private readonly DrawLayerManager drawLayerManager; private readonly RenderManager renderManager; @@ -41,11 +41,11 @@ namespace Encompass { drawLayerManager = new DrawLayerManager(); timeManager = new TimeManager(); - componentMessageManager = new ComponentMessageManager(); - componentManager = new ComponentManager(drawLayerManager, componentMessageManager); + componentUpdateManager = new ComponentUpdateManager(); + componentManager = new ComponentManager(drawLayerManager, componentUpdateManager); messageManager = new MessageManager(timeManager); entityManager = new EntityManager(componentManager); - renderManager = new RenderManager(componentManager, drawLayerManager, entityManager); + renderManager = new RenderManager(drawLayerManager); } /// @@ -78,7 +78,9 @@ namespace Encompass public void SetComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { startingComponentStoreForComponentManager.Set(entity, component); - startingComponentStoreForComponentMessageManager.Set(entity, component); + startingComponentStoreForComponentUpdateManager.Set(entity, component); + + RegisterComponent(typeof(TComponent)); if (component is IDrawableComponent drawableComponent) { @@ -101,7 +103,7 @@ namespace Encompass engine.AssignEntityManager(entityManager); engine.AssignComponentManager(componentManager); engine.AssignMessageManager(messageManager); - engine.AssignComponentMessageManager(componentMessageManager); + engine.AssignComponentUpdateManager(componentUpdateManager); engine.AssignTimeManager(timeManager); engines.Add(engine); @@ -130,11 +132,11 @@ namespace Encompass senders.Add(engine); } - foreach (var readTypes in engine.readTypes) + foreach (var componentType in engine.readTypes.Union(engine.writeTypes)) { - if (!registeredComponentTypes.Contains(readTypes)) + if (!registeredComponentTypes.Contains(componentType)) { - RegisterComponent(readTypes); + RegisterComponent(componentType); } } @@ -335,13 +337,13 @@ namespace Encompass entityManager, componentManager, messageManager, - componentMessageManager, + componentUpdateManager, timeManager, renderManager ); + componentUpdateManager.SetStartingComponentStore(startingComponentStoreForComponentUpdateManager); componentManager.SetComponentStore(startingComponentStoreForComponentManager); - componentMessageManager.SetStartingComponentStore(startingComponentStoreForComponentMessageManager); return world; } diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index ef3e9f8..febbd0b 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -1,12 +1,7 @@ -using System.ComponentModel; using NUnit.Framework; using FluentAssertions; using Encompass; -using System.Collections.Generic; -using System; -using System.Linq; -using Encompass.Exceptions; namespace Tests { From ba286f337c8ed2bf8ff26094f30c149a3aa87226 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 22:32:52 -0800 Subject: [PATCH 16/24] 0.18.0-preview4 --- encompass-cs/encompass-cs.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index e10181e..535cc04 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -1,9 +1,9 @@ - + netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview3 + 0.18.0-preview4 Evan Hemsley true Moonside Games From f0ef0fbb210b0d4f6b6c22366c84b26e470baa8d Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 23:16:47 -0800 Subject: [PATCH 17/24] fix erroneous engine cycle detection --- encompass-cs/WorldBuilder.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index d8e678e..09ed567 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -91,7 +91,6 @@ namespace Encompass internal void RegisterComponent(Type componentType) { registeredComponentTypes.Add(componentType); - AddEngine((Engine)Activator.CreateInstance(typeof(ComponentEmitter<>).MakeGenericType(componentType))); } /// @@ -134,13 +133,10 @@ namespace Encompass foreach (var componentType in engine.readTypes.Union(engine.writeTypes)) { - if (!registeredComponentTypes.Contains(componentType)) - { - RegisterComponent(componentType); - } + RegisterComponent(componentType); } - foreach (var receiveType in engine.receiveTypes.Union(engine.readPendingTypes).Union(engine.readTypes)) + foreach (var receiveType in engine.receiveTypes.Union(engine.readPendingTypes)) { if (!typeToReaders.ContainsKey(receiveType)) { @@ -327,6 +323,14 @@ namespace Encompass } var engineOrder = new List(); + + foreach (var registeredComponentType in registeredComponentTypes) + { + var emitterEngine = (Engine)Activator.CreateInstance(typeof(ComponentEmitter<>).MakeGenericType(registeredComponentType)); + AddEngine(emitterEngine); + engineOrder.Add(emitterEngine); + } + foreach (var engine in engineGraph.TopologicalSort()) { engineOrder.Add(engine); From 6ec05a16256394b8fdf825657185f79ba5144a6b Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 23:17:10 -0800 Subject: [PATCH 18/24] 0.18.0-preview5 --- encompass-cs/encompass-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 535cc04..6248fa3 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview4 + 0.18.0-preview5 Evan Hemsley true Moonside Games From 436cd9c5d2e1e153a8fca59591f8145d46979f45 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 23:55:17 -0800 Subject: [PATCH 19/24] fix write priorities not breing cleared after frame --- encompass-cs/Collections/TypedComponentStore.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index cb84a6d..9e02b46 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -48,6 +48,7 @@ namespace Encompass public override void Clear() { store.Clear(); + priorities.Clear(); } public IEnumerable<(Entity, TComponent)> All() From bb5173f4e4368d055d8eeef398c01a76b1c35cf7 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Thu, 5 Dec 2019 23:55:38 -0800 Subject: [PATCH 20/24] 0.18.0-preview6 --- encompass-cs/encompass-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 6248fa3..9da8d88 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview5 + 0.18.0-preview6 Evan Hemsley true Moonside Games From 25b8dc674968c78760a16ca2c826cd41642cc983 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Fri, 6 Dec 2019 00:36:54 -0800 Subject: [PATCH 21/24] fixes various write priority related bugs --- .../Collections/TypedComponentStore.cs | 1 + encompass-cs/ComponentUpdateManager.cs | 11 ++++++---- encompass-cs/Engine.cs | 21 +++++++++++++----- encompass-cs/WorldBuilder.cs | 2 +- test/WorldBuilderTest.cs | 22 ++++++++++++++++--- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index 9e02b46..2b47f63 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -34,6 +34,7 @@ namespace Encompass { if (!priorities.ContainsKey(entity) || priority < priorities[entity]) { store[entity] = component; + priorities[entity] = priority; return true; } diff --git a/encompass-cs/ComponentUpdateManager.cs b/encompass-cs/ComponentUpdateManager.cs index 3f27029..c61955c 100644 --- a/encompass-cs/ComponentUpdateManager.cs +++ b/encompass-cs/ComponentUpdateManager.cs @@ -38,12 +38,15 @@ namespace Encompass existingComponentStore.Set(entity, component); } - internal void AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + internal bool AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { if (pendingComponentStore.Set(entity, component, priority)) { RegisterExistingOrPendingComponentMessage(entity, component); + return true; } + + return false; } private void RegisterExistingOrPendingComponentMessage(Entity entity, TComponent component) where TComponent : struct, IComponent @@ -52,9 +55,9 @@ namespace Encompass UpToDateComponentStore.Set(entity, component); } - public void UpdateComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + public bool UpdateComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - UpToDateComponentStore.Set(entity, component, priority); + return UpToDateComponentStore.Set(entity, component, priority); } // general component reads by type @@ -90,7 +93,7 @@ namespace Encompass internal (Entity, TComponent) ReadFirstPendingComponentByType() where TComponent : struct, IComponent { - if (!SomeExistingComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } + if (!SomePendingComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } return ReadPendingComponentsByType().First(); } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 268be45..3c359dd 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -22,6 +22,7 @@ namespace Encompass internal readonly HashSet writeTypes = new HashSet(); internal readonly HashSet writePendingTypes = new HashSet(); internal readonly Dictionary writePriorities = new Dictionary(); + internal readonly int defaultWritePriority = 0; /// /// If false, the Engine will ignore time dilation. @@ -51,6 +52,13 @@ namespace Encompass writePendingTypes = activatesAttribute.writePendingTypes; } + var defaultWritePriorityAttribute = GetType().GetCustomAttribute(false); + + if (defaultWritePriorityAttribute != null) + { + defaultWritePriority = defaultWritePriorityAttribute.writePriority; + } + foreach (var writesAttribute in GetType().GetCustomAttributes(false)) { writeTypes.UnionWith(writesAttribute.writeTypes); @@ -397,23 +405,24 @@ namespace Encompass /// protected void SetComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { - var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0; + var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority; if (!writeTypes.Contains(typeof(TComponent))) { throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name); } + bool written; if (writePendingTypes.Contains(typeof(TComponent))) { - AddPendingComponent(entity, component, priority); + written = AddPendingComponent(entity, component, priority); } else { - componentUpdateManager.UpdateComponent(entity, component, priority); + written = componentUpdateManager.UpdateComponent(entity, component, priority); } - if (component is IDrawableComponent drawableComponent) + if (written && component is IDrawableComponent drawableComponent) { componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); } @@ -471,9 +480,9 @@ namespace Encompass componentUpdateManager.AddExistingComponent(entity, component); } - internal void AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent + internal bool AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - componentUpdateManager.AddPendingComponent(entity, component, priority); + return componentUpdateManager.AddPendingComponent(entity, component, priority); } /// diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 09ed567..925dbf4 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -131,7 +131,7 @@ namespace Encompass senders.Add(engine); } - foreach (var componentType in engine.readTypes.Union(engine.writeTypes)) + foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readPendingTypes)) { RegisterComponent(componentType); } diff --git a/test/WorldBuilderTest.cs b/test/WorldBuilderTest.cs index da93315..8e75f8a 100644 --- a/test/WorldBuilderTest.cs +++ b/test/WorldBuilderTest.cs @@ -223,14 +223,14 @@ namespace Tests [Receives(typeof(SetMessage))] [Writes(typeof(AComponent))] [WritesPending(typeof(AComponent))] - [Encompass.DefaultWritePriority(1)] + [Encompass.DefaultWritePriority(4)] class AEngine : Engine { public override void Update(double dt) { foreach (var setMessage in ReadMessages()) { - SetComponent(setMessage.entity, new AComponent { myInt = 0 }); + SetComponent(setMessage.entity, new AComponent { myInt = 5 }); } } } @@ -250,6 +250,20 @@ namespace Tests } } + [Receives(typeof(SetMessage))] + [Writes(typeof(AComponent), 2)] + [WritesPending(typeof(AComponent))] + class CEngine : Engine + { + public override void Update(double dt) + { + foreach (var setMessage in ReadMessages()) + { + SetComponent(setMessage.entity, new AComponent { myInt = 3 }); + } + } + } + static AComponent resultComponent; [ReadsPending(typeof(AComponent))] @@ -267,6 +281,8 @@ namespace Tests var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new AEngine()); worldBuilder.AddEngine(new BEngine()); + worldBuilder.AddEngine(new CEngine()); + worldBuilder.AddEngine(new ReadComponentEngine()); var entity = worldBuilder.CreateEntity(); worldBuilder.SendMessage(new SetMessage { entity = entity }); @@ -275,7 +291,7 @@ namespace Tests world.Update(0.01); - Assert.That(resultComponent.myInt, Is.EqualTo(0)); + Assert.That(resultComponent.myInt, Is.EqualTo(3)); } } From a29251f3d86ecd9fc0b151699a444b4aa43d01a1 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Fri, 6 Dec 2019 00:37:16 -0800 Subject: [PATCH 22/24] 0.18.0-preview7 --- encompass-cs/encompass-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 9da8d88..be174c0 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview6 + 0.18.0-preview7 Evan Hemsley true Moonside Games From 4a2771d6a2f20d84b5f644496d507b67e59dc6d4 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Fri, 6 Dec 2019 12:01:56 -0800 Subject: [PATCH 23/24] optimize away boxing for messages --- encompass-cs/Collections/MessageStore.cs | 67 ++++++++++++++ encompass-cs/Collections/TypedMessageStore.cs | 89 +++++++++++++++++++ encompass-cs/Engine.cs | 23 ++--- encompass-cs/MessageManager.cs | 87 +++++------------- encompass-cs/WorldBuilder.cs | 7 +- 5 files changed, 182 insertions(+), 91 deletions(-) create mode 100644 encompass-cs/Collections/MessageStore.cs create mode 100644 encompass-cs/Collections/TypedMessageStore.cs diff --git a/encompass-cs/Collections/MessageStore.cs b/encompass-cs/Collections/MessageStore.cs new file mode 100644 index 0000000..12aef7b --- /dev/null +++ b/encompass-cs/Collections/MessageStore.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +namespace Encompass +{ + internal class MessageStore + { + private Dictionary Stores = new Dictionary(512); + + private void RegisterMessageType() where TMessage : struct, IMessage + { + Stores.Add(typeof(TMessage), new TypedMessageStore()); + } + + private TypedMessageStore Lookup() where TMessage : struct, IMessage + { + if (!Stores.ContainsKey(typeof(TMessage))) { RegisterMessageType(); } + return Stores[typeof(TMessage)] as TypedMessageStore; + } + + public void AddMessage(TMessage message) where TMessage : struct, IMessage + { + Lookup().Add(message); + } + + public void AddMessage(TMessage message, double time) where TMessage : struct, IMessage + { + Lookup().Add(message, time); + } + + public void AddMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage + { + Lookup().AddIgnoringTimeDilation(message, time); + } + + public TMessage First() where TMessage : struct, IMessage + { + return Lookup().First(); + } + + public IEnumerable All() where TMessage : struct, IMessage + { + return Lookup().All(); + } + + public bool Any() where TMessage : struct, IMessage + { + return Lookup().Any(); + } + + public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) + { + foreach (var store in Stores.Values) + { + store.ProcessDelayedMessages(dilatedDelta, realtimeDelta); + } + } + + public void ClearAll() + { + foreach (var store in Stores.Values) + { + store.Clear(); + } + } + } +} diff --git a/encompass-cs/Collections/TypedMessageStore.cs b/encompass-cs/Collections/TypedMessageStore.cs new file mode 100644 index 0000000..06fc648 --- /dev/null +++ b/encompass-cs/Collections/TypedMessageStore.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; + +namespace Encompass +{ + internal abstract class TypedMessageStore + { + public abstract void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta); + public abstract void Clear(); + } + + internal class TypedMessageStore : TypedMessageStore where TMessage : struct, IMessage + { + private readonly List store = new List(128); + private readonly List<(TMessage, double)> delayedStore = new List<(TMessage, double)>(128); + private readonly List<(TMessage, double)> delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128); + + public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) + { + for (int i = delayedStore.Count - 1; i >= 0; i--) + { + var (message, time) = delayedStore[i]; + + var updatedTime = time - dilatedDelta; + + if (updatedTime <= 0) + { + Add(message); + delayedStore.RemoveAt(i); + } + else + { + delayedStore[i] = (message, updatedTime); + } + } + + for (int i = delayedStoreIgnoringTimeDilation.Count - 1; i >= 0; i--) + { + var (message, time) = delayedStoreIgnoringTimeDilation[i]; + + var updatedTime = time - realtimeDelta; + + if (updatedTime <= 0) + { + Add(message); + delayedStoreIgnoringTimeDilation.RemoveAt(i); + } + else + { + delayedStoreIgnoringTimeDilation[i] = (message, updatedTime); + } + } + } + + public void Add(TMessage message) + { + store.Add(message); + } + + public void Add(TMessage message, double time) + { + delayedStore.Add((message, time)); + } + + public void AddIgnoringTimeDilation(TMessage message, double time) + { + delayedStoreIgnoringTimeDilation.Add((message, time)); + } + + public TMessage First() + { + return store[0]; + } + + public bool Any() + { + return store.Count > 0; + } + + public IEnumerable All() + { + return store; + } + + public override void Clear() + { + store.Clear(); + } + } +} diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 3c359dd..4bea453 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -450,7 +450,7 @@ namespace Encompass /// The time in seconds that will elapse before the message is sent. protected void SendMessage(TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessageDelayed(message, time); + messageManager.AddMessage(message, time); } /// @@ -459,20 +459,7 @@ namespace Encompass /// The time in seconds that will elapse before the message is sent. protected void SendMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessageDelayedIgnoringTimeDilation(message, time); - } - - // unparameterized version to enable dynamic dispatch - protected void SendMessage(IMessage message) - { - var type = message.GetType(); - - if (!sendTypes.Contains(type) || !type.IsValueType) - { - throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", GetType().Name, type.Name); - } - - messageManager.AddMessage(message); + messageManager.AddMessageIgnoringTimeDilation(message, time); } internal void AddExistingComponent(Entity entity, TComponent component) where TComponent : struct, IComponent @@ -482,7 +469,7 @@ namespace Encompass internal bool AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - return componentUpdateManager.AddPendingComponent(entity, component, priority); + return componentUpdateManager.AddPendingComponent(entity, component, priority); } /// @@ -509,7 +496,7 @@ namespace Encompass /// protected TMessage ReadMessage() where TMessage : struct, IMessage { - return ReadMessages().First(); + return messageManager.First(); } /// @@ -525,7 +512,7 @@ namespace Encompass throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name); } - return ReadMessages().Any(); + return messageManager.Any(); } /// diff --git a/encompass-cs/MessageManager.cs b/encompass-cs/MessageManager.cs index c967d67..7da56bf 100644 --- a/encompass-cs/MessageManager.cs +++ b/encompass-cs/MessageManager.cs @@ -1,102 +1,55 @@ -using System; using System.Collections.Generic; -using System.Linq; namespace Encompass { internal class MessageManager { private readonly TimeManager timeManager; - - private readonly Dictionary> messageTypeToMessages = new Dictionary>(); - - private readonly List<(IMessage, double)> delayedMessages = new List<(IMessage, double)>(); - private readonly List<(IMessage, double)> delayedMessagesIgnoringTimeDilation = new List<(IMessage, double)>(); + private readonly MessageStore messageStore = new MessageStore(); public MessageManager(TimeManager timeManager) { this.timeManager = timeManager; } - internal void RegisterMessageType(Type messageType) + internal void AddMessage(TMessage message) where TMessage : struct, IMessage { - if (!messageTypeToMessages.ContainsKey(messageType)) - { - messageTypeToMessages.Add(messageType, new List()); - } + messageStore.AddMessage(message); } - internal void AddMessage(IMessage message) + internal void AddMessage(TMessage message, double time) where TMessage : struct, IMessage { - var type = message.GetType(); - - messageTypeToMessages[type].Add(message); + messageStore.AddMessage(message, time); } - internal void AddMessageDelayed(IMessage message, double time) + internal void AddMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage { - if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List()); } - - delayedMessages.Add((message, time)); - } - - internal void AddMessageDelayedIgnoringTimeDilation(IMessage message, double time) - { - if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List()); } - - delayedMessagesIgnoringTimeDilation.Add((message, time)); + messageStore.AddMessageIgnoringTimeDilation(message, time); } internal void ClearMessages() { - foreach (var entry in messageTypeToMessages) - { - entry.Value.Clear(); - } + messageStore.ClearAll(); } internal void ProcessDelayedMessages(double dt) { - for (int i = delayedMessages.Count - 1; i >= 0; i--) - { - var (message, time) = delayedMessages[i]; - - var updatedTime = time - (dt * timeManager.TimeDilationFactor); - - if (updatedTime <= 0) - { - AddMessage(message); - delayedMessages.RemoveAt(i); - } - else - { - delayedMessages[i] = (message, updatedTime); - } - } - - for (int i = delayedMessagesIgnoringTimeDilation.Count - 1; i >= 0; i--) - { - var (message, time) = delayedMessagesIgnoringTimeDilation[i]; - - var updatedTime = time - dt; - - if (updatedTime <= 0) - { - AddMessage(message); - delayedMessagesIgnoringTimeDilation.RemoveAt(i); - } - else - { - delayedMessagesIgnoringTimeDilation[i] = (message, updatedTime); - } - } + messageStore.ProcessDelayedMessages(dt * timeManager.TimeDilationFactor, dt); } internal IEnumerable GetMessagesByType() where TMessage : struct, IMessage { - return messageTypeToMessages.ContainsKey(typeof(TMessage)) ? - messageTypeToMessages[typeof(TMessage)].Cast() : - Enumerable.Empty(); + return messageStore.All(); + } + + internal bool Any() where TMessage : struct, IMessage + { + return messageStore.Any(); + } + + internal TMessage First() where TMessage : struct, IMessage + { + return messageStore.First(); } } } diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 925dbf4..331a08d 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -69,7 +69,7 @@ namespace Encompass /// public void SendMessage(TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessageDelayed(message, time); + messageManager.AddMessage(message, time); } /// @@ -111,11 +111,6 @@ namespace Encompass var messageReceiveTypes = engine.receiveTypes; var messageSendTypes = engine.sendTypes; - foreach (var messageType in messageReceiveTypes.Union(messageSendTypes)) - { - messageManager.RegisterMessageType(messageType); - } - foreach (var writePendingType in engine.writePendingTypes.Intersect(engine.readPendingTypes)) { throw new EngineSelfCycleException("Engine {0} both writes and reads pending Component {1}", engine.GetType().Name, writePendingType.Name); From 9e25494b2fa176d8a06544ad9b20a1badeb44107 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Fri, 6 Dec 2019 12:02:16 -0800 Subject: [PATCH 24/24] 0.18.0-preview8 --- encompass-cs/encompass-cs.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index be174c0..4c9af10 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -3,7 +3,7 @@ netstandard2.0 Encompass EncompassECS.Framework - 0.18.0-preview7 + 0.18.0-preview8 Evan Hemsley true Moonside Games