allow only one component per type per entity

pull/5/head
Evan Hemsley 2019-08-10 17:34:00 -07:00
parent 314a064b4e
commit c1e206ef49
11 changed files with 221 additions and 269 deletions

View File

@ -15,12 +15,12 @@ namespace Encompass
private readonly Dictionary<Guid, PooledSet<Guid>> entityIDToComponentIDs = new Dictionary<Guid, PooledSet<Guid>>();
private readonly Dictionary<Guid, Guid> componentIDToEntityID = new Dictionary<Guid, Guid>();
private readonly Dictionary<Guid, PooledDictionary<Type, HashSet<Guid>>> entityIDToComponentTypeToComponentIDs = new Dictionary<Guid, PooledDictionary<Type, HashSet<Guid>>>();
private readonly Dictionary<Guid, PooledDictionary<Type, Guid>> entityIDToComponentTypeToComponentID = new Dictionary<Guid, PooledDictionary<Type, Guid>>();
private readonly Dictionary<Type, HashSet<Guid>> typeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
private readonly List<(Entity, Type, Guid, IComponent)> componentAddData = new List<(Entity, Type, Guid, IComponent)>();
private readonly HashSet<Guid> componentsMarkedForRemoval = new HashSet<Guid>();
private readonly Dictionary<Guid, IComponent> pendingUpdates = new Dictionary<Guid, IComponent>();
public ComponentManager(DrawLayerManager drawLayerManager)
@ -31,44 +31,62 @@ namespace Encompass
internal void RegisterEntity(Guid entityID)
{
entityIDToComponentIDs.Add(entityID, new PooledSet<Guid>());
entityIDToComponentTypeToComponentIDs.Add(entityID, new PooledDictionary<Type, HashSet<Guid>>(ClearMode.Never));
entityIDToComponentTypeToComponentID.Add(entityID, new PooledDictionary<Type, Guid>());
}
internal Guid NextID()
private Guid NextID()
{
return Guid.NewGuid();
}
internal Guid AddComponent<TComponent>(Entity entity, Guid componentID, TComponent component) where TComponent : struct, IComponent
internal Guid MarkComponentForAdd<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
{
var id = NextID();
componentAddData.Add((entity, typeof(TComponent), id, component));
return id;
}
internal Guid MarkDrawComponentForAdd<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
{
var id = MarkComponentForAdd(entity, component);
drawLayerManager.RegisterComponentWithLayer(id, layer);
return id;
}
internal void AddComponent(Entity entity, Type type, Guid componentID, IComponent component)
{
IDToComponent[componentID] = component;
componentIDToType[componentID] = typeof(TComponent);
componentIDToType[componentID] = type;
if (!typeToComponentIDs.ContainsKey(typeof(TComponent)))
if (!typeToComponentIDs.ContainsKey(type))
{
typeToComponentIDs.Add(typeof(TComponent), new HashSet<Guid>());
typeToComponentIDs.Add(type, new HashSet<Guid>());
}
typeToComponentIDs[typeof(TComponent)].Add(componentID);
typeToComponentIDs[type].Add(componentID);
entityIDToComponentIDs[entity.ID].Add(componentID);
if (!entityIDToComponentTypeToComponentIDs[entity.ID].ContainsKey(typeof(TComponent))) {
entityIDToComponentTypeToComponentIDs[entity.ID].Add(typeof(TComponent), new HashSet<Guid>());
if (!entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(type))
{
entityIDToComponentTypeToComponentID[entity.ID][type] = componentID;
}
else
{
throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", entity.ID, type.Name);
}
entityIDToComponentTypeToComponentIDs[entity.ID][typeof(TComponent)].Add(componentID);
componentIDToEntityID[componentID] = entity.ID;
return componentID;
}
internal Guid AddDrawComponent<TComponent>(Entity entity, Guid componentID, TComponent component, int layer = 0) where TComponent : struct, IComponent
internal void AddMarkedComponents()
{
AddComponent(entity, componentID, component);
drawLayerManager.RegisterComponentWithLayer(componentID, layer);
return componentID;
}
foreach (var (entity, type, componentID, component) in componentAddData)
{
AddComponent(entity, type, componentID, component);
}
componentAddData.Clear();
}
internal IEnumerable<Guid> GetComponentIDsByEntityID(Guid entityID)
{
@ -88,23 +106,19 @@ namespace Encompass
return Enumerable.Empty<(Guid, TComponent)>();
}
internal IEnumerable<ValueTuple<Guid, TComponent>> GetComponentsByEntityAndType<TComponent>(Guid entityID) where TComponent : struct, IComponent
internal (Guid, TComponent) GetComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityIDToComponentTypeToComponentIDs.ContainsKey(entityID) && entityIDToComponentTypeToComponentIDs[entityID].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
if (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].TryGetValue(typeof(TComponent), out Guid id))
{
return idSet.Select(id => (id, (TComponent)IDToComponent[id]));
return (id, (TComponent)IDToComponent[id]);
}
return Enumerable.Empty<(Guid, TComponent)>();
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID);
}
internal bool EntityHasComponentOfType<TComponent>(Guid entityID) where TComponent : struct, IComponent
internal bool EntityHasComponentOfType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityIDToComponentTypeToComponentIDs.ContainsKey(entityID) && entityIDToComponentTypeToComponentIDs[entityID].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
return (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(typeof(TComponent)));
}
internal bool ComponentOfTypeExists<TComponent>() where TComponent : struct, IComponent
@ -185,6 +199,11 @@ namespace Encompass
entityIDToComponentIDs[entityID].Remove(componentID);
}
if (entityIDToComponentTypeToComponentID.ContainsKey(entityID))
{
entityIDToComponentTypeToComponentID[entityID].Remove(type);
}
IDToComponent.Remove(componentID);
componentIDToType.Remove(componentID);
componentIDToEntityID.Remove(componentID);
@ -198,12 +217,8 @@ namespace Encompass
entityIDToComponentIDs[entityID].Dispose();
entityIDToComponentIDs.Remove(entityID);
foreach (var set in entityIDToComponentTypeToComponentIDs[entityID].Values)
{
set.Clear();
}
entityIDToComponentTypeToComponentIDs[entityID].Dispose();
entityIDToComponentTypeToComponentIDs.Remove(entityID);
entityIDToComponentTypeToComponentID[entityID].Dispose();
entityIDToComponentTypeToComponentID.Remove(entityID);
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Collections.Pooled;
using Encompass.Exceptions;
namespace Encompass
{
@ -13,39 +14,27 @@ namespace Encompass
private readonly Dictionary<Type, HashSet<Guid>> componentMessageTypeToPendingComponentIDs = new Dictionary<Type, HashSet<Guid>>();
private readonly Dictionary<Type, HashSet<Guid>> componentMessageTypeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, HashSet<Guid>>> entityToTypeToExistingComponentIDs = new Dictionary<Entity, PooledDictionary<Type, HashSet<Guid>>>();
private readonly Dictionary<Entity, PooledDictionary<Type, HashSet<Guid>>> entityToTypeToPendingComponentIDs = new Dictionary<Entity, PooledDictionary<Type, HashSet<Guid>>>();
private readonly Dictionary<Entity, PooledDictionary<Type, HashSet<Guid>>> entityToTypeToComponentIDs = new Dictionary<Entity, PooledDictionary<Type, HashSet<Guid>>>();
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToExistingComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToPendingComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
internal void RegisterEntity(Entity entity)
{
entityToTypeToComponentIDs[entity] = new PooledDictionary<Type, HashSet<Guid>>(ClearMode.Never);
entityToTypeToPendingComponentIDs[entity] = new PooledDictionary<Type, HashSet<Guid>>(ClearMode.Never);
entityToTypeToExistingComponentIDs[entity] = new PooledDictionary<Type, HashSet<Guid>>(ClearMode.Never);
entityToTypeToComponentID[entity] = new PooledDictionary<Type, Guid>();
entityToTypeToPendingComponentID[entity] = new PooledDictionary<Type, Guid>();
entityToTypeToExistingComponentID[entity] = new PooledDictionary<Type, Guid>();
}
internal void RegisterDestroyedEntity(Entity entity)
{
foreach (var set in entityToTypeToComponentIDs[entity].Values)
{
set.Clear();
}
entityToTypeToComponentIDs[entity].Dispose();
entityToTypeToComponentIDs.Remove(entity);
entityToTypeToComponentID[entity].Dispose();
entityToTypeToComponentID.Remove(entity);
foreach (var set in entityToTypeToPendingComponentIDs[entity].Values)
{
set.Clear();
}
entityToTypeToPendingComponentIDs[entity].Dispose();
entityToTypeToPendingComponentIDs.Remove(entity);
entityToTypeToPendingComponentID[entity].Dispose();
entityToTypeToPendingComponentID.Remove(entity);
foreach (var set in entityToTypeToExistingComponentIDs[entity].Values)
{
set.Clear();
}
entityToTypeToExistingComponentIDs[entity].Dispose();
entityToTypeToExistingComponentIDs.Remove(entity);
entityToTypeToExistingComponentID[entity].Dispose();
entityToTypeToExistingComponentID.Remove(entity);
}
internal void ClearMessages()
@ -67,28 +56,19 @@ namespace Encompass
set.Clear();
}
foreach (var dictionary in entityToTypeToExistingComponentIDs.Values)
foreach (var dictionary in entityToTypeToExistingComponentID.Values)
{
foreach (var set in dictionary.Values)
{
set.Clear();
}
dictionary.Clear();
}
foreach (var dictionary in entityToTypeToPendingComponentIDs.Values)
foreach (var dictionary in entityToTypeToPendingComponentID.Values)
{
foreach (var set in dictionary.Values)
{
set.Clear();
}
dictionary.Clear();
}
foreach (var dictionary in entityToTypeToComponentIDs.Values)
foreach (var dictionary in entityToTypeToComponentID.Values)
{
foreach (var set in dictionary.Values)
{
set.Clear();
}
dictionary.Clear();
}
}
@ -103,12 +83,14 @@ namespace Encompass
componentMessageTypeToExistingComponentIDs[typeof(TComponent)].Add(componentMessage.componentID);
if (!entityToTypeToExistingComponentIDs[componentMessage.entity].ContainsKey(typeof(TComponent)))
if (!entityToTypeToExistingComponentID[componentMessage.entity].ContainsKey(typeof(TComponent)))
{
entityToTypeToExistingComponentIDs[componentMessage.entity].Add(typeof(TComponent), new HashSet<Guid>());
entityToTypeToExistingComponentID[componentMessage.entity].Add(typeof(TComponent), componentMessage.componentID);
}
else
{
throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", componentMessage.entity.ID, typeof(TComponent).Name);
}
entityToTypeToExistingComponentIDs[componentMessage.entity][typeof(TComponent)].Add(componentMessage.componentID);
}
internal void AddPendingComponentMessage<TComponent>(PendingComponentMessage<TComponent> pendingComponentMessage) where TComponent : struct, IComponent
@ -122,12 +104,14 @@ namespace Encompass
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
if (!entityToTypeToPendingComponentIDs[pendingComponentMessage.entity].ContainsKey(typeof(TComponent)))
if (!entityToTypeToPendingComponentID[pendingComponentMessage.entity].ContainsKey(typeof(TComponent)))
{
entityToTypeToPendingComponentIDs[pendingComponentMessage.entity].Add(typeof(TComponent), new HashSet<Guid>());
entityToTypeToPendingComponentID[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.componentID);
}
else
{
throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", pendingComponentMessage.entity.ID, typeof(TComponent).Name);
}
entityToTypeToPendingComponentIDs[pendingComponentMessage.entity][typeof(TComponent)].Add(pendingComponentMessage.componentID);
}
private void RegisterExistingOrPendingComponentMessage<TComponent>(Entity entity, Guid componentID, TComponent component) where TComponent: struct, IComponent
@ -140,12 +124,14 @@ namespace Encompass
}
componentMessageTypeToComponentIDs[typeof(TComponent)].Add(componentID);
if (!entityToTypeToComponentIDs[entity].ContainsKey(typeof(TComponent)))
if (!entityToTypeToComponentID[entity].ContainsKey(typeof(TComponent)))
{
entityToTypeToComponentIDs[entity].Add(typeof(TComponent), new HashSet<Guid>());
entityToTypeToComponentID[entity].Add(typeof(TComponent), componentID);
}
else
{
throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", entity.ID, typeof(TComponent).Name);
}
entityToTypeToComponentIDs[entity][typeof(TComponent)].Add(componentID);
}
// general component reads by type
@ -231,83 +217,45 @@ namespace Encompass
// read components by entity and type
internal IEnumerable<(Guid, TComponent)> ReadExistingAndPendingComponentsByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
internal (Guid, TComponent) ReadExistingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityToTypeToComponentIDs.ContainsKey(entity) && entityToTypeToComponentIDs[entity].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
if (entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id))
{
return idSet.Select(id => (id, (TComponent)componentIDToComponent[id]));
return (id, (TComponent)componentIDToComponent[id]);
}
return Enumerable.Empty<(Guid, TComponent)>();
}
internal IEnumerable<(Guid, TComponent)> ReadExistingComponentsByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityToTypeToExistingComponentIDs.ContainsKey(entity) && entityToTypeToExistingComponentIDs[entity].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
else
{
return idSet.Select(id => (id, (TComponent)componentIDToComponent[id]));
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID);
}
return Enumerable.Empty<(Guid, TComponent)>();
}
internal IEnumerable<(Guid, TComponent)> ReadPendingComponentsByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
internal (Guid, TComponent) ReadPendingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityToTypeToPendingComponentIDs.ContainsKey(entity) && entityToTypeToPendingComponentIDs[entity].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id))
{
return idSet.Select(id => (id, (TComponent)componentIDToComponent[id]));
return (id, (TComponent)componentIDToComponent[id]);
}
else
{
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID);
}
return Enumerable.Empty<(Guid, TComponent)>();
}
// singular read components by entity and type
internal (Guid, TComponent) ReadFirstExistingOrPendingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return ReadExistingAndPendingComponentsByEntityAndType<TComponent>(entity).First();
}
internal (Guid, TComponent) ReadFirstExistingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return ReadExistingComponentsByEntityAndType<TComponent>(entity).First();
}
internal (Guid, TComponent) ReadFirstPendingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return ReadPendingComponentsByEntityAndType<TComponent>(entity).First();
}
// check if entity has component of type
internal bool HasExistingOrPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityToTypeToComponentIDs.TryGetValue(entity, out _) && entityToTypeToComponentIDs[entity].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
return entityToTypeToComponentID.ContainsKey(entity) && entityToTypeToComponentID[entity].ContainsKey(typeof(TComponent));
}
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityToTypeToExistingComponentIDs.TryGetValue(entity, out _) && entityToTypeToExistingComponentIDs[entity].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(typeof(TComponent));
}
internal bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (entityToTypeToPendingComponentIDs.TryGetValue(entity, out _) && entityToTypeToPendingComponentIDs[entity].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
return entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].ContainsKey(typeof(TComponent));
}
}
}

