From 64f6e132164b1915efd917250775d933155fdf13 Mon Sep 17 00:00:00 2001
From: Evan Hemsley <evan@moonside.games>
Date: Wed, 17 Jul 2019 11:24:21 -0700
Subject: [PATCH] move all methods off of Entity

---
 encompass-cs/ComponentManager.cs         | 101 ++----
 encompass-cs/Engine.cs                   |  73 +++++
 encompass-cs/Entity.cs                   |  61 +---
 encompass-cs/EntityManager.cs            |   5 +-
 encompass-cs/Renderer.cs                 |  16 +-
 encompass-cs/World.cs                    |   4 -
 encompass-cs/WorldBuilder.cs             |  19 +-
 encompass-cs/renderers/EntityRenderer.cs |   4 +-
 encompass-cs/utility/EntityChecker.cs    |   4 +-
 test/ComponentTest.cs                    | 377 +++++++++++++++++++++++
 test/EngineTest.cs                       |  59 ++--
 test/EntityRendererTest.cs               |  46 ++-
 test/EntityTest.cs                       | 172 -----------
 test/GeneralRendererTest.cs              |   6 +-
 test/SpawnerTest.cs                      |  12 +-
 test/WorldTest.cs                        |  16 +-
 16 files changed, 588 insertions(+), 387 deletions(-)
 create mode 100644 test/ComponentTest.cs
 delete mode 100644 test/EntityTest.cs

diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs
index ea5e2fc..9bf4550 100644
--- a/encompass-cs/ComponentManager.cs
+++ b/encompass-cs/ComponentManager.cs
@@ -18,10 +18,6 @@ namespace Encompass
         private readonly List<Guid> activeComponents = new List<Guid>();
         private readonly List<Guid> inactiveComponents = new List<Guid>();
 
-        private readonly HashSet<Guid> componentsToActivate = new HashSet<Guid>();
-        private readonly HashSet<Guid> componentsToDeactivate = new HashSet<Guid>();
-        private readonly HashSet<Guid> componentsToRemove = new HashSet<Guid>();
-
         //shared references with EntityManager
         private readonly HashSet<Guid> entitiesWithAddedComponents;
         private readonly HashSet<Guid> entitiesWithRemovedComponents;
@@ -60,7 +56,7 @@ namespace Encompass
             componentIDToEntityID[componentID] = entityID;
 
             inactiveComponents.Add(componentID);
-            MarkForActivation(componentID);
+            Activate(componentID);
 
             entitiesWithAddedComponents.Add(entityID);
 
@@ -158,91 +154,58 @@ namespace Encompass
         {
             var componentIDs = entityIDToComponentIDs[entityID];
 
-            foreach (var componentID in componentIDs)
+            for (int i = componentIDs.Count - 1; i >= 0; i--)
             {
-                MarkForRemoval(componentID);
+                Remove(componentIDs[i]);
             }
         }
 
-        internal void MarkForActivation(Guid componentID)
+        internal void Activate(Guid componentID)
         {
-            componentsToActivate.Add(componentID);
+            if (inactiveComponents.Remove(componentID))
+            {
+                activeComponents.Add(componentID);
+            }
 
             var entityID = GetEntityIDByComponentID(componentID);
             entitiesWithAddedComponents.Add(entityID);
         }
 
-        internal void MarkForDeactivation(Guid componentID)
+        internal void Deactivate(Guid componentID)
         {
-            componentsToDeactivate.Add(componentID);
+            if (activeComponents.Remove(componentID))
+            {
+                inactiveComponents.Add(componentID);
+            }
 
             var entityID = GetEntityIDByComponentID(componentID);
             entitiesWithRemovedComponents.Add(entityID);
         }
 
-        internal void MarkForRemoval(Guid componentID)
+        internal void Remove(Guid componentID)
         {
-            componentsToRemove.Add(componentID);
+            var component = IDToComponent[componentID];
+            var type = componentIDToType[componentID];
+
+            activeComponents.Remove(componentID);
+            inactiveComponents.Remove(componentID);
+
+            var entityID = componentIDToEntityID[componentID];
+            if (entityIDToComponentIDs.ContainsKey(entityID))
+            {
+                entityIDToComponentIDs[entityID].Remove(componentID);
+            }
+
+            IDToComponent.Remove(componentID);
+            componentIDToType.Remove(componentID);
+            componentIDToEntityID.Remove(componentID);
+            typeToComponentIDs[type].Remove(componentID);
+
+            drawLayerManager.UnRegisterComponentWithLayer(componentID);
 
-            var entityID = GetEntityIDByComponentID(componentID);
             entitiesWithRemovedComponents.Add(entityID);
         }
 
