feat: added revised version of the old networking system
This commit is contained in:
parent
cd3e23b427
commit
23a0c8e893
2
Engine
2
Engine
@ -1 +1 @@
|
|||||||
Subproject commit 6e5b805803ce60f9ad904180406e57de9e9f9c4e
|
Subproject commit 0bf38234c6dbef8824045c81c4bd79c440a70abc
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<RollForward>Major</RollForward>
|
<RollForward>Major</RollForward>
|
||||||
<PublishReadyToRun>false</PublishReadyToRun>
|
<PublishReadyToRun>false</PublishReadyToRun>
|
||||||
<TieredCompilation>false</TieredCompilation>
|
<TieredCompilation>false</TieredCompilation>
|
||||||
|
8
Shared/Network/Abstract/INetworkBehaviour.cs
Normal file
8
Shared/Network/Abstract/INetworkBehaviour.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public interface INetworkBehaviour : IBehaviour, INetworkEntity
|
||||||
|
{
|
||||||
|
INetworkCommunicator NetworkCommunicator { get; }
|
||||||
|
}
|
28
Shared/Network/Abstract/INetworkCommunicator.cs
Normal file
28
Shared/Network/Abstract/INetworkCommunicator.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public interface INetworkCommunicator
|
||||||
|
{
|
||||||
|
event OnPacketReceivedDelegate? OnPacketReceived;
|
||||||
|
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
delegate void OnPacketReceivedDelegate(INetworkCommunicator sender, object packet, string from);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface INetworkCommunicatorClient : INetworkCommunicator
|
||||||
|
{
|
||||||
|
void Connect(string address, int port, string? password = null);
|
||||||
|
|
||||||
|
void SendToServer(INetworkPacket packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface INetworkCommunicatorServer : INetworkCommunicator
|
||||||
|
{
|
||||||
|
string Password { get; }
|
||||||
|
int MaxConnectionCount { get; }
|
||||||
|
int Port { get; }
|
||||||
|
|
||||||
|
void Start(int port, int maxConnectionCount, string? password = null);
|
||||||
|
|
||||||
|
void SendToClient(string to, INetworkPacket packet);
|
||||||
|
}
|
8
Shared/Network/Abstract/INetworkEntity.cs
Normal file
8
Shared/Network/Abstract/INetworkEntity.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public interface INetworkEntity : IEntity
|
||||||
|
{
|
||||||
|
void ReceiveData(object data);
|
||||||
|
}
|
12
Shared/Network/Abstract/INetworkManager.cs
Normal file
12
Shared/Network/Abstract/INetworkManager.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public interface INetworkManager
|
||||||
|
{
|
||||||
|
INetworkCommunicator NetworkCommunicator { get; }
|
||||||
|
|
||||||
|
IReadOnlyDictionary<string, INetworkEntity> NetworkEntities { get; }
|
||||||
|
IBehaviourCollector<INetworkEntity> NetworkEntityCollector { get; }
|
||||||
|
}
|
3
Shared/Network/Abstract/INetworkPacket.cs
Normal file
3
Shared/Network/Abstract/INetworkPacket.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public interface INetworkPacket;
|
7
Shared/Network/Abstract/PacketEntityData.cs
Normal file
7
Shared/Network/Abstract/PacketEntityData.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public interface INetworkPacketEntityData<T> : INetworkPacket
|
||||||
|
{
|
||||||
|
string Entity { get; }
|
||||||
|
T Data { get; }
|
||||||
|
}
|
98
Shared/Network/NetworkBase.cs
Normal file
98
Shared/Network/NetworkBase.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
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<Type> 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<T> 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<object, NetPeer> 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();
|
||||||
|
}
|
||||||
|
}
|
27
Shared/Network/NetworkClient.cs
Normal file
27
Shared/Network/NetworkClient.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using LiteNetLib.Utils;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public class NetworkClient : NetworkBase, INetworkCommunicatorClient
|
||||||
|
{
|
||||||
|
private readonly NetDataWriter netDataWriter = new();
|
||||||
|
|
||||||
|
public void Connect(string address, int port, string? password = null)
|
||||||
|
{
|
||||||
|
if (!IsInUniverse)
|
||||||
|
throw new($"{nameof(NetworkClient)} must be in an universe to connect");
|
||||||
|
|
||||||
|
Manager.Start();
|
||||||
|
Manager.Connect(address, port, password ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendToServer(INetworkPacket packet)
|
||||||
|
{
|
||||||
|
if (packet is not INetSerializable netSerializable)
|
||||||
|
throw new($"Packet trying to be sent to the server is not compatible with LiteNetLib");
|
||||||
|
|
||||||
|
netDataWriter.Reset();
|
||||||
|
netPacketProcessor.WriteNetSerializable(netDataWriter, ref netSerializable);
|
||||||
|
Manager.FirstPeer.Send(netDataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
}
|
36
Shared/Network/NetworkManager.cs
Normal file
36
Shared/Network/NetworkManager.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Syntriax.Engine.Core;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public class NetworkManager : UniverseObject, INetworkManager
|
||||||
|
{
|
||||||
|
public INetworkCommunicator NetworkCommunicator { get; set; } = null!;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, INetworkEntity> _networkEntities = [];
|
||||||
|
public IReadOnlyDictionary<string, INetworkEntity> NetworkEntities => _networkEntities;
|
||||||
|
|
||||||
|
private readonly BehaviourCollector<INetworkEntity> _networkEntityCollector = new();
|
||||||
|
public IBehaviourCollector<INetworkEntity> NetworkEntityCollector => _networkEntityCollector;
|
||||||
|
|
||||||
|
public NetworkManager()
|
||||||
|
{
|
||||||
|
_networkEntityCollector.OnCollected += OnCollected;
|
||||||
|
_networkEntityCollector.OnRemoved += OnRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCollected(IBehaviourCollector<INetworkEntity> sender, INetworkEntity behaviourCollected)
|
||||||
|
{
|
||||||
|
if (!_networkEntities.TryAdd(behaviourCollected.Id, behaviourCollected))
|
||||||
|
throw new($"Unable to add {behaviourCollected.Id} to {nameof(NetworkManager)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemoved(IBehaviourCollector<INetworkEntity> sender, INetworkEntity behaviourRemoved)
|
||||||
|
{
|
||||||
|
_networkEntities.Remove(behaviourRemoved.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnEnteringUniverse(IUniverse universe) => _networkEntityCollector.Assign(universe);
|
||||||
|
protected override void OnExitingUniverse(IUniverse universe) => _networkEntityCollector.Unassign();
|
||||||
|
}
|
60
Shared/Network/NetworkServer.cs
Normal file
60
Shared/Network/NetworkServer.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using LiteNetLib;
|
||||||
|
using LiteNetLib.Utils;
|
||||||
|
|
||||||
|
namespace Syntriax.Engine.Network;
|
||||||
|
|
||||||
|
public class NetworkServer : NetworkBase, INetworkCommunicatorServer
|
||||||
|
{
|
||||||
|
public string Password { get; private set; } = string.Empty;
|
||||||
|
public int MaxConnectionCount { get; private set; } = 2;
|
||||||
|
public int Port { get; private set; } = 8888;
|
||||||
|
|
||||||
|
private readonly NetDataWriter netDataWriter = new();
|
||||||
|
|
||||||
|
public NetworkServer() : this(8888, 2) { }
|
||||||
|
public NetworkServer(int port, int maxConnectionCount) : base()
|
||||||
|
{
|
||||||
|
MaxConnectionCount = maxConnectionCount;
|
||||||
|
Port = port;
|
||||||
|
|
||||||
|
Listener.ConnectionRequestEvent += request =>
|
||||||
|
{
|
||||||
|
if (Manager.ConnectedPeersCount < maxConnectionCount)
|
||||||
|
request.AcceptIfKey(Password);
|
||||||
|
else
|
||||||
|
request.Reject();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(int port, int maxConnectionCount, string? password = null)
|
||||||
|
{
|
||||||
|
if (!IsInUniverse)
|
||||||
|
throw new($"{nameof(NetworkServer)} must be in an universe to start");
|
||||||
|
|
||||||
|
Password = password ?? string.Empty;
|
||||||
|
MaxConnectionCount = maxConnectionCount;
|
||||||
|
Port = port;
|
||||||
|
|
||||||
|
Manager.Start(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SendToClient(string to, INetworkPacket packet)
|
||||||
|
{
|
||||||
|
if (packet is not INetSerializable netSerializable)
|
||||||
|
throw new($"Packet trying to be sent to the server is not compatible with LiteNetLib");
|
||||||
|
|
||||||
|
bool isBroadcastToAll = to.CompareTo("*") == 0;
|
||||||
|
|
||||||
|
netDataWriter.Reset();
|
||||||
|
netPacketProcessor.WriteNetSerializable(netDataWriter, ref netSerializable);
|
||||||
|
if (isBroadcastToAll)
|
||||||
|
Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
else if (Manager.ConnectedPeerList.FirstOrDefault(p => p.Id.CompareTo(to) == 0) is NetPeer netPeer)
|
||||||
|
netPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered);
|
||||||
|
else
|
||||||
|
throw new($"Peer {to} couldn't be found.");
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Apos.Shapes" Version="0.2.3" />
|
<PackageReference Include="Apos.Shapes" Version="0.2.3" />
|
||||||
|
<PackageReference Include="LiteNetLib" Version="1.3.1" />
|
||||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
||||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105">
|
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105">
|
||||||
<PrivateAssets>All</PrivateAssets>
|
<PrivateAssets>All</PrivateAssets>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user