diff --git a/Engine b/Engine index 86c9ed2..7a3202a 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 86c9ed2ba98e05f21a952b58c49af5954207e006 +Subproject commit 7a3202a053b6fd7c9adf9bc210bf8026f3412328 diff --git a/Shared/Network/NetworkManager.cs b/Shared/Network/NetworkManager.cs index fa5097d..bdf1d7a 100644 --- a/Shared/Network/NetworkManager.cs +++ b/Shared/Network/NetworkManager.cs @@ -15,11 +15,14 @@ public class NetworkManager : UniverseObject, INetworkManager private readonly Dictionary>> clientPacketArrivalMethods = []; private readonly Dictionary>> serverPacketArrivalMethods = []; - private readonly Dictionary>> clientPacketRouters = []; - private readonly Dictionary>> serverPacketRouters = []; + private readonly Dictionary> clientPacketRouters = []; + private readonly Dictionary> serverPacketRouters = []; private readonly List<(Type packetType, Delegate callback)> packetRetrievalDelegates = []; + private readonly Dictionary clearRoutesMethods = []; + private readonly Dictionary registerPacketListenersMethods = []; + private readonly Dictionary _networkEntities = []; public IReadOnlyDictionary NetworkEntities => _networkEntities; @@ -96,37 +99,41 @@ public class NetworkManager : UniverseObject, INetworkManager private static void BroadcastPacket( - Dictionary>> packetRouters, + Dictionary> packetRouters, string senderClientId, T entityDataPacket) { - if (!packetRouters.TryGetValue(entityDataPacket!.GetType(), out Dictionary>? routers)) + if (!packetRouters.TryGetValue(entityDataPacket!.GetType(), out Dictionary? routers)) return; - foreach ((string id, Event routerEvent) in routers) + foreach ((string id, object routerEventReference) in routers) + { + Event routerEvent = (Event)routerEventReference; routerEvent.Invoke(senderClientId, entityDataPacket!); + } } private static void RoutePacket( - Dictionary>> packetRouters, + Dictionary> packetRouters, string entityId, string senderClientId, T entityDataPacket) { - if (!packetRouters.TryGetValue(entityDataPacket!.GetType(), out Dictionary>? routers)) + if (!packetRouters.TryGetValue(entityDataPacket!.GetType(), out Dictionary? routers)) return; - if (!routers.TryGetValue(entityId, out Event? routerEvent)) + if (!routers.TryGetValue(entityId, out object? routerEventReference)) return; + Event routerEvent = (Event)routerEventReference; routerEvent.Invoke(senderClientId, entityDataPacket!); } #endregion #region Packet Routers - private static void RegisterPacketRoutersFor( + private void RegisterPacketRoutersFor( INetworkEntity behaviour, - Dictionary>> packetRouters, + Dictionary> packetRouters, Dictionary>> packetArrivalMethods, NetworkType networkType) { @@ -136,34 +143,44 @@ public class NetworkManager : UniverseObject, INetworkManager foreach ((Type packetType, List methods) in arrivalMethods) foreach (MethodInfo receiveMethod in methods) { - if (!packetRouters.TryGetValue(packetType, out Dictionary>? routers)) + if (!packetRouters.TryGetValue(packetType, out Dictionary? routers)) { routers = []; packetRouters.Add(packetType, routers); } - Event packetListenerEvent = new(); - RegisterPacketListenerEvent(behaviour, packetListenerEvent, receiveMethod, networkType); + object packetListenerEvent = CreateEventAndRegister(packetType, behaviour, networkType); routers.Add(behaviour.Id, packetListenerEvent); } } - private static void RegisterPacketListenerEvent( + private object CreateEventAndRegister(Type packetType, INetworkEntity behaviour, NetworkType networkType) + { + Type genericEventType = typeof(Event<,>).MakeGenericType(typeof(string), packetType); + object packetListenerEvent = Activator.CreateInstance(genericEventType)!; + + if (!registerPacketListenersMethods.TryGetValue(packetType, out MethodInfo? registerPacketListenerMethod)) + throw new($"{nameof(RegisterPacketListenerEvent)} for {packetType.Name} has not been cached."); + + registerPacketListenerMethod.Invoke(this, [behaviour, packetListenerEvent, networkType]); + return packetListenerEvent; + } + + private static void RegisterPacketListenerEvent( INetworkEntity behaviour, - Event packetListenerEvent, - MethodInfo receiveMethod, + Event packetListenerEvent, NetworkType networkType) { switch (networkType) { - case NetworkType.Client: packetListenerEvent.AddListener((sender, @object) => receiveMethod.Invoke(behaviour, [@object])); break; - case NetworkType.Server: packetListenerEvent.AddListener((sender, @object) => receiveMethod.Invoke(behaviour, [sender, @object])); break; + case NetworkType.Client: packetListenerEvent.AddListener((sender, packet) => ((IPacketListenerClient)behaviour).OnClientPacketArrived(packet)); break; + case NetworkType.Server: packetListenerEvent.AddListener((sender, packet) => ((IPacketListenerServer)behaviour).OnServerPacketArrived(sender, packet)); break; } } - private static void UnregisterPacketRoutersFor( + private void UnregisterPacketRoutersFor( INetworkEntity behaviour, - Dictionary>> packetRouters, + Dictionary> packetRouters, Dictionary>> packetArrivalMethods) { if (!packetArrivalMethods.TryGetValue(behaviour.GetType(), out Dictionary>? arrivalMethods)) @@ -171,16 +188,25 @@ public class NetworkManager : UniverseObject, INetworkManager foreach ((Type packetType, List methods) in arrivalMethods) { - if (!packetRouters.TryGetValue(packetType, out Dictionary>? routers)) + if (!packetRouters.TryGetValue(packetType, out Dictionary? routers)) continue; - if (!routers.TryGetValue(behaviour.Id, out Event? routerEvent)) + if (!routers.TryGetValue(behaviour.Id, out object? routerEventReference)) continue; - routers.Remove(behaviour.Id); - routerEvent.Clear(); + if (!clearRoutesMethods.TryGetValue(packetType, out MethodInfo? clearRouterMethod)) + continue; + + clearRouterMethod.Invoke(this, [routerEventReference]); } } + + private static void ClearRouter(object routerEventReference) + { + Event routerEvent = (Event)routerEventReference; + routerEvent.Clear(); + } + #endregion #region Engine Callbacks @@ -217,6 +243,7 @@ public class NetworkManager : UniverseObject, INetworkManager public NetworkManager() { CachePacketRetrievalDelegates(); + CacheRegistrationMethods(); CachePacketArrivalMethods(); _networkEntityCollector.OnCollected.AddListener(OnCollected); @@ -242,6 +269,22 @@ public class NetworkManager : UniverseObject, INetworkManager } } + private void CacheRegistrationMethods() + { + CacheRegistrationMethods(registerPacketListenersMethods, nameof(RegisterPacketListenerEvent)); + CacheRegistrationMethods(clearRoutesMethods, nameof(ClearRouter)); + } + + private void CacheRegistrationMethods(Dictionary registrationMethods, string methodName) + { + MethodInfo registerPacketMethod = typeof(NetworkManager).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static)!; + foreach ((Type packetType, Delegate callback) in packetRetrievalDelegates) + { + MethodInfo genericMethod = registerPacketMethod.MakeGenericMethod(packetType); + registrationMethods.Add(packetType, genericMethod); + } + } + private void CachePacketArrivalMethods() { CachePacketArrivalMethods(clientPacketArrivalMethods, typeof(IPacketListenerClient<>), nameof(IPacketListenerClient.OnClientPacketArrived));