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;
}
}
}