using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UIElements; /// /// class that loads leaderboard data and displays it in the UI /// public class LeaderboardUI : MonoBehaviour { /// /// maximum number of entries to display in the leaderboard /// public const int MaxEntries = 50; /// /// uxml template for a leaderboard entry /// [SerializeField] private VisualTreeAsset leaderboardEntryTemplate; /// /// leaderboard data /// private List _leaderboardData = new(MaxEntries); /// /// reference to the leaderboard scroll view /// private ScrollView _leaderboardScrollView; /// /// register callbacks /// private void OnEnable() { UIManager.Instance.RegisterOnDisplayStateChangeCallback((_, newState) => { if (newState == UIManager.DisplayState.LeaderboardView) LoadLeaderboardData(); }); _leaderboardScrollView = UIManager.Instance.UI.Q("LeaderboardListContent"); if (_leaderboardScrollView == null) throw new NullReferenceException("leaderboard scroll view not found in the UI"); } /// /// load leaderboard data from the backend /// private void LoadLeaderboardData() { if (GameManager.Instance.Backend.Status != Backend.FirebaseConnectionStatus.Connected) { Debug.LogError("attempted to load leaderboard data without a connection to the backend"); RenderLeaderboardData("Not connected to the backend, can't load leaderboard data."); return; } GameManager.Instance.Backend.GetLeaderboard((result, entries) => { if (result == Backend.TransactionResult.Ok) { _leaderboardData = entries; RenderLeaderboardData(); } else { Debug.LogError("failed to load leaderboard data"); RenderLeaderboardData("An error occured, couldn't load leaderboard data."); } }); } /// /// render leaderboard data in the UI /// /// message to display in the leaderboard in lieu of actual data /// /// thrown when the leaderboard scroll view is missing or when the leaderboard /// entry /// private void RenderLeaderboardData(string message = "") { _leaderboardScrollView.Clear(); if (!string.IsNullOrEmpty(message)) { Debug.Log($"rendering leaderboard with message entry-in-lieu: '{message}'"); _leaderboardScrollView.Add(BuildEntryElement("", message, "")); return; } Debug.Log($"rendering {_leaderboardData.Count} leaderboard entries"); foreach (var (entry, index) in _leaderboardData.Take(MaxEntries).Reverse() .Select((entry, index) => (entry, index))) _leaderboardScrollView.Add(BuildEntryElement((index + 1).ToString(), entry.Username, $"{entry.Rating:F3}")); } /// /// build a leaderboard entry element /// /// leaderboard position as a string /// score holder's username /// score holder's rating /// a visual element representing a leaderboard entry /// thrown when the leaderboard entry template is missing required elements private TemplateContainer BuildEntryElement(string position, string username, string rating) { var template = leaderboardEntryTemplate.Instantiate(); var templatePositionText = template.Q