component removes are treated as priority writes
parent
51a248156e
commit
7885c2e0f4
|
@ -70,21 +70,34 @@ namespace Encompass
|
||||||
|
|
||||||
public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
ComponentBitSet.Set<TComponent>(entity);
|
if (Lookup<TComponent>().Set(entity, component, priority))
|
||||||
return Lookup<TComponent>().Set(entity, component, priority);
|
{
|
||||||
|
ComponentBitSet.Set<TComponent>(entity);
|
||||||
|
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
|
||||||
{
|
{
|
||||||
ComponentBitSet.RemoveComponent<TComponent>(entity);
|
if (Lookup<TComponent>().Remove(entity, priority))
|
||||||
Lookup<TComponent>().Remove(entity);
|
{
|
||||||
|
ComponentBitSet.RemoveComponent<TComponent>(entity);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForceRemove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
Lookup<TComponent>().ForceRemove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(Entity entity)
|
public void Remove(Entity entity)
|
||||||
{
|
{
|
||||||
foreach (var entry in Stores.Values)
|
foreach (var entry in Stores.Values)
|
||||||
{
|
{
|
||||||
entry.Remove(entity);
|
entry.ForceRemove(entity);
|
||||||
}
|
}
|
||||||
ComponentBitSet.RemoveEntity(entity);
|
ComponentBitSet.RemoveEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ namespace Encompass
|
||||||
public abstract int Count { get; }
|
public abstract int Count { get; }
|
||||||
public abstract IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped();
|
public abstract IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped();
|
||||||
public abstract bool Has(Entity entity);
|
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();
|
public abstract void Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +41,25 @@ namespace Encompass
|
||||||
return false;
|
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)
|
public override bool Has(Entity entity)
|
||||||
{
|
{
|
||||||
return store.ContainsKey(entity);
|
return store.ContainsKey(entity);
|
||||||
|
@ -66,11 +86,5 @@ namespace Encompass
|
||||||
yield return (kvp.Key, typeof(TComponent), (IComponent)kvp.Value);
|
yield return (kvp.Key, typeof(TComponent), (IComponent)kvp.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Remove(Entity entity)
|
|
||||||
{
|
|
||||||
store.Remove(entity);
|
|
||||||
priorities.Remove(entity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,10 +92,24 @@ namespace Encompass
|
||||||
entitiesMarkedForRemoval.Clear();
|
entitiesMarkedForRemoval.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
public bool RemovePending<TComponent>(Entity entity, int priority) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
componentUpdateManager.Remove<TComponent>(entity);
|
if (componentUpdateManager.RemovePending<TComponent>(entity, priority))
|
||||||
drawLayerManager.UnRegisterComponentWithLayer<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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using Encompass.Collections;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -8,7 +6,6 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
internal class ComponentUpdateManager
|
internal class ComponentUpdateManager
|
||||||
{
|
{
|
||||||
private readonly ComponentStore existingAndPendingComponentStore;
|
|
||||||
private readonly ComponentStore existingComponentStore;
|
private readonly ComponentStore existingComponentStore;
|
||||||
private readonly ComponentStore pendingComponentStore;
|
private readonly ComponentStore pendingComponentStore;
|
||||||
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
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)
|
public ComponentUpdateManager(Dictionary<Type, int> typeToIndex)
|
||||||
{
|
{
|
||||||
existingAndPendingComponentStore = new ComponentStore(typeToIndex);
|
|
||||||
existingComponentStore = new ComponentStore(typeToIndex);
|
existingComponentStore = new ComponentStore(typeToIndex);
|
||||||
pendingComponentStore = new ComponentStore(typeToIndex);
|
pendingComponentStore = new ComponentStore(typeToIndex);
|
||||||
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
||||||
|
@ -27,7 +23,6 @@ namespace Encompass
|
||||||
|
|
||||||
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
existingAndPendingComponentStore.RegisterComponentType<TComponent>();
|
|
||||||
existingComponentStore.RegisterComponentType<TComponent>();
|
existingComponentStore.RegisterComponentType<TComponent>();
|
||||||
pendingComponentStore.RegisterComponentType<TComponent>();
|
pendingComponentStore.RegisterComponentType<TComponent>();
|
||||||
UpToDateComponentStore.RegisterComponentType<TComponent>();
|
UpToDateComponentStore.RegisterComponentType<TComponent>();
|
||||||
|
@ -35,7 +30,6 @@ namespace Encompass
|
||||||
|
|
||||||
public void FinishRegistering()
|
public void FinishRegistering()
|
||||||
{
|
{
|
||||||
existingAndPendingComponentStore.FinishRegistering();
|
|
||||||
existingComponentStore.FinishRegistering();
|
existingComponentStore.FinishRegistering();
|
||||||
pendingComponentStore.FinishRegistering();
|
pendingComponentStore.FinishRegistering();
|
||||||
UpToDateComponentStore.FinishRegistering();
|
UpToDateComponentStore.FinishRegistering();
|
||||||
|
@ -43,7 +37,6 @@ namespace Encompass
|
||||||
|
|
||||||
internal void Clear()
|
internal void Clear()
|
||||||
{
|
{
|
||||||
existingAndPendingComponentStore.ClearAll();
|
|
||||||
existingComponentStore.ClearAll();
|
existingComponentStore.ClearAll();
|
||||||
pendingComponentStore.ClearAll();
|
pendingComponentStore.ClearAll();
|
||||||
UpToDateComponentStore.ClearAll();
|
UpToDateComponentStore.ClearAll();
|
||||||
|
@ -77,9 +70,19 @@ namespace Encompass
|
||||||
return false;
|
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
|
private void RegisterExistingOrPendingComponentMessage<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
existingAndPendingComponentStore.Set(entity, component);
|
|
||||||
UpToDateComponentStore.Set(entity, component);
|
UpToDateComponentStore.Set(entity, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +95,7 @@ namespace Encompass
|
||||||
|
|
||||||
internal IEnumerable<(TComponent, Entity)> ReadExistingAndPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
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
|
internal IEnumerable<(TComponent, Entity)> ReadExistingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -135,7 +138,7 @@ namespace Encompass
|
||||||
|
|
||||||
internal bool SomeExistingOrPendingComponent<TComponent>() where TComponent : struct, IComponent
|
internal bool SomeExistingOrPendingComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return existingAndPendingComponentStore.Any<TComponent>();
|
return UpToDateComponentStore.Any<TComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent
|
internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -164,12 +167,12 @@ namespace Encompass
|
||||||
|
|
||||||
internal bool HasExistingOrPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
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)
|
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
|
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
@ -192,11 +195,6 @@ namespace Encompass
|
||||||
return pendingComponentStore.Has(type, entity);
|
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 PendingBits { get { return pendingComponentStore.ComponentBitSet; } }
|
||||||
internal ComponentBitSet ExistingBits { get { return existingComponentStore.ComponentBitSet; } }
|
internal ComponentBitSet ExistingBits { get { return existingComponentStore.ComponentBitSet; } }
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ namespace Encompass
|
||||||
if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity))
|
if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity))
|
||||||
{
|
{
|
||||||
var layer = typeToEntityToLayer[typeof(TComponent)][entity];
|
var layer = typeToEntityToLayer[typeof(TComponent)][entity];
|
||||||
layerIndexToComponentStore[layer].Remove<TComponent>(entity);
|
layerIndexToComponentStore[layer].ForceRemove<TComponent>(entity);
|
||||||
}
|
}
|
||||||
typeToEntityToLayer[typeof(TComponent)].Remove(entity);
|
typeToEntityToLayer[typeof(TComponent)].Remove(entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -561,12 +561,23 @@ namespace Encompass
|
||||||
/// Note that the Engine must Read the Component type that is being removed.
|
/// 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.
|
/// If a Component with the specified type does not exist on the Entity, returns false and does not mutate the Entity.
|
||||||
/// </summary>
|
/// </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);
|
if (!writeTypes.Contains(typeof(TComponent)))
|
||||||
return true;
|
{
|
||||||
|
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>
|
/// <summary>
|
||||||
|
|
|
@ -369,6 +369,7 @@ namespace Tests
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
[Receives(typeof(RemoveComponentTestMessage))]
|
[Receives(typeof(RemoveComponentTestMessage))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class RemoveComponentTestEngine : Engine
|
class RemoveComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
|
|
@ -593,7 +593,8 @@ namespace Tests
|
||||||
Assert.That(results, Does.Not.Contain((mockComponent, entity)));
|
Assert.That(results, Does.Not.Contain((mockComponent, entity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(DestroyerComponent), typeof(MockComponent))]
|
[Reads(typeof(DestroyerComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class DestroyAndAddComponentEngine : Engine
|
class DestroyAndAddComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -665,6 +666,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class DelayedMessageEngine : Engine
|
class DelayedMessageEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -711,6 +713,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class DelayedMessageIgnoringTimeDilationEngine : Engine
|
class DelayedMessageIgnoringTimeDilationEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -754,7 +757,7 @@ namespace Tests
|
||||||
|
|
||||||
[Receives(typeof(MockMessage))]
|
[Receives(typeof(MockMessage))]
|
||||||
[WritesPending(typeof(MockComponent))]
|
[WritesPending(typeof(MockComponent))]
|
||||||
[Writes(typeof(MockComponent))]
|
[Writes(typeof(MockComponent), 1)]
|
||||||
class ActivateComponentEngine : Engine
|
class ActivateComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -768,6 +771,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[ReadsPending(typeof(MockComponent))]
|
[ReadsPending(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent), 0)]
|
||||||
class RemoveComponentEngine : Engine
|
class RemoveComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -780,17 +784,20 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void EngineAddAndRemoveComponentSameFrame()
|
public void EngineAddAndRemoveComponentSameFrameWithRemovePriority()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
worldBuilder.AddEngine(new ActivateComponentEngine());
|
worldBuilder.AddEngine(new ActivateComponentEngine());
|
||||||
worldBuilder.AddEngine(new RemoveComponentEngine());
|
worldBuilder.AddEngine(new RemoveComponentEngine());
|
||||||
|
worldBuilder.AddEngine(new ReadComponentsTestEngine());
|
||||||
|
|
||||||
worldBuilder.SendMessage(new MockMessage { });
|
worldBuilder.SendMessage(new MockMessage { });
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
Assert.DoesNotThrow(() => world.Update(0.01));
|
Assert.DoesNotThrow(() => world.Update(0.01));
|
||||||
|
world.Update(0.01); // update again for the read
|
||||||
|
resultComponents.Should().BeEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DestroyComponentMessage : IMessage { public Entity entity; }
|
struct DestroyComponentMessage : IMessage { public Entity entity; }
|
||||||
|
@ -926,6 +933,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class RemoveComponentByTypeEngine : Engine
|
class RemoveComponentByTypeEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
|
Loading…
Reference in New Issue