From dd75a94d18a3550cdc85694c35db144a803d2a66 Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Wed, 19 Jun 2019 20:37:46 -0700 Subject: [PATCH] misc backend fixes + more tests --- encompass-cs/ComponentManager.cs | 14 ++++-- encompass-cs/Engine.cs | 35 +++++++++---- encompass-cs/EntityManager.cs | 1 + test/EngineTest.cs | 55 +++++++++++++++++++++ test/WorldTest.cs | 85 ++++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 14 deletions(-) create mode 100644 test/WorldTest.cs diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 4b76712..8231340 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -161,8 +161,6 @@ namespace Encompass { MarkForRemoval(componentID); } - - entityIDToComponentIDs.Remove(entityID); } internal void MarkForActivation(Guid componentID) @@ -217,7 +215,7 @@ namespace Encompass componentsToDeactivate.Clear(); } - internal void RemoveMarkedComponents() + public void RemoveMarkedComponents() { foreach (var componentID in componentsToRemove) { @@ -228,7 +226,10 @@ namespace Encompass inactiveComponents.Remove(componentID); var entityID = componentIDToEntityID[componentID]; - entityIDToComponentIDs[entityID].Remove(componentID); + if (entityIDToComponentIDs.ContainsKey(entityID)) + { + entityIDToComponentIDs[entityID].Remove(componentID); + } IDToComponent.Remove(componentID); componentIDToType.Remove(componentID); @@ -243,5 +244,10 @@ namespace Encompass componentsToRemove.Clear(); } + + public void RegisterDestroyedEntity(Guid entityID) + { + entityIDToComponentIDs.Remove(entityID); + } } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 71b3119..647c394 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -17,19 +17,19 @@ namespace Encompass public Engine() { - var mutatesAttribute = this.GetType().GetCustomAttribute(false); + var mutatesAttribute = GetType().GetCustomAttribute(false); if (mutatesAttribute != null) { mutateComponentTypes = mutatesAttribute.mutateComponentTypes; } - var emitsAttribute = this.GetType().GetCustomAttribute(false); + var emitsAttribute = GetType().GetCustomAttribute(false); if (emitsAttribute != null) { emitMessageTypes = emitsAttribute.emitMessageTypes; } - var readsAttribute = this.GetType().GetCustomAttribute(false); + var readsAttribute = GetType().GetCustomAttribute(false); if (readsAttribute != null) { readMessageTypes = readsAttribute.readMessageTypes; @@ -55,24 +55,34 @@ namespace Encompass protected Entity CreateEntity() { - return this.entityManager.CreateEntity(); + return entityManager.CreateEntity(); + } + + protected Entity GetEntity(Guid entityID) + { + return entityManager.GetEntity(entityID); + } + + protected Guid GetEntityIDFromComponentID(Guid componentID) + { + return componentManager.GetEntityIDFromComponentID(componentID); } protected IEnumerable> ReadComponents() where TComponent : struct, IComponent { - return this.componentManager.GetActiveComponentsByType(); + return componentManager.GetActiveComponentsByType(); } protected KeyValuePair ReadComponent() where TComponent : struct, IComponent { - return this.componentManager.GetActiveComponentByType(); + return componentManager.GetActiveComponentByType(); } internal void UpdateComponentInWorld(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent { if (mutateComponentTypes.Contains(typeof(TComponent))) { - this.componentManager.UpdateComponent(componentID, newComponent); + componentManager.UpdateComponent(componentID, newComponent); } else { @@ -82,14 +92,14 @@ namespace Encompass protected void UpdateComponent(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent { - this.UpdateComponentInWorld(componentID, newComponentValue); + UpdateComponentInWorld(componentID, newComponentValue); } protected void EmitMessage(TMessage message) where TMessage : struct, IMessage { if (emitMessageTypes.Contains(typeof(TMessage))) { - this.messageManager.AddMessage(message); + messageManager.AddMessage(message); } else { @@ -101,7 +111,7 @@ namespace Encompass { if (readMessageTypes.Contains(typeof(TMessage))) { - return this.messageManager.GetMessagesByType(); + return messageManager.GetMessagesByType(); } else { @@ -120,5 +130,10 @@ namespace Encompass throw new IllegalMessageReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); } } + + protected void Destroy(Guid entityID) + { + entityManager.MarkForDestroy(entityID); + } } } diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs index 26ced7e..63954cd 100644 --- a/encompass-cs/EntityManager.cs +++ b/encompass-cs/EntityManager.cs @@ -54,6 +54,7 @@ namespace Encompass entity.RemoveAllComponents(); IDToEntity.Remove(entityID); entityToEntityTrackers.Remove(entityID); + componentManager.RegisterDestroyedEntity(entityID); } entitiesMarkedForDestroy.Clear(); diff --git a/test/EngineTest.cs b/test/EngineTest.cs index 39360f9..069c49f 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -357,5 +357,60 @@ namespace Tests Assert.That(emptyComponentReadResult, Is.Empty); } + + struct DestroyerComponent : IComponent { } + + class DestroyerEngine : Engine + { + public override void Update(float dt) + { + var componentPairs = ReadComponents(); + + foreach (var componentPair in componentPairs) + { + var componentID = componentPair.Key; + var entityID = GetEntityIDFromComponentID(componentID); + Destroy(entityID); + } + } + } + + static IEnumerable> results; + class ReaderEngine : Engine + { + public override void Update(float dt) + { + results = ReadComponents(); + } + } + + [Test] + public void DestroyEntity() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(); + worldBuilder.AddEngine(); + + var entity = worldBuilder.CreateEntity(); + var entityB = worldBuilder.CreateEntity(); + + DestroyerComponent destroyerComponent; + MockComponent mockComponent; + mockComponent.myInt = 2; + mockComponent.myString = "blah"; + + entity.AddComponent(destroyerComponent); + var componentID = entity.AddComponent(mockComponent); + + entityB.AddComponent(destroyerComponent); + var componentBID = entityB.AddComponent(mockComponent); + + var world = worldBuilder.Build(); + + world.Update(0.01f); + + Assert.That(results, Does.Not.Contain(new KeyValuePair(componentID, mockComponent))); + Assert.That(results, Does.Not.Contain(new KeyValuePair(componentBID, mockComponent))); + } } } diff --git a/test/WorldTest.cs b/test/WorldTest.cs new file mode 100644 index 0000000..bcfe040 --- /dev/null +++ b/test/WorldTest.cs @@ -0,0 +1,85 @@ +using NUnit.Framework; +using FluentAssertions; + +using System; +using System.Collections.Generic; +using System.Text; + +using Encompass; + +namespace Tests +{ + public class WorldTest + { + struct TestComponent : IComponent { } + struct TestDrawComponent : IDrawComponent + { + public int Layer { get ; set; } + } + + static List drawOrder = new List(); + + [Renders(typeof(TestDrawComponent), typeof(TestComponent))] + class TestEntityRenderer : EntityRenderer + { + public override void Render(Entity entity) + { + drawOrder.Add(entity); + } + } + + class TestGeneralRenderer : GeneralRenderer + { + public new int Layer { get { return 9; } } + + public override void Render() + { + drawOrder.Add(this); + } + } + + [Test] + public void DrawOrder() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddRenderer(); + var testGeneralRenderer = worldBuilder.AddRenderer(); + + TestComponent testComponent; + TestDrawComponent testDrawComponent = default(TestDrawComponent); + testDrawComponent.Layer = 3; + + var entity = worldBuilder.CreateEntity(); + entity.AddComponent(testComponent); + entity.AddComponent(testDrawComponent); + + TestDrawComponent testDrawComponentTwo = default(TestDrawComponent); + testDrawComponentTwo.Layer = 1; + + var entityTwo = worldBuilder.CreateEntity(); + entityTwo.AddComponent(testComponent); + entityTwo.AddComponent(testDrawComponentTwo); + + TestDrawComponent testDrawComponentThree = default(TestDrawComponent); + testDrawComponentThree.Layer = 5; + + var entityThree = worldBuilder.CreateEntity(); + entityThree.AddComponent(testComponent); + entityThree.AddComponent(testDrawComponentThree); + + TestDrawComponent testDrawComponentFour = default(TestDrawComponent); + testDrawComponentFour.Layer = -5; + + var entityFour = worldBuilder.CreateEntity(); + entityFour.AddComponent(testComponent); + entityFour.AddComponent(testDrawComponentFour); + + var world = worldBuilder.Build(); + + world.Update(0.01f); + world.Draw(); + + drawOrder.Should().BeEquivalentTo(entityFour, entityTwo, entity, entityThree, testGeneralRenderer); + } + } +}