first image in client
This commit is contained in:
parent
ea7f12b0c2
commit
bc8d5ad6d0
52
TanksServer/ClientScreenServer.cs
Normal file
52
TanksServer/ClientScreenServer.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Debug",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Information"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,5 +5,12 @@
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*",
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue