146 lines
5.9 KiB
C#
146 lines
5.9 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
|
|
{
|
|
protected readonly NetPacketProcessor netPacketProcessor = new();
|
|
|
|
private readonly Dictionary<Type, Event<string, object>> listeners = [];
|
|
|
|
public EventBasedNetListener Listener { get; private set; } = null!;
|
|
public NetManager Manager { get; private set; } = null!;
|
|
|
|
public INetworkCommunicator Stop()
|
|
{
|
|
Manager.Stop();
|
|
return this;
|
|
}
|
|
|
|
protected override void OnExitingUniverse(IUniverse universe)
|
|
{
|
|
base.OnExitingUniverse(universe);
|
|
Stop();
|
|
}
|
|
|
|
protected virtual void OnPacketArrived<T>(T packet, NetPeer peer) where T : INetworkPacket
|
|
{
|
|
if (!listeners.TryGetValue(typeof(T), out Event<string, object>? @event))
|
|
return;
|
|
|
|
@event.Invoke(peer.Id.ToString(), packet);
|
|
}
|
|
|
|
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 && !t.IsAbstract && !t.IsGenericType);
|
|
|
|
MethodInfo subscribeReusableMethod = typeof(NetPacketProcessor)
|
|
.GetMethods()
|
|
.FirstOrDefault(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable) &&
|
|
m.GetParameters().Length == 1 &&
|
|
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>)
|
|
)!;
|
|
|
|
MethodInfo registerNestedTypeMethod = typeof(NetPacketProcessor)
|
|
.GetMethods()
|
|
.FirstOrDefault(m => m.Name == nameof(NetPacketProcessor.RegisterNestedType) &&
|
|
m.GetParameters().Length == 0
|
|
)!;
|
|
|
|
MethodInfo onPacketArrivedMethod = typeof(LiteNetLibCommunicatorBase)
|
|
.GetMethod(nameof(OnPacketArrived), BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
|
|
// Register all network packets by calling the methods bellow where T is our found network packet type
|
|
// NetPacketProcessor.SubscribeReusable<T, NetPeer>(Action<T, NetPeer> onReceive)
|
|
// NetPacketProcessor.RegisterNestedType<T>()
|
|
foreach (Type packetType in packetTypes)
|
|
{
|
|
if (!packetType.IsClass)
|
|
{
|
|
MethodInfo genericRegisterNestedTypeMethod = registerNestedTypeMethod.MakeGenericMethod(packetType);
|
|
genericRegisterNestedTypeMethod.Invoke(netPacketProcessor, []);
|
|
continue;
|
|
}
|
|
|
|
MethodInfo genericOnPacketArrivedMethod = onPacketArrivedMethod.MakeGenericMethod(packetType);
|
|
|
|
Type delegateType = typeof(Action<,>).MakeGenericType(packetType, typeof(NetPeer));
|
|
Delegate 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;
|
|
|
|
SetupEnginePackets();
|
|
SetupPackets();
|
|
}
|
|
|
|
private void SetupEnginePackets()
|
|
{
|
|
// I know, ugly af. I need to find a better way
|
|
netPacketProcessor.RegisterNestedType(AABBNetPacker.Write, AABBNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(CircleNetPacker.Write, CircleNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(ColorHSVNetPacker.Write, ColorHSVNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(ColorRGBANetPacker.Write, ColorRGBANetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(ColorRGBNetPacker.Write, ColorRGBNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(Line2DEquationNetPacker.Write, Line2DEquationNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(Line2DNetPacker.Write, Line2DNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(Projection1DNetPacker.Write, Projection1DNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(QuaternionNetPacker.Write, QuaternionNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(Shape2DNetPacker.Write, Shape2DNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(TriangleNetPacker.Write, TriangleNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(Vector2DNetPacker.Write, Vector2DNetPacker.Read);
|
|
netPacketProcessor.RegisterNestedType(Vector3DNetPacker.Write, Vector3DNetPacker.Read);
|
|
}
|
|
|
|
public INetworkCommunicator SubscribeToPackets<T>(Event<string, T>.EventHandler callback)
|
|
{
|
|
Type type = typeof(T);
|
|
if (!listeners.TryGetValue(type, out Event<string, object>? @event))
|
|
{
|
|
@event = new();
|
|
listeners.Add(type, @event);
|
|
}
|
|
|
|
@event.AddListener(EventDelegateWrapper(callback));
|
|
return this;
|
|
}
|
|
|
|
public INetworkCommunicator UnsubscribeFromPackets<T>(Event<string, T>.EventHandler callback)
|
|
{
|
|
Type type = typeof(T);
|
|
if (!listeners.TryGetValue(type, out Event<string, object>? @event))
|
|
return this;
|
|
|
|
@event.RemoveListener(EventDelegateWrapper(callback));
|
|
return this;
|
|
}
|
|
|
|
private static Event<string, object>.EventHandler EventDelegateWrapper<T>(Event<string, T>.EventHandler callback) => (sender, @object) => callback.Invoke(sender, (T)@object);
|
|
}
|