1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // common.c -- misc functions used in client and server
21 #include "qcommon.h"
22 #include "version.h"
23 #include <setjmp.h>
24 #include <zlib.h>
25
26 #define COM_LOGFILE_NAME "qconsole.log"
27 #define COM_CONFIG_NAME "q2config.cfg"
28 #define COM_DEFAULTCFG_NAME "default.cfg"
29 #define COM_AUTOEXECCFG_NAME "autoexec.cfg"
30
31 commonAPI_t com;
32
33 static jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame
34
35 static char com_errorMsg[MAXPRINTMSG];
36
37 cvar_t *host_speeds;
38 cvar_t *developer;
39 cvar_t *timescale;
40 cvar_t *fixedtime;
41 cvar_t *dedicated;
42
43 cvar_t *logfile_active; // 1 = create new, 2 = append to existing
44 cvar_t *logfile_flush; // 1 = flush after each print
45 cvar_t *logfile_name;
46
47 cvar_t *sv_running;
48 cvar_t *sv_paused;
49 cvar_t *cl_running;
50 cvar_t *cl_paused;
51 cvar_t *com_timedemo;
52 cvar_t *com_sleep;
53 cvar_t *com_date_format;
54 cvar_t *com_time_format;
55 cvar_t *com_debug_break;
56
57 //
58 // userinfo
59 //
60 cvar_t *info_password;
61 cvar_t *info_spectator;
62 cvar_t *info_name;
63 cvar_t *info_skin;
64 cvar_t *info_rate;
65 cvar_t *info_fov;
66 cvar_t *info_msg;
67 cvar_t *info_hand;
68 cvar_t *info_gender;
69
70 fileHandle_t com_logFile;
71 uint32 com_framenum;
72 uint32 com_eventTime;
73
74 // host_speeds times
75 int time_before_game;
76 int time_after_game;
77 int time_before_ref;
78 int time_after_ref;
79
80 void Con_Init( void );
81 void Prompt_Init( void );
82 void SCR_EndLoadingPlaque( void );
83
84 /*
85 ============================================================================
86
87 CLIENT / SERVER interactions
88
89 ============================================================================
90 */
91
92 static int rd_target;
93 static char *rd_buffer;
94 static int rd_buffersize;
95 static void (*rd_flush)(int target, char *buffer);
96
Com_BeginRedirect(int target,char * buffer,int buffersize,void (* flush))97 void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush))
98 {
99 if (!target || !buffer || !buffersize || !flush)
100 return;
101 rd_target = target;
102 rd_buffer = buffer;
103 rd_buffersize = buffersize;
104 rd_flush = flush;
105
106 *rd_buffer = 0;
107 }
108
Com_EndRedirect(void)109 void Com_EndRedirect (void)
110 {
111 rd_flush(rd_target, rd_buffer);
112
113 rd_target = 0;
114 rd_buffer = NULL;
115 rd_buffersize = 0;
116 rd_flush = NULL;
117 }
118
LogFile_Close(void)119 static void LogFile_Close( void ) {
120 if( !com_logFile ) {
121 return;
122 }
123
124 Com_Printf( "Closing %s\n", FS_GetFileName( com_logFile ) );
125
126 FS_FCloseFile( com_logFile );
127 com_logFile = 0;
128 }
129
LogFile_Open(void)130 static void LogFile_Open( void ) {
131 uint32 mode;
132
133 mode = logfile_active->integer > 1 ? FS_MODE_APPEND : FS_MODE_WRITE;
134
135 if( logfile_flush->integer ) {
136 mode |= FS_FLUSH_SYNC;
137 }
138
139 FS_FOpenFile( logfile_name->string, &com_logFile, mode );
140
141 if( !com_logFile ) {
142 Com_WPrintf( "Couldn't open %s\n", logfile_name->string );
143 Cvar_SetInteger( "logfile", 0 );
144 return;
145 }
146
147 Com_Printf( "Logging console to %s\n", logfile_name->string );
148 }
149
LogFileActive_OnChange(cvar_t * self,void * arg)150 static void LogFileActive_OnChange( cvar_t *self, void *arg ) {
151 if( !self->integer ) {
152 LogFile_Close();
153 } else {
154 LogFile_Open();
155 }
156 }
157
LogFileParam_OnChange(cvar_t * self,void * arg)158 static void LogFileParam_OnChange( cvar_t *self, void *arg ) {
159 if( logfile_active->integer ) {
160 LogFile_Close();
161 LogFile_Open();
162 }
163 }
164
LogFile_Output(const char * string)165 static void LogFile_Output( const char *string ) {
166 char text[MAXPRINTMSG];
167 char *p;
168 int length;
169
170 /* not checking for overflow - buffer size is
171 * large enough, and length may only decrease.
172 */
173 p = text;
174 while( *string ) {
175 if( Q_IsColorString( string ) ) {
176 string += 2;
177 continue;
178 }
179
180 *p++ = *string++;
181 }
182 *p = 0;
183
184 length = p - text;
185 FS_Write( text, length, com_logFile );
186 }
187
188 /*
189 =============
190 Com_Printf
191
192 Both client and server can use this, and it will output
193 to the apropriate place.
194 =============
195 */
Com_Printf(const char * fmt,...)196 void Com_Printf( const char *fmt, ... ) {
197 va_list argptr;
198 char msg[MAXPRINTMSG];
199 static int recursive;
200 int length;
201
202 if( recursive == 2 ) {
203 return;
204 }
205
206 recursive++;
207
208 va_start( argptr, fmt );
209 length = Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
210 va_end( argptr );
211
212 if( rd_target ) {
213 if( length + strlen( rd_buffer ) > rd_buffersize - 1 ) {
214 rd_flush( rd_target, rd_buffer );
215 *rd_buffer = 0;
216 }
217 Q_strcat( rd_buffer, rd_buffersize, msg );
218 } else {
219 Con_Print( msg );
220
221 // also echo to debugging console
222 Sys_ConsoleOutput( msg );
223
224 // logfile
225 if( com_logFile ) {
226 LogFile_Output( msg );
227 }
228 }
229
230 recursive--;
231
232 }
233
234
235 /*
236 ================
237 Com_DPrintf
238
239 A Com_Printf that only shows up if the "developer" cvar is set
240 ================
241 */
Com_DPrintf(const char * fmt,...)242 void Com_DPrintf( const char *fmt, ... ) {
243 va_list argptr;
244 char msg[MAXPRINTMSG];
245
246 if( !developer || !developer->integer )
247 return; // don't confuse non-developers with techie stuff...
248
249 va_start( argptr, fmt );
250 Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
251 va_end( argptr );
252
253 Com_Printf( S_COLOR_BLUE"%s", msg );
254 }
255
256 /*
257 ================
258 Com_WPrintf
259
260 ================
261 */
Com_WPrintf(const char * fmt,...)262 void Com_WPrintf( const char *fmt, ... ) {
263 va_list argptr;
264 char msg[MAXPRINTMSG];
265
266 va_start( argptr, fmt );
267 Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
268 va_end( argptr );
269
270 Com_Printf( S_COLOR_YELLOW"WARNING: %s", msg );
271 }
272
273 /*
274 ================
275 Com_EPrintf
276
277 ================
278 */
Com_EPrintf(const char * fmt,...)279 void Com_EPrintf( const char *fmt, ... ) {
280 va_list argptr;
281 char msg[MAXPRINTMSG];
282
283 va_start( argptr, fmt );
284 Q_vsnprintf( msg, sizeof( msg ), fmt, argptr );
285 va_end( argptr );
286
287 Com_Printf( S_COLOR_RED"ERROR: %s", msg );
288 }
289
290
291 /*
292 =============
293 Com_Error
294
295 Both client and server can use this, and it will
296 do the apropriate things.
297 =============
298 */
Com_Error(comErrorType_t code,const char * fmt,...)299 void Com_Error( comErrorType_t code, const char *fmt, ... ) {
300 va_list argptr;
301 static qboolean recursive;
302
303 if( recursive ) {
304 #ifndef NDEBUG
305 Sys_DebugBreak();
306 #endif
307 Sys_Error( "recursive error after: %s", com_errorMsg );
308 }
309 recursive = qtrue;
310
311 va_start( argptr, fmt );
312 Q_vsnprintf( com_errorMsg, sizeof( com_errorMsg ), fmt, argptr );
313 va_end( argptr );
314
315 /* fix up drity message buffers */
316 MSG_Init();
317
318 if( code == ERR_DISCONNECT || code == ERR_SILENT ) {
319 SV_Shutdown( va( "Server was killed: %s", com_errorMsg ),
320 KILL_DISCONNECT );
321 CL_Disconnect( code, com_errorMsg );
322 Com_Printf( S_COLOR_YELLOW "%s\n", com_errorMsg );
323 recursive = qfalse;
324 longjmp( abortframe, -1 );
325 }
326
327 if( com_debug_break && com_debug_break->integer ) {
328 Sys_DebugBreak();
329 }
330
331 if( code == ERR_DROP ) {
332 Com_Printf( S_COLOR_RED "********************\n"
333 "ERROR: %s\n"
334 "********************\n", com_errorMsg );
335 SV_Shutdown( va( "Server crashed: %s\n", com_errorMsg ), KILL_DROP );
336 CL_Disconnect( ERR_DROP, com_errorMsg );
337 recursive = qfalse;
338 longjmp( abortframe, -1 );
339 }
340
341 if( com_logFile ) {
342 FS_FPrintf( com_logFile, "FATAL: %s\n", com_errorMsg );
343 }
344
345 SV_Shutdown( va( "Server fatal crashed: %s\n", com_errorMsg ), KILL_DROP );
346 CL_Shutdown();
347 Qcommon_Shutdown( qtrue );
348
349 Sys_Error( "%s", com_errorMsg );
350 }
351
352 /*
353 ===================
354 Com_LevelPrint
355 ===================
356 */
Com_LevelPrint(comPrintType_t type,const char * str)357 void Com_LevelPrint( comPrintType_t type, const char *str ) {
358 switch( type ) {
359 case PRINT_DEVELOPER:
360 Com_DPrintf( "%s", str );
361 break;
362 case PRINT_WARNING:
363 Com_WPrintf( "%s", str );
364 break;
365 case PRINT_ERROR:
366 Com_EPrintf( "%s", str );
367 break;
368 default:
369 Com_Printf( "%s", str );
370 break;
371 }
372 }
373
374 /*
375 ===================
376 Com_LevelError
377 ===================
378 */
Com_LevelError(comErrorType_t code,const char * str)379 void Com_LevelError( comErrorType_t code, const char *str ) {
380 Com_Error( code, "%s", str );
381 }
382
383 /*
384 =============
385 Com_Quit
386
387 Both client and server can use this, and it will
388 do the apropriate things.
389 =============
390 */
Com_Quit(void)391 void Com_Quit( void ) {
392 SV_Shutdown( "Server quit\n", KILL_DROP );
393 CL_Shutdown();
394 Qcommon_Shutdown( qfalse );
395
396 Sys_Quit();
397 }
398
399
400 // ============================================================================
401
402 #ifndef DEDICATED_ONLY
403
404 /*
405 ===============
406 Com_WriteConfiguration
407
408 Writes key bindings and archived cvars to config.cfg
409 ===============
410 */
Com_WriteConfiguration(const char * path)411 static qboolean Com_WriteConfiguration( const char *path ) {
412 fileHandle_t f;
413
414 FS_FOpenFile( path, &f, FS_MODE_WRITE );
415 if( !f ) {
416 Com_WPrintf( "Couldn't write %s\n", path );
417 return qfalse;
418 }
419
420 FS_FPrintf( f, "// generated by q2pro, do not modify\n" );
421
422 Key_WriteBindings( f );
423 Cvar_WriteVariables( f );
424
425 FS_FCloseFile( f );
426
427 return qtrue;
428 }
429
430 /*
431 ===============
432 Com_WriteConfig_f
433 ===============
434 */
Com_WriteConfig_f(void)435 static void Com_WriteConfig_f( void ) {
436 char buffer[MAX_QPATH];
437
438 if( Cmd_Argc() > 2 ) {
439 Com_Printf( "Usage: %s [cfgfile]\n", Cmd_Argv( 0 ) );
440 return;
441 }
442
443 if( Cmd_Argc() < 2 ) {
444 strcpy( buffer, COM_CONFIG_NAME );
445 } else {
446 Cmd_ArgvBuffer( 1, buffer, sizeof( buffer ) );
447 COM_DefaultExtension( buffer, ".cfg", sizeof( buffer ) );
448 }
449
450 if( Com_WriteConfiguration( buffer ) ) {
451 Com_Printf( "Wrote %s\n", buffer );
452 }
453 }
454
455 #endif
456
457 /*
458 ==============================================================================
459
460 ZONE MEMORY ALLOCATION
461
462 just cleared malloc with counters now...
463
464 ==============================================================================
465 */
466
467 #define Z_MAGIC 0x1d0d
468 #define Z_TAIL 0x5b7b
469
470 typedef struct zhead_s {
471 uint16 magic;
472 uint16 tag; // for group free
473 size_t size;
474 struct zhead_s *prev, *next;
475 } zhead_t;
476
477 static zhead_t z_chain;
478
479 typedef struct zstatic_s {
480 zhead_t z;
481 char data[2]; /* !!make sure 'tail' field is aligned properly */
482 uint16 tail;
483 } zstatic_t;
484
485 static zstatic_t z_static[] = {
486 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '0', '\0' }, Z_TAIL },
487 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '1', '\0' }, Z_TAIL },
488 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '2', '\0' }, Z_TAIL },
489 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '3', '\0' }, Z_TAIL },
490 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '4', '\0' }, Z_TAIL },
491 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '5', '\0' }, Z_TAIL },
492 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '6', '\0' }, Z_TAIL },
493 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '7', '\0' }, Z_TAIL },
494 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '8', '\0' }, Z_TAIL },
495 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '9', '\0' }, Z_TAIL },
496 { { Z_MAGIC, TAG_STATIC, sizeof( zstatic_t ) }, { '\0' }, Z_TAIL },
497 };
498
499 typedef struct zstats_s {
500 size_t count;
501 size_t bytes;
502 char *name;
503 } zstats_t;
504
505 static zstats_t z_stats[TAG_MAX];
506
Z_Check(void)507 void Z_Check( void ) {
508 zhead_t *z;
509
510 for( z = z_chain.next; z != &z_chain; z = z->next ) {
511 if( z->magic != Z_MAGIC ) {
512 Com_Error( ERR_FATAL, "Z_Check: bad magic" );
513 }
514
515 if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) !=
516 Z_TAIL )
517 {
518 Com_Error( ERR_FATAL, "Z_Check: bad tail" );
519 }
520
521 if( z->tag == TAG_FREE ) {
522 Com_Error( ERR_FATAL, "Z_Check: bad tag" );
523 }
524 }
525 }
526
Z_LeakTest(memtag_t tag)527 void Z_LeakTest( memtag_t tag ) {
528 zhead_t *z;
529 zstats_t *s;
530 size_t numLeaks, numBytes;
531
532 numLeaks = numBytes = 0;
533 for( z = z_chain.next; z != &z_chain; z = z->next ) {
534 if( z->magic != Z_MAGIC )
535 Com_Error( ERR_FATAL, "Z_LeakTest: bad magic" );
536
537 if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) !=
538 Z_TAIL )
539 {
540 Com_Error( ERR_FATAL, "Z_LeakTest: bad tail" );
541 }
542
543 if( z->tag == TAG_FREE ) {
544 Com_Error( ERR_FATAL, "Z_LeakTest: bad tag" );
545 }
546
547 if( z->tag == tag ) {
548 numLeaks++;
549 numBytes += z->size;
550 }
551 }
552
553 if( numLeaks ) {
554 s = &z_stats[tag < TAG_MAX ? tag : TAG_FREE];
555 Com_Printf( S_COLOR_YELLOW "************* Z_LeakTest *************\n"
556 "%s leaked %u bytes of memory (%u object%s)\n"
557 "**************************************\n",
558 s->name, numBytes, numLeaks,
559 ( numLeaks % 10 ) == 1 ? "" : "s" );
560 }
561 }
562
563 /*
564 ========================
565 Z_Free
566 ========================
567 */
Z_Free(void * ptr)568 void Z_Free( void *ptr ) {
569 zhead_t *z;
570 zstats_t *s;
571
572 if( !ptr ) {
573 return;
574 }
575
576 z = ( ( zhead_t * )ptr ) - 1;
577
578 if( z->magic != Z_MAGIC ) {
579 Com_Error( ERR_FATAL, "Z_Free: bad magic" );
580 }
581
582 if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) != Z_TAIL ) {
583 Com_Error( ERR_FATAL, "Z_Free: bad tail" );
584 }
585
586 if( z->tag == TAG_FREE ) {
587 Com_Error( ERR_FATAL, "Z_Free: bad tag" );
588 }
589
590 s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE];
591 s->count--;
592 s->bytes -= z->size;
593
594 if( z->tag != TAG_STATIC ) {
595 z->prev->next = z->next;
596 z->next->prev = z->prev;
597
598 free( z );
599 }
600 }
601
602 /*
603 ========================
604 Z_Realloc
605 ========================
606 */
Z_Realloc(void * ptr,size_t size)607 void *Z_Realloc( void *ptr, size_t size ) {
608 zhead_t *z;
609 zstats_t *s;
610
611 if( !ptr ) {
612 return Z_Malloc( size );
613 }
614
615 if( !size ) {
616 Z_Free( ptr );
617 return NULL;
618 }
619
620 z = ( ( zhead_t * )ptr ) - 1;
621
622 if( z->magic != Z_MAGIC ) {
623 Com_Error( ERR_FATAL, "Z_Realloc: bad magic" );
624 }
625
626 if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) != Z_TAIL ) {
627 Com_Error( ERR_FATAL, "Z_Realloc: bad tail" );
628 }
629
630 if( z->tag == TAG_FREE ) {
631 Com_Error( ERR_FATAL, "Z_Realloc: bad tag" );
632 }
633
634 if( z->tag == TAG_STATIC ) {
635 Z_Free( ptr );
636 return Z_Malloc( size );
637 }
638
639 s = &z_stats[z->tag < TAG_MAX ? z->tag : TAG_FREE];
640 s->bytes -= z->size;
641
642 size += sizeof( zhead_t ) + sizeof( uint16 );
643 size = ( size + 3 ) & ~3;
644
645 z = realloc( z, size );
646 if( !z ) {
647 Com_Error( ERR_FATAL, "Z_Realloc: couldn't reallocate %u bytes", size );
648 }
649
650 z->size = size;
651 z->prev->next = z;
652 z->next->prev = z;
653
654 s->bytes += size;
655
656 *( uint16 * )( ( byte * )z + size - sizeof( uint16 ) ) = Z_TAIL;
657
658 return ( void * )( z + 1 );
659 }
660
661 /*
662 ========================
663 Z_Stats_f
664 ========================
665 */
Z_Stats_f(void)666 void Z_Stats_f( void ) {
667 size_t z_bytes, z_count;
668 zstats_t *s;
669 int i;
670
671 Com_Printf( "-----------------\n" );
672 Com_Printf( " bytes blocks\n\n" );
673
674 z_bytes = 0;
675 z_count = 0;
676 for( i = 0, s = z_stats; i < TAG_MAX; i++, s++ ) {
677 if( !s->count ) {
678 continue;
679 }
680
681 Com_Printf( "%9u %6u %s\n", s->bytes, s->count, s->name );
682 z_bytes += s->bytes;
683 z_count += s->count;
684 }
685
686 Com_Printf( "-----------------\n" );
687 Com_Printf( "%9u %6u %s\n", z_bytes, z_count, "total" );
688 }
689
690 /*
691 ========================
692 Z_FreeTags
693 ========================
694 */
Z_FreeTags(memtag_t tag)695 void Z_FreeTags( memtag_t tag ) {
696 zhead_t *z, *next;
697
698 for( z = z_chain.next; z != &z_chain; z = next ) {
699 if( z->magic != Z_MAGIC ) {
700 Com_Error( ERR_FATAL, "Z_FreeTags: bad magic" );
701 }
702
703 if( *( uint16 * )( ( byte * )z + z->size - sizeof( uint16 ) ) !=
704 Z_TAIL )
705 {
706 Com_Error( ERR_FATAL, "Z_FreeTags: bad tail" );
707 }
708
709 if( z->tag == TAG_FREE ) {
710 Com_Error( ERR_FATAL, "Z_FreeTags: bad tag" );
711 }
712 next = z->next;
713 if( z->tag == tag ) {
714 Z_Free( ( void * )( z + 1 ) );
715 }
716 }
717 }
718
719 /*
720 ========================
721 Z_TagMalloc
722 ========================
723 */
Z_TagMalloc(size_t size,memtag_t tag)724 void *Z_TagMalloc( size_t size, memtag_t tag ) {
725 zhead_t *z;
726 zstats_t *s;
727
728 if( !size ) {
729 return NULL;
730 }
731
732 if( tag == TAG_FREE )
733 Com_Error( ERR_FATAL, "Z_TagMalloc: bad tag" );
734
735 size += sizeof( zhead_t ) + sizeof( uint16 );
736 size = ( size + 3 ) & ~3;
737 z = malloc( size );
738 if( !z ) {
739 Com_Error( ERR_FATAL, "Z_TagMalloc: couldn't allocate %u bytes", size );
740 }
741 z->magic = Z_MAGIC;
742 z->tag = tag;
743 z->size = size;
744
745 z->next = z_chain.next;
746 z->prev = &z_chain;
747 z_chain.next->prev = z;
748 z_chain.next = z;
749
750 *( uint16 * )( ( byte * )z + size - sizeof( uint16 ) ) = Z_TAIL;
751
752 s = &z_stats[tag < TAG_MAX ? tag : TAG_FREE];
753 s->count++;
754 s->bytes += size;
755
756 return ( void * )( z + 1 );
757 }
758
Z_TagMallocz(size_t size,memtag_t tag)759 void *Z_TagMallocz( size_t size, memtag_t tag ) {
760 void *ptr;
761
762 if( !size ) {
763 return NULL;
764 }
765
766 ptr = Z_TagMalloc( size, tag );
767 memset( ptr, 0, size );
768
769 return ptr;
770 }
771
772 static byte *z_reserved;
773 static size_t z_reservedUnuse;
774 static size_t z_reservedTotal;
775
Z_TagReserve(size_t size,memtag_t tag)776 void Z_TagReserve( size_t size, memtag_t tag ) {
777 z_reserved = Z_TagMalloc( size, tag );
778 z_reservedTotal = size;
779 z_reservedUnuse = 0;
780 }
781
Z_ReservedAlloc(size_t size)782 void *Z_ReservedAlloc( size_t size ) {
783 byte *ptr;
784
785 if( z_reservedUnuse + size > z_reservedTotal ) {
786 Com_Error( ERR_FATAL, "Z_ReservedAlloc: out of space" );
787 }
788
789 ptr = z_reserved + z_reservedUnuse;
790 z_reservedUnuse += size;
791
792 return ( void * )ptr;
793
794 }
795
Z_ReservedCopyString(const char * in)796 char *Z_ReservedCopyString( const char *in ) {
797 char *out;
798 int length;
799
800 if( !in ) {
801 return NULL;
802 }
803
804 length = strlen( in ) + 1;
805
806 out = Z_ReservedAlloc( length );
807 strcpy( out, in );
808
809 return out;
810 }
811
812 /*
813 ========================
814 Z_Init
815 ========================
816 */
Z_Init(void)817 void Z_Init( void ) {
818 zstats_t *s;
819 int i;
820 static char *names[TAG_MAX] = {
821 "game",
822 "static",
823 "generic",
824 "cmd",
825 "cvar",
826 "filesystem",
827 "renderer",
828 "ui",
829 "cgame",
830 "server",
831 "mvd",
832 "sound",
833 "cmodel",
834 "lua"
835 };
836
837 z_chain.next = z_chain.prev = &z_chain;
838
839 for( i = 0, s = z_stats; i < TAG_MAX; i++, s++ ) {
840 s->name = names[i] ? names[i] : "unknown";
841 }
842 }
843
844 /*
845 ================
846 Z_TagCopyString
847 ================
848 */
Z_TagCopyString(const char * in,memtag_t tag)849 char *Z_TagCopyString( const char *in, memtag_t tag ) {
850 char *out;
851 int length;
852
853 if( !in ) {
854 return NULL;
855 }
856
857 length = strlen( in ) + 1;
858
859 out = Z_TagMalloc( length, tag );
860 strcpy( out, in );
861
862 return out;
863 }
864
865 /*
866 ================
867 Cvar_CopyString
868 ================
869 */
Cvar_CopyString(const char * in)870 char *Cvar_CopyString( const char *in ) {
871 char *out;
872 int length;
873 zstatic_t *z;
874
875 if( !in ) {
876 return NULL;
877 }
878
879 if( !in[0] ) {
880 z = &z_static[10];
881 z_stats[TAG_STATIC].count++;
882 z_stats[TAG_STATIC].bytes += z->z.size;
883 return z->data;
884 }
885
886 if( !in[1] && Q_isdigit( in[0] ) ) {
887 z = &z_static[ in[0] - '0' ];
888 z_stats[TAG_STATIC].count++;
889 z_stats[TAG_STATIC].bytes += z->z.size;
890 return z->data;
891 }
892
893 length = strlen( in ) + 1;
894
895 out = Z_TagMalloc( length, TAG_CVAR );
896 strcpy( out, in );
897
898 return out;
899 }
900
901 /*
902 ==============================================================================
903
904 INTERFACE TO ZLIB
905
906 ==============================================================================
907 */
908
909 static z_stream com_zStream;
910 static sizebuf_t *com_zOutputBuf;
911
912 #define ZLIB_WINDOW_BITS ( -15 )
913
914 /*
915 =============
916 Com_ZLibDeflateStart
917 =============
918 */
Com_ZLibDeflateStart(sizebuf_t * outputBuf)919 qboolean Com_ZLibDeflateStart( sizebuf_t *outputBuf ) {
920 memset( &com_zStream, 0, sizeof( com_zStream ) );
921 com_zStream.next_out = outputBuf->data;
922 com_zStream.avail_out = outputBuf->maxsize;
923
924 if( deflateInit2( &com_zStream, Z_BEST_COMPRESSION, Z_DEFLATED,
925 ZLIB_WINDOW_BITS, 9, Z_DEFAULT_STRATEGY ) != Z_OK )
926 {
927 return qfalse;
928 }
929
930 SZ_Clear( outputBuf );
931 com_zOutputBuf = outputBuf;
932
933 return qtrue;
934 }
935
936 /*
937 =============
938 Com_ZLibDeflateChunk
939 =============
940 */
Com_ZLibDeflateChunk(sizebuf_t * inputBuf)941 qboolean Com_ZLibDeflateChunk( sizebuf_t *inputBuf ) {
942 com_zStream.next_in = inputBuf->data;
943 com_zStream.avail_in = inputBuf->cursize;
944
945 if( deflate( &com_zStream, Z_SYNC_FLUSH ) != Z_OK ) {
946 return qfalse;
947 }
948
949 if( !com_zStream.avail_out ) {
950 return qfalse;
951 }
952
953 com_zOutputBuf->cursize = com_zStream.total_out;
954
955 return qtrue;
956 }
957
958 /*
959 =============
960 Com_ZLibDeflateAbort
961 =============
962 */
Com_ZLibDeflateAbort(void)963 void Com_ZLibDeflateAbort( void ) {
964 deflateEnd( &com_zStream );
965 com_zOutputBuf = NULL;
966 }
967
968 /*
969 =============
970 Com_ZLibDeflateFinish
971 =============
972 */
Com_ZLibDeflateFinish(void)973 qboolean Com_ZLibDeflateFinish( void ) {
974 if( deflate( &com_zStream, Z_FINISH ) != Z_STREAM_END ) {
975 Com_ZLibDeflateAbort();
976 return qfalse;
977 }
978
979 com_zOutputBuf->cursize = com_zStream.total_out;
980 com_zOutputBuf = NULL;
981
982 if( deflateEnd( &com_zStream ) != Z_OK ) {
983 return qfalse;
984 }
985
986 return qtrue;
987 }
988
989 /*
990 =============
991 Com_ZLibDeflateBuffer
992 =============
993 */
Com_ZLibDeflateBuffer(sizebuf_t * inputBuf,sizebuf_t * outputBuf)994 qboolean Com_ZLibDeflateBuffer( sizebuf_t *inputBuf, sizebuf_t *outputBuf ) {
995 z_stream z;
996
997 memset( &z, 0, sizeof( z ) );
998
999 z.next_in = inputBuf->data;
1000 z.avail_in = inputBuf->cursize;
1001
1002 SZ_Clear( outputBuf );
1003 z.next_out = outputBuf->data;
1004 z.avail_out = outputBuf->maxsize;
1005
1006 if( deflateInit2( &z, Z_BEST_COMPRESSION, Z_DEFLATED, ZLIB_WINDOW_BITS, 9,
1007 Z_DEFAULT_STRATEGY ) != Z_OK )
1008 {
1009 return qfalse;
1010 }
1011
1012 if( deflate( &z, Z_FINISH ) != Z_STREAM_END ) {
1013 deflateEnd( &z );
1014 return qfalse;
1015 }
1016
1017 if( deflateEnd( &z ) != Z_OK ) {
1018 return qfalse;
1019 }
1020
1021 outputBuf->cursize = z.total_out;
1022
1023 return qtrue;
1024 }
1025
1026 /*
1027 =============
1028 Com_ZLibInflateBuffer
1029 =============
1030 */
Com_ZLibInflateBuffer(sizebuf_t * inputBuf,sizebuf_t * outputBuf,int length)1031 qboolean Com_ZLibInflateBuffer( sizebuf_t *inputBuf, sizebuf_t *outputBuf,
1032 int length )
1033 {
1034 z_stream z;
1035
1036 memset( &z, 0, sizeof( z ) );
1037
1038 z.next_in = inputBuf->data + inputBuf->readcount;
1039 if( length ) {
1040 if( length < 0 || inputBuf->readcount + length > inputBuf->cursize ) {
1041 return qfalse;
1042 }
1043 z.avail_in = length;
1044 } else {
1045 z.avail_in = inputBuf->cursize - inputBuf->readcount;
1046 }
1047
1048 SZ_Clear( outputBuf );
1049 z.next_out = outputBuf->data;
1050 z.avail_out = outputBuf->maxsize;
1051
1052 if( inflateInit2( &z, ZLIB_WINDOW_BITS ) != Z_OK ) {
1053 return qfalse;
1054 }
1055
1056 if( inflate( &z, Z_FINISH ) != Z_STREAM_END ) {
1057 inflateEnd( &z );
1058 return qfalse;
1059 }
1060
1061 if( inflateEnd( &z ) != Z_OK ) {
1062 return qfalse;
1063 }
1064
1065 outputBuf->cursize = z.total_out;
1066
1067 return qtrue;
1068 }
1069
MSG_ParseZPacket(void (* parsefunc)(void))1070 void MSG_ParseZPacket( void (*parsefunc)( void ) ) {
1071 sizebuf_t decompressed, temp;
1072 byte decompressed_data[MAX_MSGLEN];
1073 int compressedLength, decompressedLength;
1074
1075 if( msg_read.data != msg_read_buffer ) {
1076 Com_Error( ERR_DROP, "MSG_ParseZPacket: recursively entered" );
1077 }
1078
1079 compressedLength = MSG_ReadShort();
1080 decompressedLength = MSG_ReadShort();
1081
1082 SZ_Init( &decompressed, decompressed_data, sizeof( decompressed_data ) );
1083 if( !Com_ZLibInflateBuffer( &msg_read, &decompressed, compressedLength ) ||
1084 decompressed.cursize != decompressedLength )
1085 {
1086 Com_Error( ERR_DROP,
1087 "MSG_ParseZPacket: decompression of %d bytes into %d failed",
1088 compressedLength, decompressedLength );
1089 }
1090
1091 temp = msg_read;
1092 msg_read = decompressed;
1093
1094 (*parsefunc)();
1095
1096 msg_read = temp;
1097 msg_read.readcount += compressedLength;
1098 }
1099
1100 #ifndef NDEBUG
1101 /*
1102 =============
1103 Com_ZLibTest_f
1104 =============
1105 */
Com_ZLibTest_f(void)1106 static void Com_ZLibTest_f( void ) {
1107 sizebuf_t in, out;
1108 byte in_buf[1024], out_buf[1200];
1109 int i;
1110 int checksum;
1111 int time = Sys_Milliseconds();
1112
1113 Com_Printf( "Testing ZLib on 1024 bytes of data...\n" );
1114
1115 SZ_Init( &in, in_buf, sizeof( in_buf ) );
1116 SZ_Init( &out, out_buf, sizeof( out_buf ) );
1117
1118 for( i = 0; i < sizeof( in_buf ); i++ ) {
1119 in_buf[i] = 'a' + ( rand() % ( 'z' - 'a' ) );
1120 }
1121
1122 checksum = Com_BlockChecksum( in_buf, sizeof( in_buf ) );
1123
1124 if( !Com_ZLibDeflateStart( &out ) ) {
1125 Com_Printf( "Com_ZLibDeflateStart() failed\n" );
1126 return;
1127 }
1128
1129 in.cursize = 256;
1130 for( i = 0; i < sizeof( in_buf ) / 256; i++ ) {
1131 if( !Com_ZLibDeflateChunk( &in ) ) {
1132 Com_ZLibDeflateAbort();
1133 Com_Printf( "Com_ZLibDeflateChunk() failed\n" );
1134 return;
1135 }
1136 in.data += 256;
1137 }
1138
1139 if( !Com_ZLibDeflateFinish() ) {
1140 Com_Printf( "Com_ZLibDeflateFinish() failed\n" );
1141 return;
1142 }
1143
1144 Com_Printf( "Compressed to %i bytes\n", out.cursize );
1145
1146 SZ_Init( &in, in_buf, sizeof( in_buf ) );
1147 memset( in_buf, 0, sizeof( in_buf ) );
1148
1149 if( !Com_ZLibInflateBuffer( &out, &in, 0 ) ) {
1150 Com_Printf( "Com_ZLibInflateBuffer() failed\n" );
1151 return;
1152 }
1153
1154 Com_Printf( "Decompressed to %i bytes\n", in.cursize );
1155
1156 if( checksum != Com_BlockChecksum( in_buf, sizeof( in_buf ) ) ) {
1157 Com_Printf( "Checksum mismatch!\n" );
1158 return;
1159 }
1160
1161 Com_Printf( "ZLib tested successfully (%i msec)\n",
1162 Sys_Milliseconds() - time );
1163 }
1164
1165 #endif
1166
1167
1168 /*
1169 ==============================================================================
1170
1171 INIT / SHUTDOWN
1172
1173 ==============================================================================
1174 */
1175
1176 /*
1177 =============
1178 Com_FillAPI
1179 =============
1180 */
Com_FillAPI(commonAPI_t * api)1181 void Com_FillAPI( commonAPI_t *api ) {
1182 api->Print = Com_LevelPrint;
1183 api->Error = Com_LevelError;
1184 api->TagMalloc = Z_TagMalloc;
1185 api->Realloc = Z_Realloc;
1186 api->Free = Z_Free;
1187 }
1188
1189 /*
1190 =============
1191 Com_Time_m
1192 =============
1193 */
Com_Time_m(char * buffer,int bufferSize)1194 void Com_Time_m( char *buffer, int bufferSize ) {
1195 #ifdef _WIN32_WCE
1196 buffer[0] = 0;
1197 #else
1198 time_t clock;
1199 struct tm *localTime;
1200
1201 time( &clock );
1202 localTime = localtime( &clock );
1203
1204 strftime( buffer, bufferSize, com_time_format->string, localTime );
1205 #endif
1206 }
1207
1208 /*
1209 =============
1210 Com_Date_m
1211 =============
1212 */
Com_Date_m(char * buffer,int bufferSize)1213 static void Com_Date_m( char *buffer, int bufferSize ) {
1214 #ifdef _WIN32_WCE
1215 buffer[0] = 0;
1216 #else
1217 time_t clock;
1218 struct tm *localTime;
1219
1220 time( &clock );
1221 localTime = localtime( &clock );
1222
1223 strftime( buffer, bufferSize, com_date_format->string, localTime );
1224 #endif
1225 }
1226
Com_LastError_f(void)1227 static void Com_LastError_f( void ) {
1228 if( com_errorMsg[0] ) {
1229 Com_Printf( "%s\n", com_errorMsg );
1230 } else {
1231 Com_Printf( "No error.\n" );
1232 }
1233 }
1234
1235 #ifndef NDEBUG
1236
1237 /*
1238 =============
1239 Com_Error_f
1240
1241 Just throw a fatal error to
1242 test error shutdown procedures
1243 =============
1244 */
Com_Error_f(void)1245 void Com_Error_f( void ) {
1246 Com_Error( ERR_FATAL, "%s", Cmd_Argv( 1 ) );
1247 }
1248
Com_ErrorDrop_f(void)1249 void Com_ErrorDrop_f( void ) {
1250 Com_Error( ERR_DROP, "%s", Cmd_Argv( 1 ) );
1251 }
1252
Com_Freeze_f(void)1253 void Com_Freeze_f( void ) {
1254 int seconds, time;
1255
1256 if( Cmd_Argc() < 2 ) {
1257 Com_Printf( "Usage: %s <seconds>\n", Cmd_Argv( 0 ) );
1258 return;
1259 }
1260
1261 seconds = atoi( Cmd_Argv( 1 ) );
1262 if( seconds < 1 ) {
1263 return;
1264 }
1265
1266 time = Sys_Milliseconds() + seconds * 1000;
1267 while( Sys_Milliseconds() < time )
1268 ;
1269
1270 }
1271
Com_Crash_f(void)1272 void Com_Crash_f( void ) {
1273 *( uint32 * )0 = 0x123456;
1274 }
1275
Com_VsnprintfTest_f(void)1276 static void Com_VsnprintfTest_f( void ) {
1277 char buffer[32];
1278 int ret;
1279 qboolean fail;
1280
1281 /* test if returned length is valid, no overflow, large buffer */
1282 Com_Printf( "test 1\n" );
1283 fail = qfalse;
1284 memset( buffer, '@', sizeof( buffer ) );
1285 ret = Com_sprintf( buffer, sizeof( buffer ), "%s", "abcd" );
1286 if( ret != 4 ) {
1287 Com_Printf( "returned %d instead of %d\n", ret, 4 );
1288 fail = qtrue;
1289 }
1290 if( buffer[4] != 0 ) {
1291 Com_Printf( "buffer left unterminated\n" );
1292 fail = qtrue;
1293 }
1294 if( buffer[5] != '@' ) {
1295 Com_Printf( "buffer overflowed\n" );
1296 fail = qtrue;
1297 }
1298 if( !fail ) {
1299 Com_Printf( "succeeded\n" );
1300 } else {
1301 Com_Printf( "failed\n" );
1302 }
1303
1304 /* test if returned length is valid, no overflow, small buffer */
1305 Com_Printf( "test 2\n" );
1306 fail = qfalse;
1307 memset( buffer, '@', sizeof( buffer ) );
1308 ret = Com_sprintf( buffer, 5, "%s", "abcd" );
1309 if( ret != 4 ) {
1310 Com_Printf( "returned %d instead of %d\n", ret, 4 );
1311 }
1312 if( buffer[4] != 0 ) {
1313 Com_Printf( "buffer left unterminated\n" );
1314 fail = qtrue;
1315 }
1316 if( buffer[5] != '@' ) {
1317 Com_Printf( "buffer overflowed\n" );
1318 fail = qtrue;
1319 }
1320 if( !fail ) {
1321 Com_Printf( "succeeded\n" );
1322 } else {
1323 Com_Printf( "failed\n" );
1324 }
1325
1326 /* test if returned length is valid, with overflow */
1327 Com_Printf( "test 3\n" );
1328 fail = qfalse;
1329 memset( buffer, '@', sizeof( buffer ) );
1330 ret = Com_sprintf( buffer, 5, "%s", "abcdefgh" );
1331 if( ret != 4 ) {
1332 Com_Printf( "returned %d instead of %d\n", ret, 4 );
1333 fail = qtrue;
1334 }
1335 if( buffer[4] != 0 ) {
1336 Com_Printf( "buffer left unterminated\n" );
1337 fail = qtrue;
1338 }
1339 if( buffer[5] != '@' ) {
1340 Com_Printf( "buffer overflowed\n" );
1341 fail = qtrue;
1342 }
1343
1344 if( !fail ) {
1345 Com_Printf( "succeeded\n" );
1346 } else {
1347 Com_Printf( "failed\n" );
1348 }
1349 }
1350
1351 #endif
1352
Com_FileNameGenerator(const char * path,const char * ext,const char * partial,qboolean stripExtension,int state)1353 const char *Com_FileNameGenerator( const char *path, const char *ext,
1354 const char *partial, qboolean stripExtension, int state ) {
1355 static int length, numFiles;
1356 static char **list;
1357 static int curpos;
1358 char *s, *p;
1359
1360 if( state == 2 ) {
1361 goto finish;
1362 }
1363
1364 if( !state ) {
1365 length = strlen( partial );
1366 list = FS_ListFiles( path, ext, 0, &numFiles );
1367 curpos = 0;
1368 }
1369
1370 while( curpos < numFiles ) {
1371 s = list[curpos++];
1372 if( stripExtension ) {
1373 p = COM_FileExtension( s );
1374 *p = 0;
1375 }
1376 if( !strncmp( s, partial, length ) ) {
1377 return s;
1378 }
1379 }
1380
1381 finish:
1382 if( list ) {
1383 FS_FreeFileList( list );
1384 list = NULL;
1385 }
1386 return NULL;
1387 }
1388
Com_FileNameGeneratorByFilter(const char * path,const char * filter,const char * partial,qboolean stripExtension,int state)1389 const char *Com_FileNameGeneratorByFilter( const char *path, const char *filter,
1390 const char *partial, qboolean stripExtension, int state ) {
1391 static int length, numFiles;
1392 static char **list;
1393 static int curpos;
1394 char *s, *p;
1395
1396 if( state == 2 ) {
1397 goto finish;
1398 }
1399
1400 if( !state ) {
1401 length = strlen( partial );
1402 list = FS_ListFiles( path, filter, FS_SEARCH_SAVEPATH |
1403 FS_SEARCH_BYFILTER, &numFiles );
1404 curpos = 0;
1405 }
1406
1407 while( curpos < numFiles ) {
1408 s = list[curpos++];
1409 if( stripExtension ) {
1410 p = COM_FileExtension( s );
1411 *p = 0;
1412 }
1413 if( !strncmp( s, partial, length ) ) {
1414 return s;
1415 }
1416 }
1417
1418 finish:
1419 if( list ) {
1420 FS_FreeFileList( list );
1421 list = NULL;
1422 }
1423 return NULL;
1424 }
1425
1426 #define MAX_LINE_COMMANDS 128
1427
1428 static char *com_commands[MAX_LINE_COMMANDS];
1429 static int com_numCommands;
1430
1431 /*
1432 ===============
1433 Com_ParseCommandLine
1434
1435 ===============
1436 */
Com_ParseCommandLine(char * commandLine)1437 static void Com_ParseCommandLine( char *commandLine ) {
1438 qboolean inquote = qfalse;
1439
1440 if( !commandLine ) {
1441 return;
1442 }
1443
1444 com_numCommands = 0;
1445 while( *commandLine ) {
1446 if( *commandLine == '\"' ) {
1447 inquote ^= 1;
1448 } else if( *commandLine == '+' && !inquote ) {
1449 com_commands[com_numCommands] = commandLine + 1;
1450 com_numCommands++;
1451
1452 *commandLine = 0;
1453
1454 if( com_numCommands == MAX_LINE_COMMANDS ) {
1455 break;
1456 }
1457 }
1458
1459 commandLine++;
1460
1461 }
1462 }
1463
1464 /*
1465 ===============
1466 Com_AddEarlyCommands
1467
1468 Adds command line parameters as script statements.
1469 Commands lead with a +, and continue until another +
1470
1471 Set commands are added early, so they are guaranteed to be set before
1472 the client and server initialize for the first time.
1473
1474 Other commands are added late, after all initialization is complete.
1475 ===============
1476 */
Com_AddEarlyCommands(qboolean clear)1477 static void Com_AddEarlyCommands( qboolean clear ) {
1478 int i;
1479 char *s, *name;
1480
1481 for( i = 0; i < com_numCommands; i++ ) {
1482 s = com_commands[i];
1483 if( !*s ) {
1484 continue;
1485 }
1486 Cmd_TokenizeString( s, qfalse );
1487 if( strcmp( Cmd_Argv( 0 ), "set" ) ) {
1488 continue;
1489 }
1490 if( Cmd_Argc() != 3 ) {
1491 Com_Printf( "Usage: +set <variable> <value>\n" );
1492 } else {
1493 name = Cmd_Argv( 1 );
1494 if( !strcmp( name, "port" ) ) {
1495 Com_WPrintf( "'port' variable is deprecated. Please use 'net_port' instead.\n" );
1496 name = "net_port";
1497 }
1498 Cvar_SetEx( name, Cmd_Argv( 2 ), CVAR_SET_COMMAND_LINE );
1499 }
1500 if( clear ) {
1501 *s = 0;
1502 }
1503 }
1504 }
1505
1506 /*
1507 =================
1508 Com_AddLateCommands
1509
1510 Adds command line parameters as script statements
1511 Commands lead with a + and continue until another +
1512
1513 Returns qtrue if any late commands were added, which
1514 will keep the demoloop from immediately starting
1515
1516 Assumes +set commands are already filtered out
1517 =================
1518 */
Com_AddLateCommands(void)1519 static qboolean Com_AddLateCommands( void ) {
1520 int i;
1521 char *s;
1522 qboolean ret = qfalse;
1523
1524 for( i = 0; i < com_numCommands; i++ ) {
1525 s = com_commands[i];
1526 if( !*s ) {
1527 continue;
1528 }
1529 Cbuf_AddText( s );
1530 Cbuf_AddText( "\n" );
1531 ret = qtrue;
1532 }
1533
1534 if( ret ) {
1535 Cbuf_Execute();
1536 }
1537
1538 return ret;
1539 }
1540
1541 /*
1542 =================
1543 Qcommon_Init
1544 =================
1545 */
Qcommon_Init(char * commandLine)1546 void Qcommon_Init( char *commandLine ) {
1547 static const char *version = APPLICATION " " VERSION " " __DATE__ " " BUILDSTRING "-" CPUSTRING;
1548
1549 if( _setjmp( abortframe ) )
1550 Sys_Error( "Error during initialization: %s", com_errorMsg );
1551
1552 Com_Printf( S_COLOR_CYAN "%s\n", version );
1553
1554 Com_ParseCommandLine( commandLine );
1555
1556 // prepare enough of the subsystems to handle
1557 // cvar and command buffer management
1558 Z_Init();
1559 MSG_Init();
1560 Cbuf_Init();
1561 Cmd_Init();
1562 Cvar_Init();
1563 Key_Init();
1564 Prompt_Init();
1565 Con_Init();
1566
1567 Com_FillAPI( &com );
1568
1569 //
1570 // init commands and vars
1571 //
1572 host_speeds = Cvar_Get ("host_speeds", "0", 0);
1573 developer = Cvar_Get ("developer", "0", 0);
1574 timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT );
1575 fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT );
1576 logfile_active = Cvar_Get( "logfile", "0", 0 );
1577 logfile_flush = Cvar_Get( "logfile_flush", "0", 0 );
1578 logfile_name = Cvar_Get( "logfile_name", COM_LOGFILE_NAME, 0 );
1579 #ifdef DEDICATED_ONLY
1580 dedicated = Cvar_Get ("dedicated", "1", CVAR_ROM);
1581 #else
1582 dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET);
1583 #endif
1584 sv_running = Cvar_Get( "sv_running", "0", CVAR_ROM );
1585 sv_paused = Cvar_Get( "sv_paused", "0", CVAR_ROM );
1586 cl_running = Cvar_Get( "cl_running", "0", CVAR_ROM );
1587 cl_paused = Cvar_Get( "cl_paused", "0", CVAR_ROM );
1588 com_timedemo = Cvar_Get( "timedemo", "0", CVAR_CHEAT );
1589 com_sleep = Cvar_Get( "com_sleep", "1", 0 );
1590 com_date_format = Cvar_Get( "com_date_format", "%Y-%m-%d", 0 );
1591 com_time_format = Cvar_Get( "com_time_format", "%H.%M.%S", 0 );
1592 com_debug_break = Cvar_Get( "com_debug_break", "0", 0 );
1593
1594 //
1595 // userinfo - shared by regular client and MVD client
1596 //
1597 info_password = Cvar_Get( "password", "", CVAR_USERINFO );
1598 info_spectator = Cvar_Get( "spectator", dedicated->integer ? "1" : "0",
1599 CVAR_USERINFO );
1600 info_name = Cvar_Get( "name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE );
1601 info_skin = Cvar_Get( "skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE );
1602 info_rate = Cvar_Get( "rate", dedicated->integer ? "15000" : "5000",
1603 CVAR_USERINFO | CVAR_ARCHIVE );
1604 info_msg = Cvar_Get( "msg", "1", CVAR_USERINFO | CVAR_ARCHIVE );
1605 info_hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
1606 info_fov = Cvar_Get( "fov", "90", CVAR_USERINFO | CVAR_ARCHIVE );
1607 info_gender = Cvar_Get( "gender", "male", CVAR_USERINFO | CVAR_ARCHIVE );
1608
1609 #ifdef NDEBUG
1610 Cvar_Get( "version", version, CVAR_SERVERINFO|CVAR_ROM );
1611 #else
1612 Cvar_Get( "version", version, CVAR_SERVERINFO );
1613 #endif
1614
1615 Cmd_AddCommand ("z_stats", Z_Stats_f);
1616
1617 #ifndef DEDICATED_ONLY
1618 if( !dedicated->integer ) {
1619 Cmd_AddCommand( "writeconfig", Com_WriteConfig_f );
1620 }
1621 #endif
1622
1623
1624 Cmd_AddMacro( "com_date", Com_Date_m );
1625 Cmd_AddMacro( "com_time", Com_Time_m );
1626
1627 // we need to add the early commands twice, because
1628 // a basedir or cddir needs to be set before execing
1629 // config files, but we want other parms to override
1630 // the settings of the config files
1631 Com_AddEarlyCommands( qfalse );
1632
1633 Sys_Init();
1634 FS_Init();
1635
1636 /* after FS is initialized, open logfile */
1637 logfile_active->changedFunc = LogFileActive_OnChange;
1638 logfile_flush->changedFunc = LogFileParam_OnChange;
1639 logfile_name->changedFunc = LogFileParam_OnChange;
1640 LogFileActive_OnChange( logfile_active, NULL );
1641
1642 Cbuf_AddText( "exec "COM_DEFAULTCFG_NAME"\n" );
1643 Cbuf_Execute();
1644
1645 Cbuf_AddText( "exec "COM_CONFIG_NAME"\n" );
1646 Cbuf_Execute();
1647
1648 Cbuf_AddText( "exec "COM_AUTOEXECCFG_NAME"\n" );
1649 Cbuf_Execute();
1650
1651 Com_AddEarlyCommands( qtrue );
1652
1653 #ifndef NDEBUG
1654 Cmd_AddCommand( "error", Com_Error_f );
1655 Cmd_AddCommand( "errordrop", Com_ErrorDrop_f );
1656 Cmd_AddCommand( "freeze", Com_Freeze_f );
1657 Cmd_AddCommand( "crash", Com_Crash_f );
1658 Cmd_AddCommand( "vstest", Com_VsnprintfTest_f );
1659 Cmd_AddCommand( "zlibtest", Com_ZLibTest_f );
1660 #endif
1661
1662 Cmd_AddCommand( "lasterror", Com_LastError_f );
1663
1664 Cmd_AddCommand( "quit", Com_Quit );
1665
1666 srand( Sys_Milliseconds() );
1667
1668 Netchan_Init();
1669 CM_Init();
1670 SV_Init();
1671 CL_Init();
1672 NET_Init();
1673
1674 if( dedicated->integer ) {
1675 NET_Config( NET_SERVER );
1676 }
1677
1678 // add + commands from command line
1679 if( !Com_AddLateCommands() ) {
1680 // if the user didn't give any commands, run default action
1681 if( dedicated->integer ) {
1682 Cbuf_AddText( "dedicated_start\n" );
1683 } else {
1684 // TODO
1685 //Cbuf_AddText( "d1\n" );
1686 }
1687 Cbuf_Execute();
1688 } else {
1689 // the user asked for something explicit
1690 // so drop the loading plaque
1691 SCR_EndLoadingPlaque();
1692 }
1693
1694
1695 Com_Printf( "====== " APPLICATION " initialized ======\n\n" );
1696 Com_Printf( S_COLOR_CYAN APPLICATION " " VERSION ", " __DATE__ "\n"
1697 S_COLOR_RESET "w/ zlib " ZLIB_VERSION "\n" );
1698 Com_Printf( "http://q2pro.sf.net\n\n" );
1699
1700 Com_DPrintf( "Working directory: %s\n", Sys_GetCurrentDirectory() );
1701
1702 com_numCommands = 0;
1703
1704 com_eventTime = Sys_Realtime();
1705 }
1706
1707 /*
1708 ==============
1709 Com_ProcessEvents
1710 ==============
1711 */
Com_ProcessEvents(void)1712 void Com_ProcessEvents( void ) {
1713 int ret;
1714
1715 while( ( ret = NET_GetPacket( NS_SERVER, &net_from ) ) != 0 ) {
1716 SV_PacketEvent( ret );
1717 }
1718
1719 #ifdef DEDICATED_ONLY
1720 while( ( ret = NET_GetPacket( NS_CLIENT, &net_from ) ) != 0 ) {
1721 MVD_PacketEvent( ret );
1722 }
1723 #else
1724 while( ( ret = NET_GetPacket( NS_CLIENT, &net_from ) ) != 0 ) {
1725 if( mvd_running->integer ) {
1726 MVD_PacketEvent( ret );
1727 } else {
1728 CL_PacketEvent( ret );
1729 }
1730 }
1731 CL_PumpEvents();
1732 CL_InputFrame();
1733 #endif
1734 }
1735
1736 #ifndef DEDICATED_ONLY
1737 /*
1738 ==============
1739 Com_ProcessLoopback
1740 ==============
1741 */
Com_ProcessLoopback(void)1742 static void Com_ProcessLoopback( void ) {
1743 int i;
1744
1745 memset( &net_from, 0, sizeof( net_from ) );
1746 net_from.type = NA_LOOPBACK;
1747
1748 // Process loopback packets
1749 for( i = 0; i < 2; i++ ) {
1750 while( NET_GetLoopPacket( NS_SERVER ) ) {
1751 if( sv_running->integer ) {
1752 SV_PacketEvent( 1 );
1753 }
1754 }
1755
1756 while( NET_GetLoopPacket( NS_CLIENT ) ) {
1757 if( cl_running->integer ) {
1758 CL_PacketEvent( 1 );
1759 }
1760 }
1761 }
1762 }
1763 #endif
1764
1765 /*
1766 =================
1767 Qcommon_Frame
1768 =================
1769 */
Qcommon_Frame(void)1770 void Qcommon_Frame( void ) {
1771 int time_before, time_event, time_between, time_after;
1772 uint32 realTime;
1773 char *s;
1774 int msec;
1775
1776 if( _setjmp( abortframe ) ) {
1777 return; // an ERR_DROP was thrown
1778 }
1779
1780 time_before = time_event = time_between = time_after = 0;
1781
1782 if( host_speeds->integer )
1783 time_before = Sys_Milliseconds();
1784
1785 do {
1786 Com_ProcessEvents();
1787 realTime = Sys_Realtime();
1788 if( com_eventTime > realTime ) {
1789 com_eventTime = realTime;
1790 }
1791 msec = realTime - com_eventTime;
1792 } while( msec < 1 );
1793 com_eventTime = realTime;
1794
1795 if( fixedtime->integer ) {
1796 Cvar_ClampInteger( fixedtime, 1, 1000 );
1797 msec = fixedtime->integer;
1798 } else if( timescale->value > 0 ) {
1799 msec *= timescale->value;
1800 if( msec < 1 )
1801 msec = 1;
1802 }
1803
1804 if( ( s = Sys_ConsoleInput() ) != NULL ) {
1805 do {
1806 Cbuf_AddText( s );
1807 Cbuf_AddText( "\n" );
1808 } while( ( s = Sys_ConsoleInput() ) != NULL );
1809
1810 Cbuf_Execute();
1811 }
1812
1813 if( host_speeds->integer )
1814 time_event = Sys_Milliseconds();
1815
1816 SV_Frame( msec );
1817
1818 if( host_speeds->integer )
1819 time_between = Sys_Milliseconds();
1820
1821 #ifndef DEDICATED_ONLY
1822 Com_ProcessLoopback();
1823 #endif
1824
1825 CL_Frame( msec );
1826
1827 if( host_speeds->integer )
1828 time_after = Sys_Milliseconds();
1829
1830 if( host_speeds->integer ) {
1831 int all, ev, sv, gm, cl, rf;
1832
1833 all = time_after - time_before;
1834 ev = time_event - time_before;
1835 sv = time_between - time_event;
1836 cl = time_after - time_between;
1837 gm = time_after_game - time_before_game;
1838 rf = time_after_ref - time_before_ref;
1839 sv -= gm;
1840 cl -= rf;
1841
1842 Com_Printf( "all:%3i ev:%3i sv:%3i gm:%3i cl:%3i rf:%3i\n",
1843 all, ev, sv, gm, cl, rf );
1844 }
1845
1846 cvar_infoModified = 0;
1847
1848 com_framenum++;
1849 }
1850
1851 /*
1852 =================
1853 Qcommon_Shutdown
1854 =================
1855 */
Qcommon_Shutdown(qboolean fatalError)1856 void Qcommon_Shutdown( qboolean fatalError ) {
1857 #ifndef DEDICATED_ONLY
1858 if( !fatalError && dedicated && !dedicated->integer ) {
1859 Com_WriteConfiguration( COM_CONFIG_NAME );
1860 }
1861 #endif
1862 LogFile_Close();
1863 FS_Shutdown( qtrue );
1864 }
1865
1866