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
|
public class NetworkManager : UniverseObject, INetworkManager
|
||||||
{
|
{
|
||||||
private INetworkCommunicator networkCommunicator = null!;
|
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 = [];
|
private readonly List<(Type packetType, Delegate callback)> delegates = [];
|
||||||
|
|
||||||
public INetworkCommunicator NetworkCommunicator
|
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 = [];
|
private readonly Dictionary<string, INetworkEntity> _networkEntities = [];
|
||||||
public IReadOnlyDictionary<string, INetworkEntity> NetworkEntities => _networkEntities;
|
public IReadOnlyDictionary<string, INetworkEntity> NetworkEntities => _networkEntities;
|
||||||
|
|
||||||
@ -39,13 +42,41 @@ public class NetworkManager : UniverseObject, INetworkManager
|
|||||||
|
|
||||||
public NetworkManager()
|
public NetworkManager()
|
||||||
{
|
{
|
||||||
CacheDelegates();
|
CachePacketDelegates();
|
||||||
|
CacheListenerDelegates();
|
||||||
|
|
||||||
_networkEntityCollector.OnCollected.AddListener(OnCollected);
|
_networkEntityCollector.OnCollected.AddListener(OnCollected);
|
||||||
_networkEntityCollector.OnRemoved.AddListener(OnRemoved);
|
_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
|
// Find network packets implementing INetworkPacket
|
||||||
IEnumerable<Type> packetTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
|
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)
|
private void OnPacketReceived<T>(string senderClientId, T entityDataPacket)
|
||||||
{
|
{
|
||||||
Type packetType = typeof(T);
|
Type packetType = typeof(T);
|
||||||
@ -128,35 +175,33 @@ public class NetworkManager : UniverseObject, INetworkManager
|
|||||||
if (!_networkEntities.TryAdd(collectedBehaviour.Id, collectedBehaviour))
|
if (!_networkEntities.TryAdd(collectedBehaviour.Id, collectedBehaviour))
|
||||||
throw new($"Unable to add {collectedBehaviour.Id} to {nameof(NetworkManager)}");
|
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<>)))
|
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)
|
||||||
{
|
{
|
||||||
Type clientListenerParameterType = clientListenerType.GetGenericArguments().First();
|
if (!clientPacketListeners.TryGetValue(parameterType, out Dictionary<string, Event<string, object>>? clientListeners))
|
||||||
MethodInfo clientListenerReceiveMethod = clientListenerType.GetMethods().First(m => m.Name == nameof(IPacketListenerClient<INetworkEntity>.OnClientPacketArrived));
|
|
||||||
|
|
||||||
if (!clientPacketListeners.TryGetValue(clientListenerParameterType, out Dictionary<string, Event<string, object>>? clientListeners))
|
|
||||||
{
|
{
|
||||||
clientListeners = [];
|
clientListeners = [];
|
||||||
clientPacketListeners.Add(clientListenerParameterType, clientListeners);
|
clientPacketListeners.Add(parameterType, clientListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event<string, object> clientListenerEvent = new();
|
Event<string, object> clientListenerEvent = new();
|
||||||
clientListenerEvent.AddListener((sender, @object) => clientListenerReceiveMethod.Invoke(collectedBehaviour, [@object]));
|
clientListenerEvent.AddListener((sender, @object) => receiveMethod.Invoke(collectedBehaviour, [@object]));
|
||||||
clientListeners.Add(collectedBehaviour.Id, clientListenerEvent);
|
clientListeners.Add(collectedBehaviour.Id, clientListenerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Type serverListenerType in collectedBehaviour.GetType().GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketListenerServer<>)))
|
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)
|
||||||
{
|
{
|
||||||
Type serverListenerParameterType = serverListenerType.GetGenericArguments().First();
|
if (!serverPacketListeners.TryGetValue(parameterType, out Dictionary<string, Event<string, object>>? serverListeners))
|
||||||
MethodInfo serverListenerReceiveMethod = serverListenerType.GetMethods().First(m => m.Name == nameof(IPacketListenerServer<INetworkEntity>.OnServerPacketArrived));
|
|
||||||
|
|
||||||
if (!serverPacketListeners.TryGetValue(serverListenerParameterType, out Dictionary<string, Event<string, object>>? serverListeners))
|
|
||||||
{
|
{
|
||||||
serverListeners = [];
|
serverListeners = [];
|
||||||
serverPacketListeners.Add(serverListenerParameterType, serverListeners);
|
serverPacketListeners.Add(parameterType, serverListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event<string, object> serverListenerEvent = new();
|
Event<string, object> serverListenerEvent = new();
|
||||||
serverListenerEvent.AddListener((sender, @object) => serverListenerReceiveMethod.Invoke(collectedBehaviour, [sender, @object]));
|
serverListenerEvent.AddListener((sender, @object) => receiveMethod.Invoke(collectedBehaviour, [sender, @object]));
|
||||||
serverListeners.Add(collectedBehaviour.Id, serverListenerEvent);
|
serverListeners.Add(collectedBehaviour.Id, serverListenerEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,4 +217,10 @@ public class NetworkManager : UniverseObject, INetworkManager
|
|||||||
_networkEntityCollector.Assign(universe);
|
_networkEntityCollector.Assign(universe);
|
||||||
NetworkCommunicator = this.GetRequiredUniverseObjectInParent<INetworkCommunicator>();
|
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