perf: reduced network manager memory allocations
This commit is contained in:
parent
8901a5469f
commit
f3ff1b74d2
@ -10,6 +10,12 @@ namespace Syntriax.Engine.Network;
|
||||
public class NetworkManager : UniverseObject, INetworkManager
|
||||
{
|
||||
private INetworkCommunicator networkCommunicator = null!;
|
||||
|
||||
private readonly Dictionary<Type, Dictionary<Type, List<DelegateData>>> clientListenerDelegates = [];
|
||||
private readonly Dictionary<Type, Dictionary<Type, List<DelegateData>>> serverListenerDelegates = [];
|
||||
|
||||
private readonly Dictionary<Type, Dictionary<string, Event<string, object>>> clientPacketListeners = [];
|
||||
private readonly Dictionary<Type, Dictionary<string, Event<string, object>>> serverPacketListeners = [];
|
||||
private readonly List<(Type packetType, Delegate callback)> delegates = [];
|
||||
|
||||
public INetworkCommunicator NetworkCommunicator
|
||||
@ -28,9 +34,6 @@ public class NetworkManager : UniverseObject, INetworkManager
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<Type, Dictionary<string, Event<string, object>>> clientPacketListeners = [];
|
||||
private readonly Dictionary<Type, Dictionary<string, Event<string, object>>> serverPacketListeners = [];
|
||||
|
||||
private readonly Dictionary<string, INetworkEntity> _networkEntities = [];
|
||||
public IReadOnlyDictionary<string, INetworkEntity> NetworkEntities => _networkEntities;
|
||||
|
||||
@ -39,13 +42,41 @@ public class NetworkManager : UniverseObject, INetworkManager
|
||||
|
||||
public NetworkManager()
|
||||
{
|
||||
CacheDelegates();
|
||||
CachePacketDelegates();
|
||||
CacheListenerDelegates();
|
||||
|
||||
_networkEntityCollector.OnCollected.AddListener(OnCollected);
|
||||
_networkEntityCollector.OnRemoved.AddListener(OnRemoved);
|
||||
}
|
||||
|
||||
private void CacheDelegates()
|
||||
private void CacheListenerDelegates()
|
||||
{
|
||||
foreach (Type clientListenerClass in GetClassesImplementing(typeof(IPacketListenerClient<>)))
|
||||
{
|
||||
Dictionary<Type, List<DelegateData>> clientInterfaceListeners = [];
|
||||
clientListenerDelegates.Add(clientListenerClass, clientInterfaceListeners);
|
||||
foreach (Type clientListenerInterface in GetInterfacesImplementing(clientListenerClass, typeof(IPacketListenerClient<>)))
|
||||
{
|
||||
Type clientListenerParameterType = clientListenerInterface.GetGenericArguments().First();
|
||||
List<DelegateData> delegateDataList = clientListenerInterface.GetMethods().Where(m => m.Name == nameof(IPacketListenerClient<INetworkEntity>.OnClientPacketArrived)).Select(m => new DelegateData(clientListenerParameterType, m)).ToList();
|
||||
clientInterfaceListeners.Add(clientListenerParameterType, delegateDataList);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Type serverListenerClass in GetClassesImplementing(typeof(IPacketListenerServer<>)))
|
||||
{
|
||||
Dictionary<Type, List<DelegateData>> serverInterfaceListeners = [];
|
||||
serverListenerDelegates.Add(serverListenerClass, serverInterfaceListeners);
|
||||
foreach (Type serverListenerInterface in GetInterfacesImplementing(serverListenerClass, typeof(IPacketListenerServer<>)))
|
||||
{
|
||||
Type serverListenerParameterType = serverListenerInterface.GetGenericArguments().First();
|
||||
List<DelegateData> delegateDataList = serverListenerInterface.GetMethods().Where(m => m.Name == nameof(IPacketListenerServer<INetworkEntity>.OnServerPacketArrived)).Select(m => new DelegateData(serverListenerParameterType, m)).ToList();
|
||||
serverInterfaceListeners.Add(serverListenerParameterType, delegateDataList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CachePacketDelegates()
|
||||
{
|
||||
// Find network packets implementing INetworkPacket
|
||||
IEnumerable<Type> packetTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
|
||||
@ -91,6 +122,22 @@ public class NetworkManager : UniverseObject, INetworkManager
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetClassesImplementing(Type type)
|
||||
=> AppDomain.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.SelectMany(a =>
|
||||
a.GetTypes().Where(
|
||||
t => t.GetInterfaces().Any(
|
||||
i => i.IsGenericType && i.GetGenericTypeDefinition() == type
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
private static IEnumerable<Type> GetInterfacesImplementing(Type type, Type interfaceType)
|
||||
=> type.GetInterfaces().Where(
|
||||
i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType
|
||||
);
|
||||
|
||||
private void OnPacketReceived<T>(string senderClientId, T entityDataPacket)
|
||||
{
|
||||
Type packetType = typeof(T);
|
||||
@ -128,37 +175,35 @@ public class NetworkManager : UniverseObject, INetworkManager
|
||||
if (!_networkEntities.TryAdd(collectedBehaviour.Id, collectedBehaviour))
|
||||
throw new($"Unable to add {collectedBehaviour.Id} to {nameof(NetworkManager)}");
|
||||
|
||||
foreach (Type clientListenerType in collectedBehaviour.GetType().GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketListenerClient<>)))
|
||||
{
|
||||
Type clientListenerParameterType = clientListenerType.GetGenericArguments().First();
|
||||
MethodInfo clientListenerReceiveMethod = clientListenerType.GetMethods().First(m => m.Name == nameof(IPacketListenerClient<INetworkEntity>.OnClientPacketArrived));
|
||||
if (clientListenerDelegates.TryGetValue(collectedBehaviour.GetType(), out Dictionary<Type, List<DelegateData>>? clientInterfaceDelegates))
|
||||
foreach ((Type clientListenerInterfaceType, List<DelegateData> clientDelegateDataList) in clientInterfaceDelegates)
|
||||
foreach ((Type parameterType, MethodInfo receiveMethod) in clientDelegateDataList)
|
||||
{
|
||||
if (!clientPacketListeners.TryGetValue(parameterType, out Dictionary<string, Event<string, object>>? clientListeners))
|
||||
{
|
||||
clientListeners = [];
|
||||
clientPacketListeners.Add(parameterType, clientListeners);
|
||||
}
|
||||
|
||||
if (!clientPacketListeners.TryGetValue(clientListenerParameterType, out Dictionary<string, Event<string, object>>? clientListeners))
|
||||
{
|
||||
clientListeners = [];
|
||||
clientPacketListeners.Add(clientListenerParameterType, clientListeners);
|
||||
}
|
||||
Event<string, object> clientListenerEvent = new();
|
||||
clientListenerEvent.AddListener((sender, @object) => receiveMethod.Invoke(collectedBehaviour, [@object]));
|
||||
clientListeners.Add(collectedBehaviour.Id, clientListenerEvent);
|
||||
}
|
||||
|
||||
Event<string, object> clientListenerEvent = new();
|
||||
clientListenerEvent.AddListener((sender, @object) => clientListenerReceiveMethod.Invoke(collectedBehaviour, [@object]));
|
||||
clientListeners.Add(collectedBehaviour.Id, clientListenerEvent);
|
||||
}
|
||||
if (serverListenerDelegates.TryGetValue(collectedBehaviour.GetType(), out Dictionary<Type, List<DelegateData>>? serverInterfaceDelegates))
|
||||
foreach ((Type serverListenerInterfaceType, List<DelegateData> serverDelegateDataList) in serverInterfaceDelegates)
|
||||
foreach ((Type parameterType, MethodInfo receiveMethod) in serverDelegateDataList)
|
||||
{
|
||||
if (!serverPacketListeners.TryGetValue(parameterType, out Dictionary<string, Event<string, object>>? serverListeners))
|
||||
{
|
||||
serverListeners = [];
|
||||
serverPacketListeners.Add(parameterType, serverListeners);
|
||||
}
|
||||
|
||||
foreach (Type serverListenerType in collectedBehaviour.GetType().GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketListenerServer<>)))
|
||||
{
|
||||
Type serverListenerParameterType = serverListenerType.GetGenericArguments().First();
|
||||
MethodInfo serverListenerReceiveMethod = serverListenerType.GetMethods().First(m => m.Name == nameof(IPacketListenerServer<INetworkEntity>.OnServerPacketArrived));
|
||||
|
||||
if (!serverPacketListeners.TryGetValue(serverListenerParameterType, out Dictionary<string, Event<string, object>>? serverListeners))
|
||||
{
|
||||
serverListeners = [];
|
||||
serverPacketListeners.Add(serverListenerParameterType, serverListeners);
|
||||
}
|
||||
|
||||
Event<string, object> serverListenerEvent = new();
|
||||
serverListenerEvent.AddListener((sender, @object) => serverListenerReceiveMethod.Invoke(collectedBehaviour, [sender, @object]));
|
||||
serverListeners.Add(collectedBehaviour.Id, serverListenerEvent);
|
||||
}
|
||||
Event<string, object> serverListenerEvent = new();
|
||||
serverListenerEvent.AddListener((sender, @object) => receiveMethod.Invoke(collectedBehaviour, [sender, @object]));
|
||||
serverListeners.Add(collectedBehaviour.Id, serverListenerEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRemoved(IBehaviourCollector<INetworkEntity> sender, IBehaviourCollector<INetworkEntity>.BehaviourRemovedArguments args)
|
||||
@ -172,4 +217,10 @@ public class NetworkManager : UniverseObject, INetworkManager
|
||||
_networkEntityCollector.Assign(universe);
|
||||
NetworkCommunicator = this.GetRequiredUniverseObjectInParent<INetworkCommunicator>();
|
||||
}
|
||||
|
||||
private record struct DelegateData(Type ParameterType, MethodInfo ReceiveMethod)
|
||||
{
|
||||
public static implicit operator (Type ParameterType, MethodInfo ReceiveMethod)(DelegateData value) => (value.ParameterType, value.ReceiveMethod);
|
||||
public static implicit operator DelegateData((Type ParameterType, MethodInfo ReceiveMethod) value) => new(value.ParameterType, value.ReceiveMethod);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user