Skip to main content

Put it all together - All time leaderboard - (Unity module)

Last updated on October 24, 2024

Connect the UI to display leaderboard rankings

  1. Open LeaderboardSelectionMenu_Starter.cs.

  2. Declare a local variable to hold the reference of the LeaderboardEssentialsWrapper_Starter wrapper.

    private LeaderboardEssentialsWrapper_Starter leaderboardWrapper;
  3. Prepare for the use of the wrapper function. Create a new callback function that will instantiate the buttons based on the leaderboard list query result, and bind the button callback function you created earlier to the buttons. You are using the same namespace for both Unity and Unreal Engine Byte Wars, so you need to filter the result to only query the Unity leaderboard based on the leaderboard names.

    private void OnGetLeaderboardListCompleted(Result<LeaderboardPagedListV3> result)
    {
    if (result.IsError)
    {
    CurrentView = LeaderboardSelectionView.Failed;
    return;
    }

    LeaderboardDataV3[] leaderboardList = result.Value.Data.Where(data => data.Name.Contains("Unity")).ToArray();

    // No relevant leaderboard was found.
    if (leaderboardList.Length < 0)
    {
    CurrentView = LeaderboardSelectionView.Failed;
    return;
    }

    // Show leaderboard list.
    leaderboardListPanel.DestroyAllChildren();
    foreach (LeaderboardDataV3 leaderboard in leaderboardList)
    {
    Button leaderboardButton =
    Instantiate(leaderboardItemButtonPrefab, leaderboardListPanel).GetComponent<Button>();
    TMP_Text leaderboardButtonText = leaderboardButton.GetComponentInChildren<TMP_Text>();
    leaderboardButtonText.text = leaderboard.Name.Replace("Unity Leaderboard ", "");

    leaderboardButton.onClick.AddListener(() => ChangeToLeaderboardCycleMenu(leaderboard.LeaderboardCode));
    }

    CurrentView = LeaderboardSelectionView.Default;
    }
  4. Create another new function to call the wrapper function to get the leaderboard list and bind it with the callback function you just created.

    private void DisplayLeaderboardList()
    {
    CurrentView = LeaderboardSelectionView.Loading;
    leaderboardWrapper.GetLeaderboardList(OnGetLeaderboardListCompleted);
    }
  5. Finally, in the OnEnable() function, initialize the leaderboard wrapper and call the DisplayLeaderboardList() to display the leaderboard list when the menu is opened.

    private void OnEnable()
    {
    leaderboardWrapper = TutorialModuleManager.Instance.GetModuleClass<LeaderboardEssentialsWrapper_Starter>();

    if (!leaderboardWrapper)
    {
    return;
    }

    DisplayLeaderboardList();
    }

