Danro/Assets/Scripts/Prizes/PrizeDatabase.cs
Danil Iarosh 78d7679e2b
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat(prizes, ui): complete Mar 24-Apr 2 sprint ahead of schedule
- завершен спринт 24 марта - 2 апреля с опережением плана и закрытием задач раньше срока
- расширена и стабилизирована система призов:
  добавлены и доработаны QR-tier конфиги, новые типы и модели данных,
  сохранение `qrCodes` в `prizes.json`, fallback-логика и синхронизация
  через `PrizeSystemManager`, `PrizeDatabase` и `LevelPrizeConfig`
- переработан flow настройки QR-призов:
  добавлены `QRCodeSettingsModal` и связанный UI-код,
  разнесены короткий текст приза и полный текст сообщения,
  добавлены шаблоны форматирования, корректная подстановка текста
  в QR и в UI-модалках, а также сохранение конфигурации между запусками
- доработан flow суперприза и текстовых настроек:
  добавлены fallback-правила показа, корректная обработка пустых строк
  и строк из одних пробелов, обновлены binders и показ текста в меню
- реализована и обновлена отдельная настройка витрины:
  добавлена `PrizeStandSettingsModal`, обновлена навигация строк,
  логика выбора ячейки и порогов очков, циклический выбор ячеек,
  ускорение изменения значений и исправления для keyboard/gamepad UX
- доработана игровая модалка витрины `PrizeStandModal`:
  добавлен вывод очков игрока, форматируемый текст счета,
  улучшено отображение ячеек и связанная логика выбора приза
- исправлен подсчет очков и интеграция с prize flow:
  `ScoreSystem` переведен на событийное обновление текущего счета,
  добавлены `CurrentScore`, `CurrentScoreChanged` и корректный display score,
  витрина и связанные UI-элементы теперь получают актуальные очки,
  а не нулевые или несвоевременные preview-значения
- переработаны модальные окна и навигация UI:
  улучшены `Modal`, `ModalManager`, `UIRowPointer`, `RulesModal`,
  `QRCodeModal`, `PrizeStandModal`, `LevelPrizeSettingsModal` и др.,
  чтобы фокус, указатель и submit работали консистентно без мыши
- обновлен win/prize UI:
  доработаны `WinBannerController`, `GameEndUIController`,
  `MainMenu`, `QRCodeUIController`, `TopPanelTextController` и настройки UI,
  улучшены тексты баннеров, отображение призов и итогового счета
- обновлены сцены и ассеты под новый flow:
  `MainMenu`, `Level UI`, prefab'ы строк настроек и кнопок,
  глобальные префабы, шрифты TMP, иконки, recovery-данные и ресурсы UI
- добавлены вспомогательные UI-компоненты и служебные скрипты:
  `ButtonTextFocusColor`, `SelectableDescriptionTarget`, `QRTier`
  и другие изменения, поддерживающие новый конфигурируемый prize UI
2026-04-01 12:47:17 +03:00

