doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Session.cpp
Go to the documentation of this file.
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 "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Session_local.h"
33 
34 idCVar idSessionLocal::com_showAngles( "com_showAngles", "0", CVAR_SYSTEM | CVAR_BOOL, "" );
35 idCVar idSessionLocal::com_minTics( "com_minTics", "1", CVAR_SYSTEM, "" );
36 idCVar idSessionLocal::com_showTics( "com_showTics", "0", CVAR_SYSTEM | CVAR_BOOL, "" );
37 idCVar idSessionLocal::com_fixedTic( "com_fixedTic", "0", CVAR_SYSTEM | CVAR_INTEGER, "", 0, 10 );
38 idCVar idSessionLocal::com_showDemo( "com_showDemo", "0", CVAR_SYSTEM | CVAR_BOOL, "" );
39 idCVar idSessionLocal::com_skipGameDraw( "com_skipGameDraw", "0", CVAR_SYSTEM | CVAR_BOOL, "" );
40 idCVar idSessionLocal::com_aviDemoSamples( "com_aviDemoSamples", "16", CVAR_SYSTEM, "" );
41 idCVar idSessionLocal::com_aviDemoWidth( "com_aviDemoWidth", "256", CVAR_SYSTEM, "" );
42 idCVar idSessionLocal::com_aviDemoHeight( "com_aviDemoHeight", "256", CVAR_SYSTEM, "" );
43 idCVar idSessionLocal::com_aviDemoTics( "com_aviDemoTics", "2", CVAR_SYSTEM | CVAR_INTEGER, "", 1, 60 );
44 idCVar idSessionLocal::com_wipeSeconds( "com_wipeSeconds", "1", CVAR_SYSTEM, "" );
46 
49 
50 // these must be kept up to date with window Levelshot in guis/mainmenu.gui
51 const int PREVIEW_X = 211;
52 const int PREVIEW_Y = 31;
53 const int PREVIEW_WIDTH = 398;
54 const int PREVIEW_HEIGHT = 298;
55 
56 void RandomizeStack( void ) {
57  // attempt to force uninitialized stack memory bugs
58  int bytes = 4000000;
59  byte *buf = (byte *)_alloca( bytes );
60 
61  int fill = rand()&255;
62  for ( int i = 0 ; i < bytes ; i++ ) {
63  buf[i] = fill;
64  }
65 }
66 
67 /*
68 =================
69 Session_RescanSI_f
70 =================
71 */
72 void Session_RescanSI_f( const idCmdArgs &args ) {
74  if ( game && idAsyncNetwork::server.IsActive() ) {
76  }
77 }
78 
79 /*
80 ==================
81 Session_Map_f
82 
83 Restart the server on a different map
84 ==================
85 */
86 static void Session_Map_f( const idCmdArgs &args ) {
87  idStr map, string;
88  findFile_t ff;
89  idCmdArgs rl_args;
90 
91  map = args.Argv(1);
92  if ( !map.Length() ) {
93  return;
94  }
95  map.StripFileExtension();
96 
97  // make sure the level exists before trying to change, so that
98  // a typo at the server console won't end the game
99  // handle addon packs through reloadEngine
100  sprintf( string, "maps/%s.map", map.c_str() );
101  ff = fileSystem->FindFile( string, true );
102  switch ( ff ) {
103  case FIND_NO:
104  common->Printf( "Can't find map %s\n", string.c_str() );
105  return;
106  case FIND_ADDON:
107  common->Printf( "map %s is in an addon pak - reloading\n", string.c_str() );
108  rl_args.AppendArg( "map" );
109  rl_args.AppendArg( map );
110  cmdSystem->SetupReloadEngine( rl_args );
111  return;
112  default:
113  break;
114  }
115 
116  cvarSystem->SetCVarBool( "developer", false );
117  sessLocal.StartNewGame( map, true );
118 }
119 
120 /*
121 ==================
122 Session_DevMap_f
123 
124 Restart the server on a different map in developer mode
125 ==================
126 */
127 static void Session_DevMap_f( const idCmdArgs &args ) {
128  idStr map, string;
129  findFile_t ff;
130  idCmdArgs rl_args;
131 
132  map = args.Argv(1);
133  if ( !map.Length() ) {
134  return;
135  }
136  map.StripFileExtension();
137 
138  // make sure the level exists before trying to change, so that
139  // a typo at the server console won't end the game
140  // handle addon packs through reloadEngine
141  sprintf( string, "maps/%s.map", map.c_str() );
142  ff = fileSystem->FindFile( string, true );
143  switch ( ff ) {
144  case FIND_NO:
145  common->Printf( "Can't find map %s\n", string.c_str() );
146  return;
147  case FIND_ADDON:
148  common->Printf( "map %s is in an addon pak - reloading\n", string.c_str() );
149  rl_args.AppendArg( "devmap" );
150  rl_args.AppendArg( map );
151  cmdSystem->SetupReloadEngine( rl_args );
152  return;
153  default:
154  break;
155  }
156 
157  cvarSystem->SetCVarBool( "developer", true );
158  sessLocal.StartNewGame( map, true );
159 }
160 
161 /*
162 ==================
163 Session_TestMap_f
164 ==================
165 */
166 static void Session_TestMap_f( const idCmdArgs &args ) {
167  idStr map, string;
168 
169  map = args.Argv(1);
170  if ( !map.Length() ) {
171  return;
172  }
173  map.StripFileExtension();
174 
175  cmdSystem->BufferCommandText( CMD_EXEC_NOW, "disconnect" );
176 
177  sprintf( string, "dmap maps/%s.map", map.c_str() );
179 
180  sprintf( string, "devmap %s", map.c_str() );
182 }
183 
184 /*
185 ==================
186 Sess_WritePrecache_f
187 ==================
188 */
189 static void Sess_WritePrecache_f( const idCmdArgs &args ) {
190  if ( args.Argc() != 2 ) {
191  common->Printf( "USAGE: writePrecache <execFile>\n" );
192  return;
193  }
194  idStr str = args.Argv(1);
195  str.DefaultFileExtension( ".cfg" );
196  idFile *f = fileSystem->OpenFileWrite( str );
200 
201  fileSystem->CloseFile( f );
202 }
203 
204 /*
205 ===============
206 idSessionLocal::MaybeWaitOnCDKey
207 ===============
208 */
210  if ( authEmitTimeout > 0 ) {
211  authWaitBox = true;
212  sessLocal.MessageBox( MSG_WAIT, common->GetLanguageDict()->GetString( "#str_07191" ), NULL, true, NULL, NULL, true );
213  return true;
214  }
215  return false;
216 }
217 
218 /*
219 ===================
220 Session_PromptKey_f
221 ===================
222 */
223 static void Session_PromptKey_f( const idCmdArgs &args ) {
224  const char *retkey;
225  bool valid[ 2 ];
226  static bool recursed = false;
227 
228  if ( recursed ) {
229  common->Warning( "promptKey recursed - aborted" );
230  return;
231  }
232  recursed = true;
233 
234  do {
235  // in case we're already waiting for an auth to come back to us ( may happen exceptionally )
236  if ( sessLocal.MaybeWaitOnCDKey() ) {
237  if ( sessLocal.CDKeysAreValid( true ) ) {
238  recursed = false;
239  return;
240  }
241  }
242  // the auth server may have replied and set an error message, otherwise use a default
243  const char *prompt_msg = sessLocal.GetAuthMsg();
244  if ( prompt_msg[ 0 ] == '\0' ) {
245  prompt_msg = common->GetLanguageDict()->GetString( "#str_04308" );
246  }
247  retkey = sessLocal.MessageBox( MSG_CDKEY, prompt_msg, common->GetLanguageDict()->GetString( "#str_04305" ), true, NULL, NULL, true );
248  if ( retkey ) {
249  if ( sessLocal.CheckKey( retkey, false, valid ) ) {
250  // if all went right, then we may have sent an auth request to the master ( unless the prompt is used during a net connect )
251  bool canExit = true;
252  if ( sessLocal.MaybeWaitOnCDKey() ) {
253  // wait on auth reply, and got denied, prompt again
254  if ( !sessLocal.CDKeysAreValid( true ) ) {
255  // server says key is invalid - MaybeWaitOnCDKey was interrupted by a CDKeysAuthReply call, which has set the right error message
256  // the invalid keys have also been cleared in the process
257  sessLocal.MessageBox( MSG_OK, sessLocal.GetAuthMsg(), common->GetLanguageDict()->GetString( "#str_04310" ), true, NULL, NULL, true );
258  canExit = false;
259  }
260  }
261  if ( canExit ) {
262  // make sure that's saved on file
263  sessLocal.WriteCDKey();
264  sessLocal.MessageBox( MSG_OK, common->GetLanguageDict()->GetString( "#str_04307" ), common->GetLanguageDict()->GetString( "#str_04305" ), true, NULL, NULL, true );
265  break;
266  }
267  } else {
268  // offline check sees key invalid
269  // build a message about keys being wrong. do not attempt to change the current key state though
270  // ( the keys may be valid, but user would have clicked on the dialog anyway, that kind of thing )
271  idStr msg;
273  sessLocal.MessageBox( MSG_OK, msg, common->GetLanguageDict()->GetString( "#str_04310" ), true, NULL, NULL, true );
274  }
275  } else if ( args.Argc() == 2 && idStr::Icmp( args.Argv(1), "force" ) == 0 ) {
276  // cancelled in force mode
279  }
280  } while ( retkey );
281  recursed = false;
282 }
283 
284 /*
285 ===============================================================================
286 
287 SESSION LOCAL
288 
289 ===============================================================================
290 */
291 
292 /*
293 ===============
294 idSessionLocal::Clear
295 ===============
296 */
298 
299  insideUpdateScreen = false;
300  insideExecuteMapChange = false;
301 
302  loadingSaveGame = false;
303  savegameFile = NULL;
304  savegameVersion = 0;
305 
308  msgFireBack[ 0 ].Clear();
309  msgFireBack[ 1 ].Clear();
310 
311  timeHitch = 0;
312 
313  rw = NULL;
314  sw = NULL;
316  readDemo = NULL;
317  writeDemo = NULL;
318  renderdemoVersion = 0;
319  cmdDemoFile = NULL;
320 
321  syncNextGameFrame = false;
322  mapSpawned = false;
323  guiActive = NULL;
324  aviCaptureMode = false;
325  timeDemo = TD_NO;
326  waitingOnBind = false;
327  lastPacifierTime = 0;
328 
329  msgRunning = false;
331  msgIgnoreButtons = false;
332 
334 
335 #if ID_CONSOLE_LOCK
336  emptyDrawCount = 0;
337 #endif
338  ClearWipe();
339 
341  modsList.Clear();
342 
343  authEmitTimeout = 0;
344  authWaitBox = false;
345 
346  authMsg.Clear();
347 }
348 
349 /*
350 ===============
351 idSessionLocal::idSessionLocal
352 ===============
353 */
358 
360 
361  Clear();
362 }
363 
364 /*
365 ===============
366 idSessionLocal::~idSessionLocal
367 ===============
368 */
370 }
371 
372 /*
373 ===============
374 idSessionLocal::Stop
375 
376 called on errors and game exits
377 ===============
378 */
380  ClearWipe();
381 
382  // clear mapSpawned and demo playing flags
383  UnloadMap();
384 
385  // disconnect async client
387 
388  // kill async server
390 
391  if ( sw ) {
392  sw->StopAllSounds();
393  }
394 
395  insideUpdateScreen = false;
396  insideExecuteMapChange = false;
397 
398  // drop all guis
399  SetGUI( NULL, NULL );
400 }
401 
402 /*
403 ===============
404 idSessionLocal::Shutdown
405 ===============
406 */
408  int i;
409 
410  if ( aviCaptureMode ) {
411  EndAVICapture();
412  }
413 
414  Stop();
415 
416  if ( rw ) {
417  delete rw;
418  rw = NULL;
419  }
420 
421  if ( sw ) {
422  delete sw;
423  sw = NULL;
424  }
425 
426  if ( menuSoundWorld ) {
427  delete menuSoundWorld;
429  }
430 
433  for ( i = 0; i < MAX_ASYNC_CLIENTS; i++ ) {
436  }
437 
438  if ( guiMainMenu_MapList != NULL ) {
442  }
443 
444  Clear();
445 }
446 
447 /*
448 ===============
449 idSessionLocal::IsMultiplayer
450 ===============
451 */
453  return idAsyncNetwork::IsActive();
454 }
455 
456 /*
457 ================
458 idSessionLocal::StartWipe
459 
460 Draws and captures the current state, then starts a wipe with that image
461 ================
462 */
463 void idSessionLocal::StartWipe( const char *_wipeMaterial, bool hold ) {
464  console->Close();
465 
466  // render the current screen into a texture for the wipe model
467  renderSystem->CropRenderSize( 640, 480, true );
468 
469  Draw();
470 
471  renderSystem->CaptureRenderToImage( "_scratch");
472  renderSystem->UnCrop();
473 
474  wipeMaterial = declManager->FindMaterial( _wipeMaterial, false );
475 
478  wipeHold = hold;
479 }
480 
481 /*
482 ================
483 idSessionLocal::CompleteWipe
484 ================
485 */
487  if ( com_ticNumber == 0 ) {
488  // if the async thread hasn't started, we would hang here
489  wipeStopTic = 0;
490  UpdateScreen( true );
491  return;
492  }
493  while ( com_ticNumber < wipeStopTic ) {
494 #if ID_CONSOLE_LOCK
495  emptyDrawCount = 0;
496 #endif
497  UpdateScreen( true );
498  }
499 }
500 
501 /*
502 ================
503 idSessionLocal::ShowLoadingGui
504 ================
505 */
507  if ( com_ticNumber == 0 ) {
508  return;
509  }
510  console->Close();
511 
512  // introduced in D3XP code. don't think it actually fixes anything, but doesn't hurt either
513 #if 1
514  // Try and prevent the while loop from being skipped over (long hitch on the main thread?)
515  int stop = Sys_Milliseconds() + 1000;
516  int force = 10;
517  while ( Sys_Milliseconds() < stop || force-- > 0 ) {
519  session->Frame();
520  session->UpdateScreen( false );
521  }
522 #else
523  int stop = com_ticNumber + 1000.0f / USERCMD_MSEC * 1.0f;
524  while ( com_ticNumber < stop ) {
526  session->Frame();
527  session->UpdateScreen( false );
528  }
529 #endif
530 }
531 
532 
533 
534 /*
535 ================
536 idSessionLocal::ClearWipe
537 ================
538 */
540  wipeHold = false;
541  wipeStopTic = 0;
543 }
544 
545 /*
546 ================
547 Session_TestGUI_f
548 ================
549 */
550 static void Session_TestGUI_f( const idCmdArgs &args ) {
551  sessLocal.TestGUI( args.Argv(1) );
552 }
553 
554 /*
555 ================
556 idSessionLocal::TestGUI
557 ================
558 */
559 void idSessionLocal::TestGUI( const char *guiName ) {
560  if ( guiName && *guiName ) {
561  guiTest = uiManager->FindGui( guiName, true, false, true );
562  } else {
563  guiTest = NULL;
564  }
565 }
566 
567 /*
568 ================
569 FindUnusedFileName
570 ================
571 */
572 static idStr FindUnusedFileName( const char *format ) {
573  int i;
574  char filename[1024];
575 
576  for ( i = 0 ; i < 999 ; i++ ) {
577  sprintf( filename, format, i );
578  int len = fileSystem->ReadFile( filename, NULL, NULL );
579  if ( len <= 0 ) {
580  return filename; // file doesn't exist
581  }
582  }
583 
584  return filename;
585 }
586 
587 /*
588 ================
589 Session_DemoShot_f
590 ================
591 */
592 static void Session_DemoShot_f( const idCmdArgs &args ) {
593  if ( args.Argc() != 2 ) {
594  idStr filename = FindUnusedFileName( "demos/shot%03i.demo" );
595  sessLocal.DemoShot( filename );
596  } else {
597  sessLocal.DemoShot( va( "demos/shot_%s.demo", args.Argv(1) ) );
598  }
599 }
600 
601 /*
602 ================
603 Session_RecordDemo_f
604 ================
605 */
606 static void Session_RecordDemo_f( const idCmdArgs &args ) {
607  if ( args.Argc() != 2 ) {
608  idStr filename = FindUnusedFileName( "demos/demo%03i.demo" );
609  sessLocal.StartRecordingRenderDemo( filename );
610  } else {
611  sessLocal.StartRecordingRenderDemo( va( "demos/%s.demo", args.Argv(1) ) );
612  }
613 }
614 
615 /*
616 ================
617 Session_CompressDemo_f
618 ================
619 */
620 static void Session_CompressDemo_f( const idCmdArgs &args ) {
621  if ( args.Argc() == 2 ) {
622  sessLocal.CompressDemoFile( "2", args.Argv(1) );
623  } else if ( args.Argc() == 3 ) {
624  sessLocal.CompressDemoFile( args.Argv(2), args.Argv(1) );
625  } else {
626  common->Printf("use: CompressDemo <file> [scheme]\nscheme is the same as com_compressDemo, defaults to 2" );
627  }
628 }
629 
630 /*
631 ================
632 Session_StopRecordingDemo_f
633 ================
634 */
635 static void Session_StopRecordingDemo_f( const idCmdArgs &args ) {
636  sessLocal.StopRecordingRenderDemo();
637 }
638 
639 /*
640 ================
641 Session_PlayDemo_f
642 ================
643 */
644 static void Session_PlayDemo_f( const idCmdArgs &args ) {
645  if ( args.Argc() >= 2 ) {
646  sessLocal.StartPlayingRenderDemo( va( "demos/%s", args.Argv(1) ) );
647  }
648 }
649 
650 /*
651 ================
652 Session_TimeDemo_f
653 ================
654 */
655 static void Session_TimeDemo_f( const idCmdArgs &args ) {
656  if ( args.Argc() >= 2 ) {
657  sessLocal.TimeRenderDemo( va( "demos/%s", args.Argv(1) ), ( args.Argc() > 2 ) );
658  }
659 }
660 
661 /*
662 ================
663 Session_TimeDemoQuit_f
664 ================
665 */
666 static void Session_TimeDemoQuit_f( const idCmdArgs &args ) {
667  sessLocal.TimeRenderDemo( va( "demos/%s", args.Argv(1) ) );
668  if ( sessLocal.timeDemo == TD_YES ) {
669  // this allows hardware vendors to automate some testing
670  sessLocal.timeDemo = TD_YES_THEN_QUIT;
671  }
672 }
673 
674 /*
675 ================
676 Session_AVIDemo_f
677 ================
678 */
679 static void Session_AVIDemo_f( const idCmdArgs &args ) {
680  sessLocal.AVIRenderDemo( va( "demos/%s", args.Argv(1) ) );
681 }
682 
683 /*
684 ================
685 Session_AVIGame_f
686 ================
687 */
688 static void Session_AVIGame_f( const idCmdArgs &args ) {
689  sessLocal.AVIGame( args.Argv(1) );
690 }
691 
692 /*
693 ================
694 Session_AVICmdDemo_f
695 ================
696 */
697 static void Session_AVICmdDemo_f( const idCmdArgs &args ) {
698  sessLocal.AVICmdDemo( args.Argv(1) );
699 }
700 
701 /*
702 ================
703 Session_WriteCmdDemo_f
704 ================
705 */
706 static void Session_WriteCmdDemo_f( const idCmdArgs &args ) {
707  if ( args.Argc() == 1 ) {
708  idStr filename = FindUnusedFileName( "demos/cmdDemo%03i.cdemo" );
709  sessLocal.WriteCmdDemo( filename );
710  } else if ( args.Argc() == 2 ) {
711  sessLocal.WriteCmdDemo( va( "demos/%s.cdemo", args.Argv( 1 ) ) );
712  } else {
713  common->Printf( "usage: writeCmdDemo [demoName]\n" );
714  }
715 }
716 
717 /*
718 ================
719 Session_PlayCmdDemo_f
720 ================
721 */
722 static void Session_PlayCmdDemo_f( const idCmdArgs &args ) {
723  sessLocal.StartPlayingCmdDemo( args.Argv(1) );
724 }
725 
726 /*
727 ================
728 Session_TimeCmdDemo_f
729 ================
730 */
731 static void Session_TimeCmdDemo_f( const idCmdArgs &args ) {
732  sessLocal.TimeCmdDemo( args.Argv(1) );
733 }
734 
735 /*
736 ================
737 Session_Disconnect_f
738 ================
739 */
740 static void Session_Disconnect_f( const idCmdArgs &args ) {
741  sessLocal.Stop();
742  sessLocal.StartMenu();
743  if ( soundSystem ) {
744  soundSystem->SetMute( false );
745  }
746 }
747 
748 #ifdef ID_DEMO_BUILD
749 /*
750 ================
751 Session_EndOfDemo_f
752 ================
753 */
754 static void Session_EndOfDemo_f( const idCmdArgs &args ) {
755  sessLocal.Stop();
756  sessLocal.StartMenu();
757  if ( soundSystem ) {
758  soundSystem->SetMute( false );
759  }
760  if ( sessLocal.guiActive ) {
761  sessLocal.guiActive->HandleNamedEvent( "endOfDemo" );
762  }
763 }
764 #endif
765 
766 /*
767 ================
768 Session_ExitCmdDemo_f
769 ================
770 */
771 static void Session_ExitCmdDemo_f( const idCmdArgs &args ) {
772  if ( !sessLocal.cmdDemoFile ) {
773  common->Printf( "not reading from a cmdDemo\n" );
774  return;
775  }
776  fileSystem->CloseFile( sessLocal.cmdDemoFile );
777  common->Printf( "Command demo exited at logIndex %i\n", sessLocal.logIndex );
778  sessLocal.cmdDemoFile = NULL;
779 }
780 
781 /*
782 ================
783 idSessionLocal::StartRecordingRenderDemo
784 ================
785 */
786 void idSessionLocal::StartRecordingRenderDemo( const char *demoName ) {
787  if ( writeDemo ) {
788  // allow it to act like a toggle
790  return;
791  }
792 
793  if ( !demoName[0] ) {
794  common->Printf( "idSessionLocal::StartRecordingRenderDemo: no name specified\n" );
795  return;
796  }
797 
798  console->Close();
799 
800  writeDemo = new idDemoFile;
801  if ( !writeDemo->OpenForWriting( demoName ) ) {
802  common->Printf( "error opening %s\n", demoName );
803  delete writeDemo;
804  writeDemo = NULL;
805  return;
806  }
807 
808  common->Printf( "recording to %s\n", writeDemo->GetName() );
809 
812 
813  // if we are in a map already, dump the current state
816 }
817 
818 /*
819 ================
820 idSessionLocal::StopRecordingRenderDemo
821 ================
822 */
824  if ( !writeDemo ) {
825  common->Printf( "idSessionLocal::StopRecordingRenderDemo: not recording\n" );
826  return;
827  }
828  sw->StopWritingDemo();
829  rw->StopWritingDemo();
830 
831  writeDemo->Close();
832  common->Printf( "stopped recording %s.\n", writeDemo->GetName() );
833  delete writeDemo;
834  writeDemo = NULL;
835 }
836 
837 /*
838 ================
839 idSessionLocal::StopPlayingRenderDemo
840 
841 Reports timeDemo numbers and finishes any avi recording
842 ================
843 */
845  if ( !readDemo ) {
846  timeDemo = TD_NO;
847  return;
848  }
849 
850  // Record the stop time before doing anything that could be time consuming
851  int timeDemoStopTime = Sys_Milliseconds();
852 
853  EndAVICapture();
854 
855  readDemo->Close();
856 
857  sw->StopAllSounds();
859 
860  common->Printf( "stopped playing %s.\n", readDemo->GetName() );
861  delete readDemo;
862  readDemo = NULL;
863 
864  if ( timeDemo ) {
865  // report the stats
866  float demoSeconds = ( timeDemoStopTime - timeDemoStartTime ) * 0.001f;
867  float demoFPS = numDemoFrames / demoSeconds;
868  idStr message = va( "%i frames rendered in %3.1f seconds = %3.1f fps\n", numDemoFrames, demoSeconds, demoFPS );
869 
870  common->Printf( message );
871  if ( timeDemo == TD_YES_THEN_QUIT ) {
873  } else {
874  soundSystem->SetMute( true );
875  MessageBox( MSG_OK, message, "Time Demo Results", true );
876  soundSystem->SetMute( false );
877  }
878  timeDemo = TD_NO;
879  }
880 }
881 
882 /*
883 ================
884 idSessionLocal::DemoShot
885 
886 A demoShot is a single frame demo
887 ================
888 */
889 void idSessionLocal::DemoShot( const char *demoName ) {
890  StartRecordingRenderDemo( demoName );
891 
892  // force draw one frame
893  UpdateScreen();
894 
896 }
897 
898 /*
899 ================
900 idSessionLocal::StartPlayingRenderDemo
901 ================
902 */
904  if ( !demoName[0] ) {
905  common->Printf( "idSessionLocal::StartPlayingRenderDemo: no name specified\n" );
906  return;
907  }
908 
909  // make sure localSound / GUI intro music shuts up
910  sw->StopAllSounds();
911  sw->PlayShaderDirectly( "", 0 );
914 
915  // exit any current game
916  Stop();
917 
918  // automatically put the console away
919  console->Close();
920 
921  // bring up the loading screen manually, since demos won't
922  // call ExecuteMapChange()
923  guiLoading = uiManager->FindGui( "guis/map/loading.gui", true, false, true );
924  guiLoading->SetStateString( "demo", common->GetLanguageDict()->GetString( "#str_02087" ) );
925  readDemo = new idDemoFile;
926  demoName.DefaultFileExtension( ".demo" );
927  if ( !readDemo->OpenForReading( demoName ) ) {
928  common->Printf( "couldn't open %s\n", demoName.c_str() );
929  delete readDemo;
930  readDemo = NULL;
931  Stop();
932  StartMenu();
933  soundSystem->SetMute( false );
934  return;
935  }
936 
937  insideExecuteMapChange = true;
938  UpdateScreen();
939  insideExecuteMapChange = false;
940  guiLoading->SetStateString( "demo", "" );
941 
942  // setup default render demo settings
943  // that's default for <= Doom3 v1.1
944  renderdemoVersion = 1;
945  savegameVersion = 16;
946 
947  AdvanceRenderDemo( true );
948 
949  numDemoFrames = 1;
950 
951  lastDemoTic = -1;
953 }
954 
955 /*
956 ================
957 idSessionLocal::TimeRenderDemo
958 ================
959 */
960 void idSessionLocal::TimeRenderDemo( const char *demoName, bool twice ) {
961  idStr demo = demoName;
962 
963  // no sound in time demos
964  soundSystem->SetMute( true );
965 
966  StartPlayingRenderDemo( demo );
967 
968  if ( twice && readDemo ) {
969  // cycle through once to precache everything
970  guiLoading->SetStateString( "demo", common->GetLanguageDict()->GetString( "#str_04852" ) );
972  while ( readDemo ) {
973  insideExecuteMapChange = true;
974  UpdateScreen();
975  insideExecuteMapChange = false;
976  AdvanceRenderDemo( true );
977  }
978  guiLoading->SetStateString( "demo", "" );
979  StartPlayingRenderDemo( demo );
980  }
981 
982 
983  if ( !readDemo ) {
984  return;
985  }
986 
987  timeDemo = TD_YES;
988 }
989 
990 
991 /*
992 ================
993 idSessionLocal::BeginAVICapture
994 ================
995 */
996 void idSessionLocal::BeginAVICapture( const char *demoName ) {
997  idStr name = demoName;
999  aviCaptureMode = true;
1000  aviDemoFrameCount = 0;
1001  aviTicStart = 0;
1002  sw->AVIOpen( va( "demos/%s/", aviDemoShortName.c_str() ), aviDemoShortName.c_str() );
1003 }
1004 
1005 /*
1006 ================
1007 idSessionLocal::EndAVICapture
1008 ================
1009 */
1011  if ( !aviCaptureMode ) {
1012  return;
1013  }
1014 
1015  sw->AVIClose();
1016 
1017  // write a .roqParam file so the demo can be converted to a roq file
1018  idFile *f = fileSystem->OpenFileWrite( va( "demos/%s/%s.roqParam",
1020  f->Printf( "INPUT_DIR demos/%s\n", aviDemoShortName.c_str() );
1021  f->Printf( "FILENAME demos/%s/%s.RoQ\n", aviDemoShortName.c_str(), aviDemoShortName.c_str() );
1022  f->Printf( "\nINPUT\n" );
1023  f->Printf( "%s_*.tga [00000-%05i]\n", aviDemoShortName.c_str(), (int)( aviDemoFrameCount-1 ) );
1024  f->Printf( "END_INPUT\n" );
1025  delete f;
1026 
1027  common->Printf( "captured %i frames for %s.\n", ( int )aviDemoFrameCount, aviDemoShortName.c_str() );
1028 
1029  aviCaptureMode = false;
1030 }
1031 
1032 
1033 /*
1034 ================
1035 idSessionLocal::AVIRenderDemo
1036 ================
1037 */
1038 void idSessionLocal::AVIRenderDemo( const char *_demoName ) {
1039  idStr demoName = _demoName; // copy off from va() buffer
1040 
1041  StartPlayingRenderDemo( demoName );
1042  if ( !readDemo ) {
1043  return;
1044  }
1045 
1046  BeginAVICapture( demoName.c_str() ) ;
1047 
1048  // I don't understand why I need to do this twice, something
1049  // strange with the nvidia swapbuffers?
1050  UpdateScreen();
1051 }
1052 
1053 /*
1054 ================
1055 idSessionLocal::AVICmdDemo
1056 ================
1057 */
1058 void idSessionLocal::AVICmdDemo( const char *demoName ) {
1059  StartPlayingCmdDemo( demoName );
1060 
1061  BeginAVICapture( demoName ) ;
1062 }
1063 
1064 /*
1065 ================
1066 idSessionLocal::AVIGame
1067 
1068 Start AVI recording the current game session
1069 ================
1070 */
1071 void idSessionLocal::AVIGame( const char *demoName ) {
1072  if ( aviCaptureMode ) {
1073  EndAVICapture();
1074  return;
1075  }
1076 
1077  if ( !mapSpawned ) {
1078  common->Printf( "No map spawned.\n" );
1079  }
1080 
1081  if ( !demoName || !demoName[0] ) {
1082  idStr filename = FindUnusedFileName( "demos/game%03i.game" );
1083  demoName = filename.c_str();
1084 
1085  // write a one byte stub .game file just so the FindUnusedFileName works,
1086  fileSystem->WriteFile( demoName, demoName, 1 );
1087  }
1088 
1089  BeginAVICapture( demoName ) ;
1090 }
1091 
1092 /*
1093 ================
1094 idSessionLocal::CompressDemoFile
1095 ================
1096 */
1097 void idSessionLocal::CompressDemoFile( const char *scheme, const char *demoName ) {
1098  idStr fullDemoName = "demos/";
1099  fullDemoName += demoName;
1100  fullDemoName.DefaultFileExtension( ".demo" );
1101  idStr compressedName = fullDemoName;
1102  compressedName.StripFileExtension();
1103  compressedName.Append( "_compressed.demo" );
1104 
1105  int savedCompression = cvarSystem->GetCVarInteger("com_compressDemos");
1106  bool savedPreload = cvarSystem->GetCVarBool("com_preloadDemos");
1107  cvarSystem->SetCVarBool( "com_preloadDemos", false );
1108  cvarSystem->SetCVarInteger("com_compressDemos", atoi(scheme) );
1109 
1110  idDemoFile demoread, demowrite;
1111  if ( !demoread.OpenForReading( fullDemoName ) ) {
1112  common->Printf( "Could not open %s for reading\n", fullDemoName.c_str() );
1113  return;
1114  }
1115  if ( !demowrite.OpenForWriting( compressedName ) ) {
1116  common->Printf( "Could not open %s for writing\n", compressedName.c_str() );
1117  demoread.Close();
1118  cvarSystem->SetCVarBool( "com_preloadDemos", savedPreload );
1119  cvarSystem->SetCVarInteger("com_compressDemos", savedCompression);
1120  return;
1121  }
1122  common->SetRefreshOnPrint( true );
1123  common->Printf( "Compressing %s to %s...\n", fullDemoName.c_str(), compressedName.c_str() );
1124 
1125  static const int bufferSize = 65535;
1126  char buffer[bufferSize];
1127  int bytesRead;
1128  while ( 0 != (bytesRead = demoread.Read( buffer, bufferSize ) ) ) {
1129  demowrite.Write( buffer, bytesRead );
1130  common->Printf( "." );
1131  }
1132 
1133  demoread.Close();
1134  demowrite.Close();
1135 
1136  cvarSystem->SetCVarBool( "com_preloadDemos", savedPreload );
1137  cvarSystem->SetCVarInteger("com_compressDemos", savedCompression);
1138 
1139  common->Printf( "Done\n" );
1140  common->SetRefreshOnPrint( false );
1141 
1142 }
1143 
1144 
1145 /*
1146 ===============
1147 idSessionLocal::StartNewGame
1148 ===============
1149 */
1150 void idSessionLocal::StartNewGame( const char *mapName, bool devmap ) {
1151 #ifdef ID_DEDICATED
1152  common->Printf( "Dedicated servers cannot start singleplayer games.\n" );
1153  return;
1154 #else
1155 #if ID_ENFORCE_KEY
1156  // strict check. don't let a game start without a definitive answer
1157  if ( !CDKeysAreValid( true ) ) {
1158  bool prompt = true;
1159  if ( MaybeWaitOnCDKey() ) {
1160  // check again, maybe we just needed more time
1161  if ( CDKeysAreValid( true ) ) {
1162  // can continue directly
1163  prompt = false;
1164  }
1165  }
1166  if ( prompt ) {
1167  cmdSystem->BufferCommandText( CMD_EXEC_NOW, "promptKey force" );
1169  }
1170  }
1171 #endif
1172  if ( idAsyncNetwork::server.IsActive() ) {
1173  common->Printf("Server running, use si_map / serverMapRestart\n");
1174  return;
1175  }
1176  if ( idAsyncNetwork::client.IsActive() ) {
1177  common->Printf("Client running, disconnect from server first\n");
1178  return;
1179  }
1180 
1181  // clear the userInfo so the player starts out with the defaults
1185 
1188  mapSpawnData.serverInfo.Set( "si_gameType", "singleplayer" );
1189 
1190  // set the devmap key so any play testing items will be given at
1191  // spawn time to set approximately the right weapons and ammo
1192  if(devmap) {
1193  mapSpawnData.serverInfo.Set( "devmap", "1" );
1194  }
1195 
1198 
1199  MoveToNewMap( mapName );
1200 #endif
1201 }
1202 
1203 /*
1204 ===============
1205 idSessionLocal::GetAutoSaveName
1206 ===============
1207 */
1208 idStr idSessionLocal::GetAutoSaveName( const char *mapName ) const {
1209  const idDecl *mapDecl = declManager->FindType( DECL_MAPDEF, mapName, false );
1210  const idDeclEntityDef *mapDef = static_cast<const idDeclEntityDef *>( mapDecl );
1211  if ( mapDef ) {
1212  mapName = common->GetLanguageDict()->GetString( mapDef->dict.GetString( "name", mapName ) );
1213  }
1214  // Fixme: Localization
1215  return va( "^3AutoSave:^0 %s", mapName );
1216 }
1217 
1218 /*
1219 ===============
1220 idSessionLocal::MoveToNewMap
1221 
1222 Leaves the existing userinfo and serverinfo
1223 ===============
1224 */
1225 void idSessionLocal::MoveToNewMap( const char *mapName ) {
1226  mapSpawnData.serverInfo.Set( "si_map", mapName );
1227 
1228  ExecuteMapChange();
1229 
1230  if ( !mapSpawnData.serverInfo.GetBool("devmap") ) {
1231  // Autosave at the beginning of the level
1232  SaveGame( GetAutoSaveName( mapName ), true );
1233  }
1234 
1235  SetGUI( NULL, NULL );
1236 }
1237 
1238 /*
1239 ==============
1240 SaveCmdDemoFromFile
1241 ==============
1242 */
1244 
1246 
1247  for ( int i = 0 ; i < MAX_ASYNC_CLIENTS ; i++ ) {
1250  }
1251 
1253 
1254  if ( numClients < 1 ) {
1255  numClients = 1;
1256  }
1257  file->Write( loggedUsercmds, numClients * logIndex * sizeof( loggedUsercmds[0] ) );
1258 }
1259 
1260 /*
1261 ==============
1262 idSessionLocal::LoadCmdDemoFromFile
1263 ==============
1264 */
1266 
1268 
1269  for ( int i = 0 ; i < MAX_ASYNC_CLIENTS ; i++ ) {
1272  }
1274 }
1275 
1276 /*
1277 ==============
1278 idSessionLocal::WriteCmdDemo
1279 
1280 Dumps the accumulated commands for the current level.
1281 This should still work after disconnecting from a level
1282 ==============
1283 */
1284 void idSessionLocal::WriteCmdDemo( const char *demoName, bool save ) {
1285 
1286  if ( !demoName[0] ) {
1287  common->Printf( "idSessionLocal::WriteCmdDemo: no name specified\n" );
1288  return;
1289  }
1290 
1291  idStr statsName;
1292  if (save) {
1293  statsName = demoName;
1294  statsName.StripFileExtension();
1295  statsName.DefaultFileExtension(".stats");
1296  }
1297 
1298  common->Printf( "writing save data to %s\n", demoName );
1299 
1300  idFile *cmdDemoFile = fileSystem->OpenFileWrite( demoName );
1301  if ( !cmdDemoFile ) {
1302  common->Printf( "Couldn't open for writing %s\n", demoName );
1303  return;
1304  }
1305 
1306  if ( save ) {
1307  cmdDemoFile->Write( &logIndex, sizeof( logIndex ) );
1308  }
1309 
1310  SaveCmdDemoToFile( cmdDemoFile );
1311 
1312  if ( save ) {
1313  idFile *statsFile = fileSystem->OpenFileWrite( statsName );
1314  if ( statsFile ) {
1315  statsFile->Write( &statIndex, sizeof( statIndex ) );
1316  statsFile->Write( loggedStats, numClients * statIndex * sizeof( loggedStats[0] ) );
1317  fileSystem->CloseFile( statsFile );
1318  }
1319  }
1320 
1321  fileSystem->CloseFile( cmdDemoFile );
1322 }
1323 
1324 /*
1325 ===============
1326 idSessionLocal::FinishCmdLoad
1327 ===============
1328 */
1330 }
1331 
1332 /*
1333 ===============
1334 idSessionLocal::StartPlayingCmdDemo
1335 ===============
1336 */
1337 void idSessionLocal::StartPlayingCmdDemo(const char *demoName) {
1338  // exit any current game
1339  Stop();
1340 
1341  idStr fullDemoName = "demos/";
1342  fullDemoName += demoName;
1343  fullDemoName.DefaultFileExtension( ".cdemo" );
1344  cmdDemoFile = fileSystem->OpenFileRead(fullDemoName);
1345 
1346  if ( cmdDemoFile == NULL ) {
1347  common->Printf( "Couldn't open %s\n", fullDemoName.c_str() );
1348  return;
1349  }
1350 
1351  guiLoading = uiManager->FindGui( "guis/map/loading.gui", true, false, true );
1352  //cmdDemoFile->Read(&loadGameTime, sizeof(loadGameTime));
1353 
1355 
1356  // start the map
1357  ExecuteMapChange();
1358 
1359  cmdDemoFile = fileSystem->OpenFileRead(fullDemoName);
1360 
1361  // have to do this twice as the execmapchange clears the cmddemofile
1363 
1364  // run one frame to get the view angles correct
1365  RunGameTic();
1366 }
1367 
1368 /*
1369 ===============
1370 idSessionLocal::TimeCmdDemo
1371 ===============
1372 */
1373 void idSessionLocal::TimeCmdDemo( const char *demoName ) {
1374  StartPlayingCmdDemo( demoName );
1375  ClearWipe();
1376  UpdateScreen();
1377 
1378  int startTime = Sys_Milliseconds();
1379  int count = 0;
1380  int minuteStart, minuteEnd;
1381  float sec;
1382 
1383  // run all the frames in sequence
1384  minuteStart = startTime;
1385 
1386  while( cmdDemoFile ) {
1387  RunGameTic();
1388  count++;
1389 
1390  if ( count / 3600 != ( count - 1 ) / 3600 ) {
1391  minuteEnd = Sys_Milliseconds();
1392  sec = ( minuteEnd - minuteStart ) / 1000.0;
1393  minuteStart = minuteEnd;
1394  common->Printf( "minute %i took %3.1f seconds\n", count / 3600, sec );
1395  UpdateScreen();
1396  }
1397  }
1398 
1399  int endTime = Sys_Milliseconds();
1400  sec = ( endTime - startTime ) / 1000.0;
1401  common->Printf( "%i seconds of game, replayed in %5.1f seconds\n", count / 60, sec );
1402 }
1403 
1404 /*
1405 ===============
1406 idSessionLocal::UnloadMap
1407 
1408 Performs cleanup that needs to happen between maps, or when a
1409 game is exited.
1410 Exits with mapSpawned = false
1411 ===============
1412 */
1415 
1416  // end the current map in the game
1417  if ( game ) {
1418  game->MapShutdown();
1419  }
1420 
1421  if ( cmdDemoFile ) {
1423  cmdDemoFile = NULL;
1424  }
1425 
1426  if ( writeDemo ) {
1428  }
1429 
1430  mapSpawned = false;
1431 }
1432 
1433 /*
1434 ===============
1435 idSessionLocal::LoadLoadingGui
1436 ===============
1437 */
1438 void idSessionLocal::LoadLoadingGui( const char *mapName ) {
1439  // load / program a gui to stay up on the screen while loading
1440  idStr stripped = mapName;
1441  stripped.StripFileExtension();
1442  stripped.StripPath();
1443 
1444  char guiMap[ MAX_STRING_CHARS ];
1445  strncpy( guiMap, va( "guis/map/%s.gui", stripped.c_str() ), MAX_STRING_CHARS );
1446  // give the gamecode a chance to override
1447  game->GetMapLoadingGUI( guiMap );
1448 
1449  if ( uiManager->CheckGui( guiMap ) ) {
1450  guiLoading = uiManager->FindGui( guiMap, true, false, true );
1451  } else {
1452  guiLoading = uiManager->FindGui( "guis/map/loading.gui", true, false, true );
1453  }
1454  guiLoading->SetStateFloat( "map_loading", 0.0f );
1455 }
1456 
1457 /*
1458 ===============
1459 idSessionLocal::GetBytesNeededForMapLoad
1460 ===============
1461 */
1462 int idSessionLocal::GetBytesNeededForMapLoad( const char *mapName ) {
1463  const idDecl *mapDecl = declManager->FindType( DECL_MAPDEF, mapName, false );
1464  const idDeclEntityDef *mapDef = static_cast<const idDeclEntityDef *>( mapDecl );
1465  if ( mapDef ) {
1466  return mapDef->dict.GetInt( va("size%d", Max( 0, com_machineSpec.GetInteger() ) ) );
1467  } else {
1468  if ( com_machineSpec.GetInteger() < 2 ) {
1469  return 200 * 1024 * 1024;
1470  } else {
1471  return 400 * 1024 * 1024;
1472  }
1473  }
1474 }
1475 
1476 /*
1477 ===============
1478 idSessionLocal::SetBytesNeededForMapLoad
1479 ===============
1480 */
1481 void idSessionLocal::SetBytesNeededForMapLoad( const char *mapName, int bytesNeeded ) {
1482  idDecl *mapDecl = const_cast<idDecl *>(declManager->FindType( DECL_MAPDEF, mapName, false ));
1483  idDeclEntityDef *mapDef = static_cast<idDeclEntityDef *>( mapDecl );
1484 
1485  if ( com_updateLoadSize.GetBool() && mapDef ) {
1486  // we assume that if com_updateLoadSize is true then the file is writable
1487 
1488  mapDef->dict.SetInt( va("size%d", com_machineSpec.GetInteger()), bytesNeeded );
1489 
1490  idStr declText = "\nmapDef ";
1491  declText += mapDef->GetName();
1492  declText += " {\n";
1493  for (int i=0; i<mapDef->dict.GetNumKeyVals(); i++) {
1494  const idKeyValue *kv = mapDef->dict.GetKeyVal( i );
1495  if ( kv && (kv->GetKey().Cmp("classname") != 0 ) ) {
1496  declText += "\t\"" + kv->GetKey() + "\"\t\t\"" + kv->GetValue() + "\"\n";
1497  }
1498  }
1499  declText += "}";
1500  mapDef->SetText( declText );
1501  mapDef->ReplaceSourceFileText();
1502  }
1503 }
1504 
1505 /*
1506 ===============
1507 idSessionLocal::ExecuteMapChange
1508 
1509 Performs the initialization of a game based on mapSpawnData, used for both single
1510 player and multiplayer, but not for renderDemos, which don't
1511 create a game at all.
1512 Exits with mapSpawned = true
1513 ===============
1514 */
1515 void idSessionLocal::ExecuteMapChange( bool noFadeWipe ) {
1516  int i;
1517  bool reloadingSameMap;
1518 
1519  // close console and remove any prints from the notify lines
1520  console->Close();
1521 
1522  if ( IsMultiplayer() ) {
1523  // make sure the mp GUI isn't up, or when players get back in the
1524  // map, mpGame's menu and the gui will be out of sync.
1525  SetGUI( NULL, NULL );
1526  }
1527 
1528  // mute sound
1529  soundSystem->SetMute( true );
1530 
1531  // clear all menu sounds
1533 
1534  // unpause the game sound world
1535  // NOTE: we UnPause again later down. not sure this is needed
1536  if ( sw->IsPaused() ) {
1537  sw->UnPause();
1538  }
1539 
1540  if ( !noFadeWipe ) {
1541  // capture the current screen and start a wipe
1542  StartWipe( "wipeMaterial", true );
1543 
1544  // immediately complete the wipe to fade out the level transition
1545  // run the wipe to completion
1546  CompleteWipe();
1547  }
1548 
1549  // extract the map name from serverinfo
1550  idStr mapString = mapSpawnData.serverInfo.GetString( "si_map" );
1551 
1552  idStr fullMapName = "maps/";
1553  fullMapName += mapString;
1554  fullMapName.StripFileExtension();
1555 
1556  // shut down the existing game if it is running
1557  UnloadMap();
1558 
1559  // don't do the deferred caching if we are reloading the same map
1560  if ( fullMapName == currentMapName ) {
1561  reloadingSameMap = true;
1562  } else {
1563  reloadingSameMap = false;
1564  currentMapName = fullMapName;
1565  }
1566 
1567  // note which media we are going to need to load
1568  if ( !reloadingSameMap ) {
1572  }
1573 
1575  uiManager->Reload( true );
1576 
1577  // set the loading gui that we will wipe to
1578  LoadLoadingGui( mapString );
1579 
1580  // cause prints to force screen updates as a pacifier,
1581  // and draw the loading gui instead of game draws
1582  insideExecuteMapChange = true;
1583 
1584  // if this works out we will probably want all the sizes in a def file although this solution will
1585  // work for new maps etc. after the first load. we can also drop the sizes into the default.cfg
1587  if ( !reloadingSameMap ) {
1589  } else {
1590  bytesNeededForMapLoad = 30 * 1024 * 1024;
1591  }
1592 
1593  ClearWipe();
1594 
1595  // let the loading gui spin for 1 second to animate out
1596  ShowLoadingGui();
1597 
1598  // note any warning prints that happen during the load process
1599  common->ClearWarnings( mapString );
1600 
1601  // release the mouse cursor
1602  // before we do this potentially long operation
1603  Sys_GrabMouseCursor( false );
1604 
1605  // if net play, we get the number of clients during mapSpawnInfo processing
1606  if ( !idAsyncNetwork::IsActive() ) {
1607  numClients = 1;
1608  }
1609 
1610  int start = Sys_Milliseconds();
1611 
1612  common->Printf( "--------- Map Initialization ---------\n" );
1613  common->Printf( "Map: %s\n", mapString.c_str() );
1614 
1615  // let the renderSystem load all the geometry
1616  if ( !rw->InitFromMap( fullMapName ) ) {
1617  common->Error( "couldn't load %s", fullMapName.c_str() );
1618  }
1619 
1620  // for the synchronous networking we needed to roll the angles over from
1621  // level to level, but now we can just clear everything
1623  memset( &mapSpawnData.mapSpawnUsercmd, 0, sizeof( mapSpawnData.mapSpawnUsercmd ) );
1624 
1625  // set the user info
1626  for ( i = 0; i < numClients; i++ ) {
1629  }
1630 
1631  // load and spawn all other entities ( from a savegame possibly )
1632  if ( loadingSaveGame && savegameFile ) {
1633  if ( game->InitFromSaveGame( fullMapName + ".map", rw, sw, savegameFile ) == false ) {
1634  // If the loadgame failed, restart the map with the player persistent data
1635  loadingSaveGame = false;
1637  savegameFile = NULL;
1638 
1640  game->InitFromNewMap( fullMapName + ".map", rw, sw, idAsyncNetwork::server.IsActive(), idAsyncNetwork::client.IsActive(), Sys_Milliseconds() );
1641  }
1642  } else {
1644  game->InitFromNewMap( fullMapName + ".map", rw, sw, idAsyncNetwork::server.IsActive(), idAsyncNetwork::client.IsActive(), Sys_Milliseconds() );
1645  }
1646 
1648  // spawn players
1649  for ( i = 0; i < numClients; i++ ) {
1650  game->SpawnPlayer( i );
1651  }
1652  }
1653 
1654  // actually purge/load the media
1655  if ( !reloadingSameMap ) {
1657  soundSystem->EndLevelLoad( mapString.c_str() );
1660  }
1662 
1664  // run a few frames to allow everything to settle
1665  for ( i = 0; i < 10; i++ ) {
1667  }
1668  }
1669 
1670  common->Printf ("-----------------------------------\n");
1671 
1672  int msec = Sys_Milliseconds() - start;
1673  common->Printf( "%6d msec to load %s\n", msec, mapString.c_str() );
1674 
1675  // let the renderSystem generate interactions now that everything is spawned
1677 
1678  common->PrintWarnings();
1679 
1680  if ( guiLoading && bytesNeededForMapLoad ) {
1681  float pct = guiLoading->State().GetFloat( "map_loading" );
1682  if ( pct < 0.0f ) {
1683  pct = 0.0f;
1684  }
1685  while ( pct < 1.0f ) {
1686  guiLoading->SetStateFloat( "map_loading", pct );
1689  UpdateScreen();
1690  pct += 0.05f;
1691  }
1692  }
1693 
1694  // capture the current screen and start a wipe
1695  StartWipe( "wipe2Material" );
1696 
1697  usercmdGen->Clear();
1698 
1699  // start saving commands for possible writeCmdDemo usage
1700  logIndex = 0;
1701  statIndex = 0;
1702  lastSaveIndex = 0;
1703 
1704  // don't bother spinning over all the tics we spent loading
1706 
1707  // remove any prints from the notify lines
1709 
1710  // stop drawing the laoding screen
1711  insideExecuteMapChange = false;
1712 
1713  Sys_SetPhysicalWorkMemory( -1, -1 );
1714 
1715  // set the game sound world for playback
1717 
1718  // when loading a save game the sound is paused
1719  if ( sw->IsPaused() ) {
1720  // unpause the game sound world
1721  sw->UnPause();
1722  }
1723 
1724  // restart entity sound playback
1725  soundSystem->SetMute( false );
1726 
1727  // we are valid for game draws now
1728  mapSpawned = true;
1729  Sys_ClearEvents();
1730 }
1731 
1732 /*
1733 ===============
1734 LoadGame_f
1735 ===============
1736 */
1737 void LoadGame_f( const idCmdArgs &args ) {
1738  console->Close();
1739  if ( args.Argc() < 2 || idStr::Icmp(args.Argv(1), "quick" ) == 0 ) {
1740  idStr saveName = common->GetLanguageDict()->GetString( "#str_07178" );
1741  sessLocal.LoadGame( saveName );
1742  } else {
1743  sessLocal.LoadGame( args.Argv(1) );
1744  }
1745 }
1746 
1747 /*
1748 ===============
1749 SaveGame_f
1750 ===============
1751 */
1752 void SaveGame_f( const idCmdArgs &args ) {
1753  if ( args.Argc() < 2 || idStr::Icmp( args.Argv(1), "quick" ) == 0 ) {
1754  idStr saveName = common->GetLanguageDict()->GetString( "#str_07178" );
1755  if ( sessLocal.SaveGame( saveName ) ) {
1756  common->Printf( "%s\n", saveName.c_str() );
1757  }
1758  } else {
1759  if ( sessLocal.SaveGame( args.Argv(1) ) ) {
1760  common->Printf( "Saved %s\n", args.Argv(1) );
1761  }
1762  }
1763 }
1764 
1765 /*
1766 ===============
1767 TakeViewNotes_f
1768 ===============
1769 */
1770 void TakeViewNotes_f( const idCmdArgs &args ) {
1771  const char *p = ( args.Argc() > 1 ) ? args.Argv( 1 ) : "";
1772  sessLocal.TakeNotes( p );
1773 }
1774 
1775 /*
1776 ===============
1777 TakeViewNotes2_f
1778 ===============
1779 */
1780 void TakeViewNotes2_f( const idCmdArgs &args ) {
1781  const char *p = ( args.Argc() > 1 ) ? args.Argv( 1 ) : "";
1782  sessLocal.TakeNotes( p, true );
1783 }
1784 
1785 /*
1786 ===============
1787 idSessionLocal::TakeNotes
1788 ===============
1789 */
1790 void idSessionLocal::TakeNotes( const char *p, bool extended ) {
1791  if ( !mapSpawned ) {
1792  common->Printf( "No map loaded!\n" );
1793  return;
1794  }
1795 
1796  if ( extended ) {
1797  guiTakeNotes = uiManager->FindGui( "guis/takeNotes2.gui", true, false, true );
1798 
1799 #if 0
1800  const char *people[] = {
1801  "Nobody", "Adam", "Brandon", "David", "PHook", "Jay", "Jake",
1802  "PatJ", "Brett", "Ted", "Darin", "Brian", "Sean"
1803  };
1804 #else
1805  const char *people[] = {
1806  "Tim", "Kenneth", "Robert",
1807  "Matt", "Mal", "Jerry", "Steve", "Pat",
1808  "Xian", "Ed", "Fred", "James", "Eric", "Andy", "Seneca", "Patrick", "Kevin",
1809  "MrElusive", "Jim", "Brian", "John", "Adrian", "Nobody"
1810  };
1811 #endif
1812  const int numPeople = sizeof( people ) / sizeof( people[0] );
1813 
1814  idListGUI * guiList_people = uiManager->AllocListGUI();
1815  guiList_people->Config( guiTakeNotes, "person" );
1816  for ( int i = 0; i < numPeople; i++ ) {
1817  guiList_people->Push( people[i] );
1818  }
1819  uiManager->FreeListGUI( guiList_people );
1820 
1821  } else {
1822  guiTakeNotes = uiManager->FindGui( "guis/takeNotes.gui", true, false, true );
1823  }
1824 
1825  SetGUI( guiTakeNotes, NULL );
1826  guiActive->SetStateString( "note", "" );
1827  guiActive->SetStateString( "notefile", p );
1828  guiActive->SetStateBool( "extended", extended );
1829  guiActive->Activate( true, com_frameTime );
1830 }
1831 
1832 /*
1833 ===============
1834 Session_Hitch_f
1835 ===============
1836 */
1837 void Session_Hitch_f( const idCmdArgs &args ) {
1839  if ( sw ) {
1840  soundSystem->SetMute(true);
1841  sw->Pause();
1843  }
1844  if ( args.Argc() == 2 ) {
1845  Sys_Sleep( atoi(args.Argv(1)) );
1846  } else {
1847  Sys_Sleep( 100 );
1848  }
1849  if ( sw ) {
1851  sw->UnPause();
1852  soundSystem->SetMute(false);
1853  }
1854 }
1855 
1856 /*
1857 ===============
1858 idSessionLocal::ScrubSaveGameFileName
1859 
1860 Turns a bad file name into a good one or your money back
1861 ===============
1862 */
1863 void idSessionLocal::ScrubSaveGameFileName( idStr &saveFileName ) const {
1864  int i;
1865  idStr inFileName;
1866 
1867  inFileName = saveFileName;
1868  inFileName.RemoveColors();
1869  inFileName.StripFileExtension();
1870 
1871  saveFileName.Clear();
1872 
1873  int len = inFileName.Length();
1874  for ( i = 0; i < len; i++ ) {
1875  if ( strchr( "',.~!@#$%^&*()[]{}<>\\|/=?+;:-\'\"", inFileName[i] ) ) {
1876  // random junk
1877  saveFileName += '_';
1878  } else if ( (const unsigned char)inFileName[i] >= 128 ) {
1879  // high ascii chars
1880  saveFileName += '_';
1881  } else if ( inFileName[i] == ' ' ) {
1882  saveFileName += '_';
1883  } else {
1884  saveFileName += inFileName[i];
1885  }
1886  }
1887 }
1888 
1889 /*
1890 ===============
1891 idSessionLocal::SaveGame
1892 ===============
1893 */
1894 bool idSessionLocal::SaveGame( const char *saveName, bool autosave ) {
1895 #ifdef ID_DEDICATED
1896  common->Printf( "Dedicated servers cannot save games.\n" );
1897  return false;
1898 #else
1899  int i;
1900  idStr gameFile, previewFile, descriptionFile, mapName;
1901 
1902  if ( !mapSpawned ) {
1903  common->Printf( "Not playing a game.\n" );
1904  return false;
1905  }
1906 
1907  if ( IsMultiplayer() ) {
1908  common->Printf( "Can't save during net play.\n" );
1909  return false;
1910  }
1911 
1912  if ( game->GetPersistentPlayerInfo( 0 ).GetInt( "health" ) <= 0 ) {
1913  MessageBox( MSG_OK, common->GetLanguageDict()->GetString ( "#str_04311" ), common->GetLanguageDict()->GetString ( "#str_04312" ), true );
1914  common->Printf( "You must be alive to save the game\n" );
1915  return false;
1916  }
1917 
1918  if ( Sys_GetDriveFreeSpace( cvarSystem->GetCVarString( "fs_savepath" ) ) < 25 ) {
1919  MessageBox( MSG_OK, common->GetLanguageDict()->GetString ( "#str_04313" ), common->GetLanguageDict()->GetString ( "#str_04314" ), true );
1920  common->Printf( "Not enough drive space to save the game\n" );
1921  return false;
1922  }
1923 
1925  if ( pauseWorld ) {
1926  pauseWorld->Pause();
1928  }
1929 
1930  // setup up filenames and paths
1931  gameFile = saveName;
1932  ScrubSaveGameFileName( gameFile );
1933 
1934  gameFile = "savegames/" + gameFile;
1935  gameFile.SetFileExtension( ".save" );
1936 
1937  previewFile = gameFile;
1938  previewFile.SetFileExtension( ".tga" );
1939 
1940  descriptionFile = gameFile;
1941  descriptionFile.SetFileExtension( ".txt" );
1942 
1943  // Open savegame file
1944  idFile *fileOut = fileSystem->OpenFileWrite( gameFile );
1945  if ( fileOut == NULL ) {
1946  common->Warning( "Failed to open save file '%s'\n", gameFile.c_str() );
1947  if ( pauseWorld ) {
1948  soundSystem->SetPlayingSoundWorld( pauseWorld );
1949  pauseWorld->UnPause();
1950  }
1951  return false;
1952  }
1953 
1954  // Write SaveGame Header:
1955  // Game Name / Version / Map Name / Persistant Player Info
1956 
1957  // game
1958  const char *gamename = GAME_NAME;
1959  fileOut->WriteString( gamename );
1960 
1961  // version
1962  fileOut->WriteInt( SAVEGAME_VERSION );
1963 
1964  // map
1965  mapName = mapSpawnData.serverInfo.GetString( "si_map" );
1966  fileOut->WriteString( mapName );
1967 
1968  // persistent player info
1969  for ( i = 0; i < MAX_ASYNC_CLIENTS; i++ ) {
1972  }
1973 
1974  // let the game save its state
1975  game->SaveGame( fileOut );
1976 
1977  // close the sava game file
1978  fileSystem->CloseFile( fileOut );
1979 
1980  // Write screenshot
1981  if ( !autosave ) {
1982  renderSystem->CropRenderSize( 320, 240, false );
1983  game->Draw( 0 );
1984  renderSystem->CaptureRenderToFile( previewFile, true );
1985  renderSystem->UnCrop();
1986  }
1987 
1988  // Write description, which is just a text file with
1989  // the unclean save name on line 1, map name on line 2, screenshot on line 3
1990  idFile *fileDesc = fileSystem->OpenFileWrite( descriptionFile );
1991  if ( fileDesc == NULL ) {
1992  common->Warning( "Failed to open description file '%s'\n", descriptionFile.c_str() );
1993  if ( pauseWorld ) {
1994  soundSystem->SetPlayingSoundWorld( pauseWorld );
1995  pauseWorld->UnPause();
1996  }
1997  return false;
1998  }
1999 
2000  idStr description = saveName;
2001  description.Replace( "\\", "\\\\" );
2002  description.Replace( "\"", "\\\"" );
2003 
2004  const idDeclEntityDef *mapDef = static_cast<const idDeclEntityDef *>(declManager->FindType( DECL_MAPDEF, mapName, false ));
2005  if ( mapDef ) {
2006  mapName = common->GetLanguageDict()->GetString( mapDef->dict.GetString( "name", mapName ) );
2007  }
2008 
2009  fileDesc->Printf( "\"%s\"\n", description.c_str() );
2010  fileDesc->Printf( "\"%s\"\n", mapName.c_str());
2011 
2012  if ( autosave ) {
2013  idStr sshot = mapSpawnData.serverInfo.GetString( "si_map" );
2014  sshot.StripPath();
2015  sshot.StripFileExtension();
2016  fileDesc->Printf( "\"guis/assets/autosave/%s\"\n", sshot.c_str() );
2017  } else {
2018  fileDesc->Printf( "\"\"\n" );
2019  }
2020 
2021  fileSystem->CloseFile( fileDesc );
2022 
2023  if ( pauseWorld ) {
2024  soundSystem->SetPlayingSoundWorld( pauseWorld );
2025  pauseWorld->UnPause();
2026  }
2027 
2028  syncNextGameFrame = true;
2029 
2030 
2031  return true;
2032 #endif
2033 }
2034 
2035 /*
2036 ===============
2037 idSessionLocal::LoadGame
2038 ===============
2039 */
2040 bool idSessionLocal::LoadGame( const char *saveName ) {
2041 #ifdef ID_DEDICATED
2042  common->Printf( "Dedicated servers cannot load games.\n" );
2043  return false;
2044 #else
2045  int i;
2046  idStr in, loadFile, saveMap, gamename;
2047 
2048  if ( IsMultiplayer() ) {
2049  common->Printf( "Can't load during net play.\n" );
2050  return false;
2051  }
2052 
2053  //Hide the dialog box if it is up.
2054  StopBox();
2055 
2056  loadFile = saveName;
2057  ScrubSaveGameFileName( loadFile );
2058  loadFile.SetFileExtension( ".save" );
2059 
2060  in = "savegames/";
2061  in += loadFile;
2062 
2063  // Open savegame file
2064  // only allow loads from the game directory because we don't want a base game to load
2065  idStr game = cvarSystem->GetCVarString( "fs_game" );
2066  savegameFile = fileSystem->OpenFileRead( in, true, game.Length() ? game : NULL );
2067 
2068  if ( savegameFile == NULL ) {
2069  common->Warning( "Couldn't open savegame file %s", in.c_str() );
2070  return false;
2071  }
2072 
2073  loadingSaveGame = true;
2074 
2075  // Read in save game header
2076  // Game Name / Version / Map Name / Persistant Player Info
2077 
2078  // game
2079  savegameFile->ReadString( gamename );
2080 
2081  // if this isn't a savegame for the correct game, abort loadgame
2082  if ( gamename != GAME_NAME ) {
2083  common->Warning( "Attempted to load an invalid savegame: %s", in.c_str() );
2084 
2085  loadingSaveGame = false;
2087  savegameFile = NULL;
2088  return false;
2089  }
2090 
2091  // version
2093 
2094  // map
2095  savegameFile->ReadString( saveMap );
2096 
2097  // persistent player info
2098  for ( i = 0; i < MAX_ASYNC_CLIENTS; i++ ) {
2100  }
2101 
2102  // check the version, if it doesn't match, cancel the loadgame,
2103  // but still load the map with the persistant playerInfo from the header
2104  // so that the player doesn't lose too much progress.
2106  !( savegameVersion == 16 && SAVEGAME_VERSION == 17 ) ) { // handle savegame v16 in v17
2107  common->Warning( "Savegame Version mismatch: aborting loadgame and starting level with persistent data" );
2108  loadingSaveGame = false;
2110  savegameFile = NULL;
2111  }
2112 
2113  common->DPrintf( "loading a v%d savegame\n", savegameVersion );
2114 
2115  if ( saveMap.Length() > 0 ) {
2116 
2117  // Start loading map
2119 
2121  mapSpawnData.serverInfo.Set( "si_gameType", "singleplayer" );
2122 
2123  mapSpawnData.serverInfo.Set( "si_map", saveMap );
2124 
2127 
2129  // make sure no buttons are pressed
2131 
2132  ExecuteMapChange();
2133 
2134  SetGUI( NULL, NULL );
2135  }
2136 
2137  if ( loadingSaveGame ) {
2139  loadingSaveGame = false;
2140  savegameFile = NULL;
2141  }
2142 
2143  return true;
2144 #endif
2145 }
2146 
2147 /*
2148 ===============
2149 idSessionLocal::ProcessEvent
2150 ===============
2151 */
2153  // hitting escape anywhere brings up the menu
2154  if ( !guiActive && event->evType == SE_KEY && event->evValue2 == 1 && event->evValue == K_ESCAPE ) {
2155  console->Close();
2156  if ( game ) {
2157  idUserInterface *gui = NULL;
2158  escReply_t op;
2159  op = game->HandleESC( &gui );
2160  if ( op == ESC_IGNORE ) {
2161  return true;
2162  } else if ( op == ESC_GUI ) {
2163  SetGUI( gui, NULL );
2164  return true;
2165  }
2166  }
2167  StartMenu();
2168  return true;
2169  }
2170 
2171  // let the pull-down console take it if desired
2172  if ( console->ProcessEvent( event, false ) ) {
2173  return true;
2174  }
2175 
2176  // if we are testing a GUI, send all events to it
2177  if ( guiTest ) {
2178  // hitting escape exits the testgui
2179  if ( event->evType == SE_KEY && event->evValue2 == 1 && event->evValue == K_ESCAPE ) {
2180  guiTest = NULL;
2181  return true;
2182  }
2183 
2184  static const char *cmd;
2185  cmd = guiTest->HandleEvent( event, com_frameTime );
2186  if ( cmd && cmd[0] ) {
2187  common->Printf( "testGui event returned: '%s'\n", cmd );
2188  }
2189  return true;
2190  }
2191 
2192  // menus / etc
2193  if ( guiActive ) {
2194  MenuEvent( event );
2195  return true;
2196  }
2197 
2198  // if we aren't in a game, force the console to take it
2199  if ( !mapSpawned ) {
2200  console->ProcessEvent( event, true );
2201  return true;
2202  }
2203 
2204  // in game, exec bindings for all key downs
2205  if ( event->evType == SE_KEY && event->evValue2 == 1 ) {
2207  return true;
2208  }
2209 
2210  return false;
2211 }
2212 
2213 /*
2214 ===============
2215 idSessionLocal::DrawWipeModel
2216 
2217 Draw the fade material over everything that has been drawn
2218 ===============
2219 */
2221  int latchedTic = com_ticNumber;
2222 
2223  if ( wipeStartTic >= wipeStopTic ) {
2224  return;
2225  }
2226 
2227  if ( !wipeHold && latchedTic >= wipeStopTic ) {
2228  return;
2229  }
2230 
2231  float fade = ( float )( latchedTic - wipeStartTic ) / ( wipeStopTic - wipeStartTic );
2232  renderSystem->SetColor4( 1, 1, 1, fade );
2233  renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, wipeMaterial );
2234 }
2235 
2236 /*
2237 ===============
2238 idSessionLocal::AdvanceRenderDemo
2239 ===============
2240 */
2241 void idSessionLocal::AdvanceRenderDemo( bool singleFrameOnly ) {
2242  if ( lastDemoTic == -1 ) {
2244  }
2245 
2246  int skipFrames = 0;
2247 
2248  if ( !aviCaptureMode && !timeDemo && !singleFrameOnly ) {
2249  skipFrames = ( (latchedTicNumber - lastDemoTic) / USERCMD_PER_DEMO_FRAME ) - 1;
2250  // never skip too many frames, just let it go into slightly slow motion
2251  if ( skipFrames > 4 ) {
2252  skipFrames = 4;
2253  }
2255  } else {
2256  // always advance a single frame with avidemo and timedemo
2258  }
2259 
2260  while( skipFrames > -1 ) {
2261  int ds = DS_FINISHED;
2262 
2263  readDemo->ReadInt( ds );
2264  if ( ds == DS_FINISHED ) {
2265  if ( numDemoFrames != 1 ) {
2266  // if the demo has a single frame (a demoShot), continuously replay
2267  // the renderView that has already been read
2268  Stop();
2269  StartMenu();
2270  }
2271  break;
2272  }
2273  if ( ds == DS_RENDER ) {
2275  // a view is ready to render
2276  skipFrames--;
2277  numDemoFrames++;
2278  }
2279  continue;
2280  }
2281  if ( ds == DS_SOUND ) {
2283  continue;
2284  }
2285  // appears in v1.2, with savegame format 17
2286  if ( ds == DS_VERSION ) {
2288  common->Printf( "reading a v%d render demo\n", renderdemoVersion );
2289  // set the savegameVersion to current for render demo paths that share the savegame paths
2291  continue;
2292  }
2293  common->Error( "Bad render demo token" );
2294  }
2295 
2296  if ( com_showDemo.GetBool() ) {
2297  common->Printf( "frame:%i DemoTic:%i latched:%i skip:%i\n", numDemoFrames, lastDemoTic, latchedTicNumber, skipFrames );
2298  }
2299 
2300 }
2301 
2302 /*
2303 ===============
2304 idSessionLocal::DrawCmdGraph
2305 
2306 Graphs yaw angle for testing smoothness
2307 ===============
2308 */
2309 static const int ANGLE_GRAPH_HEIGHT = 128;
2310 static const int ANGLE_GRAPH_STRETCH = 3;
2312  if ( !com_showAngles.GetBool() ) {
2313  return;
2314  }
2315  renderSystem->SetColor4( 0.1f, 0.1f, 0.1f, 1.0f );
2316  renderSystem->DrawStretchPic( 0, 480-ANGLE_GRAPH_HEIGHT, MAX_BUFFERED_USERCMD*ANGLE_GRAPH_STRETCH, ANGLE_GRAPH_HEIGHT, 0, 0, 1, 1, whiteMaterial );
2317  renderSystem->SetColor4( 0.9f, 0.9f, 0.9f, 1.0f );
2318  for ( int i = 0 ; i < MAX_BUFFERED_USERCMD-4 ; i++ ) {
2319  usercmd_t cmd = usercmdGen->TicCmd( latchedTicNumber - (MAX_BUFFERED_USERCMD-4) + i );
2320  int h = cmd.angles[1];
2321  h >>= 8;
2322  h &= (ANGLE_GRAPH_HEIGHT-1);
2323  renderSystem->DrawStretchPic( i* ANGLE_GRAPH_STRETCH, 480-h, 1, h, 0, 0, 1, 1, whiteMaterial );
2324  }
2325 }
2326 
2327 /*
2328 ===============
2329 idSessionLocal::PacifierUpdate
2330 ===============
2331 */
2333  if ( !insideExecuteMapChange ) {
2334  return;
2335  }
2336 
2337  // never do pacifier screen updates while inside the
2338  // drawing code, or we can have various recursive problems
2339  if ( insideUpdateScreen ) {
2340  return;
2341  }
2342 
2343  int time = eventLoop->Milliseconds();
2344 
2345  if ( time - lastPacifierTime < 100 ) {
2346  return;
2347  }
2348  lastPacifierTime = time;
2349 
2350  if ( guiLoading && bytesNeededForMapLoad ) {
2351  float n = fileSystem->GetReadCount();
2352  float pct = ( n / bytesNeededForMapLoad );
2353  // pct = idMath::ClampFloat( 0.0f, 100.0f, pct );
2354  guiLoading->SetStateFloat( "map_loading", pct );
2356  }
2357 
2359 
2360  UpdateScreen();
2361 
2364 }
2365 
2366 /*
2367 ===============
2368 idSessionLocal::Draw
2369 ===============
2370 */
2372  bool fullConsole = false;
2373 
2374  if ( insideExecuteMapChange ) {
2375  if ( guiLoading ) {
2377  }
2378  if ( guiActive == guiMsg ) {
2380  }
2381  } else if ( guiTest ) {
2382  // if testing a gui, clear the screen and draw it
2383  // clear the background, in case the tested gui is transparent
2384  // NOTE that you can't use this for aviGame recording, it will tick at real com_frameTime between screenshots..
2386  renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, declManager->FindMaterial( "_white" ) );
2388  } else if ( guiActive && !guiActive->State().GetBool( "gameDraw" ) ) {
2389 
2390  // draw the frozen gui in the background
2391  if ( guiActive == guiMsg && guiMsgRestore ) {
2393  }
2394 
2395  // draw the menus full screen
2397  game->Draw( GetLocalClientNum() );
2398  }
2399 
2401  } else if ( readDemo ) {
2404  } else if ( mapSpawned ) {
2405  bool gameDraw = false;
2406  // normal drawing for both single and multi player
2407  if ( !com_skipGameDraw.GetBool() && GetLocalClientNum() >= 0 ) {
2408  // draw the game view
2409  int start = Sys_Milliseconds();
2410  gameDraw = game->Draw( GetLocalClientNum() );
2411  int end = Sys_Milliseconds();
2412  time_gameDraw += ( end - start ); // note time used for com_speeds
2413  }
2414  if ( !gameDraw ) {
2416  renderSystem->DrawStretchPic( 0, 0, 640, 480, 0, 0, 1, 1, declManager->FindMaterial( "_white" ) );
2417  }
2418 
2419  // save off the 2D drawing from the game
2420  if ( writeDemo ) {
2422  }
2423  } else {
2424 #if ID_CONSOLE_LOCK
2425  if ( com_allowConsole.GetBool() ) {
2426  console->Draw( true );
2427  } else {
2428  emptyDrawCount++;
2429  if ( emptyDrawCount > 5 ) {
2430  // it's best if you can avoid triggering the watchgod by doing the right thing somewhere else
2431  assert( false );
2432  common->Warning( "idSession: triggering mainmenu watchdog" );
2433  emptyDrawCount = 0;
2434  StartMenu();
2435  }
2436  renderSystem->SetColor4( 0, 0, 0, 1 );
2437  renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, 1, 1, declManager->FindMaterial( "_white" ) );
2438  }
2439 #else
2440  // draw the console full screen - this should only ever happen in developer builds
2441  console->Draw( true );
2442 #endif
2443  fullConsole = true;
2444  }
2445 
2446 #if ID_CONSOLE_LOCK
2447  if ( !fullConsole && emptyDrawCount ) {
2448  common->DPrintf( "idSession: %d empty frame draws\n", emptyDrawCount );
2449  emptyDrawCount = 0;
2450  }
2451  fullConsole = false;
2452 #endif
2453 
2454  // draw the wipe material on top of this if it hasn't completed yet
2455  DrawWipeModel();
2456 
2457  // draw debug graphs
2458  DrawCmdGraph();
2459 
2460  // draw the half console / notify console on top of everything
2461  if ( !fullConsole ) {
2462  console->Draw( false );
2463  }
2464 }
2465 
2466 /*
2467 ===============
2468 idSessionLocal::UpdateScreen
2469 ===============
2470 */
2471 void idSessionLocal::UpdateScreen( bool outOfSequence ) {
2472 
2473 #ifdef _WIN32
2474 
2475  if ( com_editors ) {
2476  if ( !Sys_IsWindowVisible() ) {
2477  return;
2478  }
2479  }
2480 #endif
2481 
2482  if ( insideUpdateScreen ) {
2483  return;
2484 // common->FatalError( "idSessionLocal::UpdateScreen: recursively called" );
2485  }
2486 
2487  insideUpdateScreen = true;
2488 
2489  // if this is a long-operation update and we are in windowed mode,
2490  // release the mouse capture back to the desktop
2491  if ( outOfSequence ) {
2492  Sys_GrabMouseCursor( false );
2493  }
2494 
2496 
2497  // draw everything
2498  Draw();
2499 
2500  if ( com_speeds.GetBool() ) {
2502  } else {
2503  renderSystem->EndFrame( NULL, NULL );
2504  }
2505 
2506  insideUpdateScreen = false;
2507 }
2508 
2509 /*
2510 ===============
2511 idSessionLocal::Frame
2512 ===============
2513 */
2515 
2516  if ( com_asyncSound.GetInteger() == 0 ) {
2518  }
2519 
2520  // Editors that completely take over the game
2521  if ( com_editorActive && ( com_editors & ( EDITOR_RADIANT | EDITOR_GUI ) ) ) {
2522  return;
2523  }
2524 
2525  // if the console is down, we don't need to hold
2526  // the mouse cursor
2527  if ( console->Active() || com_editorActive ) {
2528  Sys_GrabMouseCursor( false );
2529  } else {
2530  Sys_GrabMouseCursor( true );
2531  }
2532 
2533  // save the screenshot and audio from the last draw if needed
2534  if ( aviCaptureMode ) {
2535  idStr name;
2536 
2537  name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), aviTicStart );
2538 
2539  float ratio = 30.0f / ( 1000.0f / USERCMD_MSEC / com_aviDemoTics.GetInteger() );
2540  aviDemoFrameCount += ratio;
2541  if ( aviTicStart + 1 != ( int )aviDemoFrameCount ) {
2542  // skipped frames so write them out
2544  while ( c-- ) {
2546  name = va("demos/%s/%s_%05i.tga", aviDemoShortName.c_str(), aviDemoShortName.c_str(), ++aviTicStart );
2547  }
2548  }
2550 
2551  // remove any printed lines at the top before taking the screenshot
2553 
2554  // this will call Draw, possibly multiple times if com_aviDemoSamples is > 1
2556  }
2557 
2558  // at startup, we may be backwards
2559  if ( latchedTicNumber > com_ticNumber ) {
2561  }
2562 
2563  // se how many tics we should have before continuing
2564  int minTic = latchedTicNumber + 1;
2565  if ( com_minTics.GetInteger() > 1 ) {
2566  minTic = lastGameTic + com_minTics.GetInteger();
2567  }
2568 
2569  if ( readDemo ) {
2570  if ( !timeDemo && numDemoFrames != 1 ) {
2572  } else {
2573  // timedemos and demoshots will run as fast as they can, other demos
2574  // will not run more than 30 hz
2575  minTic = latchedTicNumber;
2576  }
2577  } else if ( writeDemo ) {
2578  minTic = lastGameTic + USERCMD_PER_DEMO_FRAME; // demos are recorded at 30 hz
2579  }
2580 
2581  // fixedTic lets us run a forced number of usercmd each frame without timing
2582  if ( com_fixedTic.GetInteger() ) {
2583  minTic = latchedTicNumber;
2584  }
2585 
2586  // FIXME: deserves a cleanup and abstraction
2587 #if defined( _WIN32 )
2588  // Spin in place if needed. The game should yield the cpu if
2589  // it is running over 60 hz, because there is fundamentally
2590  // nothing useful for it to do.
2591  while( 1 ) {
2593  if ( latchedTicNumber >= minTic ) {
2594  break;
2595  }
2596  Sys_Sleep( 1 );
2597  }
2598 #else
2599  while( 1 ) {
2601  if ( latchedTicNumber >= minTic ) {
2602  break;
2603  }
2605  }
2606 #endif
2607 
2608  if ( authEmitTimeout ) {
2609  // waiting for a game auth
2610  if ( Sys_Milliseconds() > authEmitTimeout ) {
2611  // expired with no reply
2612  // means that if a firewall is blocking the master, we will let through
2613  common->DPrintf( "no reply from auth\n" );
2614  if ( authWaitBox ) {
2615  // close the wait box
2616  StopBox();
2617  authWaitBox = false;
2618  }
2619  if ( cdkey_state == CDKEY_CHECKING ) {
2621  }
2622  if ( xpkey_state == CDKEY_CHECKING ) {
2624  }
2625  // maintain this empty as it's set by auth denials
2626  authMsg.Empty();
2627  authEmitTimeout = 0;
2628  SetCDKeyGuiVars();
2629  }
2630  }
2631 
2632  // send frame and mouse events to active guis
2633  GuiFrameEvents();
2634 
2635  // advance demos
2636  if ( readDemo ) {
2637  AdvanceRenderDemo( false );
2638  return;
2639  }
2640 
2641  //------------ single player game tics --------------
2642 
2643  if ( !mapSpawned || guiActive ) {
2644  if ( !com_asyncInput.GetBool() ) {
2645  // early exit, won't do RunGameTic .. but still need to update mouse position for GUIs
2647  }
2648  }
2649 
2650  if ( !mapSpawned ) {
2651  return;
2652  }
2653 
2654  if ( guiActive ) {
2656  return;
2657  }
2658 
2659  // in message box / GUIFrame, idSessionLocal::Frame is used for GUI interactivity
2660  // but we early exit to avoid running game frames
2661  if ( idAsyncNetwork::IsActive() ) {
2662  return;
2663  }
2664 
2665  // check for user info changes
2668  game->SetUserInfo( 0, mapSpawnData.userInfo[0], false, false );
2670  }
2671 
2672  // see how many usercmds we are going to run
2673  int numCmdsToRun = latchedTicNumber - lastGameTic;
2674 
2675  // don't let a long onDemand sound load unsync everything
2676  if ( timeHitch ) {
2677  int skip = timeHitch / USERCMD_MSEC;
2678  lastGameTic += skip;
2679  numCmdsToRun -= skip;
2680  timeHitch = 0;
2681  }
2682 
2683  // don't get too far behind after a hitch
2684  if ( numCmdsToRun > 10 ) {
2685  lastGameTic = latchedTicNumber - 10;
2686  }
2687 
2688  // never use more than USERCMD_PER_DEMO_FRAME,
2689  // which makes it go into slow motion when recording
2690  if ( writeDemo ) {
2691  int fixedTic = USERCMD_PER_DEMO_FRAME;
2692  // we should have waited long enough
2693  if ( numCmdsToRun < fixedTic ) {
2694  common->Error( "idSessionLocal::Frame: numCmdsToRun < fixedTic" );
2695  }
2696  // we may need to dump older commands
2697  lastGameTic = latchedTicNumber - fixedTic;
2698  } else if ( com_fixedTic.GetInteger() > 0 ) {
2699  // this may cause commands run in a previous frame to
2700  // be run again if we are going at above the real time rate
2701  lastGameTic = latchedTicNumber - com_fixedTic.GetInteger();
2702  } else if ( aviCaptureMode ) {
2703  lastGameTic = latchedTicNumber - com_aviDemoTics.GetInteger();
2704  }
2705 
2706  // force only one game frame update this frame. the game code requests this after skipping cinematics
2707  // so we come back immediately after the cinematic is done instead of a few frames later which can
2708  // cause sounds played right after the cinematic to not play.
2709  if ( syncNextGameFrame ) {
2710  lastGameTic = latchedTicNumber - 1;
2711  syncNextGameFrame = false;
2712  }
2713 
2714  // create client commands, which will be sent directly
2715  // to the game
2716  if ( com_showTics.GetBool() ) {
2717  common->Printf( "%i ", latchedTicNumber - lastGameTic );
2718  }
2719 
2720  int gameTicsToRun = latchedTicNumber - lastGameTic;
2721  int i;
2722  for ( i = 0 ; i < gameTicsToRun ; i++ ) {
2723  RunGameTic();
2724  if ( !mapSpawned ) {
2725  // exited game play
2726  break;
2727  }
2728  if ( syncNextGameFrame ) {
2729  // long game frame, so break out and continue executing as if there was no hitch
2730  break;
2731  }
2732  }
2733 }
2734 
2735 /*
2736 ================
2737 idSessionLocal::RunGameTic
2738 ================
2739 */
2741  logCmd_t logCmd;
2742  usercmd_t cmd;
2743 
2744  // if we are doing a command demo, read or write from the file
2745  if ( cmdDemoFile ) {
2746  if ( !cmdDemoFile->Read( &logCmd, sizeof( logCmd ) ) ) {
2747  common->Printf( "Command demo completed at logIndex %i\n", logIndex );
2749  cmdDemoFile = NULL;
2750  if ( aviCaptureMode ) {
2751  EndAVICapture();
2752  Shutdown();
2753  }
2754  // we fall out of the demo to normal commands
2755  // the impulse and chat character toggles may not be correct, and the view
2756  // angle will definitely be wrong
2757  } else {
2758  cmd = logCmd.cmd;
2759  cmd.ByteSwap();
2760  logCmd.consistencyHash = LittleLong( logCmd.consistencyHash );
2761  }
2762  }
2763 
2764  // if we didn't get one from the file, get it locally
2765  if ( !cmdDemoFile ) {
2766  // get a locally created command
2767  if ( com_asyncInput.GetBool() ) {
2768  cmd = usercmdGen->TicCmd( lastGameTic );
2769  } else {
2770  cmd = usercmdGen->GetDirectUsercmd();
2771  }
2772  lastGameTic++;
2773  }
2774 
2775  // run the game logic every player move
2776  int start = Sys_Milliseconds();
2777  gameReturn_t ret = game->RunFrame( &cmd );
2778 
2779  int end = Sys_Milliseconds();
2780  time_gameFrame += end - start; // note time used for com_speeds
2781 
2782  // check for constency failure from a recorded command
2783  if ( cmdDemoFile ) {
2784  if ( ret.consistencyHash != logCmd.consistencyHash ) {
2785  common->Printf( "Consistency failure on logIndex %i\n", logIndex );
2786  Stop();
2787  return;
2788  }
2789  }
2790 
2791  // save the cmd for cmdDemo archiving
2792  if ( logIndex < MAX_LOGGED_USERCMDS ) {
2793  loggedUsercmds[logIndex].cmd = cmd;
2794  // save the consistencyHash for demo playback verification
2796  if (logIndex % 30 == 0 && statIndex < MAX_LOGGED_STATS) {
2801  statIndex++;
2802  }
2803  logIndex++;
2804  }
2805 
2807 
2808  if ( ret.sessionCommand[0] ) {
2809  idCmdArgs args;
2810 
2811  args.TokenizeString( ret.sessionCommand, false );
2812 
2813  if ( !idStr::Icmp( args.Argv(0), "map" ) ) {
2814  // get current player states
2815  for ( int i = 0 ; i < numClients ; i++ ) {
2817  }
2818  // clear the devmap key on serverinfo, so player spawns
2819  // won't get the map testing items
2820  mapSpawnData.serverInfo.Delete( "devmap" );
2821 
2822  // go to the next map
2823  MoveToNewMap( args.Argv(1) );
2824  } else if ( !idStr::Icmp( args.Argv(0), "devmap" ) ) {
2825  mapSpawnData.serverInfo.Set( "devmap", "1" );
2826  MoveToNewMap( args.Argv(1) );
2827  } else if ( !idStr::Icmp( args.Argv(0), "died" ) ) {
2828  // restart on the same map
2829  UnloadMap();
2830  SetGUI(guiRestartMenu, NULL);
2831  } else if ( !idStr::Icmp( args.Argv(0), "disconnect" ) ) {
2832  cmdSystem->BufferCommandText( CMD_EXEC_INSERT, "stoprecording ; disconnect" );
2833  } else if ( !idStr::Icmp( args.Argv(0), "endOfDemo" ) ) {
2834  cmdSystem->BufferCommandText( CMD_EXEC_NOW, "endOfDemo" );
2835  }
2836  }
2837 }
2838 
2839 /*
2840 ===============
2841 idSessionLocal::Init
2842 
2843 Called in an orderly fashion at system startup,
2844 so commands, cvars, files, etc are all available
2845 ===============
2846 */
2848 
2849  common->Printf( "-------- Initializing Session --------\n" );
2850 
2851  cmdSystem->AddCommand( "writePrecache", Sess_WritePrecache_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "writes precache commands" );
2852 
2853 #ifndef ID_DEDICATED
2854  cmdSystem->AddCommand( "map", Session_Map_f, CMD_FL_SYSTEM, "loads a map", idCmdSystem::ArgCompletion_MapName );
2855  cmdSystem->AddCommand( "devmap", Session_DevMap_f, CMD_FL_SYSTEM, "loads a map in developer mode", idCmdSystem::ArgCompletion_MapName );
2856  cmdSystem->AddCommand( "testmap", Session_TestMap_f, CMD_FL_SYSTEM, "tests a map", idCmdSystem::ArgCompletion_MapName );
2857 
2858  cmdSystem->AddCommand( "writeCmdDemo", Session_WriteCmdDemo_f, CMD_FL_SYSTEM, "writes a command demo" );
2859  cmdSystem->AddCommand( "playCmdDemo", Session_PlayCmdDemo_f, CMD_FL_SYSTEM, "plays back a command demo" );
2860  cmdSystem->AddCommand( "timeCmdDemo", Session_TimeCmdDemo_f, CMD_FL_SYSTEM, "times a command demo" );
2861  cmdSystem->AddCommand( "exitCmdDemo", Session_ExitCmdDemo_f, CMD_FL_SYSTEM, "exits a command demo" );
2862  cmdSystem->AddCommand( "aviCmdDemo", Session_AVICmdDemo_f, CMD_FL_SYSTEM, "writes AVIs for a command demo" );
2863  cmdSystem->AddCommand( "aviGame", Session_AVIGame_f, CMD_FL_SYSTEM, "writes AVIs for the current game" );
2864 
2865  cmdSystem->AddCommand( "recordDemo", Session_RecordDemo_f, CMD_FL_SYSTEM, "records a demo" );
2866  cmdSystem->AddCommand( "stopRecording", Session_StopRecordingDemo_f, CMD_FL_SYSTEM, "stops demo recording" );
2867  cmdSystem->AddCommand( "playDemo", Session_PlayDemo_f, CMD_FL_SYSTEM, "plays back a demo", idCmdSystem::ArgCompletion_DemoName );
2868  cmdSystem->AddCommand( "timeDemo", Session_TimeDemo_f, CMD_FL_SYSTEM, "times a demo", idCmdSystem::ArgCompletion_DemoName );
2869  cmdSystem->AddCommand( "timeDemoQuit", Session_TimeDemoQuit_f, CMD_FL_SYSTEM, "times a demo and quits", idCmdSystem::ArgCompletion_DemoName );
2870  cmdSystem->AddCommand( "aviDemo", Session_AVIDemo_f, CMD_FL_SYSTEM, "writes AVIs for a demo", idCmdSystem::ArgCompletion_DemoName );
2871  cmdSystem->AddCommand( "compressDemo", Session_CompressDemo_f, CMD_FL_SYSTEM, "compresses a demo file", idCmdSystem::ArgCompletion_DemoName );
2872 #endif
2873 
2874  cmdSystem->AddCommand( "disconnect", Session_Disconnect_f, CMD_FL_SYSTEM, "disconnects from a game" );
2875 
2876 #ifdef ID_DEMO_BUILD
2877  cmdSystem->AddCommand( "endOfDemo", Session_EndOfDemo_f, CMD_FL_SYSTEM, "ends the demo version of the game" );
2878 #endif
2879 
2880  cmdSystem->AddCommand( "demoShot", Session_DemoShot_f, CMD_FL_SYSTEM, "writes a screenshot for a demo" );
2881  cmdSystem->AddCommand( "testGUI", Session_TestGUI_f, CMD_FL_SYSTEM, "tests a gui" );
2882 
2883 #ifndef ID_DEDICATED
2884  cmdSystem->AddCommand( "saveGame", SaveGame_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "saves a game" );
2886 #endif
2887 
2888  cmdSystem->AddCommand( "takeViewNotes", TakeViewNotes_f, CMD_FL_SYSTEM, "take notes about the current map from the current view" );
2889  cmdSystem->AddCommand( "takeViewNotes2", TakeViewNotes2_f, CMD_FL_SYSTEM, "extended take view notes" );
2890 
2891  cmdSystem->AddCommand( "rescanSI", Session_RescanSI_f, CMD_FL_SYSTEM, "internal - rescan serverinfo cvars and tell game" );
2892 
2893  cmdSystem->AddCommand( "promptKey", Session_PromptKey_f, CMD_FL_SYSTEM, "prompt and sets the CD Key" );
2894 
2895  cmdSystem->AddCommand( "hitch", Session_Hitch_f, CMD_FL_SYSTEM|CMD_FL_CHEAT, "hitches the game" );
2896 
2897  // the same idRenderWorld will be used for all games
2898  // and demos, insuring that level specific models
2899  // will be freed
2902 
2904 
2905  // we have a single instance of the main menu
2906 #ifndef ID_DEMO_BUILD
2907  guiMainMenu = uiManager->FindGui( "guis/mainmenu.gui", true, false, true );
2908 #else
2909  guiMainMenu = uiManager->FindGui( "guis/demo_mainmenu.gui", true, false, true );
2910 #endif
2912  guiMainMenu_MapList->Config( guiMainMenu, "mapList" );
2914  guiRestartMenu = uiManager->FindGui( "guis/restart.gui", true, false, true );
2915  guiGameOver = uiManager->FindGui( "guis/gameover.gui", true, false, true );
2916  guiMsg = uiManager->FindGui( "guis/msg.gui", true, false, true );
2917  guiTakeNotes = uiManager->FindGui( "guis/takeNotes.gui", true, false, true );
2918  guiIntro = uiManager->FindGui( "guis/intro.gui", true, false, true );
2919 
2920  whiteMaterial = declManager->FindMaterial( "_white" );
2921 
2922  guiInGame = NULL;
2923  guiTest = NULL;
2924 
2925  guiActive = NULL;
2926  guiHandle = NULL;
2927 
2928  ReadCDKey();
2929 
2930  common->Printf( "session initialized\n" );
2931  common->Printf( "--------------------------------------\n" );
2932 }
2933 
2934 /*
2935 ===============
2936 idSessionLocal::GetLocalClientNum
2937 ===============
2938 */
2940  if ( idAsyncNetwork::client.IsActive() ) {
2942  } else if ( idAsyncNetwork::server.IsActive() ) {
2943  if ( idAsyncNetwork::serverDedicated.GetInteger() == 0 ) {
2944  return 0;
2945  } else if ( idAsyncNetwork::server.IsClientInGame( idAsyncNetwork::serverDrawClient.GetInteger() ) ) {
2947  } else {
2948  return -1;
2949  }
2950  } else {
2951  return 0;
2952  }
2953 }
2954 
2955 /*
2956 ===============
2957 idSessionLocal::SetPlayingSoundWorld
2958 ===============
2959 */
2961  if ( guiActive && ( guiActive == guiMainMenu || guiActive == guiIntro || guiActive == guiLoading || ( guiActive == guiMsg && !mapSpawned ) ) ) {
2963  } else {
2965  }
2966 }
2967 
2968 /*
2969 ===============
2970 idSessionLocal::TimeHitch
2971 
2972 this is used by the sound system when an OnDemand sound is loaded, so the game action
2973 doesn't advance and get things out of sync
2974 ===============
2975 */
2976 void idSessionLocal::TimeHitch( int msec ) {
2977  timeHitch += msec;
2978 }
2979 
2980 /*
2981 =================
2982 idSessionLocal::ReadCDKey
2983 =================
2984 */
2986  idStr filename;
2987  idFile *f;
2988  char buffer[32];
2989 
2991 
2992  filename = "../" BASE_GAMEDIR "/" CDKEY_FILE;
2993  f = fileSystem->OpenExplicitFileRead( fileSystem->RelativePathToOSPath( filename, "fs_savepath" ) );
2994  if ( !f ) {
2995  common->Printf( "Couldn't read %s.\n", filename.c_str() );
2996  cdkey[ 0 ] = '\0';
2997  } else {
2998  memset( buffer, 0, sizeof(buffer) );
2999  f->Read( buffer, CDKEY_BUF_LEN - 1 );
3000  fileSystem->CloseFile( f );
3001  idStr::Copynz( cdkey, buffer, CDKEY_BUF_LEN );
3002  }
3003 
3005 
3006  filename = "../" BASE_GAMEDIR "/" XPKEY_FILE;
3007  f = fileSystem->OpenExplicitFileRead( fileSystem->RelativePathToOSPath( filename, "fs_savepath" ) );
3008  if ( !f ) {
3009  common->Printf( "Couldn't read %s.\n", filename.c_str() );
3010  xpkey[ 0 ] = '\0';
3011  } else {
3012  memset( buffer, 0, sizeof(buffer) );
3013  f->Read( buffer, CDKEY_BUF_LEN - 1 );
3014  fileSystem->CloseFile( f );
3015  idStr::Copynz( xpkey, buffer, CDKEY_BUF_LEN );
3016  }
3017 }
3018 
3019 /*
3020 ================
3021 idSessionLocal::WriteCDKey
3022 ================
3023 */
3025  idStr filename;
3026  idFile *f;
3027  const char *OSPath;
3028 
3029  filename = "../" BASE_GAMEDIR "/" CDKEY_FILE;
3030  // OpenFileWrite advertises creating directories to the path if needed, but that won't work with a '..' in the path
3031  // occasionally on windows, but mostly on Linux and OSX, the fs_savepath/base may not exist in full
3032  OSPath = fileSystem->BuildOSPath( cvarSystem->GetCVarString( "fs_savepath" ), BASE_GAMEDIR, CDKEY_FILE );
3033  fileSystem->CreateOSPath( OSPath );
3034  f = fileSystem->OpenFileWrite( filename );
3035  if ( !f ) {
3036  common->Printf( "Couldn't write %s.\n", filename.c_str() );
3037  return;
3038  }
3039  f->Printf( "%s%s", cdkey, CDKEY_TEXT );
3040  fileSystem->CloseFile( f );
3041 
3042  filename = "../" BASE_GAMEDIR "/" XPKEY_FILE;
3043  f = fileSystem->OpenFileWrite( filename );
3044  if ( !f ) {
3045  common->Printf( "Couldn't write %s.\n", filename.c_str() );
3046  return;
3047  }
3048  f->Printf( "%s%s", xpkey, CDKEY_TEXT );
3049  fileSystem->CloseFile( f );
3050 }
3051 
3052 /*
3053 ===============
3054 idSessionLocal::ClearKey
3055 ===============
3056 */
3057 void idSessionLocal::ClearCDKey( bool valid[ 2 ] ) {
3058  if ( !valid[ 0 ] ) {
3059  memset( cdkey, 0, CDKEY_BUF_LEN );
3061  } else if ( cdkey_state == CDKEY_CHECKING ) {
3062  // if a key was in checking and not explicitely asked for clearing, put it back to ok
3064  }
3065  if ( !valid[ 1 ] ) {
3066  memset( xpkey, 0, CDKEY_BUF_LEN );
3068  } else if ( xpkey_state == CDKEY_CHECKING ) {
3070  }
3071  WriteCDKey( );
3072 }
3073 
3074 /*
3075 ================
3076 idSessionLocal::GetCDKey
3077 ================
3078 */
3079 const char *idSessionLocal::GetCDKey( bool xp ) {
3080  if ( !xp ) {
3081  return cdkey;
3082  }
3084  return xpkey;
3085  }
3086  return NULL;
3087 }
3088 
3089 // digits to letters table
3090 #define CDKEY_DIGITS "TWSBJCGD7PA23RLH"
3091 
3092 /*
3093 ===============
3094 idSessionLocal::EmitGameAuth
3095 we toggled some key state to CDKEY_CHECKING. send a standalone auth packet to validate
3096 ===============
3097 */
3099  // make sure the auth reply is empty, we use it to indicate an auth reply
3100  authMsg.Empty();
3101  if ( idAsyncNetwork::client.SendAuthCheck( cdkey_state == CDKEY_CHECKING ? cdkey : NULL, xpkey_state == CDKEY_CHECKING ? xpkey : NULL ) ) {
3103  common->DPrintf( "authing with the master..\n" );
3104  } else {
3105  // net is not available
3106  common->DPrintf( "sendAuthCheck failed\n" );
3107  if ( cdkey_state == CDKEY_CHECKING ) {
3109  }
3110  if ( xpkey_state == CDKEY_CHECKING ) {
3112  }
3113  }
3114 }
3115 
3116 /*
3117 ================
3118 idSessionLocal::CheckKey
3119 the function will only modify keys to _OK or _CHECKING if the offline checks are passed
3120 if the function returns false, the offline checks failed, and offline_valid holds which keys are bad
3121 ================
3122 */
3123 bool idSessionLocal::CheckKey( const char *key, bool netConnect, bool offline_valid[ 2 ] ) {
3124  char lkey[ 2 ][ CDKEY_BUF_LEN ];
3125  char l_chk[ 2 ][ 3 ];
3126  char s_chk[ 3 ];
3127  int imax,i_key;
3128  unsigned int checksum, chk8;
3129  bool edited_key[ 2 ];
3130 
3131  // make sure have a right input string
3132  assert( strlen( key ) == ( CDKEY_BUF_LEN - 1 ) * 2 + 4 + 3 + 4 );
3133 
3134  edited_key[ 0 ] = ( key[0] == '1' );
3135  idStr::Copynz( lkey[0], key + 2, CDKEY_BUF_LEN );
3136  idStr::ToUpper( lkey[0] );
3137  idStr::Copynz( l_chk[0], key + CDKEY_BUF_LEN + 2, 3 );
3138  idStr::ToUpper( l_chk[0] );
3139  edited_key[ 1 ] = ( key[ CDKEY_BUF_LEN + 2 + 3 ] == '1' );
3140  idStr::Copynz( lkey[1], key + CDKEY_BUF_LEN + 7, CDKEY_BUF_LEN );
3141  idStr::ToUpper( lkey[1] );
3142  idStr::Copynz( l_chk[1], key + CDKEY_BUF_LEN * 2 + 7, 3 );
3143  idStr::ToUpper( l_chk[1] );
3144 
3145  if ( fileSystem->HasD3XP() ) {
3146  imax = 2;
3147  } else {
3148  imax = 1;
3149  }
3150  offline_valid[ 0 ] = offline_valid[ 1 ] = true;
3151  for( i_key = 0; i_key < imax; i_key++ ) {
3152  // check that the characters are from the valid set
3153  int i;
3154  for ( i = 0; i < CDKEY_BUF_LEN - 1; i++ ) {
3155  if ( !strchr( CDKEY_DIGITS, lkey[i_key][i] ) ) {
3156  offline_valid[ i_key ] = false;
3157  continue;
3158  }
3159  }
3160 
3161  if ( edited_key[ i_key ] ) {
3162  // verify the checksum for edited keys only
3163  checksum = CRC32_BlockChecksum( lkey[i_key], CDKEY_BUF_LEN - 1 );
3164  chk8 = ( checksum & 0xff ) ^ ( ( ( checksum & 0xff00 ) >> 8 ) ^ ( ( ( checksum & 0xff0000 ) >> 16 ) ^ ( ( checksum & 0xff000000 ) >> 24 ) ) );
3165  idStr::snPrintf( s_chk, 3, "%02X", chk8 );
3166  if ( idStr::Icmp( l_chk[i_key], s_chk ) != 0 ) {
3167  offline_valid[ i_key ] = false;
3168  continue;
3169  }
3170  }
3171  }
3172 
3173  if ( !offline_valid[ 0 ] || !offline_valid[1] ) {
3174  return false;
3175  }
3176 
3177  // offline checks passed, we'll return true and optionally emit key check requests
3178  // the function should only modify the key states if the offline checks passed successfully
3179 
3180  // set the keys, don't send a game auth if we are net connecting
3181  idStr::Copynz( cdkey, lkey[0], CDKEY_BUF_LEN );
3182  netConnect ? cdkey_state = CDKEY_OK : cdkey_state = CDKEY_CHECKING;
3183  if ( fileSystem->HasD3XP() ) {
3184  idStr::Copynz( xpkey, lkey[1], CDKEY_BUF_LEN );
3185  netConnect ? xpkey_state = CDKEY_OK : xpkey_state = CDKEY_CHECKING;
3186  } else {
3188  }
3189  if ( !netConnect ) {
3190  EmitGameAuth();
3191  }
3192  SetCDKeyGuiVars();
3193 
3194  return true;
3195 }
3196 
3197 /*
3198 ===============
3199 idSessionLocal::CDKeysAreValid
3200 checking that the key is present and uses only valid characters
3201 if d3xp is installed, check for a valid xpkey as well
3202 emit an auth packet to the master if possible and needed
3203 ===============
3204 */
3205 bool idSessionLocal::CDKeysAreValid( bool strict ) {
3206  int i;
3207  bool emitAuth = false;
3208 
3209  if ( cdkey_state == CDKEY_UNKNOWN ) {
3210  if ( strlen( cdkey ) != CDKEY_BUF_LEN - 1 ) {
3212  } else {
3213  for ( i = 0; i < CDKEY_BUF_LEN-1; i++ ) {
3214  if ( !strchr( CDKEY_DIGITS, cdkey[i] ) ) {
3216  break;
3217  }
3218  }
3219  }
3220  if ( cdkey_state == CDKEY_UNKNOWN ) {
3222  emitAuth = true;
3223  }
3224  }
3225  if ( xpkey_state == CDKEY_UNKNOWN ) {
3226  if ( fileSystem->HasD3XP() ) {
3227  if ( strlen( xpkey ) != CDKEY_BUF_LEN -1 ) {
3229  } else {
3230  for ( i = 0; i < CDKEY_BUF_LEN-1; i++ ) {
3231  if ( !strchr( CDKEY_DIGITS, xpkey[i] ) ) {
3233  }
3234  }
3235  }
3236  if ( xpkey_state == CDKEY_UNKNOWN ) {
3238  emitAuth = true;
3239  }
3240  } else {
3242  }
3243  }
3244  if ( emitAuth ) {
3245  EmitGameAuth();
3246  }
3247  // make sure to keep the mainmenu gui up to date in case we made state changes
3248  SetCDKeyGuiVars();
3249  if ( strict ) {
3250  return cdkey_state == CDKEY_OK && ( xpkey_state == CDKEY_OK || xpkey_state == CDKEY_NA );
3251  } else {
3253  }
3254 }
3255 
3256 /*
3257 ===============
3258 idSessionLocal::WaitingForGameAuth
3259 ===============
3260 */
3262  return authEmitTimeout != 0;
3263 }
3264 
3265 /*
3266 ===============
3267 idSessionLocal::CDKeysAuthReply
3268 ===============
3269 */
3270 void idSessionLocal::CDKeysAuthReply( bool valid, const char *auth_msg ) {
3271  assert( authEmitTimeout > 0 );
3272  if ( authWaitBox ) {
3273  // close the wait box
3274  StopBox();
3275  authWaitBox = false;
3276  }
3277  if ( !valid ) {
3278  common->DPrintf( "auth key is invalid\n" );
3279  authMsg = auth_msg;
3280  if ( cdkey_state == CDKEY_CHECKING ) {
3282  }
3283  if ( xpkey_state == CDKEY_CHECKING ) {
3285  }
3286  } else {
3287  common->DPrintf( "client is authed in\n" );
3288  if ( cdkey_state == CDKEY_CHECKING ) {
3290  }
3291  if ( xpkey_state == CDKEY_CHECKING ) {
3293  }
3294  }
3295  authEmitTimeout = 0;
3296  SetCDKeyGuiVars();
3297 }
3298 
3299 /*
3300 ===============
3301 idSessionLocal::GetCurrentMapName
3302 ===============
3303 */
3305  return currentMapName.c_str();
3306 }
3307 
3308 /*
3309 ===============
3310 idSessionLocal::GetSaveGameVersion
3311 ===============
3312 */
3314  return savegameVersion;
3315 }
3316 
3317 /*
3318 ===============
3319 idSessionLocal::GetAuthMsg
3320 ===============
3321 */
3322 const char *idSessionLocal::GetAuthMsg( void ) {
3323  return authMsg.c_str();
3324 }
short heartRate
Definition: Session.h:43
void DrawCmdGraph()
Definition: Session.cpp:2311
float aviDemoFrameCount
void TakeViewNotes_f(const idCmdArgs &args)
Definition: Session.cpp:1770
void StartRecordingRenderDemo(const char *name)
Definition: Session.cpp:786
virtual void UnCrop()=0
virtual void SetupReloadEngine(const idCmdArgs &args)=0
virtual void SetCVarInteger(const char *name, const int value, int flags=0)=0
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
virtual const idDict * SetUserInfo(int clientNum, const idDict &userInfo, bool isClient, bool canModify)=0
#define SAVEGAME_VERSION
Definition: Licensee.h:84
const int MAX_ASYNC_CLIENTS
Definition: AsyncNetwork.h:44
char xpkey[CDKEY_BUF_LEN]
float GetFloat(const char *key, const char *defaultString="0") const
Definition: Dict.h:248
static int snPrintf(char *dest, int size, const char *fmt,...) id_attribute((format(printf
Definition: Str.cpp:1465
static void ArgCompletion_MapName(const idCmdArgs &args, void(*callback)(const char *s))
Definition: CmdSystem.h:156
void SetBytesNeededForMapLoad(const char *mapName, int bytesNeeded)
Definition: Session.cpp:1481
void StartPlayingRenderDemo(idStr name)
Definition: Session.cpp:903
virtual void EndFrame(int *frontEndMsec, int *backEndMsec)=0
idStr GetAutoSaveName(const char *mapName) const
Definition: Session.cpp:1208
int GetInt(const char *key, const char *defaultString="0") const
Definition: Dict.h:252
bool ReplaceSourceFileText(void)
Definition: DeclManager.h:184
idStr & SetFileExtension(const char *extension)
Definition: Str.cpp:743
virtual int virtual int ReadInt(int &value)
Definition: File.cpp:311
virtual void SetColor(const idVec4 &rgba)=0
idDemoFile * readDemo
Definition: Session.h:158
assert(prefInfo.fullscreenBtn)
void FinishCmdLoad()
Definition: Session.cpp:1329
void AdvanceRenderDemo(bool singleFrameOnly)
Definition: Session.cpp:2241
virtual void StateChanged(int time, bool redraw=false)=0
virtual void WritePrecacheCommands(idFile *f)=0
int Cmp(const char *text) const
Definition: Str.h:652
bool IsActive(void) const
Definition: AsyncClient.h:96
idCVarSystem * cvarSystem
Definition: CVarSystem.cpp:487
void Kill(void)
short stamina
Definition: Session.h:44
void Delete(const char *key)
Definition: Dict.cpp:496
renderView_t currentDemoRenderView
int renderdemoVersion
Definition: Session.h:160
static idCVar com_aviDemoTics
idSoundWorld * sw
Definition: Session.h:154
virtual void StopWritingDemo()=0
int stamina
Definition: Game.h:50
int health
Definition: Game.h:48
void RandomizeStack(void)
Definition: Session.cpp:56
void ToUpper(void)
Definition: Str.h:825
virtual void SetStateString(const char *varName, const char *value)=0
virtual idSoundWorld * AllocSoundWorld(idRenderWorld *rw)=0
idFile * cmdDemoFile
virtual void virtual void virtual const idLangDict * GetLanguageDict(void)=0
virtual bool CDKeysAreValid(bool strict)
Definition: Session.cpp:3205
unsigned long CRC32_BlockChecksum(const void *data, int length)
Definition: CRC32.cpp:160
GLenum GLsizei GLenum format
Definition: glext.h:2846
void AVICmdDemo(const char *name)
Definition: Session.cpp:1058
float GetFloat(void) const
Definition: CVarSystem.h:144
virtual const char * GetCurrentMapName()
Definition: Session.cpp:3304
const idStr & GetKey(void) const
Definition: Dict.h:52
const int USERCMD_PER_DEMO_FRAME
Definition: Session_local.h:79
void ScrubSaveGameFileName(idStr &saveFileName) const
Definition: Session.cpp:1863
void ShowLoadingGui()
Definition: Session.cpp:506
void DrawWipeModel()
Definition: Session.cpp:2220
#define GAME_NAME
Definition: Licensee.h:37
void TakeNotes(const char *p, bool extended=false)
Definition: Session.cpp:1790
void WriteCmdDemo(const char *name, bool save=false)
Definition: Session.cpp:1284
static idCVar com_showDemo
idUserInterface * guiMsg
ID_INLINE T Max(T x, T y)
Definition: Lib.h:158
virtual void DrawDemoPics()=0
virtual bool ProcessDemoCommand(idDemoFile *readDemo, renderView_t *demoRenderView, int *demoTimeOffset)=0
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
void TestGUI(const char *name)
Definition: Session.cpp:559
int Length(void) const
Definition: Str.h:702
virtual void ProcessDemoCommand(idDemoFile *demo)=0
virtual void Clear(void)=0
virtual const char * MessageBox(msgBoxType_t type, const char *message, const char *title=NULL, bool wait=false, const char *fire_yes=NULL, const char *fire_no=NULL, bool network=false)
int consistencyHash
Definition: Game.h:47
virtual void WriteCDKey(void)
Definition: Session.cpp:3024
void StartWipe(const char *materialName, bool hold=false)
Definition: Session.cpp:463
virtual void GetMapLoadingGUI(char gui[MAX_STRING_CHARS])=0
static const int CDKEY_AUTH_TIMEOUT
virtual void ResetReadCount(void)=0
virtual int GetCVarInteger(const char *name) const =0
virtual void PlayShaderDirectly(const char *name, int channel=-1)=0
static idAsyncClient client
Definition: AsyncNetwork.h:168
virtual int AsyncUpdate(int time)=0
virtual void SpawnPlayer(int clientNum)=0
const int SCREEN_HEIGHT
Definition: RenderSystem.h:154
GLenum GLsizei n
Definition: glext.h:3705
idRenderSystem * renderSystem
int Sys_Milliseconds(void)
void MenuEvent(const sysEvent_t *event)
case const int
Definition: Callbacks.cpp:52
#define CDKEY_TEXT
Definition: Licensee.h:112
const int PREVIEW_HEIGHT
Definition: Session.cpp:54
#define CDKEY_FILE
Definition: Licensee.h:110
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
virtual idFile * OpenExplicitFileRead(const char *OSPath)=0
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")
virtual void MapShutdown(void)=0
void TimeCmdDemo(const char *demoName)
Definition: Session.cpp:1373
static idCVar com_guid
static void ArgCompletion_DemoName(const idCmdArgs &args, void(*callback)(const char *s))
Definition: CmdSystem.h:184
virtual void Frame()
Definition: Session.cpp:2514
int combat
Definition: Game.h:51
void ExtractFileBase(idStr &dest) const
Definition: Str.cpp:940
virtual findFile_t FindFile(const char *path, bool scheduleAddons=false)=0
virtual void SetServerInfo(const idDict &serverInfo)=0
idCVar com_asyncInput("com_asyncInput","0", CVAR_BOOL|CVAR_SYSTEM,"sample input from the async thread")
virtual void ClearCDKey(bool valid[2])
Definition: Session.cpp:3057
const char * GetName(void) const
Definition: DeclManager.h:140
case const float
Definition: Callbacks.cpp:62
virtual void ExecuteCommandBuffer(void)=0
void Session_Hitch_f(const idCmdArgs &args)
Definition: Session.cpp:1837
void LoadGame_f(const idCmdArgs &args)
Definition: Session.cpp:1737
void ByteSwap()
Definition: UsercmdGen.cpp:39
GLenum GLsizei const GLvoid * string
Definition: glext.h:3472
void WriteToFileHandle(idFile *f) const
Definition: Dict.cpp:571
volatile int com_ticNumber
Definition: Common.cpp:96
virtual escReply_t HandleESC(idUserInterface **gui)=0
virtual ~idSessionLocal()
Definition: Session.cpp:369
virtual void HandleNamedEvent(const char *eventName)=0
bool OpenForWriting(const char *fileName)
Definition: DemoFile.cpp:153
virtual const idDict & GetPersistentPlayerInfo(int clientNum)=0
const int PREVIEW_X
Definition: Session.cpp:51
const idMaterial * wipeMaterial
virtual void PacifierUpdate()
Definition: Session.cpp:2332
static idCVar serverDrawClient
Definition: AsyncNetwork.h:180
int time_gameFrame
Definition: Common.cpp:89
short combat
Definition: Session.h:45
void PacifierUpdate(void)
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
static idCVar com_showTics
void Sys_Sleep(const int time)
Definition: macosx_sys.mm:67
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
int com_frameTime
Definition: Common.cpp:94
GLenum GLsizei len
Definition: glext.h:3472
idStr & DefaultFileExtension(const char *extension)
Definition: Str.cpp:794
void Set(const char *key, const char *value)
Definition: Dict.cpp:275
void Sys_GenerateEvents(void)
Definition: posix_main.cpp:980
void BeginAVICapture(const char *name)
Definition: Session.cpp:996
idUserInterfaceManager * uiManager
virtual void BeginFrame(int windowWidth, int windowHeight)=0
int i
Definition: process.py:33
idStrList loadGameList
idDict persistentPlayerInfo[MAX_ASYNC_CLIENTS]
Definition: Session_local.h:69
virtual void StartWritingDemo(idDemoFile *demo)=0
HandleGuiCommand_t guiHandle
virtual const char * HandleEvent(const sysEvent_t *event, int time, bool *updateVisuals=NULL)=0
int Icmp(const char *text) const
Definition: Str.h:667
virtual void SetPersistentPlayerInfo(int clientNum, const idDict &playerInfo)=0
virtual int WriteFile(const char *relativePath, const void *buffer, int size, const char *basePath="fs_savepath")=0
virtual void SetStateBool(const char *varName, const bool value)=0
idDemoFile * writeDemo
Definition: Session.h:159
const idMaterial * whiteMaterial
const char * GetAuthMsg(void)
Definition: Session.cpp:3322
virtual idUserInterface * FindGui(const char *qpath, bool autoLoad=false, bool needUnique=false, bool forceUnique=false)=0
idConsole * console
Definition: Console.cpp:122
static void ArgCompletion_SaveGame(const idCmdArgs &args, void(*callback)(const char *s))
Definition: CmdSystem.h:180
cdKeyState_t xpkey_state
idSoundWorld * menuSoundWorld
idStr & StripPath(void)
Definition: Str.cpp:885
virtual void Pause(void)=0
virtual void BeginLevelLoad(void)=0
void MoveToNewMap(const char *mapName)
Definition: Session.cpp:1225
virtual void SetStateFloat(const char *varName, const float value)=0
static idCVar com_wipeSeconds
void ReadFromFileHandle(idFile *f)
Definition: Dict.cpp:607
idUserInterface * guiTest
int com_editors
Definition: Common.cpp:97
Definition: File.h:50
bool insideExecuteMapChange
virtual idSoundWorld * GetPlayingSoundWorld(void)=0
findFile_t
Definition: FileSystem.h:91
virtual void BufferCommandText(cmdExecution_t exec, const char *text)=0
void StartPlayingCmdDemo(const char *demoName)
Definition: Session.cpp:1337
int Sys_GetDriveFreeSpace(const char *path)
Definition: posix_main.cpp:518
void LoadCmdDemoFromFile(idFile *file)
Definition: Session.cpp:1265
bool MaybeWaitOnCDKey(void)
Definition: Session.cpp:209
const int USERCMD_MSEC
Definition: UsercmdGen.h:41
int time_backend
Definition: Common.cpp:92
idRenderWorld * rw
Definition: Session.h:153
GLuint GLuint GLsizei count
Definition: glext.h:2845
static bool IsActive(void)
Definition: AsyncNetwork.h:149
virtual idRenderWorld * AllocRenderWorld(void)=0
void EndAVICapture()
Definition: Session.cpp:1010
void CompressDemoFile(const char *scheme, const char *name)
Definition: Session.cpp:1097
virtual int WriteInt(const int value)
Definition: File.cpp:468
virtual void CaptureRenderToFile(const char *fileName, bool fixAlpha=false)=0
void AppendArg(const char *text)
Definition: CmdArgs.cpp:177
idListGUI * guiMainMenu_MapList
idStrList modsList
const GLubyte * c
Definition: glext.h:4677
const char * GetString(const char *key, const char *defaultString="") const
Definition: Dict.h:240
idStr msgFireBack[2]
virtual void CaptureRenderToImage(const char *imageName)=0
#define BASE_GAMEDIR
Definition: Licensee.h:46
idStr & StripFileExtension(void)
Definition: Str.cpp:757
virtual const char * GetCDKey(bool xp)
Definition: Session.cpp:3079
virtual void Shutdown(void)=0
static idAsyncServer server
Definition: AsyncNetwork.h:167
#define MAX_STRING_CHARS
Definition: Lib.h:95
idCVar com_asyncSound("com_asyncSound","1", CVAR_INTEGER|CVAR_SYSTEM, ASYNCSOUND_INFO, 0, 1)
void Empty(void)
Definition: Str.h:714
virtual void ClearAllSoundEmitters(void)=0
virtual void ReadCDKey(void)
Definition: Session.cpp:2985
virtual int WriteString(const char *string)
Definition: File.cpp:546
static void BuildInvalidKeyMsg(idStr &msg, bool valid[2])
virtual void Stop()
Definition: Session.cpp:379
virtual void SetPlayingSoundWorld(idSoundWorld *soundWorld)=0
GLuint GLuint end
Definition: glext.h:2845
idFile * savegameFile
idUserInterface * guiActive
idUserInterface * guiTakeNotes
void PacifierUpdate(void)
virtual bool Draw(int clientNum)=0
idCommon * common
Definition: Common.cpp:206
virtual bool InitFromSaveGame(const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile)=0
void StartNewGame(const char *mapName, bool devmap=false)
Definition: Session.cpp:1150
bool GetBool(const char *key, const char *defaultString="0") const
Definition: Dict.h:256
virtual idListGUI * AllocListGUI(void) const =0
virtual void BeginLevelLoad(void)=0
#define NULL
Definition: Lib.h:88
virtual const char * GetCVarString(const char *name) const =0
void Clear(void)
Definition: Dict.cpp:201
int consistencyHash
Definition: Session_local.h:55
void StopRecordingRenderDemo()
Definition: Session.cpp:823
virtual const idDecl * FindType(declType_t type, const char *name, bool makeDefault=true)=0
void EmitGameAuth(void)
Definition: Session.cpp:3098
int evValue2
Definition: sys_public.h:218
GLuint buffer
Definition: glext.h:3108
virtual void SetCVarBool(const char *name, const bool value, int flags=0)=0
int GetInteger(void) const
Definition: CVarSystem.h:143
virtual bool ProcessEvent(const struct sysEvent_s *event, bool forceAccept)=0
virtual void Redraw(int time)=0
static const int CDKEY_BUF_LEN
int time_gameDraw
Definition: Common.cpp:90
idServerScan serverList
Definition: AsyncClient.h:117
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
void DemoShot(const char *name)
Definition: Session.cpp:889
const int PREVIEW_Y
Definition: Session.cpp:52
virtual void virtual void virtual void virtual void PrintWarnings(void)=0
const char * GetString(const char *str) const
Definition: LangDict.cpp:148
idCVar com_speeds("com_speeds","0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT,"show engine timings")
virtual void FreeListGUI(idListGUI *listgui)=0
virtual bool ProcessEvent(const sysEvent_t *event)
Definition: Session.cpp:2152
virtual int GetScreenWidth(void) const =0
idDict userInfo[MAX_ASYNC_CLIENTS]
Definition: Session_local.h:68
virtual gameReturn_t RunFrame(const usercmd_t *clientCmds)=0
timeDemo_t timeDemo
virtual const char * Activate(bool activate, int time)=0
const idStr & GetValue(void) const
Definition: Dict.h:53
static idCVar com_aviDemoSamples
idStr aviDemoShortName
int Argc(void) const
Definition: CmdArgs.h:48
static idCVar serverDedicated
Definition: AsyncNetwork.h:172
virtual bool InitFromMap(const char *mapName)=0
virtual void WritePrecacheCommands(idFile *f)=0
void GUIConfig(idUserInterface *pGUI, const char *name)
Definition: ServerScan.cpp:372
Definition: Session.h:51
void Clear(void)
Definition: Str.h:724
virtual void Draw(bool forceFullScreen)=0
virtual void InitForNewMap(void)=0
virtual void UnPause(void)=0
virtual void SetColor4(float r, float g, float b, float a)=0
void StopPlayingRenderDemo()
Definition: Session.cpp:844
idUsercmdGen * usercmdGen
Definition: UsercmdGen.cpp:419
idStr & RemoveColors(void)
Definition: Str.h:849
static idCVar com_showAngles
virtual int GetScreenHeight(void) const =0
virtual bool CheckGui(const char *qpath) const =0
virtual void Close(void)=0
virtual void SetPlayingSoundWorld()
Definition: Session.cpp:2960
virtual void UpdateScreen(bool outOfSequence=true)=0
virtual void Printf(const char *fmt,...) id_attribute((format(printf
virtual const idDict & State() const =0
virtual bool IsPaused(void)=0
void ExecuteMapChange(bool noFadeWipe=false)
Definition: Session.cpp:1515
virtual void DrawStretchPic(const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material, bool clip=true, float min_x=0.0f, float min_y=0.0f, float max_x=640.0f, float max_y=480.0f)=0
void SaveCmdDemoToFile(idFile *file)
Definition: Session.cpp:1243
virtual void BeginLevelLoad()=0
int LittleLong(int l)
Definition: Lib.cpp:281
usercmd_t cmd
Definition: Session_local.h:54
virtual void StartMenu(bool playIntro=false)
sysEventType_t evType
Definition: sys_public.h:216
virtual void Init()
Definition: Session.cpp:2847
virtual void AVIOpen(const char *path, const char *name)=0
virtual const char * BuildOSPath(const char *base, const char *game, const char *relativePath)=0
void SetText(const char *text)
Definition: DeclManager.h:180
static bool ExecKeyBinding(int keyNum)
Definition: KeyInput.cpp:726
virtual void Config(idUserInterface *pGUI, const char *name)=0
idDeclManager * declManager
idEventLoop * eventLoop
Definition: EventLoop.cpp:35
int GetLocalClientNum(void) const
Definition: AsyncClient.h:97
idCVar com_allowConsole("com_allowConsole","0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT,"allow toggling console with the tilde key")
virtual const char * RelativePathToOSPath(const char *relativePath, const char *basePath="fs_devpath")=0
mapSpawnData_t mapSpawnData
virtual void EndLevelLoad(void)=0
virtual void EndLevelLoad()=0
idUserInterface * guiIntro
#define XPKEY_FILE
Definition: Licensee.h:111
virtual void GenerateAllInteractions()=0
virtual void virtual void WritePrecacheCommands(idFile *f)=0
void TokenizeString(const char *text, bool keepAsStrings)
Definition: CmdArgs.cpp:106
void TimeRenderDemo(const char *name, bool twice=false)
Definition: Session.cpp:960
void Session_RescanSI_f(const idCmdArgs &args)
Definition: Session.cpp:72
virtual void SetMute(bool mute)=0
virtual int GetModifiedFlags(void) const =0
const int PREVIEW_WIDTH
Definition: Session.cpp:53
virtual bool Active(void)=0
void SetInt(const char *key, int val)
Definition: Dict.h:192
virtual void EndLevelLoad(const char *mapString)=0
virtual int GetReadCount(void)=0
idRenderModelManager * renderModelManager
const char * GetName(void)
Definition: DemoFile.h:52
idCVar gamename("gamename", GAME_VERSION, CVAR_GAME|CVAR_SERVERINFO|CVAR_ROM,"")
void TakeViewNotes2_f(const idCmdArgs &args)
Definition: Session.cpp:1780
void LoadLoadingGui(const char *mapName)
Definition: Session.cpp:1438
const int SCREEN_WIDTH
Definition: RenderSystem.h:153
virtual void Reload(bool all)=0
virtual void Shutdown()
Definition: Session.cpp:407
Definition: Game.h:66
void Clear()
Definition: Session.cpp:297
virtual void StopBox(void)
virtual void InitFromNewMap(const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed)=0
bool GetBool(void) const
Definition: CVarSystem.h:142
int Write(const void *buffer, int len)
Definition: DemoFile.cpp:322
idDict syncedCVars
Definition: Session_local.h:67
virtual void GuiFrameEvents()
tuple f
Definition: idal.py:89
void ClearWipe()
Definition: Session.cpp:539
idUserInterface * guiMainMenu
GLuint in
Definition: glext.h:5388
void Append(const char a)
Definition: Str.h:729
bool OpenForReading(const char *fileName)
Definition: DemoFile.cpp:81
short angles[3]
Definition: UsercmdGen.h:98
logStats_t loggedStats[MAX_LOGGED_STATS]
virtual void UpdateScreen(bool outOfSequence=true)
Definition: Session.cpp:2471
unsigned char byte
Definition: Lib.h:75
bool syncNextGameFrame
Definition: Game.h:52
void Sys_ClearEvents(void)
Definition: posix_main.cpp:328
virtual void SetGUI(idUserInterface *gui, HandleGuiCommand_t handle)
static idCVar com_aviDemoHeight
idUserInterface * guiGameOver
bool LoadGame(const char *saveName)
Definition: Session.cpp:2040
void AVIRenderDemo(const char *name)
Definition: Session.cpp:1038
const GLcharARB * name
Definition: glext.h:3629
idSoundSystem * soundSystem
Definition: snd_system.cpp:92
virtual void Push(const idStr &s)=0
virtual void ClearNotifyLines(void)=0
virtual int Write(const void *buffer, int len)
Definition: File.cpp:189
escReply_t
Definition: Game.h:63
const int MAX_LOGGED_USERCMDS
Definition: Session_local.h:81
Definition: Str.h:116
#define CDKEY_DIGITS
Definition: Session.cpp:3090
virtual void AVIClose(void)=0
virtual void StopWritingDemo()=0
void Sys_SetPhysicalWorkMemory(int minBytes, int maxBytes)
Definition: posix_main.cpp:508
static idCVar com_fixedTic
virtual void SetCDKeyGuiVars(void)
void Close()
Definition: DemoFile.cpp:182
const int MAX_BUFFERED_USERCMD
Definition: UsercmdGen.h:115
const char * c_str(void) const
Definition: Str.h:487
#define RENDERDEMO_VERSION
Definition: Licensee.h:88
virtual void RenderScene(const renderView_t *renderView)=0
void CompleteWipe()
Definition: Session.cpp:486
void AVIGame(const char *name)
Definition: Session.cpp:1071
virtual void StartWritingDemo(idDemoFile *demo)=0
virtual bool GetCVarBool(const char *name) const =0
char cdkey[CDKEY_BUF_LEN]
void SaveGame_f(const idCmdArgs &args)
Definition: Session.cpp:1752
const idKeyValue * GetKeyVal(int index) const
Definition: Dict.h:294
idUserInterface * guiInGame
char sessionCommand[MAX_STRING_CHARS]
Definition: Game.h:46
idUserInterface * guiLoading
const char * Argv(int arg) const
Definition: CmdArgs.h:50
virtual const idDict * MoveCVarsToDict(int flags) const =0
usercmd_t mapSpawnUsercmd[MAX_ASYNC_CLIENTS]
Definition: Session_local.h:70
virtual bool IsMultiplayer()
Definition: Session.cpp:452
idGame * game
Definition: Game_local.cpp:65
virtual void CropRenderSize(int width, int height, bool makePowerOfTwo=false, bool forceDimensions=false)=0
virtual int ReadString(idStr &string)
Definition: File.cpp:396
virtual void CreateOSPath(const char *OSPath)=0
virtual bool CheckKey(const char *key, bool netConnect, bool offline_valid[2])
Definition: Session.cpp:3123
virtual bool WaitingForGameAuth(void)
Definition: Session.cpp:3261
virtual void ClearWarnings(const char *reason)=0
virtual int GetSaveGameVersion(void)
Definition: Session.cpp:3313
virtual void SetRefreshOnPrint(bool set)=0
idSession * session
Definition: Session.cpp:48
int GetBytesNeededForMapLoad(const char *mapName)
Definition: Session.cpp:1462
char * va(const char *fmt,...)
Definition: Str.cpp:1568
virtual void CloseFile(idFile *f)=0
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
short health
Definition: Session.h:42
virtual void Error(const char *fmt,...) id_attribute((format(printf
logCmd_t loggedUsercmds[MAX_LOGGED_USERCMDS]
static idCVar com_skipGameDraw
void Replace(const char *old, const char *nw)
Definition: Str.cpp:563
GLfloat GLfloat p
Definition: glext.h:4674
static idCVar com_minTics
int time_frontend
Definition: Common.cpp:91
idCVar com_updateLoadSize("com_updateLoadSize","0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT,"update the load size after loading a map")
cdKeyState_t cdkey_state
idVec4 colorBlack
Definition: Lib.cpp:115
virtual void CDKeysAuthReply(bool valid, const char *auth_msg)
Definition: Session.cpp:3270
bool Sys_IsWindowVisible(void)
Definition: win_main.cpp:461
int GetNumKeyVals(void) const
Definition: Dict.h:290
virtual usercmd_t GetDirectUsercmd(void)=0
idUserInterface * guiMsgRestore
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
idUserInterface * guiRestartMenu
virtual usercmd_t TicCmd(int ticNumber)=0
void Sys_LeaveCriticalSection(int index)
void Sys_EnterCriticalSection(int index)
void UnloadMap()
Definition: Session.cpp:1413
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
bool com_editorActive
Definition: Common.cpp:98
int Read(void *buffer, int len)
Definition: DemoFile.cpp:309
void DisconnectFromServer(void)
virtual void ClearModifiedFlags(int flags)=0
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
virtual void BeginLevelLoad()=0
virtual bool HasD3XP(void)=0
void Sys_WaitForEvent(int index)
byte buttons
Definition: UsercmdGen.h:94
virtual void TimeHitch(int msec)
Definition: Session.cpp:2976
virtual void SaveGame(idFile *saveGameFile)=0
GLuint start
Definition: glext.h:2845
virtual void EndLevelLoad()=0
bool SaveGame(const char *saveName, bool autosave=false)
Definition: Session.cpp:1894
int GetLocalClientNum()
Definition: Session.cpp:2939
void RunGameTic()
Definition: Session.cpp:2740
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
virtual void TakeScreenshot(int width, int height, const char *fileName, int samples, struct renderView_s *ref)=0
int Milliseconds(void)
Definition: EventLoop.cpp:248
int heartRate
Definition: Game.h:49
virtual void Frame()=0
idSessionLocal sessLocal
Definition: Session.cpp:47
void Clear(void)
Definition: List.h:184
static idCVar com_aviDemoWidth
void Sys_GrabMouseCursor(bool)
Definition: dedicated.cpp:43
virtual void StopAllSounds(void)=0
virtual void WriteDemoPics()=0