1 Reply
      Latest reply on Apr 24, 2019 11:39 PM by caochao88
      modiX Level 1 Level 1 (0 points)

        I implemented GameKit into my iOS game including the saved game feature.

         

         

        Here an example how I save and load a game:

         

         

        MobSvcSavedGameData.h

            #ifndef MOBSVC_SAVEDGAMEDATA_H
            #define MOBSVC_SAVEDGAMEDATA_H
           
            #import 
           
            @interface MobSvcSavedGameData : NSObject 
           
            @property (readwrite, retain) NSString *data;
           
            +(instancetype)sharedGameData;
            -(void)reset;
           
            @end
           
           
            #endif /* MOBSVC_SAVEDGAMEDATA_H */

         

        MobSvcSavedGameData.m

            #import "MobSvcSavedGameData.h"
            #import 
           
            @interface MobSvcSavedGameData () 
           
            @end
           
            @implementation MobSvcSavedGameData
           
            #pragma mark MobSvcSavedGameData implementation
           
            static NSString * const sgDataKey = @"data";
           
            + (instancetype)sharedGameData {
              static id sharedInstance = nil;
          
              static dispatch_once_t onceToken;
              dispatch_once(&onceToken, ^{
                sharedInstance = [[self alloc] init];
              });
          
              return sharedInstance;
            }
           
            - (void)reset
            {
              self.data = nil;
            }
           
            - (void)encodeWithCoder:(NSCoder *)encoder
            {
              [encoder encodeObject:self.data forKey: sgDataKey];
            }
           
            - (nullable instancetype)initWithCoder:(nonnull NSCoder *)decoder {
              self = [self init];
              if (self) {
                self.data = [decoder decodeObjectForKey:sgDataKey];
              }
              return self;
            }
           
            @end

         

        For simplicity my saved game object above has only a `NSString` which will be serialised and uploaded like so:

        void MobSvc::uploadSavedGameDataAwait(const char *name, const char *data)
        {
          GKLocalPlayer *mobSvcAccount = [GKLocalPlayer localPlayer];
        
          if(mobSvcAccount.isAuthenticated)  
          {
            MobSvcSavedGameData *savedGameData = [[MobSvcSavedGameData alloc] init];
            savedGameData.data = [NSString stringWithUTF8String:data];
            [mobSvcAccount saveGameData:[NSKeyedArchiver archivedDataWithRootObject:savedGameData] withName:[[NSString alloc] initWithUTF8String:name] completionHandler:^(GKSavedGame * _Nullable savedGame __unused, NSError * _Nullable error) {
              if(error == nil)
              {
                NSLog(@"Successfully uploaded saved game data");
              }
              else
              {
                NSLog(@"Failed to upload saved game data: %@", error.description);
              }
            }];
          }
        }

         

        And this is how I download the most recent saved game on the next play session again:

        void MobSvc::downloadSavedGameDataAwait(const char *name)
        {
          GKLocalPlayer *mobSvcAccount = [GKLocalPlayer localPlayer];
        
          if(mobSvcAccount.isAuthenticated)
          {
            [mobSvcAccount fetchSavedGamesWithCompletionHandler:^(NSArray * _Nullable savedGames, NSError * _Nullable error) {
              if(error == nil)
              {
                GKSavedGame *savedGameToLoad = nil;
                for(GKSavedGame *savedGame in savedGames) {
                  const char *sname = savedGame.name.UTF8String;
                  if(std::strcmp(sname, name) == 0)
                  {
                    if (savedGameToLoad == nil || savedGameToLoad.modificationDate < savedGame.modificationDate) {
                      savedGameToLoad = savedGame;
                    }
                  }
                }
                if(savedGameToLoad != nil) {
                  [savedGameToLoad loadDataWithCompletionHandler:^(NSData * _Nullable data, NSError * _Nullable error) {
                    if(error == nil)
                    {
                      MobSvcSavedGameData *savedGameData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
                      NSLog(@"Successfully downloaded saved game data: %@", [savedGameData.data cStringUsingEncoding:NSUTF8StringEncoding]);
                    }
                    else
                    {
                      NSLog(@"Failed to download saved game data: %@", error.description);
                    }
                  }];
                }
              }
              else
              {
                NSLog(@"Failed to prepare saved game data: %@", error.description);
              }
            }];
          }
        }

         

        I tested this by uploading a random string and receiving it on the next session by using the same `name`. It works! However, as soon as I try to download the saved game from my second iPhone it does not work. On both phones I'm logged into the same Game-Center account, I could confirm this by comparing the `playerId` in the `GKLocalPlayer` instance.

         

         

        I've set up the proper iCloud container and linked my game to it, but the logs in the iCloud container backend remain empty.

         

         

        What is going on? How can I share the saved game across Apple devices?