00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "common.h"
00027 #include "../server/server.h"
00028 #include "../shared/parse.h"
00029 #include "../ports/system.h"
00030 #include <setjmp.h>
00031
00032 #define MAXPRINTMSG 4096
00033 #define MAX_NUM_ARGVS 50
00034
00035 csi_t csi;
00036
00037 static int com_argc;
00038 static const char *com_argv[MAX_NUM_ARGVS + 1];
00039
00040 static jmp_buf abortframe;
00041
00042 cvar_t *developer;
00043 cvar_t *http_proxy;
00044 cvar_t *http_timeout;
00045 static cvar_t *logfile_active;
00046 cvar_t *sv_dedicated;
00047 #ifndef DEDICATED_ONLY
00048 static cvar_t *cl_maxfps;
00049 cvar_t *s_language;
00050 #endif
00051 cvar_t *sv_gametype;
00052 cvar_t *masterserver_url;
00053 cvar_t *port;
00054 cvar_t* sys_priority;
00055 cvar_t* sys_affinity;
00056 cvar_t* sys_os;
00057
00058 static qFILE logfile;
00059
00060 struct memPool_s *com_aliasSysPool;
00061 struct memPool_s *com_cmdSysPool;
00062 struct memPool_s *com_cmodelSysPool;
00063 struct memPool_s *com_cvarSysPool;
00064 struct memPool_s *com_fileSysPool;
00065 struct memPool_s *com_genericPool;
00066 struct memPool_s *com_networkPool;
00067
00068 struct event {
00069 int when;
00070 event_func *func;
00071 event_check_func *check;
00072 event_clean_func *clean;
00073 void *data;
00074 struct event *next;
00075 };
00076
00077 static struct event *event_queue = NULL;
00078
00079 #define TIMER_CHECK_INTERVAL 100
00080 #define TIMER_CHECK_LAG 3
00081 #define TIMER_LATENESS_HIGH 200
00082 #define TIMER_LATENESS_LOW 50
00083 #define TIMER_LATENESS_HISTORY 32
00084
00085 struct timer {
00086 cvar_t *min_freq;
00087 int interval;
00088 int recent_lateness[TIMER_LATENESS_HISTORY];
00089 int next_lateness;
00090 int total_lateness;
00091 int next_check;
00092 int checks_high;
00093 int checks_low;
00094
00095 event_func *func;
00096 void *data;
00097 };
00098
00099
00100
00101
00102
00103
00104
00222 float Com_GrenadeTarget (const vec3_t from, const vec3_t at, float speed, qboolean launched, qboolean rolled, vec3_t v0)
00223 {
00224 const float rollAngle = 3.0;
00225 vec3_t delta;
00226 float d, h, g, v, alpha, vx, vy;
00227 float k, gd2, len;
00228
00229
00230 h = at[2] - from[2];
00231 VectorSubtract(at, from, delta);
00232 delta[2] = 0;
00233 d = VectorLength(delta);
00234
00235
00236 if (d == 0) {
00237 return 0;
00238 }
00239
00240
00241 g = GRAVITY;
00242 gd2 = g * d * d;
00243 len = sqrt(h * h + d * d);
00244
00245
00246 if (rolled) {
00247 float theta;
00248 alpha = rollAngle * torad;
00249 theta = atan2(d, -h) - 2 * alpha;
00250 k = gd2 / (len * cos(theta) - h);
00251 if (k <= 0)
00252 return 0;
00253 v = sqrt(k);
00254 } else {
00255
00256 v = speed;
00257 k = (v * v * h + gd2) / (v * v * len);
00258
00259
00260 if (launched && k >= -1 && k <= 1) {
00261
00262 alpha = 0.5 * (atan2(d, -h) - acos(k));
00263 } else {
00264
00265 alpha = 0.5 * atan2(d, -h);
00266 v = sqrt(gd2 / (len - h));
00267 }
00268 }
00269
00270
00271 vx = v * cos(alpha);
00272 vy = v * sin(alpha);
00273 VectorNormalize(delta);
00274 VectorScale(delta, vx, v0);
00275 v0[2] = vy;
00276
00277
00278 VectorNormalize(v0);
00279 VectorScale(v0, v - DIST_EPSILON, v0);
00280
00281
00282 return d / vx;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291 static char *rd_buffer;
00292 static unsigned int rd_buffersize;
00293 static struct net_stream *rd_stream;
00294
00301 void Com_BeginRedirect (struct net_stream *stream, char *buffer, int buffersize)
00302 {
00303 if (!buffer || !buffersize)
00304 return;
00305
00306 rd_stream = stream;
00307 rd_buffer = buffer;
00308 if (buffersize > MAXPRINTMSG)
00309 Com_Error(ERR_DROP, "redirect buffer may not be bigger than MAXPRINTMSG (%i)", MAXPRINTMSG);
00310 rd_buffersize = buffersize;
00311 rd_buffer[0] = '\0';
00312 }
00313
00318 void Com_EndRedirect (void)
00319 {
00320 NET_OOB_Printf(rd_stream, "print\n%s", rd_buffer);
00321
00322 rd_stream = NULL;
00323 rd_buffer = NULL;
00324 rd_buffersize = 0;
00325 }
00326
00332 void Com_MakeTimestamp (char* ts, const size_t tslen)
00333 {
00334 struct tm *t;
00335 time_t aclock;
00336
00337 time(&aclock);
00338 t = localtime(&aclock);
00339
00340 Com_sprintf(ts, tslen, "%4i/%02i/%02i %02i:%02i:%02i", t->tm_year + 1900,
00341 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
00342 }
00343
00348 void Com_vPrintf (const char *fmt, va_list ap)
00349 {
00350 char msg[MAXPRINTMSG];
00351
00352 Q_vsnprintf(msg, sizeof(msg), fmt, ap);
00353
00354
00355 if (rd_buffer) {
00356 if ((strlen(msg) + strlen(rd_buffer)) > (rd_buffersize - 1)) {
00357 NET_OOB_Printf(rd_stream, "print\n%s", rd_buffer);
00358 rd_buffer[0] = '\0';
00359 }
00360 Q_strcat(rd_buffer, msg, sizeof(char) * rd_buffersize);
00361 return;
00362 }
00363
00364 Con_Print(msg);
00365
00366
00367 Sys_ConsoleOutput(msg);
00368
00369
00370 if (logfile_active && logfile_active->integer) {
00371 if (!logfile.f) {
00372 const char *name = "ufoconsole.log";
00373 if (logfile_active->integer > 2)
00374 FS_OpenFile(name, &logfile, FILE_APPEND);
00375 else
00376 FS_OpenFile(name, &logfile, FILE_WRITE);
00377 }
00378 if (logfile.f) {
00379
00380 const char *output = msg;
00381
00382
00383 if (!strncmp(output, COLORED_GREEN, strlen(COLORED_GREEN)))
00384 output += strlen(COLORED_GREEN);
00385
00386 if (output[strlen(output) - 1] == '\n') {
00387 char timestamp[40];
00388 Com_MakeTimestamp(timestamp, sizeof(timestamp));
00389 FS_Write(timestamp, strlen(timestamp), &logfile);
00390 }
00391
00392 FS_Write(output, strlen(output), &logfile);
00393
00394 if (logfile_active->integer > 1)
00395 fflush(logfile.f);
00396 }
00397 }
00398 }
00399
00400 void Com_Printf (const char* const fmt, ...)
00401 {
00402 va_list ap;
00403
00404 va_start(ap, fmt);
00405 Com_vPrintf(fmt, ap);
00406 va_end(ap);
00407 }
00408
00412 void Com_DPrintf (int level, const char *fmt, ...)
00413 {
00414
00415 if (!developer)
00416 return;
00417
00418 if (developer->integer == 1 || (developer->integer & level)) {
00419 va_list ap;
00420
00421 va_start(ap, fmt);
00422 Com_vPrintf(fmt, ap);
00423 va_end(ap);
00424 }
00425 }
00426
00431 void Com_Error (int code, const char *fmt, ...)
00432 {
00433 va_list argptr;
00434 static char msg[MAXPRINTMSG];
00435 static qboolean recursive = qfalse;
00436
00437 if (recursive)
00438 Sys_Error("recursive error after: %s", msg);
00439 recursive = qtrue;
00440
00441 va_start(argptr, fmt);
00442 Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
00443 va_end(argptr);
00444
00445 switch (code) {
00446 case ERR_DISCONNECT:
00447 Com_Printf("%s\n", msg);
00448 Cvar_Set("mn_afterdrop", "popup");
00449 CL_Drop();
00450 recursive = qfalse;
00451 Com_Drop();
00452 case ERR_DROP:
00453 Com_Printf("********************\n");
00454 Com_Printf("ERROR: %s\n", msg);
00455 Com_Printf("********************\n");
00456 Sys_Backtrace();
00457 SV_Shutdown("Server crashed.", qfalse);
00458 CL_Drop();
00459 recursive = qfalse;
00460 Com_Drop();
00461 default:
00462 Com_Printf("%s\n", msg);
00463 SV_Shutdown("Server fatal crashed", qfalse);
00464
00465
00466 NET_Wait(0);
00467
00468 FS_CloseFile(&logfile);
00469
00470 CL_Shutdown();
00471 Qcommon_Shutdown();
00472 Sys_Error("Shutdown");
00473 }
00474 }
00475
00476 void Com_Drop (void)
00477 {
00478 longjmp(abortframe, -1);
00479 }
00480
00485 void Com_Quit (void)
00486 {
00487 #ifdef DEDICATED_ONLY
00488 Com_WriteConfigToFile("dedconfig.cfg");
00489 #else
00490 Com_WriteConfigToFile("config.cfg");
00491 #endif
00492
00493 SV_Shutdown("Server quit.", qfalse);
00494 SV_Clear();
00495 CL_Shutdown();
00496
00497
00498 NET_Wait(0);
00499 FS_CloseFile(&logfile);
00500 Sys_Quit();
00501 }
00502
00503
00508 int Com_ServerState (void)
00509 {
00510 return sv.state;
00511 }
00512
00517 void Com_SetServerState (int state)
00518 {
00519 Com_DPrintf(DEBUG_ENGINE, "Set server state to %i\n", state);
00520 if (state == ss_dead)
00521 SV_Shutdown("Server shutdown", qfalse);
00522 else if (state == ss_restart)
00523 SV_Shutdown("Server map change", qtrue);
00524 sv.state = state;
00525 }
00526
00530 unsigned int Com_HashKey (const char *name, int hashsize)
00531 {
00532 int i;
00533 unsigned int v;
00534
00535 v = 0;
00536 for (i = 0; name[i]; i++) {
00537 const unsigned int c = name[i];
00538 v = (v + i) * 37 + tolower(c);
00539 }
00540
00541 return v % hashsize;
00542 }
00543
00547 int Com_Argc (void)
00548 {
00549 return com_argc;
00550 }
00551
00555 const char *Com_Argv (int arg)
00556 {
00557 if (arg < 0 || arg >= com_argc || !com_argv[arg])
00558 return "";
00559 return com_argv[arg];
00560 }
00561
00567 void Com_ClearArgv (int arg)
00568 {
00569 if (arg < 0 || arg >= com_argc || !com_argv[arg])
00570 return;
00571 com_argv[arg] = "";
00572 }
00573
00574
00575 void Com_InitArgv (int argc, const char **argv)
00576 {
00577 int i;
00578
00579 if (argc > MAX_NUM_ARGVS)
00580 Com_Error(ERR_FATAL, "argc > MAX_NUM_ARGVS");
00581 com_argc = argc;
00582 for (i = 0; i < argc; i++) {
00583 if (!argv[i] || strlen(argv[i]) >= MAX_TOKEN_CHARS)
00584 com_argv[i] = "";
00585 else
00586 com_argv[i] = argv[i];
00587 }
00588 }
00589
00590 #define MACRO_CVAR_ID_LENGTH 6
00591
00597 const char *Com_MacroExpandString (const char *text)
00598 {
00599 int i, j, count, len;
00600 qboolean inquote;
00601 const char *scan;
00602 static char expanded[MAX_STRING_CHARS];
00603 const char *token, *start, *cvarvalue;
00604 char *pos;
00605
00606 inquote = qfalse;
00607 scan = text;
00608 if (!text || !*text)
00609 return NULL;
00610
00611 len = strlen(scan);
00612 if (len >= MAX_STRING_CHARS) {
00613 Com_Printf("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
00614 return NULL;
00615 }
00616
00617 count = 0;
00618 memset(expanded, 0, sizeof(expanded));
00619 pos = expanded;
00620
00621
00622 assert(scan[len] == '\0');
00623 for (i = 0; i <= len; i++) {
00624 if (scan[i] == '"')
00625 inquote ^= 1;
00626
00627 if (inquote || strncmp(&scan[i], "*cvar:", MACRO_CVAR_ID_LENGTH)) {
00628 *pos++ = scan[i];
00629 continue;
00630 }
00631
00632
00633 start = &scan[i + MACRO_CVAR_ID_LENGTH];
00634 token = Com_Parse(&start);
00635 if (!start)
00636 continue;
00637
00638
00639 i += MACRO_CVAR_ID_LENGTH;
00640 i += strlen(token);
00641 i--;
00642
00643
00644 cvarvalue = Cvar_GetString(token);
00645 if (!cvarvalue) {
00646 Com_Printf("Could not get cvar value for cvar: %s\n", token);
00647 return NULL;
00648 }
00649
00650 j = strlen(cvarvalue);
00651 if (strlen(pos) + j >= MAX_STRING_CHARS) {
00652 Com_Printf("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
00653 return NULL;
00654 }
00655
00656
00657
00658 Q_strncpyz(pos, cvarvalue, j + 1);
00659 pos += j;
00660
00661 if (++count == 100) {
00662 Com_Printf("Macro expansion loop, discarded.\n");
00663 return NULL;
00664 }
00665 }
00666
00667 if (inquote) {
00668 Com_Printf("Line has unmatched quote, discarded.\n");
00669 return NULL;
00670 }
00671
00672 if (count)
00673 return expanded;
00674 else
00675 return NULL;
00676 }
00677
00689 qboolean Com_ConsoleCompleteCommand (const char *s, char *target, size_t bufSize, int *pos, int offset)
00690 {
00691 const char *cmd = NULL, *cvar = NULL, *use = NULL;
00692 char cmdLine[MAXCMDLINE] = "";
00693 char cmdBase[MAXCMDLINE] = "";
00694 qboolean append = qtrue;
00695 char *tmp;
00696
00697 if (!s[0] || s[0] == ' ')
00698 return qfalse;
00699
00700 else if (s[0] == '\\' || s[0] == '/') {
00701
00702 if (s == target)
00703 offset++;
00704 s++;
00705 }
00706
00707 assert(bufSize <= MAXCMDLINE);
00708 assert(pos);
00709
00710
00711
00712 if (strstr(s, " ")) {
00713 int cntParams;
00714 Q_strncpyz(cmdLine, s, sizeof(cmdLine));
00715
00716 cmdLine[strlen(cmdLine) - 1] = '\0';
00717
00718 tmp = cmdBase;
00719 while (*s != ' ')
00720 *tmp++ = *s++;
00721
00722 s++;
00723
00724 *tmp = '\0';
00725
00726
00727 tmp = strrchr(cmdLine, ' ');
00728 if (tmp)
00729 *tmp = '\0';
00730
00731 cntParams = Cmd_CompleteCommandParameters(cmdBase, s, &cmd);
00732 if (cntParams > 1)
00733 Com_Printf("\n");
00734 if (cmd) {
00735
00736 Q_strcat(cmdLine, " ", sizeof(cmdLine));
00737 Q_strcat(cmdLine, cmd, sizeof(cmdLine));
00738 append = qfalse;
00739 use = cmdLine;
00740 } else
00741 return qfalse;
00742 } else {
00743
00744 static char cmdBackup[MAX_QPATH];
00745 int cntCvar;
00746 int cntCmd = Cmd_CompleteCommand(s, &cmd);
00747 if (cmd)
00748 Q_strncpyz(cmdBackup, cmd, sizeof(cmdBackup));
00749 cntCvar = Cvar_CompleteVariable(s, &cvar);
00750
00751
00752 if (cntCmd > 0 && !cntCvar) {
00753 use = cmd;
00754 if (cntCmd != 1)
00755 append = qfalse;
00756 } else if (!cntCmd && cntCvar > 0) {
00757 use = cvar;
00758 if (cntCvar != 1)
00759 append = qfalse;
00760 } else if (cmd && cvar) {
00761 int maxLength = min(strlen(cmdBackup),strlen(cvar));
00762 int idx = 0;
00763
00764 Q_strncpyz(cmdLine,cmdBackup,sizeof(cmdLine));
00765 for (; idx < maxLength; idx++) {
00766 if (cmdBackup[idx] != cvar[idx]) {
00767 cmdLine[idx] = '\0';
00768 break;
00769 }
00770 }
00771 if (idx == maxLength)
00772 cmdLine[idx] = '\0';
00773 use = cmdLine;
00774 append = qfalse;
00775 }
00776 }
00777
00778 if (use) {
00779 Q_strncpyz(&target[offset], use, bufSize - offset);
00780 *pos = strlen(target);
00781 if (append)
00782 target[(*pos)++] = ' ';
00783 target[*pos] = '\0';
00784
00785 return qtrue;
00786 }
00787
00788 return qfalse;
00789 }
00790
00791 void Com_SetGameType (void)
00792 {
00793 int i;
00794
00795 for (i = 0; i < numGTs; i++) {
00796 const gametype_t *gt = >s[i];
00797 if (!strcmp(gt->id, sv_gametype->string)) {
00798 int j;
00799 const cvarlist_t *list;
00800 if (sv_dedicated->integer)
00801 Com_Printf("set gametype to: %s\n", gt->id);
00802 for (j = 0, list = gt->cvars; j < gt->num_cvars; j++, list++) {
00803 Cvar_Set(list->name, list->value);
00804 if (sv_dedicated->integer)
00805 Com_Printf(" %s = %s\n", list->name, list->value);
00806 }
00807
00808 break;
00809 }
00810 }
00811
00812 if (i == numGTs)
00813 Com_Printf("Can't set the gametype - unknown value for cvar gametype: '%s'\n", sv_gametype->string);
00814 }
00815
00816 static void Com_GameTypeList_f (void)
00817 {
00818 int i;
00819
00820 Com_Printf("Available gametypes:\n");
00821 for (i = 0; i < numGTs; i++) {
00822 int j;
00823 const gametype_t *gt = >s[i];
00824 const cvarlist_t *list;
00825
00826 Com_Printf("%s\n", gt->id);
00827
00828 for (j = 0, list = gt->cvars; j < gt->num_cvars; j++, list++)
00829 Com_Printf(" %s = %s\n", list->name, list->value);
00830 }
00831 }
00832
00833 #ifdef DEBUG
00834
00837 static void Com_DebugHelp_f (void)
00838 {
00839 Cvar_PrintDebugCvars();
00840
00841 Cmd_PrintDebugCommands();
00842 }
00843
00847 static void Com_DebugError_f (void)
00848 {
00849 if (Cmd_Argc() == 3) {
00850 const char *errorType = Cmd_Argv(1);
00851 if (!strcmp(errorType, "ERR_DROP"))
00852 Com_Error(ERR_DROP, "%s", Cmd_Argv(2));
00853 else if (!strcmp(errorType, "ERR_FATAL"))
00854 Com_Error(ERR_FATAL, "%s", Cmd_Argv(2));
00855 else if (!strcmp(errorType, "ERR_DISCONNECT"))
00856 Com_Error(ERR_DISCONNECT, "%s", Cmd_Argv(2));
00857 }
00858 Com_Printf("Usage: %s <ERR_FATAL|ERR_DROP|ERR_DISCONNECT> <msg>\n", Cmd_Argv(0));
00859 }
00860 #endif
00861
00862
00863 typedef struct debugLevel_s {
00864 const char *str;
00865 int debugLevel;
00866 } debugLevel_t;
00867
00868 static const debugLevel_t debugLevels[] = {
00869 {"DEBUG_ALL", DEBUG_ALL},
00870 {"DEBUG_ENGINE", DEBUG_ENGINE},
00871 {"DEBUG_SHARED", DEBUG_SHARED},
00872 {"DEBUG_SYSTEM", DEBUG_SYSTEM},
00873 {"DEBUG_COMMANDS", DEBUG_COMMANDS},
00874 {"DEBUG_CLIENT", DEBUG_CLIENT},
00875 {"DEBUG_EVENTSYS", DEBUG_EVENTSYS},
00876 {"DEBUG_PATHING", DEBUG_PATHING},
00877 {"DEBUG_SERVER", DEBUG_SERVER},
00878 {"DEBUG_GAME", DEBUG_GAME},
00879 {"DEBUG_RENDERER", DEBUG_RENDERER},
00880 {"DEBUG_SOUND", DEBUG_SOUND},
00881
00882 {NULL, 0}
00883 };
00884
00885 static void Com_DeveloperSet_f (void)
00886 {
00887 int oldValue = Cvar_GetInteger("developer");
00888 int newValue = oldValue;
00889 int i = 0;
00890
00891 if (Cmd_Argc() == 2) {
00892 const char *debugLevel = Cmd_Argv(1);
00893 while (debugLevels[i].str) {
00894 if (!strcmp(debugLevel, debugLevels[i].str)) {
00895 if (oldValue & debugLevels[i].debugLevel)
00896 newValue &= ~debugLevels[i].debugLevel;
00897 else
00898 newValue |= debugLevels[i].debugLevel;
00899 break;
00900 }
00901 i++;
00902 }
00903 if (!debugLevels[i].str) {
00904 Com_Printf("No valid debug mode parameter\n");
00905 return;
00906 }
00907 Cvar_SetValue("developer", newValue);
00908 Com_Printf("Currently selected debug print levels\n");
00909 i = 0;
00910 while (debugLevels[i].str) {
00911 if (newValue & debugLevels[i].debugLevel)
00912 Com_Printf("* %s\n", debugLevels[i].str);
00913 i++;
00914 }
00915 } else {
00916 Com_Printf("Usage: %s <debug_level>\n", Cmd_Argv(0));
00917 Com_Printf(" valid debug_levels are:\n");
00918 while (debugLevels[i].str) {
00919 Com_Printf(" * %s\n", debugLevels[i].str);
00920 i++;
00921 }
00922 }
00923 }
00924
00925 #ifndef DEDICATED_ONLY
00926
00929 static qboolean Com_CvarCheckMaxFPS (cvar_t *cvar)
00930 {
00931
00932 return Cvar_AssertValue(cvar, 10, 1000, qtrue);
00933 }
00934 #endif
00935
00939 void Com_WriteConfigToFile (const char *filename)
00940 {
00941 qFILE f;
00942
00943 FS_OpenFile(filename, &f, FILE_WRITE);
00944 if (!f.f) {
00945 Com_Printf("Couldn't write %s.\n", filename);
00946 return;
00947 }
00948
00949 FS_Printf(&f, "// generated by ufo, do not modify\n");
00950 FS_Printf(&f, "// variables\n");
00951 Cvar_WriteVariables(&f);
00952 FS_Printf(&f, "// aliases\n");
00953 Cmd_WriteAliases(&f);
00954 FS_CloseFile(&f);
00955 Com_Printf("Wrote %s.\n", filename);
00956 }
00957
00958
00962 static void Com_WriteConfig_f (void)
00963 {
00964 char filename[MAX_QPATH];
00965
00966 if (Cmd_Argc() != 2) {
00967 Com_Printf("Usage: %s <filename>\n", Cmd_Argv(0));
00968 return;
00969 }
00970
00971 Q_strncpyz(filename, Cmd_Argv(1), sizeof(filename));
00972 Com_DefaultExtension(filename, sizeof(filename), ".cfg");
00973 Com_WriteConfigToFile(filename);
00974 }
00975
00976 static void Cbuf_Execute_timer (int now, void *data)
00977 {
00978 Cbuf_Execute();
00979 }
00980
00988 void Qcommon_Init (int argc, const char **argv)
00989 {
00990 char *s;
00991
00992 Sys_InitSignals();
00993
00994
00995 srand(time(NULL));
00996
00997 com_aliasSysPool = Mem_CreatePool("Common: Alias system for commands and enums");
00998 com_cmdSysPool = Mem_CreatePool("Common: Command system");
00999 com_cmodelSysPool = Mem_CreatePool("Common: Collision model");
01000 com_cvarSysPool = Mem_CreatePool("Common: Cvar system");
01001 com_fileSysPool = Mem_CreatePool("Common: File system");
01002 com_genericPool = Mem_CreatePool("Generic");
01003 com_networkPool = Mem_CreatePool("Network");
01004
01005 if (setjmp(abortframe))
01006 Sys_Error("Error during initialization");
01007
01008 memset(&csi, 0, sizeof(csi));
01009
01010
01011
01012 Com_InitArgv(argc, argv);
01013
01014 Swap_Init();
01015 Cbuf_Init();
01016
01017 Cmd_Init();
01018 Cvar_Init();
01019
01020 Key_Init();
01021
01022
01023
01024
01025
01026 Cbuf_AddEarlyCommands(qfalse);
01027 Cbuf_Execute();
01028
01029 FS_InitFilesystem(qtrue);
01030
01031 Cbuf_AddText("exec default.cfg\n");
01032 #ifdef DEDICATED_ONLY
01033 Cbuf_AddText("exec dedconfig.cfg\n");
01034 #else
01035 Cbuf_AddText("exec config.cfg\n");
01036 #endif
01037
01038 Cbuf_AddEarlyCommands(qtrue);
01039 Cbuf_Execute();
01040
01041 Com_SetRenderModified(qfalse);
01042 Com_SetUserinfoModified(qfalse);
01043
01044
01045 Cmd_AddCommand("saveconfig", Com_WriteConfig_f, "Write the configuration to file");
01046 Cmd_AddCommand("gametypelist", Com_GameTypeList_f, "List all available multiplayer game types");
01047 #ifdef DEBUG
01048 Cmd_AddCommand("debug_help", Com_DebugHelp_f, "Show some debugging help");
01049 Cmd_AddCommand("debug_error", Com_DebugError_f, "Just throw a fatal error to test error shutdown procedures");
01050 #endif
01051 Cmd_AddCommand("setdeveloper", Com_DeveloperSet_f, "Set the developer cvar to only get the debug output you want");
01052
01053 developer = Cvar_Get("developer", "0", 0, "Activate developer output to logfile and gameconsole");
01054 logfile_active = Cvar_Get("logfile", "1", 0, "0 = deactivate logfile, 1 = write normal logfile, 2 = flush on every new line, 3 = always append to existing file");
01055 sv_gametype = Cvar_Get("sv_gametype", "1on1", CVAR_ARCHIVE | CVAR_SERVERINFO, "Sets the multiplayer gametype - see gametypelist command for a list of all gametypes");
01056 http_proxy = Cvar_Get("http_proxy", "", CVAR_ARCHIVE, "Use this proxy for http transfers");
01057 http_timeout = Cvar_Get("http_timeout", "3", CVAR_ARCHIVE, "Http connection timeout");
01058 port = Cvar_Get("port", DOUBLEQUOTE(PORT_SERVER), CVAR_NOSET, NULL);
01059 masterserver_url = Cvar_Get("masterserver_url", MASTER_SERVER, CVAR_ARCHIVE, "URL of UFO:AI masterserver");
01060 #ifdef DEDICATED_ONLY
01061 sv_dedicated = Cvar_Get("sv_dedicated", "1", CVAR_SERVERINFO | CVAR_NOSET, "Is this a dedicated server?");
01062
01063 Cvar_ForceSet("sv_dedicated", "1");
01064 #else
01065 sv_dedicated = Cvar_Get("sv_dedicated", "0", CVAR_SERVERINFO | CVAR_NOSET, "Is this a dedicated server?");
01066
01067
01068 sv_gametype->modified = qfalse;
01069
01070 s_language = Cvar_Get("s_language", "", CVAR_ARCHIVE, "Game language - full language string e.g. en_EN.UTF-8");
01071 s_language->modified = qfalse;
01072 cl_maxfps = Cvar_Get("cl_maxfps", "50", CVAR_ARCHIVE, NULL);
01073 Cvar_SetCheckFunction("cl_maxfps", Com_CvarCheckMaxFPS);
01074 #endif
01075
01076 s = va("UFO: Alien Invasion %s %s %s %s", UFO_VERSION, CPUSTRING, __DATE__, BUILDSTRING);
01077 Cvar_Get("version", s, CVAR_NOSET, "Full version string");
01078 Cvar_Get("ver", UFO_VERSION, CVAR_SERVERINFO | CVAR_NOSET, "Version number");
01079
01080 if (sv_dedicated->integer)
01081 Cmd_AddCommand("quit", Com_Quit, "Quits the game");
01082
01083 Mem_Init();
01084 Sys_Init();
01085
01086 NET_Init();
01087
01088 curl_global_init(CURL_GLOBAL_NOTHING);
01089 Com_Printf("%s initialized.\n", curl_version());
01090
01091 SV_Init();
01092
01093
01094 CL_Init();
01095
01096 Com_ParseScripts(sv_dedicated->integer);
01097 #ifndef DEDICATED_ONLY
01098 Cbuf_AddText("exec keys.cfg\n");
01099 #endif
01100
01101 if (!sv_dedicated->integer)
01102 Cbuf_AddText("init\n");
01103 else
01104 Cbuf_AddText("dedicated_start\n");
01105 Cbuf_Execute();
01106
01107 FS_ExecAutoexec();
01108
01109
01110
01111 if (Cbuf_AddLateCommands()) {
01112
01113
01114 SCR_EndLoadingPlaque();
01115 }
01116
01117 CL_InitAfter();
01118
01119
01120 Mem_CheckGlobalIntegrity();
01121
01122
01123 Mem_TouchGlobal();
01124
01125 #ifndef DEDICATED_ONLY
01126 if (!sv_dedicated->integer) {
01127 Schedule_Timer(cl_maxfps, &CL_Frame, NULL);
01128 Schedule_Timer(Cvar_Get("cl_slowfreq", "10", 0, NULL), &CL_SlowFrame, NULL);
01129
01130
01131 Sys_ShowConsole(qfalse);
01132 }
01133 #endif
01134
01135 Schedule_Timer(Cvar_Get("sv_freq", "10", CVAR_NOSET, NULL), &SV_Frame, NULL);
01136
01138 Schedule_Timer(Cvar_Get("cbuf_freq", "10", 0, NULL), &Cbuf_Execute_timer, NULL);
01139
01140 Com_Printf("====== UFO Initialized ======\n");
01141 Com_Printf("=============================\n");
01142 }
01143
01144 static void tick_timer (int now, void *data)
01145 {
01146 struct timer *timer = data;
01147 int old_interval = timer->interval;
01148
01149
01150 const int lateness = Sys_Milliseconds() - now;
01151 timer->total_lateness -= timer->recent_lateness[timer->next_lateness];
01152 timer->recent_lateness[timer->next_lateness] = lateness;
01153 timer->total_lateness += lateness;
01154 timer->next_lateness++;
01155 timer->next_lateness %= TIMER_LATENESS_HISTORY;
01156
01157
01158 timer->next_check--;
01159 if (timer->next_check <= 0) {
01160 const int mean = timer->total_lateness / TIMER_LATENESS_HISTORY;
01161
01162
01163
01164
01165 if (mean > TIMER_LATENESS_HIGH)
01166 timer->checks_high = min(TIMER_CHECK_LAG, timer->checks_high + 1);
01167 else
01168 timer->checks_high = max(0, timer->checks_high - 1);
01169
01170 if (timer->checks_high > TIMER_CHECK_LAG)
01171 timer->interval += 2;
01172
01173
01174 if (mean < TIMER_LATENESS_LOW)
01175 timer->checks_low = min(TIMER_CHECK_LAG, timer->checks_high + 1);
01176 else
01177 timer->checks_low = max(0, timer->checks_low - 1);
01178
01179 if (timer->checks_low > TIMER_CHECK_LAG)
01180 timer->interval -= 1;
01181
01182
01183
01184
01185
01186 timer->next_check = TIMER_CHECK_INTERVAL;
01187 }
01188
01189 timer->interval = max(timer->interval, 1000 / timer->min_freq->integer);
01190
01191 if (timer->interval != old_interval)
01192 Com_DPrintf(DEBUG_ENGINE, "Adjusted timer on %s to interval %d\n", timer->min_freq->name, timer->interval);
01193
01194 if (setjmp(abortframe) == 0)
01195 timer->func(now, timer->data);
01196
01197
01198
01199
01200 Schedule_Event(now + lateness + timer->interval, &tick_timer, NULL, NULL, timer);
01201 }
01202
01203 void Schedule_Timer (cvar_t *freq, event_func *func, void *data)
01204 {
01205 struct timer *timer = Mem_PoolAlloc(sizeof(*timer), com_genericPool, 0);
01206 int i;
01207 timer->min_freq = freq;
01208 timer->interval = 1000 / freq->integer;
01209 timer->next_lateness = 0;
01210 timer->total_lateness = 0;
01211 timer->next_check = TIMER_CHECK_INTERVAL;
01212 timer->checks_high = 0;
01213 timer->checks_low = 0;
01214 timer->func = func;
01215 timer->data = data;
01216 for (i = 0; i < TIMER_LATENESS_HISTORY; i++)
01217 timer->recent_lateness[i] = 0;
01218
01219 Schedule_Event(Sys_Milliseconds() + timer->interval, &tick_timer, NULL, NULL, timer);
01220 }
01221
01233 void Schedule_Event (int when, event_func *func, event_check_func *check, event_clean_func *clean, void *data)
01234 {
01235 struct event *event = Mem_PoolAlloc(sizeof(*event), com_genericPool, 0);
01236 event->when = when;
01237 event->func = func;
01238 event->check = check;
01239 event->clean = clean;
01240 event->data = data;
01241
01242 if (!event_queue || event_queue->when > when) {
01243 event->next = event_queue;
01244 event_queue = event;
01245 } else {
01246 struct event *e = event_queue;
01247 while (e->next && e->next->when <= when)
01248 e = e->next;
01249 event->next = e->next;
01250 e->next = event;
01251 }
01252
01253 #ifdef DEBUG
01254 for (event = event_queue; event && event->next; event = event->next)
01255 if (event->when > event->next->when)
01256 abort();
01257 #endif
01258 }
01259
01265 static struct event* Dequeue_Event (int now)
01266 {
01267 struct event *event = event_queue;
01268 struct event *prev = NULL;
01269
01270 while (event && event->when <= now) {
01271 if (event->check == NULL || event->check(now, event->data)) {
01272 if (prev) {
01273 prev->next = event->next;
01274 } else {
01275 event_queue = event->next;
01276 }
01277 return event;
01278 }
01279 prev = event;
01280 event = event->next;
01281 }
01282 return NULL;
01283 }
01284
01291 void CL_FilterEventQueue (event_filter *filter)
01292 {
01293 struct event *event = event_queue;
01294 struct event *prev = NULL;
01295
01296 assert(filter);
01297
01298 while (event) {
01299 qboolean keep = filter(event->when, event->func, event->check, event->data);
01300 struct event *freeme = event;
01301
01302 if (keep) {
01303 prev = event;
01304 event = event->next;
01305 continue;
01306 }
01307
01308
01309 if (prev) {
01310 event = prev->next = event->next;
01311 } else {
01312 event = event_queue = event->next;
01313 }
01314 if (freeme->clean != NULL)
01315 freeme->clean(freeme->data);
01316 Mem_Free(freeme);
01317 }
01318 }
01319
01328 void Qcommon_Frame (void)
01329 {
01330 int time_to_next;
01331 struct event *event;
01332
01333
01334 if (setjmp(abortframe))
01335 return;
01336
01337
01338 event = Dequeue_Event(Sys_Milliseconds());
01339 if (event) {
01340 if (setjmp(abortframe)) {
01341 Mem_Free(event);
01342 return;
01343 }
01344
01345
01346 event->func(event->when, event->data);
01347
01348 if (setjmp(abortframe))
01349 return;
01350
01351 Mem_Free(event);
01352 }
01353
01354
01355
01356
01357 do {
01358 time_to_next = event_queue ? (event_queue->when - Sys_Milliseconds()) : 1000;
01359 if (time_to_next < 0)
01360 time_to_next = 0;
01361
01362 NET_Wait(time_to_next);
01363 } while (time_to_next > 0);
01364 }
01365
01373 void Qcommon_Shutdown (void)
01374 {
01375 HTTP_Cleanup();
01376
01377 FS_Shutdown();
01378 Cvar_Shutdown();
01379 Cmd_Shutdown();
01380 Mem_Shutdown();
01381 }