//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //===========================================================================// #include #include #include "isys.h" #include "console/conproc.h" #include "dedicated.h" #include "engine_hlds_api.h" #include "checksum_md5.h" #include "mathlib/mathlib.h" #include "tier0/vcrmode.h" #include "tier0/dbg.h" #include "tier1/strtools.h" #include "tier0/icommandline.h" #include "idedicatedexports.h" #include "vgui/vguihelpers.h" #include "appframework/AppFramework.h" #include "filesystem_init.h" #include "tier2/tier2.h" #include "dedicated.h" #include "vstdlib/cvar.h" #include "inputsystem/iinputsystem.h" #ifdef _WIN32 #include #include #include "KeyValues.h" #else #define _chdir chdir #include #endif void* FileSystemFactory( const char *pName, int *pReturnCode ); bool InitInstance( ); int ProcessConsoleInput( void ); bool NET_Init( void ); void NET_Shutdown( void ); const char *UTIL_GetBaseDir( void ); #ifdef _WIN32 bool g_bVGui = false; #endif #if defined ( _WIN32 ) #include "console/TextConsoleWin32.h" CTextConsoleWin32 console; #else #include "console/TextConsoleUnix.h" CTextConsoleUnix console; #endif #ifdef _WIN32 extern char *gpszCvars; #endif IDedicatedServerAPI *engine = NULL; //----------------------------------------------------------------------------- // Implementation of IVCRHelpers. //----------------------------------------------------------------------------- class CVCRHelpers : public IVCRHelpers { public: virtual void ErrorMessage( const char *pMsg ) { printf( "ERROR: %s\n", pMsg ); } virtual void* GetMainWindow() { return 0; } }; CVCRHelpers g_VCRHelpers; SpewRetval_t DedicatedSpewOutputFunc( SpewType_t spewType, char const *pMsg ); // in sys_common.cpp //----------------------------------------------------------------------------- // Run a single VGUI frame. if bFinished is true, run VGUIFinishedConfig() first. //----------------------------------------------------------------------------- static bool DoRunVGUIFrame( bool bFinished = false ) { #ifdef _WIN32 if ( g_bVGui ) { if ( bFinished ) VGUIFinishedConfig(); RunVGUIFrame(); return true; } #endif return false; } //----------------------------------------------------------------------------- // Handle the VCRHook PeekMessage loop. // Return true if WM_QUIT received. //----------------------------------------------------------------------------- static bool HandleVCRHook() { #if defined ( _WIN32 ) MSG msg; bool bDone = false; while( VCRHook_PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { //if (!GetMessage( &msg, NULL, 0, 0)) if ( msg.message == WM_QUIT ) { bDone = true; break; } TranslateMessage( &msg ); DispatchMessage( &msg ); } if ( IsPC() ) { // NOTE: Under some implementations of Win9x, // dispatching messages can cause the FPU control word to change SetupFPUControlWord(); } if ( bDone /*|| gbAppHasBeenTerminated*/ ) return true; #endif // _WIN32 return false; } //----------------------------------------------------------------------------- // // Server loop // //----------------------------------------------------------------------------- void RunServer( void ) { #ifdef _WIN32 if(gpszCvars) { engine->AddConsoleText(gpszCvars); } #endif // Run 2 engine frames first to get the engine to load its resources. for ( int i = 0; i < 2; i++ ) { DoRunVGUIFrame(); if ( !engine->RunFrame() ) return; } // Run final VGUI frame. DoRunVGUIFrame( true ); int bDone = false; while ( !bDone ) { // Check on VCRHook_PeekMessage... if ( HandleVCRHook() ) break; if ( !DoRunVGUIFrame() ) ProcessConsoleInput(); if ( !engine->RunFrame() ) bDone = true; sys->UpdateStatus( 0 /* don't force */ ); } } //----------------------------------------------------------------------------- // // initialize the console or wait for vgui to start the server // //----------------------------------------------------------------------------- static bool ConsoleStartup( ) { #ifdef _WIN32 if ( g_bVGui ) { RunVGUIFrame(); // Run the config screen while (VGUIIsInConfig() && VGUIIsRunning()) RunVGUIFrame(); if ( VGUIIsStopping() ) return false; return true; } else { if ( !console.Init() ) { return false; } } #endif // _WIN32 return true; } //----------------------------------------------------------------------------- // Instantiate all main libraries //----------------------------------------------------------------------------- bool CDedicatedAppSystemGroup::Create( ) { #ifndef _WIN32 if ( !console.Init() ) return false; #endif // Hook the debug output stuff (override the spew func in the appframework) SpewOutputFunc( DedicatedSpewOutputFunc ); // Added the dedicated exports module for the engine to grab AppModule_t dedicatedModule = LoadModule( Sys_GetFactoryThis() ); IAppSystem *pSystem = AddSystem( dedicatedModule, VENGINE_DEDICATEDEXPORTS_API_VERSION ); if ( !pSystem ) return false; if ( sys->LoadModules( this ) ) { // Find the input system and tell it to skip Steam Controller initialization (we have to set this flag before Init gets called on the // input system). Dedicated server should skip controller initialization to avoid initializing Steam, because we don't want the user to be // flagged as "playing" the game. auto inputsystem = ( IInputSystem* )FindSystem( INPUTSYSTEM_INTERFACE_VERSION ); if ( inputsystem ) { inputsystem->SetSkipControllerInitialization( true ); } return true; } else { return false; } } bool CDedicatedAppSystemGroup::PreInit( ) { // A little hack needed because dedicated links directly to filesystem .cpp files g_pFullFileSystem = NULL; if ( !BaseClass::PreInit() ) return false; CFSSteamSetupInfo steamInfo; steamInfo.m_pDirectoryName = NULL; steamInfo.m_bOnlyUseDirectoryName = false; steamInfo.m_bToolsMode = false; steamInfo.m_bSetSteamDLLPath = false; steamInfo.m_bSteam = g_pFullFileSystem->IsSteam(); steamInfo.m_bNoGameInfo = steamInfo.m_bSteam; if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK ) return false; CFSMountContentInfo fsInfo; fsInfo.m_pFileSystem = g_pFullFileSystem; fsInfo.m_bToolsMode = false; fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath; if ( FileSystem_MountContent( fsInfo ) != FS_OK ) return false; if ( !NET_Init() ) return false; #ifdef _WIN32 g_bVGui = !CommandLine()->CheckParm( "-console" ); #endif CreateInterfaceFn factory = GetFactory(); IInputSystem *inputsystem = (IInputSystem *)factory( INPUTSYSTEM_INTERFACE_VERSION, NULL ); if ( inputsystem ) { inputsystem->SetConsoleTextMode( true ); } #ifdef _WIN32 if ( g_bVGui ) { StartVGUI( GetFactory() ); } else #endif { if ( !sys->CreateConsoleWindow() ) return false; } return true; } int CDedicatedAppSystemGroup::Main( ) { if ( !ConsoleStartup() ) return -1; #ifdef _WIN32 if ( g_bVGui ) RunVGUIFrame(); #endif // Set up mod information ModInfo_t info; info.m_pInstance = GetAppInstance(); info.m_pBaseDirectory = UTIL_GetBaseDir(); info.m_pInitialMod = CommandLine()->ParmValue( "-game", "hl2" ); info.m_pInitialGame = CommandLine()->ParmValue( "-defaultgamedir", "hl2" ); info.m_pParentAppSystemGroup = this; info.m_bTextMode = CommandLine()->CheckParm( "-textmode" ); if ( engine->ModInit( info ) ) { engine->ModShutdown(); } // if engine->ModInit return 0; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDedicatedAppSystemGroup::PostShutdown() { #ifdef _WIN32 if ( g_bVGui ) StopVGUI(); #endif sys->DestroyConsoleWindow(); console.ShutDown(); NET_Shutdown(); BaseClass::PostShutdown(); } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- void CDedicatedAppSystemGroup::Destroy() { } //----------------------------------------------------------------------------- // Gets the executable name //----------------------------------------------------------------------------- bool GetExecutableName( char *out, int nMaxLen ) { #ifdef _WIN32 if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, nMaxLen ) ) return false; return true; #elif POSIX Q_strncpy( out, g_szEXEName, nMaxLen ); return true; #endif } //----------------------------------------------------------------------------- // Purpose: Return the directory where this .exe is running from // Output : char //----------------------------------------------------------------------------- void UTIL_ComputeBaseDir( char *pBaseDir, int nMaxLen ) { int j; char *pBuffer = NULL; pBaseDir[ 0 ] = 0; if ( GetExecutableName( pBaseDir, nMaxLen ) ) { pBuffer = strrchr( pBaseDir, CORRECT_PATH_SEPARATOR ); if ( pBuffer && *pBuffer ) { *(pBuffer+1) = '\0'; } j = strlen( pBaseDir ); if (j > 0) { if ( ( pBaseDir[ j-1 ] == '\\' ) || ( pBaseDir[ j-1 ] == '/' ) ) { pBaseDir[ j-1 ] = 0; } } } char const *pOverrideDir = CommandLine()->CheckParm( "-basedir" ); if ( pOverrideDir ) { strcpy( pBaseDir, pOverrideDir ); } Q_strlower( pBaseDir ); Q_FixSlashes( pBaseDir ); } //----------------------------------------------------------------------------- // This class is a helper class used for steam-based applications. // It loads up the file system in preparation for using it to load other // required modules from steam. // // I couldn't use the one in appframework because the dedicated server // inlines all the filesystem code. //----------------------------------------------------------------------------- class CDedicatedSteamApplication : public CSteamApplication { public: CDedicatedSteamApplication( CSteamAppSystemGroup *pAppSystemGroup ); virtual bool Create( ); }; //----------------------------------------------------------------------------- // This class is a helper class used for steam-based applications. // It loads up the file system in preparation for using it to load other // required modules from steam. // // I couldn't use the one in appframework because the dedicated server // inlines all the filesystem code. //----------------------------------------------------------------------------- CDedicatedSteamApplication::CDedicatedSteamApplication( CSteamAppSystemGroup *pAppSystemGroup ) : CSteamApplication( pAppSystemGroup ) { } //----------------------------------------------------------------------------- // Implementation of IAppSystemGroup //----------------------------------------------------------------------------- bool CDedicatedSteamApplication::Create( ) { // Add in the cvar factory AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() ); AddSystem( cvarModule, CVAR_INTERFACE_VERSION ); AppModule_t fileSystemModule = LoadModule( FileSystemFactory ); m_pFileSystem = (IFileSystem*)AddSystem( fileSystemModule, FILESYSTEM_INTERFACE_VERSION ); if ( !m_pFileSystem ) { Warning( "Unable to load the file system!\n" ); return false; } return true; } //----------------------------------------------------------------------------- // // Main entry point for dedicated server, shared between win32 and linux // //----------------------------------------------------------------------------- int main(int argc, char **argv) { #ifndef POSIX _asm { fninit } #endif SetupFPUControlWord(); #ifdef POSIX Q_strncpy( g_szEXEName, *argv, ARRAYSIZE( g_szEXEName ) ); // Store off command line for argument searching BuildCmdLine( argc, argv ); #endif MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f ); // Store off command line for argument searching CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() ); #ifndef _WIN32 Plat_SetCommandLine( CommandLine()->GetCmdLine() ); #endif // Start VCR mode? const char *filename; if( CommandLine()->CheckParm( "-vcrrecord", &filename ) ) { if ( !VCRStart( filename, true, &g_VCRHelpers ) ) { Error( "-vcrrecord: can't open '%s' for writing.\n", filename ); return -1; } } else if( CommandLine()->CheckParm( "-vcrplayback", &filename ) ) { if ( !VCRStart( filename, false, &g_VCRHelpers ) ) { Error( "-vcrplayback: can't open '%s' for reading.\n", filename ); return -1; } } // Figure out the directory the executable is running from // and make that be the current working directory char pBasedir[ MAX_PATH ]; UTIL_ComputeBaseDir( pBasedir, MAX_PATH ); _chdir( pBasedir ); // Rehook the command line through VCR mode. CommandLine()->CreateCmdLine( VCRHook_GetCommandLine() ); if ( !InitInstance() ) return -1; CDedicatedAppSystemGroup dedicatedSystems; CDedicatedSteamApplication steamApplication( &dedicatedSystems ); return steamApplication.Run( ); }