194 lines
7.5 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.Collections.Generic;
using System.IO;
using UnityEngine;
using RR.Common.Utility;
namespace RR.Common.Prizes
{
/// <summary>
/// Хранилище призов за уровни. Загружает и сохраняет конфигурацию в JSON-файл.
/// Если файла нет — создаёт новый с пустым списком (нет призов ни за один уровень).
/// </summary>
public class PrizeDatabase
{
private const string FileName = "prizes.json";
private readonly Dictionary<string, LevelPrizeConfig> _configs = new();
private PrizeStandSettings _prizeStandSettings = new();
private List<QRCodeInfo> _qrCodes = new();
private bool _hasStoredQRCodes;
private string _filePath;
/// <summary>Путь к JSON-файлу.</summary>
public string FilePath => _filePath;
/// <summary>Глобальные настройки витрины.</summary>
public PrizeStandSettings PrizeStandSettings => _prizeStandSettings;
public bool HasStoredQRCodes => _hasStoredQRCodes;
// ────────────── Загрузка / сохранение ──────────────
/// <summary>
/// Загружает конфигурацию из JSON-файла рядом с исполняемым файлом.
/// Если файл отсутствует — создаёт пустой.
/// </summary>
public void Load()
{
string root = Directory.GetParent(Application.dataPath)?.ToString()
?? Application.dataPath;
_filePath = Path.Combine(root, FileName);
_configs.Clear();
_prizeStandSettings = new PrizeStandSettings();
_qrCodes = new List<QRCodeInfo>();
_hasStoredQRCodes = false;
if (File.Exists(_filePath))
{
string json = File.ReadAllText(_filePath);
var data = JsonUtility.FromJson<PrizesFileData>(json);
_prizeStandSettings = data?.prizeStandSettings ?? new PrizeStandSettings();
_qrCodes = data?.qrCodes != null ? new List<QRCodeInfo>(data.qrCodes) : new List<QRCodeInfo>();
_hasStoredQRCodes = data?.qrCodes != null;
NormalizePrizeStandSettings();
if (data?.levels != null)
{
foreach (PrizeLevelEntry entry in data.levels)
{
if (!string.IsNullOrEmpty(entry.level))
_configs[entry.level] = entry.config ?? new LevelPrizeConfig();
}
}
Debug.Log($"[PrizeDatabase] Загружено {_configs.Count} записей из {_filePath}");
}
else
{
Save();
_hasStoredQRCodes = false;
Debug.Log($"[PrizeDatabase] Файл не найден — создан пустой: {_filePath}");
}
}
/// <summary>
/// Сохраняет текущую конфигурацию в JSON-файл.
/// </summary>
public void Save()
{
if (string.IsNullOrEmpty(_filePath)) return;
var data = new PrizesFileData();
data.prizeStandSettings = _prizeStandSettings ?? new PrizeStandSettings();
data.qrCodes = _qrCodes != null ? new List<QRCodeInfo>(_qrCodes) : new List<QRCodeInfo>();
foreach (var kvp in _configs)
data.levels.Add(new PrizeLevelEntry { level = kvp.Key, config = kvp.Value });
string json = JsonUtility.ToJson(data, true);
File.WriteAllText(_filePath, json);
_hasStoredQRCodes = true;
Debug.Log($"[PrizeDatabase] Сохранено {_configs.Count} записей в {_filePath}");
}
// ────────────── Чтение ──────────────
/// <summary>
/// Возвращает конфигурацию приза для указанного уровня.
/// Если для уровня нет записи — возвращает <see cref="PrizeType.None"/>.
/// </summary>
public LevelPrizeConfig GetConfig(string level)
{
return _configs.TryGetValue(level, out var config) ? config : new LevelPrizeConfig();
}
/// <summary>
/// Проверяет, есть ли запись для указанного уровня.
/// </summary>
public bool HasConfig(string level) => _configs.ContainsKey(level);
/// <summary>
/// Все записи (только для чтения).
/// </summary>
public IReadOnlyDictionary<string, LevelPrizeConfig> GetAll() => _configs;
/// <summary>
/// Возвращает глобальные настройки витрины.
/// </summary>
public PrizeStandSettings GetPrizeStandSettings()
{
NormalizePrizeStandSettings();
return _prizeStandSettings;
}
public List<QRCodeInfo> GetQRCodes()
{
return _qrCodes != null ? new List<QRCodeInfo>(_qrCodes) : new List<QRCodeInfo>();
}
// ────────────── Запись ──────────────
/// <summary>
/// Устанавливает конфигурацию приза для уровня и сохраняет файл.
/// </summary>
public void SetConfig(string level, LevelPrizeConfig config)
{
_configs[level] = config;
Save();
}
/// <summary>
/// Удаляет запись для уровня (приз = None) и сохраняет файл.
/// </summary>
public void RemoveConfig(string level)
{
if (_configs.Remove(level))
Save();
}
/// <summary>
/// Сохраняет глобальные настройки витрины.
/// </summary>
public void SetPrizeStandSettings(PrizeStandSettings settings)
{
_prizeStandSettings = settings ?? new PrizeStandSettings();
NormalizePrizeStandSettings();
Save();
}
public void SetQRCodes(List<QRCodeInfo> qrCodes)
{
_qrCodes = qrCodes != null ? new List<QRCodeInfo>(qrCodes) : new List<QRCodeInfo>();
Save();
}
/// <summary>
/// Очищает все записи и сохраняет пустой файл.
/// </summary>
public void Clear()
{
_configs.Clear();
_prizeStandSettings = new PrizeStandSettings();
_qrCodes = new List<QRCodeInfo>();
Save();
}
private void NormalizePrizeStandSettings()
{
_prizeStandSettings ??= new PrizeStandSettings();
_prizeStandSettings.boxes ??= new List<PrizeStandBoxConfig>();
_prizeStandSettings.boxes.Sort((a, b) => a.boxNumber.CompareTo(b.boxNumber));
for (int i = _prizeStandSettings.boxes.Count - 1; i >= 0; i--)
{
PrizeStandBoxConfig box = _prizeStandSettings.boxes[i];
if (box == null || box.boxNumber <= 0)
_prizeStandSettings.boxes.RemoveAt(i);
}
}
}
}