From b1df817ece6adc718c7f3d37f22c4cdd155eb73a Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Tue, 7 May 2024 21:48:58 +0200 Subject: [PATCH 01/15] fast bullet accelerates instead of being fast immediately --- tanks-backend/TanksServer/GameLogic/GameRules.cs | 2 ++ tanks-backend/TanksServer/GameLogic/MapEntityManager.cs | 6 +++--- tanks-backend/TanksServer/GameLogic/MoveBullets.cs | 2 ++ tanks-backend/TanksServer/Models/Bullet.cs | 4 +++- tanks-backend/TanksServer/appsettings.json | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tanks-backend/TanksServer/GameLogic/GameRules.cs b/tanks-backend/TanksServer/GameLogic/GameRules.cs index 2284464..3660671 100644 --- a/tanks-backend/TanksServer/GameLogic/GameRules.cs +++ b/tanks-backend/TanksServer/GameLogic/GameRules.cs @@ -27,4 +27,6 @@ internal sealed class GameRules public int ReloadDelayMs { get; set; } = 3000; public double SmartBulletInertia { get; set; } = 1; + + public double FastBulletAcceleration { get; set; } = 0.25; } diff --git a/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs b/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs index e7b376d..3b1f4f6 100644 --- a/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs +++ b/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs @@ -17,7 +17,6 @@ internal sealed class MapEntityManager( public void SpawnBullet(Player tankOwner, FloatPosition position, double rotation, MagazineType type) { - var speed = _rules.BulletSpeed * (type.HasFlag(MagazineType.Fast) ? 2 : 1); _bullets.Add(new Bullet { Owner = tankOwner, @@ -26,8 +25,9 @@ internal sealed class MapEntityManager( IsExplosive = type.HasFlag(MagazineType.Explosive), Timeout = DateTime.Now + _bulletTimeout, OwnerCollisionAfter = DateTime.Now + TimeSpan.FromSeconds(1), - Speed = speed, - IsSmart = type.HasFlag(MagazineType.Smart) + Speed = _rules.BulletSpeed, + IsSmart = type.HasFlag(MagazineType.Smart), + Acceleration = type.HasFlag(MagazineType.Fast) ? _rules.FastBulletAcceleration : 0d }); } diff --git a/tanks-backend/TanksServer/GameLogic/MoveBullets.cs b/tanks-backend/TanksServer/GameLogic/MoveBullets.cs index 96bde60..d303d84 100644 --- a/tanks-backend/TanksServer/GameLogic/MoveBullets.cs +++ b/tanks-backend/TanksServer/GameLogic/MoveBullets.cs @@ -24,6 +24,8 @@ internal sealed class MoveBullets( bullet.Rotation += difference * inertiaFactor; } + bullet.Speed *= 1 + (bullet.Acceleration * delta.TotalSeconds); + var speed = bullet.Speed * delta.TotalSeconds; var angle = bullet.Rotation * 2 * Math.PI; bullet.Position = new FloatPosition( diff --git a/tanks-backend/TanksServer/Models/Bullet.cs b/tanks-backend/TanksServer/Models/Bullet.cs index 9e17066..c5f8d1d 100644 --- a/tanks-backend/TanksServer/Models/Bullet.cs +++ b/tanks-backend/TanksServer/Models/Bullet.cs @@ -16,7 +16,9 @@ internal sealed class Bullet : IMapEntity internal required DateTime OwnerCollisionAfter { get; init; } - public required double Speed { get; init; } + public required double Speed { get; set; } + + public required double Acceleration { get; init; } public required bool IsSmart { get; init; } } diff --git a/tanks-backend/TanksServer/appsettings.json b/tanks-backend/TanksServer/appsettings.json index 37f8c7b..0eaa26e 100644 --- a/tanks-backend/TanksServer/appsettings.json +++ b/tanks-backend/TanksServer/appsettings.json @@ -33,7 +33,7 @@ "SmartBulletHomingSpeed": 1.5 }, "Host": { - "EnableServicePointDisplay": false, + "EnableServicePointDisplay": true, "ServicePointDisplayMinFrameTimeMs": 28, "ClientScreenMinFrameTime": 5 } From 827b3a93308e80ae388a2f963cbda8033441cbee Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 8 May 2024 00:29:33 +0200 Subject: [PATCH 02/15] move upgrades to tank, serialize objects directly --- tank-frontend/src/PlayerInfo.tsx | 34 +++++----- tank-frontend/src/serverCalls.tsx | 37 +++++++---- .../TanksServer/GameLogic/CollectPowerUp.cs | 62 ++++++++++++------- .../TanksServer/GameLogic/CollideBullets.cs | 6 +- .../TanksServer/GameLogic/GameRules.cs | 4 +- .../TanksServer/GameLogic/MapEntityManager.cs | 17 +++-- .../TanksServer/GameLogic/MoveBullets.cs | 5 +- .../TanksServer/GameLogic/ShootFromTanks.cs | 15 ++--- .../TanksServer/GameLogic/SpawnPowerUp.cs | 20 +----- .../TanksServer/Graphics/DrawPowerUpsStep.cs | 10 +-- .../Interactivity/PlayerInfoConnection.cs | 21 +++---- tanks-backend/TanksServer/Models/Bullet.cs | 6 +- tanks-backend/TanksServer/Models/Magazine.cs | 38 ------------ .../TanksServer/Models/PlayerInfo.cs | 16 ----- tanks-backend/TanksServer/Models/PowerUp.cs | 9 +-- tanks-backend/TanksServer/Models/Tank.cs | 15 +++-- 16 files changed, 135 insertions(+), 180 deletions(-) delete mode 100644 tanks-backend/TanksServer/Models/Magazine.cs delete mode 100644 tanks-backend/TanksServer/Models/PlayerInfo.cs diff --git a/tank-frontend/src/PlayerInfo.tsx b/tank-frontend/src/PlayerInfo.tsx index 4ab04bc..7f54c06 100644 --- a/tank-frontend/src/PlayerInfo.tsx +++ b/tank-frontend/src/PlayerInfo.tsx @@ -46,29 +46,35 @@ export default function PlayerInfo({player}: { player: string }) { if (!lastJsonMessage || readyState !== ReadyState.OPEN) return <>; + let position = ''; + if (lastJsonMessage.tank) + position = `(${Math.round(lastJsonMessage.tank.position.x)}|${Math.round(lastJsonMessage.tank.position.y)})`; + return

- Playing as {lastJsonMessage.name} + Playing as {lastJsonMessage.player.name}

- + + + + + + + + + + + + + + - - - - - - - - - - - - +
; diff --git a/tank-frontend/src/serverCalls.tsx b/tank-frontend/src/serverCalls.tsx index 83e4f2d..57ae781 100644 --- a/tank-frontend/src/serverCalls.tsx +++ b/tank-frontend/src/serverCalls.tsx @@ -14,24 +14,32 @@ export type Scores = { readonly pixelsMoved: number; }; -export type Player = { - readonly name: string; - readonly scores: Scores; -}; - -type TankInfo = { - readonly magazine: string; +type Tank = { readonly position: { x: number; y: number }; readonly orientation: number; readonly moving: boolean; + readonly bulletStats: BulletStats; + readonly reloadingUntil: string; + readonly nextShotAfter: string; + readonly magazine: { + readonly empty: boolean; + readonly usedBullets: number; + readonly maxBullets: number; + readonly displayString: string; + }; +} + +export type Player = { + readonly name: string; + readonly scores: Scores; + readonly openConnections: number; + readonly lastInput: string; } export type PlayerInfoMessage = { - readonly name: string; - readonly scores: Scores; + readonly player: Player; readonly controls: string; - readonly tank?: TankInfo; - readonly openConnections: number; + readonly tank?: Tank; } export type MapInfo = { @@ -40,6 +48,13 @@ export type MapInfo = { readonly preview: string; } +export type BulletStats = { + speed: number; + acceleration: number, + explosive: boolean, + smart: boolean +}; + export function useMyWebSocket(url: string, options: Options = {}) { return useWebSocket(url, { shouldReconnect: () => true, diff --git a/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs b/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs index 3b3571f..840c043 100644 --- a/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs +++ b/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs @@ -2,19 +2,27 @@ using System.Diagnostics; namespace TanksServer.GameLogic; -internal sealed class CollectPowerUp( - MapEntityManager entityManager -) : ITickStep +internal sealed class CollectPowerUp : ITickStep { - private readonly Predicate _collectPredicate = b => TryCollect(b, entityManager.Tanks); + private readonly Predicate _collectPredicate; + private readonly GameRules _rules; + private readonly MapEntityManager _entityManager; + + public CollectPowerUp(MapEntityManager entityManager, + IOptions options) + { + _entityManager = entityManager; + _rules = options.Value; + _collectPredicate = b => TryCollect(b, entityManager.Tanks); + } public ValueTask TickAsync(TimeSpan delta) { - entityManager.RemoveWhere(_collectPredicate); + _entityManager.RemoveWhere(_collectPredicate); return ValueTask.CompletedTask; } - private static bool TryCollect(PowerUp powerUp, IEnumerable tanks) + private bool TryCollect(PowerUp powerUp, IEnumerable tanks) { var position = powerUp.Position; foreach (var tank in tanks) @@ -34,32 +42,38 @@ internal sealed class CollectPowerUp( return false; } - private static void ApplyPowerUpEffect(PowerUp powerUp, Tank tank) + private void ApplyPowerUpEffect(PowerUp powerUp, Tank tank) { switch (powerUp.Type) { - case PowerUpType.MagazineType: - if (powerUp.MagazineType == null) - throw new UnreachableException(); - - tank.Magazine = tank.Magazine with - { - Type = tank.Magazine.Type | powerUp.MagazineType.Value, - UsedBullets = 0 - }; - - if (tank.ReloadingUntil >= DateTime.Now) - tank.ReloadingUntil = DateTime.Now; - - break; case PowerUpType.MagazineSize: - tank.Magazine = tank.Magazine with + tank.MaxBullets = (byte)int.Clamp(tank.MaxBullets + 1, 1, 32); + break; + + case PowerUpType.BulletAcceleration: + tank.BulletStats = tank.BulletStats with { - MaxBullets = (byte)int.Clamp(tank.Magazine.MaxBullets + 1, 1, 32) + Acceleration = tank.BulletStats.Acceleration * _rules.BulletAccelerationUpgradeStrength }; break; + + case PowerUpType.ExplosiveBullets: + tank.BulletStats = tank.BulletStats with { Explosive = true }; + break; + + case PowerUpType.SmartBullets: + tank.BulletStats = tank.BulletStats with { Smart = true }; + break; + + case PowerUpType.BulletSpeed: + tank.BulletStats = tank.BulletStats with + { + Speed = tank.BulletStats.Speed * _rules.BulletSpeedUpgradeStrength + }; + break; + default: - throw new UnreachableException(); + throw new NotImplementedException($"unknown type {powerUp.Type}"); } } } diff --git a/tanks-backend/TanksServer/GameLogic/CollideBullets.cs b/tanks-backend/TanksServer/GameLogic/CollideBullets.cs index 4be0dca..c75fe6a 100644 --- a/tanks-backend/TanksServer/GameLogic/CollideBullets.cs +++ b/tanks-backend/TanksServer/GameLogic/CollideBullets.cs @@ -35,7 +35,7 @@ internal sealed class CollideBullets : ITickStep if (bullet.Timeout > DateTime.Now) return false; - ExplodeAt(bullet.Position.ToPixelPosition(), bullet.IsExplosive, bullet.Owner); + ExplodeAt(bullet.Position.ToPixelPosition(), bullet.Stats.Explosive, bullet.Owner); return true; } @@ -45,7 +45,7 @@ internal sealed class CollideBullets : ITickStep if (!_map.Current.IsWall(pixel)) return false; - ExplodeAt(pixel, bullet.IsExplosive, bullet.Owner); + ExplodeAt(pixel, bullet.Stats.Explosive, bullet.Owner); return true; } @@ -55,7 +55,7 @@ internal sealed class CollideBullets : ITickStep if (hitTank == null) return false; - ExplodeAt(bullet.Position.ToPixelPosition(), bullet.IsExplosive, bullet.Owner); + ExplodeAt(bullet.Position.ToPixelPosition(), bullet.Stats.Explosive, bullet.Owner); return true; } diff --git a/tanks-backend/TanksServer/GameLogic/GameRules.cs b/tanks-backend/TanksServer/GameLogic/GameRules.cs index 3660671..2d338b3 100644 --- a/tanks-backend/TanksServer/GameLogic/GameRules.cs +++ b/tanks-backend/TanksServer/GameLogic/GameRules.cs @@ -28,5 +28,7 @@ internal sealed class GameRules public double SmartBulletInertia { get; set; } = 1; - public double FastBulletAcceleration { get; set; } = 0.25; + public double BulletAccelerationUpgradeStrength { get; set; } = 0.1; + + public double BulletSpeedUpgradeStrength { get; set; } = 0.1; } diff --git a/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs b/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs index 3b1f4f6..31cb28c 100644 --- a/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs +++ b/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs @@ -15,19 +15,17 @@ internal sealed class MapEntityManager( public IEnumerable Tanks => _playerTanks.Values; public IEnumerable PowerUps => _powerUps; - public void SpawnBullet(Player tankOwner, FloatPosition position, double rotation, MagazineType type) + public void SpawnBullet(Player tankOwner, FloatPosition position, double rotation, BulletStats stats) { _bullets.Add(new Bullet { Owner = tankOwner, Position = position, Rotation = rotation, - IsExplosive = type.HasFlag(MagazineType.Explosive), Timeout = DateTime.Now + _bulletTimeout, OwnerCollisionAfter = DateTime.Now + TimeSpan.FromSeconds(1), Speed = _rules.BulletSpeed, - IsSmart = type.HasFlag(MagazineType.Smart), - Acceleration = type.HasFlag(MagazineType.Fast) ? _rules.FastBulletAcceleration : 0d + Stats = stats }); } @@ -35,24 +33,23 @@ internal sealed class MapEntityManager( public void SpawnTank(Player player, FloatPosition position) { - var tank = new Tank + var tank = new Tank(player) { - Owner = player, Position = position, Rotation = Random.Shared.NextDouble(), - Magazine = new Magazine(MagazineType.Basic, 0, _rules.MagazineSize) + MaxBullets = _rules.MagazineSize, + BulletStats =new BulletStats(_rules.BulletSpeed, 0, false, false) }; _playerTanks[player] = tank; logger.LogInformation("Tank added for player {}", player.Name); } - public void SpawnPowerUp(FloatPosition position, PowerUpType type, MagazineType? magazineType) + public void SpawnPowerUp(FloatPosition position, PowerUpType type) { var powerUp = new PowerUp { Position = position, - Type = type, - MagazineType = magazineType + Type = type }; _powerUps.Add(powerUp); } diff --git a/tanks-backend/TanksServer/GameLogic/MoveBullets.cs b/tanks-backend/TanksServer/GameLogic/MoveBullets.cs index d303d84..71e776f 100644 --- a/tanks-backend/TanksServer/GameLogic/MoveBullets.cs +++ b/tanks-backend/TanksServer/GameLogic/MoveBullets.cs @@ -17,14 +17,15 @@ internal sealed class MoveBullets( private void MoveBullet(Bullet bullet, TimeSpan delta) { - if (bullet.IsSmart && TryGetSmartRotation(bullet.Position, bullet.Owner, out var wantedRotation)) + if (bullet.Stats.Smart && TryGetSmartRotation(bullet.Position, bullet.Owner, out var wantedRotation)) { var inertiaFactor = _smartBulletInertia * delta.TotalSeconds; var difference = wantedRotation - bullet.Rotation; bullet.Rotation += difference * inertiaFactor; } - bullet.Speed *= 1 + (bullet.Acceleration * delta.TotalSeconds); + bullet.Speed = double.Clamp(bullet.Speed * (1 + (bullet.Stats.Acceleration * delta.TotalSeconds)), 0d, + MapService.TileSize * 10); var speed = bullet.Speed * delta.TotalSeconds; var angle = bullet.Rotation * 2 * Math.PI; diff --git a/tanks-backend/TanksServer/GameLogic/ShootFromTanks.cs b/tanks-backend/TanksServer/GameLogic/ShootFromTanks.cs index 9df8a64..3014c45 100644 --- a/tanks-backend/TanksServer/GameLogic/ShootFromTanks.cs +++ b/tanks-backend/TanksServer/GameLogic/ShootFromTanks.cs @@ -26,24 +26,17 @@ internal sealed class ShootFromTanks( if (tank.ReloadingUntil >= now) return; - if (tank.Magazine.Empty) + if (tank.UsedBullets >= tank.MaxBullets) { tank.ReloadingUntil = now.AddMilliseconds(_config.ReloadDelayMs); - tank.Magazine = tank.Magazine with - { - UsedBullets = 0, - Type = MagazineType.Basic - }; + tank.UsedBullets = 0; return; } tank.NextShotAfter = now.AddMilliseconds(_config.ShootDelayMs); - tank.Magazine = tank.Magazine with - { - UsedBullets = (byte)(tank.Magazine.UsedBullets + 1) - }; + tank.UsedBullets++; tank.Owner.Scores.ShotsFired++; - entityManager.SpawnBullet(tank.Owner, tank.Position, tank.Orientation / 16d, tank.Magazine.Type); + entityManager.SpawnBullet(tank.Owner, tank.Position, tank.Orientation / 16d, tank.BulletStats); } } diff --git a/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs b/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs index 72b0592..3107b71 100644 --- a/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs +++ b/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs @@ -18,25 +18,9 @@ internal sealed class SpawnPowerUp( if (Random.Shared.NextDouble() > _spawnChance * delta.TotalSeconds) return ValueTask.CompletedTask; - - var type = Random.Shared.Next(4) == 0 - ? PowerUpType.MagazineSize - : PowerUpType.MagazineType; - - MagazineType? magazineType = type switch - { - PowerUpType.MagazineType => Random.Shared.Next(0, 3) switch - { - 0 => MagazineType.Fast, - 1 => MagazineType.Explosive, - 2 => MagazineType.Smart, - _ => throw new UnreachableException() - }, - _ => null - }; - + var type = (PowerUpType)Random.Shared.Next((int)Enum.GetValues().Max()); var position = emptyTileFinder.ChooseEmptyTile().GetCenter().ToFloatPosition(); - entityManager.SpawnPowerUp(position, type, magazineType); + entityManager.SpawnPowerUp(position, type); return ValueTask.CompletedTask; } } diff --git a/tanks-backend/TanksServer/Graphics/DrawPowerUpsStep.cs b/tanks-backend/TanksServer/Graphics/DrawPowerUpsStep.cs index 6d47060..c6125ec 100644 --- a/tanks-backend/TanksServer/Graphics/DrawPowerUpsStep.cs +++ b/tanks-backend/TanksServer/Graphics/DrawPowerUpsStep.cs @@ -14,12 +14,12 @@ internal sealed class DrawPowerUpsStep(MapEntityManager entityManager) : IDrawSt { foreach (var powerUp in entityManager.PowerUps) { - var sprite = powerUp switch + var sprite = powerUp.Type switch { - { Type: PowerUpType.MagazineSize } => _magazineSprite, - { Type: PowerUpType.MagazineType, MagazineType: MagazineType.Smart } => _smartSprite, - { Type: PowerUpType.MagazineType, MagazineType: MagazineType.Explosive } => _explosiveSprite, - { Type: PowerUpType.MagazineType, MagazineType: MagazineType.Fast } => _fastSprite, + PowerUpType.MagazineSize => _magazineSprite, + PowerUpType.BulletAcceleration or PowerUpType.BulletSpeed => _fastSprite, + PowerUpType.SmartBullets => _smartSprite, + PowerUpType.ExplosiveBullets => _explosiveSprite, _ => _genericSprite }; diff --git a/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs b/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs index 04661c3..a81d2c4 100644 --- a/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs +++ b/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs @@ -47,20 +47,7 @@ internal sealed class PlayerInfoConnection private async ValueTask?> GenerateMessageAsync() { var tank = _entityManager.GetCurrentTankOfPlayer(_player); - - TankInfo? tankInfo = null; - if (tank != null) - { - var magazine = tank.ReloadingUntil > DateTime.Now ? "[ RELOADING ]" : tank.Magazine.ToDisplayString(); - tankInfo = new TankInfo(tank.Orientation, magazine, tank.Position.ToPixelPosition(), tank.Moving); - } - - var info = new PlayerInfo( - _player.Name, - _player.Scores, - _player.Controls.ToDisplayString(), - tankInfo, - _player.OpenConnections); + var info = new PlayerInfo(_player, _player.Controls.ToDisplayString(), tank); _tempStream.Position = 0; await JsonSerializer.SerializeAsync(_tempStream, info, AppSerializerContext.Default.PlayerInfo); @@ -85,3 +72,9 @@ internal sealed class PlayerInfoConnection Interlocked.Exchange(ref _lastMessage, data)?.Dispose(); } } + +internal record struct PlayerInfo( + Player Player, + string Controls, + Tank? Tank +); diff --git a/tanks-backend/TanksServer/Models/Bullet.cs b/tanks-backend/TanksServer/Models/Bullet.cs index c5f8d1d..aed3ddf 100644 --- a/tanks-backend/TanksServer/Models/Bullet.cs +++ b/tanks-backend/TanksServer/Models/Bullet.cs @@ -8,8 +8,6 @@ internal sealed class Bullet : IMapEntity public required FloatPosition Position { get; set; } - public required bool IsExplosive { get; init; } - public required DateTime Timeout { get; init; } public PixelBounds Bounds => new(Position.ToPixelPosition(), Position.ToPixelPosition()); @@ -18,7 +16,5 @@ internal sealed class Bullet : IMapEntity public required double Speed { get; set; } - public required double Acceleration { get; init; } - - public required bool IsSmart { get; init; } + public required BulletStats Stats { get; init; } } diff --git a/tanks-backend/TanksServer/Models/Magazine.cs b/tanks-backend/TanksServer/Models/Magazine.cs deleted file mode 100644 index febd5b8..0000000 --- a/tanks-backend/TanksServer/Models/Magazine.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Text; - -namespace TanksServer.Models; - -[Flags] -internal enum MagazineType -{ - Basic = 0, - Fast = 1 << 0, - Explosive = 1 << 1, - Smart = 1 << 2, -} - -internal readonly record struct Magazine(MagazineType Type, byte UsedBullets, byte MaxBullets) -{ - public bool Empty => UsedBullets >= MaxBullets; - - public string ToDisplayString() - { - var sb = new StringBuilder(); - - if (Type.HasFlag(MagazineType.Fast)) - sb.Append("» "); - if (Type.HasFlag(MagazineType.Explosive)) - sb.Append("* "); - if (Type.HasFlag(MagazineType.Smart)) - sb.Append("@ "); - - sb.Append("[ "); - for (var i = 0; i < UsedBullets; i++) - sb.Append("\u25cb "); - for (var i = UsedBullets; i < MaxBullets; i++) - sb.Append("• "); - sb.Append(']'); - - return sb.ToString(); - } -} diff --git a/tanks-backend/TanksServer/Models/PlayerInfo.cs b/tanks-backend/TanksServer/Models/PlayerInfo.cs deleted file mode 100644 index a8545f3..0000000 --- a/tanks-backend/TanksServer/Models/PlayerInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace TanksServer.Models; - -internal record struct TankInfo( - int Orientation, - string Magazine, - PixelPosition Position, - bool Moving -); - -internal record struct PlayerInfo( - string Name, - Scores Scores, - string Controls, - TankInfo? Tank, - int OpenConnections -); diff --git a/tanks-backend/TanksServer/Models/PowerUp.cs b/tanks-backend/TanksServer/Models/PowerUp.cs index a8adb25..318a3a4 100644 --- a/tanks-backend/TanksServer/Models/PowerUp.cs +++ b/tanks-backend/TanksServer/Models/PowerUp.cs @@ -4,8 +4,11 @@ namespace TanksServer.Models; internal enum PowerUpType { - MagazineType, - MagazineSize + MagazineSize, + BulletSpeed, + BulletAcceleration, + ExplosiveBullets, + SmartBullets, } internal sealed class PowerUp: IMapEntity @@ -15,6 +18,4 @@ internal sealed class PowerUp: IMapEntity public PixelBounds Bounds => Position.GetBoundsForCenter(MapService.TileSize); public required PowerUpType Type { get; init; } - - public MagazineType? MagazineType { get; init; } } diff --git a/tanks-backend/TanksServer/Models/Tank.cs b/tanks-backend/TanksServer/Models/Tank.cs index e9de961..ee955ea 100644 --- a/tanks-backend/TanksServer/Models/Tank.cs +++ b/tanks-backend/TanksServer/Models/Tank.cs @@ -1,13 +1,14 @@ using System.Diagnostics; +using System.Text.Json.Serialization; using TanksServer.GameLogic; namespace TanksServer.Models; -internal sealed class Tank : IMapEntity +internal sealed class Tank(Player owner) : IMapEntity { private double _rotation; - public required Player Owner { get; init; } + [JsonIgnore] public Player Owner { get; } = owner; public double Rotation { @@ -26,11 +27,17 @@ internal sealed class Tank : IMapEntity public required FloatPosition Position { get; set; } - public PixelBounds Bounds => Position.GetBoundsForCenter(MapService.TileSize); + [JsonIgnore] public PixelBounds Bounds => Position.GetBoundsForCenter(MapService.TileSize); public int Orientation => (int)Math.Round(Rotation * 16) % 16; - public required Magazine Magazine { get; set; } + public int UsedBullets { get; set; } + + public int MaxBullets { get; set; } public DateTime ReloadingUntil { get; set; } + + public required BulletStats BulletStats { get; set; } } + +internal sealed record class BulletStats(double Speed, double Acceleration, bool Explosive, bool Smart); From c7bfceffe1da8b4238d673048e9042f22e0f2b1b Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 8 May 2024 00:29:51 +0200 Subject: [PATCH 03/15] fix UnreachableException --- .../DroppablePackageRequestConnection.cs | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs b/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs index 19956a9..4e5536a 100644 --- a/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs +++ b/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs @@ -10,27 +10,15 @@ internal abstract class DroppablePackageRequestConnection( where TPackage : class, IDisposable { private readonly AsyncAutoResetEvent _nextPackageEvent = new(false, 1); - private int _runningMessageHandlers = 0; private TPackage? _next; - protected override ValueTask HandleMessageAsync(Memory _) + protected override async ValueTask HandleMessageAsync(Memory _) { - if (Interlocked.Increment(ref _runningMessageHandlers) == 1) - return Core(); - - // client has requested multiple frames, ignoring duplicate requests - Interlocked.Decrement(ref _runningMessageHandlers); - return ValueTask.CompletedTask; - - async ValueTask Core() - { - await _nextPackageEvent.WaitAsync(); - var package = Interlocked.Exchange(ref _next, null); - if (package == null) - throw new UnreachableException("package should be set here"); - await SendPackageAsync(package); - Interlocked.Decrement(ref _runningMessageHandlers); - } + await _nextPackageEvent.WaitAsync(); + var package = Interlocked.Exchange(ref _next, null); + if (package == null) + return; + await SendPackageAsync(package); } protected void SetNextPackage(TPackage next) From a4aab442e5c067975683f1df92df689219985cce Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 8 May 2024 00:30:11 +0200 Subject: [PATCH 04/15] endpoint for SendHardResetAsync --- tanks-backend/TanksServer/Endpoints.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tanks-backend/TanksServer/Endpoints.cs b/tanks-backend/TanksServer/Endpoints.cs index e0e0252..1456f0f 100644 --- a/tanks-backend/TanksServer/Endpoints.cs +++ b/tanks-backend/TanksServer/Endpoints.cs @@ -1,6 +1,7 @@ using System.IO; using System.Text; using System.Text.Json; +using DisplayCommands; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Http; @@ -17,7 +18,8 @@ internal sealed class Endpoints( PlayerServer playerService, ControlsServer controlsServer, MapService mapService, - ChangeToRequestedMap changeToRequestedMap + ChangeToRequestedMap changeToRequestedMap, + IDisplayConnection displayConnection ) { public void Map(WebApplication app) @@ -29,6 +31,7 @@ internal sealed class Endpoints( app.Map("/controls", ConnectControlsAsync); app.MapGet("/map", () => mapService.MapNames); app.MapPost("/map", PostMap); + app.MapPost("/resetDisplay", displayConnection.SendHardResetAsync); app.MapGet("/map/{name}", GetMapByName); app.MapHealthChecks("/health", new HealthCheckOptions From b47901313b859ce1dba0b24cded3ff63df1f00ce Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 8 May 2024 01:00:11 +0200 Subject: [PATCH 05/15] enable and disable big screen at runtime --- .../Interactivity/SendToServicePointDisplay.cs | 8 +++++++- tanks-backend/TanksServer/Program.cs | 14 +++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs index 5625566..fc64cc9 100644 --- a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs +++ b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs @@ -18,6 +18,7 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer private readonly PlayerServer _players; private readonly Cp437Grid _scoresBuffer; private readonly TimeSpan _minFrameTime; + private readonly IOptionsMonitor _options; private DateTime _nextFailLogAfter = DateTime.Now; private DateTime _nextFrameAfter = DateTime.Now; @@ -27,7 +28,8 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer ILogger logger, IDisplayConnection displayConnection, IOptions hostOptions, - MapService mapService + MapService mapService, + IOptionsMonitor options ) { _players = players; @@ -35,6 +37,7 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer _displayConnection = displayConnection; _mapService = mapService; _minFrameTime = TimeSpan.FromMilliseconds(hostOptions.Value.ServicePointDisplayMinFrameTimeMs); + _options = options; var localIp = _displayConnection.GetLocalIPv4().Split('.'); Debug.Assert(localIp.Length == 4); @@ -50,6 +53,9 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer public async Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, PixelGrid observerPixels) { + if (!_options.CurrentValue.EnableServicePointDisplay) + return; + if (DateTime.Now < _nextFrameAfter) return; diff --git a/tanks-backend/TanksServer/Program.cs b/tanks-backend/TanksServer/Program.cs index 91c14fe..efe9bb4 100644 --- a/tanks-backend/TanksServer/Program.cs +++ b/tanks-backend/TanksServer/Program.cs @@ -1,7 +1,6 @@ using System.IO; using DisplayCommands; using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using TanksServer.GameLogic; @@ -54,11 +53,6 @@ public static class Program var healthCheckBuilder = builder.Services.AddHealthChecks(); healthCheckBuilder.AddCheck("updates check"); - builder.Services.Configure(builder.Configuration.GetSection("Host")); - var hostConfiguration = builder.Configuration.GetSection("Host").Get(); - if (hostConfiguration == null) - throw new InvalidOperationException("'Host' configuration missing"); - builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -99,12 +93,10 @@ public static class Program sp.GetRequiredService()); builder.Services.Configure(builder.Configuration.GetSection("GameRules")); + builder.Services.Configure(builder.Configuration.GetSection("Host")); - if (hostConfiguration.EnableServicePointDisplay) - { - builder.Services.AddSingleton(); - builder.Services.AddDisplay(builder.Configuration.GetSection("ServicePointDisplay")); - } + builder.Services.AddSingleton(); + builder.Services.AddDisplay(builder.Configuration.GetSection("ServicePointDisplay")); var app = builder.Build(); From a0b25b9cfb31897c31dd301e93b077ef2ffb3630 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 8 May 2024 01:01:11 +0200 Subject: [PATCH 06/15] powerup fixes --- tank-frontend/src/PlayerInfo.tsx | 24 +++++++++---------- tank-frontend/src/serverCalls.tsx | 10 +++----- .../TanksServer/GameLogic/CollectPowerUp.cs | 8 +++---- .../TanksServer/GameLogic/GameRules.cs | 6 ++--- .../TanksServer/GameLogic/MapEntityManager.cs | 3 +-- .../DroppablePackageRequestConnection.cs | 1 - tanks-backend/TanksServer/Models/Tank.cs | 8 ++++--- 7 files changed, 26 insertions(+), 34 deletions(-) diff --git a/tank-frontend/src/PlayerInfo.tsx b/tank-frontend/src/PlayerInfo.tsx index 7f54c06..37c479e 100644 --- a/tank-frontend/src/PlayerInfo.tsx +++ b/tank-frontend/src/PlayerInfo.tsx @@ -46,25 +46,24 @@ export default function PlayerInfo({player}: { player: string }) { if (!lastJsonMessage || readyState !== ReadyState.OPEN) return <>; - let position = ''; - if (lastJsonMessage.tank) - position = `(${Math.round(lastJsonMessage.tank.position.x)}|${Math.round(lastJsonMessage.tank.position.y)})`; - return

Playing as {lastJsonMessage.player.name}

- - - - - - - - + {lastJsonMessage.tank && <> + + + + + + + + + } + @@ -73,7 +72,6 @@ export default function PlayerInfo({player}: { player: string }) { -
diff --git a/tank-frontend/src/serverCalls.tsx b/tank-frontend/src/serverCalls.tsx index 57ae781..36d2e74 100644 --- a/tank-frontend/src/serverCalls.tsx +++ b/tank-frontend/src/serverCalls.tsx @@ -15,18 +15,14 @@ export type Scores = { }; type Tank = { - readonly position: { x: number; y: number }; + readonly pixelPosition: { x: number; y: number }; readonly orientation: number; readonly moving: boolean; readonly bulletStats: BulletStats; readonly reloadingUntil: string; readonly nextShotAfter: string; - readonly magazine: { - readonly empty: boolean; - readonly usedBullets: number; - readonly maxBullets: number; - readonly displayString: string; - }; + readonly usedBullets: number; + readonly maxBullets: number; } export type Player = { diff --git a/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs b/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs index 840c043..938f2f5 100644 --- a/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs +++ b/tanks-backend/TanksServer/GameLogic/CollectPowerUp.cs @@ -1,5 +1,3 @@ -using System.Diagnostics; - namespace TanksServer.GameLogic; internal sealed class CollectPowerUp : ITickStep @@ -47,13 +45,13 @@ internal sealed class CollectPowerUp : ITickStep switch (powerUp.Type) { case PowerUpType.MagazineSize: - tank.MaxBullets = (byte)int.Clamp(tank.MaxBullets + 1, 1, 32); + tank.MaxBullets = int.Clamp(tank.MaxBullets + 1, 1, 32); break; case PowerUpType.BulletAcceleration: tank.BulletStats = tank.BulletStats with { - Acceleration = tank.BulletStats.Acceleration * _rules.BulletAccelerationUpgradeStrength + Acceleration = tank.BulletStats.Acceleration + _rules.BulletAccelerationUpgradeStrength }; break; @@ -68,7 +66,7 @@ internal sealed class CollectPowerUp : ITickStep case PowerUpType.BulletSpeed: tank.BulletStats = tank.BulletStats with { - Speed = tank.BulletStats.Speed * _rules.BulletSpeedUpgradeStrength + Speed = tank.BulletStats.Speed + _rules.BulletSpeedUpgradeStrength }; break; diff --git a/tanks-backend/TanksServer/GameLogic/GameRules.cs b/tanks-backend/TanksServer/GameLogic/GameRules.cs index 2d338b3..1ebf548 100644 --- a/tanks-backend/TanksServer/GameLogic/GameRules.cs +++ b/tanks-backend/TanksServer/GameLogic/GameRules.cs @@ -16,7 +16,7 @@ internal sealed class GameRules public double ShootDelayMs { get; set; } - public double BulletSpeed { get; set; } + public double BulletSpeed { get; set; } = 75; public int SpawnDelayMs { get; set; } @@ -28,7 +28,7 @@ internal sealed class GameRules public double SmartBulletInertia { get; set; } = 1; - public double BulletAccelerationUpgradeStrength { get; set; } = 0.1; + public double BulletAccelerationUpgradeStrength { get; set; } = 15; - public double BulletSpeedUpgradeStrength { get; set; } = 0.1; + public double BulletSpeedUpgradeStrength { get; set; } = 5; } diff --git a/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs b/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs index 31cb28c..dd674a1 100644 --- a/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs +++ b/tanks-backend/TanksServer/GameLogic/MapEntityManager.cs @@ -33,9 +33,8 @@ internal sealed class MapEntityManager( public void SpawnTank(Player player, FloatPosition position) { - var tank = new Tank(player) + var tank = new Tank(player, position) { - Position = position, Rotation = Random.Shared.NextDouble(), MaxBullets = _rules.MagazineSize, BulletStats =new BulletStats(_rules.BulletSpeed, 0, false, false) diff --git a/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs b/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs index 4e5536a..49dccc2 100644 --- a/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs +++ b/tanks-backend/TanksServer/Interactivity/DroppablePackageRequestConnection.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using DotNext.Threading; namespace TanksServer.Interactivity; diff --git a/tanks-backend/TanksServer/Models/Tank.cs b/tanks-backend/TanksServer/Models/Tank.cs index ee955ea..7147349 100644 --- a/tanks-backend/TanksServer/Models/Tank.cs +++ b/tanks-backend/TanksServer/Models/Tank.cs @@ -4,13 +4,13 @@ using TanksServer.GameLogic; namespace TanksServer.Models; -internal sealed class Tank(Player owner) : IMapEntity +internal sealed class Tank(Player owner, FloatPosition position) : IMapEntity { private double _rotation; [JsonIgnore] public Player Owner { get; } = owner; - public double Rotation + [JsonIgnore] public double Rotation { get => _rotation; set @@ -25,7 +25,9 @@ internal sealed class Tank(Player owner) : IMapEntity public bool Moving { get; set; } - public required FloatPosition Position { get; set; } + [JsonIgnore] public FloatPosition Position { get; set; } = position; + + public PixelPosition PixelPosition => Position.ToPixelPosition(); [JsonIgnore] public PixelBounds Bounds => Position.GetBoundsForCenter(MapService.TileSize); From eb999b0d1aa318edf16e3fa4bfd8d155897fa95e Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 8 May 2024 01:16:18 +0200 Subject: [PATCH 07/15] remove low speed clamp --- tanks-backend/TanksServer/GameLogic/MoveBullets.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tanks-backend/TanksServer/GameLogic/MoveBullets.cs b/tanks-backend/TanksServer/GameLogic/MoveBullets.cs index 71e776f..60bd5b8 100644 --- a/tanks-backend/TanksServer/GameLogic/MoveBullets.cs +++ b/tanks-backend/TanksServer/GameLogic/MoveBullets.cs @@ -24,8 +24,7 @@ internal sealed class MoveBullets( bullet.Rotation += difference * inertiaFactor; } - bullet.Speed = double.Clamp(bullet.Speed * (1 + (bullet.Stats.Acceleration * delta.TotalSeconds)), 0d, - MapService.TileSize * 10); + bullet.Speed += (bullet.Stats.Acceleration * delta.TotalSeconds); var speed = bullet.Speed * delta.TotalSeconds; var angle = bullet.Rotation * 2 * Math.PI; From e1cfd714c108375821fd83eff51fa5e944b87248 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Mon, 13 May 2024 01:23:34 +0200 Subject: [PATCH 08/15] WIP switch to ServicePoint2 library --- tanks-backend/DisplayCommands/ByteGrid.cs | 42 --- tanks-backend/DisplayCommands/Cp437Grid.cs | 71 ----- .../DisplayCommands/DisplayCommands.csproj | 23 -- .../DisplayCommands/DisplayExtensions.cs | 25 -- tanks-backend/DisplayCommands/GlobalUsings.cs | 2 - .../DisplayCommands/IDisplayConnection.cs | 24 -- .../Internals/DisplayCommand.cs | 17 -- .../Internals/DisplayConnection.cs | 126 --------- .../Internals/DisplaySubCommand.cs | 10 - .../DisplayCommands/Internals/HeaderBitmap.cs | 19 -- .../DisplayCommands/Internals/HeaderWindow.cs | 19 -- tanks-backend/DisplayCommands/PixelGrid.cs | 59 ---- .../EndiannessGenerator.cs | 260 ------------------ .../EndiannessSourceGenerator.csproj | 25 -- .../Properties/launchSettings.json | 9 - .../EndiannessSourceGenerator/Readme.md | 5 - tanks-backend/TanksServer.sln | 18 +- tanks-backend/TanksServer/Endpoints.cs | 8 +- .../TanksServer/GameLogic/MapService.cs | 4 +- .../TanksServer/GameLogic/SpawnPowerUp.cs | 2 - .../TanksServer/Graphics/DrawMapStep.cs | 2 +- .../Graphics/GeneratePixelsTickStep.cs | 10 +- .../TanksServer/Graphics/IFrameConsumer.cs | 2 +- .../Interactivity/ClientScreenServer.cs | 2 +- .../ClientScreenServerConnection.cs | 7 +- .../Interactivity/PlayerInfoConnection.cs | 2 +- .../SendToServicePointDisplay.cs | 42 +-- .../Models}/DisplayConfiguration.cs | 4 +- tanks-backend/TanksServer/Program.cs | 10 +- tanks-backend/TanksServer/TanksServer.csproj | 5 +- tanks-backend/TanksServer/appsettings.json | 3 +- 31 files changed, 66 insertions(+), 791 deletions(-) delete mode 100644 tanks-backend/DisplayCommands/ByteGrid.cs delete mode 100644 tanks-backend/DisplayCommands/Cp437Grid.cs delete mode 100644 tanks-backend/DisplayCommands/DisplayCommands.csproj delete mode 100644 tanks-backend/DisplayCommands/DisplayExtensions.cs delete mode 100644 tanks-backend/DisplayCommands/GlobalUsings.cs delete mode 100644 tanks-backend/DisplayCommands/IDisplayConnection.cs delete mode 100644 tanks-backend/DisplayCommands/Internals/DisplayCommand.cs delete mode 100644 tanks-backend/DisplayCommands/Internals/DisplayConnection.cs delete mode 100644 tanks-backend/DisplayCommands/Internals/DisplaySubCommand.cs delete mode 100644 tanks-backend/DisplayCommands/Internals/HeaderBitmap.cs delete mode 100644 tanks-backend/DisplayCommands/Internals/HeaderWindow.cs delete mode 100644 tanks-backend/DisplayCommands/PixelGrid.cs delete mode 100644 tanks-backend/EndiannessSourceGenerator/EndiannessGenerator.cs delete mode 100644 tanks-backend/EndiannessSourceGenerator/EndiannessSourceGenerator.csproj delete mode 100644 tanks-backend/EndiannessSourceGenerator/Properties/launchSettings.json delete mode 100644 tanks-backend/EndiannessSourceGenerator/Readme.md rename tanks-backend/{DisplayCommands => TanksServer/Models}/DisplayConfiguration.cs (81%) diff --git a/tanks-backend/DisplayCommands/ByteGrid.cs b/tanks-backend/DisplayCommands/ByteGrid.cs deleted file mode 100644 index f7e990f..0000000 --- a/tanks-backend/DisplayCommands/ByteGrid.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Diagnostics; - -namespace DisplayCommands; - -public sealed class ByteGrid(ushort width, ushort height) : IEquatable -{ - public ushort Height { get; } = height; - - public ushort Width { get; } = width; - - internal Memory Data { get; } = new byte[width * height].AsMemory(); - - public byte this[ushort x, ushort y] - { - get => Data.Span[GetIndex(x, y)]; - set => Data.Span[GetIndex(x, y)] = value; - } - - public bool Equals(ByteGrid? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Height == other.Height && Width == other.Width && Data.Span.SequenceEqual(other.Data.Span); - } - - private int GetIndex(ushort x, ushort y) - { - Debug.Assert(x < Width); - Debug.Assert(y < Height); - return x + y * Width; - } - - public void Clear() => Data.Span.Clear(); - - public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (obj is ByteGrid other && Equals(other)); - - public override int GetHashCode() => HashCode.Combine(Height, Width, Data); - - public static bool operator ==(ByteGrid? left, ByteGrid? right) => Equals(left, right); - - public static bool operator !=(ByteGrid? left, ByteGrid? right) => !Equals(left, right); -} diff --git a/tanks-backend/DisplayCommands/Cp437Grid.cs b/tanks-backend/DisplayCommands/Cp437Grid.cs deleted file mode 100644 index 19afe2f..0000000 --- a/tanks-backend/DisplayCommands/Cp437Grid.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Diagnostics; -using System.Text; - -namespace DisplayCommands; - -public sealed class Cp437Grid(ushort width, ushort height) : IEquatable -{ - private readonly ByteGrid _byteGrid = new(width, height); - private readonly Encoding _encoding = Encoding.GetEncoding(437); - - public ushort Height { get; } = height; - - public ushort Width { get; } = width; - - internal Memory Data => _byteGrid.Data; - - public char this[ushort x, ushort y] - { - get => ByteToChar(_byteGrid[x, y]); - set => _byteGrid[x, y] = CharToByte(value); - } - - public string this[ushort row] - { - get - { - var rowStart = row * Width; - return _encoding.GetString(_byteGrid.Data[rowStart..(rowStart + Width)].Span); - } - set - { - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(row, Height, nameof(row)); - ArgumentOutOfRangeException.ThrowIfGreaterThan(value.Length, Width, nameof(value)); - ushort x = 0; - for (; x < value.Length; x++) - _byteGrid[x, row] = CharToByte(value[x]); - for (; x < Width; x++) - _byteGrid[x, row] = CharToByte(' '); - } - } - - private byte CharToByte(char c) - { - ReadOnlySpan valuesStr = stackalloc char[] { c }; - Span convertedStr = stackalloc byte[1]; - var consumed = _encoding.GetBytes(valuesStr, convertedStr); - Debug.Assert(consumed == 1); - return convertedStr[0]; - } - - private char ByteToChar(byte b) - { - ReadOnlySpan valueBytes = stackalloc byte[] { b }; - Span resultStr = stackalloc char[1]; - var consumed = _encoding.GetChars(valueBytes, resultStr); - Debug.Assert(consumed == 1); - return resultStr[0]; - } - - public bool Equals(Cp437Grid? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Height == other.Height && Width == other.Width && _byteGrid.Equals(other._byteGrid); - } - - public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (obj is Cp437Grid other && Equals(other)); - public override int GetHashCode() => HashCode.Combine(_byteGrid, Height, Width); - public static bool operator ==(Cp437Grid? left, Cp437Grid? right) => Equals(left, right); - public static bool operator !=(Cp437Grid? left, Cp437Grid? right) => !Equals(left, right); -} diff --git a/tanks-backend/DisplayCommands/DisplayCommands.csproj b/tanks-backend/DisplayCommands/DisplayCommands.csproj deleted file mode 100644 index ca146b4..0000000 --- a/tanks-backend/DisplayCommands/DisplayCommands.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - true - true - - - - - - - - - - - - - - diff --git a/tanks-backend/DisplayCommands/DisplayExtensions.cs b/tanks-backend/DisplayCommands/DisplayExtensions.cs deleted file mode 100644 index 5c94d8d..0000000 --- a/tanks-backend/DisplayCommands/DisplayExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Text; -using DisplayCommands.Internals; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace DisplayCommands; - -public static class DisplayExtensions -{ - static DisplayExtensions() - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - } - - public static IServiceCollection AddDisplay( - this IServiceCollection services, - IConfigurationSection? configurationSection = null - ) - { - services.AddSingleton(); - if (configurationSection != null) - services.Configure(configurationSection); - return services; - } -} \ No newline at end of file diff --git a/tanks-backend/DisplayCommands/GlobalUsings.cs b/tanks-backend/DisplayCommands/GlobalUsings.cs deleted file mode 100644 index b124d17..0000000 --- a/tanks-backend/DisplayCommands/GlobalUsings.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using System; -global using System.Threading.Tasks; diff --git a/tanks-backend/DisplayCommands/IDisplayConnection.cs b/tanks-backend/DisplayCommands/IDisplayConnection.cs deleted file mode 100644 index 950e75b..0000000 --- a/tanks-backend/DisplayCommands/IDisplayConnection.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace DisplayCommands; - -public interface IDisplayConnection -{ - ValueTask SendClearAsync(); - - ValueTask SendCp437DataAsync(ushort x, ushort y, Cp437Grid grid); - - ValueTask SendBrightnessAsync(byte brightness); - - ValueTask SendCharBrightnessAsync(ushort x, ushort y, ByteGrid luma); - - ValueTask SendHardResetAsync(); - - ValueTask SendFadeOutAsync(byte loops); - - public ValueTask SendBitmapLinearWindowAsync(ushort x, ushort y, PixelGrid pixels); - - /// - /// Returns the IPv4 address that is associated with the interface with which the display is reachable. - /// - /// IPv4 as text - public string GetLocalIPv4(); -} diff --git a/tanks-backend/DisplayCommands/Internals/DisplayCommand.cs b/tanks-backend/DisplayCommands/Internals/DisplayCommand.cs deleted file mode 100644 index abe94e1..0000000 --- a/tanks-backend/DisplayCommands/Internals/DisplayCommand.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace DisplayCommands.Internals; - -internal enum DisplayCommand : ushort -{ - Clear = 0x0002, - Cp437Data = 0x0003, - CharBrightness = 0x0005, - Brightness = 0x0007, - HardReset = 0x000b, - FadeOut = 0x000d, - [Obsolete("ignored by display code")] BitmapLegacy = 0x0010, - BitmapLinear = 0x0012, - BitmapLinearWin = 0x0013, - BitmapLinearAnd = 0x0014, - BitmapLinearOr = 0x0015, - BitmapLinearXor = 0x0016 -} diff --git a/tanks-backend/DisplayCommands/Internals/DisplayConnection.cs b/tanks-backend/DisplayCommands/Internals/DisplayConnection.cs deleted file mode 100644 index 972a5db..0000000 --- a/tanks-backend/DisplayCommands/Internals/DisplayConnection.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System.Buffers; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Runtime.InteropServices; -using Microsoft.Extensions.Options; - -namespace DisplayCommands.Internals; - -internal sealed class DisplayConnection(IOptions options) : IDisplayConnection, IDisposable -{ - private readonly ArrayPool _arrayPool = ArrayPool.Shared; - private readonly UdpClient _udpClient = new(options.Value.Hostname, options.Value.Port); - - public ValueTask SendClearAsync() - { - var header = new HeaderWindow { Command = (ushort)DisplayCommand.Clear }; - - return SendAsync(header, Memory.Empty); - } - - public ValueTask SendCp437DataAsync(ushort x, ushort y, Cp437Grid grid) - { - var header = new HeaderWindow - { - Command = (ushort)DisplayCommand.Cp437Data, - Height = grid.Height, - Width = grid.Width, - PosX = x, - PosY = y - }; - - return SendAsync(header, grid.Data); - } - - public ValueTask SendCharBrightnessAsync(ushort x, ushort y, ByteGrid luma) - { - var header = new HeaderWindow - { - Command = (ushort)DisplayCommand.CharBrightness, - PosX = x, - PosY = y, - Height = luma.Height, - Width = luma.Width - }; - - return SendAsync(header, luma.Data); - } - - public async ValueTask SendBrightnessAsync(byte brightness) - { - var header = new HeaderWindow { Command = (ushort)DisplayCommand.Brightness }; - - var payloadBuffer = _arrayPool.Rent(1); - var payload = payloadBuffer.AsMemory(0, 1); - payload.Span[0] = brightness; - - await SendAsync(header, payload); - _arrayPool.Return(payloadBuffer); - } - - public ValueTask SendHardResetAsync() - { - var header = new HeaderWindow { Command = (ushort)DisplayCommand.HardReset }; - return SendAsync(header, Memory.Empty); - } - - public async ValueTask SendFadeOutAsync(byte loops) - { - var header = new HeaderWindow { Command = (ushort)DisplayCommand.FadeOut }; - - var payloadBuffer = _arrayPool.Rent(1); - var payload = payloadBuffer.AsMemory(0, 1); - payload.Span[0] = loops; - - await SendAsync(header, payload); - _arrayPool.Return(payloadBuffer); - } - - public ValueTask SendBitmapLinearWindowAsync(ushort x, ushort y, PixelGrid pixels) - { - var header = new HeaderWindow - { - Command = (ushort)DisplayCommand.BitmapLinearWin, - PosX = x, - PosY = y, - Width = (ushort)(pixels.Width / 8), - Height = pixels.Height - }; - - return SendAsync(header, pixels.Data); - } - - public string GetLocalIPv4() - { - using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0); - socket.Connect(options.Value.Hostname, options.Value.Port); - var endPoint = socket.LocalEndPoint as IPEndPoint ?? throw new NotSupportedException(); - return endPoint.Address.ToString(); - } - - private async ValueTask SendAsync(HeaderWindow header, Memory payload) - { - int headerSize; - unsafe - { - // because we specified the struct layout, no platform-specific padding will be added and this is be safe. - headerSize = sizeof(HeaderWindow); - } - - Debug.Assert(headerSize == 10); - var messageSize = headerSize + payload.Length; - - var buffer = _arrayPool.Rent(messageSize); - var message = buffer.AsMemory(0, messageSize); - - MemoryMarshal.Write(message.Span, header); - payload.CopyTo(message[headerSize..]); - - await _udpClient.SendAsync(message); - - _arrayPool.Return(buffer); - } - - public void Dispose() => _udpClient.Dispose(); -} diff --git a/tanks-backend/DisplayCommands/Internals/DisplaySubCommand.cs b/tanks-backend/DisplayCommands/Internals/DisplaySubCommand.cs deleted file mode 100644 index bf5427f..0000000 --- a/tanks-backend/DisplayCommands/Internals/DisplaySubCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace DisplayCommands.Internals; - -internal enum DisplaySubCommand : ushort -{ - BitmapNormal = 0x0, - BitmapCompressZ = 0x677a, - BitmapCompressBz = 0x627a, - BitmapCompressLz = 0x6c7a, - BitmapCompressZs = 0x7a73 -} diff --git a/tanks-backend/DisplayCommands/Internals/HeaderBitmap.cs b/tanks-backend/DisplayCommands/Internals/HeaderBitmap.cs deleted file mode 100644 index b733995..0000000 --- a/tanks-backend/DisplayCommands/Internals/HeaderBitmap.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Runtime.InteropServices; -using EndiannessSourceGenerator; - -namespace DisplayCommands.Internals; - -[StructEndianness(IsLittleEndian = false)] -[StructLayout(LayoutKind.Sequential, Pack = 16, Size = 10)] -internal partial struct HeaderBitmap -{ - private ushort _command; - - private ushort _offset; - - private ushort _length; - - private ushort _subCommand; - - private ushort _reserved; -} diff --git a/tanks-backend/DisplayCommands/Internals/HeaderWindow.cs b/tanks-backend/DisplayCommands/Internals/HeaderWindow.cs deleted file mode 100644 index 2be4916..0000000 --- a/tanks-backend/DisplayCommands/Internals/HeaderWindow.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Runtime.InteropServices; -using EndiannessSourceGenerator; - -namespace DisplayCommands.Internals; - -[StructEndianness(IsLittleEndian = false)] -[StructLayout(LayoutKind.Sequential, Pack = 16, Size = 10)] -internal partial struct HeaderWindow -{ - private ushort _command; - - private ushort _posX; - - private ushort _posY; - - private ushort _width; - - private ushort _height; -} diff --git a/tanks-backend/DisplayCommands/PixelGrid.cs b/tanks-backend/DisplayCommands/PixelGrid.cs deleted file mode 100644 index 5006ddb..0000000 --- a/tanks-backend/DisplayCommands/PixelGrid.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Diagnostics; - -namespace DisplayCommands; - -public sealed class PixelGrid(ushort width, ushort height) : IEquatable -{ - private readonly ByteGrid _byteGrid = new((ushort)(width / 8u), height); - - public ushort Width { get; } = width; - - public ushort Height { get; } = height; - - public Memory Data => _byteGrid.Data; - - public bool this[ushort x, ushort y] - { - get - { - Debug.Assert(y < Height); - var (byteIndex, bitInByteMask) = GetIndexes(x); - var byteVal = _byteGrid[byteIndex, y]; - return (byteVal & bitInByteMask) != 0; - } - set - { - Debug.Assert(y < Height); - var (byteIndex, bitInByteMask) = GetIndexes(x); - if (value) - _byteGrid[byteIndex, y] |= bitInByteMask; - else - _byteGrid[byteIndex, y] &= (byte)(ushort.MaxValue ^ bitInByteMask); - } - } - - public void Clear() => _byteGrid.Clear(); - - public bool Equals(PixelGrid? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return Width == other.Width && Height == other.Height && _byteGrid.Equals(other._byteGrid); - } - - public override bool Equals(object? obj) => ReferenceEquals(this, obj) || (obj is PixelGrid other && Equals(other)); - public override int GetHashCode() => HashCode.Combine(_byteGrid, Width, Height); - public static bool operator ==(PixelGrid? left, PixelGrid? right) => Equals(left, right); - public static bool operator !=(PixelGrid? left, PixelGrid? right) => !Equals(left, right); - - private (ushort byteIndex, byte bitInByteMask) GetIndexes(int x) - { - Debug.Assert(x < Width); - var byteIndex = (ushort)(x / 8); - Debug.Assert(byteIndex < Width); - var bitInByteIndex = (byte)(7 - x % 8); - Debug.Assert(bitInByteIndex < 8); - var bitInByteMask = (byte)(1 << bitInByteIndex); - return (byteIndex, bitInByteMask); - } -} diff --git a/tanks-backend/EndiannessSourceGenerator/EndiannessGenerator.cs b/tanks-backend/EndiannessSourceGenerator/EndiannessGenerator.cs deleted file mode 100644 index eb772e5..0000000 --- a/tanks-backend/EndiannessSourceGenerator/EndiannessGenerator.cs +++ /dev/null @@ -1,260 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - -namespace EndiannessSourceGenerator; - -internal class DebugMeException(string message) : Exception(message); - -internal class InvalidUsageException(string message) : Exception(message); - -[Generator] -public class StructEndiannessSourceGenerator : ISourceGenerator -{ - private const string Namespace = "EndiannessSourceGenerator"; - private const string AttributeName = "StructEndiannessAttribute"; - private const string IsLittleEndianProperty = "IsLittleEndian"; - - private const string AttributeSourceCode = - $$""" - // - namespace {{Namespace}} - { - [System.AttributeUsage(System.AttributeTargets.Struct)] - public class {{AttributeName}}: System.Attribute - { - public required bool {{IsLittleEndianProperty}} { get; init; } - } - } - """; - - public void Initialize(GeneratorInitializationContext context) - { - // Register the attribute source - context.RegisterForPostInitialization(i => i.AddSource($"{AttributeName}.g.cs", AttributeSourceCode)); - } - - public void Execute(GeneratorExecutionContext context) - { - var treesWithStructsWithAttributes = context.Compilation.SyntaxTrees - .Where(st => st.GetRoot().DescendantNodes() - .OfType() - .Any(p => p.DescendantNodes() - .OfType() - .Any())) - .ToList(); - - foreach (var tree in treesWithStructsWithAttributes) - { - var semanticModel = context.Compilation.GetSemanticModel(tree); - - var structsWithAttributes = tree.GetRoot().DescendantNodes() - .OfType() - .Where(cd => cd.DescendantNodes() - .OfType() - .Any()); - - foreach (var structDeclaration in structsWithAttributes) - { - var foundAttribute = GetEndiannessAttribute(structDeclaration, semanticModel); - if (foundAttribute == null) - continue; // not my type - - var structIsLittleEndian = GetStructIsLittleEndian(foundAttribute); - HandleStruct(context, structDeclaration, semanticModel, structIsLittleEndian); - } - } - } - - private static void HandleStruct(GeneratorExecutionContext context, TypeDeclarationSyntax structDeclaration, - SemanticModel semanticModel, bool structIsLittleEndian) - { - var isPartial = structDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword)); - if (!isPartial) - throw new InvalidUsageException("struct is not marked partial"); - - var accessibilityModifier = structDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.InternalKeyword)) - ? Token(SyntaxKind.InternalKeyword) - : Token(SyntaxKind.PublicKeyword); - - var structType = semanticModel.GetDeclaredSymbol(structDeclaration); - if (structType == null) - throw new DebugMeException("struct type info is null"); - - var structNamespace = structType.ContainingNamespace?.ToDisplayString(); - if (structNamespace == null) - throw new InvalidUsageException("struct has to be contained in a namespace"); - - if (structDeclaration.Members.Any(m => m.IsKind(SyntaxKind.PropertyDeclaration))) - throw new InvalidUsageException("struct cannot have properties"); - - var fieldDeclarations = structDeclaration.Members - .Where(m => m.IsKind(SyntaxKind.FieldDeclaration)).OfType(); - - var generatedCode = CompilationUnit() - .WithUsings(List([ - UsingDirective(IdentifierName("System")), - UsingDirective(IdentifierName("System.Buffers.Binary")) - ])) - .WithMembers(List([ - FileScopedNamespaceDeclaration(IdentifierName(structNamespace)), - StructDeclaration(structType.Name) - .WithModifiers(TokenList([accessibilityModifier, Token(SyntaxKind.PartialKeyword)])) - .WithMembers(GenerateStructProperties(fieldDeclarations, semanticModel, structIsLittleEndian)) - ])) - .NormalizeWhitespace() - .ToFullString(); - - context.AddSource( - $"{structNamespace}.{structType.Name}.g.cs", - SourceText.From(generatedCode, Encoding.UTF8) - ); - } - - private static SyntaxList GenerateStructProperties( - IEnumerable fieldDeclarations, SemanticModel semanticModel, bool structIsLittleEndian) - { - var result = new List(); - foreach (var field in fieldDeclarations) - { - if (!field.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))) - throw new InvalidUsageException("fields have to be private"); - - var variableDeclaration = field.DescendantNodes() - .OfType() - .FirstOrDefault(); - if (variableDeclaration == null) - throw new DebugMeException("variable declaration of field declaration null"); - - var variableTypeInfo = semanticModel.GetTypeInfo(variableDeclaration.Type).Type; - if (variableTypeInfo == null) - throw new DebugMeException("variable type info of field declaration null"); - - var typeName = variableTypeInfo.ToDisplayString(); - var fieldName = variableDeclaration.Variables.First().Identifier.ToString(); - - result.Add(GenerateProperty(typeName, structIsLittleEndian, fieldName)); - } - - return new SyntaxList(result); - } - - private static PropertyDeclarationSyntax GenerateProperty(string typeName, - bool structIsLittleEndian, string fieldName) - { - var propertyName = GeneratePropertyName(fieldName); - var fieldIdentifier = IdentifierName(fieldName); - - ExpressionSyntax condition = MemberAccessExpression( - kind: SyntaxKind.SimpleMemberAccessExpression, - expression: IdentifierName("BitConverter"), - name: IdentifierName("IsLittleEndian") - ); - - if (!structIsLittleEndian) - condition = PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, condition); - - var reverseEndiannessMethod = MemberAccessExpression( - kind: SyntaxKind.SimpleMemberAccessExpression, - expression: IdentifierName("BinaryPrimitives"), - name: IdentifierName("ReverseEndianness") - ); - - var valueIdentifier = IdentifierName("value"); - - return PropertyDeclaration(ParseTypeName(typeName), propertyName) - .WithModifiers(TokenList([Token(SyntaxKind.PublicKeyword)])) - .WithAccessorList(AccessorList(List([ - AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) - .WithExpressionBody(ArrowExpressionClause(ConditionalExpression( - condition: condition, - whenTrue: fieldIdentifier, - whenFalse: InvocationExpression( - expression: reverseEndiannessMethod, - argumentList: ArgumentList(SingletonSeparatedList( - Argument(fieldIdentifier) - )) - ) - ))) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)), - AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) - .WithExpressionBody(ArrowExpressionClause(AssignmentExpression( - kind: SyntaxKind.SimpleAssignmentExpression, - left: fieldIdentifier, - right: ConditionalExpression( - condition: condition, - whenTrue: valueIdentifier, - whenFalse: InvocationExpression( - expression: reverseEndiannessMethod, - argumentList: ArgumentList(SingletonSeparatedList( - Argument(valueIdentifier) - )) - ) - ) - ))) - .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) - ])) - ); - } - - private static SyntaxToken GeneratePropertyName(string fieldName) - { - var propertyName = fieldName; - if (propertyName.StartsWith("_")) - propertyName = propertyName.Substring(1); - if (!char.IsLetter(propertyName, 0) || char.IsUpper(propertyName, 0)) - throw new InvalidUsageException("field names have to start with a lower case letter"); - propertyName = propertyName.Substring(0, 1).ToUpperInvariant() - + propertyName.Substring(1); - return Identifier(propertyName); - } - - private static AttributeSyntax? GetEndiannessAttribute(SyntaxNode structDeclaration, SemanticModel semanticModel) - { - AttributeSyntax? foundAttribute = null; - foreach (var attributeSyntax in structDeclaration.DescendantNodes().OfType()) - { - var attributeTypeInfo = semanticModel.GetTypeInfo(attributeSyntax).Type; - if (attributeTypeInfo == null) - throw new DebugMeException("attribute type info is null"); - - if (attributeTypeInfo.ContainingNamespace?.Name != Namespace) - continue; - if (attributeTypeInfo.Name != AttributeName) - continue; - - foundAttribute = attributeSyntax; - break; - } - - return foundAttribute; - } - - private static bool GetStructIsLittleEndian(AttributeSyntax foundAttribute) - { - var endiannessArguments = foundAttribute.ArgumentList; - if (endiannessArguments == null) - throw new InvalidUsageException("endianness attribute has no arguments"); - - var isLittleEndianArgumentSyntax = endiannessArguments.Arguments - .FirstOrDefault(argumentSyntax => - argumentSyntax.NameEquals?.Name.Identifier.ToString() == IsLittleEndianProperty); - if (isLittleEndianArgumentSyntax == null) - throw new InvalidUsageException("endianness attribute argument not found"); - - bool? structIsLittleEndian = isLittleEndianArgumentSyntax.Expression.Kind() switch - { - SyntaxKind.FalseLiteralExpression => false, - SyntaxKind.TrueLiteralExpression => true, - SyntaxKind.DefaultLiteralExpression => false, - _ => throw new InvalidUsageException($"{IsLittleEndianProperty} has to be set with a literal") - }; - return structIsLittleEndian.Value; - } -} diff --git a/tanks-backend/EndiannessSourceGenerator/EndiannessSourceGenerator.csproj b/tanks-backend/EndiannessSourceGenerator/EndiannessSourceGenerator.csproj deleted file mode 100644 index ae25c62..0000000 --- a/tanks-backend/EndiannessSourceGenerator/EndiannessSourceGenerator.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - netstandard2.0 - false - enable - latest - - true - true - EndiannessSourceGenerator - false - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - diff --git a/tanks-backend/EndiannessSourceGenerator/Properties/launchSettings.json b/tanks-backend/EndiannessSourceGenerator/Properties/launchSettings.json deleted file mode 100644 index b8b1379..0000000 --- a/tanks-backend/EndiannessSourceGenerator/Properties/launchSettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "profiles": { - "Generators": { - "commandName": "DebugRoslynComponent", - "targetProject": "../DisplayCommands/DisplayCommands.csproj" - } - } -} diff --git a/tanks-backend/EndiannessSourceGenerator/Readme.md b/tanks-backend/EndiannessSourceGenerator/Readme.md deleted file mode 100644 index a69efd1..0000000 --- a/tanks-backend/EndiannessSourceGenerator/Readme.md +++ /dev/null @@ -1,5 +0,0 @@ -# Endianness Source Generator - -When annotating a struct with the `StructEndianness` attribute, this code generator will generate properties for the declared fields. - -Each time a property is read or written, the endianness is converted from runtime endianness to struct endianness or vice-versa. diff --git a/tanks-backend/TanksServer.sln b/tanks-backend/TanksServer.sln index fc3a074..b28b08a 100644 --- a/tanks-backend/TanksServer.sln +++ b/tanks-backend/TanksServer.sln @@ -2,10 +2,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TanksServer", "TanksServer\TanksServer.csproj", "{D88BF376-47A4-4C72-ADD1-983F9285C351}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DisplayCommands", "DisplayCommands\DisplayCommands.csproj", "{B4B43561-7A2C-486B-99F7-E58A67BC370A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EndiannessSourceGenerator", "EndiannessSourceGenerator\EndiannessSourceGenerator.csproj", "{D77FE880-F2B8-43B6-8B33-B6FA089CC337}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{12DB7D48-1BB2-488B-B4D9-4126087D2F8C}" ProjectSection(SolutionItems) = preProject global.json = global.json @@ -13,6 +9,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{12DB7D Dockerfile = Dockerfile EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint2", "..\..\servicepoint2\servicepoint2-binding-cs\ServicePoint2\ServicePoint2.csproj", "{BC27CED4-82FE-4CD4-B784-B7596586801D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -23,13 +21,9 @@ Global {D88BF376-47A4-4C72-ADD1-983F9285C351}.Debug|Any CPU.Build.0 = Debug|Any CPU {D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.ActiveCfg = Release|Any CPU {D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.Build.0 = Release|Any CPU - {B4B43561-7A2C-486B-99F7-E58A67BC370A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4B43561-7A2C-486B-99F7-E58A67BC370A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B4B43561-7A2C-486B-99F7-E58A67BC370A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B4B43561-7A2C-486B-99F7-E58A67BC370A}.Release|Any CPU.Build.0 = Release|Any CPU - {D77FE880-F2B8-43B6-8B33-B6FA089CC337}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D77FE880-F2B8-43B6-8B33-B6FA089CC337}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D77FE880-F2B8-43B6-8B33-B6FA089CC337}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D77FE880-F2B8-43B6-8B33-B6FA089CC337}.Release|Any CPU.Build.0 = Release|Any CPU + {BC27CED4-82FE-4CD4-B784-B7596586801D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC27CED4-82FE-4CD4-B784-B7596586801D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC27CED4-82FE-4CD4-B784-B7596586801D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC27CED4-82FE-4CD4-B784-B7596586801D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/tanks-backend/TanksServer/Endpoints.cs b/tanks-backend/TanksServer/Endpoints.cs index 1456f0f..99da3b1 100644 --- a/tanks-backend/TanksServer/Endpoints.cs +++ b/tanks-backend/TanksServer/Endpoints.cs @@ -1,13 +1,13 @@ using System.IO; using System.Text; using System.Text.Json; -using DisplayCommands; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Diagnostics.HealthChecks; +using ServicePoint2; using TanksServer.GameLogic; using TanksServer.Interactivity; @@ -19,7 +19,7 @@ internal sealed class Endpoints( ControlsServer controlsServer, MapService mapService, ChangeToRequestedMap changeToRequestedMap, - IDisplayConnection displayConnection + Connection displayConnection ) { public void Map(WebApplication app) @@ -31,7 +31,7 @@ internal sealed class Endpoints( app.Map("/controls", ConnectControlsAsync); app.MapGet("/map", () => mapService.MapNames); app.MapPost("/map", PostMap); - app.MapPost("/resetDisplay", displayConnection.SendHardResetAsync); + app.MapPost("/resetDisplay", () => displayConnection.Send(Command.HardReset())); app.MapGet("/map/{name}", GetMapByName); app.MapHealthChecks("/health", new HealthCheckOptions @@ -117,7 +117,7 @@ internal sealed class Endpoints( if (!mapService.TryGetPreview(name, out var preview)) return TypedResults.NotFound(); - var mapInfo = new MapInfo(prototype.Name, prototype.GetType().Name, preview.Data); + var mapInfo = new MapInfo(prototype.Name, prototype.GetType().Name, preview.Data.ToArray()); return TypedResults.Ok(mapInfo); } diff --git a/tanks-backend/TanksServer/GameLogic/MapService.cs b/tanks-backend/TanksServer/GameLogic/MapService.cs index 28a5aef..753d007 100644 --- a/tanks-backend/TanksServer/GameLogic/MapService.cs +++ b/tanks-backend/TanksServer/GameLogic/MapService.cs @@ -1,7 +1,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; -using DisplayCommands; +using ServicePoint2; using TanksServer.Graphics; namespace TanksServer.GameLogic; @@ -42,7 +42,7 @@ internal sealed class MapService if (!_mapPrototypes.TryGetValue(name, out var prototype)) return false; // name not found - pixelGrid = new PixelGrid(PixelsPerRow, PixelsPerColumn); + pixelGrid = PixelGrid.New(PixelsPerRow, PixelsPerColumn); DrawMapStep.Draw(pixelGrid, prototype.CreateInstance()); _mapPreviews.TryAdd(name, pixelGrid); // another thread may have added the map already diff --git a/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs b/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs index 3107b71..b79abb0 100644 --- a/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs +++ b/tanks-backend/TanksServer/GameLogic/SpawnPowerUp.cs @@ -1,5 +1,3 @@ -using System.Diagnostics; - namespace TanksServer.GameLogic; internal sealed class SpawnPowerUp( diff --git a/tanks-backend/TanksServer/Graphics/DrawMapStep.cs b/tanks-backend/TanksServer/Graphics/DrawMapStep.cs index 3be6a37..3fc59b5 100644 --- a/tanks-backend/TanksServer/Graphics/DrawMapStep.cs +++ b/tanks-backend/TanksServer/Graphics/DrawMapStep.cs @@ -1,4 +1,4 @@ -using DisplayCommands; +using ServicePoint2; using TanksServer.GameLogic; namespace TanksServer.Graphics; diff --git a/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs b/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs index 7edf1a0..de83cbb 100644 --- a/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs +++ b/tanks-backend/TanksServer/Graphics/GeneratePixelsTickStep.cs @@ -1,4 +1,4 @@ -using DisplayCommands; +using ServicePoint2; using TanksServer.GameLogic; using TanksServer.Interactivity; @@ -10,9 +10,9 @@ internal sealed class GeneratePixelsTickStep( ) : ITickStep { private GamePixelGrid _lastGamePixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn); - private PixelGrid _lastObserverPixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn); + private PixelGrid _lastObserverPixelGrid = PixelGrid.New(MapService.PixelsPerRow, MapService.PixelsPerColumn); private GamePixelGrid _gamePixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn); - private PixelGrid _observerPixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn); + private PixelGrid _observerPixelGrid = PixelGrid.New(MapService.PixelsPerRow, MapService.PixelsPerColumn); private readonly List _drawSteps = drawSteps.ToList(); private readonly List _consumers = consumers.ToList(); @@ -20,7 +20,7 @@ internal sealed class GeneratePixelsTickStep( public async ValueTask TickAsync(TimeSpan _) { Draw(_gamePixelGrid, _observerPixelGrid); - if (_observerPixelGrid.Data.Span.SequenceEqual(_lastObserverPixelGrid.Data.Span)) + if (_observerPixelGrid.Data.SequenceEqual(_lastObserverPixelGrid.Data)) return; await _consumers.Select(c => c.OnFrameDoneAsync(_gamePixelGrid, _observerPixelGrid)) @@ -36,7 +36,7 @@ internal sealed class GeneratePixelsTickStep( foreach (var step in _drawSteps) step.Draw(gamePixelGrid); - observerPixelGrid.Clear(); + observerPixelGrid.Fill(false); for (var y = 0; y < MapService.PixelsPerColumn; y++) for (var x = 0; x < MapService.PixelsPerRow; x++) { diff --git a/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs b/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs index 5a83a86..9ee8d3e 100644 --- a/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs +++ b/tanks-backend/TanksServer/Graphics/IFrameConsumer.cs @@ -1,4 +1,4 @@ -using DisplayCommands; +using ServicePoint2; namespace TanksServer.Graphics; diff --git a/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs b/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs index 6955c4d..2832fba 100644 --- a/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs +++ b/tanks-backend/TanksServer/Interactivity/ClientScreenServer.cs @@ -1,5 +1,5 @@ using System.Net.WebSockets; -using DisplayCommands; +using ServicePoint2; using TanksServer.Graphics; namespace TanksServer.Interactivity; diff --git a/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs b/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs index 6208cbf..483176a 100644 --- a/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs +++ b/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs @@ -1,6 +1,6 @@ using System.Buffers; using System.Net.WebSockets; -using DisplayCommands; +using ServicePoint2; using TanksServer.Graphics; namespace TanksServer.Interactivity; @@ -36,8 +36,9 @@ internal sealed class ClientScreenServerConnection private Package BuildNextPackage(PixelGrid pixels, GamePixelGrid gamePixelGrid) { - var nextPixels = _bufferPool.Rent(pixels.Data.Length); - pixels.Data.CopyTo(nextPixels.Memory); + var pixelsData = pixels.Data; + var nextPixels = _bufferPool.Rent(pixelsData.Length); + pixelsData.CopyTo(nextPixels.Memory.Span); if (_playerDataBuilder == null) return new Package(nextPixels, null); diff --git a/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs b/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs index a81d2c4..6340fbc 100644 --- a/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs +++ b/tanks-backend/TanksServer/Interactivity/PlayerInfoConnection.cs @@ -13,7 +13,7 @@ internal sealed class PlayerInfoConnection private readonly MapEntityManager _entityManager; private readonly BufferPool _bufferPool; private readonly MemoryStream _tempStream = new(); - private IMemoryOwner? _lastMessage = null; + private IMemoryOwner? _lastMessage; public PlayerInfoConnection( Player player, diff --git a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs index fc64cc9..0c7cc7d 100644 --- a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs +++ b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs @@ -1,6 +1,7 @@ using System.Diagnostics; +using System.Net; using System.Net.Sockets; -using DisplayCommands; +using ServicePoint2; using TanksServer.GameLogic; using TanksServer.Graphics; @@ -12,11 +13,11 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer private const int ScoresHeight = 20; private const int ScoresPlayerRows = ScoresHeight - 6; - private readonly IDisplayConnection _displayConnection; + private readonly Connection _displayConnection; private readonly MapService _mapService; private readonly ILogger _logger; private readonly PlayerServer _players; - private readonly Cp437Grid _scoresBuffer; + private readonly ByteGrid _scoresBuffer; private readonly TimeSpan _minFrameTime; private readonly IOptionsMonitor _options; @@ -26,11 +27,11 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer public SendToServicePointDisplay( PlayerServer players, ILogger logger, - IDisplayConnection displayConnection, + Connection displayConnection, IOptions hostOptions, MapService mapService, - IOptionsMonitor options - ) + IOptionsMonitor options, + IOptions displayConfig) { _players = players; _logger = logger; @@ -39,16 +40,15 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer _minFrameTime = TimeSpan.FromMilliseconds(hostOptions.Value.ServicePointDisplayMinFrameTimeMs); _options = options; - var localIp = _displayConnection.GetLocalIPv4().Split('.'); + var localIp = GetLocalIPv4(displayConfig.Value).Split('.'); Debug.Assert(localIp.Length == 4); - _scoresBuffer = new Cp437Grid(12, 20) - { - [00] = "== TANKS! ==", - [01] = "-- scores --", - [17] = "-- join --", - [18] = string.Join('.', localIp[..2]), - [19] = string.Join('.', localIp[2..]) - }; + _scoresBuffer = ByteGrid.New(12, 20); + + _scoresBuffer[00] = "== TANKS! =="; + _scoresBuffer[01] = "-- scores --"; + _scoresBuffer[17] = "-- join --"; + _scoresBuffer[18] = string.Join('.', localIp[..2]); + _scoresBuffer[19] = string.Join('.', localIp[2..]); } public async Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, PixelGrid observerPixels) @@ -66,8 +66,8 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer try { - await _displayConnection.SendBitmapLinearWindowAsync(0, 0, observerPixels); - await _displayConnection.SendCp437DataAsync(MapService.TilesPerRow, 0, _scoresBuffer); + _displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone())); + _displayConnection.Send(Command.Cp437Data(MapService.TilesPerRow, 0, _scoresBuffer.Clone())); } catch (SocketException ex) { @@ -103,4 +103,12 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer _scoresBuffer[16] = _mapService.Current.Name[..(Math.Min(ScoresWidth, _mapService.Current.Name.Length) - 1)]; } + + private static string GetLocalIPv4(DisplayConfiguration configuration) + { + using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0); + socket.Connect(configuration.Hostname, configuration.Port); + var endPoint = socket.LocalEndPoint as IPEndPoint ?? throw new NotSupportedException(); + return endPoint.Address.ToString(); + } } diff --git a/tanks-backend/DisplayCommands/DisplayConfiguration.cs b/tanks-backend/TanksServer/Models/DisplayConfiguration.cs similarity index 81% rename from tanks-backend/DisplayCommands/DisplayConfiguration.cs rename to tanks-backend/TanksServer/Models/DisplayConfiguration.cs index ff3cf05..fc9e941 100644 --- a/tanks-backend/DisplayCommands/DisplayConfiguration.cs +++ b/tanks-backend/TanksServer/Models/DisplayConfiguration.cs @@ -1,8 +1,8 @@ -namespace DisplayCommands; +namespace TanksServer.Models; public class DisplayConfiguration { public string Hostname { get; set; } = "172.23.42.29"; public int Port { get; set; } = 2342; -} \ No newline at end of file +} diff --git a/tanks-backend/TanksServer/Program.cs b/tanks-backend/TanksServer/Program.cs index efe9bb4..89c71ae 100644 --- a/tanks-backend/TanksServer/Program.cs +++ b/tanks-backend/TanksServer/Program.cs @@ -1,8 +1,9 @@ using System.IO; -using DisplayCommands; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using ServicePoint2; +using SixLabors.ImageSharp; using TanksServer.GameLogic; using TanksServer.Graphics; using TanksServer.Interactivity; @@ -94,9 +95,14 @@ public static class Program builder.Services.Configure(builder.Configuration.GetSection("GameRules")); builder.Services.Configure(builder.Configuration.GetSection("Host")); + builder.Services.Configure(builder.Configuration.GetSection("ServicePointDisplay")); builder.Services.AddSingleton(); - builder.Services.AddDisplay(builder.Configuration.GetSection("ServicePointDisplay")); + builder.Services.AddSingleton(sp => + { + var config = sp.GetRequiredService>().Value; + return Connection.Open($"{config.Hostname}:{config.Port}"); + }); var app = builder.Build(); diff --git a/tanks-backend/TanksServer/TanksServer.csproj b/tanks-backend/TanksServer/TanksServer.csproj index 4cce028..8da3166 100644 --- a/tanks-backend/TanksServer/TanksServer.csproj +++ b/tanks-backend/TanksServer/TanksServer.csproj @@ -10,11 +10,14 @@ - + + + + diff --git a/tanks-backend/TanksServer/appsettings.json b/tanks-backend/TanksServer/appsettings.json index 0eaa26e..4555c28 100644 --- a/tanks-backend/TanksServer/appsettings.json +++ b/tanks-backend/TanksServer/appsettings.json @@ -16,7 +16,8 @@ } }, "ServicePointDisplay": { - "Hostname": "172.23.42.29", + //"Hostname": "172.23.42.29", + "Hostname": "127.0.0.1", "Port": 2342 }, "GameRules": { From 1551370655cea43fb5ee42d4be3f682e8a771c47 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Mon, 13 May 2024 21:19:50 +0200 Subject: [PATCH 09/15] simplify folder structure --- package-lock.json | 6 ------ tanks-backend/TanksServer.sln | 8 -------- tanks-backend/TanksServer/TanksServer.csproj | 19 ++++++++++++++----- tanks-backend/global.json | 6 ------ tanks-backend/shared.props | 20 -------------------- 5 files changed, 14 insertions(+), 45 deletions(-) delete mode 100644 package-lock.json delete mode 100644 tanks-backend/global.json delete mode 100644 tanks-backend/shared.props diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index fa1abcd..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "cccb-tanks-cs", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/tanks-backend/TanksServer.sln b/tanks-backend/TanksServer.sln index b28b08a..c4a9016 100644 --- a/tanks-backend/TanksServer.sln +++ b/tanks-backend/TanksServer.sln @@ -4,13 +4,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TanksServer", "TanksServer\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{12DB7D48-1BB2-488B-B4D9-4126087D2F8C}" ProjectSection(SolutionItems) = preProject - global.json = global.json - shared.props = shared.props Dockerfile = Dockerfile EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint2", "..\..\servicepoint2\servicepoint2-binding-cs\ServicePoint2\ServicePoint2.csproj", "{BC27CED4-82FE-4CD4-B784-B7596586801D}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,9 +17,5 @@ Global {D88BF376-47A4-4C72-ADD1-983F9285C351}.Debug|Any CPU.Build.0 = Debug|Any CPU {D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.ActiveCfg = Release|Any CPU {D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.Build.0 = Release|Any CPU - {BC27CED4-82FE-4CD4-B784-B7596586801D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BC27CED4-82FE-4CD4-B784-B7596586801D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BC27CED4-82FE-4CD4-B784-B7596586801D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BC27CED4-82FE-4CD4-B784-B7596586801D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/tanks-backend/TanksServer/TanksServer.csproj b/tanks-backend/TanksServer/TanksServer.csproj index 8da3166..a2845d3 100644 --- a/tanks-backend/TanksServer/TanksServer.csproj +++ b/tanks-backend/TanksServer/TanksServer.csproj @@ -1,14 +1,27 @@ - + + net8.0 + disable + enable + true + true + true + + + + Recommended + true + CA1805,CA1848 + @@ -16,8 +29,4 @@ - - - - diff --git a/tanks-backend/global.json b/tanks-backend/global.json deleted file mode 100644 index 8eb62be..0000000 --- a/tanks-backend/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sdk": { - "version": "8.0.0", - "rollForward": "latestMajor" - } -} diff --git a/tanks-backend/shared.props b/tanks-backend/shared.props deleted file mode 100644 index 2417333..0000000 --- a/tanks-backend/shared.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - net8.0 - disable - enable - - - - true - true - - - - Recommended - true - CA1805,CA1848 - - - From 448cedc84ce1b3045ac55bc7710a778e9b0a7e8a Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Mon, 13 May 2024 21:24:45 +0200 Subject: [PATCH 10/15] add servicepoint library as submodule --- .gitmodules | 3 +++ tanks-backend/servicepoint | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 tanks-backend/servicepoint diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..75a838a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "tanks-backend/servicepoint"] + path = tanks-backend/servicepoint + url = https://github.com/kaesaecracker/servicepoint.git diff --git a/tanks-backend/servicepoint b/tanks-backend/servicepoint new file mode 160000 index 0000000..ea7061d --- /dev/null +++ b/tanks-backend/servicepoint @@ -0,0 +1 @@ +Subproject commit ea7061db7f528e0fd304c845350a1c3b5a20338d From 0f00c2ff6c97a903383c9c8dea88d9f8d2dbfcde Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Mon, 13 May 2024 21:50:59 +0200 Subject: [PATCH 11/15] add servicepoint to solution --- tanks-backend/TanksServer.sln | 6 ++++++ tanks-backend/TanksServer/TanksServer.csproj | 5 ++++- tanks-backend/servicepoint | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tanks-backend/TanksServer.sln b/tanks-backend/TanksServer.sln index c4a9016..f26467a 100644 --- a/tanks-backend/TanksServer.sln +++ b/tanks-backend/TanksServer.sln @@ -7,6 +7,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{12DB7D Dockerfile = Dockerfile EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint2", "servicepoint\servicepoint2-binding-cs\src\ServicePoint2.csproj", "{DFCC69ED-E02B-4631-8A23-5D394BA01E03}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -17,5 +19,9 @@ Global {D88BF376-47A4-4C72-ADD1-983F9285C351}.Debug|Any CPU.Build.0 = Debug|Any CPU {D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.ActiveCfg = Release|Any CPU {D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.Build.0 = Release|Any CPU + {DFCC69ED-E02B-4631-8A23-5D394BA01E03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFCC69ED-E02B-4631-8A23-5D394BA01E03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFCC69ED-E02B-4631-8A23-5D394BA01E03}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFCC69ED-E02B-4631-8A23-5D394BA01E03}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/tanks-backend/TanksServer/TanksServer.csproj b/tanks-backend/TanksServer/TanksServer.csproj index a2845d3..aefb03e 100644 --- a/tanks-backend/TanksServer/TanksServer.csproj +++ b/tanks-backend/TanksServer/TanksServer.csproj @@ -21,7 +21,6 @@ - @@ -29,4 +28,8 @@ + + + + diff --git a/tanks-backend/servicepoint b/tanks-backend/servicepoint index ea7061d..51685f0 160000 --- a/tanks-backend/servicepoint +++ b/tanks-backend/servicepoint @@ -1 +1 @@ -Subproject commit ea7061db7f528e0fd304c845350a1c3b5a20338d +Subproject commit 51685f038c7560e3e4d03d5023a73f3d70471648 From d11cea32fb03cf061f955073cc17fbaa05613cc8 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Tue, 14 May 2024 00:05:27 +0200 Subject: [PATCH 12/15] update servicepoint --- tanks-backend/servicepoint | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tanks-backend/servicepoint b/tanks-backend/servicepoint index 51685f0..9b618d9 160000 --- a/tanks-backend/servicepoint +++ b/tanks-backend/servicepoint @@ -1 +1 @@ -Subproject commit 51685f038c7560e3e4d03d5023a73f3d70471648 +Subproject commit 9b618d931a7ea12e745f3adaca6116806c37fe6a From ff70f21416fc6273c0abe428d4f13f8f2f993f52 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 15 May 2024 20:37:56 +0200 Subject: [PATCH 13/15] fix podman build --- tanks-backend/.dockerignore | 2 ++ tanks-backend/Dockerfile | 10 +--------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/tanks-backend/.dockerignore b/tanks-backend/.dockerignore index d041927..5aba7dc 100644 --- a/tanks-backend/.dockerignore +++ b/tanks-backend/.dockerignore @@ -11,3 +11,5 @@ **/bin **/Dockerfile* **/obj +**/target +**/examples diff --git a/tanks-backend/Dockerfile b/tanks-backend/Dockerfile index 4fcda7d..af7acd4 100644 --- a/tanks-backend/Dockerfile +++ b/tanks-backend/Dockerfile @@ -1,18 +1,10 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build-server RUN apk add clang binutils musl-dev build-base zlib-static cmake openssl-dev openssl-libs-static openssl +RUN apk add rust cargo WORKDIR /src/tanks-server -# dependencies -COPY ./shared.props . -COPY ./TanksServer.sln . -COPY ./EndiannessSourceGenerator/EndiannessSourceGenerator.csproj EndiannessSourceGenerator/EndiannessSourceGenerator.csproj -COPY ./DisplayCommands/DisplayCommands.csproj DisplayCommands/DisplayCommands.csproj -COPY ./TanksServer/TanksServer.csproj TanksServer/TanksServer.csproj -RUN dotnet restore --runtime linux-musl-x64 TanksServer.sln - -#build COPY . . RUN dotnet build TanksServer/TanksServer.csproj -c Release -r linux-musl-x64 -o /build RUN dotnet publish TanksServer/TanksServer.csproj -c Release -r linux-musl-x64 -o /app From 167aafc9e809540a84c3aef281b5047941aa1849 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 15 May 2024 20:38:16 +0200 Subject: [PATCH 14/15] update servicepoint2 --- tanks-backend/TanksServer/Endpoints.cs | 2 +- .../TanksServer/Interactivity/SendToServicePointDisplay.cs | 4 ++-- tanks-backend/servicepoint | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tanks-backend/TanksServer/Endpoints.cs b/tanks-backend/TanksServer/Endpoints.cs index 99da3b1..baf476b 100644 --- a/tanks-backend/TanksServer/Endpoints.cs +++ b/tanks-backend/TanksServer/Endpoints.cs @@ -31,7 +31,7 @@ internal sealed class Endpoints( app.Map("/controls", ConnectControlsAsync); app.MapGet("/map", () => mapService.MapNames); app.MapPost("/map", PostMap); - app.MapPost("/resetDisplay", () => displayConnection.Send(Command.HardReset())); + app.MapPost("/resetDisplay", () => displayConnection.Send(Command.HardReset().IntoPacket())); app.MapGet("/map/{name}", GetMapByName); app.MapHealthChecks("/health", new HealthCheckOptions diff --git a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs index 0c7cc7d..a21185b 100644 --- a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs +++ b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs @@ -66,8 +66,8 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer try { - _displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone())); - _displayConnection.Send(Command.Cp437Data(MapService.TilesPerRow, 0, _scoresBuffer.Clone())); + _displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone()).IntoPacket()); + _displayConnection.Send(Command.Cp437Data(MapService.TilesPerRow, 0, _scoresBuffer.Clone()).IntoPacket()); } catch (SocketException ex) { diff --git a/tanks-backend/servicepoint b/tanks-backend/servicepoint index 9b618d9..1dad113 160000 --- a/tanks-backend/servicepoint +++ b/tanks-backend/servicepoint @@ -1 +1 @@ -Subproject commit 9b618d931a7ea12e745f3adaca6116806c37fe6a +Subproject commit 1dad113ca1fab998bec9e2084e1751d640426619 From 10cff57ad53e2154a5ea038cca3b0bad5c940e7a Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Thu, 16 May 2024 23:40:00 +0200 Subject: [PATCH 15/15] update servicepoint2 to 0.4.0 --- .../TanksServer/Interactivity/SendToServicePointDisplay.cs | 4 +++- tanks-backend/servicepoint | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs index a21185b..3effe4d 100644 --- a/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs +++ b/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs @@ -4,6 +4,7 @@ using System.Net.Sockets; using ServicePoint2; using TanksServer.GameLogic; using TanksServer.Graphics; +using CompressionCode = ServicePoint2.BindGen.CompressionCode; namespace TanksServer.Interactivity; @@ -66,7 +67,8 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer try { - _displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone()).IntoPacket()); + _displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone(), CompressionCode.Lzma) + .IntoPacket()); _displayConnection.Send(Command.Cp437Data(MapService.TilesPerRow, 0, _scoresBuffer.Clone()).IntoPacket()); } catch (SocketException ex) diff --git a/tanks-backend/servicepoint b/tanks-backend/servicepoint index 1dad113..eab2d58 160000 --- a/tanks-backend/servicepoint +++ b/tanks-backend/servicepoint @@ -1 +1 @@ -Subproject commit 1dad113ca1fab998bec9e2084e1751d640426619 +Subproject commit eab2d58945ebf68a4a6e8cf69cf113875fe6168d