How to share saved games across devices?

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?

Replies

how do you resolve Conflictings?

    #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 */ 

Thanks man, this helped me a lot with saving games.