I am using a turn-based multiplayer game through gamecenter. I have 2 devices (1 ipad, 1 iphone) for testing in sandbox mode that worked fine, but lately it started to struggle in the process of auto-negotiation. After I sent the first turn from one user, another device does not immediately recognize this game, but opens its new fresh game. Before he could immediately notice the game running on another device, and the match-match was pretty simple. And I donβt remember changing any details related to matchmaking ( NSCoding , GKTurnBasedEventHandler , GKTurnBasedMatchmakerViewControllerDelegate delegate methods, etc.).
Now I'm sending the first turn from one device and should wait about 1 minute so that the other device can successfully connect to this game. After connecting, endTurnWithMatchData causes work without any problems, it can send and receive data within 1-2 seconds. But it will not be a good UX if users start a new game and have to wait 1 minute so that another user can connect to their game. Has anyone experienced a significant lag in the auto-negotiation process? I have not yet implemented the invitation, so I cannot verify it. The mapping files I archived with NSKeyedArchiver seemed rather large, 3396 bytes, even for a new game with almost no data. And here are the relevant parts of my code:
GameOptionsViewController :
- (void)turnBasedMatchmakerViewControllerWasCancelled:(GKTurnBasedMatchmakerViewController *)viewController { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController didFailWithError:(NSError *)error { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController didFindMatch:(GKTurnBasedMatch *)match { [self dismissViewControllerAnimated:NO completion:nil]; self.gcMatch = match; [self performSegueWithIdentifier:@"GameMultiplayer" sender:self]; } - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if([segue.identifier isEqualToString:@"GameMultiplayer"]) { GameViewController *GameVC = (GameViewController *)segue.destinationViewController; [GameVC setGameMode:GAMEMODE_MULTIPLAYER_SAMEDEVICE];
GameViewController :
//This method is called according to user actions //It the only method I use to send data to other participant -(void) sendCurrentGameDataWithNewTurn:(BOOL) newTurn { NSLog(@"Sending game data current participant : %@", gcMatch.currentParticipant.playerID); //Update match data if it is corrupted anyhow if (gcMatch.currentParticipant == nil) { [GKTurnBasedMatch loadMatchWithID:gcMatch.matchID withCompletionHandler:^(GKTurnBasedMatch *match, NSError *error) { if (error != nil) { NSLog(@"Error :%@", error); return ; } [self sendCurrentGameDataWithNewTurn:newTurn]; }]; } else { NSData *matchData = [NSKeyedArchiver archivedDataWithRootObject:game]; //Game advances to new player, buttons are disabled if(newTurn) { NSLog(@"SENDING NEW TURN"); NSUInteger currentIndex = [gcMatch.participants indexOfObject:gcMatch.currentParticipant]; GKTurnBasedParticipant *nextParticipant; nextParticipant = [gcMatch.participants objectAtIndex: ((currentIndex + 1) % [gcMatch.participants count])]; [gcMatch endTurnWithNextParticipants:[NSArray arrayWithObject:nextParticipant] turnTimeout:GC_TURN_TIMEOUT matchData:matchData completionHandler:^(NSError *error) { NSLog(@"Sent"); if (error) { NSLog(@"SNT - %@", error); } }]; } else { NSLog(@"ONLY UPDATING DATA"); [gcMatch saveCurrentTurnWithMatchData:matchData completionHandler:^(NSError *error) { NSLog(@"Sent"); if (error) { NSLog(@"OUD - %@", error); } }]; } }
}
-(void) updateGameDataWithGCMatch { //Update whole game data self.game = [NSKeyedUnarchiver unarchiveObjectWithData:self.gcMatch.matchData]; //Update game ui ... } -(void) handleTurnEventForMatch:(GKTurnBasedMatch *)match didBecomeActive:(BOOL)didBecomeActive { //Check if I got data for the currently active match that options vc forwarded me here, if not do some debug print and return if(![self.gcMatch.matchID isEqual:match.matchID]) { //For debugging reasons I skip if i get info for any previous match (other player quit etc) NSLog(@"GCMatch matchID: %@ match matchID: %@",self.gcMatch.matchID,match.matchID); return; } NSLog(@"Turn event handle"); self.gcMatch = match; if([match.currentParticipant.playerID isEqualToString: [GKLocalPlayer localPlayer].playerID ]) { //Disable field buttons [self setFieldButtonsEnabled:TRUE]; [self turnChangeAnimationFromLeftToRight:FALSE]; } [self updateGameDataWithGCMatch]; }