493 lines
19 KiB
C#
493 lines
19 KiB
C#
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Unsubscribes from language change events.
|
||
|
/// </summary>
|
||
|
private void OnDisable()
|
||
|
{
|
||
|
LanguageManager.LanguageManager.onLanguageChanged -= UpdateText;
|
||
|
}
|
||
|
private void OnDestroy()
|
||
|
{
|
||
|
LanguageManager.LanguageManager.onLanguageChanged -= UpdateText;
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// Initializes the UI menu when enabled.
|
||
|
/// </summary>
|
||
|
private void OnEnable()
|
||
|
{
|
||
|
currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage();
|
||
|
LanguageManager.LanguageManager.onLanguageChanged += UpdateText;
|
||
|
UpdateText();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Called when the language is changed, forcing the UI to update translations.
|
||
|
/// </summary>
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
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.");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the current Battle Pass season has been marked as ended locally.
|
||
|
/// </summary>
|
||
|
/// <returns>Returns true if the season has ended, otherwise false.</returns>
|
||
|
public static bool HasBattlePassSeasonEnded()
|
||
|
{
|
||
|
// Check if the season ended flag is set
|
||
|
return PlayerPrefs.GetInt("BattlePassSeasonEnded", 0) == 1;
|
||
|
}
|
||
|
|
||
|
// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Adds XP to the Battle Pass and handles level up, but only if the season has not ended.
|
||
|
/// </summary>
|
||
|
/// <param name="xpAmount">Amount of XP to add.</param>
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Levels up the Battle Pass and resets the XP for the next level, but only if the season has not ended.
|
||
|
/// </summary>
|
||
|
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}");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Calculates the required XP for the next level based on the current level.
|
||
|
/// </summary>
|
||
|
/// <param name="level">Current level of the Battle Pass.</param>
|
||
|
/// <returns>Required XP for the next level.</returns>
|
||
|
public int CalculateXPForNextLevel(int level)
|
||
|
{
|
||
|
return Mathf.FloorToInt(baseExp * Mathf.Pow(1f + percentageByLevel, level - 1));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Saves the current Battle Pass progress (XP and Level) locally using PlayerPrefs and optionally to backend.
|
||
|
/// </summary>
|
||
|
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());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Loads the Battle Pass progress (XP and Level) from PlayerPrefs or backend.
|
||
|
/// </summary>
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
/// <returns>Error message if unlocking fails; otherwise, null.</returns>
|
||
|
public async Task<string> 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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the Battle Pass is unlocked.
|
||
|
/// </summary>
|
||
|
/// <returns>True if the Battle Pass is unlocked, false otherwise.</returns>
|
||
|
public bool IsBattlePassUnlocked()
|
||
|
{
|
||
|
return PlayerPrefs.GetInt(playerPrefsPassUnlockedKey, 0) == 1;
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// Claims the reward for a specific Battle Pass item.
|
||
|
/// </summary>
|
||
|
/// <param name="passItem">The Battle Pass item to claim.</param>
|
||
|
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}");
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Marks a reward as claimed in PlayerPrefs and optionally in Backend.
|
||
|
/// </summary>
|
||
|
/// <param name="passItemId">The ID of the Battle Pass item.</param>
|
||
|
public async void MarkRewardAsClaimed(string passItemId)
|
||
|
{
|
||
|
PlayerPrefs.SetInt(playerPrefsClaimedPrefix + passItemId, 1);
|
||
|
PlayerPrefs.Save();
|
||
|
|
||
|
if (BackendManager.Singleton.CheckInitialized())
|
||
|
{
|
||
|
await BackendManager.Singleton.SaveClaimedRewardAsync(passItemId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if a reward has already been claimed.
|
||
|
/// </summary>
|
||
|
/// <param name="passItemId">The ID of the Battle Pass item.</param>
|
||
|
/// <returns>True if the reward has been claimed, false otherwise.</returns>
|
||
|
public bool IsRewardClaimed(string passItemId)
|
||
|
{
|
||
|
return PlayerPrefs.GetInt(playerPrefsClaimedPrefix + passItemId, 0) == 1;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Unlocks the given characters and saves them as purchased using MonetizationManager.
|
||
|
/// </summary>
|
||
|
/// <param name="characters">The CharacterData array containing characters to unlock.</param>
|
||
|
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<PurchasedCharacter>
|
||
|
{
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Unlocks the given icon and saves it as purchased using MonetizationManager.
|
||
|
/// </summary>
|
||
|
/// <param name="icon">The IconItem to unlock.</param>
|
||
|
private void UnlockIcon(IconItem icon)
|
||
|
{
|
||
|
if (!MonetizationManager.Singleton.IsIconPurchased(icon.iconId.ToString()))
|
||
|
{
|
||
|
MonetizationManager.Singleton.SetPurchasedIcons(new List<PurchasedIcon>
|
||
|
{
|
||
|
new PurchasedIcon { iconId = icon.iconId.ToString() }
|
||
|
});
|
||
|
Debug.Log($"Icon {icon.iconId} unlocked and saved.");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"Icon {icon.iconId} is already unlocked.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Unlocks the given frame and saves it as purchased using MonetizationManager.
|
||
|
/// </summary>
|
||
|
/// <param name="frame">The FrameItem to unlock.</param>
|
||
|
private void UnlockFrame(FrameItem frame)
|
||
|
{
|
||
|
if (!MonetizationManager.Singleton.IsFramePurchased(frame.frameId.ToString()))
|
||
|
{
|
||
|
MonetizationManager.Singleton.SetPurchasedFrames(new List<PurchasedFrame>
|
||
|
{
|
||
|
new PurchasedFrame { frameId = frame.frameId.ToString() }
|
||
|
});
|
||
|
Debug.Log($"Frame {frame.frameId} unlocked and saved.");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"Frame {frame.frameId} is already unlocked.");
|
||
|
}
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// Adds test XP for debugging purposes, but only if the season has not ended.
|
||
|
/// </summary>
|
||
|
/// <param name="xpAmount">The amount of test XP to add.</param>
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|