servicepoint-tanks/tanks-backend/TanksServer/Interactivity/SendToServicePointDisplay.cs

117 lines
4 KiB
C#
Raw Normal View History

using System.Diagnostics;
2024-05-13 01:23:34 +02:00
using System.Net;
using System.Net.Sockets;
2024-05-26 15:06:09 +02:00
using ServicePoint;
using TanksServer.GameLogic;
using TanksServer.Graphics;
2024-05-26 15:06:09 +02:00
using CompressionCode = ServicePoint.BindGen.CompressionCode;
namespace TanksServer.Interactivity;
internal sealed class SendToServicePointDisplay : IFrameConsumer
{
2024-04-13 14:08:51 +02:00
private const int ScoresWidth = 12;
private const int ScoresHeight = 20;
2024-04-19 13:41:53 +02:00
private const int ScoresPlayerRows = ScoresHeight - 6;
2024-04-13 14:08:51 +02:00
2024-05-13 01:23:34 +02:00
private readonly Connection _displayConnection;
2024-04-19 13:41:53 +02:00
private readonly MapService _mapService;
private readonly ILogger<SendToServicePointDisplay> _logger;
2024-04-13 14:08:51 +02:00
private readonly PlayerServer _players;
2024-08-29 21:44:25 +02:00
private readonly Cp437Grid _scoresBuffer;
private readonly TimeSpan _minFrameTime;
private readonly IOptionsMonitor<HostConfiguration> _options;
private DateTime _nextFailLogAfter = DateTime.Now;
private DateTime _nextFrameAfter = DateTime.Now;
public SendToServicePointDisplay(
PlayerServer players,
ILogger<SendToServicePointDisplay> logger,
2024-05-13 01:23:34 +02:00
Connection displayConnection,
2024-04-19 13:41:53 +02:00
IOptions<HostConfiguration> hostOptions,
MapService mapService,
2024-05-13 01:23:34 +02:00
IOptionsMonitor<HostConfiguration> options,
IOptions<DisplayConfiguration> displayConfig)
{
_players = players;
_logger = logger;
_displayConnection = displayConnection;
2024-04-19 13:41:53 +02:00
_mapService = mapService;
_minFrameTime = TimeSpan.FromMilliseconds(hostOptions.Value.ServicePointDisplayMinFrameTimeMs);
_options = options;
2024-05-13 01:23:34 +02:00
var localIp = GetLocalIPv4(displayConfig.Value).Split('.');
Debug.Assert(localIp.Length == 4);
2024-08-29 21:44:25 +02:00
_scoresBuffer = Cp437Grid.New(12, 20);
2024-05-13 01:23:34 +02:00
_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)
{
if (!_options.CurrentValue.EnableServicePointDisplay)
return;
if (DateTime.Now < _nextFrameAfter)
return;
_nextFrameAfter = DateTime.Now + _minFrameTime;
await Task.Yield();
RefreshScores();
try
{
2024-05-16 23:40:00 +02:00
_displayConnection.Send(Command.BitmapLinearWin(0, 0, observerPixels.Clone(), CompressionCode.Lzma)
.IntoPacket());
2024-05-15 20:38:16 +02:00
_displayConnection.Send(Command.Cp437Data(MapService.TilesPerRow, 0, _scoresBuffer.Clone()).IntoPacket());
}
catch (SocketException ex)
{
if (DateTime.Now > _nextFailLogAfter)
{
_logger.LogWarning("could not send data to service point display: {}", ex.Message);
_nextFailLogAfter = DateTime.Now + TimeSpan.FromSeconds(5);
}
}
}
private void RefreshScores()
{
2024-05-03 14:45:41 +02:00
var playersToDisplay = _players.Players
2024-04-13 18:35:36 +02:00
.OrderByDescending(p => p.Scores.Kills)
.Take(ScoresPlayerRows);
ushort row = 2;
foreach (var p in playersToDisplay)
{
2024-04-13 18:35:36 +02:00
var score = p.Scores.Kills.ToString();
var nameLength = Math.Min(p.Name.Length, ScoresWidth - score.Length - 1);
var name = p.Name[..nameLength];
var spaces = new string(' ', ScoresWidth - score.Length - nameLength);
_scoresBuffer[row] = name + spaces + score;
row++;
}
2024-04-19 13:41:53 +02:00
for (; row < 16; row++)
_scoresBuffer[row] = string.Empty;
2024-04-19 13:41:53 +02:00
_scoresBuffer[16] = _mapService.Current.Name[..(Math.Min(ScoresWidth, _mapService.Current.Name.Length) - 1)];
}
2024-05-13 01:23:34 +02:00
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();
}
2024-04-13 14:08:51 +02:00
}