Gamecenter ios 9 GameCenter GKLocalPlayerListener methods not called
Asked Answered
M

4

7

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?

Mutinous answered 24/12, 2015 at 11:27 Comment(2)
I created TurnBasedSkeleton (github.com/mhatzitaskos/TurnBasedSkeleton). This project aims to create a skeleton for any turn based game using GameCenter. As GameCenter seems to lack in documentation and tutorials, especially as far as turn based gaming is concerned, I decided to create this project to help others who might want to integrate GameCenter to their projects. Any help would be appreciated. Main unsolved issue is how a player that receives an invitation may get notified. There does not seem to be any automatic notification for that.Tog
Managed to solve the invitation notification issue. TurnBasedSkeleton project has been updated.Tog
G
8

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.

Grate answered 24/12, 2015 at 22:39 Comment(0)
M
1

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.

Mutinous answered 25/12, 2015 at 8:54 Comment(1)
I did basically what you described, I have a specific VC for managing games and displaying badges for waiting games, and I pull the data under two specific circumstances. I found that I have to make so many (IMO) extraneous read/writes to the server due to other game center limitations, that this was just a drop in the bucket. I like your idea of using the reminder, though, and will play around with that too. I will update my post to indicate that reminders are confirmed.Grate
R
1

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.

Reprehension answered 31/3, 2016 at 7:30 Comment(2)
Sojourner, what event actually results in the functions firing? Is it saving the match to the server? I have GKSavedGameListener in my header, and I use localPlayer's registerListener (which was already necessary to make receivedTurnEvent fire), but I still have never ever hit breakpoints in those two functions. So, I'm still confused about what causes them to fire.Grate
Authenticate LocalPlayer, as shown in GKLocalPlayer Reference, from a function call in appDelegate:applicationDidBecomeActive. In the third part add the localPlayer.registerListener(self) and localPlayer.fetchSavedGamesWithCompletionHandler. Add extension YourClassName:GKSavedGameListener and implement the two functions from GKSavedGameListener. When calling localPlayer.saveGameData(completionHandler:) on one device player:DidModifySaveGame should fire in 20 second. I'm doing this all in swift so I have no header.Reprehension
F
0

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.

Apple bug report

Foxtrot answered 30/4, 2016 at 4:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.