messages with time dilation system

pull/5/head
thatcosmonaut 2019-11-21 14:22:10 -08:00
parent fc50bf9b81
commit d45295ae87
4 changed files with 133 additions and 9 deletions

View File

@ -554,14 +554,23 @@ namespace Encompass
}
/// <summary>
/// Sends a message after the specified number of seconds.
/// Sends a message after the specified number of seconds, respecting time dilation.
/// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessageDelayed<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
protected void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
{
messageManager.AddMessageDelayed(message, time);
}
/// <summary>
/// Sends a message after the specified number of seconds, ignoring time dilation.
/// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
protected void SendMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
{
messageManager.AddMessageDelayedIgnoringTimeDilation(message, time);
}
// unparameterized version to enable dynamic dispatch
protected void SendMessage(IMessage message)
{
@ -695,24 +704,64 @@ namespace Encompass
if (!timeDilationPriority.HasValue) { throw new TimeDilationPriorityUndefinedException("Engines that activate time dilation must use the TimeDilationPriority attribute."); }
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, timeDilationPriority.Value);
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="easeInFunction">An easing function for the easing in of time dilation.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, timeDilationPriority.Value);
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
/// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param>
public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{
CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction, timeDilationPriority.Value);
}
/// <summary>
/// Activates the Encompass time dilation system.
/// If activating time dilation, make sure the TimeDilationPriority attribute is set or an exception will be thrown.
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
/// </summary>
/// <param name="factor">The time dilation factor, which is multiplied by real delta time.</param>
/// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param>
/// <param name="easeInFunction">An easing function for the easing in of time dilation.</param>
/// <param name="activeTime">The length of real time that time will be fully dilated.</param>
/// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param>
/// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param>
public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{
CheckTimeDilationPriorityExists();

View File

@ -6,13 +6,22 @@ namespace Encompass
{
internal class MessageManager
{
private TimeManager timeManager;
private readonly Dictionary<Type, List<IMessage>> messageTypeToMessages = new Dictionary<Type, List<IMessage>>();
private readonly List<(IMessage, double)> delayedMessages = new List<(IMessage, double)>();
private readonly List<(IMessage, double)> delayedMessagesIgnoringTimeDilation = new List<(IMessage, double)>();
public MessageManager(TimeManager timeManager)
{
this.timeManager = timeManager;
}
internal void RegisterMessageType(Type messageType)
{
if (!messageTypeToMessages.ContainsKey(messageType)) {
if (!messageTypeToMessages.ContainsKey(messageType))
{
messageTypeToMessages.Add(messageType, new List<IMessage>());
}
}
@ -31,9 +40,11 @@ namespace Encompass
delayedMessages.Add((message, time));
}
internal void AddMessage<TMessage>(IMessage message) where TMessage : struct, IMessage
internal void AddMessageDelayedIgnoringTimeDilation(IMessage message, double time)
{
messageTypeToMessages[typeof(TMessage)].Add(message);
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
delayedMessagesIgnoringTimeDilation.Add((message, time));
}
internal void ClearMessages()
@ -50,7 +61,7 @@ namespace Encompass
{
var (message, time) = delayedMessages[i];
var updatedTime = time - dt;
var updatedTime = time - (dt * timeManager.TimeDilationFactor);
if (updatedTime <= 0)
{
@ -62,6 +73,23 @@ namespace Encompass
delayedMessages[i] = (message, updatedTime);
}
}
for (int i = delayedMessagesIgnoringTimeDilation.Count - 1; i >= 0; i--)
{
var (message, time) = delayedMessagesIgnoringTimeDilation[i];
var updatedTime = time - dt;
if (updatedTime <= 0)
{
AddMessage(message);
delayedMessagesIgnoringTimeDilation.RemoveAt(i);
}
else
{
delayedMessagesIgnoringTimeDilation[i] = (message, updatedTime);
}
}
}
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage

View File

@ -38,11 +38,11 @@ namespace Encompass
public WorldBuilder()
{
drawLayerManager = new DrawLayerManager();
timeManager = new TimeManager();
componentManager = new ComponentManager(drawLayerManager);
messageManager = new MessageManager();
messageManager = new MessageManager(timeManager);
componentMessageManager = new ComponentMessageManager();
entityManager = new EntityManager(componentManager, componentMessageManager);
timeManager = new TimeManager();
renderManager = new RenderManager(componentManager, drawLayerManager, entityManager);
}

View File

@ -672,7 +672,7 @@ namespace Tests
foreach (var (component, entity) in ReadComponentsIncludingEntity<MockComponent>())
{
RemoveComponent<MockComponent>(entity);
SendMessageDelayed(new MockMessage { }, 1);
SendMessage(new MockMessage { }, 1);
}
}
}
@ -683,6 +683,7 @@ namespace Tests
resultMessages.Clear();
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new DelayedMessageEngine());
worldBuilder.AddEngine(new MessageReadEngine());
@ -701,6 +702,52 @@ namespace Tests
world.Update(0.5);
resultMessages.Should().BeEmpty();
world.Update(2);
resultMessages.Should().NotBeEmpty();
resultMessages.First().Should().BeOfType<MockMessage>();
}
[Reads(typeof(MockComponent))]
class DelayedMessageIgnoringTimeDilationEngine : Engine
{
public override void Update(double dt)
{
foreach (var (component, entity) in ReadComponentsIncludingEntity<MockComponent>())
{
RemoveComponent<MockComponent>(entity);
SendMessageIgnoringTimeDilation(new MockMessage { }, 1);
}
}
}
[Test]
public void EngineSendMessageDelayedIgnoringTimeDilation()
{
resultMessages.Clear();
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new DelayedMessageIgnoringTimeDilationEngine());
worldBuilder.AddEngine(new MessageReadEngine());
var entity = worldBuilder.CreateEntity();
worldBuilder.SetComponent(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>();
}