From 36f27a5b68b084aab5045ddf135d3e83a94664d4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 08:14:18 +0000 Subject: [PATCH 1/2] Initial plan From 5c577a0c5106d4b00ef7a52b843f613f363a94f9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 08:27:20 +0000 Subject: [PATCH 2/2] Implement autoload config feature for match loading on map start Co-authored-by: MD-V <436613+MD-V@users.noreply.github.com> --- PugSharp.Config/ServerConfig.cs | 6 +++ PugSharp.Tests/ApplicationTests.cs | 22 +++++++++ PugSharp.Tests/ServerConfigTests.cs | 53 +++++++++++++++++++++ PugSharp/Application.cs | 73 +++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 PugSharp.Tests/ServerConfigTests.cs diff --git a/PugSharp.Config/ServerConfig.cs b/PugSharp.Config/ServerConfig.cs index 09fed966..f95dd64d 100644 --- a/PugSharp.Config/ServerConfig.cs +++ b/PugSharp.Config/ServerConfig.cs @@ -9,4 +9,10 @@ public class ServerConfig [JsonPropertyName("allow_players_without_match")] public bool AllowPlayersWithoutMatch { get; init; } = true; + + [JsonPropertyName("autoload_config")] + public string AutoloadConfig { get; init; } = string.Empty; + + [JsonPropertyName("autoload_config_auth_token")] + public string AutoloadConfigAuthToken { get; init; } = string.Empty; } diff --git a/PugSharp.Tests/ApplicationTests.cs b/PugSharp.Tests/ApplicationTests.cs index 8552051d..a1f72545 100644 --- a/PugSharp.Tests/ApplicationTests.cs +++ b/PugSharp.Tests/ApplicationTests.cs @@ -45,4 +45,26 @@ public void InitializeApplicationTest() application.Initialize(hotReload: false); } + + [Fact] + public void ServerConfigHasAutoloadProperties() + { + var serverConfig = new ServerConfig + { + AutoloadConfig = "https://example.com/config.json", + AutoloadConfigAuthToken = "test-token" + }; + + Assert.Equal("https://example.com/config.json", serverConfig.AutoloadConfig); + Assert.Equal("test-token", serverConfig.AutoloadConfigAuthToken); + } + + [Fact] + public void ServerConfigDefaultsToEmptyAutoloadConfig() + { + var serverConfig = new ServerConfig(); + + Assert.Equal(string.Empty, serverConfig.AutoloadConfig); + Assert.Equal(string.Empty, serverConfig.AutoloadConfigAuthToken); + } } \ No newline at end of file diff --git a/PugSharp.Tests/ServerConfigTests.cs b/PugSharp.Tests/ServerConfigTests.cs new file mode 100644 index 00000000..1ffafc09 --- /dev/null +++ b/PugSharp.Tests/ServerConfigTests.cs @@ -0,0 +1,53 @@ +using System.Text.Json; + +using PugSharp.Config; + +namespace PugSharp.Tests; + +public class ServerConfigTests +{ + [Fact] + public void ServerConfigCanBeSerializedAndDeserialized() + { + var originalConfig = new ServerConfig + { + Locale = "en", + AllowPlayersWithoutMatch = true, + AutoloadConfig = "https://example.com/config.json", + AutoloadConfigAuthToken = "test-token" + }; + + var json = JsonSerializer.Serialize(originalConfig); + var deserializedConfig = JsonSerializer.Deserialize(json); + + Assert.NotNull(deserializedConfig); + Assert.Equal(originalConfig.Locale, deserializedConfig.Locale); + Assert.Equal(originalConfig.AllowPlayersWithoutMatch, deserializedConfig.AllowPlayersWithoutMatch); + Assert.Equal(originalConfig.AutoloadConfig, deserializedConfig.AutoloadConfig); + Assert.Equal(originalConfig.AutoloadConfigAuthToken, deserializedConfig.AutoloadConfigAuthToken); + } + + [Fact] + public void ServerConfigJsonPropertyNamesAreCorrect() + { + var config = new ServerConfig + { + AutoloadConfig = "test-config", + AutoloadConfigAuthToken = "test-token" + }; + + var json = JsonSerializer.Serialize(config); + + Assert.Contains("\"autoload_config\"", json, StringComparison.Ordinal); + Assert.Contains("\"autoload_config_auth_token\"", json, StringComparison.Ordinal); + } + + [Fact] + public void ServerConfigDefaultsToEmptyAutoloadConfig() + { + var serverConfig = new ServerConfig(); + + Assert.Equal(string.Empty, serverConfig.AutoloadConfig); + Assert.Equal(string.Empty, serverConfig.AutoloadConfigAuthToken); + } +} \ No newline at end of file diff --git a/PugSharp/Application.cs b/PugSharp/Application.cs index 35bcf69f..079244ee 100644 --- a/PugSharp/Application.cs +++ b/PugSharp/Application.cs @@ -352,6 +352,11 @@ private void OnMapStartHandler(string mapName) SetMatchVariable(); }); } + else if (_Match == null && _ServerConfig != null && !string.IsNullOrEmpty(_ServerConfig.AutoloadConfig)) + { + _Logger.LogInformation("Map started, attempting to autoload config: {Config}", _ServerConfig.AutoloadConfig); + _ = Task.Run(() => TryAutoloadConfig()); + } } // TODO Add Round Events to RoundService? @@ -2024,6 +2029,74 @@ private void InitializeMatch(MatchInfo matchInfo, string roundBackupFile) KickNonMatchPlayers(); } + private async Task TryAutoloadConfig() + { + if (_ServerConfig == null || string.IsNullOrEmpty(_ServerConfig.AutoloadConfig)) + { + return; + } + + if (_Match != null) + { + _Logger.LogInformation("Match is already running, skipping autoload"); + return; + } + + _Logger.LogInformation("Attempting to autoload config: {Config}", _ServerConfig.AutoloadConfig); + + try + { + var config = _ServerConfig.AutoloadConfig; + var authToken = _ServerConfig.AutoloadConfigAuthToken; + + // Check if it's a URL or file path + if (Uri.TryCreate(config, UriKind.Absolute, out var uri) && + (uri.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.Ordinal) || uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.Ordinal))) + { + // Load from URL + var result = await _ConfigProvider.LoadMatchConfigFromUrlAsync(config, authToken).ConfigureAwait(false); + result.Switch( + error => + { + _Logger.LogError("Failed to autoload config from URL: {Error}", error.Value); + }, + matchConfig => + { + _Logger.LogInformation("Successfully autoloaded config from URL"); + + // Use same token for APIstats if there's no token set in the matchconfig + if (string.IsNullOrEmpty(matchConfig.EventulaApistatsToken)) + { + matchConfig.EventulaApistatsToken = authToken; + } + + StoreConfig(matchConfig); + InitializeMatch(matchConfig); + }); + } + else + { + // Load from file + var result = await _ConfigProvider.LoadMatchConfigFromFileAsync(config).ConfigureAwait(false); + result.Switch( + error => + { + _Logger.LogError("Failed to autoload config from file: {Error}", error.Value); + }, + matchConfig => + { + _Logger.LogInformation("Successfully autoloaded config from file"); + StoreConfig(matchConfig); + InitializeMatch(matchConfig); + }); + } + } + catch (Exception ex) + { + _Logger.LogError(ex, "Error during autoload config"); + } + } + private void OnMatchFinalized(object? sender, MatchFinalizedEventArgs e) { StopMatch();