Connect the UI to display current user rankings

  1. Open the LeaderboardMenu_Starter.cs.

  2. Add two local variables to hold the references to the LeaderboardEssentialsWrapper_Starter and AuthEssentialsWrapper wrappers.

    private LeaderboardEssentialsWrapper_Starter leaderboardWrapper;
    private AuthEssentialsWrapper authWrapper;
  3. Define the following variables that store the required values for requesting the ranking list from AccelByte Gaming Services (AGS):

    note

    TokenData is a class that contains all detailed information of the current user. Its values are returned upon a successful login.

    private TokenData currentUserData;
    private string currentLeaderboardCode;
    private LeaderboardCycleMenu_Starter.LeaderboardCycleType currentCycleType;
  4. Create a function that initializes these variables by getting them from the other leaderboard menu and the AuthEssentialsWrapper.

    private void InitializeLeaderboardRequiredValues()
    {
    currentUserData = authWrapper.UserData;
    currentLeaderboardCode = LeaderboardSelectionMenu_Starter.chosenLeaderboardCode;
    currentCycleType = LeaderboardCycleMenu_Starter.chosenCycleType;
    }
  5. You also need to define constant variables to limit the range of the leaderboard query to the top 10 players only.

    private const int QUERY_OFFSET = 0;
    private const int QUERY_LIMIT = 10;
  6. Create a function that handles the instantiation of the RankingEntryPanel that holds each player ranking info. Add userId, playerName, and playerScore as parameters since you will display these values. Also, update the UserRankingPanel as well if it's the current user ranking data.

    public void InstantiateRankingEntry(string userId, int playerRank, string playerName, float playerScore)
    {
    RankingEntryPanel rankingEntryPanel =
    Instantiate(rankingEntryPanelPrefab, rankingListPanel).GetComponent<RankingEntryPanel>();
    rankingEntryPanel.SetRankingDetails(userId, playerRank, playerName, playerScore);

    if (userId != currentUserData.user_id) return;

    // Highlight players ranking entry and set ranking details to user ranking panel
    rankingEntryPanel.SetPanelColor(new Color(1.0f, 1.0f, 1.0f, 0.098f)); // rgba 255,255,255,25
    userRankingPanel.SetRankingDetails(userId, playerRank, playerName, playerScore);
    }
  7. Since the GetRankings() function only returns an array of user IDs, you need to use the BulkGetUserInfo() function in the AuthEssentialsWrapper to get their display names. You will first create a callback function to handle the get user info result. In this function, you also call the GetUserRanking() function in the LeaderboardEssentialsWrapper_Starter if you can't find the current player's user ID in the leaderboard ranking list.

    private void OnBulkGetUserInfoCompleted(Result<ListBulkUserInfoResponse> result, Dictionary<string, float> userRankInfos)
    {
    if (result.IsError)
    {
    BytewarsLogger.LogWarning($"Failed to display leaderboard rankings. Error: {result.Error.Message}");
    CurrentView = LeaderboardMenuView.Failed;
    return;
    }

    // Populate leaderboard ranking entries.
    int rankOrder = 0;
    Dictionary<string, string> userDisplayNames =
    result.Value.data.ToDictionary(userInfo => userInfo.userId, userInfo => userInfo.displayName);
    foreach (string userId in userRankInfos.Keys)
    {
    rankOrder += 1;
    InstantiateRankingEntry(userId, rankOrder, userDisplayNames[userId], userRankInfos[userId]);

    if (userId.Equals(currentUserData.user_id))
    {
    userRankingPanel.SetRankingDetails(
    userId,
    rankOrder,
    userDisplayNames[userId],
    userRankInfos[userId]);
    }
    }

    /* No need to query current player ranking if already in the ranking list.
    * Immediately show the leaderboard ranking list. */
    if (userRankInfos.Keys.Contains(currentUserData.user_id))
    {
    CurrentView = LeaderboardMenuView.Default;
    return;
    }

    // Get current player ranking if not already in the ranking list.
    leaderboardWrapper.GetUserRanking(
    currentUserData.user_id,
    currentLeaderboardCode,
    OnGetUserRankingCompleted);
    }
  8. Create the callback function that handles the leaderboard ranking query result. Remember, you need to call the BulkGetUserInfo() function in the AuthEssentialsWrapper to get the display names of the players in the ranking list.

    public void OnGetRankingsCompleted(Result<LeaderboardRankingResult> result)
    {
    /* The backend returns result as error even if leaderboard ranking is empty.
    * Hence, the game shows the leaderboard empty message. */
    if (result.IsError || result.Value.data.Length <= 0)
    {
    BytewarsLogger.LogWarning($"Failed to display leaderboard rankings. Error: {result.Error.Message}");
    CurrentView = LeaderboardMenuView.Empty;
    return;
    }

    // Store the ranking result's userIds and points to a Dictionary
    Dictionary<string, float> userRankInfos =
    result.Value.data.ToDictionary(userPoint => userPoint.userId, userPoint => userPoint.point);

    // Get the players' display name from the provided user ids
    authWrapper.BulkGetUserInfo(
    userRankInfos.Keys.ToArray(),
    authResult => OnBulkGetUserInfoCompleted(authResult, userRankInfos));
    }
  9. Create a new function to call the DisplayRankingList() function if the leaderboard's cycle period is AllTime.

    private void DisplayRankingList()
    {
    CurrentView = LeaderboardMenuView.Loading;
    rankingListPanel.DestroyAllChildren();
    userRankingPanel.ResetRankingEntry();

    InitializeLeaderboardRequiredValues();

    if (currentCycleType == LeaderboardCycleMenu_Starter.LeaderboardCycleType.AllTime)
    {
    leaderboardWrapper.GetRankings(currentLeaderboardCode, OnGetRankingsCompleted, QUERY_OFFSET, QUERY_LIMIT);
    }
    }
  10. Create a new callback function that handles the GetUserRanking() to display the current user ranking within the leaderboard.

    private void OnGetUserRankingCompleted(Result<UserRankingDataV3> result)
    {
    if (result.IsError)
    {
    BytewarsLogger.LogWarning($"Failed to display leaderboard rankings. Error: {result.Error.Message}");
    CurrentView = LeaderboardMenuView.Failed;
    return;
    }

    if (currentCycleType == LeaderboardCycleMenu_Starter.LeaderboardCycleType.AllTime)
    {
    UserRanking allTimeUserRank = result.Value.AllTime;
    if (allTimeUserRank != null)
    {
    userRankingPanel.SetRankingDetails(
    currentUserData.user_id,
    allTimeUserRank.rank,
    currentUserData.display_name,
    allTimeUserRank.point);
    }
    }
    else
    {
    UserCycleRanking cycleUserRank = result.Value.Cycles.First(data => data.CycleId.Equals(LeaderboardCycleMenu.chosenCycleId));
    if (cycleUserRank != null)
    {
    userRankingPanel.SetRankingDetails(
    currentUserData.user_id,
    cycleUserRank.Rank,
    currentUserData.display_name,
    cycleUserRank.Point);
    }
    }

    CurrentView = LeaderboardMenuView.Default;
    }
  11. Finally, in the OnEnable() function, initialize the required wrappers and call the DisplayRankingList() to display the leaderboard rankings when the menu is opened.

    private void OnEnable()
    {
    leaderboardWrapper = TutorialModuleManager.Instance.GetModuleClass<LeaderboardEssentialsWrapper_Starter>();
    authWrapper = TutorialModuleManager.Instance.GetModuleClass<AuthEssentialsWrapper>();

    if (!leaderboardWrapper || !authWrapper)
    {
    return;
    }

    DisplayRankingList();
    }

Resources