--- /dev/null
+/* zeRace dedicated server */
+
+#include <SDL_net.h>
+#include "network.h"
+#include "car.h"
+#include "tracklist.h"
+
+/* each client has his data */
+struct _clients
+{
+ char pseudo[MAXLINELENGTH];
+ int connected;
+ int lasttime;
+ struct _car car;
+ IPaddress address;
+} clients [MAX_CLIENTS];
+
+/* UDP stuff */
+UDPsocket udpsock;
+UDPpacket *packet;
+
+struct _tracklist *tracklist;
+SDL_Surface *fun;
+
+
+/* return the id of a connected address */
+int lookup(IPaddress address)
+{
+ int i;
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].address.host==address.host && clients[i].address.port==address.port) return i;
+ return -1;
+}
+
+
+/* announce the server on internet */
+void announce(char *name,int clients)
+{
+ IPaddress ip;
+ TCPsocket tcpsock;
+ char *temp;
+ char *msg1=
+ "POST /zerace/announce.php HTTP/1.0\n"
+ "Host: royale.zerezo.com\n"
+ "User-Agent: zeRace dedicated server " VERSION "\n"
+ "Content-Type: application/x-www-form-urlencoded\n"
+ "Content-Length: 99999\n"
+ "\n"
+ "version=" VERSION
+ "&port=" PORT
+ "&name=";
+ char *msg2="&clients=";
+ int len,result;
+
+ printf("announcing server... ");
+ fflush(stdout);
+
+ if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ {
+ fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
+ return;
+ }
+
+ tcpsock=SDLNet_TCP_Open(&ip);
+ if(!tcpsock)
+ {
+ fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
+ return;
+ }
+
+ temp=(char *)malloc(strlen(msg1)+strlen(name)+strlen(msg2)+10);
+ sprintf(temp,"%s%s%s%d\n",msg1,name,msg2,clients);
+
+ len=strlen(temp);
+ result=SDLNet_TCP_Send(tcpsock,temp,len);
+ if(result<len)
+ fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
+ else
+ printf("done\n");
+
+ SDLNet_TCP_Close(tcpsock);
+}
+
+
+/* main program */
+int main(int argc,char *argv[])
+{
+ int id,i,j,time=0,nb;
+ char *tmp;
+ unsigned char ip[4];
+ int nb_laps,network_speed,pub;
+
+ if (argc!=5)
+ {
+ fprintf(stderr,
+ "usage: %s 'server_name' nb_laps network_speed (public|private)\n"
+ " server_name : the name of the server\n"
+ " nb_laps : the number of laps to complete for each race\n"
+ " network_speed : frequency of network messages (1 for fast network, 10 for slow network...)\n"
+ " private : this server will not be listed in the 'internet games'\n"
+ ,argv[0]
+ );
+ exit(1);
+ }
+ printf("server_name : %s\n",argv[1]);
+ printf("nb_laps : %d\n",nb_laps=atoi(argv[2]));
+ printf("network_speed : %d\n",network_speed=atoi(argv[3]));
+ printf("public : %d\n",pub=strcmp("private",argv[4]));
+
+ if (!zeRace_get_tracks(&tracklist)) exit(1);
+
+ if (SDL_Init(0)==-1)
+ {
+ fprintf(stderr,"SDL_Init: %s\n",SDL_GetError());
+ exit(1);
+ };
+ if (SDLNet_Init()==-1)
+ {
+ fprintf(stderr,"SDLNet_Init: %s\n",SDLNet_GetError());
+ exit(2);
+ }
+
+ udpsock=SDLNet_UDP_Open(atoi(PORT));
+ if (!udpsock)
+ {
+ fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
+ exit(2);
+ }
+
+ packet=SDLNet_AllocPacket(1024);
+ if (!packet)
+ {
+ fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
+ exit(2);
+ }
+
+ for (;;)
+ {
+ /* announce the server on internet if wanted */
+ nb=0;
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) nb++;
+ if (pub) announce(argv[1],nb);
+
+ /* load new track */
+ printf("loading track \"%s\"\n",tracklist->name);
+ fun=IMG_Load(tracklist->function);
+
+ /* reset clients variables */
+ for (i=0;i<MAX_CLIENTS;i++)
+ {
+ clients[i].lasttime=time;
+ clients[i].car.x=tracklist->x;
+ clients[i].car.y=tracklist->y;
+ clients[i].car.w=30;
+ clients[i].car.h=30;
+ clients[i].car.angle=tracklist->a*2*M_PI/360;
+ clients[i].car.speed=0;
+ clients[i].car.lap=0;
+ clients[i].car.lastcheck=0;
+ }
+
+ /* tell the clients */
+ tmp=packet->data;
+ strcpy(tmp,"track");
+ tmp+=strlen(tmp)+1;
+ *tmp++=1; /* startup countdown */
+ strcpy(tmp,tracklist->name);
+ tmp+=strlen(tmp)+1;
+ memcpy(tmp,&time,sizeof(int));
+ tmp+=sizeof(int);
+ memcpy(tmp,&network_speed,sizeof(int));
+ tmp+=sizeof(int);
+ packet->len=(void *)tmp-(void *)packet->data;
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
+ {
+ packet->address=clients[i].address;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ }
+
+ /* wait for everybody startup */
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) break;
+ if (i!=MAX_CLIENTS) SDL_Delay(5000);
+
+ printf("go\n");
+
+ /* main race loop */
+ for (;;)
+ {
+ int finish=0;
+
+ /* read all available packets */
+ while (SDLNet_UDP_Recv(udpsock,packet))
+ {
+ /* return the local id based on the address */
+ id=lookup(packet->address);
+
+ /* look for type of message */
+ tmp=packet->data;
+ /*printf("%s\n",tmp);*/
+
+ /* new connection ? */
+ if (strcmp(tmp,"connect")==0)
+ {
+ /* allready connected ? */
+ if (id!=-1 && clients[id].connected)
+ {
+ /* should not happen */
+ printf("client %d allready connected\n",id);
+ }
+ else
+ for (i=0;i<MAX_CLIENTS;i++) if (!clients[i].connected)
+ {
+ clients[i].address=packet->address;
+ clients[i].connected=1;
+ clients[i].lasttime=time;
+ memset(&clients[i].car,0,sizeof(struct _car));
+ tmp+=strlen(tmp)+1;
+ strcpy(clients[i].pseudo,tmp);
+ tmp+=strlen(tmp)+1;
+ memcpy(&clients[i].car.color,tmp,sizeof(int));
+ clients[i].car.x=tracklist->x;
+ clients[i].car.y=tracklist->y;
+ clients[i].car.w=30;
+ clients[i].car.h=30;
+ clients[i].car.angle=tracklist->a*2*M_PI/360;
+ clients[i].car.speed=0;
+ clients[i].car.lap=0;
+ clients[i].car.lastcheck=0;
+ memcpy(ip,&packet->address.host,4);
+ printf("client %d connected at %d : %d.%d.%d.%d:%d (pseudo : %s, color : %d)\n",i,time,ip[0],ip[1],ip[2],ip[3],packet->address.port,clients[i].pseudo,clients[i].car.color);
+ tmp=packet->data;
+ strcpy(tmp,"track");
+ tmp+=strlen(tmp)+1;
+ *tmp++=0; /* no startup countdown */
+ strcpy(tmp,tracklist->name);
+ tmp+=strlen(tmp)+1;
+ memcpy(tmp,&time,sizeof(int));
+ tmp+=sizeof(int);
+ memcpy(tmp,&network_speed,sizeof(int));
+ tmp+=sizeof(int);
+ packet->len=(void *)tmp-(void *)packet->data;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ break;
+ }
+ }
+ else
+
+ /* disconnection ? */
+ if (strcmp(tmp,"disconnect")==0 && id!=-1)
+ {
+ clients[id].connected=0;
+ printf("client %d disconnected\n",id);
+ }
+ else
+
+ /* keys message ? */
+ if (strcmp(tmp,"keys")==0)
+ {
+ if (id==-1 || !clients[id].connected)
+ {
+ /* should not happen */
+ printf("discarded \"keys\" message\n");
+ }
+ else
+ {
+ int temp;
+ tmp+=strlen(tmp)+1;
+ memcpy(&temp,tmp,sizeof(int));
+ tmp+=sizeof(int);
+ if (clients[id].lasttime==temp)
+ {
+ /* printf("servertime = %d lasttime = %d temp = %d strlen(tmp) = %d\n",time,clients[id].lasttime,temp,strlen(tmp)); */
+ /*printf("keys = %s\n",tmp);*/
+ while (*tmp)
+ {
+ move_car(&clients[id].car,*tmp-'A',fun);
+ /*printf("%d = %f\n",id,clients[id].car.angle);*/
+ clients[id].lasttime++;
+ tmp++;
+ }
+ }
+ }
+ }
+ }
+
+ /* check for timeouts */
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].lasttime+MAX_LAG<time)
+ {
+ printf("client %d timeout at %d\n",i,time);
+ packet->address=clients[i].address;
+ strcpy(packet->data,"disconnected");
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ clients[i].connected=0;
+ }
+
+ /* send update to clients */
+ if (time%network_speed==0) for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
+ {
+ tmp=packet->data;
+ strcpy(tmp,"positions");
+ tmp+=strlen(tmp)+1;
+ memcpy(tmp,&time,sizeof(int));
+ tmp+=sizeof(int); /* for server time */
+ tmp+=sizeof(int); /* for client time */
+ tmp+=sizeof(int); /* for number of cars */
+ nb=0;
+ for (j=0;j<MAX_CLIENTS;j++) if (j!=i && clients[j].connected)
+ {
+ memcpy(tmp,&clients[j].car,sizeof(struct _car));
+ tmp+=sizeof(struct _car);
+ nb++;
+ }
+ memcpy(packet->data+strlen("positions")+1+sizeof(int)+sizeof(int),&nb,sizeof(int));
+ packet->len=(void *)tmp-(void *)packet->data;
+ memcpy(packet->data+strlen("positions")+1+sizeof(int),&clients[i].lasttime,sizeof(int));
+ packet->address=clients[i].address;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ }
+
+ /* did someone finish the track ? */
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].car.lap==nb_laps) finish=1;
+ if (finish) break;
+
+ /* wait like clients */
+ SDL_Delay(7);
+ time++;
+ }
+
+ /* send the top 10 screen */
+ tmp=packet->data;
+ strcpy(tmp,"finish");
+ tmp+=strlen(tmp)+1;
+ tmp+=sizeof(int); /* space for number */
+ nb=0;
+ for (i=0;i<10;i++)
+ {
+ int best_sc=-1,best_id;
+ for (j=0;j<MAX_CLIENTS;j++) if (clients[j].connected && clients[j].car.lap*32+clients[j].car.lastcheck>best_sc)
+ {
+ best_sc=clients[j].car.lap*32+clients[j].car.lastcheck;
+ best_id=j;
+ }
+ if (best_sc!=-1)
+ {
+ sprintf(tmp,"%s : %d",clients[best_id].pseudo,best_sc);
+ tmp+=strlen(tmp)+1;
+ memcpy(tmp,&clients[best_id].car.color,sizeof(int));
+ tmp+=sizeof(int);
+ clients[best_id].car.lap=-1;
+ nb++;
+ printf("top %d : %s - %d\n",nb,clients[best_id].pseudo,best_sc);
+ }
+ }
+ memcpy(packet->data+strlen("finish")+1,&nb,sizeof(int));
+ packet->len=(void *)tmp-(void *)packet->data;
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
+ {
+ packet->address=clients[i].address;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ }
+ SDL_Delay(5000);
+
+ tracklist=tracklist->next;
+ }
+
+ return 0;
+}