34

I am making a multiplayer game for iOS and I read the material in Apple Developer Center, specifically this one. Here is my code for custom matchmaking, which is pretty straightforward:

- (void)findProgrammaticMatch {

    GKMatchRequest *request = [[GKMatchRequest alloc] init];
    request.minPlayers = 2;
    request.maxPlayers = 2;
    request.defaultNumberOfPlayers = 2;
    request.playersToInvite = nil;
    request.playerAttributes = 0;
    request.playerGroup = 0;

    UILabel *loading = (UILabel *)[aiw viewWithTag:792];

    [[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) {
        if (error){

            //error handling
            [loaderLayer stopAnimating];
            UIButton *cancelButton = (UIButton *)[loaderLayer viewWithTag:442];
            [cancelButton setTitle:@"Go Back" forState:UIControlStateNormal];
            loading.text = @"Cannot find any players. Please try again later.";

        } else if (match != nil) {

            //save match
            self.match = match;
            self.match.delegate = self;

            loading.text = @"Found a player. Preparing session...";

            if (!self.matchStarted && match.expectedPlayerCount == 0) {

                self.matchStarted = YES;
                //begin game logic
                [self.scene setState:1];
                self.myTicket = 1000+arc4random_uniform(999);
                [self.scene send:self.myTicket];
                [self stopLoading];
            }

        }
    }];  
}

However, matchmaking fails when one or more devices are connected to the internet via cellular networks. When I investigated the underlying error I found out that even if it is a wifi to wifi case, the completion handler does not work as intended. That is, match.expectedPlayerCount is never 0. Instead, the game starts when - (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state handler is invoked after the completion handler as following:

...
- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
    switch (state) {
        case GKPlayerStateConnected:
            self.matchStarted = YES;
            //begin game logic
            [self.scene setState:1];
            self.myTicket = 1000+arc4random_uniform(999);
            [self.scene send:self.myTicket];
            [self stopLoading];
            break;
...

The problem now is if a device with 3g is connected (and matched-sort of) didChangeState is never invoked. I checked for several other related questions on the internet and this site, although they are far from being satisfactory. I also read that sandbox servers of Game Center are not reliable and for some people production version worked perfectly(it just works!) despite the errors in sandbox mode, but I don't want to take that risk. Has anybody have experienced similar problem with their multiplayer game?

MSU_Bulldog
  • 3,465
  • 5
  • 34
  • 73
Hgeg
  • 535
  • 6
  • 18
  • 1
    Just a quick insight. Is your server open internet-wide, or are you working on a LAN? I guess it's the first one, but if someone paid me a penny every time I had this kind of simple infrastructure issues without noticing, I'd be pretty rich already :) If it's not open internet-wide, you should put your device through a VPN – Bartserk Apr 17 '15 at 08:36
  • So just to be clear, you are saying that if a device connects to the match using 3g didChangeState is never called? Because it should be getting called whenever a new player connects to the match. That is where you should be checking the expected player count for 0. – Epic Byte Apr 18 '15 at 04:45

3 Answers3

2

Hgeg,

There is nothing wrong with your code. You have to allow cellular data usage to your app which needs users permission.

The following paragraph is selected from Apple's support website :

At the Foundation layer, you can use the setAllowsCellularAccess: method on NSMutableURLRequest to specify whether a request can be sent over a cellular connection. You can also use the allowsCellularAccess to check the current value.

At the Core Foundation layer, you can achieve the same thing by setting the kCFStreamPropertyNoCellular property before opening a stream obtained from the CFSocketStream or CFHTTPStream APIs.

In older versions of iOS, you can continue to use the kSCNetworkReachabilityFlagsIsWWAN as a best-effort way of determining whether traffic will be sent over a cellular connection, but you should be aware of its limitations.

Good luck

Iman

Iman
  • 2,029
  • 2
  • 12
  • 32
1

According to the latest apple news, from iOS 9, the sand box mode will no longer exist, instead of the sandbox you'll have one unified environment.Unified envoiroment

So you'll have just one unified environments where you can share the same accounts, this should solve all the usual problems from the SandBox mode.

The new Unified System it's also compatible with TestFlight so you'll be able to test you code across multiple device and accounts.

All of these changes will be made directly by apple, so the only think that you can do it's to wait until they update to the new system, so far it's the only way to be sure that it's not a Sand Box problem. For more info please have a loot at the WWDC video

Max_Power89
  • 1,604
  • 1
  • 18
  • 36
0

Based on the code that you have shown us, there should'nt be any issue regardless of the connection type, 3G or otherwise; however, if you previously interspersed code for exception handling that was tied back to connection status, or for graphics which represent a loading state, something could be tied up elsewhere logically and produce this error at this point in the game logic. Even a corrupt spinner graphic can become an issue.

Did you have any other exception handlers in the code that called the following:

request.playersToInvite

or

request.playerGroup

or

that changed a loader layer characteristic?

miniscule
  • 740
  • 3
  • 10
  • Would also be interested in any other code you are concerned about while you have the bounty open. – miniscule Jun 17 '15 at 21:33
  • Please show us any code that directly manipulates game center preferences, does an async return to the main queue without verification of state, or has autorelease involved (always seems to be touchy). Have you noticed any differences between iOS versions by chance? Also, I recommend writing an invitation handler and introducing logging so you are doing more than notifications within routines. I know it can be tedious, but I definitely agree with your statement about risk on release. – miniscule Jun 17 '15 at 22:03
  • Before anything else, put NSLog(@"ERROR: Error makeMatch: %@", [error description] ); where your error catching is and let us know the results. You might want to consider changing to a more involved invite model so you can have more flexibility. Yes, you would be adding complexity, but the more time you spend on making your player connectivity (and status messages) rock-solid, the better your long-term support. – miniscule Jun 17 '15 at 22:34