From a9aaf899a2400fb245a016af1736729c3bb77dde Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sun, 7 Apr 2024 19:52:16 +0200 Subject: [PATCH] separate tick steps --- 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 | 3 - TanksServer/Models/FloatPosition.cs | 2 - .../ServicePointDisplayConfiguration.cs | 7 ++ TanksServer/Models/Tank.cs | 2 + TanksServer/Program.cs | 39 ++++---- .../{ => Servers}/ClientScreenServer.cs | 18 ++-- TanksServer/{ => Servers}/ControlsServer.cs | 3 +- TanksServer/{ => Servers}/PlayerServer.cs | 9 +- TanksServer/Services/BulletManager.cs | 34 +------ TanksServer/Services/GameTickService.cs | 6 +- TanksServer/Services/MapService.cs | 2 - TanksServer/Services/PixelDrawer.cs | 7 +- TanksServer/Services/TankManager.cs | 90 +------------------ .../TickSteps/CollideBulletsWithMap.cs | 17 ++++ .../TickSteps/CollideBulletsWithTanks.cs | 15 ++++ TanksServer/TickSteps/ITickStep.cs | 6 ++ TanksServer/TickSteps/MoveBullets.cs | 21 +++++ TanksServer/TickSteps/MoveTanks.cs | 60 +++++++++++++ TanksServer/TickSteps/RotateTanks.cs | 21 +++++ TanksServer/TickSteps/SendToClientScreen.cs | 13 +++ .../SendToServicePointDisplay.cs} | 11 +-- TanksServer/TickSteps/ShootFromTanks.cs | 34 +++++++ .../SpawnNewTanks.cs} | 5 +- 28 files changed, 239 insertions(+), 194 deletions(-) create mode 100644 TanksServer/Models/ServicePointDisplayConfiguration.cs rename TanksServer/{ => Servers}/ClientScreenServer.cs (89%) rename TanksServer/{ => Servers}/ControlsServer.cs (98%) rename TanksServer/{ => Servers}/PlayerServer.cs (86%) create mode 100644 TanksServer/TickSteps/CollideBulletsWithMap.cs create mode 100644 TanksServer/TickSteps/CollideBulletsWithTanks.cs create mode 100644 TanksServer/TickSteps/ITickStep.cs create mode 100644 TanksServer/TickSteps/MoveBullets.cs create mode 100644 TanksServer/TickSteps/MoveTanks.cs create mode 100644 TanksServer/TickSteps/RotateTanks.cs create mode 100644 TanksServer/TickSteps/SendToClientScreen.cs rename TanksServer/{Services/ServicePointDisplay.cs => TickSteps/SendToServicePointDisplay.cs} (61%) create mode 100644 TanksServer/TickSteps/ShootFromTanks.cs rename TanksServer/{Services/SpawnQueue.cs => TickSteps/SpawnNewTanks.cs} (89%) diff --git a/TanksServer/DrawSteps/BulletDrawer.cs b/TanksServer/DrawSteps/BulletDrawer.cs index 39e7be0..ef351c4 100644 --- a/TanksServer/DrawSteps/BulletDrawer.cs +++ b/TanksServer/DrawSteps/BulletDrawer.cs @@ -1,5 +1,4 @@ using TanksServer.Helpers; -using TanksServer.Services; namespace TanksServer.DrawSteps; diff --git a/TanksServer/DrawSteps/MapDrawer.cs b/TanksServer/DrawSteps/MapDrawer.cs index 56b9c9f..246755f 100644 --- a/TanksServer/DrawSteps/MapDrawer.cs +++ b/TanksServer/DrawSteps/MapDrawer.cs @@ -1,6 +1,4 @@ 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 b4ee9b2..b15818a 100644 --- a/TanksServer/DrawSteps/TankDrawer.cs +++ b/TanksServer/DrawSteps/TankDrawer.cs @@ -1,7 +1,6 @@ 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 3e07978..d18342c 100644 --- a/TanksServer/GlobalUsings.cs +++ b/TanksServer/GlobalUsings.cs @@ -3,3 +3,6 @@ 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 c048633..0b11586 100644 --- a/TanksServer/Helpers/AppSerializerContext.cs +++ b/TanksServer/Helpers/AppSerializerContext.cs @@ -1,5 +1,4 @@ using System.Text.Json.Serialization; -using TanksServer.Models; namespace TanksServer.Helpers; diff --git a/TanksServer/Helpers/PositionHelpers.cs b/TanksServer/Helpers/PositionHelpers.cs index 55e2bc1..d599532 100644 --- a/TanksServer/Helpers/PositionHelpers.cs +++ b/TanksServer/Helpers/PositionHelpers.cs @@ -1,7 +1,4 @@ using System.Diagnostics; -using System.Runtime.CompilerServices; -using TanksServer.Models; -using TanksServer.Services; namespace TanksServer.Helpers; diff --git a/TanksServer/Models/FloatPosition.cs b/TanksServer/Models/FloatPosition.cs index 0f47879..b4763df 100644 --- a/TanksServer/Models/FloatPosition.cs +++ b/TanksServer/Models/FloatPosition.cs @@ -1,5 +1,3 @@ -using TanksServer.Services; - namespace TanksServer.Models; internal readonly record struct FloatPosition(double X, double Y) diff --git a/TanksServer/Models/ServicePointDisplayConfiguration.cs b/TanksServer/Models/ServicePointDisplayConfiguration.cs new file mode 100644 index 0000000..9ce4d6d --- /dev/null +++ b/TanksServer/Models/ServicePointDisplayConfiguration.cs @@ -0,0 +1,7 @@ +namespace TanksServer.Services; + +internal sealed class ServicePointDisplayConfiguration +{ + public string Hostname { get; set; } = string.Empty; + public int Port { get; set; } +} diff --git a/TanksServer/Models/Tank.cs b/TanksServer/Models/Tank.cs index f3e59b0..9c2a8a4 100644 --- a/TanksServer/Models/Tank.cs +++ b/TanksServer/Models/Tank.cs @@ -18,4 +18,6 @@ internal sealed class Tank(Player player, FloatPosition spawnPosition) public FloatPosition Position { get; set; } = spawnPosition; public DateTime NextShotAfter { get; set; } + + public bool Moved { get; set; } } diff --git a/TanksServer/Program.cs b/TanksServer/Program.cs index 3495f00..e033887 100644 --- a/TanksServer/Program.cs +++ b/TanksServer/Program.cs @@ -6,7 +6,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using TanksServer.DrawSteps; using TanksServer.Helpers; -using TanksServer.Services; +using TanksServer.Servers; +using TanksServer.TickSteps; namespace TanksServer; @@ -73,31 +74,29 @@ internal static class Program options.SerializerOptions.TypeInfoResolverChain.Insert(0, new AppSerializerContext()); }); - 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.AddSingleton(); - builder.Services.AddSingleton(sp => sp.GetRequiredService()); - - builder.Services.AddSingleton(); - builder.Services.AddSingleton(sp => sp.GetRequiredService()); - - builder.Services.AddSingleton(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); - - builder.Services.AddSingleton(); - builder.Services.AddSingleton(sp => sp.GetRequiredService()); - - builder.Services.AddSingleton(); - builder.Services.AddSingleton(sp => sp.GetRequiredService()); - - builder.Services.AddSingleton(); builder.Services.AddHostedService(sp => sp.GetRequiredService()); - builder.Services.AddSingleton(sp => sp.GetRequiredService()); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + 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(); builder.Services.AddSingleton(); diff --git a/TanksServer/ClientScreenServer.cs b/TanksServer/Servers/ClientScreenServer.cs similarity index 89% rename from TanksServer/ClientScreenServer.cs rename to TanksServer/Servers/ClientScreenServer.cs index 62513c4..2191668 100644 --- a/TanksServer/ClientScreenServer.cs +++ b/TanksServer/Servers/ClientScreenServer.cs @@ -5,15 +5,13 @@ using System.Threading.Channels; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using TanksServer.Helpers; -using TanksServer.Services; -namespace TanksServer; +namespace TanksServer.Servers; internal sealed class ClientScreenServer( ILogger logger, - ILoggerFactory loggerFactory, - PixelDrawer drawer -) : IHostedLifecycleService, ITickStep + ILoggerFactory loggerFactory +) : IHostedLifecycleService { private readonly ConcurrentDictionary _connections = new(); private bool _closing; @@ -41,12 +39,6 @@ internal sealed class ClientScreenServer( return Task.WhenAll(_connections.Keys.Select(c => c.CloseAsync())); } - public Task TickAsync() - { - logger.LogTrace("Sending buffer to {} clients", _connections.Count); - return Task.WhenAll(_connections.Keys.Select(c => c.SendAsync(drawer.LastFrame))); - } - public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StartedAsync(CancellationToken cancellationToken) => Task.CompletedTask; @@ -54,8 +46,10 @@ internal sealed class ClientScreenServer( public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask; private void Remove(ClientScreenServerConnection connection) => _connections.TryRemove(connection, out _); + + public IEnumerable GetConnections() => _connections.Keys; - private sealed class ClientScreenServerConnection: IDisposable + internal sealed class ClientScreenServerConnection: IDisposable { private readonly ByteChannelWebSocket _channel; private readonly SemaphoreSlim _wantedFrames = new(1); diff --git a/TanksServer/ControlsServer.cs b/TanksServer/Servers/ControlsServer.cs similarity index 98% rename from TanksServer/ControlsServer.cs rename to TanksServer/Servers/ControlsServer.cs index 8f5d250..33f61e8 100644 --- a/TanksServer/ControlsServer.cs +++ b/TanksServer/Servers/ControlsServer.cs @@ -2,9 +2,8 @@ using System.Net.WebSockets; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using TanksServer.Helpers; -using TanksServer.Models; -namespace TanksServer; +namespace TanksServer.Servers; internal sealed class ControlsServer(ILogger logger, ILoggerFactory loggerFactory) : IHostedLifecycleService diff --git a/TanksServer/PlayerServer.cs b/TanksServer/Servers/PlayerServer.cs similarity index 86% rename from TanksServer/PlayerServer.cs rename to TanksServer/Servers/PlayerServer.cs index 06e6c2f..a0113fe 100644 --- a/TanksServer/PlayerServer.cs +++ b/TanksServer/Servers/PlayerServer.cs @@ -1,12 +1,11 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; -using TanksServer.Models; -using TanksServer.Services; +using TanksServer.TickSteps; -namespace TanksServer; +namespace TanksServer.Servers; -internal sealed class PlayerServer(ILogger logger, SpawnQueue spawnQueue) +internal sealed class PlayerServer(ILogger logger, SpawnNewTanks spawnNewTanks) { private readonly ConcurrentDictionary _players = new(); @@ -34,7 +33,7 @@ internal sealed class PlayerServer(ILogger logger, SpawnQueue spaw private Player AddAndSpawn(string name) { var player = new Player(name); - spawnQueue.SpawnTankForPlayer(player); + spawnNewTanks.SpawnTankForPlayer(player); return player; } } diff --git a/TanksServer/Services/BulletManager.cs b/TanksServer/Services/BulletManager.cs index 5752668..05a2aa1 100644 --- a/TanksServer/Services/BulletManager.cs +++ b/TanksServer/Services/BulletManager.cs @@ -1,10 +1,6 @@ -using System.Collections; -using TanksServer.Helpers; -using TanksServer.Models; - namespace TanksServer.Services; -internal sealed class BulletManager(MapService map) : ITickStep +internal sealed class BulletManager { private readonly HashSet _bullets = new(); @@ -12,32 +8,8 @@ internal sealed class BulletManager(MapService map) : ITickStep public IEnumerable GetAll() => _bullets; - public Task TickAsync() + public void RemoveWhere(Predicate predicate) { - HashSet bulletsToRemove = new(); - foreach (var bullet in _bullets) - { - MoveBullet(bullet); - - if (BulletHitsWall(bullet)) - bulletsToRemove.Add(bullet); - } - - _bullets.RemoveWhere(b => bulletsToRemove.Contains(b)); - return Task.CompletedTask; - } - - private static void MoveBullet(Bullet bullet) - { - var angle = bullet.Rotation / 16 * 2 * Math.PI; - bullet.Position = new FloatPosition( - X: bullet.Position.X + Math.Sin(angle) * 3, - Y: bullet.Position.Y - Math.Cos(angle) * 3 - ); - } - - private bool BulletHitsWall(Bullet bullet) - { - return map.IsCurrentlyWall(bullet.Position.ToPixelPosition().ToTilePosition()); + _bullets.RemoveWhere(predicate); } } diff --git a/TanksServer/Services/GameTickService.cs b/TanksServer/Services/GameTickService.cs index 93406ca..eb8f507 100644 --- a/TanksServer/Services/GameTickService.cs +++ b/TanksServer/Services/GameTickService.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Hosting; +using TanksServer.TickSteps; namespace TanksServer.Services; @@ -36,8 +37,3 @@ internal sealed class GameTickService(IEnumerable steps) : IHostedSer _run?.Dispose(); } } - -public interface ITickStep -{ - Task TickAsync(); -} diff --git a/TanksServer/Services/MapService.cs b/TanksServer/Services/MapService.cs index 25606e7..3ba2bb7 100644 --- a/TanksServer/Services/MapService.cs +++ b/TanksServer/Services/MapService.cs @@ -1,5 +1,3 @@ -using TanksServer.Models; - namespace TanksServer.Services; internal sealed class MapService diff --git a/TanksServer/Services/PixelDrawer.cs b/TanksServer/Services/PixelDrawer.cs index 865d695..43e3ae4 100644 --- a/TanksServer/Services/PixelDrawer.cs +++ b/TanksServer/Services/PixelDrawer.cs @@ -1,11 +1,6 @@ -using System.Diagnostics; -using System.Net.Mime; -using Microsoft.Extensions.Logging; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; using TanksServer.DrawSteps; using TanksServer.Helpers; -using TanksServer.Models; +using TanksServer.TickSteps; namespace TanksServer.Services; diff --git a/TanksServer/Services/TankManager.cs b/TanksServer/Services/TankManager.cs index 78e0379..50a5db6 100644 --- a/TanksServer/Services/TankManager.cs +++ b/TanksServer/Services/TankManager.cs @@ -1,20 +1,12 @@ using System.Collections; using System.Collections.Concurrent; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using TanksServer.Models; namespace TanksServer.Services; -internal sealed class TankManager( - ILogger logger, - IOptions options, - MapService map, - BulletManager bullets -) : ITickStep, IEnumerable +internal sealed class TankManager(ILogger logger) : IEnumerable { private readonly ConcurrentBag _tanks = new(); - private readonly TanksConfiguration _config = options.Value; public void Add(Tank tank) { @@ -22,86 +14,6 @@ internal sealed class TankManager( _tanks.Add(tank); } - public Task TickAsync() - { - foreach (var tank in _tanks) - { - if (TryMoveTank(tank)) - continue; - Shoot(tank); - } - - return Task.CompletedTask; - } - - private bool TryMoveTank(Tank tank) - { - logger.LogTrace("moving tank for player {}", tank.Owner.Id); - var player = tank.Owner; - - if (player.Controls.TurnLeft) - tank.Rotation -= _config.TurnSpeed; - if (player.Controls.TurnRight) - tank.Rotation += _config.TurnSpeed; - - double speed; - switch (player.Controls) - { - case { Forward: false, Backward: false }: - case { Forward: true, Backward: true }: - return false; - case { Forward: true }: - speed = +_config.MoveSpeed; - break; - case { Backward: true }: - speed = -_config.MoveSpeed; - break; - default: - return false; - } - - var angle = tank.Rotation / 16d * 2d * Math.PI; - var newX = tank.Position.X + Math.Sin(angle) * speed; - var newY = tank.Position.Y - Math.Cos(angle) * speed; - - return TryMove(tank, new FloatPosition(newX, newY)) - || TryMove(tank, tank.Position with { X = newX }) - || TryMove(tank, tank.Position with { Y = newY }); - } - - private bool TryMove(Tank tank, FloatPosition newPosition) - { - var x0 = (int)Math.Floor(newPosition.X / MapService.TileSize); - var x1 = (int)Math.Ceiling(newPosition.X / MapService.TileSize); - var y0 = (int)Math.Floor(newPosition.Y / MapService.TileSize); - var y1 = (int)Math.Ceiling(newPosition.Y / MapService.TileSize); - - TilePosition[] positions = { new(x0, y0), new(x0, y1), new(x1, y0), new(x1, y1) }; - if (positions.Any(map.IsCurrentlyWall)) - return false; - - tank.Position = newPosition; - return true; - } - - private void Shoot(Tank tank) - { - if (!tank.Owner.Controls.Shoot) - return; - if (tank.NextShotAfter >= DateTime.Now) - return; - - tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs); - - var angle = tank.Rotation / 16 * 2 * Math.PI; - var position = new FloatPosition( - X: tank.Position.X + MapService.TileSize / 2d + Math.Sin(angle) * _config.BulletSpeed, - Y: tank.Position.Y + MapService.TileSize / 2d - Math.Cos(angle) * _config.BulletSpeed - ); - - bullets.Spawn(new Bullet(tank.Owner, position, tank.Rotation)); - } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() => _tanks.GetEnumerator(); } diff --git a/TanksServer/TickSteps/CollideBulletsWithMap.cs b/TanksServer/TickSteps/CollideBulletsWithMap.cs new file mode 100644 index 0000000..9e16179 --- /dev/null +++ b/TanksServer/TickSteps/CollideBulletsWithMap.cs @@ -0,0 +1,17 @@ +using TanksServer.Helpers; + +namespace TanksServer.TickSteps; + +internal sealed class CollideBulletsWithMap(BulletManager bullets, MapService map) : ITickStep +{ + public Task TickAsync() + { + bullets.RemoveWhere(BulletHitsWall); + return Task.CompletedTask; + } + + private bool BulletHitsWall(Bullet bullet) + { + return map.IsCurrentlyWall(bullet.Position.ToPixelPosition().ToTilePosition()); + } +} diff --git a/TanksServer/TickSteps/CollideBulletsWithTanks.cs b/TanksServer/TickSteps/CollideBulletsWithTanks.cs new file mode 100644 index 0000000..87a5a6c --- /dev/null +++ b/TanksServer/TickSteps/CollideBulletsWithTanks.cs @@ -0,0 +1,15 @@ +namespace TanksServer.TickSteps; + +internal sealed class CollideBulletsWithTanks(BulletManager bullets) : ITickStep +{ + public Task TickAsync() + { + bullets.RemoveWhere(BulletHitsTank); + return Task.CompletedTask; + } + + private bool BulletHitsTank(Bullet bullet) + { + return false; // TODO + } +} diff --git a/TanksServer/TickSteps/ITickStep.cs b/TanksServer/TickSteps/ITickStep.cs new file mode 100644 index 0000000..960c06e --- /dev/null +++ b/TanksServer/TickSteps/ITickStep.cs @@ -0,0 +1,6 @@ +namespace TanksServer.TickSteps; + +public interface ITickStep +{ + Task TickAsync(); +} diff --git a/TanksServer/TickSteps/MoveBullets.cs b/TanksServer/TickSteps/MoveBullets.cs new file mode 100644 index 0000000..be7a6aa --- /dev/null +++ b/TanksServer/TickSteps/MoveBullets.cs @@ -0,0 +1,21 @@ +namespace TanksServer.TickSteps; + +internal sealed class MoveBullets(BulletManager bullets) : ITickStep +{ + public Task TickAsync() + { + foreach (var bullet in bullets.GetAll()) + MoveBullet(bullet); + + return Task.CompletedTask; + } + + private static void MoveBullet(Bullet bullet) + { + var angle = bullet.Rotation / 16 * 2 * Math.PI; + bullet.Position = new FloatPosition( + X: bullet.Position.X + Math.Sin(angle) * 3, + Y: bullet.Position.Y - Math.Cos(angle) * 3 + ); + } +} diff --git a/TanksServer/TickSteps/MoveTanks.cs b/TanksServer/TickSteps/MoveTanks.cs new file mode 100644 index 0000000..ad787ae --- /dev/null +++ b/TanksServer/TickSteps/MoveTanks.cs @@ -0,0 +1,60 @@ +namespace TanksServer.TickSteps; + +internal sealed class MoveTanks( + TankManager tanks, IOptions options, MapService map +) : ITickStep +{ + private readonly TanksConfiguration _config = options.Value; + + public Task TickAsync() + { + foreach (var tank in tanks) + tank.Moved = TryMoveTank(tank); + + return Task.CompletedTask; + } + + private bool TryMoveTank(Tank tank) + { + var player = tank.Owner; + + double speed; + switch (player.Controls) + { + case { Forward: false, Backward: false }: + case { Forward: true, Backward: true }: + return false; + case { Forward: true }: + speed = +_config.MoveSpeed; + break; + case { Backward: true }: + speed = -_config.MoveSpeed; + break; + default: + return false; + } + + var angle = tank.Rotation / 16d * 2d * Math.PI; + var newX = tank.Position.X + Math.Sin(angle) * speed; + var newY = tank.Position.Y - Math.Cos(angle) * speed; + + return TryMoveTankTo(tank, new FloatPosition(newX, newY)) + || TryMoveTankTo(tank, tank.Position with { X = newX }) + || TryMoveTankTo(tank, tank.Position with { Y = newY }); + } + + private bool TryMoveTankTo(Tank tank, FloatPosition newPosition) + { + var x0 = (int)Math.Floor(newPosition.X / MapService.TileSize); + var x1 = (int)Math.Ceiling(newPosition.X / MapService.TileSize); + var y0 = (int)Math.Floor(newPosition.Y / MapService.TileSize); + var y1 = (int)Math.Ceiling(newPosition.Y / MapService.TileSize); + + TilePosition[] positions = { new(x0, y0), new(x0, y1), new(x1, y0), new(x1, y1) }; + if (positions.Any(map.IsCurrentlyWall)) + return false; + + tank.Position = newPosition; + return true; + } +} diff --git a/TanksServer/TickSteps/RotateTanks.cs b/TanksServer/TickSteps/RotateTanks.cs new file mode 100644 index 0000000..00f96ea --- /dev/null +++ b/TanksServer/TickSteps/RotateTanks.cs @@ -0,0 +1,21 @@ +namespace TanksServer.TickSteps; + +internal sealed class RotateTanks(TankManager tanks, IOptions options) : ITickStep +{ + private readonly TanksConfiguration _config = options.Value; + + public Task TickAsync() + { + foreach (var tank in tanks) + { + var player = tank.Owner; + + if (player.Controls.TurnLeft) + tank.Rotation -= _config.TurnSpeed; + if (player.Controls.TurnRight) + tank.Rotation += _config.TurnSpeed; + } + + return Task.CompletedTask; + } +} diff --git a/TanksServer/TickSteps/SendToClientScreen.cs b/TanksServer/TickSteps/SendToClientScreen.cs new file mode 100644 index 0000000..25e4e05 --- /dev/null +++ b/TanksServer/TickSteps/SendToClientScreen.cs @@ -0,0 +1,13 @@ +using TanksServer.Servers; + +namespace TanksServer.TickSteps; + +internal sealed class SendToClientScreen( + ClientScreenServer clientScreenServer, PixelDrawer drawer +) : ITickStep +{ + public Task TickAsync() + { + return Task.WhenAll(clientScreenServer.GetConnections().Select(c => c.SendAsync(drawer.LastFrame))); + } +} diff --git a/TanksServer/Services/ServicePointDisplay.cs b/TanksServer/TickSteps/SendToServicePointDisplay.cs similarity index 61% rename from TanksServer/Services/ServicePointDisplay.cs rename to TanksServer/TickSteps/SendToServicePointDisplay.cs index ebb5502..d69aba2 100644 --- a/TanksServer/Services/ServicePointDisplay.cs +++ b/TanksServer/TickSteps/SendToServicePointDisplay.cs @@ -1,9 +1,8 @@ using System.Net.Sockets; -using Microsoft.Extensions.Options; -namespace TanksServer.Services; +namespace TanksServer.TickSteps; -internal sealed class ServicePointDisplay( +internal sealed class SendToServicePointDisplay( IOptions options, PixelDrawer drawer ) : ITickStep, IDisposable @@ -20,9 +19,3 @@ internal sealed class ServicePointDisplay( _udpClient.Dispose(); } } - -internal sealed class ServicePointDisplayConfiguration -{ - public string Hostname { get; set; } = string.Empty; - public int Port { get; set; } -} diff --git a/TanksServer/TickSteps/ShootFromTanks.cs b/TanksServer/TickSteps/ShootFromTanks.cs new file mode 100644 index 0000000..619e5e8 --- /dev/null +++ b/TanksServer/TickSteps/ShootFromTanks.cs @@ -0,0 +1,34 @@ +namespace TanksServer.TickSteps; + +internal sealed class ShootFromTanks( + TankManager tanks, IOptions options, BulletManager bulletManager +) : ITickStep +{ + private readonly TanksConfiguration _config = options.Value; + + public Task TickAsync() + { + foreach (var tank in tanks.Where(t => !t.Moved)) + Shoot(tank); + + return Task.CompletedTask; + } + + private void Shoot(Tank tank) + { + if (!tank.Owner.Controls.Shoot) + return; + if (tank.NextShotAfter >= DateTime.Now) + return; + + tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs); + + var angle = tank.Rotation / 16 * 2 * Math.PI; + var position = new FloatPosition( + X: tank.Position.X + MapService.TileSize / 2d + Math.Sin(angle) * _config.BulletSpeed, + Y: tank.Position.Y + MapService.TileSize / 2d - Math.Cos(angle) * _config.BulletSpeed + ); + + bulletManager.Spawn(new Bullet(tank.Owner, position, tank.Rotation)); + } +} diff --git a/TanksServer/Services/SpawnQueue.cs b/TanksServer/TickSteps/SpawnNewTanks.cs similarity index 89% rename from TanksServer/Services/SpawnQueue.cs rename to TanksServer/TickSteps/SpawnNewTanks.cs index 4f7ead1..3ebe6b8 100644 --- a/TanksServer/Services/SpawnQueue.cs +++ b/TanksServer/TickSteps/SpawnNewTanks.cs @@ -1,9 +1,8 @@ using System.Collections.Concurrent; -using TanksServer.Models; -namespace TanksServer.Services; +namespace TanksServer.TickSteps; -internal sealed class SpawnQueue(TankManager tanks, MapService map) : ITickStep +internal sealed class SpawnNewTanks(TankManager tanks, MapService map) : ITickStep { private readonly ConcurrentQueue _playersToSpawn = new();