more configuration, limit rate of sent frames
This commit is contained in:
parent
786c974a23
commit
3f4a301993
|
@ -1,6 +1,10 @@
|
||||||
namespace TanksServer.GameLogic;
|
namespace TanksServer.GameLogic;
|
||||||
|
|
||||||
internal sealed class CollideBulletsWithMap(BulletManager bullets, MapService map) : ITickStep
|
internal sealed class CollideBulletsWithMap(
|
||||||
|
BulletManager bullets,
|
||||||
|
MapService map,
|
||||||
|
IOptions<GameRulesConfiguration> options
|
||||||
|
) : ITickStep
|
||||||
{
|
{
|
||||||
public Task TickAsync(TimeSpan _)
|
public Task TickAsync(TimeSpan _)
|
||||||
{
|
{
|
||||||
|
@ -14,6 +18,7 @@ internal sealed class CollideBulletsWithMap(BulletManager bullets, MapService ma
|
||||||
if (!map.Current.IsWall(pixel))
|
if (!map.Current.IsWall(pixel))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (options.Value.DestructibleWalls)
|
||||||
map.Current.DestroyWallAt(pixel);
|
map.Current.DestroyWallAt(pixel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
6
TanksServer/GameLogic/GameRulesConfiguration.cs
Normal file
6
TanksServer/GameLogic/GameRulesConfiguration.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace TanksServer.GameLogic;
|
||||||
|
|
||||||
|
public class GameRulesConfiguration
|
||||||
|
{
|
||||||
|
public bool DestructibleWalls { get; set; } = true;
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
using DisplayCommands;
|
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using TanksServer.GameLogic;
|
using TanksServer.GameLogic;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using DisplayCommands;
|
|
||||||
|
|
||||||
namespace TanksServer.Graphics;
|
namespace TanksServer.Graphics;
|
||||||
|
|
||||||
internal interface IDrawStep
|
internal interface IDrawStep
|
||||||
|
|
|
@ -8,10 +8,12 @@ namespace TanksServer.Interactivity;
|
||||||
|
|
||||||
internal sealed class ClientScreenServer(
|
internal sealed class ClientScreenServer(
|
||||||
ILogger<ClientScreenServer> logger,
|
ILogger<ClientScreenServer> logger,
|
||||||
ILoggerFactory loggerFactory
|
ILoggerFactory loggerFactory,
|
||||||
|
IOptions<HostConfiguration> hostConfig
|
||||||
) : IHostedLifecycleService, IFrameConsumer
|
) : IHostedLifecycleService, IFrameConsumer
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<ClientScreenServerConnection, byte> _connections = new();
|
private readonly ConcurrentDictionary<ClientScreenServerConnection, byte> _connections = new();
|
||||||
|
private readonly TimeSpan _minFrameTime = TimeSpan.FromMilliseconds(hostConfig.Value.ClientDisplayMinFrameTimeMs);
|
||||||
private bool _closing;
|
private bool _closing;
|
||||||
|
|
||||||
public Task StoppingAsync(CancellationToken cancellationToken)
|
public Task StoppingAsync(CancellationToken cancellationToken)
|
||||||
|
@ -34,6 +36,7 @@ internal sealed class ClientScreenServer(
|
||||||
socket,
|
socket,
|
||||||
loggerFactory.CreateLogger<ClientScreenServerConnection>(),
|
loggerFactory.CreateLogger<ClientScreenServerConnection>(),
|
||||||
this,
|
this,
|
||||||
|
_minFrameTime,
|
||||||
playerGuid);
|
playerGuid);
|
||||||
var added = _connections.TryAdd(connection, 0);
|
var added = _connections.TryAdd(connection, 0);
|
||||||
Debug.Assert(added);
|
Debug.Assert(added);
|
||||||
|
|
|
@ -11,18 +11,23 @@ internal sealed class ClientScreenServerConnection : IDisposable
|
||||||
private readonly ILogger<ClientScreenServerConnection> _logger;
|
private readonly ILogger<ClientScreenServerConnection> _logger;
|
||||||
private readonly ClientScreenServer _server;
|
private readonly ClientScreenServer _server;
|
||||||
private readonly SemaphoreSlim _wantedFrames = new(1);
|
private readonly SemaphoreSlim _wantedFrames = new(1);
|
||||||
private readonly Guid? _playerGuid = null;
|
private readonly Guid? _playerGuid;
|
||||||
private readonly PlayerScreenData? _playerScreenData = null;
|
private readonly PlayerScreenData? _playerScreenData;
|
||||||
|
private readonly TimeSpan _minFrameTime;
|
||||||
|
|
||||||
|
private DateTime _nextFrameAfter = DateTime.Now;
|
||||||
|
|
||||||
public ClientScreenServerConnection(
|
public ClientScreenServerConnection(
|
||||||
WebSocket webSocket,
|
WebSocket webSocket,
|
||||||
ILogger<ClientScreenServerConnection> logger,
|
ILogger<ClientScreenServerConnection> logger,
|
||||||
ClientScreenServer server,
|
ClientScreenServer server,
|
||||||
|
TimeSpan minFrameTime,
|
||||||
Guid? playerGuid = null
|
Guid? playerGuid = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_server = server;
|
_server = server;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_minFrameTime = minFrameTime;
|
||||||
|
|
||||||
_playerGuid = playerGuid;
|
_playerGuid = playerGuid;
|
||||||
if (playerGuid.HasValue)
|
if (playerGuid.HasValue)
|
||||||
|
@ -42,12 +47,17 @@ internal sealed class ClientScreenServerConnection : IDisposable
|
||||||
|
|
||||||
public async Task SendAsync(PixelGrid pixels, GamePixelGrid gamePixelGrid)
|
public async Task SendAsync(PixelGrid pixels, GamePixelGrid gamePixelGrid)
|
||||||
{
|
{
|
||||||
|
if (_nextFrameAfter > DateTime.Now)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!await _wantedFrames.WaitAsync(TimeSpan.Zero))
|
if (!await _wantedFrames.WaitAsync(TimeSpan.Zero))
|
||||||
{
|
{
|
||||||
_logger.LogTrace("client does not want a frame yet");
|
_logger.LogTrace("client does not want a frame yet");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_nextFrameAfter = DateTime.Today + _minFrameTime;
|
||||||
|
|
||||||
if (_playerScreenData != null)
|
if (_playerScreenData != null)
|
||||||
RefreshPlayerSpecificData(gamePixelGrid);
|
RefreshPlayerSpecificData(gamePixelGrid);
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,22 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
|
||||||
private readonly ILogger<SendToServicePointDisplay> _logger;
|
private readonly ILogger<SendToServicePointDisplay> _logger;
|
||||||
private readonly PlayerServer _players;
|
private readonly PlayerServer _players;
|
||||||
private readonly Cp437Grid _scoresBuffer;
|
private readonly Cp437Grid _scoresBuffer;
|
||||||
private DateTime _nextFailLog = DateTime.Now;
|
private readonly TimeSpan _minFrameTime;
|
||||||
|
|
||||||
|
private DateTime _nextFailLogAfter = DateTime.Now;
|
||||||
|
private DateTime _nextFrameAfter = DateTime.Now;
|
||||||
|
|
||||||
public SendToServicePointDisplay(
|
public SendToServicePointDisplay(
|
||||||
PlayerServer players,
|
PlayerServer players,
|
||||||
ILogger<SendToServicePointDisplay> logger,
|
ILogger<SendToServicePointDisplay> logger,
|
||||||
IDisplayConnection displayConnection
|
IDisplayConnection displayConnection,
|
||||||
|
IOptions<HostConfiguration> hostOptions
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_players = players;
|
_players = players;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_displayConnection = displayConnection;
|
_displayConnection = displayConnection;
|
||||||
|
_minFrameTime = TimeSpan.FromMilliseconds(hostOptions.Value.ServicePointDisplayMinFrameTimeMs);
|
||||||
|
|
||||||
var localIp = _displayConnection.GetLocalIPv4().Split('.');
|
var localIp = _displayConnection.GetLocalIPv4().Split('.');
|
||||||
Debug.Assert(localIp.Length == 4);
|
Debug.Assert(localIp.Length == 4);
|
||||||
|
@ -42,7 +47,12 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
|
||||||
|
|
||||||
public async Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, PixelGrid observerPixels)
|
public async Task OnFrameDoneAsync(GamePixelGrid gamePixelGrid, PixelGrid observerPixels)
|
||||||
{
|
{
|
||||||
|
if (DateTime.Now < _nextFrameAfter)
|
||||||
|
return;
|
||||||
|
_nextFrameAfter = DateTime.Now + _minFrameTime;
|
||||||
|
|
||||||
RefreshScores();
|
RefreshScores();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _displayConnection.SendBitmapLinearWindowAsync(0, 0, observerPixels);
|
await _displayConnection.SendBitmapLinearWindowAsync(0, 0, observerPixels);
|
||||||
|
@ -50,10 +60,10 @@ internal sealed class SendToServicePointDisplay : IFrameConsumer
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (SocketException ex)
|
||||||
{
|
{
|
||||||
if (DateTime.Now > _nextFailLog)
|
if (DateTime.Now > _nextFailLogAfter)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("could not send data to service point display: {}", ex.Message);
|
_logger.LogWarning("could not send data to service point display: {}", ex.Message);
|
||||||
_nextFailLog = DateTime.Now + TimeSpan.FromSeconds(5);
|
_nextFailLogAfter = DateTime.Now + TimeSpan.FromSeconds(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
TanksServer/Models/HostConfiguration.cs
Normal file
10
TanksServer/Models/HostConfiguration.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace TanksServer.Models;
|
||||||
|
|
||||||
|
public class HostConfiguration
|
||||||
|
{
|
||||||
|
public bool EnableServicePointDisplay { get; set; } = true;
|
||||||
|
|
||||||
|
public int ServicePointDisplayMinFrameTimeMs { get; set; } = 25;
|
||||||
|
|
||||||
|
public int ClientDisplayMinFrameTimeMs { get; set; } = 25;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using DisplayCommands;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using TanksServer.GameLogic;
|
using TanksServer.GameLogic;
|
||||||
|
@ -112,6 +113,11 @@ public static class Program
|
||||||
|
|
||||||
builder.Services.AddHttpLogging(_ => { });
|
builder.Services.AddHttpLogging(_ => { });
|
||||||
|
|
||||||
|
builder.Services.Configure<HostConfiguration>(builder.Configuration.GetSection("Host"));
|
||||||
|
var hostConfiguration = builder.Configuration.GetSection("Host").Get<HostConfiguration>();
|
||||||
|
if (hostConfiguration == null)
|
||||||
|
throw new InvalidOperationException("'Host' configuration missing");
|
||||||
|
|
||||||
builder.Services.AddSingleton<MapService>();
|
builder.Services.AddSingleton<MapService>();
|
||||||
builder.Services.AddSingleton<BulletManager>();
|
builder.Services.AddSingleton<BulletManager>();
|
||||||
builder.Services.AddSingleton<TankManager>();
|
builder.Services.AddSingleton<TankManager>();
|
||||||
|
@ -137,7 +143,6 @@ public static class Program
|
||||||
builder.Services.AddSingleton<IDrawStep, DrawTanksStep>();
|
builder.Services.AddSingleton<IDrawStep, DrawTanksStep>();
|
||||||
builder.Services.AddSingleton<IDrawStep, DrawBulletsStep>();
|
builder.Services.AddSingleton<IDrawStep, DrawBulletsStep>();
|
||||||
|
|
||||||
builder.Services.AddSingleton<IFrameConsumer, SendToServicePointDisplay>();
|
|
||||||
builder.Services.AddSingleton<IFrameConsumer, ClientScreenServer>(sp =>
|
builder.Services.AddSingleton<IFrameConsumer, ClientScreenServer>(sp =>
|
||||||
sp.GetRequiredService<ClientScreenServer>());
|
sp.GetRequiredService<ClientScreenServer>());
|
||||||
|
|
||||||
|
@ -145,7 +150,13 @@ public static class Program
|
||||||
builder.Configuration.GetSection("Tanks"));
|
builder.Configuration.GetSection("Tanks"));
|
||||||
builder.Services.Configure<PlayersConfiguration>(
|
builder.Services.Configure<PlayersConfiguration>(
|
||||||
builder.Configuration.GetSection("Players"));
|
builder.Configuration.GetSection("Players"));
|
||||||
|
builder.Services.Configure<GameRulesConfiguration>(builder.Configuration.GetSection("GameRules"));
|
||||||
|
|
||||||
|
if (hostConfiguration.EnableServicePointDisplay)
|
||||||
|
{
|
||||||
|
builder.Services.AddSingleton<IFrameConsumer, SendToServicePointDisplay>();
|
||||||
builder.Services.AddDisplay(builder.Configuration.GetSection("ServicePointDisplay"));
|
builder.Services.AddDisplay(builder.Configuration.GetSection("ServicePointDisplay"));
|
||||||
|
}
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ServicePointDisplay": {
|
"ServicePointDisplay": {
|
||||||
"Enable": true,
|
|
||||||
"Hostname": "172.23.42.29",
|
"Hostname": "172.23.42.29",
|
||||||
"Port": 2342
|
"Port": 2342
|
||||||
},
|
},
|
||||||
|
@ -26,8 +25,16 @@
|
||||||
"ShootDelayMs": 450,
|
"ShootDelayMs": 450,
|
||||||
"BulletSpeed": 75
|
"BulletSpeed": 75
|
||||||
},
|
},
|
||||||
|
"GameRules": {
|
||||||
|
"DestructibleWalls": true
|
||||||
|
},
|
||||||
"Players": {
|
"Players": {
|
||||||
"SpawnDelayMs": 3000,
|
"SpawnDelayMs": 3000,
|
||||||
"IdleTimeoutMs": 30000
|
"IdleTimeoutMs": 30000
|
||||||
|
},
|
||||||
|
"Host": {
|
||||||
|
"EnableServicePointDisplay": true,
|
||||||
|
"ServicePointDisplayMinFrameTimeMs": 25,
|
||||||
|
"ClientScreenMinFrameTime": 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue