This is NetworkPlayer.m in view mode; [Download] [Up]
/* * NetworkPlayer * description: a networked subclass of Player. * history: * 3/15/93 [Erik Kay] - created * 6/2/93 [Erik Kay] - reworked much of the code * 6/8/93 [Erik Kay] - better error recovery * 6/8/93 [Erik Kay] - bycopy support for transmitting boards */ #import <remote/NXProxy.h> #import "SplatGame.h" #import "NetworkPlayer.h" // search for the server in another thread... void lookForServer (id self) { [self lookForServer]; cthread_exit(0); } @implementation NetworkPlayer - init { [super init]; otherPlayer = nil; return self; } - free { [super free]; [myServer free]; [otherPlayer free]; free(playerName); return self; } -(BOOL)isConnected { if (otherPlayer) return YES; else return NO; } // This is the method called by the main game when it wants the net client // to try to connect to the Splat server. This searching is done in another // thread so that it can be cancelled by the user. It also registers its // own NXConnection so that the server can connect to it. - connectToServer { char hn[256]; if (!hostname) { NXRunAlertPanel("Error","You must type in the hostname that the server is running on to be a Splat client. Aborting game.","OK",NULL,NULL); return self; } gethostname(hn,255); sprintf(myServerName,"splatClient%s",hn); sprintf(otherServerName,"splatServer%s",hostname); myServer = [NXConnection registerRoot:self withName:myServerName]; [myServer runFromAppKitWithPriority:NX_MODALRESPTHRESHOLD]; [myServer registerForInvalidationNotification:self]; cthread_detach(cthread_fork((cthread_fn_t)lookForServer,self)); return self; } // here's where the actual connection is being done - lookForServer { struct timeval t; struct timezone tz; long orig; // Look for the server for 60 seconds, and then abort with a timeout. //! This is really lame. I should just be using the builtin timeout //! support in DO. gettimeofday(&t,&tz); orig = t.tv_sec; while (!otherPlayer && ((t.tv_sec - orig) < 60)) { otherPlayer = [NXConnection connectToName:otherServerName onHost:hostname]; [[otherPlayer connectionForProxy] registerForInvalidationNotification:self]; gettimeofday(&t,&tz); } if (!otherPlayer) { NXRunAlertPanel("Error","Connection timed out. Unable to connect to Splat server on host %s","OK",NULL,NULL,hostname); return self; } [otherPlayer lookForClient]; return self; } // same as above, just looking for the client this time - connectToClient { char hn[256]; if (!hostname) { NXRunAlertPanel("Error","You must type in the hostname of the Splat client so that I know who to talk to. Aborting game.","OK",NULL,NULL); return self; } gethostname(hn,255); sprintf(myServerName,"splatServer%s",hn); sprintf(otherServerName,"splatClient%s",hostname); myServer = [NXConnection registerRoot:self withName:myServerName]; [myServer registerForInvalidationNotification:self]; [myServer runFromAppKitWithPriority:NX_MODALRESPTHRESHOLD]; return self; } // actually connect to the client - (oneway void)lookForClient { struct timeval t; struct timezone tz; long orig; // timeout after 10 seconds. This is not really needed at all since // we got this message from the client, so connecting should be a snap. //! Once again, I should be using the builtin timeout support in DO. gettimeofday(&t,&tz); orig = t.tv_sec; while (!otherPlayer && ((t.tv_sec - orig) < 10)) { otherPlayer = [NXConnection connectToName:otherServerName onHost:hostname]; [[otherPlayer connectionForProxy] registerForInvalidationNotification:self]; gettimeofday(&t,&tz); } if (!otherPlayer) { NXRunAlertPanel("Error","Connection timed out. Unable to connect to Splat client on host %s","OK",NULL,NULL,hostname); return; } // we're the server, so we'll make the client use our board [otherPlayer setClientBoard:[game board]]; return; } // set the game board to be what the server told us... - (oneway void)setClientBoard:(bycopy Board *)b { [game setBoard:b]; return; } // do the next move (tell the player we represent that they should do their // nexty move by passing them the last move that was done here) - doNextMove:(Board *)b { if ((b->currentMove.from.col == 0) && (b->currentMove.from.row == 0) && (b->currentMove.to.col == 0) && (b->currentMove.to.row == 0)) return self; [otherPlayer completedMove:&(b->currentMove)]; return self; } // do the last move that was done by the other side - (oneway void)completedMove:(in move *)mv { [game startMove:mv]; return; } // clean up - gameOver:(Board *)b { currentState = PLAYER_INACTIVE; [otherPlayer completedMove:&(b->currentMove)]; return self; } - setHostname:(const char *)nm { strncpy(hostname,nm,255); return self; } - (char *)hostname { return hostname; } - (char *)playerName { if (otherPlayer && !playerName) { playerName = malloc(strlen([otherPlayer otherPlayerName]) + 1); strcpy(playerName,[otherPlayer otherPlayerName]); } return playerName; } - (char *)otherPlayerName { id player1, player2; player1 = [game player1]; player2 = [game player2]; if (player1 == self) return [player2 playerName]; else return [player1 playerName]; } // when one side pauses or stops, the other side should too. - setPlayerState:(PlayerState)state { PlayerState oldState; if (state == currentState) return self; oldState = currentState; [super setPlayerState:state]; switch (currentState) { case PLAYER_STOPPED: [otherPlayer stopGame]; break; case PLAYER_PAUSED: [otherPlayer pauseGame]; break; case PLAYER_ACTIVE: if (oldState == PLAYER_STOPPED) { if (self == (id)[game player2]) { [otherPlayer initNetGame]; } } else if (oldState == PLAYER_PAUSED) { [otherPlayer unpauseGame]; } break; case PLAYER_INACTIVE: if (oldState == PLAYER_STOPPED) { if (self == (id)[game player2]) { [otherPlayer initNetGame]; } } else if (oldState == PLAYER_PAUSED) { [otherPlayer unpauseGame]; } break; } return self; } - setActive:(BOOL)state { return self; } // start a network game - (oneway void)initNetGame { if (self == (id)[game player1]) { [game showGame]; } else [game initGame]; return; } - (oneway void)stopGame { [game stopGame:self]; return; } - (oneway void)pauseGame { if ([game gameState] == GAME_RUNNING) [game pauseGame:self]; return; } - (oneway void)unpauseGame { if ([game gameState] == GAME_PAUSED) [game pauseGame:self]; return; } // abort when the connection has been dropped //! this should free/remove the game rather than just stopping it - senderIsInvalid:sender { NXRunAlertPanel("Game Aborted","%s on host %s has quit the game.", "OK",NULL,NULL,playerName,hostname); [game stopGame:self]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.