using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using UnityEngine.UI; namespace BulletHellTemplate { public class BattlePassManager : MonoBehaviour { public static BattlePassManager Singleton; [HideInInspector] public int currentXP; // Current XP accumulated [HideInInspector] public int xpForNextLevel; // XP required for the next level [HideInInspector]public int currentLevel; // Current level of the Battle Pass [Header("Battle Pass Settings")] public int maxLevel = 100; // Maximum level for the Battle Pass public float baseExp = 1000; public int SeasonLengthInDays = 30; [Header("0.1 = 10% more at each level // 1 = 100% more")] public float percentageByLevel = 0.1f; [HideInInspector]public int currentSeason; // Current season of the Battle Pass [HideInInspector] public string playerPrefsXPKey = "BattlePassXP"; [HideInInspector] public string playerPrefsLevelKey = "BattlePassLevel"; [HideInInspector] public string playerPrefsPassUnlockedKey = "BattlePassUnlocked"; [HideInInspector] public string playerPrefsClaimedPrefix = "BattlePassClaimed_"; // Prefix for claimed items [HideInInspector] private const string playerPrefsSeasonKey = "BattlePassSeason"; private const string playerPrefsSeasonEndTimeKey = "EndSeasonTime"; public string currencyID = "DM"; // Currency ID for purchasing the Battle Pass public int battlePassPrice = 1000; // Price of the Battle Pass public string notEnoughError = "Not enough currency. You need {0} more {1}."; public NameTranslatedByLanguage[] notEnoughErrorTranslated; private string currentLang; public event EventHandler OnXPChanged; private void Awake() { if (Singleton == null) { Singleton = this; } } /// /// Unsubscribes from language change events. /// private void OnDisable() { LanguageManager.LanguageManager.onLanguageChanged -= UpdateText; } private void OnDestroy() { LanguageManager.LanguageManager.onLanguageChanged -= UpdateText; } /// /// Initializes the UI menu when enabled. /// private void OnEnable() { currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage(); LanguageManager.LanguageManager.onLanguageChanged += UpdateText; UpdateText(); } /// /// Called when the language is changed, forcing the UI to update translations. /// private void UpdateText() { currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage(); } public async Task CheckAndUpdateSeasonAsync() { int seasonFromDatabase = await BackendManager.Singleton.GetCurrentSeasonAsync(); currentSeason = GetPlayerBattlePassSeason(); if (seasonFromDatabase != currentSeason) { Debug.Log($"New Season Detected: {seasonFromDatabase}. Resetting Battle Pass."); currentSeason = seasonFromDatabase; _ResetBattlePass(); return; } if (UIBattlePass.Singleton != null) { UIBattlePass.Singleton.LoadBattlePassItems(); } } public static void SetPlayerBattlePassSeason(int _currentSeason) { PlayerPrefs.SetInt(playerPrefsSeasonKey, _currentSeason); PlayerPrefs.Save(); } public static int GetPlayerBattlePassSeason() { return PlayerPrefs.GetInt(playerPrefsSeasonKey); } /// /// Marks the current Battle Pass season as ended locally by setting a flag in PlayerPrefs. /// This can be used to trigger UI notifications or other logic indicating that the season has ended. /// public static void SetPlayerBattlePassSeasonEnded() { // Set a flag indicating the season has ended PlayerPrefs.SetInt("BattlePassSeasonEnded", 1); PlayerPrefs.Save(); Debug.Log("The Battle Pass season has been marked as ended locally."); } /// /// Checks if the current Battle Pass season has been marked as ended locally. /// /// Returns true if the season has ended, otherwise false. public static bool HasBattlePassSeasonEnded() { // Check if the season ended flag is set return PlayerPrefs.GetInt("BattlePassSeasonEnded", 0) == 1; } // /// Saves the remaining time for the season to end locally in PlayerPrefs. /// It calculates the remaining time based on the current date and the start of the season. /// public void SaveRemainingSeasonTimeLocally(DateTime seasonStartDate) { // Calculate the season end time by adding the season length to the start date DateTime seasonEndTime = seasonStartDate.AddDays(SeasonLengthInDays); // Save the season end time as a string in PlayerPrefs PlayerPrefs.SetString(playerPrefsSeasonEndTimeKey, seasonEndTime.ToString("o")); // Save as ISO 8601 format PlayerPrefs.Save(); Debug.Log($"Season end time saved locally: {seasonEndTime}"); } public static string GetRemainingSeasonTimeLocally() { return PlayerPrefs.GetString(playerPrefsSeasonEndTimeKey); } /// /// Adds XP to the Battle Pass and handles level up, but only if the season has not ended. /// /// Amount of XP to add. public void AddXP(int xpAmount) { if (HasBattlePassSeasonEnded()) { Debug.LogWarning("The current Battle Pass season has ended. No more XP can be earned."); return; } currentXP += xpAmount; while (currentXP >= xpForNextLevel && currentLevel < maxLevel) { LevelUp(); } OnXPChanged?.Invoke(this, EventArgs.Empty); SaveBattlePassProgress(); if(UIMainMenu.Singleton != null) { UIMainMenu.Singleton.UpdateBattlePassInfo(); } } /// /// Levels up the Battle Pass and resets the XP for the next level, but only if the season has not ended. /// private void LevelUp() { if (HasBattlePassSeasonEnded()) { Debug.LogWarning("The current Battle Pass season has ended. No more levels can be gained."); return; } currentLevel++; currentXP -= xpForNextLevel; xpForNextLevel = CalculateXPForNextLevel(currentLevel); Debug.Log($"Level Up! Current Level: {currentLevel}"); } /// /// Calculates the required XP for the next level based on the current level. /// /// Current level of the Battle Pass. /// Required XP for the next level. public int CalculateXPForNextLevel(int level) { return Mathf.FloorToInt(baseExp * Mathf.Pow(1f + percentageByLevel, level - 1)); } /// /// Saves the current Battle Pass progress (XP and Level) locally using PlayerPrefs and optionally to backend. /// public async void SaveBattlePassProgress() { PlayerPrefs.SetInt(playerPrefsXPKey, currentXP); PlayerPrefs.SetInt(playerPrefsLevelKey, currentLevel); PlayerPrefs.Save(); if (BackendManager.Singleton.CheckInitialized()) { await BackendManager.Singleton.SaveBattlePassProgressAsync(currentXP, currentLevel, IsBattlePassUnlocked()); } } /// /// Loads the Battle Pass progress (XP and Level) from PlayerPrefs or backend. /// public async void LoadBattlePassProgress() { if (BackendManager.Singleton.CheckInitialized()) { await BackendManager.Singleton.LoadBattlePassProgressAsync(); } else { currentXP = PlayerPrefs.GetInt(playerPrefsXPKey, 0); currentLevel = PlayerPrefs.GetInt(playerPrefsLevelKey, 1); xpForNextLevel = CalculateXPForNextLevel(currentLevel); } OnXPChanged?.Invoke(this, EventArgs.Empty); } /// /// Unlocks the Battle Pass by deducting the required price from the player's currency. /// Uses translated error messages if available; otherwise, falls back to the default English message. /// Returns null if unlocking is successful; otherwise, returns the error message. /// /// Error message if unlocking fails; otherwise, null. public async Task UnlockBattlePass() { int playerCurrency = MonetizationManager.GetCurrency(currencyID); if (playerCurrency >= battlePassPrice) { MonetizationManager.SetCurrency(currencyID, playerCurrency - battlePassPrice); PlayerPrefs.SetInt(playerPrefsPassUnlockedKey, 1); PlayerPrefs.Save(); if (BackendManager.Singleton.CheckInitialized()) { await BackendManager.Singleton.SaveBattlePassProgressAsync(currentXP, currentLevel, true); } Debug.Log("Battle Pass unlocked!"); return null; } else { // Retrieve the translated error template if available; fallback to default English message string errorTemplate = GetTranslatedString(notEnoughErrorTranslated, notEnoughError, currentLang); // Format the error message by inserting the required additional currency amount and currency ID string errorMessage = string.Format(errorTemplate, battlePassPrice - playerCurrency, currencyID); Debug.LogWarning(errorMessage); return errorMessage; } } /// /// Checks if the Battle Pass is unlocked. /// /// True if the Battle Pass is unlocked, false otherwise. public bool IsBattlePassUnlocked() { return PlayerPrefs.GetInt(playerPrefsPassUnlockedKey, 0) == 1; } /// /// Claims the reward for a specific Battle Pass item. /// /// The Battle Pass item to claim. public void ClaimReward(BattlePassItem passItem) { if (!IsBattlePassUnlocked() && passItem.rewardTier == BattlePassItem.RewardTier.Paid) { Debug.LogWarning("Cannot claim reward. Battle Pass is not unlocked."); return; } if (IsRewardClaimed(passItem.passId)) { Debug.LogWarning("Reward already claimed."); return; } MonetizationManager.Singleton.BattlePassUnlockItem(passItem); MarkRewardAsClaimed(passItem.passId); Debug.Log($"Reward claimed for {passItem.itemTitle}"); } /// /// Marks a reward as claimed in PlayerPrefs and optionally in Backend. /// /// The ID of the Battle Pass item. public async void MarkRewardAsClaimed(string passItemId) { PlayerPrefs.SetInt(playerPrefsClaimedPrefix + passItemId, 1); PlayerPrefs.Save(); if (BackendManager.Singleton.CheckInitialized()) { await BackendManager.Singleton.SaveClaimedRewardAsync(passItemId); } } /// /// Checks if a reward has already been claimed. /// /// The ID of the Battle Pass item. /// True if the reward has been claimed, false otherwise. public bool IsRewardClaimed(string passItemId) { return PlayerPrefs.GetInt(playerPrefsClaimedPrefix + passItemId, 0) == 1; } /// /// Unlocks the given characters and saves them as purchased using MonetizationManager. /// /// The CharacterData array containing characters to unlock. private void UnlockCharacters(CharacterData[] characters) { foreach (var character in characters) { // Check if the character is already purchased if (!MonetizationManager.Singleton.IsCharacterPurchased(character.characterId.ToString())) { // Add the character to the list of purchased characters MonetizationManager.Singleton.SetPurchasedCharacters(new List { new PurchasedCharacter { characterId = character.characterId.ToString() } }); Debug.Log($"Character {character.characterId} unlocked and saved."); } else { Debug.LogWarning($"Character {character.characterId} is already unlocked."); } } } private void AddCurrency(CurrencyReward reward) { MonetizationManager.SetCurrency(reward.currency.coinID, MonetizationManager.GetCurrency(reward.currency.coinID) + reward.amount); } /// /// Unlocks the given icon and saves it as purchased using MonetizationManager. /// /// The IconItem to unlock. private void UnlockIcon(IconItem icon) { if (!MonetizationManager.Singleton.IsIconPurchased(icon.iconId.ToString())) { MonetizationManager.Singleton.SetPurchasedIcons(new List { new PurchasedIcon { iconId = icon.iconId.ToString() } }); Debug.Log($"Icon {icon.iconId} unlocked and saved."); } else { Debug.LogWarning($"Icon {icon.iconId} is already unlocked."); } } /// /// Unlocks the given frame and saves it as purchased using MonetizationManager. /// /// The FrameItem to unlock. private void UnlockFrame(FrameItem frame) { if (!MonetizationManager.Singleton.IsFramePurchased(frame.frameId.ToString())) { MonetizationManager.Singleton.SetPurchasedFrames(new List { new PurchasedFrame { frameId = frame.frameId.ToString() } }); Debug.Log($"Frame {frame.frameId} unlocked and saved."); } else { Debug.LogWarning($"Frame {frame.frameId} is already unlocked."); } } /// /// Adds test XP for debugging purposes, but only if the season has not ended. /// /// The amount of test XP to add. public void AddTestXP(int xpAmount) { if (HasBattlePassSeasonEnded()) { Debug.LogWarning("The current Battle Pass season has ended. No more XP can be earned."); return; } AddXP(xpAmount); Debug.Log($"Test XP added: {xpAmount}. Current XP: {currentXP}, Current Level: {currentLevel}"); OnXPChanged?.Invoke(this, EventArgs.Empty); } public async void _ResetBattlePass() { currentXP = 0; currentLevel = 1; xpForNextLevel = CalculateXPForNextLevel(currentLevel); PlayerPrefs.DeleteKey(playerPrefsXPKey); PlayerPrefs.DeleteKey(playerPrefsLevelKey); PlayerPrefs.DeleteKey(playerPrefsPassUnlockedKey); // Continue attempting to access and clear until successful while (UIBattlePass.Singleton == null || UIBattlePass.Singleton.battlePassItems == null) { Debug.LogWarning("UIBattlePass.Singleton or battlePassItems is null. Retrying..."); await Task.Delay(100); } // Once accessible, proceed with clearing the claimed items foreach (BattlePassItem item in UIBattlePass.Singleton.battlePassItems) { PlayerPrefs.DeleteKey(playerPrefsClaimedPrefix + item.passId); } PlayerPrefs.Save(); if (BackendManager.Singleton.CheckInitialized()) { await BackendManager.Singleton.ResetBattlePassProgressAsync(); } if(UIBattlePass.Singleton != null) { UIBattlePass.Singleton.LoadBattlePassItems(); } Debug.Log("Battle Pass progress reset."); OnXPChanged?.Invoke(this, EventArgs.Empty); } private string GetTranslatedString(NameTranslatedByLanguage[] translations, string fallback, string currentLang) { // Log the current language being used for translation Debug.Log($"Current language: {currentLang}"); if (translations != null) { foreach (var trans in translations) { Debug.Log($"Checking translation: LanguageId = {trans.LanguageId}, Translate = {trans.Translate}"); // Use case-insensitive comparison to avoid mismatches if (!string.IsNullOrEmpty(trans.LanguageId) && trans.LanguageId.Equals(currentLang, StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(trans.Translate)) { return trans.Translate; } } } Debug.Log("Using fallback translation."); return fallback; } private string GetTranslatedString(DescriptionTranslatedByLanguage[] translations, string fallback, string currentLang) { if (translations != null) { foreach (var trans in translations) { if (!string.IsNullOrEmpty(trans.LanguageId) && trans.LanguageId.Equals(currentLang) && !string.IsNullOrEmpty(trans.Translate)) { return trans.Translate; } } } return fallback; } } }