diff --git a/AssettoServer/Program.cs b/AssettoServer/Program.cs index ccac219c..d7983f28 100644 --- a/AssettoServer/Program.cs +++ b/AssettoServer/Program.cs @@ -1,11 +1,11 @@ -using AssettoServer.Server.Configuration; -using System; +using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using AssettoServer.Server.Configuration; using AssettoServer.Utils; using Autofac.Extensions.DependencyInjection; using CommandLine; @@ -28,7 +28,7 @@ public static class Program #else public static readonly bool IsDebugBuild = false; #endif - + [UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] private class Options { @@ -59,19 +59,20 @@ private class StartOptions public string? Preset { get; init; } public string? ServerCfgPath { get; init; } public string? EntryListPath { get; init; } + public PortOverrides? PortOverrides { get; init; } } public static bool IsContentManager; private static bool _loadPluginsFromWorkdir; private static bool _generatePluginConfigs; private static TaskCompletionSource _restartTask = new(); - + internal static async Task Main(string[] args) { SetupFluentValidation(); SetupMetrics(); DetectContentManager(); - + var options = Parser.Default.ParseArguments(args).Value; if (options == null) return; @@ -85,21 +86,19 @@ internal static async Task Main(string[] args) if (options.UseRandomPreset) { - var presetsPath = Path.Join(AppContext.BaseDirectory, "presets"); var presets = Path.Exists(presetsPath) ? Directory.EnumerateDirectories("presets").Select(Path.GetFileName).OfType().ToArray() : []; if (presets.Length > 0) options.Preset = presets[Random.Shared.Next(presets.Length)]; - else + else Log.Warning("Presets directory does not exist or contain any preset"); - } string logPrefix = string.IsNullOrEmpty(options.Preset) ? "log" : options.Preset; Logging.CreateDefaultLogger(logPrefix, IsContentManager, options.UseVerboseLogging); - + AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; Log.Information("AssettoServer {Version}", ThisAssembly.AssemblyInformationalVersion); if (IsContentManager) @@ -113,12 +112,12 @@ internal static async Task Main(string[] args) ServerCfgPath = options.ServerCfgPath, EntryListPath = options.EntryListPath }; - + while (true) { _restartTask = new TaskCompletionSource(); using var cts = new CancellationTokenSource(); - var serverTask = RunServerAsync(startOptions.Preset, startOptions.ServerCfgPath, startOptions.EntryListPath, options.UseVerboseLogging, cts.Token); + var serverTask = RunServerAsync(startOptions.Preset, startOptions.ServerCfgPath, startOptions.EntryListPath, startOptions.PortOverrides ,options.UseVerboseLogging, cts.Token); var finishedTask = await Task.WhenAny(serverTask, _restartTask.Task); if (finishedTask == _restartTask.Task) @@ -132,14 +131,19 @@ internal static async Task Main(string[] args) } } - public static void RestartServer(string? preset, string? serverCfgPath = null, string? entryListPath = null) + public static void RestartServer( + string? preset, + string? serverCfgPath = null, + string? entryListPath = null, + PortOverrides? portOverrides = null) { Log.Information("Initiated in-process server restart"); _restartTask.SetResult(new StartOptions { Preset = preset, ServerCfgPath = serverCfgPath, - EntryListPath = entryListPath + EntryListPath = entryListPath, + PortOverrides = portOverrides, }); } @@ -147,14 +151,15 @@ private static async Task RunServerAsync( string? preset, string? serverCfgPath, string? entryListPath, + PortOverrides? portOverrides, bool useVerboseLogging, CancellationToken token = default) { var configLocations = ConfigurationLocations.FromOptions(preset, serverCfgPath, entryListPath); - + try { - var config = new ACServerConfiguration(preset, configLocations, _loadPluginsFromWorkdir, _generatePluginConfigs); + var config = new ACServerConfiguration(preset, configLocations, _loadPluginsFromWorkdir, _generatePluginConfigs, portOverrides); if (config.Extra.LokiSettings != null && !string.IsNullOrEmpty(config.Extra.LokiSettings.Url) @@ -192,7 +197,7 @@ private static async Task RunServerAsync( .UseUrls($"http://0.0.0.0:{config.Server.HttpPort}"); }) .Build(); - + await host.RunAsync(token); } catch (Exception ex) @@ -239,8 +244,8 @@ private static void SetupMetrics() Metrics.ConfigureMeterAdapter(adapterOptions => { // Disable a bunch of verbose / unnecessary default metrics - adapterOptions.InstrumentFilterPredicate = inst => - inst.Name != "kestrel.active_connections" + adapterOptions.InstrumentFilterPredicate = inst => + inst.Name != "kestrel.active_connections" && inst.Name != "http.server.active_requests" && inst.Name != "kestrel.queued_connections" && inst.Name != "http.server.request.duration" diff --git a/AssettoServer/Server/Configuration/ACServerConfiguration.cs b/AssettoServer/Server/Configuration/ACServerConfiguration.cs index d4105415..1811e116 100644 --- a/AssettoServer/Server/Configuration/ACServerConfiguration.cs +++ b/AssettoServer/Server/Configuration/ACServerConfiguration.cs @@ -53,13 +53,13 @@ public partial class ACServerConfiguration * * When "entryListPath" is set, it takes precedence and entry_list.ini will be loaded from the specified path. */ - public ACServerConfiguration(string? preset, ConfigurationLocations locations, bool loadPluginsFromWorkdir, bool generatePluginConfigs) + public ACServerConfiguration(string? preset, ConfigurationLocations locations, bool loadPluginsFromWorkdir, bool generatePluginConfigs, PortOverrides? portOverrides) { Preset = preset; BaseFolder = locations.BaseFolder; LoadPluginsFromWorkdir = loadPluginsFromWorkdir; GeneratePluginConfigs = generatePluginConfigs; - Server = LoadServerConfiguration(locations.ServerCfgPath); + Server = LoadServerConfiguration(locations.ServerCfgPath, portOverrides); EntryList = LoadEntryList(locations.EntryListPath); Setups = LoadSetups(); WelcomeMessage = LoadWelcomeMessage(); @@ -107,7 +107,7 @@ public ACServerConfiguration(string? preset, ConfigurationLocations locations, b validator.ValidateAndThrow(this); } - private ServerConfiguration LoadServerConfiguration(string path) + private ServerConfiguration LoadServerConfiguration(string path, PortOverrides? portOverrides) { Log.Debug("Loading server_cfg.ini from {Path}", path); try @@ -121,7 +121,16 @@ private ServerConfiguration LoadServerConfiguration(string path) serverCfg.CopyTo(outFile); } - return ServerConfiguration.FromFile(path); + var config = ServerConfiguration.FromFile(path); + + if (portOverrides != null) + { + config.TcpPort = portOverrides.TcpPort; + config.UdpPort = portOverrides.UdpPort; + config.HttpPort = portOverrides.HttpPort; + } + + return config; } catch (Exception ex) { diff --git a/AssettoServer/Server/Configuration/Kunos/ServerConfiguration.cs b/AssettoServer/Server/Configuration/Kunos/ServerConfiguration.cs index 8ed0bd9d..883b33c2 100644 --- a/AssettoServer/Server/Configuration/Kunos/ServerConfiguration.cs +++ b/AssettoServer/Server/Configuration/Kunos/ServerConfiguration.cs @@ -13,9 +13,9 @@ public class ServerConfiguration [IniField("SERVER", "PASSWORD")] public string? Password { get; set; } [IniField("SERVER", "ADMIN_PASSWORD")] public string? AdminPassword { get; set; } [IniField("SERVER", "MAX_CLIENTS")] public int MaxClients { get; internal set; } - [IniField("SERVER", "UDP_PORT")] public ushort UdpPort { get; init; } = 9600; - [IniField("SERVER", "TCP_PORT")] public ushort TcpPort { get; init; } = 9600; - [IniField("SERVER", "HTTP_PORT")] public ushort HttpPort { get; init; } = 8081; + [IniField("SERVER", "UDP_PORT")] public ushort UdpPort { get; set; } = 9600; + [IniField("SERVER", "TCP_PORT")] public ushort TcpPort { get; set; } = 9600; + [IniField("SERVER", "HTTP_PORT")] public ushort HttpPort { get; set; } = 8081; [IniField("SERVER", "CLIENT_SEND_INTERVAL_HZ")] public byte RefreshRateHz { get; init; } = 20; [IniField("SERVER", "TRACK")] public string Track { get; internal set; } = ""; [IniField("SERVER", "CONFIG_TRACK")] public string TrackConfig { get; init; } = ""; diff --git a/AssettoServer/Server/Configuration/PortOverrides.cs b/AssettoServer/Server/Configuration/PortOverrides.cs new file mode 100644 index 00000000..b6fc7b5b --- /dev/null +++ b/AssettoServer/Server/Configuration/PortOverrides.cs @@ -0,0 +1,8 @@ +namespace AssettoServer.Server.Configuration; + +public class PortOverrides +{ + public ushort TcpPort { get; set; } + public ushort UdpPort { get; set; } + public ushort HttpPort { get; set; } +} diff --git a/VotingPresetPlugin/Preset/PresetManager.cs b/VotingPresetPlugin/Preset/PresetManager.cs index ebc0b7ec..78e7177d 100644 --- a/VotingPresetPlugin/Preset/PresetManager.cs +++ b/VotingPresetPlugin/Preset/PresetManager.cs @@ -16,7 +16,7 @@ public class PresetManager : CriticalBackgroundService private const string RestartKickReason = "SERVER RESTART FOR TRACK CHANGE (won't take long)"; - public PresetManager(ACServerConfiguration acServerConfiguration, + public PresetManager(ACServerConfiguration acServerConfiguration, EntryCarManager entryCarManager, IHostApplicationLifetime applicationLifetime) : base(applicationLifetime) { @@ -30,7 +30,7 @@ public void SetPreset(PresetData preset) { CurrentPreset = preset; _presetChangeRequested = true; - + if (!CurrentPreset.IsInit) _ = UpdatePreset(); } @@ -60,10 +60,10 @@ private async Task UpdatePreset() if (CurrentPreset.UpcomingType != null && !CurrentPreset.Type!.Equals(CurrentPreset.UpcomingType!)) { Log.Information("Preset change to \'{Name}\' initiated", CurrentPreset.UpcomingType!.Name); - + // Notify about restart Log.Information("Restarting server"); - + if (_acServerConfiguration.Extra.EnableClientMessages) { // Reconnect clients @@ -76,14 +76,21 @@ private async Task UpdatePreset() _entryCarManager.BroadcastPacket(new CSPKickBanMessageOverride { Message = RestartKickReason }); _entryCarManager.BroadcastPacket(new KickCar { SessionId = 255, Reason = KickReason.Kicked }); } - + var preset = new DirectoryInfo(CurrentPreset.UpcomingType!.PresetFolder).Name; - + // Restart the server var sleep = (CurrentPreset.TransitionDuration - 1) * 1000; await Task.Delay(sleep); - - Program.RestartServer(preset); + + Program.RestartServer( + preset, + portOverrides: new PortOverrides + { + TcpPort = _acServerConfiguration.Server.TcpPort, + UdpPort = _acServerConfiguration.Server.UdpPort, + HttpPort = _acServerConfiguration.Server.HttpPort + }); } } }