render current player in secondary color
This commit is contained in:
parent
fbaad86555
commit
c4c4eb6358
13 changed files with 255 additions and 72 deletions
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
39
TanksServer/Interactivity/PlayerScreenData.cs
Normal file
39
TanksServer/Interactivity/PlayerScreenData.cs
Normal 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++;
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
||||
|
|
|
@ -41,7 +41,8 @@
|
|||
</Content>
|
||||
<Content Include="../Makefile"/>
|
||||
<Content Include="../.editorconfig"/>
|
||||
<Content Include="../README.md"/>
|
||||
<None Include="assets\maps\**" CopyToOutputDirectory="PreserveNewest"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue