Google Play Game Services unlock achievement - store unlock in game or call unlock() every time?
Asked Answered
K

2

3

I am developing an Android game which uses Google Play Game Services.

When a player reach for example 10000 points an achievement gets unlocked. So when the player reaches 10000 points I call

Games.Achievements.unlock(...)

The question is what to do when the user reaches 10000 points again in another game. Do I have to check if this achievement is already unlocked or can I just call unlock() again?

I know that the Play Services popup is diplayed only when the achievement gets first unlocked. But I am concerned about the quota of api calls. If I for example store the achievement unlock from shared preferences then I would do something like this:

if(myAchievementIsLocked){
   Games.Achievements.unlock(...)
}

What are the best practices? I was looking at some samples but didn't find the answers which I was looking for.

Kazantzakis answered 24/5, 2014 at 17:46 Comment(0)
K
8

As far as I can tell, unlock() will check with the local Play Games app first to see if the achievement is already unlocked, and only if it is not will it send the request to the server. This means that calling unlock() on an already unlocked achievement should not affect any quotas apart from the first time it is called on a device - since the device's instance of the Play Games may not have synced that achievement from the server yet.

On the other hand, it is possible to check the state of all achievements after signing-in and keeping a local copy of their states - which indeed you should do if the player is NOT signed-in (so that you can unlock any achievements earned at the next sign-in). This process is not documented well anywhere except for the API documentation but there are no full examples, so I will give you one here :)

Ensure that you run this method asynchronously (using AsyncTask or a separate thread) as it will take some time to complete (waiting for responses from the server). Also, do this only when the player is signed in successfully - onSignInSucceeded() is a good place for it.

Update for Play Service Games 11.8.0

public void loadAchievements()  {
    mAchievementsClient.load(true).addOnCompleteListener(new OnCompleteListener<AnnotatedData<AchievementBuffer>>() {
        @Override
        public void onComplete(@NonNull Task<AnnotatedData<AchievementBuffer>> task) {
            AchievementBuffer buff = task.getResult().get();
            Log.d("BUFF", "onComplete: ");
            int bufSize = buff.getCount();
            for (int i=0; i < bufSize; i++)  {
                Achievement ach = buff.get(i);
                String id = ach.getAchievementId();
                boolean unlocked = ach.getState() == Achievement.STATE_UNLOCKED;
            }
            buff.release();
        }
    });

Older Play Service Games

  public void loadAchievements()  {

     boolean fullLoad = false;  // set to 'true' to reload all achievements (ignoring cache)
     float waitTime = 60.0f;    // seconds to wait for achievements to load before timing out

     // load achievements
     PendingResult p = Games.Achievements.load( playHelper.getApiClient(), fullLoad );
     Achievements.LoadAchievementsResult r = (Achievements.LoadAchievementsResult)p.await( waitTime, TimeUnit.SECONDS );
     int status = r.getStatus().getStatusCode();
     if ( status != GamesStatusCodes.STATUS_OK )  {
        r.release();
        return;           // Error Occured
     }

     // cache the loaded achievements
     AchievementBuffer buf = r.getAchievements();
     int bufSize = buf.getCount();
     for ( int i = 0; i < bufSize; i++ )  {
        Achievement ach = buf.get( i );

        // here you now have access to the achievement's data
        String id = ach.getAchievementId();  // the achievement ID string
        boolean unlocked = ach.getState == Achievement.STATE_UNLOCKED;  // is unlocked
        boolean incremental = ach.getType() == Achievement.TYPE_INCREMENTAL;  // is incremental
        if ( incremental )
           int steps = ach.getCurrentSteps();  // current incremental steps
     }
     buf.close();
     r.release();
  }

See the API documentation for more info on these processes.

So using this method you could create a local copy of the achievements (just alter the internals of the for loop to save the achievement values to some local structure) and refer to it as needed.

Katherine answered 25/5, 2014 at 7:57 Comment(1)
I´ve updated it with the latest sdk network call since I´ve been looking for it. Some parts of this answer helped me achieve what I was trying to do.Ginter
L
1

Calling .unlock(...) on an already unlocked achievement shouldn't be a problem. My guess is there is already some sort of "check if unlocked" handling in the .unlock(...) method.

Levitt answered 24/5, 2014 at 18:4 Comment(1)
That is also my guess...but I am asking because the official documentation is not that precise on this matter.Kazantzakis

© 2022 - 2024 — McMap. All rights reserved.