-        internal void ActivateMarkedComponents()
-        {
-            foreach (var componentID in componentsToActivate)
-            {
-                var component = IDToComponent[componentID];
-                if (inactiveComponents.Remove(componentID))
-                {
-                    activeComponents.Add(componentID);
-                }
-            }
-
-            componentsToActivate.Clear();
-        }
-
-        internal void DeactivateMarkedComponents()
-        {
-            foreach (var componentID in componentsToDeactivate)
-            {
-                var component = IDToComponent[componentID];
-                if (activeComponents.Remove(componentID))
-                {
-                    inactiveComponents.Add(componentID);
-                }
-            }
-
-            componentsToDeactivate.Clear();
-        }
-
-        public void RemoveMarkedComponents()
-        {
-            foreach (var componentID in componentsToRemove)
-            {
-                var component = IDToComponent[componentID];
-                var type = componentIDToType[componentID];
-
-                activeComponents.Remove(componentID);
-                inactiveComponents.Remove(componentID);
-
-                var entityID = componentIDToEntityID[componentID];
-                if (entityIDToComponentIDs.ContainsKey(entityID))
-                {
-                    entityIDToComponentIDs[entityID].Remove(componentID);
-                }
-
-                IDToComponent.Remove(componentID);
-                componentIDToType.Remove(componentID);
-                componentIDToEntityID.Remove(componentID);
-                typeToComponentIDs[type].Remove(componentID);
-
-                drawLayerManager.UnRegisterComponentWithLayer(componentID);
-            }
-
-            componentsToRemove.Clear();
-        }
-
         public void RegisterDestroyedEntity(Guid entityID)
         {
             entityIDToComponentIDs.Remove(entityID);
diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs
index 9c336df..d51c8ca 100644
--- a/encompass-cs/Engine.cs
+++ b/encompass-cs/Engine.cs
@@ -107,6 +107,68 @@ namespace Encompass
             return componentManager.GetActiveComponentByType<TComponent>();
         }
 
+        protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
+        {
+            if (!writeTypes.Contains(typeof(TComponent)))
+            {
+                throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
+            }
+
+            return componentManager.AddComponent(entity.ID, component);
+        }
+
+        protected Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
+        {
+            if (!writeTypes.Contains(typeof(TComponent)))
+            {
+                throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
+            }
+
+            return componentManager.AddDrawComponent(entity.ID, component, layer);
+        }
+
+        protected void ActivateComponent(Guid componentID)
+        {
+            var type = componentManager.GetComponentTypeByID(componentID);
+            if (!writeTypes.Contains(type))
+            {
+                throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, type.Name);
+            }
+
+            componentManager.Activate(componentID);
+        }
+
+        protected void DeactivateComponent(Guid componentID)
+        {
+            var type = componentManager.GetComponentTypeByID(componentID);
+            if (!writeTypes.Contains(type))
+            {
+                throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, type.Name);
+            }
+
+            componentManager.Deactivate(componentID);
+        }
+
+        protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
+        {
+            if (!readTypes.Contains(typeof(TComponent)))
+            {
+                throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
+            }
+
+            return componentManager.GetComponentsByEntityAndType<TComponent>(entity.ID);
+        }
+
+        protected ValueTuple<Guid, TComponent> GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
+        {
+            return GetComponents<TComponent>(entity).First();
+        }
+
+        protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
+        {
+            return componentManager.EntityHasComponentOfType<TComponent>(entity.ID);
+        }
+
         internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent
         {
             if (!writeTypes.Contains(typeof(TComponent)))
@@ -157,5 +219,16 @@ namespace Encompass
         {
             entityManager.MarkForDestroy(entityID);
         }
+
+        protected void RemoveComponent(Guid componentID)
+        {
+            var type = componentManager.GetComponentTypeByID(componentID);
+            if (!writeTypes.Contains(type))
+            {
+                throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, type.Name);
+            }
+
+            componentManager.Remove(componentID);
+        }
     }
 }
diff --git a/encompass-cs/Entity.cs b/encompass-cs/Entity.cs
index 20b3101..fd45ad5 100644
--- a/encompass-cs/Entity.cs
+++ b/encompass-cs/Entity.cs
@@ -1,69 +1,14 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
 
 namespace Encompass
 {
     public struct Entity
     {
-        public readonly Guid id;
+        public readonly Guid ID;
 
-        private readonly ComponentManager componentManager;
-
-        internal Entity(Guid id, ComponentManager componentManager)
+        internal Entity(Guid id)
         {
-            this.id = id;
-            this.componentManager = componentManager;
-        }
-
-        public Guid AddComponent<TComponent>(TComponent component) where TComponent : struct, IComponent
-        {
-            return componentManager.AddComponent(id, component);
-        }
-
-        public Guid AddDrawComponent<TComponent>(TComponent component, int layer = 0) where TComponent : struct, IComponent
-        {
-            return componentManager.AddDrawComponent(id, component, layer);
-        }
-
-        public IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>() where TComponent : struct, IComponent
-        {
-            return componentManager.GetComponentsByEntityAndType<TComponent>(id);
-        }
-
-        public ValueTuple<Guid, TComponent> GetComponent<TComponent>() where TComponent : struct, IComponent
-        {
-            return GetComponents<TComponent>().First();
-        }
-
-        public bool HasComponent<TComponent>() where TComponent : struct, IComponent
-        {
-            return componentManager.EntityHasComponentOfType<TComponent>(id);
-        }
-
-        internal bool HasComponent(Type type)
-        {
-            return componentManager.EntityHasComponentOfType(id, type);
-        }
-
-        public void ActivateComponent(Guid componentID)
-        {
-            componentManager.MarkForActivation(componentID);
-        }
-
-        public void DeactivateComponent(Guid componentID)
-        {
-            componentManager.MarkForDeactivation(componentID);
-        }
-
-        public void RemoveComponent(Guid componentID)
-        {
-            componentManager.MarkForRemoval(componentID);
-        }
-
-        internal void RemoveAllComponents()
-        {
-            componentManager.RemoveAllComponentsFromEntity(id);
+            this.ID = id;
         }
     }
 }
diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs
index f58fe19..a01969f 100644
--- a/encompass-cs/EntityManager.cs
+++ b/encompass-cs/EntityManager.cs
@@ -31,7 +31,7 @@ namespace Encompass
         public Entity CreateEntity()
         {
             var id = NextID();
-            var entity = new Entity(id, componentManager);
+            var entity = new Entity(id);
             IDToEntity[id] = entity;
             componentManager.RegisterEntity(id);
             return entity;
@@ -56,8 +56,7 @@ namespace Encompass
         {
             foreach (var entityID in entitiesMarkedForDestroy)
             {
-                var entity = IDToEntity[entityID];
-                entity.RemoveAllComponents();
+                componentManager.RemoveAllComponentsFromEntity(entityID);
                 IDToEntity.Remove(entityID);
                 entityToEntityTrackers.Remove(entityID);
                 componentManager.RegisterDestroyedEntity(entityID);
diff --git a/encompass-cs/Renderer.cs b/encompass-cs/Renderer.cs
index 1e6dee8..d96e93e 100644
--- a/encompass-cs/Renderer.cs
+++ b/encompass-cs/Renderer.cs
@@ -1,13 +1,13 @@
 using System;
 using System.Collections.Generic;
-using System.Text;
+using System.Linq;
 
 namespace Encompass
 {
     public abstract class Renderer
     {
-        private EntityManager entityManager;
-        private ComponentManager componentManager;
+        internal EntityManager entityManager;
+        internal ComponentManager componentManager;
 
         internal void AssignEntityManager(EntityManager entityManager)
         {
@@ -48,5 +48,15 @@ namespace Encompass
         {
             return componentManager.GetActiveComponentByType<TComponent>();
         }
+
+        protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
+        {
+            return componentManager.GetComponentsByEntityAndType<TComponent>(entity.ID);
+        }
+
+        protected ValueTuple<Guid, TComponent> GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
+        {
+            return GetComponents<TComponent>(entity).First();
+        }
     }
 }
diff --git a/encompass-cs/World.cs b/encompass-cs/World.cs
index f349877..9d9abe6 100644
--- a/encompass-cs/World.cs
+++ b/encompass-cs/World.cs
@@ -35,10 +35,6 @@ namespace Encompass
             messageManager.ClearMessages();
             entityManager.DestroyMarkedEntities();
 
-            componentManager.ActivateMarkedComponents();
-            componentManager.DeactivateMarkedComponents();
-            componentManager.RemoveMarkedComponents();
-
             entityManager.CheckEntitiesWithAddedComponents();
             entityManager.CheckEntitiesWithRemovedComponents();
         }
diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs
index 3026171..4732fe4 100644
--- a/encompass-cs/WorldBuilder.cs
+++ b/encompass-cs/WorldBuilder.cs
@@ -41,6 +41,21 @@ namespace Encompass
             messageManager.AddMessage(message);
         }
 
+        public Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
+        {
+            return componentManager.AddComponent(entity.ID, component);
+        }
+
+        public Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
+        {
+            return componentManager.AddDrawComponent(entity.ID, component, layer);
+        }
+
+        public void DeactivateComponent(Guid componentID)
+        {
+            componentManager.Deactivate(componentID);
+        }
+
         public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
         {
             engine.AssignEntityManager(entityManager);
@@ -214,10 +229,6 @@ namespace Encompass
                 renderManager
             );
 
-            componentManager.ActivateMarkedComponents();
-            componentManager.DeactivateMarkedComponents();
-            componentManager.RemoveMarkedComponents();
-
             entityManager.CheckEntitiesWithAddedComponents();
             entityManager.CheckEntitiesWithRemovedComponents();
 
diff --git a/encompass-cs/renderers/EntityRenderer.cs b/encompass-cs/renderers/EntityRenderer.cs
index f491362..b384a8b 100644
--- a/encompass-cs/renderers/EntityRenderer.cs
+++ b/encompass-cs/renderers/EntityRenderer.cs
@@ -47,8 +47,8 @@ namespace Encompass
 
         private bool CheckEntity(Entity entity)
         {
-            return EntityChecker.CheckEntity(entity, componentTypes)
-                && entity.HasComponent(DrawComponentType);
+            return EntityChecker.CheckEntity(componentManager, entity, componentTypes)
+                && componentManager.EntityHasComponentOfType(entity.ID, DrawComponentType);
         }
     }
 }
diff --git a/encompass-cs/utility/EntityChecker.cs b/encompass-cs/utility/EntityChecker.cs
index eaabb76..75483e1 100644
--- a/encompass-cs/utility/EntityChecker.cs
+++ b/encompass-cs/utility/EntityChecker.cs
@@ -6,9 +6,9 @@ namespace Encompass
 {
     internal static class EntityChecker
     {
-        public static bool CheckEntity(Entity entity, IEnumerable<Type> componentTypes)
+        public static bool CheckEntity(ComponentManager componentManager, Entity entity, IEnumerable<Type> componentTypes)
         {
-            return componentTypes.All((componentType) => entity.HasComponent(componentType));
+            return componentTypes.All((componentType) => componentManager.EntityHasComponentOfType(entity.ID, componentType));
         }
     }
 }
diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs
new file mode 100644
index 0000000..30e1ba6
--- /dev/null
+++ b/test/ComponentTest.cs
@@ -0,0 +1,377 @@
+using NUnit.Framework;
+using FluentAssertions;
+
+using Encompass;
+using System.Collections.Generic;
+using System;
+using System.Linq;
+
+namespace Tests
+{
+    public class ComponentTests
+    {
+        struct MockComponent : IComponent
+        {
+            public string myString;
+            public int myInt;
+        }
+
+        struct EntityMessage : IMessage
+        {
+            public Entity entity;
+        }
+
+        static IEnumerable<(Guid, MockComponent)> gottenMockComponentIDPairs = Enumerable.Empty<(Guid, MockComponent)>();
+        static (Guid, MockComponent) gottenMockComponentIDPair;
+
+        [Reads(typeof(EntityMessage), typeof(MockComponent))]
+        class GetMockComponentsEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                gottenMockComponentIDPairs = Enumerable.Empty<(Guid, MockComponent)>();
+
+                foreach (var entityMessage in ReadMessages<EntityMessage>())
+                {
+                    gottenMockComponentIDPairs = GetComponents<MockComponent>(entityMessage.entity);
+                }
+            }
+        }
+
+        [Reads(typeof(EntityMessage), typeof(MockComponent))]
+        class GetMockComponentEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var entityMessage in ReadMessages<EntityMessage>())
+                {
+                    gottenMockComponentIDPair = GetComponent<MockComponent>(entityMessage.entity);
+                }
+            }
+        }
+
+        struct AddComponentTestMessage : IMessage
+        {
+            public Entity entity;
+            public MockComponent mockComponent;
+        }
+
+        [Reads(typeof(AddComponentTestMessage), typeof(MockComponent))]
+        class AddComponentEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var addComponentTestMessage in ReadMessages<AddComponentTestMessage>())
+                {
+                    Assert.IsTrue(HasComponent<MockComponent>(addComponentTestMessage.entity));
+                    Assert.That(GetComponent<MockComponent>(addComponentTestMessage.entity).Item2, Is.EqualTo(addComponentTestMessage.mockComponent));
+                }
+            }
+        }
+
+        [Test]
+        public void AddComponent()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new AddComponentEngine());
+            worldBuilder.AddEngine(new GetMockComponentEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            worldBuilder.AddComponent(entity, mockComponent);
+
+            AddComponentTestMessage addComponentTestMessage;
+            addComponentTestMessage.entity = entity;
+            addComponentTestMessage.mockComponent = mockComponent;
+            worldBuilder.EmitMessage(addComponentTestMessage);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01);
+        }
+
+        [Test]
+        public void GetComponents()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new GetMockComponentsEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponentA;
+            mockComponentA.myInt = 3;
+            mockComponentA.myString = "hello";
+
+            MockComponent mockComponentB;
+            mockComponentB.myInt = 5;
+            mockComponentB.myString = "wassup";
+
+            MockComponent mockComponentC;
+            mockComponentC.myInt = 1;
+            mockComponentC.myString = "howdy";
+
+            var componentAID = worldBuilder.AddComponent(entity, mockComponentA);
+            var componentBID = worldBuilder.AddComponent(entity, mockComponentB);
+            var componentCID = worldBuilder.AddComponent(entity, mockComponentC);
+
+            EntityMessage entityMessage;
+            entityMessage.entity = entity;
+            worldBuilder.EmitMessage(entityMessage);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01);
+
+            gottenMockComponentIDPairs.Should().Contain((componentAID, mockComponentA));
+            gottenMockComponentIDPairs.Should().Contain((componentBID, mockComponentB));
+            gottenMockComponentIDPairs.Should().Contain((componentCID, mockComponentC));
+        }
+
+        [Test]
+        public void GetComponent()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new GetMockComponentEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            var componentID = worldBuilder.AddComponent<MockComponent>(entity, mockComponent);
+
+            EntityMessage entityMessage;
+            entityMessage.entity = entity;
+            worldBuilder.EmitMessage(entityMessage);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01);
+
+            Assert.AreEqual((componentID, mockComponent), gottenMockComponentIDPair);
+        }
+
+        struct HasComponentTestMessage : IMessage
+        {
+            public Entity entity;
+        }
+
+        [Reads(typeof(HasComponentTestMessage), typeof(MockComponent))]
+        class HasComponentTestEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var hasComponentTestEngine in ReadMessages<HasComponentTestMessage>())
+                {
+                    Assert.IsTrue(HasComponent<MockComponent>(hasComponentTestEngine.entity));
+                }
+            }
+        }
+
+        [Test]
+        public void HasComponent()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new HasComponentTestEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            worldBuilder.AddComponent(entity, mockComponent);
+
+            HasComponentTestMessage hasComponentTestMessage;
+            hasComponentTestMessage.entity = entity;
+            worldBuilder.EmitMessage(hasComponentTestMessage);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01);
+        }
+
+        struct HasComponentWhenInactiveTestMessage : IMessage
+        {
+            public Entity entity;
+        }
+
+        [Reads(typeof(HasComponentWhenInactiveTestMessage))]
+        class HasComponentWhenInactiveTestEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var hasComponentTestEngine in ReadMessages<HasComponentWhenInactiveTestMessage>())
+                {
+                    Assert.IsFalse(HasComponent<MockComponent>(hasComponentTestEngine.entity));
+                }
+            }
+        }
+
+        [Test]
+        public void HasComponentWhenInactive()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new HasComponentWhenInactiveTestEngine());
+            var entity = worldBuilder.CreateEntity();
+            
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            var componentID = worldBuilder.AddComponent(entity, mockComponent);
+
+            HasComponentWhenInactiveTestMessage testMessage;
+            testMessage.entity = entity;
+            worldBuilder.EmitMessage(testMessage);
+
+            worldBuilder.DeactivateComponent(componentID);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01f);
+        }
+
+        struct RemoveComponentTestMessage : IMessage
+        {
+            public Entity entity;
+            public Guid componentID;
+        }
+
+        [Reads(typeof(RemoveComponentTestMessage), typeof(MockComponent))]
+        [Writes(typeof(MockComponent))]
+        class RemoveComponentTestEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var removeComponentMessage in ReadMessages<RemoveComponentTestMessage>())
+                {
+                    RemoveComponent(removeComponentMessage.componentID);
+
+                    Assert.IsFalse(HasComponent<MockComponent>(removeComponentMessage.entity));
+                    Assert.IsEmpty(GetComponents<MockComponent>(removeComponentMessage.entity));
+                }
+            }
+        }
+
+        [Test]
+        public void RemoveComponent()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new RemoveComponentTestEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            var componentID = worldBuilder.AddComponent(entity, mockComponent);
+
+            RemoveComponentTestMessage removeComponentMessage;
+            removeComponentMessage.entity = entity;
+            removeComponentMessage.componentID = componentID;
+            worldBuilder.EmitMessage(removeComponentMessage);
+
+            var world = worldBuilder.Build();
+
+
+            world.Update(0.01f);
+        }
+
+        struct ActivateComponentMessage : IMessage
+        {
+            public Entity entity;
+            public Guid componentID;
+        }
+
+        [Reads(typeof(ActivateComponentMessage))]
+        [Writes(typeof(MockComponent))]
+        class ActivateComponentEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var activateComponentMessage in ReadMessages<ActivateComponentMessage>())
+                {
+                    ActivateComponent(activateComponentMessage.componentID);
+                    Assert.IsTrue(HasComponent<MockComponent>(activateComponentMessage.entity));
+                }
+            }
+        }
+
+        [Test]
+        public void ActivateComponent()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new ActivateComponentEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            var componentID = worldBuilder.AddComponent(entity, mockComponent);
+
+            worldBuilder.DeactivateComponent(componentID);
+
+            ActivateComponentMessage activateMessage;
+            activateMessage.entity = entity;
+            activateMessage.componentID = componentID;
+            worldBuilder.EmitMessage(activateMessage);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01f);
+        }
+
+        struct DeactivateComponentMessage : IMessage
+        {
+            public Entity entity;
+            public Guid componentID;
+        }
+
+        [Reads(typeof(DeactivateComponentMessage))]
+        [Writes(typeof(MockComponent))]
+        class DeactivateComponentEngine : Engine
+        {
+            public override void Update(double dt)
+            {
+                foreach (var deactivateComponentMessage in ReadMessages<DeactivateComponentMessage>())
+                {
+                    DeactivateComponent(deactivateComponentMessage.componentID);
+                    Assert.IsFalse(HasComponent<MockComponent>(deactivateComponentMessage.entity));
+                }
+            }
+        }
+
+        [Test]
+        public void DeactivateComponent()
+        {
+            var worldBuilder = new WorldBuilder();
+            worldBuilder.AddEngine(new DeactivateComponentEngine());
+
+            var entity = worldBuilder.CreateEntity();
+
+            MockComponent mockComponent;
+            mockComponent.myInt = 3;
+            mockComponent.myString = "hello";
+
+            var componentID = worldBuilder.AddComponent(entity, mockComponent);
+
+            DeactivateComponentMessage deactivateComponentMessage;
+            deactivateComponentMessage.entity = entity;
+            deactivateComponentMessage.componentID = componentID;
+            worldBuilder.EmitMessage(deactivateComponentMessage);
+
+            var world = worldBuilder.Build();
+
+            world.Update(0.01);
+        }
+    }
+}
diff --git a/test/EngineTest.cs b/test/EngineTest.cs
index 21a7ff9..1ae33f6 100644
--- a/test/EngineTest.cs
+++ b/test/EngineTest.cs
@@ -10,6 +10,12 @@ using Encompass.Exceptions;
 
 namespace Tests
 {
+    struct MockComponent : IComponent
+    { 
+        public int myInt;
+        public string myString;
+    }
+
     public class EngineTest
     {
         static List<ValueTuple<Guid, MockComponent>> resultComponents;
@@ -51,11 +57,11 @@ namespace Tests
             mockComponentB.myInt = 1;
             mockComponentB.myString = "howdy";
 
-            var componentAID = entity.AddComponent(mockComponent);
-            var componentBID = entity.AddComponent(mockComponentB);
-            var inactiveComponentAID = entity.AddComponent(mockComponent);
+            var componentAID = worldBuilder.AddComponent(entity, mockComponent);
+            var componentBID = worldBuilder.AddComponent(entity, mockComponentB);
+            var inactiveComponentAID = worldBuilder.AddComponent(entity, mockComponent);
 
-            entity.DeactivateComponent(inactiveComponentAID);
+            worldBuilder.DeactivateComponent(inactiveComponentAID);
 
             var world = worldBuilder.Build();
 
@@ -79,7 +85,7 @@ namespace Tests
             mockComponent.myInt = 0;
             mockComponent.myString = "hello";
 
-            entity.AddComponent(mockComponent);
+            worldBuilder.AddComponent(entity, mockComponent);
 
             var world = worldBuilder.Build();
 
@@ -104,8 +110,8 @@ namespace Tests
             mockComponentB.myInt = 1;
             mockComponentB.myString = "howdy";
 
-            entity.AddComponent(mockComponent);
-            entity.AddComponent(mockComponentB);
+            worldBuilder.AddComponent(entity, mockComponent);
+            worldBuilder.AddComponent(entity, mockComponentB);
 
             var world = worldBuilder.Build();
 
@@ -140,7 +146,7 @@ namespace Tests
             mockComponent.myInt = 0;
             mockComponent.myString = "hello";
 
-            entity.AddComponent(mockComponent);
+            worldBuilder.AddComponent(entity, mockComponent);
 
             var world = worldBuilder.Build();
 
@@ -177,7 +183,7 @@ namespace Tests
             mockComponent.myInt = 0;
             mockComponent.myString = "hello";
 
-            entity.AddComponent(mockComponent);
+            worldBuilder.AddComponent(entity, mockComponent);
 
             var world = worldBuilder.Build();
 
@@ -359,8 +365,8 @@ namespace Tests
             componentB.myString = "hello";
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(componentA);
-            entity.AddComponent(componentB);
+            worldBuilder.AddComponent(entity, componentA);
+            worldBuilder.AddComponent(entity, componentB);
 
             var world = worldBuilder.Build();
             world.Update(0.01f);
@@ -434,11 +440,11 @@ namespace Tests
             mockComponent.myInt = 2;
             mockComponent.myString = "blah";
 
-            entity.AddComponent(destroyerComponent);
-            var componentID = entity.AddComponent(mockComponent);
+            worldBuilder.AddComponent(entity, destroyerComponent);
+            var componentID = worldBuilder.AddComponent(entity, mockComponent);
 
-            entityB.AddComponent(destroyerComponent);
-            var componentBID = entityB.AddComponent(mockComponent);
+            worldBuilder.AddComponent(entityB, destroyerComponent);
+            var componentBID = worldBuilder.AddComponent(entityB, mockComponent);
 
             var world = worldBuilder.Build();
 
@@ -448,7 +454,8 @@ namespace Tests
             Assert.That(results, Does.Not.Contain((componentBID, mockComponent)));
         }
 
-        [Reads(typeof(DestroyerComponent))]
+        [Reads(typeof(DestroyerComponent), typeof(MockComponent))]
+        [Writes(typeof(MockComponent))]
         class DestroyAndAddComponentEngine : Engine
         {
             public override void Update(double dt)
@@ -457,9 +464,9 @@ namespace Tests
                 {
                     var componentID = componentPair.Item1;
                     var entity = GetEntityByComponentID(componentID);
-                    var (id, _) = entity.GetComponent<MockComponent>();
-                    entity.RemoveComponent(id);
-                    Destroy(entity.id);
+                    var (id, _) = GetComponent<MockComponent>(entity);
+                    RemoveComponent(id);
+                    Destroy(entity.ID);
                 }
             }
         }
