feat: IConnection interface added for connection information

This commit is contained in:
Syntriax 2025-06-17 23:21:46 +03:00
parent 7cc3bb4d83
commit d89af5ccad
11 changed files with 88 additions and 42 deletions

View File

@ -65,12 +65,12 @@ public class BallBehaviour : Behaviour2D, IFirstFrameUpdate, IPhysicsUpdate, INe
public BallBehaviour() { }
public BallBehaviour(float speed) => Speed = speed;
void IPacketListenerClient<BallResetPacket>.OnClientPacketArrived(BallResetPacket packet) => ResetBall();
void IPacketListenerClient<BallUpdatePacket>.OnClientPacketArrived(BallUpdatePacket packet)
void IPacketListenerClient<BallResetPacket>.OnClientPacketArrived(IConnection sender, BallResetPacket packet) => ResetBall();
void IPacketListenerClient<BallUpdatePacket>.OnClientPacketArrived(IConnection sender, BallUpdatePacket packet)
{
networkTween = Transform.TweenPositionAdditive(tweenManager, .25f, Transform.Position.FromTo(packet.Position));
RigidBody.Velocity = packet.Velocity;
physicsEngine2D.StepIndividual(RigidBody, new System.DateTime(System.DateTime.UtcNow.Ticks - packet.Timestamp).Second);
physicsEngine2D.StepIndividual(RigidBody, sender.Ping);
}
private class BallResetPacket : INetworkPacket;
@ -78,14 +78,12 @@ public class BallBehaviour : Behaviour2D, IFirstFrameUpdate, IPhysicsUpdate, INe
{
public Vector2D Position { get; set; } = Vector2D.Zero;
public Vector2D Velocity { get; set; } = Vector2D.Zero;
public long Timestamp { get; set; } = 0;
public BallUpdatePacket() { }
public BallUpdatePacket(BallBehaviour ballBehaviour)
{
Position = ballBehaviour.Transform.Position;
Velocity = ballBehaviour.RigidBody.Velocity;
Timestamp = System.DateTime.UtcNow.Ticks;
}
}
}

View File

