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