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> /// <summary>
/// Sends a message after the specified number of seconds. /// Sends a message after the specified number of seconds, respecting time dilation.
/// </summary> /// </summary>
/// <param name="time">The time in seconds that will elapse before the message is sent.</param> /// <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); 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 // unparameterized version to enable dynamic dispatch
protected void SendMessage(IMessage message) 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."); } 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) public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime)
{ {
CheckTimeDilationPriorityExists(); CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, timeDilationPriority.Value); 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) public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime)
{ {
CheckTimeDilationPriorityExists(); CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, timeDilationPriority.Value); 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) public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction)
{ {
CheckTimeDilationPriorityExists(); CheckTimeDilationPriorityExists();
timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction, timeDilationPriority.Value); 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) 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(); CheckTimeDilationPriorityExists();

View File

@ -6,13 +6,22 @@ namespace Encompass
{ {
internal class MessageManager internal class MessageManager
{ {
private TimeManager timeManager;
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)>(); 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) internal void RegisterMessageType(Type messageType)
{ {
if (!messageTypeToMessages.ContainsKey(messageType)) { if (!messageTypeToMessages.ContainsKey(messageType))
{
messageTypeToMessages.Add(messageType, new List<IMessage>()); messageTypeToMessages.Add(messageType, new List<IMessage>());
} }
} }
@ -31,9 +40,11 @@ namespace Encompass
delayedMessages.Add((message, time)); 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() internal void ClearMessages()
@ -50,7 +61,7 @@ namespace Encompass
{ {
var (message, time) = delayedMessages[i]; var (message, time) = delayedMessages[i];
var updatedTime = time - dt; var updatedTime = time - (dt * timeManager.TimeDilationFactor);
if (updatedTime <= 0) if (updatedTime <= 0)
{ {
@ -62,6 +73,23 @@ namespace Encompass
delayedMessages[i] = (message, updatedTime); 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 internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage

View File

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

View File

@ -672,7 +672,7 @@ namespace Tests
foreach (var (component, entity) in ReadComponentsIncludingEntity<MockComponent>()) foreach (var (component, entity) in ReadComponentsIncludingEntity<MockComponent>())
{ {
RemoveComponent<MockComponent>(entity); RemoveComponent<MockComponent>(entity);
SendMessageDelayed(new MockMessage { }, 1); SendMessage(new MockMessage { }, 1);
} }
} }
} }
@ -683,6 +683,7 @@ namespace Tests
resultMessages.Clear(); resultMessages.Clear();
var worldBuilder = new WorldBuilder(); var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine(new ActivateTimeDilationEngine());
worldBuilder.AddEngine(new DelayedMessageEngine()); worldBuilder.AddEngine(new DelayedMessageEngine());
worldBuilder.AddEngine(new MessageReadEngine()); worldBuilder.AddEngine(new MessageReadEngine());
@ -701,6 +702,52 @@ namespace Tests
world.Update(0.5); 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.Should().NotBeEmpty();
resultMessages.First().Should().BeOfType<MockMessage>(); resultMessages.First().Should().BeOfType<MockMessage>();
} }