component removes are treated as priority writes

pull/5/head
Evan Hemsley 2019-12-23 18:01:49 -08:00
parent 51a248156e
commit 7885c2e0f4
8 changed files with 101 additions and 42 deletions

View File

@ -69,22 +69,35 @@ namespace Encompass
}
public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
{
if (Lookup<TComponent>().Set(entity, component, priority))
{
ComponentBitSet.Set<TComponent>(entity);
return Lookup<TComponent>().Set(entity, component, priority);
return true;
}
return false;
}
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
public bool Remove<TComponent>(Entity entity, int priority) where TComponent : struct, IComponent
{
if (Lookup<TComponent>().Remove(entity, priority))
{
ComponentBitSet.RemoveComponent<TComponent>(entity);
Lookup<TComponent>().Remove(entity);
return true;
}
return false;
}
public void ForceRemove<TComponent>(Entity entity) where TComponent : struct, IComponent
{
Lookup<TComponent>().ForceRemove(entity);
}
public void Remove(Entity entity)
{
foreach (var entry in Stores.Values)
{
entry.Remove(entity);
entry.ForceRemove(entity);
}
ComponentBitSet.RemoveEntity(entity);
}

View File

@ -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);
}
}
}

View File

@ -92,10 +92,24 @@ namespace Encompass
entitiesMarkedForRemoval.Clear();
}
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
public bool RemovePending<TComponent>(Entity entity, int priority) where TComponent : struct, IComponent
{
if (componentUpdateManager.RemovePending<TComponent>(entity, priority))
{
componentUpdateManager.Remove<TComponent>(entity);
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity);
return true;
}
return false;
}
public bool Remove<TComponent>(Entity entity, int priority) where TComponent : struct, IComponent
{
if (componentUpdateManager.Remove<TComponent>(entity, priority))
{
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity);
return true;
}
return false;
}
}
}

View File

@ -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<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
@ -18,7 +15,6 @@ namespace Encompass
public ComponentUpdateManager(Dictionary<Type, int> 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<TComponent>() where TComponent : struct, IComponent
{
existingAndPendingComponentStore.RegisterComponentType<TComponent>();
existingComponentStore.RegisterComponentType<TComponent>();
pendingComponentStore.RegisterComponentType<TComponent>();
UpToDateComponentStore.RegisterComponentType<TComponent>();
@ -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<TComponent>(Entity entity, int priority) where TComponent : struct, IComponent
{
UpToDateComponentStore.Remove<TComponent>(entity, priority);
return pendingComponentStore.Remove<TComponent>(entity, priority);
}
internal bool Remove<TComponent>(Entity entity, int priority) where TComponent : struct, IComponent
{
return UpToDateComponentStore.Remove<TComponent>(entity, priority);
}
private void RegisterExistingOrPendingComponentMessage<TComponent>(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<TComponent>() where TComponent : struct, IComponent
{
return existingAndPendingComponentStore.All<TComponent>();
return UpToDateComponentStore.All<TComponent>();
}
internal IEnumerable<(TComponent, Entity)> ReadExistingComponentsByType<TComponent>() where TComponent : struct, IComponent
@ -135,7 +138,7 @@ namespace Encompass
internal bool SomeExistingOrPendingComponent<TComponent>() where TComponent : struct, IComponent
{
return existingAndPendingComponentStore.Any<TComponent>();
return UpToDateComponentStore.Any<TComponent>();
}
internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent
@ -164,12 +167,12 @@ namespace Encompass
internal bool HasExistingOrPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return existingAndPendingComponentStore.Has<TComponent>(entity);
return UpToDateComponentStore.Has<TComponent>(entity);
}
internal bool HasExistingOrPendingComponent(Entity entity, Type type)
{
return existingAndPendingComponentStore.Has(type, entity);
return UpToDateComponentStore.Has(type, entity);
}
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
@ -192,11 +195,6 @@ namespace Encompass
return pendingComponentStore.Has(type, entity);
}
internal void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
{
UpToDateComponentStore.Remove<TComponent>(entity);
}
internal ComponentBitSet PendingBits { get { return pendingComponentStore.ComponentBitSet; } }
internal ComponentBitSet ExistingBits { get { return existingComponentStore.ComponentBitSet; } }
}

View File

@ -96,7 +96,7 @@ namespace Encompass
if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity))
{
var layer = typeToEntityToLayer[typeof(TComponent)][entity];
layerIndexToComponentStore[layer].Remove<TComponent>(entity);
layerIndexToComponentStore[layer].ForceRemove<TComponent>(entity);
}
typeToEntityToLayer[typeof(TComponent)].Remove(entity);
}

View File

@ -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.
/// </summary>
protected bool RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
protected void RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (!HasComponent<TComponent>(entity)) { return false; }
var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority;
componentManager.Remove<TComponent>(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<TComponent>(entity, priority);
}
else
{
componentManager.Remove<TComponent>(entity, priority);
}
}
/// <summary>

View File

@ -369,6 +369,7 @@ namespace Tests
[Reads(typeof(MockComponent))]
[Receives(typeof(RemoveComponentTestMessage))]
[Writes(typeof(MockComponent))]
class RemoveComponentTestEngine : Engine
{
public override void Update(double dt)

View File

@ -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)