Leaderboards
Read more about the Leaderboards system in Hiro here.
Get all leaderboards
#
Get the leaderboards defined for the game.
1
2
3
4
5
6
7
8
9
10
| FHiroOnLeaderboardsConfigGet OnLeaderboardsConfigGet;
OnLeaderboardsConfigGet.AddDynamic(this, &AMyActor::OnLeaderboardsConfigGet);
FOnError OnError;
HiroClient->LeaderboardsConfigGet(Session, OnLeaderboardsConfigGet, OnError);
void AMyActor::OnLeaderboardsConfigGet(const FHiroLeaderboardConfigList& LeaderboardConfigList)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *LeaderboardConfigList.ToJson());
}
|
Online Subsystem
#
Hiro backs Unreal Engine’s standard IOnlineLeaderboards interface, so you can read and write Hiro leaderboard scores using the same code patterns you’d use with any other Online Subsystem provider. Scores are stored in Nakama and inherit all of Hiro’s leaderboard features — regional scoring, friend queries, and configurable operators — without any additional setup.
This interface is separate from the Hiro client API documented above. For setup instructions, see Online Subsystem.
Retrieve the interface from the subsystem after initialization:
1
| IOnlineLeaderboardsPtr LeaderboardsInterface = OnlineSubsystem->GetLeaderboardsInterface();
|
For setup instructions, see Online Subsystem.
Writing scores
#
Writing a score is a two-step operation: stage the record with WriteLeaderboards, then commit it to the server with FlushLeaderboards. Only "score" and "subscore" are valid property names.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| FOnlineLeaderboardWrite WriteObject = FOnlineLeaderboardWrite();
WriteObject.UpdateMethod = ELeaderboardUpdateMethod::Force;
WriteObject.SortMethod = ELeaderboardSort::None;
WriteObject.LeaderboardNames = { TEXT("my-leaderboard") };
WriteObject.Properties.Emplace(TEXT("score"), 100);
WriteObject.Properties.Emplace(TEXT("subscore"), 10);
LeaderboardsInterface->WriteLeaderboards(TEXT(""), *LocalUserId, WriteObject);
FDelegateHandle FlushHandle = LeaderboardsInterface->AddOnLeaderboardFlushCompleteDelegate_Handle(
FOnLeaderboardFlushCompleteDelegate::CreateLambda([](const FName& Name, bool bWasSuccessful)
{
if (bWasSuccessful)
{
// Score submitted.
}
})
);
LeaderboardsInterface->FlushLeaderboards(TEXT(""));
|
Calling WriteLeaderboards while a flush is already in progress may cause the new value to be lost if a record for the same player and leaderboard is currently being submitted.
Score merging behavior
#
UpdateMethod and SortMethod on FOnlineLeaderboardWrite control how a new staged value merges with an existing cached value for the same player and leaderboard:
| Setting | Behavior |
|---|
ELeaderboardUpdateMethod::Force or ELeaderboardSort::None | Always overwrites the cached value |
ELeaderboardSort::Ascending | Keeps the cached value if it’s lower than the new score |
ELeaderboardSort::Descending | Keeps the cached value if it’s higher than the new score |
Reading scores for specific players
#
ReadLeaderboards fetches records for the given player IDs and populates the FOnlineLeaderboardRead object asynchronously. All player IDs must be Hiro IDs (FUniqueNetIdHiro).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| FOnlineLeaderboardReadPtr LeaderboardRead = MakeShared<FOnlineLeaderboardRead>();
LeaderboardRead->LeaderboardName = TEXT("my-leaderboard");
FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardRead.ToSharedRef();
FDelegateHandle ReadHandle = LeaderboardsInterface->AddOnLeaderboardReadCompleteDelegate_Handle(
FOnLeaderboardReadCompleteDelegate::CreateLambda([LeaderboardReadRef](bool bWasSuccessful)
{
if (bWasSuccessful)
{
for (const FOnlineStatsRow& Row : LeaderboardReadRef->Rows)
{
// Row.PlayerId, Row.Rank, Row.Columns
}
}
})
);
LeaderboardsInterface->ReadLeaderboards({ LocalUserId.ToSharedRef() }, LeaderboardReadRef);
|
Each row in Rows contains three columns:
"score" — the player’s primary score (Int32)"subscore" — the player’s secondary score (Int32)"num_score" — the number of times the player has submitted a score (Int32)
Reading scores around a player
#
ReadLeaderboardsAroundUser returns scores for the players ranked closest to the given player. The Range parameter controls the window size: the interface requests 2 × Range + 1 records centered on the player.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| FOnlineLeaderboardReadPtr LeaderboardRead = MakeShared<FOnlineLeaderboardRead>();
LeaderboardRead->LeaderboardName = TEXT("my-leaderboard");
FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardRead.ToSharedRef();
FDelegateHandle ReadHandle = LeaderboardsInterface->AddOnLeaderboardReadCompleteDelegate_Handle(
FOnLeaderboardReadCompleteDelegate::CreateLambda([LeaderboardReadRef](bool bWasSuccessful)
{
if (bWasSuccessful)
{
// LeaderboardReadRef->Rows contains players around the target.
}
})
);
uint32 Range = 5; // Returns up to 11 rows (5 above, player, 5 below).
LeaderboardsInterface->ReadLeaderboardsAroundUser(LocalUserId.ToSharedRef(), Range, LeaderboardReadRef);
|
Reading a friends’ leaderboard
#
ReadLeaderboardsForFriends fetches leaderboard scores for all friends of the specified local player. It automatically paginates through the friends list (up to 1,000 per page) before issuing the leaderboard read.
LocalUserNum is the local player index used to look up the player’s session and friends list.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| FOnlineLeaderboardReadPtr LeaderboardRead = MakeShared<FOnlineLeaderboardRead>();
LeaderboardRead->LeaderboardName = TEXT("my-leaderboard");
FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardRead.ToSharedRef();
FDelegateHandle ReadHandle = LeaderboardsInterface->AddOnLeaderboardReadCompleteDelegate_Handle(
FOnLeaderboardReadCompleteDelegate::CreateLambda([LeaderboardReadRef](bool bWasSuccessful)
{
if (bWasSuccessful)
{
// LeaderboardReadRef->Rows contains the friends' scores.
}
})
);
int32 LocalUserNum = 0;
LeaderboardsInterface->ReadLeaderboardsForFriends(LocalUserNum, LeaderboardReadRef);
|
Unsupported operations
#
ReadLeaderboardsAroundRank is not supported. It always returns false and fires OnLeaderboardReadComplete with a failure state.