I am trying to use Game Center to achieve peer to peer communication. But I meet some issues while testing game center. The user authentication is fine, it went through. The problem is matchmaking.
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error) {
NSLog(#"%#",error.localizedDescription);
}else if (match != nil) {
NSLog(#"good match");
[match setDelegate:self];
}else {
NSLog(#"other error");
}
}];
I want to create own request instead of using GKMatchmakerViewController. But the block code is NOT steady, some time it can work, some time gives me error: cannot connect to server, I don't know it's Game Center server's problem or my code?
Once the above code is working fine, then I set the following handler:
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite=[NSArray arrayWithObjects:#"G:****", nil];//yin
request.inviteMessage=#"Welcome to my Game";
request.inviteeResponseHandler=^(NSString *playerID, GKInviteeResponse response) {
if(response==0){
NSLog(#"Accepted....");
}else if(response==1){
NSLog(#"Declined....");
}else if(response==2){
NSLog(#"Failed....");
}else if(response==3){
NSLog(#"3");
}else if(response==4){
NSLog(#"4");
}else if(response==5){
NSLog(#"5");
}else{
NSLog(#"unknown...");
}
};
I tested on different iphone. Once one iphone sends request to other, other can receive the notification, but only other rejects the invitation, then sender iphone can receive, if other accepts, the sender iphone receive nothing. I don't know why this things happened????
And at the receiver iphone side the inviteHandler is working fine. This is wired I tested the whole day, I cannot make it through. I am very brand new with IOS developing. Please help me out of this, appreciate very much!!!!
Related
I'm trying to invite nearby players to a match, but the invite is either never sent or never received.
GKMatchMaker startBrowsingForNearbyPlayersWithHandler works and returns nearby players that are on same wifi, but then I use findMatchForRequest and it returns a match without any players, and the players I try to invite never receive an invite notification. Here is my code.
I start by authenticating the local player:
GKLocalPlayer.localPlayer.authenticateHandler= ^(UIViewController *controller, NSError *error)
{
if (error)
{
NSLog(#"%s:: Error authenticating: %#", __PRETTY_FUNCTION__, error.localizedDescription);
return;
}
if(controller)
{
// User has not yet authenticated
[pViewController presentViewController:controller animated:YES completion:^(void)
{
[self lookForNearbyPlayers];
}];
return;
}
[self lookForNearbyPlayers];
};
-(void)lookForNearbyPlayers
{
if(!GKLocalPlayer.localPlayer.authenticated)
{
NSLog(#"%s:: User not authenticated", __PRETTY_FUNCTION__);
return;
}
I register my view controller as a delegate of GKLocalPlayerListener:
[GKLocalPlayer.localPlayer registerListener:self]; // self is a view controller.
// This works. My test local player which is a second device and appleID I setup shows up when this handler is called.
[GKMatchmaker.sharedMatchmaker startBrowsingForNearbyPlayersWithHandler:^(GKPlayer *player, BOOL reachable)
{
NSArray * paPlayers= [NSArray arrayWithObject:player];
_pMatchRequest= [[GKMatchRequest alloc] init];
_pMatchRequest.minPlayers= 2;
_pMatchRequest.maxPlayers= 4;
_pMatchRequest.recipients = paPlayers;
_pMatchRequest.inviteMessage = #"Join our match!";
_pMatchRequest.recipientResponseHandler = ^(GKPlayer *player, GKInviteeResponse response)
{
// This is never called.
NSLog((response == GKInviteeResponseAccepted) ? #"Player %# Accepted" : #"Player %# Declined", player.alias);
};
// This returns with a match without any players.
[GKMatchmaker.sharedMatchmaker findMatchForRequest:_pMatchRequest withCompletionHandler:^(GKMatch *match, NSError *error)
{
if(error)
{
NSLog(#"%s:: %#", __PRETTY_FUNCTION__, error.localizedDescription);
return;
}
else if(match != nil)
{
_pMatch= match;
match.delegate = self;
NSLog(#"players count= %lu", (unsigned long)_pMatch.players.count); // Always returns 0
}
}];
}
}
I have delegate methods for GKLocalPlayerListener setup, but they are never called:
- (void)player:(GKPlayer *)player didRequestMatchWithRecipients:(NSArray<GKPlayer *> *)recipientPlayers
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
Does anyone know how to get this to work without GKMatchmakerViewController and for iOS9? The only examples I can find have the deprecated -inviteHandler method.
This code is working in Swift if you know how you can convert it to Objective-C and to try it.
GKMatchmaker.sharedMatchmaker().findMatchForRequest(
request,
withCompletionHandler: {(match : GKMatch!, error: NSError!) -> Void in
NSLog("This works")
})
Based on multiple questions here on SO, Game Center seems to be getting stuck from time to time. In the best case, it returns "Game not recognized" errors. In the worst case, it just cheerfully returns nil to GC calls. Sometimes it resumes working on it's own, sometimes it doesn't. But it seems you can kickstart it again by logging into iTunesConnect and do any of the following:
Add a leaderboard
Change the default leaderboard
Add an achievement
I've added this to my debugging routine. If some aspect of GC stops working, or returns nil, I try making one of the above changes in iTunesConnect before proceeding. In my case, I get the "game not recognized" several times per week, but several others have noted the "nil return values."
I know this an older post, but I ran across it when trying to establish a connection between several app instances over the internet. I believe the part you're missing is that after registering for the listener, you need to receive the connected status with
- (void)match:(GKMatch *)match
player:(GKPlayer *)player
didChangeConnectionState:(GKPlayerConnectionState)state
{
NSLog(#">>> did change state");
if (state == GKPlayerStateConnected)
{
NSLog(#">>>> match:%# did change to Connected for player %# ",match, player.displayName);
}
else if (state == GKPlayerStateDisconnected)
{
NSLog(#">>>> match:%# disconnected for player %# ",match, player.displayName);
}
I find the match has 0 players when the completionHandler is called from findMatchForRequest:, but that I can successfully use the GKMatch and GKPlayer as returned in didChangeConnectionState:
Hope that helps someone who reads this long after the OP.
I've sent scores to the leaderboard with different test accounts but when I try to see the leaderboard I can only see the score from the account that I'm logged in.
I used this code to send the scores :
- (void)reportScore:(int64_t)score forLeaderboardID:(NSString*)identifier
{
GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier: #"GHS"];
scoreReporter.value = score;
scoreReporter.context = 0;
[GKScore reportScores:#[scoreReporter] withCompletionHandler:^(NSError *error) {
if (error == nil) {
NSLog(#"Score reported successfully!");
} else {
NSLog(#"Unable to report score!");
}
}];
}
This is the code I'm using to show the leaderboard:
- (void)showLeaderboardOnViewController:(UIViewController*)viewController
{
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil) {
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterController.leaderboardIdentifier = _leaderboardIdentifier;
[viewController presentViewController: gameCenterController animated: YES completion:nil];
}
}
Maybe it's because it is sandboxed and stuff? is this normal maybe?
Thanks
I've had this issue before and after much searching it seems to be an error with sandbox accounts. I split my table into highest of all time, highest today and highest friend and in each case other higher scores from my other sandbox accounts were ignored. When I added another one of my accounts as a friend, they started sharing scores just fine.
I used code more or less identical to your own and submitted to the App Store where it was accepted, now it works fine with live accounts.
Using the sandboxed Gamecenter.
No matter what I do the scores never appear in a leaderboard.
I am using the following code:
- (void)scoreReported: (NSError*) error {
NSLog(#"%#",[error localizedDescription]);
}
- (void)submitScore{
if(self.currentScore > 0)
{
NSLog(#"Score: %lli submitted to leaderboard %#", self.currentScore, self.currentLeaderBoard);
[gameCenterManager reportScore: self.currentScore forCategory: self.currentLeaderBoard];
}
}
And scoreReported doesnt produce an error, yet the score doesnt appear in the leaderboard. I know the category is correct as I use currentLeaderBoard in:
- (void)showLeaderboard {
NSLog(#"leaderboard = %#", self.currentLeaderBoard);
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != NULL)
{
leaderboardController.category = self.currentLeaderBoard;
//leaderboardController.category = nil;
leaderboardController.timeScope = GKLeaderboardTimeScopeWeek;
leaderboardController.leaderboardDelegate = self;
[self presentModalViewController: leaderboardController animated: YES];
}
}
I have tried the usual
2 different sandbox GC accounts to get the leaderboard working
Even tried 4 different GC accounts each logging in on both the simulator (iOS 6.1) and device (iOS 6.0.1)
Yet still no joy
any suggestions - or is it just that the sandboxed gamecenter is far too buggy!!! (I would raise a bug about sandbox but the apple bug reporting form has a bug in it so that doesnt work either)
Score reporting to Game Center works almost immediately for me, even in sandbox mode.
Here are the few things you can try
Make sure the the Leaderboard identifiers are correct when reporting scores (Should exactly match with "Leaderboard ID"s in iTunesConnect)
Try Deleting the test data under "Manage Game Center" section of iTunesConnect
Delete the application, launch "Game Center" application in your device and goto "Games" tab and remove your app. Reinstall the app and try reporting the score again.
Make sure [gkScore reportScoreWithCompletionHandler:^(NSError *error) doesn't return any error
For those who want to know this what I changed my submitScore method to:
- (void)submitScore {
GKScore * GCscore = [[GKScore alloc] initWithCategory:self.currentLeaderBoard];
GCscore.value = [[NSUserDefaults standardUserDefaults] integerForKey:#"NEWSCORE"];
[GCscore reportScoreWithCompletionHandler:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (error == NULL) {
NSLog(#"Score Sent");
} else {
NSLog(#"Score Failed, %#",[error localizedDescription]);
}
});
}];
}
and it worked
I'm in sandbox mode implementing game center in my application. The problem comes when I log to gameCenter, in some devices works fine in some others I get a GKErrorCanceled without even get the interface shown.
This devices don't have any user logged in gameCenter so it's not related to have a non sandbox account logged. My code is:
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
//First we try the new iOS6 authentification method for gamekit, if it's not implemented we will use the deprecated one
if ([localPlayer respondsToSelector:#selector(setAuthenticateHandler:)]) {
if (localPlayer.isAuthenticated) {
this->setState(connectionLoged);
this->getDelegate().socialConnectionDidSucceedLogin(*this);
return;
}
else if(!localPlayer.isAuthenticated && localPlayer.authenticateHandler){
this->setState(connectionClosed);
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string("The user already resign to login"));
return;
}
else{
localPlayer.authenticateHandler = ^(UIViewController* viewController, NSError* error){
if (localPlayer.isAuthenticated)
{
_name = [localPlayer.displayName UTF8String];
_userId = [localPlayer.playerID UTF8String];
[GKPlayer loadPlayersForIdentifiers:localPlayer.friends withCompletionHandler:^(NSArray *players, NSError *error) {
for (GKPlayer* player in players) {
if ([player isFriend]) {
NSDictionary* dict =
#{#"displayName" : player.displayName,
#"alias" : player.alias,
#"playerID" : player.playerID};
AttrDictionary* playerInfo = [dict hydraAttrDictionary];
SocialFriend* socialfriend = this->getNewFriendInstance(*playerInfo);
this->addFriend(socialfriend);
delete playerInfo;
}
}
this->getDelegate().socialConnectionDidSucceedLogin(*this);
this->setState(connectionLoged);
}];
}
else if(viewController){
UIViewController* rootViewController = (UIViewController*) [UIApplication sharedApplication].keyWindow.rootViewController ;
[rootViewController presentModalViewController:viewController animated:YES];
}
else{
if(error){
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string([error.description UTF8String]));
}
else{
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string("User cancelled login"));
}
}
};
}
}
//deprecated at IOs 6 authentification method
else
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated)
{
_name = [localPlayer.displayName UTF8String];
_userId = [localPlayer.playerID UTF8String];
[GKPlayer loadPlayersForIdentifiers:localPlayer.friends withCompletionHandler:^(NSArray *players, NSError *error) {
for (GKPlayer* player in players) {
if ([player isFriend]) {
NSDictionary* dict =
#{#"displayName" : player.displayName,
#"alias" : player.alias,
#"playerID" : player.playerID};
AttrDictionary* playerInfo = [dict hydraAttrDictionary];
SocialFriend* socialfriend = this->getNewFriendInstance(*playerInfo);
this->addFriend(socialfriend);
delete playerInfo;
}
}
this->getDelegate().socialConnectionDidSucceedLogin(*this);
this->setState(connectionLoged);
}];
}
else{
NSString* errorString = [error localizedDescription];
this->getDelegate().socialConnectionDidFailToLogin(*this, std::string([errorString UTF8String]));
this->setState(connectionClosed);
}
}];
I need the code compatible with iOS 6 and iOS 5 so you will see I have the two implementations. For iOS 6 the completion handler returns with an UIViewController null and the error as I say. I'm afraid that in production it happends the same. In the simulator all works fine.
PS- You will find some c++ code, it's because I implement a c++ wrapper for GameCenter as my game is write in cocos2dx...
When someone cancels out of the interface to sign in to game center, it will give you GKErrorCanceled. The third time in a row that they cancel, it will warn them that it will disable game center.
If they do choose to disable game center, then it won't show the interface anymore, and it will just give you GKErrorCanceled instead.
Once game center has been disabled, the only way to sign in is by going into the actual game center app.
The 3 times in a row could be in any app or any combination of apps that use game center, and game center will be disabled for all apps that use game center. The 3 times in a row restarts every time they sign in to game center.
This is for both sandbox and non-sandbox.
This is for both ios 5 and ios 6.
How can I implement & test a multiplayer (turn-based) game using GameKit? Here are the problems I'm facing:
There are no other matches connected to the sandbox, so I don't get any callbacks from macth finder.
Xcode allows only 1 instance of the simulator to run, so how can I have 2 clients connected?
Some suggestions would be great on testing multiplayer GameKit based games.
EDIT:
I have an instance of the app running on device. another on simulator, and I still can't find a match.
// I call this code on both clients after authentication is successful
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error)
{
// Process the error.
NSLog(#"error");
}
else if (match != nil)
{
self.myMatch = match;
match.delegate = self;
if (!self.matchStarted && match.expectedPlayerCount == 0)
{
self.matchStarted = YES;
}
}
}];
You need two devices for testing because the simulator doesn't get any callbacks. Also, if you use auto-match give the Game Center servers a few minutes to update before you search for an auto-match game on the second devices.