From d82964526c68965b0d83b3ec425fcb09ff28676e Mon Sep 17 00:00:00 2001 From: edmand46 Date: Sat, 13 Apr 2024 16:17:31 +0300 Subject: [PATCH 1/3] feat(wip): room list support --- .../Sources/Handler/JoinSuccessHandler.cs | 8 +- .../Sources/Handler/RoomListHandler.cs | 43 ++++++++++ .../Listener/IRagonRoomListListener.cs | 6 ++ Ragon.Client/Sources/RagonClient.cs | 86 +++++++++---------- Ragon.Client/Sources/RagonListenerList.cs | 7 ++ Ragon.Client/Sources/RagonRoom.cs | 12 +-- Ragon.Client/Sources/RagonRoomInformation.cs | 13 +++ Ragon.Protocol/Sources/RagonOperation.cs | 1 + .../Sources/Handler/RoomCreateOperation.cs | 3 + .../Handler/RoomJoinOrCreateOperation.cs | 7 ++ Ragon.Server/Sources/Lobby/IRagonLobby.cs | 1 + .../Sources/Lobby/RagonLobbyDispatcher.cs | 33 +++++++ .../Sources/Lobby/RagonLobbyInMemory.cs | 2 + Ragon.Server/Sources/RagonServer.cs | 20 ++++- Ragon.Server/Sources/Room/IRagonRoom.cs | 6 ++ Ragon.Server/Sources/Time/RagonActionTimer.cs | 21 +++++ 16 files changed, 215 insertions(+), 54 deletions(-) create mode 100644 Ragon.Client/Sources/Handler/RoomListHandler.cs create mode 100644 Ragon.Client/Sources/Listener/IRagonRoomListListener.cs create mode 100644 Ragon.Client/Sources/RagonRoomInformation.cs create mode 100644 Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs create mode 100644 Ragon.Server/Sources/Time/RagonActionTimer.cs diff --git a/Ragon.Client/Sources/Handler/JoinSuccessHandler.cs b/Ragon.Client/Sources/Handler/JoinSuccessHandler.cs index 2d68fc0..8e1c433 100644 --- a/Ragon.Client/Sources/Handler/JoinSuccessHandler.cs +++ b/Ragon.Client/Sources/Handler/JoinSuccessHandler.cs @@ -19,9 +19,9 @@ using Ragon.Protocol; namespace Ragon.Client; -public struct RagonRoomInformation +public struct RoomParameters { - public RagonRoomInformation(string roomId, string playerId, string ownerId, ushort min, ushort max) + public RoomParameters(string roomId, string playerId, string ownerId, ushort min, ushort max) { RoomId = roomId; PlayerId = playerId; @@ -39,6 +39,8 @@ public struct RagonRoomInformation internal class JoinSuccessHandler : IHandler { + + private readonly RagonListenerList _listenerList; private readonly RagonPlayerCache _playerCache; private readonly RagonEntityCache _entityCache; @@ -67,7 +69,7 @@ internal class JoinSuccessHandler : IHandler var sceneName = reader.ReadString(); var scene = new RagonScene(_client, _playerCache, _entityCache, sceneName); - var roomInfo = new RagonRoomInformation(roomId, localId, ownerId, min, max); + var roomInfo = new RoomParameters(roomId, localId, ownerId, min, max); var room = new RagonRoom(_client, _entityCache, _playerCache, roomInfo, scene); _playerCache.SetOwnerAndLocal(ownerId, localId); diff --git a/Ragon.Client/Sources/Handler/RoomListHandler.cs b/Ragon.Client/Sources/Handler/RoomListHandler.cs new file mode 100644 index 0000000..6656893 --- /dev/null +++ b/Ragon.Client/Sources/Handler/RoomListHandler.cs @@ -0,0 +1,43 @@ +using Ragon.Protocol; + +namespace Ragon.Client; + +internal class RoomListHandler: IHandler +{ + private RagonListenerList _listenerList; + private RagonSession _session; + + public RoomListHandler(RagonSession session, RagonListenerList list) + { + _session = session; + _listenerList = list; + } + + public void Handle(RagonBuffer reader) + { + var roomCount = reader.ReadUShort(); + var roomList = new RagonRoomInformation[roomCount]; + for (int i = 0; i < roomCount; i++) + { + var id = reader.ReadString(); + var scene = reader.ReadString(); + var players = reader.ReadUShort(); + var maxPlayers = reader.ReadUShort(); + var minPlayers = reader.ReadUShort(); + + var roomInfo = new RagonRoomInformation() + { + Id = id, + Scene = scene, + PlayerCount = players, + PlayerMax = maxPlayers, + PlayerMin = minPlayers, + Properties = new Dictionary() + }; + + roomList[i] = roomInfo; + } + + _listenerList.OnRoomList(roomList); + } +} \ No newline at end of file diff --git a/Ragon.Client/Sources/Listener/IRagonRoomListListener.cs b/Ragon.Client/Sources/Listener/IRagonRoomListListener.cs new file mode 100644 index 0000000..5b91ee3 --- /dev/null +++ b/Ragon.Client/Sources/Listener/IRagonRoomListListener.cs @@ -0,0 +1,6 @@ +namespace Ragon.Client; + +public interface IRagonRoomListListener +{ + public void OnRoomListUpdate(IReadOnlyList roomsInfos); +} \ No newline at end of file diff --git a/Ragon.Client/Sources/RagonClient.cs b/Ragon.Client/Sources/RagonClient.cs index 7e7644c..a3533b8 100644 --- a/Ragon.Client/Sources/RagonClient.cs +++ b/Ragon.Client/Sources/RagonClient.cs @@ -29,7 +29,7 @@ namespace Ragon.Client private RagonBuffer _writeBuffer; private RagonRoom _room; private RagonSession _session; - private RagonListenerList listeners; + private RagonListenerList _listeners; private RagonPlayerCache _playerCache; private RagonEntityCache _entityCache; private RagonEventCache _eventCache; @@ -56,7 +56,7 @@ namespace Ragon.Client public RagonClient(INetworkConnection connection, int rate) { - listeners = new RagonListenerList(this); + _listeners = new RagonListenerList(this); _connection = connection; _connection.OnData += OnData; @@ -104,25 +104,26 @@ namespace Ragon.Client _entityCache = new RagonEntityCache(this, _playerCache, _sceneCollector); _handlers = new IHandler[byte.MaxValue]; - _handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(this, listeners); - _handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(listeners); - _handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, listeners, _playerCache, _entityCache); - _handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(listeners); - _handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, listeners, _entityCache); - _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(listeners, _playerCache, _entityCache); - _handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new EntityOwnershipHandler(listeners, _playerCache, _entityCache); - _handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, listeners); - _handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, listeners); - _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, listeners); + _handlers[(byte)RagonOperation.AUTHORIZED_SUCCESS] = new AuthorizeSuccessHandler(this, _listeners); + _handlers[(byte)RagonOperation.AUTHORIZED_FAILED] = new AuthorizeFailedHandler(_listeners); + _handlers[(byte)RagonOperation.JOIN_SUCCESS] = new JoinSuccessHandler(this, _listeners, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.JOIN_FAILED] = new JoinFailedHandler(_listeners); + _handlers[(byte)RagonOperation.LEAVE_ROOM] = new LeaveRoomHandler(this, _listeners, _entityCache); + _handlers[(byte)RagonOperation.OWNERSHIP_ROOM_CHANGED] = new OwnershipRoomHandler(_listeners, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.OWNERSHIP_ENTITY_CHANGED] = new EntityOwnershipHandler(_listeners, _playerCache, _entityCache); + _handlers[(byte)RagonOperation.PLAYER_JOINED] = new PlayerJoinHandler(_playerCache, _listeners); + _handlers[(byte)RagonOperation.PLAYER_LEAVED] = new PlayerLeftHandler(_entityCache, _playerCache, _listeners); + _handlers[(byte)RagonOperation.LOAD_SCENE] = new SceneLoadHandler(this, _listeners); _handlers[(byte)RagonOperation.CREATE_ENTITY] = new EntityCreateHandler(this, _playerCache, _entityCache, _entityListener); _handlers[(byte)RagonOperation.REMOVE_ENTITY] = new EntityRemoveHandler(_entityCache); _handlers[(byte)RagonOperation.REPLICATE_ENTITY_STATE] = new StateEntityHandler(_entityCache); _handlers[(byte)RagonOperation.REPLICATE_ENTITY_EVENT] = new EntityEventHandler(_playerCache, _entityCache); _handlers[(byte)RagonOperation.REPLICATE_ROOM_EVENT] = new RoomEventHandler(this, _playerCache); - _handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, listeners, _entityCache, _playerCache, _entityListener); + _handlers[(byte)RagonOperation.SNAPSHOT] = new SnapshotHandler(this, _listeners, _entityCache, _playerCache, _entityListener); _handlers[(byte)RagonOperation.TIMESTAMP_SYNCHRONIZATION] = new TimestampHandler(this); - _handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new RoomDataHandler(_playerCache, listeners); - + _handlers[(byte)RagonOperation.REPLICATE_RAW_DATA] = new RoomDataHandler(_playerCache, _listeners); + _handlers[(byte)RagonOperation.ROOM_LIST_UPDATED] = new RoomListHandler(_session, _listeners); + var protocolRaw = RagonVersion.Parse(protocol); _connection.Connect(address, port, protocolRaw); } @@ -152,7 +153,7 @@ namespace Ragon.Client _stats.Update(_connection.BytesSent, _connection.BytesReceived, _connection.Ping, dt); } - listeners.Update(); + _listeners.Update(); _connection.Update(); } @@ -166,31 +167,30 @@ namespace Ragon.Client _connection.Dispose(); } - public void AddListener(IRagonListener listener) => listeners.Add(listener); - public void AddListener(IRagonAuthorizationListener listener) => listeners.Add(listener); - public void AddListener(IRagonConnectionListener listener) => listeners.Add(listener); - public void AddListener(IRagonFailedListener listener) => listeners.Add(listener); - public void AddListener(IRagonJoinListener listener) => listeners.Add(listener); - public void AddListener(IRagonLeftListener listener) => listeners.Add(listener); - public void AddListener(IRagonOwnershipChangedListener listener) => listeners.Add(listener); - public void AddListener(IRagonPlayerJoinListener listener) => listeners.Add(listener); - public void AddListener(IRagonPlayerLeftListener listener) => listeners.Add(listener); - public void AddListener(IRagonSceneListener listener) => listeners.Add(listener); - public void AddListener(IRagonSceneRequestListener listener) => listeners.Add(listener); - public void AddListener(IRagonDataListener listener) => listeners.Add(listener); - - public void RemoveListener(IRagonListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonAuthorizationListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonConnectionListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonFailedListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonJoinListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonLeftListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonOwnershipChangedListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonPlayerJoinListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonPlayerLeftListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonSceneListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonSceneRequestListener listener) => listeners.Remove(listener); - public void RemoveListener(IRagonDataListener listener) => listeners.Remove(listener); + public void AddListener(IRagonListener listener) => _listeners.Add(listener); + public void AddListener(IRagonAuthorizationListener listener) => _listeners.Add(listener); + public void AddListener(IRagonConnectionListener listener) => _listeners.Add(listener); + public void AddListener(IRagonFailedListener listener) => _listeners.Add(listener); + public void AddListener(IRagonJoinListener listener) => _listeners.Add(listener); + public void AddListener(IRagonLeftListener listener) => _listeners.Add(listener); + public void AddListener(IRagonOwnershipChangedListener listener) => _listeners.Add(listener); + public void AddListener(IRagonPlayerJoinListener listener) => _listeners.Add(listener); + public void AddListener(IRagonPlayerLeftListener listener) => _listeners.Add(listener); + public void AddListener(IRagonSceneListener listener) => _listeners.Add(listener); + public void AddListener(IRagonSceneRequestListener listener) => _listeners.Add(listener); + public void AddListener(IRagonDataListener listener) => _listeners.Add(listener); + public void RemoveListener(IRagonListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonAuthorizationListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonConnectionListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonFailedListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonJoinListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonLeftListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonOwnershipChangedListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonPlayerJoinListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonPlayerLeftListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonSceneListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonSceneRequestListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonDataListener listener) => _listeners.Remove(listener); #endregion @@ -234,7 +234,7 @@ namespace Ragon.Client { RagonLog.Trace("Connected"); - listeners.OnConnected(); + _listeners.OnConnected(); _status = RagonStatus.CONNECTED; } @@ -242,7 +242,7 @@ namespace Ragon.Client { RagonLog.Trace($"Disconnected: {reason}"); - listeners.OnDisconnected(reason); + _listeners.OnDisconnected(reason); _status = RagonStatus.DISCONNECTED; } diff --git a/Ragon.Client/Sources/RagonListenerList.cs b/Ragon.Client/Sources/RagonListenerList.cs index 24af60d..10b8848 100644 --- a/Ragon.Client/Sources/RagonListenerList.cs +++ b/Ragon.Client/Sources/RagonListenerList.cs @@ -32,6 +32,7 @@ namespace Ragon.Client private readonly List _playerJoinListeners = new(); private readonly List _playerLeftListeners = new(); private readonly List _dataListeners = new(); + private readonly List _roomListListeners = new(); private readonly List _delayedActions = new(); public RagonListenerList(RagonClient client) @@ -263,5 +264,11 @@ namespace Ragon.Client foreach (var listener in _dataListeners) listener.OnData(player, data); } + + public void OnRoomList(RagonRoomInformation[] roomInfos) + { + foreach (var listListener in _roomListListeners) + listListener.OnRoomListUpdate(roomInfos); + } } } \ No newline at end of file diff --git a/Ragon.Client/Sources/RagonRoom.cs b/Ragon.Client/Sources/RagonRoom.cs index 3d46051..bf8d7c9 100644 --- a/Ragon.Client/Sources/RagonRoom.cs +++ b/Ragon.Client/Sources/RagonRoom.cs @@ -53,11 +53,11 @@ namespace Ragon.Client private RagonScene _scene; private RagonEntityCache _entityCache; private RagonPlayerCache _playerCache; - private RagonRoomInformation _information; + private RoomParameters _parameters; - public string Id => _information.RoomId; - public int MinPlayers => _information.Min; - public int MaxPlayers => _information.Max; + public string Id => _parameters.RoomId; + public int MinPlayers => _parameters.Min; + public int MaxPlayers => _parameters.Max; public string Scene => _scene.Name; public IReadOnlyList Players => _playerCache.Players; @@ -71,11 +71,11 @@ namespace Ragon.Client public RagonRoom(RagonClient client, RagonEntityCache entityCache, RagonPlayerCache playerCache, - RagonRoomInformation information, + RoomParameters parameters, RagonScene scene) { _client = client; - _information = information; + _parameters = parameters; _entityCache = entityCache; _playerCache = playerCache; _scene = scene; diff --git a/Ragon.Client/Sources/RagonRoomInformation.cs b/Ragon.Client/Sources/RagonRoomInformation.cs new file mode 100644 index 0000000..aeda469 --- /dev/null +++ b/Ragon.Client/Sources/RagonRoomInformation.cs @@ -0,0 +1,13 @@ +using Ragon.Protocol; + +namespace Ragon.Client; + +public struct RagonRoomInformation +{ + public string Id; + public string Scene; + public int PlayerMax; + public int PlayerMin; + public int PlayerCount; + public Dictionary Properties; +} \ No newline at end of file diff --git a/Ragon.Protocol/Sources/RagonOperation.cs b/Ragon.Protocol/Sources/RagonOperation.cs index 2c43def..b7d6787 100644 --- a/Ragon.Protocol/Sources/RagonOperation.cs +++ b/Ragon.Protocol/Sources/RagonOperation.cs @@ -44,5 +44,6 @@ namespace Ragon.Protocol TRANSFER_ROOM_OWNERSHIP = 23, TRANSFER_ENTITY_OWNERSHIP = 24, TIMESTAMP_SYNCHRONIZATION = 25, + ROOM_LIST_UPDATED = 26, } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs index a2b5b10..90060ce 100644 --- a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs @@ -80,6 +80,9 @@ public sealed class RoomCreateOperation : BaseOperation var roomPlugin = _serverPlugin.CreateRoomPlugin(information); var room = new RagonRoom(roomId, information, roomPlugin); + if (!roomPlugin.OnPlayerJoined(roomPlayer)) + return; + roomPlayer.OnAttached(room); context.Scheduler.Run(room); diff --git a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs index c19938b..325cfaf 100644 --- a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs @@ -53,6 +53,10 @@ public sealed class RoomJoinOrCreateOperation : BaseOperation if (context.Lobby.FindRoomByScene(_roomParameters.Scene, out var existsRoom)) { var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); + + if (!existsRoom.Plugin.OnPlayerJoined(player)) + return; + context.SetRoom(existsRoom, player); _ragonWebHookPlugin.RoomJoined(context, existsRoom, player); @@ -72,6 +76,9 @@ public sealed class RoomJoinOrCreateOperation : BaseOperation var roomPlugin = _serverPlugin.CreateRoomPlugin(information); var room = new RagonRoom(roomId, information, roomPlugin); + if (!roomPlugin.OnPlayerJoined(roomPlayer)) + return; + _ragonWebHookPlugin.RoomCreated(context, room, roomPlayer); context.Lobby.Persist(room); diff --git a/Ragon.Server/Sources/Lobby/IRagonLobby.cs b/Ragon.Server/Sources/Lobby/IRagonLobby.cs index 2c047a3..f80eecb 100644 --- a/Ragon.Server/Sources/Lobby/IRagonLobby.cs +++ b/Ragon.Server/Sources/Lobby/IRagonLobby.cs @@ -21,6 +21,7 @@ namespace Ragon.Server.Lobby; public interface IRagonLobby { + public IReadOnlyList Rooms { get; } public bool FindRoomById(string roomId, [MaybeNullWhen(false)] out RagonRoom room); public bool FindRoomByScene(string sceneName, [MaybeNullWhen(false)] out RagonRoom room); public void Persist(RagonRoom room); diff --git a/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs b/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs new file mode 100644 index 0000000..e843c67 --- /dev/null +++ b/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs @@ -0,0 +1,33 @@ +using Ragon.Protocol; +using Ragon.Server.Room; + +namespace Ragon.Server.Lobby; + +public class RagonLobbyDispatcher +{ + private IRagonLobby _lobby; + + public RagonLobbyDispatcher(IRagonLobby lobby) + { + _lobby = lobby; + } + + public void Write(RagonBuffer writer) + { + writer.Clear(); + writer.Write((byte)RagonOperation.ROOM_LIST_UPDATED); + var rooms = _lobby.Rooms; + + writer.WriteUShort((ushort)rooms.Count); + for (int i = 0; i < rooms.Count; i++) + { + var room = rooms[i]; + + writer.WriteString(room.Id); + writer.WriteString(room.Scene); + writer.WriteUShort((ushort)room.PlayerMax); + writer.WriteUShort((ushort)room.PlayerMin); + writer.WriteUShort((ushort)room.PlayerCount); + } + } +} \ No newline at end of file diff --git a/Ragon.Server/Sources/Lobby/RagonLobbyInMemory.cs b/Ragon.Server/Sources/Lobby/RagonLobbyInMemory.cs index f3b287c..42073b6 100644 --- a/Ragon.Server/Sources/Lobby/RagonLobbyInMemory.cs +++ b/Ragon.Server/Sources/Lobby/RagonLobbyInMemory.cs @@ -25,6 +25,8 @@ public class LobbyInMemory : IRagonLobby private readonly List _rooms = new(); private readonly Logger _logger = LogManager.GetCurrentClassLogger(); + public IReadOnlyList Rooms => _rooms.AsReadOnly(); + public bool FindRoomById(string roomId, [MaybeNullWhen(false)] out RagonRoom room) { foreach (var existRagonRoom in _rooms) diff --git a/Ragon.Server/Sources/RagonServer.cs b/Ragon.Server/Sources/RagonServer.cs index 2b3e1e0..a504049 100644 --- a/Ragon.Server/Sources/RagonServer.cs +++ b/Ragon.Server/Sources/RagonServer.cs @@ -45,6 +45,7 @@ public class RagonServer : IRagonServer, INetworkListener private readonly Dictionary _contextsByConnection; private readonly Dictionary _contextsByPlayerId; private readonly Stopwatch _timer; + private readonly RagonLobbyDispatcher _lobbySerializer; private readonly long _tickRate = 0; public RagonServer( @@ -59,6 +60,7 @@ public class RagonServer : IRagonServer, INetworkListener _contextsByConnection = new Dictionary(); _contextsByPlayerId = new Dictionary(); _lobby = new LobbyInMemory(); + _lobbySerializer = new RagonLobbyDispatcher(_lobby); _scheduler = new RagonScheduler(); _webhooks = new RagonWebHookPlugin(this, configuration); _dedicatedThread = new Thread(Execute); @@ -68,9 +70,11 @@ public class RagonServer : IRagonServer, INetworkListener _writer = new RagonBuffer(); _tickRate = 1000 / _configuration.ServerTickRate; _timer = new Stopwatch(); - + var contextObserver = new RagonContextObserver(_contextsByPlayerId); - + + _scheduler.Run(new RagonActionTimer(SendRoomList, 1.0f)); + _serverPlugin.OnAttached(this); _handlers = new BaseOperation[byte.MaxValue]; @@ -228,6 +232,18 @@ public class RagonServer : IRagonServer, INetworkListener _server.Broadcast(sendData, NetworkChannel.UNRELIABLE); } + public void SendRoomList() + { + _lobbySerializer.Write(_writer); + + var sendData = _writer.ToArray(); + foreach (var (_, value) in _contextsByPlayerId) + { + if (value.Room == null) // If only in lobby, then send room list data + value.Connection.Reliable.Send(sendData); + } + } + public BaseOperation ResolveHandler(RagonOperation operation) { return _handlers[(byte)operation]; diff --git a/Ragon.Server/Sources/Room/IRagonRoom.cs b/Ragon.Server/Sources/Room/IRagonRoom.cs index 54c4134..de2aacb 100644 --- a/Ragon.Server/Sources/Room/IRagonRoom.cs +++ b/Ragon.Server/Sources/Room/IRagonRoom.cs @@ -21,6 +21,12 @@ namespace Ragon.Server.Room; public interface IRagonRoom { + public string Id { get; } + public string Scene { get; } + public int PlayerMin { get; } + public int PlayerMax { get; } + public int PlayerCount { get; } + RagonRoomPlayer GetPlayerByConnection(INetworkConnection connection); RagonRoomPlayer GetPlayerById(string id); IRagonEntity GetEntityById(ushort id); diff --git a/Ragon.Server/Sources/Time/RagonActionTimer.cs b/Ragon.Server/Sources/Time/RagonActionTimer.cs new file mode 100644 index 0000000..d9ebedf --- /dev/null +++ b/Ragon.Server/Sources/Time/RagonActionTimer.cs @@ -0,0 +1,21 @@ +using Ragon.Server.Time; + +public class RagonActionTimer: IRagonAction +{ + private Action _callback; + private float _timer; + private float _time; + + public RagonActionTimer(Action callback, float timeInSeconds) + { + _callback = callback; + _time = timeInSeconds * 1000; + } + + public void Tick(float dt) + { + _timer += dt; + if (_timer >= _time) + _callback?.Invoke(); + } +} \ No newline at end of file From c4811ef052746bcafa456e5f0f54ba6df5602d6f Mon Sep 17 00:00:00 2001 From: edmand46 Date: Sat, 13 Apr 2024 17:43:23 +0300 Subject: [PATCH 2/3] feat(wip): list rooms --- Ragon.Client/Sources/RagonRoomInformation.cs | 21 +++++++++---------- Ragon.Client/Sources/RagonSession.cs | 10 ++++----- Ragon.Protocol/Sources/RagonRoomParameters.cs | 2 +- .../Sources/Handler/RoomCreateOperation.cs | 10 ++++----- .../Handler/RoomJoinOrCreateOperation.cs | 12 +++++------ Ragon.Server/Sources/Logging/IRagonLogger.cs | 9 ++++---- .../Sources/Logging/IRagonLoggerFactory.cs | 6 ++++++ Ragon.Server/Sources/Logging/LoggerManager.cs | 17 +++++++++++++++ 8 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 Ragon.Server/Sources/Logging/IRagonLoggerFactory.cs create mode 100644 Ragon.Server/Sources/Logging/LoggerManager.cs diff --git a/Ragon.Client/Sources/RagonRoomInformation.cs b/Ragon.Client/Sources/RagonRoomInformation.cs index aeda469..2b9a72d 100644 --- a/Ragon.Client/Sources/RagonRoomInformation.cs +++ b/Ragon.Client/Sources/RagonRoomInformation.cs @@ -1,13 +1,12 @@ -using Ragon.Protocol; - -namespace Ragon.Client; - -public struct RagonRoomInformation +namespace Ragon.Client { - public string Id; - public string Scene; - public int PlayerMax; - public int PlayerMin; - public int PlayerCount; - public Dictionary Properties; + public struct RagonRoomInformation + { + public string Id; + public string Scene; + public int PlayerMax; + public int PlayerMin; + public int PlayerCount; + public Dictionary Properties; + } } \ No newline at end of file diff --git a/Ragon.Client/Sources/RagonSession.cs b/Ragon.Client/Sources/RagonSession.cs index 972d767..befc560 100644 --- a/Ragon.Client/Sources/RagonSession.cs +++ b/Ragon.Client/Sources/RagonSession.cs @@ -31,11 +31,11 @@ namespace Ragon.Client public void CreateOrJoin(string sceneName, int minPlayers, int maxPlayers) { - var parameters = new RagonRoomParameters() {Scene = sceneName, Min = minPlayers, Max = maxPlayers}; + var parameters = new RagonRoomPayload() {Scene = sceneName, Min = minPlayers, Max = maxPlayers}; CreateOrJoin(parameters); } - public void CreateOrJoin(RagonRoomParameters parameters) + public void CreateOrJoin(RagonRoomPayload parameters) { _buffer.Clear(); _buffer.WriteOperation(RagonOperation.JOIN_OR_CREATE_ROOM); @@ -48,15 +48,15 @@ namespace Ragon.Client public void Create(string sceneName, int minPlayers, int maxPlayers) { - Create(null, new RagonRoomParameters() {Scene = sceneName, Min = minPlayers, Max = maxPlayers}); + Create(null, new RagonRoomPayload() {Scene = sceneName, Min = minPlayers, Max = maxPlayers}); } public void Create(string roomId, string sceneName, int minPlayers, int maxPlayers) { - Create(roomId, new RagonRoomParameters() {Scene = sceneName, Min = minPlayers, Max = maxPlayers}); + Create(roomId, new RagonRoomPayload() {Scene = sceneName, Min = minPlayers, Max = maxPlayers}); } - public void Create(string roomId, RagonRoomParameters parameters) + public void Create(string roomId, RagonRoomPayload parameters) { _buffer.Clear(); _buffer.WriteOperation(RagonOperation.CREATE_ROOM); diff --git a/Ragon.Protocol/Sources/RagonRoomParameters.cs b/Ragon.Protocol/Sources/RagonRoomParameters.cs index b205173..9aa502f 100644 --- a/Ragon.Protocol/Sources/RagonRoomParameters.cs +++ b/Ragon.Protocol/Sources/RagonRoomParameters.cs @@ -17,7 +17,7 @@ namespace Ragon.Protocol { - public class RagonRoomParameters: IRagonSerializable + public class RagonRoomPayload: IRagonSerializable { public string Scene { get; set; } public int Min { get; set; } diff --git a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs index 90060ce..86b5a66 100644 --- a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs @@ -26,7 +26,7 @@ namespace Ragon.Server.Handler; public sealed class RoomCreateOperation : BaseOperation { - private readonly RagonRoomParameters _roomParameters = new(); + private readonly RagonRoomPayload _roomPayload = new(); private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly IServerPlugin _serverPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin; @@ -65,13 +65,13 @@ public sealed class RoomCreateOperation : BaseOperation } } - _roomParameters.Deserialize(Reader); + _roomPayload.Deserialize(Reader); var information = new RoomInformation() { - Scene = _roomParameters.Scene, - Max = _roomParameters.Max, - Min = _roomParameters.Min, + Scene = _roomPayload.Scene, + Max = _roomPayload.Max, + Min = _roomPayload.Min, }; var lobbyPlayer = context.LobbyPlayer; diff --git a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs index 325cfaf..46bfa55 100644 --- a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs @@ -26,7 +26,7 @@ namespace Ragon.Server.Handler; public sealed class RoomJoinOrCreateOperation : BaseOperation { - private readonly RagonRoomParameters _roomParameters = new(); + private readonly RagonRoomPayload _roomPayload = new(); private readonly Logger _logger = LogManager.GetCurrentClassLogger(); private readonly IServerPlugin _serverPlugin; private readonly RagonWebHookPlugin _ragonWebHookPlugin; @@ -48,9 +48,9 @@ public sealed class RoomJoinOrCreateOperation : BaseOperation var roomId = Guid.NewGuid().ToString(); var lobbyPlayer = context.LobbyPlayer; - _roomParameters.Deserialize(Reader); + _roomPayload.Deserialize(Reader); - if (context.Lobby.FindRoomByScene(_roomParameters.Scene, out var existsRoom)) + if (context.Lobby.FindRoomByScene(_roomPayload.Scene, out var existsRoom)) { var player = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); @@ -67,9 +67,9 @@ public sealed class RoomJoinOrCreateOperation : BaseOperation { var information = new RoomInformation() { - Scene = _roomParameters.Scene, - Max = _roomParameters.Max, - Min = _roomParameters.Min, + Scene = _roomPayload.Scene, + Max = _roomPayload.Max, + Min = _roomPayload.Min, }; var roomPlayer = new RagonRoomPlayer(context.Connection, lobbyPlayer.Id, lobbyPlayer.Name); diff --git a/Ragon.Server/Sources/Logging/IRagonLogger.cs b/Ragon.Server/Sources/Logging/IRagonLogger.cs index bbad315..bc63b68 100644 --- a/Ragon.Server/Sources/Logging/IRagonLogger.cs +++ b/Ragon.Server/Sources/Logging/IRagonLogger.cs @@ -2,8 +2,9 @@ namespace Ragon.Server.Logging; public interface IRagonLogger { - public void Warning(string tag, string message); - public void Info(string tag, string message); - public void Error(string tag, string message); - public void Trace(string tag, string message); + public void Warning(string message); + public void Info(string message); + public void Error(string message); + public void Error(Exception ex); + public void Trace(string message); } \ No newline at end of file diff --git a/Ragon.Server/Sources/Logging/IRagonLoggerFactory.cs b/Ragon.Server/Sources/Logging/IRagonLoggerFactory.cs new file mode 100644 index 0000000..0e1109c --- /dev/null +++ b/Ragon.Server/Sources/Logging/IRagonLoggerFactory.cs @@ -0,0 +1,6 @@ +namespace Ragon.Server.Logging; + +public interface IRagonLoggerFactory +{ + public IRagonLogger GetLogger(string tag); +} \ No newline at end of file diff --git a/Ragon.Server/Sources/Logging/LoggerManager.cs b/Ragon.Server/Sources/Logging/LoggerManager.cs new file mode 100644 index 0000000..466fea7 --- /dev/null +++ b/Ragon.Server/Sources/Logging/LoggerManager.cs @@ -0,0 +1,17 @@ +namespace Ragon.Server.Logging +{ + public class LoggerManager + { + private static IRagonLoggerFactory _factory; + + public static void SetLoggerFactory(IRagonLoggerFactory loggerFactory) + { + _factory = loggerFactory; + } + + public static IRagonLogger GetLogger(string tag) + { + return _factory.GetLogger(tag); + } + } +} \ No newline at end of file From bd0c6df5ea34bc868563545a4130e5ea9fd4b395 Mon Sep 17 00:00:00 2001 From: edmand46 Date: Sat, 13 Apr 2024 18:25:39 +0300 Subject: [PATCH 3/3] fix: timer, providing api for listeners --- Ragon.Client/Sources/Handler/RoomListHandler.cs | 4 ++-- Ragon.Client/Sources/RagonClient.cs | 2 ++ Ragon.Client/Sources/RagonListenerList.cs | 10 ++++++++++ Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs | 2 +- Ragon.Server/Sources/Logging/LoggerManager.cs | 2 +- Ragon.Server/Sources/RagonServer.cs | 2 +- Ragon.Server/Sources/Time/RagonActionTimer.cs | 3 +++ 7 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Ragon.Client/Sources/Handler/RoomListHandler.cs b/Ragon.Client/Sources/Handler/RoomListHandler.cs index 6656893..3150b1e 100644 --- a/Ragon.Client/Sources/Handler/RoomListHandler.cs +++ b/Ragon.Client/Sources/Handler/RoomListHandler.cs @@ -21,10 +21,10 @@ internal class RoomListHandler: IHandler { var id = reader.ReadString(); var scene = reader.ReadString(); - var players = reader.ReadUShort(); var maxPlayers = reader.ReadUShort(); var minPlayers = reader.ReadUShort(); - + var players = reader.ReadUShort(); + var roomInfo = new RagonRoomInformation() { Id = id, diff --git a/Ragon.Client/Sources/RagonClient.cs b/Ragon.Client/Sources/RagonClient.cs index a3533b8..8144981 100644 --- a/Ragon.Client/Sources/RagonClient.cs +++ b/Ragon.Client/Sources/RagonClient.cs @@ -179,6 +179,7 @@ namespace Ragon.Client public void AddListener(IRagonSceneListener listener) => _listeners.Add(listener); public void AddListener(IRagonSceneRequestListener listener) => _listeners.Add(listener); public void AddListener(IRagonDataListener listener) => _listeners.Add(listener); + public void AddListener(IRagonRoomListListener listener) => _listeners.Add(listener); public void RemoveListener(IRagonListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonAuthorizationListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonConnectionListener listener) => _listeners.Remove(listener); @@ -191,6 +192,7 @@ namespace Ragon.Client public void RemoveListener(IRagonSceneListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonSceneRequestListener listener) => _listeners.Remove(listener); public void RemoveListener(IRagonDataListener listener) => _listeners.Remove(listener); + public void RemoveListener(IRagonRoomListListener listener) => _listeners.Remove(listener); #endregion diff --git a/Ragon.Client/Sources/RagonListenerList.cs b/Ragon.Client/Sources/RagonListenerList.cs index 10b8848..c7c6053 100644 --- a/Ragon.Client/Sources/RagonListenerList.cs +++ b/Ragon.Client/Sources/RagonListenerList.cs @@ -132,6 +132,11 @@ namespace Ragon.Client _playerLeftListeners.Add(listener); } + public void Add(IRagonRoomListListener listener) + { + _roomListListeners.Add(listener); + } + public void Remove(IRagonDataListener listener) { _delayedActions.Add(() => _dataListeners.Remove(listener)); @@ -186,6 +191,11 @@ namespace Ragon.Client { _delayedActions.Add(() => _playerLeftListeners.Remove(listener)); } + + public void Remove(IRagonRoomListListener listener) + { + _delayedActions.Add(() => _roomListListeners.Remove(listener)); + } public void OnAuthorizationSuccess(string playerId, string playerName, string payload) { diff --git a/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs b/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs index e843c67..1bc0b5d 100644 --- a/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs +++ b/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs @@ -15,7 +15,7 @@ public class RagonLobbyDispatcher public void Write(RagonBuffer writer) { writer.Clear(); - writer.Write((byte)RagonOperation.ROOM_LIST_UPDATED); + writer.WriteOperation(RagonOperation.ROOM_LIST_UPDATED); var rooms = _lobby.Rooms; writer.WriteUShort((ushort)rooms.Count); diff --git a/Ragon.Server/Sources/Logging/LoggerManager.cs b/Ragon.Server/Sources/Logging/LoggerManager.cs index 466fea7..085add6 100644 --- a/Ragon.Server/Sources/Logging/LoggerManager.cs +++ b/Ragon.Server/Sources/Logging/LoggerManager.cs @@ -2,7 +2,7 @@ namespace Ragon.Server.Logging { public class LoggerManager { - private static IRagonLoggerFactory _factory; + private static IRagonLoggerFactory _factory = null!; public static void SetLoggerFactory(IRagonLoggerFactory loggerFactory) { diff --git a/Ragon.Server/Sources/RagonServer.cs b/Ragon.Server/Sources/RagonServer.cs index a504049..db57d26 100644 --- a/Ragon.Server/Sources/RagonServer.cs +++ b/Ragon.Server/Sources/RagonServer.cs @@ -111,7 +111,7 @@ public class RagonServer : IRagonServer, INetworkListener if (_timer.ElapsedMilliseconds > _tickRate) { _timer.Restart(); - _scheduler.Update(_timer.ElapsedMilliseconds / 1000.0f); + _scheduler.Update(_tickRate); SendTimestamp(); } diff --git a/Ragon.Server/Sources/Time/RagonActionTimer.cs b/Ragon.Server/Sources/Time/RagonActionTimer.cs index d9ebedf..d8af36b 100644 --- a/Ragon.Server/Sources/Time/RagonActionTimer.cs +++ b/Ragon.Server/Sources/Time/RagonActionTimer.cs @@ -16,6 +16,9 @@ public class RagonActionTimer: IRagonAction { _timer += dt; if (_timer >= _time) + { _callback?.Invoke(); + _timer = 0; + } } } \ No newline at end of file