@@ -473,8 +480,8 @@ namespace Tests
 
             var entity = worldBuilder.CreateEntity();
 
-            entity.AddComponent(new DestroyerComponent());
-            entity.AddComponent(new MockComponent());
+            worldBuilder.AddComponent(entity, new DestroyerComponent());
+            worldBuilder.AddComponent(entity, new MockComponent());
 
             var world = worldBuilder.Build();
 
@@ -504,7 +511,7 @@ namespace Tests
             component.myString = "howdy";
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(component);
+            worldBuilder.AddComponent(entity, component);
 
             var world = worldBuilder.Build();
             world.Update(0.01f);
@@ -534,7 +541,7 @@ namespace Tests
             component.myString = "howdy";
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(component);
+            worldBuilder.AddComponent(entity, component);
 
             var world = worldBuilder.Build();
             world.Update(0.01f);
@@ -565,7 +572,7 @@ namespace Tests
             component.myString = "howdy";
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(component);
+            worldBuilder.AddComponent(entity, component);
 
             var world = worldBuilder.Build();
 
@@ -598,9 +605,9 @@ namespace Tests
             var entityTwo = worldBuilder.CreateEntity();
 
             EntityIDComponent entityIDComponent;
-            entityIDComponent.entityID = entityTwo.id;
+            entityIDComponent.entityID = entityTwo.ID;
 
