Guest User

Untitled

a guest
Jul 18th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.03 KB | None | 0 0
  1. #pragma mark -
  2. #pragma mark Peer Picker Related Methods
  3.  
  4. -(void)startPicker {
  5. GKPeerPickerController* picker;
  6.  
  7. self.gameState = kStatePicker; // we're going to do Multiplayer!
  8.  
  9. picker = [[GKPeerPickerController alloc] init]; // note: picker is released in various picker delegate methods when picker use is done.
  10. picker.delegate = self;
  11. [picker show]; // show the Peer Picker
  12. }
  13.  
  14. #pragma mark GKPeerPickerControllerDelegate Methods
  15.  
  16. - (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker {
  17. // Peer Picker automatically dismisses on user cancel. No need to programmatically dismiss.
  18.  
  19. // autorelease the picker.
  20. picker.delegate = nil;
  21. [picker autorelease];
  22.  
  23. // invalidate and release game session if one is around.
  24. if(self.gameSession != nil) {
  25. [self invalidateSession:self.gameSession];
  26. self.gameSession = nil;
  27. }
  28.  
  29. // go back to start mode
  30. self.gameState = kStateStartGame;
  31. }
  32.  
  33. /*
  34. * Note: No need to implement -peerPickerController:didSelectConnectionType: delegate method since this app does not support multiple connection types.
  35. * - see reference documentation for this delegate method and the GKPeerPickerController's connectionTypesMask property.
  36. */
  37.  
  38. //
  39. // Provide a custom session that has a custom session ID. This is also an opportunity to provide a session with a custom display name.
  40. //
  41. - (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type {
  42. GKSession *session = [[GKSession alloc] initWithSessionID:kTankSessionID displayName:nil sessionMode:GKSessionModePeer];
  43. return [session autorelease]; // peer picker retains a reference, so autorelease ours so we don't leak.
  44. }
  45.  
  46. - (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session {
  47. // Remember the current peer.
  48. self.gamePeerId = peerID; // copy
  49.  
  50. // Make sure we have a reference to the game session and it is set up
  51. self.gameSession = session; // retain
  52. self.gameSession.delegate = self;
  53. [self.gameSession setDataReceiveHandler:self withContext:NULL];
  54.  
  55. // Done with the Peer Picker so dismiss it.
  56. [picker dismiss];
  57. picker.delegate = nil;
  58. [picker autorelease];
  59.  
  60. // Start Multiplayer game by entering a cointoss state to determine who is server/client.
  61. self.gameState = kStateMultiplayerCointoss;
  62. }
  63.  
  64. #pragma mark -
  65. #pragma mark Session Related Methods
  66.  
  67. //
  68. // invalidate session
  69. //
  70. - (void)invalidateSession:(GKSession *)session {
  71. if(session != nil) {
  72. [session disconnectFromAllPeers];
  73. session.available = NO;
  74. [session setDataReceiveHandler: nil withContext: NULL];
  75. session.delegate = nil;
  76. }
  77. }
  78.  
  79. #pragma mark Data Send/Receive Methods
  80.  
  81. /*
  82. * Getting a data packet. This is the data receive handler method expected by the GKSession.
  83. * We set ourselves as the receive data handler in the -peerPickerController:didConnectPeer:toSession: method.
  84. */
  85. - (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context {
  86. static int lastPacketTime = -1;
  87. unsigned char *incomingPacket = (unsigned char *)[data bytes];
  88. int *pIntData = (int *)&incomingPacket[0];
  89. //
  90. // developer check the network time and make sure packers are in order
  91. //
  92. int packetTime = pIntData[0];
  93. int packetID = pIntData[1];
  94. if(packetTime < lastPacketTime && packetID != NETWORK_COINTOSS) {
  95. return;
  96. }
  97.  
  98. lastPacketTime = packetTime;
  99. switch( packetID ) {
  100. case NETWORK_COINTOSS:
  101. {
  102. // coin toss to determine roles of the two players
  103. int coinToss = pIntData[2];
  104. // if other player's coin is higher than ours then that player is the server
  105. if(coinToss > gameUniqueID) {
  106. self.peerStatus = kClient;
  107. }
  108.  
  109. // notify user of tank color
  110. self.gameLabel.text = (self.peerStatus == kServer) ? kBlueLabel : kRedLabel; // server is the blue tank, client is red
  111. self.gameLabel.hidden = NO;
  112. // after 1 second fire method to hide the label
  113. [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(hideGameLabel:) userInfo:nil repeats:NO];
  114. }
  115. break;
  116. case NETWORK_MOVE_EVENT:
  117. {
  118. // received move event from other player, update other player's position/destination info
  119. tankInfo *ts = (tankInfo *)&incomingPacket[8];
  120. int peer = (self.peerStatus == kServer) ? kClient : kServer;
  121. tankInfo *ds = &tankStats[peer];
  122. ds->tankDestination = ts->tankDestination;
  123. ds->tankDirection = ts->tankDirection;
  124. }
  125. break;
  126. case NETWORK_FIRE_EVENT:
  127. {
  128. // received a missile fire event from other player, update other player's firing status
  129. tankInfo *ts = (tankInfo *)&incomingPacket[8];
  130. int peer = (self.peerStatus == kServer) ? kClient : kServer;
  131. tankInfo *ds = &tankStats[peer];
  132. ds->tankMissile = ts->tankMissile;
  133. ds->tankMissilePosition = ts->tankMissilePosition;
  134. ds->tankMissileDirection = ts->tankMissileDirection;
  135. }
  136. break;
  137. case NETWORK_HEARTBEAT:
  138. {
  139. // Received heartbeat data with other player's position, destination, and firing status.
  140.  
  141. // update the other player's info from the heartbeat
  142. tankInfo *ts = (tankInfo *)&incomingPacket[8]; // tank data as seen on other client
  143. int peer = (self.peerStatus == kServer) ? kClient : kServer;
  144. tankInfo *ds = &tankStats[peer]; // same tank, as we see it on this client
  145. memcpy( ds, ts, sizeof(tankInfo) );
  146.  
  147. // update heartbeat timestamp
  148. self.lastHeartbeatDate = [NSDate date];
  149.  
  150. // if we were trying to reconnect, set the state back to multiplayer as the peer is back
  151. if(self.gameState == kStateMultiplayerReconnect) {
  152. if(self.connectionAlert && self.connectionAlert.visible) {
  153. [self.connectionAlert dismissWithClickedButtonIndex:-1 animated:YES];
  154. }
  155. self.gameState = kStateMultiplayer;
  156. }
  157. }
  158. break;
  159. default:
  160. // error
  161. break;
  162. }
  163. }
  164.  
  165. - (void)sendNetworkPacket:(GKSession *)session packetID:(int)packetID withData:(void *)data ofLength:(int)length reliable:(BOOL)howtosend {
  166. // the packet we'll send is resued
  167. static unsigned char networkPacket[kMaxTankPacketSize];
  168. const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our header
  169.  
  170. if(length < (kMaxTankPacketSize - packetHeaderSize)) { // our networkPacket buffer size minus the size of the header info
  171. int *pIntData = (int *)&networkPacket[0];
  172. // header info
  173. pIntData[0] = gamePacketNumber++;
  174. pIntData[1] = packetID;
  175. // copy data in after the header
  176. memcpy( &networkPacket[packetHeaderSize], data, length );
  177.  
  178. NSData *packet = [NSData dataWithBytes: networkPacket length: (length+8)];
  179. if(howtosend == YES) {
  180. [session sendData:packet toPeers:[NSArray arrayWithObject:gamePeerId] withDataMode:GKSendDataReliable error:nil];
  181. } else {
  182. [session sendData:packet toPeers:[NSArray arrayWithObject:gamePeerId] withDataMode:GKSendDataUnreliable error:nil];
  183. }
  184. }
  185. }
  186.  
  187. #pragma mark GKSessionDelegate Methods
  188.  
  189. // we've gotten a state change in the session
  190. - (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
  191. if(self.gameState == kStatePicker) {
  192. return; // only do stuff if we're in multiplayer, otherwise it is probably for Picker
  193. }
  194.  
  195. if(state == GKPeerStateDisconnected) {
  196. // We've been disconnected from the other peer.
  197.  
  198. // Update user alert or throw alert if it isn't already up
  199. NSString *message = [NSString stringWithFormat:@"Could not reconnect with %@.", [session displayNameForPeer:peerID]];
  200. if((self.gameState == kStateMultiplayerReconnect) && self.connectionAlert && self.connectionAlert.visible) {
  201. self.connectionAlert.message = message;
  202. }
  203. else {
  204. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Lost Connection" message:message delegate:self cancelButtonTitle:@"End Game" otherButtonTitles:nil];
  205. self.connectionAlert = alert;
  206. [alert show];
  207. [alert release];
  208. }
  209.  
  210. // go back to start mode
  211. self.gameState = kStateStartGame;
  212. }
  213. }
Add Comment
Please, Sign In to add comment