Reputation: 585
This is about GameCenter
.
Since "the GKLocalPlayerListener
protocol inherits the methods from GKChallengeListener
, GKInviteEventListener
, and GKTurnBasedEventListener
.
In order to handle multiple events" and "do not implement GKChallengeListener
, GKInviteEventListener
, and GKTurnBasedEventListener
directly; implement GKLocalPlayerListener
instead.
You can listen for, and handle multiple events using GKLocalPlayerListener
" (these are from apple docs).
One would expect that after registering the GKLocalPlayerListener
after the GKLocalPlayer.localPlayer()
has been authenticated, then all the methods in the GKLocalPlayerListener
would be called, when the appropriate events happen.
However, apart from "player(player: GKPlayer
, receivedTurnEventForMatch match: GKTurnBasedMatch
, didBecomeActive: Bool)", which is called, all the other methods, including "player(player: GKPlayer
, matchEnded match: GKTurnBasedMatch
)" is never called when such an event occurs.
Do we need to register some other listener or is there something I am missing?
Upvotes: 7
Views: 1217
Reputation: 3031
You are not missing anything. Apple has chosen to
remove [these] feature[s]
I opened a submitted a bug with Apple to investigate further. Their response was un satisfactory to say the least.
Upvotes: 0
Reputation: 128
I don't have the a reputation high enough to comment on Thunks answer but I can submit my own, so that is how I will get this out info out there. The biggest part of the problem is that there is no examples of how to use this code and the documentation is lacking. So, code not firing is not proof that the code is broken, just that we don't know how to use it.
But based upon the statements that Thunk is making I was able to get the player:didModifySavedGame and player:hasConflictingSavedGames which he says that he has never seen them fire.
These are the methods to the GKSavedGameListener madness. the problem I was having with this protocol is that it does not have a delegate to assign it, so I can pick any class in my program and make it conform to this protocol and then expect the methods to fire, which seemed unlikely. So I needed some sort of a delegate to say which class conformed.
I found that by setting the localPlayer.registerListener(self) where self is the conforming class I get them to fire.
So double check any methods that are not firing with this set and let us know if it works better.
Upvotes: 1
Reputation: 4177
Regarding detecting that you've been invited to a turn based match: no event is sent, but when you query your list of matches from the server, you just have a new match suddenly show up (and your status will be invited). (the recipient does get an UIAlert prompt that they've received an invite, though)
Regarding if/when the various API functions fire, I have spent many, many, many hours trying to decipher when these various functions fire. I've opened more than a few bugs either against the functions or against the documentation. Here are my current notes; This is how I've organized all the delegate functions in my helper class, indicating which listener they apply to as well as notes as to what causes them to fire.
You can see there are several that I've never deciphered. Any additional input/clarifications on this list would be greatly appreciated.
#pragma mark - specific to real-time matches
//this is for real-time matches only (but the docs don't say that)
-(void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite
#pragma mark - saved game listener (GKSavedGameListener)
//never fires. Theory: only fires if the SAME player tries to save the game from a different device while being the active player
-(void)player:(GKPlayer *)player didModifySavedGame:(GKSavedGame *)savedGame
//never fires. Theory: only fires if the SAME player tries to save the game from a different device while being the active player
-(void)player:(GKPlayer *)player hasConflictingSavedGames:(NSArray *)savedGames
#pragma mark - game launched via game center (GKLocalPlayerListener)
//DEPRECATED: This is fired when the user asks to play with a friend from the game center.app
-(void)player:(GKPlayer *)player didRequestMatchWithPlayers:(NSArray *)playerIDsToInvite
//This is fired when the user launches the game from Game Center and requests to play with a friend
-(void)player:(GKPlayer *)player didRequestMatchWithRecipients:(NSArray *)recipientPlayers
//Never seen this fire. Possibly fired when the user launches the game from Game Center. Unclear how this varies from didRequestMatchWithRecipients
-(void)player:(GKPlayer *)player didRequestMatchWithOtherPlayers:(NSArray *)playersToInvite
#pragma mark - Ending turn based matches (GKLocalPlayerListener)
//I've never seen this fire
-(void)player:(GKPlayer *)player matchEnded:(GKTurnBasedMatch *)match
//I've never seen this fire
-(void)player:(GKPlayer *)player wantsToQuitMatch:(nonnull GKTurnBasedMatch *)match
#pragma mark - challenges (GKLocalPlayerListener)
//untested, I don't use challenges
-(void)player:(GKPlayer *)player issuedChallengeWasCompleted:(GKChallenge *)challenge byFriend:(GKPlayer *)friendPlayer
//untested, I don't use challenges
-(void)player:(GKPlayer *)player didCompleteChallenge:(GKChallenge *)challenge issuedByFriend:(GKPlayer *)friendPlayer
//untested, I don't use challenges
-(void)player:(GKPlayer *)player didReceiveChallenge:(GKChallenge *)challenge
//untested, I don't use challenges
-(void)player:(GKPlayer *)player wantsToPlayChallenge:(GKChallenge *)challenge
#pragma mark - exchanges (GKLocalPlayerListener)
//seems to work as expected
-(void)player:(GKPlayer *)player receivedExchangeCancellation:(GKTurnBasedExchange *)exchange forMatch:(GKTurnBasedMatch *)match
//this fires for the Current Player AND the Exchange Initiator AFTER all replies/timeouts are complete.
-(void)player:(GKPlayer *)player receivedExchangeReplies:(NSArray *)replies forCompletedExchange:(GKTurnBasedExchange *)exchange forMatch:(GKTurnBasedMatch *)match
//seems to work as expected
-(void)player:(GKPlayer *)player receivedExchangeRequest:(GKTurnBasedExchange *)exchange forMatch:(GKTurnBasedMatch *)match
#pragma mark - event handler (GKLocalPlayerListener)
-(void)player:(GKPlayer *)player receivedTurnEventForMatch:(GKTurnBasedMatch *)match didBecomeActive:(BOOL)didBecomeActive
/*
Apple says this fires when:
1. When it becomes the active player's turn, including the inviting player creating a new match (CHECK)
2. When the time out is about to fire (FAIL. It fires AFTER the timeout expires, which may just be item #4 happening)
3. Player accepts an invite from another player (FAIL. Never happens. Instead it fires when an INVITED player starts playing a session FROM this player.)
4. Turn was passed to another player. (CHECK)
5. player receives a reminder (CHECK, confirmed by μ4ρκ05)
It Also fires when:
6. A remote user quits (CHECK)
7. A remote user declines (unconfirmed)
8. An automatch player joins the game (CHECK)
9. An invited player starts playing (CHECK)
10. A remote user saves the game (CHECK)
*/
Edit: updated the status of "reminder" notifications based on μ4ρκ05's feedback.
Upvotes: 8
Reputation: 585
Ok, your list and explanation of the various methods got me thinking.
First of all. The problem of getting no notification when a match is received is one of the most pressing problems for me since if you don't get notified it means that you will need to pull to data. So, when do you load the matches again? Every x seconds or every time the view controller with the list of games appears? Both will be issuing unnecessary network calls that will be annoying and also since the list of games may need to be reloaded, without any actual change, it might not look good as well. So at first I was thinking of using exchanges so that the opponent may get notified and reload the games. However, reading your post I remembered about player receives a reminder (UNTESTED)
that called the receivedTurnEventForMatch
. Now, I managed to get the opponent notified of the new game by initializing the new game, taking a turn, and then sending a reminder.
I've updated my TurnBasedSkeleton project.
Upvotes: 1