From e09216cc72efa6ba9f7984b98f813fde01ce4971 Mon Sep 17 00:00:00 2001 From: EnderdracheLP Date: Sun, 29 Dec 2024 23:54:45 +0100 Subject: [PATCH 1/4] Add VersionRanges and AuthedClients to configuration, add X-Robots-Tag to all responses, add LocalDevelopment appsettings --- .gitignore | 2 +- .../BeatTogether.MasterServer.Api.csproj | 2 +- .../Configuration/ApiServerConfiguration.cs | 8 +++- .../Extensions/HostBuilderExtensions.cs | 13 ++++-- .../GetMultiplayerInstanceController.cs | 44 +++++++++++++++---- .../Implimentations/UserAuthenticator.cs | 13 ++---- .../BeatTogether.MasterServer.Domain.csproj | 2 +- .../Models/Server.cs | 5 ++- ...BeatTogether.MasterServer.Interface.csproj | 2 +- ...BeatTogether.MasterServer.Messaging.csproj | 2 +- .../Enums/MultiplayerPlacementErrorCode.cs | 3 +- ...ogether.MasterServer.NodeController.csproj | 2 +- .../NodeControllerConfiguration.cs | 4 +- .../BeatTogether.MasterServer.csproj | 7 ++- .../Properties/launchSettings.json | 10 +++++ .../appsettings.Development.json | 23 ++++++++-- BeatTogether.MasterServer/appsettings.json | 24 ++++++++-- 17 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 BeatTogether.MasterServer/Properties/launchSettings.json diff --git a/.gitignore b/.gitignore index 14470a3..e38866c 100644 --- a/.gitignore +++ b/.gitignore @@ -351,4 +351,4 @@ MigrationBackup/ out/ run/ -/BeatTogether.MasterServer.Kernel/Properties/launchSettings.json +/BeatTogether.MasterServer/appsettings.LocalDevelopment.json diff --git a/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj b/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj index 29fa6db..d7de00f 100644 --- a/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj +++ b/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj @@ -17,7 +17,7 @@ - + diff --git a/BeatTogether.MasterServer.Api/Configuration/ApiServerConfiguration.cs b/BeatTogether.MasterServer.Api/Configuration/ApiServerConfiguration.cs index d32a774..2fbae25 100644 --- a/BeatTogether.MasterServer.Api/Configuration/ApiServerConfiguration.cs +++ b/BeatTogether.MasterServer.Api/Configuration/ApiServerConfiguration.cs @@ -1,10 +1,16 @@ using System; +using System.Collections.Generic; +using BeatTogether.Core.Enums; +using BeatTogether.Core.Models; +using BeatTogether.MasterServer.Api.Util; namespace BeatTogether.MasterServer.Api.Configuration { - public class ApiServerConfiguration + public sealed class ApiServerConfiguration { public int SessionTimeToLive { get; set; } = 180; public bool AuthenticateClients { get; set; } = true; + public HashSet VersionRanges { get; set; } = new(); + public HashSet AuthedClients { get; set; } = new(); } } diff --git a/BeatTogether.MasterServer.Api/Extensions/HostBuilderExtensions.cs b/BeatTogether.MasterServer.Api/Extensions/HostBuilderExtensions.cs index 921b2f4..43728f8 100644 --- a/BeatTogether.MasterServer.Api/Extensions/HostBuilderExtensions.cs +++ b/BeatTogether.MasterServer.Api/Extensions/HostBuilderExtensions.cs @@ -7,8 +7,10 @@ using BeatTogether.MasterServer.Api.Implementations; using BeatTogether.MasterServer.Api.Implimentations; using BeatTogether.MasterServer.Kernel.Implementations.Providers; +using BinaryRecords.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Rewrite; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -38,9 +40,14 @@ public static IHostBuilder UseMasterServerApi(this IHostBuilder hostBuilder) => ) .Configure(applicationBuilder => applicationBuilder - .UseRouting() + .Use((context, next) => + { + context.Response.Headers.Add("X-Robots-Tag", "noindex, nofollow"); // Tell everyone that we don't want to be indexed + return next(context); + }) + .UseRouting() .UseEndpoints(endPointRouteBuilder => endPointRouteBuilder.MapControllers()) - ) - ); + ) + ); } } diff --git a/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs b/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs index 1470f73..3a8e3af 100644 --- a/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs +++ b/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Threading.Tasks; using BeatTogether.MasterServer.Messaging.Enums; using BeatTogether.MasterServer.Messaging.Models; @@ -10,8 +11,10 @@ using BeatTogether.MasterServer.Api.Abstractions; using BeatTogether.MasterServer.Api.Util; using System.Text; +using BeatTogether.Core.Models; using BeatTogether.MasterServer.Domain.Models; using BeatTogether.MasterServer.Api.Abstractions.Providers; +using BeatTogether.MasterServer.Api.Configuration; namespace BeatTogether.MasterServer.Api.HttpControllers { @@ -30,12 +33,15 @@ public class GetMultiplayerInstanceController : Controller private readonly ILayer2 _layer2; - public GetMultiplayerInstanceController( + private readonly ApiServerConfiguration _apiServerConfiguration; + + public GetMultiplayerInstanceController( IMasterServerSessionService sessionService, ILayer2 layer2, IServerCodeProvider serverCodeProvider, ISecretProvider secretProvider, - IUserAuthenticator userAuthenticator) + IUserAuthenticator userAuthenticator, + ApiServerConfiguration configuration) { _layer2 = layer2; _sessionService = sessionService; @@ -43,8 +49,9 @@ public GetMultiplayerInstanceController( _secretProvider = secretProvider; _userAuthenticator = userAuthenticator; - - _logger = Log.ForContext(); + _apiServerConfiguration = configuration; + + _logger = Log.ForContext(); } /// @@ -57,8 +64,6 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye var response = new GetMultiplayerInstanceResponse(); response.AddRequestContext(request); - // TODO Validate game client version supported range? - if (HttpContext.Connection.RemoteIpAddress is null) { _logger.Warning("Auth failure: Missing IP address from HTTP request context"); @@ -143,14 +148,25 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye { string secret = request.PrivateGameSecret; string managerId = FixedServerUserId; + VersionRange supportedRange = VersionRange.FindVersionRange(_apiServerConfiguration.VersionRanges.ToList(), session.PlayerClientVersion!); + if (supportedRange == null) + { + // Version not supported at all according to config + _logger.Error($"Could not find matching version range for client version: {session.PlayerClientVersion}"); + response.ErrorCode = MultiplayerPlacementErrorCode.LobbyHostVersionMismatch; + return new JsonResult(response); + } + + _logger.Debug( + $"Found version range MinVersion: '{supportedRange.MinVersion}' MaxVersion: '{supportedRange.MaxVersion}' for client version '{session.PlayerClientVersion}'"); if (!isQuickplay) - managerId = session.HashedUserId;//sets the manager to the player who is requesting + managerId = session.HashedUserId; //sets the manager to the player who is requesting else secret = _secretProvider.GetSecret(); string ServerName = string.Empty; if (isQuickplay) - ServerName = "BeatTogether Quickplay: " + ((Core.Enums.BeatmapDifficultyMask)request.BeatmapLevelSelectionMask.BeatmapDifficultyMask).ToString(); + ServerName = "BeatTogether Quickplay: " + ((Core.Enums.BeatmapDifficultyMask)request.BeatmapLevelSelectionMask.BeatmapDifficultyMask); else if (request.ExtraServerConfiguration != null && request.ExtraServerConfiguration.ServerName != null) { ServerName = request.ExtraServerConfiguration.ServerName; @@ -184,7 +200,8 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye ServerStartJoinTimeout = 10000L, //ServerStartJoinTimeout = request.ExtraServerConfiguration.Timeout ?? 10, //Dont allow everyone to do this as -1 means infinite server online time, server wont turn off when a player leaves PermanentManager = request.ExtraServerConfiguration != null ? request.ExtraServerConfiguration.PermenantManger ?? true : true, - }; + SupportedVersionRange = supportedRange + }; //Missing values from the server instance such as endpoint, will be added from within the CreateInstance function below. if (!await _layer2.CreateInstance(server)) { @@ -203,6 +220,15 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye return new JsonResult(response); } + // Checks if the joining players version is witin the supported range of the lobby + if (!VersionRange.VersionRangeSatisfies(server.SupportedVersionRange, + session.PlayerClientVersion.ToString())) + { + _logger.Warning($"Player '{session.HashedUserId}' on version '{session.PlayerClientVersion}' cannot join lobby with range {server.SupportedVersionRange.MinVersion} - {server.SupportedVersionRange.MaxVersion}"); + response.ErrorCode = MultiplayerPlacementErrorCode.LobbyHostVersionMismatch; + return new JsonResult(response); + } + _logger.Information("Player session data from player: " + session.HashedUserId + " Is being sent to node: " + server.InstanceEndPoint + ", Server secret: " + server.Secret + ", Player count before join: " + server.PlayerHashes.Count); if (!await _layer2.SetPlayerSessionData(server.Secret, session)) diff --git a/BeatTogether.MasterServer.Api/Implimentations/UserAuthenticator.cs b/BeatTogether.MasterServer.Api/Implimentations/UserAuthenticator.cs index f072962..f92b000 100644 --- a/BeatTogether.MasterServer.Api/Implimentations/UserAuthenticator.cs +++ b/BeatTogether.MasterServer.Api/Implimentations/UserAuthenticator.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Net.Http; using System.Text; using System.Text.Json; @@ -146,14 +147,8 @@ public async Task TryAuthenticateUserWithPlatform(MasterServerSession sess private bool GetPlatformRequiresAuth(Platform platform) { - return platform switch - { - Platform.Steam => true, - Platform.OculusQuest => true, - Platform.Oculus => true, - Platform.Pico => true, - _ => false, - }; - } + _logger.Debug("Authed Platforms: " + string.Join(", ", _apiServerConfiguration.AuthedClients)); + return _apiServerConfiguration.AuthedClients.Contains(platform); + } } } \ No newline at end of file diff --git a/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj b/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj index 5de638e..592be07 100644 --- a/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj +++ b/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj @@ -6,7 +6,7 @@ - + diff --git a/BeatTogether.MasterServer.Domain/Models/Server.cs b/BeatTogether.MasterServer.Domain/Models/Server.cs index 1b66665..419c6f2 100644 --- a/BeatTogether.MasterServer.Domain/Models/Server.cs +++ b/BeatTogether.MasterServer.Domain/Models/Server.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Net; using BeatTogether.Core.Abstractions; using BeatTogether.Core.Enums; @@ -23,6 +24,8 @@ public Server() { } public HashSet PlayerHashes { get; set; } = new(); public string ManagerId { get; set; } + + public VersionRange SupportedVersionRange { get; set; } public bool PermanentManager { get; set; } public long ServerStartJoinTimeout { get; set; } public bool NeverCloseServer { get; set; } diff --git a/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj b/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj index 6b77df7..4c5f94e 100644 --- a/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj +++ b/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj @@ -17,7 +17,7 @@ - + diff --git a/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj b/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj index 8783c96..cd6c480 100644 --- a/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj +++ b/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj @@ -7,7 +7,7 @@ - + diff --git a/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs b/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs index b5e854d..8c5c63b 100644 --- a/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs +++ b/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs @@ -9,6 +9,7 @@ public enum MultiplayerPlacementErrorCode ServerAtCapacity, AuthenticationFailed, RequestTimeout, - MatchmakingTimeout + MatchmakingTimeout, + LobbyHostVersionMismatch = 50 } } \ No newline at end of file diff --git a/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj b/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj index 3f2ac91..477a04b 100644 --- a/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj +++ b/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj @@ -19,7 +19,7 @@ - + diff --git a/BeatTogether.MasterServer.NodeController/Configuration/NodeControllerConfiguration.cs b/BeatTogether.MasterServer.NodeController/Configuration/NodeControllerConfiguration.cs index b08f3bb..cb5b85b 100644 --- a/BeatTogether.MasterServer.NodeController/Configuration/NodeControllerConfiguration.cs +++ b/BeatTogether.MasterServer.NodeController/Configuration/NodeControllerConfiguration.cs @@ -3,8 +3,8 @@ namespace BeatTogether.MasterServer.NodeController.Configuration { public class NodeControllerConfiguration { - public Version MasterServerVersion { get; } = new(2,0,0); - public Version[] SupportedDediServerVersions { get; } = { new(2,0,0) }; //for example, if 1.1 is here, then 1.1.1, 1.1.5, 1.1.23, would all be accepted verisions and 1.2.3 would not. Only change when dedi and master would be incompat otherwise + public Version MasterServerVersion { get; } = new(2,1,0); + public Version[] SupportedDediServerVersions { get; } = { new(2,1,0) }; //for example, if 1.1 is here, then 1.1.1, 1.1.5, 1.1.23, would all be accepted verisions and 1.2.3 would not. Only change when dedi and master would be incompat otherwise public long TicksBetweenUpdatingCachedApiResponses { get; set; } = TimeSpan.TicksPerSecond; } } diff --git a/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj b/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj index 6375494..f9bc280 100644 --- a/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj +++ b/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj @@ -12,11 +12,14 @@ + + Always + - PreserveNewest + Always - PreserveNewest + Always diff --git a/BeatTogether.MasterServer/Properties/launchSettings.json b/BeatTogether.MasterServer/Properties/launchSettings.json new file mode 100644 index 0000000..020b106 --- /dev/null +++ b/BeatTogether.MasterServer/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "BeatTogether.MasterServer": { + "commandName": "Project", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "LocalDevelopment" + } + } + } +} \ No newline at end of file diff --git a/BeatTogether.MasterServer/appsettings.Development.json b/BeatTogether.MasterServer/appsettings.Development.json index 7ee48b1..ec21292 100644 --- a/BeatTogether.MasterServer/appsettings.Development.json +++ b/BeatTogether.MasterServer/appsettings.Development.json @@ -1,14 +1,31 @@ { "Urls": "http://0.0.0.0:8989", + "RabbitMQ": { + "HostName": "127.0.0.1" + }, "Serilog": { "MinimumLevel": { "Default": "Verbose", "Overrides": { "Microsoft": "Warning" } - }, - "ServerConfiguration": { - "AuthenticateClients": false } + }, + "ServerConfiguration": { + "VersionRanges": [ + { + "MinVersion": "1.37.0", + "MaxVersion": "1.39.1" + }, + { + "MinVersion": "1.40.0" + } + ], + "AuthenticateClients": true, + "AuthedClients": [ + "Steam", + "Oculus", + "Pico" + ] } } diff --git a/BeatTogether.MasterServer/appsettings.json b/BeatTogether.MasterServer/appsettings.json index bd63313..23bbaf2 100644 --- a/BeatTogether.MasterServer/appsettings.json +++ b/BeatTogether.MasterServer/appsettings.json @@ -1,5 +1,8 @@ { "Urls": "http://0.0.0.0:8989", + "RabbitMQ": { + "HostName": "127.0.0.1" + }, "Serilog": { "File": { "Path": "logs/BeatTogether.MasterServer-{Date}.log" @@ -9,9 +12,24 @@ "Overrides": { "Microsoft": "Warning" } - }, - "ServerConfiguration": { - "AuthenticateClients": false } + }, + "ServerConfiguration": { + "VersionRanges": [ + { + "MinVersion": "1.37.0", + "MaxVersion": "1.39.1" + }, + { + "MinVersion": "1.40.0" + } + ], + "AuthenticateClients": true, + "AuthedClients": [ + "Steam", + "Oculus", + "Pico", + "OculusQuest" + ] } } From 9c607b80b2f03db814bae56b08050d6c349060c9 Mon Sep 17 00:00:00 2001 From: EnderdracheLP Date: Mon, 30 Dec 2024 17:55:00 +0100 Subject: [PATCH 2/4] Fix build error by specifying wildcard for appsettings.Environment.json --- BeatTogether.MasterServer/BeatTogether.MasterServer.csproj | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj b/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj index f9bc280..1939b05 100644 --- a/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj +++ b/BeatTogether.MasterServer/BeatTogether.MasterServer.csproj @@ -7,15 +7,12 @@ - + - - Always - - + Always From 9a5d977cb2f300a69394a3f23725efeef2370810 Mon Sep 17 00:00:00 2001 From: EnderdracheLP Date: Sat, 4 Jan 2025 00:16:22 +0100 Subject: [PATCH 3/4] Add a /test with a little message to master api, for people to test connections --- .../HttpControllers/MasterServerController.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/BeatTogether.MasterServer.NodeController/HttpControllers/MasterServerController.cs b/BeatTogether.MasterServer.NodeController/HttpControllers/MasterServerController.cs index ba68736..49962ec 100644 --- a/BeatTogether.MasterServer.NodeController/HttpControllers/MasterServerController.cs +++ b/BeatTogether.MasterServer.NodeController/HttpControllers/MasterServerController.cs @@ -25,6 +25,17 @@ public MasterServerController( _Configuration = nodeControllerConfiguration; } + /// + /// Returns a test message so players can test if the connection works + /// + /// + [HttpGet] + [Route("test")] + public string GetTestMessage() + { + return "Yay, seems like you are able to connect to the master server!"; + } + /// /// Returns the amount of active instances /// From 3e623f59a85eca9f63196bb4045558c11c023e78 Mon Sep 17 00:00:00 2001 From: EnderdracheLP Date: Sun, 12 Jan 2025 16:45:06 +0100 Subject: [PATCH 4/4] Update Quickplay Lobby request and change version range check to return too new/old or unknown errors --- .../BeatTogether.MasterServer.Api.csproj | 2 +- .../GetMultiplayerInstanceController.cs | 64 ++++++++++------ .../Repositories/IServerRepository.cs | 18 +++-- .../Repositories/MemoryServerRepository.cs | 75 ++++++++++--------- .../Repositories/ServerRepository.cs | 4 +- .../BeatTogether.MasterServer.Domain.csproj | 2 +- ...BeatTogether.MasterServer.Interface.csproj | 2 +- ...BeatTogether.MasterServer.Messaging.csproj | 2 +- .../Enums/MultiplayerPlacementErrorCode.cs | 5 +- ...ogether.MasterServer.NodeController.csproj | 2 +- .../NodeControllerLayer.cs | 8 +- 11 files changed, 109 insertions(+), 75 deletions(-) diff --git a/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj b/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj index d7de00f..e0de5b1 100644 --- a/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj +++ b/BeatTogether.MasterServer.Api/BeatTogether.MasterServer.Api.csproj @@ -17,7 +17,7 @@ - + diff --git a/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs b/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs index 3a8e3af..7676689 100644 --- a/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs +++ b/BeatTogether.MasterServer.Api/HttpControllers/GetMultiplayerInstanceController.cs @@ -109,8 +109,25 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye //if(session == null) { _logger.Information("Player Session is null"); } response.AddSessionContext(session.PlayerSessionId); - //Player authed and has a session, now get them a server. - bool isQuickplay = string.IsNullOrEmpty(request.PrivateGameCode) && string.IsNullOrEmpty(request.PrivateGameSecret); //Quickplay is true if there is no code and no secret + // Get version range of player + VersionRange supportedRange = VersionRange.FindVersionRange(_apiServerConfiguration.VersionRanges.ToList(), session.PlayerClientVersion!); + if (supportedRange == null) + { + // Version not supported at all according to config + _logger.Error($"Could not find matching version range for client version: {session.PlayerClientVersion}"); + response.ErrorCode = MultiplayerPlacementErrorCode.GameVersionUnknown; + return new JsonResult(response); + } + + //if (supportedRange != null) // TODO: Should we just set to exact version match if not known? + // supportedRange = new VersionRange + // { MinVersion = session.PlayerClientVersion.ToString(), MaxVersion = session.PlayerClientVersion.ToString() }; + + _logger.Debug( + $"Found version range MinVersion: '{supportedRange.MinVersion}' MaxVersion: '{supportedRange.MaxVersion}' for client version '{session.PlayerClientVersion}'"); + + //Player authed and has a session, now get them a server. + bool isQuickplay = string.IsNullOrEmpty(request.PrivateGameCode) && string.IsNullOrEmpty(request.PrivateGameSecret); //Quickplay is true if there is no code and no secret IServerInstance server = null; if (!isQuickplay) { @@ -128,7 +145,8 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye (Core.Enums.GameplayServerControlSettings)request.GameplayServerConfiguration.GameplayServerControlSettings, (Core.Enums.BeatmapDifficultyMask)request.BeatmapLevelSelectionMask.BeatmapDifficultyMask, (Core.Enums.GameplayModifiersMask)request.BeatmapLevelSelectionMask.GameplayModifiersMask, - request.BeatmapLevelSelectionMask.SongPackMasks); + request.BeatmapLevelSelectionMask.SongPackMasks, + supportedRange); } //If the server is still null, then make new server @@ -148,17 +166,6 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye { string secret = request.PrivateGameSecret; string managerId = FixedServerUserId; - VersionRange supportedRange = VersionRange.FindVersionRange(_apiServerConfiguration.VersionRanges.ToList(), session.PlayerClientVersion!); - if (supportedRange == null) - { - // Version not supported at all according to config - _logger.Error($"Could not find matching version range for client version: {session.PlayerClientVersion}"); - response.ErrorCode = MultiplayerPlacementErrorCode.LobbyHostVersionMismatch; - return new JsonResult(response); - } - - _logger.Debug( - $"Found version range MinVersion: '{supportedRange.MinVersion}' MaxVersion: '{supportedRange.MaxVersion}' for client version '{session.PlayerClientVersion}'"); if (!isQuickplay) managerId = session.HashedUserId; //sets the manager to the player who is requesting else @@ -221,15 +228,28 @@ public async Task GetMultiplayerInstance([FromBody] GetMultiplaye } // Checks if the joining players version is witin the supported range of the lobby - if (!VersionRange.VersionRangeSatisfies(server.SupportedVersionRange, - session.PlayerClientVersion.ToString())) + switch (VersionRange.CheckVersionRange(server.SupportedVersionRange, session.PlayerClientVersion)) { - _logger.Warning($"Player '{session.HashedUserId}' on version '{session.PlayerClientVersion}' cannot join lobby with range {server.SupportedVersionRange.MinVersion} - {server.SupportedVersionRange.MaxVersion}"); - response.ErrorCode = MultiplayerPlacementErrorCode.LobbyHostVersionMismatch; - return new JsonResult(response); - } - - _logger.Information("Player session data from player: " + session.HashedUserId + " Is being sent to node: " + server.InstanceEndPoint + ", Server secret: " + server.Secret + ", Player count before join: " + server.PlayerHashes.Count); + case VersionRange.VersionStatus.Ok: + break; + case VersionRange.VersionStatus.TooHigh: + _logger.Warning($"Player '{session.HashedUserId}' on version '{session.PlayerClientVersion}' cannot join lobby with range {server.SupportedVersionRange.MinVersion} - {server.SupportedVersionRange.MaxVersion} reason: Game Version Too New"); + response.ErrorCode = MultiplayerPlacementErrorCode.GameVersionTooNew; + return new JsonResult(response); + case VersionRange.VersionStatus.TooLow: + _logger.Warning($"Player '{session.HashedUserId}' on version '{session.PlayerClientVersion}' cannot join lobby with range {server.SupportedVersionRange.MinVersion} - {server.SupportedVersionRange.MaxVersion} reason: Game Version Too Old"); + response.ErrorCode = MultiplayerPlacementErrorCode.GameVersionTooOld; + return new JsonResult(response); + } + //if (!VersionRange.VersionRangeSatisfies(server.SupportedVersionRange, + // session.PlayerClientVersion.ToString())) + //{ + // _logger.Warning($"Player '{session.HashedUserId}' on version '{session.PlayerClientVersion}' cannot join lobby with range {server.SupportedVersionRange.MinVersion} - {server.SupportedVersionRange.MaxVersion}"); + // response.ErrorCode = MultiplayerPlacementErrorCode.LobbyHostVersionMismatch; + // return new JsonResult(response); + //} + + _logger.Information("Player session data from player: " + session.HashedUserId + " Is being sent to node: " + server.InstanceEndPoint + ", Server secret: " + server.Secret + ", Player count before join: " + server.PlayerHashes.Count); if (!await _layer2.SetPlayerSessionData(server.Secret, session)) { diff --git a/BeatTogether.MasterServer.Data/Abstractions/Repositories/IServerRepository.cs b/BeatTogether.MasterServer.Data/Abstractions/Repositories/IServerRepository.cs index fbaa8fd..1753b0b 100644 --- a/BeatTogether.MasterServer.Data/Abstractions/Repositories/IServerRepository.cs +++ b/BeatTogether.MasterServer.Data/Abstractions/Repositories/IServerRepository.cs @@ -1,6 +1,7 @@ using System.Net; using System.Threading.Tasks; using BeatTogether.Core.Enums; +using BeatTogether.Core.Models; using BeatTogether.MasterServer.Domain.Models; namespace BeatTogether.MasterServer.Data.Abstractions.Repositories @@ -10,14 +11,15 @@ public interface IServerRepository Task GetServer(string secret); Task GetServerByCode(string code); Task GetAvailablePublicServer( - InvitePolicy invitePolicy, - GameplayServerMode serverMode, - SongSelectionMode songMode, - GameplayServerControlSettings serverControlSettings, - BeatmapDifficultyMask difficultyMask, - GameplayModifiersMask modifiersMask, - string SongPackMasks); - Task UpdateServer(string secret, Server server); + InvitePolicy invitePolicy, + GameplayServerMode serverMode, + SongSelectionMode songMode, + GameplayServerControlSettings serverControlSettings, + BeatmapDifficultyMask difficultyMask, + GameplayModifiersMask modifiersMask, + string SongPackMasks, + VersionRange versionRange); + Task UpdateServer(string secret, Server server); Task GetPublicServerSecrets(); Task GetPublicServerCodes(); Task GetPublicServerList(); diff --git a/BeatTogether.MasterServer.Data/Implementations/Repositories/MemoryServerRepository.cs b/BeatTogether.MasterServer.Data/Implementations/Repositories/MemoryServerRepository.cs index bb9c2d9..c7385ef 100644 --- a/BeatTogether.MasterServer.Data/Implementations/Repositories/MemoryServerRepository.cs +++ b/BeatTogether.MasterServer.Data/Implementations/Repositories/MemoryServerRepository.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; @@ -6,6 +7,7 @@ using System.Threading.Tasks; using BeatTogether.MasterServer.Data.Abstractions.Repositories; using BeatTogether.Core.Enums; +using BeatTogether.Core.Models; using BeatTogether.MasterServer.Domain.Models; namespace BeatTogether.MasterServer.Data.Implementations.Repositories @@ -96,42 +98,45 @@ public Task GetServerByCode(string code) } public Task GetAvailablePublicServer( - InvitePolicy invitePolicy, - GameplayServerMode serverMode, - SongSelectionMode songMode, - GameplayServerControlSettings serverControlSettings, - BeatmapDifficultyMask difficultyMask, - GameplayModifiersMask modifiersMask, - string SongPackMasks) - { - if (!_servers.Any()) - return Task.FromResult(null); - var publicServers = _servers.Values.Where(server => - server.GameplayServerConfiguration.DiscoveryPolicy == DiscoveryPolicy.Public && - server.GameplayServerConfiguration.InvitePolicy == invitePolicy && - server.GameplayServerConfiguration.GameplayServerMode == serverMode && - server.GameplayServerConfiguration.SongSelectionMode == songMode && - server.GameplayServerConfiguration.GameplayServerControlSettings == serverControlSettings && - server.BeatmapDifficultyMask == difficultyMask && - server.GameplayModifiersMask == modifiersMask && - server.SongPackMasks == SongPackMasks - ); - if (!publicServers.Any()) - return Task.FromResult(null); - var server = publicServers.First(); - foreach (var publicServer in publicServers) - { - if ((publicServer.CurrentPlayerCount < publicServer.GameplayServerConfiguration.MaxPlayerCount && publicServer.CurrentPlayerCount > server.CurrentPlayerCount)) - { - server = publicServer; - } - } - if (server.CurrentPlayerCount >= server.GameplayServerConfiguration.MaxPlayerCount) - return Task.FromResult(null); - return Task.FromResult(server); + InvitePolicy invitePolicy, + GameplayServerMode serverMode, + SongSelectionMode songMode, + GameplayServerControlSettings serverControlSettings, + BeatmapDifficultyMask difficultyMask, + GameplayModifiersMask modifiersMask, + string SongPackMasks, + VersionRange versionRange) + { + if (!_servers.Any()) + return Task.FromResult(null); + var publicServers = _servers.Values.Where(server => + server.GameplayServerConfiguration.DiscoveryPolicy == DiscoveryPolicy.Public && + server.GameplayServerConfiguration.InvitePolicy == invitePolicy && + server.GameplayServerConfiguration.GameplayServerMode == serverMode && + server.GameplayServerConfiguration.SongSelectionMode == songMode && + server.GameplayServerConfiguration.GameplayServerControlSettings == serverControlSettings && + server.BeatmapDifficultyMask == difficultyMask && + server.GameplayModifiersMask == modifiersMask && + server.SongPackMasks == SongPackMasks && + server.SupportedVersionRange == versionRange + ); + if (!publicServers.Any()) + return Task.FromResult(null); + var server = publicServers.First(); + foreach (var publicServer in publicServers) + { + if ((publicServer.CurrentPlayerCount < publicServer.GameplayServerConfiguration.MaxPlayerCount && publicServer.CurrentPlayerCount > server.CurrentPlayerCount)) + { + server = publicServer; + } + } + if (server.CurrentPlayerCount >= server.GameplayServerConfiguration.MaxPlayerCount) + return Task.FromResult(null); + return Task.FromResult(server); } - public Task AddServer(Server server) + + public Task AddServer(Server server) { if (!_servers.TryAdd(server.Secret, server)) return Task.FromResult(false); diff --git a/BeatTogether.MasterServer.Data/Implementations/Repositories/ServerRepository.cs b/BeatTogether.MasterServer.Data/Implementations/Repositories/ServerRepository.cs index 28c60a2..c89b0cb 100644 --- a/BeatTogether.MasterServer.Data/Implementations/Repositories/ServerRepository.cs +++ b/BeatTogether.MasterServer.Data/Implementations/Repositories/ServerRepository.cs @@ -97,7 +97,8 @@ public async Task GetAvailablePublicServer(InvitePolicy invitePolicy, GameplayServerControlSettings serverControlSettings, BeatmapDifficultyMask difficultyMask, GameplayModifiersMask modifiersMask, - string SongPackMasks) + string SongPackMasks, + VersionRange versionRange) { var database = _connectionMultiplexer.GetDatabase(); var redisValues = await database.SortedSetRangeByScoreAsync(RedisKeys.PublicServersByPlayerCount, take: 1); @@ -132,6 +133,7 @@ public async Task AddServer(Server server) currentPlayerCount = (RedisValue)server.CurrentPlayerCount, //random = (RedisValue)server.Random, //publicKey = (RedisValue)server.PublicKey + //SupportedVersionRange = (RedisValue)() }, flags: CommandFlags.DemandMaster ); diff --git a/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj b/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj index 592be07..57521b0 100644 --- a/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj +++ b/BeatTogether.MasterServer.Domain/BeatTogether.MasterServer.Domain.csproj @@ -6,7 +6,7 @@ - + diff --git a/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj b/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj index 4c5f94e..aeee24e 100644 --- a/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj +++ b/BeatTogether.MasterServer.Interface/BeatTogether.MasterServer.Interface.csproj @@ -17,7 +17,7 @@ - + diff --git a/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj b/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj index cd6c480..81e3ed7 100644 --- a/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj +++ b/BeatTogether.MasterServer.Messaging/BeatTogether.MasterServer.Messaging.csproj @@ -7,7 +7,7 @@ - + diff --git a/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs b/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs index 8c5c63b..225756b 100644 --- a/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs +++ b/BeatTogether.MasterServer.Messaging/Enums/MultiplayerPlacementErrorCode.cs @@ -10,6 +10,9 @@ public enum MultiplayerPlacementErrorCode AuthenticationFailed, RequestTimeout, MatchmakingTimeout, - LobbyHostVersionMismatch = 50 + // Below are our custom error codes + GameVersionUnknown = 50, + GameVersionTooOld, + GameVersionTooNew } } \ No newline at end of file diff --git a/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj b/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj index 477a04b..4de95a9 100644 --- a/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj +++ b/BeatTogether.MasterServer.NodeController/BeatTogether.MasterServer.NodeController.csproj @@ -19,7 +19,7 @@ - + diff --git a/BeatTogether.MasterServer.NodeController/NodeControllerLayer.cs b/BeatTogether.MasterServer.NodeController/NodeControllerLayer.cs index 844ee7e..6396ac5 100644 --- a/BeatTogether.MasterServer.NodeController/NodeControllerLayer.cs +++ b/BeatTogether.MasterServer.NodeController/NodeControllerLayer.cs @@ -10,6 +10,7 @@ using BinaryRecords; using Serilog; using System.Net; +using BeatTogether.Core.Models; namespace BeatTogether.MasterServer.NodeController { @@ -61,11 +62,12 @@ public Task DisconnectPlayer(string InstanceId, string PlayerUserId) return Task.CompletedTask; } - public async Task GetAvailablePublicServer(InvitePolicy invitePolicy, GameplayServerMode serverMode, SongSelectionMode songMode, GameplayServerControlSettings serverControlSettings, BeatmapDifficultyMask difficultyMask, GameplayModifiersMask modifiersMask, string songPackMasks) + public async Task GetAvailablePublicServer(InvitePolicy invitePolicy, GameplayServerMode serverMode, SongSelectionMode songMode, GameplayServerControlSettings serverControlSettings, BeatmapDifficultyMask difficultyMask, GameplayModifiersMask modifiersMask, string songPackMasks, VersionRange versionRange) { - return await _serverRepository.GetAvailablePublicServer(invitePolicy, serverMode, songMode, serverControlSettings, difficultyMask, modifiersMask, songPackMasks); + return await _serverRepository.GetAvailablePublicServer(invitePolicy, serverMode, songMode, serverControlSettings, difficultyMask, modifiersMask, songPackMasks, versionRange); } - public async Task GetServer(string secret) + + public async Task GetServer(string secret) { return await _serverRepository.GetServer(secret); }