common.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663
  1. // common.c -- misc functions used in client and server
  2. #include "../game/q_shared.h"
  3. #include "qcommon.h"
  4. #include "../qcommon/sstring.h" // to get Gil's string class, because MS's doesn't compile properly in here
  5. #include "stv_version.h"
  6. #ifdef _XBOX
  7. #include "../win32/win_file.h"
  8. #include "../ui/ui_splash.h"
  9. #endif
  10. #include "platform.h"
  11. #define MAXPRINTMSG 4096
  12. #define MAX_NUM_ARGVS 50
  13. int com_argc;
  14. char *com_argv[MAX_NUM_ARGVS+1];
  15. #ifndef _XBOX
  16. static fileHandle_t logfile;
  17. static fileHandle_t speedslog;
  18. static fileHandle_t camerafile;
  19. fileHandle_t com_journalFile;
  20. fileHandle_t com_journalDataFile; // config files are written here
  21. #endif
  22. // Global language setting - this should be used instead of the myriad language
  23. // cvars. Will be one of the Xbox values: XC_LANGUAGE_(ENGLISH|FRENCH|GERMAN)
  24. DWORD g_dwLanguage;
  25. cvar_t *com_viewlog;
  26. cvar_t *com_speeds;
  27. cvar_t *com_developer;
  28. cvar_t *com_timescale;
  29. cvar_t *com_fixedtime;
  30. cvar_t *com_maxfps;
  31. cvar_t *com_sv_running;
  32. cvar_t *com_cl_running;
  33. cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print
  34. cvar_t *com_showtrace;
  35. cvar_t *com_terrainPhysics;
  36. cvar_t *com_version;
  37. cvar_t *com_buildScript; // for automated data building scripts
  38. cvar_t *cl_paused;
  39. cvar_t *sv_paused;
  40. cvar_t *com_skippingcin;
  41. cvar_t *com_speedslog; // 1 = buffer log, 2 = flush after each print
  42. extern cvar_t *inSplashMenu;
  43. extern cvar_t *controllerOut;
  44. #ifdef G2_PERFORMANCE_ANALYSIS
  45. cvar_t *com_G2Report;
  46. #endif
  47. // com_speeds times
  48. int time_game;
  49. int time_frontend; // renderer frontend time
  50. int time_backend; // renderer backend time
  51. int timeInTrace;
  52. int timeInPVSCheck;
  53. int numTraces;
  54. int com_frameTime;
  55. int com_frameMsec;
  56. int com_frameNumber = 0;
  57. qboolean com_errorEntered;
  58. qboolean com_fullyInitialized = qfalse;
  59. char com_errorMessage[MAXPRINTMSG];
  60. void Com_WriteConfig_f( void );
  61. //============================================================================
  62. #ifndef _XBOX
  63. static char *rd_buffer;
  64. static int rd_buffersize;
  65. static void (*rd_flush)( char *buffer );
  66. void Com_BeginRedirect (char *buffer, int buffersize, void (*flush)( char *) )
  67. {
  68. if (!buffer || !buffersize || !flush)
  69. return;
  70. rd_buffer = buffer;
  71. rd_buffersize = buffersize;
  72. rd_flush = flush;
  73. *rd_buffer = 0;
  74. }
  75. void Com_EndRedirect (void)
  76. {
  77. if ( rd_flush ) {
  78. rd_flush(rd_buffer);
  79. }
  80. rd_buffer = NULL;
  81. rd_buffersize = 0;
  82. rd_flush = NULL;
  83. }
  84. #ifndef FINAL_BUILD
  85. #define OUTPUT_TO_BUILD_WINDOW
  86. #endif
  87. #endif //not xbox
  88. /*
  89. =============
  90. Com_Printf
  91. Both client and server can use this, and it will output
  92. to the apropriate place.
  93. A raw string should NEVER be passed as fmt, because of "%f" type crashers.
  94. =============
  95. */
  96. void QDECL Com_Printf( const char *fmt, ... ) {
  97. #ifndef FINAL_BUILD
  98. va_list argptr;
  99. char msg[MAXPRINTMSG];
  100. va_start (argptr,fmt);
  101. vsprintf (msg,fmt,argptr);
  102. va_end (argptr);
  103. #ifndef _XBOX
  104. if ( rd_buffer ) {
  105. if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1)) {
  106. rd_flush(rd_buffer);
  107. *rd_buffer = 0;
  108. }
  109. strcat (rd_buffer, msg);
  110. return;
  111. }
  112. #endif
  113. CL_ConsolePrint( msg );
  114. // echo to dedicated console and early console
  115. Sys_Print( msg );
  116. #ifdef OUTPUT_TO_BUILD_WINDOW
  117. OutputDebugString(msg);
  118. #endif
  119. #ifndef _XBOX
  120. // logfile
  121. if ( com_logfile && com_logfile->integer ) {
  122. if ( !logfile ) {
  123. logfile = FS_FOpenFileWrite( "qconsole.log" );
  124. if ( com_logfile->integer > 1 ) {
  125. // force it to not buffer so we get valid
  126. // data even if we are crashing
  127. FS_ForceFlush(logfile);
  128. }
  129. }
  130. if ( logfile ) {
  131. FS_Write(msg, strlen(msg), logfile);
  132. }
  133. }
  134. #endif
  135. #endif
  136. }
  137. void QDECL Com_PrintfAlways( const char *fmt, ... ) {
  138. va_list argptr;
  139. char msg[MAXPRINTMSG];
  140. va_start (argptr,fmt);
  141. vsprintf (msg,fmt,argptr);
  142. va_end (argptr);
  143. #ifndef _XBOX
  144. if ( rd_buffer ) {
  145. if ((strlen (msg) + strlen(rd_buffer)) > (rd_buffersize - 1)) {
  146. rd_flush(rd_buffer);
  147. *rd_buffer = 0;
  148. }
  149. strcat (rd_buffer, msg);
  150. return;
  151. }
  152. #endif
  153. CL_ConsolePrint( msg );
  154. // echo to dedicated console and early console
  155. #ifndef FINAL_BUILD
  156. Sys_Print( msg );
  157. #ifdef OUTPUT_TO_BUILD_WINDOW
  158. OutputDebugString(msg);
  159. #endif
  160. #endif
  161. #ifndef _XBOX
  162. // logfile
  163. if ( com_logfile && com_logfile->integer ) {
  164. if ( !logfile ) {
  165. logfile = FS_FOpenFileWrite( "qconsole.log" );
  166. if ( com_logfile->integer > 1 ) {
  167. // force it to not buffer so we get valid
  168. // data even if we are crashing
  169. FS_ForceFlush(logfile);
  170. }
  171. }
  172. if ( logfile ) {
  173. FS_Write(msg, strlen(msg), logfile);
  174. }
  175. }
  176. #endif
  177. }
  178. /*
  179. ================
  180. Com_DPrintf
  181. A Com_Printf that only shows up if the "developer" cvar is set
  182. ================
  183. */
  184. void QDECL Com_DPrintf( const char *fmt, ...) {
  185. va_list argptr;
  186. char msg[MAXPRINTMSG];
  187. if ( !com_developer || !com_developer->integer ) {
  188. return; // don't confuse non-developers with techie stuff...
  189. }
  190. va_start (argptr,fmt);
  191. vsprintf (msg,fmt,argptr);
  192. va_end (argptr);
  193. Com_Printf ("%s", msg);
  194. }
  195. void Com_WriteCam ( const char *text )
  196. {
  197. #ifndef _XBOX
  198. static char mapname[MAX_QPATH];
  199. // camerafile
  200. if ( !camerafile )
  201. {
  202. extern cvar_t *sv_mapname;
  203. //NOTE: always saves in working dir if using one...
  204. sprintf( mapname, "maps/%s_cam.map", sv_mapname->string );
  205. camerafile = FS_FOpenFileWrite( mapname );
  206. }
  207. if ( camerafile )
  208. {
  209. FS_Printf( camerafile, "%s", text );
  210. }
  211. Com_Printf( "%s\n", mapname );
  212. #endif
  213. }
  214. void Com_FlushCamFile()
  215. {
  216. #ifndef _XBOX
  217. if (!camerafile)
  218. {
  219. // nothing to flush, right?
  220. Com_Printf("No cam file available\n");
  221. return;
  222. }
  223. FS_ForceFlush(camerafile);
  224. FS_FCloseFile (camerafile);
  225. camerafile = 0;
  226. static char flushedMapname[MAX_QPATH];
  227. extern cvar_t *sv_mapname;
  228. sprintf( flushedMapname, "maps/%s_cam.map", sv_mapname->string );
  229. Com_Printf("flushed all cams to %s\n", flushedMapname);
  230. #endif
  231. }
  232. /*
  233. =============
  234. Com_Error
  235. Both client and server can use this, and it will
  236. do the apropriate things.
  237. =============
  238. */
  239. void SG_WipeSavegame(const char *name); // pretty sucky, but that's how SoF did it...<g>
  240. void SG_Shutdown();
  241. //void SCR_UnprecacheScreenshot();
  242. void QDECL Com_Error( int code, const char *fmt, ... ) {
  243. va_list argptr;
  244. #if defined(_WIN32) && defined(_DEBUG)
  245. if ( code != ERR_DISCONNECT && code != ERR_NEED_CD ) {
  246. // if (com_noErrorInterrupt && !com_noErrorInterrupt->integer)
  247. {
  248. __asm {
  249. int 0x03
  250. }
  251. }
  252. }
  253. #endif
  254. // when we are running automated scripts, make sure we
  255. // know if anything failed
  256. if ( com_buildScript && com_buildScript->integer ) {
  257. code = ERR_FATAL;
  258. }
  259. if ( com_errorEntered ) {
  260. Sys_Error( "recursive error after: %s", com_errorMessage );
  261. }
  262. com_errorEntered = qtrue;
  263. //reset some game stuff here
  264. // SCR_UnprecacheScreenshot();
  265. va_start (argptr,fmt);
  266. vsprintf (com_errorMessage,fmt,argptr);
  267. va_end (argptr);
  268. if ( code != ERR_DISCONNECT ) {
  269. Cvar_Get("com_errorMessage", "", CVAR_ROM); //give com_errorMessage a default so it won't come back to life after a resetDefaults
  270. Cvar_Set("com_errorMessage", com_errorMessage);
  271. }
  272. SG_Shutdown(); // close any file pointers
  273. if ( code == ERR_DISCONNECT ) {
  274. SV_Shutdown("Disconnect");
  275. CL_Disconnect();
  276. CL_FlushMemory();
  277. CL_StartHunkUsers();
  278. com_errorEntered = qfalse;
  279. throw ("DISCONNECTED\n");
  280. } else if ( code == ERR_DROP ) {
  281. // If loading/saving caused the crash/error - delete the temp file
  282. // SG_WipeSavegame("current"); // delete file
  283. SV_Shutdown (va("Server crashed: %s\n", com_errorMessage));
  284. CL_Disconnect();
  285. CL_FlushMemory();
  286. CL_StartHunkUsers();
  287. Com_Printf (S_COLOR_RED"********************\n"S_COLOR_MAGENTA"ERROR: %s\n"S_COLOR_RED"********************\n", com_errorMessage);
  288. com_errorEntered = qfalse;
  289. throw ("DROPPED\n");
  290. } else if ( code == ERR_NEED_CD ) {
  291. SV_Shutdown( "Server didn't have CD\n" );
  292. if ( com_cl_running && com_cl_running->integer ) {
  293. CL_Disconnect();
  294. CL_FlushMemory();
  295. CL_StartHunkUsers();
  296. com_errorEntered = qfalse;
  297. } else {
  298. Com_Printf("Server didn't have CD\n" );
  299. }
  300. throw ("NEED CD\n");
  301. } else {
  302. CL_Shutdown ();
  303. SV_Shutdown (va(S_COLOR_RED"Server fatal crashed: %s\n", com_errorMessage));
  304. }
  305. Com_Shutdown ();
  306. Sys_Error ("%s", com_errorMessage);
  307. }
  308. /*
  309. =============
  310. Com_Quit_f
  311. Both client and server can use this, and it will
  312. do the apropriate things.
  313. =============
  314. */
  315. void Com_Quit_f( void ) {
  316. // don't try to shutdown if we are in a recursive error
  317. if ( !com_errorEntered ) {
  318. SV_Shutdown ("Server quit\n");
  319. CL_Shutdown ();
  320. Com_Shutdown ();
  321. }
  322. Sys_Quit ();
  323. }
  324. /*
  325. ============================================================================
  326. COMMAND LINE FUNCTIONS
  327. + characters seperate the commandLine string into multiple console
  328. command lines.
  329. All of these are valid:
  330. quake3 +set test blah +map test
  331. quake3 set test blah+map test
  332. quake3 set test blah + map test
  333. ============================================================================
  334. */
  335. #define MAX_CONSOLE_LINES 32
  336. int com_numConsoleLines;
  337. char *com_consoleLines[MAX_CONSOLE_LINES];
  338. /*
  339. ==================
  340. Com_ParseCommandLine
  341. Break it up into multiple console lines
  342. ==================
  343. */
  344. void Com_ParseCommandLine( char *commandLine ) {
  345. com_consoleLines[0] = commandLine;
  346. com_numConsoleLines = 1;
  347. while ( *commandLine ) {
  348. // look for a + seperating character
  349. // if commandLine came from a file, we might have real line seperators
  350. if ( *commandLine == '+' || *commandLine == '\n' ) {
  351. if ( com_numConsoleLines == MAX_CONSOLE_LINES ) {
  352. return;
  353. }
  354. com_consoleLines[com_numConsoleLines] = commandLine + 1;
  355. com_numConsoleLines++;
  356. *commandLine = 0;
  357. }
  358. commandLine++;
  359. }
  360. }
  361. /*
  362. ===================
  363. Com_SafeMode
  364. Check for "safe" on the command line, which will
  365. skip loading of jaconfig.cfg
  366. ===================
  367. */
  368. qboolean Com_SafeMode( void ) {
  369. int i;
  370. for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
  371. Cmd_TokenizeString( com_consoleLines[i] );
  372. if ( !Q_stricmp( Cmd_Argv(0), "safe" )
  373. || !Q_stricmp( Cmd_Argv(0), "cvar_restart" ) ) {
  374. com_consoleLines[i][0] = 0;
  375. return qtrue;
  376. }
  377. }
  378. return qfalse;
  379. }
  380. /*
  381. ===============
  382. Com_StartupVariable
  383. Searches for command line parameters that are set commands.
  384. If match is not NULL, only that cvar will be looked for.
  385. That is necessary because cddir and basedir need to be set
  386. before the filesystem is started, but all other sets should
  387. be after execing the config and default.
  388. ===============
  389. */
  390. void Com_StartupVariable( const char *match ) {
  391. int i;
  392. char *s;
  393. cvar_t *cv;
  394. for (i=0 ; i < com_numConsoleLines ; i++) {
  395. Cmd_TokenizeString( com_consoleLines[i] );
  396. if ( strcmp( Cmd_Argv(0), "set" ) ) {
  397. continue;
  398. }
  399. s = Cmd_Argv(1);
  400. if ( !match || !stricmp( s, match ) ) {
  401. Cvar_Set( s, Cmd_Argv(2) );
  402. cv = Cvar_Get( s, "", 0 );
  403. cv->flags |= CVAR_USER_CREATED;
  404. // com_consoleLines[i] = 0;
  405. }
  406. }
  407. }
  408. /*
  409. =================
  410. Com_AddStartupCommands
  411. Adds command line parameters as script statements
  412. Commands are seperated by + signs
  413. Returns qtrue if any late commands were added, which
  414. will keep the demoloop from immediately starting
  415. =================
  416. */
  417. qboolean Com_AddStartupCommands( void ) {
  418. int i;
  419. qboolean added;
  420. added = qfalse;
  421. // quote every token, so args with semicolons can work
  422. for (i=0 ; i < com_numConsoleLines ; i++) {
  423. if ( !com_consoleLines[i] || !com_consoleLines[i][0] ) {
  424. continue;
  425. }
  426. // set commands won't override menu startup
  427. if ( Q_stricmpn( com_consoleLines[i], "set", 3 ) ) {
  428. added = qtrue;
  429. }
  430. Cbuf_AddText( com_consoleLines[i] );
  431. Cbuf_AddText( "\n" );
  432. }
  433. return added;
  434. }
  435. //============================================================================
  436. void Info_Print( const char *s ) {
  437. char key[512];
  438. char value[512];
  439. char *o;
  440. int l;
  441. if (*s == '\\')
  442. s++;
  443. while (*s)
  444. {
  445. o = key;
  446. while (*s && *s != '\\')
  447. *o++ = *s++;
  448. l = o - key;
  449. if (l < 20)
  450. {
  451. memset (o, ' ', 20-l);
  452. key[20] = 0;
  453. }
  454. else
  455. *o = 0;
  456. Com_Printf ("%s", key);
  457. if (!*s)
  458. {
  459. Com_Printf ("MISSING VALUE\n");
  460. return;
  461. }
  462. o = value;
  463. s++;
  464. while (*s && *s != '\\')
  465. *o++ = *s++;
  466. *o = 0;
  467. if (*s)
  468. s++;
  469. Com_Printf ("%s\n", value);
  470. }
  471. }
  472. /*
  473. ============
  474. Com_StringContains
  475. ============
  476. */
  477. char *Com_StringContains(char *str1, char *str2, int casesensitive) {
  478. int len, i, j;
  479. len = strlen(str1) - strlen(str2);
  480. for (i = 0; i <= len; i++, str1++) {
  481. for (j = 0; str2[j]; j++) {
  482. if (casesensitive) {
  483. if (str1[j] != str2[j]) {
  484. break;
  485. }
  486. }
  487. else {
  488. if (toupper(str1[j]) != toupper(str2[j])) {
  489. break;
  490. }
  491. }
  492. }
  493. if (!str2[j]) {
  494. return str1;
  495. }
  496. }
  497. return NULL;
  498. }
  499. /*
  500. ============
  501. Com_Filter
  502. ============
  503. */
  504. int Com_Filter(char *filter, char *name, int casesensitive) {
  505. char buf[MAX_TOKEN_CHARS];
  506. char *ptr;
  507. int i;
  508. while(*filter) {
  509. if (*filter == '*') {
  510. filter++;
  511. for (i = 0; *filter; i++) {
  512. if (*filter == '*' || *filter == '?') {
  513. break;
  514. }
  515. buf[i] = *filter;
  516. filter++;
  517. }
  518. buf[i] = '\0';
  519. if (strlen(buf)) {
  520. ptr = Com_StringContains(name, buf, casesensitive);
  521. if (!ptr) {
  522. return qfalse;
  523. }
  524. name = ptr + strlen(buf);
  525. }
  526. }
  527. else if (*filter == '?') {
  528. filter++;
  529. name++;
  530. }
  531. else {
  532. if (casesensitive) {
  533. if (*filter != *name) {
  534. return qfalse;
  535. }
  536. }
  537. else {
  538. if (toupper(*filter) != toupper(*name)) {
  539. return qfalse;
  540. }
  541. }
  542. filter++;
  543. name++;
  544. }
  545. }
  546. return qtrue;
  547. }
  548. /*
  549. =================
  550. Com_InitHunkMemory
  551. =================
  552. */
  553. void Com_InitHunkMemory( void )
  554. {
  555. Hunk_Clear();
  556. // Cmd_AddCommand( "meminfo", Z_Details_f );
  557. }
  558. // I'm leaving this in just in case we ever need to remember where's a good place to hook something like this in.
  559. //
  560. void Com_ShutdownHunkMemory(void)
  561. {
  562. }
  563. /*
  564. ===================
  565. Hunk_SetMark
  566. The server calls this after the level and game VM have been loaded
  567. ===================
  568. */
  569. void Hunk_SetMark( void )
  570. {
  571. }
  572. /*
  573. =================
  574. Hunk_ClearToMark
  575. The client calls this before starting a vid_restart or snd_restart
  576. =================
  577. */
  578. void Hunk_ClearToMark( void )
  579. {
  580. Z_TagFree(TAG_HUNKALLOC);
  581. // Z_TagFree(TAG_HUNKMISCMODELS);
  582. }
  583. /*
  584. =================
  585. Hunk_Clear
  586. The server calls this before shutting down or loading a new map
  587. =================
  588. */
  589. void Hunk_Clear( void )
  590. {
  591. Z_TagFree(TAG_HUNKALLOC);
  592. // Z_TagFree(TAG_HUNKMISCMODELS);
  593. extern void CIN_CloseAllVideos();
  594. CIN_CloseAllVideos();
  595. extern void R_ClearStuffToStopGhoul2CrashingThings(void);
  596. R_ClearStuffToStopGhoul2CrashingThings();
  597. }
  598. /*
  599. ===================================================================
  600. EVENTS AND JOURNALING
  601. In addition to these events, .cfg files are also copied to the
  602. journaled file
  603. ===================================================================
  604. */
  605. #define MAX_PUSHED_EVENTS 64
  606. int com_pushedEventsHead, com_pushedEventsTail;
  607. sysEvent_t com_pushedEvents[MAX_PUSHED_EVENTS];
  608. /*
  609. =================
  610. Com_GetRealEvent
  611. =================
  612. */
  613. sysEvent_t Com_GetRealEvent( void ) {
  614. sysEvent_t ev;
  615. // get an event from the system
  616. ev = Sys_GetEvent();
  617. return ev;
  618. }
  619. /*
  620. =================
  621. Com_PushEvent
  622. =================
  623. */
  624. void Com_PushEvent( sysEvent_t *event ) {
  625. sysEvent_t *ev;
  626. static int printedWarning;
  627. ev = &com_pushedEvents[ com_pushedEventsHead & (MAX_PUSHED_EVENTS-1) ];
  628. if ( com_pushedEventsHead - com_pushedEventsTail >= MAX_PUSHED_EVENTS ) {
  629. // don't print the warning constantly, or it can give time for more...
  630. if ( !printedWarning ) {
  631. printedWarning = qtrue;
  632. Com_Printf( "WARNING: Com_PushEvent overflow\n" );
  633. }
  634. if ( ev->evPtr ) {
  635. Z_Free( ev->evPtr );
  636. }
  637. com_pushedEventsTail++;
  638. } else {
  639. printedWarning = qfalse;
  640. }
  641. *ev = *event;
  642. com_pushedEventsHead++;
  643. }
  644. /*
  645. =================
  646. Com_GetEvent
  647. =================
  648. */
  649. sysEvent_t Com_GetEvent( void ) {
  650. if ( com_pushedEventsHead > com_pushedEventsTail ) {
  651. com_pushedEventsTail++;
  652. return com_pushedEvents[ (com_pushedEventsTail-1) & (MAX_PUSHED_EVENTS-1) ];
  653. }
  654. return Com_GetRealEvent();
  655. }
  656. /*
  657. =================
  658. Com_RunAndTimeServerPacket
  659. =================
  660. */
  661. void Com_RunAndTimeServerPacket( netadr_t *evFrom, msg_t *buf ) {
  662. int t1, t2, msec;
  663. t1 = 0;
  664. if ( com_speeds->integer ) {
  665. t1 = Sys_Milliseconds ();
  666. }
  667. SV_PacketEvent( *evFrom, buf );
  668. if ( com_speeds->integer ) {
  669. t2 = Sys_Milliseconds ();
  670. msec = t2 - t1;
  671. if ( com_speeds->integer == 3 ) {
  672. Com_Printf( "SV_PacketEvent time: %i\n", msec );
  673. }
  674. }
  675. }
  676. /*
  677. =================
  678. Com_EventLoop
  679. Returns last event time
  680. =================
  681. */
  682. int Com_EventLoop( void ) {
  683. sysEvent_t ev;
  684. netadr_t evFrom;
  685. byte bufData[MAX_MSGLEN];
  686. msg_t buf;
  687. MSG_Init( &buf, bufData, sizeof( bufData ) );
  688. while ( 1 ) {
  689. ev = Com_GetEvent();
  690. // if no more events are available
  691. if ( ev.evType == SE_NONE ) {
  692. // manually send packet events for the loopback channel
  693. while ( NET_GetLoopPacket( NS_CLIENT, &evFrom, &buf ) ) {
  694. CL_PacketEvent( evFrom, &buf );
  695. }
  696. while ( NET_GetLoopPacket( NS_SERVER, &evFrom, &buf ) ) {
  697. // if the server just shut down, flush the events
  698. if ( com_sv_running->integer ) {
  699. Com_RunAndTimeServerPacket( &evFrom, &buf );
  700. }
  701. }
  702. return ev.evTime;
  703. }
  704. switch ( ev.evType ) {
  705. default:
  706. Com_Error( ERR_FATAL, "Com_EventLoop: bad event type %i", ev.evTime );
  707. break;
  708. case SE_NONE:
  709. break;
  710. case SE_KEY:
  711. CL_KeyEvent( ev.evValue, ev.evValue2, ev.evTime );
  712. break;
  713. case SE_CHAR:
  714. CL_CharEvent( ev.evValue );
  715. break;
  716. case SE_MOUSE:
  717. CL_MouseEvent( ev.evValue, ev.evValue2, ev.evTime );
  718. break;
  719. case SE_JOYSTICK_AXIS:
  720. CL_JoystickEvent( ev.evValue, ev.evValue2, ev.evTime );
  721. break;
  722. case SE_CONSOLE:
  723. Cbuf_AddText( (char *)ev.evPtr );
  724. Cbuf_AddText( "\n" );
  725. break;
  726. case SE_PACKET:
  727. evFrom = *(netadr_t *)ev.evPtr;
  728. buf.cursize = ev.evPtrLength - sizeof( evFrom );
  729. // we must copy the contents of the message out, because
  730. // the event buffers are only large enough to hold the
  731. // exact payload, but channel messages need to be large
  732. // enough to hold fragment reassembly
  733. if ( (unsigned)buf.cursize > buf.maxsize ) {
  734. Com_Printf("Com_EventLoop: oversize packet\n");
  735. continue;
  736. }
  737. memcpy( buf.data, (byte *)((netadr_t *)ev.evPtr + 1), buf.cursize );
  738. if ( com_sv_running->integer ) {
  739. Com_RunAndTimeServerPacket( &evFrom, &buf );
  740. } else {
  741. CL_PacketEvent( evFrom, &buf );
  742. }
  743. break;
  744. }
  745. // free any block data
  746. if ( ev.evPtr ) {
  747. Z_Free( ev.evPtr );
  748. }
  749. }
  750. }
  751. /*
  752. ================
  753. Com_Milliseconds
  754. Can be used for profiling, but will be journaled accurately
  755. ================
  756. */
  757. int Com_Milliseconds (void) {
  758. sysEvent_t ev;
  759. // get events and push them until we get a null event with the current time
  760. do {
  761. ev = Com_GetRealEvent();
  762. if ( ev.evType != SE_NONE ) {
  763. Com_PushEvent( &ev );
  764. }
  765. } while ( ev.evType != SE_NONE );
  766. return ev.evTime;
  767. }
  768. //============================================================================
  769. /*
  770. =============
  771. Com_Error_f
  772. Just throw a fatal error to
  773. test error shutdown procedures
  774. =============
  775. */
  776. static void Com_Error_f (void) {
  777. if ( Cmd_Argc() > 1 ) {
  778. Com_Error( ERR_DROP, "Testing drop error" );
  779. } else {
  780. Com_Error( ERR_FATAL, "Testing fatal error" );
  781. }
  782. }
  783. /*
  784. =============
  785. Com_Freeze_f
  786. Just freeze in place for a given number of seconds to test
  787. error recovery
  788. =============
  789. */
  790. static void Com_Freeze_f (void) {
  791. float s;
  792. int start, now;
  793. if ( Cmd_Argc() != 2 ) {
  794. Com_Printf( "freeze <seconds>\n" );
  795. return;
  796. }
  797. s = atof( Cmd_Argv(1) );
  798. start = Com_Milliseconds();
  799. while ( 1 ) {
  800. now = Com_Milliseconds();
  801. if ( ( now - start ) * 0.001 > s ) {
  802. break;
  803. }
  804. }
  805. }
  806. /*
  807. =================
  808. Com_Crash_f
  809. A way to force a bus error for development reasons
  810. =================
  811. */
  812. static void Com_Crash_f( void ) {
  813. * ( int * ) 0 = 0x12345678;
  814. }
  815. /*
  816. =================
  817. Com_Init
  818. =================
  819. */
  820. extern void Com_InitZoneMemory();
  821. extern void R_InitWorldEffects();
  822. void Com_Init( char *commandLine ) {
  823. char *s;
  824. Com_Printf( "%s %s %s\n", Q3_VERSION, CPUSTRING, __DATE__ );
  825. try {
  826. // Grab the user's langauge preference from the dashboard right away!
  827. // We only support french/german/english (with english as default)
  828. g_dwLanguage = XGetLanguage();
  829. if( g_dwLanguage != XC_LANGUAGE_FRENCH && g_dwLanguage != XC_LANGUAGE_GERMAN )
  830. g_dwLanguage = XC_LANGUAGE_ENGLISH;
  831. // prepare enough of the subsystems to handle
  832. // cvar and command buffer management
  833. Com_ParseCommandLine( commandLine );
  834. Swap_Init ();
  835. Cbuf_Init ();
  836. Com_InitZoneMemory();
  837. #ifdef _XBOX
  838. WF_Init();
  839. // set up ri
  840. extern void CL_InitRef( void );
  841. CL_InitRef();
  842. // register renderer cvars
  843. extern void R_Register(void);
  844. R_Register();
  845. // start the gl render layer
  846. extern void GLimp_Init(void);
  847. GLimp_Init();
  848. // put up the license screen
  849. SP_DoLicense();
  850. #endif
  851. Cmd_Init ();
  852. Cvar_Init ();
  853. // get the commandline cvars set
  854. Com_StartupVariable( NULL );
  855. // done early so bind command exists
  856. CL_InitKeyCommands();
  857. #ifdef _XBOX
  858. extern void Sys_FilecodeScan_f();
  859. Sys_InitFileCodes();
  860. Cmd_AddCommand("filecodes", Sys_FilecodeScan_f);
  861. extern void Sys_StreamInit();
  862. Sys_StreamInit();
  863. // This just forces the static singleton in the function to call
  864. // its constructor, which allocates a stupid 12 byte block of
  865. // memory that never gets freed. Otherwise, it ends up stranded in
  866. // the middle of the zone:
  867. TheGhoul2InfoArray();
  868. #endif
  869. FS_InitFilesystem (); //uses z_malloc
  870. R_InitWorldEffects(); // this doesn't do much but I want to be sure certain variables are intialized.
  871. Cbuf_AddText ("exec default.cfg\n");
  872. // skip the jaconfig.cfg if "safe" is on the command line
  873. if ( !Com_SafeMode() ) {
  874. Cbuf_AddText ("exec jaconfig.cfg\n");
  875. }
  876. Cbuf_AddText ("exec autoexec.cfg\n");
  877. Cbuf_Execute ();
  878. // override anything from the config files with command line args
  879. Com_StartupVariable( NULL );
  880. // allocate the stack based hunk allocator
  881. Com_InitHunkMemory();
  882. // if any archived cvars are modified after this, we will trigger a writing
  883. // of the config file
  884. cvar_modifiedFlags &= ~CVAR_ARCHIVE;
  885. //
  886. // init commands and vars
  887. //
  888. Cmd_AddCommand ("quit", Com_Quit_f);
  889. Cmd_AddCommand ("writeconfig", Com_WriteConfig_f );
  890. com_maxfps = Cvar_Get ("com_maxfps", "85", CVAR_ARCHIVE);
  891. com_developer = Cvar_Get ("developer", "0", CVAR_TEMP );
  892. com_logfile = Cvar_Get ("logfile", "0", CVAR_TEMP );
  893. com_speedslog = Cvar_Get ("speedslog", "0", CVAR_TEMP );
  894. com_timescale = Cvar_Get ("timescale", "1", CVAR_CHEAT );
  895. com_fixedtime = Cvar_Get ("fixedtime", "0", CVAR_CHEAT);
  896. com_showtrace = Cvar_Get ("com_showtrace", "0", CVAR_CHEAT);
  897. com_terrainPhysics = Cvar_Get ("com_terrainPhysics", "1", CVAR_CHEAT);
  898. com_viewlog = Cvar_Get( "viewlog", "0", CVAR_TEMP );
  899. com_speeds = Cvar_Get ("com_speeds", "0", 0);
  900. #ifdef G2_PERFORMANCE_ANALYSIS
  901. com_G2Report = Cvar_Get("com_G2Report", "0", 0);
  902. #endif
  903. cl_paused = Cvar_Get ("cl_paused", "0", CVAR_ROM);
  904. sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM);
  905. com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM);
  906. com_cl_running = Cvar_Get ("cl_running", "0", CVAR_ROM);
  907. com_skippingcin = Cvar_Get ("skippingCinematic", "0", CVAR_ROM);
  908. com_buildScript = Cvar_Get( "com_buildScript", "0", 0 );
  909. if ( com_developer && com_developer->integer ) {
  910. Cmd_AddCommand ("error", Com_Error_f);
  911. Cmd_AddCommand ("crash", Com_Crash_f );
  912. Cmd_AddCommand ("freeze", Com_Freeze_f);
  913. }
  914. s = va("%s %s %s", Q3_VERSION, CPUSTRING, __DATE__ );
  915. com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO );
  916. // So any controller can skip the logo movies:
  917. inSplashMenu = Cvar_Get( "inSplashMenu", "1", 0 );
  918. controllerOut= Cvar_Get( "ControllerOutNum", "-1", 0);
  919. #ifdef XBOX_DEMO
  920. // Cvar used to hide "QUIT TO DEMOS MENU" options if we weren't started by CDX
  921. extern bool demoLaunchDataValid;
  922. if( demoLaunchDataValid )
  923. Cvar_SetValue( "ui_allowDemoQuit", 1 );
  924. else
  925. Cvar_SetValue( "ui_allowDemoQuit", 0 );
  926. #endif
  927. SE_Init(); // Initialize StringEd
  928. Sys_Init(); // this also detects CPU type, so I can now do this CPU check below...
  929. Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random
  930. // VM_Init();
  931. SV_Init();
  932. CL_Init();
  933. #ifdef _XBOX
  934. // Experiment. Sound memory never gets freed, move it earlier. This
  935. // will also let us play movies sooner, if we need to.
  936. extern void CL_StartSound(void);
  937. CL_StartSound();
  938. #endif
  939. Sys_ShowConsole( com_viewlog->integer, qfalse );
  940. // set com_frameTime so that if a map is started on the
  941. // command line it will still be able to count on com_frameTime
  942. // being random enough for a serverid
  943. com_frameTime = Com_Milliseconds();
  944. // add + commands from command line
  945. #ifndef _XBOX
  946. if ( !Com_AddStartupCommands() ) {
  947. #ifdef NDEBUG
  948. // if the user didn't give any commands, run default action
  949. // if ( !com_dedicated->integer )
  950. {
  951. Cbuf_AddText ("cinematic openinglogos\n");
  952. // if( !com_introPlayed->integer ) {
  953. // Cvar_Set( com_introPlayed->name, "1" );
  954. // Cvar_Set( "nextmap", "cinematic intro" );
  955. // }
  956. }
  957. #endif
  958. }
  959. #endif
  960. com_fullyInitialized = qtrue;
  961. Com_Printf ("--- Common Initialization Complete ---\n");
  962. //HACKERY FOR THE DEUTSCH
  963. //if ( (Cvar_VariableIntegerValue("ui_iscensored") == 1) //if this was on before, set it again so it gets its flags
  964. // )
  965. //{
  966. // Cvar_Get( "ui_iscensored", "1", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART);
  967. // Cvar_Set( "ui_iscensored", "1"); //just in case it was archived
  968. // // NOTE : I also create this in UI_Init()
  969. // Cvar_Get( "g_dismemberment", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT);
  970. // Cvar_Set( "g_dismemberment", "0"); //just in case it was archived
  971. //}
  972. }
  973. catch (const char* reason) {
  974. Sys_Error ("Error during initialization %s", reason);
  975. }
  976. #ifdef _XBOX
  977. //Load these early to keep them at the beginning of memory. Perhaps
  978. //here is too early though. After the license screen would be better.
  979. extern void SE_CheckForLanguageUpdates(void);
  980. SE_CheckForLanguageUpdates();
  981. #endif
  982. }
  983. //==================================================================
  984. void Com_WriteConfigToFile( const char *filename ) {
  985. #ifndef _XBOX
  986. fileHandle_t f;
  987. f = FS_FOpenFileWrite( filename );
  988. if ( !f ) {
  989. Com_Printf ("Couldn't write %s.\n", filename );
  990. return;
  991. }
  992. FS_Printf (f, "// generated by Star Wars Jedi Academy, do not modify\n");
  993. Key_WriteBindings (f);
  994. Cvar_WriteVariables (f);
  995. FS_FCloseFile( f );
  996. #endif
  997. }
  998. /*
  999. ===============
  1000. Com_WriteConfiguration
  1001. Writes key bindings and archived cvars to config file if modified
  1002. ===============
  1003. */
  1004. void Com_WriteConfiguration( void ) {
  1005. // if we are quiting without fully initializing, make sure
  1006. // we don't write out anything
  1007. if ( !com_fullyInitialized ) {
  1008. return;
  1009. }
  1010. if ( !(cvar_modifiedFlags & CVAR_ARCHIVE ) ) {
  1011. return;
  1012. }
  1013. cvar_modifiedFlags &= ~CVAR_ARCHIVE;
  1014. Com_WriteConfigToFile( "jaconfig.cfg" );
  1015. }
  1016. /*
  1017. ===============
  1018. Com_WriteConfig_f
  1019. Write the config file to a specific name
  1020. ===============
  1021. */
  1022. void Com_WriteConfig_f( void ) {
  1023. char filename[MAX_QPATH];
  1024. if ( Cmd_Argc() != 2 ) {
  1025. Com_Printf( "Usage: writeconfig <filename>\n" );
  1026. return;
  1027. }
  1028. Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) );
  1029. COM_DefaultExtension( filename, sizeof( filename ), ".cfg" );
  1030. Com_Printf( "Writing %s.\n", filename );
  1031. Com_WriteConfigToFile( filename );
  1032. }
  1033. /*
  1034. ================
  1035. Com_ModifyMsec
  1036. ================
  1037. */
  1038. int Com_ModifyMsec( int msec, float &fraction )
  1039. {
  1040. int clampTime;
  1041. fraction=0.0f;
  1042. //
  1043. // modify time for debugging values
  1044. //
  1045. if ( com_fixedtime->integer )
  1046. {
  1047. msec = com_fixedtime->integer;
  1048. }
  1049. else if ( com_timescale->value )
  1050. {
  1051. fraction=(float)msec;
  1052. fraction*=com_timescale->value;
  1053. msec=(int)floor(fraction);
  1054. fraction-=(float)msec;
  1055. }
  1056. // don't let it scale below 1 msec
  1057. if ( msec < 1 )
  1058. {
  1059. msec = 1;
  1060. fraction=0.0f;
  1061. }
  1062. if ( com_skippingcin->integer ) {
  1063. // we're skipping ahead so let it go a bit faster
  1064. clampTime = 500;
  1065. } else {
  1066. // for local single player gaming
  1067. // we may want to clamp the time to prevent players from
  1068. // flying off edges when something hitches.
  1069. clampTime = 200;
  1070. }
  1071. if ( msec > clampTime ) {
  1072. msec = clampTime;
  1073. fraction=0.0f;
  1074. }
  1075. return msec;
  1076. }
  1077. /*
  1078. =================
  1079. Com_Frame
  1080. =================
  1081. */
  1082. static vec3_t corg;
  1083. static vec3_t cangles;
  1084. static bool bComma;
  1085. void Com_SetOrgAngles(vec3_t org,vec3_t angles)
  1086. {
  1087. VectorCopy(org,corg);
  1088. VectorCopy(angles,cangles);
  1089. }
  1090. #ifdef G2_PERFORMANCE_ANALYSIS
  1091. void G2Time_ResetTimers(void);
  1092. void G2Time_ReportTimers(void);
  1093. #endif
  1094. #pragma warning (disable: 4701) //local may have been used without init (timing info vars)
  1095. void Com_Frame( void ) {
  1096. try
  1097. {
  1098. int timeBeforeFirstEvents, timeBeforeServer, timeBeforeEvents, timeBeforeClient, timeAfter;
  1099. int msec, minMsec;
  1100. static int lastTime;
  1101. // write config file if anything changed
  1102. #ifndef _XBOX
  1103. Com_WriteConfiguration();
  1104. // if "viewlog" has been modified, show or hide the log console
  1105. if ( com_viewlog->modified ) {
  1106. Sys_ShowConsole( com_viewlog->integer, qfalse );
  1107. com_viewlog->modified = qfalse;
  1108. }
  1109. #endif
  1110. //
  1111. // main event loop
  1112. //
  1113. if ( com_speeds->integer ) {
  1114. timeBeforeFirstEvents = Sys_Milliseconds ();
  1115. }
  1116. // we may want to spin here if things are going too fast
  1117. if ( com_maxfps->integer > 0 ) {
  1118. minMsec = 1000 / com_maxfps->integer;
  1119. } else {
  1120. minMsec = 1;
  1121. }
  1122. do {
  1123. com_frameTime = Com_EventLoop();
  1124. if ( lastTime > com_frameTime ) {
  1125. lastTime = com_frameTime; // possible on first frame
  1126. }
  1127. msec = com_frameTime - lastTime;
  1128. } while ( msec < minMsec );
  1129. Cbuf_Execute ();
  1130. lastTime = com_frameTime;
  1131. // mess with msec if needed
  1132. com_frameMsec = msec;
  1133. float fractionMsec=0.0f;
  1134. msec = Com_ModifyMsec( msec, fractionMsec);
  1135. //
  1136. // server side
  1137. //
  1138. if ( com_speeds->integer ) {
  1139. timeBeforeServer = Sys_Milliseconds ();
  1140. }
  1141. SV_Frame (msec, fractionMsec);
  1142. //
  1143. // client system
  1144. //
  1145. #ifdef _XBOX
  1146. extern bool TestDemoTimer();
  1147. extern void PlayDemo();
  1148. if ( TestDemoTimer())
  1149. {
  1150. PlayDemo();
  1151. }
  1152. #endif
  1153. // if ( !com_dedicated->integer )
  1154. {
  1155. //
  1156. // run event loop a second time to get server to client packets
  1157. // without a frame of latency
  1158. //
  1159. if ( com_speeds->integer ) {
  1160. timeBeforeEvents = Sys_Milliseconds ();
  1161. }
  1162. Com_EventLoop();
  1163. Cbuf_Execute ();
  1164. //
  1165. // client side
  1166. //
  1167. if ( com_speeds->integer ) {
  1168. timeBeforeClient = Sys_Milliseconds ();
  1169. }
  1170. CL_Frame (msec, fractionMsec);
  1171. if ( com_speeds->integer ) {
  1172. timeAfter = Sys_Milliseconds ();
  1173. }
  1174. }
  1175. //
  1176. // report timing information
  1177. //
  1178. if ( com_speeds->integer ) {
  1179. int all, sv, ev, cl;
  1180. all = timeAfter - timeBeforeServer;
  1181. sv = timeBeforeEvents - timeBeforeServer;
  1182. ev = timeBeforeServer - timeBeforeFirstEvents + timeBeforeClient - timeBeforeEvents;
  1183. cl = timeAfter - timeBeforeClient;
  1184. sv -= time_game;
  1185. cl -= time_frontend + time_backend;
  1186. Com_Printf("fr:%i all:%3i sv:%3i ev:%3i cl:%3i gm:%3i tr:%3i pvs:%3i rf:%3i bk:%3i\n",
  1187. com_frameNumber, all, sv, ev, cl, time_game, timeInTrace, timeInPVSCheck, time_frontend, time_backend);
  1188. #ifndef _XBOX
  1189. // speedslog
  1190. if ( com_speedslog && com_speedslog->integer )
  1191. {
  1192. if(!speedslog)
  1193. {
  1194. speedslog = FS_FOpenFileWrite("speeds.log");
  1195. FS_Write("data={\n", strlen("data={\n"), speedslog);
  1196. bComma=false;
  1197. if ( com_speedslog->integer > 1 )
  1198. {
  1199. // force it to not buffer so we get valid
  1200. // data even if we are crashing
  1201. FS_ForceFlush(logfile);
  1202. }
  1203. }
  1204. if (speedslog)
  1205. {
  1206. char msg[MAXPRINTMSG];
  1207. if(bComma)
  1208. {
  1209. FS_Write(",\n", strlen(",\n"), speedslog);
  1210. bComma=false;
  1211. }
  1212. FS_Write("{", strlen("{"), speedslog);
  1213. Com_sprintf(msg,sizeof(msg),
  1214. "%8.4f,%8.4f,%8.4f,%8.4f,%8.4f,%8.4f,",corg[0],corg[1],corg[2],cangles[0],cangles[1],cangles[2]);
  1215. FS_Write(msg, strlen(msg), speedslog);
  1216. Com_sprintf(msg,sizeof(msg),
  1217. "%i,%3i,%3i,%3i,%3i,%3i,%3i,%3i,%3i,%3i}",
  1218. com_frameNumber, all, sv, ev, cl, time_game, timeInTrace, timeInPVSCheck, time_frontend, time_backend);
  1219. FS_Write(msg, strlen(msg), speedslog);
  1220. bComma=true;
  1221. }
  1222. }
  1223. #endif
  1224. timeInTrace = timeInPVSCheck = 0;
  1225. }
  1226. //
  1227. // trace optimization tracking
  1228. //
  1229. if ( com_showtrace->integer ) {
  1230. extern int c_traces, c_brush_traces, c_patch_traces;
  1231. extern int c_pointcontents;
  1232. /*
  1233. Com_Printf( "%4i non-sv_traces, %4i sv_traces, %4i ms, ave %4.2f ms\n", c_traces - numTraces, numTraces, timeInTrace, (float)timeInTrace/(float)numTraces );
  1234. timeInTrace = numTraces = 0;
  1235. c_traces = 0;
  1236. */
  1237. Com_Printf ("%4i traces (%ib %ip) %4i points\n", c_traces,
  1238. c_brush_traces, c_patch_traces, c_pointcontents);
  1239. c_traces = 0;
  1240. c_brush_traces = 0;
  1241. c_patch_traces = 0;
  1242. c_pointcontents = 0;
  1243. }
  1244. com_frameNumber++;
  1245. }//try
  1246. catch (const char* reason) {
  1247. Com_Printf (reason);
  1248. return; // an ERR_DROP was thrown
  1249. }
  1250. #ifdef G2_PERFORMANCE_ANALYSIS
  1251. if (com_G2Report && com_G2Report->integer)
  1252. {
  1253. G2Time_ReportTimers();
  1254. }
  1255. G2Time_ResetTimers();
  1256. #endif
  1257. Cvar_Get("levelSelectCheat", "-1", CVAR_SAVEGAME | CVAR_ARCHIVE);
  1258. #ifdef XBOX_DEMO
  1259. // This is for the code that auto-reboots back to CDX after a timeout:
  1260. extern void Demo_TimerUpdate( void );
  1261. Demo_TimerUpdate();
  1262. #endif
  1263. }
  1264. #pragma warning (default: 4701) //local may have been used without init
  1265. /*
  1266. =================
  1267. Com_Shutdown
  1268. =================
  1269. */
  1270. extern void CM_FreeShaderText(void);
  1271. void Com_Shutdown (void) {
  1272. CM_ClearMap();
  1273. #ifndef _XBOX
  1274. CM_FreeShaderText();
  1275. if (logfile) {
  1276. FS_FCloseFile (logfile);
  1277. logfile = 0;
  1278. }
  1279. if (speedslog) {
  1280. FS_Write("\n};", strlen("\n};"), speedslog);
  1281. FS_FCloseFile (speedslog);
  1282. speedslog = 0;
  1283. }
  1284. if (camerafile) {
  1285. FS_FCloseFile (camerafile);
  1286. camerafile = 0;
  1287. }
  1288. if ( com_journalFile ) {
  1289. FS_FCloseFile( com_journalFile );
  1290. com_journalFile = 0;
  1291. }
  1292. #endif
  1293. #ifdef _XBOX
  1294. extern void Sys_StreamShutdown();
  1295. Sys_StreamShutdown();
  1296. Sys_ShutdownFileCodes();
  1297. #endif
  1298. // SE_ShutDown();//close the string packages
  1299. extern void Netchan_Shutdown();
  1300. Netchan_Shutdown();
  1301. }
  1302. /*
  1303. ============
  1304. ParseTextFile
  1305. ============
  1306. */
  1307. bool Com_ParseTextFile(const char *file, class CGenericParser2 &parser, bool cleanFirst)
  1308. {
  1309. fileHandle_t f;
  1310. int length = 0;
  1311. char *buf = 0, *bufParse = 0;
  1312. length = FS_FOpenFileByMode( file, &f, FS_READ );
  1313. if (!f || !length)
  1314. {
  1315. return false;
  1316. }
  1317. buf = new char [length + 1];
  1318. FS_Read( buf, length, f );
  1319. buf[length] = 0;
  1320. bufParse = buf;
  1321. parser.Parse(&bufParse, cleanFirst);
  1322. delete buf;
  1323. FS_FCloseFile( f );
  1324. return true;
  1325. }
  1326. void Com_ParseTextFileDestroy(class CGenericParser2 &parser)
  1327. {
  1328. parser.Clean();
  1329. }
  1330. CGenericParser2 *Com_ParseTextFile(const char *file, bool cleanFirst, bool writeable)
  1331. {
  1332. fileHandle_t f;
  1333. int length = 0;
  1334. char *buf = 0, *bufParse = 0;
  1335. CGenericParser2 *parse;
  1336. length = FS_FOpenFileByMode( file, &f, FS_READ );
  1337. if (!f || !length)
  1338. {
  1339. return 0;
  1340. }
  1341. buf = new char [length + 1];
  1342. FS_Read( buf, length, f );
  1343. FS_FCloseFile( f );
  1344. buf[length] = 0;
  1345. bufParse = buf;
  1346. parse = new CGenericParser2;
  1347. if (!parse->Parse(&bufParse, cleanFirst, writeable))
  1348. {
  1349. delete parse;
  1350. parse = 0;
  1351. }
  1352. delete buf;
  1353. return parse;
  1354. }