make big display toggleable
This commit is contained in:
parent
a9aaf899a2
commit
dc9ad21a3d
|
@ -1,4 +1,5 @@
|
|||
using TanksServer.Helpers;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.DrawSteps;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using TanksServer.Helpers;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.DrawSteps;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using TanksServer.Helpers;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.DrawSteps;
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
global using System;
|
||||
global using System.Collections.Concurrent;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
global using Microsoft.Extensions.Options;
|
||||
global using TanksServer.Models;
|
||||
global using TanksServer.Services;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Text.Json.Serialization;
|
||||
using TanksServer.Models;
|
||||
|
||||
namespace TanksServer.Helpers;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.Diagnostics;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.Helpers;
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
namespace TanksServer.Services;
|
||||
namespace TanksServer.Models;
|
||||
|
||||
internal sealed class ServicePointDisplayConfiguration
|
||||
{
|
||||
public bool Enable { get; set; } = true;
|
||||
public string Hostname { get; set; } = string.Empty;
|
||||
public int Port { get; set; }
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using Microsoft.Extensions.FileProviders;
|
||||
using TanksServer.DrawSteps;
|
||||
using TanksServer.Helpers;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Servers;
|
||||
using TanksServer.Services;
|
||||
using TanksServer.TickSteps;
|
||||
|
||||
namespace TanksServer;
|
||||
|
@ -74,14 +76,17 @@ internal static class Program
|
|||
options.SerializerOptions.TypeInfoResolverChain.Insert(0, new AppSerializerContext());
|
||||
});
|
||||
|
||||
builder.Services.AddOptions();
|
||||
|
||||
builder.Services.AddSingleton<MapService>();
|
||||
builder.Services.AddSingleton<BulletManager>();
|
||||
builder.Services.AddSingleton<TankManager>();
|
||||
builder.Services.AddSingleton<SpawnNewTanks>();
|
||||
builder.Services.AddSingleton<PixelDrawer>();
|
||||
builder.Services.AddSingleton<ControlsServer>();
|
||||
builder.Services.AddSingleton<PlayerServer>();
|
||||
builder.Services.AddSingleton<ClientScreenServer>();
|
||||
builder.Services.AddSingleton<LastFinishedFrameProvider>();
|
||||
builder.Services.AddSingleton<SpawnQueueProvider>();
|
||||
|
||||
builder.Services.AddHostedService<GameTickService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<ControlsServer>());
|
||||
|
@ -94,7 +99,7 @@ internal static class Program
|
|||
builder.Services.AddSingleton<ITickStep, MoveTanks>();
|
||||
builder.Services.AddSingleton<ITickStep, ShootFromTanks>();
|
||||
builder.Services.AddSingleton<ITickStep>(sp => sp.GetRequiredService<SpawnNewTanks>());
|
||||
builder.Services.AddSingleton<ITickStep>(sp => sp.GetRequiredService<PixelDrawer>());
|
||||
builder.Services.AddSingleton<ITickStep, DrawStateToFrame>();
|
||||
builder.Services.AddSingleton<ITickStep, SendToServicePointDisplay>();
|
||||
builder.Services.AddSingleton<ITickStep, SendToClientScreen>();
|
||||
|
||||
|
@ -102,6 +107,9 @@ internal static class Program
|
|||
builder.Services.AddSingleton<IDrawStep, TankDrawer>();
|
||||
builder.Services.AddSingleton<IDrawStep, BulletDrawer>();
|
||||
|
||||
builder.Services.Configure<ServicePointDisplayConfiguration>(
|
||||
builder.Configuration.GetSection("ServicePointDisplay"));
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Channels;
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Net.WebSockets;
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TanksServer.Helpers;
|
||||
using TanksServer.Models;
|
||||
|
||||
namespace TanksServer.Servers;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TanksServer.TickSteps;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.Servers;
|
||||
|
||||
internal sealed class PlayerServer(ILogger<PlayerServer> logger, SpawnNewTanks spawnNewTanks)
|
||||
internal sealed class PlayerServer(ILogger<PlayerServer> logger, SpawnQueueProvider spawnQueueProvider)
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Player> _players = new();
|
||||
|
||||
|
@ -33,7 +33,7 @@ internal sealed class PlayerServer(ILogger<PlayerServer> logger, SpawnNewTanks s
|
|||
private Player AddAndSpawn(string name)
|
||||
{
|
||||
var player = new Player(name);
|
||||
spawnNewTanks.SpawnTankForPlayer(player);
|
||||
spawnQueueProvider.Queue.Enqueue(player);
|
||||
return player;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using TanksServer.Models;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
|
||||
internal sealed class BulletManager
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TanksServer.TickSteps;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
|
||||
internal sealed class GameTickService(IEnumerable<ITickStep> steps) : IHostedService, IDisposable
|
||||
internal sealed class GameTickService(
|
||||
IEnumerable<ITickStep> steps, IHostApplicationLifetime lifetime, ILogger<GameTickService> logger
|
||||
) : IHostedService, IDisposable
|
||||
{
|
||||
private readonly CancellationTokenSource _cancellation = new();
|
||||
private readonly List<ITickStep> _steps = steps.ToList();
|
||||
|
@ -17,11 +20,19 @@ internal sealed class GameTickService(IEnumerable<ITickStep> steps) : IHostedSer
|
|||
|
||||
private async Task RunAsync()
|
||||
{
|
||||
while (!_cancellation.IsCancellationRequested)
|
||||
try
|
||||
{
|
||||
foreach (var step in _steps)
|
||||
await step.TickAsync();
|
||||
await Task.Delay(1000/25);
|
||||
while (!_cancellation.IsCancellationRequested)
|
||||
{
|
||||
foreach (var step in _steps)
|
||||
await step.TickAsync();
|
||||
await Task.Delay(1000 / 25);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "game tick service crashed");
|
||||
lifetime.StopApplication();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
TanksServer/Services/LastFinishedFrameProvider.cs
Normal file
14
TanksServer/Services/LastFinishedFrameProvider.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using TanksServer.Helpers;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
|
||||
internal sealed class LastFinishedFrameProvider
|
||||
{
|
||||
private DisplayPixelBuffer? _lastFrame;
|
||||
|
||||
public DisplayPixelBuffer LastFrame
|
||||
{
|
||||
get => _lastFrame ?? throw new InvalidOperationException("first frame not yet drawn");
|
||||
set => _lastFrame = value;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
using TanksServer.Models;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
|
||||
internal sealed class MapService
|
||||
|
|
8
TanksServer/Services/SpawnQueueProvider.cs
Normal file
8
TanksServer/Services/SpawnQueueProvider.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using TanksServer.Models;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
|
||||
internal sealed class SpawnQueueProvider
|
||||
{
|
||||
public ConcurrentQueue<Player> Queue { get; } = new();
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TanksServer.Models;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using TanksServer.Helpers;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class CollideBulletsWithTanks(BulletManager bullets) : ITickStep
|
||||
|
|
|
@ -1,30 +1,25 @@
|
|||
using TanksServer.DrawSteps;
|
||||
using TanksServer.Helpers;
|
||||
using TanksServer.TickSteps;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.Services;
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class PixelDrawer(IEnumerable<IDrawStep> drawSteps) : ITickStep
|
||||
internal sealed class DrawStateToFrame(
|
||||
IEnumerable<IDrawStep> drawSteps, LastFinishedFrameProvider lastFrameProvider
|
||||
) : ITickStep
|
||||
{
|
||||
private const uint GameFieldPixelCount = MapService.PixelsPerRow * MapService.PixelsPerColumn;
|
||||
private DisplayPixelBuffer? _lastFrame;
|
||||
private readonly List<IDrawStep> _drawSteps = drawSteps.ToList();
|
||||
|
||||
public DisplayPixelBuffer LastFrame
|
||||
{
|
||||
get => _lastFrame ?? throw new InvalidOperationException("first frame not yet drawn");
|
||||
private set => _lastFrame = value;
|
||||
}
|
||||
|
||||
public Task TickAsync()
|
||||
{
|
||||
var buffer = CreateGameFieldPixelBuffer();
|
||||
foreach (var step in _drawSteps)
|
||||
foreach (var step in _drawSteps)
|
||||
step.Draw(buffer);
|
||||
LastFrame = buffer;
|
||||
lastFrameProvider.LastFrame = buffer;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
private static DisplayPixelBuffer CreateGameFieldPixelBuffer()
|
||||
{
|
||||
var data = new byte[10 + GameFieldPixelCount / 8];
|
|
@ -1,3 +1,6 @@
|
|||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class MoveBullets(BulletManager bullets) : ITickStep
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class MoveTanks(
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class RotateTanks(TankManager tanks, IOptions<TanksConfiguration> options) : ITickStep
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
using TanksServer.Servers;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class SendToClientScreen(
|
||||
ClientScreenServer clientScreenServer, PixelDrawer drawer
|
||||
ClientScreenServer clientScreenServer,
|
||||
LastFinishedFrameProvider lastFinishedFrameProvider
|
||||
) : ITickStep
|
||||
{
|
||||
public Task TickAsync()
|
||||
{
|
||||
return Task.WhenAll(clientScreenServer.GetConnections().Select(c => c.SendAsync(drawer.LastFrame)));
|
||||
var tasks = clientScreenServer
|
||||
.GetConnections()
|
||||
.Select(c => c.SendAsync(lastFinishedFrameProvider.LastFrame));
|
||||
return Task.WhenAll(tasks);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
using System.Net.Sockets;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class SendToServicePointDisplay(
|
||||
IOptions<ServicePointDisplayConfiguration> options,
|
||||
PixelDrawer drawer
|
||||
IOptions<ServicePointDisplayConfiguration> options,
|
||||
LastFinishedFrameProvider lastFinishedFrameProvider
|
||||
) : ITickStep, IDisposable
|
||||
{
|
||||
private readonly UdpClient _udpClient = new(options.Value.Hostname, options.Value.Port);
|
||||
private readonly UdpClient? _udpClient = options.Value.Enable
|
||||
? new(options.Value.Hostname, options.Value.Port)
|
||||
: null;
|
||||
|
||||
public Task TickAsync()
|
||||
{
|
||||
return _udpClient.SendAsync(drawer.LastFrame.Data).AsTask();
|
||||
return _udpClient?.SendAsync(lastFinishedFrameProvider.LastFrame.Data).AsTask() ?? Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_udpClient.Dispose();
|
||||
_udpClient?.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class ShootFromTanks(
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System.Collections.Concurrent;
|
||||
using TanksServer.Models;
|
||||
using TanksServer.Services;
|
||||
|
||||
namespace TanksServer.TickSteps;
|
||||
|
||||
internal sealed class SpawnNewTanks(TankManager tanks, MapService map) : ITickStep
|
||||
internal sealed class SpawnNewTanks(TankManager tanks, MapService map, SpawnQueueProvider queueProvider) : ITickStep
|
||||
{
|
||||
private readonly ConcurrentQueue<Player> _playersToSpawn = new();
|
||||
|
||||
public Task TickAsync()
|
||||
{
|
||||
while (_playersToSpawn.TryDequeue(out var player))
|
||||
while (queueProvider.Queue.TryDequeue(out var player))
|
||||
{
|
||||
var tank = new Tank(player, ChooseSpawnPosition())
|
||||
{
|
||||
|
@ -42,9 +41,4 @@ internal sealed class SpawnNewTanks(TankManager tanks, MapService map) : ITickSt
|
|||
chosenTile.Y * MapService.TileSize
|
||||
);
|
||||
}
|
||||
|
||||
public void SpawnTankForPlayer(Player player)
|
||||
{
|
||||
_playersToSpawn.Enqueue(player);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,5 +13,10 @@
|
|||
"Url": "http://localhost:3000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ServicePointDisplay": {
|
||||
"Enable": false,
|
||||
"Hostname": "172.23.42.29",
|
||||
"Port": 2342
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue