This commit is contained in:
2022-12-17 21:16:02 +04:00
parent 13044357a5
commit ab85578ccf
9 changed files with 565 additions and 558 deletions
+106 -100
View File
@@ -1,101 +1,107 @@
using System.Diagnostics; using System.Diagnostics;
using NLog; using NLog;
using Ragon.Common; using Ragon.Common;
using Ragon.Core.Lobby; using Ragon.Core.Lobby;
using Ragon.Core.Time; using Ragon.Core.Time;
using Ragon.Server; using Ragon.Server;
using Ragon.Server.ENet; using Ragon.Server.ENet;
namespace Ragon.Core; namespace Ragon.Core;
public class Application : INetworkListener public class Application : INetworkListener
{ {
private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly INetworkServer _server; private readonly INetworkServer _server;
private readonly Thread _dedicatedThread; private readonly Thread _dedicatedThread;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly HandlerRegistry _handlerRegistry; private readonly HandlerRegistry _handlerRegistry;
private readonly ILobby _lobby; private readonly ILobby _lobby;
private readonly Loop _loop; private readonly Loop _loop;
private readonly Dictionary<ushort, PlayerContext> _contexts; private readonly Dictionary<ushort, PlayerContext> _contexts;
public Application(Configuration configuration) public Application(Configuration configuration)
{ {
_configuration = configuration; _configuration = configuration;
_dedicatedThread = new Thread(Execute); _dedicatedThread = new Thread(Execute);
_dedicatedThread.IsBackground = true; _dedicatedThread.IsBackground = true;
_contexts = new Dictionary<ushort, PlayerContext>(); _contexts = new Dictionary<ushort, PlayerContext>();
_handlerRegistry = new HandlerRegistry(); _handlerRegistry = new HandlerRegistry();
_lobby = new LobbyInMemory(); _lobby = new LobbyInMemory();
_loop = new Loop(); _loop = new Loop();
if (configuration.Socket == "enet") if (configuration.Socket == "enet")
_server = new ENetServer(); _server = new ENetServer();
Debug.Assert(_server != null, $"Socket type not supported: {configuration.Socket}. Supported: [enet, websocket]"); Debug.Assert(_server != null, $"Socket type not supported: {configuration.Socket}. Supported: [enet, websocket]");
} }
public void Execute() public void Execute()
{ {
while (true) while (true)
{ {
_loop.Tick(); _loop.Tick();
_server.Poll(); _server.Poll();
Thread.Sleep((int) 1000.0f / _configuration.SendRate); Thread.Sleep((int) 1000.0f / _configuration.SendRate);
} }
} }
public void Start() public void Start()
{ {
var networkConfiguration = new NetworkConfiguration() var networkConfiguration = new NetworkConfiguration()
{ {
LimitConnections = _configuration.LimitConnections, LimitConnections = _configuration.LimitConnections,
Protocol = RagonVersion.Parse(_configuration.Protocol), Protocol = RagonVersion.Parse(_configuration.Protocol),
Address = "0.0.0.0", Address = "0.0.0.0",
Port = _configuration.Port, Port = _configuration.Port,
}; };
_server.Start(this, networkConfiguration); _server.Start(this, networkConfiguration);
_dedicatedThread.Start(); _dedicatedThread.Start();
} }
public void Stop() public void Stop()
{ {
_server.Stop(); _server.Stop();
_dedicatedThread.Interrupt(); _dedicatedThread.Interrupt();
} }
public void OnConnected(INetworkConnection connection) public void OnConnected(INetworkConnection connection)
{ {
var context = new PlayerContext(connection, new LobbyPlayer(connection)); var context = new PlayerContext(connection, new LobbyPlayer(connection));
context.Lobby = _lobby; context.Lobby = _lobby;
context.Loop = _loop; context.Loop = _loop;
_logger.Trace($"Connected {connection.Id}"); _logger.Trace($"Connected {connection.Id}");
_contexts.Add(connection.Id, context); _contexts.Add(connection.Id, context);
} }
public void OnDisconnected(INetworkConnection connection) public void OnDisconnected(INetworkConnection connection)
{ {
_logger.Trace($"Disconnected {connection.Id}"); _logger.Trace($"Disconnected {connection.Id}");
if (_contexts.Remove(connection.Id, out var context)) if (_contexts.Remove(connection.Id, out var context))
{ {
context.Room?.RemovePlayer(context.RoomPlayer); var room = context.Room;
context.Dispose(); if (room != null)
} {
} room.RemovePlayer(context.RoomPlayer);
public void OnTimeout(INetworkConnection connection) _lobby.RemoveIfEmpty(room);
{ }
if (_contexts.Remove(connection.Id, out var context)) context.Dispose();
context.Dispose(); }
} }
public void OnData(INetworkConnection connection, byte[] data) public void OnTimeout(INetworkConnection connection)
{ {
if (_contexts.TryGetValue(connection.Id, out var context)) if (_contexts.Remove(connection.Id, out var context))
_handlerRegistry.Handle(context, data); context.Dispose();
} }
public void OnData(INetworkConnection connection, byte[] data)
{
if (_contexts.TryGetValue(connection.Id, out var context))
_handlerRegistry.Handle(context, data);
}
} }
+33 -34
View File
@@ -1,35 +1,34 @@
namespace Ragon.Core.Game; namespace Ragon.Core.Game;
public class EntityList public class EntityList
{ {
private readonly List<Entity> _dynamicEntitiesList = new List<Entity>(); private readonly List<Entity> _dynamicEntitiesList = new List<Entity>();
private readonly List<Entity> _staticEntitiesList = new List<Entity>(); private readonly List<Entity> _staticEntitiesList = new List<Entity>();
private readonly Dictionary<ushort, Entity> _entitiesMap = new Dictionary<ushort, Entity>(); private readonly Dictionary<ushort, Entity> _entitiesMap = new Dictionary<ushort, Entity>();
public IReadOnlyList<Entity> StaticList => _staticEntitiesList; public IReadOnlyList<Entity> StaticList => _staticEntitiesList;
public IReadOnlyList<Entity> DynamicList => _dynamicEntitiesList; public IReadOnlyList<Entity> DynamicList => _dynamicEntitiesList;
public IReadOnlyDictionary<ushort, Entity> Map => _entitiesMap; public IReadOnlyDictionary<ushort, Entity> Map => _entitiesMap;
public void Add(Entity entity) public void Add(Entity entity)
{ {
if (entity.StaticId != 0) if (entity.StaticId != 0)
_staticEntitiesList.Add(entity); _staticEntitiesList.Add(entity);
else else
_dynamicEntitiesList.Add(entity); _dynamicEntitiesList.Add(entity);
_entitiesMap.Add(entity.Id, entity); _entitiesMap.Add(entity.Id, entity);
} }
public Entity Remove(Entity entity) public bool Remove(Entity entity)
{ {
if (_entitiesMap.Remove(entity.Id, out var existEntity)) if (_entitiesMap.Remove(entity.Id, out var existEntity))
{ {
_staticEntitiesList.Remove(entity); _staticEntitiesList.Remove(entity);
_dynamicEntitiesList.Remove(entity); _dynamicEntitiesList.Remove(entity);
return existEntity; return true;
} }
return false;
return null; }
}
} }
+99 -99
View File
@@ -1,100 +1,100 @@
using NLog; using NLog;
using Ragon.Common; using Ragon.Common;
namespace Ragon.Core.Game; namespace Ragon.Core.Game;
public class EntityState public class EntityState
{ {
private Logger _logger = LogManager.GetCurrentClassLogger(); private Logger _logger = LogManager.GetCurrentClassLogger();
private List<EntityStateProperty> _properties; private List<EntityStateProperty> _properties;
private Entity _entity; private Entity _entity;
public EntityState(Entity entity, int capacity = 10) public EntityState(Entity entity, int capacity = 10)
{ {
_entity = entity; _entity = entity;
_properties = new List<EntityStateProperty>(10); _properties = new List<EntityStateProperty>(10);
} }
public void AddProperty(EntityStateProperty property) public void AddProperty(EntityStateProperty property)
{ {
_properties.Add(property); _properties.Add(property);
} }
public void Write(RagonSerializer serializer) public void Write(RagonSerializer serializer)
{ {
serializer.WriteUShort(_entity.Id); serializer.WriteUShort(_entity.Id);
for (int propertyIndex = 0; propertyIndex < _properties.Count; propertyIndex++) for (int propertyIndex = 0; propertyIndex < _properties.Count; propertyIndex++)
{ {
var property = _properties[propertyIndex]; var property = _properties[propertyIndex];
if (property.IsDirty) if (property.IsDirty)
{ {
serializer.WriteBool(true); serializer.WriteBool(true);
var span = serializer.GetWritableData(property.Size); var span = serializer.GetWritableData(property.Size);
var data = property.Read(); var data = property.Read();
data.CopyTo(span); data.CopyTo(span);
property.Clear(); property.Clear();
} }
else else
{ {
serializer.WriteBool(false); serializer.WriteBool(false);
} }
} }
} }
public void Read(RagonSerializer serializer) public void Read(RagonSerializer serializer)
{ {
for (var i = 0; i < _properties.Count; i++) for (var i = 0; i < _properties.Count; i++)
{ {
if (serializer.ReadBool()) if (serializer.ReadBool())
{ {
var property = _properties[i]; var property = _properties[i];
var size = property.Size; var size = property.Size;
if (!property.IsFixed) if (!property.IsFixed)
size = serializer.ReadUShort(); size = serializer.ReadUShort();
if (size > property.Capacity) if (size > property.Capacity)
{ {
Console.WriteLine($"Property {i} payload too large, size: {size}"); Console.WriteLine($"Property {i} payload too large, size: {size}");
continue; continue;
} }
var propertyPayload = serializer.ReadData(size); var propertyPayload = serializer.ReadData(size);
property.Write(ref propertyPayload); property.Write(ref propertyPayload);
property.Size = size; property.Size = size;
} }
} }
} }
public void Snapshot(RagonSerializer serializer) public void Snapshot(RagonSerializer serializer)
{ {
ReadOnlySpan<byte> payload = _entity.Payload.AsSpan(); ReadOnlySpan<byte> payload = _entity.Payload.AsSpan();
serializer.WriteUShort(_entity.Type); serializer.WriteUShort(_entity.Type);
serializer.WriteUShort(_entity.Id); serializer.WriteUShort(_entity.Id);
if (_entity.StaticId != 0) if (_entity.StaticId != 0)
serializer.WriteUShort(_entity.StaticId); serializer.WriteUShort(_entity.StaticId);
serializer.WriteUShort(_entity.Owner.Connection.Id); serializer.WriteUShort(_entity.Owner.Connection.Id);
serializer.WriteUShort((ushort) payload.Length); serializer.WriteUShort((ushort) payload.Length);
serializer.WriteData(ref payload); serializer.WriteData(ref payload);
for (int propertyIndex = 0; propertyIndex < _properties.Count; propertyIndex++) for (int propertyIndex = 0; propertyIndex < _properties.Count; propertyIndex++)
{ {
var property = _properties[propertyIndex]; var property = _properties[propertyIndex];
var hasPayload = property.IsFixed || property.Size > 0 && !property.IsFixed; var hasPayload = property.IsFixed || property.Size > 0 && !property.IsFixed;
if (hasPayload) if (hasPayload)
{ {
serializer.WriteBool(true); serializer.WriteBool(true);
var span = serializer.GetWritableData(property.Size); var span = serializer.GetWritableData(property.Size);
var data = property.Read(); var data = property.Read();
data.CopyTo(span); data.CopyTo(span);
} }
else else
{ {
serializer.WriteBool(false); serializer.WriteBool(false);
} }
} }
} }
} }
+165 -168
View File
@@ -1,169 +1,166 @@
using Ragon.Common; using Ragon.Common;
using Ragon.Core.Time; using Ragon.Core.Time;
namespace Ragon.Core.Game; namespace Ragon.Core.Game;
public class Room: IAction public class Room: IAction
{ {
public string Id { get; } public string Id { get; private set; }
public RoomInformation Info { get; } public RoomInformation Info { get; private set; }
public RoomPlayer Owner { get; set; } public RoomPlayer Owner { get; private set; }
public RagonSerializer Writer { get; }
public Dictionary<ushort, RoomPlayer> Players { get; } public Dictionary<ushort, RoomPlayer> Players { get; private set; }
public List<RoomPlayer> WaitPlayersList { get; private set; } public List<RoomPlayer> WaitPlayersList { get; private set; }
public List<RoomPlayer> ReadyPlayersList { get; private set; } public List<RoomPlayer> ReadyPlayersList { get; private set; }
public List<RoomPlayer> PlayerList { get; private set; } public List<RoomPlayer> PlayerList { get; private set; }
public Dictionary<ushort, Entity> Entities { get; private set; } public Dictionary<ushort, Entity> Entities { get; private set; }
public List<Entity> DynamicEntitiesList { get; private set; } public List<Entity> DynamicEntitiesList { get; private set; }
public List<Entity> StaticEntitiesList { get; private set; } public List<Entity> StaticEntitiesList { get; private set; }
public List<Entity> EntityList { get; private set; } public List<Entity> EntityList { get; private set; }
private HashSet<Entity> _entitiesDirtySet; private readonly HashSet<Entity> _entitiesDirtySet;
private RagonSerializer _writer;
public Room(string roomId, RoomInformation info)
public RagonSerializer Writer => _writer; {
Id = roomId;
public Room(string roomId, RoomInformation info) Info = info;
{
Id = roomId; Players = new Dictionary<ushort, RoomPlayer>(info.Max);
Info = info; WaitPlayersList = new List<RoomPlayer>(info.Max);
ReadyPlayersList = new List<RoomPlayer>(info.Max);
Players = new Dictionary<ushort, RoomPlayer>(info.Max); PlayerList = new List<RoomPlayer>(info.Max);
WaitPlayersList = new List<RoomPlayer>(info.Max);
ReadyPlayersList = new List<RoomPlayer>(info.Max); Entities = new Dictionary<ushort, Entity>();
PlayerList = new List<RoomPlayer>(info.Max); DynamicEntitiesList = new List<Entity>();
StaticEntitiesList = new List<Entity>();
Entities = new Dictionary<ushort, Entity>(); EntityList = new List<Entity>();
DynamicEntitiesList = new List<Entity>();
StaticEntitiesList = new List<Entity>(); _entitiesDirtySet = new HashSet<Entity>();
EntityList = new List<Entity>(); Writer = new RagonSerializer(512);
}
_entitiesDirtySet = new HashSet<Entity>();
_writer = new RagonSerializer(512); public void AttachEntity(RoomPlayer newOwner, Entity entity)
} {
Entities.Add(entity.Id, entity);
public void AttachEntity(RoomPlayer newOwner, Entity entity) EntityList.Add(entity);
{
Entities.Add(entity.Id, entity); if (entity.StaticId == 0)
EntityList.Add(entity); DynamicEntitiesList.Add(entity);
else
if (entity.StaticId == 0) StaticEntitiesList.Add(entity);
DynamicEntitiesList.Add(entity);
else entity.Create();
StaticEntitiesList.Add(entity);
newOwner.Entities.Add(entity);
entity.Create(); }
newOwner.Entities.Add(entity); public void DetachEntity(RoomPlayer currentOwner, Entity entity, byte[] payload)
} {
Entities.Remove(entity.Id);
public void DetachEntity(RoomPlayer currentOwner, Entity entity, byte[] payload) EntityList.Remove(entity);
{ StaticEntitiesList.Remove(entity);
Entities.Remove(entity.Id); DynamicEntitiesList.Remove(entity);
EntityList.Remove(entity); _entitiesDirtySet.Remove(entity);
StaticEntitiesList.Remove(entity);
DynamicEntitiesList.Remove(entity); entity.Destroy(payload);
_entitiesDirtySet.Remove(entity); currentOwner.Entities.Remove(entity);
}
entity.Destroy(payload);
currentOwner.Entities.Remove(entity); public void Tick()
} {
var entities = (ushort) _entitiesDirtySet.Count;
public void Tick() if (entities > 0)
{ {
var entities = (ushort) _entitiesDirtySet.Count; Writer.Clear();
if (entities > 0) Writer.WriteOperation(RagonOperation.REPLICATE_ENTITY_STATE);
{ Writer.WriteUShort(entities);
_writer.Clear();
_writer.WriteOperation(RagonOperation.REPLICATE_ENTITY_STATE); foreach (var entity in _entitiesDirtySet)
_writer.WriteUShort(entities); entity.State.Write(Writer);
foreach (var entity in _entitiesDirtySet) _entitiesDirtySet.Clear();
entity.State.Write(_writer);
var sendData = Writer.ToArray();
_entitiesDirtySet.Clear(); foreach (var roomPlayer in ReadyPlayersList)
roomPlayer.Connection.UnreliableChannel.Send(sendData);
var sendData = _writer.ToArray(); }
foreach (var roomPlayer in ReadyPlayersList) }
roomPlayer.Connection.UnreliableChannel.Send(sendData);
} public void AddPlayer(RoomPlayer player)
} {
if (Players.Count == 0)
public void AddPlayer(RoomPlayer player) Owner = player;
{
if (Players.Count == 0) player.Attach(this);
Owner = player;
PlayerList.Add(player);
player.Attach(this); Players.Add(player.Connection.Id, player);
}
PlayerList.Add(player);
Players.Add(player.Connection.Id, player); public void RemovePlayer(RoomPlayer roomPlayer)
} {
if (Players.Remove(roomPlayer.Connection.Id, out var player))
public void RemovePlayer(RoomPlayer roomPlayer) {
{ PlayerList.Remove(player);
if (Players.Remove(roomPlayer.Connection.Id, out var player))
{ {
PlayerList.Remove(player); Writer.Clear();
Writer.WriteOperation(RagonOperation.PLAYER_LEAVED);
{ Writer.WriteString(player.Id);
_writer.Clear();
_writer.WriteOperation(RagonOperation.PLAYER_LEAVED); var entitiesToDelete = player.Entities.DynamicList;
_writer.WriteString(player.Id); Writer.WriteUShort((ushort) entitiesToDelete.Count);
foreach (var entity in entitiesToDelete)
var entitiesToDelete = player.Entities.DynamicList; {
_writer.WriteUShort((ushort) entitiesToDelete.Count); Writer.WriteUShort(entity.Id);
foreach (var entity in entitiesToDelete) EntityList.Remove(entity);
{ }
_writer.WriteUShort(entity.Id);
EntityList.Remove(entity); var sendData = Writer.ToArray();
} Broadcast(sendData);
}
var sendData = _writer.ToArray();
Broadcast(sendData); if (roomPlayer.Connection.Id == Owner.Connection.Id && PlayerList.Count > 0)
} {
var nextOwner = PlayerList[0];
if (roomPlayer.Connection.Id == Owner.Connection.Id && PlayerList.Count > 0)
{ Owner = nextOwner;
var nextOwner = PlayerList[0];
var entitiesToUpdate = roomPlayer.Entities.StaticList;
Owner = nextOwner;
Writer.Clear();
var entitiesToUpdate = roomPlayer.Entities.StaticList; Writer.WriteOperation(RagonOperation.OWNERSHIP_CHANGED);
Writer.WriteString(Owner.Id);
_writer.Clear(); Writer.WriteUShort((ushort) entitiesToUpdate.Count);
_writer.WriteOperation(RagonOperation.OWNERSHIP_CHANGED);
_writer.WriteString(Owner.Id); foreach (var entity in entitiesToUpdate)
_writer.WriteUShort((ushort) entitiesToUpdate.Count); {
Writer.WriteUShort(entity.Id);
foreach (var entity in entitiesToUpdate)
{ entity.SetOwner(nextOwner);
_writer.WriteUShort(entity.Id); nextOwner.Entities.Add(entity);
}
entity.SetOwner(nextOwner);
nextOwner.Entities.Add(entity); var sendData = Writer.ToArray();
} Broadcast(sendData);
}
var sendData = _writer.ToArray(); }
Broadcast(sendData); }
}
} public void UpdateReadyPlayerList()
} {
ReadyPlayersList = PlayerList.Where(p => p.IsLoaded).ToList();
public void UpdateReadyPlayerList() }
{
ReadyPlayersList = PlayerList.Where(p => p.IsLoaded).ToList(); public void Track(Entity entity)
} {
_entitiesDirtySet.Add(entity);
public void Track(Entity entity) }
{
_entitiesDirtySet.Add(entity); public void Broadcast(byte[] data)
} {
foreach (var readyPlayer in ReadyPlayersList)
public void Broadcast(byte[] data) readyPlayer.Connection.ReliableChannel.Send(data);
{ }
foreach (var readyPlayer in ReadyPlayersList)
readyPlayer.Connection.ReliableChannel.Send(data);
}
} }
+12 -12
View File
@@ -1,13 +1,13 @@
namespace Ragon.Core.Game; namespace Ragon.Core.Game;
public class RoomInformation public class RoomInformation
{ {
public string Map { get; set; } public string Map { get; init; } = "none";
public int Min { get; set; } public int Min { get; init; }
public int Max { get; set; } public int Max { get; init; }
public override string ToString() public override string ToString()
{ {
return $"Map: {Map} Count: {Min}/{Max}"; return $"Map: {Map} Count: {Min}/{Max}";
} }
} }
+1 -1
View File
@@ -8,5 +8,5 @@ public interface ILobby
public bool FindRoomById(string roomId, [MaybeNullWhen(false)] out Room room); public bool FindRoomById(string roomId, [MaybeNullWhen(false)] out Room room);
public bool FindRoomByMap(string map, [MaybeNullWhen(false)] out Room room); public bool FindRoomByMap(string map, [MaybeNullWhen(false)] out Room room);
public void Persist(Room room); public void Persist(Room room);
public void Remove(Room room); public void RemoveIfEmpty(Room room);
} }
+7 -3
View File
@@ -47,11 +47,15 @@ public class LobbyInMemory : ILobby
_rooms.Add(room); _rooms.Add(room);
foreach (var r in _rooms) foreach (var r in _rooms)
_logger.Trace($"{r.Id} {r.Info}"); _logger.Trace($"Room: {r.Id} {r.Info} Players: {r.Players.Count}");
} }
public void Remove(Room room) public void RemoveIfEmpty(Room room)
{ {
_rooms.Remove(room); if (room.Players.Count == 0)
_rooms.Remove(room);
foreach (var r in _rooms)
_logger.Trace($"Room: {r.Id} {r.Info} Players: {r.Players.Count}");
} }
} }
+27 -27
View File
@@ -1,28 +1,28 @@
using NLog; using NLog;
using Ragon.Core.Game; using Ragon.Core.Game;
using Ragon.Core.Lobby; using Ragon.Core.Lobby;
using Ragon.Core.Time; using Ragon.Core.Time;
using Ragon.Server; using Ragon.Server;
namespace Ragon.Core; namespace Ragon.Core;
public class PlayerContext: IDisposable public class PlayerContext: IDisposable
{ {
public INetworkConnection Connection { get; } public INetworkConnection Connection { get; }
public Loop Loop; public Loop Loop;
public ILobby Lobby { get; set; } public ILobby Lobby { get; set; }
public LobbyPlayer LobbyPlayer { private set; get; } public LobbyPlayer LobbyPlayer { private set; get; }
public Room? Room { get; set; } public Room? Room { get; set; }
public RoomPlayer? RoomPlayer { get; set; } public RoomPlayer? RoomPlayer { get; set; }
public PlayerContext(INetworkConnection conn, LobbyPlayer player) public PlayerContext(INetworkConnection conn, LobbyPlayer player)
{ {
Connection = conn; Connection = conn;
LobbyPlayer = player; LobbyPlayer = player;
} }
public void Dispose() public void Dispose()
{ {
RoomPlayer?.Room.RemovePlayer(RoomPlayer); RoomPlayer?.Room.RemovePlayer(RoomPlayer);
} }
} }
+115 -114
View File
@@ -1,115 +1,116 @@
using System.Diagnostics; using System.Diagnostics;
using ENet; using ENet;
using NLog; using NLog;
using Ragon.Common; using Ragon.Common;
namespace Ragon.Server.ENet namespace Ragon.Server.ENet
{ {
public sealed class ENetServer: INetworkServer public sealed class ENetServer: INetworkServer
{ {
public ENetConnection[] Connections; private readonly Host _host;
private ILogger _logger = LogManager.GetCurrentClassLogger(); private readonly ILogger _logger = LogManager.GetCurrentClassLogger();
private INetworkListener _listener;
private uint _protocol; private ENetConnection[] _connections;
private Host _host; private uint _protocol;
private Event _event; private INetworkListener _listener;
private NetworkConfiguration _configuration; private Event _event;
public ENetServer() public ENetServer()
{ {
_host = new Host(); _host = new Host();
} _connections = Array.Empty<ENetConnection>();
}
public void Start(INetworkListener listener, NetworkConfiguration configuration)
{ public void Start(INetworkListener listener, NetworkConfiguration configuration)
Library.Initialize(); {
Library.Initialize();
_listener = listener;
_protocol = configuration.Protocol; _connections = new ENetConnection[configuration.LimitConnections];
Connections = new ENetConnection[configuration.LimitConnections]; _listener = listener;
_protocol = configuration.Protocol;
var address = new Address { Port = (ushort) configuration.Port };
_host.Create(address, Connections.Length, 2, 0, 0, 1024 * 1024); var address = new Address { Port = (ushort) configuration.Port };
_host.Create(address, _connections.Length, 2, 0, 0, 1024 * 1024);
var protocolDecoded = RagonVersion.Parse(_protocol);
_logger.Info($"Network listening on {configuration.Port}"); var protocolDecoded = RagonVersion.Parse(_protocol);
_logger.Info($"Protocol: {protocolDecoded}"); _logger.Info($"Network listening on {configuration.Port}");
} _logger.Info($"Protocol: {protocolDecoded}");
}
public void Poll()
{ public void Poll()
bool polled = false; {
while (!polled) bool polled = false;
{ while (!polled)
if (_host.CheckEvents(out _event) <= 0) {
{ if (_host.CheckEvents(out _event) <= 0)
if (_host.Service(0, out _event) <= 0) {
break; if (_host.Service(0, out _event) <= 0)
break;
polled = true;
} polled = true;
}
switch (_event.Type)
{ switch (_event.Type)
case EventType.None: {
{ case EventType.None:
_logger.Trace("None event"); {
break; _logger.Trace("None event");
} break;
case EventType.Connect: }
{ case EventType.Connect:
if (IsValidProtocol(_event.Data)) {
{ if (!IsValidProtocol(_event.Data))
_logger.Warn("Mismatched protocol, close connection"); {
break; _logger.Warn("Mismatched protocol, close connection");
} break;
}
var connection = new ENetConnection(_event.Peer);
Connections[_event.Peer.ID] = connection; var connection = new ENetConnection(_event.Peer);
_connections[_event.Peer.ID] = connection;
_listener.OnConnected(connection); _listener.OnConnected(connection);
break; break;
} }
case EventType.Disconnect: case EventType.Disconnect:
{ {
var connection = Connections[_event.Peer.ID]; var connection = _connections[_event.Peer.ID];
_listener.OnDisconnected(connection); _listener.OnDisconnected(connection);
break; break;
} }
case EventType.Timeout: case EventType.Timeout:
{ {
var connection = Connections[_event.Peer.ID]; var connection = _connections[_event.Peer.ID];
_listener.OnTimeout(connection); _listener.OnTimeout(connection);
break; break;
} }
case EventType.Receive: case EventType.Receive:
{ {
var peerId = (ushort) _event.Peer.ID; var peerId = (ushort) _event.Peer.ID;
var connection = Connections[peerId]; var connection = _connections[peerId];
var dataRaw = new byte[_event.Packet.Length]; var dataRaw = new byte[_event.Packet.Length];
_event.Packet.CopyTo(dataRaw); _event.Packet.CopyTo(dataRaw);
_event.Packet.Dispose(); _event.Packet.Dispose();
_listener.OnData(connection, dataRaw); _listener.OnData(connection, dataRaw);
break; break;
} }
} }
} }
} }
public void Stop() public void Stop()
{ {
_host?.Dispose(); _host?.Dispose();
Library.Deinitialize(); Library.Deinitialize();
} }
private bool IsValidProtocol(uint protocol) private bool IsValidProtocol(uint protocol)
{ {
return protocol == _configuration.Protocol; Console.WriteLine($"{protocol} {_protocol}");
} return protocol == _protocol;
} }
}
} }