-            entity.AddComponent(entityIDComponent);
+            worldBuilder.AddComponent(entity, entityIDComponent);
 
             var world = worldBuilder.Build();
 
diff --git a/test/EntityRendererTest.cs b/test/EntityRendererTest.cs
index 75367cf..5a52d89 100644
--- a/test/EntityRendererTest.cs
+++ b/test/EntityRendererTest.cs
@@ -32,27 +32,27 @@ namespace Tests
             TestDrawComponent testDrawComponent = default(TestDrawComponent);
 
             var entityToTrack = worldBuilder.CreateEntity();
-            entityToTrack.AddComponent(aComponent);
-            entityToTrack.AddComponent(bComponent);
-            entityToTrack.AddComponent(testDrawComponent);
+            worldBuilder.AddComponent(entityToTrack, aComponent);
+            worldBuilder.AddComponent(entityToTrack, bComponent);
+            worldBuilder.AddComponent(entityToTrack, testDrawComponent);
 
             var entityNotToTrack = worldBuilder.CreateEntity();
-            entityNotToTrack.AddComponent(aComponent);
-            entityNotToTrack.AddComponent(testDrawComponent);
+            worldBuilder.AddComponent(entityNotToTrack, aComponent);
+            worldBuilder.AddComponent(entityNotToTrack, testDrawComponent);
 
             var entityWithoutDrawComponent = worldBuilder.CreateEntity();
-            entityWithoutDrawComponent.AddComponent(aComponent);
-            entityWithoutDrawComponent.AddComponent(bComponent);
+            worldBuilder.AddComponent(entityWithoutDrawComponent, aComponent);
+            worldBuilder.AddComponent(entityWithoutDrawComponent, bComponent);
 
             var world = worldBuilder.Build();
 
             world.Update(0.01f);
 
-            Console.WriteLine(renderer.IsTracking(entityNotToTrack.id));
+            Console.WriteLine(renderer.IsTracking(entityNotToTrack.ID));
 
-            Assert.IsTrue(renderer.IsTracking(entityToTrack.id));
-            Assert.IsFalse(renderer.IsTracking(entityNotToTrack.id));
-            Assert.IsFalse(renderer.IsTracking(entityWithoutDrawComponent.id));
+            Assert.IsTrue(renderer.IsTracking(entityToTrack.ID));
+            Assert.IsFalse(renderer.IsTracking(entityNotToTrack.ID));
+            Assert.IsFalse(renderer.IsTracking(entityWithoutDrawComponent.ID));
         }
 
         static bool called = false;
