1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include <SDL.h>
30
31 #include "sys/platform.h"
32 #include "idlib/containers/HashTable.h"
33 #include "idlib/LangDict.h"
34 #include "idlib/MapFile.h"
35 #include "cm/CollisionModel.h"
36 #include "framework/async/AsyncNetwork.h"
37 #include "framework/async/NetworkSystem.h"
38 #include "framework/BuildVersion.h"
39 #include "framework/Licensee.h"
40 #include "framework/Console.h"
41 #include "framework/Session.h"
42 #include "framework/Game.h"
43 #include "framework/KeyInput.h"
44 #include "framework/EventLoop.h"
45 #include "renderer/Image.h"
46 #include "renderer/Model.h"
47 #include "renderer/ModelManager.h"
48 #include "renderer/RenderSystem.h"
49 #include "tools/compilers/compiler_public.h"
50 #include "tools/compilers/aas/AASFileManager.h"
51 #include "tools/edit_public.h"
52
53 #include "framework/Common.h"
54
55 #include "GameCallbacks_local.h"
56 #include "Session_local.h" // DG: For FT_IsDemo/isDemo() hack
57
58 #define MAX_PRINT_MSG_SIZE 4096
59 #define MAX_WARNING_LIST 256
60
61 typedef enum {
62 ERP_NONE,
63 ERP_FATAL, // exit the entire game with a popup window
64 ERP_DROP, // print to console and disconnect from game
65 ERP_DISCONNECT // don't kill server
66 } errorParm_t;
67
68 #if defined( _DEBUG )
69 #define BUILD_DEBUG "-debug"
70 #else
71 #define BUILD_DEBUG ""
72 #endif
73
74 struct version_s {
version_sversion_s75 version_s( void ) { sprintf( string, "%s.%d%s %s-%s %s %s", ENGINE_VERSION, BUILD_NUMBER, BUILD_DEBUG, BUILD_OS, BUILD_CPU, ID__DATE__, ID__TIME__ ); }
76 char string[256];
77 } version;
78
79 idCVar com_version( "si_version", version.string, CVAR_SYSTEM|CVAR_ROM|CVAR_SERVERINFO, "engine version" );
80 idCVar com_skipRenderer( "com_skipRenderer", "0", CVAR_BOOL|CVAR_SYSTEM, "skip the renderer completely" );
81 idCVar com_machineSpec( "com_machineSpec", "-1", CVAR_INTEGER | CVAR_ARCHIVE | CVAR_SYSTEM, "hardware classification, -1 = not detected, 0 = low quality, 1 = medium quality, 2 = high quality, 3 = ultra quality" );
82 idCVar com_purgeAll( "com_purgeAll", "0", CVAR_BOOL | CVAR_ARCHIVE | CVAR_SYSTEM, "purge everything between level loads" );
83 idCVar com_memoryMarker( "com_memoryMarker", "-1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_INIT, "used as a marker for memory stats" );
84 idCVar com_preciseTic( "com_preciseTic", "1", CVAR_BOOL|CVAR_SYSTEM, "run one game tick every async thread update" );
85 idCVar com_asyncInput( "com_asyncInput", "0", CVAR_BOOL|CVAR_SYSTEM, "sample input from the async thread" );
86 #define ASYNCSOUND_INFO "0: mix sound inline, 1 or 3: async update every 16ms 2: async update about every 100ms (original behavior)"
87 idCVar com_asyncSound( "com_asyncSound", "1", CVAR_INTEGER|CVAR_SYSTEM, ASYNCSOUND_INFO, 0, 3 );
88 idCVar com_forceGenericSIMD( "com_forceGenericSIMD", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "force generic platform independent SIMD" );
89 idCVar com_developer( "developer", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "developer mode" );
90 idCVar com_allowConsole( "com_allowConsole", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "allow toggling console with the tilde key" );
91 idCVar com_speeds( "com_speeds", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show engine timings" );
92 idCVar com_showFPS( "com_showFPS", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_ARCHIVE|CVAR_NOCHEAT, "show frames rendered per second" );
93 idCVar com_showMemoryUsage( "com_showMemoryUsage", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show total and per frame memory usage" );
94 idCVar com_showAsyncStats( "com_showAsyncStats", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show async network stats" );
95 idCVar com_showSoundDecoders( "com_showSoundDecoders", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "show sound decoders" );
96 idCVar com_timestampPrints( "com_timestampPrints", "0", CVAR_SYSTEM, "print time with each console print, 1 = msec, 2 = sec", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
97 idCVar com_timescale( "timescale", "1", CVAR_SYSTEM | CVAR_FLOAT, "scales the time", 0.1f, 10.0f );
98 idCVar com_makingBuild( "com_makingBuild", "0", CVAR_BOOL | CVAR_SYSTEM, "1 when making a build" );
99 idCVar com_updateLoadSize( "com_updateLoadSize", "0", CVAR_BOOL | CVAR_SYSTEM | CVAR_NOCHEAT, "update the load size after loading a map" );
100
101 idCVar com_product_lang_ext( "com_product_lang_ext", "1", CVAR_INTEGER | CVAR_SYSTEM | CVAR_ARCHIVE, "Extension to use when creating language files." );
102
103 // com_speeds times
104 int time_gameFrame;
105 int time_gameDraw;
106 int time_frontend; // renderSystem frontend time
107 int time_backend; // renderSystem backend time
108
109 int com_frameTime; // time for the current frame in milliseconds
110 int com_frameNumber; // variable frame number
111 volatile int com_ticNumber; // 60 hz tics
112 int com_editors; // currently opened editor(s)
113 bool com_editorActive; // true if an editor has focus
114
115 #ifdef _WIN32
116 HWND com_hwndMsg = NULL;
117 bool com_outputMsg = false;
118 unsigned int com_msgID = -1;
119 #endif
120
121 #ifdef __DOOM_DLL__
122 idGame * game = NULL;
123 idGameEdit * gameEdit = NULL;
124 #endif
125
126 // writes si_version to the config file - in a kinda obfuscated way
127 //#define ID_WRITE_VERSION
128
129 class idCommonLocal : public idCommon {
130 public:
131 idCommonLocal( void );
132
133 virtual void Init( int argc, char **argv );
134 virtual void Shutdown( void );
135 virtual void Quit( void );
136 virtual bool IsInitialized( void ) const;
137 virtual void Frame( void );
138 virtual void GUIFrame( bool execCmd, bool network );
139 virtual void Async( void );
140 virtual void StartupVariable( const char *match, bool once );
141 virtual void InitTool( const toolFlag_t tool, const idDict *dict );
142 virtual void ActivateTool( bool active );
143 virtual void WriteConfigToFile( const char *filename );
144 virtual void WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd );
145 virtual void BeginRedirect( char *buffer, int buffersize, void (*flush)( const char * ) );
146 virtual void EndRedirect( void );
147 virtual void SetRefreshOnPrint( bool set );
148 virtual void Printf( const char *fmt, ... ) id_attribute((format(printf,2,3)));
149 virtual void VPrintf( const char *fmt, va_list arg );
150 virtual void DPrintf( const char *fmt, ... ) id_attribute((format(printf,2,3)));
151 virtual void Warning( const char *fmt, ... ) id_attribute((format(printf,2,3)));
152 virtual void DWarning( const char *fmt, ...) id_attribute((format(printf,2,3)));
153 virtual void PrintWarnings( void );
154 virtual void ClearWarnings( const char *reason );
155 virtual void Error( const char *fmt, ... ) id_attribute((format(printf,2,3)));
156 virtual void FatalError( const char *fmt, ... ) id_attribute((format(printf,2,3)));
157 virtual const idLangDict * GetLanguageDict( void );
158
159 virtual const char * KeysFromBinding( const char *bind );
160 virtual const char * BindingFromKey( const char *key );
161
162 virtual int ButtonState( int key );
163 virtual int KeyState( int key );
164
165 // DG: hack to allow adding callbacks and exporting additional functions without breaking the game ABI
166 // see Common.h for longer explanation...
167
168 // returns true if setting the callback was successful, else false
169 // When a game DLL is unloaded the callbacks are automatically removed from the Engine
170 // so you usually don't have to worry about that; but you can call this with cb = NULL
171 // and userArg = NULL to remove a callback manually (e.g. if userArg refers to an object you deleted)
172 virtual bool SetCallback(idCommon::CallbackType cbt, idCommon::FunctionPointer cb, void* userArg);
173
174 // returns true if that function is available in this version of dhewm3
175 // *out_fnptr will be the function (you'll have to cast it probably)
176 // *out_userArg will be an argument you have to pass to the function, if appropriate (else NULL)
177 // NOTE: this doesn't do anything yet, but allows to add ugly mod-specific hacks without breaking the Game interface
178 virtual bool GetAdditionalFunction(idCommon::FunctionType ft, idCommon::FunctionPointer* out_fnptr, void** out_userArg);
179
180 // DG end
181
182 void InitGame( void );
183 void ShutdownGame( bool reloading );
184
185 // localization
186 void InitLanguageDict( void );
187 void LocalizeGui( const char *fileName, idLangDict &langDict );
188 void LocalizeMapData( const char *fileName, idLangDict &langDict );
189 void LocalizeSpecificMapData( const char *fileName, idLangDict &langDict, const idLangDict &replaceArgs );
190
191 void SetMachineSpec( void );
192
193 private:
194 void InitCommands( void );
195 void InitRenderSystem( void );
196 void InitSIMD( void );
197 bool AddStartupCommands( void );
198 void ParseCommandLine( int argc, char **argv );
199 void ClearCommandLine( void );
200 bool SafeMode( void );
201 void CheckToolMode( void );
202 void WriteConfiguration( void );
203 void DumpWarnings( void );
204 void SingleAsyncTic( void );
205 void LoadGameDLL( void );
206 void LoadGameDLLbyName( const char *dll, idStr& s );
207 void UnloadGameDLL( void );
208 void PrintLoadingMessage( const char *msg );
209 void FilterLangList( idStrList* list, idStr lang );
210
211 bool com_fullyInitialized;
212 bool com_refreshOnPrint; // update the screen every print for dmap
213 int com_errorEntered; // 0, ERP_DROP, etc
214
215 char errorMessage[MAX_PRINT_MSG_SIZE];
216
217 char * rd_buffer;
218 int rd_buffersize;
219 void (*rd_flush)( const char *buffer );
220
221 idStr warningCaption;
222 idStrList warningList;
223 idStrList errorList;
224
225 uintptr_t gameDLL;
226
227 idLangDict languageDict;
228
229 #ifdef ID_WRITE_VERSION
230 idCompressor * config_compressor;
231 #endif
232
233 SDL_TimerID async_timer;
234 };
235
236 idCommonLocal commonLocal;
237 idCommon * common = &commonLocal;
238
239 /*
240 ==================
241 idCommonLocal::idCommonLocal
242 ==================
243 */
idCommonLocal(void)244 idCommonLocal::idCommonLocal( void ) {
245 com_fullyInitialized = false;
246 com_refreshOnPrint = false;
247 com_errorEntered = 0;
248
249 strcpy( errorMessage, "" );
250
251 rd_buffer = NULL;
252 rd_buffersize = 0;
253 rd_flush = NULL;
254
255 gameDLL = 0;
256
257 #ifdef ID_WRITE_VERSION
258 config_compressor = NULL;
259 #endif
260
261 async_timer = 0;
262 }
263
264 /*
265 ==================
266 idCommonLocal::BeginRedirect
267 ==================
268 */
BeginRedirect(char * buffer,int buffersize,void (* flush)(const char *))269 void idCommonLocal::BeginRedirect( char *buffer, int buffersize, void (*flush)( const char *) ) {
270 if ( !buffer || !buffersize || !flush ) {
271 return;
272 }
273 rd_buffer = buffer;
274 rd_buffersize = buffersize;
275 rd_flush = flush;
276
277 *rd_buffer = 0;
278 }
279
280 /*
281 ==================
282 idCommonLocal::EndRedirect
283 ==================
284 */
EndRedirect(void)285 void idCommonLocal::EndRedirect( void ) {
286 if ( rd_flush && rd_buffer[ 0 ] ) {
287 rd_flush( rd_buffer );
288 }
289
290 rd_buffer = NULL;
291 rd_buffersize = 0;
292 rd_flush = NULL;
293 }
294
295 #ifdef _WIN32
296
297 /*
298 ==================
299 EnumWindowsProc
300 ==================
301 */
EnumWindowsProc(HWND hwnd,LPARAM lParam)302 BOOL CALLBACK EnumWindowsProc( HWND hwnd, LPARAM lParam ) {
303 char buff[1024];
304
305 ::GetWindowText( hwnd, buff, sizeof( buff ) );
306 if ( idStr::Icmpn( buff, EDITOR_WINDOWTEXT, strlen( EDITOR_WINDOWTEXT ) ) == 0 ) {
307 com_hwndMsg = hwnd;
308 return FALSE;
309 }
310 return TRUE;
311 }
312
313 /*
314 ==================
315 FindEditor
316 ==================
317 */
FindEditor(void)318 bool FindEditor( void ) {
319 com_hwndMsg = NULL;
320 EnumWindows( EnumWindowsProc, 0 );
321 return !( com_hwndMsg == NULL );
322 }
323
324 #endif
325
326 /*
327 ==================
328 idCommonLocal::SetRefreshOnPrint
329 ==================
330 */
SetRefreshOnPrint(bool set)331 void idCommonLocal::SetRefreshOnPrint( bool set ) {
332 com_refreshOnPrint = set;
333 }
334
335 /*
336 ==================
337 idCommonLocal::VPrintf
338
339 A raw string should NEVER be passed as fmt, because of "%f" type crashes.
340 ==================
341 */
VPrintf(const char * fmt,va_list args)342 void idCommonLocal::VPrintf( const char *fmt, va_list args ) {
343 char msg[MAX_PRINT_MSG_SIZE];
344 int timeLength;
345
346 // if the cvar system is not initialized
347 if ( !cvarSystem->IsInitialized() ) {
348 return;
349 }
350
351 // optionally put a timestamp at the beginning of each print,
352 // so we can see how long different init sections are taking
353 if ( com_timestampPrints.GetInteger() ) {
354 int t = Sys_Milliseconds();
355 if ( com_timestampPrints.GetInteger() == 1 ) {
356 t /= 1000;
357 }
358 sprintf( msg, "[%i]", t );
359 timeLength = strlen( msg );
360 } else {
361 timeLength = 0;
362 }
363
364 // don't overflow
365 if ( idStr::vsnPrintf( msg+timeLength, MAX_PRINT_MSG_SIZE-timeLength-1, fmt, args ) < 0 ) {
366 msg[sizeof(msg)-2] = '\n'; msg[sizeof(msg)-1] = '\0'; // avoid output garbling
367 Sys_Printf( "idCommon::VPrintf: truncated to %zd characters\n", strlen(msg)-1 );
368 }
369
370 if ( rd_buffer ) {
371 if ( (int)( strlen( msg ) + strlen( rd_buffer ) ) > ( rd_buffersize - 1 ) ) {
372 rd_flush( rd_buffer );
373 *rd_buffer = 0;
374 }
375 strcat( rd_buffer, msg );
376 return;
377 }
378
379 // echo to console buffer
380 console->Print( msg );
381
382 // remove any color codes
383 idStr::RemoveColors( msg );
384
385 // echo to dedicated console and early console
386 Sys_Printf( "%s", msg );
387
388 // print to script debugger server
389 // DebuggerServerPrint( msg );
390
391 #if 0 // !@#
392 #if defined(_DEBUG) && defined(WIN32)
393 if ( strlen( msg ) < 512 ) {
394 TRACE( msg );
395 }
396 #endif
397 #endif
398
399 // don't trigger any updates if we are in the process of doing a fatal error
400 if ( com_errorEntered != ERP_FATAL ) {
401 // update the console if we are in a long-running command, like dmap
402 if ( com_refreshOnPrint ) {
403 session->UpdateScreen();
404 }
405
406 // let session redraw the animated loading screen if necessary
407 session->PacifierUpdate();
408 }
409
410 #ifdef _WIN32
411
412 if ( com_outputMsg ) {
413 if ( com_msgID == -1 ) {
414 com_msgID = ::RegisterWindowMessage( DMAP_MSGID );
415 if ( !FindEditor() ) {
416 com_outputMsg = false;
417 } else {
418 Sys_ShowWindow( false );
419 }
420 }
421 if ( com_hwndMsg ) {
422 ATOM atom = ::GlobalAddAtom( msg );
423 ::PostMessage( com_hwndMsg, com_msgID, 0, static_cast<LPARAM>(atom) );
424 }
425 }
426
427 #endif
428 }
429
430 /*
431 ==================
432 idCommonLocal::Printf
433
434 Both client and server can use this, and it will output to the appropriate place.
435
436 A raw string should NEVER be passed as fmt, because of "%f" type crashers.
437 ==================
438 */
Printf(const char * fmt,...)439 void idCommonLocal::Printf( const char *fmt, ... ) {
440 va_list argptr;
441 va_start( argptr, fmt );
442 VPrintf( fmt, argptr );
443 va_end( argptr );
444 }
445
446 /*
447 ==================
448 idCommonLocal::DPrintf
449
450 prints message that only shows up if the "developer" cvar is set
451 ==================
452 */
DPrintf(const char * fmt,...)453 void idCommonLocal::DPrintf( const char *fmt, ... ) {
454 va_list argptr;
455 char msg[MAX_PRINT_MSG_SIZE];
456
457 if ( !cvarSystem->IsInitialized() || !com_developer.GetBool() ) {
458 return; // don't confuse non-developers with techie stuff...
459 }
460
461 va_start( argptr, fmt );
462 idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr );
463 va_end( argptr );
464 msg[sizeof(msg)-1] = '\0';
465
466 // never refresh the screen, which could cause reentrency problems
467 bool temp = com_refreshOnPrint;
468 com_refreshOnPrint = false;
469
470 Printf( S_COLOR_RED"%s", msg );
471
472 com_refreshOnPrint = temp;
473 }
474
475 /*
476 ==================
477 idCommonLocal::DWarning
478
479 prints warning message in yellow that only shows up if the "developer" cvar is set
480 ==================
481 */
DWarning(const char * fmt,...)482 void idCommonLocal::DWarning( const char *fmt, ... ) {
483 va_list argptr;
484 char msg[MAX_PRINT_MSG_SIZE];
485
486 if ( !com_developer.GetBool() ) {
487 return; // don't confuse non-developers with techie stuff...
488 }
489
490 va_start( argptr, fmt );
491 idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr );
492 va_end( argptr );
493 msg[sizeof(msg)-1] = '\0';
494
495 Printf( S_COLOR_YELLOW"WARNING: %s\n", msg );
496 }
497
498 /*
499 ==================
500 idCommonLocal::Warning
501
502 prints WARNING %s and adds the warning message to a queue to be printed later on
503 ==================
504 */
Warning(const char * fmt,...)505 void idCommonLocal::Warning( const char *fmt, ... ) {
506 va_list argptr;
507 char msg[MAX_PRINT_MSG_SIZE];
508
509 va_start( argptr, fmt );
510 idStr::vsnPrintf( msg, sizeof(msg), fmt, argptr );
511 va_end( argptr );
512 msg[sizeof(msg)-1] = 0;
513
514 Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", msg );
515
516 if ( warningList.Num() < MAX_WARNING_LIST ) {
517 warningList.AddUnique( msg );
518 }
519 }
520
521 /*
522 ==================
523 idCommonLocal::PrintWarnings
524 ==================
525 */
PrintWarnings(void)526 void idCommonLocal::PrintWarnings( void ) {
527 int i;
528
529 if ( !warningList.Num() ) {
530 return;
531 }
532
533 warningList.Sort();
534
535 Printf( "----- Warnings -----\n" );
536 Printf( "during %s...\n", warningCaption.c_str() );
537
538 for ( i = 0; i < warningList.Num(); i++ ) {
539 Printf( S_COLOR_YELLOW "WARNING: " S_COLOR_RED "%s\n", warningList[i].c_str() );
540 }
541 if ( warningList.Num() ) {
542 if ( warningList.Num() >= MAX_WARNING_LIST ) {
543 Printf( "more than %d warnings\n", MAX_WARNING_LIST );
544 } else {
545 Printf( "%d warnings\n", warningList.Num() );
546 }
547 }
548 }
549
550 /*
551 ==================
552 idCommonLocal::ClearWarnings
553 ==================
554 */
ClearWarnings(const char * reason)555 void idCommonLocal::ClearWarnings( const char *reason ) {
556 warningCaption = reason;
557 warningList.Clear();
558 }
559
560 /*
561 ==================
562 idCommonLocal::DumpWarnings
563 ==================
564 */
DumpWarnings(void)565 void idCommonLocal::DumpWarnings( void ) {
566 int i;
567 idFile *warningFile;
568
569 if ( !warningList.Num() ) {
570 return;
571 }
572
573 warningFile = fileSystem->OpenFileWrite( "warnings.txt", "fs_savepath" );
574 if ( warningFile ) {
575
576 warningFile->Printf( "----- Warnings -----\n\n" );
577 warningFile->Printf( "during %s...\n", warningCaption.c_str() );
578 warningList.Sort();
579 for ( i = 0; i < warningList.Num(); i++ ) {
580 warningList[i].RemoveColors();
581 warningFile->Printf( "WARNING: %s\n", warningList[i].c_str() );
582 }
583 if ( warningList.Num() >= MAX_WARNING_LIST ) {
584 warningFile->Printf( "\nmore than %d warnings!\n", MAX_WARNING_LIST );
585 } else {
586 warningFile->Printf( "\n%d warnings.\n", warningList.Num() );
587 }
588
589 warningFile->Printf( "\n\n----- Errors -----\n\n" );
590 errorList.Sort();
591 for ( i = 0; i < errorList.Num(); i++ ) {
592 errorList[i].RemoveColors();
593 warningFile->Printf( "ERROR: %s", errorList[i].c_str() );
594 }
595
596 warningFile->ForceFlush();
597
598 fileSystem->CloseFile( warningFile );
599
600 #if defined(_WIN32) && !defined(_DEBUG)
601 idStr osPath;
602 osPath = fileSystem->RelativePathToOSPath( "warnings.txt", "fs_savepath" );
603 WinExec( va( "Notepad.exe %s", osPath.c_str() ), SW_SHOW );
604 #endif
605 }
606 }
607
608 /*
609 ==================
610 idCommonLocal::Error
611 ==================
612 */
Error(const char * fmt,...)613 void idCommonLocal::Error( const char *fmt, ... ) {
614 va_list argptr;
615 static int lastErrorTime;
616 static int errorCount;
617 int currentTime;
618
619 int code = ERP_DROP;
620
621 // always turn this off after an error
622 com_refreshOnPrint = false;
623
624 // when we are running automated scripts, make sure we
625 // know if anything failed
626 if ( cvarSystem->GetCVarInteger( "fs_copyfiles" ) ) {
627 code = ERP_FATAL;
628 }
629
630 // if we don't have GL running, make it a fatal error
631 if ( !renderSystem->IsOpenGLRunning() ) {
632 code = ERP_FATAL;
633 }
634
635 // if we got a recursive error, make it fatal
636 if ( com_errorEntered ) {
637 // if we are recursively erroring while exiting
638 // from a fatal error, just kill the entire
639 // process immediately, which will prevent a
640 // full screen rendering window covering the
641 // error dialog
642 if ( com_errorEntered == ERP_FATAL ) {
643 Sys_Quit();
644 }
645 code = ERP_FATAL;
646 }
647
648 // if we are getting a solid stream of ERP_DROP, do an ERP_FATAL
649 currentTime = Sys_Milliseconds();
650 if ( currentTime - lastErrorTime < 100 ) {
651 if ( ++errorCount > 3 ) {
652 code = ERP_FATAL;
653 }
654 } else {
655 errorCount = 0;
656 }
657 lastErrorTime = currentTime;
658
659 com_errorEntered = code;
660
661 va_start (argptr,fmt);
662 idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr );
663 va_end (argptr);
664 errorMessage[sizeof(errorMessage)-1] = '\0';
665
666 // copy the error message to the clip board
667 Sys_SetClipboardData( errorMessage );
668
669 // add the message to the error list
670 errorList.AddUnique( errorMessage );
671
672 // Dont shut down the session for gui editor or debugger
673 if ( !( com_editors & ( EDITOR_GUI | EDITOR_DEBUGGER ) ) ) {
674 session->Stop();
675 }
676
677 if ( code == ERP_DISCONNECT ) {
678 com_errorEntered = 0;
679 throw idException( errorMessage );
680 // The gui editor doesnt want thing to com_error so it handles exceptions instead
681 } else if( com_editors & ( EDITOR_GUI | EDITOR_DEBUGGER ) ) {
682 com_errorEntered = 0;
683 throw idException( errorMessage );
684 } else if ( code == ERP_DROP ) {
685 Printf( "********************\nERROR: %s\n********************\n", errorMessage );
686 com_errorEntered = 0;
687 throw idException( errorMessage );
688 } else {
689 Printf( "********************\nERROR: %s\n********************\n", errorMessage );
690 }
691
692 if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
693 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" );
694 }
695
696 Shutdown();
697
698 Sys_Error( "%s", errorMessage );
699 }
700
701 /*
702 ==================
703 idCommonLocal::FatalError
704
705 Dump out of the game to a system dialog
706 ==================
707 */
FatalError(const char * fmt,...)708 void idCommonLocal::FatalError( const char *fmt, ... ) {
709 va_list argptr;
710
711 // if we got a recursive error, make it fatal
712 if ( com_errorEntered ) {
713 // if we are recursively erroring while exiting
714 // from a fatal error, just kill the entire
715 // process immediately, which will prevent a
716 // full screen rendering window covering the
717 // error dialog
718
719 Sys_Printf( "FATAL: recursed fatal error:\n%s\n", errorMessage );
720
721 va_start( argptr, fmt );
722 idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr );
723 va_end( argptr );
724 errorMessage[sizeof(errorMessage)-1] = '\0';
725
726 Sys_Printf( "%s\n", errorMessage );
727
728 // write the console to a log file?
729 Sys_Quit();
730 }
731 com_errorEntered = ERP_FATAL;
732
733 va_start( argptr, fmt );
734 idStr::vsnPrintf( errorMessage, sizeof(errorMessage), fmt, argptr );
735 va_end( argptr );
736 errorMessage[sizeof(errorMessage)-1] = '\0';
737
738 if ( cvarSystem->GetCVarBool( "r_fullscreen" ) ) {
739 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "vid_restart partial windowed\n" );
740 }
741
742 Sys_Printf( "shutting down: %s\n", errorMessage );
743
744 Shutdown();
745
746 Sys_Error( "%s", errorMessage );
747 }
748
749 /*
750 ==================
751 idCommonLocal::Quit
752 ==================
753 */
Quit(void)754 void idCommonLocal::Quit( void ) {
755
756 #ifdef ID_ALLOW_TOOLS
757 if ( com_editors & EDITOR_RADIANT ) {
758 RadiantInit();
759 return;
760 }
761 #endif
762
763 // don't try to shutdown if we are in a recursive error
764 if ( !com_errorEntered ) {
765 Shutdown();
766 }
767
768 Sys_Quit();
769 }
770
771
772 /*
773 ============================================================================
774
775 COMMAND LINE FUNCTIONS
776
777 + characters separate the commandLine string into multiple console
778 command lines.
779
780 All of these are valid:
781
782 doom +set test blah +map test
783 doom set test blah+map test
784 doom set test blah + map test
785
786 ============================================================================
787 */
788
789 #define MAX_CONSOLE_LINES 32
790 int com_numConsoleLines;
791 idCmdArgs com_consoleLines[MAX_CONSOLE_LINES];
792
793 /*
794 ==================
795 idCommonLocal::ParseCommandLine
796 ==================
797 */
ParseCommandLine(int argc,char ** argv)798 void idCommonLocal::ParseCommandLine( int argc, char **argv ) {
799 int i;
800
801 com_numConsoleLines = 0;
802 // API says no program path
803 for ( i = 0; i < argc; i++ ) {
804 if ( argv[ i ][ 0 ] == '+' ) {
805 com_numConsoleLines++;
806 com_consoleLines[ com_numConsoleLines-1 ].AppendArg( argv[ i ] + 1 );
807 } else {
808 if ( !com_numConsoleLines ) {
809 com_numConsoleLines++;
810 }
811 com_consoleLines[ com_numConsoleLines-1 ].AppendArg( argv[ i ] );
812 }
813 }
814 }
815
816 /*
817 ==================
818 idCommonLocal::ClearCommandLine
819 ==================
820 */
ClearCommandLine(void)821 void idCommonLocal::ClearCommandLine( void ) {
822 com_numConsoleLines = 0;
823 }
824
825 /*
826 ==================
827 idCommonLocal::SafeMode
828
829 Check for "safe" on the command line, which will
830 skip loading of config file (DoomConfig.cfg)
831 ==================
832 */
SafeMode(void)833 bool idCommonLocal::SafeMode( void ) {
834 int i;
835
836 for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
837 if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "safe" )
838 || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "cvar_restart" ) ) {
839 com_consoleLines[ i ].Clear();
840 return true;
841 }
842 }
843 return false;
844 }
845
846 /*
847 ==================
848 idCommonLocal::CheckToolMode
849
850 Check for "renderbump", "dmap", or "editor" on the command line,
851 and force fullscreen off in those cases
852 ==================
853 */
CheckToolMode(void)854 void idCommonLocal::CheckToolMode( void ) {
855 int i;
856
857 for ( i = 0 ; i < com_numConsoleLines ; i++ ) {
858 if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "guieditor" ) ) {
859 com_editors |= EDITOR_GUI;
860 }
861 else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "debugger" ) ) {
862 com_editors |= EDITOR_DEBUGGER;
863 }
864 else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "editor" ) ) {
865 com_editors |= EDITOR_RADIANT;
866 }
867 // Nerve: Add support for the material editor
868 else if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "materialEditor" ) ) {
869 com_editors |= EDITOR_MATERIAL;
870 }
871
872 if ( !idStr::Icmp( com_consoleLines[ i ].Argv(0), "renderbump" )
873 || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "editor" )
874 || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "guieditor" )
875 || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "debugger" )
876 || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "dmap" )
877 || !idStr::Icmp( com_consoleLines[ i ].Argv(0), "materialEditor" )
878 ) {
879 cvarSystem->SetCVarBool( "r_fullscreen", false );
880 return;
881 }
882 }
883 }
884
885 /*
886 ==================
887 idCommonLocal::StartupVariable
888
889 Searches for command line parameters that are set commands.
890 If match is not NULL, only that cvar will be looked for.
891 That is necessary because cddir and basedir need to be set
892 before the filesystem is started, but all other sets should
893 be after execing the config and default.
894 ==================
895 */
StartupVariable(const char * match,bool once)896 void idCommonLocal::StartupVariable( const char *match, bool once ) {
897 int i;
898 const char *s;
899
900 i = 0;
901 while ( i < com_numConsoleLines ) {
902 if ( strcmp( com_consoleLines[ i ].Argv( 0 ), "set" ) ) {
903 i++;
904 continue;
905 }
906
907 s = com_consoleLines[ i ].Argv(1);
908
909 if ( !match || !idStr::Icmp( s, match ) ) {
910 cvarSystem->SetCVarString( s, com_consoleLines[ i ].Argv( 2 ) );
911 if ( once ) {
912 // kill the line
913 int j = i + 1;
914 while ( j < com_numConsoleLines ) {
915 com_consoleLines[ j - 1 ] = com_consoleLines[ j ];
916 j++;
917 }
918 com_numConsoleLines--;
919 continue;
920 }
921 }
922 i++;
923 }
924 }
925
926 /*
927 ==================
928 idCommonLocal::AddStartupCommands
929
930 Adds command line parameters as script statements
931 Commands are separated by + signs
932
933 Returns true if any late commands were added, which
934 will keep the demoloop from immediately starting
935 ==================
936 */
AddStartupCommands(void)937 bool idCommonLocal::AddStartupCommands( void ) {
938 int i;
939 bool added;
940
941 added = false;
942 // quote every token, so args with semicolons can work
943 for ( i = 0; i < com_numConsoleLines; i++ ) {
944 if ( !com_consoleLines[i].Argc() ) {
945 continue;
946 }
947
948 // set commands won't override menu startup
949 if ( idStr::Icmpn( com_consoleLines[i].Argv(0), "set", 3 ) ) {
950 added = true;
951 }
952 // directly as tokenized so nothing gets screwed
953 cmdSystem->BufferCommandArgs( CMD_EXEC_APPEND, com_consoleLines[i] );
954 }
955
956 return added;
957 }
958
959 /*
960 =================
961 idCommonLocal::InitTool
962 =================
963 */
InitTool(const toolFlag_t tool,const idDict * dict)964 void idCommonLocal::InitTool( const toolFlag_t tool, const idDict *dict ) {
965 #ifdef ID_ALLOW_TOOLS
966 if ( tool & EDITOR_SOUND ) {
967 SoundEditorInit( dict );
968 } else if ( tool & EDITOR_LIGHT ) {
969 LightEditorInit( dict );
970 } else if ( tool & EDITOR_PARTICLE ) {
971 ParticleEditorInit( dict );
972 } else if ( tool & EDITOR_AF ) {
973 AFEditorInit( dict );
974 }
975 #endif
976 }
977
978 /*
979 ==================
980 idCommonLocal::ActivateTool
981
982 Activates or Deactivates a tool
983 ==================
984 */
ActivateTool(bool active)985 void idCommonLocal::ActivateTool( bool active ) {
986 com_editorActive = active;
987 Sys_GrabMouseCursor( !active );
988 }
989
990 /*
991 ==================
992 idCommonLocal::WriteFlaggedCVarsToFile
993 ==================
994 */
WriteFlaggedCVarsToFile(const char * filename,int flags,const char * setCmd)995 void idCommonLocal::WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd ) {
996 idFile *f;
997
998 f = fileSystem->OpenFileWrite( filename, "fs_configpath" );
999 if ( !f ) {
1000 Printf( "Couldn't write %s.\n", filename );
1001 return;
1002 }
1003 cvarSystem->WriteFlaggedVariables( flags, setCmd, f );
1004 fileSystem->CloseFile( f );
1005 }
1006
1007 /*
1008 ==================
1009 idCommonLocal::WriteConfigToFile
1010 ==================
1011 */
WriteConfigToFile(const char * filename)1012 void idCommonLocal::WriteConfigToFile( const char *filename ) {
1013 idFile *f;
1014 #ifdef ID_WRITE_VERSION
1015 ID_TIME_T t;
1016 char *curtime;
1017 idStr runtag;
1018 idFile_Memory compressed( "compressed" );
1019 idBase64 out;
1020 #endif
1021
1022 f = fileSystem->OpenFileWrite( filename, "fs_configpath" );
1023 if ( !f ) {
1024 Printf ("Couldn't write %s.\n", filename );
1025 return;
1026 }
1027
1028 #ifdef ID_WRITE_VERSION
1029 assert( config_compressor );
1030 t = time( NULL );
1031 curtime = ctime( &t );
1032 sprintf( runtag, "%s - %s", cvarSystem->GetCVarString( "si_version" ), curtime );
1033 config_compressor->Init( &compressed, true, 8 );
1034 config_compressor->Write( runtag.c_str(), runtag.Length() );
1035 config_compressor->FinishCompress( );
1036 out.Encode( (const byte *)compressed.GetDataPtr(), compressed.Length() );
1037 f->Printf( "// %s\n", out.c_str() );
1038 #endif
1039
1040 idKeyInput::WriteBindings( f );
1041 cvarSystem->WriteFlaggedVariables( CVAR_ARCHIVE, "seta", f );
1042 fileSystem->CloseFile( f );
1043 }
1044
1045 /*
1046 ===============
1047 idCommonLocal::WriteConfiguration
1048
1049 Writes key bindings and archived cvars to config file if modified
1050 ===============
1051 */
WriteConfiguration(void)1052 void idCommonLocal::WriteConfiguration( void ) {
1053 // if we are quiting without fully initializing, make sure
1054 // we don't write out anything
1055 if ( !com_fullyInitialized ) {
1056 return;
1057 }
1058
1059 if ( !( cvarSystem->GetModifiedFlags() & CVAR_ARCHIVE ) ) {
1060 return;
1061 }
1062 cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
1063
1064 // disable printing out the "Writing to:" message
1065 bool developer = com_developer.GetBool();
1066 com_developer.SetBool( false );
1067
1068 WriteConfigToFile( CONFIG_FILE );
1069 session->WriteCDKey( );
1070
1071 // restore the developer cvar
1072 com_developer.SetBool( developer );
1073 }
1074
1075 /*
1076 ===============
1077 KeysFromBinding()
1078 Returns the key bound to the command
1079 ===============
1080 */
KeysFromBinding(const char * bind)1081 const char* idCommonLocal::KeysFromBinding( const char *bind ) {
1082 return idKeyInput::KeysFromBinding( bind );
1083 }
1084
1085 /*
1086 ===============
1087 BindingFromKey()
1088 Returns the binding bound to key
1089 ===============
1090 */
BindingFromKey(const char * key)1091 const char* idCommonLocal::BindingFromKey( const char *key ) {
1092 return idKeyInput::BindingFromKey( key );
1093 }
1094
1095 /*
1096 ===============
1097 ButtonState()
1098 Returns the state of the button
1099 ===============
1100 */
ButtonState(int key)1101 int idCommonLocal::ButtonState( int key ) {
1102 return usercmdGen->ButtonState(key);
1103 }
1104
1105 /*
1106 ===============
1107 ButtonState()
1108 Returns the state of the key
1109 ===============
1110 */
KeyState(int key)1111 int idCommonLocal::KeyState( int key ) {
1112 return usercmdGen->KeyState(key);
1113 }
1114
1115 //============================================================================
1116
1117 #ifdef ID_ALLOW_TOOLS
1118 /*
1119 ==================
1120 Com_Editor_f
1121
1122 we can start the editor dynamically, but we won't ever get back
1123 ==================
1124 */
Com_Editor_f(const idCmdArgs & args)1125 static void Com_Editor_f( const idCmdArgs &args ) {
1126 RadiantInit();
1127 }
1128
1129 /*
1130 =============
1131 Com_ScriptDebugger_f
1132 =============
1133 */
Com_ScriptDebugger_f(const idCmdArgs & args)1134 static void Com_ScriptDebugger_f( const idCmdArgs &args ) {
1135 // Make sure it wasnt on the command line
1136 if ( !( com_editors & EDITOR_DEBUGGER ) ) {
1137 common->Printf( "Script debugger is currently disabled\n" );
1138 // DebuggerClientLaunch();
1139 }
1140 }
1141
1142 /*
1143 =============
1144 Com_EditGUIs_f
1145 =============
1146 */
Com_EditGUIs_f(const idCmdArgs & args)1147 static void Com_EditGUIs_f( const idCmdArgs &args ) {
1148 GUIEditorInit();
1149 }
1150
1151 /*
1152 =============
1153 Com_MaterialEditor_f
1154 =============
1155 */
Com_MaterialEditor_f(const idCmdArgs & args)1156 static void Com_MaterialEditor_f( const idCmdArgs &args ) {
1157 // Turn off sounds
1158 soundSystem->SetMute( true );
1159 MaterialEditorInit();
1160 }
1161 #endif // ID_ALLOW_TOOLS
1162
1163 /*
1164 ============
1165 idCmdSystemLocal::PrintMemInfo_f
1166
1167 This prints out memory debugging data
1168 ============
1169 */
PrintMemInfo_f(const idCmdArgs & args)1170 static void PrintMemInfo_f( const idCmdArgs &args ) {
1171 MemInfo_t mi;
1172
1173 memset( &mi, 0, sizeof( mi ) );
1174 mi.filebase = session->GetCurrentMapName();
1175
1176 renderSystem->PrintMemInfo( &mi ); // textures and models
1177 soundSystem->PrintMemInfo( &mi ); // sounds
1178
1179 common->Printf( " Used image memory: %s bytes\n", idStr::FormatNumber( mi.imageAssetsTotal ).c_str() );
1180 mi.assetTotals += mi.imageAssetsTotal;
1181
1182 common->Printf( " Used model memory: %s bytes\n", idStr::FormatNumber( mi.modelAssetsTotal ).c_str() );
1183 mi.assetTotals += mi.modelAssetsTotal;
1184
1185 common->Printf( " Used sound memory: %s bytes\n", idStr::FormatNumber( mi.soundAssetsTotal ).c_str() );
1186 mi.assetTotals += mi.soundAssetsTotal;
1187
1188 common->Printf( " Used asset memory: %s bytes\n", idStr::FormatNumber( mi.assetTotals ).c_str() );
1189
1190 // write overview file
1191 idFile *f;
1192
1193 f = fileSystem->OpenFileAppend( "maps/printmeminfo.txt" );
1194 if ( !f ) {
1195 return;
1196 }
1197
1198 f->Printf( "total(%s ) image(%s ) model(%s ) sound(%s ): %s\n", idStr::FormatNumber( mi.assetTotals ).c_str(), idStr::FormatNumber( mi.imageAssetsTotal ).c_str(),
1199 idStr::FormatNumber( mi.modelAssetsTotal ).c_str(), idStr::FormatNumber( mi.soundAssetsTotal ).c_str(), mi.filebase.c_str() );
1200
1201 fileSystem->CloseFile( f );
1202 }
1203
1204 #ifdef ID_ALLOW_TOOLS
1205 /*
1206 ==================
1207 Com_EditLights_f
1208 ==================
1209 */
Com_EditLights_f(const idCmdArgs & args)1210 static void Com_EditLights_f( const idCmdArgs &args ) {
1211 LightEditorInit( NULL );
1212 cvarSystem->SetCVarInteger( "g_editEntityMode", 1 );
1213 }
1214
1215 /*
1216 ==================
1217 Com_EditSounds_f
1218 ==================
1219 */
Com_EditSounds_f(const idCmdArgs & args)1220 static void Com_EditSounds_f( const idCmdArgs &args ) {
1221 SoundEditorInit( NULL );
1222 cvarSystem->SetCVarInteger( "g_editEntityMode", 2 );
1223 }
1224
1225 /*
1226 ==================
1227 Com_EditDecls_f
1228 ==================
1229 */
Com_EditDecls_f(const idCmdArgs & args)1230 static void Com_EditDecls_f( const idCmdArgs &args ) {
1231 DeclBrowserInit( NULL );
1232 }
1233
1234 /*
1235 ==================
1236 Com_EditAFs_f
1237 ==================
1238 */
Com_EditAFs_f(const idCmdArgs & args)1239 static void Com_EditAFs_f( const idCmdArgs &args ) {
1240 AFEditorInit( NULL );
1241 }
1242
1243 /*
1244 ==================
1245 Com_EditParticles_f
1246 ==================
1247 */
Com_EditParticles_f(const idCmdArgs & args)1248 static void Com_EditParticles_f( const idCmdArgs &args ) {
1249 ParticleEditorInit( NULL );
1250 }
1251
1252 /*
1253 ==================
1254 Com_EditScripts_f
1255 ==================
1256 */
Com_EditScripts_f(const idCmdArgs & args)1257 static void Com_EditScripts_f( const idCmdArgs &args ) {
1258 ScriptEditorInit( NULL );
1259 }
1260
1261 /*
1262 ==================
1263 Com_EditPDAs_f
1264 ==================
1265 */
Com_EditPDAs_f(const idCmdArgs & args)1266 static void Com_EditPDAs_f( const idCmdArgs &args ) {
1267 PDAEditorInit( NULL );
1268 }
1269 #endif // ID_ALLOW_TOOLS
1270
1271 /*
1272 ==================
1273 Com_Error_f
1274
1275 Just throw a fatal error to test error shutdown procedures.
1276 ==================
1277 */
Com_Error_f(const idCmdArgs & args)1278 static void Com_Error_f( const idCmdArgs &args ) {
1279 if ( !com_developer.GetBool() ) {
1280 commonLocal.Printf( "error may only be used in developer mode\n" );
1281 return;
1282 }
1283
1284 if ( args.Argc() > 1 ) {
1285 commonLocal.FatalError( "Testing fatal error" );
1286 } else {
1287 commonLocal.Error( "Testing drop error" );
1288 }
1289 }
1290
1291 /*
1292 ==================
1293 Com_Freeze_f
1294
1295 Just freeze in place for a given number of seconds to test error recovery.
1296 ==================
1297 */
Com_Freeze_f(const idCmdArgs & args)1298 static void Com_Freeze_f( const idCmdArgs &args ) {
1299 float s;
1300 int start, now;
1301
1302 if ( args.Argc() != 2 ) {
1303 commonLocal.Printf( "freeze <seconds>\n" );
1304 return;
1305 }
1306
1307 if ( !com_developer.GetBool() ) {
1308 commonLocal.Printf( "freeze may only be used in developer mode\n" );
1309 return;
1310 }
1311
1312 s = atof( args.Argv(1) );
1313
1314 start = eventLoop->Milliseconds();
1315
1316 while ( 1 ) {
1317 now = eventLoop->Milliseconds();
1318 if ( ( now - start ) * 0.001f > s ) {
1319 break;
1320 }
1321 }
1322 }
1323
1324 /*
1325 =================
1326 Com_Crash_f
1327
1328 A way to force a bus error for development reasons
1329 =================
1330 */
Com_Crash_f(const idCmdArgs & args)1331 static void Com_Crash_f( const idCmdArgs &args ) {
1332 if ( !com_developer.GetBool() ) {
1333 commonLocal.Printf( "crash may only be used in developer mode\n" );
1334 return;
1335 }
1336
1337 #ifdef __GNUC__
1338 __builtin_trap();
1339 #else
1340 * ( int * ) 0 = 0x12345678;
1341 #endif
1342 }
1343
1344 /*
1345 =================
1346 Com_Quit_f
1347 =================
1348 */
Com_Quit_f(const idCmdArgs & args)1349 static void Com_Quit_f( const idCmdArgs &args ) {
1350 commonLocal.Quit();
1351 }
1352
1353 /*
1354 ===============
1355 Com_WriteConfig_f
1356
1357 Write the config file to a specific name
1358 ===============
1359 */
Com_WriteConfig_f(const idCmdArgs & args)1360 void Com_WriteConfig_f( const idCmdArgs &args ) {
1361 idStr filename;
1362
1363 if ( args.Argc() != 2 ) {
1364 commonLocal.Printf( "Usage: writeconfig <filename>\n" );
1365 return;
1366 }
1367
1368 filename = args.Argv(1);
1369 filename.DefaultFileExtension( ".cfg" );
1370 commonLocal.Printf( "Writing %s.\n", filename.c_str() );
1371 commonLocal.WriteConfigToFile( filename );
1372 }
1373
1374 /*
1375 =================
1376 Com_SetMachineSpecs_f
1377 =================
1378 */
Com_SetMachineSpec_f(const idCmdArgs & args)1379 void Com_SetMachineSpec_f( const idCmdArgs &args ) {
1380 commonLocal.SetMachineSpec();
1381 }
1382
1383 /*
1384 =================
1385 Com_ExecMachineSpecs_f
1386 =================
1387 */
1388 #ifdef MACOS_X
1389 void OSX_GetVideoCard( int& outVendorId, int& outDeviceId );
1390 bool OSX_GetCPUIdentification( int& cpuId, bool& oldArchitecture );
1391 #endif
Com_ExecMachineSpec_f(const idCmdArgs & args)1392 void Com_ExecMachineSpec_f( const idCmdArgs &args ) {
1393 if ( com_machineSpec.GetInteger() == 3 ) {
1394 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1395 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1396 cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE );
1397 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1398 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1399 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1400 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE );
1401 cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE );
1402 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1403 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1404 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 0, CVAR_ARCHIVE );
1405 cvarSystem->SetCVarInteger( "image_downsize", 0 , CVAR_ARCHIVE );
1406 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1407 cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE );
1408 cvarSystem->SetCVarInteger( "image_useCompression", 0, CVAR_ARCHIVE );
1409 cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE );
1410 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 0, CVAR_ARCHIVE );
1411 cvarSystem->SetCVarInteger( "r_mode", 5, CVAR_ARCHIVE );
1412 cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE );
1413 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1414 } else if ( com_machineSpec.GetInteger() == 2 ) {
1415 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1416 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1417 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1418 cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE );
1419 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1420 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1421 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1422 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE );
1423 cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE );
1424 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1425 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1426 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE );
1427 cvarSystem->SetCVarInteger( "image_downsize", 0, CVAR_ARCHIVE );
1428 cvarSystem->SetCVarInteger( "image_anisotropy", 8, CVAR_ARCHIVE );
1429 cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE );
1430 cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 0, CVAR_ARCHIVE );
1431 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 0, CVAR_ARCHIVE );
1432 cvarSystem->SetCVarInteger( "image_useNormalCompression", 0, CVAR_ARCHIVE );
1433 cvarSystem->SetCVarInteger( "r_mode", 4, CVAR_ARCHIVE );
1434 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1435 } else if ( com_machineSpec.GetInteger() == 1 ) {
1436 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1437 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1438 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1439 cvarSystem->SetCVarInteger( "image_downSize", 0, CVAR_ARCHIVE );
1440 cvarSystem->SetCVarInteger( "image_forceDownSize", 0, CVAR_ARCHIVE );
1441 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1442 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1443 cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE );
1444 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1445 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE );
1446 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 0, CVAR_ARCHIVE );
1447 cvarSystem->SetCVarInteger( "image_downSizeBump", 0, CVAR_ARCHIVE );
1448 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1449 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1450 cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE );
1451 cvarSystem->SetCVarInteger( "r_mode", 3, CVAR_ARCHIVE );
1452 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1453 } else {
1454 cvarSystem->SetCVarString( "image_filter", "GL_LINEAR_MIPMAP_LINEAR", CVAR_ARCHIVE );
1455 cvarSystem->SetCVarInteger( "image_anisotropy", 1, CVAR_ARCHIVE );
1456 cvarSystem->SetCVarInteger( "image_lodbias", 0, CVAR_ARCHIVE );
1457 cvarSystem->SetCVarInteger( "image_roundDown", 1, CVAR_ARCHIVE );
1458 cvarSystem->SetCVarInteger( "image_preload", 1, CVAR_ARCHIVE );
1459 cvarSystem->SetCVarInteger( "image_useAllFormats", 1, CVAR_ARCHIVE );
1460 cvarSystem->SetCVarInteger( "image_usePrecompressedTextures", 1, CVAR_ARCHIVE );
1461 cvarSystem->SetCVarInteger( "image_downSize", 1, CVAR_ARCHIVE );
1462 cvarSystem->SetCVarInteger( "image_anisotropy", 0, CVAR_ARCHIVE );
1463 cvarSystem->SetCVarInteger( "image_useCompression", 1, CVAR_ARCHIVE );
1464 cvarSystem->SetCVarInteger( "image_ignoreHighQuality", 1, CVAR_ARCHIVE );
1465 cvarSystem->SetCVarInteger( "s_maxSoundsPerShader", 1, CVAR_ARCHIVE );
1466 cvarSystem->SetCVarInteger( "image_downSizeSpecular", 1, CVAR_ARCHIVE );
1467 cvarSystem->SetCVarInteger( "image_downSizeBump", 1, CVAR_ARCHIVE );
1468 cvarSystem->SetCVarInteger( "image_downSizeSpecularLimit", 64, CVAR_ARCHIVE );
1469 cvarSystem->SetCVarInteger( "image_downSizeBumpLimit", 256, CVAR_ARCHIVE );
1470 cvarSystem->SetCVarInteger( "r_mode", 3 , CVAR_ARCHIVE );
1471 cvarSystem->SetCVarInteger( "image_useNormalCompression", 2, CVAR_ARCHIVE );
1472 cvarSystem->SetCVarInteger( "r_multiSamples", 0, CVAR_ARCHIVE );
1473 }
1474
1475 cvarSystem->SetCVarBool( "com_purgeAll", false, CVAR_ARCHIVE );
1476 cvarSystem->SetCVarBool( "r_forceLoadImages", false, CVAR_ARCHIVE );
1477
1478 cvarSystem->SetCVarBool( "g_decals", true, CVAR_ARCHIVE );
1479 cvarSystem->SetCVarBool( "g_projectileLights", true, CVAR_ARCHIVE );
1480 cvarSystem->SetCVarBool( "g_doubleVision", true, CVAR_ARCHIVE );
1481 cvarSystem->SetCVarBool( "g_muzzleFlash", true, CVAR_ARCHIVE );
1482
1483 #if MACOS_X
1484 // On low settings, G4 systems & 64MB FX5200/NV34 Systems should default shadows off
1485 bool oldArch;
1486 int vendorId, deviceId, cpuId;
1487 OSX_GetVideoCard( vendorId, deviceId );
1488 OSX_GetCPUIdentification( cpuId, oldArch );
1489 bool isFX5200 = vendorId == 0x10DE && ( deviceId & 0x0FF0 ) == 0x0320;
1490 if ( oldArch && ( com_machineSpec.GetInteger() == 0 ) ) {
1491 cvarSystem->SetCVarBool( "r_shadows", false, CVAR_ARCHIVE );
1492 } else {
1493 cvarSystem->SetCVarBool( "r_shadows", true, CVAR_ARCHIVE );
1494 }
1495 #endif
1496 }
1497
1498 /*
1499 =================
1500 Com_ReloadEngine_f
1501 =================
1502 */
Com_ReloadEngine_f(const idCmdArgs & args)1503 void Com_ReloadEngine_f( const idCmdArgs &args ) {
1504 bool menu = false;
1505
1506 if ( !commonLocal.IsInitialized() ) {
1507 return;
1508 }
1509
1510 if ( args.Argc() > 1 && idStr::Icmp( args.Argv( 1 ), "menu" ) == 0 ) {
1511 menu = true;
1512 }
1513
1514 common->Printf( "============= ReloadEngine start =============\n" );
1515 if ( !menu ) {
1516 Sys_ShowConsole( 1, false );
1517 }
1518 commonLocal.ShutdownGame( true );
1519 commonLocal.InitGame();
1520 if ( !menu && !idAsyncNetwork::serverDedicated.GetBool() ) {
1521 Sys_ShowConsole( 0, false );
1522 }
1523 common->Printf( "============= ReloadEngine end ===============\n" );
1524
1525 if ( !cmdSystem->PostReloadEngine() ) {
1526 if ( menu ) {
1527 session->StartMenu( );
1528 }
1529 }
1530 }
1531
1532 /*
1533 ===============
1534 idCommonLocal::GetLanguageDict
1535 ===============
1536 */
GetLanguageDict(void)1537 const idLangDict *idCommonLocal::GetLanguageDict( void ) {
1538 return &languageDict;
1539 }
1540
1541 /*
1542 ===============
1543 idCommonLocal::FilterLangList
1544 ===============
1545 */
FilterLangList(idStrList * list,idStr lang)1546 void idCommonLocal::FilterLangList( idStrList* list, idStr lang ) {
1547
1548 idStr temp;
1549 for( int i = 0; i < list->Num(); i++ ) {
1550 temp = (*list)[i];
1551 temp = temp.Right(temp.Length()-strlen("strings/"));
1552 temp = temp.Left(lang.Length());
1553 if(idStr::Icmp(temp, lang) != 0) {
1554 list->RemoveIndex(i);
1555 i--;
1556 }
1557 }
1558 }
1559
1560 /*
1561 ===============
1562 idCommonLocal::InitLanguageDict
1563 ===============
1564 */
InitLanguageDict(void)1565 void idCommonLocal::InitLanguageDict( void ) {
1566 idStr fileName;
1567 languageDict.Clear();
1568
1569 //D3XP: Instead of just loading a single lang file for each language
1570 //we are going to load all files that begin with the language name
1571 //similar to the way pak files work. So you can place english001.lang
1572 //to add new strings to the english language dictionary
1573 idFileList* langFiles;
1574 langFiles = fileSystem->ListFilesTree( "strings", ".lang", true );
1575
1576 idStrList langList = langFiles->GetList();
1577
1578 StartupVariable( "sys_lang", false ); // let it be set on the command line - this is needed because this init happens very early
1579 idStr langName = cvarSystem->GetCVarString( "sys_lang" );
1580
1581 //Loop through the list and filter
1582 idStrList currentLangList = langList;
1583 FilterLangList(¤tLangList, langName);
1584
1585 if ( currentLangList.Num() == 0 ) {
1586 // reset cvar to default and try to load again
1587 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "reset sys_lang" );
1588 langName = cvarSystem->GetCVarString( "sys_lang" );
1589 currentLangList = langList;
1590 FilterLangList(¤tLangList, langName);
1591 }
1592
1593 for( int i = 0; i < currentLangList.Num(); i++ ) {
1594 //common->Printf("%s\n", currentLangList[i].c_str());
1595 languageDict.Load( currentLangList[i], false );
1596 }
1597
1598 fileSystem->FreeFileList(langFiles);
1599
1600 Sys_InitScanTable();
1601 }
1602
1603 /*
1604 ===============
1605 idCommonLocal::LocalizeSpecificMapData
1606 ===============
1607 */
LocalizeSpecificMapData(const char * fileName,idLangDict & langDict,const idLangDict & replaceArgs)1608 void idCommonLocal::LocalizeSpecificMapData( const char *fileName, idLangDict &langDict, const idLangDict &replaceArgs ) {
1609 idStr out, ws, work;
1610
1611 idMapFile map;
1612 if ( map.Parse( fileName, false, false ) ) {
1613 int count = map.GetNumEntities();
1614 for ( int i = 0; i < count; i++ ) {
1615 idMapEntity *ent = map.GetEntity( i );
1616 if ( ent ) {
1617 for ( int j = 0; j < replaceArgs.GetNumKeyVals(); j++ ) {
1618 const idLangKeyValue *kv = replaceArgs.GetKeyVal( j );
1619 const char *temp = ent->epairs.GetString( kv->key );
1620 if ( temp && *temp ) {
1621 idStr val = kv->value;
1622 if ( val == temp ) {
1623 ent->epairs.Set( kv->key, langDict.AddString( temp ) );
1624 }
1625 }
1626 }
1627 }
1628 }
1629 map.Write( fileName, ".map" );
1630 }
1631 }
1632
1633 /*
1634 ===============
1635 idCommonLocal::LocalizeMapData
1636 ===============
1637 */
LocalizeMapData(const char * fileName,idLangDict & langDict)1638 void idCommonLocal::LocalizeMapData( const char *fileName, idLangDict &langDict ) {
1639 const char *buffer = NULL;
1640 idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1641
1642 common->SetRefreshOnPrint( true );
1643
1644 if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1645 src.LoadMemory( buffer, strlen(buffer), fileName );
1646 if ( src.IsLoaded() ) {
1647 common->Printf( "Processing %s\n", fileName );
1648 idStr mapFileName;
1649 idToken token, token2;
1650 idLangDict replaceArgs;
1651 while ( src.ReadToken( &token ) ) {
1652 mapFileName = token;
1653 replaceArgs.Clear();
1654 src.ExpectTokenString( "{" );
1655 while ( src.ReadToken( &token) ) {
1656 if ( token == "}" ) {
1657 break;
1658 }
1659 if ( src.ReadToken( &token2 ) ) {
1660 if ( token2 == "}" ) {
1661 break;
1662 }
1663 replaceArgs.AddKeyVal( token, token2 );
1664 }
1665 }
1666 common->Printf( " localizing map %s...\n", mapFileName.c_str() );
1667 LocalizeSpecificMapData( mapFileName, langDict, replaceArgs );
1668 }
1669 }
1670 fileSystem->FreeFile( (void*)buffer );
1671 }
1672
1673 common->SetRefreshOnPrint( false );
1674 }
1675
1676 /*
1677 ===============
1678 idCommonLocal::LocalizeGui
1679 ===============
1680 */
LocalizeGui(const char * fileName,idLangDict & langDict)1681 void idCommonLocal::LocalizeGui( const char *fileName, idLangDict &langDict ) {
1682 idStr out, ws, work;
1683 const char *buffer = NULL;
1684 out.Empty();
1685 int k;
1686 char ch;
1687 char slash = '\\';
1688 char tab = 't';
1689 char nl = 'n';
1690 idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1691 if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1692 src.LoadMemory( buffer, strlen(buffer), fileName );
1693 if ( src.IsLoaded() ) {
1694 idFile *outFile = fileSystem->OpenFileWrite( fileName );
1695 common->Printf( "Processing %s\n", fileName );
1696 session->UpdateScreen();
1697 idToken token;
1698 while( src.ReadToken( &token ) ) {
1699 src.GetLastWhiteSpace( ws );
1700 out += ws;
1701 if ( token.type == TT_STRING ) {
1702 out += va( "\"%s\"", token.c_str() );
1703 } else {
1704 out += token;
1705 }
1706 if ( out.Length() > 200000 ) {
1707 outFile->Write( out.c_str(), out.Length() );
1708 out = "";
1709 }
1710 work = token.Right( 6 );
1711 if ( token.Icmp( "text" ) == 0 || work.Icmp( "::text" ) == 0 || token.Icmp( "choices" ) == 0 ) {
1712 if ( src.ReadToken( &token ) ) {
1713 // see if already exists, if so save that id to this position in this file
1714 // otherwise add this to the list and save the id to this position in this file
1715 src.GetLastWhiteSpace( ws );
1716 out += ws;
1717 token = langDict.AddString( token );
1718 out += "\"";
1719 for ( k = 0; k < token.Length(); k++ ) {
1720 ch = token[k];
1721 if ( ch == '\t' ) {
1722 out += slash;
1723 out += tab;
1724 } else if ( ch == '\n' || ch == '\r' ) {
1725 out += slash;
1726 out += nl;
1727 } else {
1728 out += ch;
1729 }
1730 }
1731 out += "\"";
1732 }
1733 } else if ( token.Icmp( "comment" ) == 0 ) {
1734 if ( src.ReadToken( &token ) ) {
1735 // need to write these out by hand to preserve any \n's
1736 // see if already exists, if so save that id to this position in this file
1737 // otherwise add this to the list and save the id to this position in this file
1738 src.GetLastWhiteSpace( ws );
1739 out += ws;
1740 out += "\"";
1741 for ( k = 0; k < token.Length(); k++ ) {
1742 ch = token[k];
1743 if ( ch == '\t' ) {
1744 out += slash;
1745 out += tab;
1746 } else if ( ch == '\n' || ch == '\r' ) {
1747 out += slash;
1748 out += nl;
1749 } else {
1750 out += ch;
1751 }
1752 }
1753 out += "\"";
1754 }
1755 }
1756 }
1757 outFile->Write( out.c_str(), out.Length() );
1758 fileSystem->CloseFile( outFile );
1759 }
1760 fileSystem->FreeFile( (void*)buffer );
1761 }
1762 }
1763
1764 /*
1765 =================
1766 ReloadLanguage_f
1767 =================
1768 */
Com_ReloadLanguage_f(const idCmdArgs & args)1769 void Com_ReloadLanguage_f( const idCmdArgs &args ) {
1770 commonLocal.InitLanguageDict();
1771 }
1772
1773 typedef idHashTable<idStrList> ListHash;
LoadMapLocalizeData(ListHash & listHash)1774 void LoadMapLocalizeData(ListHash& listHash) {
1775
1776 idStr fileName = "map_localize.cfg";
1777 const char *buffer = NULL;
1778 idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1779
1780 if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1781 src.LoadMemory( buffer, strlen(buffer), fileName );
1782 if ( src.IsLoaded() ) {
1783 idStr classname;
1784 idToken token;
1785
1786
1787
1788 while ( src.ReadToken( &token ) ) {
1789 classname = token;
1790 src.ExpectTokenString( "{" );
1791
1792 idStrList list;
1793 while ( src.ReadToken( &token) ) {
1794 if ( token == "}" ) {
1795 break;
1796 }
1797 list.Append(token);
1798 }
1799
1800 listHash.Set(classname, list);
1801 }
1802 }
1803 fileSystem->FreeFile( (void*)buffer );
1804 }
1805
1806 }
1807
LoadGuiParmExcludeList(idStrList & list)1808 void LoadGuiParmExcludeList(idStrList& list) {
1809
1810 idStr fileName = "guiparm_exclude.cfg";
1811 const char *buffer = NULL;
1812 idLexer src( LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
1813
1814 if ( fileSystem->ReadFile( fileName, (void**)&buffer ) > 0 ) {
1815 src.LoadMemory( buffer, strlen(buffer), fileName );
1816 if ( src.IsLoaded() ) {
1817 idStr classname;
1818 idToken token;
1819
1820
1821
1822 while ( src.ReadToken( &token ) ) {
1823 list.Append(token);
1824 }
1825 }
1826 fileSystem->FreeFile( (void*)buffer );
1827 }
1828 }
1829
TestMapVal(idStr & str)1830 bool TestMapVal(idStr& str) {
1831 //Already Localized?
1832 if(str.Find("#str_") != -1) {
1833 return false;
1834 }
1835
1836 return true;
1837 }
1838
TestGuiParm(const char * parm,const char * value,idStrList & excludeList)1839 bool TestGuiParm(const char* parm, const char* value, idStrList& excludeList) {
1840
1841 idStr testVal = value;
1842
1843 //Already Localized?
1844 if(testVal.Find("#str_") != -1) {
1845 return false;
1846 }
1847
1848 //Numeric
1849 if(testVal.IsNumeric()) {
1850 return false;
1851 }
1852
1853 //Contains ::
1854 if(testVal.Find("::") != -1) {
1855 return false;
1856 }
1857
1858 //Contains /
1859 if(testVal.Find("/") != -1) {
1860 return false;
1861 }
1862
1863 if(excludeList.Find(testVal)) {
1864 return false;
1865 }
1866
1867 return true;
1868 }
1869
GetFileList(const char * dir,const char * ext,idStrList & list)1870 void GetFileList(const char* dir, const char* ext, idStrList& list) {
1871
1872 //Recurse Subdirectories
1873 idStrList dirList;
1874 Sys_ListFiles(dir, "/", dirList);
1875 for(int i = 0; i < dirList.Num(); i++) {
1876 if(dirList[i] == "." || dirList[i] == "..") {
1877 continue;
1878 }
1879 idStr fullName = va("%s/%s", dir, dirList[i].c_str());
1880 GetFileList(fullName, ext, list);
1881 }
1882
1883 idStrList fileList;
1884 Sys_ListFiles(dir, ext, fileList);
1885 for(int i = 0; i < fileList.Num(); i++) {
1886 idStr fullName = va("%s/%s", dir, fileList[i].c_str());
1887 list.Append(fullName);
1888 }
1889 }
1890
LocalizeMap(const char * mapName,idLangDict & langDict,ListHash & listHash,idStrList & excludeList,bool writeFile)1891 int LocalizeMap(const char* mapName, idLangDict &langDict, ListHash& listHash, idStrList& excludeList, bool writeFile) {
1892
1893 common->Printf("Localizing Map '%s'\n", mapName);
1894
1895 int strCount = 0;
1896
1897 idMapFile map;
1898 if ( map.Parse(mapName, false, false ) ) {
1899 int count = map.GetNumEntities();
1900 for ( int j = 0; j < count; j++ ) {
1901 idMapEntity *ent = map.GetEntity( j );
1902 if ( ent ) {
1903
1904 idStr classname = ent->epairs.GetString("classname");
1905
1906 //Hack: for info_location
1907 bool hasLocation = false;
1908
1909 idStrList* list;
1910 listHash.Get(classname, &list);
1911 if(list) {
1912
1913 for(int k = 0; k < list->Num(); k++) {
1914
1915 idStr val = ent->epairs.GetString((*list)[k], "");
1916
1917 if(val.Length() && classname == "info_location" && (*list)[k] == "location") {
1918 hasLocation = true;
1919 }
1920
1921 if(val.Length() && TestMapVal(val)) {
1922
1923 if(!hasLocation || (*list)[k] == "location") {
1924 //Localize it!!!
1925 strCount++;
1926 ent->epairs.Set( (*list)[k], langDict.AddString( val ) );
1927 }
1928 }
1929 }
1930 }
1931
1932 listHash.Get("all", &list);
1933 if(list) {
1934 for(int k = 0; k < list->Num(); k++) {
1935 idStr val = ent->epairs.GetString((*list)[k], "");
1936 if(val.Length() && TestMapVal(val)) {
1937 //Localize it!!!
1938 strCount++;
1939 ent->epairs.Set( (*list)[k], langDict.AddString( val ) );
1940 }
1941 }
1942 }
1943
1944 //Localize the gui_parms
1945 const idKeyValue* kv = ent->epairs.MatchPrefix("gui_parm");
1946 while( kv ) {
1947 if(TestGuiParm(kv->GetKey(), kv->GetValue(), excludeList)) {
1948 //Localize It!
1949 strCount++;
1950 ent->epairs.Set( kv->GetKey(), langDict.AddString( kv->GetValue() ) );
1951 }
1952 kv = ent->epairs.MatchPrefix( "gui_parm", kv );
1953 }
1954 }
1955 }
1956 if(writeFile && strCount > 0) {
1957 //Before we write the map file lets make a backup of the original
1958 idStr file = fileSystem->RelativePathToOSPath(mapName);
1959 idStr bak = file.Left(file.Length() - 4);
1960 bak.Append(".bak_loc");
1961 fileSystem->CopyFile( file, bak );
1962
1963 map.Write( mapName, ".map" );
1964 }
1965 }
1966
1967 common->Printf("Count: %d\n", strCount);
1968 return strCount;
1969 }
1970
1971 /*
1972 =================
1973 LocalizeMaps_f
1974 =================
1975 */
Com_LocalizeMaps_f(const idCmdArgs & args)1976 void Com_LocalizeMaps_f( const idCmdArgs &args ) {
1977 if ( args.Argc() < 2 ) {
1978 common->Printf( "Usage: localizeMaps <count | dictupdate | all> <map>\n" );
1979 return;
1980 }
1981
1982 int strCount = 0;
1983
1984 bool count = false;
1985 bool dictUpdate = false;
1986 bool write = false;
1987
1988 if ( idStr::Icmp( args.Argv(1), "count" ) == 0 ) {
1989 count = true;
1990 } else if ( idStr::Icmp( args.Argv(1), "dictupdate" ) == 0 ) {
1991 count = true;
1992 dictUpdate = true;
1993 } else if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
1994 count = true;
1995 dictUpdate = true;
1996 write = true;
1997 } else {
1998 common->Printf( "Invalid Command\n" );
1999 common->Printf( "Usage: localizeMaps <count | dictupdate | all>\n" );
2000 return;
2001
2002 }
2003
2004 idLangDict strTable;
2005 idStr filename = va("strings/english%.3i.lang", com_product_lang_ext.GetInteger());
2006 if(strTable.Load( filename ) == false) {
2007 //This is a new file so set the base index
2008 strTable.SetBaseID(com_product_lang_ext.GetInteger()*100000);
2009 }
2010
2011 common->SetRefreshOnPrint( true );
2012
2013 ListHash listHash;
2014 LoadMapLocalizeData(listHash);
2015
2016 idStrList excludeList;
2017 LoadGuiParmExcludeList(excludeList);
2018
2019 if(args.Argc() == 3) {
2020 strCount += LocalizeMap(args.Argv(2), strTable, listHash, excludeList, write);
2021 } else {
2022 idStrList files;
2023 GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
2024 for ( int i = 0; i < files.Num(); i++ ) {
2025 idStr file = fileSystem->OSPathToRelativePath(files[i]);
2026 strCount += LocalizeMap(file, strTable, listHash, excludeList, write);
2027 }
2028 }
2029
2030 if(count) {
2031 common->Printf("Localize String Count: %d\n", strCount);
2032 }
2033
2034 common->SetRefreshOnPrint( false );
2035
2036 if(dictUpdate) {
2037 strTable.Save( filename );
2038 }
2039 }
2040
2041 /*
2042 =================
2043 LocalizeGuis_f
2044 =================
2045 */
Com_LocalizeGuis_f(const idCmdArgs & args)2046 void Com_LocalizeGuis_f( const idCmdArgs &args ) {
2047
2048 if ( args.Argc() != 2 ) {
2049 common->Printf( "Usage: localizeGuis <all | gui>\n" );
2050 return;
2051 }
2052
2053 idLangDict strTable;
2054
2055 idStr filename = va("strings/english%.3i.lang", com_product_lang_ext.GetInteger());
2056 if(strTable.Load( filename ) == false) {
2057 //This is a new file so set the base index
2058 strTable.SetBaseID(com_product_lang_ext.GetInteger()*100000);
2059 }
2060
2061 idFileList *files;
2062 if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
2063 idStr game = cvarSystem->GetCVarString( "fs_game" );
2064 if(game.Length()) {
2065 files = fileSystem->ListFilesTree( "guis", "*.gui", true, game );
2066 } else {
2067 files = fileSystem->ListFilesTree( "guis", "*.gui", true );
2068 }
2069 for ( int i = 0; i < files->GetNumFiles(); i++ ) {
2070 commonLocal.LocalizeGui( files->GetFile( i ), strTable );
2071 }
2072 fileSystem->FreeFileList( files );
2073
2074 if(game.Length()) {
2075 files = fileSystem->ListFilesTree( "guis", "*.pd", true, game );
2076 } else {
2077 files = fileSystem->ListFilesTree( "guis", "*.pd", true, "d3xp" );
2078 }
2079
2080 for ( int i = 0; i < files->GetNumFiles(); i++ ) {
2081 commonLocal.LocalizeGui( files->GetFile( i ), strTable );
2082 }
2083 fileSystem->FreeFileList( files );
2084
2085 } else {
2086 commonLocal.LocalizeGui( args.Argv(1), strTable );
2087 }
2088 strTable.Save( filename );
2089 }
2090
Com_LocalizeGuiParmsTest_f(const idCmdArgs & args)2091 void Com_LocalizeGuiParmsTest_f( const idCmdArgs &args ) {
2092
2093 common->SetRefreshOnPrint( true );
2094
2095 idFile *localizeFile = fileSystem->OpenFileWrite( "gui_parm_localize.csv" );
2096 idFile *noLocalizeFile = fileSystem->OpenFileWrite( "gui_parm_nolocalize.csv" );
2097
2098 idStrList excludeList;
2099 LoadGuiParmExcludeList(excludeList);
2100
2101 idStrList files;
2102 GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
2103
2104 for ( int i = 0; i < files.Num(); i++ ) {
2105
2106 common->Printf("Testing Map '%s'\n", files[i].c_str());
2107 idMapFile map;
2108
2109 idStr file = fileSystem->OSPathToRelativePath(files[i]);
2110 if ( map.Parse(file, false, false ) ) {
2111 int count = map.GetNumEntities();
2112 for ( int j = 0; j < count; j++ ) {
2113 idMapEntity *ent = map.GetEntity( j );
2114 if ( ent ) {
2115 const idKeyValue* kv = ent->epairs.MatchPrefix("gui_parm");
2116 while( kv ) {
2117 if(TestGuiParm(kv->GetKey(), kv->GetValue(), excludeList)) {
2118 idStr out = va("%s,%s,%s\r\n", kv->GetValue().c_str(), kv->GetKey().c_str(), file.c_str());
2119 localizeFile->Write( out.c_str(), out.Length() );
2120 } else {
2121 idStr out = va("%s,%s,%s\r\n", kv->GetValue().c_str(), kv->GetKey().c_str(), file.c_str());
2122 noLocalizeFile->Write( out.c_str(), out.Length() );
2123 }
2124 kv = ent->epairs.MatchPrefix( "gui_parm", kv );
2125 }
2126 }
2127 }
2128 }
2129 }
2130
2131 fileSystem->CloseFile( localizeFile );
2132 fileSystem->CloseFile( noLocalizeFile );
2133
2134 common->SetRefreshOnPrint( false );
2135 }
2136
2137
Com_LocalizeMapsTest_f(const idCmdArgs & args)2138 void Com_LocalizeMapsTest_f( const idCmdArgs &args ) {
2139
2140 ListHash listHash;
2141 LoadMapLocalizeData(listHash);
2142
2143
2144 common->SetRefreshOnPrint( true );
2145
2146 idFile *localizeFile = fileSystem->OpenFileWrite( "map_localize.csv" );
2147
2148 idStrList files;
2149 GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
2150
2151 for ( int i = 0; i < files.Num(); i++ ) {
2152
2153 common->Printf("Testing Map '%s'\n", files[i].c_str());
2154 idMapFile map;
2155
2156 idStr file = fileSystem->OSPathToRelativePath(files[i]);
2157 if ( map.Parse(file, false, false ) ) {
2158 int count = map.GetNumEntities();
2159 for ( int j = 0; j < count; j++ ) {
2160 idMapEntity *ent = map.GetEntity( j );
2161 if ( ent ) {
2162
2163 //Temp code to get a list of all entity key value pairs
2164 /*idStr classname = ent->epairs.GetString("classname");
2165 if(classname == "worldspawn" || classname == "func_static" || classname == "light" || classname == "speaker" || classname.Left(8) == "trigger_") {
2166 continue;
2167 }
2168 for( int i = 0; i < ent->epairs.GetNumKeyVals(); i++) {
2169 const idKeyValue* kv = ent->epairs.GetKeyVal(i);
2170 idStr out = va("%s,%s,%s,%s\r\n", classname.c_str(), kv->GetKey().c_str(), kv->GetValue().c_str(), file.c_str());
2171 localizeFile->Write( out.c_str(), out.Length() );
2172 }*/
2173
2174 idStr classname = ent->epairs.GetString("classname");
2175
2176 //Hack: for info_location
2177 bool hasLocation = false;
2178
2179 idStrList* list;
2180 listHash.Get(classname, &list);
2181 if(list) {
2182
2183 for(int k = 0; k < list->Num(); k++) {
2184
2185 idStr val = ent->epairs.GetString((*list)[k], "");
2186
2187 if(classname == "info_location" && (*list)[k] == "location") {
2188 hasLocation = true;
2189 }
2190
2191 if(val.Length() && TestMapVal(val)) {
2192
2193 if(!hasLocation || (*list)[k] == "location") {
2194 idStr out = va("%s,%s,%s\r\n", val.c_str(), (*list)[k].c_str(), file.c_str());
2195 localizeFile->Write( out.c_str(), out.Length() );
2196 }
2197 }
2198 }
2199 }
2200
2201 listHash.Get("all", &list);
2202 if(list) {
2203 for(int k = 0; k < list->Num(); k++) {
2204 idStr val = ent->epairs.GetString((*list)[k], "");
2205 if(val.Length() && TestMapVal(val)) {
2206 idStr out = va("%s,%s,%s\r\n", val.c_str(), (*list)[k].c_str(), file.c_str());
2207 localizeFile->Write( out.c_str(), out.Length() );
2208 }
2209 }
2210 }
2211 }
2212 }
2213 }
2214 }
2215
2216 fileSystem->CloseFile( localizeFile );
2217
2218 common->SetRefreshOnPrint( false );
2219 }
2220
2221 /*
2222 =================
2223 Com_StartBuild_f
2224 =================
2225 */
Com_StartBuild_f(const idCmdArgs & args)2226 void Com_StartBuild_f( const idCmdArgs &args ) {
2227 globalImages->StartBuild();
2228 }
2229
2230 /*
2231 =================
2232 Com_FinishBuild_f
2233 =================
2234 */
Com_FinishBuild_f(const idCmdArgs & args)2235 void Com_FinishBuild_f( const idCmdArgs &args ) {
2236 if ( game ) {
2237 game->CacheDictionaryMedia( NULL );
2238 }
2239 globalImages->FinishBuild( ( args.Argc() > 1 ) );
2240 }
2241
2242 /*
2243 ==============
2244 Com_Help_f
2245 ==============
2246 */
Com_Help_f(const idCmdArgs & args)2247 void Com_Help_f( const idCmdArgs &args ) {
2248 common->Printf( "\nCommonly used commands:\n" );
2249 common->Printf( " spawnServer - start the server.\n" );
2250 common->Printf( " disconnect - shut down the server.\n" );
2251 common->Printf( " listCmds - list all console commands.\n" );
2252 common->Printf( " listCVars - list all console variables.\n" );
2253 common->Printf( " kick - kick a client by number.\n" );
2254 common->Printf( " gameKick - kick a client by name.\n" );
2255 common->Printf( " serverNextMap - immediately load next map.\n" );
2256 common->Printf( " serverMapRestart - restart the current map.\n" );
2257 common->Printf( " serverForceReady - force all players to ready status.\n" );
2258 common->Printf( "\nCommonly used variables:\n" );
2259 common->Printf( " si_name - server name (change requires a restart to see)\n" );
2260 common->Printf( " si_gametype - type of game.\n" );
2261 common->Printf( " si_fragLimit - max kills to win (or lives in Last Man Standing).\n" );
2262 common->Printf( " si_timeLimit - maximum time a game will last.\n" );
2263 common->Printf( " si_warmup - do pre-game warmup.\n" );
2264 common->Printf( " si_pure - pure server.\n" );
2265 common->Printf( " g_mapCycle - name of .scriptcfg file for cycling maps.\n" );
2266 common->Printf( "See mapcycle.scriptcfg for an example of a mapcyle script.\n\n" );
2267 }
2268
2269 /*
2270 =================
2271 idCommonLocal::InitCommands
2272 =================
2273 */
InitCommands(void)2274 void idCommonLocal::InitCommands( void ) {
2275 cmdSystem->AddCommand( "error", Com_Error_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "causes an error" );
2276 cmdSystem->AddCommand( "crash", Com_Crash_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "causes a crash" );
2277 cmdSystem->AddCommand( "freeze", Com_Freeze_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "freezes the game for a number of seconds" );
2278 cmdSystem->AddCommand( "quit", Com_Quit_f, CMD_FL_SYSTEM, "quits the game" );
2279 cmdSystem->AddCommand( "exit", Com_Quit_f, CMD_FL_SYSTEM, "exits the game" );
2280 cmdSystem->AddCommand( "writeConfig", Com_WriteConfig_f, CMD_FL_SYSTEM, "writes a config file" );
2281 cmdSystem->AddCommand( "reloadEngine", Com_ReloadEngine_f, CMD_FL_SYSTEM, "reloads the engine down to including the file system" );
2282 cmdSystem->AddCommand( "setMachineSpec", Com_SetMachineSpec_f, CMD_FL_SYSTEM, "detects system capabilities and sets com_machineSpec to appropriate value" );
2283 cmdSystem->AddCommand( "execMachineSpec", Com_ExecMachineSpec_f, CMD_FL_SYSTEM, "execs the appropriate config files and sets cvars based on com_machineSpec" );
2284
2285 #if !defined( ID_DEDICATED )
2286 // compilers
2287 cmdSystem->AddCommand( "dmap", Dmap_f, CMD_FL_TOOL, "compiles a map", idCmdSystem::ArgCompletion_MapName );
2288 cmdSystem->AddCommand( "renderbump", RenderBump_f, CMD_FL_TOOL, "renders a bump map", idCmdSystem::ArgCompletion_ModelName );
2289 cmdSystem->AddCommand( "renderbumpFlat", RenderBumpFlat_f, CMD_FL_TOOL, "renders a flat bump map", idCmdSystem::ArgCompletion_ModelName );
2290 cmdSystem->AddCommand( "runAAS", RunAAS_f, CMD_FL_TOOL, "compiles an AAS file for a map", idCmdSystem::ArgCompletion_MapName );
2291 cmdSystem->AddCommand( "runAASDir", RunAASDir_f, CMD_FL_TOOL, "compiles AAS files for all maps in a folder", idCmdSystem::ArgCompletion_MapName );
2292 cmdSystem->AddCommand( "runReach", RunReach_f, CMD_FL_TOOL, "calculates reachability for an AAS file", idCmdSystem::ArgCompletion_MapName );
2293 cmdSystem->AddCommand( "roq", RoQFileEncode_f, CMD_FL_TOOL, "encodes a roq file" );
2294 #endif
2295
2296 #ifdef ID_ALLOW_TOOLS
2297 // editors
2298 cmdSystem->AddCommand( "editor", Com_Editor_f, CMD_FL_TOOL, "launches the level editor Radiant" );
2299 cmdSystem->AddCommand( "editLights", Com_EditLights_f, CMD_FL_TOOL, "launches the in-game Light Editor" );
2300 cmdSystem->AddCommand( "editSounds", Com_EditSounds_f, CMD_FL_TOOL, "launches the in-game Sound Editor" );
2301 cmdSystem->AddCommand( "editDecls", Com_EditDecls_f, CMD_FL_TOOL, "launches the in-game Declaration Editor" );
2302 cmdSystem->AddCommand( "editAFs", Com_EditAFs_f, CMD_FL_TOOL, "launches the in-game Articulated Figure Editor" );
2303 cmdSystem->AddCommand( "editParticles", Com_EditParticles_f, CMD_FL_TOOL, "launches the in-game Particle Editor" );
2304 cmdSystem->AddCommand( "editScripts", Com_EditScripts_f, CMD_FL_TOOL, "launches the in-game Script Editor" );
2305 cmdSystem->AddCommand( "editGUIs", Com_EditGUIs_f, CMD_FL_TOOL, "launches the GUI Editor" );
2306 cmdSystem->AddCommand( "editPDAs", Com_EditPDAs_f, CMD_FL_TOOL, "launches the in-game PDA Editor" );
2307 cmdSystem->AddCommand( "debugger", Com_ScriptDebugger_f, CMD_FL_TOOL, "launches the Script Debugger" );
2308
2309 //BSM Nerve: Add support for the material editor
2310 cmdSystem->AddCommand( "materialEditor", Com_MaterialEditor_f, CMD_FL_TOOL, "launches the Material Editor" );
2311 #endif
2312
2313 cmdSystem->AddCommand( "printMemInfo", PrintMemInfo_f, CMD_FL_SYSTEM, "prints memory debugging data" );
2314
2315 // idLib commands
2316 cmdSystem->AddCommand( "memoryDump", Mem_Dump_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "creates a memory dump" );
2317 cmdSystem->AddCommand( "memoryDumpCompressed", Mem_DumpCompressed_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "creates a compressed memory dump" );
2318 cmdSystem->AddCommand( "showStringMemory", idStr::ShowMemoryUsage_f, CMD_FL_SYSTEM, "shows memory used by strings" );
2319 cmdSystem->AddCommand( "showDictMemory", idDict::ShowMemoryUsage_f, CMD_FL_SYSTEM, "shows memory used by dictionaries" );
2320 cmdSystem->AddCommand( "listDictKeys", idDict::ListKeys_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "lists all keys used by dictionaries" );
2321 cmdSystem->AddCommand( "listDictValues", idDict::ListValues_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "lists all values used by dictionaries" );
2322 cmdSystem->AddCommand( "testSIMD", idSIMD::Test_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "test SIMD code" );
2323
2324 // localization
2325 cmdSystem->AddCommand( "localizeGuis", Com_LocalizeGuis_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "localize guis" );
2326 cmdSystem->AddCommand( "localizeMaps", Com_LocalizeMaps_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "localize maps" );
2327 cmdSystem->AddCommand( "reloadLanguage", Com_ReloadLanguage_f, CMD_FL_SYSTEM, "reload language dict" );
2328
2329 //D3XP Localization
2330 cmdSystem->AddCommand( "localizeGuiParmsTest", Com_LocalizeGuiParmsTest_f, CMD_FL_SYSTEM, "Create test files that show gui parms localized and ignored." );
2331 cmdSystem->AddCommand( "localizeMapsTest", Com_LocalizeMapsTest_f, CMD_FL_SYSTEM, "Create test files that shows which strings will be localized." );
2332
2333 // build helpers
2334 cmdSystem->AddCommand( "startBuild", Com_StartBuild_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "prepares to make a build" );
2335 cmdSystem->AddCommand( "finishBuild", Com_FinishBuild_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "finishes the build process" );
2336
2337 #ifdef ID_DEDICATED
2338 cmdSystem->AddCommand( "help", Com_Help_f, CMD_FL_SYSTEM, "shows help" );
2339 #endif
2340 }
2341
2342 /*
2343 =================
2344 idCommonLocal::InitRenderSystem
2345 =================
2346 */
InitRenderSystem(void)2347 void idCommonLocal::InitRenderSystem( void ) {
2348 if ( com_skipRenderer.GetBool() ) {
2349 return;
2350 }
2351
2352 renderSystem->InitOpenGL();
2353 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04343" ) );
2354 }
2355
2356 /*
2357 =================
2358 idCommonLocal::PrintLoadingMessage
2359 =================
2360 */
PrintLoadingMessage(const char * msg)2361 void idCommonLocal::PrintLoadingMessage( const char *msg ) {
2362 if ( !( msg && *msg ) ) {
2363 return;
2364 }
2365 renderSystem->BeginFrame( renderSystem->GetScreenWidth(), renderSystem->GetScreenHeight() );
2366 renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, declManager->FindMaterial( "splashScreen" ) );
2367 int len = strlen( msg );
2368 renderSystem->DrawSmallStringExt( ( 640 - len * SMALLCHAR_WIDTH ) / 2, 410, msg, idVec4( 0.0f, 0.81f, 0.94f, 1.0f ), true, declManager->FindMaterial( "textures/bigchars" ) );
2369 renderSystem->EndFrame( NULL, NULL );
2370 }
2371
2372 /*
2373 =================
2374 idCommonLocal::InitSIMD
2375 =================
2376 */
InitSIMD(void)2377 void idCommonLocal::InitSIMD( void ) {
2378 idSIMD::InitProcessor( "doom", com_forceGenericSIMD.GetBool() );
2379 com_forceGenericSIMD.ClearModified();
2380 }
2381
2382 /*
2383 =================
2384 idCommonLocal::Frame
2385 =================
2386 */
Frame(void)2387 void idCommonLocal::Frame( void ) {
2388 try {
2389
2390 // pump all the events
2391 Sys_GenerateEvents();
2392
2393 // write config file if anything changed
2394 WriteConfiguration();
2395
2396 // change SIMD implementation if required
2397 if ( com_forceGenericSIMD.IsModified() ) {
2398 InitSIMD();
2399 }
2400
2401 eventLoop->RunEventLoop();
2402
2403 com_frameTime = com_ticNumber * USERCMD_MSEC;
2404
2405 idAsyncNetwork::RunFrame();
2406
2407 if ( idAsyncNetwork::IsActive() ) {
2408 if ( idAsyncNetwork::serverDedicated.GetInteger() != 1 ) {
2409 session->GuiFrameEvents();
2410 session->UpdateScreen( false );
2411 }
2412 } else {
2413 session->Frame();
2414
2415 // normal, in-sequence screen update
2416 session->UpdateScreen( false );
2417 }
2418
2419 // report timing information
2420 if ( com_speeds.GetBool() ) {
2421 static int lastTime;
2422 int nowTime = Sys_Milliseconds();
2423 int com_frameMsec = nowTime - lastTime;
2424 lastTime = nowTime;
2425 Printf( "frame:%i all:%3i gfr:%3i rf:%3i bk:%3i\n", com_frameNumber, com_frameMsec, time_gameFrame, time_frontend, time_backend );
2426 time_gameFrame = 0;
2427 time_gameDraw = 0;
2428 }
2429
2430 com_frameNumber++;
2431
2432 // set idLib frame number for frame based memory dumps
2433 idLib::frameNumber = com_frameNumber;
2434 }
2435
2436 catch( idException & ) {
2437 return; // an ERP_DROP was thrown
2438 }
2439 }
2440
2441 /*
2442 =================
2443 idCommonLocal::GUIFrame
2444 =================
2445 */
GUIFrame(bool execCmd,bool network)2446 void idCommonLocal::GUIFrame( bool execCmd, bool network ) {
2447 Sys_GenerateEvents();
2448 eventLoop->RunEventLoop( execCmd ); // and execute any commands
2449 com_frameTime = com_ticNumber * USERCMD_MSEC;
2450 if ( network ) {
2451 idAsyncNetwork::RunFrame();
2452 }
2453 session->Frame();
2454 session->UpdateScreen( false );
2455 }
2456
2457 /*
2458 =================
2459 idCommonLocal::SingleAsyncTic
2460
2461 The system will asyncronously call this function 60 times a second to
2462 handle the time-critical functions that we don't want limited to
2463 the frame rate:
2464
2465 sound mixing
2466 user input generation (conditioned by com_asyncInput)
2467 packet server operation
2468 packet client operation
2469
2470 We are not using thread safe libraries, so any functionality put here must
2471 be VERY VERY careful about what it calls.
2472 =================
2473 */
2474
2475 typedef struct {
2476 int milliseconds; // should always be incremeting by 60hz
2477 int deltaMsec; // should always be 16
2478 int timeConsumed; // msec spent in Com_AsyncThread()
2479 int clientPacketsReceived;
2480 int serverPacketsReceived;
2481 int mostRecentServerPacketSequence;
2482 } asyncStats_t;
2483
2484 static const int MAX_ASYNC_STATS = 1024;
2485 asyncStats_t com_asyncStats[MAX_ASYNC_STATS]; // indexed by com_ticNumber
2486 int prevAsyncMsec;
2487 int lastTicMsec;
2488
SingleAsyncTic(void)2489 void idCommonLocal::SingleAsyncTic( void ) {
2490 // main thread code can prevent this from happening while modifying
2491 // critical data structures
2492 Sys_EnterCriticalSection();
2493
2494 asyncStats_t *stat = &com_asyncStats[com_ticNumber & (MAX_ASYNC_STATS-1)];
2495 memset( stat, 0, sizeof( *stat ) );
2496 stat->milliseconds = Sys_Milliseconds();
2497 stat->deltaMsec = stat->milliseconds - com_asyncStats[(com_ticNumber - 1) & (MAX_ASYNC_STATS-1)].milliseconds;
2498
2499 if ( usercmdGen && com_asyncInput.GetBool() ) {
2500 usercmdGen->UsercmdInterrupt();
2501 }
2502
2503 switch ( com_asyncSound.GetInteger() ) {
2504 case 1:
2505 case 3:
2506 // DG: these are now used for the new default behavior of "update every async tic (every 16ms)"
2507 soundSystem->AsyncUpdateWrite( stat->milliseconds );
2508 break;
2509 case 2:
2510 // DG: use 2 for the old "update only 10x/second" behavior in case anyone likes that..
2511 soundSystem->AsyncUpdate( stat->milliseconds );
2512 break;
2513 }
2514
2515 // we update com_ticNumber after all the background tasks
2516 // have completed their work for this tic
2517 com_ticNumber++;
2518
2519 stat->timeConsumed = Sys_Milliseconds() - stat->milliseconds;
2520
2521 Sys_LeaveCriticalSection();
2522 }
2523
2524 /*
2525 =================
2526 idCommonLocal::Async
2527 =================
2528 */
Async(void)2529 void idCommonLocal::Async( void ) {
2530 int msec = Sys_Milliseconds();
2531 if ( !lastTicMsec ) {
2532 lastTicMsec = msec - USERCMD_MSEC;
2533 }
2534
2535 if ( !com_preciseTic.GetBool() ) {
2536 // just run a single tic, even if the exact msec isn't precise
2537 SingleAsyncTic();
2538 return;
2539 }
2540
2541 int ticMsec = USERCMD_MSEC;
2542
2543 // the number of msec per tic can be varies with the timescale cvar
2544 float timescale = com_timescale.GetFloat();
2545 if ( timescale != 1.0f ) {
2546 ticMsec /= timescale;
2547 if ( ticMsec < 1 ) {
2548 ticMsec = 1;
2549 }
2550 }
2551
2552 // don't skip too many
2553 if ( timescale == 1.0f ) {
2554 if ( lastTicMsec + 10 * USERCMD_MSEC < msec ) {
2555 lastTicMsec = msec - 10*USERCMD_MSEC;
2556 }
2557 }
2558
2559 while ( lastTicMsec + ticMsec <= msec ) {
2560 SingleAsyncTic();
2561 lastTicMsec += ticMsec;
2562 }
2563 }
2564
2565 /*
2566 =================
2567 idCommonLocal::LoadGameDLLbyName
2568
2569 Helper for LoadGameDLL() to make it less painfull to try different dll names.
2570 =================
2571 */
LoadGameDLLbyName(const char * dll,idStr & s)2572 void idCommonLocal::LoadGameDLLbyName( const char *dll, idStr& s ) {
2573 s.CapLength(0);
2574 // try next to the binary first (build tree)
2575 if (Sys_GetPath(PATH_EXE, s)) {
2576 // "s = " seems superfluous, but works around g++ 4.7 bug else StripFilename()
2577 // (and possibly even CapLength()) seems to be "optimized" away and the string contains garbage
2578 s = s.StripFilename();
2579 s.AppendPath(dll);
2580 gameDLL = sys->DLL_Load(s);
2581 }
2582
2583 #if defined(_WIN32)
2584 // then the lib/ dir relative to the binary on windows
2585 if (!gameDLL && Sys_GetPath(PATH_EXE, s)) {
2586 s.StripFilename();
2587 s.AppendPath("lib");
2588 s.AppendPath(dll);
2589 gameDLL = sys->DLL_Load(s);
2590 }
2591 #elif defined(MACOS_X)
2592 // then the binary dir in the bundle on osx
2593 if (!gameDLL && Sys_GetPath(PATH_EXE, s)) {
2594 s.StripFilename();
2595 s.AppendPath(dll);
2596 gameDLL = sys->DLL_Load(s);
2597 }
2598 #else
2599 // then the install folder on *nix
2600 if (!gameDLL) {
2601 s = BUILD_LIBDIR;
2602 s.AppendPath(dll);
2603 gameDLL = sys->DLL_Load(s);
2604 }
2605 #endif
2606 }
2607
2608 /*
2609 =================
2610 idCommonLocal::LoadGameDLL
2611 =================
2612 */
LoadGameDLL(void)2613 void idCommonLocal::LoadGameDLL( void ) {
2614 #ifdef __DOOM_DLL__
2615 const char *fs_game;
2616 char dll[MAX_OSPATH];
2617 idStr s;
2618
2619 gameImport_t gameImport;
2620 gameExport_t gameExport;
2621 GetGameAPI_t GetGameAPI;
2622
2623 fs_game = cvarSystem->GetCVarString("fs_game");
2624 if (!fs_game || !fs_game[0])
2625 fs_game = BASE_GAMEDIR;
2626
2627 gameDLL = 0;
2628
2629 sys->DLL_GetFileName(fs_game, dll, sizeof(dll));
2630 LoadGameDLLbyName(dll, s);
2631
2632 // there was no gamelib for this mod, use default one from base game
2633 if (!gameDLL) {
2634 common->Warning( "couldn't load mod-specific %s, defaulting to base game's library!", dll );
2635 sys->DLL_GetFileName(BASE_GAMEDIR, dll, sizeof(dll));
2636 LoadGameDLLbyName(dll, s);
2637 }
2638
2639 if ( !gameDLL ) {
2640 common->FatalError( "couldn't load game dynamic library" );
2641 return;
2642 }
2643
2644 common->Printf("loaded game library '%s'.\n", s.c_str());
2645
2646 GetGameAPI = (GetGameAPI_t) Sys_DLL_GetProcAddress( gameDLL, "GetGameAPI" );
2647 if ( !GetGameAPI ) {
2648 Sys_DLL_Unload( gameDLL );
2649 gameDLL = 0;
2650 common->FatalError( "couldn't find game DLL API" );
2651 return;
2652 }
2653
2654 gameImport.version = GAME_API_VERSION;
2655 gameImport.sys = ::sys;
2656 gameImport.common = ::common;
2657 gameImport.cmdSystem = ::cmdSystem;
2658 gameImport.cvarSystem = ::cvarSystem;
2659 gameImport.fileSystem = ::fileSystem;
2660 gameImport.networkSystem = ::networkSystem;
2661 gameImport.renderSystem = ::renderSystem;
2662 gameImport.soundSystem = ::soundSystem;
2663 gameImport.renderModelManager = ::renderModelManager;
2664 gameImport.uiManager = ::uiManager;
2665 gameImport.declManager = ::declManager;
2666 gameImport.AASFileManager = ::AASFileManager;
2667 gameImport.collisionModelManager = ::collisionModelManager;
2668
2669 gameExport = *GetGameAPI( &gameImport );
2670
2671 if ( gameExport.version != GAME_API_VERSION ) {
2672 Sys_DLL_Unload( gameDLL );
2673 gameDLL = 0;
2674 common->FatalError( "wrong game DLL API version" );
2675 return;
2676 }
2677
2678 game = gameExport.game;
2679 gameEdit = gameExport.gameEdit;
2680
2681 #endif
2682
2683 // initialize the game object
2684 if ( game != NULL ) {
2685 game->Init();
2686 }
2687 }
2688
2689 /*
2690 =================
2691 idCommonLocal::UnloadGameDLL
2692 =================
2693 */
UnloadGameDLL(void)2694 void idCommonLocal::UnloadGameDLL( void ) {
2695
2696 // shut down the game object
2697 if ( game != NULL ) {
2698 game->Shutdown();
2699 }
2700
2701 #ifdef __DOOM_DLL__
2702
2703 if ( gameDLL ) {
2704 Sys_DLL_Unload( gameDLL );
2705 gameDLL = 0;
2706 }
2707 game = NULL;
2708 gameEdit = NULL;
2709
2710 #endif
2711
2712 gameCallbacks.Reset(); // DG: these callbacks are invalid now because DLL has been unloaded
2713 }
2714
2715 /*
2716 =================
2717 idCommonLocal::IsInitialized
2718 =================
2719 */
IsInitialized(void) const2720 bool idCommonLocal::IsInitialized( void ) const {
2721 return com_fullyInitialized;
2722 }
2723
2724 /*
2725 =================
2726 idCommonLocal::SetMachineSpec
2727 =================
2728 */
SetMachineSpec(void)2729 void idCommonLocal::SetMachineSpec( void ) {
2730 int sysRam = Sys_GetSystemRam();
2731
2732 Printf( "Detected\n\t%i MB of System memory\n\n", sysRam );
2733
2734 if ( sysRam >= 1024 ) {
2735 Printf( "This system qualifies for Ultra quality!\n" );
2736 com_machineSpec.SetInteger( 3 );
2737 } else if ( sysRam >= 512 ) {
2738 Printf( "This system qualifies for High quality!\n" );
2739 com_machineSpec.SetInteger( 2 );
2740 } else if ( sysRam >= 384 ) {
2741 Printf( "This system qualifies for Medium quality.\n" );
2742 com_machineSpec.SetInteger( 1 );
2743 } else {
2744 Printf( "This system qualifies for Low quality.\n" );
2745 com_machineSpec.SetInteger( 0 );
2746 }
2747 }
2748
AsyncTimer(unsigned int interval,void *)2749 static unsigned int AsyncTimer(unsigned int interval, void *) {
2750 common->Async();
2751 Sys_TriggerEvent(TRIGGER_EVENT_ONE);
2752
2753 // calculate the next interval to get as close to 60fps as possible
2754 unsigned int now = SDL_GetTicks();
2755 unsigned int tick = com_ticNumber * USERCMD_MSEC;
2756 // FIXME: this is pretty broken and basically always returns 1 because now now is much bigger than tic
2757 // (probably com_tickNumber only starts incrementing a second after engine starts?)
2758 // only reason this works is common->Async() checking again before calling SingleAsyncTic()
2759
2760 if (now >= tick)
2761 return 1;
2762
2763 return tick - now;
2764 }
2765
2766 #ifdef _WIN32
2767 #include "../sys/win32/win_local.h" // for Conbuf_AppendText()
2768 #endif // _WIN32
2769
checkForHelp(int argc,char ** argv)2770 static bool checkForHelp(int argc, char **argv)
2771 {
2772 const char* helpArgs[] = { "--help", "-h", "-help", "-?", "/?" };
2773 const int numHelpArgs = sizeof(helpArgs)/sizeof(helpArgs[0]);
2774
2775 for (int i=0; i<argc; ++i)
2776 {
2777 const char* arg = argv[i];
2778 for (int h=0; h<numHelpArgs; ++h)
2779 {
2780 if (idStr::Icmp(arg, helpArgs[h]) == 0)
2781 {
2782 #ifdef _WIN32
2783 // write it to the Windows-only console window
2784 #define WriteString(s) Conbuf_AppendText(s)
2785 #else // not windows
2786 // write it to stdout
2787 #define WriteString(s) fputs(s, stdout);
2788 #endif // _WIN32
2789 WriteString(ENGINE_VERSION " - http://dhewm3.org\n");
2790 WriteString("Commandline arguments:\n");
2791 WriteString("-h or --help: Show this help\n");
2792 WriteString("+<command> [command arguments]\n");
2793 WriteString(" executes a command (with optional arguments)\n");
2794
2795 WriteString("\nSome interesting commands:\n");
2796 WriteString("+map <map>\n");
2797 WriteString(" directly loads the given level, e.g. +map game/hell1\n");
2798 WriteString("+exec <config>\n");
2799 WriteString(" execute the given config (mainly relevant for dedicated servers)\n");
2800 WriteString("+disconnect\n");
2801 WriteString(" starts the game, goes directly into main menu without showing\n logo video\n");
2802 WriteString("+connect <host>[:port]\n");
2803 WriteString(" directly connect to multiplayer server at given host/port\n");
2804 WriteString(" e.g. +connect d3.example.com\n");
2805 WriteString(" e.g. +connect d3.example.com:27667\n");
2806 WriteString(" e.g. +connect 192.168.0.42:27666\n");
2807 WriteString("+set <cvarname> <value>\n");
2808 WriteString(" Set the given cvar to the given value, e.g. +set r_fullscreen 0\n");
2809 WriteString("+seta <cvarname> <value>\n");
2810 WriteString(" like +set, but also makes sure the changed cvar is saved (\"archived\")\n in a cfg\n");
2811
2812 WriteString("\nSome interesting cvars:\n");
2813 WriteString("+set fs_basepath <gamedata path>\n");
2814 WriteString(" set path to your Doom3 game data (the directory base/ is in)\n");
2815 WriteString("+set fs_game <modname>\n");
2816 WriteString(" start the given addon/mod, e.g. +set fs_game d3xp\n");
2817 #ifndef ID_DEDICATED
2818 WriteString("+set r_fullscreen <0 or 1>\n");
2819 WriteString(" start game in windowed (0) or fullscreen (1) mode\n");
2820 WriteString("+set r_mode <modenumber>\n");
2821 WriteString(" start game in resolution belonging to <modenumber>,\n");
2822 WriteString(" use -1 for custom resolutions:\n");
2823 WriteString("+set r_customWidth <size in pixels>\n");
2824 WriteString("+set r_customHeight <size in pixels>\n");
2825 WriteString(" if r_mode is set to -1, these cvars allow you to specify the\n");
2826 WriteString(" width/height of your custom resolution\n");
2827 #endif // !ID_DEDICATED
2828 WriteString("\nSee https://modwiki.dhewm3.org/CVars_%28Doom_3%29 for more cvars\n");
2829 WriteString("See https://modwiki.dhewm3.org/Commands_%28Doom_3%29 for more commands\n");
2830
2831 #undef WriteString
2832
2833 return true;
2834 }
2835 }
2836 }
2837 return false;
2838 }
2839
2840 #ifdef UINTPTR_MAX // DG: make sure D3_SIZEOFPTR is consistent with reality
2841
2842 #if D3_SIZEOFPTR == 4
2843 #if UINTPTR_MAX != 0xFFFFFFFFUL
2844 #error "CMake assumes that we're building for a 32bit architecture, but UINTPTR_MAX doesn't match!"
2845 #endif
2846 #elif D3_SIZEOFPTR == 8
2847 #if UINTPTR_MAX != 18446744073709551615ULL
2848 #error "CMake assumes that we're building for a 64bit architecture, but UINTPTR_MAX doesn't match!"
2849 #endif
2850 #else
2851 // Hello future person with a 128bit(?) CPU, I hope the future doesn't suck too much and that you don't still use CMake.
2852 // Also, please adapt this check and send a pull request (or whatever way we have to send patches in the future)
2853 #error "D3_SIZEOFPTR should really be 4 (for 32bit targets) or 8 (for 64bit targets), what kind of machine is this?!"
2854 #endif
2855
2856 #endif // UINTPTR_MAX defined
2857
2858 /*
2859 =================
2860 idCommonLocal::Init
2861 =================
2862 */
Init(int argc,char ** argv)2863 void idCommonLocal::Init( int argc, char **argv ) {
2864
2865 // in case UINTPTR_MAX isn't defined (or wrong), do a runtime check at startup
2866 if ( D3_SIZEOFPTR != sizeof(void*) ) {
2867 Sys_Error( "Something went wrong in your build: CMake assumed that sizeof(void*) == %d but in reality it's %d!\n",
2868 (int)D3_SIZEOFPTR, (int)sizeof(void*) );
2869 }
2870
2871 if(checkForHelp(argc, argv))
2872 {
2873 // game has been started with --help (or similar), usage message has been shown => quit
2874 #ifdef _WIN32
2875 // this enforces that the console window is shown until the user closes it
2876 // => checkForHelp() writes to the console window on Windows
2877 Sys_Error(".");
2878 #endif // _WIN32
2879 exit(1);
2880 }
2881
2882 #ifdef ID_DEDICATED
2883 // we want to use the SDL event queue for dedicated servers. That
2884 // requires video to be initialized, so we just use the dummy
2885 // driver for headless boxen
2886 #if SDL_VERSION_ATLEAST(2, 0, 0)
2887 SDL_setenv("SDL_VIDEODRIVER", "dummy", 1);
2888 #else
2889 char dummy[] = "SDL_VIDEODRIVER=dummy\0";
2890 SDL_putenv(dummy);
2891 #endif
2892 #endif
2893
2894 if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)) // init joystick to work around SDL 2.0.9 bug #4391
2895 Sys_Error("Error while initializing SDL: %s", SDL_GetError());
2896
2897 Sys_InitThreads();
2898
2899 try {
2900
2901 // set interface pointers used by idLib
2902 idLib::sys = sys;
2903 idLib::common = common;
2904 idLib::cvarSystem = cvarSystem;
2905 idLib::fileSystem = fileSystem;
2906
2907 // initialize idLib
2908 idLib::Init();
2909
2910 // clear warning buffer
2911 ClearWarnings( GAME_NAME " initialization" );
2912
2913 // parse command line options
2914 ParseCommandLine( argc, argv );
2915
2916 // init console command system
2917 cmdSystem->Init();
2918
2919 // init CVar system
2920 cvarSystem->Init();
2921
2922 // start file logging right away, before early console or whatever
2923 StartupVariable( "win_outputDebugString", false );
2924
2925 // register all static CVars
2926 idCVar::RegisterStaticVars();
2927
2928 // print engine version
2929 #if SDL_VERSION_ATLEAST(2, 0, 0)
2930 SDL_version sdlv;
2931 SDL_GetVersion(&sdlv);
2932 #else
2933 SDL_version sdlv = *SDL_Linked_Version();
2934 #endif
2935 Printf( "%s using SDL v%u.%u.%u\n",
2936 version.string, sdlv.major, sdlv.minor, sdlv.patch );
2937
2938 // initialize key input/binding, done early so bind command exists
2939 idKeyInput::Init();
2940
2941 // init the console so we can take prints
2942 console->Init();
2943
2944 // get architecture info
2945 Sys_Init();
2946
2947 // initialize networking
2948 Sys_InitNetworking();
2949
2950 // override cvars from command line
2951 StartupVariable( NULL, false );
2952
2953 // set fpu double extended precision
2954 Sys_FPU_SetPrecision();
2955
2956 // initialize processor specific SIMD implementation
2957 InitSIMD();
2958
2959 // init commands
2960 InitCommands();
2961
2962 #ifdef ID_WRITE_VERSION
2963 config_compressor = idCompressor::AllocArithmetic();
2964 #endif
2965
2966 // game specific initialization
2967 InitGame();
2968
2969 // don't add startup commands if no CD key is present
2970 #if ID_ENFORCE_KEY
2971 if ( !session->CDKeysAreValid( false ) || !AddStartupCommands() ) {
2972 #else
2973 if ( !AddStartupCommands() ) {
2974 #endif
2975 // if the user didn't give any commands, run default action
2976 session->StartMenu( true );
2977 }
2978
2979 // print all warnings queued during initialization
2980 PrintWarnings();
2981
2982 #ifdef ID_DEDICATED
2983 Printf( "\nType 'help' for dedicated server info.\n\n" );
2984 #endif
2985
2986 // remove any prints from the notify lines
2987 console->ClearNotifyLines();
2988
2989 ClearCommandLine();
2990
2991 // load the persistent console history
2992 console->LoadHistory();
2993
2994 com_fullyInitialized = true;
2995 }
2996
2997 catch( idException & ) {
2998 Sys_Error( "Error during initialization" );
2999 }
3000
3001 async_timer = SDL_AddTimer(USERCMD_MSEC, AsyncTimer, NULL);
3002
3003 if (!async_timer)
3004 Sys_Error("Error while starting the async timer: %s", SDL_GetError());
3005 }
3006
3007
3008 /*
3009 =================
3010 idCommonLocal::Shutdown
3011 =================
3012 */
3013 void idCommonLocal::Shutdown( void ) {
3014 if (async_timer) {
3015 SDL_RemoveTimer(async_timer);
3016 async_timer = 0;
3017 }
3018
3019 idAsyncNetwork::server.Kill();
3020 idAsyncNetwork::client.Shutdown();
3021
3022 // save persistent console history
3023 console->SaveHistory();
3024
3025 // game specific shut down
3026 ShutdownGame( false );
3027
3028 // shut down non-portable system services
3029 Sys_Shutdown();
3030
3031 // shut down the console
3032 console->Shutdown();
3033
3034 // shut down the key system
3035 idKeyInput::Shutdown();
3036
3037 // shut down the cvar system
3038 cvarSystem->Shutdown();
3039
3040 // shut down the console command system
3041 cmdSystem->Shutdown();
3042
3043 #ifdef ID_WRITE_VERSION
3044 delete config_compressor;
3045 config_compressor = NULL;
3046 #endif
3047
3048 // free any buffered warning messages
3049 ClearWarnings( GAME_NAME " shutdown" );
3050 warningCaption.Clear();
3051 errorList.Clear();
3052
3053 // free language dictionary
3054 languageDict.Clear();
3055
3056 // enable leak test
3057 Mem_EnableLeakTest( "doom" );
3058
3059 // shutdown idLib
3060 idLib::ShutDown();
3061
3062 Sys_ShutdownThreads();
3063
3064 SDL_Quit();
3065 }
3066
3067 /*
3068 =================
3069 idCommonLocal::InitGame
3070 =================
3071 */
3072 void idCommonLocal::InitGame( void ) {
3073 // initialize the file system
3074 fileSystem->Init();
3075
3076 // initialize the declaration manager
3077 declManager->Init();
3078
3079 // force r_fullscreen 0 if running a tool
3080 CheckToolMode();
3081
3082 idFile *file = fileSystem->OpenExplicitFileRead( fileSystem->RelativePathToOSPath( CONFIG_SPEC, "fs_configpath" ) );
3083 bool sysDetect = ( file == NULL );
3084 if ( file ) {
3085 fileSystem->CloseFile( file );
3086 } else {
3087 file = fileSystem->OpenFileWrite( CONFIG_SPEC, "fs_configpath" );
3088 fileSystem->CloseFile( file );
3089 }
3090
3091 idCmdArgs args;
3092 if ( sysDetect ) {
3093 SetMachineSpec();
3094 Com_ExecMachineSpec_f( args );
3095 }
3096
3097 // initialize the renderSystem data structures, but don't start OpenGL yet
3098 renderSystem->Init();
3099
3100 // initialize string database right off so we can use it for loading messages
3101 InitLanguageDict();
3102
3103 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04344" ) );
3104
3105 // load the font, etc
3106 console->LoadGraphics();
3107
3108 // init journalling, etc
3109 eventLoop->Init();
3110
3111 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04345" ) );
3112
3113 // exec the startup scripts
3114 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec editor.cfg\n" );
3115 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec default.cfg\n" );
3116
3117 // skip the config file if "safe" is on the command line
3118 if ( !SafeMode() ) {
3119 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec " CONFIG_FILE "\n" );
3120 }
3121 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "exec autoexec.cfg\n" );
3122
3123 // reload the language dictionary now that we've loaded config files
3124 cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "reloadLanguage\n" );
3125
3126 // run cfg execution
3127 cmdSystem->ExecuteCommandBuffer();
3128
3129 // re-override anything from the config files with command line args
3130 StartupVariable( NULL, false );
3131
3132 // if any archived cvars are modified after this, we will trigger a writing of the config file
3133 cvarSystem->ClearModifiedFlags( CVAR_ARCHIVE );
3134
3135 // init the user command input code
3136 usercmdGen->Init();
3137
3138 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04346" ) );
3139
3140 // start the sound system, but don't do any hardware operations yet
3141 soundSystem->Init();
3142
3143 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04347" ) );
3144
3145 // init async network
3146 idAsyncNetwork::Init();
3147
3148 #ifdef ID_DEDICATED
3149 idAsyncNetwork::server.InitPort();
3150 cvarSystem->SetCVarBool( "s_noSound", true );
3151 #else
3152 if ( idAsyncNetwork::serverDedicated.GetInteger() == 1 ) {
3153 idAsyncNetwork::server.InitPort();
3154 cvarSystem->SetCVarBool( "s_noSound", true );
3155 } else {
3156 // init OpenGL, which will open a window and connect sound and input hardware
3157 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04348" ) );
3158 InitRenderSystem();
3159 }
3160 #endif
3161
3162 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04349" ) );
3163
3164 // initialize the user interfaces
3165 uiManager->Init();
3166
3167 // startup the script debugger
3168 // DebuggerServerInit();
3169
3170 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04350" ) );
3171
3172 // load the game dll
3173 LoadGameDLL();
3174
3175 PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04351" ) );
3176
3177 // init the session
3178 session->Init();
3179
3180 // have to do this twice.. first one sets the correct r_mode for the renderer init
3181 // this time around the backend is all setup correct.. a bit fugly but do not want
3182 // to mess with all the gl init at this point.. an old vid card will never qualify for
3183 if ( sysDetect ) {
3184 SetMachineSpec();
3185 Com_ExecMachineSpec_f( args );
3186 cvarSystem->SetCVarInteger( "s_numberOfSpeakers", 6 );
3187 cmdSystem->BufferCommandText( CMD_EXEC_NOW, "s_restart\n" );
3188 cmdSystem->ExecuteCommandBuffer();
3189 }
3190 }
3191
3192 /*
3193 =================
3194 idCommonLocal::ShutdownGame
3195 =================
3196 */
3197 void idCommonLocal::ShutdownGame( bool reloading ) {
3198
3199 // kill sound first
3200 idSoundWorld *sw = soundSystem->GetPlayingSoundWorld();
3201 if ( sw ) {
3202 sw->StopAllSounds();
3203 }
3204
3205 // shutdown the script debugger
3206 // DebuggerServerShutdown();
3207
3208 idAsyncNetwork::client.Shutdown();
3209
3210 // shut down the session
3211 session->Shutdown();
3212
3213 // shut down the user interfaces
3214 uiManager->Shutdown();
3215
3216 // shut down the sound system
3217 soundSystem->Shutdown();
3218
3219 // shut down async networking
3220 idAsyncNetwork::Shutdown();
3221
3222 // shut down the user command input code
3223 usercmdGen->Shutdown();
3224
3225 // shut down the event loop
3226 eventLoop->Shutdown();
3227
3228 // shut down the renderSystem
3229 renderSystem->Shutdown();
3230
3231 // shutdown the decl manager
3232 declManager->Shutdown();
3233
3234 // unload the game dll
3235 UnloadGameDLL();
3236
3237 // dump warnings to "warnings.txt"
3238 #ifdef DEBUG
3239 DumpWarnings();
3240 #endif
3241
3242 // shut down the file system
3243 fileSystem->Shutdown( reloading );
3244 }
3245
3246 // DG: below here are hacks to allow adding callbacks and exporting additional functions to the
3247 // Game DLL without breaking the ABI. See Common.h for longer explanation...
3248
3249
3250 // returns true if setting the callback was successful, else false
3251 // When a game DLL is unloaded the callbacks are automatically removed from the Engine
3252 // so you usually don't have to worry about that; but you can call this with cb = NULL
3253 // and userArg = NULL to remove a callback manually (e.g. if userArg refers to an object you deleted)
3254 bool idCommonLocal::SetCallback(idCommon::CallbackType cbt, idCommon::FunctionPointer cb, void* userArg)
3255 {
3256 switch(cbt)
3257 {
3258 case idCommon::CB_ReloadImages:
3259 gameCallbacks.reloadImagesCB = (idGameCallbacks::ReloadImagesCallback)cb;
3260 gameCallbacks.reloadImagesUserArg = userArg;
3261 return true;
3262
3263 default:
3264 Warning("Called idCommon::SetCallback() with unknown CallbackType %d!\n", cbt);
3265 return false;
3266 }
3267 }
3268
3269 static bool isDemo(void)
3270 {
3271 return sessLocal.IsDemoVersion();
3272 }
3273
3274 // returns true if that function is available in this version of dhewm3
3275 // *out_fnptr will be the function (you'll have to cast it probably)
3276 // *out_userArg will be an argument you have to pass to the function, if appropriate (else NULL)
3277 bool idCommonLocal::GetAdditionalFunction(idCommon::FunctionType ft, idCommon::FunctionPointer* out_fnptr, void** out_userArg)
3278 {
3279 if(out_userArg != NULL)
3280 *out_userArg = NULL;
3281
3282 if(out_fnptr == NULL)
3283 {
3284 Warning("Called idCommon::GetAdditionalFunction() with out_fnptr == NULL!\n");
3285 return false;
3286 }
3287 switch(ft)
3288 {
3289 case idCommon::FT_IsDemo:
3290 *out_fnptr = (idCommon::FunctionPointer)isDemo;
3291 // don't set *out_userArg, this function takes no arguments
3292 return true;
3293
3294 default:
3295 *out_fnptr = NULL;
3296 Warning("Called idCommon::SetCallback() with unknown FunctionType %d!\n", ft);
3297 return false;
3298 }
3299 }
3300
3301
3302 idGameCallbacks gameCallbacks;
3303
3304 idGameCallbacks::idGameCallbacks()
3305 : reloadImagesCB(NULL), reloadImagesUserArg(NULL)
3306 {}
3307
3308 void idGameCallbacks::Reset()
3309 {
3310 reloadImagesCB = NULL;
3311 reloadImagesUserArg = NULL;
3312 }
3313