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.