render current player in secondary color

This commit is contained in:
Vinzenz Schroeter 2024-04-16 00:07:44 +02:00
parent fbaad86555
commit c4c4eb6358
13 changed files with 255 additions and 72 deletions

View file

@ -15,10 +15,10 @@ internal sealed class GamePixelGrid : IEnumerable<GamePixel>
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();
_pixels = new GamePixel[width, height];
for (var y = 0; y < height; y++)
for (var x = 0; x < width; x++)
this[x, y] = new GamePixel();
}
public GamePixel this[int x, int y]
@ -26,8 +26,9 @@ internal sealed class GamePixelGrid : IEnumerable<GamePixel>
get
{
Debug.Assert(y * Width + x < _pixels.Length);
return _pixels[y, x];
return _pixels[x, y];
}
set => _pixels[x, y] = value;
}
public void Clear()
@ -40,8 +41,8 @@ internal sealed class GamePixelGrid : IEnumerable<GamePixel>
public IEnumerator<GamePixel> GetEnumerator()
{
for (var row = 0; row < Height; row++)
for (var column = 0; column < Width; column++)
yield return _pixels[row, column];
for (var y = 0; y < Height; y++)
for (var x = 0; x < Width; x++)
yield return this[x, y];
}
}

View file

@ -21,7 +21,7 @@ internal sealed class ClientScreenServer(
return Task.WhenAll(_connections.Keys.Select(c => c.CloseAsync()));
}
public Task HandleClient(WebSocket socket)
public Task HandleClient(WebSocket socket, Guid? playerGuid)
{
if (_closing)
{
@ -30,8 +30,11 @@ internal sealed class ClientScreenServer(
}
logger.LogDebug("HandleClient");
var connection =
new ClientScreenServerConnection(socket, loggerFactory.CreateLogger<ClientScreenServerConnection>(), this);
var connection = new ClientScreenServerConnection(
socket,
loggerFactory.CreateLogger<ClientScreenServerConnection>(),
this,
playerGuid);
var added = _connections.TryAdd(connection, 0);
Debug.Assert(added);
return connection.Done;

View file

@ -1,7 +1,6 @@
using System.Diagnostics;
using System.Net.WebSockets;
using DisplayCommands;
using TanksServer.GameLogic;
using TanksServer.Graphics;
namespace TanksServer.Interactivity;
@ -27,7 +26,7 @@ internal sealed class ClientScreenServerConnection : IDisposable
_playerGuid = playerGuid;
if (playerGuid.HasValue)
_playerScreenData = new PlayerScreenData();
_playerScreenData = new PlayerScreenData(logger);
_channel = new ByteChannelWebSocket(webSocket, logger, 0);
Done = ReceiveAsync();
@ -55,6 +54,7 @@ internal sealed class ClientScreenServerConnection : IDisposable
_logger.LogTrace("sending");
try
{
_logger.LogTrace("sending {} bytes of pixel data", pixels.Data.Length);
await _channel.SendAsync(pixels.Data, _playerScreenData == null);
if (_playerScreenData != null)
await _channel.SendAsync(_playerScreenData.GetPacket());
@ -92,24 +92,3 @@ internal sealed class ClientScreenServerConnection : IDisposable
return _channel.CloseAsync();
}
}
internal sealed class PlayerScreenData
{
private Memory<byte> _data = new byte[MapService.PixelsPerRow * MapService.PixelsPerColumn];
public int Count { get; private set; } = 0;
public void Clear() => Count = 0;
public ReadOnlyMemory<byte> GetPacket() => _data[..Count];
public void Add(GamePixelEntityType entityKind, bool isCurrentPlayer)
{
var result = (byte)(isCurrentPlayer ? 0x1b : 0x0b);
var kind = (byte)entityKind;
Debug.Assert(kind < 3);
result += (byte)(kind << 2);
_data.Span[Count] = result;
Count++;
}
}

View file

@ -0,0 +1,39 @@
using System.Diagnostics;
using TanksServer.GameLogic;
using TanksServer.Graphics;
namespace TanksServer.Interactivity;
internal sealed class PlayerScreenData(ILogger logger)
{
private readonly Memory<byte> _data = new byte[MapService.PixelsPerRow * MapService.PixelsPerColumn / 2];
private int _count = 0;
public void Clear()
{
_count = 0;
_data.Span.Clear();
}
public ReadOnlyMemory<byte> GetPacket()
{
var index = _count / 2 + (_count % 2 == 0 ? 0 : 1);
logger.LogTrace("packet length: {} (count={})", index, _count);
return _data[..index];
}
public void Add(GamePixelEntityType entityKind, bool isCurrentPlayer)
{
var result = (byte)(isCurrentPlayer ? 0x1 : 0x0);
var kind = (byte)entityKind;
Debug.Assert(kind < 3);
result += (byte)(kind << 2);
var index = _count / 2;
if (_count % 2 != 0)
_data.Span[index] |= (byte)(result << 4);
else
_data.Span[index] = result;
_count++;
}
}

View file

@ -16,8 +16,6 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
private readonly ILogger<SendToServicePointDisplay> _logger;
private readonly PlayerServer _players;
private readonly Cp437Grid _scoresBuffer;
private PixelGrid? _lastSentFrame;
private DateTime _nextFailLog = DateTime.Now;
public SendToServicePointDisplay(
@ -47,12 +45,8 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
RefreshScores();
try
{
await _displayConnection.SendBitmapLinearWindowAsync(0, 0, observerPixels);
await _displayConnection.SendCp437DataAsync(MapService.TilesPerRow, 0, _scoresBuffer);
if (_lastSentFrame == observerPixels)
return;
_lastSentFrame = observerPixels;
await _displayConnection.SendBitmapLinearWindowAsync(0, 0, _lastSentFrame);
}
catch (SocketException ex)
{

View file

@ -28,7 +28,7 @@ public static class Program
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
app.MapPost("/player", (string name, Guid id) =>
app.MapPost("/player", (string name, Guid? id) =>
{
name = name.Trim().ToUpperInvariant();
if (name == string.Empty)
@ -36,7 +36,7 @@ public static class Program
if (name.Length > 12)
return Results.BadRequest("name too long");
var player = playerService.GetOrAdd(name, id);
var player = playerService.GetOrAdd(name, id ?? Guid.NewGuid());
return player != null
? Results.Ok(new NameId(player.Name, player.Id))
: Results.Unauthorized();
@ -50,13 +50,13 @@ public static class Program
app.MapGet("/scores", () => playerService.GetAll());
app.Map("/screen", async (HttpContext context) =>
app.Map("/screen", async (HttpContext context, [FromQuery] Guid? player) =>
{
if (!context.WebSockets.IsWebSocketRequest)
return Results.BadRequest();
using var ws = await context.WebSockets.AcceptWebSocketAsync();
await clientScreenServer.HandleClient(ws);
await clientScreenServer.HandleClient(ws, player);
return Results.Empty;
});

View file

@ -41,7 +41,8 @@
</Content>
<Content Include="../Makefile"/>
<Content Include="../.editorconfig"/>
<Content Include="../README.md"/>
<None Include="assets\maps\**" CopyToOutputDirectory="PreserveNewest"/>
</ItemGroup>
</Project>