I'm implementing a turn-based game with multiplayer mode through gamecenter. I have 2 devices (1 ipad, 1 iphone) to test in sandbox mode which were working fine but lately it has started to struggle in auto matchmaking process. After I send the first turn from one user, the other device doesn't immediately recognize that game but opens up its own fresh game. Before it was able to immediately spot the game started in the other device and matchmaking was fairly straightforward. And I don't remember changing any parts relevant to matchmaking (NSCoding
, GKTurnBasedEventHandler
, GKTurnBasedMatchmakerViewControllerDelegate
delegate methods etc).
Now I send the first turn from one device and need to wait around 1 min so the other device can successfully connect to that game. After connection occurs endTurnWithMatchData calls work without any problems, it can send and receive data within 1-2 secs. But it won't be a good UX if users start a fresh game and had to wait 1 min so another user can connect to his game. Has anyone been experiencing significant lag in auto matchmaking process? I didn't implement invitations yet, so I cannot check it. The matchdata I archive with NSKeyedArchiver seemed quite big, 3396 bytes, even for a fresh game with almost no data. And here are 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];
//Multiplayer game it is
if(self.gcMatch != nil)
{
[GameVC setGameMode:GAMEMODE_MULTIPLAYER_GAMECENTER];
GameVC.gcMatchDelegate = self;
GameVC.gcMatch = self.gcMatch;
NSLog(@"Game OVC Segue: Match ID | %@", self.gcMatch.matchID);
}
}
else
{
...
}
}
GameViewController
:
//This method is called according to user actions
//It's 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];
}