├── .gitignore ├── .travis.yml ├── Changelog.md ├── GC Manager ├── GCMConstants.h ├── GCMMultiplayer.h ├── GCMMultiplayer.m ├── GameCenterManager Mac-Bridging-Header.h ├── GameCenterManager-Bridging-Header.h ├── GameCenterManager.h ├── GameCenterManager.m ├── Multiplayer.swift ├── NSDataAES256.h ├── NSDataAES256.m ├── Reachability.h ├── Reachability.m └── Referee.swift ├── GameCenterManager Mac ├── GameCenterManager Mac-Info.plist ├── GameCenterManager Mac-Prefix.pch ├── GameCenterManager Mac.entitlements ├── MacViewController.h ├── MacViewController.m ├── Storyboard.storyboard ├── en.lproj │ ├── Credits.rtf │ └── InfoPlist.strings └── main.m ├── GameCenterManager tvOS ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ └── Storyboard_tvOS.storyboard ├── GameCenterManager-Prefix.pch ├── Info.plist ├── ViewController.h ├── ViewController.m ├── main.m └── tvOSImages.xcassets │ ├── Brand Assets.brandassets │ ├── App Icon - Large.imagestack │ │ ├── Back.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── GCMLargeIconBottom.png │ │ │ └── Contents.json │ │ ├── Brackets.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── GCMLargeIconBrackets.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Front.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── GCMLargeIconTop.png │ │ │ └── Contents.json │ │ └── Middle.imagestacklayer │ │ │ ├── Content.imageset │ │ │ ├── Contents.json │ │ │ └── GCMLargeIconMiddle.png │ │ │ └── Contents.json │ ├── App Icon - Small.imagestack │ │ ├── Back.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── GCMSmallIconBottom.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Front.imagestacklayer │ │ │ ├── Content.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── GCMSmallIconTop.png │ │ │ └── Contents.json │ │ └── Middle.imagestacklayer │ │ │ ├── Content.imageset │ │ │ ├── Contents.json │ │ │ └── GCMSmallIconMiddle.png │ │ │ └── Contents.json │ ├── Contents.json │ └── Top Shelf Image.imageset │ │ ├── Contents.json │ │ └── LaunchImage.png │ ├── Contents.json │ ├── LaunchImage.launchimage │ ├── Contents.json │ └── LaunchImage.png │ └── Leaderboard.gcleaderboard │ ├── Contents.json │ └── Poster.imagestack │ ├── Back.imagestacklayer │ ├── Content.imageset │ │ ├── Contents.json │ │ └── PosterBack.png │ └── Contents.json │ ├── Contents.json │ ├── Front.imagestacklayer │ ├── Content.imageset │ │ ├── Contents.json │ │ └── PosterFront.png │ └── Contents.json │ └── Middle.imagestacklayer │ ├── Content.imageset │ └── Contents.json │ └── Contents.json ├── GameCenterManager.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── GameCenterManager.xccheckout │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── Spencers.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings │ │ ├── nihalahmed.xcuserdatad │ │ └── WorkspaceSettings.xcsettings │ │ └── samspencer.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ ├── Spencers.xcuserdatad │ ├── xcdebugger │ │ ├── Breakpoints.xcbkptlist │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── GameCenterManager Mac.xcscheme │ │ ├── GameCenterManager.xcscheme │ │ └── xcschememanagement.plist │ ├── nihalahmed.xcuserdatad │ └── xcschemes │ │ ├── GameCenterManager.xcscheme │ │ └── xcschememanagement.plist │ └── samspencer.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── GameCenterManager Mac.xcscheme │ ├── GameCenterManager.xcscheme │ └── xcschememanagement.plist ├── GameCenterManager ├── AppDelegate.h ├── AppDelegate.m ├── GameCenterManager-Info.plist ├── GameCenterManager-Prefix.pch ├── ViewController.h ├── ViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── Storyboard_iPhone.storyboard └── main.m ├── Images.xcassets ├── AppIcon.appiconset │ ├── AppIcon29x29.png │ ├── AppIcon29x29@2x.png │ ├── AppIcon40x40@2x.png │ ├── AppIcon60x60@2x.png │ ├── Contents.json │ ├── Icon.png │ └── Icon@2x.png ├── Contents.json ├── GCSymbol.imageset │ ├── Contents.json │ ├── GK Icon-512.png │ └── GK Icon-512@2x.png ├── LaunchImage.launchimage │ ├── Contents.json │ ├── Default-568h@2x.png │ ├── Default.png │ ├── Default@2x-1.png │ └── Default@2x.png └── MacAppIcon.appiconset │ ├── Contents.json │ ├── GK Icon-128.png │ ├── GK Icon-128@2x.png │ ├── GK Icon-16.png │ ├── GK Icon-16@2x.png │ ├── GK Icon-256.png │ ├── GK Icon-256@2x.png │ ├── GK Icon-32.png │ ├── GK Icon-32@2x.png │ ├── GK Icon-512.png │ └── GK Icon-512@2x.png ├── Images ├── GameBanner.png ├── GameBanner.psd ├── Interface.png └── Interface.psd ├── License.md ├── README.md └── travis ├── ios └── build.sh └── osx └── build.sh /.gitignore: -------------------------------------------------------------------------------- 1 | GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata 2 | GameCenterManager.xcodeproj/xcuserdata 3 | 4 | *.xcuserstate 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: objective-c 3 | compiler: clang 4 | osx_image: xcode7.2 5 | sudo: truev 6 | matrix: 7 | include: 8 | - os: osx 9 | compiler: clang 10 | env: TARGET="osx" 11 | - os: osx 12 | compiler: clang 13 | env: TARGET="ios" 14 | script: 15 | - travis/$TARGET/build.sh 16 | git: 17 | depth: 10 18 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | #Changelog 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 20 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 60 | 61 |
Version 5.3
Updated GameCenterManager for iOS 7 and OS X 10.9 Improved Singleton. New features and enhancements.
7 |
    8 |
  • Added compiler checks for ARC, iOS 7, and OS X Mavericks 10.9.
  • 9 |
  • Deprecated initGameCenter. Use setupManagerAndSetShouldCryptWithKey: or setupManager instead.
  • 10 |
  • Encryption of local data is no longer required. Use the new setup methods to define encrytion parameters, or to turn it OFF.
  • 11 |
  • Improved Singleton - Removed nil object creation and replaced allocWithZone: with alloc. Improved private init method.
  • 12 |
  • Added three new methods for presenting GameKit ViewControllers
  • 13 |
  • New properties to handle encryption.
  • 14 |
  • Improved sample apps
  • 15 |
16 |
Version 5.2
Consolidated the GameCenterManager for iOS and OS X classes into one class. Improved Singleton. 64-bit compatible. Bug fixes and enhancements. Documentation improvements.
21 |
    22 |
  • Combined the GameCenterManager classes for Mac and iOS and combined them into one single class.
  • 23 |
  • Deprecated delegate methods with new (better) names and parameters. Now some delegates pass actual GKScore and GKAchievement objects instead of NSDictionaries with those objects.
  • 24 |
  • Moved project files around for better organization.
  • 25 |
  • Improved Singleton - now uses GCD dispatch once to properly setup. Improved setup.
  • 26 |
  • 64-bit compatible - added arm64 architecture to the build settings and updated the encryption files for 64-bit
  • 27 |
  • Documentation improvements - added more extensive documentation for all methods and properties. Now documentation can be viewed with Xcode 5.0's built-in documentation viewer / Quick Help features.
  • 28 |
  • Bug fixes and enhancements
  • 29 |
  • New properties
  • 30 |
31 |
Version 5.1
This update adds support for iOS 7, makes improvements to the iOS & Mac OS X demo apps, fixes bugs with error reporting, improves player data methods, and makes some breaking changes to resetting achievements.
36 |
    37 |
  • Major improvements to the demo apps including new UI and Icons
  • 38 |
  • Limited iOS 7 support. The project runs on iOS 7, but the classes are not fully optimized for iOS 7. A new branch will be created soon which has specific iOS 7 changes.
  • 39 |
  • Fixed a bug where checking for GameCenter availability would return NO, but wouldn't deliver an error message.
  • 40 |
  • Deprecated gameCenterManager:resetAchievements: delegate method in favor of a completion handler now available on the resetAchievements: method. The gameCenterManager:resetAchievements: delegate method is no longer called
  • 41 |
  • Fixed a bug where resetting achievements may not work
  • 42 |
  • Cleaned code, minor improvements to code
  • 43 |
44 |
Version 5.0
This update adds support for Game Center on Mac OS X and makes improvements to the iOS demo app. Improvements have also been made to error reporting, challenges, and player data.
49 |
    50 |
  • Adds support for Mac OS X. Use the GameCenterManager Mac folder to access resources for the OS X compatible version of GameCenterManager. This also includes an OS X demo app that works with the iOS demo app.
  • 51 |
  • Improved Game Center Error Reporting. The gameCenterManager: error: delegate method now passes an NSError as the error parameter instead of an NSDictionary. New GCMError constants are provided as error codes in each error.
  • 52 |
  • Makes improvements to thread management and background tasks - heavy background tasks like syncing to GameCenter (which involve networking, encryption, and file system management) are performed on the background thread and will continue to finish the process even after the user exits the app.
  • 53 |
  • Fixed bug where the getChallenges method would always return nil. The getChallenges: method no longer returns a value - instead it uses a completion handler and delegate methods.
  • 54 |
  • Added a new method to retrieve a player's profile picture, localPlayerPhoto:(void (^)(UIImage *playerPhoto))handler
  • 55 |
  • Fixed bug where achievements may not sync, esp. after resetting achievements.
  • 56 |
  • Reorganized code
  • 57 |
58 | Known Issues
Resetting achievements causes them to reset on Game Center, but the cache remains locally. This cahce eventually causes all achievement data to be uploaded to Game Center. 59 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 93 | 94 |
Version 4.4
Fixed issue where new GKLeaderboard object's category property was being set to the saved GKLeaderboard object. Pull Request from michaelpatzer
Version 4.3
Added support for Game Center Leaderboard score orders. When submitting scores you can now set the score order from High to Low or Low to High using new Game Center types: GameCenterSortOrderHighToLow, GameCenterSortOrderLowToHigh. Pull Request from michaelpatzer
Version 4.2
Fixed issue where GameCenter Manager would fail to handle authentication after calling the authenticateHandler. Pull Request by Jonathan Swafford
Version 4.1
Fixed issue where GameCenter Manager would fail to report achievements and scores even if Game Center was available.
Version 4.0
This update makes massive improvements to the flow and performance of code, updates Objective-C compiler and build settings, redesigns the demo app, and adds three new methods and eight new delegate methods.
83 |
    84 |
  • Removed NSNotifications and replaced with delegate methods. This makes integration with current projects easier and faster; it is also more reliable. See the Delegates section of this document for more.
  • 85 |
  • Improved Game Center Availability Checking and Error Reporting. Now check for the availablity of Game Center with the checkGameCenterAvailability method.
  • 86 |
  • Makes improvements to thread switching - now UI tasks are performed on the main thread. Previously they were performed on a background thread for Game Center.
  • 87 |
  • In depth error reporting for Game Center errors and availability issues.
  • 88 |
  • The demo app has undergone massive improvements, including many interface improvements. To eliminate redundancy, the iPad part of the Demo App has been removed - GameCenter Manager still works with iPad though.
  • 89 |
  • Code cleanup and reorganization to make it easier on the eyes.
  • 90 |
  • Upgrades ARMV6 assembler codegen from THUMB to ARM
  • 91 |
      92 |
