using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using LiteNetLib; using LiteNetLib.Utils; using Syntriax.Engine.Core; namespace Syntriax.Engine.Network; public abstract class LiteNetLibCommunicatorBase : UniverseObject, INetworkCommunicator { public event INetworkCommunicator.OnPacketReceivedDelegate? OnPacketReceived = null; protected readonly NetPacketProcessor netPacketProcessor = new(); public EventBasedNetListener Listener { get; private set; } = null!; public NetManager Manager { get; private set; } = null!; public INetworkCommunicator Stop() { Manager.Stop(); return this; } protected override void OnEnteringUniverse(IUniverse universe) { universe.OnPreUpdate += PollEvents; } protected override void OnExitingUniverse(IUniverse universe) { universe.OnPreUpdate -= PollEvents; Stop(); } private void PollEvents(IUniverse sender, UniverseTime engineTime) => Manager.PollEvents(); protected virtual void OnPacketArrived(T packet, NetPeer peer) where T : INetworkPacket { OnPacketReceived?.Invoke(this, packet, peer.Id.ToString()); } private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod) { try { netPacketProcessor.ReadAllPackets(reader, peer); } catch { } } private void SetupPackets() { // Find network packets implementing INetworkPacket IEnumerable packetTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()) .Where(t => typeof(INetworkPacket).IsAssignableFrom(t) && !t.IsInterface); MethodInfo subscribeReusableMethod = typeof(NetPacketProcessor) .GetMethods() .FirstOrDefault(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>) )!; 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) { var genericOnPacketArrivedMethod = onPacketArrivedMethod.MakeGenericMethod(packetType); 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]); } } public LiteNetLibCommunicatorBase() { Listener = new EventBasedNetListener(); Manager = new NetManager(Listener); Listener.NetworkReceiveEvent += NetworkReceiveEvent; SetupPackets(); } }