103 lines
4.3 KiB
C#
Raw Permalink Normal View History

2025-09-19 19:43:49 +05:00
using System;
2025-09-19 14:56:58 +05:00
using UnityEngine;
2025-09-19 19:43:49 +05:00
using Cysharp.Threading.Tasks;
2025-09-19 14:56:58 +05:00
namespace BulletHellTemplate
{
2025-09-19 19:43:49 +05:00
/// <summary>
/// Maintains Battle-Pass XP, level and premium/reward flow.
/// Serverside persistence is delegated to <see cref="BackendManager.Service"/>.
/// Season state (number/start/end) is cached in <see cref="PlayerSave"/>.
/// </summary>
[DisallowMultipleComponent]
public sealed class BattlePassManager : MonoBehaviour
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
public static BattlePassManager Singleton { get; private set; }
2025-09-19 14:56:58 +05:00
public event EventHandler OnXPChanged;
2025-09-19 19:43:49 +05:00
/*──────────── Runtime state ───────────*/
[HideInInspector] public int currentXP;
[HideInInspector] public int currentLevel;
[HideInInspector] public int xpForNextLevel;
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
[Header("Translations")]
[SerializeField]
private string notEnoughFallback = "Not enough {1}. Need {0} more.";
[SerializeField] private NameTranslatedByLanguage[] notEnoughTranslated;
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
/*────────────────── Unity ──────────────*/
private void Awake()
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
if (Singleton == null)
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
Singleton = this;
LoadProgress();
2025-09-19 14:56:58 +05:00
}
2025-09-19 19:43:49 +05:00
else Destroy(gameObject);
2025-09-19 14:56:58 +05:00
}
2025-09-19 19:43:49 +05:00
/*───────────────── Public API ──────────*/
public bool IsPremium() => PlayerSave.CheckBattlePassPremiumUnlocked();
public bool IsRewardClaimed(string id) => PlayerSave.CheckBattlePassRewardClaimed(id);
public bool HasSeasonEnded() => PlayerSave.HasSeasonEnded();
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
public int XPForLevel(int level) =>
Mathf.FloorToInt(GameInstance.Singleton.baseExpPass * Mathf.Pow(1f + GameInstance.Singleton.incPerLevelPass, level - 1));
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
/// <summary>Re-reads XP/level from <see cref="PlayerSave"/> and raises <see cref="OnXPChanged"/>.</summary>
public void SyncFromPlayerSave() => LoadProgress();
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
/// <summary>Returns the cached season number.</summary>
public UniTask<int> GetSeasonAsync() =>
UniTask.FromResult(Mathf.Max(1, PlayerSave.GetBattlePassCurrentSeason()));
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
/// <summary>Returns remaining time until season end based on cached timestamps.</summary>
public UniTask<TimeSpan> GetRemainingAsync() =>
UniTask.FromResult(PlayerSave.GetBattlePassSeasonRemaining());
2025-09-19 14:56:58 +05:00
2025-09-19 19:43:49 +05:00
/*──────────── Premium / Reward ────────*/
public async UniTask<string> TryUnlockPremiumAsync()
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
RequestResult ok = await BackendManager.Service.UnlockBattlePassPremiumAsync();
if (ok.Success)
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
OnXPChanged?.Invoke(this, EventArgs.Empty);
2025-09-19 14:56:58 +05:00
return null;
}
2025-09-19 19:43:49 +05:00
int balance = MonetizationManager.GetCurrency(GameInstance.Singleton.battlePassCurrencyID);
string tpl = Translate(notEnoughTranslated, notEnoughFallback);
return string.Format(tpl, GameInstance.Singleton.battlePassPrice - balance, GameInstance.Singleton.battlePassCurrencyID);
2025-09-19 14:56:58 +05:00
}
2025-09-19 19:43:49 +05:00
public async UniTask ClaimRewardAsync(BattlePassItem item)
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
var r = await BackendManager.Service.ClaimBattlePassRewardAsync(item);
if (!r.Success) Debug.LogWarning(r.Reason);
2025-09-19 14:56:58 +05:00
}
2025-09-19 19:43:49 +05:00
/*──────────── Persistence ─────────────*/
private void LoadProgress()
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
(int xp, int lvl, bool _) = PlayerSave.GetBattlePassProgress();
currentXP = xp;
currentLevel = lvl;
xpForNextLevel = XPForLevel(lvl);
2025-09-19 14:56:58 +05:00
OnXPChanged?.Invoke(this, EventArgs.Empty);
}
2025-09-19 19:43:49 +05:00
/*──────────── Translation helper ──────*/
private static string Translate(NameTranslatedByLanguage[] table, string fallback)
2025-09-19 14:56:58 +05:00
{
2025-09-19 19:43:49 +05:00
string lang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage();
foreach (var t in table)
if (t.LanguageId.Equals(lang, StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(t.Translate))
return t.Translate;
2025-09-19 14:56:58 +05:00
return fallback;
}
}
}