ios - redes - No puedo recibir invitaciones del centro de juegos
informacion mediatica (2)
Ok, parece que funciona de nuevo sin ningún cambio en nuestro código o configuración de red. Abrí el boleto para el soporte de Apple, los registros de errores, etc. ... y parece que algunos de ellos funcionaron ...
Ahora entendemos que fue un error en la zona de pruebas de Game Center. Por lo que veo, la versión de sanbox del centro de juegos no es tan estable y la gente de Apple no presta suficiente atención a este servicio. Tampoco hay forma de verificar el estado del sistema en internet.
Todavía sigo debatiendo con el soporte de Apple para comprender el motivo y compartiré toda la conversación aquí cuando esté completa.
Feliz codificación ...
Estoy intentando desarrollar un juego multijugador en tiempo real para IOS utilizando cocos2d utilizando el tutorial en http://www.raywenderlich.com/3325/how-to-make-a-simple-multiplayer-game-with-game-center -tutorial-part-22
Todo funciona bien, incluida la coincidencia automática con un reproductor aleatorio, pero invitar a un amigo no funciona porque otros dispositivos no pueden recibir una invitación.
Cuando hice clic en el botón invitar amigos y luego seleccioné a un amigo usando la interfaz estándar del centro de juegos, dice esperar (para siempre) y no pasa nada. Mi amigo no puede recibir una invitación del centro de juegos (sin notificaciones).
Puedo invitar a un amigo mediante el uso de la funcionalidad de amigos cercanos (cuando esta funcionalidad está habilitada en ambos dispositivos) pero sin notificación de invitación cuando los amigos cercanos están deshabilitados.
Pasé horas y horas buscando en Google, encontré casos similares pero no encontré ninguna solución.
Algunos comentarios tempranos sobre posibles respuestas:
- Uso dos dispositivos (un iPhone y un iPad), sin simulador
- Todas las configuraciones en iTunes Connect están bien, incluida la configuración de multijugador
- Validé que ambos dispositivos están conectados a Sandbox mediante el uso de diferentes cuentas de prueba
- Ya he comprobado las configuraciones de notificación para Game Center en ambos dispositivos
- Ya revisé todos los problemas de proxy / firewall e intenté con WiFi y Cellular para ambos dispositivos
- Las invitaciones a juegos están habilitadas para ambos dispositivos / cuentas
- Ya revisé las ID del paquete, las ID de la versión de la aplicación, etc.
- Ambos dispositivos son iOS 6.x y la versión de destino de la aplicación OS IOS 5.0
- No tengo otros problemas sobre el centro de juego (tablas de clasificación, emparejamiento aleatorio, etc ... todo bien)
- Llamo al método inviteHandler tan pronto después de autenticar a un usuario como sea posible, como se menciona en la documentación de Apple.
Aquí está mi archivo de encabezado de la clase de ayudante del centro de juegos:
#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>
@protocol GCHelperDelegate
- (void)matchStarted;
- (void)matchEnded;
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data
fromPlayer:(NSString *)playerID;
- (void)inviteReceived;
@end
@interface GCHelper : NSObject <GKMatchmakerViewControllerDelegate, GKMatchDelegate>{
BOOL gameCenterAvailable;
BOOL userAuthenticated;
UIViewController *presentingViewController;
GKMatch *match;
BOOL matchStarted;
id <GCHelperDelegate> delegate;
NSMutableDictionary *playersDict;
GKInvite *pendingInvite;
NSArray *pendingPlayersToInvite;
NSMutableArray *unsentScores;
}
@property (retain) GKInvite *pendingInvite;
@property (retain) NSArray *pendingPlayersToInvite;
@property (assign, readonly) BOOL gameCenterAvailable;
@property (retain) NSMutableDictionary *playersDict;
@property (retain) UIViewController *presentingViewController;
@property (retain) GKMatch *match;
@property (assign) id <GCHelperDelegate> delegate;
- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers
viewController:(UIViewController *)viewController
delegate:(id<GCHelperDelegate>)theDelegate;
- (BOOL) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent;
+ (GCHelper *)sharedInstance;
- (void)authenticateLocalUser;
@end
Y aquí está la implementación de la clase de ayuda del centro de juegos
#import "GCHelper.h"
@implementation GCHelper
@synthesize gameCenterAvailable;
@synthesize presentingViewController;
@synthesize match;
@synthesize delegate;
@synthesize playersDict;
@synthesize pendingInvite;
@synthesize pendingPlayersToInvite;
#pragma mark Initialization
static GCHelper *sharedHelper = nil;
+ (GCHelper *) sharedInstance {
if (!sharedHelper) {
sharedHelper = [[GCHelper alloc] init];
}
return sharedHelper;
}
- (BOOL)isGameCenterAvailable {
// check for presence of GKLocalPlayer API
Class gcClass = (NSClassFromString(@"GKLocalPlayer"));
// check if the device is running iOS 4.1 or later
NSString *reqSysVer = @"4.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer
options:NSNumericSearch] != NSOrderedAscending);
return (gcClass && osVersionSupported);
}
- (id)init {
if ((self = [super init])) {
gameCenterAvailable = [self isGameCenterAvailable];
if (gameCenterAvailable) {
NSNotificationCenter *nc =
[NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:@selector(authenticationChanged)
name:GKPlayerAuthenticationDidChangeNotificationName
object:nil];
}
}
return self;
}
- (void)authenticationChanged {
if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) {
NSLog(@"Authentication changed: player authenticated.");
userAuthenticated = TRUE;
[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
NSLog(@"Received invite");
self.pendingInvite = acceptedInvite;
self.pendingPlayersToInvite = playersToInvite;
[delegate inviteReceived];
};
} else if (![GKLocalPlayer localPlayer].isAuthenticated && userAuthenticated) {
NSLog(@"Authentication changed: player not authenticated");
userAuthenticated = FALSE;
}
}
- (void)lookupPlayers {
NSLog(@"Looking up %d players...", match.playerIDs.count);
[GKPlayer loadPlayersForIdentifiers:match.playerIDs withCompletionHandler:^(NSArray *players, NSError *error) {
if (error != nil) {
NSLog(@"Error retrieving player info: %@", error.localizedDescription);
matchStarted = NO;
[delegate matchEnded];
} else {
// Populate players dict
self.playersDict = [NSMutableDictionary dictionaryWithCapacity:players.count];
for (GKPlayer *player in players) {
NSLog(@"Found player: %@", player.alias);
[playersDict setObject:player forKey:player.playerID];
}
// Notify delegate match can begin
matchStarted = YES;
[delegate matchStarted];
}
}];
}
#pragma mark User functions
- (void)authenticateLocalUser {
if (!gameCenterAvailable) return;
NSLog(@"Authenticating local user...");
if ([GKLocalPlayer localPlayer].authenticated == NO) {
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:nil];
} else {
NSLog(@"Already authenticated!");
}
}
- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers viewController:(UIViewController *)viewController delegate:(id<GCHelperDelegate>)theDelegate {
if (!gameCenterAvailable) return;
matchStarted = NO;
self.match = nil;
self.presentingViewController = viewController;
delegate = theDelegate;
if (pendingInvite != nil) {
[presentingViewController dismissModalViewControllerAnimated:NO];
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:pendingInvite] autorelease];
mmvc.matchmakerDelegate = self;
[presentingViewController presentModalViewController:mmvc animated:YES];
self.pendingInvite = nil;
self.pendingPlayersToInvite = nil;
} else {
[presentingViewController dismissModalViewControllerAnimated:NO];
GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
request.minPlayers = minPlayers;
request.maxPlayers = maxPlayers;
request.playersToInvite = pendingPlayersToInvite;
GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
mmvc.matchmakerDelegate = self;
[presentingViewController presentModalViewController:mmvc animated:YES];
self.pendingInvite = nil;
self.pendingPlayersToInvite = nil;
}
}
#pragma mark GKMatchmakerViewControllerDelegate
// The user has cancelled matchmaking
- (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController {
[presentingViewController dismissModalViewControllerAnimated:YES];
}
// Matchmaking has failed with an error
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error {
[presentingViewController dismissModalViewControllerAnimated:YES];
NSLog(@"Error finding match: %@", error.localizedDescription);
}
// A peer-to-peer match has been found, the game should start
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)theMatch {
[presentingViewController dismissModalViewControllerAnimated:YES];
self.match = theMatch;
match.delegate = self;
if (!matchStarted && match.expectedPlayerCount == 0) {
NSLog(@"Ready to start match!");
[self lookupPlayers];
}
}
#pragma mark GKMatchDelegate
// The match received data sent from the player.
- (void)match:(GKMatch *)theMatch didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
if (match != theMatch) return;
[delegate match:theMatch didReceiveData:data fromPlayer:playerID];
}
// The player state changed (eg. connected or disconnected)
- (void)match:(GKMatch *)theMatch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state {
if (match != theMatch) return;
switch (state) {
case GKPlayerStateConnected:
// handle a new player connection.
NSLog(@"Player connected!");
if (!matchStarted && theMatch.expectedPlayerCount == 0) {
NSLog(@"Ready to start match!");
[self lookupPlayers];
}
break;
case GKPlayerStateDisconnected:
// a player just disconnected.
NSLog(@"Player disconnected!");
matchStarted = NO;
[delegate matchEnded];
break;
}
}
// The match was unable to connect with the player due to an error.
- (void)match:(GKMatch *)theMatch connectionWithPlayerFailed:(NSString *)playerID withError:(NSError *)error {
if (match != theMatch) return;
NSLog(@"Failed to connect to player with error: %@", error.localizedDescription);
matchStarted = NO;
[delegate matchEnded];
}
// The match was unable to be established with any players due to an error.
- (void)match:(GKMatch *)theMatch didFailWithError:(NSError *)error {
if (match != theMatch) return;
NSLog(@"Match failed with error: %@", error.localizedDescription);
matchStarted = NO;
[delegate matchEnded];
}
- (void)reportScore:(int64_t)score forCategory:(NSString *)category {
// Only execute if OS supports Game Center & player is logged in
if ([self isGameCenterAvailable] && [GKLocalPlayer localPlayer].authenticated == YES)
{
// Create score object
GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
// Set the score value
scoreReporter.value = score;
// Try to send
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil)
{
// Handle reporting error here by adding object to a serializable array, to be sent again later
[unsentScores addObject:scoreReporter];
}
}];
}
}
- (BOOL) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent {
if ([self isGameCenterAvailable] && [GKLocalPlayer localPlayer].authenticated == YES)
{
GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
if (achievement)
{
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
// Retain the achievement object and try again later (not shown).
}
}];
}
return YES;
}
return NO;
}
@end
Y finalmente, así es como llamo al centro de juegos desde mi capa de juego (probé dos opciones diferentes pero ninguna de ellas funcionó)
Opción 1
[[GCHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2 viewController: [[[UIApplication sharedApplication] keyWindow] rootViewController] delegate: self];
opcion 2
AppController *app = (AppController*) [[UIApplication sharedApplication] delegate];
UINavigationController *viewController = [app navController];
[[GCHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2 viewController:viewController delegate:self];
Cualquier ayuda será apreciada. Gracias por adelantado...
He estado lidiando con el modo multijugador durante unos meses y las invitaciones han sido un verdadero problema para mí ... y como tú, utilicé el tutorial de Ray para comenzar. Me di cuenta hoy que el código de Ray tiene un error en el que las invitaciones no funcionarán si ambos clientes tienen el GKMatchmakerView arriba. Debes descartarlo cuando recibas la invitación por primera vez con algo como:
[gcdelegate.viewController dismissViewControllerAnimated:YES
completion:^{
GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:pendingInvite];
mmvc.matchmakerDelegate = self;
[gcdelegate.viewController presentModalViewController:mmvc animated:YES];
self.pendingInvite = nil;
self.pendingPlayersToInvite = nil;
boo_invite=true;
}];