component writes moved back to end of frame

pull/5/head
thatcosmonaut 2019-07-17 18:12:29 -07:00
parent 1016f05d42
commit f960712f57
11 changed files with 248 additions and 144 deletions

View File

@ -14,9 +14,9 @@ namespace Encompass
{
foreach (var readType in readTypes)
{
if (!readType.GetInterfaces().Contains(typeof(IMessage)) && !readType.GetInterfaces().Contains(typeof(IComponent)))
if (!readType.GetInterfaces().Contains(typeof(IMessage)))
{
throw new IllegalReadTypeException("{0} must be a Message or Component", readType.Name);
throw new IllegalReadTypeException("{0} must be a Message", readType.Name);
}
}

View File

@ -20,6 +20,11 @@ namespace Encompass
}
}
if (writeTypes.Any((type) => type.GetInterfaces().Contains(typeof(IMessage))) && writeTypes.Any((type) => type.GetInterfaces().Contains(typeof(IComponent))))
{
throw new ComponentAndMessageWriteException("An Engine which writes Components cannot also write Messages");
}
this.writeTypes = new HashSet<Type>(writeTypes);
}
}

View File

@ -10,14 +10,18 @@ namespace Encompass
private readonly Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>();
private readonly Dictionary<Guid, IComponent> IDToComponent = new Dictionary<Guid, IComponent>();
private readonly Dictionary<Guid, List<Guid>> entityIDToComponentIDs = new Dictionary<Guid, List<Guid>>();
private readonly Dictionary<Guid, List<Guid>> entityIDToComponentIDs = new Dictionary<Guid, List<Guid>>(); // TODO: hashset
private readonly Dictionary<Guid, Guid> componentIDToEntityID = new Dictionary<Guid, Guid>();
private readonly Dictionary<Type, List<Guid>> typeToComponentIDs = new Dictionary<Type, List<Guid>>();
private readonly Dictionary<Type, List<Guid>> typeToComponentIDs = new Dictionary<Type, List<Guid>>(); // TODO: hashset
private readonly List<Guid> activeComponents = new List<Guid>();
private readonly List<Guid> inactiveComponents = new List<Guid>();
private readonly HashSet<Guid> componentsMarkedForActivation = new HashSet<Guid>();
private readonly HashSet<Guid> componentsMarkedForDeactivation = new HashSet<Guid>();
private readonly HashSet<Guid> componentsMarkedForRemoval = new HashSet<Guid>();
//shared references with EntityManager
private readonly HashSet<Guid> entitiesWithAddedComponents;
private readonly HashSet<Guid> entitiesWithRemovedComponents;
@ -56,7 +60,7 @@ namespace Encompass
componentIDToEntityID[componentID] = entityID;
inactiveComponents.Add(componentID);
Activate(componentID);
MarkForActivation(componentID);
entitiesWithAddedComponents.Add(entityID);
@ -150,17 +154,30 @@ namespace Encompass
IDToComponent[componentID] = newComponentValue;
}
internal void RemoveAllComponentsFromEntity(Guid entityID)
internal void MarkAllComponentsOnEntityForRemoval(Guid entityID)
{
var componentIDs = entityIDToComponentIDs[entityID];
for (int i = componentIDs.Count - 1; i >= 0; i--)
foreach (var componentID in GetComponentIDsByEntityID(entityID))
{
Remove(componentIDs[i]);
MarkForRemoval(componentID);
}
}
internal void Activate(Guid componentID)
internal void MarkForActivation(Guid componentID)
{
componentsMarkedForActivation.Add(componentID);
}
internal void ActivateMarkedComponents()
{
foreach (var componentID in componentsMarkedForActivation)
{
Activate(componentID);
}
componentsMarkedForActivation.Clear();
}
private void Activate(Guid componentID)
{
if (inactiveComponents.Remove(componentID))
{
@ -171,7 +188,22 @@ namespace Encompass
entitiesWithAddedComponents.Add(entityID);
}
internal void Deactivate(Guid componentID)
internal void MarkForDeactivation(Guid componentID)
{
componentsMarkedForDeactivation.Add(componentID);
}
internal void DeactivateMarkedComponents()
{
foreach (var componentID in componentsMarkedForDeactivation)
{
Deactivate(componentID);
}
componentsMarkedForDeactivation.Clear();
}
private void Deactivate(Guid componentID)
{
if (activeComponents.Remove(componentID))
{
@ -182,7 +214,22 @@ namespace Encompass
entitiesWithRemovedComponents.Add(entityID);
}
internal void Remove(Guid componentID)
internal void MarkForRemoval(Guid componentID)
{
componentsMarkedForRemoval.Add(componentID);
}
internal void RemoveMarkedComponents()
{
foreach (var componentID in componentsMarkedForRemoval)
{
Remove(componentID);
}
componentsMarkedForRemoval.Clear();
}
private void Remove(Guid componentID)
{
var component = IDToComponent[componentID];
var type = componentIDToType[componentID];

View File

@ -74,11 +74,6 @@ namespace Encompass
protected TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent
{
if (!readTypes.Contains(typeof(TComponent)))
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
if (componentManager.GetComponentTypeByID(componentID) != typeof(TComponent))
{
throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentManager.GetComponentTypeByID(componentID).Name);
@ -89,73 +84,36 @@ namespace Encompass
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
{
if (!readTypes.Contains(typeof(TComponent)))
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.GetActiveComponentsByType<TComponent>();
}
protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent
{
if (!readTypes.Contains(typeof(TComponent)))
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.GetActiveComponentByType<TComponent>();
}
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
{
if (!writeTypes.Contains(typeof(TComponent)))
{
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.AddComponent(entity.ID, component);
}
protected Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
{
if (!writeTypes.Contains(typeof(TComponent)))
{
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.AddDrawComponent(entity.ID, component, layer);
}
protected void ActivateComponent(Guid componentID)
{
var type = componentManager.GetComponentTypeByID(componentID);
if (!writeTypes.Contains(type))
{
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, type.Name);
}
componentManager.Activate(componentID);
componentManager.MarkForActivation(componentID);
}
protected void DeactivateComponent(Guid componentID)
{
var type = componentManager.GetComponentTypeByID(componentID);
if (!writeTypes.Contains(type))
{
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, type.Name);
}
componentManager.Deactivate(componentID);
componentManager.MarkForDeactivation(componentID);
}
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (!readTypes.Contains(typeof(TComponent)))
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.GetComponentsByEntityAndType<TComponent>(entity.ID);
}
@ -166,11 +124,6 @@ namespace Encompass
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
if (!readTypes.Contains(typeof(TComponent)))
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.EntityHasComponentOfType<TComponent>(entity.ID);
}
@ -193,11 +146,10 @@ namespace Encompass
{
if (!writeTypes.Contains(typeof(TMessage)))
{
throw new IllegalWriteException("Engine {0} tried to emit undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
throw new IllegalWriteException("Engine {0} tried to write undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
}
messageManager.AddMessage(message);
}
protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
@ -222,11 +174,6 @@ namespace Encompass
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
{
if (!readTypes.Contains(typeof(TComponent)))
{
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
}
return componentManager.GetActiveComponentsByType<TComponent>().Any();
}
@ -237,13 +184,7 @@ namespace Encompass
protected void RemoveComponent(Guid componentID)
{
var type = componentManager.GetComponentTypeByID(componentID);
if (!writeTypes.Contains(type))
{
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, type.Name);
}
componentManager.Remove(componentID);
componentManager.MarkForRemoval(componentID);
}
}
}

View File

@ -56,7 +56,7 @@ namespace Encompass
{
foreach (var entityID in entitiesMarkedForDestroy)
{
componentManager.RemoveAllComponentsFromEntity(entityID);
componentManager.MarkAllComponentsOnEntityForRemoval(entityID);
IDToEntity.Remove(entityID);
entityToEntityTrackers.Remove(entityID);
componentManager.RegisterDestroyedEntity(entityID);

View File

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

View File

@ -35,6 +35,10 @@ namespace Encompass
messageManager.ClearMessages();
entityManager.DestroyMarkedEntities();
componentManager.ActivateMarkedComponents();
componentManager.DeactivateMarkedComponents();
componentManager.RemoveMarkedComponents();
entityManager.CheckEntitiesWithAddedComponents();
entityManager.CheckEntitiesWithRemovedComponents();
}

View File

@ -53,7 +53,7 @@ namespace Encompass
public void DeactivateComponent(Guid componentID)
{
componentManager.Deactivate(componentID);
componentManager.MarkForDeactivation(componentID);
}
public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
@ -65,12 +65,7 @@ namespace Encompass
engines.Add(engine);
engineGraph.AddVertex(engine);
if (engine is IEntityTracker)
{
entityManager.RegisterEntityTracker(engine as IEntityTracker);
}
foreach (var writeType in engine.writeTypes)
foreach (var writeType in engine.writeTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))))
{
if (!typeToEmitters.ContainsKey(writeType))
{
@ -98,7 +93,7 @@ namespace Encompass
}
}
foreach (var readType in engine.readTypes)
foreach (var readType in engine.readTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))))
{
if (!typeToReaders.ContainsKey(readType))
{
@ -229,6 +224,10 @@ namespace Encompass
renderManager
);
componentManager.ActivateMarkedComponents();
componentManager.DeactivateMarkedComponents();
componentManager.RemoveMarkedComponents();
entityManager.CheckEntitiesWithAddedComponents();
entityManager.CheckEntitiesWithRemovedComponents();

View File

@ -24,7 +24,7 @@ namespace Tests
static IEnumerable<(Guid, MockComponent)> gottenMockComponentIDPairs = Enumerable.Empty<(Guid, MockComponent)>();
static (Guid, MockComponent) gottenMockComponentIDPair;
[Reads(typeof(EntityMessage), typeof(MockComponent))]
[Reads(typeof(EntityMessage))]
class GetMockComponentsEngine : Engine
{
public override void Update(double dt)
@ -38,7 +38,7 @@ namespace Tests
}
}
[Reads(typeof(EntityMessage), typeof(MockComponent))]
[Reads(typeof(EntityMessage))]
class GetMockComponentEngine : Engine
{
public override void Update(double dt)
@ -56,7 +56,7 @@ namespace Tests
public MockComponent mockComponent;
}
[Reads(typeof(AddComponentTestMessage), typeof(MockComponent))]
[Reads(typeof(AddComponentTestMessage))]
class AddComponentEngine : Engine
{
public override void Update(double dt)
@ -161,7 +161,7 @@ namespace Tests
public Entity entity;
}
[Reads(typeof(HasComponentTestMessage), typeof(MockComponent))]
[Reads(typeof(HasComponentTestMessage))]
class HasComponentTestEngine : Engine
{
public override void Update(double dt)
@ -201,7 +201,7 @@ namespace Tests
public Entity entity;
}
[Reads(typeof(HasComponentWhenInactiveTestMessage), typeof(MockComponent))]
[Reads(typeof(HasComponentWhenInactiveTestMessage))]
class HasComponentWhenInactiveTestEngine : Engine
{
public override void Update(double dt)
@ -243,7 +243,7 @@ namespace Tests
public Guid componentID;
}
[Reads(typeof(RemoveComponentTestMessage), typeof(MockComponent))]
[Reads(typeof(RemoveComponentTestMessage))]
[Writes(typeof(MockComponent))]
class RemoveComponentTestEngine : Engine
{
@ -252,9 +252,36 @@ namespace Tests
foreach (var removeComponentMessage in ReadMessages<RemoveComponentTestMessage>())
{
RemoveComponent(removeComponentMessage.componentID);
}
}
}
Assert.IsFalse(HasComponent<MockComponent>(removeComponentMessage.entity));
Assert.IsEmpty(GetComponents<MockComponent>(removeComponentMessage.entity));
[Reads(typeof(RemoveComponentTestMessage))]
[Writes(typeof(CheckHasMockComponentMessage))]
class DoRemoveCheckEngine : Engine
{
private Entity entity;
public DoRemoveCheckEngine(Entity entity)
{
this.entity = entity;
}
public override void Update(double dt)
{
if (SomeMessage<RemoveComponentTestMessage>())
{
CheckHasMockComponentMessage checkHasMockComponentMessage;
checkHasMockComponentMessage.entity = entity;
checkHasMockComponentMessage.shouldHaveComponent = true;
EmitMessage(checkHasMockComponentMessage);
}
else
{
CheckHasMockComponentMessage checkHasMockComponentMessage;
checkHasMockComponentMessage.entity = entity;
checkHasMockComponentMessage.shouldHaveComponent = false;
EmitMessage(checkHasMockComponentMessage);
}
}
}
@ -263,10 +290,12 @@ namespace Tests
public void RemoveComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new RemoveComponentTestEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.AddEngine(new RemoveComponentTestEngine());
worldBuilder.AddEngine(new CheckHasMockComponentEngine());
worldBuilder.AddEngine(new DoRemoveCheckEngine(entity));
MockComponent mockComponent;
mockComponent.myInt = 3;
mockComponent.myString = "hello";
@ -280,7 +309,6 @@ namespace Tests
var world = worldBuilder.Build();
world.Update(0.01f);
}
@ -290,7 +318,7 @@ namespace Tests
public Guid componentID;
}
[Reads(typeof(ActivateComponentMessage), typeof(MockComponent))]
[Reads(typeof(ActivateComponentMessage))]
[Writes(typeof(MockComponent))]
class ActivateComponentEngine : Engine
{
@ -299,7 +327,61 @@ namespace Tests
foreach (var activateComponentMessage in ReadMessages<ActivateComponentMessage>())
{
ActivateComponent(activateComponentMessage.componentID);
Assert.IsTrue(HasComponent<MockComponent>(activateComponentMessage.entity));
}
}
}
struct CheckHasMockComponentMessage : IMessage
{
public Entity entity;
public bool shouldHaveComponent;
}
[Reads(typeof(ActivateComponentMessage))]
[Writes(typeof(CheckHasMockComponentMessage))]
class DoActivateCheckEngine : Engine
{
private Entity entity;
public DoActivateCheckEngine(Entity entity)
{
this.entity = entity;
}
public override void Update(double dt)
{
if (SomeMessage<ActivateComponentMessage>())
{
CheckHasMockComponentMessage checkHasMockComponentMessage;
checkHasMockComponentMessage.entity = entity;
checkHasMockComponentMessage.shouldHaveComponent = false;
EmitMessage(checkHasMockComponentMessage);
}
else
{
CheckHasMockComponentMessage checkHasMockComponentMessage;
checkHasMockComponentMessage.entity = entity;
checkHasMockComponentMessage.shouldHaveComponent = true;
EmitMessage(checkHasMockComponentMessage);
}
}
}
[Reads(typeof(CheckHasMockComponentMessage))]
class CheckHasMockComponentEngine : Engine
{
public override void Update(double dt)
{
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
{
if (checkHasMockComponentMessage.shouldHaveComponent)
{
Assert.IsTrue(HasComponent<MockComponent>(checkHasMockComponentMessage.entity));
}
else
{
Assert.IsFalse(HasComponent<MockComponent>(checkHasMockComponentMessage.entity));
}
}
}
}
@ -308,10 +390,12 @@ namespace Tests
public void ActivateComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateComponentEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.AddEngine(new ActivateComponentEngine());
worldBuilder.AddEngine(new CheckHasMockComponentEngine());
worldBuilder.AddEngine(new DoActivateCheckEngine(entity));
MockComponent mockComponent;
mockComponent.myInt = 3;
mockComponent.myString = "hello";
@ -327,7 +411,8 @@ namespace Tests
var world = worldBuilder.Build();
world.Update(0.01f);
world.Update(0.01);
world.Update(0.01);
}
struct DeactivateComponentMessage : IMessage
@ -336,7 +421,7 @@ namespace Tests
public Guid componentID;
}
[Reads(typeof(DeactivateComponentMessage), typeof(MockComponent))]
[Reads(typeof(DeactivateComponentMessage))]
[Writes(typeof(MockComponent))]
class DeactivateComponentEngine : Engine
{
@ -345,7 +430,36 @@ namespace Tests
foreach (var deactivateComponentMessage in ReadMessages<DeactivateComponentMessage>())
{
DeactivateComponent(deactivateComponentMessage.componentID);
Assert.IsFalse(HasComponent<MockComponent>(deactivateComponentMessage.entity));
}
}
}
[Reads(typeof(DeactivateComponentMessage))]
[Writes(typeof(CheckHasMockComponentMessage))]
class DoDeactivateCheckEngine : Engine
{
private Entity entity;
public DoDeactivateCheckEngine(Entity entity)
{
this.entity = entity;
}
public override void Update(double dt)
{
if (SomeMessage<DeactivateComponentMessage>())
{
CheckHasMockComponentMessage checkHasMockComponentMessage;
checkHasMockComponentMessage.entity = entity;
checkHasMockComponentMessage.shouldHaveComponent = true;
EmitMessage(checkHasMockComponentMessage);
}
else
{
CheckHasMockComponentMessage checkHasMockComponentMessage;
checkHasMockComponentMessage.entity = entity;
checkHasMockComponentMessage.shouldHaveComponent = false;
EmitMessage(checkHasMockComponentMessage);
}
}
}
@ -354,10 +468,12 @@ namespace Tests
public void DeactivateComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new DeactivateComponentEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.AddEngine(new DeactivateComponentEngine());
worldBuilder.AddEngine(new CheckHasMockComponentEngine());
worldBuilder.AddEngine(new DoDeactivateCheckEngine(entity));
MockComponent mockComponent;
mockComponent.myInt = 3;
mockComponent.myString = "hello";

