344 lines
12 KiB
C#
344 lines
12 KiB
C#
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;
|
|
/// <summary>
|
|
/// List of all instantiated ranking entries.
|
|
/// </summary>
|
|
private List<RankingEntry> rankingEntries = new List<RankingEntry>();
|
|
|
|
private void Awake()
|
|
{
|
|
if (Singleton == null)
|
|
{
|
|
Singleton = this;
|
|
}
|
|
else
|
|
{
|
|
Destroy(gameObject);
|
|
}
|
|
LoadRankings();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the object becomes enabled and active.
|
|
/// Selects the first ranking entry once everything is loaded.
|
|
/// </summary>
|
|
private void OnEnable()
|
|
{
|
|
OnOpenMenu.Invoke();
|
|
currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage();
|
|
if (rankingEntries.Count > 0)
|
|
{
|
|
OnRankingEntrySelected(rankingEntries[0]);
|
|
}
|
|
LoadLocalPlayerInfo();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
OnCloseMenu.Invoke();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the cooldown for the refresh button.
|
|
/// </summary>
|
|
public void ResetCooldown()
|
|
{
|
|
StartCoroutine(StartCooldown());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the rankings and displays the top players, sorted by score in descending order.
|
|
/// </summary>
|
|
public async void LoadRankings()
|
|
{
|
|
if (isCooldownActive) return;
|
|
|
|
StartCoroutine(StartCooldown());
|
|
|
|
List<Dictionary<string, object>> 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<string, object> 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;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the selection of a ranking entry.
|
|
/// Activates the selected image and updates selected player variables.
|
|
/// </summary>
|
|
/// <param name="selectedEntry">The ranking entry that was selected.</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Instantiates the favorite character in the specified container.
|
|
/// </summary>
|
|
/// <param name="characterId">The ID of the character to instantiate.</param>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the cooldown for the refresh button and updates the UI.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
}
|
|
}
|