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 NetworkBase : 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 void Stop() => Manager.Stop(); 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(); private void OnPacketArrived(INetworkPacket packet, NetPeer peer) { 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() { #region Packet Types Registration IEnumerable packetTypes = Assembly.GetExecutingAssembly().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() .GetMethods() .Where(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable)) .FirstOrDefault(m => m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>) )!; MethodInfo packetArrivedMethod = typeof(NetworkBase) .GetMethod(nameof(OnPacketArrived), BindingFlags.NonPublic | BindingFlags.Instance)!; foreach (var packetType in packetTypes) { MethodInfo genericSubscribeMethod = subscribeMethod.MakeGenericMethod(packetType, typeof(NetPeer)); Action handler = (packet, peer) => { MethodInfo handlerMethod = packetArrivedMethod.MakeGenericMethod(packetType); handlerMethod.Invoke(this, [packet, peer]); }; genericSubscribeMethod.Invoke(netPacketProcessor, [handler]); } #endregion } public NetworkBase() { Listener = new EventBasedNetListener(); Manager = new NetManager(Listener); Listener.NetworkReceiveEvent += NetworkReceiveEvent; SetupPackets(); } }