Search code examples
androidc++google-play-games

Google Play Games C++ API - Unable to Access Friends Programatically


The Google Play Games C++ does not seem to be returning correct friend data for me.

The basic idea here is that we have a page in our game that shows a list of friends scores. Additionally, when you're playing the game, it will show an indicator on-screen when you're approaching and when you pass your friends' best scores.

The game is written in Cocos2d-x and as a result we're using the Google Play Games C++ library. GPG authenticates successfully and other functionality (such as unlocking achievements and actually submitting scores) is working correctly. As an aside, if anyone from Google is reading, there is Release Notes for version 2.2 on the website but the downloads page only has 2.1 so that's what we're using.

Anyway, we have two devices with different Google Play accounts that are friends. We have the option to open the default, native Games Services Leaderboards UI and if I go to the social leaderboard, then both devices see the other player's high score from this page - so it seems like we have successfully made the two accounts friends.

Unfortunately, I am unable to get this friend data programatically using the C++ API.

Here is the relevant code.

void GameCenterSession::fetchFriends()
{
    __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Fetching friends!");

    //GET INVITABLE FRIENDS
    game_services_->Players().FetchInvitable(gpg::DataSource::CACHE_OR_NETWORK, [] (gpg::PlayerManager::FetchListResponse response) {
        __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Got invitable friends response: %d", response.status);
        __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Got invitable players info! Num players: %d", response.data.size());
        if (gpg::IsSuccess(response.status)) {
            //PROCESS PLAYERS
            GameCenterSession::getInstance()->onPlayersInfoReceived(kRequestFriendsInfo, response.data);
        }
    });

    //GET CONNECTED FRIENDS
    game_services_->Players().FetchConnected(gpg::DataSource::CACHE_OR_NETWORK, [] (gpg::PlayerManager::FetchListResponse response) {
        __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Got connected friends response: %d", response.status);
        __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Got connected players info! Num players: %d", response.data.size());
    });
}

void GameCenterSession::onPlayersInfoReceived(const int requestId, std::vector<gpg::Player> playersInfo) {

    __android_log_print(ANDROID_LOG_INFO, "MyGame!", "onPlayersInfoReceived num players: %d", playersInfo.size());
    const gpg::ScorePage::ScorePageToken distanceToken = game_services_->Leaderboards().ScorePageToken(
        kLeaderboardBestDistance,
        gpg::LeaderboardStart::TOP_SCORES,
        gpg::LeaderboardTimeSpan::ALL_TIME,
        gpg::LeaderboardCollection::SOCIAL
    );

    //FETCH ALL TIME SOCIAL SCORES FOR DISTANCE
    game_services_->Leaderboards().FetchScorePage(gpg::DataSource::CACHE_OR_NETWORK, distanceToken, 1000, [] (gpg::LeaderboardManager::FetchScorePageResponse response) {

        if (gpg::IsSuccess(response.status) && response.data.Valid()) {
            __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Got social leaderboard! Num players: %d", response.data.Entries().size());
            gpg::ScorePage::Entry myEntry = gpg::ScorePage::Entry();

            //search through and find my score!
            for (auto score : response.data.Entries()) {
                __android_log_print(ANDROID_LOG_INFO, "MyGame!", "%s got distance %d", score.PlayerId().c_str(), score.Score().Value());


                if (score.PlayerId().compare(GameCenterSession::getInstance()->myPlayer.Id()) == 0) {
                    __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Distance - Yup that's me");
                    myEntry = score;
                } else {
                    __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Distance - It's another player!");
                }
            }

            GameCenterSession::getInstance()->onScoresReceived(kRequestFriendsDistancesInfo, myEntry, response.data.Entries());
        }
    });


    const gpg::ScorePage::ScorePageToken scoreToken = game_services_->Leaderboards().ScorePageToken(
        kLeaderboardBestScore,
        gpg::LeaderboardStart::TOP_SCORES,
        gpg::LeaderboardTimeSpan::ALL_TIME,
        gpg::LeaderboardCollection::SOCIAL
    );

    game_services_->Leaderboards().FetchScorePage(gpg::DataSource::CACHE_OR_NETWORK, scoreToken, 1000, [] (gpg::LeaderboardManager::FetchScorePageResponse response) {
        if (gpg::IsSuccess(response.status) && response.data.Valid()) {

            gpg::ScorePage::Entry myEntry = gpg::ScorePage::Entry();

            //search through and find my score!
            for (auto score : response.data.Entries()) {
                __android_log_print(ANDROID_LOG_INFO, "MyGame!", "%s got score %d", score.PlayerId().c_str(), score.Score().Value());


                if (score.PlayerId().compare(GameCenterSession::getInstance()->myPlayer.Id()) == 0) {
                    __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Score - Yup that's me");
                    myEntry = score;
                } else {
                    __android_log_print(ANDROID_LOG_INFO, "MyGame!", "Score - It's another player!");
                }
            }

            GameCenterSession::getInstance()->onScoresReceived(kRequestFriendsScoresInfo, myEntry, response.data.Entries());
        }
    });

    if (requestId == kRequestFriendsInfo)
    {
        friends = playersInfo;
    }
}

