From e78e8048ff8bb149c52b394f746a294bcaa7f18c Mon Sep 17 00:00:00 2001 From: edmand46 Date: Sat, 4 Oct 2025 15:08:53 +0300 Subject: [PATCH] feat: multi project support, maintaince --- Ragon.Protocol/Sources/RagonBuffer.cs | 17 +++++- Ragon.Relay/Ragon.Relay.csproj | 2 +- Ragon.Relay/relay.config.json | 3 +- .../Sources/WebSocketServer.cs | 34 ++++++------ Ragon.Server/Sources/Data/RagonData.cs | 16 ++++-- .../Sources/Handler/AuthorizationOperation.cs | 54 ++++++++++++------- .../Handler/PlayerUserDataOperation.cs | 2 +- .../Sources/Handler/RoomCreateOperation.cs | 2 +- .../Sources/Handler/RoomJoinOperation.cs | 7 +++ .../Handler/RoomJoinOrCreateOperation.cs | 8 ++- .../Sources/Handler/RoomUserDataOperation.cs | 2 +- .../Sources/Lobby/RagonLobbyDispatcher.cs | 7 ++- .../Sources/Lobby/RagonLobbyPlayer.cs | 6 ++- .../Sources/Plugin/BaseServerPlugin.cs | 2 +- Ragon.Server/Sources/RagonServer.cs | 48 +++++++++++------ .../Sources/RagonServerConfiguration.cs | 1 + Ragon.Server/Sources/Room/IRagonRoom.cs | 1 + Ragon.Server/Sources/Room/RagonRoom.cs | 6 ++- 18 files changed, 152 insertions(+), 66 deletions(-) diff --git a/Ragon.Protocol/Sources/RagonBuffer.cs b/Ragon.Protocol/Sources/RagonBuffer.cs index 2b5b468..0a00697 100644 --- a/Ragon.Protocol/Sources/RagonBuffer.cs +++ b/Ragon.Protocol/Sources/RagonBuffer.cs @@ -65,6 +65,8 @@ namespace Ragon.Protocol { public class RagonBuffer { + private const int MaxBufferSize = 1024 * 1024; // 1MB max buffer size + private int _read; private int _write; private uint[] _buckets; @@ -404,6 +406,12 @@ namespace Ragon.Protocol public void FromArray(byte[] data) { var length = data.Length; + + if (length > MaxBufferSize) + { + throw new InvalidOperationException($"Input data exceeds maximum buffer size: {length} bytes > {MaxBufferSize} bytes"); + } + var bucketsCount = length / 4 + 1; if (_buckets.Length < bucketsCount) @@ -493,7 +501,14 @@ namespace Ragon.Protocol private void Resize(int capacity) { - var buckets = new uint[_buckets.Length * 2 + capacity]; + var newSize = _buckets.Length * 2 + capacity; + + if (newSize * 4 > MaxBufferSize) + { + throw new InvalidOperationException($"Buffer size limit exceeded: {newSize * 4} bytes > {MaxBufferSize} bytes"); + } + + var buckets = new uint[newSize]; Array.Copy(_buckets, buckets, _buckets.Length); _buckets = buckets; } diff --git a/Ragon.Relay/Ragon.Relay.csproj b/Ragon.Relay/Ragon.Relay.csproj index 23b5632..99685ce 100644 --- a/Ragon.Relay/Ragon.Relay.csproj +++ b/Ragon.Relay/Ragon.Relay.csproj @@ -3,7 +3,7 @@ Exe Ragon.Relay - net8.0 + net9.0 diff --git a/Ragon.Relay/relay.config.json b/Ragon.Relay/relay.config.json index f80ef6e..d6c92cc 100644 --- a/Ragon.Relay/relay.config.json +++ b/Ragon.Relay/relay.config.json @@ -10,5 +10,6 @@ "limitRooms": 200, "limitBufferedEvents": 50, "limitUserDataSize": 1024, - "limitPropertySize": 512 + "limitPropertySize": 512, + "limitConnectionsPerProject": 100 } \ No newline at end of file diff --git a/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs b/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs index 6d5f232..cad4356 100644 --- a/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs +++ b/Ragon.Server.WebSocketServer/Sources/WebSocketServer.cs @@ -43,7 +43,7 @@ public class WebSocketServer : INetworkServer _executor = new Executor(); } - public async void StartAccept(CancellationToken cancellationToken) + public async ValueTask StartAccept(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { @@ -58,26 +58,26 @@ public class WebSocketServer : INetworkServer context.Response.Close(); continue; } - + var webSocketContext = await context.AcceptWebSocketAsync(null); var webSocket = webSocketContext.WebSocket; var peerId = _sequencer.Pop(); - - connection = new WebSocketConnection(webSocket, peerId); + + connection = new WebSocketConnection(webSocket, peerId); } catch (Exception ex) { _logger.Error(ex); continue; } - + _connections[connection.Id] = connection; - - StartListen(connection, cancellationToken); + + _ = StartListen(connection, cancellationToken); } } - async void StartListen(WebSocketConnection connection, CancellationToken cancellationToken) + async ValueTask StartListen(WebSocketConnection connection, CancellationToken cancellationToken) { _activeConnections.Add(connection); _networkListener.OnConnected(connection); @@ -86,7 +86,7 @@ public class WebSocketServer : INetworkServer var rawData = new byte[2048]; var rawDataBuffer = new Memory(rawData); var data = new ArrayBufferWriter(); - + while (webSocket.State == WebSocketState.Open || !cancellationToken.IsCancellationRequested) { try @@ -95,17 +95,17 @@ public class WebSocketServer : INetworkServer { var result = await webSocket.ReceiveAsync(rawDataBuffer, cancellationToken); var payload = rawDataBuffer.Slice(0, result.Count); - + data.Write(payload.Span); - + if (result.EndOfMessage) break; } - + if (data.WrittenCount > 0) { _networkListener.OnData(connection, NetworkChannel.RELIABLE, data.WrittenMemory.ToArray()); - + data.Clear(); } } @@ -117,15 +117,15 @@ public class WebSocketServer : INetworkServer _sequencer.Push(connection.Id); _activeConnections.Remove(connection); - + _networkListener.OnDisconnected(connection); } public void Update() { _executor.Update(); - - Flush(); + + _ = Flush(); } public void Broadcast(byte[] data, NetworkChannel channel) @@ -134,7 +134,7 @@ public class WebSocketServer : INetworkServer activeConnection.Reliable.Send(data); } - public async void Flush() + public async ValueTask Flush() { foreach (var conn in _activeConnections) await conn.Flush(); diff --git a/Ragon.Server/Sources/Data/RagonData.cs b/Ragon.Server/Sources/Data/RagonData.cs index 992f15f..97a8782 100644 --- a/Ragon.Server/Sources/Data/RagonData.cs +++ b/Ragon.Server/Sources/Data/RagonData.cs @@ -12,13 +12,25 @@ public class RagonData { } - public void Read(RagonBuffer buffer) + public void Read(RagonBuffer buffer, int maxSize = 0) { var len = buffer.ReadUShort(); + var totalSize = 0; + for (int i = 0; i < len; i++) { var key = buffer.ReadString(); var valueSize = buffer.ReadUShort(); + + if (maxSize > 0) + { + totalSize += valueSize; + if (totalSize > maxSize) + { + throw new InvalidOperationException($"User data exceeds limit: {totalSize} > {maxSize}"); + } + } + if (valueSize > 0) { var value = buffer.ReadBytes(valueSize); @@ -59,8 +71,6 @@ public class RagonData buffer.WriteString(prop.Key); buffer.WriteUShort((ushort)prop.Value.Length); buffer.WriteBytes(prop.Value); - - Console.WriteLine($"Key: {prop.Key} Value: {prop.Value.Length}"); } } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/AuthorizationOperation.cs b/Ragon.Server/Sources/Handler/AuthorizationOperation.cs index 27cdc7d..45fc4fe 100644 --- a/Ragon.Server/Sources/Handler/AuthorizationOperation.cs +++ b/Ragon.Server/Sources/Handler/AuthorizationOperation.cs @@ -19,6 +19,7 @@ using Ragon.Server.IO; using Ragon.Server.Lobby; using Ragon.Server.Logging; using Ragon.Server.Plugin; +using Ragon.Server.Project; namespace Ragon.Server.Handler { @@ -30,19 +31,22 @@ namespace Ragon.Server.Handler private readonly RagonContextObserver _observer; private readonly RagonServerConfiguration _configuration; private readonly RagonBuffer _writer; + private readonly ProjectRegistry _projectRegistry; public AuthorizationOperation(RagonBuffer reader, RagonBuffer writer, IRagonServer server, IServerPlugin serverPlugin, RagonContextObserver observer, - RagonServerConfiguration configuration) : base(reader, writer) + RagonServerConfiguration configuration, + ProjectRegistry projectRegistry) : base(reader, writer) { _serverPlugin = serverPlugin; _configuration = configuration; _observer = observer; _writer = writer; _server = server; + _projectRegistry = projectRegistry; } public override void Handle(RagonContext context, NetworkChannel channel) @@ -59,31 +63,45 @@ namespace Ragon.Server.Handler return; } - var configuration = _configuration; - var key = Reader.ReadString(); + var projectKey = Reader.ReadString(); var name = Reader.ReadString(); var payload = Reader.ReadString(); - if (key == configuration.ServerKey) + if (!_projectRegistry.ValidateKey(projectKey)) { - var authorizeViaPlugin = _serverPlugin.OnAuthorize(new ConnectionRequest(_server, context.Connection.Id, payload)); - if (authorizeViaPlugin) - return; - - var id = Guid.NewGuid().ToString(); - Approve(context, new ConnectionResponse(id, name, payload)); - } - else - { - _logger.Warning($"Invalid key for connection {context.Connection.Id}"); - + _logger.Warning($"Invalid project key from connection {context.Connection.Id}"); Reject(context); + return; } + + if (!_projectRegistry.CanConnect(projectKey)) + { + _logger.Warning($"Connection limit reached for project key: {projectKey}"); + Reject(context); + return; + } + + var authorizeViaPlugin = _serverPlugin.OnAuthorize(new ConnectionRequest(_server, context.Connection.Id, payload)); + if (authorizeViaPlugin) + return; + + var project = _projectRegistry.GetOrCreateProject(projectKey); + if (project == null) + { + _logger.Warning($"Failed to create project for key: {projectKey}"); + Reject(context); + return; + } + + var id = Guid.NewGuid().ToString(); + Approve(context, new ConnectionResponse(id, name, payload), project.Id); + + _projectRegistry.RegisterConnection(project.Id); } - public void Approve(RagonContext context, ConnectionResponse result) + public void Approve(RagonContext context, ConnectionResponse result, int projectId) { - var lobbyPlayer = new RagonLobbyPlayer(context.Connection, result.Id, result.Name, result.Payload); + var lobbyPlayer = new RagonLobbyPlayer(context.Connection, result.Id, result.Name, result.Payload, projectId); context.SetPlayer(lobbyPlayer); context.ConnectionStatus = ConnectionStatus.Authorized; @@ -102,7 +120,7 @@ namespace Ragon.Server.Handler var sendData = _writer.ToArray(); context.Connection.Reliable.Send(sendData); - _logger.Trace($"Approved {context.Connection.Id} as {playerId}|{context.LobbyPlayer.Name}"); + _logger.Trace($"Approved {context.Connection.Id} as {playerId}|{context.LobbyPlayer.Name} for project {projectId}"); } public void Reject(RagonContext context) diff --git a/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs b/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs index 36d84d8..cca732d 100644 --- a/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs +++ b/Ragon.Server/Sources/Handler/PlayerUserDataOperation.cs @@ -27,7 +27,7 @@ namespace Ragon.Server.Handler return; } - context.UserData.Read(Reader); + context.UserData.Read(Reader, _userDataLimit); } } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs index c1b09f0..039ca26 100644 --- a/Ragon.Server/Sources/Handler/RoomCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomCreateOperation.cs @@ -88,7 +88,7 @@ namespace Ragon.Server.Handler var roomPlayer = new RagonRoomPlayer(context, lobbyPlayer.Id, lobbyPlayer.Name); var roomPlugin = _serverPlugin.CreateRoomPlugin(information); - var room = new RagonRoom(roomId, information, roomPlugin); + var room = new RagonRoom(roomId, information, roomPlugin, lobbyPlayer.ProjectId); room.Plugin.OnAttached(room); roomPlayer.OnAttached(room); diff --git a/Ragon.Server/Sources/Handler/RoomJoinOperation.cs b/Ragon.Server/Sources/Handler/RoomJoinOperation.cs index 2e38022..12d705f 100644 --- a/Ragon.Server/Sources/Handler/RoomJoinOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomJoinOperation.cs @@ -43,6 +43,13 @@ public sealed class RoomJoinOperation : BaseOperation return; } + if (existsRoom.ProjectId != lobbyPlayer.ProjectId) + { + JoinFailed(context, Writer); + _logger.Warning($"Player {context.Connection.Id}|{lobbyPlayer.Name} tried to join room from different project"); + return; + } + var player = new RagonRoomPlayer(context, lobbyPlayer.Id, lobbyPlayer.Name); context.SetRoom(existsRoom, player); diff --git a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs index 3cba271..af3e129 100644 --- a/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomJoinOrCreateOperation.cs @@ -57,6 +57,12 @@ public sealed class RoomJoinOrCreateOperation : BaseOperation if (context.Lobby.FindRoomByScene(_roomParameters.Scene, out var existsRoom)) { + if (existsRoom.ProjectId != lobbyPlayer.ProjectId) + { + _logger.Warning($"Player {context.Connection.Id}|{lobbyPlayer.Name} tried to join room from different project"); + return; + } + var player = new RagonRoomPlayer(context, lobbyPlayer.Id, lobbyPlayer.Name); context.SetRoom(existsRoom, player); @@ -81,7 +87,7 @@ public sealed class RoomJoinOrCreateOperation : BaseOperation var roomPlayer = new RagonRoomPlayer(context, lobbyPlayer.Id, lobbyPlayer.Name); var roomPlugin = _serverPlugin.CreateRoomPlugin(information); - var room = new RagonRoom(roomId, information, roomPlugin); + var room = new RagonRoom(roomId, information, roomPlugin, lobbyPlayer.ProjectId); _serverPlugin.OnRoomCreate(lobbyPlayer, room); diff --git a/Ragon.Server/Sources/Handler/RoomUserDataOperation.cs b/Ragon.Server/Sources/Handler/RoomUserDataOperation.cs index 7a020db..0f3c039 100644 --- a/Ragon.Server/Sources/Handler/RoomUserDataOperation.cs +++ b/Ragon.Server/Sources/Handler/RoomUserDataOperation.cs @@ -45,6 +45,6 @@ public sealed class RoomUserDataOperation : BaseOperation var room = context.Room; if (room != null) - room.UserData.Read(Reader); + room.UserData.Read(Reader, _userDataLimit); } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs b/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs index 1bc0b5d..32e8a04 100644 --- a/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs +++ b/Ragon.Server/Sources/Lobby/RagonLobbyDispatcher.cs @@ -12,12 +12,17 @@ public class RagonLobbyDispatcher _lobby = lobby; } - public void Write(RagonBuffer writer) + public void Write(RagonBuffer writer, int projectId = 0) { writer.Clear(); writer.WriteOperation(RagonOperation.ROOM_LIST_UPDATED); var rooms = _lobby.Rooms; + if (projectId > 0) + { + rooms = rooms.Where(r => r.ProjectId == projectId).ToList(); + } + writer.WriteUShort((ushort)rooms.Count); for (int i = 0; i < rooms.Count; i++) { diff --git a/Ragon.Server/Sources/Lobby/RagonLobbyPlayer.cs b/Ragon.Server/Sources/Lobby/RagonLobbyPlayer.cs index 6bd41e1..d51cf5f 100644 --- a/Ragon.Server/Sources/Lobby/RagonLobbyPlayer.cs +++ b/Ragon.Server/Sources/Lobby/RagonLobbyPlayer.cs @@ -32,12 +32,14 @@ public class RagonLobbyPlayer public string Id { get; private set; } public string Name { get; private set; } public string Payload { get; private set; } - - public RagonLobbyPlayer(INetworkConnection connection, string id, string name, string payload) + public int ProjectId { get; private set; } + + public RagonLobbyPlayer(INetworkConnection connection, string id, string name, string payload, int projectId) { Id = id; Name = name; Connection = connection; Payload = payload; + ProjectId = projectId; } } \ No newline at end of file diff --git a/Ragon.Server/Sources/Plugin/BaseServerPlugin.cs b/Ragon.Server/Sources/Plugin/BaseServerPlugin.cs index 3511e90..bbb75d2 100644 --- a/Ragon.Server/Sources/Plugin/BaseServerPlugin.cs +++ b/Ragon.Server/Sources/Plugin/BaseServerPlugin.cs @@ -47,7 +47,7 @@ namespace Ragon.Server.Plugin return; var operation = (AuthorizationOperation)_server.ResolveHandler(RagonOperation.AUTHORIZE); - operation.Approve(ctx, new ConnectionResponse(id, name, payload)); + operation.Approve(ctx, new ConnectionResponse(id, name, payload), 0); } public void Reject() diff --git a/Ragon.Server/Sources/RagonServer.cs b/Ragon.Server/Sources/RagonServer.cs index 358eadc..8212ec4 100644 --- a/Ragon.Server/Sources/RagonServer.cs +++ b/Ragon.Server/Sources/RagonServer.cs @@ -21,6 +21,7 @@ using Ragon.Server.IO; using Ragon.Server.Lobby; using Ragon.Server.Logging; using Ragon.Server.Plugin; +using Ragon.Server.Project; using Ragon.Server.Time; namespace Ragon.Server; @@ -28,7 +29,7 @@ namespace Ragon.Server; public class RagonServer : IRagonServer, INetworkListener { private const string ServerVersion = "1.4.1"; - + private readonly IRagonLogger _logger = LoggerManager.GetLogger(nameof(RagonServer)); private readonly INetworkServer _server; private readonly BaseOperation[] _handlers; @@ -40,12 +41,14 @@ public class RagonServer : IRagonServer, INetworkListener private readonly RagonScheduler _scheduler; private readonly Dictionary _contextsByConnection; private readonly Dictionary _contextsByPlayerId; + private readonly ProjectRegistry _projectRegistry; private readonly Stopwatch _timer; private readonly RagonLobbyDispatcher _lobbySerializer; private readonly long _tickRate = 0; private bool _isRunning = false; public bool IsRunning => _isRunning; + public ProjectRegistry ProjectRegistry => _projectRegistry; public RagonServer( INetworkServer server, @@ -57,6 +60,7 @@ public class RagonServer : IRagonServer, INetworkListener _serverPlugin = plugin; _contextsByConnection = new Dictionary(); _contextsByPlayerId = new Dictionary(); + _projectRegistry = new ProjectRegistry(configuration.LimitConnectionsPerProject); _lobby = new LobbyInMemory(); _lobbySerializer = new RagonLobbyDispatcher(_lobby); _scheduler = new RagonScheduler(); @@ -73,7 +77,7 @@ public class RagonServer : IRagonServer, INetworkListener _serverPlugin.OnAttached(this); _handlers = new BaseOperation[byte.MaxValue]; - _handlers[(byte)RagonOperation.AUTHORIZE] = new AuthorizationOperation(_reader, _writer, this, _serverPlugin, contextObserver, configuration); + _handlers[(byte)RagonOperation.AUTHORIZE] = new AuthorizationOperation(_reader, _writer, this, _serverPlugin, contextObserver, configuration, _projectRegistry); _handlers[(byte)RagonOperation.JOIN_OR_CREATE_ROOM] = new RoomJoinOrCreateOperation(_reader, _writer, plugin, _configuration); _handlers[(byte)RagonOperation.CREATE_ROOM] = new RoomCreateOperation(_reader, _writer, plugin, _configuration); _handlers[(byte)RagonOperation.JOIN_ROOM] = new RoomJoinOperation(_reader, _writer); @@ -152,12 +156,15 @@ public class RagonServer : IRagonServer, INetworkListener if (room != null) { room.DetachPlayer(context.RoomPlayer); - + _lobby.RemoveIfEmpty(room); } - + if (context.ConnectionStatus == ConnectionStatus.Authorized) + { _contextsByPlayerId.Remove(context.LobbyPlayer.Id); + _projectRegistry.UnregisterConnection(context.LobbyPlayer.ProjectId); + } _logger.Trace($"Disconnected: {connection.Id}"); } @@ -177,10 +184,13 @@ public class RagonServer : IRagonServer, INetworkListener room.DetachPlayer(context.RoomPlayer); _lobby.RemoveIfEmpty(room); } - + if (context.ConnectionStatus == ConnectionStatus.Authorized) + { _contextsByPlayerId.Remove(context.LobbyPlayer.Id); - + _projectRegistry.UnregisterConnection(context.LobbyPlayer.ProjectId); + } + _logger.Trace($"Timeout: {connection.Id}|{context.LobbyPlayer.Name}|{context.LobbyPlayer.Id}"); } else @@ -198,9 +208,16 @@ public class RagonServer : IRagonServer, INetworkListener _writer.Clear(); _reader.Clear(); _reader.FromArray(data); - + var operation = _reader.ReadByte(); - _handlers[operation]?.Handle(context, channel); + + if (operation >= _handlers.Length || _handlers[operation] == null) + { + _logger.Warning($"Invalid operation code: {operation} from connection {connection.Id}"); + return; + } + + _handlers[operation].Handle(context, channel); } } catch (Exception ex) @@ -228,13 +245,14 @@ public class RagonServer : IRagonServer, INetworkListener public void SendRoomList() { - _lobbySerializer.Write(_writer); - - var sendData = _writer.ToArray(); - foreach (var (_, value) in _contextsByPlayerId) + foreach (var (_, context) in _contextsByPlayerId) { - if (value.Room == null) // If only in lobby, then send room list data - value.Connection.Reliable.Send(sendData); + if (context.Room == null) // If only in lobby, then send room list data + { + _lobbySerializer.Write(_writer, context.LobbyPlayer.ProjectId); + var sendData = _writer.ToArray(); + context.Connection.Reliable.Send(sendData); + } } } @@ -287,7 +305,7 @@ public class RagonServer : IRagonServer, INetworkListener { return _contextsByPlayerId.TryGetValue(playerId, out var context) ? context : null; } - + private void CopyrightInfo() { _logger.Info($"Server Version: {ServerVersion}"); diff --git a/Ragon.Server/Sources/RagonServerConfiguration.cs b/Ragon.Server/Sources/RagonServerConfiguration.cs index 5c4cc7d..bb70412 100644 --- a/Ragon.Server/Sources/RagonServerConfiguration.cs +++ b/Ragon.Server/Sources/RagonServerConfiguration.cs @@ -36,6 +36,7 @@ public struct RagonServerConfiguration public int LimitBufferedEvents; public int LimitUserDataSize; public int LimitPropertySize; + public int LimitConnectionsPerProject; private static Dictionary _serverTypes = new Dictionary() { diff --git a/Ragon.Server/Sources/Room/IRagonRoom.cs b/Ragon.Server/Sources/Room/IRagonRoom.cs index cd5197e..62389f6 100644 --- a/Ragon.Server/Sources/Room/IRagonRoom.cs +++ b/Ragon.Server/Sources/Room/IRagonRoom.cs @@ -24,6 +24,7 @@ public interface IRagonRoom { public string Id { get; } public string Scene { get; } + public int ProjectId { get; } public int PlayerMin { get; } public int PlayerMax { get; } public int PlayerCount { get; } diff --git a/Ragon.Server/Sources/Room/RagonRoom.cs b/Ragon.Server/Sources/Room/RagonRoom.cs index 7c40f3c..3a77661 100644 --- a/Ragon.Server/Sources/Room/RagonRoom.cs +++ b/Ragon.Server/Sources/Room/RagonRoom.cs @@ -31,7 +31,8 @@ public class RagonRoom : IRagonRoom, IRagonAction public int PlayerMax { get; private set; } public int PlayerMin { get; private set; } public int PlayerCount => WaitPlayersList.Count; - + public int ProjectId { get; private set; } + public bool IsDone { get; private set; } public RagonData UserData { get; set; } @@ -53,13 +54,14 @@ public class RagonRoom : IRagonRoom, IRagonAction private readonly List _bufferedEvents; private readonly int _limitBufferedEvents; - public RagonRoom(string roomId, RoomInformation info, IRoomPlugin roomPlugin) + public RagonRoom(string roomId, RoomInformation info, IRoomPlugin roomPlugin, int projectId) { Id = roomId; Scene = info.Scene; PlayerMax = info.Max; PlayerMin = info.Min; Plugin = roomPlugin; + ProjectId = projectId; Players = new Dictionary(info.Max); WaitPlayersList = new List(info.Max);