From dc9ad21a3dc5d84d5ead821dfb98d61c9bd2855d Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sun, 7 Apr 2024 20:16:22 +0200 Subject: [PATCH] make big display toggleable --- TanksServer/DrawSteps/BulletDrawer.cs | 1 + TanksServer/DrawSteps/MapDrawer.cs | 2 ++ TanksServer/DrawSteps/TankDrawer.cs | 1 + TanksServer/GlobalUsings.cs | 3 +-- TanksServer/Helpers/AppSerializerContext.cs | 1 + TanksServer/Helpers/PositionHelpers.cs | 2 ++ .../ServicePointDisplayConfiguration.cs | 3 ++- TanksServer/Program.cs | 12 +++++++++-- TanksServer/Servers/ClientScreenServer.cs | 1 - TanksServer/Servers/ControlsServer.cs | 1 + TanksServer/Servers/PlayerServer.cs | 8 +++---- TanksServer/Services/BulletManager.cs | 2 ++ TanksServer/Services/GameTickService.cs | 21 ++++++++++++++----- .../Services/LastFinishedFrameProvider.cs | 14 +++++++++++++ TanksServer/Services/MapService.cs | 2 ++ TanksServer/Services/SpawnQueueProvider.cs | 8 +++++++ TanksServer/Services/TankManager.cs | 2 +- TanksServer/TanksServer.csproj | 1 + .../TickSteps/CollideBulletsWithMap.cs | 2 ++ .../TickSteps/CollideBulletsWithTanks.cs | 3 +++ .../DrawStateToFrame.cs} | 21 +++++++------------ TanksServer/TickSteps/MoveBullets.cs | 3 +++ TanksServer/TickSteps/MoveTanks.cs | 3 +++ TanksServer/TickSteps/RotateTanks.cs | 3 +++ TanksServer/TickSteps/SendToClientScreen.cs | 9 ++++++-- .../TickSteps/SendToServicePointDisplay.cs | 14 ++++++++----- TanksServer/TickSteps/ShootFromTanks.cs | 3 +++ TanksServer/TickSteps/SpawnNewTanks.cs | 14 ++++--------- TanksServer/appsettings.json | 5 +++++ 29 files changed, 119 insertions(+), 46 deletions(-) create mode 100644 TanksServer/Services/LastFinishedFrameProvider.cs create mode 100644 TanksServer/Services/SpawnQueueProvider.cs rename TanksServer/{Services/PixelDrawer.cs => TickSteps/DrawStateToFrame.cs} (64%) diff --git a/TanksServer/DrawSteps/BulletDrawer.cs b/TanksServer/DrawSteps/BulletDrawer.cs index ef351c4..39e7be0 100644 --- a/TanksServer/DrawSteps/BulletDrawer.cs +++ b/TanksServer/DrawSteps/BulletDrawer.cs @@ -1,4 +1,5 @@ using TanksServer.Helpers; +using TanksServer.Services; namespace TanksServer.DrawSteps; diff --git a/TanksServer/DrawSteps/MapDrawer.cs b/TanksServer/DrawSteps/MapDrawer.cs index 246755f..56b9c9f 100644 --- a/TanksServer/DrawSteps/MapDrawer.cs +++ b/TanksServer/DrawSteps/MapDrawer.cs @@ -1,4 +1,6 @@ using TanksServer.Helpers; +using TanksServer.Models; +using TanksServer.Services; namespace TanksServer.DrawSteps; diff --git a/TanksServer/DrawSteps/TankDrawer.cs b/TanksServer/DrawSteps/TankDrawer.cs index b15818a..b4ee9b2 100644 --- a/TanksServer/DrawSteps/TankDrawer.cs +++ b/TanksServer/DrawSteps/TankDrawer.cs @@ -1,6 +1,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using TanksServer.Helpers; +using TanksServer.Services; namespace TanksServer.DrawSteps; diff --git a/TanksServer/GlobalUsings.cs b/TanksServer/GlobalUsings.cs index d18342c..d98adb0 100644 --- a/TanksServer/GlobalUsings.cs +++ b/TanksServer/GlobalUsings.cs @@ -1,8 +1,7 @@ global using System; +global using System.Collections.Concurrent; global using System.Collections.Generic; global using System.Linq; global using System.Threading; global using System.Threading.Tasks; global using Microsoft.Extensions.Options; -global using TanksServer.Models; -global using TanksServer.Services; diff --git a/TanksServer/Helpers/AppSerializerContext.cs b/TanksServer/Helpers/AppSerializerContext.cs index 0b11586..c048633 100644 --- a/TanksServer/Helpers/AppSerializerContext.cs +++ b/TanksServer/Helpers/AppSerializerContext.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using TanksServer.Models; namespace TanksServer.Helpers; diff --git a/TanksServer/Helpers/PositionHelpers.cs b/TanksServer/Helpers/PositionHelpers.cs index d599532..0a644a8 100644 --- a/TanksServer/Helpers/PositionHelpers.cs +++ b/TanksServer/Helpers/PositionHelpers.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using TanksServer.Models; +using TanksServer.Services; namespace TanksServer.Helpers; diff --git a/TanksServer/Models/ServicePointDisplayConfiguration.cs b/TanksServer/Models/ServicePointDisplayConfiguration.cs index 9ce4d6d..2d4e0e5 100644 --- a/TanksServer/Models/ServicePointDisplayConfiguration.cs +++ b/TanksServer/Models/ServicePointDisplayConfiguration.cs @@ -1,7 +1,8 @@ -namespace TanksServer.Services; +namespace TanksServer.Models; internal sealed class ServicePointDisplayConfiguration { + public bool Enable { get; set; } = true; public string Hostname { get; set; } = string.Empty; public int Port { get; set; } } diff --git a/TanksServer/Program.cs b/TanksServer/Program.cs index e033887..13d2659 100644 --- a/TanksServer/Program.cs +++ b/TanksServer/Program.cs @@ -6,7 +6,9 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using TanksServer.DrawSteps; using TanksServer.Helpers; +using TanksServer.Models; using TanksServer.Servers; +using TanksServer.Services; using TanksServer.TickSteps; namespace TanksServer; @@ -74,14 +76,17 @@ internal static class Program options.SerializerOptions.TypeInfoResolverChain.Insert(0, new AppSerializerContext()); }); + builder.Services.AddOptions(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddHostedService(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); @@ -94,7 +99,7 @@ internal static class Program builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(sp => sp.GetRequiredService()); - builder.Services.AddSingleton(sp => sp.GetRequiredService()); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -102,6 +107,9 @@ internal static class Program builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.Configure( + builder.Configuration.GetSection("ServicePointDisplay")); + return builder.Build(); } } diff --git a/TanksServer/Servers/ClientScreenServer.cs b/TanksServer/Servers/ClientScreenServer.cs index 2191668..7b7d453 100644 --- a/TanksServer/Servers/ClientScreenServer.cs +++ b/TanksServer/Servers/ClientScreenServer.cs @@ -1,4 +1,3 @@ -using System.Collections.Concurrent; using System.Diagnostics; using System.Net.WebSockets; using System.Threading.Channels; diff --git a/TanksServer/Servers/ControlsServer.cs b/TanksServer/Servers/ControlsServer.cs index 33f61e8..38058bd 100644 --- a/TanksServer/Servers/ControlsServer.cs +++ b/TanksServer/Servers/ControlsServer.cs @@ -2,6 +2,7 @@ using System.Net.WebSockets; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using TanksServer.Helpers; +using TanksServer.Models; namespace TanksServer.Servers; diff --git a/TanksServer/Servers/PlayerServer.cs b/TanksServer/Servers/PlayerServer.cs index a0113fe..80b9443 100644 --- a/TanksServer/Servers/PlayerServer.cs +++ b/TanksServer/Servers/PlayerServer.cs @@ -1,11 +1,11 @@ -using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; -using TanksServer.TickSteps; +using TanksServer.Models; +using TanksServer.Services; namespace TanksServer.Servers; -internal sealed class PlayerServer(ILogger logger, SpawnNewTanks spawnNewTanks) +internal sealed class PlayerServer(ILogger logger, SpawnQueueProvider spawnQueueProvider) { private readonly ConcurrentDictionary _players = new(); @@ -33,7 +33,7 @@ internal sealed class PlayerServer(ILogger logger, SpawnNewTanks s private Player AddAndSpawn(string name) { var player = new Player(name); - spawnNewTanks.SpawnTankForPlayer(player); + spawnQueueProvider.Queue.Enqueue(player); return player; } } diff --git a/TanksServer/Services/BulletManager.cs b/TanksServer/Services/BulletManager.cs index 05a2aa1..5e72db5 100644 --- a/TanksServer/Services/BulletManager.cs +++ b/TanksServer/Services/BulletManager.cs @@ -1,3 +1,5 @@ +using TanksServer.Models; + namespace TanksServer.Services; internal sealed class BulletManager diff --git a/TanksServer/Services/GameTickService.cs b/TanksServer/Services/GameTickService.cs index eb8f507..d21b2ca 100644 --- a/TanksServer/Services/GameTickService.cs +++ b/TanksServer/Services/GameTickService.cs @@ -1,9 +1,12 @@ using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using TanksServer.TickSteps; namespace TanksServer.Services; -internal sealed class GameTickService(IEnumerable steps) : IHostedService, IDisposable +internal sealed class GameTickService( + IEnumerable steps, IHostApplicationLifetime lifetime, ILogger logger +) : IHostedService, IDisposable { private readonly CancellationTokenSource _cancellation = new(); private readonly List _steps = steps.ToList(); @@ -17,11 +20,19 @@ internal sealed class GameTickService(IEnumerable steps) : IHostedSer private async Task RunAsync() { - while (!_cancellation.IsCancellationRequested) + try { - foreach (var step in _steps) - await step.TickAsync(); - await Task.Delay(1000/25); + while (!_cancellation.IsCancellationRequested) + { + foreach (var step in _steps) + await step.TickAsync(); + await Task.Delay(1000 / 25); + } + } + catch (Exception ex) + { + logger.LogError(ex, "game tick service crashed"); + lifetime.StopApplication(); } } diff --git a/TanksServer/Services/LastFinishedFrameProvider.cs b/TanksServer/Services/LastFinishedFrameProvider.cs new file mode 100644 index 0000000..fb9a2ef --- /dev/null +++ b/TanksServer/Services/LastFinishedFrameProvider.cs @@ -0,0 +1,14 @@ +using TanksServer.Helpers; + +namespace TanksServer.Services; + +internal sealed class LastFinishedFrameProvider +{ + private DisplayPixelBuffer? _lastFrame; + + public DisplayPixelBuffer LastFrame + { + get => _lastFrame ?? throw new InvalidOperationException("first frame not yet drawn"); + set => _lastFrame = value; + } +} diff --git a/TanksServer/Services/MapService.cs b/TanksServer/Services/MapService.cs index 3ba2bb7..25606e7 100644 --- a/TanksServer/Services/MapService.cs +++ b/TanksServer/Services/MapService.cs @@ -1,3 +1,5 @@ +using TanksServer.Models; + namespace TanksServer.Services; internal sealed class MapService diff --git a/TanksServer/Services/SpawnQueueProvider.cs b/TanksServer/Services/SpawnQueueProvider.cs new file mode 100644 index 0000000..57be6e3 --- /dev/null +++ b/TanksServer/Services/SpawnQueueProvider.cs @@ -0,0 +1,8 @@ +using TanksServer.Models; + +namespace TanksServer.Services; + +internal sealed class SpawnQueueProvider +{ + public ConcurrentQueue Queue { get; } = new(); +} diff --git a/TanksServer/Services/TankManager.cs b/TanksServer/Services/TankManager.cs index 50a5db6..b4ae7b4 100644 --- a/TanksServer/Services/TankManager.cs +++ b/TanksServer/Services/TankManager.cs @@ -1,6 +1,6 @@ using System.Collections; -using System.Collections.Concurrent; using Microsoft.Extensions.Logging; +using TanksServer.Models; namespace TanksServer.Services; diff --git a/TanksServer/TanksServer.csproj b/TanksServer/TanksServer.csproj index 6a5b5f4..059aefa 100644 --- a/TanksServer/TanksServer.csproj +++ b/TanksServer/TanksServer.csproj @@ -16,6 +16,7 @@ + diff --git a/TanksServer/TickSteps/CollideBulletsWithMap.cs b/TanksServer/TickSteps/CollideBulletsWithMap.cs index 9e16179..7f4882f 100644 --- a/TanksServer/TickSteps/CollideBulletsWithMap.cs +++ b/TanksServer/TickSteps/CollideBulletsWithMap.cs @@ -1,4 +1,6 @@ using TanksServer.Helpers; +using TanksServer.Models; +using TanksServer.Services; namespace TanksServer.TickSteps; diff --git a/TanksServer/TickSteps/CollideBulletsWithTanks.cs b/TanksServer/TickSteps/CollideBulletsWithTanks.cs index 87a5a6c..bd93f94 100644 --- a/TanksServer/TickSteps/CollideBulletsWithTanks.cs +++ b/TanksServer/TickSteps/CollideBulletsWithTanks.cs @@ -1,3 +1,6 @@ +using TanksServer.Models; +using TanksServer.Services; + namespace TanksServer.TickSteps; internal sealed class CollideBulletsWithTanks(BulletManager bullets) : ITickStep diff --git a/TanksServer/Services/PixelDrawer.cs b/TanksServer/TickSteps/DrawStateToFrame.cs similarity index 64% rename from TanksServer/Services/PixelDrawer.cs rename to TanksServer/TickSteps/DrawStateToFrame.cs index 43e3ae4..078567e 100644 --- a/TanksServer/Services/PixelDrawer.cs +++ b/TanksServer/TickSteps/DrawStateToFrame.cs @@ -1,30 +1,25 @@ using TanksServer.DrawSteps; using TanksServer.Helpers; -using TanksServer.TickSteps; +using TanksServer.Services; -namespace TanksServer.Services; +namespace TanksServer.TickSteps; -internal sealed class PixelDrawer(IEnumerable drawSteps) : ITickStep +internal sealed class DrawStateToFrame( + IEnumerable drawSteps, LastFinishedFrameProvider lastFrameProvider +) : ITickStep { private const uint GameFieldPixelCount = MapService.PixelsPerRow * MapService.PixelsPerColumn; - private DisplayPixelBuffer? _lastFrame; private readonly List _drawSteps = drawSteps.ToList(); - public DisplayPixelBuffer LastFrame - { - get => _lastFrame ?? throw new InvalidOperationException("first frame not yet drawn"); - private set => _lastFrame = value; - } - public Task TickAsync() { var buffer = CreateGameFieldPixelBuffer(); - foreach (var step in _drawSteps) + foreach (var step in _drawSteps) step.Draw(buffer); - LastFrame = buffer; + lastFrameProvider.LastFrame = buffer; return Task.CompletedTask; } - + private static DisplayPixelBuffer CreateGameFieldPixelBuffer() { var data = new byte[10 + GameFieldPixelCount / 8]; diff --git a/TanksServer/TickSteps/MoveBullets.cs b/TanksServer/TickSteps/MoveBullets.cs index be7a6aa..78dc921 100644 --- a/TanksServer/TickSteps/MoveBullets.cs +++ b/TanksServer/TickSteps/MoveBullets.cs @@ -1,3 +1,6 @@ +using TanksServer.Models; +using TanksServer.Services; + namespace TanksServer.TickSteps; internal sealed class MoveBullets(BulletManager bullets) : ITickStep diff --git a/TanksServer/TickSteps/MoveTanks.cs b/TanksServer/TickSteps/MoveTanks.cs index ad787ae..6da4eef 100644 --- a/TanksServer/TickSteps/MoveTanks.cs +++ b/TanksServer/TickSteps/MoveTanks.cs @@ -1,3 +1,6 @@ +using TanksServer.Models; +using TanksServer.Services; + namespace TanksServer.TickSteps; internal sealed class MoveTanks( diff --git a/TanksServer/TickSteps/RotateTanks.cs b/TanksServer/TickSteps/RotateTanks.cs index 00f96ea..52eccf2 100644 --- a/TanksServer/TickSteps/RotateTanks.cs +++ b/TanksServer/TickSteps/RotateTanks.cs @@ -1,3 +1,6 @@ +using TanksServer.Models; +using TanksServer.Services; + namespace TanksServer.TickSteps; internal sealed class RotateTanks(TankManager tanks, IOptions options) : ITickStep diff --git a/TanksServer/TickSteps/SendToClientScreen.cs b/TanksServer/TickSteps/SendToClientScreen.cs index 25e4e05..2c136c9 100644 --- a/TanksServer/TickSteps/SendToClientScreen.cs +++ b/TanksServer/TickSteps/SendToClientScreen.cs @@ -1,13 +1,18 @@ using TanksServer.Servers; +using TanksServer.Services; namespace TanksServer.TickSteps; internal sealed class SendToClientScreen( - ClientScreenServer clientScreenServer, PixelDrawer drawer + ClientScreenServer clientScreenServer, + LastFinishedFrameProvider lastFinishedFrameProvider ) : ITickStep { public Task TickAsync() { - return Task.WhenAll(clientScreenServer.GetConnections().Select(c => c.SendAsync(drawer.LastFrame))); + var tasks = clientScreenServer + .GetConnections() + .Select(c => c.SendAsync(lastFinishedFrameProvider.LastFrame)); + return Task.WhenAll(tasks); } } diff --git a/TanksServer/TickSteps/SendToServicePointDisplay.cs b/TanksServer/TickSteps/SendToServicePointDisplay.cs index d69aba2..1aaed8e 100644 --- a/TanksServer/TickSteps/SendToServicePointDisplay.cs +++ b/TanksServer/TickSteps/SendToServicePointDisplay.cs @@ -1,21 +1,25 @@ using System.Net.Sockets; +using TanksServer.Models; +using TanksServer.Services; namespace TanksServer.TickSteps; internal sealed class SendToServicePointDisplay( - IOptions options, - PixelDrawer drawer + IOptions options, + LastFinishedFrameProvider lastFinishedFrameProvider ) : ITickStep, IDisposable { - private readonly UdpClient _udpClient = new(options.Value.Hostname, options.Value.Port); + private readonly UdpClient? _udpClient = options.Value.Enable + ? new(options.Value.Hostname, options.Value.Port) + : null; public Task TickAsync() { - return _udpClient.SendAsync(drawer.LastFrame.Data).AsTask(); + return _udpClient?.SendAsync(lastFinishedFrameProvider.LastFrame.Data).AsTask() ?? Task.CompletedTask; } public void Dispose() { - _udpClient.Dispose(); + _udpClient?.Dispose(); } } diff --git a/TanksServer/TickSteps/ShootFromTanks.cs b/TanksServer/TickSteps/ShootFromTanks.cs index 619e5e8..02eb819 100644 --- a/TanksServer/TickSteps/ShootFromTanks.cs +++ b/TanksServer/TickSteps/ShootFromTanks.cs @@ -1,3 +1,6 @@ +using TanksServer.Models; +using TanksServer.Services; + namespace TanksServer.TickSteps; internal sealed class ShootFromTanks( diff --git a/TanksServer/TickSteps/SpawnNewTanks.cs b/TanksServer/TickSteps/SpawnNewTanks.cs index 3ebe6b8..2ab5761 100644 --- a/TanksServer/TickSteps/SpawnNewTanks.cs +++ b/TanksServer/TickSteps/SpawnNewTanks.cs @@ -1,14 +1,13 @@ -using System.Collections.Concurrent; +using TanksServer.Models; +using TanksServer.Services; namespace TanksServer.TickSteps; -internal sealed class SpawnNewTanks(TankManager tanks, MapService map) : ITickStep +internal sealed class SpawnNewTanks(TankManager tanks, MapService map, SpawnQueueProvider queueProvider) : ITickStep { - private readonly ConcurrentQueue _playersToSpawn = new(); - public Task TickAsync() { - while (_playersToSpawn.TryDequeue(out var player)) + while (queueProvider.Queue.TryDequeue(out var player)) { var tank = new Tank(player, ChooseSpawnPosition()) { @@ -42,9 +41,4 @@ internal sealed class SpawnNewTanks(TankManager tanks, MapService map) : ITickSt chosenTile.Y * MapService.TileSize ); } - - public void SpawnTankForPlayer(Player player) - { - _playersToSpawn.Enqueue(player); - } } diff --git a/TanksServer/appsettings.json b/TanksServer/appsettings.json index 11c1499..61f9680 100644 --- a/TanksServer/appsettings.json +++ b/TanksServer/appsettings.json @@ -13,5 +13,10 @@ "Url": "http://localhost:3000" } } + }, + "ServicePointDisplay": { + "Enable": false, + "Hostname": "172.23.42.29", + "Port": 2342 } }