diff --git a/tanks-backend/TanksServer/GameLogic/GameTickWorker.cs b/tanks-backend/TanksServer/GameLogic/GameTickWorker.cs index e684b80..de806bd 100644 --- a/tanks-backend/TanksServer/GameLogic/GameTickWorker.cs +++ b/tanks-backend/TanksServer/GameLogic/GameTickWorker.cs @@ -7,13 +7,11 @@ internal sealed class GameTickWorker( IEnumerable steps, IHostApplicationLifetime lifetime, ILogger logger -) : IHostedLifecycleService, IDisposable +) : BackgroundService, IDisposable { - private readonly CancellationTokenSource _cancellation = new(); - private readonly TaskCompletionSource _shutdownCompletion = new(); private readonly List _steps = steps.ToList(); - public async Task StartedAsync(CancellationToken cancellationToken) + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { await Task.Yield(); @@ -23,7 +21,7 @@ internal sealed class GameTickWorker( try { - while (!_cancellation.IsCancellationRequested) + while (!cancellationToken.IsCancellationRequested) { var delta = sw.Elapsed; sw.Restart(); @@ -37,19 +35,5 @@ internal sealed class GameTickWorker( logger.LogError(ex, "game tick service crashed"); lifetime.StopApplication(); } - - _shutdownCompletion.SetResult(); } - - public Task StoppingAsync(CancellationToken cancellationToken) => _cancellation.CancelAsync(); - - public Task StopAsync(CancellationToken cancellationToken) => _shutdownCompletion.Task; - - public void Dispose() => _cancellation.Dispose(); - - public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs b/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs index 829c0d4..af2f781 100644 --- a/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs +++ b/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs @@ -1,4 +1,3 @@ -using ServicePoint; using TanksServer.GameLogic; using TanksServer.Interactivity; diff --git a/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs b/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs index 09fc940..6f1e463 100644 --- a/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs +++ b/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs @@ -1,5 +1,3 @@ -using ServicePoint; - namespace TanksServer.Graphics; internal interface IFrameConsumer diff --git a/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs b/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs index 6c1165f..695f404 100644 --- a/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs +++ b/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs @@ -1,5 +1,4 @@ using System.Net.WebSockets; -using ServicePoint; using TanksServer.Graphics; namespace TanksServer.Interactivity; diff --git a/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs b/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs index a3486e0..a1640da 100644 --- a/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs +++ b/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs @@ -1,6 +1,5 @@ using System.Buffers; using System.Net.WebSockets; -using ServicePoint; using TanksServer.Graphics; namespace TanksServer.Interactivity; diff --git a/tanks-backend/TanksServer/Interactivity/LoggingLifecycleService.cs b/tanks-backend/TanksServer/Interactivity/LoggingLifecycleService.cs new file mode 100644 index 0000000..a083dfa --- /dev/null +++ b/tanks-backend/TanksServer/Interactivity/LoggingLifecycleService.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Hosting; + +internal class LoggingLifecycleService(ILogger logger) : IHostedLifecycleService +{ + private protected readonly ILogger Logger = logger; + + public virtual Task StartAsync(CancellationToken cancellationToken) + { + Logger.LogDebug("StartAsync"); + return Task.CompletedTask; + } + + public virtual Task StartedAsync(CancellationToken cancellationToken) + { + Logger.LogDebug("StartedAsync"); + return Task.CompletedTask; + } + + public virtual Task StartingAsync(CancellationToken cancellationToken) + { + Logger.LogDebug("StartingAsync"); + return Task.CompletedTask; + } + + public virtual Task StopAsync(CancellationToken cancellationToken) + { + Logger.LogDebug("StopAsync"); + return Task.CompletedTask; + } + + public virtual Task StoppedAsync(CancellationToken cancellationToken) + { + Logger.LogDebug("StoppedAsync"); + return Task.CompletedTask; + } + + public virtual Task StoppingAsync(CancellationToken cancellationToken) + { + Logger.LogDebug("StoppingAsync"); + return Task.CompletedTask; + } +} diff --git a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs index 9758cff..cb96f0c 100644 --- a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs +++ b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.Net; using System.Net.Sockets; -using ServicePoint; using TanksServer.GameLogic; using TanksServer.Graphics; @@ -42,13 +41,13 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer, IDisposable var localIp = GetLocalIPv4(displayConfig.Value).Split('.'); Debug.Assert(localIp.Length == 4); - _scoresBuffer = new CharGrid(12, 20); + _scoresBuffer = new CharGrid(ScoresWidth, ScoresHeight); _scoresBuffer.SetRow(00, "== TANKS! =="); _scoresBuffer.SetRow(01, "-- scores --"); _scoresBuffer.SetRow(17, "-- join --"); - _scoresBuffer.SetRow(18, string.Join('.', localIp[..2])); - _scoresBuffer.SetRow(19, string.Join('.', localIp[2..])); + _scoresBuffer.SetRow(18, $"{localIp[0]}.{localIp[1]}".PadRight(ScoresWidth)); + _scoresBuffer.SetRow(19, $"{localIp[2]}.{localIp[3]}".PadRight(ScoresWidth)); } public async Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, Bitmap observerPixels) @@ -101,7 +100,7 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer, IDisposable for (; row < 16; row++) _scoresBuffer.SetRow(row, new string(' ', ScoresWidth)); - _scoresBuffer.SetRow(16, _mapService.Current.Name[..(Math.Min(ScoresWidth, _mapService.Current.Name.Length) - 1)]); + _scoresBuffer.SetRow(16, _mapService.Current.Name[..(Math.Min(ScoresWidth, _mapService.Current.Name.Length) - 1)].PadRight(ScoresWidth)); } private static string GetLocalIPv4(DisplayConfiguration configuration) diff --git a/tanks-backend/TanksServer/Interactivity/WebsocketServer.cs b/tanks-backend/TanksServer/Interactivity/WebsocketServer.cs index 0c33e4c..6c1f24e 100644 --- a/tanks-backend/TanksServer/Interactivity/WebsocketServer.cs +++ b/tanks-backend/TanksServer/Interactivity/WebsocketServer.cs @@ -1,23 +1,23 @@ using System.Diagnostics; -using Microsoft.Extensions.Hosting; namespace TanksServer.Interactivity; internal abstract class WebsocketServer( ILogger logger -) : IHostedLifecycleService +) : LoggingLifecycleService(logger) where T : WebsocketServerConnection { private bool _closing; private readonly ConcurrentDictionary _connections = []; - public async Task StoppingAsync(CancellationToken cancellationToken) + public async override Task StoppingAsync(CancellationToken cancellationToken) { + await base.StoppingAsync(cancellationToken); _closing = true; - logger.LogInformation("closing connections"); + Logger.LogInformation("closing connections"); await _connections.Keys.Select(c => c.CloseAsync()) .WhenAll(); - logger.LogInformation("closed connections"); + Logger.LogInformation("closed connections"); } protected IEnumerable Connections => _connections.Keys; @@ -26,7 +26,7 @@ internal abstract class WebsocketServer( { if (_closing) { - logger.LogWarning("refusing connection because server is shutting down"); + Logger.LogWarning("refusing connection because server is shutting down"); await connection.CloseAsync(); return; } @@ -39,14 +39,4 @@ internal abstract class WebsocketServer( _ = _connections.TryRemove(connection, out _); connection.Dispose(); } - - public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public Task StartedAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/tanks-backend/TanksServer/Program.cs b/tanks-backend/TanksServer/Program.cs index cbfff75..e794589 100644 --- a/tanks-backend/TanksServer/Program.cs +++ b/tanks-backend/TanksServer/Program.cs @@ -67,8 +67,8 @@ public static class Program builder.Services.AddSingleton(); builder.Services.AddHostedService(); - builder.Services.AddHostedService(sp => sp.GetRequiredService()); - builder.Services.AddHostedService(sp => sp.GetRequiredService()); + builder.Services.AddHostedService(FromServices); + builder.Services.AddHostedService(FromServices); builder.Services.AddSingleton(sp => sp.GetRequiredService()); @@ -113,4 +113,6 @@ public static class Program return app; } + + private static T FromServices(IServiceProvider sp) where T : notnull => sp.GetRequiredService(); }