Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

530 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include "isys.h"
  10. #include "console/conproc.h"
  11. #include "dedicated.h"
  12. #include "engine_hlds_api.h"
  13. #include "checksum_md5.h"
  14. #include "mathlib/mathlib.h"
  15. #include "tier0/vcrmode.h"
  16. #include "tier0/dbg.h"
  17. #include "tier1/strtools.h"
  18. #include "tier0/icommandline.h"
  19. #include "idedicatedexports.h"
  20. #include "vgui/vguihelpers.h"
  21. #include "appframework/AppFramework.h"
  22. #include "filesystem_init.h"
  23. #include "tier2/tier2.h"
  24. #include "dedicated.h"
  25. #include "vstdlib/cvar.h"
  26. #include "inputsystem/iinputsystem.h"
  27. #ifdef _WIN32
  28. #include <windows.h>
  29. #include <direct.h>
  30. #include "KeyValues.h"
  31. #else
  32. #define _chdir chdir
  33. #include <unistd.h>
  34. #endif
  35. void* FileSystemFactory( const char *pName, int *pReturnCode );
  36. bool InitInstance( );
  37. int ProcessConsoleInput( void );
  38. bool NET_Init( void );
  39. void NET_Shutdown( void );
  40. const char *UTIL_GetBaseDir( void );
  41. #ifdef _WIN32
  42. bool g_bVGui = false;
  43. #endif
  44. #if defined ( _WIN32 )
  45. #include "console/TextConsoleWin32.h"
  46. CTextConsoleWin32 console;
  47. #else
  48. #include "console/TextConsoleUnix.h"
  49. CTextConsoleUnix console;
  50. #endif
  51. #ifdef _WIN32
  52. extern char *gpszCvars;
  53. #endif
  54. IDedicatedServerAPI *engine = NULL;
  55. //-----------------------------------------------------------------------------
  56. // Implementation of IVCRHelpers.
  57. //-----------------------------------------------------------------------------
  58. class CVCRHelpers : public IVCRHelpers
  59. {
  60. public:
  61. virtual void ErrorMessage( const char *pMsg )
  62. {
  63. printf( "ERROR: %s\n", pMsg );
  64. }
  65. virtual void* GetMainWindow()
  66. {
  67. return 0;
  68. }
  69. };
  70. CVCRHelpers g_VCRHelpers;
  71. SpewRetval_t DedicatedSpewOutputFunc( SpewType_t spewType, char const *pMsg ); // in sys_common.cpp
  72. //-----------------------------------------------------------------------------
  73. // Run a single VGUI frame. if bFinished is true, run VGUIFinishedConfig() first.
  74. //-----------------------------------------------------------------------------
  75. static bool DoRunVGUIFrame( bool bFinished = false )
  76. {
  77. #ifdef _WIN32
  78. if ( g_bVGui )
  79. {
  80. if ( bFinished )
  81. VGUIFinishedConfig();
  82. RunVGUIFrame();
  83. return true;
  84. }
  85. #endif
  86. return false;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Handle the VCRHook PeekMessage loop.
  90. // Return true if WM_QUIT received.
  91. //-----------------------------------------------------------------------------
  92. static bool HandleVCRHook()
  93. {
  94. #if defined ( _WIN32 )
  95. MSG msg;
  96. bool bDone = false;
  97. while( VCRHook_PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  98. {
  99. //if (!GetMessage( &msg, NULL, 0, 0))
  100. if ( msg.message == WM_QUIT )
  101. {
  102. bDone = true;
  103. break;
  104. }
  105. TranslateMessage( &msg );
  106. DispatchMessage( &msg );
  107. }
  108. if ( IsPC() )
  109. {
  110. // NOTE: Under some implementations of Win9x,
  111. // dispatching messages can cause the FPU control word to change
  112. SetupFPUControlWord();
  113. }
  114. if ( bDone /*|| gbAppHasBeenTerminated*/ )
  115. return true;
  116. #endif // _WIN32
  117. return false;
  118. }
  119. //-----------------------------------------------------------------------------
  120. //
  121. // Server loop
  122. //
  123. //-----------------------------------------------------------------------------
  124. void RunServer( void )
  125. {
  126. #ifdef _WIN32
  127. if(gpszCvars)
  128. {
  129. engine->AddConsoleText(gpszCvars);
  130. }
  131. #endif
  132. // Run 2 engine frames first to get the engine to load its resources.
  133. for ( int i = 0; i < 2; i++ )
  134. {
  135. DoRunVGUIFrame();
  136. if ( !engine->RunFrame() )
  137. return;
  138. }
  139. // Run final VGUI frame.
  140. DoRunVGUIFrame( true );
  141. int bDone = false;
  142. while ( !bDone )
  143. {
  144. // Check on VCRHook_PeekMessage...
  145. if ( HandleVCRHook() )
  146. break;
  147. if ( !DoRunVGUIFrame() )
  148. ProcessConsoleInput();
  149. if ( !engine->RunFrame() )
  150. bDone = true;
  151. sys->UpdateStatus( 0 /* don't force */ );
  152. }
  153. }
  154. //-----------------------------------------------------------------------------
  155. //
  156. // initialize the console or wait for vgui to start the server
  157. //
  158. //-----------------------------------------------------------------------------
  159. static bool ConsoleStartup( )
  160. {
  161. #ifdef _WIN32
  162. if ( g_bVGui )
  163. {
  164. RunVGUIFrame();
  165. // Run the config screen
  166. while (VGUIIsInConfig() && VGUIIsRunning())
  167. RunVGUIFrame();
  168. if ( VGUIIsStopping() )
  169. return false;
  170. return true;
  171. }
  172. else
  173. {
  174. if ( !console.Init() )
  175. {
  176. return false;
  177. }
  178. }
  179. #endif // _WIN32
  180. return true;
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Instantiate all main libraries
  184. //-----------------------------------------------------------------------------
  185. bool CDedicatedAppSystemGroup::Create( )
  186. {
  187. #ifndef _WIN32
  188. if ( !console.Init() )
  189. return false;
  190. #endif
  191. // Hook the debug output stuff (override the spew func in the appframework)
  192. SpewOutputFunc( DedicatedSpewOutputFunc );
  193. // Added the dedicated exports module for the engine to grab
  194. AppModule_t dedicatedModule = LoadModule( Sys_GetFactoryThis() );
  195. IAppSystem *pSystem = AddSystem( dedicatedModule, VENGINE_DEDICATEDEXPORTS_API_VERSION );
  196. if ( !pSystem )
  197. return false;
  198. if ( sys->LoadModules( this ) )
  199. {
  200. // Find the input system and tell it to skip Steam Controller initialization (we have to set this flag before Init gets called on the
  201. // input system). Dedicated server should skip controller initialization to avoid initializing Steam, because we don't want the user to be
  202. // flagged as "playing" the game.
  203. auto inputsystem = ( IInputSystem* )FindSystem( INPUTSYSTEM_INTERFACE_VERSION );
  204. if ( inputsystem )
  205. {
  206. inputsystem->SetSkipControllerInitialization( true );
  207. }
  208. return true;
  209. }
  210. else
  211. {
  212. return false;
  213. }
  214. }
  215. bool CDedicatedAppSystemGroup::PreInit( )
  216. {
  217. // A little hack needed because dedicated links directly to filesystem .cpp files
  218. g_pFullFileSystem = NULL;
  219. if ( !BaseClass::PreInit() )
  220. return false;
  221. CFSSteamSetupInfo steamInfo;
  222. steamInfo.m_pDirectoryName = NULL;
  223. steamInfo.m_bOnlyUseDirectoryName = false;
  224. steamInfo.m_bToolsMode = false;
  225. steamInfo.m_bSetSteamDLLPath = false;
  226. steamInfo.m_bSteam = g_pFullFileSystem->IsSteam();
  227. steamInfo.m_bNoGameInfo = steamInfo.m_bSteam;
  228. if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
  229. return false;
  230. CFSMountContentInfo fsInfo;
  231. fsInfo.m_pFileSystem = g_pFullFileSystem;
  232. fsInfo.m_bToolsMode = false;
  233. fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
  234. if ( FileSystem_MountContent( fsInfo ) != FS_OK )
  235. return false;
  236. if ( !NET_Init() )
  237. return false;
  238. #ifdef _WIN32
  239. g_bVGui = !CommandLine()->CheckParm( "-console" );
  240. #endif
  241. CreateInterfaceFn factory = GetFactory();
  242. IInputSystem *inputsystem = (IInputSystem *)factory( INPUTSYSTEM_INTERFACE_VERSION, NULL );
  243. if ( inputsystem )
  244. {
  245. inputsystem->SetConsoleTextMode( true );
  246. }
  247. #ifdef _WIN32
  248. if ( g_bVGui )
  249. {
  250. StartVGUI( GetFactory() );
  251. }
  252. else
  253. #endif
  254. {
  255. if ( !sys->CreateConsoleWindow() )
  256. return false;
  257. }
  258. return true;
  259. }
  260. int CDedicatedAppSystemGroup::Main( )
  261. {
  262. if ( !ConsoleStartup() )
  263. return -1;
  264. #ifdef _WIN32
  265. if ( g_bVGui )
  266. RunVGUIFrame();
  267. #endif
  268. // Set up mod information
  269. ModInfo_t info;
  270. info.m_pInstance = GetAppInstance();
  271. info.m_pBaseDirectory = UTIL_GetBaseDir();
  272. info.m_pInitialMod = CommandLine()->ParmValue( "-game", "hl2" );
  273. info.m_pInitialGame = CommandLine()->ParmValue( "-defaultgamedir", "hl2" );
  274. info.m_pParentAppSystemGroup = this;
  275. info.m_bTextMode = CommandLine()->CheckParm( "-textmode" );
  276. if ( engine->ModInit( info ) )
  277. {
  278. engine->ModShutdown();
  279. } // if engine->ModInit
  280. return 0;
  281. }
  282. //-----------------------------------------------------------------------------
  283. //
  284. //-----------------------------------------------------------------------------
  285. void CDedicatedAppSystemGroup::PostShutdown()
  286. {
  287. #ifdef _WIN32
  288. if ( g_bVGui )
  289. StopVGUI();
  290. #endif
  291. sys->DestroyConsoleWindow();
  292. console.ShutDown();
  293. NET_Shutdown();
  294. BaseClass::PostShutdown();
  295. }
  296. //-----------------------------------------------------------------------------
  297. //
  298. //-----------------------------------------------------------------------------
  299. void CDedicatedAppSystemGroup::Destroy()
  300. {
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Gets the executable name
  304. //-----------------------------------------------------------------------------
  305. bool GetExecutableName( char *out, int nMaxLen )
  306. {
  307. #ifdef _WIN32
  308. if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, nMaxLen ) )
  309. return false;
  310. return true;
  311. #elif POSIX
  312. Q_strncpy( out, g_szEXEName, nMaxLen );
  313. return true;
  314. #endif
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose: Return the directory where this .exe is running from
  318. // Output : char
  319. //-----------------------------------------------------------------------------
  320. void UTIL_ComputeBaseDir( char *pBaseDir, int nMaxLen )
  321. {
  322. int j;
  323. char *pBuffer = NULL;
  324. pBaseDir[ 0 ] = 0;
  325. if ( GetExecutableName( pBaseDir, nMaxLen ) )
  326. {
  327. pBuffer = strrchr( pBaseDir, CORRECT_PATH_SEPARATOR );
  328. if ( pBuffer && *pBuffer )
  329. {
  330. *(pBuffer+1) = '\0';
  331. }
  332. j = strlen( pBaseDir );
  333. if (j > 0)
  334. {
  335. if ( ( pBaseDir[ j-1 ] == '\\' ) ||
  336. ( pBaseDir[ j-1 ] == '/' ) )
  337. {
  338. pBaseDir[ j-1 ] = 0;
  339. }
  340. }
  341. }
  342. char const *pOverrideDir = CommandLine()->CheckParm( "-basedir" );
  343. if ( pOverrideDir )
  344. {
  345. strcpy( pBaseDir, pOverrideDir );
  346. }
  347. Q_strlower( pBaseDir );
  348. Q_FixSlashes( pBaseDir );
  349. }
  350. //-----------------------------------------------------------------------------
  351. // This class is a helper class used for steam-based applications.
  352. // It loads up the file system in preparation for using it to load other
  353. // required modules from steam.
  354. //
  355. // I couldn't use the one in appframework because the dedicated server
  356. // inlines all the filesystem code.
  357. //-----------------------------------------------------------------------------
  358. class CDedicatedSteamApplication : public CSteamApplication
  359. {
  360. public:
  361. CDedicatedSteamApplication( CSteamAppSystemGroup *pAppSystemGroup );
  362. virtual bool Create( );
  363. };
  364. //-----------------------------------------------------------------------------
  365. // This class is a helper class used for steam-based applications.
  366. // It loads up the file system in preparation for using it to load other
  367. // required modules from steam.
  368. //
  369. // I couldn't use the one in appframework because the dedicated server
  370. // inlines all the filesystem code.
  371. //-----------------------------------------------------------------------------
  372. CDedicatedSteamApplication::CDedicatedSteamApplication( CSteamAppSystemGroup *pAppSystemGroup ) : CSteamApplication( pAppSystemGroup )
  373. {
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Implementation of IAppSystemGroup
  377. //-----------------------------------------------------------------------------
  378. bool CDedicatedSteamApplication::Create( )
  379. {
  380. // Add in the cvar factory
  381. AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() );
  382. AddSystem( cvarModule, CVAR_INTERFACE_VERSION );
  383. AppModule_t fileSystemModule = LoadModule( FileSystemFactory );
  384. m_pFileSystem = (IFileSystem*)AddSystem( fileSystemModule, FILESYSTEM_INTERFACE_VERSION );
  385. if ( !m_pFileSystem )
  386. {
  387. Warning( "Unable to load the file system!\n" );
  388. return false;
  389. }
  390. return true;
  391. }
  392. //-----------------------------------------------------------------------------
  393. //
  394. // Main entry point for dedicated server, shared between win32 and linux
  395. //
  396. //-----------------------------------------------------------------------------
  397. int main(int argc, char **argv)
  398. {
  399. #ifndef POSIX
  400. _asm
  401. {
  402. fninit
  403. }
  404. #endif
  405. SetupFPUControlWord();
  406. #ifdef POSIX
  407. Q_strncpy( g_szEXEName, *argv, ARRAYSIZE( g_szEXEName ) );
  408. // Store off command line for argument searching
  409. BuildCmdLine( argc, argv );
  410. #endif
  411. MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f );
  412. // Store off command line for argument searching
  413. CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() );
  414. #ifndef _WIN32
  415. Plat_SetCommandLine( CommandLine()->GetCmdLine() );
  416. #endif
  417. // Start VCR mode?
  418. const char *filename;
  419. if( CommandLine()->CheckParm( "-vcrrecord", &filename ) )
  420. {
  421. if ( !VCRStart( filename, true, &g_VCRHelpers ) )
  422. {
  423. Error( "-vcrrecord: can't open '%s' for writing.\n", filename );
  424. return -1;
  425. }
  426. }
  427. else if( CommandLine()->CheckParm( "-vcrplayback", &filename ) )
  428. {
  429. if ( !VCRStart( filename, false, &g_VCRHelpers ) )
  430. {
  431. Error( "-vcrplayback: can't open '%s' for reading.\n", filename );
  432. return -1;
  433. }
  434. }
  435. // Figure out the directory the executable is running from
  436. // and make that be the current working directory
  437. char pBasedir[ MAX_PATH ];
  438. UTIL_ComputeBaseDir( pBasedir, MAX_PATH );
  439. _chdir( pBasedir );
  440. // Rehook the command line through VCR mode.
  441. CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() );
  442. if ( !InitInstance() )
  443. return -1;
  444. CDedicatedAppSystemGroup dedicatedSystems;
  445. CDedicatedSteamApplication steamApplication( &dedicatedSystems );
  446. return steamApplication.Run( );
  447. }