home *** CD-ROM | disk | FTP | other *** search
- /* server.c
- *
- * Contains code needed to start and run the game server.
- */
- #include "net3d.h"
- #include <netdb.h>
- #include <netinet/in.h>
-
- static void displayhelp(char *);
-
- int main(int argc, char **argv)
- {
- int mainsock; /* socket used for accepting new players */
- int psocks[MAX_PLAYERS]; /* sockets connecting to players */
- fd_set fds; /* file descriptors for select */
- int plcount=0; /* number of players */
- char *pnames[MAX_PLAYERS]; /* names of players */
- struct object *ohead=NULL; /* object list */
- struct vehicle *vhead=NULL; /* vehicle list */
- struct map mp={NULL, NULL, 0, 0, 0.0, 0.0, {0,0,300}};
- /* game world terrain details */
- struct vehicle *vpos; /* vehicle assigned to each player */
- struct vehicle *pvehicles[MAX_PLAYERS];
- /* vehicles owned by players */
- int finalcountdown=100; /* frames between death of the last
- * player and the end of the game */
- char *filepaths[50]; /* actual paths to .v files given on
- * command line */
-
- int i; /* scratch variables */
- int j;
-
- if (argc == 1) {
- printf("usage : Server mode : %s <vehicle files>\n",argv[0]);
- printf(" Help : %s -help\n",argv[0]);
- exit(0);
- }
- if (!strcmp(argv[1],"-help")) {
- displayhelp(argv[0]);
- exit(0);
- }
-
- /* We want children reaped automatically by default. */
- signal(SIGCHLD, SIG_IGN);
-
- initcaches();
- readextravehicles(); /* read extra vehicles from internal array */
-
- /* For each vehicle file on the command line, pass it through cpp
- * before reading into the object and vehicle lists.
- */
- for(i=1; i<argc; i++) {
- int pifd; /* file descriptor for pipe */
- struct stat dummy;
- char currentdir[100]; /* path to .v file in current dir */
- char net3ddir[100]; /* path to .v file in NET3D_DIR */
-
- /* Look for the file in the current directory and in NET3D_DIR,
- * then pipe it through cpp.
- */
- sprintf(currentdir,"%s",argv[i]);
- sprintf(net3ddir,"%s/%s",NET3D_DIR,argv[i]);
- if (stat(currentdir,&dummy) != -1) {
- pifd=pipethrough(CPPPATH,currentdir);
- readfile(&ohead,&vhead,pifd,&mp);
- printf("done reading %s\n",currentdir);
- close(pifd);
- filepaths[i] = strdupe(currentdir);
- }
- else if (stat(net3ddir,&dummy) != -1) {
- pifd=pipethrough(CPPPATH,net3ddir);
- readfile(&ohead,&vhead,pifd,&mp);
- printf("done reading %s\n",net3ddir);
- close(pifd);
- filepaths[i] = strdupe(net3ddir);
- }
- else {
- printf("file %s not found\n",argv[i]);
- exit(0);
- }
- }
-
- /* check if a sensible world was read in */
- if (vhead==NULL) {
- printf("No vehicles available for use\n");
- exit(1);
- }
- else {
- makemap(&ohead,&mp);
- worldinfo(vhead,ohead);
- printf("Waiting for players... hit return to start game\n");
- }
-
- /* open initial socket for connections from clients */
- mainsock=OpenDest();
-
- do {
- /* wait for either a key-press or a new connection */
- FD_ZERO(&fds);
- FD_SET(0,&fds);
- FD_SET(mainsock,&fds);
- #ifdef __hpux
- select(mainsock+1,(int *)&fds,NULL,NULL,NULL);
- #else
- select(mainsock+1,&fds,NULL,NULL,NULL);
- #endif
-
- if (FD_ISSET(mainsock,&fds)) {
- char *hname;
-
- /* A new connection has arrived.
- */
- struct sockaddr_in newaddr;
- struct hostent *newhost;
- int newaddrsize;
-
- /* accept incoming connection, and find the address
- * of the sender. */
- newaddrsize = sizeof(newaddr);
- psocks[plcount]=accept(mainsock,(struct sockaddr *)
- &newaddr,&newaddrsize);
- newhost = gethostbyaddr((char *)&newaddr.sin_addr.s_addr,
- 4,AF_INET);
- hname = newhost ? newhost->h_name : "unknown";
-
- /* tell player the version number */
- nprintf(psocks[plcount],"%s\n",NET3D_VERSION);
-
- /* get name from player, or version error */
- pnames[plcount]=strdupe(ngets(psocks[plcount]));
- if (!strcmp(pnames[plcount],VERSION_ERROR)) {
- printf("player on machine %s has wrong version..."
- "rejected\n",hname);
- close(psocks[plcount]);
- }
- else {
- printf("received connection from %s on %s\n",
- pnames[plcount],hname);
- plcount++;
- }
- }
- } while(!FD_ISSET(0,&fds));
-
- if (plcount)
- printf("starting game with %d players\n",plcount);
- else {
- printf("no players :(\n");
- exit(0);
- }
-
- /* list all players */
- for(i=0; i<plcount; i++)
- printf("Player %d is \"%s\"\n",i,pnames[i]);
-
- /* once again, run all the vehicle files through cpp, but this time
- * send them through the sockets to each client
- */
- for(i=1; i<argc; i++) {
- char syscom[100]; /* buffer used for 'popen' call */
- FILE *pifp; /* file pointer for 'popen' call */
-
- sprintf(syscom,"%s %s",CPPPATH,filepaths[i]);
- pifp=popen(syscom,"r");
- while(!feof(pifp)) {
- char buf[100]; /* a line from the pre-processor */
- int j;
-
- /* read a line, and send it to all clients */
- fgets(buf,100,pifp);
- for(j=0; j<plcount; j++)
- nprintf(psocks[j],"%s",buf);
- }
- pclose(pifp);
- for(j=0; j<plcount; j++)
- nprintf(psocks[j],"\n");
- printf("done transmitting %s\n",filepaths[i]);
- }
- /* send the 'end' token to all clients, to indicate the end of
- * the vehicle files
- */
- for(i=0; i<plcount; i++)
- nprintf(psocks[i],"\nend\n");
-
- /* tell each client their player number */
- vpos=vhead;
- for(i=0; i<plcount; i++) {
- if (vpos) {
- printf("%s has vehicle %s\n",pnames[i],vpos->code);
- nprintf(psocks[i],"%d\n",i);
- vpos=vpos->next;
- }
- else {
- printf("player %d has no vehicle!!\n",i);
- break;
- }
- }
- /* send 'no vehicle' signal to all clients who don't have a vehicle */
- j=i;
- for(; i<plcount; i++) {
- nprintf(psocks[i],"-1\n",i);
- shutdown(psocks[i],2);
- close(psocks[i]);
- }
- /* truncate player list to the number who got vehicles */
- plcount=j;
- stillalive=plcount;
-
- /* tell each client the number of players in the game, and the names
- * of the players.
- */
- for(i=0; i<plcount; i++) {
- int j;
- nprintf(psocks[i],"%d\n",plcount);
- for(j=0; j<plcount; j++)
- nprintf(psocks[i],"%s\n",pnames[j]);
- }
-
- /* store the vehicles owned by each player */
- vpos=vhead;
- for(i=0; i<plcount; i++) {
- pvehicles[i]=vpos;
- vpos=vpos->next;
- }
-
- /* send to each client a message consisting only of the game time,
- * to start each client up.
- */
- for(i=0; i<plcount; i++)
- nprintf(psocks[i],"%lf\n",gametime());
-
- /* The main server loop.
- *
- * In here, we wait for all the clients to reply with their commands,
- * and once done, send gametime() and those commands to all clients.
- */
- while(stillalive || finalcountdown) {
- processnet(psocks,plcount,mainsock);
- if (!stillalive)
- finalcountdown--;
- }
-
- /* no-one is left. Send quit messages to all clients */
- printf("All players destroyed. GAME OVER\n");
- for(i=0; i<plcount; i++)
- nprintf(psocks[i],"%lf q 0 0.0\n",gametime());
-
- /* close all connections to players and the main socket
- */
- for(i=0; i<plcount;i++) {
- shutdown(psocks[i],2);
- close(psocks[i]);
- }
- shutdown(mainsock,2);
- close(mainsock);
- return(0);
- }
-
- static void displayhelp(char *cn)
- {
- printf(
- "net3d server help\n"
- "-----------------\n"
- "Server mode : To start the net3d server, type :\n"
- " %s <vehicle file> <vehicle file> ...\n"
- " Vehicle files have the extension .v, and at least one must\n"
- " be given."
- "\n"
- " Once the server has started, it will wait for net3d clients\n"
- " to connect, and display connections as they are received.\n"
- " When enough connections have arrived, and you want to start\n"
- " the game, hit return. Each player will be given a vehicle, and\n"
- " the game will start\n"
- ,cn);
- }
-
-
-