Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- добавлена новая система призов: PrizeBase, PrizeType, PrizeDatabase, LevelPrizeConfig и реализации для hopper, QR-кода, отсутствия приза и стойки с призом - добавлена конфигурация призов уровней через `prizes.json` и связанная логика загрузки/обработки в менеджерах игры - расширен UI главного меню и настроек уровней: добавлены LevelSettingsModal, LevelPrizeSettingsModal, QRCodeModal и PrizeStandModal - обновлена навигация модальных окон и связанный UI-код: ModalManager, MainMenu, RulesModal, PauseMenu, PrizeErrorDisplay, UIRowPointer и WinBannerController - доработаны настройки и генерация UI-элементов: обновлены SettingsDatabase, SettingsUIGenerator, SettingUIItem, ValueSelectorRow и editor drawer для настроек - обновлены и добавлены UI-prefab'ы для кнопок, строк настроек, панели групп и кнопки настроек уровня - обновлены сцены `MainMenu` и `Level UI` под новый флоу настройки уровней, выбора призов и отображения модалок - добавлены файлы лаунчера в `StreamingAssets`, включая `RRLauncher.exe`, служебные meta-файлы и документацию - улучшено логирование через FileLogger и удален устаревший код лицензирования - удалены больше неиспользуемые файлы: `Licensing.cs`, `SteppedSlider.cs` и recovery-сцены
237 lines
9.2 KiB
C#
237 lines
9.2 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using RR.Common.Prizes;
|
||
using RR.Common.Settings;
|
||
using RR.Common.UI;
|
||
using RR.Common.Utility;
|
||
using RR.Game2D.Core.Managers;
|
||
|
||
namespace RR.Common.Managers
|
||
{
|
||
/// <summary>
|
||
/// Центральный менеджер системы призов.
|
||
/// Не знает конкретики о призах — читает конфигурацию из JSON (<see cref="PrizeDatabase"/>)
|
||
/// и делегирует выдачу зарегистрированным исполнителям (<see cref="PrizeBase"/>).
|
||
/// </summary>
|
||
public class PrizeSystemManager : MonoBehaviour
|
||
{
|
||
public static PrizeSystemManager Instance { get; private set; }
|
||
|
||
[Header("QR-коды (глобальная конфигурация)")]
|
||
[SerializeField] private List<QRCodeInfo> qrCodes = new();
|
||
[SerializeField] private string phoneNumberMask = "+7XXXXXXXXXX";
|
||
|
||
|
||
/// <summary>Хранилище призов за уровни (JSON).</summary>
|
||
public PrizeDatabase Database { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Вызывается после выдачи любого приза. Параметры: тип приза, успех.
|
||
/// </summary>
|
||
public event Action<PrizeType, bool> OnAnyPrizeResult;
|
||
|
||
// ── Исполнители ──
|
||
private readonly Dictionary<PrizeType, PrizeBase> _executors = new();
|
||
|
||
|
||
// ── QR-коды ──
|
||
private readonly List<Texture2D> _generatedQRCodes = new();
|
||
private Texture2D[] _qrCodesCache;
|
||
private bool _qrCodesDirty = true;
|
||
private string _phoneNumber = string.Empty;
|
||
|
||
// ────────────── Инициализация ──────────────
|
||
|
||
public void Initialize()
|
||
{
|
||
if (Instance != null && Instance != this)
|
||
{
|
||
Destroy(gameObject);
|
||
return;
|
||
}
|
||
|
||
Instance = this;
|
||
DontDestroyOnLoad(gameObject);
|
||
|
||
// Загружаем базу призов из JSON
|
||
Database = new PrizeDatabase();
|
||
Database.Load();
|
||
|
||
// QR-коды (глобальные)
|
||
RefreshPhoneNumber();
|
||
GenerateQRCodes();
|
||
SubscribeToSettings();
|
||
|
||
// Регистрируем исполнителей — модальные окна регистрируют себя сами через static Current
|
||
RegisterExecutor(new NonePrize());
|
||
RegisterExecutor(new QRCodePrize(() => QRCodeModal.Current, GetQRCodes));
|
||
RegisterExecutor(new HopperPrize());
|
||
RegisterExecutor(new PrizeStandPrize(() => PrizeStandModal.Current));
|
||
|
||
Debug.Log("[PrizeSystemManager] Инициализирован. " +
|
||
$"Исполнители: {_executors.Count}, Уровней в базе: {Database.GetAll().Count}");
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
UnsubscribeFromSettings();
|
||
if (Instance == this) Instance = null;
|
||
}
|
||
|
||
// ────────────── Публичный API ──────────────
|
||
|
||
/// <summary>
|
||
/// Выдаёт приз за текущий уровень (World-Stage).
|
||
/// Конфигурация берётся из <see cref="PrizeDatabase"/>.
|
||
/// </summary>
|
||
public void GivePrizeForCurrentLevel()
|
||
{
|
||
string level = $"{GameManager.Instance.World}-{GameManager.Instance.Stage}";
|
||
GivePrizeForLevel(level);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Выдаёт приз за указанный уровень.
|
||
/// </summary>
|
||
public void GivePrizeForLevel(string levelName)
|
||
{
|
||
LevelPrizeConfig config = Database.GetConfig(levelName);
|
||
|
||
if (config.type == PrizeType.None)
|
||
{
|
||
Debug.Log($"[PrizeSystemManager] Уровень «{levelName}»: приз не назначен.");
|
||
OnAnyPrizeResult?.Invoke(PrizeType.None, true);
|
||
return;
|
||
}
|
||
|
||
if (!_executors.TryGetValue(config.type, out PrizeBase executor))
|
||
{
|
||
Debug.LogWarning($"[PrizeSystemManager] Нет исполнителя для типа «{config.type}».");
|
||
return;
|
||
}
|
||
|
||
if (executor.IsGiving)
|
||
{
|
||
Debug.LogWarning($"[PrizeSystemManager] Исполнитель «{config.type}» занят.");
|
||
return;
|
||
}
|
||
|
||
Debug.Log($"[PrizeSystemManager] Уровень «{levelName}» → приз «{config.type}».");
|
||
executor.Execute(this, config);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обратная совместимость: выдаёт приз хоппером (если включён в настройках).
|
||
/// </summary>
|
||
public void GivePrize()
|
||
{
|
||
bool hopperEnabled = SettingsManager.Instance != null
|
||
&& SettingsManager.Instance.GetBool("prizes.giveSmallPrize");
|
||
|
||
if (hopperEnabled && _executors.TryGetValue(PrizeType.Hopper, out PrizeBase executor))
|
||
executor.Execute(this, new LevelPrizeConfig { type = PrizeType.Hopper });
|
||
else
|
||
Debug.Log("[PrizeSystemManager] Хоппер отключён в настройках.");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Выдаёт приз указанного типа с конфигурацией по умолчанию.
|
||
/// </summary>
|
||
public void GivePrize(PrizeType type)
|
||
{
|
||
if (!_executors.TryGetValue(type, out PrizeBase executor))
|
||
{
|
||
Debug.LogWarning($"[PrizeSystemManager] Нет исполнителя для «{type}».");
|
||
return;
|
||
}
|
||
|
||
executor.Execute(this, new LevelPrizeConfig { type = type });
|
||
}
|
||
|
||
/// <summary>Возвращает QR-коды (кешируется до перегенерации).</summary>
|
||
public Texture2D[] GetQRCodes()
|
||
{
|
||
if (_qrCodesDirty || _qrCodesCache == null)
|
||
{
|
||
_qrCodesCache = _generatedQRCodes.ToArray();
|
||
_qrCodesDirty = false;
|
||
}
|
||
return _qrCodesCache;
|
||
}
|
||
|
||
/// <summary>Идёт ли выдача какого-либо приза.</summary>
|
||
public bool IsAnyPrizeGiving
|
||
{
|
||
get
|
||
{
|
||
foreach (PrizeBase ex in _executors.Values)
|
||
if (ex.IsGiving) return true;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
// ────────────── Регистрация исполнителей ──────────────
|
||
|
||
/// <summary>Регистрирует исполнитель приза. Заменяет предыдущий для того же типа.</summary>
|
||
public void RegisterExecutor(PrizeBase executor)
|
||
{
|
||
_executors[executor.Type] = executor;
|
||
executor.OnPrizeResult += success => OnAnyPrizeResult?.Invoke(executor.Type, success);
|
||
}
|
||
|
||
// ────────────── QR-коды (глобальная генерация) ──────────────
|
||
|
||
private void RefreshPhoneNumber()
|
||
{
|
||
var settings = SettingsManager.Instance;
|
||
_phoneNumber = settings?.GetString("prizes.phoneNumber") ?? string.Empty;
|
||
_phoneNumber = PhoneNumberUtils.ValidatePhoneNumber(_phoneNumber);
|
||
_phoneNumber = PhoneNumberUtils.ApplyPhoneMask(_phoneNumber, phoneNumberMask);
|
||
}
|
||
|
||
private void GenerateQRCodes()
|
||
{
|
||
_generatedQRCodes.Clear();
|
||
_qrCodesDirty = true;
|
||
|
||
foreach (QRCodeInfo data in qrCodes)
|
||
{
|
||
if (!data.generateQRCode) continue;
|
||
|
||
string fullLink = data.GetFullLink(_phoneNumber);
|
||
Texture2D tex = QRMaker.MakeTexture(
|
||
fullLink, 8, true,
|
||
QRCodeInfo.GetColor(data.darkColor),
|
||
QRCodeInfo.GetColor(data.lightColor));
|
||
|
||
_generatedQRCodes.Add(tex);
|
||
}
|
||
}
|
||
|
||
// ────────────── Настройки ──────────────
|
||
|
||
private void SubscribeToSettings()
|
||
{
|
||
var settings = SettingsManager.Instance;
|
||
if (settings != null) settings.OnSettingChanged += OnSettingChanged;
|
||
}
|
||
|
||
private void UnsubscribeFromSettings()
|
||
{
|
||
var settings = SettingsManager.Instance;
|
||
if (settings != null) settings.OnSettingChanged -= OnSettingChanged;
|
||
}
|
||
|
||
private void OnSettingChanged(string key, SettingValue value)
|
||
{
|
||
if (key == "prizes.phoneNumber")
|
||
{
|
||
RefreshPhoneNumber();
|
||
GenerateQRCodes();
|
||
Debug.Log("[PrizeSystemManager] QR-коды перегенерированы.");
|
||
}
|
||
}
|
||
}
|
||
} |