Looking at the code, you'll see that I first fetch the friends list and check how many players are in that list. I try to access both invititable friends (judging by documentation this is the one I would want) and with connected friends (just as a test). I go on to grab two different all time social leaderboards - distance and score, and I check how many players are in the result. Here is my log output.

//Device 1

I/MyGame!( 1510): Google Play Games authenticated successfully!
I/MyGame!( 1510): Fetching friends!
I/MyGame!( 1510): Got invitable friends response: 1
I/MyGame!( 1510): Got invitable players info! Num players: 0
I/MyGame!( 1510): onPlayersInfoReceived num players: 0
I/MyGame!( 1510): Got connected friends response: 1
I/MyGame!( 1510): Got connected players info! Num players: 0
I/MyGame!( 1510): Got social leaderboard! Num players: 1
I/MyGame!( 1510): g1703186947466536XXXX got distance 310
I/MyGame!( 1510): Distance - Yup that's me
I/MyGame!( 1510): g1703186947466536XXXX got score 2510
I/MyGame!( 1510): Score - Yup that's me

//Device 2

01-23 17:11:27.227 17187 17234 I MyGame!: Google Play Games authenticated successfully!
01-23 17:11:27.250 17187 17234 I MyGame!: Fetching friends!
01-23 17:11:27.451 17187 17234 I MyGame!: Got invitable friends response: 1
01-23 17:11:27.451 17187 17234 I MyGame!: Got invitable players info! Num players: 0
01-23 17:11:27.451 17187 17234 I MyGame!: onPlayersInfoReceived num players: 0
01-23 17:11:27.581 17187 17234 I MyGame!: Got connected friends response: 1
01-23 17:11:27.581 17187 17234 I MyGame!: Got connected players info! Num players: 0
01-23 17:11:27.973 17187 17234 I MyGame!: Got social leaderboard! Num players: 1
01-23 17:11:27.973 17187 17234 I MyGame!: g0152008166550356XXXX got distance 712
01-23 17:11:27.973 17187 17234 I MyGame!: Distance - Yup that's me
01-23 17:11:28.444 17187 17234 I MyGame!: g0152008166550356XXXX got score 2142
01-23 17:11:28.444 17187 17234 I MyGame!: Score - Yup that's me

As you can see, my callbacks all return successful result codes. Unfortunately, neither device returns any friends, and the social leaderboard callback only contains the player on the device, not their friends' score.

I followed the documentation as best I could, and I have reviewed the code without being able to find any issue, but if it is just a semantics issue I'd be happy to hear about my mistakes. Am I doing something wrong here, or is there an issue with the C++ API itself?

Thanks in advance.


Solution

  • The API is behaving as expected. From: https://android-developers.googleblog.com/2016/12/games-authentication-adopting-google.html

    Google+ is no longer integrated Announced last year, Games is decoupled from Google+ during this transition. As a result the public APIs for getting connected players via circles stopped working, but the standard UIs for multiplayer invitations and social leaderboards continued to work. Starting from February 2017, the standard UIs will also not display the Social graph results as Google+ data becomes inaccessible. This will affect multiplayer games, social leaderboards, and gifts API on Android. The effect will be that these APIs will return successfully, but with an empty list of players.