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