@@ -75,19 +75,17 @@ namespace Tests
             TestDrawComponent testDrawComponent = default(TestDrawComponent);
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(aComponent);
-            entity.AddComponent(bComponent);
-            var testDrawComponentID = entity.AddDrawComponent(testDrawComponent, 1);
+            worldBuilder.AddComponent(entity, aComponent);
+            worldBuilder.AddComponent(entity, bComponent);
+            var testDrawComponentID = worldBuilder.AddDrawComponent(entity, testDrawComponent, 1);
+
+            worldBuilder.DeactivateComponent(testDrawComponentID);
 
             var world = worldBuilder.Build();
 
             world.Update(0.01f);
 
-            entity.DeactivateComponent(testDrawComponentID);
-
-            world.Update(0.01f);
-
-            Assert.IsFalse(renderer.IsTracking(entity.id));
+            Assert.IsFalse(renderer.IsTracking(entity.ID));
 
             world.Draw();
 
@@ -101,7 +99,7 @@ namespace Tests
         {
             public override void Render(Entity entity)
             {
-                resultComponents = entity.GetComponents<TestDrawComponent>();
+                resultComponents = GetComponents<TestDrawComponent>(entity);
                 calledOnDraw = true;
             }
         }
@@ -117,16 +115,16 @@ namespace Tests
             TestDrawComponent testDrawComponent;
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(aComponent);
-            entity.AddComponent(cComponent);
-            var testDrawComponentID = entity.AddDrawComponent(testDrawComponent, 2);
+            worldBuilder.AddComponent(entity, aComponent);
+            worldBuilder.AddComponent(entity, cComponent);
+            var testDrawComponentID = worldBuilder.AddDrawComponent(entity, testDrawComponent, 2);
 
             var world = worldBuilder.Build();
 
             world.Update(0.01f);
             world.Draw();
 
-            Assert.IsTrue(renderer.IsTracking(entity.id));
+            Assert.IsTrue(renderer.IsTracking(entity.ID));
             Assert.IsTrue(calledOnDraw);
             resultComponents.Should().Contain(new ValueTuple<Guid, TestDrawComponent>(testDrawComponentID, testDrawComponent));
         }
diff --git a/test/EntityTest.cs b/test/EntityTest.cs
deleted file mode 100644
index bbd4d9e..0000000
--- a/test/EntityTest.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using NUnit.Framework;
-using FluentAssertions;
-
-using Encompass;
-using System.Collections.Generic;
-using System;
-
-namespace Tests
-{
-    struct MockComponent : IComponent
-    {
-        public string myString;
-        public int myInt;
-    }
-
-    public class EntityTest
-    {
-        [Test]
-        public void AddComponent()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-
-            MockComponent mockComponent;
-            mockComponent.myInt = 3;
-            mockComponent.myString = "hello";
-
-            entity.AddComponent(mockComponent);
-
-            var world = worldBuilder.Build();
-
-            Assert.IsTrue(entity.HasComponent<MockComponent>());
-            Assert.That(entity.GetComponent<MockComponent>().Item2, Is.EqualTo(mockComponent));
-        }
-
-        [Test]
-        public void GetComponents()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-
-            MockComponent mockComponentA;
-            mockComponentA.myInt = 3;
-            mockComponentA.myString = "hello";
-
-            MockComponent mockComponentB;
-            mockComponentB.myInt = 5;
-            mockComponentB.myString = "wassup";
-
-            MockComponent mockComponentC;
-            mockComponentC.myInt = 1;
-            mockComponentC.myString = "howdy";
-
-            var componentAID = entity.AddComponent(mockComponentA);
-            var componentBID = entity.AddComponent(mockComponentB);
-            var componentCID = entity.AddComponent(mockComponentC);
-
-            var world = worldBuilder.Build();
-
-            var components = entity.GetComponents<MockComponent>();
-            components.Should().Contain(new ValueTuple<Guid, MockComponent>(componentAID, mockComponentA));
-            components.Should().Contain(new ValueTuple<Guid, MockComponent>(componentBID, mockComponentB));
-            components.Should().Contain(new ValueTuple<Guid, MockComponent>(componentCID, mockComponentC));
-        }
-
-        [Test]
-        public void GetComponent()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-
-            MockComponent mockComponent;
-            mockComponent.myInt = 3;
-            mockComponent.myString = "hello";
-
-            var componentID = entity.AddComponent<MockComponent>(mockComponent);
-
-            var world = worldBuilder.Build();
-
-            Assert.AreEqual(new ValueTuple<Guid, MockComponent>(componentID, mockComponent), entity.GetComponent<MockComponent>());
-        }
-
-        [Test]
-        public void HasComponent()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-
-            MockComponent mockComponent;
-            mockComponent.myInt = 3;
-            mockComponent.myString = "hello";
-
-            entity.AddComponent(mockComponent);
-
-            var world = worldBuilder.Build();
-
-            Assert.IsTrue(entity.HasComponent<MockComponent>());
-        }
-
-        [Test]
-        public void HasComponentWhenInactive()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-            
-            MockComponent mockComponent;
-            mockComponent.myInt = 3;
-            mockComponent.myString = "hello";
-
-            var componentID = entity.AddComponent(mockComponent);
-
-            var world = worldBuilder.Build();
-
-            entity.DeactivateComponent(componentID);
-
-            world.Update(0.01f);
-
-            Assert.IsFalse(entity.HasComponent<MockComponent>());
-        }
-
-        [Test]
-        public void RemoveComponent()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-
-            MockComponent mockComponent;
-            mockComponent.myInt = 3;
-            mockComponent.myString = "hello";
-
-            var componentID = entity.AddComponent(mockComponent);
-
-            var world = worldBuilder.Build();
-
-            entity.RemoveComponent(componentID);
-
-            world.Update(0.01f);
-
-            Assert.IsFalse(entity.HasComponent<MockComponent>());
-            Assert.IsEmpty(entity.GetComponents<MockComponent>());
-        }
-
-        [Test]
-        public void ReactivateComponent()
-        {
-            var worldBuilder = new WorldBuilder();
-            var entity = worldBuilder.CreateEntity();
-
-            MockComponent mockComponent;
-            mockComponent.myInt = 3;
-            mockComponent.myString = "hello";
-
-            var componentID = entity.AddComponent(mockComponent);
-
-            var world = worldBuilder.Build();
-
-            entity.DeactivateComponent(componentID);
-
-            world.Update(0.01f);
-
-            Assert.IsFalse(entity.HasComponent<MockComponent>());
-            Assert.IsEmpty(entity.GetComponents<MockComponent>());
-
-            entity.ActivateComponent(componentID);
-
-            world.Update(0.01f);
-
-            Assert.IsTrue(entity.HasComponent<MockComponent>());
-            Assert.IsNotEmpty(entity.GetComponents<MockComponent>());
-        }
-    }
-}
diff --git a/test/GeneralRendererTest.cs b/test/GeneralRendererTest.cs
index fd0e099..497464d 100644
--- a/test/GeneralRendererTest.cs
+++ b/test/GeneralRendererTest.cs
@@ -32,7 +32,7 @@ namespace Tests
                 AComponent aComponent;
 
                 var entity = worldBuilder.CreateEntity();
