first image in client

This commit is contained in:
Vinzenz Schroeter 2024-04-06 16:38:26 +02:00
parent ea7f12b0c2
commit bc8d5ad6d0
6 changed files with 82 additions and 39 deletions

View file

@ -0,0 +1,52 @@
using System.Net.WebSockets;
namespace TanksServer;
internal sealed class ClientScreenServer
{
private readonly List<ClientScreenServerConnection> _connections = new();
public ClientScreenServerConnection AddClient(WebSocket socket)
{
var connection = new ClientScreenServerConnection(socket);
_connections.Add(connection);
return connection;
}
public Task Send(DisplayPixelBuffer buf)
{
return Task.WhenAll(_connections.Select(c => c.Send(buf)));
}
}
internal sealed class ClientScreenServerConnection
{
private readonly WebSocket _socket;
private readonly Task _readTask;
private readonly TaskCompletionSource _completionSource = new();
private bool _wantsNewFrame = true;
public ClientScreenServerConnection(WebSocket webSocket)
{
_socket = webSocket;
_readTask = Read();
}
public Task Done => _completionSource.Task;
private async Task Read()
{
while (true)
{
await _socket.ReceiveAsync(ArraySegment<byte>.Empty, default);
_wantsNewFrame = true;
}
}
public Task Send(DisplayPixelBuffer buf)
{
if (!_wantsNewFrame)
return Task.CompletedTask;
return _socket.SendAsync(buf.Data, WebSocketMessageType.Binary, true, default);
}
}

View file

@ -7,11 +7,7 @@ public sealed class FixedSizeBitFieldView(Memory<byte> data) : IList<bool>
public int Count => data.Length * 8; public int Count => data.Length * 8;
public bool IsReadOnly => false; public bool IsReadOnly => false;
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
{
return GetEnumerator();
}
public IEnumerator<bool> GetEnumerator() public IEnumerator<bool> GetEnumerator()
{ {
return Enumerable().GetEnumerator(); return Enumerable().GetEnumerator();
@ -69,33 +65,10 @@ public sealed class FixedSizeBitFieldView(Memory<byte> data) : IList<bool>
} }
} }
public void Add(bool item) public void Add(bool item) => throw new NotSupportedException();
{ public bool Contains(bool item) => throw new NotSupportedException();
throw new NotSupportedException(); public bool Remove(bool item) => throw new NotSupportedException();
} public int IndexOf(bool item) => throw new NotSupportedException();
public void Insert(int index, bool item) => throw new NotSupportedException();
public bool Contains(bool item) public void RemoveAt(int index) => throw new NotSupportedException();
{
throw new NotSupportedException();
}
public bool Remove(bool item)
{
throw new NotSupportedException();
}
public int IndexOf(bool item)
{
throw new NotSupportedException();
}
public void Insert(int index, bool item)
{
throw new NotSupportedException();
}
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
} }

View file

@ -1,3 +1,4 @@
global using System; global using System;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks; global using System.Threading.Tasks;

View file

@ -1,5 +1,7 @@
using System.IO;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
namespace TanksServer; namespace TanksServer;
@ -11,18 +13,25 @@ internal static class Program
var display = app.Services.GetRequiredService<ServicePointDisplay>(); var display = app.Services.GetRequiredService<ServicePointDisplay>();
var mapDrawer = app.Services.GetRequiredService<MapDrawer>(); var mapDrawer = app.Services.GetRequiredService<MapDrawer>();
var clientScreenServer = app.Services.GetRequiredService<ClientScreenServer>();
var buffer = mapDrawer.CreateGameFieldPixelBuffer(); var buffer = mapDrawer.CreateGameFieldPixelBuffer();
mapDrawer.DrawInto(buffer); mapDrawer.DrawInto(buffer);
await display.Send(buffer); await display.Send(buffer);
app.UseWebSockets(); var clientFileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "client"));
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
app.UseWebSockets();
app.Map("/screen", async context => app.Map("/screen", async context =>
{ {
if (!context.WebSockets.IsWebSocketRequest) if (!context.WebSockets.IsWebSocketRequest)
return; return;
using var ws = await context.WebSockets.AcceptWebSocketAsync(); var ws = await context.WebSockets.AcceptWebSocketAsync();
var client = clientScreenServer.AddClient(ws);
await client.Send(buffer);
await client.Done;
}); });
await app.RunAsync(); await app.RunAsync();
@ -35,6 +44,7 @@ internal static class Program
builder.Services.AddSingleton<ServicePointDisplay>(); builder.Services.AddSingleton<ServicePointDisplay>();
builder.Services.AddSingleton<MapService>(); builder.Services.AddSingleton<MapService>();
builder.Services.AddSingleton<MapDrawer>(); builder.Services.AddSingleton<MapDrawer>();
builder.Services.AddSingleton<ClientScreenServer>();
return builder.Build(); return builder.Build();
} }

View file

@ -1,8 +1,8 @@
{ {
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Debug",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Information"
} }
} }
} }

View file

@ -5,5 +5,12 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*" "AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:3000"
}
}
}
} }