- Добавлен асинхронный процесс аппаратной выдачи физических призов (хоппер и витрина) в GameplayHudController. - Реализована блокировка выдачи по 10-секундному таймауту датчика хоппера с гарантированной отправкой команды отключения двигателя '300'. - Реализован автоматический таймаут неактивности на экране QR-кода с последующим переходом в главное меню. - Расширен сервис статистики PrizeSessionStateService новыми долгосрочными счетчиками (сыгранные игры, очки, монеты, сбои связи COM, физ. выдачи и ошибки). - Обновлен построитель сводки статистики в меню настроек для отображения новых счетчиков и списка последних 5 сессий. - Написаны EditMode тесты для проверки инкремента счетчиков и запуска выдачи призов.
81 lines
4.4 KiB
C#
81 lines
4.4 KiB
C#
using System;
|
||
using System.Linq;
|
||
using DanroJump.Prizes;
|
||
|
||
namespace DanroJump.Settings
|
||
{
|
||
/// <summary>
|
||
/// Собирает текст сервисной статистики без знания о маршрутизации кнопок.
|
||
/// </summary>
|
||
internal static class ServiceSettingsStatisticsSummaryBuilder
|
||
{
|
||
public static ServiceSettingsActionResult Build(
|
||
IReadOnlyServiceSettings settings,
|
||
IPrizeSessionStateService prizeSessionState)
|
||
{
|
||
var snapshot = settings?.Snapshot();
|
||
var totalSettings = snapshot?.Count ?? 0;
|
||
var visibleDefinitions = settings?.Database?.Entries.Count(entry => entry.ShownInServiceMenu) ?? 0;
|
||
var startCost = settings != null ? Math.Max(0, settings.GetInt(ServiceSettingsKeys.StartGameCost)) : 0;
|
||
var freePlay = settings != null && settings.GetBool(ServiceSettingsKeys.FreePlay);
|
||
var priceText = freePlay ? "free play" : $"{startCost}";
|
||
|
||
var prizeSummary = string.Empty;
|
||
if (prizeSessionState != null)
|
||
{
|
||
var historyList = prizeSessionState.History;
|
||
var recentHistory = historyList != null && historyList.Count > 0
|
||
? string.Join("\n", historyList.Skip(Math.Max(0, historyList.Count - 5)).Select(record =>
|
||
$"- [{record.StartedAtUtc:yyyy-MM-dd HH:mm:ss}] {FormatReward(record.Result.RewardKind)} ({record.Result.Score}очк) -> {FormatStatus(record.Status)}{(string.IsNullOrWhiteSpace(record.Note) ? "" : ": " + record.Note)}"))
|
||
: "История призов пуста.";
|
||
|
||
prizeSummary = $"\n\n--- Эксплуатационная статистика ---\n" +
|
||
$"Всего сыграно игр: {prizeSessionState.TotalGamesPlayed}\n" +
|
||
$"Набрано очков всего: {prizeSessionState.TotalScore}\n" +
|
||
$"Собрано монет всего: {prizeSessionState.TotalCoins}\n" +
|
||
$"Показов QR-кодов: {prizeSessionState.QrShows}\n" +
|
||
$"Успешных физ. выдач: {prizeSessionState.PhysicalDispenses}\n" +
|
||
$"Сбоев физ. выдач: {prizeSessionState.PhysicalDispenseFailures}\n" +
|
||
$"Сбоев связи по COM: {prizeSessionState.ComErrors}\n" +
|
||
$"Призовые сессии: начато {prizeSessionState.StartedCount}, завершено {prizeSessionState.CompletedCount}, сбоев {prizeSessionState.FailedCount}, повторов заблокировано {prizeSessionState.DuplicateBlockedCount}\n" +
|
||
$"\n--- Последние Призовые сессии (до 5) ---\n{recentHistory}";
|
||
}
|
||
else
|
||
{
|
||
prizeSummary = "\nПризовая история недоступна в текущем контексте.";
|
||
}
|
||
|
||
return ServiceSettingsActionResult.Success(
|
||
"Статистика",
|
||
$"Настроек загружено: {totalSettings}. Видимых пунктов: {visibleDefinitions}. Стоимость старта: {priceText}.{prizeSummary}",
|
||
"Статистика");
|
||
}
|
||
|
||
private static string FormatReward(PrizeRewardKind rewardKind)
|
||
{
|
||
return rewardKind switch
|
||
{
|
||
PrizeRewardKind.QRCode => "QR",
|
||
PrizeRewardKind.Hopper => "Хоппер",
|
||
PrizeRewardKind.PrizeStand => "Витрина",
|
||
PrizeRewardKind.Big => "Большой приз",
|
||
PrizeRewardKind.Small => "Малый приз",
|
||
_ => "Нет приза",
|
||
};
|
||
}
|
||
|
||
private static string FormatStatus(PrizeSessionStatus status)
|
||
{
|
||
return status switch
|
||
{
|
||
PrizeSessionStatus.Pending => "ожидает показа",
|
||
PrizeSessionStatus.Shown => "показана",
|
||
PrizeSessionStatus.Completed => "завершена",
|
||
PrizeSessionStatus.Failed => "ошибка",
|
||
PrizeSessionStatus.DuplicateBlocked => "повтор заблокирован",
|
||
_ => status.ToString(),
|
||
};
|
||
}
|
||
}
|
||
}
|