@ -70,7 +70,7 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
private void OnDownPressed(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isDownPressed = true; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); }
private void OnDownReleased(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isDownPressed = false; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); }
public void OnServerPacketArrived(string sender, PaddleKeyStatePacket packet)
public void OnServerPacketArrived(IConnection sender, PaddleKeyStatePacket packet)
{
isUpPressed = packet.IsUpPressed;
isDownPressed = packet.IsDownPressed;
@ -78,7 +78,7 @@ public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Sp
networkServer?.SendToClient("*", new PaddleKeyStatePacket(this));
}
public void OnClientPacketArrived(PaddleKeyStatePacket packet)
public void OnClientPacketArrived(IConnection sender, PaddleKeyStatePacket packet)
{
isUpPressed = packet.IsUpPressed;
isDownPressed = packet.IsDownPressed;

View File

@ -89,7 +89,7 @@ public class PongManagerBehaviour : Behaviour, INetworkEntity, IFirstFrameUpdate
return Vector2D.Right.Rotate(isBackwards ? rotation + Syntriax.Engine.Core.Math.PI : rotation);
}
void IPacketListenerServer<RequestStartPacket>.OnServerPacketArrived(string sender, RequestStartPacket packet)
void IPacketListenerServer<RequestStartPacket>.OnServerPacketArrived(IConnection sender, RequestStartPacket packet)
{
if (ball.RigidBody.Velocity.MagnitudeSquared > 0.01f)
return;

View File

@ -0,0 +1,8 @@
namespace Syntriax.Engine.Network;
public interface IConnection
{
string Id { get; }
float Ping { get; }
float RoundTrip { get; }
}

View File

@ -1,13 +1,20 @@
using System.Collections.Generic;
using Syntriax.Engine.Core;
namespace Syntriax.Engine.Network;
public interface INetworkCommunicator
{
Event<INetworkCommunicator, IConnection> OnConnectionEstablished { get; }
Event<INetworkCommunicator, IConnection> OnConnectionAbolished { get; }
IReadOnlyDictionary<string, IConnection> Connections { get; }
INetworkCommunicator Stop();
INetworkCommunicator SubscribeToPackets<T>(Event<string, T>.EventHandler callback);
INetworkCommunicator UnsubscribeFromPackets<T>(Event<string, T>.EventHandler callback);
INetworkCommunicator SubscribeToPackets<T>(Event<IConnection, T>.EventHandler callback);
INetworkCommunicator UnsubscribeFromPackets<T>(Event<IConnection, T>.EventHandler callback);
}
public interface INetworkCommunicatorClient : INetworkCommunicator

View File

@ -2,5 +2,5 @@ namespace Syntriax.Engine.Network;
public interface IPacketListenerClient<T> : INetworkEntity
{
void OnClientPacketArrived(T packet);
void OnClientPacketArrived(IConnection sender, T packet);
}

View File

@ -2,5 +2,5 @@ namespace Syntriax.Engine.Network;
public interface IPacketListenerServer<T> : INetworkEntity
{
void OnServerPacketArrived(string sender, T packet);
void OnServerPacketArrived(IConnection sender, T packet);
}

View File

@ -14,11 +14,16 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
{
protected readonly NetPacketProcessor netPacketProcessor = new();
private readonly Dictionary<Type, Event<string, object>> listeners = [];
private readonly Dictionary<Type, Event<IConnection, object>> listeners = [];
private readonly Dictionary<string, IConnection> _connections = [];
public IReadOnlyDictionary<string, IConnection> Connections => _connections;
public EventBasedNetListener Listener { get; private set; } = null!;
public NetManager Manager { get; private set; } = null!;
public Event<INetworkCommunicator, IConnection> OnConnectionEstablished { get; } = new();
public Event<INetworkCommunicator, IConnection> OnConnectionAbolished { get; } = new();
public INetworkCommunicator Stop()
{
Manager.Stop();
@ -33,10 +38,10 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
protected virtual void OnPacketArrived<T>(T packet, NetPeer peer) where T : INetworkPacket
{
if (!listeners.TryGetValue(typeof(T), out Event<string, object>? @event))
if (!listeners.TryGetValue(typeof(T), out Event<IConnection, object>? @event))
return;
@event.Invoke(peer.Id.ToString(), packet);
@event.Invoke(Connections[peer.Id.ToString()], packet);
}
private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod)
@ -45,6 +50,22 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
catch { }
}
private void ConnectionEstablished(NetPeer peer)
{
LiteNetLibConnection connection = new(peer);
_connections.Add(connection.Id, connection);
OnConnectionEstablished.Invoke(this, connection);
}
private void ConnectionAbolished(NetPeer peer, DisconnectInfo disconnectInfo)
{
if (!_connections.TryGetValue(peer.Id.ToString(), out var connection))
return;
_connections.Remove(connection.Id);
OnConnectionAbolished.Invoke(this, connection);
}
private void SetupPackets()
{
// Find network packets implementing INetworkPacket
@ -95,6 +116,8 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
Manager = new NetManager(Listener);
Listener.NetworkReceiveEvent += NetworkReceiveEvent;
Listener.PeerConnectedEvent += ConnectionEstablished;
Listener.PeerDisconnectedEvent += ConnectionAbolished;
SetupEnginePackets();
SetupPackets();
@ -118,10 +141,10 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
netPacketProcessor.RegisterNestedType(Vector3DNetPacker.Write, Vector3DNetPacker.Read);
}
public INetworkCommunicator SubscribeToPackets<T>(Event<string, T>.EventHandler callback)
public INetworkCommunicator SubscribeToPackets<T>(Event<IConnection, T>.EventHandler callback)
{
Type type = typeof(T);
if (!listeners.TryGetValue(type, out Event<string, object>? @event))
if (!listeners.TryGetValue(type, out Event<IConnection, object>? @event))
{
@event = new();
listeners.Add(type, @event);
@ -131,15 +154,15 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
return this;
}
public INetworkCommunicator UnsubscribeFromPackets<T>(Event<string, T>.EventHandler callback)
public INetworkCommunicator UnsubscribeFromPackets<T>(Event<IConnection, T>.EventHandler callback)
{
Type type = typeof(T);
if (!listeners.TryGetValue(type, out Event<string, object>? @event))
if (!listeners.TryGetValue(type, out Event<IConnection, 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);
private static Event<IConnection, object>.EventHandler EventDelegateWrapper<T>(Event<IConnection, T>.EventHandler callback) => (sender, @object) => callback.Invoke(sender, (T)@object);
}

View File

@ -0,0 +1,10 @@
using LiteNetLib;
namespace Syntriax.Engine.Network;
public record class LiteNetLibConnection(NetPeer NetPeer) : IConnection
{
public string Id { get; } = NetPeer.Id.ToString();
public float Ping => NetPeer.Ping * .001f;
public float RoundTrip => NetPeer.RoundTripTime * .001f;
}

View File

@ -39,7 +39,7 @@ public class LiteNetLibServer : LiteNetLibCommunicatorBase, INetworkCommunicator
MaxConnectionCount = maxConnectionCount;
Port = port;
Manager.Start(port);
Manager.Start(8888);
return this;
}

View File

@ -73,50 +73,50 @@ public class NetworkManager : Behaviour, INetworkManager
#endregion
#region Packet Routing
private void OnPacketReceived<T>(string senderClientId, T entityDataPacket)
private void OnPacketReceived<T>(IConnection sender, T entityDataPacket)
{
if (entityDataPacket is IEntityNetworkPacket entityPacket)
RoutePacket(senderClientId, entityDataPacket, entityPacket);
RoutePacket(sender, entityDataPacket, entityPacket);
else
BroadcastPacket(senderClientId, entityDataPacket);
BroadcastPacket(sender, entityDataPacket);
}
private void RoutePacket<T>(string senderClientId, T entityDataPacket, IEntityNetworkPacket entityPacket)
private void RoutePacket<T>(IConnection sender, T entityDataPacket, IEntityNetworkPacket entityPacket)
{
if (NetworkCommunicator is INetworkCommunicatorClient)
RoutePacket(clientPacketRouters, entityPacket.EntityId, senderClientId, entityDataPacket);
RoutePacket(clientPacketRouters, entityPacket.EntityId, sender, entityDataPacket);
if (NetworkCommunicator is INetworkCommunicatorServer)
RoutePacket(serverPacketRouters, entityPacket.EntityId, senderClientId, entityDataPacket);
RoutePacket(serverPacketRouters, entityPacket.EntityId, sender, entityDataPacket);
}
private void BroadcastPacket<T>(string senderClientId, T entityDataPacket)
private void BroadcastPacket<T>(IConnection sender, T entityDataPacket)
{
if (NetworkCommunicator is INetworkCommunicatorClient)
BroadcastPacket(clientPacketRouters, senderClientId, entityDataPacket);
BroadcastPacket(clientPacketRouters, sender, entityDataPacket);
if (NetworkCommunicator is INetworkCommunicatorServer)
BroadcastPacket(serverPacketRouters, senderClientId, entityDataPacket);
BroadcastPacket(serverPacketRouters, sender, entityDataPacket);
}
private static void BroadcastPacket<T>(
Dictionary<Type, Dictionary<string, object>> packetRouters,
string senderClientId,
IConnection sender,
T entityDataPacket)
{
if (!packetRouters.TryGetValue(entityDataPacket!.GetType(), out Dictionary<string, object>? routers))
return;
foreach ((string id, object routerEventReference) in routers)
foreach ((string behaviourId, object routerEventReference) in routers)
{
Event<string, T> routerEvent = (Event<string, T>)routerEventReference;
routerEvent.Invoke(senderClientId, entityDataPacket!);
Event<IConnection, T> routerEvent = (Event<IConnection, T>)routerEventReference;
routerEvent.Invoke(sender, entityDataPacket!);
}
}
private static void RoutePacket<T>(
Dictionary<Type, Dictionary<string, object>> packetRouters,
string entityId,
string senderClientId,
IConnection sender,
T entityDataPacket)
{
if (!packetRouters.TryGetValue(entityDataPacket!.GetType(), out Dictionary<string, object>? routers))
@ -125,8 +125,8 @@ public class NetworkManager : Behaviour, INetworkManager
if (!routers.TryGetValue(entityId, out object? routerEventReference))
return;
Event<string, T> routerEvent = (Event<string, T>)routerEventReference;
routerEvent.Invoke(senderClientId, entityDataPacket!);
Event<IConnection, T> routerEvent = (Event<IConnection, T>)routerEventReference;
routerEvent.Invoke(sender, entityDataPacket!);
}
#endregion
@ -156,7 +156,7 @@ public class NetworkManager : Behaviour, INetworkManager
private object CreateEventAndRegister(Type packetType, INetworkEntity behaviour, NetworkType networkType)
{
Type genericEventType = typeof(Event<,>).MakeGenericType(typeof(string), packetType);
Type genericEventType = typeof(Event<,>).MakeGenericType(typeof(IConnection), packetType);
object packetListenerEvent = Activator.CreateInstance(genericEventType)!;
if (!registerPacketListenersMethods.TryGetValue(packetType, out MethodInfo? registerPacketListenerMethod))
@ -168,12 +168,12 @@ public class NetworkManager : Behaviour, INetworkManager
private static void RegisterPacketListenerEvent<T>(
INetworkEntity behaviour,
Event<string, T> packetListenerEvent,
Event<IConnection, T> packetListenerEvent,
NetworkType networkType)
{
switch (networkType)
{
case NetworkType.Client: packetListenerEvent.AddListener((sender, packet) => ((IPacketListenerClient<T>)behaviour).OnClientPacketArrived(packet)); break;
case NetworkType.Client: packetListenerEvent.AddListener((sender, packet) => ((IPacketListenerClient<T>)behaviour).OnClientPacketArrived(sender, packet)); break;
case NetworkType.Server: packetListenerEvent.AddListener((sender, packet) => ((IPacketListenerServer<T>)behaviour).OnServerPacketArrived(sender, packet)); break;
}
}
@ -203,7 +203,7 @@ public class NetworkManager : Behaviour, INetworkManager
private static void ClearRouter<T>(object routerEventReference)
{
Event<string, T> routerEvent = (Event<string, T>)routerEventReference;
Event<IConnection, T> routerEvent = (Event<IConnection, T>)routerEventReference;
routerEvent.Clear();
}
@ -262,7 +262,7 @@ public class NetworkManager : Behaviour, INetworkManager
{
MethodInfo genericOnPacketArrivedMethod = onPacketArrivedMethod.MakeGenericMethod(packetType);
Type genericDelegateType = typeof(Event<,>.EventHandler).MakeGenericType(typeof(string), packetType);
Type genericDelegateType = typeof(Event<,>.EventHandler).MakeGenericType(typeof(IConnection), packetType);
Delegate genericPacketReceivedDelegate = Delegate.CreateDelegate(genericDelegateType, this, genericOnPacketArrivedMethod);
packetRetrievalDelegates.Add((packetType, genericPacketReceivedDelegate));