delayed message system

pull/5/head
thatcosmonaut 2019-08-19 19:05:18 -07:00
parent 6a51ceb590
commit d084286c83
6 changed files with 119 additions and 2 deletions

View File

@ -308,6 +308,11 @@ namespace Encompass
messageManager.AddMessage(message); messageManager.AddMessage(message);
} }
protected void SendMessageDelayed<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
{
messageManager.AddMessageDelayed(message, time);
}
// unparameterized version to enable dynamic dispatch // unparameterized version to enable dynamic dispatch
protected void SendMessage(IMessage message) protected void SendMessage(IMessage message)
{ {

View File

@ -8,6 +8,8 @@ namespace Encompass
{ {
private readonly Dictionary<Type, List<IMessage>> messageTypeToMessages = new Dictionary<Type, List<IMessage>>(); private readonly Dictionary<Type, List<IMessage>> messageTypeToMessages = new Dictionary<Type, List<IMessage>>();
private readonly List<(IMessage, double)> delayedMessages = new List<(IMessage, double)>();
internal void RegisterMessageType(Type messageType) internal void RegisterMessageType(Type messageType)
{ {
if (!messageTypeToMessages.ContainsKey(messageType)) { if (!messageTypeToMessages.ContainsKey(messageType)) {
@ -22,6 +24,13 @@ namespace Encompass
messageTypeToMessages[type].Add(message); messageTypeToMessages[type].Add(message);
} }
internal void AddMessageDelayed(IMessage message, double time)
{
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
delayedMessages.Add((message, time));
}
internal void AddMessage<TMessage>(IMessage message) where TMessage : struct, IMessage internal void AddMessage<TMessage>(IMessage message) where TMessage : struct, IMessage
{ {
messageTypeToMessages[typeof(TMessage)].Add(message); 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<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
{ {
return messageTypeToMessages.ContainsKey(typeof(TMessage)) ? return messageTypeToMessages.ContainsKey(typeof(TMessage)) ?

View File

@ -30,6 +30,8 @@ namespace Encompass
public void Update(double dt) public void Update(double dt)
{ {
messageManager.ProcessDelayedMessages(dt);
foreach (var engine in enginesInOrder) foreach (var engine in enginesInOrder)
{ {
engine.Update(dt); engine.Update(dt);

View File

@ -45,6 +45,11 @@ namespace Encompass
messageManager.AddMessage(message); messageManager.AddMessage(message);
} }
public void SendMessageDelayed<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
{
messageManager.AddMessageDelayed(message, time);
}
public Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent public Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
{ {
return componentManager.MarkComponentForAdd(entity, component); return componentManager.MarkComponentForAdd(entity, component);

View File

@ -21,7 +21,7 @@ namespace Tests
static List<ValueTuple<Guid, MockComponent>> resultComponents; static List<ValueTuple<Guid, MockComponent>> resultComponents;
static MockComponent resultComponent; static MockComponent resultComponent;
static List<MockMessage> resultMessages; static List<MockMessage> resultMessages = new List<MockMessage>();
[Reads(typeof(MockComponent))] [Reads(typeof(MockComponent))]
public class ReadComponentsTestEngine : Engine public class ReadComponentsTestEngine : Engine
@ -763,5 +763,46 @@ namespace Tests
var world = worldBuilder.Build(); var world = worldBuilder.Build();
Assert.Throws<RepeatUpdateComponentException>(() => world.Update(0.01)); Assert.Throws<RepeatUpdateComponentException>(() => world.Update(0.01));
} }
[Reads(typeof(MockComponent))]
class DelayedMessageEngine : Engine
{
public override void Update(double dt)
{
foreach (var (componentID, component) in ReadComponents<MockComponent>())
{
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<MockMessage>();
}
} }
} }

View File

@ -3,6 +3,8 @@ using NUnit.Framework;
using Encompass; using Encompass;
using System.Collections.Generic; using System.Collections.Generic;
using Encompass.Exceptions; using Encompass.Exceptions;
using System.Linq;
using FluentAssertions;
namespace Tests namespace Tests
{ {
@ -273,6 +275,39 @@ namespace Tests
Assert.That(order.IndexOf(engineB), Is.LessThan(order.IndexOf(engineC))); Assert.That(order.IndexOf(engineB), Is.LessThan(order.IndexOf(engineC)));
Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD))); Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD)));
} }
static List<AMessage> resultMessages = new List<AMessage>();
[Receives(typeof(AMessage))]
class ReadMessageEngine : Engine
{
public override void Update(double dt)
{
resultMessages = ReadMessages<AMessage>().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<AMessage>();
}
} }
} }
} }