version 0.5
[zeRace] / server.c
index 047d985..a2ccbcd 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 */
@@ -82,22 +84,56 @@ void announce(char *name,int clients)
 }
 
 
+/* 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);
@@ -106,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);
 
@@ -133,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 */
@@ -197,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)
@@ -264,22 +302,58 @@ int main(int argc,char *argv[])
           }
           else
           {
-            int temp;
+            int temp,x,y,x2,y2;
             tmp+=strlen(tmp)+1;
             temp=SDLNet_Read32(tmp);
             tmp+=4;
+            x=SDLNet_Read32(tmp);
+            tmp+=4;
+            y=SDLNet_Read32(tmp);
+            tmp+=4;
             if (clients[id].lasttime<=temp)
             {
               tmp+=temp-clients[id].lasttime;
-              /* 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 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;
+              }
             }
           }
         }
@@ -295,6 +369,83 @@ 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)
       {
@@ -316,6 +467,12 @@ int main(int argc,char *argv[])
           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++;
         }
         SDLNet_Write16(nb,packet->data+strlen("positions")+1+4+4);
@@ -326,6 +483,7 @@ int main(int argc,char *argv[])
       }
       
       /* 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;