1 /* zeRace dedicated server */
8 /* each client has his data */
11 char pseudo[MAXLINELENGTH];
17 } clients [MAX_CLIENTS];
23 struct _tracklist *tracklist;
25 SDL_Surface *cars[256];
28 /* return the id of a connected address */
29 int lookup(IPaddress address)
32 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;
37 /* announce the server on internet */
38 void announce(char *name,int clients)
44 "POST /zerace/announce.php HTTP/1.0\n"
45 "Host: royale.zerezo.com\n"
46 "User-Agent: zeRace dedicated server " VERSION "\n"
47 "Content-Type: application/x-www-form-urlencoded\n"
48 "Content-Length: 99999\n"
53 char *msg2="&clients=";
56 printf("announcing server... ");
59 if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
61 fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
65 tcpsock=SDLNet_TCP_Open(&ip);
68 fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
72 temp=(char *)malloc(strlen(msg1)+strlen(name)+strlen(msg2)+10);
73 sprintf(temp,"%s%s%s%d\n",msg1,name,msg2,clients);
76 result=SDLNet_TCP_Send(tcpsock,temp,len);
78 fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
83 SDLNet_TCP_Close(tcpsock);
87 /* load the car sprite and rotate it for every angles */
88 void zeRace_generate_cars()
92 char temp[20]="sprites/carX.png";
94 /* load the car sprite */
96 /* and rotate it for all available angles */
101 if ((cars[j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,RMASK,GMASK,BMASK,AMASK))==NULL)
103 fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
105 tcos=cos(2*M_PI*j/256);
106 tsin=sin(2*M_PI*j/256);
107 for (x=0;x<cars[j]->w;x++) for (y=0;y<cars[j]->h;y++)
110 x2=(x-cars[j]->w/2.0)*tcos+(y-cars[j]->h/2.0)*tsin+car->w/2.0;
111 y2=(x-cars[j]->w/2.0)*tsin-(y-cars[j]->h/2.0)*tcos+car->h/2.0;
112 if (x2>0 && x2<car->w && y2>0 && y2<car->h)
113 putpixel(cars[j],x,y,getpixel(car,x2,y2));
116 SDL_FreeSurface(car);
121 int main(int argc,char *argv[])
123 int id,i,j,time=0,nb;
126 int nb_laps,network_speed,pub,col;
131 "Usage: %s 'server_name' nb_laps network_speed (public|private) (col|nocol)\n"
132 " server_name : the name of the server\n"
133 " nb_laps : the number of laps to complete for each race\n"
134 " network_speed : frequency of network messages (1 for fast network, 10 for slow network...)\n"
135 " private : this server will not be listed in the 'internet games'\n"
136 " col : the server will compute collisions between cars\n"
141 printf("server_name : %s\n",argv[1]);
142 printf("nb_laps : %d\n",nb_laps=atoi(argv[2]));
143 printf("network_speed : %d\n",network_speed=atoi(argv[3]));
144 printf("public : %d\n",pub=strcmp("private",argv[4]));
145 printf("col : %d\n",col=strcmp("nocol",argv[5]));
147 if (!zeRace_get_tracks(&tracklist)) exit(1);
151 fprintf(stderr,"SDL_Init: %s\n",SDL_GetError());
154 if (SDLNet_Init()==-1)
156 fprintf(stderr,"SDLNet_Init: %s\n",SDLNet_GetError());
160 udpsock=SDLNet_UDP_Open(atoi(PORT));
163 fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
167 packet=SDLNet_AllocPacket(1024);
170 fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
174 zeRace_generate_cars();
178 /* announce the server on internet if wanted */
180 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) nb++;
181 if (pub) announce(argv[1],nb);
184 printf("loading track \"%s\"\n",tracklist->name);
185 fun=IMG_Load(tracklist->function);
187 /* reset clients variables */
188 for (i=0;i<MAX_CLIENTS;i++)
190 clients[i].lasttime=time;
191 clients[i].car.x=tracklist->x;
192 clients[i].car.y=tracklist->y;
195 clients[i].car.angle=tracklist->a*2*M_PI/360;
196 clients[i].car.speed=0;
197 clients[i].car.lap=0;
198 clients[i].car.lastcheck=0;
201 /* tell the clients */
205 *tmp++=1; /* startup countdown */
206 strcpy(tmp,tracklist->name);
208 SDLNet_Write32(time,tmp);
210 SDLNet_Write32(network_speed,tmp);
212 packet->len=(void *)tmp-(void *)packet->data;
213 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
215 packet->address=clients[i].address;
216 SDLNet_UDP_Send(udpsock,-1,packet);
219 /* wait for everybody startup */
220 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) break;
221 /* 5000ms for countdown, and 500ms for loading time... */
222 if (i!=MAX_CLIENTS) SDL_Delay(5500);
231 /* read all available packets */
232 while (SDLNet_UDP_Recv(udpsock,packet))
234 /* return the local id based on the address */
235 id=lookup(packet->address);
237 /* look for type of message */
240 /* new connection ? */
241 if (strcmp(tmp,"connect")==0)
243 /* allready connected ? */
244 if (id!=-1 && clients[id].connected)
246 /* should not happen */
247 printf("client %d allready connected\n",id);
250 for (i=0;i<MAX_CLIENTS;i++) if (!clients[i].connected)
252 clients[i].address=packet->address;
253 clients[i].connected=1;
254 clients[i].lasttime=time;
255 memset(&clients[i].car,0,sizeof(struct _car));
257 strcpy(clients[i].pseudo,tmp);
259 clients[i].car.color=SDLNet_Read16(tmp);
260 clients[i].car.x=tracklist->x;
261 clients[i].car.y=tracklist->y;
264 clients[i].car.angle=tracklist->a*2*M_PI/360;
265 clients[i].car.speed=0;
266 clients[i].car.lap=0;
267 clients[i].car.lastcheck=0;
268 memcpy(ip,&packet->address.host,4);
269 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);
273 *tmp++=0; /* no startup countdown */
274 strcpy(tmp,tracklist->name);
276 SDLNet_Write32(time,tmp);
278 SDLNet_Write32(network_speed,tmp);
280 packet->len=(void *)tmp-(void *)packet->data;
281 SDLNet_UDP_Send(udpsock,-1,packet);
287 /* disconnection ? */
288 if (strcmp(tmp,"disconnect")==0 && id!=-1)
290 clients[id].connected=0;
291 printf("client %d disconnected\n",id);
296 if (strcmp(tmp,"keys")==0)
298 if (id==-1 || !clients[id].connected)
300 /* should not happen */
301 printf("discarded \"keys\" message\n");
307 temp=SDLNet_Read32(tmp);
309 x=SDLNet_Read32(tmp);
311 y=SDLNet_Read32(tmp);
313 if (clients[id].lasttime<=temp)
315 tmp+=temp-clients[id].lasttime;
318 move_car(&clients[id].car,*tmp-'A',fun);
319 clients[id].lasttime++;
322 /* check that the server and the client are still synchronized */
323 x2=clients[id].car.x;
324 y2=clients[id].car.y;
328 /* this should not happen with a perfect network protocol :) */
329 printf("client %d unsync at %d\n",id,time);
330 /* instead of dropping the client, we send him a "dumb" collision to resync him */
332 strcpy(tmp,"collision");
334 SDLNet_Write32(time,tmp);
336 round=(clients[id].car.x+100)*65536;
337 clients[id].car.x=(float)round/65536-100;
338 SDLNet_Write32(round,tmp);
340 round=(clients[id].car.y+100)*65536;
341 clients[id].car.y=(float)round/65536-100;
342 SDLNet_Write32(round,tmp);
344 round=(clients[id].car.speed+100)*65536;
345 clients[id].car.speed=(float)round/65536-100;
346 SDLNet_Write32(round,tmp);
348 round=(clients[id].car.angle+100)*65536;
349 clients[id].car.angle=(float)round/65536-100;
350 SDLNet_Write32(round,tmp);
352 packet->len=(void *)tmp-(void *)packet->data;
353 packet->address=clients[id].address;
354 SDLNet_UDP_Send(udpsock,-1,packet);
355 clients[id].lasttime=time;
362 /* check for timeouts */
363 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].lasttime+MAX_LAG<time)
365 printf("client %d timeout at %d\n",i,time);
366 packet->address=clients[i].address;
367 strcpy(packet->data,"disconnected");
368 SDLNet_UDP_Send(udpsock,-1,packet);
369 clients[i].connected=0;
372 /* should we check for collisions ? */
375 /* check for collisions */
376 for (i=0;i<MAX_CLIENTS;i++) clients[i].dx=clients[i].dy=0;
377 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
378 for (j=i+1;j<MAX_CLIENTS;j++) if (clients[j].connected)
380 if (abs(clients[i].car.x-clients[j].car.x)<30 && abs(clients[i].car.y-clients[j].car.y)<30)
383 for (x1=0;x1<30;x1++)
384 for (y1=0;y1<30;y1++)
385 if (getpixel(cars[(unsigned char)(256*clients[i].car.angle/2.0/M_PI)%256],x1,y1)!=0)
387 x2=x1+clients[i].car.x-clients[j].car.x;
388 y2=y1+clients[i].car.y-clients[j].car.y;
389 if (x2>0 && x2<30 && y2>0 && y2<30)
391 if (getpixel(cars[(unsigned char)(256*clients[j].car.angle/2.0/M_PI)%256],x2,y2)!=0)
393 if (x1<30/2) { clients[i].dx++; clients[j].dx--; } else { clients[i].dx--; clients[j].dx++; }
394 if (y1<30/2) { clients[i].dy++; clients[j].dy--; } else { clients[i].dy--; clients[j].dy++; }
400 /* now compute the collisions */
401 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) if (clients[i].dx || clients[i].dy)
405 int dx=clients[i].dx;
406 int dy=clients[i].dy;
407 /* do not jump to much */
408 while (abs(dx)>5) dx/=2;
409 while (abs(dy)>5) dy/=2;
410 /* get the pixel color under the center of car in the function map */
411 c=getpixel(fun,clients[i].car.x+dx,clients[i].car.y+dy);
412 /* green layer (road quality) */
413 SDL_GetRGB(c,fun->format,&t,&g,&t);
414 /* if the destination is not a wall and not outside of the track */
415 if (g!=0 && clients[i].car.x>cars[0]->w && clients[i].car.x<fun->w-cars[0]->w && clients[i].car.y>cars[0]->h && clients[i].car.y<fun->h-cars[0]->h)
418 clients[i].car.x+=dx;
419 clients[i].car.y+=dy;
421 strcpy(tmp,"collision");
423 SDLNet_Write32(time,tmp);
425 round=(clients[i].car.x+100)*65536;
426 clients[i].car.x=(float)round/65536-100;
427 SDLNet_Write32(round,tmp);
429 round=(clients[i].car.y+100)*65536;
430 clients[i].car.y=(float)round/65536-100;
431 SDLNet_Write32(round,tmp);
433 round=(clients[i].car.speed+100)*65536;
434 clients[i].car.speed=(float)round/65536-100;
435 SDLNet_Write32(round,tmp);
437 round=(clients[i].car.angle+100)*65536;
438 clients[i].car.angle=(float)round/65536-100;
439 SDLNet_Write32(round,tmp);
441 packet->len=(void *)tmp-(void *)packet->data;
442 packet->address=clients[i].address;
443 SDLNet_UDP_Send(udpsock,-1,packet);
444 clients[i].lasttime=time;
449 /* send update to clients */
450 if (time%network_speed==0) for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
453 strcpy(tmp,"positions");
455 SDLNet_Write32(time,tmp);
456 tmp+=4; /* for server time */
457 tmp+=4; /* for client time */
458 tmp+=2; /* for number of cars */
460 for (j=0;j<MAX_CLIENTS;j++) if (j!=i && clients[j].connected)
462 SDLNet_Write16(clients[j].car.x,tmp);
464 SDLNet_Write16(clients[j].car.y,tmp);
466 SDLNet_Write16(clients[j].car.angle*1000,tmp);
468 SDLNet_Write16(clients[j].car.color,tmp);
470 SDLNet_Write16(clients[j].car.lights_brake,tmp);
472 SDLNet_Write16(clients[j].car.lights_backwards,tmp);
474 SDLNet_Write16(clients[j].car.lights_warning,tmp);
478 SDLNet_Write16(nb,packet->data+strlen("positions")+1+4+4);
479 SDLNet_Write32(clients[i].lasttime,packet->data+strlen("positions")+1+4);
480 packet->len=(void *)tmp-(void *)packet->data;
481 packet->address=clients[i].address;
482 SDLNet_UDP_Send(udpsock,-1,packet);
485 /* did someone finish the track ? */
486 for (i=0;i<MAX_CLIENTS;i++) { if (clients[i].car.lapflag==1) printf("client %d : %d laps\n",i,clients[i].car.lap); clients[i].car.lapflag=0; }
487 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].car.lap==nb_laps) finish=1;
490 /* wait like clients */
495 /* send the top 10 screen */
497 strcpy(tmp,"finish");
499 tmp+=2; /* space for number */
503 int best_sc=-1,best_id;
504 for (j=0;j<MAX_CLIENTS;j++) if (clients[j].connected && clients[j].car.lap*32+clients[j].car.lastcheck>best_sc)
506 best_sc=clients[j].car.lap*32+clients[j].car.lastcheck;
511 sprintf(tmp,"%s : %d",clients[best_id].pseudo,best_sc);
513 SDLNet_Write16(clients[best_id].car.color,tmp);
515 clients[best_id].car.lap=-1;
517 printf("top %d : %s - %d\n",nb,clients[best_id].pseudo,best_sc);
520 SDLNet_Write16(nb,packet->data+strlen("finish")+1);
521 packet->len=(void *)tmp-(void *)packet->data;
522 for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
524 packet->address=clients[i].address;
525 SDLNet_UDP_Send(udpsock,-1,packet);
529 SDL_FreeSurface(fun);
530 tracklist=tracklist->next;