using System; using System.Collections; using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; namespace BulletHellTemplate { /// /// Manages the Battle Pass UI, including displaying items, XP, error messages, and handling popups. /// public class UIBattlePass : MonoBehaviour { [Header("Battle Pass Items")] public BattlePassItem[] battlePassItems; public PassEntry passEntryPrefab; public Transform containerPassItems; [Header("UI Elements")] public TextMeshProUGUI errorMessage; public TextMeshProUGUI levelText; public TextMeshProUGUI xpText; public Image xpProgressBar; public TextMeshProUGUI currentSeason; public TextMeshProUGUI remainingSeasonTime; public TextMeshProUGUI endSeasonText; public GameObject ButtonBuyPassVisual; [Header("Purchase Pass Popup")] public GameObject purchasePopup; public Image purchaseIconCurrency; public TextMeshProUGUI purchaseTextPrice; [Header("Claim Reward Popup")] public GameObject claimPopup; public Image claimIconReward; public TextMeshProUGUI claimTextRewardAmount; [Header("Translated Labels and Fallbacks")] public string levelLabelFallback = "Level: {0}"; [Tooltip("Translation for the 'Level: {0}' label.")] public NameTranslatedByLanguage[] levelLabelTranslated; [Space] [Tooltip("Translation for the 'XP: {0} / {1}' label.")] public string xpLabelFallback = "XP: {0} / {1}"; public NameTranslatedByLanguage[] xpLabelTranslated; [Space] [Tooltip("Translation for the 'Season: {0}' label.")] public string seasonLabelFallback = "Season: {0}"; public NameTranslatedByLanguage[] seasonLabelTranslated; [Space] [Tooltip("Translation for the 'Season ended' label.")] public string seasonEndedLabelFallback = "Season ended"; public NameTranslatedByLanguage[] seasonEndedLabelTranslated; [Space] [Tooltip("Translation for the 'Ends: ' prefix label.")] public string seasonEndsLabelFallback = "Ends: "; public NameTranslatedByLanguage[] seasonEndsLabelTranslated; private bool firstLoad; public static UIBattlePass Singleton; [Header("Events")] [Tooltip("Event invoked when the menu is opened.")] public UnityEvent OnOpenMenu; [Tooltip("Event invoked when the menu is closed.")] public UnityEvent OnCloseMenu; private void Awake() { if (Singleton == null) { Singleton = this; } LoadSeasonInfoAsync(); } /// /// Loads season information and checks for updates. /// public async void LoadSeasonInfoAsync() { await BattlePassManager.Singleton.CheckAndUpdateSeasonAsync(); firstLoad = true; } private void OnEnable() { if (firstLoad) { BattlePassManager.Singleton.OnXPChanged += OnXPChanged; LoadBattlePassItems(); } errorMessage.text = ""; } private void OnDisable() { BattlePassManager.Singleton.OnXPChanged -= OnXPChanged; } /// /// Starts a coroutine to update the remaining season time after the UI has been rendered. /// /// IEnumerator for coroutine. private IEnumerator StartRemainingTimeCoroutineAfterFrame() { yield return null; StartCoroutine(GetRemainingSeasonTime()); } /// /// Retrieves and updates the remaining season time from PlayerPrefs. /// /// IEnumerator for coroutine. public IEnumerator GetRemainingSeasonTime() { string savedEndTimeStr = BattlePassManager.GetRemainingSeasonTimeLocally(); string currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage(); if (string.IsNullOrEmpty(savedEndTimeStr)) { Debug.LogWarning("No season end time found. Please ensure it is saved locally."); yield break; } DateTime seasonEndTime = DateTime.Parse(savedEndTimeStr, null, System.Globalization.DateTimeStyles.RoundtripKind); while (true) { TimeSpan remainingTime = seasonEndTime - DateTime.UtcNow; if (remainingTime.TotalSeconds <= 0) { Debug.Log("The current season has ended."); BattlePassManager.SetPlayerBattlePassSeasonEnded(); string seasonEndedLabel = GetTranslatedString(seasonEndedLabelTranslated, seasonEndedLabelFallback, currentLang); remainingSeasonTime.text = seasonEndedLabel; yield break; } string seasonEndsLabel = GetTranslatedString(seasonEndsLabelTranslated, seasonEndsLabelFallback, currentLang); string formattedTime = seasonEndsLabel + $"{remainingTime.Days}d {remainingTime.Hours}h {remainingTime.Minutes}m : {remainingTime.Seconds:D2}s"; if (remainingSeasonTime != null) { remainingSeasonTime.text = formattedTime; } yield return new WaitForSeconds(1f); } } /// /// Updates the XP UI elements and progress bars for each PassEntry. /// public void UpdateXPUI() { string currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage(); string translatedSeasonLabel = GetTranslatedString(seasonLabelTranslated, seasonLabelFallback, currentLang); currentSeason.text = string.Format(translatedSeasonLabel, BattlePassManager.GetPlayerBattlePassSeason()); StartCoroutine(StartRemainingTimeCoroutineAfterFrame()); if (endSeasonText != null && BattlePassManager.HasBattlePassSeasonEnded()) { endSeasonText.gameObject.SetActive(true); } int currentLevel = BattlePassManager.Singleton.currentLevel; int currentXP = BattlePassManager.Singleton.currentXP; int xpForNextLevel = BattlePassManager.Singleton.xpForNextLevel; string translatedLevelLabel = GetTranslatedString(levelLabelTranslated, levelLabelFallback, currentLang); string translatedXpLabel = GetTranslatedString(xpLabelTranslated, xpLabelFallback, currentLang); levelText.text = string.Format(translatedLevelLabel, currentLevel); xpText.text = string.Format(translatedXpLabel, currentXP, xpForNextLevel); xpProgressBar.fillAmount = (float)currentXP / xpForNextLevel; foreach (Transform child in containerPassItems) { PassEntry passEntry = child.GetComponent(); if (passEntry != null) { passEntry.UpdateProgressBar(); } } } /// /// Loads the Battle Pass items and instantiates PassEntry prefabs with translated titles and descriptions. /// public async void LoadBattlePassItems() { ClearPassItems(); string currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage(); for (int i = 0; i < battlePassItems.Length; i++) { BattlePassItem item = battlePassItems[i]; PassEntry passEntry = Instantiate(passEntryPrefab, containerPassItems); bool isUnlocked = BattlePassManager.Singleton.IsBattlePassUnlocked() || item.rewardTier == BattlePassItem.RewardTier.Free; bool isClaimed = BattlePassManager.Singleton.IsRewardClaimed(item.passId); string translatedTitle = item.GetTranslatedTitle(currentLang); string translatedDescription = item.GetTranslatedDescription(currentLang); passEntry.SetPassItemInfo(item, item.passId, translatedTitle, translatedDescription, item.itemIcon, item.rewardTier == BattlePassItem.RewardTier.Paid, isUnlocked, isClaimed, i); } await Task.Delay(100); UpdateBuyPassButtonVisibility(); UpdateXPUI(); } /// /// Adds test XP for debugging and reloads Battle Pass items. /// public void TestEXPPass() { BattlePassManager.Singleton.AddTestXP(300); LoadBattlePassItems(); } /// /// Clears all PassEntry objects from the container. /// public void ClearPassItems() { foreach (Transform child in containerPassItems) { Destroy(child.gameObject); } } /// /// Coroutine to hide the error message after a specified delay. /// /// Delay in seconds before hiding the error message. /// IEnumerator for coroutine. private IEnumerator HideErrorMessageAfterDelay(float delay) { yield return new WaitForSeconds(delay); errorMessage.text = ""; } /// /// Handles the button click to purchase the Battle Pass. /// public async void OnClickPurchaseBattlePass() { string error = await BattlePassManager.Singleton.UnlockBattlePass(); if (string.IsNullOrEmpty(error)) { LoadBattlePassItems(); UpdateXPUI(); purchasePopup.SetActive(false); } else { errorMessage.text = error; StartCoroutine(HideErrorMessageAfterDelay(3f)); } } /// /// Displays the purchase popup with the correct currency icon and price. /// public void ShowPurchasePopup() { purchaseIconCurrency.sprite = MonetizationManager.Singleton.GetCurrencyIcon(BattlePassManager.Singleton.currencyID); purchaseTextPrice.text = BattlePassManager.Singleton.battlePassPrice.ToString(); purchasePopup.SetActive(true); } /// /// Displays the claim popup with the reward details. /// /// Title of the reward. /// Icon of the reward. /// Description of the reward. public void ShowClaimPopup(string rewardTitle, Sprite rewardIcon, string rewardDescription) { claimIconReward.sprite = rewardIcon; claimTextRewardAmount.text = rewardDescription; claimPopup.SetActive(true); } /// /// Hides the claim popup. /// public void HideClaimPopup() { claimPopup.SetActive(false); } /// /// Updates the UI when XP changes. /// /// Event sender. /// Event arguments. private void OnXPChanged(object sender, EventArgs e) { UpdateXPUI(); } /// /// Updates the visibility of the Buy Pass button based on the unlock status. /// private void UpdateBuyPassButtonVisibility() { ButtonBuyPassVisual.SetActive(!BattlePassManager.Singleton.IsBattlePassUnlocked()); } /// /// Retrieves the translated string based on the provided translations array and fallback. /// /// Array of translations. /// Fallback string if no translation is found. /// Current language identifier. /// The translated string if available; otherwise, the fallback string. private string GetTranslatedString(NameTranslatedByLanguage[] translations, string fallback, string currentLang) { if (translations != null) { foreach (var trans in translations) { if (!string.IsNullOrEmpty(trans.LanguageId) && trans.LanguageId.Equals(currentLang, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(trans.Translate)) { return trans.Translate; } } } return fallback; } } }