servicepoint-tanks/tanks-backend/TanksServer/Interactivity/ClientScreenServerConnection.cs

85 lines
2.4 KiB
C#
Raw Normal View History

using System.Buffers;
using System.Net.WebSockets;
2024-05-26 15:06:09 +02:00
using ServicePoint;
using TanksServer.Graphics;
namespace TanksServer.Interactivity;
internal sealed class ClientScreenServerConnection
2024-05-04 14:25:37 +02:00
: DroppablePackageRequestConnection<ClientScreenServerConnection.Package>
{
2024-05-03 14:45:41 +02:00
private readonly BufferPool _bufferPool;
2024-05-02 21:27:56 +02:00
private readonly PlayerScreenData? _playerDataBuilder;
private readonly Player? _player;
2024-05-03 14:45:41 +02:00
public ClientScreenServerConnection(
WebSocket webSocket,
2024-05-02 21:27:56 +02:00
ILogger<ClientScreenServerConnection> logger,
2024-05-03 14:45:41 +02:00
Player? player,
BufferPool bufferPool
) : base(logger, new ByteChannelWebSocket(webSocket, logger, 0))
2024-05-02 21:27:56 +02:00
{
_player = player;
2024-05-03 14:45:41 +02:00
_bufferPool = bufferPool;
2024-05-02 21:27:56 +02:00
_player?.IncrementConnectionCount();
_playerDataBuilder = player == null
? null
: new PlayerScreenData(logger, player);
}
2024-10-16 20:15:32 +02:00
public async Task OnGameTickAsync(Bitmap pixels, GamePixelGrid gamePixelGrid)
{
await Task.Yield();
var next = BuildNextPackage(pixels, gamePixelGrid);
2024-05-04 14:25:37 +02:00
SetNextPackage(next);
}
2024-10-16 20:15:32 +02:00
private Package BuildNextPackage(Bitmap pixels, GamePixelGrid gamePixelGrid)
{
var pixelsData = pixels.CopyRaw();
2024-05-13 01:23:34 +02:00
var nextPixels = _bufferPool.Rent(pixelsData.Length);
pixelsData.CopyTo(nextPixels.Memory.Span);
2024-05-04 14:25:37 +02:00
if (_playerDataBuilder == null)
return new Package(nextPixels, null);
var data = _playerDataBuilder.Build(gamePixelGrid);
var nextPlayerData = _bufferPool.Rent(data.Length);
data.CopyTo(nextPlayerData.Memory);
2024-05-04 14:25:37 +02:00
return new Package(nextPixels, nextPlayerData);
2024-05-02 21:27:56 +02:00
}
2024-05-04 14:25:37 +02:00
protected override async ValueTask SendPackageAsync(Package package)
{
try
{
2024-05-03 14:45:41 +02:00
await Socket.SendBinaryAsync(package.Pixels.Memory, package.PlayerData == null);
if (package.PlayerData != null)
2024-05-03 14:45:41 +02:00
await Socket.SendBinaryAsync(package.PlayerData.Memory);
}
catch (WebSocketException ex)
{
2024-04-22 19:03:07 +02:00
Logger.LogWarning(ex, "send failed");
}
}
2024-05-04 14:25:37 +02:00
public override void Dispose()
{
base.Dispose();
_player?.DecrementConnectionCount();
}
internal sealed record class Package(
IMemoryOwner<byte> Pixels,
IMemoryOwner<byte>? PlayerData
) : IDisposable
{
public void Dispose()
{
Pixels.Dispose();
PlayerData?.Dispose();
}
}
}