diff --git a/src/ComponentManager.cs b/src/ComponentManager.cs index 8c847a6..4218195 100644 --- a/src/ComponentManager.cs +++ b/src/ComponentManager.cs @@ -6,133 +6,111 @@ namespace Encompass { internal class ComponentManager { - private Dictionary> entityIDToComponents = new Dictionary>(); - private Dictionary componentToEntityID = new Dictionary(); + private Dictionary IDToComponent = new Dictionary(); + private Dictionary> entityIDToComponentIDs = new Dictionary>(); + private Dictionary componentIDToEntityID = new Dictionary(); - private Dictionary> activeComponents = new Dictionary>(); - private Dictionary> inactiveComponents = new Dictionary>(); + private Dictionary> activeComponents = new Dictionary>(); + private Dictionary> inactiveComponents = new Dictionary>(); - private List componentsToActivate = new List(); - private List componentsToDeactivate = new List(); - private List componentsToRemove = new List(); + private List componentsToActivate = new List(); + private List componentsToDeactivate = new List(); + private List componentsToRemove = new List(); - internal void AddComponent(uint entityID, TComponent component) where TComponent : struct, IComponent + internal Guid AddComponent(Guid entityID, TComponent component) where TComponent : struct, IComponent { - if (!entityIDToComponents.ContainsKey(entityID)) + var componentID = Guid.NewGuid(); + + IDToComponent[componentID] = component; + + if (!entityIDToComponentIDs.ContainsKey(entityID)) { - entityIDToComponents.Add(entityID, new List()); + entityIDToComponentIDs.Add(entityID, new List()); } - entityIDToComponents[entityID].Add(component); - componentToEntityID[component] = entityID; + entityIDToComponentIDs[entityID].Add(componentID); + componentIDToEntityID[componentID] = entityID; if (!activeComponents.ContainsKey(typeof(TComponent))) { - activeComponents.Add(typeof(TComponent), new List()); - inactiveComponents.Add(typeof(TComponent), new List()); + activeComponents.Add(typeof(TComponent), new List()); + inactiveComponents.Add(typeof(TComponent), new List()); } - MarkForActivation(component); + MarkForActivation(componentID); + + return componentID; } - internal IEnumerable GetComponentsByEntity(uint entityID) + internal IEnumerable> GetComponentsByEntity(Guid entityID) { - return entityIDToComponents[entityID]; + return entityIDToComponentIDs[entityID].Select((id) => new KeyValuePair(id, IDToComponent[id])); } - internal IEnumerable GetActiveComponentsByType() where TComponent : struct, IComponent + internal IEnumerable> GetActiveComponentsByType() where TComponent : struct, IComponent { - return activeComponents[typeof(TComponent)].Cast(); + return activeComponents[typeof(TComponent)].Select((id) => new KeyValuePair(id, (TComponent)IDToComponent[id])); } - internal TComponent GetActiveComponentByType() where TComponent : struct, IComponent + internal KeyValuePair GetActiveComponentByType() where TComponent : struct, IComponent { return GetActiveComponentsByType().Single(); } - internal IEnumerable GetComponentsByEntityAndType(uint entityID) where TComponent : struct, IComponent + internal IEnumerable> GetComponentsByEntityAndType(Guid entityID) where TComponent : struct, IComponent { - var entity_components = GetComponentsByEntity(entityID).Cast(); + var entity_components = GetComponentsByEntity(entityID).Select((kv) => new KeyValuePair(kv.Key, (TComponent)kv.Value)); var active_components_by_type = GetActiveComponentsByType(); - return entity_components.Intersect(active_components_by_type).Cast(); + return entity_components.Intersect(active_components_by_type); } - internal bool EntityHasComponentOfType(uint entityID) where TComponent : struct, IComponent + internal bool EntityHasComponentOfType(Guid entityID) where TComponent : struct, IComponent { return GetComponentsByEntityAndType(entityID).Any(); } - /** Replaces the component with another. */ - internal void UpdateComponent(TComponent originalComponent, TComponent newComponent) where TComponent : struct, IComponent + internal void UpdateComponent(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent { - var entityID = componentToEntityID[originalComponent]; - - entityIDToComponents[entityID].Remove(originalComponent); - entityIDToComponents[entityID].Add(newComponent); - - componentToEntityID.Remove(originalComponent); - componentToEntityID.Add(newComponent, entityID); - - if (activeComponents[originalComponent.GetType()].Remove(originalComponent)) - { - activeComponents[originalComponent.GetType()].Add(newComponent); - } - - if (inactiveComponents[originalComponent.GetType()].Remove(originalComponent)) - { - inactiveComponents[originalComponent.GetType()].Add(newComponent); - } - - if (componentsToActivate.Remove(originalComponent)) - { - componentsToActivate.Add(newComponent); - } - - if (componentsToDeactivate.Remove(originalComponent)) - { - componentsToDeactivate.Add(newComponent); - } - - if (componentsToRemove.Remove(originalComponent)) - { - componentsToRemove.Add(newComponent); - } + var entityID = componentIDToEntityID[componentID]; + IDToComponent[componentID] = newComponentValue; } - internal void RemoveAllComponentsFromEntity(uint entityID) + internal void RemoveAllComponentsFromEntity(Guid entityID) { - var components = GetComponentsByEntity(entityID); + var componentIDs = entityIDToComponentIDs[entityID]; - foreach (var component in components) + foreach (var componentID in componentIDs) { - activeComponents[component.GetType()].Remove(component); - inactiveComponents[component.GetType()].Remove(component); + var component = IDToComponent[componentID]; + activeComponents[component.GetType()].Remove(componentID); + inactiveComponents[component.GetType()].Remove(componentID); } - entityIDToComponents.Remove(entityID); + entityIDToComponentIDs.Remove(entityID); } - internal void MarkForActivation(IComponent component) + internal void MarkForActivation(Guid componentID) { - componentsToActivate.Add(component); + componentsToActivate.Add(componentID); } - internal void MarkForDeactivation(IComponent component) + internal void MarkForDeactivation(Guid componentID) { - componentsToDeactivate.Add(component); + componentsToDeactivate.Add(componentID); } - internal void MarkForRemoval(IComponent component) + internal void MarkForRemoval(Guid componentID) { - componentsToRemove.Add(component); + componentsToRemove.Add(componentID); } internal void ActivateComponents() { - foreach (var component in componentsToActivate) + foreach (var componentID in componentsToActivate) { - activeComponents[component.GetType()].Add(component); - inactiveComponents[component.GetType()].Remove(component); + var component = IDToComponent[componentID]; + activeComponents[component.GetType()].Add(componentID); + inactiveComponents[component.GetType()].Remove(componentID); } componentsToActivate.Clear(); @@ -140,19 +118,23 @@ namespace Encompass internal void DeactivateComponents() { - foreach (var component in componentsToDeactivate) + foreach (var componentID in componentsToDeactivate) { - activeComponents[component.GetType()].Remove(component); - inactiveComponents[component.GetType()].Add(component); + var component = IDToComponent[componentID]; + activeComponents[component.GetType()].Remove(componentID); + inactiveComponents[component.GetType()].Add(componentID); } + + componentsToDeactivate.Clear(); } internal void RemoveComponents() { - foreach (var component in componentsToRemove) + foreach (var componentID in componentsToRemove) { - activeComponents[component.GetType()].Remove(component); - inactiveComponents[component.GetType()].Remove(component); + var component = IDToComponent[componentID]; + activeComponents[component.GetType()].Remove(componentID); + inactiveComponents[component.GetType()].Remove(componentID); } componentsToRemove.Clear(); diff --git a/src/Engine.cs b/src/Engine.cs index dcf6925..71b3119 100644 --- a/src/Engine.cs +++ b/src/Engine.cs @@ -58,21 +58,21 @@ namespace Encompass return this.entityManager.CreateEntity(); } - protected IEnumerable ReadComponents() where TComponent : struct, IComponent + protected IEnumerable> ReadComponents() where TComponent : struct, IComponent { return this.componentManager.GetActiveComponentsByType(); } - protected TComponent ReadComponent() where TComponent : struct, IComponent + protected KeyValuePair ReadComponent() where TComponent : struct, IComponent { return this.componentManager.GetActiveComponentByType(); } - internal void UpdateComponentInWorld(TComponent originalComponent, TComponent newComponent) where TComponent : struct, IComponent + internal void UpdateComponentInWorld(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent { if (mutateComponentTypes.Contains(typeof(TComponent))) { - this.componentManager.UpdateComponent(originalComponent, newComponent); + this.componentManager.UpdateComponent(componentID, newComponent); } else { @@ -80,18 +80,9 @@ namespace Encompass } } - protected void UpdateComponent(TComponent component, Func updateFunction) where TComponent : struct, IComponent + protected void UpdateComponent(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent { - var updatedComponent = updateFunction(component); - this.UpdateComponentInWorld(component, updatedComponent); - } - - protected void UpdateComponents(IEnumerable components, Func updateFunction) where TComponent : struct, IComponent - { - foreach (var component in components) - { - this.UpdateComponent(component, updateFunction); - } + this.UpdateComponentInWorld(componentID, newComponentValue); } protected void EmitMessage(TMessage message) where TMessage : struct, IMessage diff --git a/src/Entity.cs b/src/Entity.cs index 98152d9..0c9ce69 100644 --- a/src/Entity.cs +++ b/src/Entity.cs @@ -1,31 +1,32 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace Encompass { public struct Entity { - public readonly uint id; + public readonly Guid id; private ComponentManager componentManager; - internal Entity(uint id, ComponentManager componentManager) + internal Entity(Guid id, ComponentManager componentManager) { this.id = id; this.componentManager = componentManager; } - public void AddComponent(TComponent component) where TComponent : struct, IComponent + public Guid AddComponent(TComponent component) where TComponent : struct, IComponent { - componentManager.AddComponent(id, component); + return componentManager.AddComponent(id, component); } - public IEnumerable GetComponents() where TComponent : struct, IComponent + public IEnumerable> GetComponents() where TComponent : struct, IComponent { return componentManager.GetComponentsByEntityAndType(id); } - public TComponent GetComponent() where TComponent : struct, IComponent + public KeyValuePair GetComponent() where TComponent : struct, IComponent { return GetComponents().First(); } diff --git a/src/EntityManager.cs b/src/EntityManager.cs index 12272c0..49c4ffe 100644 --- a/src/EntityManager.cs +++ b/src/EntityManager.cs @@ -1,13 +1,12 @@ +using System; using System.Collections.Generic; namespace Encompass { internal class EntityManager { - private uint nextID = 1; - private List entities = new List(); - private Dictionary IDToEntity = new Dictionary(); + private Dictionary IDToEntity = new Dictionary(); private List entitiesMarkedForDestroy = new List(); @@ -25,7 +24,7 @@ namespace Encompass return new Entity(NextID(), componentManager); } - public Entity GetEntity(uint id) + public Entity GetEntity(Guid id) { return this.IDToEntity[id]; } @@ -43,11 +42,9 @@ namespace Encompass } } - private uint NextID() + private Guid NextID() { - var id = this.nextID; - this.nextID++; - return id; + return Guid.NewGuid(); } } } diff --git a/test/EngineTest.cs b/test/EngineTest.cs index 47aa79e..189c5ba 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -1,15 +1,17 @@ using NUnit.Framework; -using System.Linq; +using FluentAssertions; using Encompass; -using System.Collections.Generic; + using System; +using System.Linq; +using System.Collections.Generic; namespace Tests { public class EngineTest { - static IEnumerable resultComponents; + static List> resultComponents; static MockComponent resultComponent; static List resultMessages; @@ -18,7 +20,7 @@ namespace Tests { public override void Update(float dt) { - resultComponents = this.ReadComponents(); + resultComponents = this.ReadComponents().ToList(); } } @@ -26,7 +28,7 @@ namespace Tests { public override void Update(float dt) { - resultComponent = this.ReadComponent(); + resultComponent = this.ReadComponent().Value; } } @@ -46,15 +48,16 @@ namespace Tests mockComponentB.myInt = 1; mockComponentB.myString = "howdy"; - entity.AddComponent(mockComponent); - entity.AddComponent(mockComponentB); + var componentAID = entity.AddComponent(mockComponent); + var componentBID = entity.AddComponent(mockComponentB); var world = worldBuilder.Build(); world.Update(0.01f); - Assert.Contains(mockComponent, resultComponents.ToList()); - Assert.Contains(mockComponentB, resultComponents.ToList()); + var resultComponentValues = resultComponents.Select((kv) => kv.Value); + resultComponentValues.Should().Contain(mockComponent); + resultComponentValues.Should().Contain(mockComponentB); } [Test] @@ -107,14 +110,13 @@ namespace Tests { public override void Update(float dt) { - var component = this.ReadComponent(); - this.UpdateComponent(component, (MockComponent comp) => - { - comp.myInt = 420; - comp.myString = "blaze it"; - return comp; - }); - resultComponent = this.ReadComponent(); + (var componentID, var component) = this.ReadComponent(); + + component.myInt = 420; + component.myString = "blaze it"; + this.UpdateComponent(componentID, component); + + resultComponent = this.ReadComponent().Value; } } @@ -144,14 +146,13 @@ namespace Tests { public override void Update(float dt) { - var component = this.ReadComponent(); - this.UpdateComponent(component, (MockComponent comp) => - { - comp.myInt = 420; - comp.myString = "blaze it"; - return comp; - }); - component = this.ReadComponent(); + (var componentID, var component) = this.ReadComponent(); + + component.myInt = 420; + component.myString = "blaze it"; + this.UpdateComponent(componentID, component); + + component = this.ReadComponent().Value; } } diff --git a/test/EntityTest.cs b/test/EntityTest.cs index 2ab8906..6fb4a9d 100644 --- a/test/EntityTest.cs +++ b/test/EntityTest.cs @@ -1,10 +1,16 @@ using NUnit.Framework; +using FluentAssertions; + using System.Linq; using Encompass; +using System.Collections.Generic; +using System; -namespace Tests { - struct MockComponent : IComponent { +namespace Tests +{ + struct MockComponent : IComponent + { public string myString; public int myInt; } @@ -27,7 +33,7 @@ namespace Tests { // world.Update(); Assert.IsTrue(entity.HasComponent()); - Assert.AreEqual(mockComponent, entity.GetComponent()); + Assert.That(entity.GetComponent().Value, Is.EqualTo(mockComponent)); } [Test] @@ -48,15 +54,16 @@ namespace Tests { mockComponentC.myInt = 1; mockComponentC.myString = "howdy"; - entity.AddComponent(mockComponentA); - entity.AddComponent(mockComponentB); - entity.AddComponent(mockComponentC); + var componentAID = entity.AddComponent(mockComponentA); + var componentBID = entity.AddComponent(mockComponentB); + var componentCID = entity.AddComponent(mockComponentC); var world = worldBuilder.Build(); - Assert.Contains(mockComponentA, entity.GetComponents().ToList()); - Assert.Contains(mockComponentB, entity.GetComponents().ToList()); - Assert.Contains(mockComponentC, entity.GetComponents().ToList()); + var components = entity.GetComponents(); + components.Should().Contain(new KeyValuePair(componentAID, mockComponentA)); + components.Should().Contain(new KeyValuePair(componentBID, mockComponentB)); + components.Should().Contain(new KeyValuePair(componentCID, mockComponentC)); } [Test] @@ -69,11 +76,11 @@ namespace Tests { mockComponent.myInt = 3; mockComponent.myString = "hello"; - entity.AddComponent(mockComponent); + var componentID = entity.AddComponent(mockComponent); var world = worldBuilder.Build(); - Assert.AreEqual(mockComponent, entity.GetComponent()); + Assert.AreEqual(new KeyValuePair(componentID, mockComponent), entity.GetComponent()); } [Test]