From d45295ae87616cd11bb77fd5200bdc8da6363f38 Mon Sep 17 00:00:00 2001 From: thatcosmonaut Date: Thu, 21 Nov 2019 14:22:10 -0800 Subject: [PATCH] messages with time dilation system --- encompass-cs/Engine.cs | 53 ++++++++++++++++++++++++++++++++-- encompass-cs/MessageManager.cs | 36 ++++++++++++++++++++--- encompass-cs/WorldBuilder.cs | 4 +-- test/EngineTest.cs | 49 ++++++++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 9 deletions(-) diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index e26146f..9ec8870 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -554,14 +554,23 @@ namespace Encompass } /// - /// Sends a message after the specified number of seconds. + /// Sends a message after the specified number of seconds, respecting time dilation. /// /// The time in seconds that will elapse before the message is sent. - protected void SendMessageDelayed(TMessage message, double time) where TMessage : struct, IMessage + protected void SendMessage(TMessage message, double time) where TMessage : struct, IMessage { messageManager.AddMessageDelayed(message, time); } + /// + /// Sends a message after the specified number of seconds, ignoring time dilation. + /// + /// The time in seconds that will elapse before the message is sent. + protected void SendMessageIgnoringTimeDilation(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."); } } + /// + /// 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. + /// + /// The time dilation factor, which is multiplied by real delta time. + /// The time that will elapse before time is fully dilated, in real time. + /// The length of real time that time will be fully dilated. + /// The time that will elapse before time is fully undilated. public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime) { CheckTimeDilationPriorityExists(); timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, timeDilationPriority.Value); } + /// + /// 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. + /// + /// The time dilation factor, which is multiplied by real delta time. + /// The time that will elapse before time is fully dilated, in real time. + /// An easing function for the easing in of time dilation. + /// The length of real time that time will be fully dilated. + /// The time that will elapse before time is fully undilated. public void ActivateTimeDilation(double factor, double easeInTime, System.Func easeInFunction, double activeTime, double easeOutTime) { CheckTimeDilationPriorityExists(); timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, timeDilationPriority.Value); } + /// + /// 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. + /// + /// The time dilation factor, which is multiplied by real delta time. + /// The time that will elapse before time is fully dilated, in real time. + /// The length of real time that time will be fully dilated. + /// The time that will elapse before time is fully undilated. + /// An easing function for the easing out of time dilation. public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func easeOutFunction) { CheckTimeDilationPriorityExists(); timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction, timeDilationPriority.Value); } + /// + /// 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. + /// + /// The time dilation factor, which is multiplied by real delta time. + /// The time that will elapse before time is fully dilated, in real time. + /// An easing function for the easing in of time dilation. + /// The length of real time that time will be fully dilated. + /// The time that will elapse before time is fully undilated. + /// An easing function for the easing out of time dilation. public void ActivateTimeDilation(double factor, double easeInTime, System.Func easeInFunction, double activeTime, double easeOutTime, System.Func easeOutFunction) { CheckTimeDilationPriorityExists(); diff --git a/encompass-cs/MessageManager.cs b/encompass-cs/MessageManager.cs index 1f86cb9..7846092 100644 --- a/encompass-cs/MessageManager.cs +++ b/encompass-cs/MessageManager.cs @@ -6,13 +6,22 @@ namespace Encompass { internal class MessageManager { + private TimeManager timeManager; + private readonly Dictionary> messageTypeToMessages = new Dictionary>(); 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()); } } @@ -31,9 +40,11 @@ namespace Encompass delayedMessages.Add((message, time)); } - internal void AddMessage(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()); } + + 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 GetMessagesByType() where TMessage : struct, IMessage diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 8e1d510..a44e452 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -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); } diff --git a/test/EngineTest.cs b/test/EngineTest.cs index c23f6e9..849371a 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -672,7 +672,7 @@ namespace Tests foreach (var (component, entity) in ReadComponentsIncludingEntity()) { RemoveComponent(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(); + } + + [Reads(typeof(MockComponent))] + class DelayedMessageIgnoringTimeDilationEngine : Engine + { + public override void Update(double dt) + { + foreach (var (component, entity) in ReadComponentsIncludingEntity()) + { + RemoveComponent(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(); }