added: stress testing
This commit is contained in:
@@ -17,12 +17,12 @@ namespace Game.Source
|
|||||||
public override void OnPlayerJoined(Player player)
|
public override void OnPlayerJoined(Player player)
|
||||||
{
|
{
|
||||||
|
|
||||||
_logger.Info($"Player({player.PlayerName}) joined to Room({GameRoom.Id})");
|
// _logger.Info($"Player({player.PlayerName}) joined to Room({GameRoom.Id})");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPlayerLeaved(Player player)
|
public override void OnPlayerLeaved(Player player)
|
||||||
{
|
{
|
||||||
_logger.Info($"Player({player.PlayerName}) left from Room({GameRoom.Id})");
|
// _logger.Info($"Player({player.PlayerName}) left from Room({GameRoom.Id})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
using System;
|
||||||
|
using ENet;
|
||||||
|
using Ragon.Common;
|
||||||
|
|
||||||
|
namespace Stress
|
||||||
|
{
|
||||||
|
class SimulationClient
|
||||||
|
{
|
||||||
|
public Host Host;
|
||||||
|
public Peer Peer;
|
||||||
|
public bool InRoom;
|
||||||
|
public List<int> Entities = new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimulationThread
|
||||||
|
{
|
||||||
|
private List<SimulationClient> _clients = new List<SimulationClient>();
|
||||||
|
|
||||||
|
public void Start(string url, ushort port, int numClients)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < numClients; i++)
|
||||||
|
{
|
||||||
|
var client = CreateClient(url, port);
|
||||||
|
_clients.Add(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
var thread = new Thread(Execute);
|
||||||
|
thread.IsBackground = true;
|
||||||
|
thread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
var ragonSerializer = new RagonSerializer();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
foreach (SimulationClient simulationClient in _clients)
|
||||||
|
{
|
||||||
|
bool polled = false;
|
||||||
|
Event netEvent;
|
||||||
|
|
||||||
|
while (!polled)
|
||||||
|
{
|
||||||
|
if (simulationClient.Host.CheckEvents(out netEvent) <= 0)
|
||||||
|
{
|
||||||
|
if (simulationClient.Host.Service(0, out netEvent) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
polled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (netEvent.Type)
|
||||||
|
{
|
||||||
|
case EventType.None:
|
||||||
|
break;
|
||||||
|
case EventType.Connect:
|
||||||
|
{
|
||||||
|
ragonSerializer.Clear();
|
||||||
|
ragonSerializer.WriteOperation(RagonOperation.AUTHORIZE);
|
||||||
|
ragonSerializer.WriteString("defaultkey");
|
||||||
|
ragonSerializer.WriteString("Player " + DateTime.Now.Ticks);
|
||||||
|
ragonSerializer.WriteByte(0);
|
||||||
|
|
||||||
|
var sendData = ragonSerializer.ToArray();
|
||||||
|
var packet = new Packet();
|
||||||
|
packet.Create(sendData, PacketFlags.Reliable);
|
||||||
|
simulationClient.Peer.Send(0, ref packet);
|
||||||
|
Console.WriteLine("Client connected to server");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EventType.Disconnect:
|
||||||
|
Console.WriteLine("Client disconnected from server");
|
||||||
|
break;
|
||||||
|
case EventType.Timeout:
|
||||||
|
Console.WriteLine("Client connection timeout");
|
||||||
|
break;
|
||||||
|
case EventType.Receive:
|
||||||
|
var data = new byte[netEvent.Packet.Length];
|
||||||
|
netEvent.Packet.CopyTo(data);
|
||||||
|
|
||||||
|
var op = (RagonOperation) data[0];
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case RagonOperation.AUTHORIZED_SUCCESS:
|
||||||
|
{
|
||||||
|
ragonSerializer.Clear();
|
||||||
|
ragonSerializer.WriteOperation(RagonOperation.JOIN_OR_CREATE_ROOM);
|
||||||
|
ragonSerializer.WriteInt(2);
|
||||||
|
ragonSerializer.WriteInt(20);
|
||||||
|
ragonSerializer.WriteString("map");
|
||||||
|
|
||||||
|
var sendData = ragonSerializer.ToArray();
|
||||||
|
var packet = new Packet();
|
||||||
|
packet.Create(sendData, PacketFlags.Reliable);
|
||||||
|
simulationClient.Peer.Send(0, ref packet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RagonOperation.JOIN_SUCCESS:
|
||||||
|
{
|
||||||
|
simulationClient.InRoom = true;
|
||||||
|
|
||||||
|
ragonSerializer.Clear();
|
||||||
|
ragonSerializer.WriteOperation(RagonOperation.SCENE_IS_LOADED);
|
||||||
|
|
||||||
|
var sendData = ragonSerializer.ToArray();
|
||||||
|
var packet = new Packet();
|
||||||
|
packet.Create(sendData, PacketFlags.Reliable);
|
||||||
|
simulationClient.Peer.Send(0, ref packet);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RagonOperation.SNAPSHOT:
|
||||||
|
{
|
||||||
|
ragonSerializer.Clear();
|
||||||
|
ragonSerializer.WriteOperation(RagonOperation.CREATE_ENTITY);
|
||||||
|
ragonSerializer.WriteUShort(0);
|
||||||
|
ragonSerializer.WriteUShort(0);
|
||||||
|
ragonSerializer.WriteUShort(0);
|
||||||
|
|
||||||
|
var sendData = ragonSerializer.ToArray();
|
||||||
|
var packet = new Packet();
|
||||||
|
packet.Create(sendData, PacketFlags.Reliable);
|
||||||
|
simulationClient.Peer.Send(0, ref packet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RagonOperation.CREATE_ENTITY:
|
||||||
|
{
|
||||||
|
ReadOnlySpan<byte> payload = data.AsSpan().Slice(1, data.Length - 1);
|
||||||
|
ragonSerializer.Clear();
|
||||||
|
ragonSerializer.FromSpan(ref payload);
|
||||||
|
|
||||||
|
var entityType = ragonSerializer.ReadUShort();
|
||||||
|
var state = ragonSerializer.ReadByte();
|
||||||
|
var ennt = ragonSerializer.ReadByte();
|
||||||
|
var entityId = ragonSerializer.ReadInt();
|
||||||
|
|
||||||
|
simulationClient.Entities.Add(entityId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine(op);
|
||||||
|
// Console.WriteLine("Packet received from server - Channel ID: " + netEvent.ChannelID + ", Data length: " + netEvent.Packet.Length);
|
||||||
|
netEvent.Packet.Dispose();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simulationClient.InRoom)
|
||||||
|
{
|
||||||
|
foreach (var entity in simulationClient.Entities)
|
||||||
|
{
|
||||||
|
ragonSerializer.Clear();
|
||||||
|
ragonSerializer.WriteOperation(RagonOperation.REPLICATE_ENTITY_STATE);
|
||||||
|
ragonSerializer.WriteInt(entity);
|
||||||
|
ragonSerializer.WriteInt(100);
|
||||||
|
ragonSerializer.WriteInt(200);
|
||||||
|
ragonSerializer.WriteInt(300);
|
||||||
|
|
||||||
|
var sendData = ragonSerializer.ToArray();
|
||||||
|
var packet = new Packet();
|
||||||
|
packet.Create(sendData, PacketFlags.Instant);
|
||||||
|
simulationClient.Peer.Send(1, ref packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SimulationClient CreateClient(string url, ushort port)
|
||||||
|
{
|
||||||
|
Host client = new Host();
|
||||||
|
Address address = new Address();
|
||||||
|
|
||||||
|
address.SetHost(url);
|
||||||
|
address.Port = port;
|
||||||
|
|
||||||
|
client.Create();
|
||||||
|
Console.WriteLine("Created client");
|
||||||
|
|
||||||
|
Peer peer = client.Connect(address);
|
||||||
|
|
||||||
|
return new SimulationClient() {Host = client, Peer = peer};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Library.Initialize();
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
{
|
||||||
|
var thread = new SimulationThread();
|
||||||
|
thread.Start("127.0.0.1", 4444, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
|
||||||
|
|
||||||
|
Console.ReadKey();
|
||||||
|
Library.Deinitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,26 +11,25 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
private readonly GameThread _gameThread;
|
private readonly GameThread _gameThread;
|
||||||
|
private readonly ENetServer _netServer;
|
||||||
public Application(PluginFactory factory, Configuration configuration)
|
public Application(PluginFactory factory, Configuration configuration)
|
||||||
{
|
{
|
||||||
ThreadPool.SetMinThreads(1, 1);
|
|
||||||
|
|
||||||
_gameThread = new GameThread(factory, configuration);
|
_gameThread = new GameThread(factory, configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
Library.Initialize();
|
Library.Initialize();
|
||||||
|
|
||||||
_gameThread.Start();
|
_gameThread.Start();
|
||||||
|
_logger.Info("Started");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
_gameThread.Stop();
|
_gameThread.Stop();
|
||||||
|
|
||||||
Library.Deinitialize();
|
Library.Deinitialize();
|
||||||
|
_logger.Info("Stopped");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NLog.Targets;
|
||||||
using Ragon.Common;
|
using Ragon.Common;
|
||||||
|
|
||||||
namespace Ragon.Core;
|
namespace Ragon.Core;
|
||||||
@@ -25,9 +27,12 @@ public class AuthorizationManager : IAuthorizationManager
|
|||||||
|
|
||||||
public void OnAuthorization(uint peerId, string key, string name, byte protocol)
|
public void OnAuthorization(uint peerId, string key, string name, byte protocol)
|
||||||
{
|
{
|
||||||
var dispatcher = _gameThread.GetDispatcher();
|
var dispatcher = _gameThread.Dispatcher;
|
||||||
_provider.OnAuthorizationRequest(key, name, protocol, Array.Empty<byte>(),
|
_provider.OnAuthorizationRequest(key, name, protocol, Array.Empty<byte>(),
|
||||||
(playerId, playerName) => { dispatcher.Dispatch(() => Accepted(peerId, playerId, playerName)); },
|
(playerId, playerName) =>
|
||||||
|
{
|
||||||
|
dispatcher.Dispatch(() => Accepted(peerId, playerId, playerName));
|
||||||
|
},
|
||||||
(errorCode) => { dispatcher.Dispatch(() => Rejected(peerId, errorCode)); });
|
(errorCode) => { dispatcher.Dispatch(() => Rejected(peerId, errorCode)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +57,7 @@ public class AuthorizationManager : IAuthorizationManager
|
|||||||
_playersByPeers.Add(peerId, player);
|
_playersByPeers.Add(peerId, player);
|
||||||
|
|
||||||
var sendData = _serializer.ToArray();
|
var sendData = _serializer.ToArray();
|
||||||
_gameThread.SendSocketEvent(new SocketEvent() {Data = sendData, PeerId = peerId, Type = EventType.DATA, Delivery = DeliveryType.Reliable});
|
_gameThread.Server.Send(peerId, sendData, DeliveryType.Reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Rejected(uint peerId, uint code)
|
public void Rejected(uint peerId, uint code)
|
||||||
@@ -62,9 +67,8 @@ public class AuthorizationManager : IAuthorizationManager
|
|||||||
_serializer.WriteInt((int) code);
|
_serializer.WriteInt((int) code);
|
||||||
|
|
||||||
var sendData = _serializer.ToArray();
|
var sendData = _serializer.ToArray();
|
||||||
_gameThread.SendSocketEvent(new SocketEvent() {Data = sendData, PeerId = peerId, Type = EventType.DATA, Delivery = DeliveryType.Reliable});
|
_gameThread.Server.Send(peerId, sendData, DeliveryType.Reliable);
|
||||||
var emtpyData = Array.Empty<byte>();
|
_gameThread.Server.Disconnect(peerId, 0);
|
||||||
_gameThread.SendSocketEvent(new SocketEvent() {Data = emtpyData, PeerId = peerId, Type = EventType.DISCONNECTED, Delivery = DeliveryType.Reliable});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cleanup(uint peerId)
|
public void Cleanup(uint peerId)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Ragon.Core
|
|||||||
private uint _ticks;
|
private uint _ticks;
|
||||||
|
|
||||||
private readonly PluginBase _plugin;
|
private readonly PluginBase _plugin;
|
||||||
private readonly IGameThread _sender;
|
private readonly IGameThread _gameThread;
|
||||||
private readonly RagonSerializer _serializer = new(512);
|
private readonly RagonSerializer _serializer = new(512);
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
@@ -30,9 +30,9 @@ namespace Ragon.Core
|
|||||||
private uint[] _allPlayers = Array.Empty<uint>();
|
private uint[] _allPlayers = Array.Empty<uint>();
|
||||||
private Entity[] _entitiesAll = Array.Empty<Entity>();
|
private Entity[] _entitiesAll = Array.Empty<Entity>();
|
||||||
|
|
||||||
public GameRoom(IGameThread sender, PluginBase pluginBase, string map, int min, int max)
|
public GameRoom(IGameThread gameThread, PluginBase pluginBase, string map, int min, int max)
|
||||||
{
|
{
|
||||||
_sender = sender;
|
_gameThread = gameThread;
|
||||||
_plugin = pluginBase;
|
_plugin = pluginBase;
|
||||||
|
|
||||||
Map = map;
|
Map = map;
|
||||||
@@ -367,40 +367,22 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
public void Send(uint peerId, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Send(uint peerId, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
_sender.SendSocketEvent(new SocketEvent()
|
_gameThread.Server.Send(peerId, rawData, deliveryType);
|
||||||
{
|
|
||||||
PeerId = peerId,
|
|
||||||
Data = rawData,
|
|
||||||
Type = EventType.DATA,
|
|
||||||
Delivery = deliveryType,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Broadcast(uint[] peersIds, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Broadcast(uint[] peersIds, byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
foreach (var peer in peersIds)
|
foreach (var peer in peersIds)
|
||||||
{
|
{
|
||||||
_sender.SendSocketEvent(new SocketEvent()
|
_gameThread.Server.Send(peer, rawData, deliveryType);
|
||||||
{
|
|
||||||
PeerId = peer,
|
|
||||||
Data = rawData,
|
|
||||||
Type = EventType.DATA,
|
|
||||||
Delivery = deliveryType,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Broadcast(byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
public void Broadcast(byte[] rawData, DeliveryType deliveryType = DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
foreach (var player in _players.Values.ToArray())
|
foreach (var peer in _allPlayers)
|
||||||
{
|
{
|
||||||
_sender.SendSocketEvent(new SocketEvent()
|
_gameThread.Server.Send(peer, rawData, deliveryType);
|
||||||
{
|
|
||||||
PeerId = player.PeerId,
|
|
||||||
Data = rawData,
|
|
||||||
Type = EventType.DATA,
|
|
||||||
Delivery = deliveryType,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,36 +2,41 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using ENet;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
namespace Ragon.Core
|
namespace Ragon.Core
|
||||||
{
|
{
|
||||||
public class GameThread : IGameThread
|
public class GameThread : IGameThread, IHandler
|
||||||
{
|
{
|
||||||
private readonly Dictionary<uint, GameRoom> _socketByRooms;
|
private readonly Dictionary<uint, GameRoom> _socketByRooms;
|
||||||
private readonly RoomManager _roomManager;
|
private readonly RoomManager _roomManager;
|
||||||
private readonly ENetServer _socketServer;
|
private readonly ISocketServer _server;
|
||||||
private readonly Thread _thread;
|
private readonly Thread _thread;
|
||||||
private readonly Server _serverConfiguration;
|
private readonly Server _serverConfiguration;
|
||||||
private readonly Stopwatch _gameLoopTimer;
|
private readonly Stopwatch _gameLoopTimer;
|
||||||
private readonly Lobby _lobby;
|
private readonly Lobby _lobby;
|
||||||
private readonly IDispatcher _dispatcher;
|
|
||||||
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
|
private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
|
||||||
private readonly float _deltaTime = 0.0f;
|
private readonly float _deltaTime = 0.0f;
|
||||||
|
|
||||||
private int _packets = 0;
|
|
||||||
private readonly Stopwatch _packetsTimer;
|
private readonly Stopwatch _packetsTimer;
|
||||||
|
private int _packets = 0;
|
||||||
|
|
||||||
|
public IDispatcher Dispatcher { get; private set; }
|
||||||
|
public ISocketServer Server { get; private set; }
|
||||||
|
|
||||||
public GameThread(PluginFactory factory, Configuration configuration)
|
public GameThread(PluginFactory factory, Configuration configuration)
|
||||||
{
|
{
|
||||||
var authorizationProvider = factory.CreateAuthorizationProvider(configuration);
|
var authorizationProvider = factory.CreateAuthorizationProvider(configuration);
|
||||||
|
|
||||||
|
Dispatcher = new Dispatcher();
|
||||||
|
Server = new ENetServer(this);
|
||||||
|
|
||||||
_serverConfiguration = configuration.Server;
|
_serverConfiguration = configuration.Server;
|
||||||
_deltaTime = 1000.0f / configuration.TickRate;
|
_deltaTime = 1000.0f / configuration.TickRate;
|
||||||
|
|
||||||
_dispatcher = new Dispatcher();
|
|
||||||
_roomManager = new RoomManager(factory, this);
|
_roomManager = new RoomManager(factory, this);
|
||||||
_lobby = new Lobby(authorizationProvider, _roomManager, this);
|
_lobby = new Lobby(authorizationProvider, _roomManager, this);
|
||||||
_socketServer = new ENetServer();
|
|
||||||
_gameLoopTimer = new Stopwatch();
|
_gameLoopTimer = new Stopwatch();
|
||||||
_packetsTimer = new Stopwatch();
|
_packetsTimer = new Stopwatch();
|
||||||
_socketByRooms = new Dictionary<uint, GameRoom>();
|
_socketByRooms = new Dictionary<uint, GameRoom>();
|
||||||
@@ -43,18 +48,19 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
Server.Start(_serverConfiguration.Port);
|
||||||
|
|
||||||
_gameLoopTimer.Start();
|
_gameLoopTimer.Start();
|
||||||
_packetsTimer.Start();
|
_packetsTimer.Start();
|
||||||
|
|
||||||
_socketServer.Start(_serverConfiguration.Port);
|
|
||||||
_thread.Start();
|
_thread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
Server.Stop();
|
||||||
|
|
||||||
_gameLoopTimer.Stop();
|
_gameLoopTimer.Stop();
|
||||||
_packetsTimer.Stop();
|
_packetsTimer.Stop();
|
||||||
_socketServer.Stop();
|
|
||||||
_thread.Interrupt();
|
_thread.Interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,40 +68,8 @@ namespace Ragon.Core
|
|||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
_dispatcher.Process();
|
Server.Process();
|
||||||
|
Dispatcher.Process();
|
||||||
while (_socketServer.ReceiveBuffer.TryDequeue(out var evnt))
|
|
||||||
{
|
|
||||||
if (evnt.Type == EventType.DISCONNECTED || evnt.Type == EventType.TIMEOUT)
|
|
||||||
{
|
|
||||||
if (_socketByRooms.Remove(evnt.PeerId, out var room))
|
|
||||||
room.Leave(evnt.PeerId);
|
|
||||||
|
|
||||||
_lobby.OnDisconnected(evnt.PeerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evnt.Type == EventType.DATA)
|
|
||||||
{
|
|
||||||
_packets += 1;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var peerId = evnt.PeerId;
|
|
||||||
var data = new ReadOnlySpan<byte>(evnt.Data);
|
|
||||||
if (_socketByRooms.TryGetValue(evnt.PeerId, out var room))
|
|
||||||
{
|
|
||||||
room.ProcessEvent(peerId, data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_lobby.ProcessEvent(peerId, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
_logger.Error(exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var elapsedMilliseconds = _gameLoopTimer.ElapsedMilliseconds;
|
var elapsedMilliseconds = _gameLoopTimer.ElapsedMilliseconds;
|
||||||
if (elapsedMilliseconds > _deltaTime)
|
if (elapsedMilliseconds > _deltaTime)
|
||||||
@@ -125,14 +99,40 @@ namespace Ragon.Core
|
|||||||
_socketByRooms.Remove(peerId);
|
_socketByRooms.Remove(peerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendSocketEvent(SocketEvent socketEvent)
|
public void OnEvent(Event evnt)
|
||||||
{
|
{
|
||||||
_socketServer.SendBuffer.Enqueue(socketEvent);
|
if (evnt.Type == ENet.EventType.Timeout || evnt.Type == ENet.EventType.Disconnect)
|
||||||
|
{
|
||||||
|
if (_socketByRooms.Remove(evnt.Peer.ID, out var room))
|
||||||
|
room.Leave(evnt.Peer.ID);
|
||||||
|
|
||||||
|
_lobby.OnDisconnected(evnt.Peer.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDispatcher GetDispatcher()
|
if (evnt.Type == ENet.EventType.Receive)
|
||||||
{
|
{
|
||||||
return _dispatcher;
|
_packets += 1;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var peerId = evnt.Peer.ID;
|
||||||
|
var dataRaw = new byte[evnt.Packet.Length];
|
||||||
|
evnt.Packet.CopyTo(dataRaw);
|
||||||
|
|
||||||
|
var data = new ReadOnlySpan<byte>(dataRaw);
|
||||||
|
if (_socketByRooms.TryGetValue(peerId, out var room))
|
||||||
|
{
|
||||||
|
room.ProcessEvent(peerId, data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_lobby.ProcessEvent(peerId, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.Error(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ public interface IGameThread
|
|||||||
{
|
{
|
||||||
public void Attach(uint peerId, GameRoom room);
|
public void Attach(uint peerId, GameRoom room);
|
||||||
public void Detach(uint peerId);
|
public void Detach(uint peerId);
|
||||||
public void SendSocketEvent(SocketEvent socketEvent);
|
public IDispatcher Dispatcher { get; }
|
||||||
public IDispatcher GetDispatcher();
|
public ISocketServer Server { get; }
|
||||||
}
|
}
|
||||||
@@ -17,82 +17,69 @@ namespace Ragon.Core
|
|||||||
Connected
|
Connected
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ENetServer
|
public class ENetServer : ISocketServer
|
||||||
{
|
{
|
||||||
public Status Status { get; private set; }
|
public Status Status { get; private set; }
|
||||||
|
|
||||||
private ILogger _logger = LogManager.GetCurrentClassLogger();
|
private ILogger _logger = LogManager.GetCurrentClassLogger();
|
||||||
private Thread _thread;
|
|
||||||
private Host _host;
|
private Host _host;
|
||||||
private Address _address;
|
private Address _address;
|
||||||
private ENet.Event _netEvent;
|
private Event _netEvent;
|
||||||
private Peer[] _peers;
|
private Peer[] _peers;
|
||||||
private int _seconds = 0;
|
private IHandler _handler;
|
||||||
private Stopwatch _packetsTimer;
|
|
||||||
public RingBuffer<SocketEvent> SendBuffer;
|
public ENetServer(IHandler handler)
|
||||||
public RingBuffer<SocketEvent> ReceiveBuffer;
|
{
|
||||||
|
_handler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
public void Start(ushort port)
|
public void Start(ushort port)
|
||||||
{
|
{
|
||||||
_address = default;
|
_address = default;
|
||||||
_address.Port = port;
|
_address.Port = port;
|
||||||
|
_peers = new Peer[2048];
|
||||||
|
|
||||||
_host = new Host();
|
_host = new Host();
|
||||||
_host.Create(_address, 4095, 2, 0, 0, 1024 * 1024);
|
_host.Create(_address, 2048, 2, 0, 0, 1024 * 1024);
|
||||||
|
|
||||||
_peers = new Peer[4095];
|
|
||||||
|
|
||||||
ReceiveBuffer = new RingBuffer<SocketEvent>(8192 + 8192);
|
|
||||||
SendBuffer = new RingBuffer<SocketEvent>(8192 + 8192);
|
|
||||||
|
|
||||||
Status = Status.Listening;
|
Status = Status.Listening;
|
||||||
_packetsTimer = new Stopwatch();
|
|
||||||
_thread = new Thread(Execute);
|
|
||||||
_thread.Name = "NetworkThread";
|
|
||||||
_thread.Start();
|
|
||||||
_logger.Info($"Network listening on {port}");
|
_logger.Info($"Network listening on {port}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Execute()
|
public void Send(uint peerId, byte[] data, DeliveryType type)
|
||||||
{
|
|
||||||
_packetsTimer.Start();
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
while (SendBuffer.TryDequeue(out var data))
|
|
||||||
{
|
|
||||||
if (data.Type == EventType.DATA)
|
|
||||||
{
|
{
|
||||||
var newPacket = new Packet();
|
var newPacket = new Packet();
|
||||||
var packetFlags = PacketFlags.Instant;
|
var packetFlags = PacketFlags.Instant;
|
||||||
byte channel = 1;
|
byte channel = 1;
|
||||||
|
|
||||||
if (data.Delivery == DeliveryType.Reliable)
|
if (type == DeliveryType.Reliable)
|
||||||
{
|
{
|
||||||
packetFlags = PacketFlags.Reliable;
|
packetFlags = PacketFlags.Reliable;
|
||||||
channel = 0;
|
channel = 0;
|
||||||
}
|
}
|
||||||
else if (data.Delivery == DeliveryType.Unreliable)
|
else if (type == DeliveryType.Unreliable)
|
||||||
{
|
{
|
||||||
channel = 1;
|
channel = 1;
|
||||||
packetFlags = PacketFlags.Instant;
|
packetFlags = PacketFlags.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
newPacket.Create(data.Data, data.Data.Length, packetFlags);
|
newPacket.Create(data, data.Length, packetFlags);
|
||||||
_peers[data.PeerId].Send(channel, ref newPacket);
|
_peers[peerId].Send(channel, ref newPacket);
|
||||||
}
|
}
|
||||||
else if (data.Type == EventType.DISCONNECTED)
|
|
||||||
|
public void Disconnect(uint peerId, uint errorCode)
|
||||||
{
|
{
|
||||||
_peers[data.PeerId].DisconnectNow(0);
|
_peers[peerId].Reset();
|
||||||
ReceiveBuffer.Enqueue(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Process()
|
||||||
|
{
|
||||||
bool polled = false;
|
bool polled = false;
|
||||||
while (!polled)
|
while (!polled)
|
||||||
{
|
{
|
||||||
if (_host.CheckEvents(out _netEvent) <= 0)
|
if (_host.CheckEvents(out _netEvent) <= 0)
|
||||||
{
|
{
|
||||||
if (_host.Service(15, out _netEvent) <= 0)
|
if (_host.Service(0, out _netEvent) <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
polled = true;
|
polled = true;
|
||||||
@@ -106,43 +93,28 @@ namespace Ragon.Core
|
|||||||
|
|
||||||
case ENet.EventType.Connect:
|
case ENet.EventType.Connect:
|
||||||
{
|
{
|
||||||
var @event = new SocketEvent {PeerId = _netEvent.Peer.ID, Type = EventType.CONNECTED};
|
|
||||||
_peers[_netEvent.Peer.ID] = _netEvent.Peer;
|
_peers[_netEvent.Peer.ID] = _netEvent.Peer;
|
||||||
ReceiveBuffer.Enqueue(@event);
|
_handler.OnEvent(_netEvent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ENet.EventType.Disconnect:
|
case ENet.EventType.Disconnect:
|
||||||
{
|
{
|
||||||
var @event = new SocketEvent {PeerId = _netEvent.Peer.ID, Type = EventType.DISCONNECTED};
|
_handler.OnEvent(_netEvent);
|
||||||
ReceiveBuffer.Enqueue(@event);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ENet.EventType.Timeout:
|
case ENet.EventType.Timeout:
|
||||||
{
|
{
|
||||||
var @event = new SocketEvent {PeerId = _netEvent.Peer.ID, Type = EventType.TIMEOUT};
|
_handler.OnEvent(_netEvent);
|
||||||
ReceiveBuffer.Enqueue(@event);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ENet.EventType.Receive:
|
case ENet.EventType.Receive:
|
||||||
{
|
{
|
||||||
var data = new byte[_netEvent.Packet.Length];
|
_handler.OnEvent(_netEvent);
|
||||||
|
|
||||||
_netEvent.Packet.CopyTo(data);
|
|
||||||
_netEvent.Packet.Dispose();
|
_netEvent.Packet.Dispose();
|
||||||
|
|
||||||
var @event = new SocketEvent {PeerId = _netEvent.Peer.ID, Type = EventType.DATA, Data = data };
|
|
||||||
ReceiveBuffer.Enqueue(@event);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_packetsTimer.Elapsed.Seconds > 5)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Connections: {_host.PeersCount}");
|
|
||||||
_packetsTimer.Restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using ENet;
|
||||||
|
|
||||||
|
namespace Ragon.Core;
|
||||||
|
|
||||||
|
public interface IHandler
|
||||||
|
{
|
||||||
|
public void OnEvent(Event evnt);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Ragon.Core;
|
||||||
|
|
||||||
|
public interface ISocketServer
|
||||||
|
{
|
||||||
|
public void Start(ushort port);
|
||||||
|
public void Process();
|
||||||
|
public void Stop();
|
||||||
|
public void Send(uint peerId, byte[] data, DeliveryType type);
|
||||||
|
public void Disconnect(uint peerId, uint errorCode);
|
||||||
|
}
|
||||||
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user