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() { }
public BallBehaviour(float speed) => Speed = speed; public BallBehaviour(float speed) => Speed = speed;
void IPacketListenerClient<BallResetPacket>.OnClientPacketArrived(BallResetPacket packet) => ResetBall(); void IPacketListenerClient<BallResetPacket>.OnClientPacketArrived(IConnection sender, BallResetPacket packet) => ResetBall();
void IPacketListenerClient<BallUpdatePacket>.OnClientPacketArrived(BallUpdatePacket packet) void IPacketListenerClient<BallUpdatePacket>.OnClientPacketArrived(IConnection sender, BallUpdatePacket packet)
{ {
networkTween = Transform.TweenPositionAdditive(tweenManager, .25f, Transform.Position.FromTo(packet.Position)); networkTween = Transform.TweenPositionAdditive(tweenManager, .25f, Transform.Position.FromTo(packet.Position));
RigidBody.Velocity = packet.Velocity; 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; private class BallResetPacket : INetworkPacket;
@ -78,14 +78,12 @@ public class BallBehaviour : Behaviour2D, IFirstFrameUpdate, IPhysicsUpdate, INe
{ {
public Vector2D Position { get; set; } = Vector2D.Zero; public Vector2D Position { get; set; } = Vector2D.Zero;
public Vector2D Velocity { get; set; } = Vector2D.Zero; public Vector2D Velocity { get; set; } = Vector2D.Zero;
public long Timestamp { get; set; } = 0;
public BallUpdatePacket() { } public BallUpdatePacket() { }
public BallUpdatePacket(BallBehaviour ballBehaviour) public BallUpdatePacket(BallBehaviour ballBehaviour)
{ {
Position = ballBehaviour.Transform.Position; Position = ballBehaviour.Transform.Position;
Velocity = ballBehaviour.RigidBody.Velocity; 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 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)); } 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; isUpPressed = packet.IsUpPressed;
isDownPressed = packet.IsDownPressed; 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)); networkServer?.SendToClient("*", new PaddleKeyStatePacket(this));
} }
public void OnClientPacketArrived(PaddleKeyStatePacket packet) public void OnClientPacketArrived(IConnection sender, PaddleKeyStatePacket packet)
{ {
isUpPressed = packet.IsUpPressed; isUpPressed = packet.IsUpPressed;
isDownPressed = packet.IsDownPressed; 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); 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) if (ball.RigidBody.Velocity.MagnitudeSquared > 0.01f)
return; 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; using Syntriax.Engine.Core;
namespace Syntriax.Engine.Network; namespace Syntriax.Engine.Network;
public interface INetworkCommunicator public interface INetworkCommunicator
{ {
Event<INetworkCommunicator, IConnection> OnConnectionEstablished { get; }
Event<INetworkCommunicator, IConnection> OnConnectionAbolished { get; }
IReadOnlyDictionary<string, IConnection> Connections { get; }
INetworkCommunicator Stop(); INetworkCommunicator Stop();
INetworkCommunicator SubscribeToPackets<T>(Event<string, T>.EventHandler callback); INetworkCommunicator SubscribeToPackets<T>(Event<IConnection, T>.EventHandler callback);
INetworkCommunicator UnsubscribeFromPackets<T>(Event<string, T>.EventHandler callback); INetworkCommunicator UnsubscribeFromPackets<T>(Event<IConnection, T>.EventHandler callback);
} }
public interface INetworkCommunicatorClient : INetworkCommunicator public interface INetworkCommunicatorClient : INetworkCommunicator

View File

@ -2,5 +2,5 @@ namespace Syntriax.Engine.Network;
public interface IPacketListenerClient<T> : INetworkEntity 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 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(); 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 EventBasedNetListener Listener { get; private set; } = null!;
public NetManager Manager { 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() public INetworkCommunicator Stop()
{ {
Manager.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 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; 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) private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod)
@ -45,6 +50,22 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
catch { } 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() private void SetupPackets()
{ {
// Find network packets implementing INetworkPacket // Find network packets implementing INetworkPacket
@ -95,6 +116,8 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
Manager = new NetManager(Listener); Manager = new NetManager(Listener);
Listener.NetworkReceiveEvent += NetworkReceiveEvent; Listener.NetworkReceiveEvent += NetworkReceiveEvent;
Listener.PeerConnectedEvent += ConnectionEstablished;
Listener.PeerDisconnectedEvent += ConnectionAbolished;
SetupEnginePackets(); SetupEnginePackets();
SetupPackets(); SetupPackets();
@ -118,10 +141,10 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
netPacketProcessor.RegisterNestedType(Vector3DNetPacker.Write, Vector3DNetPacker.Read); 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); Type type = typeof(T);
if (!listeners.TryGetValue(type, out Event<string, object>? @event)) if (!listeners.TryGetValue(type, out Event<IConnection, object>? @event))
{ {
@event = new(); @event = new();
listeners.Add(type, @event); listeners.Add(type, @event);
@ -131,15 +154,15 @@ public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicat
return this; return this;
} }
public INetworkCommunicator UnsubscribeFromPackets<T>(Event<string, T>.EventHandler callback) public INetworkCommunicator UnsubscribeFromPackets<T>(Event<IConnection, T>.EventHandler callback)
{ {
Type type = typeof(T); Type type = typeof(T);
if (!listeners.TryGetValue(type, out Event<string, object>? @event)) if (!listeners.TryGetValue(type, out Event<IConnection, object>? @event))
return this; return this;
@event.RemoveListener(EventDelegateWrapper(callback)); @event.RemoveListener(EventDelegateWrapper(callback));
return this; 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; MaxConnectionCount = maxConnectionCount;
Port = port; Port = port;
Manager.Start(port); Manager.Start(8888);
return this; return this;
} }

View File

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