I've got a peer to peer iPhone game working pretty well. I've created a table to display available peers and I can connect (so far) up to four devices and play a full round of a game from start to finish:
But here's my problem...
I create a GKSession
on one device with GKSessionModeClient
and the other with GKSessionModeServer
. The client sees the server, selects to connect it, then the server approves. The server then can tap "start game" when all the peers are connected.
If--before the server starts the game-- the client taps the "back" button to go to the previous screen, the custom peer picker display is popped from the view and the session is "destroyed"...
[_gkSession disconnectFromAllPeers];
[_gkSession setAvailable:NO];
[_gkSession setDelegate:nil];
[_gkSession setDataReceiveHandler:nil withContext:nil];
now, if the client goes back to the peer picker and joins the server again, I get a GKSessionStateConnected
state again, but when I sendDataToAllPeers:
nothing reaches the client. It works flawlessly if one device starts a game and three devices join and then the server taps "start game". But if someone quits out before the game starts, then recreating a session and joining fails.
Any ideas? My only hack I can think of at this point is preventing a user from tapping "back" once they connect to a server, but that kind of sucks...they'd have to quit the app completely if they changed their mind. I'm at my wits end with this one as the app is running as well as I like it except for this connection issue. Kind of an edge case but I can see a user being annoyed if they can't start a game without having to restart the application to get the sessions cleared.
Will make this a bounty when I can. Please help!
Edit @byteclub
- Does the server clean up all of the relevant data structures correctly if client leaves before game begins?
If the client leaves the game lobby after the server accepts their connection, the client's session is destroyed:
- (void)destroySession
{
trace(@"destroySession");
self.gameDelegate = nil;
self.lobbyDelegate = nil;
[_gkSession disconnectFromAllPeers];
[_gkSession setAvailable:NO];
[_gkSession setDelegate:nil];
[_gkSession setDataReceiveHandler:nil withContext:nil];
[_peerList removeAllObjects];
}
I do not call any disconnectFromPeers methods on the server device though.
* Is the client-disconnect-cleanup procedure different for cases when the
game has been started already?
Slightly, if a client disconnects then everyone receives a "peer quit" notification and the game ends. I don't worry about reconnecting in this case. It's mainly in the game lobby where the client can "Cancel" to go back to the home screen where the problem is. The client's session is destroyed in this case. If they then go back to the lobby and a new GKSession is alloc'ed, they can connect to the server still, but sendDataToAllPeers no longer works once they are connected.
* Do you still have a problem if, before reconnecting, you restart the
client, but leave the server running as is?
The client can reconnect in any case. I can quit, go back, restart the app and reconnect no problem. Just sendDataToPeers fails unless the server and client are both restarted.
* Do you completely destroy GKSession object on the client side
when user taps "back"?
Yes. (see code above)
I realize this is probably insane to debug from afar but if you have any suggestions for what I could look into, I'd appreciate it.
It works flawlessly if one device starts a game and three devices join and then the server taps "start game". But if someone quits out before the game starts, then recreating a session and joining fails.
If I'm reading this right, it looks like you have the thing working correctly in some cases, but not others. I'd check the logic to make sure client connects/disconnects are handled the same (correct) way every time.
Some questions: