Download

How to get Steam Leaderboards to work in C++

Hi,

I have been digging this for days but I can’t seems to get it work.

First I am kind of beginner in C++ programming and leaderboards management seems to be a quite complex feature to handle. I tried to understand leaderboards in ShooterGame source code and my main goal is to make use of this function :


virtual bool ReadLeaderboardsAroundUser(TSharedRef<const FUniqueNetId> Player, uint32 Range, FOnlineLeaderboardReadRef& ReadObject) = 0; 

To simply get Steam leaderboards of people around the user and expose it to Blueprint.

So far I’ve written this function :


int32 UZombieSteamworks::GetPlayerScore()
{
    //Get the online sub system
    IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get();

    if (OnlineSub)
    {
        //Get the Identity from the sub system
        //Meaning our player's profile and various online services
        IOnlineIdentityPtr Identity = OnlineSub->GetIdentityInterface();

        if (Identity.IsValid())
        {
            //Get a thread-safe pointer
            TSharedPtr<const FUniqueNetId> UserIdPtr = Identity->GetUniquePlayerId(0);
            TSharedRef<const FUniqueNetId> UserIdRef = UserIdPtr.ToSharedRef();

            IOnlineLeaderboardsPtr Leaderboards = OnlineSub->GetLeaderboardsInterface();

            if (Leaderboards.IsValid())
            {
                //Make a shared pointer for leaderboards reading
                FOnlineLeaderboardReadPtr LeaderboardReadPtr = MakeShareable(new ZombieSteamWorksLeaderboardRead());
                FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardReadPtr.ToSharedRef();

                bool HasReadLeaderboard = Leaderboards->ReadLeaderboardsAroundUser(UserIdRef, 2, LeaderboardReadRef);

                if (HasReadLeaderboard)
                {
                    TSharedPtr<FLeaderboardRow> NewLeaderboardRow = MakeShareable(new FLeaderboardRow(LeaderboardReadRef->Rows[0]));
                    return 1;
                    //return LeaderboardReadRef->Rows.Lenght;

                    //if (LeaderboardReadRef->Rows[0] != NULL)
                    //{
                        //return LeaderboardReadRef->Rows[0].Rank;
                    //}
                }
            }
        }
    }

    return 0;
}

This code will compile fine but will crash the game when trying to access value of LeaderboardReadRef->Rows.

How is one able to get Steam leaderboard and how does OnlineLeaderboardInteface works ?

I do have Leaderboard working on Steamworks web API with a name and scores stored from the player but where would I reference in the code.

I did made some interesting progress and I succeed to have the ReadLeaderboards() to work. Unfortunately other functions such as ReadLeaderboardsAroundRank() or ReadLeaderboardsAroundUser() don’t return any score.

I checked the source for these functions and I was somehow amazed to see that it seems there is a big chunk of code missing for these :


bool FOnlineLeaderboardsSteam::**ReadLeaderboards**(const TArray< TSharedRef<const FUniqueNetId> >& Players, FOnlineLeaderboardReadRef& ReadObject)
{
    ReadObject->ReadState = EOnlineAsyncTaskState::InProgress;

    // Clear out any existing data
    ReadObject->Rows.Empty();

    // Will retrieve the leaderboard, making async calls as appropriate
    FindLeaderboard(ReadObject->LeaderboardName);

    // Retrieve the leaderboard data
    FOnlineAsyncTaskSteamRetrieveLeaderboardEntries* NewLeaderboardTask = new FOnlineAsyncTaskSteamRetrieveLeaderboardEntries(SteamSubsystem, Players, ReadObject);
    SteamSubsystem->QueueAsyncTask(NewLeaderboardTask);

**// This function is working and retrieves the stats after getting the leaderboard data with this loop**

    // Retrieve the stats related to this leaderboard
    int32 NumPlayers = Players.Num();
    for (int32 UserIdx=0; UserIdx < NumPlayers; UserIdx++)
    {
        bool bLastPlayer = (UserIdx == NumPlayers-1) ? true : false;
        FUniqueNetIdSteam UserId(*(uint64*)Players[UserIdx]->GetBytes());
        FOnlineAsyncTaskSteamRetrieveStats* NewStatsTask = new FOnlineAsyncTaskSteamRetrieveStats(SteamSubsystem, UserId, ReadObject, bLastPlayer);
        SteamSubsystem->QueueAsyncTask(NewStatsTask);
    }

    return true;
}

bool FOnlineLeaderboardsSteam::**ReadLeaderboardsAroundRank**(int32 Rank, uint32 Range, FOnlineLeaderboardReadRef& ReadObject)
{
    ReadObject->ReadState = EOnlineAsyncTaskState::InProgress;

    // Clear out any existing data
    ReadObject->Rows.Empty();

    // Will retrieve the leaderboard, making async calls as appropriate
    FindLeaderboard(ReadObject->LeaderboardName);

    FOnlineAsyncTaskSteamRetrieveLeaderboardEntries* NewLeaderboardTask = new FOnlineAsyncTaskSteamRetrieveLeaderboardEntries(SteamSubsystem, Rank, Range, ReadObject);
    SteamSubsystem->QueueAsyncTask(NewLeaderboardTask);

**// Where is the loop to retrieve the stats related to this leaderboard??!**

    return true;
}

This code is from the engine so it’s hard to edit. But how is it possible that the loop wasn’t included in any of the other Steam reading leaderboards functions.

I have a Steam Plugin (SteamCore::](SteamCore in Code Plugins - UE Marketplace)) that you can use to get and manipulate Leaderboards, it includes the Source code for the plugin if you want to dig into it and see how I deal with leaderboards in c++.

That’s exactly what I try to achieve. Did you make some progress? Is ReadLeaderboardsAroundRank and ReadLeaderboards now working for you and you could get the leader board scores of top players and friends?
Would be really great when you could help! Thanks a lot!

Searched Engine Code now: https://github.com/EpicGames/UnrealEngine/blob/f8f4b403eb682ffc055613c7caf9d2ba5df7f319/Engine/Plugins/Online/OnlineSubsystemSteam/Source/Private/OnlineLeaderboardInterfaceSteam.cpp

This is “ReadLeaderboards” which seems to work fine.


bool FOnlineLeaderboardsSteam::ReadLeaderboards(const TArray< TSharedRef<const FUniqueNetId> >& Players, FOnlineLeaderboardReadRef& ReadObject)
{
ReadObject->ReadState = EOnlineAsyncTaskState::InProgress;

// Clear out any existing data
ReadObject->Rows.Empty();

// Will retrieve the leaderboard, making async calls as appropriate
FindLeaderboard(ReadObject->LeaderboardName);

// Retrieve the leaderboard data
FOnlineAsyncTaskSteamRetrieveLeaderboardEntries* NewLeaderboardTask = new FOnlineAsyncTaskSteamRetrieveLeaderboardEntries(SteamSubsystem, Players, ReadObject);
SteamSubsystem->QueueAsyncTask(NewLeaderboardTask);

**// Retrieve the stats related to this leaderboard
int32 NumPlayers = Players.Num();
for (int32 UserIdx=0; UserIdx < NumPlayers; UserIdx++)
{
bool bLastPlayer = (UserIdx == NumPlayers-1) ? true : false;
FUniqueNetIdSteam UserId(*(uint64*)Players[UserIdx]->GetBytes());
FOnlineAsyncTaskSteamRetrieveStats* NewStatsTask = new FOnlineAsyncTaskSteamRetrieveStats(SteamSubsystem, UserId, ReadObject, bLastPlayer);
SteamSubsystem->QueueAsyncTask(NewStatsTask);
}

return true;
}**

These show getting values after get leader board data,

But the following, ReadLeaderboardsAroundRank, ReadLeaderboardsAroundUser, ReadLeaderboardsForFriends
show only get leader board data, but I do not see the loop or something else to retrieve or select concrete data.


bool FOnlineLeaderboardsSteam::ReadLeaderboardsAroundRank(int32 Rank, uint32 Range, FOnlineLeaderboardReadRef& ReadObject)
{
ReadObject->ReadState = EOnlineAsyncTaskState::InProgress;

// Clear out any existing data
ReadObject->Rows.Empty();

// Will retrieve the leaderboard, making async calls as appropriate
FindLeaderboard(ReadObject->LeaderboardName);

FOnlineAsyncTaskSteamRetrieveLeaderboardEntries* NewLeaderboardTask = new FOnlineAsyncTaskSteamRetrieveLeaderboardEntries(SteamSubsystem, Rank, Range, ReadObject);
SteamSubsystem->QueueAsyncTask(NewLeaderboardTask);

return true;
}
bool FOnlineLeaderboardsSteam::ReadLeaderboardsAroundUser(TSharedRef<const FUniqueNetId> Player, uint32 Range, FOnlineLeaderboardReadRef& ReadObject)
{
ReadObject->ReadState = EOnlineAsyncTaskState::InProgress;

// Clear out any existing data
ReadObject->Rows.Empty();

// Will retrieve the leaderboard, making async calls as appropriate
FindLeaderboard(ReadObject->LeaderboardName);

FOnlineAsyncTaskSteamRetrieveLeaderboardEntries* NewLeaderboardTask = new FOnlineAsyncTaskSteamRetrieveLeaderboardEntries(SteamSubsystem, Player, Range, ReadObject);

SteamSubsystem->QueueAsyncTask(NewLeaderboardTask);

return true;
}

bool FOnlineLeaderboardsSteam::ReadLeaderboardsForFriends(int32 LocalUserNum, FOnlineLeaderboardReadRef& ReadObject)
{
ReadObject->ReadState = EOnlineAsyncTaskState::InProgress;

// Clear out any existing data
ReadObject->Rows.Empty();

// Will retrieve the leaderboard, making async calls as appropriate
FindLeaderboard(ReadObject->LeaderboardName);

FOnlineAsyncTaskSteamRetrieveLeaderboardEntries* NewLeaderboardTask = new FOnlineAsyncTaskSteamRetrieveLeaderboardEntries(SteamSubsystem, ReadObject);
SteamSubsystem->QueueAsyncTask(NewLeaderboardTask);

return true;
}

So what Devdan2 pointed out is correct?
“ReadLeaderboardsAroundRank, ReadLeaderboardsAroundUser, ReadLeaderboardsForFriends” are not even working for steam?

Would be very frustrating. I am trying for two days to populate ReadLeaderboardsAroundRank, ReadLeaderboardsAroundUser, ReadLeaderboardsForFriends to BP to make in BP useable. An now find that it would not even work. :frowning:

Same topic was here, but also 4 years old topic and links to solutions/tutorials are also not working:
https://answers.unrealengine.com/questions/499549/working-with-steam-leaderboards-a-few-very-specifi.html

Hi sorry for the late reply!
This part of engine wasn’t the best time I had from working with it.
At the end I effectively reported an issue to Epic Games and it was fixed since I could used all of these features for my games.
So everything is working now.
Also to point an issue or mostly something strange is that Steam leaderboards can decrease internally a score to a smaller value which will reflect when getting the value in UE4 but will not update the Steam leaderboard page!
So if you had a player that had 1000 points on the leaderboards and you lower it to 400 it will updatein the backend of Steam and UE4 but not on the webpage of Steam leaderboards!

Hello, I am working on reading leaderboard values also. But I couldn’t figure out how to expose keys to blueprints.It gives me PlayerName and Rank but how can I get StatValue and how to expose it to blueprints? Anyone knows?