Handle invitation to GKTurnBasedMatch without game

2019-04-09 05:30发布

问题:

I am working on a simple turn-based word game, and I'm having a difficult time figuring out how invitations are working. When user A invites user B to a game, I want user B to be able to see this game in my custom match interface (ie a screen where all of user B's games are listed). Things are fine if user B clicks on the notification when he is invited to a game, but I still want the game to be visible through my own interface if user B just navigates to the app on his own.

Whenever this match interface screen appears, I am using [GKTurnBasedMatch loadMatchesWithCompletionHandler:] to get all of the local player's matches. With this, I would assume that user B would be able to see the match he has been invited to, but this new match doesn't show up. If I accept the invitation through the GKTurnBasedMatchmakerViewController, the user enters the game as expected, but what makes this even more puzzling is that if I open up my GKTurnBasedMatchmakerViewController and then cancel without accepting the invitation, a new match now shows up in my custom match interface, but it lacks the match data that was sent by user A.

To sum up, I am really just wondering how to properly display and accept GKTurnBasedMatch invitations with a custom interface (rather than having to use GKTurnBasedMatchmakerViewController). Thanks!

回答1:

This question seems to be of interest to a couple people, so here's a rough approximation of what I ended up doing.

First of all, the reason new matches weren't showing up at all was just that I wasn't calling [GKTurnBasedMatch loadMatchesWithCompletionHandler:] every time I wanted the view to refresh like I though I was. So no real issue there as I recall.

The real issue was the case where I was receiving and displaying the new GKTurnBasedMatch, but none of the data (i.e. the opposing player's first move) was available. Essentially, [GKTurnBasedMatch loadMatchesWithCompletionHandler:] doesn't seem to guarantee providing you with the most up-to-date GKTurnBasedMatch objects available. To make sure the matches are up-to-date, I had to also call [match loadMatchDataWithCompletionHandler:], on each match returned by [GKTurnBasedMatch loadMatchesWithCompletionHandler:] (where match is one of those GKTurnBasedMatches). This returns the most current match data associated with that match as an NSData object. I was then able to use this NSData to make sure all the matches in my match table were refreshed to reflect the most recent changes in game center.

In short, use loadMatchDataWithCompletionHandler on your GKTurnBasedMatch objects to make sure their data is up to date.



回答2:

UPDATE: now includes the actual answer for receiving invitations.

I have struggled with programmatically handling invites for turn-based matches for close to a week. I finally found the answer. I'm gonna super-highlight it because it took me so long to find:

Game Center treats turn-based invitations as turn events. They are not handled like other invitations.

Turn-based events are handled in this function in the GKLocalPlayerListener protocol:

player(_ player: GKPlayer, receivedTurnEventFor match: GKTurnBasedMatch, 
       didBecomeActive: Bool)

When you recieve the match, check if you're invited to it, and presto. You've received an invitation.

BUT:

Through frustrating trial and error I have found some caveats, which hopefully can save you some serious time:

  1. It just plain doesn't always work. Believe it or not, Game Center is unreliable. This means you need a back-up system that reviews your local player's open matches and searches them for new invitations. That itself pertains to caveat #2.
  2. A player that is invited to a match (for instance say playerJake is invited to matchFoo) will not actually get that invitation nor see that match in the matches returned by loadMatches until it is their turn. Apparently Game Center does not actually involve any player on a match's invitation list in any way until it is their turn.
  3. If you can identify a match you're invited to, but haven't responded to, you must call acceptInvite(...) directly on that match. So if playerJake inspected the matches retrieved by loadMatches, and was able to detect that matchFoo still had an open invitation, playerJake has to call matchFoo.acceptInvite( /* ...completion handler stuff here... */), and then happy playerJake is off and running.

From this you should be able to get your own programmatic matching system to work. Best of luck, and I mean it!