diff --git a/Shared/Network/Abstract/INetworkCommunicator.cs b/Shared/Network/Abstract/INetworkCommunicator.cs index 4152c8d..c2035e7 100644 --- a/Shared/Network/Abstract/INetworkCommunicator.cs +++ b/Shared/Network/Abstract/INetworkCommunicator.cs @@ -4,16 +4,16 @@ public interface INetworkCommunicator { event OnPacketReceivedDelegate? OnPacketReceived; - void Stop(); + INetworkCommunicator Stop(); delegate void OnPacketReceivedDelegate(INetworkCommunicator sender, object packet, string from); } public interface INetworkCommunicatorClient : INetworkCommunicator { - void Connect(string address, int port, string? password = null); + INetworkCommunicatorClient Connect(string address, int port, string? password = null); - void SendToServer(INetworkPacket packet); + INetworkCommunicatorClient SendToServer(T packet) where T : class, new(); } public interface INetworkCommunicatorServer : INetworkCommunicator @@ -22,7 +22,7 @@ public interface INetworkCommunicatorServer : INetworkCommunicator int MaxConnectionCount { get; } int Port { get; } - void Start(int port, int maxConnectionCount, string? password = null); + INetworkCommunicatorServer Start(int port, int maxConnectionCount, string? password = null); - void SendToClient(string to, INetworkPacket packet); + INetworkCommunicatorServer SendToClient(string to, T packet) where T : class, new(); } diff --git a/Shared/Network/Abstract/INetworkManager.cs b/Shared/Network/Abstract/INetworkManager.cs index 93ad5cf..3f9e4db 100644 --- a/Shared/Network/Abstract/INetworkManager.cs +++ b/Shared/Network/Abstract/INetworkManager.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Syntriax.Engine.Core; namespace Syntriax.Engine.Network; diff --git a/Shared/Network/LiteNetLibClient.cs b/Shared/Network/LiteNetLibClient.cs new file mode 100644 index 0000000..19a5d32 --- /dev/null +++ b/Shared/Network/LiteNetLibClient.cs @@ -0,0 +1,28 @@ +using LiteNetLib.Utils; + +namespace Syntriax.Engine.Network; + +public class LiteNetLibClient : LiteNetLibCommunicatorBase, INetworkCommunicatorClient +{ + private readonly NetDataWriter netDataWriter = new(); + + public INetworkCommunicatorClient Connect(string address, int port, string? password = null) + { + if (!IsInUniverse) + throw new($"{nameof(LiteNetLibClient)} must be in an universe to connect"); + + Manager.Start(); + Manager.Connect(address, port, password ?? string.Empty); + + return this; + } + + public INetworkCommunicatorClient SendToServer(T packet) where T : class, new() + { + netDataWriter.Reset(); + netPacketProcessor.Write(netDataWriter, packet); + Manager.FirstPeer.Send(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered); + + return this; + } +} diff --git a/Shared/Network/NetworkBase.cs b/Shared/Network/LiteNetLibCommunicatorBase.cs similarity index 53% rename from Shared/Network/NetworkBase.cs rename to Shared/Network/LiteNetLibCommunicatorBase.cs index 42d4160..f4a55b1 100644 --- a/Shared/Network/NetworkBase.cs +++ b/Shared/Network/LiteNetLibCommunicatorBase.cs @@ -10,7 +10,7 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Network; -public abstract class NetworkBase : UniverseObject, INetworkCommunicator +public abstract class LiteNetLibCommunicatorBase : UniverseObject, INetworkCommunicator { public event INetworkCommunicator.OnPacketReceivedDelegate? OnPacketReceived = null; @@ -19,7 +19,11 @@ public abstract class NetworkBase : UniverseObject, INetworkCommunicator public EventBasedNetListener Listener { get; private set; } = null!; public NetManager Manager { get; private set; } = null!; - public void Stop() => Manager.Stop(); + public INetworkCommunicator Stop() + { + Manager.Stop(); + return this; + } protected override void OnEnteringUniverse(IUniverse universe) { @@ -34,8 +38,7 @@ public abstract class NetworkBase : UniverseObject, INetworkCommunicator } private void PollEvents(IUniverse sender, UniverseTime engineTime) => Manager.PollEvents(); - - private void OnPacketArrived(INetworkPacket packet, NetPeer peer) + protected virtual void OnPacketArrived(T packet, NetPeer peer) where T : INetworkPacket { OnPacketReceived?.Invoke(this, packet, peer.Id.ToString()); } @@ -45,54 +48,42 @@ public abstract class NetworkBase : UniverseObject, INetworkCommunicator try { netPacketProcessor.ReadAllPackets(reader, peer); } catch { } } - private void SetupPackets() { - #region Packet Types Registration - IEnumerable packetTypes = Assembly.GetExecutingAssembly().GetTypes() + // Find network packets implementing INetworkPacket + IEnumerable packetTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) .Where(t => typeof(INetworkPacket).IsAssignableFrom(t) && !t.IsInterface); - MethodInfo registerPacketTypeMethodInfo = typeof(NetPacketProcessor).GetMethod(nameof(NetPacketProcessor.RegisterNestedType), BindingFlags.Instance)!; - foreach (Type packetType in packetTypes) - { - MethodInfo genericRegisterPacketTypeMethodInfo = registerPacketTypeMethodInfo?.MakeGenericMethod(packetType)!; - genericRegisterPacketTypeMethodInfo.Invoke(netPacketProcessor, null); - } - #endregion - - #region Deserialization Callback via netPacketProcessor.SubscribeReusable to OnPacketArrived - MethodInfo subscribeMethod = netPacketProcessor.GetType() + MethodInfo subscribeReusableMethod = typeof(NetPacketProcessor) .GetMethods() - .Where(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable)) - .FirstOrDefault(m => + .FirstOrDefault(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>) )!; - MethodInfo packetArrivedMethod = typeof(NetworkBase) + MethodInfo onPacketArrivedMethod = typeof(LiteNetLibCommunicatorBase) .GetMethod(nameof(OnPacketArrived), BindingFlags.NonPublic | BindingFlags.Instance)!; + // Register all network packets by calling the method bellow where T is our found network packet type + // NetPacketProcessor.SubscribeReusable(Action onReceive) foreach (var packetType in packetTypes) { - MethodInfo genericSubscribeMethod = subscribeMethod.MakeGenericMethod(packetType, typeof(NetPeer)); + var genericOnPacketArrivedMethod = onPacketArrivedMethod.MakeGenericMethod(packetType); - Action handler = (packet, peer) => - { - MethodInfo handlerMethod = packetArrivedMethod.MakeGenericMethod(packetType); - handlerMethod.Invoke(this, [packet, peer]); - }; - genericSubscribeMethod.Invoke(netPacketProcessor, [handler]); + var delegateType = typeof(Action<,>).MakeGenericType(packetType, typeof(NetPeer)); + var delegateHandler = Delegate.CreateDelegate(delegateType, this, genericOnPacketArrivedMethod); + + var genericSubscribeReusableMethod = subscribeReusableMethod.MakeGenericMethod(packetType, typeof(NetPeer)); + genericSubscribeReusableMethod.Invoke(netPacketProcessor, [delegateHandler]); } - #endregion } - public NetworkBase() + public LiteNetLibCommunicatorBase() { Listener = new EventBasedNetListener(); Manager = new NetManager(Listener); Listener.NetworkReceiveEvent += NetworkReceiveEvent; - SetupPackets(); } } diff --git a/Shared/Network/NetworkServer.cs b/Shared/Network/LiteNetLibServer.cs similarity index 64% rename from Shared/Network/NetworkServer.cs rename to Shared/Network/LiteNetLibServer.cs index d44474b..6efe0e7 100644 --- a/Shared/Network/NetworkServer.cs +++ b/Shared/Network/LiteNetLibServer.cs @@ -5,7 +5,7 @@ using LiteNetLib.Utils; namespace Syntriax.Engine.Network; -public class NetworkServer : NetworkBase, INetworkCommunicatorServer +public class LiteNetLibServer : LiteNetLibCommunicatorBase, INetworkCommunicatorServer { public string Password { get; private set; } = string.Empty; public int MaxConnectionCount { get; private set; } = 2; @@ -13,8 +13,8 @@ public class NetworkServer : NetworkBase, INetworkCommunicatorServer private readonly NetDataWriter netDataWriter = new(); - public NetworkServer() : this(8888, 2) { } - public NetworkServer(int port, int maxConnectionCount) : base() + public LiteNetLibServer() : this(8888, 2) { } + public LiteNetLibServer(int port, int maxConnectionCount) : base() { MaxConnectionCount = maxConnectionCount; Port = port; @@ -28,33 +28,34 @@ public class NetworkServer : NetworkBase, INetworkCommunicatorServer }; } - public void Start(int port, int maxConnectionCount, string? password = null) + public INetworkCommunicatorServer Start(int port, int maxConnectionCount, string? password = null) { if (!IsInUniverse) - throw new($"{nameof(NetworkServer)} must be in an universe to start"); + throw new($"{nameof(LiteNetLibServer)} must be in an universe to start"); Password = password ?? string.Empty; MaxConnectionCount = maxConnectionCount; Port = port; Manager.Start(port); + + return this; } - public void SendToClient(string to, INetworkPacket packet) + public INetworkCommunicatorServer SendToClient(string to, T packet) where T : class, new() { - if (packet is not INetSerializable netSerializable) - throw new($"Packet trying to be sent to the server is not compatible with LiteNetLib"); - bool isBroadcastToAll = to.CompareTo("*") == 0; netDataWriter.Reset(); - netPacketProcessor.WriteNetSerializable(netDataWriter, ref netSerializable); + netPacketProcessor.Write(netDataWriter, packet); if (isBroadcastToAll) Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); - else if (Manager.ConnectedPeerList.FirstOrDefault(p => p.Id.CompareTo(to) == 0) is NetPeer netPeer) + else if (Manager.ConnectedPeerList.FirstOrDefault(p => p.Id.ToString().CompareTo(to) == 0) is NetPeer netPeer) netPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); else throw new($"Peer {to} couldn't be found."); + + return this; } } diff --git a/Shared/Network/NetworkClient.cs b/Shared/Network/NetworkClient.cs deleted file mode 100644 index d9ebd4a..0000000 --- a/Shared/Network/NetworkClient.cs +++ /dev/null @@ -1,27 +0,0 @@ -using LiteNetLib.Utils; - -namespace Syntriax.Engine.Network; - -public class NetworkClient : NetworkBase, INetworkCommunicatorClient -{ - private readonly NetDataWriter netDataWriter = new(); - - public void Connect(string address, int port, string? password = null) - { - if (!IsInUniverse) - throw new($"{nameof(NetworkClient)} must be in an universe to connect"); - - Manager.Start(); - Manager.Connect(address, port, password ?? string.Empty); - } - - public void SendToServer(INetworkPacket packet) - { - if (packet is not INetSerializable netSerializable) - throw new($"Packet trying to be sent to the server is not compatible with LiteNetLib"); - - netDataWriter.Reset(); - netPacketProcessor.WriteNetSerializable(netDataWriter, ref netSerializable); - Manager.FirstPeer.Send(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered); - } -}