1 
2 /***********************************************************
3 *                      K O U L E S                         *
4 *----------------------------------------------------------*
5 *  C1995 JAHUSOFT                                          *
6 *        Jan Hubicka                                       *
7 *        Dukelskych Bojovniku 1944                         *
8 *        390 03 Tabor                                      *
9 *        Czech Republic                                    *
10 *        Phone: 0041-361-32613                             *
11 *        eMail: hubicka@limax.paru.cas.cz                  *
12 *----------------------------------------------------------*
13 *   Copyright(c)1995,1996 by Jan Hubicka.See README for    *
14 *                    licence details.                      *
15 *----------------------------------------------------------*
16 *  client.c network client routines                        *
17 ***********************************************************/
18 #include <stdio.h>
19 #include <sys/time.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <errno.h>
23 #include "sock.h"
24 #include "net.h"
25 #include "client.h"
26 #include "koules.h"
27 #ifdef NETSUPPORT
28 #define error printf
29 #ifdef SOUND
30 extern int      ssound;
31 #endif
32 extern void     process_keys ();
33 extern int      fadedout;
34 extern int      nplayers;
35 extern int      explosion (int x, int y, int type, int letter, int n);
36 extern int      creators_points (int radius, int x, int y, int color);
37 extern void     setnplayers (int n);
38 extern int      read_objects (unsigned char *buffer, int n);
39 extern void     effect (int nos);
40 extern void     cmenu2 (unsigned char *message, int size);
41 extern void     client_loop2 (int draw);
42 char            servername[256];
43 static int      socket_c;
44 static int      sock;
45 static int      nodata;
46 static int      quited = 0;
47 static int      port;
48 static int      falied;
49 static int      allframes, dispframes, realdisplayed;
50 static int      rframe;
51 static long     rpos;
52 static long     rcount = 1;
53 static long     rrcount = 0;
54 static long     timeout = 1;
55 static int      nodisplayco = 0;
56 static char     hostname[256];
57 #define BUFFERSIZE 65536
58 static unsigned char buffer[BUFFERSIZE];
59 struct c_table
60   {
61     void            (*func) (unsigned char *message, int size);
62   };
63 static unsigned char obuffer[BUFFERSIZE];
64 static unsigned char ibuffer[BUFFERSIZE];
65 static unsigned char rbuffer[BUFFERSIZE];
66 static int      rposition;
67 static int      obufferpos;
68 #define WAITTIME 5
69 void
70                 csendbegining (unsigned char *message, int size);
71 
72 void
csetrrcount(long scount)73 csetrrcount (long scount)
74 {
75   int             size, pos = 0, count;
76   if (scount <= rrcount)
77     return;			/*Old repeated message */
78   do
79     {
80       GETLONG ((rbuffer + pos), count);
81       GETSHORT ((rbuffer + pos) + 4, size);
82       pos += size;
83     }
84   while (count < scount);
85   memmove (rbuffer, rbuffer + pos, rposition - pos);
86   rposition -= pos;
87   rrcount = scount;
88 }
89 
90 void
cflushreliable()91 cflushreliable ()
92 {
93   if (rposition)
94     {
95       PUTHEAD (SRELIABLE) memcpy (buffer + HEADSIZE, rbuffer, rposition);
96       csendbegining (buffer, rposition + HEADSIZE);
97     }
98 }
99 
100 void
csendbuffer()101 csendbuffer ()
102 {
103   int             result;
104   if (timeout)
105     {
106       timeout--;
107       if (!timeout)
108 	{
109 	  cflushreliable ();
110 	  timeout = WAITTIME;
111 	}
112     }
113   if (!obufferpos)
114     return;
115   PUTLONG ((obuffer), rpos);
116   falied = 0;
117   GetSocketError (sock);
118   /*if (!(rand()%2)) *//*Emulate internet :)))))) */
119   if ((result = DgramSend (sock, servername, port,
120 			   (char *) obuffer, obufferpos + 4)) <= 0)
121     {
122       if (errno == EAGAIN || errno == EWOULDBLOCK || result >= 0)
123 	{
124 	  GetSocketError (sock);
125 	  falied = 1;
126 	  if (timeout == WAITTIME)
127 	    timeout = 1;
128 	}
129       else
130 	{
131 	  perror ("Can't send message to server\n");
132 	  SocketClose (socket_c);
133 	  SocketClose (sock);
134 	  exit(-1);
135 	}
136     }
137   obufferpos = 0;
138 }
139 void
csendbegining(unsigned char * message,int size)140 csendbegining (unsigned char *message, int size)	/*send at more reliable beggining of packet */
141 {
142   if (obufferpos + size + 6 > BUFFERSIZE)
143     csendbuffer ();
144 
145   memmove (obuffer + size + 6, obuffer + 4, obufferpos);
146   PUTSHORT ((obuffer + 4), size + 2);
147   memcpy (obuffer + 6, message, size);
148   obufferpos += size + 2;
149 }
150 void
csendreliable(unsigned char * message,int size)151 csendreliable (unsigned char *message, int size)
152 {
153   if (size == 0)
154     return;
155   if (rposition + size + 6 > BUFFERSIZE)
156     {
157       printf ("Connection to server broken too long! Reliable buffer owerfllow\n"
158 	      "Game aborted\n");
159       exit (-1);
160     }
161   PUTLONG ((rbuffer + rposition), rcount);
162   rcount++;
163   PUTSHORT ((rbuffer + rposition + 4), (size + 6));
164   memcpy (rbuffer + rposition + 6, message, size);
165   rposition += size + 6;
166   timeout = 1;
167 }
168 
169 void
csend(unsigned char * message,int size)170 csend (unsigned char *message, int size)
171 {
172   if (obufferpos + size + 2 + 4 > BUFFERSIZE)
173     csendbuffer ();
174   PUTSHORT ((obuffer + obufferpos + 4), size + 2);
175   memcpy (obuffer + obufferpos + 6, message, size);
176   obufferpos += size + 2;
177 }
178 void
register_players()179 register_players ()
180 {
181   PUTHEAD (SREGISTER);
182   PUTCHAR ((buffer + 1), nplayers);
183   csendreliable (buffer, HEADSIZE + 1);
184   gamemode = WAIT;
185 }
186 void
start_game()187 start_game ()
188 {
189   PUTHEAD (SSTART);
190   csendreliable (buffer, HEADSIZE);
191   gamemode = WAIT;
192 #ifdef SOUND
193   sound = ssound;
194 #endif
195 }
196 void
CQuit(char * text)197 CQuit (char *text)
198 {
199   static int      n;
200   if (quited)
201     return;
202   quited = 1;
203   PUTHEAD (SQUIT);
204   strcpy ((char *) (buffer + HEADSIZE), text);
205   printf ("Terminating game.\nReason:%s\n", text);
206   for (n = 0; n < 5; n++)
207     {				/*repeat quiting messages to make sure that
208 				   all clients received it */
209       csend (buffer, strlen (text) + HEADSIZE + 1);
210       csendbuffer ();
211     }
212   SocketClose (sock);
213   quited = 1;
214   /*exit(0); */
215   uninitialize ();
216   exit (0);
217 }
218 
219 void
GetPos(void)220 GetPos (void)
221 {
222 #if 0
223   int             x = /*(dispframes + realdisplayed + 1) / 2 */ dispframes / 4;
224 #else
225   int             x = realdisplayed + 5;
226 #endif
227   PUTHEAD (SPOS);
228   PUTCHAR (buffer + HEADSIZE, x);
229   csendreliable (buffer, HEADSIZE + 1);
230 }
231 void
SendKeys(int player,int c)232 SendKeys (int player, int c)
233 {
234   PUTHEAD (SKEY);
235   PUTCHAR (buffer + HEADSIZE, c);
236   PUTCHAR (buffer + HEADSIZE + 1, player);
237   csendreliable (buffer, HEADSIZE + 2);
238 }
239 void
SendRotation(int player,int c)240 SendRotation (int player, int c)
241 {
242   PUTHEAD (SROT);
243   PUTCHAR (buffer + HEADSIZE, c);
244   PUTCHAR (buffer + HEADSIZE + 1, player);
245   csendreliable (buffer, HEADSIZE + 2);
246 }
247 void
SendMouse(int player,int x,int y,int buttons)248 SendMouse (int player, int x, int y, int buttons)
249 {
250   PUTHEAD (SMOUSE);
251   PUTSHORT (buffer + HEADSIZE, x);
252   PUTSHORT (buffer + HEADSIZE + 2, y);
253   PUTCHAR (buffer + HEADSIZE + 4, buttons);
254   PUTCHAR (buffer + HEADSIZE + 5, player);
255   csendreliable (buffer, HEADSIZE + 6);
256 }
257 void
SendJoystick(int player,int x,int y,int buttons)258 SendJoystick (int player, int x, int y, int buttons)
259 {
260   PUTHEAD (SJOYSTICK);
261   PUTSHORT (buffer + HEADSIZE, x);
262   PUTSHORT (buffer + HEADSIZE + 2, y);
263   PUTCHAR (buffer + HEADSIZE + 4, buttons);
264   PUTCHAR (buffer + HEADSIZE + 5, player);
265   csendreliable (buffer, HEADSIZE + 6);
266 }
267 void
SendControls()268 SendControls ()
269 {
270   static struct control c[5];
271   int             i;
272   for (i = 0; i < 5; i++)
273     {
274       if (control[i] && memcmp ((char *) &controls[i], (char *) &c[i], sizeof (controls[i])))
275 	{
276 	  memcpy ((char *) &c[i], (char *) &controls[i], sizeof (controls[i]));
277 	  switch (c[i].type)
278 	    {
279 	    case C_KEYBOARD:
280 	      SendKeys (i, c[i].mask);
281 	      break;
282 	    case C_RKEYBOARD:
283 	      SendRotation (i, c[i].mask);
284 	      break;
285 	    case C_MOUSE:
286 	      SendMouse (i, c[i].mx, c[i].my, c[i].mask);
287 	      break;
288 	    case C_JOYSTICK1:
289 	      SendMouse (i, c[i].jx, c[i].jy, c[i].mask);
290 	      break;
291 	    }
292 	}
293     }
294 }
295 void
Ready(void)296 Ready (void)
297 {
298   PUTHEAD (SREADY);
299   csendreliable (buffer, HEADSIZE);
300 }
301 static void
print(unsigned char * message,int size)302 print (unsigned char *message, int size)
303 {
304   printf ("Server's message:%s\n", (char *) message);
305 }
306 static void
quit(unsigned char * message,int size)307 quit (unsigned char *message, int size)
308 {
309   printf ("Uninitializing:%s\n", (char *) message);
310   SocketClose (sock);
311   quited = 1;
312   exit (0);
313 }
314 static void
cexplosion(unsigned char * message,int size)315 cexplosion (unsigned char *message, int size)
316 {
317   int             x, y, type, letter, n;
318   GETSHORT (message, x);
319   GETSHORT ((message + 2), y);
320   GETCHAR ((message + 4), type);
321   GETCHAR ((message + 5), letter);
322   GETCHAR ((message + 6), n);
323   explosion (x, y, type, letter, n);
324 }
325 static void
coutro(unsigned char * message,int size)326 coutro (unsigned char *message, int size)
327 {
328   outro2 ();
329   CQuit ("End of game\nBye");
330 }
331 static void
ccreatord_points(unsigned char * message,int size)332 ccreatord_points (unsigned char *message, int size)
333 {
334   int             x, y, radius, color;
335   GETSHORT (message, x);
336   GETSHORT ((message + 2), y);
337   GETSHORT ((message + 4), radius);
338   GETCHAR ((message + 6), color);
339   creators_points (radius, x, y, color);
340 }
341 static void
csound(unsigned char * message,int size)342 csound (unsigned char *message, int size)
343 {
344   int             s;
345   GETCHAR (message, s);
346   Effect (s, next);
347 }
348 
349 static void
cplayers(unsigned char * message,int size)350 cplayers (unsigned char *message, int size)
351 {
352   int             s;
353   GETCHAR (message, s);
354   setnplayers (s);
355 }
356 static void
creg(unsigned char * message,int size)357 creg (unsigned char *message, int size)
358 {
359   int             s;
360   for (s = 0; s < MAXROCKETS; s++)
361     if (message[s])
362       control[s] = 1;
363     else
364       control[s] = 0;
365 }
366 static void
cpos(unsigned char * message,int size)367 cpos (unsigned char *message, int size)
368 {
369   read_objects ((unsigned char *) message, nodata);
370   rframe = 1;
371   nodata = 0;
372 }
373 static void
clevel(unsigned char * message,int size)374 clevel (unsigned char *message, int size)
375 {
376   int             nos;
377   GETCHAR (message, lastlevel);
378   GETCHAR (message + 1, nos);
379   GETCHAR (message + 2, gameplan);
380   gamemode = GAME;
381 #ifdef SOUND
382   sound = ssound;
383 #endif
384   gameplan_init ();
385   effect (nos);
386   nodisplayco = 10;
387   Ready ();
388 }
389 static void
cgame(unsigned char * message,int size)390 cgame (unsigned char *message, int size)
391 {
392   gamemode = GAME;
393   Ready ();
394 }
395 void            creliable (unsigned char *message, int size);
396 static struct c_table ctable[] =
397 {
398   {print},
399   {quit},
400   {cpos},
401   {cexplosion},
402   {ccreatord_points},
403   {csound},
404   {cplayers},
405   {creg},
406   {cmenu2},
407   {clevel},
408   {cgame},
409   {creliable},
410   {coutro}
411 };
412 void
creliable(unsigned char * message,int size)413 creliable (unsigned char *message, int size)
414 {
415   int             pos = 0;
416   while (pos < size)
417     {
418       long            rpos1;
419       int             size;
420       GETLONG ((message + pos), rpos1);
421       if (rpos1 > rpos + 1)
422 	{
423 	  printf ("Fatal error in transfering reliable messages!\n"
424 		  "Game may become VERY unstable..please contact author \n");
425 	  return;
426 	}
427       GETSHORT ((message + pos + 4), size);
428       if (rpos1 <= rpos)
429 	{
430 	  pos += size;
431 	  continue;
432 	}
433       rpos = rpos1;
434       ctable[message[pos + 6]].func ((message + pos + 7), size - 7);
435       pos += size;
436     }
437 }
438 void
process_message(void)439 process_message (void)
440 {
441   int             bytes, pos = 4;
442   long            scount;
443   if (!SocketReadable (sock))
444     return;
445   GetSocketError (sock);
446   if ((bytes = DgramReceiveAny (sock, (char *) ibuffer, BUFFERSIZE)) <= 0)
447     {
448       if (errno == EAGAIN || errno == EWOULDBLOCK || bytes >= 0)
449 	{
450 	  GetSocketError (sock);
451 	  return;
452 	}
453       CQuit ("Can't receive server's message\n");
454       SocketClose (sock);
455     }
456   GETLONG (ibuffer, scount);
457   csetrrcount (scount);
458   while (pos + 2 < bytes)
459     {
460       int             size;
461       GETSHORT (ibuffer + pos, size);
462       if (pos + size <= bytes)
463 	{
464 	  ctable[ibuffer[pos + 2]].func ((ibuffer + pos + 3), size - 3);
465 	}
466       pos += size;
467     }
468 
469 }
470 #define VERSION 0
471 int
init_client(void)472 init_client (void)
473 {
474   long            bytes, pport;
475   int             gx, gy;
476   int             retries = 0;
477 /*Open server socket */
478   printf ("Opening server socket\n");
479   if ((socket_c = CreateDgramSocket (0)) == -1)
480     {
481       error ("Could not create connection socket");
482       SocketClose (socket_c);
483       exit (-1);
484     }
485   strcpy(hostname,GetSockAddr(socket_c));
486 /*Create connection message */
487   strcpy ((char *) buffer, "Koules");
488   PUTCHAR (buffer + 7, VERSION);
489   PUTSHORT (buffer + 8, GAMEWIDTH);
490   PUTSHORT (buffer + 10, GAMEHEIGHT);
491   PUTLONG (buffer + 12, (long) getpid ());
492   printf ("Asking server at %s port %i\n", servername, initport);
493 #if 0
494   if (DgramConnect (socket_c, servername, initport) == -1)
495     {
496       perror ("Connection error");
497       error ("Can't connect to server %s on port %d", servername, port);
498       close (socket_c);
499       return -1;
500     }
501 #endif
502 again:
503   GetSocketError (socket_c);
504   errno = 0;
505   do
506     {
507       if (retries)
508 	sleep (1);
509       retries++;
510       if (retries > 100)
511 	printf (" Connection timed out\n"), exit (-1);
512       if (errno)
513 	{
514 	  perror ("Can't receive reply");
515 	  exit (-1);
516 	}
517       if (DgramSend (socket_c, servername, initport,
518 		     (char *) buffer, INITPACKETSIZE) == -1)
519 	{
520 	  SocketClose (socket_c);
521 	  perror ("Can't send message to server");
522 	  exit (-1);
523 	}
524       if (errno)
525 	{
526 	  perror ("Can't send message to server");
527 	  /*exit (-1); */
528 	  GetSocketError (socket_c);
529 	  errno = 0;
530 	}
531       SetTimeout (1, 10 * 1000);
532     }
533   while (!(SocketReadable (socket_c)));
534   bytes = DgramReceiveAny (socket_c, (char *) buffer, BUFFERSIZE);
535   if (bytes != REPLYSIZE)
536     goto again;
537   SocketClose (socket_c);
538   GETLONG (buffer, port);
539   if (port == 0)
540     {
541       printf ("Server refused me! (too many players or incompatible screen size)\n"
542 	      "Try -W server's option is you are using 320x200 clients..\n");
543       exit (-1);
544     }
545   GETSHORT ((buffer + 4), gx);
546   GETSHORT ((buffer + 6), gy);
547 
548   printf ("YYYYAAAAAAA Server replied.\n"
549 	  "Opening port %i\n", port);
550   if ((sock = CreateDgramSocket (0)) == -1)
551     {
552       error ("Can't create datagram socket");
553       return -1;
554     }
555   SetTimeout (1, 10 * 1000);
556 
557   /*if (DgramConnect (sock, servername, port) == -1)
558      {
559      error ("Can't connect to server %s on port %d", servername, port);
560      close (sock);
561      return -1;
562      } */
563   if (SetSocketNonBlocking (sock, 1) == -1)
564     {
565       error ("Can't make socket non-blocking");
566       return -1;
567     }
568   printf ("Sending initialization message\n");
569   pport = GetPortNum (sock);
570   if (gx / DIV > GAMEWIDTH || gy / DIV > GAMEHEIGHT)
571     {
572       printf ("Server's gamepool too large\n"
573 	      "Try -W on server's command line\n");
574 
575       PUTLONG (buffer, 0);
576       if (DgramSend (sock, servername, port,
577 		     (char *) buffer, 4) == -1)
578 	close (sock);
579       exit (-1);
580     }
581   else
582     GAMEWIDTH = gx, GAMEHEIGHT = gy;
583   PUTHEAD (SINIT);
584   PUTLONG (buffer + HEADSIZE, pport);
585   if (SetSocketReceiveBufferSize (sock, NETBUFFER) == -1)
586     {
587       error ("Can't set socket buffer size");
588       return -1;
589     }
590   if (SetSocketSendBufferSize (sock, NETBUFFER) == -1)
591     {
592       error ("Can't set socket buffer size");
593       return -1;
594     }
595   GetSocketError (sock);
596   csendreliable (buffer, 4 + HEADSIZE);
597   csendbuffer ();
598   csendbuffer ();
599   csendbuffer ();
600   printf ("Starting game...\n");
601   return (0);
602 }
603 void
client_loop(void)604 client_loop (void)
605 {
606   long            VfTime = 0;
607   long            VendSleep = 0;
608   struct timeval  VlastClk;
609   struct timeval  VnewClk;
610   int             wait = 0;
611 #if 0
612   int             drawed = 0;
613   int             display = 1;
614 #endif
615   client = 1;
616 
617   load_rc ();
618   init_menu ();
619 
620   Ready ();
621 #ifdef XSUPPORT
622   nopause = 1;
623 #endif
624   gamemode = MENU;
625   gettimeofday (&VlastClk, NULL);
626   gettimeofday (&VnewClk, NULL);
627   VendSleep = VlastClk.tv_usec;
628   VfTime = 1000000 / 25;
629   dispframes = 25 * 4;
630   realdisplayed = 25;
631   GetPos ();
632   dispframes = 0;
633   realdisplayed = 0;
634   while (1)
635     {
636       if (nodisplayco)
637 	nodisplayco--;
638       SetTimeout (0, 0);
639       nodata++;
640       while (SocketReadable (sock))
641 	process_message ();
642       gettimeofday (&VnewClk, NULL);
643       if (VnewClk.tv_usec < VendSleep)
644 	VendSleep -= 1000000;
645       wait = (VfTime - VnewClk.tv_usec + VendSleep);
646       allframes++;
647       if (fadedout)
648 	rframe = 1;
649       process_keys ();
650       if ((wait > 0 || tbreak))
651 	{			/*display=0; */
652 	  csendbuffer ();
653 	  realdisplayed++;
654 	  client_loop2 (rframe && (!nodisplayco));
655 	  rframe = 0;
656 	}
657       else
658 	{
659 	  csendbuffer ();
660 	  client_loop2 (0);
661 	}
662       if (allframes == 25 || tbreak)
663 	{
664 	  /*printf ("Displayed frames:%i really:%i\n", dispframes / 4, realdisplayed); */
665 	  if (tbreak)
666 	    realdisplayed = 25;
667 	  GetPos ();
668 	  allframes = 0;
669 	  dispframes = 0;
670 	  realdisplayed = 0;
671 	}
672       SendControls ();
673 #ifndef HAVEUSLEEP
674       do
675 	{			/*my emulation of usleep isn't reiable on HP-UX machines
676 				   when sockets are comming :( */
677 #endif
678 	  gettimeofday (&VnewClk, NULL);
679 	  if (VnewClk.tv_usec < VendSleep)
680 	    VendSleep -= 1000000;
681 	  wait = (VfTime - VnewClk.tv_usec + VendSleep);
682 	  if (tbreak)
683 	    wait = VfTime;
684 	  if (wait > 0)
685 	    usleep (wait);
686 #ifndef HAVEUSLEEP
687 	}
688       while (wait > 10 && !tbreak);
689 #endif
690       VendSleep = VnewClk.tv_usec + wait;
691       gettimeofday (&VlastClk, NULL);
692       if (tbreak)
693 	VendSleep = VlastClk.tv_usec;
694       tbreak = 0;
695     }
696 }
697 #endif
698