using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace BulletHellTemplate
{
public class UIRankingMenu : MonoBehaviour
{
[Header("Prefabs and Containers")]
[Tooltip("Prefab for each ranking entry.")]
public RankingEntry rankingEntryPrefab;
[Tooltip("Container for ranking entries.")]
public Transform container;
[Tooltip("Container for displaying the favorite character.")]
public Transform characterFavouriteContainer;
[Header("Selected Player UI Elements")]
[Tooltip("Text displaying the selected player's nickname.")]
public TextMeshProUGUI selectedPlayerNickname;
[Tooltip("Text displaying the selected player's rank.")]
public TextMeshProUGUI selectedPlayerRank;
[Tooltip("Image displaying the selected player's icon.")]
public Image selectedPlayerIcon;
[Tooltip("Image displaying the selected player's frame.")]
public Image selectedPlayerFrame;
[Header("Other UI Elements")]
[Tooltip("Text displaying the current player's rank.")]
public TextMeshProUGUI myRank;
public TextMeshProUGUI localPlayerName;
public Image localPlayerIcon;
public Image localPlayerFrame;
[Tooltip("Button to refresh the rankings.")]
public Button refreshButton;
[Tooltip("Image used to display cooldown on the refresh button.")]
public Image cooldownImage;
[Header("UI Translates Messages")]
public string yourRank = "Your Rank: {0}";
public NameTranslatedByLanguage[] yourRankTranslated;
public string rankNotAvaliable = "Rank not available";
public NameTranslatedByLanguage[] rankNotAvaliableTranslated;
public string rank = "Rank:";
public NameTranslatedByLanguage[] rankTranslated;
[Header("Events")]
[Tooltip("Event invoked when the menu is opened.")]
public UnityEvent OnOpenMenu;
[Tooltip("Event invoked when the menu is closed.")]
public UnityEvent OnCloseMenu;
public static UIRankingMenu Singleton;
private bool isCooldownActive = false;
private float cooldownTime = 5f;
private string currentLang;
private int localRanking;
///
/// List of all instantiated ranking entries.
///
private List rankingEntries = new List();
private void Awake()
{
if (Singleton == null)
{
Singleton = this;
}
else
{
Destroy(gameObject);
}
LoadRankings();
}
///
/// Called when the object becomes enabled and active.
/// Selects the first ranking entry once everything is loaded.
///
private void OnEnable()
{
OnOpenMenu.Invoke();
currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage();
if (rankingEntries.Count > 0)
{
OnRankingEntrySelected(rankingEntries[0]);
}
LoadLocalPlayerInfo();
}
private void OnDisable()
{
OnCloseMenu.Invoke();
}
///
/// Resets the cooldown for the refresh button.
///
public void ResetCooldown()
{
StartCoroutine(StartCooldown());
}
///
/// Loads the rankings and displays the top players, sorted by score in descending order.
///
public async void LoadRankings()
{
if (isCooldownActive) return;
StartCoroutine(StartCooldown());
List> topPlayers = await BackendManager.Singleton.GetTopPlayersAsync();
// Sort players by score in descending order
var sortedPlayers = topPlayers
.Select(playerData =>
{
string scoreStr = playerData.ContainsKey("score") ? playerData["score"].ToString() : "0";
long.TryParse(scoreStr, out long score); // Convert score to long
string playerName = playerData.ContainsKey("PlayerName") ? playerData["PlayerName"].ToString() : "Unknown";
return new
{
PlayerData = playerData,
Score = score,
PlayerName = playerName
};
})
.OrderByDescending(p => p.Score) // Sort by score descending
.ToList();
// Clear existing entries
foreach (Transform child in container)
{
Destroy(child.gameObject);
}
rankingEntries.Clear();
// Populate the ranking list
for (int i = 0; i < sortedPlayers.Count; i++)
{
var playerInfo = sortedPlayers[i];
Dictionary playerData = playerInfo.PlayerData;
RankingEntry entry = Instantiate(rankingEntryPrefab, container);
// Retrieve player data with error handling for missing information
string playerName = playerInfo.PlayerName;
string score = playerInfo.Score.ToString();
string playerIconId = playerData.ContainsKey("PlayerIcon") ? playerData["PlayerIcon"].ToString() : "defaultIconId";
string playerFrameId = playerData.ContainsKey("PlayerFrame") ? playerData["PlayerFrame"].ToString() : "defaultFrameId";
// Convert PlayerCharacterFavourite to int
int playerCharacterFavourite = playerData.ContainsKey("PlayerCharacterFavourite") ? int.Parse(playerData["PlayerCharacterFavourite"].ToString()) : 0;
// Set ranking information
entry.SetRankingInfo(
_playerName: playerName,
_score: score,
rankingPosition: i + 1,
playerIconId: GetPlayerIcon(playerIconId),
playerFrameId: GetPlayerFrame(playerFrameId),
playerCharacterFavourite: playerCharacterFavourite
);
// Add entry to the list
rankingEntries.Add(entry);
}
// Get and display the current player's rank
localRanking = await BackendManager.Singleton.GetPlayerRankAsync();
if (rankingEntries.Count > 0)
{
OnRankingEntrySelected(rankingEntries[0]);
}
}
public void LoadLocalPlayerInfo()
{
string _playerName = PlayerSave.GetPlayerName();
string _playerIcon = PlayerSave.GetPlayerIcon();
string _playerFrame = PlayerSave.GetPlayerFrame();
localPlayerName.text = _playerName;
localPlayerIcon.sprite = GetPlayerIcon(_playerIcon);
localPlayerFrame.sprite = GetPlayerFrame(_playerFrame);
string _yourRankTranslated = GetTranslatedString(yourRankTranslated, yourRank, currentLang);
string _rankNotEvaliableTranslated = GetTranslatedString(rankNotAvaliableTranslated, rankNotAvaliable, currentLang);
string formattedYourRank = string.Format(_yourRankTranslated, rank);
myRank.text = localRanking > 0 ? formattedYourRank : _rankNotEvaliableTranslated;
}
///
/// Handles the selection of a ranking entry.
/// Activates the selected image and updates selected player variables.
///
/// The ranking entry that was selected.
public void OnRankingEntrySelected(RankingEntry selectedEntry)
{
// Deactivate 'selected' image on all entries
foreach (var entry in rankingEntries)
{
entry.SetSelected(false);
}
// Activate 'selected' image on the selected entry
selectedEntry.SetSelected(true);
// Update selected player variables
selectedPlayerNickname.text = selectedEntry.playerName.text;
string stringRankTranslated = GetTranslatedString(rankTranslated, rank, currentLang);
selectedPlayerRank.text = $"{stringRankTranslated} {selectedEntry.ranking.text}";
selectedPlayerIcon.sprite = selectedEntry.playerIcon.sprite;
selectedPlayerFrame.sprite = selectedEntry.playerFrame.sprite;
// Display the favorite character
DisplayFavouriteCharacter(selectedEntry.characterFavourite);
}
///
/// Instantiates the favorite character in the specified container.
///
/// The ID of the character to instantiate.
public void DisplayFavouriteCharacter(int characterId)
{
// Clear existing favorite character display
foreach (Transform child in characterFavouriteContainer)
{
Destroy(child.gameObject);
}
// Find the character prefab by ID and instantiate it
CharacterData characterPrefab = null;
foreach (var character in GameInstance.Singleton.characterData)
{
if (character.characterId == characterId)
{
characterPrefab = character;
break;
}
}
if (characterPrefab != null)
{
Instantiate(characterPrefab.characterModel, characterFavouriteContainer);
}
else
{
Debug.LogWarning("Character with ID " + characterId + " not found.");
}
if (DragRotateAndHit.Singleton != null)
{
DragRotateAndHit.Singleton.UpdateCharacter();
}
}
public Sprite GetPlayerIcon(string iconId)
{
foreach (var icon in GameInstance.Singleton.iconItems)
{
if (icon.iconId == iconId)
{
return icon.icon; ;
}
}
return null;
}
public Sprite GetPlayerFrame(string frameId)
{
foreach (var frame in GameInstance.Singleton.frameItems)
{
if (frame.frameId == frameId)
{
return frame.icon; ;
}
}
return null;
}
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)
&& !string.IsNullOrEmpty(trans.Translate))
{
return trans.Translate;
}
}
}
return fallback;
}
///
/// Starts the cooldown for the refresh button and updates the UI.
///
///
private IEnumerator StartCooldown()
{
isCooldownActive = true;
refreshButton.interactable = false;
float elapsedTime = 0f;
while (elapsedTime < cooldownTime)
{
elapsedTime += Time.deltaTime;
cooldownImage.fillAmount = 1 - (elapsedTime / cooldownTime);
yield return null;
}
cooldownImage.fillAmount = 0f;
refreshButton.interactable = true;
isCooldownActive = false;
}
}
}