Engine-Pong/Shared/Network/LiteNetLibCommunicatorBase.cs

90 lines
3.2 KiB
C#

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>(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<Type> 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<T, NetPeer>(Action<T, NetPeer> 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();
}
}