int lasttime;
struct _car car;
IPaddress address;
+ int dx,dy;
} clients [MAX_CLIENTS];
/* UDP stuff */
struct _tracklist *tracklist;
SDL_Surface *fun;
+SDL_Surface *cars[256];
/* return the id of a connected address */
printf("announcing server... ");
fflush(stdout);
- if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ 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)
+ if (!tcpsock)
{
fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
return;
len=strlen(temp);
result=SDLNet_TCP_Send(tcpsock,temp,len);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
else
printf("done\n");
-
+
+ free(temp);
SDLNet_TCP_Close(tcpsock);
}
+/* load the car sprite and rotate it for every angles */
+void zeRace_generate_cars()
+{
+ int j;
+ SDL_Surface *car;
+ char temp[20]="sprites/carX.png";
+ temp[11]='A';
+ /* load the car sprite */
+ car=IMG_Load(temp);
+ /* and rotate it for all available angles */
+ for (j=0;j<256;j++)
+ {
+ float x,y;
+ float tcos,tsin;
+ if ((cars[j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,RMASK,GMASK,BMASK,AMASK))==NULL)
+ {
+ fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
+ };
+ tcos=cos(2*M_PI*j/256);
+ tsin=sin(2*M_PI*j/256);
+ for (x=0;x<cars[j]->w;x++) for (y=0;y<cars[j]->h;y++)
+ {
+ int x2,y2;
+ x2=(x-cars[j]->w/2.0)*tcos+(y-cars[j]->h/2.0)*tsin+car->w/2.0;
+ y2=(x-cars[j]->w/2.0)*tsin-(y-cars[j]->h/2.0)*tcos+car->h/2.0;
+ if (x2>0 && x2<car->w && y2>0 && y2<car->h)
+ putpixel(cars[j],x,y,getpixel(car,x2,y2));
+ }
+ }
+ SDL_FreeSurface(car);
+}
+
+
/* 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;
+ int nb_laps,network_speed,pub,col;
- if (argc!=5)
+ if (argc!=6)
{
fprintf(stderr,
- "usage: %s 'server_name' nb_laps network_speed (public|private)\n"
+ "Usage: %s 'server_name' nb_laps network_speed (public|private) (col|nocol)\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"
+ " col : the server will compute collisions between cars\n"
,argv[0]
);
exit(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]));
+ printf("col : %d\n",col=strcmp("nocol",argv[5]));
if (!zeRace_get_tracks(&tracklist)) exit(1);
fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
exit(2);
}
-
+
+ zeRace_generate_cars();
+
for (;;)
{
/* announce the server on internet if wanted */
*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);
+ SDLNet_Write32(time,tmp);
+ tmp+=4;
+ SDLNet_Write32(network_speed,tmp);
+ tmp+=4;
packet->len=(void *)tmp-(void *)packet->data;
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
{
/* wait for everybody startup */
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) break;
- if (i!=MAX_CLIENTS) SDL_Delay(5000);
+ /* 5000ms for countdown, and 500ms for loading time... */
+ if (i!=MAX_CLIENTS) SDL_Delay(5500);
printf("go\n");
/* look for type of message */
tmp=packet->data;
- /*printf("%s\n",tmp);*/
/* new connection ? */
if (strcmp(tmp,"connect")==0)
tmp+=strlen(tmp)+1;
strcpy(clients[i].pseudo,tmp);
tmp+=strlen(tmp)+1;
- memcpy(&clients[i].car.color,tmp,sizeof(int));
+ clients[i].car.color=SDLNet_Read16(tmp);
clients[i].car.x=tracklist->x;
clients[i].car.y=tracklist->y;
clients[i].car.w=30;
*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);
+ SDLNet_Write32(time,tmp);
+ tmp+=4;
+ SDLNet_Write32(network_speed,tmp);
+ tmp+=4;
packet->len=(void *)tmp-(void *)packet->data;
SDLNet_UDP_Send(udpsock,-1,packet);
break;
}
else
{
- int temp;
+ int temp,x,y,x2,y2;
tmp+=strlen(tmp)+1;
- memcpy(&temp,tmp,sizeof(int));
- tmp+=sizeof(int);
- if (clients[id].lasttime==temp)
+ temp=SDLNet_Read32(tmp);
+ tmp+=4;
+ x=SDLNet_Read32(tmp);
+ tmp+=4;
+ y=SDLNet_Read32(tmp);
+ tmp+=4;
+ 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);*/
+ tmp+=temp-clients[id].lasttime;
while (*tmp)
{
move_car(&clients[id].car,*tmp-'A',fun);
- /*printf("%d = %f\n",id,clients[id].car.angle);*/
clients[id].lasttime++;
tmp++;
}
+ /* check that the server and the client are still synchronized */
+ x2=clients[id].car.x;
+ y2=clients[id].car.y;
+ if (x!=x2 || y!=y2)
+ {
+ int round;
+ /* this should not happen with a perfect network protocol :) */
+ printf("client %d unsync at %d\n",id,time);
+ /* instead of dropping the client, we send him a "dumb" collision to resync him */
+ tmp=packet->data;
+ strcpy(tmp,"collision");
+ tmp+=strlen(tmp)+1;
+ SDLNet_Write32(time,tmp);
+ tmp+=4;
+ round=(clients[id].car.x+100)*65536;
+ clients[id].car.x=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ round=(clients[id].car.y+100)*65536;
+ clients[id].car.y=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ round=(clients[id].car.speed+100)*65536;
+ clients[id].car.speed=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ round=(clients[id].car.angle+100)*65536;
+ clients[id].car.angle=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ packet->len=(void *)tmp-(void *)packet->data;
+ packet->address=clients[id].address;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ clients[id].lasttime=time;
+ }
}
}
}
clients[i].connected=0;
}
+ /* should we check for collisions ? */
+ if (col)
+ {
+ /* check for collisions */
+ for (i=0;i<MAX_CLIENTS;i++) clients[i].dx=clients[i].dy=0;
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
+ for (j=i+1;j<MAX_CLIENTS;j++) if (clients[j].connected)
+ if (i!=j)
+ if (abs(clients[i].car.x-clients[j].car.x)<30 && abs(clients[i].car.y-clients[j].car.y)<30)
+ {
+ int x1,y1,x2,y2;
+ for (x1=0;x1<30;x1++)
+ for (y1=0;y1<30;y1++)
+ if (getpixel(cars[(unsigned char)(256*clients[i].car.angle/2.0/M_PI)%256],x1,y1)!=0)
+ {
+ x2=x1+clients[i].car.x-clients[j].car.x;
+ y2=y1+clients[i].car.y-clients[j].car.y;
+ if (x2>0 && x2<30 && y2>0 && y2<30)
+ {
+ if (getpixel(cars[(unsigned char)(256*clients[j].car.angle/2.0/M_PI)%256],x2,y2)!=0)
+ {
+ if (x1<30/2) { clients[i].dx++; clients[j].dx--; } else { clients[i].dx--; clients[j].dx++; }
+ if (y1<30/2) { clients[i].dy++; clients[j].dy--; } else { clients[i].dy--; clients[j].dy++; }
+ }
+ }
+ }
+ }
+
+ /* now compute the collisions */
+ for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) if (clients[i].dx || clients[i].dy)
+ {
+ Uint32 c;
+ Uint8 g,t;
+ int dx=clients[i].dx;
+ int dy=clients[i].dy;
+ /* do not jump to much */
+ while (abs(dx)>5) dx/=2;
+ while (abs(dy)>5) dy/=2;
+ /* get the pixel color under the center of car in the function map */
+ c=getpixel(fun,clients[i].car.x+dx,clients[i].car.y+dy);
+ /* green layer (road quality) */
+ SDL_GetRGB(c,fun->format,&t,&g,&t);
+ /* if the destination is not a wall and not outside of the track */
+ 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)
+ {
+ int round;
+ clients[i].car.x+=dx;
+ clients[i].car.y+=dy;
+ tmp=packet->data;
+ strcpy(tmp,"collision");
+ tmp+=strlen(tmp)+1;
+ SDLNet_Write32(time,tmp);
+ tmp+=4;
+ round=(clients[i].car.x+100)*65536;
+ clients[i].car.x=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ round=(clients[i].car.y+100)*65536;
+ clients[i].car.y=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ round=(clients[i].car.speed+100)*65536;
+ clients[i].car.speed=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ round=(clients[i].car.angle+100)*65536;
+ clients[i].car.angle=(float)round/65536-100;
+ SDLNet_Write32(round,tmp);
+ tmp+=4;
+ packet->len=(void *)tmp-(void *)packet->data;
+ packet->address=clients[i].address;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ clients[i].lasttime=time;
+ }
+ }
+ }
+
/* 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 */
+ SDLNet_Write32(time,tmp);
+ tmp+=4; /* for server time */
+ tmp+=4; /* for client time */
+ tmp+=2; /* 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);
+ SDLNet_Write16(clients[j].car.x,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.y,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.angle*1000,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.color,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.lights_brake,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.lights_backwards,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.lights_warning,tmp);
+ tmp+=2;
nb++;
}
- memcpy(packet->data+strlen("positions")+1+sizeof(int)+sizeof(int),&nb,sizeof(int));
+ SDLNet_Write16(nb,packet->data+strlen("positions")+1+4+4);
+ SDLNet_Write32(clients[i].lasttime,packet->data+strlen("positions")+1+4);
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].car.lapflag==1) printf("client %d : %d laps\n",i,clients[i].car.lap); clients[i].car.lapflag=0; }
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].car.lap==nb_laps) finish=1;
if (finish) break;
tmp=packet->data;
strcpy(tmp,"finish");
tmp+=strlen(tmp)+1;
- tmp+=sizeof(int); /* space for number */
+ tmp+=2; /* space for number */
nb=0;
for (i=0;i<10;i++)
{
{
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);
+ SDLNet_Write16(clients[best_id].car.color,tmp);
+ tmp+=2;
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));
+ SDLNet_Write16(nb,packet->data+strlen("finish")+1);
packet->len=(void *)tmp-(void *)packet->data;
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
{
SDLNet_UDP_Send(udpsock,-1,packet);
}
SDL_Delay(5000);
-
+
+ SDL_FreeSurface(fun);
tracklist=tracklist->next;
}