//----------------------------------------------------------------------------- // Loads the file system module //----------------------------------------------------------------------------- FSReturnCode_t FileSystem_LoadFileSystemModule( CFSLoadModuleInfo &fsInfo ) { // First, locate the directory with gameinfo.txt. FSReturnCode_t ret = FileSystem_SetupSteamEnvironment( fsInfo ); if ( ret != FS_OK ) return ret; // Now that the environment is setup, load the filesystem module. if ( !Sys_LoadInterface( fsInfo.m_pFileSystemDLLName, FILESYSTEM_INTERFACE_VERSION, &fsInfo.m_pModule, (void**)&fsInfo.m_pFileSystem ) ) { return SetupFileSystemError( false, FS_UNABLE_TO_INIT, "Can't load %s.", fsInfo.m_pFileSystemDLLName ); } if ( !fsInfo.m_pFileSystem->Connect( fsInfo.m_ConnectFactory ) ) return SetupFileSystemError( false, FS_UNABLE_TO_INIT, "%s IFileSystem::Connect failed.", fsInfo.m_pFileSystemDLLName ); if ( fsInfo.m_pFileSystem->Init() != INIT_OK ) return SetupFileSystemError( false, FS_UNABLE_TO_INIT, "%s IFileSystem::Init failed.", fsInfo.m_pFileSystemDLLName ); return FS_OK; }
FSReturnCode_t SetSteamInstallPath( char *steamInstallPath, int steamInstallPathLen, CSteamEnvVars &steamEnvVars, bool bErrorsAsWarnings ) { if ( IsConsole() ) { // consoles don't use steam return FS_MISSING_STEAM_DLL; } // Start at our bin directory and move up until we find a directory with steam.dll in it. char executablePath[MAX_PATH]; if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) { if ( bErrorsAsWarnings ) { Warning( "SetSteamInstallPath: FileSystem_GetExecutableDir failed.\n" ); return FS_INVALID_PARAMETERS; } else { return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); } } Q_strncpy( steamInstallPath, executablePath, steamInstallPathLen ); while ( 1 ) { // Ignore steamapp.cfg here in case they're debugging. We still need to know the real steam path so we can find their username. // find if ( DoesFileExistIn( steamInstallPath, "steam.dll" ) && !DoesFileExistIn( steamInstallPath, "steamapp.cfg" ) ) break; if ( !Q_StripLastDir( steamInstallPath, steamInstallPathLen ) ) { if ( bErrorsAsWarnings ) { Warning( "Can't find steam.dll relative to executable path: %s.\n", executablePath ); return FS_MISSING_STEAM_DLL; } else { return SetupFileSystemError( false, FS_MISSING_STEAM_DLL, "Can't find steam.dll relative to executable path: %s.", executablePath ); } } } // Also, add the install path to their PATH environment variable, so filesystem_steam.dll can get to steam.dll. char szPath[ 8192 ]; steamEnvVars.m_Path.GetValue( szPath, sizeof( szPath ) ); if ( !DoesPathExistAlready( szPath, steamInstallPath ) ) { steamEnvVars.m_Path.SetValue( "%s;%s", szPath, steamInstallPath ); } return FS_OK; }
//----------------------------------------------------------------------------- // Returns the name of the file system DLL to use //----------------------------------------------------------------------------- FSReturnCode_t FileSystem_GetFileSystemDLLName( char *pFileSystemDLL, int nMaxLen, bool &bSteam ) { bSteam = false; // Inside of here, we don't have a filesystem yet, so we have to assume that the filesystem_stdio or filesystem_steam // is in this same directory with us. char executablePath[MAX_PATH]; if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); #if defined( _WIN32 ) Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_stdio.dll", executablePath, CORRECT_PATH_SEPARATOR ); #elif defined( POSIX ) Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_stdio", executablePath, CORRECT_PATH_SEPARATOR ); struct stat statBuf; if ( CommandLine()->FindParm( "-steam" ) || CommandLine()->FindParm( "-steamlocal" ) || stat( pFileSystemDLL, &statBuf ) != 0 ) { Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_steam.dylib", executablePath, CORRECT_PATH_SEPARATOR ); bSteam = true; } #else #error "define a filesystem dll name" #endif return FS_OK; }
FSReturnCode_t GetSteamCfgPath( char *steamCfgPath, int steamCfgPathLen ) { steamCfgPath[0] = 0; char executablePath[MAX_PATH]; if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) { return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); } Q_strncpy( steamCfgPath, executablePath, steamCfgPathLen ); while ( 1 ) { if ( DoesFileExistIn( steamCfgPath, "steam.cfg" ) ) break; if ( !Q_StripLastDir( steamCfgPath, steamCfgPathLen) ) { // the file isnt found, thats ok, its not mandatory return FS_OK; } } Q_AppendSlash( steamCfgPath, steamCfgPathLen ); Q_strncat( steamCfgPath, "steam.cfg", steamCfgPathLen, COPY_ALL_CHARACTERS ); return FS_OK; }
//----------------------------------------------------------------------------- // Returns the name of the file system DLL to use //----------------------------------------------------------------------------- FSReturnCode_t FileSystem_GetFileSystemDLLName( char *pFileSystemDLL, int nMaxLen, bool &bSteam ) { bSteam = false; // Inside of here, we don't have a filesystem yet, so we have to assume that the filesystem_stdio or filesystem_steam // is in this same directory with us. char executablePath[MAX_PATH]; if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); #if defined( _WIN32 ) && !defined( _X360 ) // If filesystem_stdio.dll is missing or -steam is specified, then load filesystem_steam.dll. // There are two command line parameters for Steam: // 1) -steam (runs Steam in remote filesystem mode; requires Steam backend) // 2) -steamlocal (runs Steam in local filesystem mode (all content off HDD) Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_stdio.dll", executablePath, CORRECT_PATH_SEPARATOR ); if ( CommandLine()->FindParm( "-steam" ) || CommandLine()->FindParm( "-steamlocal" ) || _access( pFileSystemDLL, 0 ) != 0 ) { Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_steam.dll", executablePath, CORRECT_PATH_SEPARATOR ); bSteam = true; } #elif defined( _X360 ) Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_stdio.dll", executablePath, CORRECT_PATH_SEPARATOR ); #elif defined( _LINUX ) Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_i486.so", executablePath, CORRECT_PATH_SEPARATOR ); #else #error "define a filesystem dll name" #endif return FS_OK; }
FSReturnCode_t LoadGameInfoFile( const char *pDirectoryName, KeyValues *&pMainFile, KeyValues *&pFileSystemInfo, KeyValues *&pSearchPaths ) { // If GameInfo.txt exists under pBaseDir, then this is their game directory. // All the filesystem mappings will be in this file. char gameinfoFilename[MAX_PATH]; Q_strncpy( gameinfoFilename, pDirectoryName, sizeof( gameinfoFilename ) ); Q_AppendSlash( gameinfoFilename, sizeof( gameinfoFilename ) ); Q_strncat( gameinfoFilename, GAMEINFO_FILENAME, sizeof( gameinfoFilename ), COPY_ALL_CHARACTERS ); Q_FixSlashes( gameinfoFilename ); pMainFile = ReadKeyValuesFile( gameinfoFilename ); if ( IsX360() && !pMainFile ) { // try again Q_strncpy( gameinfoFilename, pDirectoryName, sizeof( gameinfoFilename ) ); Q_AppendSlash( gameinfoFilename, sizeof( gameinfoFilename ) ); Q_strncat( gameinfoFilename, GAMEINFO_FILENAME_ALTERNATE, sizeof( gameinfoFilename ), COPY_ALL_CHARACTERS ); Q_FixSlashes( gameinfoFilename ); pMainFile = ReadKeyValuesFile( gameinfoFilename ); } if ( !pMainFile ) { return SetupFileSystemError( true, FS_MISSING_GAMEINFO_FILE, "%s is missing.", gameinfoFilename ); } pFileSystemInfo = pMainFile->FindKey( "FileSystem" ); if ( !pFileSystemInfo ) { pMainFile->deleteThis(); return SetupFileSystemError( true, FS_INVALID_GAMEINFO_FILE, "%s is not a valid format.", gameinfoFilename ); } // Now read in all the search paths. pSearchPaths = pFileSystemInfo->FindKey( "SearchPaths" ); if ( !pSearchPaths ) { pMainFile->deleteThis(); return SetupFileSystemError( true, FS_INVALID_GAMEINFO_FILE, "%s is not a valid format.", gameinfoFilename ); } return FS_OK; }
FSReturnCode_t FileSystem_SetBasePaths( IFileSystem *pFileSystem ) { pFileSystem->RemoveSearchPaths( "EXECUTABLE_PATH" ); char executablePath[MAX_PATH]; if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); pFileSystem->AddSearchPath( executablePath, "EXECUTABLE_PATH" ); return FS_OK; }
FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo ) { if ( !initInfo.m_pFileSystem || !initInfo.m_pDirectoryName ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_LoadSearchPaths: Invalid parameters specified." ); KeyValues *pMainFile, *pFileSystemInfo, *pSearchPaths; FSReturnCode_t retVal = LoadGameInfoFile( initInfo.m_pDirectoryName, pMainFile, pFileSystemInfo, pSearchPaths ); if ( retVal != FS_OK ) return retVal; // All paths except those marked with |gameinfo_path| are relative to the base dir. char baseDir[MAX_PATH]; if ( !FileSystem_GetBaseDir( baseDir, sizeof( baseDir ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); // The MOD directory is always the one that contains gameinfo.txt Q_strncpy( initInfo.m_ModPath, initInfo.m_pDirectoryName, sizeof( initInfo.m_ModPath ) ); #define GAMEINFOPATH_TOKEN "|gameinfo_path|" #define BASESOURCEPATHS_TOKEN "|all_source_engine_paths|" const char *pszExtraSearchPath = CommandLine()->ParmValue( "-insert_search_path" ); if ( pszExtraSearchPath ) { CUtlStringList vecPaths; V_SplitString( pszExtraSearchPath, ",", vecPaths ); FOR_EACH_VEC( vecPaths, idxExtraPath ) { char szAbsSearchPath[MAX_PATH]; Q_StripPrecedingAndTrailingWhitespace( vecPaths[ idxExtraPath ] ); V_MakeAbsolutePath( szAbsSearchPath, sizeof( szAbsSearchPath ), vecPaths[ idxExtraPath ], baseDir ); V_FixSlashes( szAbsSearchPath ); if ( !V_RemoveDotSlashes( szAbsSearchPath ) ) Error( "Bad -insert_search_path - Can't resolve pathname for '%s'", szAbsSearchPath ); V_StripTrailingSlash( szAbsSearchPath ); FileSystem_AddLoadedSearchPath( initInfo, "GAME", szAbsSearchPath, false ); FileSystem_AddLoadedSearchPath( initInfo, "MOD", szAbsSearchPath, false ); } }
//----------------------------------------------------------------------------- // Mounds a particular steam cache //----------------------------------------------------------------------------- FSReturnCode_t FileSystem_MountContent( CFSMountContentInfo &mountContentInfo ) { // This part is Steam-only. if ( mountContentInfo.m_pFileSystem->IsSteam() ) { // Find out the "extra app id". This is for tools, which want to mount a base app's filesystem // like HL2, then mount the SDK content (tools materials and models, etc) in addition. int nExtraAppId = -1; if ( mountContentInfo.m_bToolsMode ) { FSReturnCode_t ret = GetSteamExtraAppId( mountContentInfo.m_pDirectoryName, &nExtraAppId ); if ( ret != FS_OK ) return ret; } // Set our working directory temporarily so Steam can remember it. // This is what Steam strips off absolute filenames like c:\program files\valve\steam\steamapps\username\sourcesdk // to get to the relative part of the path. char baseDir[MAX_PATH], oldWorkingDir[MAX_PATH]; if ( !FileSystem_GetBaseDir( baseDir, sizeof( baseDir ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); Q_getwd( oldWorkingDir, sizeof( oldWorkingDir ) ); _chdir( baseDir ); // Filesystem_tools needs to add dependencies in here beforehand. FilesystemMountRetval_t retVal = mountContentInfo.m_pFileSystem->MountSteamContent( nExtraAppId ); _chdir( oldWorkingDir ); if ( retVal != FILESYSTEM_MOUNT_OK ) return SetupFileSystemError( true, FS_UNABLE_TO_INIT, "Unable to mount Steam content in the file system" ); } return FileSystem_SetBasePaths( mountContentInfo.m_pFileSystem ); }
FSReturnCode_t LocateGameInfoFile( const CFSSteamSetupInfo &fsInfo, char *pOutDir, int outDirLen ) { // Engine and Hammer don't want to search around for it. if ( fsInfo.m_bOnlyUseDirectoryName ) { if ( !fsInfo.m_pDirectoryName ) return SetupFileSystemError( false, FS_MISSING_GAMEINFO_FILE, "bOnlyUseDirectoryName=1 and pDirectoryName=NULL." ); bool bExists = DoesFileExistIn( fsInfo.m_pDirectoryName, GAMEINFO_FILENAME ); if ( IsX360() && !bExists ) { bExists = DoesFileExistIn( fsInfo.m_pDirectoryName, GAMEINFO_FILENAME_ALTERNATE ); } if ( !bExists ) { if ( IsX360() && CommandLine()->FindParm( "-basedir" ) ) { char basePath[MAX_PATH]; strcpy( basePath, CommandLine()->ParmValue( "-basedir", "" ) ); Q_AppendSlash( basePath, sizeof( basePath ) ); Q_strncat( basePath, fsInfo.m_pDirectoryName, sizeof( basePath ), COPY_ALL_CHARACTERS ); if ( DoesFileExistIn( basePath, GAMEINFO_FILENAME ) ) { Q_strncpy( pOutDir, basePath, outDirLen ); return FS_OK; } if ( IsX360() && DoesFileExistIn( basePath, GAMEINFO_FILENAME_ALTERNATE ) ) { Q_strncpy( pOutDir, basePath, outDirLen ); return FS_OK; } } return SetupFileSystemError( true, FS_MISSING_GAMEINFO_FILE, "Setup file '%s' doesn't exist in subdirectory '%s'.\nCheck your -game parameter or VCONFIG setting.", GAMEINFO_FILENAME, fsInfo.m_pDirectoryName ); } Q_strncpy( pOutDir, fsInfo.m_pDirectoryName, outDirLen ); return FS_OK; } // First, check for overrides on the command line or environment variables. const char *pProject = GetVProjectCmdLineValue(); if ( pProject ) { if ( DoesFileExistIn( pProject, GAMEINFO_FILENAME ) ) { Q_MakeAbsolutePath( pOutDir, outDirLen, pProject ); return FS_OK; } if ( IsX360() && DoesFileExistIn( pProject, GAMEINFO_FILENAME_ALTERNATE ) ) { Q_MakeAbsolutePath( pOutDir, outDirLen, pProject ); return FS_OK; } if ( IsX360() && CommandLine()->FindParm( "-basedir" ) ) { char basePath[MAX_PATH]; strcpy( basePath, CommandLine()->ParmValue( "-basedir", "" ) ); Q_AppendSlash( basePath, sizeof( basePath ) ); Q_strncat( basePath, pProject, sizeof( basePath ), COPY_ALL_CHARACTERS ); if ( DoesFileExistIn( basePath, GAMEINFO_FILENAME ) ) { Q_strncpy( pOutDir, basePath, outDirLen ); return FS_OK; } if ( DoesFileExistIn( basePath, GAMEINFO_FILENAME_ALTERNATE ) ) { Q_strncpy( pOutDir, basePath, outDirLen ); return FS_OK; } } if ( fsInfo.m_bNoGameInfo ) { // fsInfo.m_bNoGameInfo is set by the Steam dedicated server, before it knows which mod to use. // Steam dedicated server doesn't need a gameinfo.txt, because we'll ask which mod to use, even if // -game is supplied on the command line. Q_strncpy( pOutDir, "", outDirLen ); return FS_OK; } else { // They either specified vproject on the command line or it's in their registry. Either way, // we don't want to continue if they've specified it but it's not valid. goto ShowError; } } if ( fsInfo.m_bNoGameInfo ) { Q_strncpy( pOutDir, "", outDirLen ); return FS_OK; } // Ask the application if it can provide us with a game info directory { bool bBubbleDir = true; SuggestGameInfoDirFn_t pfnSuggestGameInfoDirFn = GetSuggestGameInfoDirFn(); if ( pfnSuggestGameInfoDirFn && ( * pfnSuggestGameInfoDirFn )( &fsInfo, pOutDir, outDirLen, &bBubbleDir ) && FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, bBubbleDir ) ) return FS_OK; } // Try to use the environment variable / registry if ( ( pProject = getenv( GAMEDIR_TOKEN ) ) != NULL && ( Q_MakeAbsolutePath( pOutDir, outDirLen, pProject ), 1 ) && FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, false ) ) return FS_OK; if ( IsPC() ) { Warning( "Warning: falling back to auto detection of vproject directory.\n" ); // Now look for it in the directory they passed in. if ( fsInfo.m_pDirectoryName ) Q_MakeAbsolutePath( pOutDir, outDirLen, fsInfo.m_pDirectoryName ); else Q_MakeAbsolutePath( pOutDir, outDirLen, "." ); if ( FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, true ) ) return FS_OK; // Use the CWD Q_getwd( pOutDir, outDirLen ); if ( FS_OK == TryLocateGameInfoFile( pOutDir, outDirLen, true ) ) return FS_OK; } ShowError: return SetupFileSystemError( true, FS_MISSING_GAMEINFO_FILE, "Unable to find %s. Solutions:\n\n" "1. Read http://www.valve-erc.com/srcsdk/faq.html#NoGameDir\n" "2. Run vconfig to specify which game you're working on.\n" "3. Add -game <path> on the command line where <path> is the directory that %s is in.\n", GAMEINFO_FILENAME, GAMEINFO_FILENAME ); }
FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo ) { if ( !initInfo.m_pFileSystem || !initInfo.m_pDirectoryName ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_LoadSearchPaths: Invalid parameters specified." ); KeyValues *pMainFile, *pFileSystemInfo, *pSearchPaths; FSReturnCode_t retVal = LoadGameInfoFile( initInfo.m_pDirectoryName, pMainFile, pFileSystemInfo, pSearchPaths ); if ( retVal != FS_OK ) return retVal; // All paths except those marked with |gameinfo_path| are relative to the base dir. char baseDir[MAX_PATH]; if ( !FileSystem_GetBaseDir( baseDir, sizeof( baseDir ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); initInfo.m_ModPath[0] = 0; #define GAMEINFOPATH_TOKEN "|gameinfo_path|" #define BASESOURCEPATHS_TOKEN "|all_source_engine_paths|" bool bLowViolence = IsLowViolenceBuild(); bool bFirstGamePath = true; for ( KeyValues *pCur=pSearchPaths->GetFirstValue(); pCur; pCur=pCur->GetNextValue() ) { const char *pPathID = pCur->GetName(); const char *pLocation = pCur->GetString(); if ( Q_stristr( pLocation, GAMEINFOPATH_TOKEN ) == pLocation ) { pLocation += strlen( GAMEINFOPATH_TOKEN ); FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, initInfo.m_pDirectoryName, pLocation, bLowViolence ); } else if ( Q_stristr( pLocation, BASESOURCEPATHS_TOKEN ) == pLocation ) { // This is a special identifier that tells it to add the specified path for all source engine versions equal to or prior to this version. // So in Orange Box, if they specified: // |all_source_engine_paths|hl2 // it would add the ep2\hl2 folder and the base (ep1-era) hl2 folder. // // We need a special identifier in the gameinfo.txt here because the base hl2 folder exists in different places. // In the case of a game or a Steam-launched dedicated server, all the necessary prior engine content is mapped in with the Steam depots, // so we can just use the path as-is. // In the case of an hldsupdatetool dedicated server, the base hl2 folder is "..\..\hl2" (since we're up in the 'orangebox' folder). pLocation += strlen( BASESOURCEPATHS_TOKEN ); // Add the Orange-box path (which also will include whatever the depots mapped in as well if we're // running a Steam-launched app). FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, baseDir, pLocation, bLowViolence ); if ( FileSystem_IsHldsUpdateToolDedicatedServer() ) { // If we're using the hldsupdatetool dedicated server, then go up a directory to get the ep1-era files too. char ep1EraPath[MAX_PATH]; V_snprintf( ep1EraPath, sizeof( ep1EraPath ), "..%c%s", CORRECT_PATH_SEPARATOR, pLocation ); FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, baseDir, ep1EraPath, bLowViolence ); } } else { FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, baseDir, pLocation, bLowViolence ); } } pMainFile->deleteThis(); // // Set up search paths for add-ons // if ( IsPC() ) { #ifdef ENGINE_DLL FileSystem_UpdateAddonSearchPaths( initInfo.m_pFileSystem ); #endif } // these specialized tool paths are not used on 360 and cause a costly constant perf tax, so inhibited if ( IsPC() ) { // Create a content search path based on the game search path const char *pGameRoot = getenv( GAMEROOT_TOKEN ); const char *pContentRoot = getenv( CONTENTROOT_TOKEN ); if ( pGameRoot && pContentRoot ) { int nLen = initInfo.m_pFileSystem->GetSearchPath( "GAME", false, NULL, 0 ); char *pSearchPath = (char*)stackalloc( nLen * sizeof(char) ); initInfo.m_pFileSystem->GetSearchPath( "GAME", false, pSearchPath, nLen ); char *pPath = pSearchPath; while( pPath ) { char *pSemiColon = strchr( pPath, ';' ); if ( pSemiColon ) { *pSemiColon = 0; } Q_StripTrailingSlash( pPath ); Q_FixSlashes( pPath ); const char *pCurPath = pPath; pPath = pSemiColon ? pSemiColon + 1 : NULL; char pRelativePath[MAX_PATH]; char pContentPath[MAX_PATH]; if ( !Q_MakeRelativePath( pCurPath, pGameRoot, pRelativePath, sizeof(pRelativePath) ) ) continue; Q_ComposeFileName( pContentRoot, pRelativePath, pContentPath, sizeof(pContentPath) ); initInfo.m_pFileSystem->AddSearchPath( pContentPath, "CONTENT" ); } // Add the "platform" directory as a game searchable path char pPlatformPath[MAX_PATH]; Q_ComposeFileName( pGameRoot, "platform", pPlatformPath, sizeof(pPlatformPath) ); initInfo.m_pFileSystem->AddSearchPath( pPlatformPath, "GAME", PATH_ADD_TO_TAIL ); initInfo.m_pFileSystem->AddSearchPath( pContentRoot, "CONTENTROOT" ); initInfo.m_pFileSystem->AddSearchPath( pGameRoot, "GAMEROOT" ); } else { // Come up with some reasonable default int nLen = initInfo.m_pFileSystem->GetSearchPath( "MOD", false, NULL, 0 ); char *pSearchPath = (char*)stackalloc( nLen * sizeof(char) ); initInfo.m_pFileSystem->GetSearchPath( "MOD", false, pSearchPath, nLen ); char *pSemiColon = strchr( pSearchPath, ';' ); if ( pSemiColon ) { *pSemiColon = 0; } char pGameRootPath[MAX_PATH]; Q_strncpy( pGameRootPath, pSearchPath, sizeof(pGameRootPath) ); Q_StripTrailingSlash( pGameRootPath ); Q_StripFilename( pGameRootPath ); char pContentRootPath[MAX_PATH]; Q_strncpy( pContentRootPath, pGameRootPath, sizeof(pContentRootPath) ); char *pGame = Q_stristr( pContentRootPath, "game" ); if ( pGame ) { Q_strcpy( pGame, "content" ); } initInfo.m_pFileSystem->AddSearchPath( pContentRootPath, "CONTENTROOT" ); initInfo.m_pFileSystem->AddSearchPath( pGameRootPath, "GAMEROOT" ); } // Also, mark specific path IDs as "by request only". That way, we won't waste time searching in them // when people forget to specify a search path. initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "contentroot", true ); initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "gameroot", true ); initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "content", true ); } // Also, mark specific path IDs as "by request only". That way, we won't waste time searching in them // when people forget to specify a search path. initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "executable_path", true ); initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "gamebin", true ); initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "mod", true ); // Add the write path last. if ( initInfo.m_ModPath[0] != 0 ) { initInfo.m_pFileSystem->AddSearchPath( initInfo.m_ModPath, "DEFAULT_WRITE_PATH", PATH_ADD_TO_TAIL ); } #ifdef _DEBUG initInfo.m_pFileSystem->PrintSearchPaths(); #endif #if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) && !defined( _X360 ) //copy search paths to stack tools so it can grab pdb's from all over. But only on P4 or Steam Beta builds if( (CommandLine()->FindParm( "-steam" ) == 0) || //not steam (CommandLine()->FindParm( "-internalbuild" ) != 0) ) //steam beta is ok { char szSearchPaths[4096]; //int CBaseFileSystem::GetSearchPath( const char *pathID, bool bGetPackFiles, char *pPath, int nMaxLen ) int iLength1 = initInfo.m_pFileSystem->GetSearchPath( "EXECUTABLE_PATH", false, szSearchPaths, 4096 ); if( iLength1 == 1 ) iLength1 = 0; int iLength2 = initInfo.m_pFileSystem->GetSearchPath( "GAMEBIN", false, szSearchPaths + iLength1, 4096 - iLength1 ); if( (iLength2 > 1) && (iLength1 > 1) ) { szSearchPaths[iLength1 - 1] = ';'; //replace first null terminator } const char *szAdditionalPath = CommandLine()->ParmValue( "-AdditionalPDBSearchPath" ); if( szAdditionalPath && szAdditionalPath[0] ) { int iLength = iLength1; if( iLength2 > 1 ) iLength += iLength2; if( iLength != 0 ) { szSearchPaths[iLength - 1] = ';'; //replaces null terminator } V_strncpy( &szSearchPaths[iLength], szAdditionalPath, 4096 - iLength ); } //Append the perforce symbol server last. Documentation says that "srv*\\perforce\symbols" should work, but it doesn't. //"symsrv*symsrv.dll*\\perforce\symbols" which the docs say is the same statement, works. { V_strncat( szSearchPaths, ";symsrv*symsrv.dll*\\\\perforce\\symbols", 4096 ); } SetStackTranslationSymbolSearchPath( szSearchPaths ); //MessageBox( NULL, szSearchPaths, "Search Paths", 0 ); } #endif return FS_OK; }
FSReturnCode_t SetSteamInstallPath( char *steamInstallPath, int steamInstallPathLen, CSteamEnvVars &steamEnvVars, bool bErrorsAsWarnings ) { if ( IsConsole() ) { // consoles don't use steam return FS_MISSING_STEAM_DLL; } if ( IsPosix() ) return FS_OK; // under posix the content does not live with steam.dll up the path, rely on the environment already being set by steam // Start at our bin directory and move up until we find a directory with steam.dll in it. char executablePath[MAX_PATH]; if ( !FileSystem_GetExecutableDir( executablePath, sizeof( executablePath ) ) ) { if ( bErrorsAsWarnings ) { Warning( "SetSteamInstallPath: FileSystem_GetExecutableDir failed.\n" ); return FS_INVALID_PARAMETERS; } else { return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetExecutableDir failed." ); } } Q_strncpy( steamInstallPath, executablePath, steamInstallPathLen ); #ifdef WIN32 const char *pchSteamDLL = "steam.dll"; #elif defined(OSX) // under osx the bin lives in the bin/ folder, so step back one Q_StripLastDir( steamInstallPath, steamInstallPathLen ); const char *pchSteamDLL = "libsteam.dylib"; #elif defined(LINUX) // under linux the bin lives in the bin/ folder, so step back one Q_StripLastDir( steamInstallPath, steamInstallPathLen ); const char *pchSteamDLL = "libsteam.so"; #else #error #endif while ( 1 ) { // Ignore steamapp.cfg here in case they're debugging. We still need to know the real steam path so we can find their username. // find if ( DoesFileExistIn( steamInstallPath, pchSteamDLL ) && !DoesFileExistIn( steamInstallPath, "steamapp.cfg" ) ) break; if ( !Q_StripLastDir( steamInstallPath, steamInstallPathLen ) ) { if ( bErrorsAsWarnings ) { Warning( "Can't find %s relative to executable path: %s.\n", pchSteamDLL, executablePath ); return FS_MISSING_STEAM_DLL; } else { return SetupFileSystemError( false, FS_MISSING_STEAM_DLL, "Can't find %s relative to executable path: %s.", pchSteamDLL, executablePath ); } } } // Also, add the install path to their PATH environment variable, so filesystem_steam.dll can get to steam.dll. char szPath[ 8192 ]; steamEnvVars.m_Path.GetValue( szPath, sizeof( szPath ) ); if ( !DoesPathExistAlready( szPath, steamInstallPath ) ) { #ifdef WIN32 #define PATH_SEP ";" #else #define PATH_SEP ":" #endif steamEnvVars.m_Path.SetValue( "%s%s%s", szPath, PATH_SEP, steamInstallPath ); } return FS_OK; }
FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo ) { if ( !initInfo.m_pFileSystem || !initInfo.m_pDirectoryName ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_LoadSearchPaths: Invalid parameters specified." ); KeyValues *pMainFile, *pFileSystemInfo, *pSearchPaths; FSReturnCode_t retVal = LoadGameInfoFile( initInfo.m_pDirectoryName, pMainFile, pFileSystemInfo, pSearchPaths ); if ( retVal != FS_OK ) return retVal; // All paths except those marked with |gameinfo_path| are relative to the base dir. char baseDir[MAX_PATH]; if ( !FileSystem_GetBaseDir( baseDir, sizeof( baseDir ) ) ) return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." ); initInfo.m_ModPath[0] = 0; #define GAMEINFOPATH_TOKEN "|gameinfo_path|" #define BASESOURCEPATHS_TOKEN "|all_source_engine_paths|" bool bLowViolence = IsLowViolenceBuild(); bool bFirstGamePath = true; for ( KeyValues *pCur=pSearchPaths->GetFirstValue(); pCur; pCur=pCur->GetNextValue() ) { const char *pPathID = pCur->GetName(); const char *pLocation = pCur->GetString(); if ( Q_stristr( pLocation, GAMEINFOPATH_TOKEN ) == pLocation ) { pLocation += strlen( GAMEINFOPATH_TOKEN ); FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, initInfo.m_pDirectoryName, pLocation, bLowViolence ); } else if ( Q_stristr( pLocation, BASESOURCEPATHS_TOKEN ) == pLocation ) { // This is a special identifier that tells it to add the specified path for all source engine versions equal to or prior to this version. // So in Orange Box, if they specified: // |all_source_engine_paths|hl2 // it would add the ep2\hl2 folder and the base (ep1-era) hl2 folder. // // We need a special identifier in the gameinfo.txt here because the base hl2 folder exists in different places. // In the case of a game or a Steam-launched dedicated server, all the necessary prior engine content is mapped in with the Steam depots, // so we can just use the path as-is. // In the case of an hldsupdatetool dedicated server, the base hl2 folder is "..\..\hl2" (since we're up in the 'orangebox' folder). pLocation += strlen( BASESOURCEPATHS_TOKEN ); // Add the Orange-box path (which also will include whatever the depots mapped in as well if we're // running a Steam-launched app). FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, baseDir, pLocation, bLowViolence ); if ( FileSystem_IsHldsUpdateToolDedicatedServer() ) { // If we're using the hldsupdatetool dedicated server, then go up a directory to get the ep1-era files too. char ep1EraPath[MAX_PATH]; V_snprintf( ep1EraPath, sizeof( ep1EraPath ), "..%c%s", CORRECT_PATH_SEPARATOR, pLocation ); FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, baseDir, ep1EraPath, bLowViolence ); } } else { FileSystem_AddLoadedSearchPath( initInfo, pPathID, &bFirstGamePath, baseDir, pLocation, bLowViolence ); } } pMainFile->deleteThis(); // Also, mark specific path IDs as "by request only". That way, we won't waste time searching in them // when people forget to specify a search path. initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "executable_path", true ); initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "gamebin", true ); initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "mod", true ); if ( initInfo.m_ModPath[0] != 0 ) { // Add the write path last. initInfo.m_pFileSystem->AddSearchPath( initInfo.m_ModPath, "DEFAULT_WRITE_PATH", PATH_ADD_TO_TAIL ); } #ifdef _DEBUG initInfo.m_pFileSystem->PrintSearchPaths(); #endif return FS_OK; }