summaryrefslogtreecommitdiffstats
path: root/pacman-c++/server
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2011-05-05 00:57:07 +0200
committermanuel <manuel@mausz.at>2011-05-05 00:57:07 +0200
commitce48af53646cd9e7ec762fc1ac176b3aa620b11d (patch)
treef8fbf2cae8c7d0cbac2696a8f4cf94410bfb4928 /pacman-c++/server
parente54ccad07e256ba877bd41d70bd358bd0085bd1e (diff)
downloadfoop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.tar.gz
foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.tar.bz2
foop-ce48af53646cd9e7ec762fc1ac176b3aa620b11d.zip
- refactorized the whole project and made a few subprojects
- replaced tcp with enet - added connect dialog - some smaller bugfixes
Diffstat (limited to 'pacman-c++/server')
-rw-r--r--pacman-c++/server/anyoption.cpp1175
-rw-r--r--pacman-c++/server/anyoption.h270
-rw-r--r--pacman-c++/server/server.cpp971
-rw-r--r--pacman-c++/server/server.h85
-rw-r--r--pacman-c++/server/server.pro10
5 files changed, 2511 insertions, 0 deletions
diff --git a/pacman-c++/server/anyoption.cpp b/pacman-c++/server/anyoption.cpp
new file mode 100644
index 0000000..4e3828e
--- /dev/null
+++ b/pacman-c++/server/anyoption.cpp
@@ -0,0 +1,1175 @@
1/*
2 * AnyOption 1.3
3 *
4 * kishan at hackorama dot com www.hackorama.com JULY 2001
5 *
6 * + Acts as a common facade class for reading
7 * commandline options as well as options from
8 * an optionfile with delimited type value pairs
9 *
10 * + Handles the POSIX style single character options ( -w )
11 * as well as the newer GNU long options ( --width )
12 *
13 * + The option file assumes the traditional format of
14 * first character based comment lines and type value
15 * pairs with a delimiter , and flags which are not pairs
16 *
17 * # this is a coment
18 * # next line is an option value pair
19 * width : 100
20 * # next line is a flag
21 * noimages
22 *
23 * + Supports printing out Help and Usage
24 *
25 * + Why not just use getopt() ?
26 *
27 * getopt() Its a POSIX standard not part of ANSI-C.
28 * So it may not be available on platforms like Windows.
29 *
30 * + Why it is so long ?
31 *
32 * The actual code which does command line parsing
33 * and option file parsing are done in few methods.
34 * Most of the extra code are for providing a flexible
35 * common public interface to both a resourcefile and
36 * and command line supporting POSIX style and
37 * GNU long option as well as mixing of both.
38 *
39 * + Please see "anyoption.h" for public method descriptions
40 *
41 */
42
43/* Updated Auguest 2004
44 * Fix from Michael D Peters (mpeters at sandia.gov)
45 * to remove static local variables, allowing multiple instantiations
46 * of the reader (for using multiple configuration files). There is
47 * an error in the destructor when using multiple instances, so you
48 * cannot delete your objects (it will crash), but not calling the
49 * destructor only introduces a small memory leak, so I
50 * have not bothered tracking it down.
51 *
52 * Also updated to use modern C++ style headers, rather than
53 * depricated iostream.h (it was causing my compiler problems)
54*/
55
56/*
57 * Updated September 2006
58 * Fix from Boyan Asenov for a bug in mixing up option indexes
59 * leading to exception when mixing different options types
60 */
61
62#include "anyoption.h"
63#include <cstring>
64
65AnyOption::AnyOption()
66{
67 init();
68}
69
70AnyOption::AnyOption(int maxopt)
71{
72 init( maxopt , maxopt );
73}
74
75AnyOption::AnyOption(int maxopt, int maxcharopt)
76{
77 init( maxopt , maxcharopt );
78}
79
80AnyOption::~AnyOption()
81{
82 if( mem_allocated )
83 cleanup();
84}
85
86void
87AnyOption::init()
88{
89 init( DEFAULT_MAXOPTS , DEFAULT_MAXOPTS );
90}
91
92void
93AnyOption::init(int maxopt, int maxcharopt )
94{
95
96 max_options = maxopt;
97 max_char_options = maxcharopt;
98 max_usage_lines = DEFAULT_MAXUSAGE;
99 usage_lines = 0 ;
100 argc = 0;
101 argv = NULL;
102 posix_style = true;
103 verbose = false;
104 filename = NULL;
105 appname = NULL;
106 option_counter = 0;
107 optchar_counter = 0;
108 new_argv = NULL;
109 new_argc = 0 ;
110 max_legal_args = 0 ;
111 command_set = false;
112 file_set = false;
113 values = NULL;
114 g_value_counter = 0;
115 mem_allocated = false;
116 command_set = false;
117 file_set = false;
118 opt_prefix_char = '-';
119 file_delimiter_char = ':';
120 file_comment_char = '#';
121 equalsign = '=';
122 comment = '#' ;
123 delimiter = ':' ;
124 endofline = '\n';
125 whitespace = ' ' ;
126 nullterminate = '\0';
127 set = false;
128 once = true;
129 hasoptions = false;
130 autousage = false;
131
132 strcpy( long_opt_prefix , "--" );
133
134 if( alloc() == false ){
135 cout << endl << "OPTIONS ERROR : Failed allocating memory" ;
136 cout << endl ;
137 cout << "Exiting." << endl ;
138 exit (0);
139 }
140}
141
142bool
143AnyOption::alloc()
144{
145 int i = 0 ;
146 int size = 0 ;
147
148 if( mem_allocated )
149 return true;
150
151 size = (max_options+1) * sizeof(const char*);
152 options = (const char**)malloc( size );
153 optiontype = (int*) malloc( (max_options+1)*sizeof(int) );
154 optionindex = (int*) malloc( (max_options+1)*sizeof(int) );
155 if( options == NULL || optiontype == NULL || optionindex == NULL )
156 return false;
157 else
158 mem_allocated = true;
159 for( i = 0 ; i < max_options ; i++ ){
160 options[i] = NULL;
161 optiontype[i] = 0 ;
162 optionindex[i] = -1 ;
163 }
164 optionchars = (char*) malloc( (max_char_options+1)*sizeof(char) );
165 optchartype = (int*) malloc( (max_char_options+1)*sizeof(int) );
166 optcharindex = (int*) malloc( (max_char_options+1)*sizeof(int) );
167 if( optionchars == NULL ||
168 optchartype == NULL ||
169 optcharindex == NULL )
170 {
171 mem_allocated = false;
172 return false;
173 }
174 for( i = 0 ; i < max_char_options ; i++ ){
175 optionchars[i] = '0';
176 optchartype[i] = 0 ;
177 optcharindex[i] = -1 ;
178 }
179
180 size = (max_usage_lines+1) * sizeof(const char*) ;
181 usage = (const char**) malloc( size );
182
183 if( usage == NULL ){
184 mem_allocated = false;
185 return false;
186 }
187 for( i = 0 ; i < max_usage_lines ; i++ )
188 usage[i] = NULL;
189
190 return true;
191}
192
193bool
194AnyOption::doubleOptStorage()
195{
196 options = (const char**)realloc( options,
197 ((2*max_options)+1) * sizeof( const char*) );
198 optiontype = (int*) realloc( optiontype ,
199 ((2 * max_options)+1)* sizeof(int) );
200 optionindex = (int*) realloc( optionindex,
201 ((2 * max_options)+1) * sizeof(int) );
202 if( options == NULL || optiontype == NULL || optionindex == NULL )
203 return false;
204 /* init new storage */
205 for( int i = max_options ; i < 2*max_options ; i++ ){
206 options[i] = NULL;
207 optiontype[i] = 0 ;
208 optionindex[i] = -1 ;
209 }
210 max_options = 2 * max_options ;
211 return true;
212}
213
214bool
215AnyOption::doubleCharStorage()
216{
217 optionchars = (char*) realloc( optionchars,
218 ((2*max_char_options)+1)*sizeof(char) );
219 optchartype = (int*) realloc( optchartype,
220 ((2*max_char_options)+1)*sizeof(int) );
221 optcharindex = (int*) realloc( optcharindex,
222 ((2*max_char_options)+1)*sizeof(int) );
223 if( optionchars == NULL ||
224 optchartype == NULL ||
225 optcharindex == NULL )
226 return false;
227 /* init new storage */
228 for( int i = max_char_options ; i < 2*max_char_options ; i++ ){
229 optionchars[i] = '0';
230 optchartype[i] = 0 ;
231 optcharindex[i] = -1 ;
232 }
233 max_char_options = 2 * max_char_options;
234 return true;
235}
236
237bool
238AnyOption::doubleUsageStorage()
239{
240 usage = (const char**)realloc( usage,
241 ((2*max_usage_lines)+1) * sizeof( const char*) );
242 if ( usage == NULL )
243 return false;
244 for( int i = max_usage_lines ; i < 2*max_usage_lines ; i++ )
245 usage[i] = NULL;
246 max_usage_lines = 2 * max_usage_lines ;
247 return true;
248
249}
250
251
252void
253AnyOption::cleanup()
254{
255 free (options);
256 free (optiontype);
257 free (optionindex);
258 free (optionchars);
259 free (optchartype);
260 free (optcharindex);
261 free (usage);
262 if( values != NULL )
263 free (values);
264 if( new_argv != NULL )
265 free (new_argv);
266}
267
268void
269AnyOption::setCommandPrefixChar( char _prefix )
270{
271 opt_prefix_char = _prefix;
272}
273
274void
275AnyOption::setCommandLongPrefix( char *_prefix )
276{
277 if( strlen( _prefix ) > MAX_LONG_PREFIX_LENGTH ){
278 *( _prefix + MAX_LONG_PREFIX_LENGTH ) = '\0';
279 }
280
281 strcpy (long_opt_prefix, _prefix);
282}
283
284void
285AnyOption::setFileCommentChar( char _comment )
286{
287 file_delimiter_char = _comment;
288}
289
290
291void
292AnyOption::setFileDelimiterChar( char _delimiter )
293{
294 file_comment_char = _delimiter ;
295}
296
297bool
298AnyOption::CommandSet()
299{
300 return( command_set );
301}
302
303bool
304AnyOption::FileSet()
305{
306 return( file_set );
307}
308
309void
310AnyOption::noPOSIX()
311{
312 posix_style = false;
313}
314
315bool
316AnyOption::POSIX()
317{
318 return posix_style;
319}
320
321
322void
323AnyOption::setVerbose()
324{
325 verbose = true ;
326}
327
328void
329AnyOption::printVerbose()
330{
331 if( verbose )
332 cout << endl ;
333}
334void
335AnyOption::printVerbose( const char *msg )
336{
337 if( verbose )
338 cout << msg ;
339}
340
341void
342AnyOption::printVerbose( char *msg )
343{
344 if( verbose )
345 cout << msg ;
346}
347
348void
349AnyOption::printVerbose( char ch )
350{
351 if( verbose )
352 cout << ch ;
353}
354
355bool
356AnyOption::hasOptions()
357{
358 return hasoptions;
359}
360
361void
362AnyOption::autoUsagePrint(bool _autousage)
363{
364 autousage = _autousage;
365}
366
367void
368AnyOption::useCommandArgs( int _argc, char **_argv )
369{
370 argc = _argc;
371 argv = _argv;
372 command_set = true;
373 appname = argv[0];
374 if(argc > 1) hasoptions = true;
375}
376
377void
378AnyOption::useFiileName( const char *_filename )
379{
380 filename = _filename;
381 file_set = true;
382}
383
384/*
385 * set methods for options
386 */
387
388void
389AnyOption::setCommandOption( const char *opt )
390{
391 addOption( opt , COMMAND_OPT );
392 g_value_counter++;
393}
394
395void
396AnyOption::setCommandOption( char opt )
397{
398 addOption( opt , COMMAND_OPT );
399 g_value_counter++;
400}
401
402void
403AnyOption::setCommandOption( const char *opt , char optchar )
404{
405 addOption( opt , COMMAND_OPT );
406 addOption( optchar , COMMAND_OPT );
407 g_value_counter++;
408}
409
410void
411AnyOption::setCommandFlag( const char *opt )
412{
413 addOption( opt , COMMAND_FLAG );
414 g_value_counter++;
415}
416
417void
418AnyOption::setCommandFlag( char opt )
419{
420 addOption( opt , COMMAND_FLAG );
421 g_value_counter++;
422}
423
424void
425AnyOption::setCommandFlag( const char *opt , char optchar )
426{
427 addOption( opt , COMMAND_FLAG );
428 addOption( optchar , COMMAND_FLAG );
429 g_value_counter++;
430}
431
432void
433AnyOption::setFileOption( const char *opt )
434{
435 addOption( opt , FILE_OPT );
436 g_value_counter++;
437}
438
439void
440AnyOption::setFileOption( char opt )
441{
442 addOption( opt , FILE_OPT );
443 g_value_counter++;
444}
445
446void
447AnyOption::setFileOption( const char *opt , char optchar )
448{
449 addOption( opt , FILE_OPT );
450 addOption( optchar, FILE_OPT );
451 g_value_counter++;
452}
453
454void
455AnyOption::setFileFlag( const char *opt )
456{
457 addOption( opt , FILE_FLAG );
458 g_value_counter++;
459}
460
461void
462AnyOption::setFileFlag( char opt )
463{
464 addOption( opt , FILE_FLAG );
465 g_value_counter++;
466}
467
468void
469AnyOption::setFileFlag( const char *opt , char optchar )
470{
471 addOption( opt , FILE_FLAG );
472 addOption( optchar , FILE_FLAG );
473 g_value_counter++;
474}
475
476void
477AnyOption::setOption( const char *opt )
478{
479 addOption( opt , COMMON_OPT );
480 g_value_counter++;
481}
482
483void
484AnyOption::setOption( char opt )
485{
486 addOption( opt , COMMON_OPT );
487 g_value_counter++;
488}
489
490void
491AnyOption::setOption( const char *opt , char optchar )
492{
493 addOption( opt , COMMON_OPT );
494 addOption( optchar , COMMON_OPT );
495 g_value_counter++;
496}
497
498void
499AnyOption::setFlag( const char *opt )
500{
501 addOption( opt , COMMON_FLAG );
502 g_value_counter++;
503}
504
505void
506AnyOption::setFlag( const char opt )
507{
508 addOption( opt , COMMON_FLAG );
509 g_value_counter++;
510}
511
512void
513AnyOption::setFlag( const char *opt , char optchar )
514{
515 addOption( opt , COMMON_FLAG );
516 addOption( optchar , COMMON_FLAG );
517 g_value_counter++;
518}
519
520void
521AnyOption::addOption( const char *opt, int type )
522{
523 if( option_counter >= max_options ){
524 if( doubleOptStorage() == false ){
525 addOptionError( opt );
526 return;
527 }
528 }
529 options[ option_counter ] = opt ;
530 optiontype[ option_counter ] = type ;
531 optionindex[ option_counter ] = g_value_counter;
532 option_counter++;
533}
534
535void
536AnyOption::addOption( char opt, int type )
537{
538 if( !POSIX() ){
539 printVerbose("Ignoring the option character \"");
540 printVerbose( opt );
541 printVerbose( "\" ( POSIX options are turned off )" );
542 printVerbose();
543 return;
544 }
545
546
547 if( optchar_counter >= max_char_options ){
548 if( doubleCharStorage() == false ){
549 addOptionError( opt );
550 return;
551 }
552 }
553 optionchars[ optchar_counter ] = opt ;
554 optchartype[ optchar_counter ] = type ;
555 optcharindex[ optchar_counter ] = g_value_counter;
556 optchar_counter++;
557}
558
559void
560AnyOption::addOptionError( const char *opt )
561{
562 cout << endl ;
563 cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
564 cout << "While adding the option : \""<< opt << "\"" << endl;
565 cout << "Exiting." << endl ;
566 cout << endl ;
567 exit(0);
568}
569
570void
571AnyOption::addOptionError( char opt )
572{
573 cout << endl ;
574 cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
575 cout << "While adding the option: \""<< opt << "\"" << endl;
576 cout << "Exiting." << endl ;
577 cout << endl ;
578 exit(0);
579}
580
581void
582AnyOption::processOptions()
583{
584 if( ! valueStoreOK() )
585 return;
586}
587
588void
589AnyOption::processCommandArgs(int max_args)
590{
591 max_legal_args = max_args;
592 processCommandArgs();
593}
594
595void
596AnyOption::processCommandArgs( int _argc, char **_argv, int max_args )
597{
598 max_legal_args = max_args;
599 processCommandArgs( _argc, _argv );
600}
601
602void
603AnyOption::processCommandArgs( int _argc, char **_argv )
604{
605 useCommandArgs( _argc, _argv );
606 processCommandArgs();
607}
608
609void
610AnyOption::processCommandArgs()
611{
612 if( ! ( valueStoreOK() && CommandSet() ) )
613 return;
614
615 if( max_legal_args == 0 )
616 max_legal_args = argc;
617 new_argv = (int*) malloc( (max_legal_args+1) * sizeof(int) );
618 for( int i = 1 ; i < argc ; i++ ){/* ignore first argv */
619 if( argv[i][0] == long_opt_prefix[0] &&
620 argv[i][1] == long_opt_prefix[1] ) { /* long GNU option */
621 int match_at = parseGNU( argv[i]+2 ); /* skip -- */
622 if( match_at >= 0 && i < argc-1 ) /* found match */
623 setValue( options[match_at] , argv[++i] );
624 }else if( argv[i][0] == opt_prefix_char ) { /* POSIX char */
625 if( POSIX() ){
626 char ch = parsePOSIX( argv[i]+1 );/* skip - */
627 if( ch != '0' && i < argc-1 ) /* matching char */
628 setValue( ch , argv[++i] );
629 } else { /* treat it as GNU option with a - */
630 int match_at = parseGNU( argv[i]+1 ); /* skip - */
631 if( match_at >= 0 && i < argc-1 ) /* found match */
632 setValue( options[match_at] , argv[++i] );
633 }
634 }else { /* not option but an argument keep index */
635 if( new_argc < max_legal_args ){
636 new_argv[ new_argc ] = i ;
637 new_argc++;
638 }else{ /* ignore extra arguments */
639 printVerbose( "Ignoring extra argument: " );
640 printVerbose( argv[i] );
641 printVerbose( );
642 printAutoUsage();
643 }
644 printVerbose( "Unknown command argument option : " );
645 printVerbose( argv[i] );
646 printVerbose( );
647 printAutoUsage();
648 }
649 }
650}
651
652char
653AnyOption::parsePOSIX( char* arg )
654{
655
656 for( unsigned int i = 0 ; i < strlen(arg) ; i++ ){
657 char ch = arg[i] ;
658 if( matchChar(ch) ) { /* keep matching flags till an option */
659 /*if last char argv[++i] is the value */
660 if( i == strlen(arg)-1 ){
661 return ch;
662 }else{/* else the rest of arg is the value */
663 i++; /* skip any '=' and ' ' */
664 while( arg[i] == whitespace
665 || arg[i] == equalsign )
666 i++;
667 setValue( ch , arg+i );
668 return '0';
669 }
670 }
671 }
672 printVerbose( "Unknown command argument option : " );
673 printVerbose( arg );
674 printVerbose( );
675 printAutoUsage();
676 return '0';
677}
678
679int
680AnyOption::parseGNU( char *arg )
681{
682 int split_at = 0;
683 /* if has a '=' sign get value */
684 for( unsigned int i = 0 ; i < strlen(arg) ; i++ ){
685 if(arg[i] == equalsign ){
686 split_at = i ; /* store index */
687 i = strlen(arg); /* get out of loop */
688 }
689 }
690 if( split_at > 0 ){ /* it is an option value pair */
691 char* tmp = (char*) malloc( (split_at+1)*sizeof(char) );
692 for( int i = 0 ; i < split_at ; i++ )
693 tmp[i] = arg[i];
694 tmp[split_at] = '\0';
695
696 if ( matchOpt( tmp ) >= 0 ){
697 setValue( options[matchOpt(tmp)] , arg+split_at+1 );
698 free (tmp);
699 }else{
700 printVerbose( "Unknown command argument option : " );
701 printVerbose( arg );
702 printVerbose( );
703 printAutoUsage();
704 free (tmp);
705 return -1;
706 }
707 }else{ /* regular options with no '=' sign */
708 return matchOpt(arg);
709 }
710 return -1;
711}
712
713
714int
715AnyOption::matchOpt( char *opt )
716{
717 for( int i = 0 ; i < option_counter ; i++ ){
718 if( strcmp( options[i], opt ) == 0 ){
719 if( optiontype[i] == COMMON_OPT ||
720 optiontype[i] == COMMAND_OPT )
721 { /* found option return index */
722 return i;
723 }else if( optiontype[i] == COMMON_FLAG ||
724 optiontype[i] == COMMAND_FLAG )
725 { /* found flag, set it */
726 setFlagOn( opt );
727 return -1;
728 }
729 }
730 }
731 printVerbose( "Unknown command argument option : " );
732 printVerbose( opt ) ;
733 printVerbose( );
734 printAutoUsage();
735 return -1;
736}
737bool
738AnyOption::matchChar( char c )
739{
740 for( int i = 0 ; i < optchar_counter ; i++ ){
741 if( optionchars[i] == c ) { /* found match */
742 if(optchartype[i] == COMMON_OPT ||
743 optchartype[i] == COMMAND_OPT )
744 { /* an option store and stop scanning */
745 return true;
746 }else if( optchartype[i] == COMMON_FLAG ||
747 optchartype[i] == COMMAND_FLAG ) { /* a flag store and keep scanning */
748 setFlagOn( c );
749 return true;
750 }
751 }
752 }
753 //printVerbose( "Unknown command argument option : " );
754 //printVerbose( c ) ;
755 //printVerbose( );
756 printAutoUsage();
757 return false;
758}
759
760bool
761AnyOption::valueStoreOK( )
762{
763 int size= 0;
764 if( !set ){
765 if( g_value_counter > 0 ){
766 size = g_value_counter * sizeof(char*);
767 values = (char**)malloc( size );
768 for( int i = 0 ; i < g_value_counter ; i++)
769 values[i] = NULL;
770 set = true;
771 }
772 }
773 return set;
774}
775
776/*
777 * public get methods
778 */
779char*
780AnyOption::getValue( const char *option )
781{
782 if( !valueStoreOK() )
783 return NULL;
784
785 for( int i = 0 ; i < option_counter ; i++ ){
786 if( strcmp( options[i], option ) == 0 )
787 return values[ optionindex[i] ];
788 }
789 return NULL;
790}
791
792bool
793AnyOption::getFlag( const char *option )
794{
795 if( !valueStoreOK() )
796 return false;
797 for( int i = 0 ; i < option_counter ; i++ ){
798 if( strcmp( options[i], option ) == 0 )
799 return findFlag( values[ optionindex[i] ] );
800 }
801 return false;
802}
803
804char*
805AnyOption::getValue( char option )
806{
807 if( !valueStoreOK() )
808 return NULL;
809 for( int i = 0 ; i < optchar_counter ; i++ ){
810 if( optionchars[i] == option )
811 return values[ optcharindex[i] ];
812 }
813 return NULL;
814}
815
816bool
817AnyOption::getFlag( char option )
818{
819 if( !valueStoreOK() )
820 return false;
821 for( int i = 0 ; i < optchar_counter ; i++ ){
822 if( optionchars[i] == option )
823 return findFlag( values[ optcharindex[i] ] ) ;
824 }
825 return false;
826}
827
828bool
829AnyOption::findFlag( char* val )
830{
831 if( val == NULL )
832 return false;
833
834 if( strcmp( TRUE_FLAG , val ) == 0 )
835 return true;
836
837 return false;
838}
839
840/*
841 * private set methods
842 */
843bool
844AnyOption::setValue( const char *option , char *value )
845{
846 if( !valueStoreOK() )
847 return false;
848 for( int i = 0 ; i < option_counter ; i++ ){
849 if( strcmp( options[i], option ) == 0 ){
850 values[ optionindex[i] ] = (char*) malloc((strlen(value)+1)*sizeof(char));
851 strcpy( values[ optionindex[i] ], value );
852 return true;
853 }
854 }
855 return false;
856}
857
858bool
859AnyOption::setFlagOn( const char *option )
860{
861 if( !valueStoreOK() )
862 return false;
863 for( int i = 0 ; i < option_counter ; i++ ){
864 if( strcmp( options[i], option ) == 0 ){
865 values[ optionindex[i] ] = (char*) malloc((strlen(TRUE_FLAG)+1)*sizeof(char));
866 strcpy( values[ optionindex[i] ] , TRUE_FLAG );
867 return true;
868 }
869 }
870 return false;
871}
872
873bool
874AnyOption::setValue( char option , char *value )
875{
876 if( !valueStoreOK() )
877 return false;
878 for( int i = 0 ; i < optchar_counter ; i++ ){
879 if( optionchars[i] == option ){
880 values[ optcharindex[i] ] = (char*) malloc((strlen(value)+1)*sizeof(char));
881 strcpy( values[ optcharindex[i] ], value );
882 return true;
883 }
884 }
885 return false;
886}
887
888bool
889AnyOption::setFlagOn( char option )
890{
891 if( !valueStoreOK() )
892 return false;
893 for( int i = 0 ; i < optchar_counter ; i++ ){
894 if( optionchars[i] == option ){
895 values[ optcharindex[i] ] = (char*) malloc((strlen(TRUE_FLAG)+1)*sizeof(char));
896 strcpy( values[ optcharindex[i] ] , TRUE_FLAG );
897 return true;
898 }
899 }
900 return false;
901}
902
903
904int
905AnyOption::getArgc( )
906{
907 return new_argc;
908}
909
910char*
911AnyOption::getArgv( int index )
912{
913 if( index < new_argc ){
914 return ( argv[ new_argv[ index ] ] );
915 }
916 return NULL;
917}
918
919/* dotfile sub routines */
920
921bool
922AnyOption::processFile()
923{
924 if( ! (valueStoreOK() && FileSet()) )
925 return false;
926 return ( consumeFile(readFile()) );
927}
928
929bool
930AnyOption::processFile( const char *filename )
931{
932 useFiileName(filename );
933 return ( processFile() );
934}
935
936char*
937AnyOption::readFile()
938{
939 return ( readFile(filename) );
940}
941
942/*
943 * read the file contents to a character buffer
944 */
945
946char*
947AnyOption::readFile( const char* fname )
948{
949 int length;
950 char *buffer;
951 ifstream is;
952 is.open ( fname , ifstream::in );
953 if( ! is.good() ){
954 is.close();
955 return NULL;
956 }
957 is.seekg (0, ios::end);
958 length = is.tellg();
959 is.seekg (0, ios::beg);
960 buffer = (char*) malloc(length*sizeof(char));
961 is.read (buffer,length);
962 is.close();
963 return buffer;
964}
965
966/*
967 * scans a char* buffer for lines that does not
968 * start with the specified comment character.
969 */
970bool
971AnyOption::consumeFile( char *buffer )
972{
973
974 if( buffer == NULL )
975 return false;
976
977 char *cursor = buffer;/* preserve the ptr */
978 char *pline = NULL ;
979 int linelength = 0;
980 bool newline = true;
981 for( unsigned int i = 0 ; i < strlen( buffer ) ; i++ ){
982 if( *cursor == endofline ) { /* end of line */
983 if( pline != NULL ) /* valid line */
984 processLine( pline, linelength );
985 pline = NULL;
986 newline = true;
987 }else if( newline ){ /* start of line */
988 newline = false;
989 if( (*cursor != comment ) ){ /* not a comment */
990 pline = cursor ;
991 linelength = 0 ;
992 }
993 }
994 cursor++; /* keep moving */
995 linelength++;
996 }
997 free (buffer);
998 return true;
999}
1000
1001
1002/*
1003 * find a valid type value pair separated by a delimiter
1004 * character and pass it to valuePairs()
1005 * any line which is not valid will be considered a value
1006 * and will get passed on to justValue()
1007 *
1008 * assuming delimiter is ':' the behaviour will be,
1009 *
1010 * width:10 - valid pair valuePairs( width, 10 );
1011 * width : 10 - valid pair valuepairs( width, 10 );
1012 *
1013 * :::: - not valid
1014 * width - not valid
1015 * :10 - not valid
1016 * width: - not valid
1017 * :: - not valid
1018 * : - not valid
1019 *
1020 */
1021
1022void
1023AnyOption::processLine( char *theline, int length )
1024{
1025 bool found = false;
1026 char *pline = (char*) malloc( (length+1)*sizeof(char) );
1027 for( int i = 0 ; i < length ; i ++ )
1028 pline[i]= *(theline++);
1029 pline[length] = nullterminate;
1030 char *cursor = pline ; /* preserve the ptr */
1031 if( *cursor == delimiter || *(cursor+length-1) == delimiter ){
1032 justValue( pline );/* line with start/end delimiter */
1033 }else{
1034 for( int i = 1 ; i < length-1 && !found ; i++){/* delimiter */
1035 if( *cursor == delimiter ){
1036 *(cursor-1) = nullterminate; /* two strings */
1037 found = true;
1038 valuePairs( pline , cursor+1 );
1039 }
1040 cursor++;
1041 }
1042 cursor++;
1043 if( !found ) /* not a pair */
1044 justValue( pline );
1045 }
1046 free (pline);
1047}
1048
1049/*
1050 * removes trailing and preceeding whitespaces from a string
1051 */
1052char*
1053AnyOption::chomp( char *str )
1054{
1055 while( *str == whitespace )
1056 str++;
1057 char *end = str+strlen(str)-1;
1058 while( *end == whitespace )
1059 end--;
1060 *(end+1) = nullterminate;
1061 return str;
1062}
1063
1064void
1065AnyOption::valuePairs( char *type, char *value )
1066{
1067 if ( strlen(chomp(type)) == 1 ){ /* this is a char option */
1068 for( int i = 0 ; i < optchar_counter ; i++ ){
1069 if( optionchars[i] == type[0] ){ /* match */
1070 if( optchartype[i] == COMMON_OPT ||
1071 optchartype[i] == FILE_OPT )
1072 {
1073 setValue( type[0] , chomp(value) );
1074 return;
1075 }
1076 }
1077 }
1078 }
1079 /* if no char options matched */
1080 for( int i = 0 ; i < option_counter ; i++ ){
1081 if( strcmp( options[i], type ) == 0 ){ /* match */
1082 if( optiontype[i] == COMMON_OPT ||
1083 optiontype[i] == FILE_OPT )
1084 {
1085 setValue( type , chomp(value) );
1086 return;
1087 }
1088 }
1089 }
1090 printVerbose( "Unknown option in resourcefile : " );
1091 printVerbose( type );
1092 printVerbose( );
1093}
1094
1095void
1096AnyOption::justValue( char *type )
1097{
1098
1099 if ( strlen(chomp(type)) == 1 ){ /* this is a char option */
1100 for( int i = 0 ; i < optchar_counter ; i++ ){
1101 if( optionchars[i] == type[0] ){ /* match */
1102 if( optchartype[i] == COMMON_FLAG ||
1103 optchartype[i] == FILE_FLAG )
1104 {
1105 setFlagOn( type[0] );
1106 return;
1107 }
1108 }
1109 }
1110 }
1111 /* if no char options matched */
1112 for( int i = 0 ; i < option_counter ; i++ ){
1113 if( strcmp( options[i], type ) == 0 ){ /* match */
1114 if( optiontype[i] == COMMON_FLAG ||
1115 optiontype[i] == FILE_FLAG )
1116 {
1117 setFlagOn( type );
1118 return;
1119 }
1120 }
1121 }
1122 printVerbose( "Unknown option in resourcefile : " );
1123 printVerbose( type );
1124 printVerbose( );
1125}
1126
1127/*
1128 * usage and help
1129 */
1130
1131
1132void
1133AnyOption::printAutoUsage()
1134{
1135 if( autousage ) printUsage();
1136}
1137
1138void
1139AnyOption::printUsage()
1140{
1141
1142 if( once ) {
1143 once = false ;
1144 cout << endl ;
1145 for( int i = 0 ; i < usage_lines ; i++ )
1146 cout << usage[i] << endl ;
1147 cout << endl ;
1148 }
1149}
1150
1151
1152void
1153AnyOption::addUsage( const char *line )
1154{
1155 if( usage_lines >= max_usage_lines ){
1156 if( doubleUsageStorage() == false ){
1157 addUsageError( line );
1158 exit(1);
1159 }
1160 }
1161 usage[ usage_lines ] = line ;
1162 usage_lines++;
1163}
1164
1165void
1166AnyOption::addUsageError( const char *line )
1167{
1168 cout << endl ;
1169 cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
1170 cout << "While adding the usage/help : \""<< line << "\"" << endl;
1171 cout << "Exiting." << endl ;
1172 cout << endl ;
1173 exit(0);
1174
1175}
diff --git a/pacman-c++/server/anyoption.h b/pacman-c++/server/anyoption.h
new file mode 100644
index 0000000..3f7a5de
--- /dev/null
+++ b/pacman-c++/server/anyoption.h
@@ -0,0 +1,270 @@
1#ifndef _ANYOPTION_H
2#define _ANYOPTION_H
3
4#include <iostream>
5#include <fstream>
6#include <stdlib.h>
7#include <string>
8
9#define COMMON_OPT 1
10#define COMMAND_OPT 2
11#define FILE_OPT 3
12#define COMMON_FLAG 4
13#define COMMAND_FLAG 5
14#define FILE_FLAG 6
15
16#define COMMAND_OPTION_TYPE 1
17#define COMMAND_FLAG_TYPE 2
18#define FILE_OPTION_TYPE 3
19#define FILE_FLAG_TYPE 4
20#define UNKNOWN_TYPE 5
21
22#define DEFAULT_MAXOPTS 10
23#define MAX_LONG_PREFIX_LENGTH 2
24
25#define DEFAULT_MAXUSAGE 3
26#define DEFAULT_MAXHELP 10
27
28#define TRUE_FLAG "true"
29
30using namespace std;
31
32class AnyOption
33{
34
35public: /* the public interface */
36 AnyOption();
37 AnyOption(int maxoptions );
38 AnyOption(int maxoptions , int maxcharoptions);
39 ~AnyOption();
40
41 /*
42 * following set methods specifies the
43 * special characters and delimiters
44 * if not set traditional defaults will be used
45 */
46
47 void setCommandPrefixChar( char _prefix ); /* '-' in "-w" */
48 void setCommandLongPrefix( char *_prefix ); /* '--' in "--width" */
49 void setFileCommentChar( char _comment ); /* '#' in shellscripts */
50 void setFileDelimiterChar( char _delimiter );/* ':' in "width : 100" */
51
52 /*
53 * provide the input for the options
54 * like argv[] for commndline and the
55 * option file name to use;
56 */
57
58 void useCommandArgs( int _argc, char **_argv );
59 void useFiileName( const char *_filename );
60
61 /*
62 * turn off the POSIX style options
63 * this means anything starting with a '-' or "--"
64 * will be considered a valid option
65 * which alo means you cannot add a bunch of
66 * POIX options chars together like "-lr" for "-l -r"
67 *
68 */
69
70 void noPOSIX();
71
72 /*
73 * prints warning verbose if you set anything wrong
74 */
75 void setVerbose();
76
77
78 /*
79 * there are two types of options
80 *
81 * Option - has an associated value ( -w 100 )
82 * Flag - no value, just a boolean flag ( -nogui )
83 *
84 * the options can be either a string ( GNU style )
85 * or a character ( traditional POSIX style )
86 * or both ( --width, -w )
87 *
88 * the options can be common to the commandline and
89 * the optionfile, or can belong only to either of
90 * commandline and optionfile
91 *
92 * following set methods, handle all the aboove
93 * cases of options.
94 */
95
96 /* options comman to command line and option file */
97 void setOption( const char *opt_string );
98 void setOption( char opt_char );
99 void setOption( const char *opt_string , char opt_char );
100 void setFlag( const char *opt_string );
101 void setFlag( char opt_char );
102 void setFlag( const char *opt_string , char opt_char );
103
104 /* options read from commandline only */
105 void setCommandOption( const char *opt_string );
106 void setCommandOption( char opt_char );
107 void setCommandOption( const char *opt_string , char opt_char );
108 void setCommandFlag( const char *opt_string );
109 void setCommandFlag( char opt_char );
110 void setCommandFlag( const char *opt_string , char opt_char );
111
112 /* options read from an option file only */
113 void setFileOption( const char *opt_string );
114 void setFileOption( char opt_char );
115 void setFileOption( const char *opt_string , char opt_char );
116 void setFileFlag( const char *opt_string );
117 void setFileFlag( char opt_char );
118 void setFileFlag( const char *opt_string , char opt_char );
119
120 /*
121 * process the options, registerd using
122 * useCommandArgs() and useFileName();
123 */
124 void processOptions();
125 void processCommandArgs();
126 void processCommandArgs( int max_args );
127 bool processFile();
128
129 /*
130 * process the specified options
131 */
132 void processCommandArgs( int _argc, char **_argv );
133 void processCommandArgs( int _argc, char **_argv, int max_args );
134 bool processFile( const char *_filename );
135
136 /*
137 * get the value of the options
138 * will return NULL if no value is set
139 */
140 char *getValue( const char *_option );
141 bool getFlag( const char *_option );
142 char *getValue( char _optchar );
143 bool getFlag( char _optchar );
144
145 /*
146 * Print Usage
147 */
148 void printUsage();
149 void printAutoUsage();
150 void addUsage( const char *line );
151 void printHelp();
152 /* print auto usage printing for unknown options or flag */
153 void autoUsagePrint(bool flag);
154
155 /*
156 * get the argument count and arguments sans the options
157 */
158 int getArgc();
159 char* getArgv( int index );
160 bool hasOptions();
161
162private: /* the hidden data structure */
163 int argc; /* commandline arg count */
164 char **argv; /* commndline args */
165 const char* filename; /* the option file */
166 char* appname; /* the application name from argv[0] */
167
168 int *new_argv; /* arguments sans options (index to argv) */
169 int new_argc; /* argument count sans the options */
170 int max_legal_args; /* ignore extra arguments */
171
172
173 /* option strings storage + indexing */
174 int max_options; /* maximum number of options */
175 const char **options; /* storage */
176 int *optiontype; /* type - common, command, file */
177 int *optionindex; /* index into value storage */
178 int option_counter; /* counter for added options */
179
180 /* option chars storage + indexing */
181 int max_char_options; /* maximum number options */
182 char *optionchars; /* storage */
183 int *optchartype; /* type - common, command, file */
184 int *optcharindex; /* index into value storage */
185 int optchar_counter; /* counter for added options */
186
187 /* values */
188 char **values; /* common value storage */
189 int g_value_counter; /* globally updated value index LAME! */
190
191 /* help and usage */
192 const char **usage; /* usage */
193 int max_usage_lines; /* max usage lines reseverd */
194 int usage_lines; /* number of usage lines */
195
196 bool command_set; /* if argc/argv were provided */
197 bool file_set; /* if a filename was provided */
198 bool mem_allocated; /* if memory allocated in init() */
199 bool posix_style; /* enables to turn off POSIX style options */
200 bool verbose; /* silent|verbose */
201 bool print_usage; /* usage verbose */
202 bool print_help; /* help verbose */
203
204 char opt_prefix_char; /* '-' in "-w" */
205 char long_opt_prefix[MAX_LONG_PREFIX_LENGTH]; /* '--' in "--width" */
206 char file_delimiter_char; /* ':' in width : 100 */
207 char file_comment_char; /* '#' in "#this is a comment" */
208 char equalsign;
209 char comment;
210 char delimiter;
211 char endofline;
212 char whitespace;
213 char nullterminate;
214
215 bool set; //was static member
216 bool once; //was static member
217
218 bool hasoptions;
219 bool autousage;
220
221private: /* the hidden utils */
222 void init();
223 void init(int maxopt, int maxcharopt );
224 bool alloc();
225 void cleanup();
226 bool valueStoreOK();
227
228 /* grow storage arrays as required */
229 bool doubleOptStorage();
230 bool doubleCharStorage();
231 bool doubleUsageStorage();
232
233 bool setValue( const char *option , char *value );
234 bool setFlagOn( const char *option );
235 bool setValue( char optchar , char *value);
236 bool setFlagOn( char optchar );
237
238 void addOption( const char* option , int type );
239 void addOption( char optchar , int type );
240 void addOptionError( const char *opt);
241 void addOptionError( char opt);
242 bool findFlag( char* value );
243 void addUsageError( const char *line );
244 bool CommandSet();
245 bool FileSet();
246 bool POSIX();
247
248 char parsePOSIX( char* arg );
249 int parseGNU( char *arg );
250 bool matchChar( char c );
251 int matchOpt( char *opt );
252
253 /* dot file methods */
254 char *readFile();
255 char *readFile( const char* fname );
256 bool consumeFile( char *buffer );
257 void processLine( char *theline, int length );
258 char *chomp( char *str );
259 void valuePairs( char *type, char *value );
260 void justValue( char *value );
261
262 void printVerbose( const char *msg );
263 void printVerbose( char *msg );
264 void printVerbose( char ch );
265 void printVerbose( );
266
267
268};
269
270#endif /* ! _ANYOPTION_H */
diff --git a/pacman-c++/server/server.cpp b/pacman-c++/server/server.cpp
new file mode 100644
index 0000000..c9e4fff
--- /dev/null
+++ b/pacman-c++/server/server.cpp
@@ -0,0 +1,971 @@
1#include "server.h"
2#include "util.h"
3#include "pacman.pb.h"
4#include "block.h"
5#include "anyoption.h"
6#include "bonuspoint.h"
7#include "point.h"
8#include <QTextStream>
9#include <algorithm>
10
11Server::Server(QWidget *parent)
12 : SceneHolder(parent), m_host(NULL), m_bindaddress(QHostAddress::Any),
13 m_port(Constants::Networking::port), m_numbots(0),
14 m_rounds(3), m_curRound(0), m_running(false), m_finishRound(false)
15{
16 /* determine max players by using order array */
17 for(m_maxplayers = 0; Color::order[m_maxplayers] != Color::none; ++m_maxplayers);
18}
19
20Server::~Server()
21{
22 if (m_host != NULL)
23 {
24 foreach(ENetPeer *peer, m_clientConnections.keys())
25 enet_peer_disconnect(peer, 0);
26
27 /* allow up to 3 seconds for the disconnect to succeed
28 * and drop any packets received packets
29 */
30 ENetEvent event;
31 while (m_clientConnections.count() > 0
32 && enet_host_service(m_host, &event, 3000) > 0)
33 {
34 switch (event.type)
35 {
36 case ENET_EVENT_TYPE_RECEIVE:
37 enet_packet_destroy(event.packet);
38 break;
39 case ENET_EVENT_TYPE_DISCONNECT:
40 m_clientConnections.remove(event.peer);
41 return;
42 default:
43 break;
44 }
45 }
46
47 enet_host_destroy(m_host);
48 }
49}
50
51bool Server::run()
52{
53 /* create eating order list first */
54 for(unsigned int i = 0; i < m_maxplayers; ++i)
55 m_eatingorder.append(Color::order[i]);
56 m_eatingorder.append(m_eatingorder.at(0));
57
58 m_tickTimer = new QTimer(this);
59 m_tickTimer->setInterval(Constants::tick);
60 connect(m_tickTimer, SIGNAL(timeout()), this, SLOT(tick()));
61
62 std::cout << "[Server] Running server..." << std::endl
63 << "[Server] Max players: " << m_maxplayers << std::endl
64 << "[Server] Number of bots: " << m_numbots << std::endl
65 << "[Server] Number of rounds: " << m_rounds << std::endl;
66 if (!waitForClientConnections())
67 return false;
68
69 connect(this, SIGNAL(allPointsRemoved()), this, SLOT(setFinishRound()));
70 initRoundMap();
71 return true;
72}
73
74void Server::tick()
75{
76 //qDebug() << "[Tick] Doing server update";
77 if (m_finishRound)
78 stopGame(true);
79 if (!m_running)
80 {
81 Transmission::map_t map = Util::createEmptyMap();
82 sendUpdate(map);
83 Util::deleteMap(map);
84 return;
85 }
86
87 /* fetch key updates */
88 keyPressUpdate();
89
90 /* let the bots move */
91 foreach (Color::Color color, m_bots)
92 botCalculate(m_actors[color]);
93
94 /* move on the virtual map */
95 Transmission::map_t map = calculateUpdates();
96 updateMap(map);
97
98 /* add a random bonus point */
99 QPoint pos = addRandomPoint(map, Transmission::bonuspoint);
100 if (!pos.isNull())
101 updateMap(map, pos.x(), pos.y());
102
103 /* add/remove random colorized block */
104 if (this->property("coloredblocks").toBool())
105 colorizeBlocks(map);
106
107 sendUpdate(map);
108 Util::deleteMap(map);
109}
110
111Transmission::map_t Server::calculateUpdates()
112{
113 QMap<Color::Color, QPair<QPoint, QPoint> > movements;
114 Transmission::map_t map = Util::createEmptyMap();
115
116 QMutableMapIterator<Color::Color, Actor::Movement> i(m_actorMovements);
117 while (i.hasNext())
118 {
119 i.next();
120 Color::Color color = i.key();
121 Actor *actor = m_actors[color];
122 QPoint mapPosition = CoordToMapPosition(actor->pos().toPoint());
123 Actor::Movement direction = i.value();
124 int turn = 0;
125
126invalid_direction:
127 ++turn;
128 qDebug() << "[Calc] Actor wants to move: color=" << color
129 << "pos=" << mapPosition << "direction=" << direction;
130
131 QPoint newMapPosition = mapPosition + Actor::movementToPoint(direction);
132 if (newMapPosition.x() < 0)
133 newMapPosition.setX(0);
134 if (newMapPosition.x() >= visualMap.size())
135 newMapPosition.setX(visualMap.size() - 1);
136 if (newMapPosition.y() < 0)
137 newMapPosition.setY(0);
138 if (newMapPosition.y() >= visualMap[newMapPosition.x()].size())
139 newMapPosition.setY(visualMap[newMapPosition.x()].size() - 1);
140
141 /* check if there's an item at new location of actor */
142 GameEntity *item = visualMap[newMapPosition.x()][newMapPosition.y()];
143 GameEntity *oldItem = visualMap[mapPosition.x()][mapPosition.y()];
144 if (item != NULL && oldItem != item)
145 {
146 qDebug() << "[Calc] Found item at new actor location";
147 if (!item->checkEnter(actor))
148 {
149 /* movement invalid. e.g. move against wall */
150 newMapPosition = mapPosition;
151 qDebug() << "[Calc] Item blocks actor";
152 }
153 else
154 {
155 /* apply actions of entering this field */
156 GameEntity::EnteredState survive = item->enter(actor);
157 if (survive == GameEntity::DestroyedEntity)
158 map[newMapPosition.x()][newMapPosition.y()] = Transmission::empty | actor->color();
159 else if (survive == GameEntity::DestroyedActor)
160 {
161 map[newMapPosition.x()][newMapPosition.y()] = Transmission::death | actor->color();
162 m_actors[item->color()]->addRoundPoints(actor->getRoundPoints());
163 actor->finishRound(true);
164 setFinishRound();
165 }
166 }
167 }
168
169 /* movement didn't work - e.g. was blocked */
170 if (mapPosition == newMapPosition)
171 {
172 /* check turn */
173 if (turn == 1 && direction != actor->direction())
174 {
175 /* set direction back to last known direction and try again */
176 qDebug() << "[Calc] Movement was blocked. Trying last known actor direction";
177 direction = actor->direction();
178 goto invalid_direction;
179 }
180 else
181 {
182 /* second turn didn't work too -> stop movement */
183 direction = Actor::None;
184 qDebug() << "[Calc] No good direction known. Movement stopped";
185 }
186 }
187
188 /* store movement for collision */
189 movements.insert(color, QPair<QPoint, QPoint>(mapPosition, newMapPosition));
190
191 /* set direction (used for collision detection) */
192 actor->setDirection(direction);
193
194 /* DEBUG: uncomments to disable auto-movement */
195 //direction = Actor::None;
196
197 /* actor is not moving anymore: remove from list */
198 if (direction == Actor::None)
199 i.remove();
200 }
201
202 /* check for actor collision */
203 QList<Actor *> blocked;
204 foreach(Color::Color color, movements.keys())
205 {
206 Actor *actor = m_actors[color];
207 QPoint oldpos = movements[color].first;
208 QPoint newpos = movements[color].second;
209 QPoint scenepos = actor->pos().toPoint();
210
211 /* first move actor to new position */
212 actor->move(actor->direction());
213
214 /* next check for collisions */
215 Actor *orderer = NULL;
216 Actor *meal = NULL;
217 foreach(Actor *other, m_actors)
218 {
219 if (actor == other)
220 continue;
221 if (!actor->collidesWithItem(other))
222 continue;
223 /* both move in the same direction */
224 if (actor->direction() == other->direction())
225 continue;
226
227 if (other->canEat(actor, m_eatingorder))
228 {
229 qDebug() << "[Collision] Actor" << actor->color() << "got EATEN by" << other->color();
230 orderer = other;
231 meal = actor;
232 break;
233 }
234 else if (actor->canEat(other, m_eatingorder))
235 {
236 qDebug() << "[Collision] Actor" << actor->color() << "EATS" << other->color();
237 orderer = actor;
238 meal = other;
239 blocked.append(other);
240 break;
241 }
242 else
243 {
244 qDebug() << "[Collision] Actor" << actor->color() << "got BLOCKED by" << other->color();
245 blocked.append(actor);
246 /* no break here */
247 }
248 }
249
250 /* update map depending on collision */
251 if (orderer != NULL && meal != NULL)
252 {
253 map[newpos.x()][newpos.y()] |= Transmission::pacman | Transmission::death
254 | orderer->color() | meal->color();
255 orderer->addRoundPoints(meal->getRoundPoints());
256 meal->finishRound(true);
257 setFinishRound();
258 }
259 else if (blocked.contains(actor))
260 {
261 /* move actor back early cause he won't move */
262 actor->setPos(scenepos);
263 map[oldpos.x()][oldpos.y()] |= Transmission::pacman | color;
264 }
265 else
266 {
267 map[newpos.x()][newpos.y()] |= Transmission::pacman | color;
268 }
269 }
270
271 /* move all actors back to their origin position */
272 foreach(Color::Color color, movements.keys())
273 m_actors[color]->setPos(mapPositionToCoord(movements[color].first));
274
275#ifndef QT_NO_DEBUG
276 /* collision sanity check: colors must be unique */
277 foreach(Color::Color col, m_eatingorder.toSet())
278 {
279 QList<QPoint> found;
280 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
281 {
282 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
283 {
284 if ((map[x][y] & Transmission::color_mask) & col)
285 found.append(QPoint(x, y));
286 }
287 }
288 if (found.count() > 1)
289 qCritical() << "[Collision] found" << found.count() << "fields with color=" << col;
290 }
291#endif
292
293 return map;
294}
295
296QPoint Server::addRandomPoint(Transmission::map_t map, Transmission::field_t type)
297{
298 int chance = Constants::Game::bouns_point_chance
299 - Constants::Game::bouns_point_chance_playerfactor * (m_maxplayers - 1);
300 int rand = (int) (chance * (qrand() / (RAND_MAX + 1.0)));
301 if (rand != 0)
302 return QPoint();
303
304 /* get list of valid positions */
305 QList<QPoint> validpos;
306 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
307 {
308 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
309 {
310 if (visualMap[x][y] == NULL)
311 validpos.append(QPoint(x, y));
312 }
313 }
314
315 /* remove actors positions from list
316 * performance would be better if actors would be listed in visualMap too
317 * but this isn't possible that easily. see comment in updateMap(map)
318 */
319 foreach (Actor *actor, m_actors)
320 {
321 QPoint actorpos = CoordToMapPosition(actor->pos().toPoint());
322 validpos.removeAll(actorpos);
323 }
324
325 if (validpos.empty())
326 return QPoint();
327
328 rand = (int) (validpos.size() * (qrand() / (RAND_MAX + 1.0)));
329 QPoint pos = validpos.at(rand);
330 map[pos.x()][pos.y()] = type;
331 return pos;
332}
333
334void Server::colorizeBlocks(Transmission::map_t map)
335{
336 /* decrement tickcount of colored blocks */
337 if (!m_coloredBlocks.empty())
338 {
339 QMutableMapIterator<QPoint, unsigned int> i(m_coloredBlocks);
340 while(i.hasNext())
341 {
342 i.next();
343 unsigned val = i.value();
344 if (val > 0)
345 i.setValue(--val);
346 else
347 {
348 QPoint block = i.key();
349 /* check for actor collision */
350 bool skip = false;
351 foreach (Actor *actor, m_actors)
352 {
353 if (CoordToMapPosition(actor->pos().toPoint()) == block)
354 skip = true;
355 if (skip)
356 break;
357 }
358 if (skip)
359 continue;
360
361 map[block.x()][block.y()] |= Transmission::block | Color::none;
362 updateMap(map, block.x(), block.y());
363 m_blocks.append(block);
364 i.remove();
365 }
366 }
367 }
368
369 /* colorize a random block */
370 int rand = (int) (Constants::Game::colorize_block_chance * (qrand() / (RAND_MAX + 1.0)));
371 if (rand == 0)
372 {
373 rand = (int) (m_blocks.size() * (qrand() / (RAND_MAX + 1.0)));
374 QPoint block = m_blocks.at(rand);
375 m_blocks.removeAt(rand);
376
377 unsigned int min = Constants::Game::colorize_block_tickcount_min;
378 unsigned int max = Constants::Game::colorize_block_tickcount_max;
379 int tickcount = min + (int) ((max - min + 1) * (qrand() / (RAND_MAX + 1.0)));
380 m_coloredBlocks.insert(block, tickcount);
381
382 unsigned int color = (int) (m_maxplayers * (qrand() / (RAND_MAX + 1.0)));
383 map[block.x()][block.y()] |= Transmission::block | Color::order[color];
384 updateMap(map, block.x(), block.y());
385 }
386}
387
388bool Server::waitForClientConnections()
389{
390 // server must stay alive as long as sockets (qt parent mem mechanism)
391 ENetAddress address;
392 address.host = ENET_HOST_ANY;
393 if (m_bindaddress != QHostAddress::Any)
394 enet_address_set_host(&address, qPrintable(m_bindaddress.toString()));
395 address.port = m_port;
396
397 m_host = enet_host_create(&address, m_maxplayers - m_numbots, 1, 0, 0);
398 if (m_host == NULL)
399 {
400 qCritical() << "An error occurred while trying to create an ENet server host";
401 return false;
402 }
403
404 char buf[1024];
405 enet_address_get_host_ip(&m_host->address, buf, 1024);
406 std::cout << "[Server] Listening on: "
407 << qPrintable(QString("%1:%2").arg(buf).arg(m_host->address.port)) << std::endl;
408
409 /* add bots first */
410 for (unsigned int i = (m_maxplayers - m_numbots); i < m_maxplayers; ++i)
411 {
412 m_bots.append(Color::order[i]);
413 m_actorMovements[Color::order[i]] = Actor::None;
414 }
415
416 std::cout << "[Server] Waiting for clients" << std::endl;
417 ProtoBuf::Init packet;
418 packet.set_maxplayers(m_maxplayers);
419 unsigned int i = 0;
420 while(m_clientConnections.count() < int(m_maxplayers - m_numbots))
421 {
422 ENetEvent event;
423 if (enet_host_service(m_host, &event, 3000) > 0)
424 {
425 switch (event.type)
426 {
427 case ENET_EVENT_TYPE_CONNECT:
428 {
429 /* assign color and notify client */
430 Color::Color color = Color::order[i++];
431 m_clientConnections[event.peer] = color;
432 packet.set_color(color);
433 Util::sendPacket(packet, event.peer, m_host);
434 std::cout << "[Connect] New Player: color=" << qPrintable(Util::colorToString(color)) << std::endl;
435 }
436 break;
437 case ENET_EVENT_TYPE_RECEIVE:
438 keyPressUpdate(&event);
439 break;
440 case ENET_EVENT_TYPE_DISCONNECT:
441 keyPressUpdate(&event);
442 break;
443 default:
444 break;
445 }
446 }
447 }
448
449 qDebug() << "[Server] All Clients connected";
450 return true;
451}
452
453void Server::sendUpdate(Transmission::map_t map, bool firstPacket)
454{
455 m_updatepacket.Clear();
456
457 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
458 {
459 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
460 m_updatepacket.add_field(map[x][y]);
461 }
462
463 for(unsigned int i = 0; i < m_maxplayers; ++i)
464 {
465 m_updatepacket.add_round_points(m_actors.value(Color::order[i])->getRoundPoints());
466 m_updatepacket.add_game_points(m_actors.value(Color::order[i])->getGamePoints());
467 }
468
469 /* we send the eating_order inside the first packet */
470 if (firstPacket)
471 {
472 foreach(Color::Color color, m_eatingorder)
473 m_updatepacket.add_eating_order(color);
474 }
475
476 QSharedPointer<QByteArray> data = Util::createPacket(m_updatepacket);
477 QMutableMapIterator<ENetPeer *, Color::Color> i(m_clientConnections);
478 while(i.hasNext())
479 {
480 i.next();
481 ENetPeer *peer = i.key();
482
483 if (!Util::sendPacket(data.data(), peer, m_host))
484 {
485 qWarning() << "[Connect] Error while sending data to client" << i.value() << "-> Disconnecting...";
486 std::cout << "[Connect] Actor color=" << qPrintable(Util::colorToString(i.value()))
487 << " is now a bot" << std::endl;
488 m_bots.append(i.value());
489 ++m_numbots;
490 i.remove();
491 }
492 }
493
494 if (m_maxplayers == m_numbots)
495 {
496 std::cout << "[Connect] No more real players left. Exiting..." << std::endl;
497 qApp->quit();
498 }
499}
500
501void Server::botCalculate(Actor *actor)
502{
503 QPoint actorpos = CoordToMapPosition(actor->pos().toPoint());
504
505 /* first make list of possible directions based on current actor position */
506 QHash<Actor::Movement, unsigned int> directions;
507 if (actorpos.x() > 0)
508 directions.insert(Actor::Left, 0);
509 if (actorpos.x() < visualMap.size() - 1)
510 directions.insert(Actor::Right, 0);
511 if (actorpos.y() > 0)
512 directions.insert(Actor::Up, 0);
513 if (actorpos.y() < visualMap[actorpos.x()].size() - 1)
514 directions.insert(Actor::Down, 0);
515
516 /* check neighbours for blocks first */
517 QMutableHashIterator<Actor::Movement, unsigned int> i(directions);
518 while(i.hasNext())
519 {
520 i.next();
521 QPoint newpos = actorpos + Actor::movementToPoint(i.key());
522 if (newpos.x() < 0 || newpos.x() >= visualMap.size())
523 continue;
524 if (newpos.y() < 0 || newpos.y() >= visualMap[newpos.x()].size())
525 continue;
526 GameEntity *item = visualMap[newpos.x()][newpos.y()];
527
528 /* check if neighbour is a block */
529 Block *block = qgraphicsitem_cast<Block *>(item);
530 if (block != NULL && block->color() != actor->color())
531 i.remove();
532 }
533
534 /* we're enclosed by blocks */
535 if (directions.empty())
536 return;
537
538 /* determine if other actors are in range to be afraid/to hunt */
539 int mindistance = Constants::AI::player_minimum_distance;
540 QList<QPoint> pos_afraid;
541 QList<QPoint> pos_hunt;
542 foreach (Actor *other, m_actors)
543 {
544 if (actor == other)
545 continue;
546
547 QList<QPoint> *ptr = NULL;
548 if (other->canEat(actor, m_eatingorder))
549 ptr = &pos_afraid;
550 else if (actor->canEat(other, m_eatingorder))
551 ptr = &pos_hunt;
552 if (ptr == NULL)
553 continue;
554
555 QPoint otherpos = CoordToMapPosition(other->pos().toPoint());
556 QPoint distance = actorpos - otherpos;
557 if (distance.manhattanLength() < mindistance)
558 ptr->append(otherpos);
559 }
560
561 /* check new directions and change direction-weight */
562 i = directions;
563 while(i.hasNext())
564 {
565 i.next();
566 QPoint newpos = actorpos + Actor::movementToPoint(i.key());
567
568 /* check for new positions in afraid list */
569 foreach(QPoint otherpos, pos_afraid)
570 {
571 int olddistance = (actorpos - otherpos).manhattanLength();
572 int newdistance = (newpos - otherpos).manhattanLength();
573 if (newdistance >= olddistance)
574 i.setValue(i.value() + Constants::AI::weight_afraid);
575
576 /* check for blocks of own color: other pacman can't follow their */
577 GameEntity *item = visualMap[newpos.x()][newpos.y()];
578 Block *block = qgraphicsitem_cast<Block *>(item);
579 if (block != NULL && block->color() == actor->color())
580 i.setValue(i.value() + Constants::AI::weight_colorblock);
581 }
582
583 /* check for new positions in hunt list */
584 foreach(QPoint otherpos, pos_hunt)
585 {
586 int olddistance = (actorpos - otherpos).manhattanLength();
587 int newdistance = (newpos - otherpos).manhattanLength();
588 if (newdistance <= olddistance)
589 i.setValue(i.value() + Constants::AI::weight_hunt);
590 }
591
592 /* check for bonuspoint */
593 GameEntity *item = visualMap[newpos.x()][newpos.y()];
594 BonusPoint *bpoint = qgraphicsitem_cast<BonusPoint *>(item);
595 if (bpoint != NULL)
596 i.setValue(i.value() + Constants::AI::weight_bonus_point);
597
598 /* check for normal point */
599 Point *point = qgraphicsitem_cast<Point *>(item);
600 if (point != NULL)
601 i.setValue(i.value() + Constants::AI::weight_point);
602 }
603
604 /* sort directions */
605 QList<unsigned int> weightlist = directions.values();
606 qSort(weightlist.begin(), weightlist.end(), qGreater<unsigned int>());
607
608 /* remove directions with lesser weight */
609 unsigned int max = weightlist.at(0);
610 i = directions;
611 while(i.hasNext())
612 {
613 i.next();
614 if (i.value() < max)
615 i.remove();
616 }
617
618 QList<Actor::Movement> list = directions.keys();
619
620 /* default is no direction change */
621 if (list.contains(actor->direction()))
622 return;
623
624 /* random direction */
625 int rand = (int) (list.size() * (qrand() / (RAND_MAX + 1.0)));
626 m_actorMovements[actor->color()] = list.at(rand);
627}
628
629void Server::keyPressUpdate()
630{
631 ProtoBuf::KeyPressUpdate packet;
632 ENetEvent event;
633 while (enet_host_service(m_host, &event, 1) > 0)
634 keyPressUpdate(&event);
635}
636
637void Server::keyPressUpdate(ENetEvent *event)
638{
639 ProtoBuf::KeyPressUpdate packet;
640 switch(event->type)
641 {
642 case ENET_EVENT_TYPE_RECEIVE:
643 {
644 QSharedPointer<QByteArray> data = Util::receivePacket(event->packet);
645 enet_packet_destroy(event->packet);
646 bool worked = packet.ParseFromArray(data->data(), data->size());
647 Q_ASSERT(worked);
648 Q_UNUSED(worked);
649 Transmission::field_t direction = packet.newkey();
650 Color::Color color = m_clientConnections[event->peer];
651 qDebug() << "[KeyPress] actor=" << color << "direction=" << direction;
652 m_actorMovements[color] = Util::transmissionMovementToActor(direction);
653 }
654 break;
655 case ENET_EVENT_TYPE_DISCONNECT:
656 {
657 Color::Color color = m_clientConnections[event->peer];
658 std::cout << "[Connect] Actor color=" << qPrintable(Util::colorToString(color))
659 << " is now a bot" << std::endl;
660 m_bots.append(color);
661 ++m_numbots;
662 m_clientConnections.remove(event->peer);
663 }
664 break;
665 default:
666 break;
667 }
668}
669
670void Server::initRoundMap()
671{
672 std::cout << "[Game] New round starts..." << std::endl;
673 m_tickTimer->stop();
674
675 /* reset scene and clean up items */
676 reset();
677
678 /* randomize color eating order */
679 m_eatingorder.removeLast();
680 random_shuffle(m_eatingorder.begin(), m_eatingorder.end());
681 m_eatingorder.append(m_eatingorder.at(0));
682
683 /* create new map */
684 Transmission::map_t map = Util::createDemoMap();
685 Util::placeActors(map, m_maxplayers, Color::order);
686 Util::fillPoints(map);
687
688#if 0 // actor eating actor tests - TODO: remove
689 m_actorMovements.clear();
690#if 0
691 //works
692 map[0][0] = Color::order[0] | Transmission::pacman;
693 map[0][1] = Color::order[1] | Transmission::pacman;
694 m_actorMovements.insert(Color::order[0], Actor::Down);
695#elif 0
696 //works
697 map[0][0] = Color::order[0] | Transmission::pacman;
698 map[0][3] = Color::order[1] | Transmission::pacman;
699 m_actorMovements.insert(Color::order[0], Actor::Down);
700#elif 0
701 //works
702 map[0][0] = Color::order[0] | Transmission::pacman;
703 map[0][4] = Color::order[1] | Transmission::pacman;
704 m_actorMovements.insert(Color::order[0], Actor::Down);
705#elif 0
706 //works
707 map[0][0] = Color::order[0] | Transmission::pacman;
708 map[0][5] = Color::order[1] | Transmission::pacman;
709 m_actorMovements.insert(Color::order[0], Actor::Down);
710#elif 0
711 //works
712 map[0][0] = Color::order[1] | Transmission::pacman;
713 map[0][5] = Color::order[0] | Transmission::pacman;
714 m_actorMovements.insert(Color::order[1], Actor::Down);
715#elif 0
716 //works
717 map[0][0] = Color::order[0] | Transmission::pacman;
718 map[0][5] = Color::order[1] | Transmission::pacman;
719 m_actorMovements.insert(Color::order[0], Actor::Down);
720 m_actorMovements.insert(Color::order[1], Actor::Up);
721#elif 0
722 //works
723 map[0][0] = Color::order[0] | Transmission::pacman;
724 map[0][6] = Color::order[1] | Transmission::pacman;
725 m_actorMovements.insert(Color::order[0], Actor::Down);
726 m_actorMovements.insert(Color::order[1], Actor::Up);
727#elif 0
728 //works
729 map[0][0] = Color::order[0] | Transmission::pacman;
730 map[0][7] = Color::order[1] | Transmission::pacman;
731 m_actorMovements.insert(Color::order[0], Actor::Down);
732 m_actorMovements.insert(Color::order[1], Actor::Up);
733#elif 1
734 //works
735 map[0][0] = Color::order[0] | Transmission::pacman;
736 map[0][1] = Color::order[1] | Transmission::pacman;
737 m_actorMovements.insert(Color::order[0], Actor::Down);
738 m_actorMovements.insert(Color::order[1], Actor::Down);
739#endif
740#endif
741
742 /* save positions of blocks for later usage */
743 m_blocks.clear();
744 for (unsigned int x = 0; x < Constants::map_size.width; ++x)
745 {
746 for (unsigned int y = 0; y < Constants::map_size.height; ++y)
747 {
748 Transmission::field_t &cur = map[x][y];
749 if (cur & Transmission::block)
750 m_blocks.append(QPoint(x, y));
751 }
752 }
753
754 updateMap(map);
755 sendUpdate(map, true);
756 Util::deleteMap(map);
757 map = NULL;
758
759 m_actorMovements.clear();
760
761 disconnect(AudioManager::self()->audioPlayer(), NULL, this, NULL);
762 connect(AudioManager::self()->audioPlayer(), SIGNAL(finished()), this, SLOT(startGame()));
763 AudioManager::self()->play(Sound::Intro, true);
764 m_tickTimer->start();
765}
766
767void Server::startGame()
768{
769 m_running = true;
770}
771
772void Server::stopGame(bool delay)
773{
774 /* first finish previous round */
775 foreach(Actor *actor, m_actors)
776 actor->finishRound();
777 m_finishRound = false;
778 m_running = false;
779
780 /* add delay if requested */
781 if (delay)
782 {
783 disconnect(AudioManager::self()->audioPlayer(), NULL, this, NULL);
784 connect(AudioManager::self()->audioPlayer(), SIGNAL(finished()), this, SLOT(stopGame()));
785 AudioManager::self()->play(Sound::Die, true);
786 return;
787 }
788
789 std::cout << "[Game] Round finished..." << std::endl;
790
791 /* do next-round work */
792 ++m_curRound;
793 if(m_rounds == 0 || m_curRound < m_rounds)
794 initRoundMap();
795 else
796 {
797 /* end of game */
798 std::cout << "[Game] All round finished. Exiting..." << std::endl;
799 qApp->quit();
800 }
801}
802
803void Server::setFinishRound()
804{
805 m_finishRound = true;
806}
807
808bool Server::parseCommandline()
809{
810 AnyOption opt;
811 opt.setVerbose();
812
813 /* usage strings must remain valid until parsing is done */
814 QString exec = QFileInfo(qApp->applicationFilePath()).fileName();
815 QByteArray usage;
816 QTextStream out(&usage, QIODevice::ReadWrite | QIODevice::Text);
817 out << "Usage: " << exec << " [OPTION]" << endl
818 << "Usage: " << exec << " -h" << endl
819 << endl;
820 out << " -b, --bind <bind_address>" << endl
821 << " Specifies the ip address on which the server listens for connections" << endl
822 << " Default: " << m_bindaddress.toString() << endl
823 << endl;
824 opt.setOption("bind", 'b');
825 out << " -p, --port <port>" << endl
826 << " Specifies the port on which the server listens for connections" << endl
827 << " Default: " << m_port << endl
828 << endl;
829 opt.setOption("port", 'p');
830 out << " -m, --maxplayers [1.." << m_maxplayers << "]" << endl
831 << " Specifies the maximum number of players/pacmans" << endl
832 << " Default: " << m_maxplayers << endl
833 << endl;
834 opt.setOption("maxplayers", 'm');
835 out << " --bots [0..maxplayers-1]" << endl
836 << " Specifies the number of AI pacmans/bots" << endl
837 << " Default: " << m_numbots << endl
838 << endl;
839 opt.setOption("bots");
840 out << " --nocolorblocks" << endl
841 << " Disable random colorized blocks" << endl
842 << endl;
843 opt.setOption("rounds", 'r');
844 out << " -r, --rounds [0 | 1..n]" << endl
845 << " Number of rounds to play" << endl
846 << " Default: " << m_rounds << endl
847 << endl;
848 opt.setFlag("nocolorblocks");
849 out << " -h, --help" << endl
850 << " Prints this help message" << endl;
851 opt.setFlag("help", 'h');
852 out.flush();
853 opt.addUsage(usage.constData());
854 opt.processCommandArgs(qApp->argc(), qApp->argv());
855
856 if (opt.getFlag("help") || opt.getFlag('h'))
857 {
858 opt.printUsage();
859 return false;
860 }
861
862 if (opt.getValue("port") != NULL)
863 {
864 bool ok;
865 m_port = QString(opt.getValue("port")).toUInt(&ok);
866 if (!ok || m_port < 1 || m_port > 65535)
867 {
868 qCritical() << "Invalid port-option:" << opt.getValue("port") << endl
869 << "Port must be between 1 and 65535";
870 return false;
871 }
872 }
873
874 if (opt.getValue("bind") != NULL)
875 {
876 m_bindaddress = opt.getValue("bind");
877 if (m_bindaddress.isNull())
878 {
879 qCritical() << "Invalid bind-option:" << opt.getValue("bind") << endl
880 << "Bind address must be an ip address";
881 return false;
882 }
883 }
884
885 if (opt.getValue("maxplayers") != NULL)
886 {
887 bool ok;
888 unsigned int maxplayers = QString(opt.getValue("maxplayers")).toUInt(&ok);
889 if (!ok || maxplayers < 1 || maxplayers > m_maxplayers)
890 {
891 qCritical() << "Invalid maxplayers-option:" << opt.getValue("maxplayers") << endl
892 << "Maxplayers must be between 1 and" << m_maxplayers;
893 return false;
894 }
895 m_maxplayers = maxplayers;
896 if (m_maxplayers == 2)
897 {
898 qCritical() << "2 player game is not supported (who wins if a player gets eaten?)";
899 return false;
900 }
901 }
902
903 if (opt.getValue("bots") != NULL)
904 {
905 bool ok;
906 unsigned int numbots = QString(opt.getValue("bots")).toUInt(&ok);
907 if (!ok || numbots >= m_maxplayers)
908 {
909 qCritical() << "Invalid numbots-options:" << opt.getValue("bots") << endl
910 << "AI pacmans/bots must be between 0 and" << m_maxplayers - 1;
911 return false;
912 }
913 m_numbots = numbots;
914 }
915
916 if (opt.getValue("rounds") != NULL)
917 {
918 bool ok;
919 unsigned int rounds = QString(opt.getValue("rounds")).toUInt(&ok);
920 if (!ok)
921 {
922 qCritical() << "Invalid number of rounds: " << opt.getValue("rounds") << endl;
923 return false;
924 }
925 m_rounds = rounds;
926 }
927
928 this->setProperty("coloredblocks", !opt.getFlag("nocolorblocks"));
929
930 return true;
931}
932
933bool operator<(const QPoint& lhs, const QPoint& rhs)
934{
935 if (lhs.x() < rhs.x())
936 return true;
937 else if (lhs.x() == rhs.x())
938 return lhs.y() < rhs.y();
939 else
940 return false;
941}
942
943bool Constants::server = true;
944
945int main(int argc, char **argv)
946{
947 /* Verify that the version of the library that we linked against is
948 * compatible with the version of the headers we compiled against.
949 */
950 GOOGLE_PROTOBUF_VERIFY_VERSION;
951
952 QApplication app(argc, argv, false);
953 app.setApplicationName("Pacman Server");
954 app.setWindowIcon(QIcon(":/appicon"));
955
956 qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
957
958 int ret = 0;
959 Server server;
960 if (!ret && !server.parseCommandline())
961 ret = 1;
962 if (!ret && !server.run())
963 ret = 1;
964 if (!ret)
965 ret = app.exec();
966
967 /* Delete all global objects allocated by libprotobuf */
968 google::protobuf::ShutdownProtobufLibrary();
969
970 return ret;
971}
diff --git a/pacman-c++/server/server.h b/pacman-c++/server/server.h
new file mode 100644
index 0000000..857f23d
--- /dev/null
+++ b/pacman-c++/server/server.h
@@ -0,0 +1,85 @@
1#ifndef SERVER_H
2#define SERVER_H
3
4#include "sceneholder.h"
5#include "actor.h"
6#include "pacman.pb.h"
7#include <QtGui>
8#include <QtNetwork/QHostAddress>
9
10extern "C" {
11#include "enet/enet.h"
12}
13
14class QTcpSocket;
15
16class Server
17 : public SceneHolder
18{
19 Q_OBJECT
20public:
21 Server(QWidget *parent = 0);
22 ~Server();
23 bool parseCommandline();
24 bool run();
25
26protected slots:
27 void tick();
28
29 /* receive updates of client */
30 void keyPressUpdate();
31 void keyPressUpdate(ENetEvent *event);
32
33protected:
34 /* block until we have connections from all clients */
35 bool waitForClientConnections();
36
37 /* calculate updates of current tick for sending to client */
38 Transmission::map_t calculateUpdates();
39
40 /* update client maps */
41 void sendUpdate(Transmission::map_t map, bool firstPacket = false);
42
43 QPoint addRandomPoint(Transmission::map_t map, Transmission::field_t type = Transmission::bonuspoint);
44 void colorizeBlocks(Transmission::map_t map);
45 void botCalculate(Actor *actor);
46 void initRoundMap();
47
48protected slots:
49 /* called when a round is started/finished */
50 void startGame();
51 void stopGame(bool delay = false);
52 void setFinishRound();
53
54protected:
55 ENetHost *m_host;
56 QMap<ENetPeer *, Color::Color> m_clientConnections;
57 QList<Color::Color> m_bots;
58
59 /* current movements. required to make pacmans continue their movement */
60 QMap<Color::Color, Actor::Movement> m_actorMovements;
61
62 /* allocate as member variable as this packet is large and used often */
63 ProtoBuf::MapUpdate m_updatepacket;
64
65 /* list of blocks */
66 QList<QPoint> m_blocks;
67 /* currently colored blocks + tickcount before they will turn to non-colored back */
68 QMap<QPoint, unsigned int> m_coloredBlocks;
69
70 QHostAddress m_bindaddress;
71 unsigned int m_port;
72 unsigned int m_maxplayers;
73 unsigned int m_numbots;
74 /* number of rounds (>= 1) */
75 unsigned int m_rounds;
76 /* current round, starting at 0 */
77 unsigned int m_curRound;
78 bool m_running;
79 bool m_finishRound;
80
81 QTimer *m_tickTimer;
82
83};
84
85#endif // SERVER_H
diff --git a/pacman-c++/server/server.pro b/pacman-c++/server/server.pro
new file mode 100644
index 0000000..05d5c9d
--- /dev/null
+++ b/pacman-c++/server/server.pro
@@ -0,0 +1,10 @@
1TEMPLATE = app
2TARGET = pacman-server
3
4SOURCES += anyoption.cpp \
5 server.cpp
6HEADERS += anyoption.h \
7 server.h
8
9include(../common.pri)
10PRE_TARGETDEPS += ../common/libcommon.a