optimize away boxing for messages
parent
a29251f3d8
commit
4a2771d6a2
|
@ -0,0 +1,67 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
internal class MessageStore
|
||||||
|
{
|
||||||
|
private Dictionary<Type, TypedMessageStore> Stores = new Dictionary<Type, TypedMessageStore>(512);
|
||||||
|
|
||||||
|
private void RegisterMessageType<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
Stores.Add(typeof(TMessage), new TypedMessageStore<TMessage>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypedMessageStore<TMessage> Lookup<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
if (!Stores.ContainsKey(typeof(TMessage))) { RegisterMessageType<TMessage>(); }
|
||||||
|
return Stores[typeof(TMessage)] as TypedMessageStore<TMessage>;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
Lookup<TMessage>().Add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
Lookup<TMessage>().Add(message, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
Lookup<TMessage>().AddIgnoringTimeDilation(message, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TMessage First<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
return Lookup<TMessage>().First();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TMessage> All<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
return Lookup<TMessage>().All();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Any<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
return Lookup<TMessage>().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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<TMessage> : TypedMessageStore where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
private readonly List<TMessage> store = new List<TMessage>(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<TMessage> All()
|
||||||
|
{
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear()
|
||||||
|
{
|
||||||
|
store.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -450,7 +450,7 @@ namespace Encompass
|
||||||
/// <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 SendMessage<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.AddMessage(message, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -459,20 +459,7 @@ namespace Encompass
|
||||||
/// <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 SendMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
protected void SendMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
messageManager.AddMessageDelayedIgnoringTimeDilation(message, time);
|
messageManager.AddMessageIgnoringTimeDilation(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
|
@ -482,7 +469,7 @@ namespace Encompass
|
||||||
|
|
||||||
internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentUpdateManager.AddPendingComponent<TComponent>(entity, component, priority);
|
return componentUpdateManager.AddPendingComponent(entity, component, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -509,7 +496,7 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
return ReadMessages<TMessage>().First();
|
return messageManager.First<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -525,7 +512,7 @@ namespace Encompass
|
||||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReadMessages<TMessage>().Any();
|
return messageManager.Any<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,102 +1,55 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
internal class MessageManager
|
internal class MessageManager
|
||||||
{
|
{
|
||||||
private readonly TimeManager timeManager;
|
private readonly TimeManager timeManager;
|
||||||
|
private readonly MessageStore messageStore = new MessageStore();
|
||||||
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)
|
public MessageManager(TimeManager timeManager)
|
||||||
{
|
{
|
||||||
this.timeManager = timeManager;
|
this.timeManager = timeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterMessageType(Type messageType)
|
internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
if (!messageTypeToMessages.ContainsKey(messageType))
|
messageStore.AddMessage<TMessage>(message);
|
||||||
{
|
|
||||||
messageTypeToMessages.Add(messageType, new List<IMessage>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddMessage(IMessage message)
|
internal void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
var type = message.GetType();
|
messageStore.AddMessage(message, time);
|
||||||
|
|
||||||
messageTypeToMessages[type].Add(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddMessageDelayed(IMessage message, double time)
|
internal void AddMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
|
messageStore.AddMessageIgnoringTimeDilation(message, time);
|
||||||
|
|
||||||
delayedMessages.Add((message, time));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddMessageDelayedIgnoringTimeDilation(IMessage message, double time)
|
|
||||||
{
|
|
||||||
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
|
|
||||||
|
|
||||||
delayedMessagesIgnoringTimeDilation.Add((message, time));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearMessages()
|
internal void ClearMessages()
|
||||||
{
|
{
|
||||||
foreach (var entry in messageTypeToMessages)
|
messageStore.ClearAll();
|
||||||
{
|
|
||||||
entry.Value.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ProcessDelayedMessages(double dt)
|
internal void ProcessDelayedMessages(double dt)
|
||||||
{
|
{
|
||||||
for (int i = delayedMessages.Count - 1; i >= 0; i--)
|
messageStore.ProcessDelayedMessages(dt * timeManager.TimeDilationFactor, dt);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
|
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
return messageTypeToMessages.ContainsKey(typeof(TMessage)) ?
|
return messageStore.All<TMessage>();
|
||||||
messageTypeToMessages[typeof(TMessage)].Cast<TMessage>() :
|
}
|
||||||
Enumerable.Empty<TMessage>();
|
|
||||||
|
internal bool Any<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
return messageStore.Any<TMessage>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TMessage First<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
return messageStore.First<TMessage>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
messageManager.AddMessageDelayed(message, time);
|
messageManager.AddMessage<TMessage>(message, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -111,11 +111,6 @@ namespace Encompass
|
||||||
var messageReceiveTypes = engine.receiveTypes;
|
var messageReceiveTypes = engine.receiveTypes;
|
||||||
var messageSendTypes = engine.sendTypes;
|
var messageSendTypes = engine.sendTypes;
|
||||||
|
|
||||||
foreach (var messageType in messageReceiveTypes.Union(messageSendTypes))
|
|
||||||
{
|
|
||||||
messageManager.RegisterMessageType(messageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var writePendingType in engine.writePendingTypes.Intersect(engine.readPendingTypes))
|
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);
|
throw new EngineSelfCycleException("Engine {0} both writes and reads pending Component {1}", engine.GetType().Name, writePendingType.Name);
|
||||||
|
|
Loading…
Reference in New Issue