View File

@ -23,7 +23,6 @@ namespace Tests
static List<MockMessage> resultMessages;
[Reads(typeof(MockComponent))]
public class ReadComponentsTestEngine : Engine
{
public override void Update(double dt)
@ -32,7 +31,6 @@ namespace Tests
}
}
[Reads(typeof(MockComponent))]
public class ReadComponentTestEngine : Engine
{
public override void Update(double dt)
@ -118,7 +116,6 @@ namespace Tests
Assert.Throws<InvalidOperationException>(() => world.Update(0.01f));
}
[Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))]
public class UpdateComponentTestEngine : Engine
{
@ -156,7 +153,6 @@ namespace Tests
Assert.AreEqual("blaze it", resultComponent.myString);
}
[Reads(typeof(MockComponent))]
public class UndeclaredUpdateComponentTestEngine : Engine
{
public override void Update(double dt)
@ -243,6 +239,7 @@ namespace Tests
}
static IEnumerable<MockMessage> emptyReadMessagesResult;
[Reads(typeof(MockMessage))]
class ReadMessagesWhenNoneExistEngine : Engine
{
@ -274,7 +271,7 @@ namespace Tests
var world = worldBuilder.Build();
var ex = Assert.Throws<IllegalWriteException>(() => world.Update(0.01f));
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to emit undeclared Message MockMessage"));
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to write undeclared Message MockMessage"));
}
static bool someTest;
@ -334,7 +331,6 @@ namespace Tests
Assert.Throws<IllegalReadException>(() => world.Update(0.01f));
}
[Reads(typeof(MockComponent))]
class SomeComponentTestEngine : Engine
{
public override void Update(double dt)
@ -356,32 +352,9 @@ namespace Tests
world.Update(0.01);
}
class UndeclaredSomeComponentEngine : Engine
{
public override void Update(double dt)
{
SomeComponent<MockComponent>();
}
}
[Test]
public void UndeclaredSomeComponent()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new UndeclaredSomeComponentEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.AddComponent(entity, new MockComponent());
var world = worldBuilder.Build();
Assert.Throws<IllegalReadException>(() => world.Update(0.01));
}
static ValueTuple<Guid, MockComponent> pairA;
static ValueTuple<Guid, MockComponent> pairB;
[Reads(typeof(MockComponent))]
class SameValueComponentReadEngine : Engine
{
public override void Update(double dt)
@ -421,7 +394,6 @@ namespace Tests
static IEnumerable<ValueTuple<Guid, MockComponent>> emptyComponentReadResult;
[Reads(typeof(MockComponent))]
class ReadEmptyMockComponentsEngine : Engine
{
public override void Update(double dt)
@ -444,7 +416,6 @@ namespace Tests
struct DestroyerComponent : IComponent { }
[Reads(typeof(DestroyerComponent))]
class DestroyerEngine : Engine
{
public override void Update(double dt)
@ -460,7 +431,6 @@ namespace Tests
static IEnumerable<ValueTuple<Guid, MockComponent>> results;
[Reads(typeof(MockComponent))]
class ReaderEngine : Engine
{
public override void Update(double dt)
@ -498,7 +468,6 @@ namespace Tests
Assert.That(results, Does.Not.Contain((componentBID, mockComponent)));
}
[Reads(typeof(DestroyerComponent), typeof(MockComponent))]
[Writes(typeof(MockComponent))]
class DestroyAndAddComponentEngine : Engine
{
@ -534,7 +503,6 @@ namespace Tests
static Entity entityFromComponentIDResult;
[Reads(typeof(MockComponent))]
class GetEntityFromComponentIDEngine : Engine
{
public override void Update(double dt)
@ -565,7 +533,6 @@ namespace Tests
static MockComponent mockComponentByIDResult;
[Reads(typeof(MockComponent))]
class GetComponentByIDEngine : Engine
{
public override void Update(double dt)
@ -595,7 +562,6 @@ namespace Tests
struct OtherComponent : IComponent { }
[Reads(typeof(MockComponent), typeof(OtherComponent))]
class GetComponentByIDWithTypeMismatchEngine : Engine
{
public override void Update(double dt)
@ -626,7 +592,6 @@ namespace Tests
struct EntityIDComponent : IComponent { public Guid entityID; }
static bool hasEntity;
[Reads(typeof(EntityIDComponent))]
class HasEntityTestEngine : Engine
{
public override void Update(double dt)
@ -663,5 +628,19 @@ namespace Tests
Assert.IsFalse(hasEntity);
}
[Writes(typeof(MockComponent), typeof(MockMessage))]
class EngineThatWritesComponentAndMessage : Engine
{
public override void Update(double dt) { }
}
[Test]
public void EngineWritesComponentAndMessage()
{
var worldBuilder = new WorldBuilder();
Assert.Throws<ComponentAndMessageWriteException>(() => worldBuilder.AddEngine(new EngineThatWritesComponentAndMessage()));
}
}
}

View File

@ -216,7 +216,7 @@ namespace Tests
struct CMessage : IMessage { }
struct DMessage : IMessage { }
[Writes(typeof(AComponent), typeof(AMessage))]
[Writes(typeof(AMessage))]
class AEngine : Engine
{
public override void Update(double dt)
@ -225,7 +225,7 @@ namespace Tests
}
}
[Writes(typeof(BComponent), typeof(BMessage))]
[Writes(typeof(BMessage))]
class BEngine : Engine
{
public override void Update(double dt)