View File

@ -119,9 +119,7 @@ namespace Encompass
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
{
var componentID = componentManager.NextID();
componentManager.AddComponent(entity, componentID, component);
var componentID = componentManager.MarkComponentForAdd(entity, component);
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
{
@ -138,9 +136,7 @@ namespace Encompass
protected Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
{
var componentID = componentManager.NextID();
componentManager.AddDrawComponent(entity, componentID, component, layer);
var componentID = componentManager.MarkDrawComponentForAdd(entity, component, layer);
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
{
@ -221,43 +217,21 @@ namespace Encompass
}
}
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
{
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
if (existingRead && pendingRead)
{
return componentMessageManager.ReadExistingAndPendingComponentsByEntityAndType<TComponent>(entity);
}
else if (existingRead)
{
return componentMessageManager.ReadExistingComponentsByEntityAndType<TComponent>(entity);
}
else if (pendingRead)
{
return componentMessageManager.ReadPendingComponentsByEntityAndType<TComponent>(entity);
}
else
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
}
}
protected ValueTuple<Guid, TComponent> GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
if (existingRead && pendingRead)
{
return componentMessageManager.ReadFirstExistingOrPendingComponentByEntityAndType<TComponent>(entity);
return componentMessageManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
}
else if (existingRead)
{
return componentMessageManager.ReadFirstExistingComponentByEntityAndType<TComponent>(entity);
return componentMessageManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
}
else if (pendingRead)
{
return componentMessageManager.ReadFirstPendingComponentByEntityAndType<TComponent>(entity);
return componentMessageManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
}
else
{

View File

@ -0,0 +1,12 @@
using System;
namespace Encompass.Exceptions
{
public class MultipleComponentOfSameTypeException : Exception
{
public MultipleComponentOfSameTypeException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace Encompass.Exceptions
{
public class NoComponentOfTypeOnEntityException : Exception
{
public NoComponentOfTypeOnEntityException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -49,19 +49,14 @@ namespace Encompass
return ReadComponents<TComponent>().First();
}
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();
return componentManager.GetComponentByEntityAndType<TComponent>(entity);
}
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return componentManager.EntityHasComponentOfType<TComponent>(entity.ID);
return componentManager.EntityHasComponentOfType<TComponent>(entity);
}
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent

View File

@ -41,6 +41,7 @@ namespace Encompass
componentManager.PerformComponentUpdates();
componentManager.RemoveMarkedComponents();
componentManager.AddMarkedComponents();
}
public void Draw()

View File

@ -47,14 +47,12 @@ namespace Encompass
public Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
{
var componentID = componentManager.NextID();
return componentManager.AddComponent(entity, componentID, component);
return componentManager.MarkComponentForAdd(entity, component);
}
public Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
{
var componentID = componentManager.NextID();
return componentManager.AddDrawComponent(entity, componentID, component, layer);
return componentManager.MarkDrawComponentForAdd(entity, component, layer);
}
internal void RegisterComponent(Type componentType)
@ -256,6 +254,7 @@ namespace Encompass
componentManager.PerformComponentUpdates();
componentManager.RemoveMarkedComponents();
componentManager.AddMarkedComponents();
return world;
}

View File

@ -5,6 +5,7 @@ using Encompass;
using System.Collections.Generic;
using System;
using System.Linq;
using Encompass.Exceptions;
namespace Tests
{
@ -81,6 +82,78 @@ namespace Tests
world.Update(0.01);
}
[Test]
public void AddMultipleComponentOfSameTypeToEntity()
{
var worldBuilder = new WorldBuilder();
MockComponent mockComponent;
mockComponent.myInt = 3;
mockComponent.myString = "hello";
var entity = worldBuilder.CreateEntity();
worldBuilder.AddComponent(entity, mockComponent);
worldBuilder.AddComponent(entity, mockComponent);
Assert.Throws<MultipleComponentOfSameTypeException>(() => worldBuilder.Build());
}
[Reads(typeof(MockComponent))]
class MultipleAddEngine : Engine
{
public override void Update(double dt)
{
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
{
var entity = GetEntityByComponentID(mockComponentID);
AddComponent(entity, new MockComponent());
}
}
}
[Test]
public void EngineAddMultipleComponentOfSameTypeToEntity()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new MultipleAddEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.AddComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.Throws<MultipleComponentOfSameTypeException>(() => world.Update(0.01));
}
[Reads(typeof(MockComponent))]
class AddAndRemoveComponentEngine : Engine
{
public override void Update(double dt)
{
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
{
var entity = GetEntityByComponentID(mockComponentID);
AddComponent(entity, mockComponent);
RemoveComponent(mockComponentID);
}
}
}
[Test]
public void AddMultipleComponentSameFrameAsRemove()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new AddAndRemoveComponentEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.AddComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.DoesNotThrow(() => world.Update(0.01));
}
struct AddMockComponentMessage : IMessage
{
public Entity entity;
@ -154,89 +227,6 @@ namespace Tests
world.Update(0.01);
}
[Receives(typeof(EntityMessage))]
[Reads(typeof(MockComponent))]
class GetMockComponentsEngine : Engine
{
private Entity entity;
private Guid componentAID;
private Guid componentBID;
private Guid componentCID;
private MockComponent componentA;
private MockComponent componentB;
private MockComponent componentC;
public GetMockComponentsEngine(
Entity entity,
Guid componentAID,
MockComponent componentA,
Guid componentBID,
MockComponent componentB,
Guid componentCID,
MockComponent componentC
) {
this.entity = entity;
this.componentAID = componentAID;
this.componentA = componentA;
this.componentBID = componentBID;
this.componentB = componentB;
this.componentCID = componentCID;
this.componentC = componentC;
}
public override void Update(double dt)
{
foreach (var entityMessage in ReadMessages<EntityMessage>())
{
var results = GetComponents<MockComponent>(entityMessage.entity);
results.Should().Contain((componentAID, componentA));
results.Should().Contain((componentBID, componentB));
results.Should().Contain((componentCID, componentC));
}
}
}
[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 = worldBuilder.AddComponent(entity, mockComponentA);
var componentBID = worldBuilder.AddComponent(entity, mockComponentB);
var componentCID = worldBuilder.AddComponent(entity, mockComponentC);
worldBuilder.AddEngine(new GetMockComponentsEngine(
entity,
componentAID,
mockComponentA,
componentBID,
mockComponentB,
componentCID,
mockComponentC
));
EntityMessage entityMessage;
entityMessage.entity = entity;
worldBuilder.SendMessage(entityMessage);
var world = worldBuilder.Build();
world.Update(0.01);
}
[Test]
public void GetComponent()
{

View File

@ -49,6 +49,7 @@ namespace Tests
worldBuilder.AddEngine(new ReadComponentsTestEngine());
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
MockComponent mockComponent;
mockComponent.myInt = 0;
@ -59,7 +60,7 @@ namespace Tests
mockComponentB.myString = "howdy";
var componentAID = worldBuilder.AddComponent(entity, mockComponent);
var componentBID = worldBuilder.AddComponent(entity, mockComponentB);
var componentBID = worldBuilder.AddComponent(entityB, mockComponentB);
var world = worldBuilder.Build();
@ -98,6 +99,7 @@ namespace Tests
worldBuilder.AddEngine(new ReadComponentTestEngine());
var entity = worldBuilder.CreateEntity();
var entityB = worldBuilder.CreateEntity();
MockComponent mockComponent;
mockComponent.myInt = 0;
@ -108,7 +110,7 @@ namespace Tests
mockComponentB.myString = "howdy";
worldBuilder.AddComponent(entity, mockComponent);
worldBuilder.AddComponent(entity, mockComponentB);
worldBuilder.AddComponent(entityB, mockComponentB);
var world = worldBuilder.Build();
@ -390,7 +392,9 @@ namespace Tests
var entity = worldBuilder.CreateEntity();
worldBuilder.AddComponent(entity, componentA);
worldBuilder.AddComponent(entity, componentB);
var entityB = worldBuilder.CreateEntity();
worldBuilder.AddComponent(entityB, componentB);
var world = worldBuilder.Build();
world.Update(0.01f);

View File

@ -53,7 +53,9 @@ namespace Tests
var entity = worldBuilder.CreateEntity();
var componentID = worldBuilder.AddComponent(entity, aComponent);
var componentTwoID = worldBuilder.AddComponent(entity, aComponentTwo);
var entityB = worldBuilder.CreateEntity();
var componentTwoID = worldBuilder.AddComponent(entityB, aComponentTwo);
var world = worldBuilder.Build();
world.Update(0.01f);