95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |
Version 3.1
Improved error reporting and reorganized files to remove duplicates. Added a way to retrieve challenges. Converted old demo app files to support iOS 5+ - now using storyboards intead of XIB.
Version 3.0
Added ARC compatibility. All files are now ready to be used with ARC. Many methods have been updated that were depreciated in iOS 6.0. The demo app has undergone massive improvements, including many interface improvements, iPhone 5 support, a new icon, and better GC status reporting.
Version 2.3
Fixed leaderboard synchronization bug where it would crash if user didn't submit a score previously.
Version 2.2
Fixed leaderboard synchronization bug where it would only sync the default leaderboard.
Version 2.1
Fixed NSNotification Bug
Version 2.0
Added encryption, fixed synchronization bug and added comments and readme
Version 1.0
Initial Commit
127 | -------------------------------------------------------------------------------- /GC Manager/GCMConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCMConstants.h 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 11/23/15. 6 | // Copyright © 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | #ifndef GCMConstants_h 10 | #define GCMConstants_h 11 | 12 | #if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 13 | #define GCM_FINAL __attribute__((objc_subclassing_restricted)) 14 | #else 15 | #define GCM_FINAL 16 | #endif 17 | 18 | 19 | /// Leaderboard sort order. Use this value when submitting new leaderboard scores. This value should match the value set in iTunes Connect for the speicifed leaderboard. 20 | typedef enum GameCenterSortOrder { 21 | /// Scores are sorted highest to lowest. Higher scores are on the top of the leaderboard 22 | GameCenterSortOrderHighToLow, 23 | /// Scores are sorted lowest to highest. Lower scores are on the top of the leaderboard 24 | GameCenterSortOrderLowToHigh 25 | } GameCenterSortOrder; 26 | 27 | enum { 28 | /// An unknown error occurred 29 | GCMErrorUnknown = 1, 30 | /// GameCenterManager is unavailable, possibly for a variety of reasons 31 | GCMErrorNotAvailable = 2, 32 | /// The requested feature is unavailable on the current device or iOS version 33 | GCMErrorFeatureNotAvailable = 3, 34 | /// There is no active internet connection for the requested operation 35 | GCMErrorInternetNotAvailable = 4, 36 | /// The achievement data submitted was not valid because there were missing parameters 37 | GCMErrorAchievementDataMissing = 5, 38 | /// The multiplayer data could not be sent with the specified connection type because it was too large 39 | GCMErrorMultiplayerDataPacketTooLarge = 6 40 | }; 41 | /// GameCenterManager error codes that may be passed in a completion handler's error parameter 42 | typedef NSInteger GCMErrorCode; 43 | 44 | /// GameCenter availability status. Use these statuss to identify the state of GameCenter's availability. 45 | typedef enum GameCenterAvailability { 46 | /// GameKit Framework not available on this device 47 | GameCenterAvailabilityNotAvailable, 48 | /// Cannot connect to the internet 49 | GameCenterAvailabilityNoInternet, 50 | /// Player is not yet signed into GameCenter 51 | GameCenterAvailabilityNoPlayer, 52 | /// Player is not signed into GameCenter, has declined to sign into GameCenter, or GameKit had an issue validating this game / app 53 | GameCenterAvailabilityPlayerNotAuthenticated, 54 | /// Player is signed into GameCenter 55 | GameCenterAvailabilityPlayerAuthenticated 56 | } GameCenterAvailability; 57 | 58 | #endif /* GCMConstants_h */ 59 | -------------------------------------------------------------------------------- /GC Manager/GCMMultiplayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // GCMMultiplayer.h 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 11/23/15. 6 | // Copyright © 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "GCMConstants.h" 13 | 14 | @protocol GameCenterMultiplayerManagerDelegate; 15 | 16 | GCM_FINAL @interface GCMMultiplayer : NSObject 17 | 18 | /// Returns the default instance of the multiplayer manager 19 | + (GCMMultiplayer *)defaultMultiplayerManager; 20 | 21 | /// GameCenterManager multiplayerDelegate property that should be used to set the delegate for multiplayer matches 22 | @property (nonatomic, weak) id multiplayerDelegate; 23 | 24 | /// Begin listening and responding to Game Center match requests / invites. This should be one of the first calls made to the GCMMultiplayer object. 25 | - (void)beginListeningForMatches; 26 | 27 | /// Finds and sets up a multiplayer match using the specified parameters and the default MatchmakerViewController 28 | - (void)findMatchWithMinimumPlayers:(int)minPlayers maximumPlayers:(int)maxPlayers onViewController:(UIViewController *)viewController; 29 | 30 | /// Finds and sets up a multiplayer match using a custom GKMatchRequest object - this allows for ultimate match flexibility (eg. player groups, invited players, player attributes, etc.) 31 | - (void)findMatchWithGKMatchRequest:(GKMatchRequest *)matchRequest onViewController:(UIViewController *)viewController; 32 | 33 | /** Sends data to \b all players in the current multiplayer match using the specified parameters 34 | 35 | @discussion Use this method to send data to all players in a match. If you do not need to send data to all players, instead use the alternate method which lets you specify players. 36 | 37 | Send messages at the lowest frequency that allows your game to function well. Your game’s graphics engine may be running at 30 to 60 frames per second, but your networking code can send updates much less frequently. 38 | 39 | Use the smallest message format that gets the job done. Messages that are sent frequently or messages that must be received quickly by other participants should be carefully scrutinized to ensure that no unnecessary data is being sent. 40 | 41 | Pack your data into the smallest representation you can without losing valuable information. For example, an integer in your program may use 32 or 64 bits to store its data. If the value stored in the integer is always in the range 1 through 10, you can store it in your network message in only 4 bits. 42 | 43 | Send messages only to the participants that need the information contained in the message. For example, if your game has two different teams, team-related messages should be sent only to the members of the same team. Sending data to all participants in the match uses up networking bandwidth for little gain. 44 | 45 | @param data The data to be sent to all of the players. This should not exceed 1000 bytes for quick sending, and should not exceed 87 kilobytes when sending reliably. 46 | @param sendQuickly Specify YES if the data should be sent without ensuring delivery (faster). NO if the data's delivery should be guaranteed (slower). 47 | @param handler Implement the completion handler to recieve information about the status of the data send. The error parameter may be nil if there was no error. */ 48 | - (BOOL)sendAllPlayersMatchData:(NSData *)data shouldSendQuickly:(BOOL)sendQuickly completion:(void (^)(BOOL success, NSError *error))handler; 49 | 50 | /** Sends data to the specified players in the current multiplayer match using the specified parameters 51 | 52 | @discussion Use this method to send data to all players in a match. If you do not need to send data to all players, instead use the alternate method which lets you specify players. 53 | 54 | Send messages at the lowest frequency that allows your game to function well. Your game’s graphics engine may be running at 30 to 60 frames per second, but your networking code can send updates much less frequently. 55 | 56 | Use the smallest message format that gets the job done. Messages that are sent frequently or messages that must be received quickly by other participants should be carefully scrutinized to ensure that no unnecessary data is being sent. 57 | 58 | Pack your data into the smallest representation you can without losing valuable information. For example, an integer in your program may use 32 or 64 bits to store its data. If the value stored in the integer is always in the range 1 through 10, you can store it in your network message in only 4 bits. 59 | 60 | Send messages only to the participants that need the information contained in the message. For example, if your game has two different teams, team-related messages should be sent only to the members of the same team. Sending data to all participants in the match uses up networking bandwidth for little gain. 61 | 62 | @param data The data to be sent to all of the players. This should not exceed 1000 bytes for quick sending, and should not exceed 87 kilobytes when sending reliably. 63 | @param players An array of GKPlayer objects to which the data should be sent (can be more efficient if you are not implementing a peer-to-peer connection, or don't need to send to all players). 64 | @param sendQuickly Specify YES if the data should be sent without ensuring delivery (faster). NO if the data's delivery should be guaranteed (slower). 65 | @param handler Implement the completion handler to recieve information about the status of the data send. The error parameter may be nil if there was no error. */ 66 | - (BOOL)sendMatchData:(NSData *)data toPlayers:(NSArray *)players shouldSendQuickly:(BOOL)sendQuickly completion:(void (^)(BOOL success, NSError *error))handler; 67 | 68 | /// Disconnects the current (local) player from the multiplayer match. The matchEnded: delegate method will be called after disconnecting, regardless of the number of players. 69 | - (void)disconnectLocalPlayerFromMatch; 70 | 71 | /// @b Readonly. Retrieve the current GKMatch object. May be nil if no match has been setup. 72 | @property (nonatomic, strong, readonly) GKMatch *multiplayerMatch; 73 | 74 | /// @b Readonly. Indicates whether or not the multiplayer match has started (if one has been created). 75 | @property (nonatomic, assign, readonly) BOOL multiplayerMatchStarted; 76 | 77 | @property (nonatomic, strong, readonly) UIViewController *matchPresentingController; 78 | 79 | @end 80 | 81 | /// GameCenterManager Multiplayer Delegate. Handles multiplayer connections, match data, and other aspects of live multiplayer matchs. 82 | @protocol GameCenterMultiplayerManagerDelegate 83 | 84 | 85 | @required 86 | 87 | /// Sent to the delegate when a live multiplayer match begins 88 | - (void)gameCenterManager:(GCMMultiplayer *)manager matchStarted:(GKMatch *)match; 89 | 90 | /// Sent to the delegate when a live multiplayer match ends 91 | - (void)gameCenterManager:(GCMMultiplayer *)manager matchEnded:(GKMatch *)match; 92 | 93 | /// Sent to the delegate when data is recieved on the current device (sent from another player in the match) 94 | - (void)gameCenterManager:(GCMMultiplayer *)manager match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID; 95 | 96 | 97 | @optional 98 | 99 | /// Sent to the delegate when all players are connected. Passes an array of players in the match to the delegate. 100 | - (void)gameCenterManager:(GCMMultiplayer *)manager match:(GKMatch *)match didConnectAllPlayers:(NSArray *)gkPlayerArray; 101 | 102 | /// Sent to the delegate when a player is disconnected. Passes the disconnected player to the delegate. 103 | - (void)gameCenterManager:(GCMMultiplayer *)manager match:(GKMatch *)match playerDidDisconnect:(GKPlayer *)player __OSX_AVAILABLE_STARTING(__OSX_10_9,__IPHONE_7_0); 104 | 105 | /// Sent to the delegate when a player recieves a match invitation. Use this opportunity to begin a match or setup the match request. 106 | - (void)gameCenterManager:(GCMMultiplayer *)manager match:(GKMatch *)match didRecieveMatchInvitationForPlayer:(GKPlayer *)invitedPlayer playersToInvite:(NSArray *)players; 107 | 108 | /// Sent to the delegate when a player accepts a match invitation. Use this opportunity to handle your match. 109 | - (void)gameCenterManager:(GCMMultiplayer *)manager match:(GKMatch *)match didAcceptMatchInvitation:(GKInvite *)invite player:(GKPlayer *)player; 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /GC Manager/GCMMultiplayer.m: -------------------------------------------------------------------------------- 1 | // 2 | // GCMMultiplayer.m 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 11/23/15. 6 | // Copyright © 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | #import "GCMMultiplayer.h" 10 | #import "GameCenterManager.h" 11 | 12 | @interface GCMMultiplayer () 13 | @property (nonatomic, strong, readwrite) GKMatch *multiplayerMatch; 14 | @property (nonatomic, assign, readwrite) BOOL multiplayerMatchStarted; 15 | @property (nonatomic, strong, readwrite) UIViewController *matchPresentingController; 16 | @end 17 | 18 | @implementation GCMMultiplayer 19 | 20 | #pragma mark - Object Lifecycle 21 | 22 | + (GCMMultiplayer *)defaultMultiplayerManager { 23 | static GCMMultiplayer *singleton; 24 | 25 | static dispatch_once_t onceToken; 26 | dispatch_once(&onceToken, ^{ 27 | singleton = [[self alloc] init]; 28 | }); 29 | 30 | return singleton; 31 | } 32 | 33 | - (void)beginListeningForMatches { 34 | // Register for GKInvites 35 | [[GKLocalPlayer localPlayer] registerListener:self]; 36 | } 37 | 38 | - (void)dealloc { 39 | [[GKLocalPlayer localPlayer] unregisterAllListeners]; 40 | } 41 | 42 | #pragma mark - Match Handling 43 | 44 | - (void)findMatchWithMinimumPlayers:(int)minPlayers maximumPlayers:(int)maxPlayers onViewController:(UIViewController *)viewController { 45 | if (![[GameCenterManager sharedManager] isGameCenterAvailable]) { 46 | NSError *error = [NSError errorWithDomain:[NSString stringWithFormat:@"GameCenter Unavailable"] code:GCMErrorNotAvailable userInfo:nil]; 47 | if ([[[GameCenterManager sharedManager] delegate] respondsToSelector:@selector(gameCenterManager:error:)]) 48 | [[[GameCenterManager sharedManager] delegate] gameCenterManager:[GameCenterManager sharedManager] error:error]; 49 | 50 | return; 51 | } 52 | 53 | self.multiplayerMatchStarted = NO; 54 | self.multiplayerMatch = nil; 55 | self.matchPresentingController = viewController; 56 | 57 | // [matchPresentingController dismissViewControllerAnimated:YES completion:nil]; 58 | 59 | GKMatchRequest *request = [[GKMatchRequest alloc] init]; 60 | request.minPlayers = minPlayers; 61 | request.maxPlayers = maxPlayers; 62 | 63 | GKMatchmakerViewController *matchViewController = [[GKMatchmakerViewController alloc] initWithMatchRequest:request]; 64 | matchViewController.matchmakerDelegate = self; 65 | 66 | [self.matchPresentingController presentViewController:matchViewController animated:YES completion:nil]; 67 | } 68 | 69 | - (void)findMatchWithGKMatchRequest:(GKMatchRequest *)matchRequest onViewController:(UIViewController *)viewController { 70 | if (![[GameCenterManager sharedManager] isGameCenterAvailable]) { 71 | NSError *error = [NSError errorWithDomain:[NSString stringWithFormat:@"GameCenter Unavailable"] code:GCMErrorNotAvailable userInfo:nil]; 72 | if ([[[GameCenterManager sharedManager] delegate] respondsToSelector:@selector(gameCenterManager:error:)]) 73 | [[[GameCenterManager sharedManager] delegate] gameCenterManager:[GameCenterManager sharedManager] error:error]; 74 | 75 | return; 76 | } 77 | 78 | self.multiplayerMatchStarted = NO; 79 | self.multiplayerMatch = nil; 80 | self.matchPresentingController = viewController; 81 | 82 | GKMatchmakerViewController *matchViewController = [[GKMatchmakerViewController alloc] initWithMatchRequest:matchRequest]; 83 | matchViewController.matchmakerDelegate = self; 84 | 85 | [self.matchPresentingController presentViewController:matchViewController animated:YES completion:nil]; 86 | } 87 | 88 | - (BOOL)sendAllPlayersMatchData:(NSData *)data shouldSendQuickly:(BOOL)sendQuickly completion:(void (^)(BOOL success, NSError *error))handler { 89 | // Create the error object 90 | NSError *error; 91 | 92 | // Check if data should be sent reliably or unreliably 93 | // Reliable: ensures that the data is sent and arrives, can take a long time. Best used for critical game updates. 94 | // Unreliable: data is sent quickly, data can be lost or fragmented. Best used for frequent game updates. 95 | 96 | if (sendQuickly == YES) { 97 | // The data should be sent unreliably 98 | if (data.length > 1000) { 99 | // Limit the size of unreliable messages to 1000 bytes or smaller - as per Apple documentation guidelines 100 | if (handler != nil) handler(NO, [NSError errorWithDomain:@"The specified data exceeded the unreliable sending limit of 1000 bytes. Either send the data reliably (max. 87 kB) or decrease data packet size." code:GCMErrorMultiplayerDataPacketTooLarge userInfo:@{@"data": data, @"method": @"unreliable"}]); 101 | return NO; 102 | } 103 | 104 | // Send the data unreliably to all players 105 | BOOL success = [self.multiplayerMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataUnreliable error:&error]; 106 | if (!success) { 107 | // There was an error while sending the data 108 | if (handler != nil) handler(NO, error); 109 | return NO; 110 | } else { 111 | // There was no error while sending the data 112 | // No gauruntee is made as to whether or not it is recieved. 113 | if (handler != nil) handler(YES, nil); 114 | return YES; 115 | } 116 | } else { 117 | // Limit the size of reliable messages to 87 kilobytes (89,088 bytes) or smaller - as per Apple documentation guidelines 118 | if (data.length > 89088) { 119 | if (handler != nil) handler(NO, [NSError errorWithDomain:@"The specified data exceeded the reliable sending limit of 87 kilobytes. You must decrease the data packet size." code:GCMErrorMultiplayerDataPacketTooLarge userInfo:@{@"data": data, @"method": @"reliable"}]); 120 | return NO; 121 | } 122 | 123 | // Send the data reliably to all players 124 | BOOL success = [self.multiplayerMatch sendDataToAllPlayers:data withDataMode:GKMatchSendDataReliable error:&error]; 125 | if (!success) { 126 | // There was an error while sending the data 127 | if (handler != nil) handler(NO, error); 128 | return NO; 129 | } else { 130 | // There was no error while sending the data 131 | // No gauruntee is made as to when it will be recieved. 132 | if (handler != nil) handler(YES, nil); 133 | return YES; 134 | } 135 | } 136 | } 137 | 138 | - (BOOL)sendMatchData:(NSData *)data toPlayers:(NSArray *)players shouldSendQuickly:(BOOL)sendQuickly completion:(void (^)(BOOL success, NSError *error))handler { 139 | // Create the error object 140 | 141 | #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) 142 | // Check if data should be sent reliably or unreliably 143 | // Reliable: ensures that the data is sent and arrives, can take a long time. Best used for critical game updates. 144 | // Unreliable: data is sent quickly, data can be lost or fragmented. Best used for frequent game updates. 145 | NSError *error; 146 | if (sendQuickly == YES) { 147 | // The data should be sent unreliably 148 | if (data.length > 1000) { 149 | // Limit the size of unreliable messages to 1000 bytes or smaller - as per Apple documentation guidelines 150 | if (handler != nil) handler(NO, [NSError errorWithDomain:@"The specified data exceeded the unreliable sending limit of 1000 bytes. Either send the data reliably (max. 87 kB) or decrease data packet size." code:GCMErrorMultiplayerDataPacketTooLarge userInfo:@{@"data": data, @"method": @"unreliable", @"players": players}]); 151 | return NO; 152 | } 153 | 154 | // Send the data unreliably to the specified players 155 | BOOL success = [self.multiplayerMatch sendData:data toPlayers:players withDataMode:GKMatchSendDataUnreliable error:&error]; 156 | if (!success) { 157 | // There was an error while sending the data 158 | if (handler != nil) handler(NO, error); 159 | return NO; 160 | } else { 161 | // There was no error while sending the data 162 | // No gauruntee is made as to whether or not it is recieved. 163 | if (handler != nil) handler(YES, nil); 164 | return YES; 165 | } 166 | } else { 167 | // Limit the size of reliable messages to 87 kilobytes (89,088 bytes) or smaller - as per Apple documentation guidelines 168 | if (data.length > 89088) { 169 | if (handler != nil) handler(NO, [NSError errorWithDomain:@"The specified data exceeded the reliable sending limit of 87 kilobytes. You must decrease the data packet size." code:GCMErrorMultiplayerDataPacketTooLarge userInfo:@{@"data": data, @"method": @"reliable", @"players": players}]); 170 | return NO; 171 | } 172 | 173 | // Send the data reliably to the specified players 174 | BOOL success = [self.multiplayerMatch sendData:data toPlayers:players withDataMode:GKMatchSendDataReliable error:&error]; 175 | if (!success) { 176 | // There was an error while sending the data 177 | if (handler != nil) handler(NO, error); 178 | return NO; 179 | } else { 180 | // There was no error while sending the data 181 | // No gauruntee is made as to when it will be recieved. 182 | if (handler != nil) handler(YES, nil); 183 | return YES; 184 | } 185 | } 186 | #else 187 | #warning GCMMultiplayer::sendMatchData not implemented 188 | return NO; 189 | #endif 190 | } 191 | 192 | - (void)disconnectLocalPlayerFromMatch { 193 | NSLog(@"[GameCenterManager] Attempting to disconnect local player"); 194 | 195 | if (!self.multiplayerMatch) return; 196 | 197 | [self.multiplayerMatch disconnect]; 198 | 199 | NSLog(@"[GameCenterManager] Disconnected local player"); 200 | 201 | self.multiplayerMatchStarted = NO; 202 | self.multiplayerMatch.delegate = nil; 203 | self.multiplayerMatch = nil; 204 | 205 | [self.multiplayerDelegate gameCenterManager:self matchEnded:self.multiplayerMatch]; 206 | } 207 | 208 | #pragma mark - GKLocalPlayerListener 209 | 210 | - (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite { 211 | if ([self.multiplayerDelegate respondsToSelector:@selector(gameCenterManager:match:didAcceptMatchInvitation:player:)]) 212 | [self.multiplayerDelegate gameCenterManager:self match:self.multiplayerMatch didAcceptMatchInvitation:invite player:player]; 213 | } 214 | 215 | - (void)player:(GKPlayer *)player didRequestMatchWithPlayers:(NSArray *)playerIDsToInvite { 216 | if ([self.multiplayerDelegate respondsToSelector:@selector(gameCenterManager:match:didRecieveMatchInvitationForPlayer:playersToInvite:)]) 217 | [self.multiplayerDelegate gameCenterManager:self match:self.multiplayerMatch didRecieveMatchInvitationForPlayer:player playersToInvite:playerIDsToInvite]; 218 | } 219 | 220 | #pragma mark - GKMatchmakerViewControllerDelegate 221 | 222 | - (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController { 223 | // Matchmaking was cancelled by the user 224 | [self.matchPresentingController dismissViewControllerAnimated:YES completion:nil]; 225 | } 226 | 227 | - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error { 228 | // Matchmaking failed due to an error 229 | [self.matchPresentingController dismissViewControllerAnimated:YES completion:nil]; 230 | NSLog(@"Error finding match: %@", error); 231 | } 232 | 233 | - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)theMatch { 234 | // A peer-to-peer match has been found, the game should start 235 | [self.matchPresentingController dismissViewControllerAnimated:YES completion:nil]; 236 | self.multiplayerMatch = theMatch; 237 | self.multiplayerMatch.delegate = self; 238 | 239 | if (!self.multiplayerMatchStarted && self.multiplayerMatch.expectedPlayerCount == 0) { 240 | NSLog(@"Ready to start match!"); 241 | NSLog(@"The didFindMatch: connection is being called. You need to determine if this should be handled."); 242 | 243 | // Match was found and all players are connected 244 | 245 | self.multiplayerMatchStarted = YES; 246 | [self.multiplayerDelegate gameCenterManager:self matchStarted:theMatch]; 247 | } 248 | } 249 | 250 | #pragma mark - GKMatchDelegate 251 | 252 | - (void)match:(GKMatch *)theMatch didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID { 253 | // The match received data sent from the player 254 | 255 | if (self.multiplayerMatch != theMatch) return; 256 | 257 | [self.multiplayerDelegate gameCenterManager:self match:theMatch didReceiveData:data fromPlayer:playerID]; 258 | } 259 | 260 | - (void)match:(GKMatch *)theMatch player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state { 261 | // The player state changed (eg. connected or disconnected) 262 | 263 | if (self.multiplayerMatch != theMatch) return; 264 | 265 | switch (state) { 266 | case GKPlayerStateConnected: 267 | // Handle a new player connection 268 | NSLog(@"Player connected!"); 269 | 270 | if (!self.multiplayerMatchStarted && theMatch.expectedPlayerCount == 0) { 271 | NSLog(@"Ready to start match!"); 272 | 273 | // TODO: Match was found and all players are connected 274 | NSLog(@"The didChangeState: connection is being called. You need to determine if this should be handled. For now it will not be handled."); 275 | 276 | if ([self.multiplayerDelegate respondsToSelector:@selector(gameCenterManager:match:didConnectAllPlayers:)]) { 277 | #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) 278 | [GKPlayer loadPlayersForIdentifiers:theMatch.playerIDs withCompletionHandler:^(NSArray *players, NSError *error) { 279 | [self.multiplayerDelegate gameCenterManager:self match:theMatch didConnectAllPlayers:players]; 280 | }]; 281 | #endif 282 | } 283 | } 284 | 285 | break; 286 | case GKPlayerStateDisconnected: 287 | // A player just disconnected 288 | NSLog(@"Player disconnected"); 289 | 290 | if ([self.multiplayerDelegate respondsToSelector:@selector(gameCenterManager:match:playerDidDisconnect:)]) { 291 | [GKPlayer loadPlayersForIdentifiers:@[playerID] withCompletionHandler:^(NSArray *players, NSError *error) { 292 | [self.multiplayerDelegate gameCenterManager:self match:theMatch playerDidDisconnect:[players firstObject]]; 293 | }]; 294 | } 295 | 296 | self.multiplayerMatchStarted = NO; 297 | [self.multiplayerDelegate gameCenterManager:self matchEnded:theMatch]; 298 | 299 | break; 300 | 301 | case GKPlayerStateUnknown: 302 | // Player state is unknown 303 | NSLog(@"Player state unknown"); 304 | break; 305 | } 306 | 307 | } 308 | 309 | - (void)match:(GKMatch *)theMatch connectionWithPlayerFailed:(NSString *)playerID withError:(NSError *)error { 310 | // The match was unable to connect with the player due to an error 311 | 312 | if (self.multiplayerMatch != theMatch) return; 313 | 314 | NSLog(@"Failed to connect to player with error: %@", error); 315 | 316 | self.multiplayerMatchStarted = NO; 317 | [self.multiplayerDelegate gameCenterManager:self matchEnded:theMatch]; 318 | } 319 | 320 | - (void)match:(GKMatch *)theMatch didFailWithError:(NSError *)error { 321 | // The match was unable to be established with any players due to an error 322 | 323 | if (self.multiplayerMatch != theMatch) return; 324 | 325 | NSLog(@"Match failed with error: %@", error); 326 | 327 | self.multiplayerMatchStarted = NO; 328 | [self.multiplayerDelegate gameCenterManager:self matchEnded:theMatch]; 329 | } 330 | 331 | @end 332 | -------------------------------------------------------------------------------- /GC Manager/GameCenterManager Mac-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /GC Manager/GameCenterManager-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /GC Manager/GameCenterManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // GameCenterManager.h 3 | // 4 | // Created by Nihal Ahmed on 12-03-16. Updated by iRare Media on 7/2/13. 5 | // Copyright (c) 2012 NABZ Software. All rights reserved. 6 | // 7 | 8 | #include 9 | 10 | // As of version 5.3, GameCenterManager only runs on iOS 7.0+ and OS X 10.9+, check for compatibility before building. See the GitHub Releases page (https://github.com/nihalahmed/GameCenterManager/releases) for older versions which work with iOS 4.1 and higher and OS X 10.8 and higher. The last supported version for iOS < 7.0 is version 5.2. The last supported version for OS X < 10.9 is also version 5.2. 11 | #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) 12 | #ifndef __IPHONE_7_0 13 | #warning GameCenterManager uses features only available in iOS SDK 7.0 and later. Running on an older version of iOS may result in a crash. Download an older release from GitHub for compatibility with iOS SDK < 7.0 14 | #endif 15 | #elif TARGET_OS_TV 16 | // 17 | #else 18 | #ifndef __MAC_10_9 19 | #warning GameCenterManager uses features only available in OS X SDK 10.9 and later. Running on an older version of OS X may result in a crash. Download an older release from GitHub for compatibility with OS X SDK < 10.9 20 | #endif 21 | #endif 22 | 23 | #if TARGET_OS_IOS || (TARGET_OS_IPHONE && !TARGET_OS_TV) 24 | #define kApplicationAppSupportDirectory [NSHomeDirectory() stringByAppendingPathComponent:@"Library"] 25 | #define kGameCenterManagerDataFile @"GameCenterManager.plist" 26 | #define kGameCenterManagerDataPath [kApplicationAppSupportDirectory stringByAppendingPathComponent:kGameCenterManagerDataFile] 27 | #elif TARGET_OS_TV 28 | // tvOS uses NSUserDefaults 29 | #else 30 | #define kApplicationAppSupportDirectory [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]] 31 | #define kGameCenterManagerDataFile @"GameCenterManager.plist" 32 | #define kGameCenterManagerDataPath [kApplicationAppSupportDirectory stringByAppendingPathComponent:kGameCenterManagerDataFile] 33 | #endif 34 | 35 | 36 | #import 37 | #import 38 | 39 | #if TARGET_OS_IPHONE 40 | #import 41 | #else 42 | #import 43 | #endif 44 | 45 | #import "Reachability.h" 46 | #import "NSDataAES256.h" 47 | #import "GCMConstants.h" 48 | 49 | #if TARGET_OS_IPHONE 50 | // Multiplayer is currently only available for the iOS platform 51 | #import "GCMMultiplayer.h" 52 | #endif 53 | 54 | /// GameCenter Manager helps to manage Game Center in iOS and Mac apps. Report and keep track of high scores, achievements, and challenges for different players. GameCenter Manager also takes care of the heavy lifting - checking internet availability, saving data when offline and uploading it when online, etc. 55 | @class GameCenterManager; 56 | @protocol GameCenterManagerDelegate; 57 | GCM_FINAL @interface GameCenterManager : NSObject 58 | 59 | 60 | /// Returns the shared instance of GameCenterManager. 61 | + (GameCenterManager *)sharedManager; 62 | 63 | /// GameCenterManager delegate property that can be used to set the delegate 64 | @property (nonatomic, weak) id delegate; 65 | 66 | 67 | #if TARGET_OS_IPHONE 68 | /// The multiplayer object used to facilitate and create peer-to-peer multiplayer sessions 69 | @property (nonatomic, strong) GCMMultiplayer *multiplayerObject; 70 | #endif 71 | 72 | 73 | /** DEPRECTAED. Use \p setupManagerAndSetShouldCryptWithKey: instead. 74 | @discussion Initializes GameCenterManager. Should be called at app launch. */ 75 | - (void)initGameCenter __deprecated; 76 | 77 | /** Initializes GameCenterManager. Should be called at app launch. Locally saved scores and achievements will be encrypted with the specified keyword when saved. 78 | 79 | @discussion This is more secure, but it may be slower. When submitting an app to the AppStore with GCManager Encryption, you may need to register for US Export Compliance. */ 80 | - (void)setupManagerAndSetShouldCryptWithKey:(NSString *)cryptKey; 81 | 82 | /** Initializes GameCenterManager. Should be called at app launch. Locally saved scores and achievements will not be encrypted when saved. 83 | 84 | @discussion This is less secure, but it may be faster. When submitting an app to the AppStore without using GCManager Encryption, you will not have to register for US Export Compliance (unless other parts of your app require it). */ 85 | - (void)setupManager; 86 | 87 | /// Synchronizes local player data with Game Center data. 88 | - (void)syncGameCenter; 89 | 90 | 91 | /** Saves score locally and reports it to Game Center. If error occurs, score is saved to be submitted later. 92 | 93 | @param score The long long value of the score to be submitted to Game Center. This score should not be formatted, instead it should be a plain long long (int). For example, if you wanted to submit a score of 45.28 meters then you would submit it as an integer of 4528. To format your scores, you must set the Score Formatter for your leaderboard in iTunes Connect. 94 | @param identifier The Leaderboard ID set through iTunes Connect. This is different from the name of the leaderboard, and it is not shown to the user. 95 | @param order The score sort order that you set in iTunes Connect - either high to low or low to high. This is used to determine if the user has a new highscore before submitting. */ 96 | - (void)saveAndReportScore:(long long)score leaderboard:(NSString *)identifier sortOrder:(GameCenterSortOrder)order __attribute__((nonnull)); 97 | 98 | /** Saves achievement locally and reports it to Game Center. If error occurs, achievement is saved to be submitted later. 99 | 100 | @param identifier The Achievement ID set through iTunes Connect. This is different from the name of the achievement, and it is not shown to the user. 101 | @param percentComplete A percentage value that states how far the player has progressed on this achievement. The range of legal values is between 0.0 and 100.0. Submitting 100.0 will mark the achievement as completed. Submitting a percent which is lower than what the user has already achieved will be ignored - the user's achievement progress cannot go down. 102 | @param displayNotification YES if GCManager should display a Game Center Achievement banner. NO if no banner should be displayed */ 103 | - (void)saveAndReportAchievement:(NSString *)identifier percentComplete:(double)percentComplete shouldDisplayNotification:(BOOL)displayNotification __attribute__((nonnull)); 104 | 105 | 106 | /// Reports scores and achievements which could not be reported earlier. 107 | - (void)reportSavedScoresAndAchievements; 108 | 109 | /// Saves score to be submitted later. 110 | - (void)saveScoreToReportLater:(GKScore *)score; 111 | 112 | /// Saves achievement to be submitted later. 113 | - (void)saveAchievementToReportLater:(NSString *)identifier percentComplete:(double)percentComplete; 114 | 115 | 116 | /// Returns local player's high score for specified leaderboard. 117 | - (long long)highScoreForLeaderboard:(NSString *)identifier; 118 | 119 | /// Returns local player's high scores for multiple leaderboards. 120 | - (NSDictionary *)highScoreForLeaderboards:(NSArray *)identifiers; 121 | 122 | 123 | /// Returns local player's percent completed for specified achievement. 124 | - (double)progressForAchievement:(NSString *)identifier; 125 | 126 | /// Returns local player's percent completed for multiple achievements. 127 | - (NSDictionary *)progressForAchievements:(NSArray *)identifiers; 128 | 129 | 130 | /** Gets a list of challenges for the current player and game. If GameCenter is not available it will return nil and provide an error using the gameCenterManager:error: delegate method. Use the completion handler to get challenges. 131 | @param handler Completion handler with an NSArray containing challenges and an NSError. The NSError object will be nil if there is no error. */ 132 | - (void)getChallengesWithCompletion:(void (^)(NSArray *challenges, NSError *error))handler __attribute__((nonnull)); 133 | 134 | 135 | #if TARGET_OS_IPHONE 136 | /// Presents the GameCenter Achievements ViewController over the specified ViewController. Dismissal and delegation is handled by GameCenterManager. 137 | - (void)presentAchievementsOnViewController:(UIViewController *)viewController; 138 | 139 | /// DEPRECATED. Use presentLeaderboardsOnViewController: withLeaderboard: instead. 140 | - (void)presentLeaderboardsOnViewController:(UIViewController *)viewController __deprecated; 141 | 142 | /// Presents the GameCenter Leaderboards ViewController with Leaderboard Identifier over the specified ViewController. Dismissal and delegation is handled by GameCenterManager. 143 | - (void)presentLeaderboardsOnViewController:(UIViewController *)viewController withLeaderboard:(NSString *)leaderboard; 144 | 145 | /// Presents the GameCenter Challenges ViewController over the specified ViewController. Dismissal and delegation is handled by GameCenterManager. 146 | - (void)presentChallengesOnViewController:(UIViewController *)viewController; 147 | #endif 148 | 149 | 150 | #if TARGET_OS_IPHONE 151 | /// Resets all of the local player's achievements and progress for the current game 152 | - (void)resetAchievementsWithCompletion:(void (^)(NSError *error))handler __attribute__((nonnull)); 153 | #else 154 | /// Resets all of the local player's achievements and progress for the current game 155 | - (void)resetAchievementsWithCompletion:(void (^)(NSError *error))handler __attribute__((nonnull)); 156 | 157 | /// DEPRECATED. Use resetAchievementsWithCompletion: instead. 158 | - (void)resetAchievements __deprecated __unavailable; 159 | #endif 160 | 161 | 162 | /// Returns currently authenticated local player ID. If no player is authenticated, "unknownPlayer" is returned. 163 | - (NSString *)localPlayerId; 164 | 165 | /// Returns currently authenticated local player's display name (alias or actual name depending on friendship). If no player is authenticated, "unknownPlayer" is returned. Player Alias will be returned if the Display Name property is not available 166 | - (NSString *)localPlayerDisplayName; 167 | 168 | /// Returns currently authenticated local player and all associated data. If no player is authenticated, `nil` is returned. 169 | - (GKLocalPlayer *)localPlayerData; 170 | 171 | #if TARGET_OS_IPHONE 172 | /// Fetches a UIImage with the local player's profile picture at full resolution. The completion handler passes a UIImage object when the image is downloaded from the GameCenter Servers 173 | - (void)localPlayerPhoto:(void (^)(UIImage *playerPhoto))handler __attribute__((nonnull)) __OSX_AVAILABLE_STARTING(__OSX_10_8,__IPHONE_5_0); 174 | #else 175 | /// Fetches an NSImage with the local player's profile picture at full resolution. The completion handler passes an NSImage object when the image is downloaded from the GameCenter Servers 176 | - (void)localPlayerPhoto:(void (^)(NSImage *playerPhoto))handler __attribute__((nonnull)); 177 | #endif 178 | 179 | 180 | /// Returns YES if an active internet connection is available. 181 | - (BOOL)isInternetAvailable; 182 | 183 | /// DEPRECATED. Use checkGameCenterAvailability: ignorePreviousStatus: instead. 184 | - (BOOL)checkGameCenterAvailability __deprecated; 185 | 186 | /// Check if Game Center is supported 187 | - (BOOL)checkGameCenterAvailability:(BOOL)ignorePreviousStatus; 188 | 189 | /// Use this property to check if Game Center is available and supported on the current device. 190 | @property (nonatomic, assign) BOOL isGameCenterAvailable; 191 | 192 | /// @b Readonly. Indicates whether or not locally saved scores and achievements should be encrypted. To turn ON this feature, initialize GameCenterManager using the \p setupManagerAndSetShouldCryptWithKey: method (instead of just \p setupManager) 193 | @property (nonatomic, assign, readonly) BOOL shouldCryptData; 194 | 195 | /// @b Readonly. The key used to encrypt and decrypt locally saved scores and achievements. To set the key, setup GameCenterManager using the \p setupManagerAndSetShouldCryptWithKey: method 196 | @property (nonatomic, strong, readonly) NSString *cryptKey; 197 | 198 | 199 | @end 200 | 201 | 202 | /// GameCenterManager Delegate. Used for deeper control of the GameCenterManager class - allows for notification subscription, error reporting, and availability handling. 203 | @protocol GameCenterManagerDelegate 204 | 205 | #if TARGET_OS_IPHONE 206 | @required 207 | /// Required Delegate Method called when the user needs to be authenticated using the GameCenter Login View Controller 208 | - (void)gameCenterManager:(GameCenterManager *)manager authenticateUser:(UIViewController *)gameCenterLoginController; 209 | #else 210 | @required 211 | /// Required Delegate Method called when the user needs to be authenticated using the Game Center Login View Controller 212 | - (void)gameCenterManager:(GameCenterManager *)manager authenticateUser:(NSViewController *)gameCenterLoginController; 213 | #endif 214 | 215 | @optional 216 | /// Delegate Method called when the availability of GameCenter changes 217 | - (void)gameCenterManager:(GameCenterManager *)manager availabilityChanged:(NSDictionary *)availabilityInformation; 218 | 219 | /// Delegate Method called when the there is an error with GameCenter or GC Manager 220 | - (void)gameCenterManager:(GameCenterManager *)manager error:(NSError *)error; 221 | 222 | /// Sent to the delegate when a score is reported to GameCenter 223 | - (void)gameCenterManager:(GameCenterManager *)manager reportedScore:(GKScore *)score withError:(NSError *)error; 224 | /// Sent to the delegate when an achievement is reported to GameCenter 225 | - (void)gameCenterManager:(GameCenterManager *)manager reportedAchievement:(GKAchievement *)achievement withError:(NSError *)error; 226 | 227 | /// Sent to the delegate when an achievement is saved locally 228 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveAchievement:(GKAchievement *)achievement; 229 | /// Sent to the delegate when a score is saved locally 230 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveScore:(GKScore *)score; 231 | /// Sent to the delegate when the Game Center is synced 232 | - (void)gameCenterManager:(GameCenterManager *)manager gameCenterSynced:(BOOL)synced; 233 | 234 | /// Sent to the delegate when the Game Center View Controller is On Screen 235 | - (void)gameCenterManager:(GameCenterManager *)manager gameCenterViewControllerPresented:(BOOL)finished; 236 | /// Sent to the delegate when the Game Center View Controller has been dismissed 237 | - (void)gameCenterManager:(GameCenterManager *)manager gameCenterViewControllerDidFinish:(BOOL)finished; 238 | 239 | //----------------------------------// 240 | //-- Deprecated Delegate Methods ---// 241 | //----------------------------------// 242 | 243 | /// DEPRECATED. Use gameCenterManager: didSaveScore: instead. 244 | - (void)gameCenterManager:(GameCenterManager *)manager savedScore:(GKScore *)score __deprecated; 245 | 246 | /// DEPRECATED. Use gameCenterManager: didSaveAchievement: instead. 247 | - (void)gameCenterManager:(GameCenterManager *)manager savedAchievement:(NSDictionary *)achievementInformation __deprecated; 248 | 249 | /// DEPRECATED. Use gameCenterManager: reportedScore: withError: instead. 250 | - (void)gameCenterManager:(GameCenterManager *)manager reportedScore:(NSDictionary *)scoreInformation __deprecated; 251 | 252 | /// DEPRECATED. Use gameCenterManager: reportedAchievement: withError: instead. 253 | - (void)gameCenterManager:(GameCenterManager *)manager reportedAchievement:(NSDictionary *)achievementInformation __deprecated; 254 | 255 | /// DEPRECATED. UNAVAILABLE. Use the completion handler on resetAchievementsWithCompletion: 256 | - (void)gameCenterManager:(GameCenterManager *)manager resetAchievements:(NSError *)error __deprecated __unavailable; 257 | 258 | @end 259 | 260 | 261 | -------------------------------------------------------------------------------- /GC Manager/Multiplayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Multiplayer.swift 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 12/13/15. 6 | // Copyright © 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import GameKit 11 | 12 | protocol MultiplerManagerDelegate { 13 | func matchStarted(manager:Multiplayer, match:GKMatch) 14 | func matchEnded(manager:Multiplayer, match:GKMatch) 15 | func matchRecievedData(manager:Multiplayer, match:GKMatch, data:NSData, sendingPlayerID:NSString) 16 | } 17 | 18 | protocol MultiplayerPlayerManagerDelegate { 19 | func allPlayersConnectedToMatch(manager:Multiplayer, match:GKMatch, players:[String]) 20 | func allPlayersDisconnectedFromMatch(manager:Multiplayer, match:GKMatch, players:[String]) 21 | func recievedMatchInvitation(manager:Multiplayer, invitedPlayer:GKPlayer, players:[GKPlayer]) 22 | func acceptedMatchInvitation(manager:Multiplayer, invite:GKInvite, player:GKPlayer) 23 | } 24 | 25 | class Multiplayer: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDelegate, GKLocalPlayerListener { 26 | 27 | var matchPresentingController: UIViewController? 28 | var multiplayerMatchStarted: Bool 29 | var multiplayerMatch: GKMatch? 30 | 31 | override init() { 32 | // Initialize the class 33 | matchPresentingController = nil 34 | multiplayerMatchStarted = false 35 | multiplayerMatch = nil 36 | 37 | super.init() 38 | } 39 | 40 | deinit { 41 | GKLocalPlayer.localPlayer().unregisterAllListeners() 42 | } 43 | 44 | class MultiplayerManager { 45 | static let sharedInstance = Multiplayer() 46 | } 47 | 48 | func beginListeningForMatches() { 49 | GKLocalPlayer.localPlayer().registerListener(self) 50 | } 51 | 52 | func matchmakerViewControllerWasCancelled(viewController: GKMatchmakerViewController) { 53 | // Matchmaking was cancelled by the user 54 | matchPresentingController!.dismissViewControllerAnimated(true) { () -> Void in 55 | NSLog("Matchmaking View Controller was dissmissed.") 56 | } 57 | } 58 | 59 | func matchmakerViewController(viewController: GKMatchmakerViewController, didFailWithError error: NSError) { 60 | // Matchmaking failed due to an error 61 | matchPresentingController!.dismissViewControllerAnimated(true) { () -> Void in 62 | NSLog("Error finding match: %@", error) 63 | } 64 | } 65 | 66 | func matchmakerViewController(viewController: GKMatchmakerViewController, didFindMatch match: GKMatch) { 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /GC Manager/NSDataAES256.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataAES256.h 3 | // 4 | 5 | #import 6 | 7 | @interface NSData (AES256) 8 | 9 | - (NSData *)encryptedWithKey:(NSData *)key; 10 | - (NSData *)decryptedWithKey:(NSData *)key; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /GC Manager/NSDataAES256.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDataAES256.m 3 | // 4 | 5 | #import "NSDataAES256.h" 6 | #import 7 | 8 | // Key size is 32 bytes for AES256 9 | #define kKeySize kCCKeySizeAES256 10 | 11 | @implementation NSData (AES256) 12 | 13 | - (NSData *)makeCryptedVersionWithKeyData:(const void *) keyData ofLength:(int) keyLength decrypt:(bool) decrypt { 14 | // Copy the key data, padding with zeroes if needed 15 | char key[kKeySize]; 16 | bzero(key, sizeof(key)); 17 | memcpy(key, keyData, keyLength > kKeySize ? kKeySize : keyLength); 18 | 19 | size_t bufferSize = [self length] + kCCBlockSizeAES128; 20 | void *buffer = malloc(bufferSize); 21 | 22 | size_t dataUsed; 23 | 24 | CCCryptorStatus status = CCCrypt(decrypt ? kCCDecrypt : kCCEncrypt, 25 | kCCAlgorithmAES128, 26 | kCCOptionPKCS7Padding | kCCOptionECBMode, 27 | key, kKeySize, 28 | NULL, 29 | [self bytes], [self length], 30 | buffer, bufferSize, 31 | &dataUsed); 32 | 33 | switch(status) { 34 | case kCCSuccess: 35 | return [NSData dataWithBytesNoCopy:buffer length:dataUsed]; 36 | case kCCParamError: 37 | NSLog(@"Error: NSDataAES256: Could not %s data: Param error", decrypt ? "decrypt" : "encrypt"); 38 | break; 39 | case kCCBufferTooSmall: 40 | NSLog(@"Error: NSDataAES256: Could not %s data: Buffer too small", decrypt ? "decrypt" : "encrypt"); 41 | break; 42 | case kCCMemoryFailure: 43 | NSLog(@"Error: NSDataAES256: Could not %s data: Memory failure", decrypt ? "decrypt" : "encrypt"); 44 | break; 45 | case kCCAlignmentError: 46 | NSLog(@"Error: NSDataAES256: Could not %s data: Alignment error", decrypt ? "decrypt" : "encrypt"); 47 | break; 48 | case kCCDecodeError: 49 | NSLog(@"Error: NSDataAES256: Could not %s data: Decode error", decrypt ? "decrypt" : "encrypt"); 50 | break; 51 | case kCCUnimplemented: 52 | NSLog(@"Error: NSDataAES256: Could not %s data: Unimplemented", decrypt ? "decrypt" : "encrypt"); 53 | break; 54 | default: 55 | NSLog(@"Error: NSDataAES256: Could not %s data: Unknown error", decrypt ? "decrypt" : "encrypt"); 56 | } 57 | 58 | free(buffer); 59 | return nil; 60 | } 61 | 62 | - (NSData *)encryptedWithKey:(NSData *)key { 63 | return [self makeCryptedVersionWithKeyData:[key bytes] ofLength:(int)[key length] decrypt:NO]; 64 | } 65 | 66 | - (NSData *)decryptedWithKey:(NSData *)key { 67 | return [self makeCryptedVersionWithKeyData:[key bytes] ofLength:(int)[key length] decrypt:YES]; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /GC Manager/Reachability.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Tony Million. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #import 29 | #import 30 | 31 | #import 32 | #import 33 | #import 34 | #import 35 | #import 36 | #import 37 | 38 | /** 39 | * Does ARC support support GCD objects? 40 | * It does if the minimum deployment target is iOS 6+ or Mac OS X 8+ 41 | * 42 | * @see http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h 43 | **/ 44 | #if OS_OBJECT_USE_OBJC 45 | #define NEEDS_DISPATCH_RETAIN_RELEASE 0 46 | #else 47 | #define NEEDS_DISPATCH_RETAIN_RELEASE 1 48 | #endif 49 | 50 | 51 | extern NSString *const kReachabilityChangedNotification; 52 | 53 | typedef enum { 54 | // Apple NetworkStatus Compatible Names. 55 | NotReachable = 0, 56 | ReachableViaWiFi = 2, 57 | ReachableViaWWAN = 1 58 | } NetworkStatus; 59 | 60 | @class Reachability; 61 | 62 | typedef void (^NetworkReachable)(Reachability * reachability); 63 | typedef void (^NetworkUnreachable)(Reachability * reachability); 64 | 65 | @interface Reachability : NSObject 66 | 67 | @property (nonatomic, copy) NetworkReachable reachableBlock; 68 | @property (nonatomic, copy) NetworkUnreachable unreachableBlock; 69 | 70 | 71 | @property (nonatomic, assign) BOOL reachableOnWWAN; 72 | 73 | +(Reachability*)reachabilityWithHostname:(NSString*)hostname; 74 | +(Reachability*)reachabilityForInternetConnection; 75 | +(Reachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress; 76 | +(Reachability*)reachabilityForLocalWiFi; 77 | 78 | -(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref; 79 | 80 | -(BOOL)startNotifier; 81 | -(void)stopNotifier; 82 | 83 | -(BOOL)isReachable; 84 | -(BOOL)isReachableViaWWAN; 85 | -(BOOL)isReachableViaWiFi; 86 | 87 | // WWAN may be available, but not active until a connection has been established. 88 | // WiFi may require a connection for VPN on Demand. 89 | -(BOOL)isConnectionRequired; // Identical DDG variant. 90 | -(BOOL)connectionRequired; // Apple's routine. 91 | // Dynamic, on demand connection? 92 | -(BOOL)isConnectionOnDemand; 93 | // Is user intervention required? 94 | -(BOOL)isInterventionRequired; 95 | 96 | -(NetworkStatus)currentReachabilityStatus; 97 | -(SCNetworkReachabilityFlags)reachabilityFlags; 98 | -(NSString*)currentReachabilityString; 99 | -(NSString*)currentReachabilityFlags; 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /GC Manager/Reachability.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Tony Million. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #import "Reachability.h" 29 | 30 | 31 | NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification"; 32 | 33 | @interface Reachability () 34 | 35 | @property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef; 36 | 37 | 38 | #if NEEDS_DISPATCH_RETAIN_RELEASE 39 | @property (nonatomic, assign) dispatch_queue_t reachabilitySerialQueue; 40 | #else 41 | @property (nonatomic, strong) dispatch_queue_t reachabilitySerialQueue; 42 | #endif 43 | 44 | 45 | @property (nonatomic, strong) id reachabilityObject; 46 | 47 | -(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags; 48 | -(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags; 49 | 50 | @end 51 | 52 | static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags) 53 | { 54 | return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c", 55 | #if TARGET_OS_IPHONE 56 | (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', 57 | #else 58 | 'X', 59 | #endif 60 | (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', 61 | (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', 62 | (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', 63 | (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', 64 | (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', 65 | (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', 66 | (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', 67 | (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; 68 | } 69 | 70 | //Start listening for reachability notifications on the current run loop 71 | static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) 72 | { 73 | #pragma unused (target) 74 | #if __has_feature(objc_arc) 75 | Reachability *reachability = ((__bridge Reachability*)info); 76 | #else 77 | Reachability *reachability = ((Reachability*)info); 78 | #endif 79 | 80 | // we probably dont need an autoreleasepool here as GCD docs state each queue has its own autorelease pool 81 | // but what the heck eh? 82 | @autoreleasepool 83 | { 84 | [reachability reachabilityChanged:flags]; 85 | } 86 | } 87 | 88 | 89 | @implementation Reachability 90 | 91 | @synthesize reachabilityRef; 92 | @synthesize reachabilitySerialQueue; 93 | 94 | @synthesize reachableOnWWAN; 95 | 96 | @synthesize reachableBlock; 97 | @synthesize unreachableBlock; 98 | 99 | @synthesize reachabilityObject; 100 | 101 | #pragma mark - class constructor methods 102 | +(Reachability*)reachabilityWithHostname:(NSString*)hostname 103 | { 104 | SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]); 105 | if (ref) 106 | { 107 | id reachability = [[self alloc] initWithReachabilityRef:ref]; 108 | 109 | #if __has_feature(objc_arc) 110 | return reachability; 111 | #else 112 | return [reachability autorelease]; 113 | #endif 114 | 115 | } 116 | 117 | return nil; 118 | } 119 | 120 | +(Reachability *)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress 121 | { 122 | SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); 123 | if (ref) 124 | { 125 | id reachability = [[self alloc] initWithReachabilityRef:ref]; 126 | 127 | #if __has_feature(objc_arc) 128 | return reachability; 129 | #else 130 | return [reachability autorelease]; 131 | #endif 132 | } 133 | 134 | return nil; 135 | } 136 | 137 | +(Reachability *)reachabilityForInternetConnection 138 | { 139 | struct sockaddr_in zeroAddress; 140 | bzero(&zeroAddress, sizeof(zeroAddress)); 141 | zeroAddress.sin_len = sizeof(zeroAddress); 142 | zeroAddress.sin_family = AF_INET; 143 | 144 | return [self reachabilityWithAddress:&zeroAddress]; 145 | } 146 | 147 | +(Reachability*)reachabilityForLocalWiFi 148 | { 149 | struct sockaddr_in localWifiAddress; 150 | bzero(&localWifiAddress, sizeof(localWifiAddress)); 151 | localWifiAddress.sin_len = sizeof(localWifiAddress); 152 | localWifiAddress.sin_family = AF_INET; 153 | // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 154 | localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); 155 | 156 | return [self reachabilityWithAddress:&localWifiAddress]; 157 | } 158 | 159 | 160 | // initialization methods 161 | 162 | -(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref 163 | { 164 | self = [super init]; 165 | if (self != nil) 166 | { 167 | self.reachableOnWWAN = YES; 168 | self.reachabilityRef = ref; 169 | } 170 | 171 | return self; 172 | } 173 | 174 | -(void)dealloc 175 | { 176 | [self stopNotifier]; 177 | 178 | if(self.reachabilityRef) 179 | { 180 | CFRelease(self.reachabilityRef); 181 | self.reachabilityRef = nil; 182 | } 183 | 184 | 185 | #if !(__has_feature(objc_arc)) 186 | [super dealloc]; 187 | #endif 188 | 189 | 190 | } 191 | 192 | #pragma mark - notifier methods 193 | 194 | // Notifier 195 | // NOTE: this uses GCD to trigger the blocks - they *WILL NOT* be called on THE MAIN THREAD 196 | // - In other words DO NOT DO ANY UI UPDATES IN THE BLOCKS. 197 | // INSTEAD USE dispatch_async(dispatch_get_main_queue(), ^{UISTUFF}) (or dispatch_sync if you want) 198 | 199 | -(BOOL)startNotifier 200 | { 201 | SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; 202 | 203 | // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves 204 | // woah 205 | self.reachabilityObject = self; 206 | 207 | 208 | 209 | // first we need to create a serial queue 210 | // we allocate this once for the lifetime of the notifier 211 | self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL); 212 | if(!self.reachabilitySerialQueue) 213 | { 214 | return NO; 215 | } 216 | 217 | #if __has_feature(objc_arc) 218 | context.info = (__bridge void *)self; 219 | #else 220 | context.info = (void *)self; 221 | #endif 222 | 223 | if (!SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) 224 | { 225 | #ifdef DEBUG 226 | NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError())); 227 | #endif 228 | 229 | //clear out the dispatch queue 230 | if(self.reachabilitySerialQueue) 231 | { 232 | #if NEEDS_DISPATCH_RETAIN_RELEASE 233 | dispatch_release(self.reachabilitySerialQueue); 234 | #endif 235 | self.reachabilitySerialQueue = nil; 236 | } 237 | 238 | self.reachabilityObject = nil; 239 | 240 | return NO; 241 | } 242 | 243 | // set it as our reachability queue which will retain the queue 244 | if(!SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue)) 245 | { 246 | #ifdef DEBUG 247 | NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError())); 248 | #endif 249 | 250 | //UH OH - FAILURE! 251 | 252 | // first stop any callbacks! 253 | SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); 254 | 255 | // then clear out the dispatch queue 256 | if(self.reachabilitySerialQueue) 257 | { 258 | #if NEEDS_DISPATCH_RETAIN_RELEASE 259 | dispatch_release(self.reachabilitySerialQueue); 260 | #endif 261 | self.reachabilitySerialQueue = nil; 262 | } 263 | 264 | self.reachabilityObject = nil; 265 | 266 | return NO; 267 | } 268 | 269 | return YES; 270 | } 271 | 272 | -(void)stopNotifier 273 | { 274 | // first stop any callbacks! 275 | SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); 276 | 277 | // unregister target from the GCD serial dispatch queue 278 | SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL); 279 | 280 | if(self.reachabilitySerialQueue) 281 | { 282 | #if NEEDS_DISPATCH_RETAIN_RELEASE 283 | dispatch_release(self.reachabilitySerialQueue); 284 | #endif 285 | self.reachabilitySerialQueue = nil; 286 | } 287 | 288 | self.reachabilityObject = nil; 289 | } 290 | 291 | #pragma mark - reachability tests 292 | 293 | // this is for the case where you flick the airplane mode 294 | // you end up getting something like this: 295 | //Reachability: WR ct----- 296 | //Reachability: -- ------- 297 | //Reachability: WR ct----- 298 | //Reachability: -- ------- 299 | // we treat this as 4 UNREACHABLE triggers - really apple should do better than this 300 | 301 | #define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection) 302 | 303 | -(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags 304 | { 305 | BOOL connectionUP = YES; 306 | 307 | if(!(flags & kSCNetworkReachabilityFlagsReachable)) 308 | connectionUP = NO; 309 | 310 | if( (flags & testcase) == testcase ) 311 | connectionUP = NO; 312 | 313 | #if TARGET_OS_IPHONE 314 | if(flags & kSCNetworkReachabilityFlagsIsWWAN) 315 | { 316 | // we're on 3G 317 | if(!self.reachableOnWWAN) 318 | { 319 | // we dont want to connect when on 3G 320 | connectionUP = NO; 321 | } 322 | } 323 | #endif 324 | 325 | return connectionUP; 326 | } 327 | 328 | -(BOOL)isReachable 329 | { 330 | SCNetworkReachabilityFlags flags; 331 | 332 | if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) 333 | return NO; 334 | 335 | return [self isReachableWithFlags:flags]; 336 | } 337 | 338 | -(BOOL)isReachableViaWWAN 339 | { 340 | #if TARGET_OS_IPHONE 341 | 342 | SCNetworkReachabilityFlags flags = 0; 343 | 344 | if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 345 | { 346 | // check we're REACHABLE 347 | if(flags & kSCNetworkReachabilityFlagsReachable) 348 | { 349 | // now, check we're on WWAN 350 | if(flags & kSCNetworkReachabilityFlagsIsWWAN) 351 | { 352 | return YES; 353 | } 354 | } 355 | } 356 | #endif 357 | 358 | return NO; 359 | } 360 | 361 | -(BOOL)isReachableViaWiFi 362 | { 363 | SCNetworkReachabilityFlags flags = 0; 364 | 365 | if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 366 | { 367 | // check we're reachable 368 | if((flags & kSCNetworkReachabilityFlagsReachable)) 369 | { 370 | #if TARGET_OS_IPHONE 371 | // check we're NOT on WWAN 372 | if((flags & kSCNetworkReachabilityFlagsIsWWAN)) 373 | { 374 | return NO; 375 | } 376 | #endif 377 | return YES; 378 | } 379 | } 380 | 381 | return NO; 382 | } 383 | 384 | 385 | // WWAN may be available, but not active until a connection has been established. 386 | // WiFi may require a connection for VPN on Demand. 387 | -(BOOL)isConnectionRequired 388 | { 389 | return [self connectionRequired]; 390 | } 391 | 392 | -(BOOL)connectionRequired 393 | { 394 | SCNetworkReachabilityFlags flags; 395 | 396 | if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 397 | { 398 | return (flags & kSCNetworkReachabilityFlagsConnectionRequired); 399 | } 400 | 401 | return NO; 402 | } 403 | 404 | // Dynamic, on demand connection? 405 | -(BOOL)isConnectionOnDemand 406 | { 407 | SCNetworkReachabilityFlags flags; 408 | 409 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 410 | { 411 | return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && 412 | (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); 413 | } 414 | 415 | return NO; 416 | } 417 | 418 | // Is user intervention required? 419 | -(BOOL)isInterventionRequired 420 | { 421 | SCNetworkReachabilityFlags flags; 422 | 423 | if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 424 | { 425 | return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && 426 | (flags & kSCNetworkReachabilityFlagsInterventionRequired)); 427 | } 428 | 429 | return NO; 430 | } 431 | 432 | 433 | #pragma mark - reachability status stuff 434 | 435 | -(NetworkStatus)currentReachabilityStatus 436 | { 437 | if([self isReachable]) 438 | { 439 | if([self isReachableViaWiFi]) 440 | return ReachableViaWiFi; 441 | 442 | #if TARGET_OS_IPHONE 443 | return ReachableViaWWAN; 444 | #endif 445 | } 446 | 447 | return NotReachable; 448 | } 449 | 450 | -(SCNetworkReachabilityFlags)reachabilityFlags 451 | { 452 | SCNetworkReachabilityFlags flags = 0; 453 | 454 | if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) 455 | { 456 | return flags; 457 | } 458 | 459 | return 0; 460 | } 461 | 462 | -(NSString*)currentReachabilityString 463 | { 464 | NetworkStatus temp = [self currentReachabilityStatus]; 465 | 466 | if(temp == reachableOnWWAN) 467 | { 468 | // updated for the fact we have CDMA phones now! 469 | return NSLocalizedString(@"Cellular", @""); 470 | } 471 | if (temp == ReachableViaWiFi) 472 | { 473 | return NSLocalizedString(@"WiFi", @""); 474 | } 475 | 476 | return NSLocalizedString(@"No Connection", @""); 477 | } 478 | 479 | -(NSString*)currentReachabilityFlags 480 | { 481 | return reachabilityFlags([self reachabilityFlags]); 482 | } 483 | 484 | #pragma mark - callback function calls this method 485 | 486 | -(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags 487 | { 488 | if([self isReachableWithFlags:flags]) 489 | { 490 | if(self.reachableBlock) 491 | { 492 | self.reachableBlock(self); 493 | } 494 | } 495 | else 496 | { 497 | if(self.unreachableBlock) 498 | { 499 | self.unreachableBlock(self); 500 | } 501 | } 502 | 503 | // this makes sure the change notification happens on the MAIN THREAD 504 | dispatch_async(dispatch_get_main_queue(), ^{ 505 | [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification 506 | object:self]; 507 | }); 508 | } 509 | 510 | #pragma mark - Debug Description 511 | 512 | - (NSString *) description; 513 | { 514 | NSString *description = [NSString stringWithFormat:@"<%@: %#x>", 515 | NSStringFromClass([self class]), (unsigned int) self]; 516 | return description; 517 | } 518 | 519 | @end 520 | -------------------------------------------------------------------------------- /GC Manager/Referee.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Referee.swift 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 12/13/15. 6 | // Copyright © 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | 10 | import Foundation 11 | import GameKit 12 | 13 | class Referee: NSObject { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /GameCenterManager Mac/GameCenterManager Mac-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 5.3.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 5.3.1 23 | LSApplicationCategoryType 24 | public.app-category.games 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2013 iRare Media. All rights reserved. 29 | NSMainStoryboardFile 30 | Storyboard 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /GameCenterManager Mac/GameCenterManager Mac-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'GameCenterManager Mac' target in the 'GameCenterManager Mac' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /GameCenterManager Mac/GameCenterManager Mac.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.game-center 6 | 7 | com.apple.security.app-sandbox 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /GameCenterManager Mac/MacViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MacViewController.h 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 1/17/15. 6 | // Copyright (c) 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "GameCenterManager.h" 11 | 12 | @interface MacViewController : NSViewController 13 | 14 | @property (weak) IBOutlet NSTextField *gameCenterStatus; 15 | @property (weak) IBOutlet NSTextField *detailedStatus; 16 | @property (weak) IBOutlet NSTextField *actionStatus; 17 | @property (weak) IBOutlet NSTextField *playerName; 18 | @property (weak) IBOutlet NSTextField *playerStatus; 19 | @property (weak) IBOutlet NSImageView *playerProfilePicture; 20 | 21 | - (IBAction)submitHighscore:(id)sender; 22 | - (IBAction)submitAchievement:(id)sender; 23 | - (IBAction)resetAchievements:(id)sender; 24 | - (IBAction)openLeaderboards:(id)sender; 25 | - (IBAction)openAchievements:(id)sender; 26 | - (IBAction)fetchChallenges:(id)sender; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /GameCenterManager Mac/MacViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MacViewController.m 3 | // GameCenterManager 4 | // 5 | // Created by Sam Spencer on 1/17/15. 6 | // Copyright (c) 2015 NABZ Software. All rights reserved. 7 | // 8 | 9 | #import "MacViewController.h" 10 | 11 | @interface MacViewController () 12 | 13 | @end 14 | 15 | @implementation MacViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | // Do view setup here. 21 | self.view.wantsLayer = YES; 22 | self.view.layer.backgroundColor = [NSColor whiteColor].CGColor; 23 | [[NSApplication sharedApplication] setDelegate:self]; 24 | 25 | // Setup Image Rounding 26 | self.playerProfilePicture.layer.cornerRadius = self.playerProfilePicture.bounds.size.width/2; 27 | 28 | // Setup Game Center Manager 29 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 30 | [[GameCenterManager sharedManager] setupManager]; 31 | [[GameCenterManager sharedManager] setDelegate:self]; 32 | 33 | // Setup Game Center Manager 34 | BOOL available = [[GameCenterManager sharedManager] checkGameCenterAvailability:YES]; 35 | if (available) self.gameCenterStatus.stringValue = @"GAME CENTER AVAILABLE"; 36 | else self.gameCenterStatus.stringValue = @"GAME CENTER UNAVAILABLE"; 37 | 38 | // Get Player Status 39 | GKLocalPlayer *player = [[GameCenterManager sharedManager] localPlayerData]; 40 | if (player) { 41 | if ([player isUnderage] == NO) { 42 | self.actionStatus.stringValue = [NSString stringWithFormat:@"%@ signed in.", player.displayName]; 43 | self.playerName.stringValue = player.displayName; 44 | _playerStatus.stringValue = @"Player is not underage"; 45 | [[GameCenterManager sharedManager] localPlayerPhoto:^(NSImage *playerPhoto) { 46 | self.playerProfilePicture.image = playerPhoto; 47 | }]; 48 | } else { 49 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Underage player, %@, signed in.", player.displayName]; 50 | } 51 | } else { 52 | self.actionStatus.stringValue = [NSString stringWithFormat:@"No GameCenter player found."]; 53 | } 54 | }); 55 | } 56 | 57 | - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { 58 | return YES; 59 | } 60 | 61 | - (void)gameCenterManager:(GameCenterManager *)manager authenticateUser:(NSViewController *)gameCenterLoginController { 62 | NSLog(@"Attempting to present login controller"); 63 | [self presentViewControllerAsModalWindow:gameCenterLoginController]; 64 | } 65 | 66 | - (void)gameCenterManager:(GameCenterManager *)manager availabilityChanged:(NSDictionary *)availabilityInformation { 67 | NSLog(@"GC Availability: %@", availabilityInformation); 68 | if ([availabilityInformation objectForKey:@"message"] != nil) { 69 | self.detailedStatus.stringValue = [availabilityInformation objectForKey:@"message"]; 70 | } 71 | 72 | if ([[availabilityInformation objectForKey:@"status"] isEqualToString:@"GameCenter Available"]) { 73 | self.gameCenterStatus.stringValue = @"GAME CENTER AVAILABLE"; 74 | self.detailedStatus.stringValue = @"Game Center is online, the current player is logged in, and this app is setup."; 75 | } else { 76 | self.gameCenterStatus.stringValue = @"GAME CENTER UNAVAILABLE"; 77 | self.detailedStatus.stringValue = [availabilityInformation objectForKey:@"message"]; 78 | } 79 | 80 | // Get Player Status 81 | GKLocalPlayer *player = [[GameCenterManager sharedManager] localPlayerData]; 82 | if (player) { 83 | if ([player isUnderage] == NO) { 84 | self.actionStatus.stringValue = [NSString stringWithFormat:@"%@ signed in.", player.displayName]; 85 | self.playerName.stringValue = player.displayName; 86 | self.playerStatus.stringValue = @"Player is not underage and is signed in"; 87 | [[GameCenterManager sharedManager] localPlayerPhoto:^(NSImage *playerPhoto) { 88 | self.playerProfilePicture.image = playerPhoto; 89 | self.playerProfilePicture.layer.cornerRadius = self.playerProfilePicture.bounds.size.width/2; 90 | [self.playerProfilePicture setNeedsDisplay]; 91 | }]; 92 | } else { 93 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Underage player, %@, signed in.", player.displayName]; 94 | } 95 | } else { 96 | self.actionStatus.stringValue = [NSString stringWithFormat:@"No GameCenter player found."]; 97 | } 98 | } 99 | 100 | - (void)gameCenterManager:(GameCenterManager *)manager error:(NSError *)error { 101 | NSLog(@"GC Error: %@", error); 102 | if (error.code == GCMErrorAchievementDataMissing) { 103 | self.detailedStatus.stringValue = [NSString stringWithFormat:@"Could not save achievement. Data missing."]; 104 | } 105 | } 106 | 107 | - (void)gameCenterManager:(GameCenterManager *)manager reportedAchievement:(GKAchievement *)achievement withError:(NSError *)error { 108 | if (!error) { 109 | NSLog(@"GCM Reported Achievement: %@", achievement); 110 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Reported achievement with %.1f percent completed", achievement.percentComplete]; 111 | } else { 112 | NSLog(@"GCM Error while reporting achievement: %@", error); 113 | } 114 | } 115 | 116 | - (void)gameCenterManager:(GameCenterManager *)manager reportedScore:(GKScore *)score withError:(NSError *)error { 117 | if (!error) { 118 | NSLog(@"GCM Reported Score: %@", score); 119 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Reported leaderboard score: %lld", score.value]; 120 | } else { 121 | NSLog(@"GCM Error while reporting score: %@", error); 122 | } 123 | } 124 | 125 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveScore:(GKScore *)score { 126 | NSLog(@"Saved GCM Score with value: %lld", score.value); 127 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Score saved for upload to GameCenter."]; 128 | } 129 | 130 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveAchievement:(GKAchievement *)achievement { 131 | NSLog(@"Saved GCM Achievement: %@", achievement); 132 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Achievement saved for upload to GameCenter."]; 133 | } 134 | 135 | - (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController { 136 | [gameCenterViewController dismissViewController:gameCenterViewController]; 137 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Displayed GameCenter leaderboard."]; 138 | } 139 | 140 | - (IBAction)submitHighscore:(id)sender { 141 | [[GameCenterManager sharedManager] saveAndReportScore:[[GameCenterManager sharedManager] highScoreForLeaderboard:@"grp.PlayerScores"]+1 leaderboard:@"grp.PlayerScores" sortOrder:GameCenterSortOrderHighToLow]; 142 | [self.actionStatus setStringValue:[NSString stringWithFormat:@"Score recorded."]]; 143 | } 144 | 145 | - (IBAction)submitAchievement:(id)sender { 146 | if ([[GameCenterManager sharedManager] progressForAchievement:@"grp.FirstAchievement"] == 100) { 147 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.SecondAchievement" percentComplete:100 shouldDisplayNotification:YES]; 148 | } 149 | 150 | if ([[GameCenterManager sharedManager] progressForAchievement:@"grp.FirstAchievement"] == 0) { 151 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.FirstAchievement" percentComplete:100 shouldDisplayNotification:YES]; 152 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.SecondAchievement" percentComplete:50 shouldDisplayNotification:NO]; 153 | } 154 | 155 | NSLog(@"Achievement One Progress: %f | Achievement Two Progress: %f", [[GameCenterManager sharedManager] progressForAchievement:@"grp.FirstAchievement"], [[GameCenterManager sharedManager] progressForAchievement:@"grp.SecondAchievement"]); 156 | [self.actionStatus setStringValue:[NSString stringWithFormat:@"Achievement recorded."]]; 157 | } 158 | 159 | - (IBAction)resetAchievements:(id)sender { 160 | [[GameCenterManager sharedManager] resetAchievementsWithCompletion:^(NSError *error) { 161 | if (error) { 162 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Error reseting all GameCenter achievements."]; 163 | } else { 164 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Reset all GameCenter achievements."]; 165 | } 166 | }]; 167 | } 168 | 169 | - (IBAction)openLeaderboards:(id)sender { 170 | GKGameCenterViewController *leaderboardViewController = [[GKGameCenterViewController alloc] init]; 171 | leaderboardViewController.viewState = GKGameCenterViewControllerStateLeaderboards; 172 | leaderboardViewController.gameCenterDelegate = self; 173 | [self presentViewControllerAsModalWindow:leaderboardViewController]; 174 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Attempting to display GameCenter leaderboards."]; 175 | NSLog(@"Attempting to display GameCenter leaderboards."); 176 | } 177 | 178 | - (IBAction)openAchievements:(id)sender { 179 | GKGameCenterViewController *achievementViewController = [[GKGameCenterViewController alloc] init]; 180 | achievementViewController.viewState = GKGameCenterViewControllerStateAchievements; 181 | achievementViewController.gameCenterDelegate = self; 182 | [self presentViewControllerAsModalWindow:achievementViewController]; 183 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Attempting to display GameCenter achievements."]; 184 | NSLog(@"Attempting to display GameCenter achievements."); 185 | } 186 | 187 | - (IBAction)fetchChallenges:(id)sender { 188 | // This feature is only supported in OS X 10.8.2 and higher 189 | [[GameCenterManager sharedManager] getChallengesWithCompletion:^(NSArray *challenges, NSError *error) { 190 | self.actionStatus.stringValue = [NSString stringWithFormat:@"Loaded GameCenter challenges."]; 191 | NSLog(@"GC Challenges: %@", challenges); 192 | }]; 193 | } 194 | 195 | @end 196 | -------------------------------------------------------------------------------- /GameCenterManager Mac/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /GameCenterManager Mac/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /GameCenterManager Mac/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GameCenterManager Mac 4 | // 5 | // Created by Sam Spencer on 7/2/13. 6 | // Copyright (c) 2013 NABZ Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | return NSApplicationMain(argc, (const char **)argv); 13 | } 14 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "GameCenterManager.h" 11 | 12 | @class ViewController; 13 | 14 | @interface AppDelegate : UIResponder 15 | 16 | @property (strong, nonatomic) UIWindow *window; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // Copyright (c) 2015 Daniel Rosser. All rights reserved. 8 | // 9 | 10 | #import "AppDelegate.h" 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | @synthesize window = _window; 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | // Override point for customization after application launch. 18 | 19 | // Setup GameCenter 20 | [[GameCenterManager sharedManager] setupManager]; 21 | 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application { 26 | /* Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. */ 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | /* Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | */ 34 | } 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | /* Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. */ 38 | } 39 | 40 | - (void)applicationDidBecomeActive:(UIApplication *)application { 41 | /* Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. */ 42 | } 43 | 44 | - (void)applicationWillTerminate:(UIApplication *)application { 45 | /* Called when the application is about to terminate. 46 | Save data if appropriate. 47 | See also applicationDidEnterBackground:. */ 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/Base.lproj/Storyboard_tvOS.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 41 | 47 | 48 | 49 | 50 | 60 | 70 | 80 | 90 | 100 | 110 | 117 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/GameCenterManager-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'GameCenterManager' target in the 'GameCenterManager' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #import 15 | #endif 16 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | GCManager 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIcons 12 | 13 | CFBundleIcons~ipad 14 | 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(PRODUCT_NAME) 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.0 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 1 29 | UIMainStoryboardFile 30 | Storyboard_tvOS 31 | UIRequiredDeviceCapabilities 32 | 33 | arm64 34 | gamekit 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // Copyright (c) 2015 Daniel Rosser. All rights reserved. 8 | // 9 | 10 | #import 11 | #import "GameCenterManager.h" 12 | 13 | @interface ViewController : UIViewController 14 | 15 | @property (strong, nonatomic) IBOutlet UILabel *statusDetailLabel; 16 | @property (weak, nonatomic) IBOutlet UILabel *actionLabel; 17 | @property (weak, nonatomic) IBOutlet UIBarButtonItem *actionBarLabel; 18 | @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; 19 | @property (strong, nonatomic) IBOutlet UIImageView *playerPicture; 20 | @property (weak, nonatomic) IBOutlet UILabel *playerName; 21 | @property (weak, nonatomic) IBOutlet UILabel *playerStatus; 22 | @property (weak, nonatomic) IBOutlet UILabel *tvOSInfo; 23 | 24 | @property (weak, nonatomic) IBOutlet UIButton *buttonReportScore; 25 | @property (weak, nonatomic) IBOutlet UIButton *buttonReportAchievement; 26 | @property (weak, nonatomic) IBOutlet UIButton *buttonFetchChallenges; 27 | @property (weak, nonatomic) IBOutlet UIButton *buttonOpenLeaderboards; 28 | @property (weak, nonatomic) IBOutlet UIButton *buttonOpenAchievements; 29 | @property (weak, nonatomic) IBOutlet UIButton *buttonResetAchievements; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // Copyright (c) 2015 Daniel Rosser. All rights reserved. 8 | // 9 | 10 | #import "ViewController.h" 11 | 12 | @implementation ViewController 13 | @synthesize scrollView; 14 | @synthesize statusDetailLabel, actionLabel, actionBarLabel; 15 | @synthesize playerPicture, playerName, playerStatus, tvOSInfo; 16 | @synthesize buttonReportScore, buttonReportAchievement, buttonFetchChallenges, buttonOpenAchievements, buttonOpenLeaderboards, buttonResetAchievements; 17 | 18 | //------------------------------------------------------------------------------------------------------------// 19 | //------- View Lifecycle -------------------------------------------------------------------------------------// 20 | //------------------------------------------------------------------------------------------------------------// 21 | #pragma mark - View Lifecycle 22 | 23 | - (UIView *)preferredFocusedView 24 | { 25 | if (buttonReportScore) { 26 | return buttonReportScore; 27 | } 28 | 29 | return self.view.preferredFocusedView; 30 | 31 | } 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | 36 | // Setup ViewController Appearance 37 | scrollView.contentSize = CGSizeMake(320, 450); 38 | playerPicture.layer.cornerRadius = playerPicture.frame.size.height/2; 39 | playerPicture.layer.masksToBounds = YES; 40 | [actionBarLabel setTitleTextAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:10]} forState:UIControlStateNormal]; 41 | 42 | // Set GameCenter Manager Delegate 43 | [[GameCenterManager sharedManager] setDelegate:self]; 44 | 45 | UIFocusGuide *focusGuide = [[UIFocusGuide alloc]init]; 46 | focusGuide.preferredFocusedView = [self preferredFocusedView]; 47 | [self.view addLayoutGuide:focusGuide]; 48 | } 49 | 50 | - (void)viewWillAppear:(BOOL)animated { 51 | [super viewWillAppear:YES]; 52 | 53 | BOOL available = [[GameCenterManager sharedManager] checkGameCenterAvailability:YES]; 54 | if (available) { 55 | [self.navigationController.navigationBar setValue:@"GameCenter Available" forKeyPath:@"prompt"]; 56 | } else { 57 | [self.navigationController.navigationBar setValue:@"GameCenter Unavailable" forKeyPath:@"prompt"]; 58 | } 59 | 60 | GKLocalPlayer *player = [[GameCenterManager sharedManager] localPlayerData]; 61 | if (player) { 62 | if ([player isUnderage] == NO) { 63 | actionBarLabel.title = [NSString stringWithFormat:@"%@ signed in.", player.displayName]; 64 | playerName.text = player.displayName; 65 | playerStatus.text = @"Player is not underage"; 66 | [[GameCenterManager sharedManager] localPlayerPhoto:^(UIImage *playerPhoto) { 67 | playerPicture.image = playerPhoto; 68 | }]; 69 | } else { 70 | playerName.text = player.displayName; 71 | playerStatus.text = @"Player is underage"; 72 | actionBarLabel.title = [NSString stringWithFormat:@"Underage player, %@, signed in.", player.displayName]; 73 | } 74 | } else { 75 | actionBarLabel.title = [NSString stringWithFormat:@"No GameCenter player found."]; 76 | } 77 | 78 | #if TARGET_OS_SIMULATOR 79 | tvOSInfo.text = @"With the tvOS Simulator use the Keyboard: Cursor Control Keys (Up Down), Enter = Select, Escape = Menu/Back"; 80 | #endif 81 | 82 | } 83 | 84 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 85 | return YES; 86 | } 87 | 88 | //------------------------------------------------------------------------------------------------------------// 89 | //------- GameCenter Scores ----------------------------------------------------------------------------------// 90 | //------------------------------------------------------------------------------------------------------------// 91 | #pragma mark - GameCenter Scores 92 | 93 | - (IBAction)reportScore { 94 | [[GameCenterManager sharedManager] saveAndReportScore:[[GameCenterManager sharedManager] highScoreForLeaderboard:@"grp.GameCenterManager.PlayerScores"]+1 leaderboard:@"grp.GameCenterManager.PlayerScores" sortOrder:GameCenterSortOrderHighToLow]; 95 | actionBarLabel.title = [NSString stringWithFormat:@"Score recorded."]; 96 | } 97 | 98 | - (IBAction)showLeaderboard { 99 | [[GameCenterManager sharedManager] presentLeaderboardsOnViewController:self withLeaderboard:@"grp.GameCenterManager.PlayerScores"]; 100 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter Leaderboards."]; 101 | } 102 | 103 | //------------------------------------------------------------------------------------------------------------// 104 | //------- GameCenter Achievements ----------------------------------------------------------------------------// 105 | //------------------------------------------------------------------------------------------------------------// 106 | #pragma mark - GameCenter Achievements 107 | 108 | - (IBAction)reportAchievement { 109 | if ([[GameCenterManager sharedManager] progressForAchievement:@"grp.GameCenterManager.FirstAchievement"] == 100) { 110 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.GameCenterManager.SecondAchievement" percentComplete:100 shouldDisplayNotification:YES]; 111 | } 112 | 113 | if ([[GameCenterManager sharedManager] progressForAchievement:@"grp.GameCenterManager.FirstAchievement"] == 0) { 114 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.GameCenterManager.FirstAchievement" percentComplete:100 shouldDisplayNotification:YES]; 115 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.GameCenterManager.SecondAchievement" percentComplete:50 shouldDisplayNotification:NO]; 116 | } 117 | 118 | NSLog(@"Achievement One Progress: %f | Achievement Two Progress: %f", [[GameCenterManager sharedManager] progressForAchievement:@"grp.GameCenterManager.FirstAchievement"], [[GameCenterManager sharedManager] progressForAchievement:@"grp.GameCenterManager.SecondAchievement"]); 119 | actionBarLabel.title = [NSString stringWithFormat:@"Achievement recorded."]; 120 | } 121 | 122 | - (IBAction)showAchievements { 123 | [[GameCenterManager sharedManager] presentAchievementsOnViewController:self]; 124 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter Achievements."]; 125 | } 126 | 127 | //------------------------------------------------------------------------------------------------------------// 128 | //------- GameCenter Challenges ------------------------------------------------------------------------------// 129 | //------------------------------------------------------------------------------------------------------------// 130 | #pragma mark - GameCenter Challenges 131 | 132 | - (IBAction)loadChallenges { 133 | // This feature is only supported in iOS 6 and higher (don't worry - GC Manager will check for you and return NIL if it isn't available) 134 | [[GameCenterManager sharedManager] getChallengesWithCompletion:^(NSArray *challenges, NSError *error) { 135 | actionBarLabel.title = [NSString stringWithFormat:@"Loaded GameCenter challenges. Check log."]; 136 | NSLog(@"GC Challenges: %@ | Error: %@", challenges, error); 137 | }]; 138 | } 139 | 140 | //------------------------------------------------------------------------------------------------------------// 141 | //------- GameKit Delegate -----------------------------------------------------------------------------------// 142 | //------------------------------------------------------------------------------------------------------------// 143 | #pragma mark - GameKit Delegate 144 | 145 | - (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController { 146 | [self dismissViewControllerAnimated:YES completion:nil]; 147 | } 148 | 149 | //------------------------------------------------------------------------------------------------------------// 150 | //------- GameCenter Manager Delegate ------------------------------------------------------------------------// 151 | //------------------------------------------------------------------------------------------------------------// 152 | #pragma mark - GameCenter Manager Delegate 153 | 154 | - (void)gameCenterManager:(GameCenterManager *)manager authenticateUser:(UIViewController *)gameCenterLoginController { 155 | [self presentViewController:gameCenterLoginController animated:YES completion:^{ 156 | NSLog(@"Finished Presenting Authentication Controller"); 157 | }]; 158 | } 159 | 160 | - (void)gameCenterManager:(GameCenterManager *)manager availabilityChanged:(NSDictionary *)availabilityInformation { 161 | NSLog(@"GC Availabilty: %@", availabilityInformation); 162 | if ([[availabilityInformation objectForKey:@"status"] isEqualToString:@"GameCenter Available"]) { 163 | [self.navigationController.navigationBar setValue:@"GameCenter Available" forKeyPath:@"prompt"]; 164 | statusDetailLabel.text = @"Game Center is online, the current player is logged in, and this app is setup."; 165 | } else { 166 | [self.navigationController.navigationBar setValue:@"GameCenter Unavailable" forKeyPath:@"prompt"]; 167 | statusDetailLabel.text = [availabilityInformation objectForKey:@"error"]; 168 | } 169 | 170 | GKLocalPlayer *player = [[GameCenterManager sharedManager] localPlayerData]; 171 | if (player) { 172 | if ([player isUnderage] == NO) { 173 | actionBarLabel.title = [NSString stringWithFormat:@"%@ signed in.", player.displayName]; 174 | playerName.text = player.displayName; 175 | playerStatus.text = @"Player is not underage and is signed-in"; 176 | [[GameCenterManager sharedManager] localPlayerPhoto:^(UIImage *playerPhoto) { 177 | playerPicture.image = playerPhoto; 178 | }]; 179 | } else { 180 | playerName.text = player.displayName; 181 | playerStatus.text = @"Player is underage"; 182 | actionBarLabel.title = [NSString stringWithFormat:@"Underage player, %@, signed in.", player.displayName]; 183 | } 184 | } else { 185 | actionBarLabel.title = [NSString stringWithFormat:@"No GameCenter player found."]; 186 | } 187 | } 188 | 189 | - (void)gameCenterManager:(GameCenterManager *)manager error:(NSError *)error { 190 | NSLog(@"GCM Error: %@", error); 191 | actionBarLabel.title = error.domain; 192 | } 193 | 194 | - (void)gameCenterManager:(GameCenterManager *)manager reportedAchievement:(GKAchievement *)achievement withError:(NSError *)error { 195 | if (!error) { 196 | NSLog(@"GCM Reported Achievement: %@", achievement); 197 | actionBarLabel.title = [NSString stringWithFormat:@"Reported achievement with %.1f percent completed", achievement.percentComplete]; 198 | } else { 199 | NSLog(@"GCM Error while reporting achievement: %@", error); 200 | } 201 | } 202 | 203 | - (void)gameCenterManager:(GameCenterManager *)manager reportedScore:(GKScore *)score withError:(NSError *)error { 204 | if (!error) { 205 | NSLog(@"GCM Reported Score: %@", score); 206 | actionBarLabel.title = [NSString stringWithFormat:@"Reported leaderboard score: %lld", score.value]; 207 | } else { 208 | NSLog(@"GCM Error while reporting score: %@", error); 209 | } 210 | } 211 | 212 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveScore:(GKScore *)score { 213 | NSLog(@"Saved GCM Score with value: %lld", score.value); 214 | actionBarLabel.title = [NSString stringWithFormat:@"Score saved for upload to GameCenter."]; 215 | } 216 | 217 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveAchievement:(GKAchievement *)achievement { 218 | NSLog(@"Saved GCM Achievement: %@", achievement); 219 | actionBarLabel.title = [NSString stringWithFormat:@"Achievement saved for upload to GameCenter."]; 220 | } 221 | 222 | - (IBAction)resetAchievements { 223 | [[GameCenterManager sharedManager] resetAchievementsWithCompletion:^(NSError *error) { 224 | if (error) NSLog(@"Error Resetting Achievements: %@", error); 225 | }]; 226 | } 227 | 228 | 229 | @end 230 | 231 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GameCenterManager 4 | // 5 | // Copyright (c) 2015 Daniel Rosser. All rights reserved. 6 | // 7 | 8 | #import 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMLargeIconBottom.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/GCMLargeIconBottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/GCMLargeIconBottom.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Brackets.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMLargeIconBrackets.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Brackets.imagestacklayer/Content.imageset/GCMLargeIconBrackets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Brackets.imagestacklayer/Content.imageset/GCMLargeIconBrackets.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Brackets.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Brackets.imagestacklayer" 11 | }, 12 | { 13 | "filename" : "Back.imagestacklayer" 14 | } 15 | ], 16 | "info" : { 17 | "version" : 1, 18 | "author" : "xcode" 19 | } 20 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMLargeIconTop.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/GCMLargeIconTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/GCMLargeIconTop.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMLargeIconMiddle.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/GCMLargeIconMiddle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/GCMLargeIconMiddle.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMSmallIconBottom.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/GCMSmallIconBottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/GCMSmallIconBottom.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMSmallIconTop.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/GCMSmallIconTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/GCMSmallIconTop.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "GCMSmallIconMiddle.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/GCMSmallIconMiddle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/GCMSmallIconMiddle.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "size" : "1280x768", 5 | "idiom" : "tv", 6 | "filename" : "App Icon - Large.imagestack", 7 | "role" : "primary-app-icon" 8 | }, 9 | { 10 | "size" : "400x240", 11 | "idiom" : "tv", 12 | "filename" : "App Icon - Small.imagestack", 13 | "role" : "primary-app-icon" 14 | }, 15 | { 16 | "size" : "1920x720", 17 | "idiom" : "tv", 18 | "filename" : "Top Shelf Image.imageset", 19 | "role" : "top-shelf-image" 20 | } 21 | ], 22 | "info" : { 23 | "version" : 1, 24 | "author" : "xcode" 25 | } 26 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/Top Shelf Image.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Brand Assets.brandassets/Top Shelf Image.imageset/LaunchImage.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "landscape", 5 | "idiom" : "tv", 6 | "filename" : "LaunchImage.png", 7 | "extent" : "full-screen", 8 | "minimum-system-version" : "9.0", 9 | "scale" : "1x" 10 | } 11 | ], 12 | "info" : { 13 | "version" : 1, 14 | "author" : "xcode" 15 | } 16 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/LaunchImage.launchimage/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/LaunchImage.launchimage/LaunchImage.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "properties" : { 7 | "identifier" : "grp.GameCenterManager.PlayerScores" 8 | } 9 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "PosterBack.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Back.imagestacklayer/Content.imageset/PosterBack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Back.imagestacklayer/Content.imageset/PosterBack.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "filename" : "PosterFront.png", 6 | "scale" : "1x" 7 | } 8 | ], 9 | "info" : { 10 | "version" : 1, 11 | "author" : "xcode" 12 | } 13 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Front.imagestacklayer/Content.imageset/PosterFront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Front.imagestacklayer/Content.imageset/PosterFront.png -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /GameCenterManager tvOS/tvOSImages.xcassets/Leaderboard.gcleaderboard/Poster.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcshareddata/GameCenterManager.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 7CA789E6-5EBC-40E8-90A6-4A021603BD5F 9 | IDESourceControlProjectName 10 | GameCenterManager 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | B46B0F71F29146CBE0ED10C5B186CB1872D5105B 14 | https://github.com/nihalahmed/GameCenterManager.git 15 | 16 | IDESourceControlProjectPath 17 | GameCenterManager.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | B46B0F71F29146CBE0ED10C5B186CB1872D5105B 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/nihalahmed/GameCenterManager.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | B46B0F71F29146CBE0ED10C5B186CB1872D5105B 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | B46B0F71F29146CBE0ED10C5B186CB1872D5105B 36 | IDESourceControlWCCName 37 | GameCenterManager 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/Spencers.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/Spencers.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/Spencers.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/nihalahmed.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceUserSettings_HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | IDEWorkspaceUserSettings_SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/samspencer.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/samspencer.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/project.xcworkspace/xcuserdata/samspencer.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcschemes/GameCenterManager Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcschemes/GameCenterManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GameCenterManager Mac.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | GameCenterManager.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 659699D51515718800724EBE 21 | 22 | primary 23 | 24 | 25 | 994E293F17838BF300EAACD2 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/nihalahmed.xcuserdatad/xcschemes/GameCenterManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 49 | 50 | 56 | 57 | 58 | 59 | 60 | 61 | 67 | 68 | 74 | 75 | 76 | 77 | 79 | 80 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/nihalahmed.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GameCenterManager.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 659699D51515718800724EBE 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/samspencer.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/samspencer.xcuserdatad/xcschemes/GameCenterManager Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/samspencer.xcuserdatad/xcschemes/GameCenterManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /GameCenterManager.xcodeproj/xcuserdata/samspencer.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GameCenterManager Mac.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | GameCenterManager TV.xcscheme 13 | 14 | orderHint 15 | 2 16 | 17 | GameCenterManager tvOS.xcscheme 18 | 19 | orderHint 20 | 3 21 | 22 | GameCenterManager.xcscheme 23 | 24 | orderHint 25 | 0 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 659699D51515718800724EBE 31 | 32 | primary 33 | 34 | 35 | 99108E3A1C1E7A3200BDD25F 36 | 37 | primary 38 | 39 | 40 | 994E293F17838BF300EAACD2 41 | 42 | primary 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /GameCenterManager/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "GameCenterManager.h" 11 | 12 | @class ViewController; 13 | 14 | @interface AppDelegate : UIResponder 15 | 16 | @property (strong, nonatomic) UIWindow *window; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /GameCenterManager/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @implementation AppDelegate 13 | @synthesize window = _window; 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 16 | // Override point for customization after application launch. 17 | 18 | // Setup GameCenter 19 | [[GameCenterManager sharedManager] setupManager]; 20 | 21 | return YES; 22 | } 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | /* Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. */ 27 | } 28 | 29 | - (void)applicationDidEnterBackground:(UIApplication *)application { 30 | /* Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 31 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 32 | */ 33 | } 34 | 35 | - (void)applicationWillEnterForeground:(UIApplication *)application { 36 | /* Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. */ 37 | } 38 | 39 | - (void)applicationDidBecomeActive:(UIApplication *)application { 40 | /* Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. */ 41 | } 42 | 43 | - (void)applicationWillTerminate:(UIApplication *)application { 44 | /* Called when the application is about to terminate. 45 | Save data if appropriate. 46 | See also applicationDidEnterBackground:. */ 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /GameCenterManager/GameCenterManager-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | GC Manager 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.iRare-Media.GameCenterManager 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 5.3 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 5.3 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Storyboard_iPhone 29 | UIPrerenderedIcon 30 | 31 | UIRequiredDeviceCapabilities 32 | 33 | gamekit 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /GameCenterManager/GameCenterManager-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'GameCenterManager' target in the 'GameCenterManager' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #import 15 | #endif 16 | -------------------------------------------------------------------------------- /GameCenterManager/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "GameCenterManager.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @property (strong, nonatomic) IBOutlet UILabel *statusDetailLabel; 15 | @property (weak, nonatomic) IBOutlet UILabel *actionLabel; 16 | @property (weak, nonatomic) IBOutlet UIBarButtonItem *actionBarLabel; 17 | @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; 18 | @property (strong, nonatomic) IBOutlet UIImageView *playerPicture; 19 | @property (weak, nonatomic) IBOutlet UILabel *playerName; 20 | @property (weak, nonatomic) IBOutlet UILabel *playerStatus; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /GameCenterManager/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // GameCenterManager 4 | // 5 | // Created by iRare Media on Sepetmber 21, 2013. 6 | // Copyright (c) 2013 iRare Media. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @implementation ViewController 12 | @synthesize scrollView; 13 | @synthesize statusDetailLabel, actionLabel, actionBarLabel; 14 | @synthesize playerPicture, playerName, playerStatus; 15 | 16 | //------------------------------------------------------------------------------------------------------------// 17 | //------- View Lifecycle -------------------------------------------------------------------------------------// 18 | //------------------------------------------------------------------------------------------------------------// 19 | #pragma mark - View Lifecycle 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | // Setup ViewController Appearance 25 | scrollView.contentSize = CGSizeMake(320, 450); 26 | playerPicture.layer.cornerRadius = playerPicture.frame.size.height/2; 27 | playerPicture.layer.masksToBounds = YES; 28 | [actionBarLabel setTitleTextAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:10]} forState:UIControlStateNormal]; 29 | 30 | // Set GameCenter Manager Delegate 31 | [[GameCenterManager sharedManager] setDelegate:self]; 32 | } 33 | 34 | - (void)viewWillAppear:(BOOL)animated { 35 | [super viewWillAppear:YES]; 36 | 37 | BOOL available = [[GameCenterManager sharedManager] checkGameCenterAvailability:YES]; 38 | if (available) { 39 | [self.navigationController.navigationBar setValue:@"GameCenter Available" forKeyPath:@"prompt"]; 40 | } else { 41 | [self.navigationController.navigationBar setValue:@"GameCenter Unavailable" forKeyPath:@"prompt"]; 42 | } 43 | 44 | GKLocalPlayer *player = [[GameCenterManager sharedManager] localPlayerData]; 45 | if (player) { 46 | if ([player isUnderage] == NO) { 47 | actionBarLabel.title = [NSString stringWithFormat:@"%@ signed in.", player.displayName]; 48 | playerName.text = player.displayName; 49 | playerStatus.text = @"Player is not underage"; 50 | [[GameCenterManager sharedManager] localPlayerPhoto:^(UIImage *playerPhoto) { 51 | playerPicture.image = playerPhoto; 52 | }]; 53 | } else { 54 | playerName.text = player.displayName; 55 | playerStatus.text = @"Player is underage"; 56 | actionBarLabel.title = [NSString stringWithFormat:@"Underage player, %@, signed in.", player.displayName]; 57 | } 58 | } else { 59 | actionBarLabel.title = [NSString stringWithFormat:@"No GameCenter player found."]; 60 | } 61 | } 62 | 63 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 64 | return YES; 65 | } 66 | 67 | //------------------------------------------------------------------------------------------------------------// 68 | //------- GameCenter Scores ----------------------------------------------------------------------------------// 69 | //------------------------------------------------------------------------------------------------------------// 70 | #pragma mark - GameCenter Scores 71 | 72 | - (IBAction)reportScore { 73 | [[GameCenterManager sharedManager] saveAndReportScore:[[GameCenterManager sharedManager] highScoreForLeaderboard:@"grp.PlayerScores"]+1 leaderboard:@"grp.PlayerScores" sortOrder:GameCenterSortOrderHighToLow]; 74 | actionBarLabel.title = [NSString stringWithFormat:@"Score recorded."]; 75 | } 76 | 77 | - (IBAction)showLeaderboard { 78 | [[GameCenterManager sharedManager] presentLeaderboardsOnViewController:self withLeaderboard:@"grp.PlayerScores"]; 79 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter Leaderboards."]; 80 | } 81 | 82 | //------------------------------------------------------------------------------------------------------------// 83 | //------- GameCenter Achievements ----------------------------------------------------------------------------// 84 | //------------------------------------------------------------------------------------------------------------// 85 | #pragma mark - GameCenter Achievements 86 | 87 | - (IBAction)reportAchievement { 88 | if ([[GameCenterManager sharedManager] progressForAchievement:@"grp.FirstAchievement"] == 100) { 89 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.SecondAchievement" percentComplete:100 shouldDisplayNotification:YES]; 90 | } 91 | 92 | if ([[GameCenterManager sharedManager] progressForAchievement:@"grp.FirstAchievement"] == 0) { 93 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.FirstAchievement" percentComplete:100 shouldDisplayNotification:YES]; 94 | [[GameCenterManager sharedManager] saveAndReportAchievement:@"grp.SecondAchievement" percentComplete:50 shouldDisplayNotification:NO]; 95 | } 96 | 97 | NSLog(@"Achievement One Progress: %f | Achievement Two Progress: %f", [[GameCenterManager sharedManager] progressForAchievement:@"grp.FirstAchievement"], [[GameCenterManager sharedManager] progressForAchievement:@"grp.SecondAchievement"]); 98 | actionBarLabel.title = [NSString stringWithFormat:@"Achievement recorded."]; 99 | } 100 | 101 | - (IBAction)showAchievements { 102 | [[GameCenterManager sharedManager] presentAchievementsOnViewController:self]; 103 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter Achievements."]; 104 | } 105 | 106 | - (IBAction)resetAchievements { 107 | UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Really Reset ALL Achievements?" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Reset Achievements" otherButtonTitles:nil]; 108 | [actionSheet showInView:self.view]; 109 | } 110 | 111 | //------------------------------------------------------------------------------------------------------------// 112 | //------- GameCenter Challenges ------------------------------------------------------------------------------// 113 | //------------------------------------------------------------------------------------------------------------// 114 | #pragma mark - GameCenter Challenges 115 | 116 | - (IBAction)loadChallenges { 117 | // This feature is only supported in iOS 6 and higher (don't worry - GC Manager will check for you and return NIL if it isn't available) 118 | [[GameCenterManager sharedManager] getChallengesWithCompletion:^(NSArray *challenges, NSError *error) { 119 | actionBarLabel.title = [NSString stringWithFormat:@"Loaded GameCenter challenges. Check log."]; 120 | NSLog(@"GC Challenges: %@ | Error: %@", challenges, error); 121 | }]; 122 | } 123 | 124 | //------------------------------------------------------------------------------------------------------------// 125 | //------- GameKit Delegate -----------------------------------------------------------------------------------// 126 | //------------------------------------------------------------------------------------------------------------// 127 | #pragma mark - GameKit Delegate 128 | 129 | - (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController { 130 | [self dismissViewControllerAnimated:YES completion:nil]; 131 | if (gameCenterViewController.viewState == GKGameCenterViewControllerStateAchievements) { 132 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter achievements."]; 133 | } else if (gameCenterViewController.viewState == GKGameCenterViewControllerStateLeaderboards) { 134 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter leaderboard."]; 135 | } else { 136 | actionBarLabel.title = [NSString stringWithFormat:@"Displayed GameCenter controller."]; 137 | } 138 | } 139 | 140 | //------------------------------------------------------------------------------------------------------------// 141 | //------- GameCenter Manager Delegate ------------------------------------------------------------------------// 142 | //------------------------------------------------------------------------------------------------------------// 143 | #pragma mark - GameCenter Manager Delegate 144 | 145 | - (void)gameCenterManager:(GameCenterManager *)manager authenticateUser:(UIViewController *)gameCenterLoginController { 146 | [self presentViewController:gameCenterLoginController animated:YES completion:^{ 147 | NSLog(@"Finished Presenting Authentication Controller"); 148 | }]; 149 | } 150 | 151 | - (void)gameCenterManager:(GameCenterManager *)manager availabilityChanged:(NSDictionary *)availabilityInformation { 152 | NSLog(@"GC Availabilty: %@", availabilityInformation); 153 | if ([[availabilityInformation objectForKey:@"status"] isEqualToString:@"GameCenter Available"]) { 154 | [self.navigationController.navigationBar setValue:@"GameCenter Available" forKeyPath:@"prompt"]; 155 | statusDetailLabel.text = @"Game Center is online, the current player is logged in, and this app is setup."; 156 | } else { 157 | [self.navigationController.navigationBar setValue:@"GameCenter Unavailable" forKeyPath:@"prompt"]; 158 | statusDetailLabel.text = [availabilityInformation objectForKey:@"error"]; 159 | } 160 | 161 | GKLocalPlayer *player = [[GameCenterManager sharedManager] localPlayerData]; 162 | if (player) { 163 | if ([player isUnderage] == NO) { 164 | actionBarLabel.title = [NSString stringWithFormat:@"%@ signed in.", player.displayName]; 165 | playerName.text = player.displayName; 166 | playerStatus.text = @"Player is not underage and is signed-in"; 167 | [[GameCenterManager sharedManager] localPlayerPhoto:^(UIImage *playerPhoto) { 168 | playerPicture.image = playerPhoto; 169 | }]; 170 | } else { 171 | playerName.text = player.displayName; 172 | playerStatus.text = @"Player is underage"; 173 | actionBarLabel.title = [NSString stringWithFormat:@"Underage player, %@, signed in.", player.displayName]; 174 | } 175 | } else { 176 | actionBarLabel.title = [NSString stringWithFormat:@"No GameCenter player found."]; 177 | } 178 | } 179 | 180 | - (void)gameCenterManager:(GameCenterManager *)manager error:(NSError *)error { 181 | NSLog(@"GCM Error: %@", error); 182 | actionBarLabel.title = error.domain; 183 | } 184 | 185 | - (void)gameCenterManager:(GameCenterManager *)manager reportedAchievement:(GKAchievement *)achievement withError:(NSError *)error { 186 | if (!error) { 187 | NSLog(@"GCM Reported Achievement: %@", achievement); 188 | actionBarLabel.title = [NSString stringWithFormat:@"Reported achievement with %.1f percent completed", achievement.percentComplete]; 189 | } else { 190 | NSLog(@"GCM Error while reporting achievement: %@", error); 191 | } 192 | } 193 | 194 | - (void)gameCenterManager:(GameCenterManager *)manager reportedScore:(GKScore *)score withError:(NSError *)error { 195 | if (!error) { 196 | NSLog(@"GCM Reported Score: %@", score); 197 | actionBarLabel.title = [NSString stringWithFormat:@"Reported leaderboard score: %lld", score.value]; 198 | } else { 199 | NSLog(@"GCM Error while reporting score: %@", error); 200 | } 201 | } 202 | 203 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveScore:(GKScore *)score { 204 | NSLog(@"Saved GCM Score with value: %lld", score.value); 205 | actionBarLabel.title = [NSString stringWithFormat:@"Score saved for upload to GameCenter."]; 206 | } 207 | 208 | - (void)gameCenterManager:(GameCenterManager *)manager didSaveAchievement:(GKAchievement *)achievement { 209 | NSLog(@"Saved GCM Achievement: %@", achievement); 210 | actionBarLabel.title = [NSString stringWithFormat:@"Achievement saved for upload to GameCenter."]; 211 | } 212 | 213 | //------------------------------------------------------------------------------------------------------------// 214 | //------- UIActionSheet Delegate -----------------------------------------------------------------------------// 215 | //------------------------------------------------------------------------------------------------------------// 216 | #pragma mark - UIActionSheet Delegate 217 | 218 | - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { 219 | NSString *buttonTitle = [actionSheet buttonTitleAtIndex:buttonIndex]; 220 | if ([buttonTitle isEqualToString:@"Reset Achievements"]) { 221 | [[GameCenterManager sharedManager] resetAchievementsWithCompletion:^(NSError *error) { 222 | if (error) NSLog(@"Error Resetting Achievements: %@", error); 223 | }]; 224 | } 225 | } 226 | 227 | @end 228 | 229 | -------------------------------------------------------------------------------- /GameCenterManager/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /GameCenterManager/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // GameCenterManager 4 | // 5 | // Created by Nihal Ahmed on 12-03-17. 6 | // Copyright (c) 2012 NABZ Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/AppIcon29x29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/AppIcon.appiconset/AppIcon29x29.png -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "filename" : "AppIcon29x29.png", 15 | "idiom" : "iphone", 16 | "scale" : "1x", 17 | "size" : "29x29" 18 | }, 19 | { 20 | "filename" : "AppIcon29x29@2x.png", 21 | "idiom" : "iphone", 22 | "scale" : "2x", 23 | "size" : "29x29" 24 | }, 25 | { 26 | "idiom" : "iphone", 27 | "scale" : "3x", 28 | "size" : "29x29" 29 | }, 30 | { 31 | "filename" : "AppIcon40x40@2x.png", 32 | "idiom" : "iphone", 33 | "scale" : "2x", 34 | "size" : "40x40" 35 | }, 36 | { 37 | "idiom" : "iphone", 38 | "scale" : "3x", 39 | "size" : "40x40" 40 | }, 41 | { 42 | "filename" : "Icon.png", 43 | "idiom" : "iphone", 44 | "scale" : "1x", 45 | "size" : "57x57" 46 | }, 47 | { 48 | "filename" : "Icon@2x.png", 49 | "idiom" : "iphone", 50 | "scale" : "2x", 51 | "size" : "57x57" 52 | }, 53 | { 54 | "filename" : "AppIcon60x60@2x.png", 55 | "idiom" : "iphone", 56 | "scale" : "2x", 57 | "size" : "60x60" 58 | }, 59 | { 60 | "idiom" : "iphone", 61 | "scale" : "3x", 62 | "size" : "60x60" 63 | }, 64 | { 65 | "idiom" : "ios-marketing", 66 | "scale" : "1x", 67 | "size" : "1024x1024" 68 | } 69 | ], 70 | "info" : { 71 | "author" : "xcode", 72 | "version" : 1 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /Images.xcassets/AppIcon.appiconset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/AppIcon.appiconset/Icon@2x.png -------------------------------------------------------------------------------- /Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Images.xcassets/GCSymbol.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "GK Icon-512.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "GK Icon-512@2x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Images.xcassets/GCSymbol.imageset/GK Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/GCSymbol.imageset/GK Icon-512.png -------------------------------------------------------------------------------- /Images.xcassets/GCSymbol.imageset/GK Icon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/GCSymbol.imageset/GK Icon-512@2x.png -------------------------------------------------------------------------------- /Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "filename" : "Default@2x.png", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "extent" : "full-screen", 13 | "idiom" : "iphone", 14 | "subtype" : "retina4", 15 | "filename" : "Default-568h@2x.png", 16 | "minimum-system-version" : "7.0", 17 | "orientation" : "portrait", 18 | "scale" : "2x" 19 | }, 20 | { 21 | "orientation" : "portrait", 22 | "idiom" : "iphone", 23 | "extent" : "full-screen", 24 | "filename" : "Default.png", 25 | "scale" : "1x" 26 | }, 27 | { 28 | "orientation" : "portrait", 29 | "idiom" : "iphone", 30 | "extent" : "full-screen", 31 | "filename" : "Default@2x-1.png", 32 | "scale" : "2x" 33 | }, 34 | { 35 | "orientation" : "portrait", 36 | "idiom" : "iphone", 37 | "extent" : "full-screen", 38 | "filename" : "Default-568h@2x.png", 39 | "subtype" : "retina4", 40 | "scale" : "2x" 41 | } 42 | ], 43 | "info" : { 44 | "version" : 1, 45 | "author" : "xcode" 46 | } 47 | } -------------------------------------------------------------------------------- /Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /Images.xcassets/LaunchImage.launchimage/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/LaunchImage.launchimage/Default.png -------------------------------------------------------------------------------- /Images.xcassets/LaunchImage.launchimage/Default@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/LaunchImage.launchimage/Default@2x-1.png -------------------------------------------------------------------------------- /Images.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "GK Icon-16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "GK Icon-16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "GK Icon-32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "GK Icon-32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "GK Icon-128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "GK Icon-128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "GK Icon-256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "GK Icon-256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "GK Icon-512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "GK Icon-512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-128.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-128@2x.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-16.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-16@2x.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-256.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-256@2x.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-32.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-32@2x.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-512.png -------------------------------------------------------------------------------- /Images.xcassets/MacAppIcon.appiconset/GK Icon-512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images.xcassets/MacAppIcon.appiconset/GK Icon-512@2x.png -------------------------------------------------------------------------------- /Images/GameBanner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images/GameBanner.png -------------------------------------------------------------------------------- /Images/GameBanner.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images/GameBanner.psd -------------------------------------------------------------------------------- /Images/Interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images/Interface.png -------------------------------------------------------------------------------- /Images/Interface.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nihalahmed/GameCenterManager/bcde6691bb55bb00737a1778799625061f485ca4/Images/Interface.psd -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | #GameCenter Manager 2 | Copyright © 2013, iRare Media. Copyright © 2012, Nihal Ahmed. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | Neither the name of NABZ Software, iRare Media, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | 13 | #Reachability 14 | Reachability Class from Tony Million is used in this project. The Reachability project is available on [GitHub](https://github.com/tonymillion/Reachability). The Reachability license (as of October 20, 2013) is included, verbatim, below: 15 | 16 | Copyright (c) 2011-2013, Tony Million. All rights reserved. 17 | 18 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 19 | 20 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 21 | 22 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 23 | 24 | > THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 28 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /travis/ios/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ev 3 | echo "**** Building - iOS GameCenterManager Example Project ****" 4 | ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../.." ; pwd -P )"} 5 | xcodebuild -project "$ROOT/GameCenterManager.xcodeproj" -target GameCenterManager -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO 6 | 7 | -------------------------------------------------------------------------------- /travis/osx/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ev 3 | ROOT=${TRAVIS_BUILD_DIR:-"$( cd "$(dirname "$0")/../.." ; pwd -P )"} 4 | echo "**** Building - OSX GameCenterManager Example Project ****" 5 | xcodebuild -configuration Release -target "GameCenterManager Mac" -project "$ROOT/GameCenterManager.xcodeproj" 6 | 7 | --------------------------------------------------------------------------------