From 7885c2e0f49855b2c799e036b44640d040977ae3 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Mon, 23 Dec 2019 18:01:49 -0800 Subject: [PATCH] component removes are treated as priority writes --- encompass-cs/Collections/ComponentStore.cs | 25 ++++++++++---- .../Collections/TypedComponentStore.cs | 28 +++++++++++---- encompass-cs/ComponentManager.cs | 20 +++++++++-- encompass-cs/ComponentUpdateManager.cs | 34 +++++++++---------- encompass-cs/DrawLayerManager.cs | 2 +- encompass-cs/Engine.cs | 19 ++++++++--- test/ComponentTest.cs | 1 + test/EngineTest.cs | 14 ++++++-- 8 files changed, 101 insertions(+), 42 deletions(-) diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index 90280c5..1d5287d 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -70,21 +70,34 @@ namespace Encompass public bool Set(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - ComponentBitSet.Set(entity); - return Lookup().Set(entity, component, priority); + if (Lookup().Set(entity, component, priority)) + { + ComponentBitSet.Set(entity); + return true; + } + return false; } - public void Remove(Entity entity) where TComponent : struct, IComponent + public bool Remove(Entity entity, int priority) where TComponent : struct, IComponent { - ComponentBitSet.RemoveComponent(entity); - Lookup().Remove(entity); + if (Lookup().Remove(entity, priority)) + { + ComponentBitSet.RemoveComponent(entity); + return true; + } + return false; + } + + public void ForceRemove(Entity entity) where TComponent : struct, IComponent + { + Lookup().ForceRemove(entity); } public void Remove(Entity entity) { foreach (var entry in Stores.Values) { - entry.Remove(entity); + entry.ForceRemove(entity); } ComponentBitSet.RemoveEntity(entity); } diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index 63409a2..54f1298 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -8,7 +8,8 @@ namespace Encompass 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 bool Remove(Entity entity, int priority); + public abstract void ForceRemove(Entity entity); public abstract void Clear(); } @@ -40,6 +41,25 @@ namespace Encompass return false; } + public override bool Remove(Entity entity, int priority) + { + if (!priorities.ContainsKey(entity) || priority < priorities[entity]) + { + priorities[entity] = priority; + store.Remove(entity); + priorities.Remove(entity); + return true; + } + + return false; + } + + public override void ForceRemove(Entity entity) + { + store.Remove(entity); + priorities.Remove(entity); + } + public override bool Has(Entity entity) { return store.ContainsKey(entity); @@ -66,11 +86,5 @@ namespace Encompass yield return (kvp.Key, typeof(TComponent), (IComponent)kvp.Value); } } - - 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 30d024b..36f6cd8 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -92,10 +92,24 @@ namespace Encompass entitiesMarkedForRemoval.Clear(); } - public void Remove(Entity entity) where TComponent : struct, IComponent + public bool RemovePending(Entity entity, int priority) where TComponent : struct, IComponent { - componentUpdateManager.Remove(entity); - drawLayerManager.UnRegisterComponentWithLayer(entity); + if (componentUpdateManager.RemovePending(entity, priority)) + { + drawLayerManager.UnRegisterComponentWithLayer(entity); + return true; + } + return false; + } + + public bool Remove(Entity entity, int priority) where TComponent : struct, IComponent + { + if (componentUpdateManager.Remove(entity, priority)) + { + drawLayerManager.UnRegisterComponentWithLayer(entity); + return true; + } + return false; } } } diff --git a/encompass-cs/ComponentUpdateManager.cs b/encompass-cs/ComponentUpdateManager.cs index d0ee527..aa195e1 100644 --- a/encompass-cs/ComponentUpdateManager.cs +++ b/encompass-cs/ComponentUpdateManager.cs @@ -1,6 +1,4 @@ -using Encompass.Collections; -using System; -using System.Collections; +using System; using System.Collections.Generic; using System.Linq; @@ -8,7 +6,6 @@ namespace Encompass { internal class ComponentUpdateManager { - private readonly ComponentStore existingAndPendingComponentStore; private readonly ComponentStore existingComponentStore; private readonly ComponentStore pendingComponentStore; private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(128); @@ -18,7 +15,6 @@ namespace Encompass public ComponentUpdateManager(Dictionary typeToIndex) { - existingAndPendingComponentStore = new ComponentStore(typeToIndex); existingComponentStore = new ComponentStore(typeToIndex); pendingComponentStore = new ComponentStore(typeToIndex); UpToDateComponentStore = new ComponentStore(typeToIndex); @@ -27,7 +23,6 @@ namespace Encompass public void RegisterComponentType() where TComponent : struct, IComponent { - existingAndPendingComponentStore.RegisterComponentType(); existingComponentStore.RegisterComponentType(); pendingComponentStore.RegisterComponentType(); UpToDateComponentStore.RegisterComponentType(); @@ -35,7 +30,6 @@ namespace Encompass public void FinishRegistering() { - existingAndPendingComponentStore.FinishRegistering(); existingComponentStore.FinishRegistering(); pendingComponentStore.FinishRegistering(); UpToDateComponentStore.FinishRegistering(); @@ -43,7 +37,6 @@ namespace Encompass internal void Clear() { - existingAndPendingComponentStore.ClearAll(); existingComponentStore.ClearAll(); pendingComponentStore.ClearAll(); UpToDateComponentStore.ClearAll(); @@ -77,9 +70,19 @@ namespace Encompass return false; } + internal bool RemovePending(Entity entity, int priority) where TComponent : struct, IComponent + { + UpToDateComponentStore.Remove(entity, priority); + return pendingComponentStore.Remove(entity, priority); + } + + internal bool Remove(Entity entity, int priority) where TComponent : struct, IComponent + { + return UpToDateComponentStore.Remove(entity, priority); + } + private void RegisterExistingOrPendingComponentMessage(Entity entity, TComponent component) where TComponent : struct, IComponent { - existingAndPendingComponentStore.Set(entity, component); UpToDateComponentStore.Set(entity, component); } @@ -92,7 +95,7 @@ namespace Encompass internal IEnumerable<(TComponent, Entity)> ReadExistingAndPendingComponentsByType() where TComponent : struct, IComponent { - return existingAndPendingComponentStore.All(); + return UpToDateComponentStore.All(); } internal IEnumerable<(TComponent, Entity)> ReadExistingComponentsByType() where TComponent : struct, IComponent @@ -135,7 +138,7 @@ namespace Encompass internal bool SomeExistingOrPendingComponent() where TComponent : struct, IComponent { - return existingAndPendingComponentStore.Any(); + return UpToDateComponentStore.Any(); } internal bool SomeExistingComponent() where TComponent : struct, IComponent @@ -164,12 +167,12 @@ namespace Encompass internal bool HasExistingOrPendingComponent(Entity entity) where TComponent : struct, IComponent { - return existingAndPendingComponentStore.Has(entity); + return UpToDateComponentStore.Has(entity); } internal bool HasExistingOrPendingComponent(Entity entity, Type type) { - return existingAndPendingComponentStore.Has(type, entity); + return UpToDateComponentStore.Has(type, entity); } internal bool HasExistingComponent(Entity entity) where TComponent : struct, IComponent @@ -192,11 +195,6 @@ namespace Encompass return pendingComponentStore.Has(type, entity); } - internal void Remove(Entity entity) where TComponent : struct, IComponent - { - UpToDateComponentStore.Remove(entity); - } - internal ComponentBitSet PendingBits { get { return pendingComponentStore.ComponentBitSet; } } internal ComponentBitSet ExistingBits { get { return existingComponentStore.ComponentBitSet; } } } diff --git a/encompass-cs/DrawLayerManager.cs b/encompass-cs/DrawLayerManager.cs index 65cde48..b2bc047 100644 --- a/encompass-cs/DrawLayerManager.cs +++ b/encompass-cs/DrawLayerManager.cs @@ -96,7 +96,7 @@ namespace Encompass if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { var layer = typeToEntityToLayer[typeof(TComponent)][entity]; - layerIndexToComponentStore[layer].Remove(entity); + layerIndexToComponentStore[layer].ForceRemove(entity); } typeToEntityToLayer[typeof(TComponent)].Remove(entity); } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index b61752d..5157fa5 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -561,12 +561,23 @@ namespace Encompass /// Note that the Engine must Read the Component type that is being removed. /// If a Component with the specified type does not exist on the Entity, returns false and does not mutate the Entity. /// - protected bool RemoveComponent(Entity entity) where TComponent : struct, IComponent + protected void RemoveComponent(Entity entity) where TComponent : struct, IComponent { - if (!HasComponent(entity)) { return false; } + var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority; - componentManager.Remove(entity); - return true; + if (!writeTypes.Contains(typeof(TComponent))) + { + throw new IllegalWriteException("Engine {0} tried to remove undeclared Component {1}. Declare with Writes attribute.", GetType().Name, typeof(TComponent).Name); + } + + if (writePendingTypes.Contains(typeof(TComponent))) + { + componentManager.RemovePending(entity, priority); + } + else + { + componentManager.Remove(entity, priority); + } } /// diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index febbd0b..c7c1c78 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -369,6 +369,7 @@ namespace Tests [Reads(typeof(MockComponent))] [Receives(typeof(RemoveComponentTestMessage))] + [Writes(typeof(MockComponent))] class RemoveComponentTestEngine : Engine { public override void Update(double dt) diff --git a/test/EngineTest.cs b/test/EngineTest.cs index 1b36ce6..3fc6a9a 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -593,7 +593,8 @@ namespace Tests Assert.That(results, Does.Not.Contain((mockComponent, entity))); } - [Reads(typeof(DestroyerComponent), typeof(MockComponent))] + [Reads(typeof(DestroyerComponent))] + [Writes(typeof(MockComponent))] class DestroyAndAddComponentEngine : Engine { public override void Update(double dt) @@ -665,6 +666,7 @@ namespace Tests } [Reads(typeof(MockComponent))] + [Writes(typeof(MockComponent))] class DelayedMessageEngine : Engine { public override void Update(double dt) @@ -711,6 +713,7 @@ namespace Tests } [Reads(typeof(MockComponent))] + [Writes(typeof(MockComponent))] class DelayedMessageIgnoringTimeDilationEngine : Engine { public override void Update(double dt) @@ -754,7 +757,7 @@ namespace Tests [Receives(typeof(MockMessage))] [WritesPending(typeof(MockComponent))] - [Writes(typeof(MockComponent))] + [Writes(typeof(MockComponent), 1)] class ActivateComponentEngine : Engine { public override void Update(double dt) @@ -768,6 +771,7 @@ namespace Tests } [ReadsPending(typeof(MockComponent))] + [Writes(typeof(MockComponent), 0)] class RemoveComponentEngine : Engine { public override void Update(double dt) @@ -780,17 +784,20 @@ namespace Tests } [Test] - public void EngineAddAndRemoveComponentSameFrame() + public void EngineAddAndRemoveComponentSameFrameWithRemovePriority() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ActivateComponentEngine()); worldBuilder.AddEngine(new RemoveComponentEngine()); + worldBuilder.AddEngine(new ReadComponentsTestEngine()); worldBuilder.SendMessage(new MockMessage { }); var world = worldBuilder.Build(); Assert.DoesNotThrow(() => world.Update(0.01)); + world.Update(0.01); // update again for the read + resultComponents.Should().BeEmpty(); } struct DestroyComponentMessage : IMessage { public Entity entity; } @@ -926,6 +933,7 @@ namespace Tests } [Reads(typeof(MockComponent))] + [Writes(typeof(MockComponent))] class RemoveComponentByTypeEngine : Engine { public override void Update(double dt)