74 lines
2.1 KiB
C#
74 lines
2.1 KiB
C#
using System.Net.WebSockets;
|
|
using DisplayCommands;
|
|
using TanksServer.Graphics;
|
|
|
|
namespace TanksServer.Interactivity;
|
|
|
|
internal sealed class ClientScreenServerConnection(
|
|
WebSocket webSocket,
|
|
ILogger<ClientScreenServerConnection> logger,
|
|
string? playerName = null
|
|
) : WebsocketServerConnection(logger, new ByteChannelWebSocket(webSocket, logger, 0))
|
|
{
|
|
private bool _wantsFrameOnTick = true;
|
|
|
|
private PixelGrid? _lastSentPixels;
|
|
private PixelGrid? _nextPixels;
|
|
private readonly PlayerScreenData? _nextPlayerData = playerName != null ? new PlayerScreenData(logger) : null;
|
|
|
|
protected override async ValueTask HandleMessageLockedAsync(Memory<byte> _)
|
|
{
|
|
if (_nextPixels == null)
|
|
{
|
|
_wantsFrameOnTick = true;
|
|
return;
|
|
}
|
|
|
|
await SendNowAsync();
|
|
}
|
|
|
|
public ValueTask OnGameTickAsync(PixelGrid pixels, GamePixelGrid gamePixelGrid) => LockedAsync(async () =>
|
|
{
|
|
if (pixels == _lastSentPixels)
|
|
return;
|
|
|
|
if (_nextPlayerData != null)
|
|
{
|
|
_nextPlayerData.Clear();
|
|
foreach (var gamePixel in gamePixelGrid)
|
|
{
|
|
if (!gamePixel.EntityType.HasValue)
|
|
continue;
|
|
_nextPlayerData.Add(gamePixel.EntityType.Value, gamePixel.BelongsTo?.Name == playerName);
|
|
}
|
|
}
|
|
|
|
_nextPixels = pixels;
|
|
if (_wantsFrameOnTick)
|
|
_ = await SendNowAsync();
|
|
});
|
|
|
|
private async ValueTask<bool> SendNowAsync()
|
|
{
|
|
var pixels = _nextPixels
|
|
?? throw new InvalidOperationException("next pixels not set");
|
|
|
|
try
|
|
{
|
|
await Socket.SendBinaryAsync(pixels.Data, _nextPlayerData == null);
|
|
if (_nextPlayerData != null)
|
|
await Socket.SendBinaryAsync(_nextPlayerData.GetPacket());
|
|
|
|
_lastSentPixels = _nextPixels;
|
|
_nextPixels = null;
|
|
_wantsFrameOnTick = false;
|
|
return true;
|
|
}
|
|
catch (WebSocketException ex)
|
|
{
|
|
Logger.LogWarning(ex, "send failed");
|
|
return false;
|
|
}
|
|
}
|
|
}
|