namespace CommonwealthOnline.Server; internal sealed class ServerRuntime : IAsyncDisposable { private readonly ServerOptions _options; private readonly AuthoritativeServer _server; private readonly TcpServerTransport _tcp; private readonly GnsServerTransport? _gns; private readonly AdminControlServer _admin; private readonly LanDiscoveryService _discovery; private int _started; public ServerRuntime(ServerOptions options) { _options = options; _server = new AuthoritativeServer(options); _tcp = new TcpServerTransport(options, _server); _gns = options.EnableGnsTransport ? new GnsServerTransport(options, _server) : null; _admin = new AdminControlServer(_server, options); _discovery = new LanDiscoveryService(_server, options); } public AuthoritativeServer Server => _server; public void Start() { if (Interlocked.Exchange(ref _started, 1) != 0) return; _admin.Start(); try { _tcp.Start(); _gns?.Start(); try { _discovery.Start(); } catch (Exception ex) { _server.Log($"LAN discovery unavailable on UDP {LanDiscoveryService.DiscoveryPort}: {ex.Message}. Direct connections still work.", "warning"); } } catch { DisposeAsync().AsTask().GetAwaiter().GetResult(); throw; } _server.Log($"Commonwealth Online server listening on {_options.Host}:{_options.Port}"); _server.Log($"Protocol v{ProtocolConstants.ProtocolVersion} negotiation enabled; legacy TCP clients remain temporarily compatible."); } public async ValueTask DisposeAsync() { if (_gns is not null) await _gns.DisposeAsync(); await _tcp.DisposeAsync(); await _discovery.DisposeAsync(); await _admin.DisposeAsync(); await _server.DisposeAsync(); } }