WIP switch to ServicePoint2 library

This commit is contained in:
Vinzenz Schroeter 2024-05-13 01:23:34 +02:00
parent eb999b0d1a
commit e1cfd714c1
31 changed files with 66 additions and 791 deletions

View file

@ -1,13 +1,13 @@
using System.IO;
using System.Text;
using System.Text.Json;
using DisplayCommands;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using ServicePoint2;
using TanksServer.GameLogic;
using TanksServer.Interactivity;
@ -19,7 +19,7 @@ internal sealed class Endpoints(
ControlsServer controlsServer,
MapService mapService,
ChangeToRequestedMap changeToRequestedMap,
IDisplayConnection displayConnection
Connection displayConnection
)
{
public void Map(WebApplication app)
@ -31,7 +31,7 @@ internal sealed class Endpoints(
app.Map("/controls", ConnectControlsAsync);
app.MapGet("/map", () => mapService.MapNames);
app.MapPost("/map", PostMap);
app.MapPost("/resetDisplay", displayConnection.SendHardResetAsync);
app.MapPost("/resetDisplay", () => displayConnection.Send(Command.HardReset()));
app.MapGet("/map/{name}", GetMapByName);
app.MapHealthChecks("/health", new HealthCheckOptions
@ -117,7 +117,7 @@ internal sealed class Endpoints(
if (!mapService.TryGetPreview(name, out var preview))
return TypedResults.NotFound();
var mapInfo = new MapInfo(prototype.Name, prototype.GetType().Name, preview.Data);
var mapInfo = new MapInfo(prototype.Name, prototype.GetType().Name, preview.Data.ToArray());
return TypedResults.Ok(mapInfo);
}

View file

@ -1,7 +1,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using DisplayCommands;
using ServicePoint2;
using TanksServer.Graphics;
namespace TanksServer.GameLogic;
@ -42,7 +42,7 @@ internal sealed class MapService
if (!_mapPrototypes.TryGetValue(name, out var prototype))
return false; // name not found
pixelGrid = new PixelGrid(PixelsPerRow, PixelsPerColumn);
pixelGrid = PixelGrid.New(PixelsPerRow, PixelsPerColumn);
DrawMapStep.Draw(pixelGrid, prototype.CreateInstance());
_mapPreviews.TryAdd(name, pixelGrid); // another thread may have added the map already

View file

@ -1,5 +1,3 @@
using System.Diagnostics;
namespace TanksServer.GameLogic;
internal sealed class SpawnPowerUp(

View file

@ -1,4 +1,4 @@
using DisplayCommands;
using ServicePoint2;
using TanksServer.GameLogic;
namespace TanksServer.Graphics;

View file

@ -1,4 +1,4 @@
using DisplayCommands;
using ServicePoint2;
using TanksServer.GameLogic;
using TanksServer.Interactivity;
@ -10,9 +10,9 @@ internal sealed class GeneratePixelsTickStep(
) : ITickStep
{
private GamePixelGrid _lastGamePixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private PixelGrid _lastObserverPixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private PixelGrid _lastObserverPixelGrid = PixelGrid.New(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private GamePixelGrid _gamePixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private PixelGrid _observerPixelGrid = new(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private PixelGrid _observerPixelGrid = PixelGrid.New(MapService.PixelsPerRow, MapService.PixelsPerColumn);
private readonly List<IDrawStep> _drawSteps = drawSteps.ToList();
private readonly List<IFrameConsumer> _consumers = consumers.ToList();
@ -20,7 +20,7 @@ internal sealed class GeneratePixelsTickStep(
public async ValueTask TickAsync(TimeSpan _)
{
Draw(_gamePixelGrid, _observerPixelGrid);
if (_observerPixelGrid.Data.Span.SequenceEqual(_lastObserverPixelGrid.Data.Span))
if (_observerPixelGrid.Data.SequenceEqual(_lastObserverPixelGrid.Data))
return;
await _consumers.Select(c => c.OnFrameDoneAsync(_gamePixelGrid, _observerPixelGrid))
@ -36,7 +36,7 @@ internal sealed class GeneratePixelsTickStep(
foreach (var step in _drawSteps)
step.Draw(gamePixelGrid);
observerPixelGrid.Clear();
observerPixelGrid.Fill(false);
for (var y = 0; y < MapService.PixelsPerColumn; y++)
for (var x = 0; x < MapService.PixelsPerRow; x++)
{

View file

@ -1,4 +1,4 @@
using DisplayCommands;
using ServicePoint2;
namespace TanksServer.Graphics;

View file

@ -1,5 +1,5 @@
using System.Net.WebSockets;
using DisplayCommands;
using ServicePoint2;
using TanksServer.Graphics;
namespace TanksServer.Interactivity;

View file

@ -1,6 +1,6 @@
using System.Buffers;
using System.Net.WebSockets;
using DisplayCommands;
using ServicePoint2;
using TanksServer.Graphics;
namespace TanksServer.Interactivity;
@ -36,8 +36,9 @@ internal sealed class ClientScreenServerConnection
private Package BuildNextPackage(PixelGrid pixels, GamePixelGrid gamePixelGrid)
{
var nextPixels = _bufferPool.Rent(pixels.Data.Length);
pixels.Data.CopyTo(nextPixels.Memory);
var pixelsData = pixels.Data;
var nextPixels = _bufferPool.Rent(pixelsData.Length);
pixelsData.CopyTo(nextPixels.Memory.Span);
if (_playerDataBuilder == null)
return new Package(nextPixels, null);

View file

@ -13,7 +13,7 @@ internal sealed class PlayerInfoConnection
private readonly MapEntityManager _entityManager;
private readonly BufferPool _bufferPool;
private readonly MemoryStream _tempStream = new();
private IMemoryOwner<byte>? _lastMessage = null;
private IMemoryOwner<byte>? _lastMessage;
public PlayerInfoConnection(
Player player,

View file

@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using DisplayCommands;
using ServicePoint2;
using TanksServer.GameLogic;
using TanksServer.Graphics;
@ -12,11 +13,11 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
private const int ScoresHeight = 20;
private const int ScoresPlayerRows = ScoresHeight - 6;
private readonly IDisplayConnection _displayConnection;
private readonly Connection _displayConnection;
private readonly MapService _mapService;
private readonly ILogger<SendToServicePointDisplay> _logger;
private readonly PlayerServer _players;
private readonly Cp437Grid _scoresBuffer;
private readonly ByteGrid _scoresBuffer;
private readonly TimeSpan _minFrameTime;
private readonly IOptionsMonitor<HostConfiguration> _options;
@ -26,11 +27,11 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
public SendToServicePointDisplay(
PlayerServer players,
ILogger<SendToServicePointDisplay> logger,
IDisplayConnection displayConnection,
Connection displayConnection,
IOptions<HostConfiguration> hostOptions,
MapService mapService,
IOptionsMonitor<HostConfiguration> options
)
IOptionsMonitor<HostConfiguration> options,
IOptions<DisplayConfiguration> displayConfig)
{
_players = players;
_logger = logger;
@ -39,16 +40,15 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
_minFrameTime = TimeSpan.FromMilliseconds(hostOptions.Value.ServicePointDisplayMinFrameTimeMs);
_options = options;
var localIp = _displayConnection.GetLocalIPv4().Split('.');
var localIp = GetLocalIPv4(displayConfig.Value).Split('.');
Debug.Assert(localIp.Length == 4);
_scoresBuffer = new Cp437Grid(12, 20)
{
[00] = "== TANKS! ==",
[01] = "-- scores --",
[17] = "-- join --",
[18] = string.Join('.', localIp[..2]),
[19] = string.Join('.', localIp[2..])
};
_scoresBuffer = ByteGrid.New(12, 20);
_scoresBuffer[00] = "== TANKS! ==";
_scoresBuffer[01] = "-- scores --";
_scoresBuffer[17] = "-- join --";
_scoresBuffer[18] = string.Join('.', localIp[..2]);
_scoresBuffer[19] = string.Join('.', localIp[2..]);
}
public async Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, PixelGrid observerPixels)
@ -66,8 +66,8 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
try
{
await _displayConnection.SendBitmapLinearWindowAsync(0, 0, observerPixels);
await _displayConnection.SendCp437DataAsync(MapService.TilesPerRow, 0, _scoresBuffer);
_displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone()));
_displayConnection.Send(Command.Cp437Data(MapService.TilesPerRow, 0, _scoresBuffer.Clone()));
}
catch (SocketException ex)
{
@ -103,4 +103,12 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
_scoresBuffer[16] = _mapService.Current.Name[..(Math.Min(ScoresWidth, _mapService.Current.Name.Length) - 1)];
}
private static string GetLocalIPv4(DisplayConfiguration configuration)
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0);
socket.Connect(configuration.Hostname, configuration.Port);
var endPoint = socket.LocalEndPoint as IPEndPoint ?? throw new NotSupportedException();
return endPoint.Address.ToString();
}
}

View file

@ -0,0 +1,8 @@
namespace TanksServer.Models;
public class DisplayConfiguration
{
public string Hostname { get; set; } = "172.23.42.29";
public int Port { get; set; } = 2342;
}

View file

@ -1,8 +1,9 @@
using System.IO;
using DisplayCommands;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using ServicePoint2;
using SixLabors.ImageSharp;
using TanksServer.GameLogic;
using TanksServer.Graphics;
using TanksServer.Interactivity;
@ -94,9 +95,14 @@ public static class Program
builder.Services.Configure<GameRules>(builder.Configuration.GetSection("GameRules"));
builder.Services.Configure<HostConfiguration>(builder.Configuration.GetSection("Host"));
builder.Services.Configure<DisplayConfiguration>(builder.Configuration.GetSection("ServicePointDisplay"));
builder.Services.AddSingleton<IFrameConsumer, SendToServicePointDisplay>();
builder.Services.AddDisplay(builder.Configuration.GetSection("ServicePointDisplay"));
builder.Services.AddSingleton<Connection>(sp =>
{
var config = sp.GetRequiredService<IOptions<DisplayConfiguration>>().Value;
return Connection.Open($"{config.Hostname}:{config.Port}");
});
var app = builder.Build();

View file

@ -10,11 +10,14 @@
<PackageReference Include="DotNext.Threading" Version="5.3.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
<ProjectReference Include="../DisplayCommands/DisplayCommands.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="./assets/**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\servicepoint2\servicepoint2-binding-cs\ServicePoint2\ServicePoint2.csproj" />
</ItemGroup>
</Project>

View file

@ -16,7 +16,8 @@
}
},
"ServicePointDisplay": {
"Hostname": "172.23.42.29",
//"Hostname": "172.23.42.29",
"Hostname": "127.0.0.1",
"Port": 2342
},
"GameRules": {