-                var componentID = entity.AddComponent(aComponent);
+                var componentID = worldBuilder.AddComponent(entity, aComponent);
 
                 var world = worldBuilder.Build();
 
@@ -52,8 +52,8 @@ namespace Tests
                 AComponent aComponentTwo;
 
                 var entity = worldBuilder.CreateEntity();
-                var componentID = entity.AddComponent(aComponent);
-                var componentTwoID = entity.AddComponent(aComponentTwo);
+                var componentID = worldBuilder.AddComponent(entity, aComponent);
+                var componentTwoID = worldBuilder.AddComponent(entity, aComponentTwo);
                 var world = worldBuilder.Build();
 
                 world.Update(0.01f);
diff --git a/test/SpawnerTest.cs b/test/SpawnerTest.cs
index 446fe4e..564eeba 100644
--- a/test/SpawnerTest.cs
+++ b/test/SpawnerTest.cs
@@ -23,12 +23,14 @@ namespace Tests
             }
         }
 
+        [Writes(typeof(TestComponent))]
         class TestSpawner : Spawner<SpawnMessageA>
         {
             protected override void Spawn(SpawnMessageA message)
             {
                 resultEntity = CreateEntity();
-                resultEntity.AddComponent(new TestComponent());
+                AddComponent(resultEntity, new TestComponent());
+                Assert.Pass();
             }
         }
 
@@ -42,14 +44,6 @@ namespace Tests
             var world = worldBuilder.Build();
 
             world.Update(0.01);
-
-            Assert.That(resultEntity.HasComponent<TestComponent>(), Is.True);
-
-            var id = resultEntity.id;
-
-            world.Update(0.01);
-
-            Assert.That(resultEntity.id, Is.Not.EqualTo(id));
         }
     }
 }
diff --git a/test/WorldTest.cs b/test/WorldTest.cs
index 675a75e..fc1b8ff 100644
--- a/test/WorldTest.cs
+++ b/test/WorldTest.cs
@@ -44,26 +44,26 @@ namespace Tests
             TestDrawComponent testDrawComponent = default(TestDrawComponent);
 
             var entity = worldBuilder.CreateEntity();
-            entity.AddComponent(testComponent);
-            entity.AddDrawComponent(testDrawComponent, 3);
+            worldBuilder.AddComponent(entity, testComponent);
+            worldBuilder.AddDrawComponent(entity, testDrawComponent, 3);
 
             TestDrawComponent testDrawComponentTwo = default(TestDrawComponent);
 
             var entityTwo = worldBuilder.CreateEntity();
-            entityTwo.AddComponent(testComponent);
-            entityTwo.AddDrawComponent(testDrawComponentTwo, 1);
+            worldBuilder.AddComponent(entityTwo, testComponent);
+            worldBuilder.AddDrawComponent(entityTwo, testDrawComponentTwo, 1);
 
             TestDrawComponent testDrawComponentThree = default(TestDrawComponent);
 
             var entityThree = worldBuilder.CreateEntity();
-            entityThree.AddComponent(testComponent);
-            entityThree.AddDrawComponent(testDrawComponentThree, 5);
+            worldBuilder.AddComponent(entityThree, testComponent);
+            worldBuilder.AddDrawComponent(entityThree, testDrawComponentThree, 5);
 
             TestDrawComponent testDrawComponentFour = default(TestDrawComponent);
 
             var entityFour = worldBuilder.CreateEntity();
-            entityFour.AddComponent(testComponent);
-            entityFour.AddDrawComponent(testDrawComponentFour, -5);
+            worldBuilder.AddComponent(entityFour, testComponent);
+            worldBuilder.AddDrawComponent(entityFour, testDrawComponentFour, -5);
 
             var world = worldBuilder.Build();