home *** CD-ROM | disk | FTP | other *** search
- /* This program was written by Helmut Hoenig */
- /* in May of 1988 at the Unitversity of */
- /* Kaiserslautern, Germany. It may be copied freely. */
-
- #define moremessages 0
-
- #include <X11/Xlib.h>
- #include <stdio.h>
- #include <strings.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/uio.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <netdb.h>
-
- #include "header.h"
- #include "messages.h"
-
- short readshort();
-
- #define HMAX 8
- int max; /* when starting the system, this is the actual number of players */
-
- int messflag;
- #define MAXPLAYERS 10
-
- /* fields for result-messages */
- static int points[MAXPLAYERS];
- static int place[MAXPLAYERS];
- static int count[MAXPLAYERS];
- static int sorted[MAXPLAYERS];
- static char tscreen[20][80];
- static int lines;
- static int players;
-
- struct hostent *hostaddr[HMAX];
- int active[HMAX]={ 0,0,0,0,0,0,0,0 };
- int auto_only[HMAX]={ 0,0,0,0,0,0,0,0 };
-
- char host_name[HMAX][20];
- char disp_name[HMAX][20];
-
- int sockets[HMAX],ports[HMAX];
- long play_time[HMAX];
- struct sockaddr_in rsin[HMAX];
- int rsinlen[HMAX];
- int socks[HMAX];
-
-
- char *my_host; /* eigener hostname */
-
- struct servent *sp;
-
- struct sockaddr_in sin;
- int mastersocket;
-
- char *getenv();
-
- long packet_count = 0;
- int data_error=0;
- int g_count=0;
- int match;
-
- Display *display;
- Screen *screen;
- char dispname[20];
- extern XFontStruct *(finfo[]);
- extern Window aw;
- int waiting;
- XEvent event;
- #define FID 0
-
- usage()
- {
- printf("\n\nusage:\ttron_server [ option ] <player_list>\n");
- printf("\n\t-v - prints some additional messages in starting sequence.\n");
- printf("\t-h - prints this.\n");
- printf("\t-s<sec> - to sleep <sec> seconds after the start of each players.\n");
- printf("\n<player_list>: List with the display_names and/or host_names of the players.\n");
- printf(" If only one name per player is given, the display is the display of the host.\n");
- printf(" Otherwise you can write <display_name>'^'<host_name> to get a special display.\n");
- printf(" An empty display-name stands for an automatic player. (e.g. ^host)\n");
- printf("\n");
- }
-
- main(argc,argv)
- int argc;
- char *argv[];
- { int i,j;
- char command[200];
- int test;
- int waitflag=0;
- char *ptr;
- char *disp_arg=NULL;
- XSetWindowAttributes attrib;
-
- /*********************************************************************
- * At first, the host-names of the command-line are tested. *
- * If there is a display for the player (no auto-player), the server *
- * tests the possibility of opening XWindows on the display. If that *
- * fails or a display is used twice, the player is ignored. *
- * ==> In the end, there should be at least 2 correct names. *
- *********************************************************************/
-
- max=0;
- messflag=0;
- printf("\nTRON - programmed by Helmut Hoenig. (MAY-1988)\n");
- printf("startup-sequence at the following displays:\n");
-
- if (argc==1)
- { usage();
- exit();
- };
-
- for (i=1;i<argc;i++)
- { if (strcmp("-v",argv[i])==0) messflag=1;
- else if (strncmp("-s",argv[i],2)==0) waitflag=atoi(&argv[i][2]);
- else if ((strcmp("-",argv[i])==0)||(strcmp("-h",argv[i])==0))
- { usage();
- exit();
- }
- else if (strcmp("-display",argv[i])==0) disp_arg = argv[++i];
- else if (max<HMAX)
- { ptr = index(argv[i],'^');
- if (ptr==NULL)
- { if ((ptr=index(argv[i],':'))==NULL)
- {
- /* a single host-name is extended by ":0.0" to the display-name */
- strcpy(host_name[max],argv[i]);
- strcpy(disp_name[max],argv[i]);
- strcat(disp_name[max],":0.0");
- }
- else
- {
- /* in display-names the host-names are the string up to the ':' */
- strncpy(host_name[max],argv[i],ptr-argv[i]);
- host_name[max][ptr-argv[i]+1]='\0';
- strcpy(disp_name[max],argv[i]);
- if ((ptr=index(argv[i],'.'))==NULL)
- { strcat(disp_name[max],".0");
- }
- }
- }
- else
- {
- /* if host- and display is given the display-name, the display-name
- might be extended to a '*:*.0'-form. */
- strcpy(host_name[max],ptr+1);
- if (ptr==argv[i])
- {
- /* A missing display-name indicates an auto-player. */
- strcpy(disp_name[max],host_name[max]);
- strcat(disp_name[max],"-0");
- }
- else
- { *ptr ='\0';
- strcpy(disp_name[max],argv[i]);
- if ((ptr=index(argv[i],':'))==NULL)
- { strcat(disp_name[max],":0.0");
- }
- else
- { if ((ptr=index(argv[i],'.'))==NULL)
- { strcat(disp_name[max],".0");
- }
- }
- }
- }
-
- /* after extending names: check, if the argument is a host-name. */
- hostaddr[max]=gethostbyname(host_name[max]);
- if (hostaddr[max]==NULL)
- { printf("*** %s is not a host.\n",host_name[max]);
- }
- else
- {
- /* check the display-name */
- do
- { for (j=0;j<max;j++)
- { if (strcmp(disp_name[j],disp_name[max])==NULL) break;
- }
-
- if (j==max)
- { if (index(disp_name[max],'-')!=NULL)
- {
- /* Name of Auto-Player is O.K. */
- printf("%2d: auto-player %s\n",max+1,disp_name[max]);
- auto_only[max++]=1;
- }
- else
- {
- if ((display=XOpenDisplay(disp_name[max]))==NULL)
- { printf("XWindows ??? ");
- }
- else
- /* Display is O.K. */
- { XCloseDisplay(display);
- }
- if (strncmp(disp_name[max],host_name[max],strlen(host_name[max]))==NULL)
- printf("%2d: %s\n",max+1,disp_name[max]);
- else
- printf("%2d: %s (%s)\n",max+1,disp_name[max],host_name[max]);
- auto_only[max++]=0;
- }
- break;
- }
- else
- {
- /* disp_name[max] already used. is it for an auto-player ? */
- if (index(disp_name[max],'-')!=NULL)
- { disp_name[max][strlen(disp_name[max])-1]++;
- }
- else
- { printf("display %s used twice.\n",disp_name[max]);
- break;
- }
- }
- }
- while(j<max);
- };
- }
- }
-
- if (max<2)
- { fprintf(stderr,"*** But there should be at least 2 players. ***\n");
- usage();
- exit(0);
- };
-
- /***************************************************************
- * After name-checking is done, a streamsocket is created *
- * where the player-programs can connect to. A socket_name is *
- * *NOT* nescessary as the server tells the clients his *
- * socket-number as a parameter. *
- ***************************************************************/
-
- my_host=getenv("HOST");
-
- /* Erzeugung eines Streamsockets in der Domain AF_INET */
- mastersocket=streamsocket();
-
- /* Information ueber den Service mit Namen "service" */
- if ((sp=getservbyname(SOCKET_NAME,0))==0)
- { fprintf(stderr,"#%s: socket not found by name.\n",my_host);
- init_addr(&sin,my_host,htons((short)22222));
- }
- else
- /* Initialisieren der Struktur sockaddr_in */
- { bzero(&sin,sizeof sin);
- sin.sin_family=AF_INET;
- sin.sin_port= sp->s_port;
- sin.sin_addr.s_addr= INADDR_ANY;
- };
-
- /* Namensbindung an den Socket */
- if (bind ( mastersocket,&sin,sizeof sin)<0)
- { fprintf(stderr,"### #%s: error in bind.\n",my_host);
- do
- { sin.sin_port++;
- }
- while (bind (mastersocket,&sin,sizeof sin)<0);
- fprintf(stderr,"### #%s: port %d selected as an alternative.\n",my_host,ntohs(sin.sin_port));
- };
- if (messflag) printf("*** master-socket is %s@%d. ***\n",my_host,(int)ntohs(sin.sin_port));
-
- /* Einrichten einer Warteschlange */
- listen(mastersocket,max);
-
- /******************************************************************
- * The 'tron_run'-Program will now be started on each player-host.*
- * A Bell-Signal is given on each display. *
- ******************************************************************/
-
- for (i=0;i<max;i++)
- { play_time[i]=0;
- if (!auto_only[i])
- { if ((display=XOpenDisplay(disp_name[i]))!=NULL)
- { XBell(display,60);
- XCloseDisplay(display);
- }
- }
-
- /***********************************************************************************
- the following command is now prepared to be executed by system():
- '<foreign_host> <file_name> <my_host> <mastersocket> <count> <message_flag> &'
- with <foreign_host> - host for a player
- <file_name> - name of the 'tron_run'-binary-file on that host
- the macro TRON_RUN_FILE from the top off that source-file is used.
- <my_host> - my host (for the stream-connection)
- <mastersocket> - my socket (for the stream-connection)
- <display> - the display, usually <foreign_host>:0.0
- <count> - to get the players in an order
- <messageflag> - to produce additional messages by the players
- ***********************************************************************************/
- sprintf(command,"%s '%s %s %d %s %d %d' &",
- host_name[i],
- TRON_RUN_FILE,
- my_host,
- (int)ntohs(sin.sin_port),
- disp_name[i],
- i,
- messflag);
-
- if (messflag) printf("#%s: starting up %s on %s.\n",my_host,disp_name[i],host_name[i]);
- #if (moremessages)
- printf("%s\n",command);
- #endif
- system(command);
- if (waitflag)
- { printf("sleeping %d seconds.\n",waitflag);
- fflush(stdout);
- sleep(waitflag);
- }
- }
-
- printf("#%s: %d clients started.\n",my_host,max);
-
- /********************************************************************************
- * The server waits, until all players are started and connected to the server. *
- * Each Player-Program returns a port-number, which it uses in the game. *
- ********************************************************************************/
-
- for (i=0;i<max;i++)
- { int j,count,auto_player;
-
- rsinlen[i]=sizeof rsin[i];
- socks[i]=accept(mastersocket,&rsin[i],&rsinlen[i]);
- count=readint(socks[i]); /*** that's the <count>-argument
- of the player's command-line. ***/
- sockets[count]=socks[i];
- ports[count]=(int)readshort(sockets[count]);
- auto_player = readint(sockets[count]);
- if (auto_player!=auto_only[count])
- { fprintf(stderr,"*** no XWindows on %s -> auto-player-mode only\n",disp_name[count]);
- auto_only[count]=auto_player;
- };
- if (messflag) printf("#%s: connection %s@%d established.\n",my_host,disp_name[count],ports[count]);
- };
- printf("#%s: all clients connected.\n",my_host);
-
- close(mastersocket);
-
- /**********************************************************
- * After all players are running, a window can be openend *
- * to select who is really playing. *
- **********************************************************/
-
- if ((display=XOpenDisplay(disp_arg))==NULL)
- { fprintf(stderr,"*** %s: Can't open display.\n",my_host);
- exit(0);
- };
- screen=XScreenOfDisplay(display,DefaultScreen(display));
- init_texter();
-
- aw=XCreateSimpleWindow(display,RootWindowOfScreen(screen),
- 20,50,26 * CharWidth(FID),(max+3+7) * CharHeight(FID),
- 4,XBlackPixelOfScreen(screen),XWhitePixelOfScreen(screen));
- attrib.override_redirect = 1;
- XChangeWindowAttributes(display,aw,CWOverrideRedirect,&attrib);
- XSelectInput(display,aw,ExposureMask | ButtonPressMask);
-
- /*************************************************************************
- * The next loop is executed, until QUIT is selected in the main menu. *
- * You have to wait until a match is ended to get back to the main menu. *
- *************************************************************************/
- for(;;)
- { long tp1,tp2;
-
- if (data_error)
- prepare_message();
- else
- prepare_scores();
- send_scores();
-
- if (match)
- { int root_x,root_y,x,y;
- Window root,child;
- int mask;
-
- sleep(2);
- /***********************************************************
- * you CAN STOP a match by holding down the left AND right *
- * button on your mouse, befor the next game starts. *
- ***********************************************************/
-
- XQueryPointer(display,ROOT,&root,&child,&root_x,&root_y,&x,&y,&mask);
- if ((mask & Button3Mask) && (mask & Button1Mask))
- { match=0;
- sprintf(tscreen[0],"Match ended.");
- send_scores();
- };
- };
-
- if (!match)
- {
- XMapRaised(display,aw);
- waiting=1;
- do
- {
- XWindowEvent(display,aw,ExposureMask | ButtonPressMask,&event);
- aw_event(event.type);
- }
- while(waiting);
- XUnmapWindow(display,aw);
- };
- tp1=time((long)0);
- send_game_start();
- wait_players_ready();
- wait_game_over();
- tp2=time((long)0);
-
- for(i=0;i<max;i++)
- if (active[i]==1) play_time[i]+=(tp2 - tp1);
- };
- }
-
- int check_points(a,b)
- int *a,*b;
- {
- if (points[*a]<points[*b]) return(1);
- if (points[*a]>points[*b]) return(-1);
- return(0);
- }
-
- /************************************************
- * preparation of a text-field with the *
- * sorted list of players with their scores. *
- ************************************************/
- prepare_scores()
- { int i;
-
- /* Spieler nach Punkten sortieren */
- players=0;
- for (i=0;i<max;i++)
- if (active[i]) sorted[players++]=i;
-
- qsort(sorted,players,sizeof(int),check_points);
-
- /* pruefen, ob Spielende erreicht */
- if (match)
- { int mp=5*players;
-
- if ((points[sorted[0]]>=mp) && (points[sorted[0]]>points[sorted[1]]+1))
- { match=0;
- sprintf(tscreen[0],"-- Final Result --");
- }
- else
- sprintf(tscreen[0],"Points: (%d)",mp);
- }
- else
- {
- sprintf(tscreen[0],"Points:");
- };
-
- sprintf(tscreen[1],"");
-
- lines=2;
- for (i=0;i<players;i++)
- sprintf(tscreen[lines++],"%-13s%2d%3d",disp_name[sorted[i]],place[sorted[i]],points[sorted[i]]);
- }
-
- show_keys()
- {
- sprintf(tscreen[0],"**** TRON - by Helmut Hoenig ****");
- sprintf(tscreen[1],"");
- sprintf(tscreen[2]," Keyboard Mouse");
- sprintf(tscreen[3],"");
- sprintf(tscreen[4],"left turn: 'z' 'x' 'm' ',' left");
- sprintf(tscreen[5],"right turn: 'c' 'v' '.' '/' right");
- sprintf(tscreen[6],"jump: SPACE middle");
- sprintf(tscreen[7],"speed: SHIFT");
- sprintf(tscreen[8],"booster: SHIFT & CTRL");
- sprintf(tscreen[9],"");
- sprintf(tscreen[10]," >> no turns while booster's on. <<");
- lines=11;
- send_scores();
- };
-
- prepare_message()
- {
- sprintf(tscreen[0],"- Timeout -");
- lines=1;
- }
-
- /*********************************************
- * sends the textfield to all active players *
- *********************************************/
- send_scores()
- { int i,l;
-
- for (i=0;i<max;i++)
- if (active[i] & 1)
- { writeint(sockets[i],SCORE);
- writeint(sockets[i],lines);
- for (l=0;l<lines;l++)
- { writestring(sockets[i],tscreen[l]);
- };
- };
- }
-
- /**************************************************************
- * sends the game_start-message to all players. *
- * containing the port-number and host of the next player and *
- * a flag, if the player should create the first datagram. *
- **************************************************************/
- send_game_start()
- { int i,ind=0,starter=0;
-
- int perm[MAXPLAYERS];
-
- g_count++;
-
- for (i=0;i<max;i++)
- if (active[i]) perm[ind++]=i;
-
- for (i=0;i<ind;i++)
- { writeint(sockets[perm[i]],GAMESTART);
- writeint(sockets[perm[i]],players);
- writeint(sockets[perm[i]],active[perm[i]]);
- writeint(sockets[perm[i]],g_count);
- if (i == 0)
- writeint(sockets[perm[i]],1);
- else
- writeint(sockets[perm[i]],0);
-
- writestring(sockets[perm[i]],host_name[perm[((i+1) % ind)]]);
- writeshort(sockets[perm[i]],ports[perm[((i+1) % ind)]]);
- };
- }
-
- send_exit()
- { int i;
-
- for (i=0;i<max;i++)
- writeint(sockets[i],EXIT);
- }
-
- /***********************************************
- * waits, until all players are ready to start *
- ***********************************************/
- wait_players_ready()
- {
- int readfds,writefds,execptfds;
- struct timeval timeout;
-
- int ready_count=0,i,nfound;
-
- do
- { readfds=0;
- writefds=0;
- execptfds=0;
- /* timeout.tv_sec=0;
- timeout.tv_usec=0;
- */
- for (i=0;i<max;i++)
- if (active[i]) readfds |= (1<<sockets[i]);
-
- nfound=select(32,&readfds,&writefds,&execptfds,0);
- if (nfound<0)
- { fprintf(stderr,"#%s: error occured in select.\n",my_host);
- exit(0);
- };
- for (i=0;i<max;i++)
- if (readfds & (1<<sockets[i]))
- { int v;
- if ((v=readint(sockets[i]))!=PLAYER_READY)
- { fprintf(stderr,"#%s: illegal message (%d) received from %s.\n",my_host,v,disp_name[i]);
- send_exit();
- exit(0);
- };
- ready_count++;
- };
- }
- while(ready_count<players);
- }
-
- int check_count(a,b)
- int *a,*b;
- {
- if (count[*a]<count[*b]) return(1);
- if (count[*a]>count[*b]) return(-1);
- return(0);
- }
-
- /***************************************************
- * waits, until the game is over. *
- * the server receives a counter from each player, *
- * which says, when it was destroyed. *
- ***************************************************/
- wait_game_over()
- {
- int readfds,writefds,execptfds;
- struct timeval timeout;
-
- int ready_count=0,i,nfound;
-
- data_error=0;
- while(ready_count<players)
- { readfds=0;
- writefds=0;
- execptfds=0;
- /* timeout.tv_sec=0;
- timeout.tv_usec=0;
- */
- for (i=0;i<max;i++)
- if (active[i]) readfds |= (1<<sockets[i]);
-
- nfound=select(32,&readfds,&writefds,&execptfds,0);
- if (nfound<0)
- { fprintf(stderr,"#%s: error occured in select.\n",my_host);
- exit(0);
- };
- for (i=0;i<max;i++)
- if (readfds & (1<<sockets[i]))
- { int v;
- if ((v=readint(sockets[i]))!=DESTROYED)
- { data_error=1;
- printf("#%s: error-message by %s.\n",my_host,disp_name[i]);
- fflush(stdout);
- }
- else
- {
- /* printf("#%s: %s destroyed.\n",my_host,disp_name[i]); */
- count[i]=readint(sockets[i]);
- };
- ready_count++;
- };
- };
-
- /* printf("#%s: all players destroyed.\n",my_host); */
-
- /* Punkte verteilen */
- if (!data_error)
- { players=0;
- for (i=0;i<max;i++)
- if (active[i]) sorted[players++]=i;
-
- qsort(sorted,players,sizeof(int),check_count);
-
- for (i=0;i<players;i++)
- { points[sorted[i]] +=(place[sorted[i]] = players-i-1);
-
- };
- packet_count += (long)count[sorted[0]];
- };
- }
-
-
- /*******************************************************
- * XWindow-Functions for redrawing and event-executing *
- *******************************************************/
- redraw_disps()
- { int i;
-
- XRaiseWindow(display,aw);
- printat(1,1,"TRON",FID);
- for (i=0;i<max;i++)
- { printat(1,i+3,disp_name[i],FID);
- if (active[i]==2)
- printcleared(20,i+3,"AUTO",FID);
- else if (active[i]==1)
- printcleared(20,i+3," YES",FID);
- else
- printcleared(20,i+3," NO",FID);
- };
- printat(1,3+max+1,"Start Match",FID);
- printat(1,3+max+2,"Start Game",FID);
- printat(1,3+max+3,"Show Keys",FID);
- printat(1,3+max+4,"Clear Scores",FID);
- printat(1,3+max+5,"Quit",FID);
- XFlush(display);
- }
-
- aw_event(type)
- unsigned type;
- { int i,y;
-
- switch(type)
- {
- case Expose:
- redraw_disps();
- break;
- case ButtonPress:
- y=((event.xbutton.y)/CharHeight(FID))-3;
- if (y<0) break;
-
- if (y<max)
- {
- active[y]=(active[y]+1)%3; /* switching: NO->YES->AUTO->NO */
- if (auto_only[y])
- { if (active[y]==1) active[y]++;
- }
- if (active[y] & 2) writeint(sockets[y],UNMAP);
- }
- else
- { y-=max+1;
- if (y<2) /* START GAME OR MATCH */
- { int i1,i2,j;
-
- i1=i2=0;
- for (j=0;j<max;j++)
- { if (active[j])
- { i1++;
- if (active[j]==1) i2++;
- }
- }
- if ((i1>1)&&(i2>0))
- { waiting=0;
- match=(y==0);
- }
- else
- { XBell(display,50);
- XFlush(display);
- }
- };
- if (y==2) /* SHOW KEYS */
- { int t;
- for (t=0;t<max;t++)
- if (active[t]==1) break;
- if (t==max)
- XBell(display,10);
- else
- show_keys();
- return;
- };
-
- if ((y==3) || (match)) /* CLEAR SCORES */
- for (i=0;i<max;i++)
- { sorted[i]=i;
- points[i]=0;
- place[i]=0;
- };
- if (y==4) /* QUIT */
- { send_exit();
-
- printf("#%s: program ends.\n",my_host);
- printf("#total number of datagrams: %ld\n",packet_count);
- fflush(stdout);
- exit(0);
- };
- };
- if (waiting)
- { redraw_disps();
- prepare_scores();
- send_scores();
- };
- };
- }
-