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>
|
||||
protected void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
messageManager.AddMessageDelayed(message, time);
|
||||
messageManager.AddMessage(message, time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -459,20 +459,7 @@ namespace Encompass
|
|||
/// <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)
|
||||
{
|
||||
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<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
|
||||
{
|
||||
return componentUpdateManager.AddPendingComponent<TComponent>(entity, component, priority);
|
||||
return componentUpdateManager.AddPendingComponent(entity, component, priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -509,7 +496,7 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return ReadMessages<TMessage>().First();
|
||||
return messageManager.First<TMessage>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -525,7 +512,7 @@ namespace Encompass
|
|||
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>
|
||||
|
|
|
@ -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<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)>();
|
||||
private readonly MessageStore messageStore = new MessageStore();
|
||||
|
||||
public MessageManager(TimeManager timeManager)
|
||||
{
|
||||
this.timeManager = timeManager;
|
||||
}
|
||||
|
||||
internal void RegisterMessageType(Type messageType)
|
||||
internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||
{
|
||||
if (!messageTypeToMessages.ContainsKey(messageType))
|
||||
{
|
||||
messageTypeToMessages.Add(messageType, new List<IMessage>());
|
||||
}
|
||||
messageStore.AddMessage<TMessage>(message);
|
||||
}
|
||||
|
||||
internal void AddMessage(IMessage message)
|
||||
internal void AddMessage<TMessage>(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>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
|
||||
|
||||
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));
|
||||
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<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return messageTypeToMessages.ContainsKey(typeof(TMessage)) ?
|
||||
messageTypeToMessages[typeof(TMessage)].Cast<TMessage>() :
|
||||
Enumerable.Empty<TMessage>();
|
||||
return messageStore.All<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>
|
||||
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
messageManager.AddMessageDelayed(message, time);
|
||||
messageManager.AddMessage<TMessage>(message, time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue