343 lines
13 KiB
C#
343 lines
13 KiB
C#
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Threading.Tasks;
|
||
|
using TMPro;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Events;
|
||
|
using UnityEngine.UI;
|
||
|
|
||
|
namespace BulletHellTemplate
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Manages the Battle Pass UI, including displaying items, XP, error messages, and handling popups.
|
||
|
/// </summary>
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Loads season information and checks for updates.
|
||
|
/// </summary>
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Starts a coroutine to update the remaining season time after the UI has been rendered.
|
||
|
/// </summary>
|
||
|
/// <returns>IEnumerator for coroutine.</returns>
|
||
|
private IEnumerator StartRemainingTimeCoroutineAfterFrame()
|
||
|
{
|
||
|
yield return null;
|
||
|
StartCoroutine(GetRemainingSeasonTime());
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Retrieves and updates the remaining season time from PlayerPrefs.
|
||
|
/// </summary>
|
||
|
/// <returns>IEnumerator for coroutine.</returns>
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the XP UI elements and progress bars for each PassEntry.
|
||
|
/// </summary>
|
||
|
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<PassEntry>();
|
||
|
if (passEntry != null)
|
||
|
{
|
||
|
passEntry.UpdateProgressBar();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Loads the Battle Pass items and instantiates PassEntry prefabs with translated titles and descriptions.
|
||
|
/// </summary>
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Adds test XP for debugging and reloads Battle Pass items.
|
||
|
/// </summary>
|
||
|
public void TestEXPPass()
|
||
|
{
|
||
|
BattlePassManager.Singleton.AddTestXP(300);
|
||
|
LoadBattlePassItems();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Clears all PassEntry objects from the container.
|
||
|
/// </summary>
|
||
|
public void ClearPassItems()
|
||
|
{
|
||
|
foreach (Transform child in containerPassItems)
|
||
|
{
|
||
|
Destroy(child.gameObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Coroutine to hide the error message after a specified delay.
|
||
|
/// </summary>
|
||
|
/// <param name="delay">Delay in seconds before hiding the error message.</param>
|
||
|
/// <returns>IEnumerator for coroutine.</returns>
|
||
|
private IEnumerator HideErrorMessageAfterDelay(float delay)
|
||
|
{
|
||
|
yield return new WaitForSeconds(delay);
|
||
|
errorMessage.text = "";
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Handles the button click to purchase the Battle Pass.
|
||
|
/// </summary>
|
||
|
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));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Displays the purchase popup with the correct currency icon and price.
|
||
|
/// </summary>
|
||
|
public void ShowPurchasePopup()
|
||
|
{
|
||
|
purchaseIconCurrency.sprite = MonetizationManager.Singleton.GetCurrencyIcon(BattlePassManager.Singleton.currencyID);
|
||
|
purchaseTextPrice.text = BattlePassManager.Singleton.battlePassPrice.ToString();
|
||
|
purchasePopup.SetActive(true);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Displays the claim popup with the reward details.
|
||
|
/// </summary>
|
||
|
/// <param name="rewardTitle">Title of the reward.</param>
|
||
|
/// <param name="rewardIcon">Icon of the reward.</param>
|
||
|
/// <param name="rewardDescription">Description of the reward.</param>
|
||
|
public void ShowClaimPopup(string rewardTitle, Sprite rewardIcon, string rewardDescription)
|
||
|
{
|
||
|
claimIconReward.sprite = rewardIcon;
|
||
|
claimTextRewardAmount.text = rewardDescription;
|
||
|
claimPopup.SetActive(true);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Hides the claim popup.
|
||
|
/// </summary>
|
||
|
public void HideClaimPopup()
|
||
|
{
|
||
|
claimPopup.SetActive(false);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the UI when XP changes.
|
||
|
/// </summary>
|
||
|
/// <param name="sender">Event sender.</param>
|
||
|
/// <param name="e">Event arguments.</param>
|
||
|
private void OnXPChanged(object sender, EventArgs e)
|
||
|
{
|
||
|
UpdateXPUI();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the visibility of the Buy Pass button based on the unlock status.
|
||
|
/// </summary>
|
||
|
private void UpdateBuyPassButtonVisibility()
|
||
|
{
|
||
|
ButtonBuyPassVisual.SetActive(!BattlePassManager.Singleton.IsBattlePassUnlocked());
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Retrieves the translated string based on the provided translations array and fallback.
|
||
|
/// </summary>
|
||
|
/// <param name="translations">Array of translations.</param>
|
||
|
/// <param name="fallback">Fallback string if no translation is found.</param>
|
||
|
/// <param name="currentLang">Current language identifier.</param>
|
||
|
/// <returns>The translated string if available; otherwise, the fallback string.</returns>
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|