diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 19b1ddf..5ba8489 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -113,7 +113,7 @@ namespace Encompass } // these next two are for the ComponentMessageEmitter only - + internal IEnumerable<(Guid, TComponent)> ReadComponentsFromWorld() where TComponent : struct, IComponent { return componentManager.GetComponentsByType(); @@ -308,6 +308,11 @@ namespace Encompass messageManager.AddMessage(message); } + protected void SendMessageDelayed(TMessage message, double time) where TMessage : struct, IMessage + { + messageManager.AddMessageDelayed(message, time); + } + // unparameterized version to enable dynamic dispatch protected void SendMessage(IMessage message) { diff --git a/encompass-cs/MessageManager.cs b/encompass-cs/MessageManager.cs index 0829dc4..1f86cb9 100644 --- a/encompass-cs/MessageManager.cs +++ b/encompass-cs/MessageManager.cs @@ -8,6 +8,8 @@ namespace Encompass { private readonly Dictionary> messageTypeToMessages = new Dictionary>(); + private readonly List<(IMessage, double)> delayedMessages = new List<(IMessage, double)>(); + internal void RegisterMessageType(Type messageType) { if (!messageTypeToMessages.ContainsKey(messageType)) { @@ -22,6 +24,13 @@ namespace Encompass messageTypeToMessages[type].Add(message); } + internal void AddMessageDelayed(IMessage message, double time) + { + if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List()); } + + delayedMessages.Add((message, time)); + } + internal void AddMessage(IMessage message) where TMessage : struct, IMessage { messageTypeToMessages[typeof(TMessage)].Add(message); @@ -35,6 +44,26 @@ namespace Encompass } } + internal void ProcessDelayedMessages(double dt) + { + for (int i = delayedMessages.Count - 1; i >= 0; i--) + { + var (message, time) = delayedMessages[i]; + + var updatedTime = time - dt; + + if (updatedTime <= 0) + { + AddMessage(message); + delayedMessages.RemoveAt(i); + } + else + { + delayedMessages[i] = (message, updatedTime); + } + } + } + internal IEnumerable GetMessagesByType() where TMessage : struct, IMessage { return messageTypeToMessages.ContainsKey(typeof(TMessage)) ? diff --git a/encompass-cs/World.cs b/encompass-cs/World.cs index abf97c7..efbf537 100644 --- a/encompass-cs/World.cs +++ b/encompass-cs/World.cs @@ -30,6 +30,8 @@ namespace Encompass public void Update(double dt) { + messageManager.ProcessDelayedMessages(dt); + foreach (var engine in enginesInOrder) { engine.Update(dt); diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index ad75fdd..3dd2603 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -45,6 +45,11 @@ namespace Encompass messageManager.AddMessage(message); } + public void SendMessageDelayed(TMessage message, double time) where TMessage : struct, IMessage + { + messageManager.AddMessageDelayed(message, time); + } + public Guid AddComponent(Entity entity, TComponent component) where TComponent : struct, IComponent { return componentManager.MarkComponentForAdd(entity, component); diff --git a/test/EngineTest.cs b/test/EngineTest.cs index a3ac290..381be18 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -21,7 +21,7 @@ namespace Tests static List> resultComponents; static MockComponent resultComponent; - static List resultMessages; + static List resultMessages = new List(); [Reads(typeof(MockComponent))] public class ReadComponentsTestEngine : Engine @@ -763,5 +763,46 @@ namespace Tests var world = worldBuilder.Build(); Assert.Throws(() => world.Update(0.01)); } + + [Reads(typeof(MockComponent))] + class DelayedMessageEngine : Engine + { + public override void Update(double dt) + { + foreach (var (componentID, component) in ReadComponents()) + { + RemoveComponent(componentID); + SendMessageDelayed(new MockMessage {}, 1); + } + } + } + + [Test] + public void EngineSendMessageDelayed() + { + resultMessages.Clear(); + + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(new DelayedMessageEngine()); + worldBuilder.AddEngine(new MessageReadEngine()); + + var entity = worldBuilder.CreateEntity(); + worldBuilder.AddComponent(entity, new MockComponent {}); + + var world = worldBuilder.Build(); + + world.Update(0.01); + + resultMessages.Should().BeEmpty(); + + world.Update(0.5); + + resultMessages.Should().BeEmpty(); + + world.Update(0.5); + + resultMessages.Should().NotBeEmpty(); + resultMessages.First().Should().BeOfType(); + } } } diff --git a/test/WorldBuilderTest.cs b/test/WorldBuilderTest.cs index 589c994..91777d2 100644 --- a/test/WorldBuilderTest.cs +++ b/test/WorldBuilderTest.cs @@ -3,6 +3,8 @@ using NUnit.Framework; using Encompass; using System.Collections.Generic; using Encompass.Exceptions; +using System.Linq; +using FluentAssertions; namespace Tests { @@ -273,6 +275,39 @@ namespace Tests Assert.That(order.IndexOf(engineB), Is.LessThan(order.IndexOf(engineC))); Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD))); } + + static List resultMessages = new List(); + + [Receives(typeof(AMessage))] + class ReadMessageEngine : Engine + { + public override void Update(double dt) + { + resultMessages = ReadMessages().ToList(); + } + } + + [Test] + public void SendMessageDelayed() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(new ReadMessageEngine()); + + worldBuilder.SendMessageDelayed(new AMessage {}, 0.5); + + var world = worldBuilder.Build(); + + resultMessages.Should().BeEmpty(); + + world.Update(0.25); + + resultMessages.Should().BeEmpty(); + + world.Update(0.25); + + resultMessages.Should().NotBeEmpty(); + resultMessages.First().Should().BeOfType(); + } } } }