engines must declare component reads + validation for Reads and Writes arguments
							parent
							
								
									7ab512e522
								
							
						
					
					
						commit
						9b58473ae8
					
				|  | @ -74,37 +74,47 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|         protected TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent |         protected TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
| 
 |             if (!readTypes.Contains(typeof(TComponent)))  | ||||||
|             if (componentManager.GetComponentTypeByID(componentID) == typeof(TComponent)) |  | ||||||
|             { |             { | ||||||
|                 return (TComponent)componentManager.GetComponentByID(componentID); |                 throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name); | ||||||
|             } |             } | ||||||
|             else | 
 | ||||||
|  |             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); |                 throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentManager.GetComponentTypeByID(componentID).Name); | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             return (TComponent)componentManager.GetComponentByID(componentID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent |         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>(); |             return componentManager.GetActiveComponentsByType<TComponent>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent |         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>(); |             return componentManager.GetActiveComponentByType<TComponent>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent |         internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             if (writeTypes.Contains(typeof(TComponent))) |             if (!writeTypes.Contains(typeof(TComponent))) | ||||||
|             { |             { | ||||||
|                 componentManager.UpdateComponent(componentID, newComponent); |                 throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name); | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 throw new IllegalComponentMutationException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name); |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             componentManager.UpdateComponent(componentID, newComponent); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected void UpdateComponent<TComponent>(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent |         protected void UpdateComponent<TComponent>(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent | ||||||
|  | @ -114,38 +124,33 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|         protected void EmitMessage<TMessage>(TMessage message) where TMessage : struct, IMessage |         protected void EmitMessage<TMessage>(TMessage message) where TMessage : struct, IMessage | ||||||
|         { |         { | ||||||
|             if (writeTypes.Contains(typeof(TMessage))) |             if (!writeTypes.Contains(typeof(TMessage))) | ||||||
|             { |             { | ||||||
|                 messageManager.AddMessage(message); |                 throw new IllegalWriteException("Engine {0} tried to emit undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 throw new IllegalMessageEmitException("Engine {0} tried to emit undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             messageManager.AddMessage(message); | ||||||
|  | 
 | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage |         protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage | ||||||
|         { |         { | ||||||
|             if (readTypes.Contains(typeof(TMessage))) |             if (!readTypes.Contains(typeof(TMessage))) | ||||||
|             { |             { | ||||||
|                 return messageManager.GetMessagesByType<TMessage>(); |                 throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 throw new IllegalMessageReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             return messageManager.GetMessagesByType<TMessage>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected bool Some<TMessage>() where TMessage : struct, IMessage |         protected bool Some<TMessage>() where TMessage : struct, IMessage | ||||||
|         { |         { | ||||||
|             if (readTypes.Contains(typeof(TMessage))) |             if (!readTypes.Contains(typeof(TMessage))) | ||||||
|             { |             { | ||||||
|                 return messageManager.GetMessagesByType<TMessage>().Any(); |                 throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 throw new IllegalMessageReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); |  | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             return messageManager.GetMessagesByType<TMessage>().Any(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected void Destroy(Guid entityID) |         protected void Destroy(Guid entityID) | ||||||
|  |  | ||||||
|  | @ -17,8 +17,8 @@ namespace Encompass | ||||||
|         private readonly DrawLayerManager drawLayerManager; |         private readonly DrawLayerManager drawLayerManager; | ||||||
|         private readonly RenderManager renderManager; |         private readonly RenderManager renderManager; | ||||||
| 
 | 
 | ||||||
|         private readonly Dictionary<Type, HashSet<Engine>> messageTypeToEmitters = new Dictionary<Type, HashSet<Engine>>(); |         private readonly Dictionary<Type, HashSet<Engine>> typeToEmitters = new Dictionary<Type, HashSet<Engine>>(); | ||||||
|         private readonly Dictionary<Type, HashSet<Engine>> messageTypeToReaders = new Dictionary<Type, HashSet<Engine>>(); |         private readonly Dictionary<Type, HashSet<Engine>> typeToReaders = new Dictionary<Type, HashSet<Engine>>(); | ||||||
| 
 | 
 | ||||||
|         public WorldBuilder() |         public WorldBuilder() | ||||||
|         { |         { | ||||||
|  | @ -55,38 +55,58 @@ namespace Encompass | ||||||
|                 entityManager.RegisterEntityTracker(engine as IEntityTracker); |                 entityManager.RegisterEntityTracker(engine as IEntityTracker); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var emitMessageType in engine.writeTypes) |             foreach (var writeType in engine.writeTypes) | ||||||
|             { |             { | ||||||
|                 if (!messageTypeToEmitters.ContainsKey(emitMessageType)) |                 if (!typeToEmitters.ContainsKey(writeType)) | ||||||
|                 { |                 { | ||||||
|                     messageTypeToEmitters.Add(emitMessageType, new HashSet<Engine>()); |                     typeToEmitters.Add(writeType, new HashSet<Engine>()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 messageTypeToEmitters[emitMessageType].Add(engine); |                 typeToEmitters[writeType].Add(engine); | ||||||
| 
 | 
 | ||||||
|                 if (messageTypeToReaders.ContainsKey(emitMessageType)) |                 if (typeToReaders.ContainsKey(writeType)) | ||||||
|                 { |                 { | ||||||
|                     foreach (var reader in messageTypeToReaders[emitMessageType]) |                     foreach (var reader in typeToReaders[writeType]) | ||||||
|                     { |                     { | ||||||
|                         engineGraph.AddEdge(engine, reader); |                         if (engine == reader) | ||||||
|  |                         { | ||||||
|  |                             if (writeType.GetInterfaces().Contains(typeof(IMessage))) | ||||||
|  |                             { | ||||||
|  |                                 throw new EngineMessageSelfCycleException("Engine both reads and writes Message {0}", writeType.Name); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         else | ||||||
|  |                         { | ||||||
|  |                             engineGraph.AddEdge(engine, reader); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var readMessageType in engine.readTypes) |             foreach (var readType in engine.readTypes) | ||||||
|             { |             { | ||||||
|                 if (!messageTypeToReaders.ContainsKey(readMessageType)) |                 if (!typeToReaders.ContainsKey(readType)) | ||||||
|                 { |                 { | ||||||
|                     messageTypeToReaders.Add(readMessageType, new HashSet<Engine>()); |                     typeToReaders.Add(readType, new HashSet<Engine>()); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 messageTypeToReaders[readMessageType].Add(engine); |                 typeToReaders[readType].Add(engine); | ||||||
| 
 | 
 | ||||||
|                 if (messageTypeToEmitters.ContainsKey(readMessageType)) |                 if (typeToEmitters.ContainsKey(readType)) | ||||||
|                 { |                 { | ||||||
|                     foreach (var emitter in messageTypeToEmitters[readMessageType]) |                     foreach (var emitter in typeToEmitters[readType]) | ||||||
|                     { |                     { | ||||||
|                         engineGraph.AddEdge(emitter, engine); |                         if (emitter == engine) | ||||||
|  |                         { | ||||||
|  |                             if (readType.GetInterfaces().Contains(typeof(IMessage))) | ||||||
|  |                             { | ||||||
|  |                                 throw new EngineMessageSelfCycleException("Engine both reads and writes Message {0}", readType.Name); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         else | ||||||
|  |                         { | ||||||
|  |                             engineGraph.AddEdge(emitter, engine); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -177,7 +197,7 @@ namespace Encompass | ||||||
|                     string.Join(", ", componentToEngines[componentType].Select((engine) => engine.GetType().Name)); |                     string.Join(", ", componentToEngines[componentType].Select((engine) => engine.GetType().Name)); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 throw new EngineMutationConflictException(errorString); |                 throw new EngineWriteConflictException(errorString); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var engineOrder = new List<Engine>(); |             var engineOrder = new List<Engine>(); | ||||||
|  |  | ||||||
|  | @ -1,16 +0,0 @@ | ||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| 
 |  | ||||||
| namespace Encompass |  | ||||||
| { |  | ||||||
|     [AttributeUsage(AttributeTargets.Class)] |  | ||||||
|     public class Writes : Attribute |  | ||||||
|     { |  | ||||||
|         public readonly List<Type> writeTypes; |  | ||||||
| 
 |  | ||||||
|         public Writes(params Type[] writeTypes) |  | ||||||
|         { |  | ||||||
|             this.writeTypes = new List<Type>(writeTypes); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | using Encompass.Exceptions; | ||||||
| 
 | 
 | ||||||
| namespace Encompass | namespace Encompass | ||||||
| { | { | ||||||
|  | @ -8,9 +10,17 @@ namespace Encompass | ||||||
|     { |     { | ||||||
|         public readonly List<Type> readTypes; |         public readonly List<Type> readTypes; | ||||||
| 
 | 
 | ||||||
|         public Reads(params Type[] readMessageTypes) |         public Reads(params Type[] readTypes) | ||||||
|         { |         { | ||||||
|             this.readTypes = new List<Type>(readMessageTypes); |             foreach (var readType in readTypes) | ||||||
|  |             { | ||||||
|  |                 if (!readType.GetInterfaces().Contains(typeof(IMessage)) && !readType.GetInterfaces().Contains(typeof(IComponent))) | ||||||
|  |                 { | ||||||
|  |                     throw new IllegalReadTypeException("{0} must be a Message or Component", readType.Name); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this.readTypes = new List<Type>(readTypes); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | using Encompass.Exceptions; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     [AttributeUsage(AttributeTargets.Class)] | ||||||
|  |     public class Writes : Attribute | ||||||
|  |     { | ||||||
|  |         public readonly List<Type> writeTypes; | ||||||
|  | 
 | ||||||
|  |         public Writes(params Type[] writeTypes) | ||||||
|  |         { | ||||||
|  |             foreach (var writeType in writeTypes) | ||||||
|  |             { | ||||||
|  |                 if (!writeType.GetInterfaces().Contains(typeof(IMessage)) && !writeType.GetInterfaces().Contains(typeof(IComponent))) | ||||||
|  |                 { | ||||||
|  |                     throw new IllegalWriteTypeException("{0} must be a Message or Component", writeType.Name); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this.writeTypes = new List<Type>(writeTypes); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -2,9 +2,9 @@ using System; | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class EngineMutationConflictException : Exception |     public class EngineMessageSelfCycleException : Exception | ||||||
|     { |     { | ||||||
|         public EngineMutationConflictException( |         public EngineMessageSelfCycleException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  | @ -2,9 +2,9 @@ using System; | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class IllegalComponentMutationException : Exception |     public class EngineWriteConflictException : Exception | ||||||
|     { |     { | ||||||
|         public IllegalComponentMutationException( |         public EngineWriteConflictException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  | @ -2,9 +2,9 @@ using System; | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class IllegalMessageReadException : Exception |     public class IllegalReadException : Exception | ||||||
|     { |     { | ||||||
|         public IllegalMessageReadException( |         public IllegalReadException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  | @ -2,9 +2,9 @@ using System; | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class IllegalMessageEmitException : Exception |     public class IllegalReadTypeException : Exception | ||||||
|     { |     { | ||||||
|         public IllegalMessageEmitException( |         public IllegalReadTypeException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | using System; | ||||||
|  | 
 | ||||||
|  | namespace Encompass.Exceptions | ||||||
|  | { | ||||||
|  |     public class IllegalWriteException : Exception | ||||||
|  |     { | ||||||
|  |         public IllegalWriteException( | ||||||
|  |             string format, | ||||||
|  |             params object[] args | ||||||
|  |         ) : base(string.Format(format, args)) { } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | using System; | ||||||
|  | 
 | ||||||
|  | namespace Encompass.Exceptions | ||||||
|  | { | ||||||
|  |     public class IllegalWriteTypeException : Exception | ||||||
|  |     { | ||||||
|  |         public IllegalWriteTypeException( | ||||||
|  |             string format, | ||||||
|  |             params object[] args | ||||||
|  |         ) : base(string.Format(format, args)) { } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -27,7 +27,7 @@ namespace Encompass | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected List<T> _vertices = new List<T>(); |         protected List<T> _vertices = new List<T>(); | ||||||
|         protected Dictionary<T, List<T>> _neighbors = new Dictionary<T, List<T>>(); |         protected Dictionary<T, HashSet<T>> _neighbors = new Dictionary<T, HashSet<T>>(); | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<T> Vertices { get { return _vertices; } } |         public IEnumerable<T> Vertices { get { return _vertices; } } | ||||||
| 
 | 
 | ||||||
|  | @ -40,7 +40,7 @@ namespace Encompass | ||||||
|             if (!VertexExists(vertex)) |             if (!VertexExists(vertex)) | ||||||
|             { |             { | ||||||
|                 _vertices.Add(vertex); |                 _vertices.Add(vertex); | ||||||
|                 _neighbors.Add(vertex, new List<T>()); |                 _neighbors.Add(vertex, new HashSet<T>()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         static List<MockMessage> resultMessages; |         static List<MockMessage> resultMessages; | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         public class ReadComponentsTestEngine : Engine |         public class ReadComponentsTestEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -25,6 +26,7 @@ namespace Tests | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         public class ReadComponentTestEngine : Engine |         public class ReadComponentTestEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -110,6 +112,7 @@ namespace Tests | ||||||
|             Assert.Throws<InvalidOperationException>(() => world.Update(0.01f)); |             Assert.Throws<InvalidOperationException>(() => world.Update(0.01f)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         [Writes(typeof(MockComponent))] |         [Writes(typeof(MockComponent))] | ||||||
|         public class UpdateComponentTestEngine : Engine |         public class UpdateComponentTestEngine : Engine | ||||||
|         { |         { | ||||||
|  | @ -147,6 +150,7 @@ namespace Tests | ||||||
|             Assert.AreEqual("blaze it", resultComponent.myString); |             Assert.AreEqual("blaze it", resultComponent.myString); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         public class UndeclaredUpdateComponentTestEngine : Engine |         public class UndeclaredUpdateComponentTestEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -177,7 +181,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
| 
 | 
 | ||||||
|             var ex = Assert.Throws<IllegalComponentMutationException>(() => world.Update(0.01f)); |             var ex = Assert.Throws<IllegalWriteException>(() => world.Update(0.01f)); | ||||||
|             Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to write undeclared Component MockComponent")); |             Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to write undeclared Component MockComponent")); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -263,7 +267,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
| 
 | 
 | ||||||
|             var ex = Assert.Throws<IllegalMessageEmitException>(() => world.Update(0.01f)); |             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 emit undeclared Message MockMessage")); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -321,12 +325,13 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
| 
 | 
 | ||||||
|             Assert.Throws<IllegalMessageReadException>(() => world.Update(0.01f)); |             Assert.Throws<IllegalReadException>(() => world.Update(0.01f)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         static ValueTuple<Guid, MockComponent> pairA; |         static ValueTuple<Guid, MockComponent> pairA; | ||||||
|         static ValueTuple<Guid, MockComponent> pairB; |         static ValueTuple<Guid, MockComponent> pairB; | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         class SameValueComponentReadEngine : Engine |         class SameValueComponentReadEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -366,6 +371,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         static IEnumerable<ValueTuple<Guid, MockComponent>> emptyComponentReadResult; |         static IEnumerable<ValueTuple<Guid, MockComponent>> emptyComponentReadResult; | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         class ReadEmptyMockComponentsEngine : Engine |         class ReadEmptyMockComponentsEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -388,6 +394,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         struct DestroyerComponent : IComponent { } |         struct DestroyerComponent : IComponent { } | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(DestroyerComponent))] | ||||||
|         class DestroyerEngine : Engine |         class DestroyerEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -402,6 +409,8 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         static IEnumerable<ValueTuple<Guid, MockComponent>> results; |         static IEnumerable<ValueTuple<Guid, MockComponent>> results; | ||||||
|  | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         class ReaderEngine : Engine |         class ReaderEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -439,6 +448,7 @@ namespace Tests | ||||||
|             Assert.That(results, Does.Not.Contain((componentBID, mockComponent))); |             Assert.That(results, Does.Not.Contain((componentBID, mockComponent))); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(DestroyerComponent))] | ||||||
|         class DestroyAndAddComponentEngine : Engine |         class DestroyAndAddComponentEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -472,6 +482,8 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         static Entity entityFromComponentIDResult; |         static Entity entityFromComponentIDResult; | ||||||
|  | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         class GetEntityFromComponentIDEngine : Engine |         class GetEntityFromComponentIDEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -501,6 +513,8 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         static MockComponent mockComponentByIDResult; |         static MockComponent mockComponentByIDResult; | ||||||
|  | 
 | ||||||
|  |         [Reads(typeof(MockComponent))] | ||||||
|         class GetComponentByIDEngine : Engine |         class GetComponentByIDEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -530,6 +544,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         struct OtherComponent : IComponent { } |         struct OtherComponent : IComponent { } | ||||||
| 
 | 
 | ||||||
|  |         [Reads(typeof(MockComponent), typeof(OtherComponent))] | ||||||
|         class GetComponentByIDWithTypeMismatchEngine : Engine |         class GetComponentByIDWithTypeMismatchEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -559,6 +574,8 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         struct EntityIDComponent : IComponent { public Guid entityID;  } |         struct EntityIDComponent : IComponent { public Guid entityID;  } | ||||||
|         static bool hasEntity; |         static bool hasEntity; | ||||||
|  | 
 | ||||||
|  |         [Reads(typeof(EntityIDComponent))] | ||||||
|         class HasEntityTestEngine : Engine |         class HasEntityTestEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  |  | ||||||
|  | @ -133,7 +133,74 @@ namespace Tests | ||||||
|                 worldBuilder.AddEngine(new AEngine()); |                 worldBuilder.AddEngine(new AEngine()); | ||||||
|                 worldBuilder.AddEngine(new BEngine()); |                 worldBuilder.AddEngine(new BEngine()); | ||||||
| 
 | 
 | ||||||
|                 Assert.Throws<EngineMutationConflictException>(() => worldBuilder.Build()); |                 Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public class EngineMessageSelfCycle | ||||||
|  |         { | ||||||
|  |             struct AMessage : IMessage { } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(AMessage))] | ||||||
|  |             [Writes(typeof(AMessage))] | ||||||
|  |             class AEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                      | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void ThrowsError() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 Assert.Throws<EngineMessageSelfCycleException>(() => worldBuilder.AddEngine(new AEngine()), "Engine both reads and writes Message AMessage"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public class IllegalReadType | ||||||
|  |         { | ||||||
|  |             struct ANonMessage { } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(ANonMessage))] | ||||||
|  |             class MyEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void ThrowsError() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 Assert.Throws<IllegalReadTypeException>(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public class IllegalWriteType | ||||||
|  |         { | ||||||
|  |             struct ANonMessage { } | ||||||
|  | 
 | ||||||
|  |             [Writes(typeof(ANonMessage))] | ||||||
|  |             class MyEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void ThrowsError() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 Assert.Throws<IllegalWriteTypeException>(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue