version 0.7
[zeRace] / server.c
index c6da730..6c410cc 100644 (file)
--- a/server.c
+++ b/server.c
@@ -13,6 +13,7 @@ struct _clients
   int lasttime;
   struct _car car;
   IPaddress address;
+  int dx,dy;
 } clients [MAX_CLIENTS];
 
 /* UDP stuff */
@@ -21,6 +22,7 @@ UDPpacket *packet;
 
 struct _tracklist *tracklist;
 SDL_Surface *fun;
+SDL_Surface *cars[256];
 
 
 /* return the id of a connected address */
@@ -54,14 +56,14 @@ void announce(char *name,int clients)
   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;
@@ -72,31 +74,66 @@ void announce(char *name,int clients)
   
   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);
@@ -105,6 +142,7 @@ int main(int argc,char *argv[])
   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);
 
@@ -132,7 +170,9 @@ int main(int argc,char *argv[])
     fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
     exit(2);
   }
-
+  
+  zeRace_generate_cars();
+  
   for (;;)
   {
     /* announce the server on internet if wanted */
@@ -165,10 +205,10 @@ int main(int argc,char *argv[])
     *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)
     {
@@ -178,7 +218,8 @@ int main(int argc,char *argv[])
     
     /* 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");
     
@@ -195,7 +236,6 @@ int main(int argc,char *argv[])
         
         /* look for type of message */
         tmp=packet->data;
-        /*printf("%s\n",tmp);*/
         
         /* new connection ? */
         if (strcmp(tmp,"connect")==0)
@@ -216,7 +256,7 @@ int main(int argc,char *argv[])
             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;
@@ -233,10 +273,10 @@ int main(int argc,char *argv[])
             *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;
@@ -262,21 +302,58 @@ int main(int argc,char *argv[])
           }
           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;
+              }
             }
           }
         }
@@ -292,31 +369,121 @@ int main(int argc,char *argv[])
         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;
         
@@ -329,7 +496,7 @@ int main(int argc,char *argv[])
     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++)
     {
@@ -343,14 +510,14 @@ int main(int argc,char *argv[])
       {
         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)
     {
@@ -358,7 +525,8 @@ int main(int argc,char *argv[])
       SDLNet_UDP_Send(udpsock,-1,packet);
     }
     SDL_Delay(5000);
-  
+    
+    SDL_FreeSurface(fun);
     tracklist=tracklist->next;
   }