Danro-Jump/Assets/Scripts/Runtime/Settings/Core/ServiceSettingsStatisticsSummaryBuilder.cs
Danil Iarosh d39d160d92 Implement physical prize dispensing, service stats, and QR screen timeout
- Добавлен асинхронный процесс аппаратной выдачи физических призов (хоппер и витрина) в GameplayHudController.
- Реализована блокировка выдачи по 10-секундному таймауту датчика хоппера с гарантированной отправкой команды отключения двигателя '300'.
- Реализован автоматический таймаут неактивности на экране QR-кода с последующим переходом в главное меню.
- Расширен сервис статистики PrizeSessionStateService новыми долгосрочными счетчиками (сыгранные игры, очки, монеты, сбои связи COM, физ. выдачи и ошибки).
- Обновлен построитель сводки статистики в меню настроек для отображения новых счетчиков и списка последних 5 сессий.
- Написаны EditMode тесты для проверки инкремента счетчиков и запуска выдачи призов.
2026-06-23 10:36:13 +03:00

81 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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(),
};
}
}
}