From c1aa6a07c90c6801d95633fef8fbef81819f2b06 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Sat, 15 Jun 2019 18:55:35 -0700 Subject: [PATCH] start on message stuff --- src/Engine.cs | 44 +++++++++++++ src/MessageManager.cs | 32 +++++++++ src/World.cs | 6 +- src/WorldBuilder.cs | 6 +- src/attributes/Emits.cs | 16 +++++ src/attributes/Reads.cs | 16 +++++ src/encompass-cs.csproj | 4 ++ src/exceptions/IllegalMessageEmitException.cs | 12 ++++ src/exceptions/IllegalMessageReadException.cs | 12 ++++ test/EngineTest.cs | 65 +++++++++++++++++++ 10 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 src/MessageManager.cs create mode 100644 src/attributes/Emits.cs create mode 100644 src/attributes/Reads.cs create mode 100644 src/exceptions/IllegalMessageEmitException.cs create mode 100644 src/exceptions/IllegalMessageReadException.cs diff --git a/src/Engine.cs b/src/Engine.cs index 792ec16..1d15bee 100644 --- a/src/Engine.cs +++ b/src/Engine.cs @@ -7,9 +7,12 @@ namespace Encompass public abstract class Engine { public readonly List mutateComponentTypes = new List(); + public readonly List emitMessageTypes = new List(); + public readonly List readMessageTypes = new List(); private EntityManager entityManager; private ComponentManager componentManager; + private MessageManager messageManager; public Engine() { @@ -18,6 +21,18 @@ namespace Encompass { mutateComponentTypes = mutatesAttribute.mutateComponentTypes; } + + var emitsAttribute = this.GetType().GetCustomAttribute(false); + if (emitsAttribute != null) + { + emitMessageTypes = emitsAttribute.emitMessageTypes; + } + + var readsAttribute = this.GetType().GetCustomAttribute(false); + if (readsAttribute != null) + { + readMessageTypes = readsAttribute.readMessageTypes; + } } internal void AssignEntityManager(EntityManager entityManager) @@ -30,6 +45,11 @@ namespace Encompass this.componentManager = componentManager; } + internal void AssignMessageManager(MessageManager messageManager) + { + this.messageManager = messageManager; + } + public abstract void Update(float dt); protected Entity CreateEntity() @@ -72,5 +92,29 @@ namespace Encompass this.UpdateComponent(component, updateFunction); } } + + protected void EmitMessage(TMessage message) where TMessage : struct, IMessage + { + if (emitMessageTypes.Contains(typeof(TMessage))) + { + this.messageManager.AddMessage(message); + } + else + { + throw new IllegalMessageEmitException("Engine {0} tried to emit undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); + } + } + + protected IEnumerable ReadMessages() where TMessage : struct, IMessage + { + if (readMessageTypes.Contains(typeof(TMessage))) + { + return this.messageManager.GetMessagesByType(); + } + else + { + throw new IllegalMessageReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); + } + } } } diff --git a/src/MessageManager.cs b/src/MessageManager.cs new file mode 100644 index 0000000..2f0cad1 --- /dev/null +++ b/src/MessageManager.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Encompass +{ + internal class MessageManager + { + private Dictionary> messageTypeToMessages = new Dictionary>(); + + internal void AddMessage(TMessage message) where TMessage : struct, IMessage + { + if (!messageTypeToMessages.ContainsKey(typeof(TMessage))) + { + messageTypeToMessages.Add(typeof(TMessage), new List()); + } + } + + internal void ClearMessages() + { + foreach (var entry in messageTypeToMessages) + { + entry.Value.Clear(); + } + } + + internal IEnumerable GetMessagesByType() where TMessage : struct, IMessage + { + return messageTypeToMessages[typeof(TMessage)].Cast(); + } + } +} diff --git a/src/World.cs b/src/World.cs index 784479a..a33e08e 100644 --- a/src/World.cs +++ b/src/World.cs @@ -7,16 +7,19 @@ namespace Encompass private List engines; private EntityManager entityManager; private ComponentManager componentManager; + private MessageManager messageManager; internal World( List engines, EntityManager entityManager, - ComponentManager componentManager + ComponentManager componentManager, + MessageManager messageManager ) { this.engines = engines; this.entityManager = entityManager; this.componentManager = componentManager; + this.messageManager = messageManager; } public void Update(float dt) @@ -26,6 +29,7 @@ namespace Encompass engine.Update(dt); } + messageManager.ClearMessages(); entityManager.DestroyMarkedEntities(); componentManager.ActivateComponents(); componentManager.RemoveComponents(); diff --git a/src/WorldBuilder.cs b/src/WorldBuilder.cs index 50a2663..c32f8c1 100644 --- a/src/WorldBuilder.cs +++ b/src/WorldBuilder.cs @@ -8,11 +8,13 @@ namespace Encompass private ComponentManager componentManager; private EntityManager entityManager; + private MessageManager messageManager; public WorldBuilder() { componentManager = new ComponentManager(); entityManager = new EntityManager(componentManager); + messageManager = new MessageManager(); } public Entity CreateEntity() @@ -26,6 +28,7 @@ namespace Encompass engine.AssignEntityManager(this.entityManager); engine.AssignComponentManager(this.componentManager); + engine.AssignMessageManager(this.messageManager); engines.Add(engine); @@ -37,7 +40,8 @@ namespace Encompass var world = new World( this.engines, this.entityManager, - this.componentManager + this.componentManager, + this.messageManager ); this.componentManager.ActivateComponents(); diff --git a/src/attributes/Emits.cs b/src/attributes/Emits.cs new file mode 100644 index 0000000..dc25fca --- /dev/null +++ b/src/attributes/Emits.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Encompass +{ + [System.AttributeUsage(System.AttributeTargets.Class)] + public class Emits : System.Attribute + { + public readonly List emitMessageTypes; + + public Emits(params Type[] emitMessageTypes) + { + this.emitMessageTypes = new List(emitMessageTypes); + } + } +} diff --git a/src/attributes/Reads.cs b/src/attributes/Reads.cs new file mode 100644 index 0000000..d738d20 --- /dev/null +++ b/src/attributes/Reads.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Encompass +{ + [System.AttributeUsage(System.AttributeTargets.Class)] + public class Reads : System.Attribute + { + public readonly List readMessageTypes; + + public Reads(params Type[] readMessageTypes) + { + this.readMessageTypes = new List(readMessageTypes); + } + } +} diff --git a/src/encompass-cs.csproj b/src/encompass-cs.csproj index 5b6a9c5..f199fa6 100644 --- a/src/encompass-cs.csproj +++ b/src/encompass-cs.csproj @@ -17,5 +17,9 @@ + + + + \ No newline at end of file diff --git a/src/exceptions/IllegalMessageEmitException.cs b/src/exceptions/IllegalMessageEmitException.cs new file mode 100644 index 0000000..79972f3 --- /dev/null +++ b/src/exceptions/IllegalMessageEmitException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Encompass +{ + public class IllegalMessageEmitException : Exception + { + public IllegalMessageEmitException( + string format, + params object[] args + ) : base(string.Format(format, args)) { } + } +} diff --git a/src/exceptions/IllegalMessageReadException.cs b/src/exceptions/IllegalMessageReadException.cs new file mode 100644 index 0000000..4a1c1f6 --- /dev/null +++ b/src/exceptions/IllegalMessageReadException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Encompass +{ + public class IllegalMessageReadException : Exception + { + public IllegalMessageReadException( + string format, + params object[] args + ) : base(string.Format(format, args)) { } + } +} diff --git a/test/EngineTest.cs b/test/EngineTest.cs index d03afa0..c1a6e2d 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -12,6 +12,8 @@ namespace Tests static IEnumerable resultComponents; static MockComponent resultComponent; + static IEnumerable resultMessages; + public class ReadComponentsTestEngine : Engine { public override void Update(float dt) @@ -172,5 +174,68 @@ namespace Tests var ex = Assert.Throws(() => world.Update(0.01f)); Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to mutate undeclared Component MockComponent")); } + + struct MockMessage : IMessage + { + public string myString; + } + + [Emits(typeof(MockMessage))] + public class MessageEmitEngine : Engine + { + public override void Update(float dt) + { + MockMessage message; + message.myString = "howdy"; + + this.EmitMessage(message); + } + } + + [Reads(typeof(MockMessage))] + public class MessageReadEngine : Engine + { + public override void Update(float dt) + { + resultMessages = this.ReadMessages(); + } + } + + [Test] + public void EmitAndReadMessage() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(); + worldBuilder.AddEngine(); + + var world = worldBuilder.Build(); + + world.Update(0.01f); + + Assert.AreEqual(resultMessages.First().myString, "howdy"); + } + + public class UndeclaredMessageEmitEngine : Engine + { + public override void Update(float dt) + { + MockMessage message; + message.myString = "howdy"; + + this.EmitMessage(message); + } + } + + [Test] + public void EmitUndeclaredMessage() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(); + + var world = worldBuilder.Build(); + + var ex = Assert.Throws(() => world.Update(0.01f)); + Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to emit undeclared Message MockMessage")); + } } }