すべてを統合する - 全期間のリーダーボード - (Unity モジュール)
Connect the UI to display leaderboard rankings
Open
LeaderboardSelectionMenu_Starter.cs
.Declare a local variable to hold the reference of the
LeaderboardEssentialsWrapper_Starter
wrapper.private LeaderboardEssentialsWrapper_Starter leaderboardWrapper;
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.Empty;
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;
}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);
}Finally, in the
OnEnable()
function, initialize the leaderboard wrapper and call theDisplayLeaderboardList()
to display the leaderboard list when the menu is opened.private void OnEnable()
{
leaderboardWrapper = TutorialModuleManager.Instance.GetModuleClass<LeaderboardEssentialsWrapper_Starter>();
if (!leaderboardWrapper)
{
return;
}
if (ApiClientHelper.IsPlayerLoggedIn)
{
DisplayLeaderboardList();
}
}
Connect the UI to display current user rankings
Open the
LeaderboardMenu_Starter.cs
.Add two local variables to hold the references to the
LeaderboardEssentialsWrapper_Starter
andAuthEssentialsWrapper
wrappers.private LeaderboardEssentialsWrapper_Starter leaderboardWrapper;
private AuthEssentialsWrapper authWrapper;Define the following variables that store the required values for requesting the ranking list from AccelByte Gaming Services (AGS):
注記TokenData
is a class that contains all detailed information of the current user. Its values are returned upon a successful login.private PlayerState currentUserData;
private string currentLeaderboardCode;
private LeaderboardCycleMenu_Starter.LeaderboardCycleType currentCycleType;Create a function that initializes these variables by getting them from the other leaderboard menu and the
AuthEssentialsWrapper
.private void InitializeLeaderboardRequiredValues()
{
currentUserData = GameData.CachedPlayerState;
currentLeaderboardCode = LeaderboardSelectionMenu_Starter.chosenLeaderboardCode;
currentCycleType = LeaderboardCycleMenu_Starter.chosenCycleType;
}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;Create a function that handles the instantiation of the
RankingEntryPanel
that holds each player ranking info. AdduserId
,playerName
, andplayerScore
as parameters since you will display these values. Also, update theUserRankingPanel
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.playerId) 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);
}Since the
GetRankings()
function only returns an array of user IDs, you need to use theBulkGetUserInfo()
function in theAuthEssentialsWrapper
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 theGetUserRanking()
function in theLeaderboardEssentialsWrapper_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.playerName))
{
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.playerId))
{
CurrentView = LeaderboardMenuView.Default;
return;
}
// Get current player ranking if not already in the ranking list.
leaderboardWrapper.GetUserRanking(
currentUserData.playerId,
currentLeaderboardCode,
OnGetUserRankingCompleted);
}Create the callback function that handles the leaderboard ranking query result. Remember, you need to call the
BulkGetUserInfo()
function in theAuthEssentialsWrapper
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, here the game show 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));
}Create a new function to call the
DisplayRankingList()
function if the leaderboard's cycle period isAllTime
.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);
}
}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)
{
// This block prevents leaderboard display issues caused by players without rankings
if (result.Error.Code == ErrorCode.LeaderboardRankingUnableToRetrieve)
{
BytewarsLogger.LogWarning($"Failed to Get User Ranking. Error: {result.Error.Message}");
CurrentView = LeaderboardMenuView.Default;
return;
}
else
{
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.playerId,
allTimeUserRank.rank,
currentUserData.playerName,
allTimeUserRank.point);
}
}
else
{
UserCycleRanking cycleUserRank = result.Value.Cycles.First(data => data.CycleId.Equals(LeaderboardCycleMenu_Starter.chosenCycleId));
if (cycleUserRank != null)
{
userRankingPanel.SetRankingDetails(
currentUserData.playerId,
cycleUserRank.Rank,
currentUserData.playerName,
cycleUserRank.Point);
}
}
CurrentView = LeaderboardMenuView.Default;
}Finally, in the
OnEnable()
function, initialize the required wrappers and call theDisplayRankingList()
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
- GitHub Link to the files in the Byte Wars repository: