diff --git a/encompass-cs/Collections/MessageStore.cs b/encompass-cs/Collections/MessageStore.cs new file mode 100644 index 0000000..12aef7b --- /dev/null +++ b/encompass-cs/Collections/MessageStore.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; + +namespace Encompass +{ + internal class MessageStore + { + private Dictionary Stores = new Dictionary(512); + + private void RegisterMessageType() where TMessage : struct, IMessage + { + Stores.Add(typeof(TMessage), new TypedMessageStore()); + } + + private TypedMessageStore Lookup() where TMessage : struct, IMessage + { + if (!Stores.ContainsKey(typeof(TMessage))) { RegisterMessageType(); } + return Stores[typeof(TMessage)] as TypedMessageStore; + } + + public void AddMessage(TMessage message) where TMessage : struct, IMessage + { + Lookup().Add(message); + } + + public void AddMessage(TMessage message, double time) where TMessage : struct, IMessage + { + Lookup().Add(message, time); + } + + public void AddMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage + { + Lookup().AddIgnoringTimeDilation(message, time); + } + + public TMessage First() where TMessage : struct, IMessage + { + return Lookup().First(); + } + + public IEnumerable All() where TMessage : struct, IMessage + { + return Lookup().All(); + } + + public bool Any() where TMessage : struct, IMessage + { + return Lookup().Any(); + } + + public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) + { + foreach (var store in Stores.Values) + { + store.ProcessDelayedMessages(dilatedDelta, realtimeDelta); + } + } + + public void ClearAll() + { + foreach (var store in Stores.Values) + { + store.Clear(); + } + } + } +} diff --git a/encompass-cs/Collections/TypedMessageStore.cs b/encompass-cs/Collections/TypedMessageStore.cs new file mode 100644 index 0000000..06fc648 --- /dev/null +++ b/encompass-cs/Collections/TypedMessageStore.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; + +namespace Encompass +{ + internal abstract class TypedMessageStore + { + public abstract void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta); + public abstract void Clear(); + } + + internal class TypedMessageStore : TypedMessageStore where TMessage : struct, IMessage + { + private readonly List store = new List(128); + private readonly List<(TMessage, double)> delayedStore = new List<(TMessage, double)>(128); + private readonly List<(TMessage, double)> delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128); + + public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) + { + for (int i = delayedStore.Count - 1; i >= 0; i--) + { + var (message, time) = delayedStore[i]; + + var updatedTime = time - dilatedDelta; + + if (updatedTime <= 0) + { + Add(message); + delayedStore.RemoveAt(i); + } + else + { + delayedStore[i] = (message, updatedTime); + } + } + + for (int i = delayedStoreIgnoringTimeDilation.Count - 1; i >= 0; i--) + { + var (message, time) = delayedStoreIgnoringTimeDilation[i]; + + var updatedTime = time - realtimeDelta; + + if (updatedTime <= 0) + { + Add(message); + delayedStoreIgnoringTimeDilation.RemoveAt(i); + } + else + { + delayedStoreIgnoringTimeDilation[i] = (message, updatedTime); + } + } + } + + public void Add(TMessage message) + { + store.Add(message); + } + + public void Add(TMessage message, double time) + { + delayedStore.Add((message, time)); + } + + public void AddIgnoringTimeDilation(TMessage message, double time) + { + delayedStoreIgnoringTimeDilation.Add((message, time)); + } + + public TMessage First() + { + return store[0]; + } + + public bool Any() + { + return store.Count > 0; + } + + public IEnumerable All() + { + return store; + } + + public override void Clear() + { + store.Clear(); + } + } +} diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 3c359dd..4bea453 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -450,7 +450,7 @@ namespace Encompass /// The time in seconds that will elapse before the message is sent. protected void SendMessage(TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessageDelayed(message, time); + messageManager.AddMessage(message, time); } /// @@ -459,20 +459,7 @@ namespace Encompass /// 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) - { - var type = message.GetType(); - - if (!sendTypes.Contains(type) || !type.IsValueType) - { - throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", GetType().Name, type.Name); - } - - messageManager.AddMessage(message); + messageManager.AddMessageIgnoringTimeDilation(message, time); } internal void AddExistingComponent(Entity entity, TComponent component) where TComponent : struct, IComponent @@ -482,7 +469,7 @@ namespace Encompass internal bool AddPendingComponent(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent { - return componentUpdateManager.AddPendingComponent(entity, component, priority); + return componentUpdateManager.AddPendingComponent(entity, component, priority); } /// @@ -509,7 +496,7 @@ namespace Encompass /// protected TMessage ReadMessage() where TMessage : struct, IMessage { - return ReadMessages().First(); + return messageManager.First(); } /// @@ -525,7 +512,7 @@ namespace Encompass throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name); } - return ReadMessages().Any(); + return messageManager.Any(); } /// diff --git a/encompass-cs/MessageManager.cs b/encompass-cs/MessageManager.cs index c967d67..7da56bf 100644 --- a/encompass-cs/MessageManager.cs +++ b/encompass-cs/MessageManager.cs @@ -1,102 +1,55 @@ -using System; using System.Collections.Generic; -using System.Linq; namespace Encompass { internal class MessageManager { private readonly 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)>(); + private readonly MessageStore messageStore = new MessageStore(); public MessageManager(TimeManager timeManager) { this.timeManager = timeManager; } - internal void RegisterMessageType(Type messageType) + internal void AddMessage(TMessage message) where TMessage : struct, IMessage { - if (!messageTypeToMessages.ContainsKey(messageType)) - { - messageTypeToMessages.Add(messageType, new List()); - } + messageStore.AddMessage(message); } - internal void AddMessage(IMessage message) + internal void AddMessage(TMessage message, double time) where TMessage : struct, IMessage { - var type = message.GetType(); - - messageTypeToMessages[type].Add(message); + messageStore.AddMessage(message, time); } - internal void AddMessageDelayed(IMessage message, double time) + internal void AddMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage { - if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List()); } - - delayedMessages.Add((message, time)); - } - - internal void AddMessageDelayedIgnoringTimeDilation(IMessage message, double time) - { - if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List()); } - - delayedMessagesIgnoringTimeDilation.Add((message, time)); + messageStore.AddMessageIgnoringTimeDilation(message, time); } internal void ClearMessages() { - foreach (var entry in messageTypeToMessages) - { - entry.Value.Clear(); - } + messageStore.ClearAll(); } internal void ProcessDelayedMessages(double dt) { - for (int i = delayedMessages.Count - 1; i >= 0; i--) - { - var (message, time) = delayedMessages[i]; - - var updatedTime = time - (dt * timeManager.TimeDilationFactor); - - if (updatedTime <= 0) - { - AddMessage(message); - delayedMessages.RemoveAt(i); - } - else - { - 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); - } - } + messageStore.ProcessDelayedMessages(dt * timeManager.TimeDilationFactor, dt); } internal IEnumerable GetMessagesByType() where TMessage : struct, IMessage { - return messageTypeToMessages.ContainsKey(typeof(TMessage)) ? - messageTypeToMessages[typeof(TMessage)].Cast() : - Enumerable.Empty(); + return messageStore.All(); + } + + internal bool Any() where TMessage : struct, IMessage + { + return messageStore.Any(); + } + + internal TMessage First() where TMessage : struct, IMessage + { + return messageStore.First(); } } } diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 925dbf4..331a08d 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -69,7 +69,7 @@ namespace Encompass /// public void SendMessage(TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessageDelayed(message, time); + messageManager.AddMessage(message, time); } /// @@ -111,11 +111,6 @@ namespace Encompass var messageReceiveTypes = engine.receiveTypes; var messageSendTypes = engine.sendTypes; - foreach (var messageType in messageReceiveTypes.Union(messageSendTypes)) - { - messageManager.RegisterMessageType(messageType); - } - foreach (var writePendingType in engine.writePendingTypes.Intersect(engine.readPendingTypes)) { throw new EngineSelfCycleException("Engine {0} both writes and reads pending Component {1}", engine.GetType().Name, writePendingType.Name);