playgameservices / android-basic-samples

Google Play game services - Android samples
Apache License 2.0
971 stars 973 forks source link

Failing to get current player leaderboard score for more than 3 leaderboards #279

Open tomasbecket opened 6 years ago

tomasbecket commented 6 years ago

After the user signs into Play Games on Android, our app is trying to fetch the players current score from 10 leaderboards (to restore his score on the device). However after first 3 that get successfully restored all the rest fail with com.google.android.gms.common.api.ApiException: 26504: NETWORK_ERROR_NO_DATA

Sample code (kotlin) where the calls to Games API are chained, in order not to send them all at once:

private fun updateScore(context: Context, account: GoogleSignInAccount, leaderboardIds: MutableList<String>) {
    if (achievements.isEmpty()) {
        return
    }
    val leaderboardId = leaderboardIds.removeAt(0)
    Games.getLeaderboardsClient(context, account).loadCurrentPlayerLeaderboardScore(leaderboardId,
            LeaderboardVariant.TIME_SPAN_ALL_TIME, COLLECTION_PUBLIC).addOnCompleteListener { result ->
        if (result.isSuccessful) {
            // Here we restore the local score
        } else {
            // 4th and all other leaderboards hit this
        }
        Thread.sleep(1000) // I know this isn't cool, just making sure for debugging we're not hitting the quota
        updateScore(context, account, leaderboardIds)
    }
}

Checked the APIs quota in the developer console and the highest the "Queries per 100 seconds" goes is about 20 (nowhere near the 500 claimed). At the same time the overview reports quite few 403 errors (I assume those are the failures our app is receiving).

thiagolr commented 4 years ago

This is happening since 2015, they don't seem to care...

danoli3 commented 3 years ago

Well maybe they don't seem to care, but I do! Heres the fix:

I would suggest another approach I have discovered as there seems to be no other to this quota per session/activity for loadCurrentPlayerLeaderboardScore

Use loadPlayerCenteredScores instead . Limit the scores to 1. The resultant buffer will return only the player score. You are now in the user quota of 500 requests instead of 3.

long limitResultsTo = 1;
String leaderboardID = getString(R.string.leaderboard_name); // or string of ID
Games.getLeaderboardsClient(this, GoogleSignIn.getLastSignedInAccount(this))
    .loadPlayerCenteredScores(leaderboardName, LeaderboardVariant.TIME_SPAN_ALL_TIME, LeaderboardVariant.COLLECTION_PUBLIC, limitResultsTo)
    .addOnSuccessListener(new OnSuccessListener<AnnotatedData<LeaderboardsClient.LeaderboardScores>>() {
        @Override
        public void onSuccess(AnnotatedData<LeaderboardsClient.LeaderboardScores> leaderboardScoreAnnotatedData) { // big ups Danoli3.com for the fix for loadCurrentPlayerLeaderboardScore
            LeaderboardsClient.LeaderboardScores scoresResult =  leaderboardScoreAnnotatedData.get();
            LeaderboardScore scoreResult = (scoresResult != null ? scoresResult.getScores().get(0) : null);
            long score = 0;
            if(scoreResult != null) score = scoreResult.getRawScore();

            // use the score in your own code here
            // Log.i(TAG, "loadPlayerCenteredScores:" + leaderboardID + " score:" + score);

            leaderboardScoreAnnotatedData = null; 
        }
    }).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
        Log.e(TAG, "Failure:loadPlayerCenteredScores  GPG:Leader:" + leaderboardID + " Ex:" + e.getMessage());
    }