seems like I am still not done with the connections
This commit is contained in:
parent
57d2a11fd5
commit
f477d1e5de
|
@ -1,18 +1,20 @@
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using DisplayCommands;
|
using DisplayCommands;
|
||||||
|
using DotNext.Threading;
|
||||||
using TanksServer.Graphics;
|
using TanksServer.Graphics;
|
||||||
|
|
||||||
namespace TanksServer.Interactivity;
|
namespace TanksServer.Interactivity;
|
||||||
|
|
||||||
internal sealed class ClientScreenServerConnection : WebsocketServerConnection
|
internal sealed class ClientScreenServerConnection
|
||||||
|
: WebsocketServerConnection, IDisposable
|
||||||
{
|
{
|
||||||
private sealed record class Package(IMemoryOwner<byte> Pixels, IMemoryOwner<byte>? PlayerData);
|
|
||||||
|
|
||||||
private readonly BufferPool _bufferPool;
|
private readonly BufferPool _bufferPool;
|
||||||
private readonly PlayerScreenData? _playerDataBuilder;
|
private readonly PlayerScreenData? _playerDataBuilder;
|
||||||
private readonly Player? _player;
|
private readonly Player? _player;
|
||||||
private int _wantsFrameOnTick = 1;
|
private readonly AsyncAutoResetEvent _nextPackageEvent = new(false, 1);
|
||||||
|
private int _runningMessageHandlers = 0;
|
||||||
private Package? _next;
|
private Package? _next;
|
||||||
|
|
||||||
public ClientScreenServerConnection(
|
public ClientScreenServerConnection(
|
||||||
|
@ -32,23 +34,49 @@ internal sealed class ClientScreenServerConnection : WebsocketServerConnection
|
||||||
|
|
||||||
protected override ValueTask HandleMessageAsync(Memory<byte> _)
|
protected override ValueTask HandleMessageAsync(Memory<byte> _)
|
||||||
{
|
{
|
||||||
if (_wantsFrameOnTick != 0)
|
if (Interlocked.Increment(ref _runningMessageHandlers) == 1)
|
||||||
return ValueTask.CompletedTask;
|
return Core();
|
||||||
|
|
||||||
var package = Interlocked.Exchange(ref _next, null);
|
Interlocked.Decrement(ref _runningMessageHandlers);
|
||||||
if (package != null)
|
|
||||||
return SendAndDisposeAsync(package);
|
|
||||||
|
|
||||||
// the delay between one exchange and this set could be enough for another frame to complete
|
|
||||||
// this would mean the client simply drops a frame, so this should be fine
|
|
||||||
_wantsFrameOnTick = 1;
|
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
|
|
||||||
|
async ValueTask Core()
|
||||||
|
{
|
||||||
|
await _nextPackageEvent.WaitAsync();
|
||||||
|
var package = Interlocked.Exchange(ref _next, null);
|
||||||
|
if (package == null)
|
||||||
|
throw new UnreachableException("package should be set here");
|
||||||
|
await SendAndDisposeAsync(package);
|
||||||
|
Interlocked.Decrement(ref _runningMessageHandlers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnGameTickAsync(PixelGrid pixels, GamePixelGrid gamePixelGrid)
|
public async Task OnGameTickAsync(PixelGrid pixels, GamePixelGrid gamePixelGrid)
|
||||||
{
|
{
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
|
|
||||||
|
var next = BuildNextPackage(pixels, gamePixelGrid);
|
||||||
|
var oldNext = Interlocked.Exchange(ref _next, next);
|
||||||
|
|
||||||
|
_nextPackageEvent.Set();
|
||||||
|
|
||||||
|
oldNext?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ValueTask RemovedAsync()
|
||||||
|
{
|
||||||
|
_player?.DecrementConnectionCount();
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_nextPackageEvent.Dispose();
|
||||||
|
Interlocked.Exchange(ref _next, null)?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Package BuildNextPackage(PixelGrid pixels, GamePixelGrid gamePixelGrid)
|
||||||
|
{
|
||||||
var nextPixels = _bufferPool.Rent(pixels.Data.Length);
|
var nextPixels = _bufferPool.Rent(pixels.Data.Length);
|
||||||
pixels.Data.CopyTo(nextPixels.Memory);
|
pixels.Data.CopyTo(nextPixels.Memory);
|
||||||
|
|
||||||
|
@ -61,21 +89,7 @@ internal sealed class ClientScreenServerConnection : WebsocketServerConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
var next = new Package(nextPixels, nextPlayerData);
|
var next = new Package(nextPixels, nextPlayerData);
|
||||||
if (Interlocked.Exchange(ref _wantsFrameOnTick, 0) != 0)
|
return next;
|
||||||
{
|
|
||||||
await SendAndDisposeAsync(next);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldNext = Interlocked.Exchange(ref _next, next);
|
|
||||||
oldNext?.Pixels.Dispose();
|
|
||||||
oldNext?.PlayerData?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ValueTask RemovedAsync()
|
|
||||||
{
|
|
||||||
_player?.DecrementConnectionCount();
|
|
||||||
return ValueTask.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ValueTask SendAndDisposeAsync(Package package)
|
private async ValueTask SendAndDisposeAsync(Package package)
|
||||||
|
@ -92,8 +106,19 @@ internal sealed class ClientScreenServerConnection : WebsocketServerConnection
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
package.Pixels.Dispose();
|
package.Dispose();
|
||||||
package.PlayerData?.Dispose();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record class Package(
|
||||||
|
IMemoryOwner<byte> Pixels,
|
||||||
|
IMemoryOwner<byte>? PlayerData
|
||||||
|
) : IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Pixels.Dispose();
|
||||||
|
PlayerData?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0"/>
|
<PackageReference Include="DotNext.Threading" Version="5.3.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4"/>
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||||
<ProjectReference Include="../DisplayCommands/DisplayCommands.csproj"/>
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||||
|
<ProjectReference Include="../DisplayCommands/DisplayCommands.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in a new issue