1

Im a noob in game center @ games generally. Im making my second game now and implemented the game center.

If the internet is available, there is no problem, everything works well. But just now I purposely make the internet unreachable, and when I get an achievement, obviously it does not register to the Game Center's Achievement.

How and what's the best way to handle this issue?

Thank you....

GeneCode
  • 7,545
  • 8
  • 50
  • 85

5 Answers5

2

You could add the GKAchievement objects that fail to register to an array and then resend them when you get back connectivity. You should also consider committing that array to persistent storage, in case your app terminates before it has a chance to send those achievements. Try this in your completion handler:

// Load or create array of leftover achievements
if (achievementsToReport == nil) {
    achievementsToReport = [[NSKeyedUnarchiver unarchiveObjectWithFile:pathForFile(kAchievementsToReportFilename)] retain];
    if (achievementsToReport == nil) {
        achievementsToReport = [[NSMutableArray array] retain];
    }
}

@synchronized(achievementsToReport) {
    if(error == nil)
    {
        // Achievement reporting succeded

        // Resend any leftover achievements
        BOOL leftoverAchievementReported = NO;
        while ([achievementsToReport count] != 0) {
            [self resendAchievement:[achievementsToReport lastObject]];
            [achievementsToReport removeLastObject];
            leftoverAchievementReported = YES;
        }

        // Commit leftover achievements to persistent storage
        if (leftoverAchievementReported == YES) {
            [NSKeyedArchiver archiveRootObject:achievementsToReport toFile:pathForFile(kAchievementsToReportFilename)];
        }
    }
    else
    {
        // Achievement reporting failed
        [achievementsToReport addObject:theAchievement];
        [NSKeyedArchiver archiveRootObject:achievementsToReport toFile:pathForFile(kAchievementsToReportFilename)];
    }
}

Hope this helps.

Spiros
  • 709
  • 4
  • 9
  • Hi Spiros, thanks for providing this sample code. Where does it go though? I am using the GameCenter.m and .h from the GKTapped sample code. – GeneCode Jul 18 '11 at 14:27
  • The snippet I provided should normally go into the completion handler of `reportAchievementWithCompletionHandler:`. In the GKTapper case, I guess it should go into `achievementSubmitted:error:`, but this needs checking. – Spiros Jul 19 '11 at 06:59
  • I tried to put it in, but tonnes of errors came out. I give up on this. It would be great though if anyone could make a simple Game Center Helper for Scores and Achievements only. I will try something else for my game... – GeneCode Jul 19 '11 at 10:47
  • I feel your pain. I'm similarly frustrated with the amount of effort required to integrate Game Center and cover all the angles. You should modify my snippet to fit your particular environment. At a minimum, you should have an `NSMutableArray* achievementsToReport` ivar, a `pathForFile(NSString* filename)` function, a `kAchievementsToReportFilename` constant defined, and a `resendAchievement:(GKAchivement*)ach` method similar to the `submitAchievement:percentComplete:` method. – Spiros Jul 19 '11 at 11:06
  • I ended up making my own methods. Thanks for your help anyways. – GeneCode Jul 25 '11 at 15:08
1

I see that the two answers here focus on the specific mechanisms for archiving the undelivered achievement messages. For a higher-level description of the overall approach, you can see my answer to this related question: Robust Game Center Achievement code

Community
  • 1
  • 1
M Katz
  • 5,098
  • 3
  • 44
  • 66
0
    // Submit an achievement to the server and store if submission fails
- (void)submitAchievement:(GKAchievement *)achievement 
{
    if (achievement)
    {
        // Submit the achievement. 
        [achievement reportAchievementWithCompletionHandler: ^(NSError *error)
        {
            if (error)
            {
                // Store achievement to be submitted at a later time. 
                [self storeAchievement:achievement];
            }
            else
            {
                 NSLog(@"Achievement %@ Submitted..",achievement);
                if ([storedAchievements objectForKey:achievement.identifier]) {
                    // Achievement is reported, remove from store.
                    [storedAchievements removeObjectForKey:achievement.identifier];
                } 
                [self resubmitStoredAchievements];
            }
        }];
    }
}
0

In case anyone stumbles upon this question in the future, Apple now has sample code for submitting achievements that includes a way to archive achievements that failed to submit (due to no network connection, etc). You'll find it in the Game Center programming guide.

bmueller
  • 2,681
  • 1
  • 27
  • 45
0

Achievements (and all of the gamecenter stuff like leaderboard updates) conform to NSCoding. You can store them if you get an error submitting them and submit them later. This is what apple recommends in their docs.

Your application must handle errors when it fails to report progress to Game Center. For example, the device may not have had a network when you attempted to report the progress. The proper way for your application to handle network errors is to retain the achievement object (possibly adding it to an array). Then, your application needs to periodically attempt to report the progress until it is successfully reported. The GKAchievement class supports the NSCoding protocol to allow your application to archive an achievement object when it moves into the background.

from: http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/Achievements/Achievements.html#//apple_ref/doc/uid/TP40008304-CH7-SW13

Joshua Smith
  • 6,561
  • 1
  • 30
  • 28
  • Yes, I've read that. What is needed is to translate that docs into codes, which I am not sure how to do. Thanks for replying anyways. – GeneCode Jul 18 '11 at 14:27
  • NSCoding is a way to serialize objects (this is not all, but for your purposes will do). Once serialized, you can then store them (ie in a file or in Core Data) and retrieve them later in order to resend them. – Joshua Smith Jul 18 '11 at 14:58