version 0.3
[zeRace] / server.c
1 /* zeRace dedicated server */
2
3 #include <SDL_net.h>
4 #include "network.h"
5 #include "car.h"
6 #include "tracklist.h"
7
8 /* each client has his data */
9 struct _clients
10 {
11   char pseudo[MAXLINELENGTH];
12   int connected;
13   int lasttime;
14   struct _car car;
15   IPaddress address;
16 } clients [MAX_CLIENTS];
17
18 /* UDP stuff */
19 UDPsocket udpsock;
20 UDPpacket *packet;
21
22 struct _tracklist *tracklist;
23 SDL_Surface *fun;
24
25
26 /* return the id of a connected address */
27 int lookup(IPaddress address)
28 {
29   int i;
30   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;
31   return -1;
32 }
33
34
35 /* announce the server on internet */
36 void announce(char *name,int clients)
37 {
38   IPaddress ip;
39   TCPsocket tcpsock;
40   char *temp;
41   char *msg1=
42     "POST /zerace/announce.php HTTP/1.0\n"
43     "Host: royale.zerezo.com\n"
44     "User-Agent: zeRace dedicated server " VERSION "\n"
45     "Content-Type: application/x-www-form-urlencoded\n"
46     "Content-Length: 99999\n"
47     "\n"
48     "version=" VERSION
49     "&port=" PORT
50     "&name=";
51   char *msg2="&clients=";
52   int len,result;
53   
54   printf("announcing server... ");
55   fflush(stdout);
56
57   if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
58   {
59     fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
60     return;
61   }
62   
63   tcpsock=SDLNet_TCP_Open(&ip);
64   if(!tcpsock)
65   {
66     fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
67     return;
68   }
69
70   temp=(char *)malloc(strlen(msg1)+strlen(name)+strlen(msg2)+10);
71   sprintf(temp,"%s%s%s%d\n",msg1,name,msg2,clients);
72   
73   len=strlen(temp);
74   result=SDLNet_TCP_Send(tcpsock,temp,len);
75   if(result<len)
76     fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
77   else
78     printf("done\n");
79
80   SDLNet_TCP_Close(tcpsock);
81 }
82
83
84 /* main program */
85 int main(int argc,char *argv[])
86 {
87   int id,i,j,time=0,nb;
88   char *tmp;
89   unsigned char ip[4];
90   int nb_laps,network_speed,pub;
91   
92   if (argc!=5)
93   {
94     fprintf(stderr,
95       "usage: %s 'server_name' nb_laps network_speed (public|private)\n"
96       "  server_name : the name of the server\n"
97       "  nb_laps : the number of laps to complete for each race\n"
98       "  network_speed : frequency of network messages (1 for fast network, 10 for slow network...)\n"
99       "  private : this server will not be listed in the 'internet games'\n"
100       ,argv[0]
101     );
102     exit(1);
103   }
104   printf("server_name : %s\n",argv[1]);
105   printf("nb_laps : %d\n",nb_laps=atoi(argv[2]));
106   printf("network_speed : %d\n",network_speed=atoi(argv[3]));
107   printf("public : %d\n",pub=strcmp("private",argv[4]));
108   
109   if (!zeRace_get_tracks(&tracklist)) exit(1);
110
111   if (SDL_Init(0)==-1)
112   {
113     fprintf(stderr,"SDL_Init: %s\n",SDL_GetError());
114     exit(1);
115   };
116   if (SDLNet_Init()==-1)
117   {
118     fprintf(stderr,"SDLNet_Init: %s\n",SDLNet_GetError());
119     exit(2);
120   }
121   
122   udpsock=SDLNet_UDP_Open(atoi(PORT));
123   if (!udpsock)
124   {
125     fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
126     exit(2);
127   }
128
129   packet=SDLNet_AllocPacket(1024);
130   if (!packet)
131   {
132     fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
133     exit(2);
134   }
135
136   for (;;)
137   {
138     /* announce the server on internet if wanted */
139     nb=0;
140     for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) nb++;
141     if (pub) announce(argv[1],nb);
142     
143     /* load new track */
144     printf("loading track \"%s\"\n",tracklist->name);
145     fun=IMG_Load(tracklist->function);
146     
147     /* reset clients variables */
148     for (i=0;i<MAX_CLIENTS;i++)
149     {
150       clients[i].lasttime=time;
151       clients[i].car.x=tracklist->x;
152       clients[i].car.y=tracklist->y;
153       clients[i].car.w=30;
154       clients[i].car.h=30;
155       clients[i].car.angle=tracklist->a*2*M_PI/360;
156       clients[i].car.speed=0;
157       clients[i].car.lap=0;
158       clients[i].car.lastcheck=0;
159     }
160     
161     /* tell the clients */
162     tmp=packet->data;
163     strcpy(tmp,"track");
164     tmp+=strlen(tmp)+1;
165     *tmp++=1; /* startup countdown */
166     strcpy(tmp,tracklist->name);
167     tmp+=strlen(tmp)+1;
168     memcpy(tmp,&time,sizeof(int));
169     tmp+=sizeof(int);
170     memcpy(tmp,&network_speed,sizeof(int));
171     tmp+=sizeof(int);
172     packet->len=(void *)tmp-(void *)packet->data;
173     for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
174     {
175       packet->address=clients[i].address;
176       SDLNet_UDP_Send(udpsock,-1,packet);
177     }
178     
179     /* wait for everybody startup */
180     for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) break;
181     if (i!=MAX_CLIENTS) SDL_Delay(5000);
182     
183     printf("go\n");
184     
185     /* main race loop */
186     for (;;)
187     {
188       int finish=0;
189       
190       /* read all available packets */
191       while (SDLNet_UDP_Recv(udpsock,packet))
192       {
193         /* return the local id based on the address */
194         id=lookup(packet->address);
195         
196         /* look for type of message */
197         tmp=packet->data;
198         /*printf("%s\n",tmp);*/
199         
200         /* new connection ? */
201         if (strcmp(tmp,"connect")==0)
202         {
203           /* allready connected ? */
204           if (id!=-1 && clients[id].connected)
205           {
206             /* should not happen */
207             printf("client %d allready connected\n",id);
208           }
209           else
210           for (i=0;i<MAX_CLIENTS;i++) if (!clients[i].connected)
211           {
212             clients[i].address=packet->address;
213             clients[i].connected=1;
214             clients[i].lasttime=time;
215             memset(&clients[i].car,0,sizeof(struct _car));
216             tmp+=strlen(tmp)+1;
217             strcpy(clients[i].pseudo,tmp);
218             tmp+=strlen(tmp)+1;
219             memcpy(&clients[i].car.color,tmp,sizeof(int));
220             clients[i].car.x=tracklist->x;
221             clients[i].car.y=tracklist->y;
222             clients[i].car.w=30;
223             clients[i].car.h=30;
224             clients[i].car.angle=tracklist->a*2*M_PI/360;
225             clients[i].car.speed=0;
226             clients[i].car.lap=0;
227             clients[i].car.lastcheck=0;
228             memcpy(ip,&packet->address.host,4);
229             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);
230             tmp=packet->data;
231             strcpy(tmp,"track");
232             tmp+=strlen(tmp)+1;
233             *tmp++=0; /* no startup countdown */
234             strcpy(tmp,tracklist->name);
235             tmp+=strlen(tmp)+1;
236             memcpy(tmp,&time,sizeof(int));
237             tmp+=sizeof(int);
238             memcpy(tmp,&network_speed,sizeof(int));
239             tmp+=sizeof(int);
240             packet->len=(void *)tmp-(void *)packet->data;
241             SDLNet_UDP_Send(udpsock,-1,packet);
242             break;
243           }
244         }
245         else
246         
247         /* disconnection ? */
248         if (strcmp(tmp,"disconnect")==0 && id!=-1)
249         {
250           clients[id].connected=0;
251           printf("client %d disconnected\n",id);
252         }
253         else
254         
255         /* keys message ? */
256         if (strcmp(tmp,"keys")==0)
257         {
258           if (id==-1 || !clients[id].connected)
259           {
260             /* should not happen */
261             printf("discarded \"keys\" message\n");
262           }
263           else
264           {
265             int temp;
266             tmp+=strlen(tmp)+1;
267             memcpy(&temp,tmp,sizeof(int));
268             tmp+=sizeof(int);
269             if (clients[id].lasttime==temp)
270             {
271               /* printf("servertime = %d lasttime = %d temp = %d strlen(tmp) = %d\n",time,clients[id].lasttime,temp,strlen(tmp)); */
272               /*printf("keys = %s\n",tmp);*/
273               while (*tmp)
274               {
275                 move_car(&clients[id].car,*tmp-'A',fun);
276                 /*printf("%d = %f\n",id,clients[id].car.angle);*/
277                 clients[id].lasttime++;
278                 tmp++;
279               }
280             }
281           }
282         }
283       }
284       
285       /* check for timeouts */
286       for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].lasttime+MAX_LAG<time)
287       {
288         printf("client %d timeout at %d\n",i,time);
289         packet->address=clients[i].address;
290         strcpy(packet->data,"disconnected");
291         SDLNet_UDP_Send(udpsock,-1,packet);
292         clients[i].connected=0;
293       }
294       
295       /* send update to clients */
296       if (time%network_speed==0) for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
297       {
298         tmp=packet->data;
299         strcpy(tmp,"positions");
300         tmp+=strlen(tmp)+1;
301         memcpy(tmp,&time,sizeof(int));
302         tmp+=sizeof(int); /* for server time */
303         tmp+=sizeof(int); /* for client time */
304         tmp+=sizeof(int); /* for number of cars */
305         nb=0;
306         for (j=0;j<MAX_CLIENTS;j++) if (j!=i && clients[j].connected)
307         {
308           memcpy(tmp,&clients[j].car,sizeof(struct _car));
309           tmp+=sizeof(struct _car);
310           nb++;
311         }
312         memcpy(packet->data+strlen("positions")+1+sizeof(int)+sizeof(int),&nb,sizeof(int));
313         packet->len=(void *)tmp-(void *)packet->data;
314         memcpy(packet->data+strlen("positions")+1+sizeof(int),&clients[i].lasttime,sizeof(int));
315         packet->address=clients[i].address;
316         SDLNet_UDP_Send(udpsock,-1,packet);
317       }
318       
319       /* did someone finish the track ? */
320       for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].car.lap==nb_laps) finish=1;
321       if (finish) break;
322         
323       /* wait like clients */
324       SDL_Delay(7);
325       time++;
326     }
327     
328     /* send the top 10 screen */
329     tmp=packet->data;
330     strcpy(tmp,"finish");
331     tmp+=strlen(tmp)+1;
332     tmp+=sizeof(int); /* space for number */
333     nb=0;
334     for (i=0;i<10;i++)
335     {
336       int best_sc=-1,best_id;
337       for (j=0;j<MAX_CLIENTS;j++) if (clients[j].connected && clients[j].car.lap*32+clients[j].car.lastcheck>best_sc)
338       {
339         best_sc=clients[j].car.lap*32+clients[j].car.lastcheck;
340         best_id=j;
341       }
342       if (best_sc!=-1)
343       {
344         sprintf(tmp,"%s : %d",clients[best_id].pseudo,best_sc);
345         tmp+=strlen(tmp)+1;
346         memcpy(tmp,&clients[best_id].car.color,sizeof(int));
347         tmp+=sizeof(int);
348         clients[best_id].car.lap=-1;
349         nb++;
350         printf("top %d : %s - %d\n",nb,clients[best_id].pseudo,best_sc);
351       }
352     }
353     memcpy(packet->data+strlen("finish")+1,&nb,sizeof(int));
354     packet->len=(void *)tmp-(void *)packet->data;
355     for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
356     {
357       packet->address=clients[i].address;
358       SDLNet_UDP_Send(udpsock,-1,packet);
359     }
360     SDL_Delay(5000);
361   
362     tracklist=tracklist->next;
363   }
364
365   return 0;
366 }