prepare to send different data per client

This commit is contained in:
Vinzenz Schroeter 2024-04-15 20:34:23 +02:00
parent fcd84d2c83
commit fbaad86555
15 changed files with 245 additions and 128 deletions

View file

@ -1,13 +1,16 @@
using DisplayCommands;
using TanksServer.GameLogic;
namespace TanksServer.Graphics;
internal sealed class DrawBulletsStep(BulletManager bullets) : IDrawStep
{
public void Draw(PixelGrid buffer)
public void Draw(GamePixelGrid pixels)
{
foreach (var position in bullets.GetAll().Select(b => b.Position.ToPixelPosition()))
buffer[(ushort)position.X, (ushort)position.Y] = true;
foreach (var bullet in bullets.GetAll())
{
var position = bullet.Position.ToPixelPosition();
pixels[position.X, position.Y].EntityType = GamePixelEntityType.Bullet;
pixels[position.X, position.Y].BelongsTo = bullet.Owner;
}
}
}

View file

@ -1,11 +1,10 @@
using DisplayCommands;
using TanksServer.GameLogic;
namespace TanksServer.Graphics;
internal sealed class DrawMapStep(MapService map) : IDrawStep
{
public void Draw(PixelGrid buffer)
public void Draw(GamePixelGrid pixels)
{
for (ushort y = 0; y < MapService.PixelsPerColumn; y++)
for (ushort x = 0; x < MapService.PixelsPerRow; x++)
@ -13,7 +12,8 @@ internal sealed class DrawMapStep(MapService map) : IDrawStep
var pixel = new PixelPosition(x, y);
if (!map.Current.IsWall(pixel))
continue;
buffer[x, y] = true;
pixels[x, y].EntityType = GamePixelEntityType.Wall;
}
}
}

View file

@ -27,7 +27,7 @@ internal sealed class DrawTanksStep : IDrawStep
_tankSpriteWidth = tankImage.Width;
}
public void Draw(PixelGrid buffer)
public void Draw(GamePixelGrid pixels)
{
foreach (var tank in _tanks)
{
@ -40,7 +40,8 @@ internal sealed class DrawTanksStep : IDrawStep
continue;
var (x, y) = tankPosition.GetPixelRelative(dx, dy);
buffer[(ushort)x, (ushort)y] = true;
pixels[x, y].EntityType = GamePixelEntityType.Tank;
pixels[x, y].BelongsTo = tank.Owner;
}
}
}

View file

@ -0,0 +1,21 @@
namespace TanksServer.Graphics;
internal sealed class GamePixel
{
public Player? BelongsTo { get; set; }
public GamePixelEntityType? EntityType { get; set; }
public void Clear()
{
BelongsTo = null;
EntityType = null;
}
}
internal enum GamePixelEntityType : byte
{
Wall = 0x0,
Tank = 0x1,
Bullet = 0x2
}

View file

@ -0,0 +1,47 @@
using System.Collections;
using System.Diagnostics;
namespace TanksServer.Graphics;
internal sealed class GamePixelGrid : IEnumerable<GamePixel>
{
public int Width { get; }
public int Height { get; }
private readonly GamePixel[,] _pixels;
public GamePixelGrid(int width, int height)
{
Width = width;
Height = height;
_pixels = new GamePixel[height, width];
for (var row = 0; row < height; row++)
for (var column = 0; column < width; column++)
_pixels[row, column] = new GamePixel();
}
public GamePixel this[int x, int y]
{
get
{
Debug.Assert(y * Width + x < _pixels.Length);
return _pixels[y, x];
}
}
public void Clear()
{
foreach (var pixel in _pixels)
pixel.Clear();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<GamePixel> GetEnumerator()
{
for (var row = 0; row < Height; row++)
for (var column = 0; column < Width; column++)
yield return _pixels[row, column];
}
}

View file

@ -5,18 +5,30 @@ namespace TanksServer.Graphics;
internal sealed class GeneratePixelsTickStep(
IEnumerable<IDrawStep> drawSteps,
LastFinishedFrameProvider lastFrameProvider
IEnumerable<IFrameConsumer> consumers
) : ITickStep
{
private readonly List<IDrawStep> _drawSteps = drawSteps.ToList();
private readonly PixelGrid _drawGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private readonly List<IFrameConsumer> _consumers = consumers.ToList();
public Task TickAsync()
private readonly PixelGrid _observerPixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private readonly GamePixelGrid _gamePixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
public async Task TickAsync()
{
_drawGrid.Clear();
_gamePixelGrid.Clear();
foreach (var step in _drawSteps)
step.Draw(_drawGrid);
lastFrameProvider.LastFrame = _drawGrid;
return Task.CompletedTask;
step.Draw(_gamePixelGrid);
_observerPixelGrid.Clear();
for (var y = 0; y < MapService.PixelsPerColumn; y++)
for (var x = 0; x < MapService.PixelsPerRow; x++)
{
if (_gamePixelGrid[x, y].EntityType.HasValue)
_observerPixelGrid[(ushort)x, (ushort)y] = true;
}
foreach (var consumer in _consumers)
await consumer.OnFrameDoneAsync(_gamePixelGrid, _observerPixelGrid);
}
}

View file

@ -4,5 +4,5 @@ namespace TanksServer.Graphics;
internal interface IDrawStep
{
void Draw(PixelGrid buffer);
void Draw(GamePixelGrid pixels);
}

View file

@ -0,0 +1,8 @@
using DisplayCommands;
namespace TanksServer.Graphics;
internal interface IFrameConsumer
{
Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, PixelGrid observerPixels);
}

View file

@ -1,14 +0,0 @@
using DisplayCommands;
namespace TanksServer.Graphics;
internal sealed class LastFinishedFrameProvider
{
private PixelGrid? _lastFrame;
public PixelGrid LastFrame
{
get => _lastFrame ?? throw new InvalidOperationException("first frame not yet drawn");
set => _lastFrame = value;
}
}