From d4d0abd013ec4a06fa51a18cdd0a5b6796544a92 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sat, 13 Apr 2024 14:07:14 +0200 Subject: [PATCH] position is now center, socket improvements --- .../GameLogic/CollideBulletsWithTanks.cs | 6 +- TanksServer/GameLogic/MoveTanks.cs | 11 ++- TanksServer/GameLogic/ShootFromTanks.cs | 6 +- TanksServer/GameLogic/SpawnNewTanks.cs | 7 +- TanksServer/GameLogic/TankManager.cs | 10 +-- TanksServer/Graphics/BulletDrawer.cs | 16 ----- TanksServer/Graphics/DrawBulletsStep.cs | 13 ++++ .../Graphics/{MapDrawer.cs => DrawMapStep.cs} | 4 +- .../{TankDrawer.cs => DrawTanksStep.cs} | 10 ++- ...teToFrame.cs => GeneratePixelsTickStep.cs} | 5 +- .../Interactivity/ByteChannelWebSocket.cs | 70 ++++++++++++------- TanksServer/Models/Bullet.cs | 12 ++-- TanksServer/Models/IMapEntity.cs | 4 +- TanksServer/Models/PixelBounds.cs | 3 + TanksServer/Models/PositionHelpers.cs | 23 +++--- TanksServer/Models/Tank.cs | 18 ++++- TanksServer/Program.cs | 8 +-- TanksServer/TanksServer.csproj | 14 ++-- 18 files changed, 134 insertions(+), 106 deletions(-) delete mode 100644 TanksServer/Graphics/BulletDrawer.cs create mode 100644 TanksServer/Graphics/DrawBulletsStep.cs rename TanksServer/Graphics/{MapDrawer.cs => DrawMapStep.cs} (92%) rename TanksServer/Graphics/{TankDrawer.cs => DrawTanksStep.cs} (90%) rename TanksServer/Graphics/{DrawStateToFrame.cs => GeneratePixelsTickStep.cs} (77%) create mode 100644 TanksServer/Models/PixelBounds.cs diff --git a/TanksServer/GameLogic/CollideBulletsWithTanks.cs b/TanksServer/GameLogic/CollideBulletsWithTanks.cs index 7ccafd0..b62ac95 100644 --- a/TanksServer/GameLogic/CollideBulletsWithTanks.cs +++ b/TanksServer/GameLogic/CollideBulletsWithTanks.cs @@ -1,7 +1,9 @@ namespace TanksServer.GameLogic; internal sealed class CollideBulletsWithTanks( - BulletManager bullets, TankManager tanks, SpawnQueue spawnQueue + BulletManager bullets, + TankManager tanks, + SpawnQueue spawnQueue ) : ITickStep { public Task TickAsync() @@ -14,7 +16,7 @@ internal sealed class CollideBulletsWithTanks( { foreach (var tank in tanks) { - var (topLeft, bottomRight) = TankManager.GetTankBounds(tank.Position.ToPixelPosition()); + var (topLeft, bottomRight) = tank.Bounds; if (bullet.Position.X < topLeft.X || bullet.Position.X > bottomRight.X || bullet.Position.Y < topLeft.Y || bullet.Position.Y > bottomRight.Y) continue; diff --git a/TanksServer/GameLogic/MoveTanks.cs b/TanksServer/GameLogic/MoveTanks.cs index d10cd3b..c77c0d1 100644 --- a/TanksServer/GameLogic/MoveTanks.cs +++ b/TanksServer/GameLogic/MoveTanks.cs @@ -47,9 +47,7 @@ internal sealed class MoveTanks( private bool TryMoveTankTo(Tank tank, FloatPosition newPosition) { - var (topLeft, bottomRight) = TankManager.GetTankBounds(newPosition.ToPixelPosition()); - - if (HitsWall(topLeft, bottomRight)) + if (HitsWall(newPosition)) return false; if (HitsTank(tank, newPosition)) return false; @@ -63,15 +61,16 @@ internal sealed class MoveTanks( .Where(otherTank => otherTank != tank) .Any(otherTank => newPosition.Distance(otherTank.Position) < MapService.TileSize); - private bool HitsWall(PixelPosition topLeft, PixelPosition bottomRight) + private bool HitsWall(FloatPosition newPosition) { + var (topLeft, bottomRight) = Tank.GetBoundsForCenter(newPosition); TilePosition[] positions = [ topLeft.ToTilePosition(), new PixelPosition(bottomRight.X, topLeft.Y).ToTilePosition(), new PixelPosition(topLeft.X, bottomRight.Y).ToTilePosition(), - bottomRight.ToTilePosition(), + bottomRight.ToTilePosition() ]; return positions.Any(map.IsCurrentlyWall); } -} \ No newline at end of file +} diff --git a/TanksServer/GameLogic/ShootFromTanks.cs b/TanksServer/GameLogic/ShootFromTanks.cs index 22c243d..4597f7f 100644 --- a/TanksServer/GameLogic/ShootFromTanks.cs +++ b/TanksServer/GameLogic/ShootFromTanks.cs @@ -27,10 +27,10 @@ internal sealed class ShootFromTanks( var angle = tank.Rotation * 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 + tank.Position.X + Math.Sin(angle) * _config.BulletSpeed, + tank.Position.Y - Math.Cos(angle) * _config.BulletSpeed ); bulletManager.Spawn(new Bullet(tank.Owner, position, tank.Rotation)); } -} \ No newline at end of file +} diff --git a/TanksServer/GameLogic/SpawnNewTanks.cs b/TanksServer/GameLogic/SpawnNewTanks.cs index 42d0dc1..a5455ff 100644 --- a/TanksServer/GameLogic/SpawnNewTanks.cs +++ b/TanksServer/GameLogic/SpawnNewTanks.cs @@ -44,9 +44,6 @@ internal sealed class SpawnNewTanks( } var min = candidates.MaxBy(kvp => kvp.Value).Key; - return new FloatPosition( - min.X * MapService.TileSize, - min.Y * MapService.TileSize - ); + return min.ToPixelPosition().GetPixelRelative(4, 4).ToFloatPosition(); } -} \ No newline at end of file +} diff --git a/TanksServer/GameLogic/TankManager.cs b/TanksServer/GameLogic/TankManager.cs index c22eb55..a8cd345 100644 --- a/TanksServer/GameLogic/TankManager.cs +++ b/TanksServer/GameLogic/TankManager.cs @@ -20,12 +20,4 @@ internal sealed class TankManager(ILogger logger) : IEnumerable b.Position.ToPixelPosition())) + buffer[position.X, position.Y] = true; + } +} diff --git a/TanksServer/Graphics/MapDrawer.cs b/TanksServer/Graphics/DrawMapStep.cs similarity index 92% rename from TanksServer/Graphics/MapDrawer.cs rename to TanksServer/Graphics/DrawMapStep.cs index 37d36bd..63e593d 100644 --- a/TanksServer/Graphics/MapDrawer.cs +++ b/TanksServer/Graphics/DrawMapStep.cs @@ -3,7 +3,7 @@ using TanksServer.GameLogic; namespace TanksServer.Graphics; -internal sealed class MapDrawer(MapService map) : IDrawStep +internal sealed class DrawMapStep(MapService map) : IDrawStep { public void Draw(PixelGrid buffer) { @@ -22,4 +22,4 @@ internal sealed class MapDrawer(MapService map) : IDrawStep } } } -} \ No newline at end of file +} diff --git a/TanksServer/Graphics/TankDrawer.cs b/TanksServer/Graphics/DrawTanksStep.cs similarity index 90% rename from TanksServer/Graphics/TankDrawer.cs rename to TanksServer/Graphics/DrawTanksStep.cs index 4c1cf5c..d3185d8 100644 --- a/TanksServer/Graphics/TankDrawer.cs +++ b/TanksServer/Graphics/DrawTanksStep.cs @@ -5,13 +5,13 @@ using TanksServer.GameLogic; namespace TanksServer.Graphics; -internal sealed class TankDrawer : IDrawStep +internal sealed class DrawTanksStep : IDrawStep { private readonly TankManager _tanks; private readonly bool[] _tankSprite; private readonly int _tankSpriteWidth; - public TankDrawer(TankManager tanks) + public DrawTanksStep(TankManager tanks) { _tanks = tanks; @@ -22,9 +22,7 @@ internal sealed class TankDrawer : IDrawStep var i = 0; for (var y = 0; y < tankImage.Height; y++) for (var x = 0; x < tankImage.Width; x++, i++) - { _tankSprite[i] = tankImage[x, y] == whitePixel; - } _tankSpriteWidth = tankImage.Width; } @@ -33,7 +31,7 @@ internal sealed class TankDrawer : IDrawStep { foreach (var tank in _tanks) { - var tankPosition = tank.Position.ToPixelPosition(); + var tankPosition = tank.Bounds.TopLeft; var orientation = (int)Math.Round(tank.Rotation * 16d) % 16; for (byte dy = 0; dy < MapService.TileSize; dy++) @@ -56,4 +54,4 @@ internal sealed class TankDrawer : IDrawStep return _tankSprite[index]; } -} \ No newline at end of file +} diff --git a/TanksServer/Graphics/DrawStateToFrame.cs b/TanksServer/Graphics/GeneratePixelsTickStep.cs similarity index 77% rename from TanksServer/Graphics/DrawStateToFrame.cs rename to TanksServer/Graphics/GeneratePixelsTickStep.cs index d633b63..442ce83 100644 --- a/TanksServer/Graphics/DrawStateToFrame.cs +++ b/TanksServer/Graphics/GeneratePixelsTickStep.cs @@ -3,8 +3,9 @@ using TanksServer.GameLogic; namespace TanksServer.Graphics; -internal sealed class DrawStateToFrame( - IEnumerable drawSteps, LastFinishedFrameProvider lastFrameProvider +internal sealed class GeneratePixelsTickStep( + IEnumerable drawSteps, + LastFinishedFrameProvider lastFrameProvider ) : ITickStep { private readonly List _drawSteps = drawSteps.ToList(); diff --git a/TanksServer/Interactivity/ByteChannelWebSocket.cs b/TanksServer/Interactivity/ByteChannelWebSocket.cs index dead8fd..a0ea688 100644 --- a/TanksServer/Interactivity/ByteChannelWebSocket.cs +++ b/TanksServer/Interactivity/ByteChannelWebSocket.cs @@ -12,30 +12,10 @@ internal sealed class ByteChannelWebSocket(WebSocket socket, ILogger logger, int public async IAsyncEnumerable> ReadAllAsync() { - while (true) + while (socket.State is WebSocketState.Open or WebSocketState.CloseSent) { - if (socket.State is not (WebSocketState.Open or WebSocketState.CloseSent)) - break; - - var response = await socket.ReceiveAsync(_buffer, CancellationToken.None); - if (response.MessageType == WebSocketMessageType.Close) - { - if (socket.State == WebSocketState.CloseReceived) - await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, - CancellationToken.None); - break; - } - - if (response.Count != _buffer.Length) - { - await socket.CloseOutputAsync( - WebSocketCloseStatus.InvalidPayloadData, - "response has unexpected size", - CancellationToken.None); - break; - } - - yield return _buffer.ToArray(); + if (await TryReadAsync()) + yield return _buffer.ToArray(); } if (socket.State != WebSocketState.Closed) @@ -44,7 +24,45 @@ internal sealed class ByteChannelWebSocket(WebSocket socket, ILogger logger, int public async Task CloseAsync() { - logger.LogDebug("closing socket"); - await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); + if (socket.State != WebSocketState.Open) + return; + + try + { + await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); + } + catch (WebSocketException socketException) + { + logger.LogDebug(socketException, "could not close socket properly"); + } } -} \ No newline at end of file + + private async Task TryReadAsync() + { + try + { + var response = await socket.ReceiveAsync(_buffer, CancellationToken.None); + if (response.MessageType == WebSocketMessageType.Close) + { + await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, + CancellationToken.None); + return false; + } + + if (response.Count != _buffer.Length) + { + await socket.CloseOutputAsync(WebSocketCloseStatus.InvalidPayloadData, + "response has unexpected size", + CancellationToken.None); + return false; + } + + return true; + } + catch (WebSocketException socketException) + { + logger.LogDebug(socketException, "could not read"); + return false; + } + } +} diff --git a/TanksServer/Models/Bullet.cs b/TanksServer/Models/Bullet.cs index efb5674..4fded2b 100644 --- a/TanksServer/Models/Bullet.cs +++ b/TanksServer/Models/Bullet.cs @@ -1,10 +1,12 @@ namespace TanksServer.Models; -internal sealed class Bullet(Player tankOwner, FloatPosition position, double rotation): IMapEntity +internal sealed class Bullet(Player tankOwner, FloatPosition position, double rotation) : IMapEntity { public Player Owner { get; } = tankOwner; - - public FloatPosition Position { get; set; } = position; - + public double Rotation { get; set; } = rotation; -} \ No newline at end of file + + public FloatPosition Position { get; set; } = position; + + public PixelBounds Bounds => new (Position.ToPixelPosition(), Position.ToPixelPosition()); +} diff --git a/TanksServer/Models/IMapEntity.cs b/TanksServer/Models/IMapEntity.cs index 53ac5bf..05b5700 100644 --- a/TanksServer/Models/IMapEntity.cs +++ b/TanksServer/Models/IMapEntity.cs @@ -3,4 +3,6 @@ namespace TanksServer.Models; internal interface IMapEntity { FloatPosition Position { get; set; } -} \ No newline at end of file + + PixelBounds Bounds { get; } +} diff --git a/TanksServer/Models/PixelBounds.cs b/TanksServer/Models/PixelBounds.cs new file mode 100644 index 0000000..a2ee757 --- /dev/null +++ b/TanksServer/Models/PixelBounds.cs @@ -0,0 +1,3 @@ +namespace TanksServer.Models; + +internal record struct PixelBounds(PixelPosition TopLeft, PixelPosition BottomRight); diff --git a/TanksServer/Models/PositionHelpers.cs b/TanksServer/Models/PositionHelpers.cs index be4459d..4443e04 100644 --- a/TanksServer/Models/PositionHelpers.cs +++ b/TanksServer/Models/PositionHelpers.cs @@ -10,8 +10,8 @@ internal static class PositionHelpers Debug.Assert(subX < 8); Debug.Assert(subY < 8); return new PixelPosition( - x: (ushort)(position.X * MapService.TileSize + subX), - y: (ushort)(position.Y * MapService.TileSize + subY) + (ushort)(position.X * MapService.TileSize + subX), + (ushort)(position.Y * MapService.TileSize + subY) ); } @@ -23,21 +23,26 @@ internal static class PositionHelpers } public static PixelPosition ToPixelPosition(this FloatPosition position) => new( - x: (ushort)((int)position.X % MapService.PixelsPerRow), - y: (ushort)((int)position.Y % MapService.PixelsPerRow) + (ushort)((int)position.X % MapService.PixelsPerRow), + (ushort)((int)position.Y % MapService.PixelsPerRow) + ); + + public static PixelPosition ToPixelPosition(this TilePosition position) => new( + (ushort)(position.X * MapService.TileSize), + (ushort)(position.Y * MapService.TileSize) ); public static TilePosition ToTilePosition(this PixelPosition position) => new( - x: (ushort)(position.X / MapService.TileSize), - y: (ushort)(position.Y / MapService.TileSize) + (ushort)(position.X / MapService.TileSize), + (ushort)(position.Y / MapService.TileSize) ); public static FloatPosition ToFloatPosition(this PixelPosition position) => new(position.X, position.Y); - public static double Distance(this FloatPosition p1, FloatPosition p2) - => Math.Sqrt( + public static double Distance(this FloatPosition p1, FloatPosition p2) => + Math.Sqrt( Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2) ); -} \ No newline at end of file +} diff --git a/TanksServer/Models/Tank.cs b/TanksServer/Models/Tank.cs index 551e5c2..e4d51ef 100644 --- a/TanksServer/Models/Tank.cs +++ b/TanksServer/Models/Tank.cs @@ -20,9 +20,21 @@ internal sealed class Tank(Player player, FloatPosition spawnPosition) : IMapEnt } } - public FloatPosition Position { get; set; } = spawnPosition; - public DateTime NextShotAfter { get; set; } public bool Moved { get; set; } -} \ No newline at end of file + + public FloatPosition Position { get; set; } = spawnPosition; + + public PixelBounds Bounds => GetBoundsForCenter(Position); + + public static PixelBounds GetBoundsForCenter(FloatPosition position) => new( + new PixelPosition( + (ushort)(position.X - MapService.TileSize / 2d), + (ushort)(position.Y - MapService.TileSize / 2d) + ), new PixelPosition( + (ushort)(position.X + MapService.TileSize / 2d - 1d), + (ushort)(position.Y + MapService.TileSize / 2d - 1d) + ) + ); +} diff --git a/TanksServer/Program.cs b/TanksServer/Program.cs index 611889f..d0a846d 100644 --- a/TanksServer/Program.cs +++ b/TanksServer/Program.cs @@ -100,13 +100,13 @@ public static class Program 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.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.Configure( builder.Configuration.GetSection("Tanks")); diff --git a/TanksServer/TanksServer.csproj b/TanksServer/TanksServer.csproj index b42f76c..bbfdc06 100644 --- a/TanksServer/TanksServer.csproj +++ b/TanksServer/TanksServer.csproj @@ -19,7 +19,6 @@ true false - true true true true @@ -31,19 +30,20 @@ - - + + - ..\Dockerfile + Dockerfile - ../Dockerfile + Dockerfile - + + - +