source-sdk-2013-mapbase/sp/src/public/filesystem_init.cpp
Joe Ludwig beaae8ac45 Updated the SDK with the latest code from the TF and HL2 branches
* Adds support for Visual Studio 2012 and 2013
* VR Mode:
. Switches from headtrack.dll to sourcevr.dll
. Improved readability of the UI in VR
. Removed the IPD calibration tool. TF2 will now obey the Oculus
configuration file. Use the Oculus calibration tool in your SDK or
install and run "OpenVR" under Tools in Steam to calibrate your IPD.
. Added dropdown to enable VR mode in the Video options. Removed the -vr
command line option.
. Added the ability to switch in and out of VR mode without quitting the
game
. By default VR mode will run full screen. To switch back to a
borderless window set the vr_force_windowed convar.
. Added support for VR mode on Linux
* Many assorted bug fixes and other changes from Team Fortress in
various shared files
2013-12-03 08:54:16 -08:00

1384 lines
43 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#undef PROTECTED_THINGS_ENABLE
#undef PROTECT_FILEIO_FUNCTIONS
#ifndef POSIX
#undef fopen
#endif
#if defined( _WIN32 ) && !defined( _X360 )
#include <windows.h>
#include <direct.h>
#include <io.h>
#include <process.h>
#elif defined( POSIX )
#include <unistd.h>
#define _chdir chdir
#define _access access
#endif
#include <stdio.h>
#include <sys/stat.h>
#include "tier1/strtools.h"
#include "tier1/utlbuffer.h"
#include "filesystem_init.h"
#include "tier0/icommandline.h"
#include "KeyValues.h"
#include "appframework/IAppSystemGroup.h"
#include "tier1/smartptr.h"
#if defined( _X360 )
#include "xbox\xbox_win32stubs.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
#if !defined( _X360 )
#define GAMEINFO_FILENAME "gameinfo.txt"
#else
// The .xtx file is a TCR requirement, as .txt files cannot live on the DVD.
// The .xtx file only exists outside the zips (same as .txt and is made during the image build) and is read to setup the search paths.
// So all other code should be able to safely expect gameinfo.txt after the zip is mounted as the .txt file exists inside the zips.
// The .xtx concept is private and should only have to occurr here. As a safety measure, if the .xtx file is not found
// a retry is made with the original .txt name
#define GAMEINFO_FILENAME "gameinfo.xtx"
#endif
#define GAMEINFO_FILENAME_ALTERNATE "gameinfo.txt"
static char g_FileSystemError[256];
static bool s_bUseVProjectBinDir = false;
static FSErrorMode_t g_FileSystemErrorMode = FS_ERRORMODE_VCONFIG;
// Call this to use a bin directory relative to VPROJECT
void FileSystem_UseVProjectBinDir( bool bEnable )
{
s_bUseVProjectBinDir = bEnable;
}
// This class lets you modify environment variables, and it restores the original value
// when it goes out of scope.
class CTempEnvVar
{
public:
CTempEnvVar( const char *pVarName )
{
m_bRestoreOriginalValue = true;
m_pVarName = pVarName;
const char *pValue = NULL;
#ifdef _WIN32
// Use GetEnvironmentVariable instead of getenv because getenv doesn't pick up changes
// to the process environment after the DLL was loaded.
char szBuf[ 4096 ];
if ( GetEnvironmentVariable( m_pVarName, szBuf, sizeof( szBuf ) ) != 0)
{
pValue = szBuf;
}
#else
// LINUX BUG: see above
pValue = getenv( pVarName );
#endif
if ( pValue )
{
m_bExisted = true;
m_OriginalValue.SetSize( strlen( pValue ) + 1 );
memcpy( m_OriginalValue.Base(), pValue, m_OriginalValue.Count() );
}
else
{
m_bExisted = false;
}
}
~CTempEnvVar()
{
if ( m_bRestoreOriginalValue )
{
// Restore the original value.
if ( m_bExisted )
{
SetValue( "%s", m_OriginalValue.Base() );
}
else
{
ClearValue();
}
}
}
void SetRestoreOriginalValue( bool bRestore )
{
m_bRestoreOriginalValue = bRestore;
}
int GetValue(char *pszBuf, int nBufSize )
{
if ( !pszBuf || ( nBufSize <= 0 ) )
return 0;
#ifdef _WIN32
// Use GetEnvironmentVariable instead of getenv because getenv doesn't pick up changes
// to the process environment after the DLL was loaded.
return GetEnvironmentVariable( m_pVarName, pszBuf, nBufSize );
#else
// LINUX BUG: see above
const char *pszOut = getenv( m_pVarName );
if ( !pszOut )
{
*pszBuf = '\0';
return 0;
}
Q_strncpy( pszBuf, pszOut, nBufSize );
return Q_strlen( pszBuf );
#endif
}
void SetValue( const char *pValue, ... )
{
char valueString[4096];
va_list marker;
va_start( marker, pValue );
Q_vsnprintf( valueString, sizeof( valueString ), pValue, marker );
va_end( marker );
#ifdef WIN32
char str[4096];
Q_snprintf( str, sizeof( str ), "%s=%s", m_pVarName, valueString );
_putenv( str );
#else
setenv( m_pVarName, valueString, 1 );
#endif
}
void ClearValue()
{
#ifdef WIN32
char str[512];
Q_snprintf( str, sizeof( str ), "%s=", m_pVarName );
_putenv( str );
#else
setenv( m_pVarName, "", 1 );
#endif
}
private:
bool m_bRestoreOriginalValue;
const char *m_pVarName;
bool m_bExisted;
CUtlVector<char> m_OriginalValue;
};
class CSteamEnvVars
{
public:
CSteamEnvVars() :
m_SteamAppId( "SteamAppId" ),
m_SteamUserPassphrase( "SteamUserPassphrase" ),
m_SteamAppUser( "SteamAppUser" ),
m_Path( "path" )
{
}
void SetRestoreOriginalValue_ALL( bool bRestore )
{
m_SteamAppId.SetRestoreOriginalValue( bRestore );
m_SteamUserPassphrase.SetRestoreOriginalValue( bRestore );
m_SteamAppUser.SetRestoreOriginalValue( bRestore );
m_Path.SetRestoreOriginalValue( bRestore );
}
CTempEnvVar m_SteamAppId;
CTempEnvVar m_SteamUserPassphrase;
CTempEnvVar m_SteamAppUser;
CTempEnvVar m_Path;
};
// ---------------------------------------------------------------------------------------------------- //
// Helpers.
// ---------------------------------------------------------------------------------------------------- //
void Q_getwd( char *out, int outSize )
{
#if defined( _WIN32 ) || defined( WIN32 )
_getcwd( out, outSize );
Q_strncat( out, "\\", outSize, COPY_ALL_CHARACTERS );
#else
getcwd( out, outSize );
strcat( out, "/" );
#endif
Q_FixSlashes( out );
}
// ---------------------------------------------------------------------------------------------------- //
// Module interface.
// ---------------------------------------------------------------------------------------------------- //
CFSSearchPathsInit::CFSSearchPathsInit()
{
m_pDirectoryName = NULL;
m_pLanguage = NULL;
m_ModPath[0] = 0;
m_bMountHDContent = m_bLowViolence = false;
}
CFSSteamSetupInfo::CFSSteamSetupInfo()
{
m_pDirectoryName = NULL;
m_bOnlyUseDirectoryName = false;
m_bSteam = false;
m_bToolsMode = true;
m_bNoGameInfo = false;
}
CFSLoadModuleInfo::CFSLoadModuleInfo()
{
m_pFileSystemDLLName = NULL;
m_pFileSystem = NULL;
m_pModule = NULL;
}
CFSMountContentInfo::CFSMountContentInfo()
{
m_bToolsMode = true;
m_pDirectoryName = NULL;
m_pFileSystem = NULL;
}
const char *FileSystem_GetLastErrorString()
{
return g_FileSystemError;
}
KeyValues* ReadKeyValuesFile( const char *pFilename )
{
// Read in the gameinfo.txt file and null-terminate it.
FILE *fp = fopen( pFilename, "rb" );
if ( !fp )
return NULL;
CUtlVector<char> buf;
fseek( fp, 0, SEEK_END );
buf.SetSize( ftell( fp ) + 1 );
fseek( fp, 0, SEEK_SET );
fread( buf.Base(), 1, buf.Count()-1, fp );
fclose( fp );
buf[buf.Count()-1] = 0;
KeyValues *kv = new KeyValues( "" );
if ( !kv->LoadFromBuffer( pFilename, buf.Base() ) )
{
kv->deleteThis();
return NULL;
}
return kv;
}
static bool Sys_GetExecutableName( char *out, int len )
{
#if defined( _WIN32 )
if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), out, len ) )
{
return false;
}
#else
if ( CommandLine()->GetParm(0) )
{
Q_MakeAbsolutePath( out, len, CommandLine()->GetParm(0) );
}
else
{
return false;
}
#endif
return true;
}
bool FileSystem_GetExecutableDir( char *exedir, int exeDirLen )
{
exedir[0] = 0;
if ( s_bUseVProjectBinDir )
{
const char *pProject = GetVProjectCmdLineValue();
if ( !pProject )
{
// Check their registry.
pProject = getenv( GAMEDIR_TOKEN );
}
if ( pProject )
{
Q_snprintf( exedir, exeDirLen, "%s%c..%cbin", pProject, CORRECT_PATH_SEPARATOR, CORRECT_PATH_SEPARATOR );
return true;
}
return false;
}
if ( !Sys_GetExecutableName( exedir, exeDirLen ) )
return false;
Q_StripFilename( exedir );
if ( IsX360() )
{
// The 360 can have its exe and dlls reside on different volumes
// use the optional basedir as the exe dir
if ( CommandLine()->FindParm( "-basedir" ) )
{
strcpy( exedir, CommandLine()->ParmValue( "-basedir", "" ) );
}
}
Q_FixSlashes( exedir );
// Return the bin directory as the executable dir if it's not in there
// because that's really where we're running from...
char ext[MAX_PATH];
Q_StrRight( exedir, 4, ext, sizeof( ext ) );
if ( ext[0] != CORRECT_PATH_SEPARATOR || Q_stricmp( ext+1, "bin" ) != 0 )
{
Q_strncat( exedir, CORRECT_PATH_SEPARATOR_S, exeDirLen, COPY_ALL_CHARACTERS );
Q_strncat( exedir, "bin", exeDirLen, COPY_ALL_CHARACTERS );
Q_FixSlashes( exedir );
}
return true;
}
static bool FileSystem_GetBaseDir( char *baseDir, int baseDirLen )
{
if ( FileSystem_GetExecutableDir( baseDir, baseDirLen ) )
{
Q_StripFilename( baseDir );
return true;
}
return false;
}
void LaunchVConfig()
{
#if defined( _WIN32 ) && !defined( _X360 )
char vconfigExe[MAX_PATH];
FileSystem_GetExecutableDir( vconfigExe, sizeof( vconfigExe ) );
Q_AppendSlash( vconfigExe, sizeof( vconfigExe ) );
Q_strncat( vconfigExe, "vconfig.exe", sizeof( vconfigExe ), COPY_ALL_CHARACTERS );
char *argv[] =
{
vconfigExe,
"-allowdebug",
NULL
};
_spawnv( _P_NOWAIT, vconfigExe, argv );
#elif defined( _X360 )
Msg( "Launching vconfig.exe not supported\n" );
#endif
}
const char* GetVProjectCmdLineValue()
{
return CommandLine()->ParmValue( "-vproject", CommandLine()->ParmValue( "-game" ) );
}
FSReturnCode_t SetupFileSystemError( bool bRunVConfig, FSReturnCode_t retVal, const char *pMsg, ... )
{
va_list marker;
va_start( marker, pMsg );
Q_vsnprintf( g_FileSystemError, sizeof( g_FileSystemError ), pMsg, marker );
va_end( marker );
Warning( "%s\n", g_FileSystemError );
// Run vconfig?
// Don't do it if they specifically asked for it not to, or if they manually specified a vconfig with -game or -vproject.
if ( bRunVConfig && g_FileSystemErrorMode == FS_ERRORMODE_VCONFIG && !CommandLine()->FindParm( CMDLINEOPTION_NOVCONFIG ) && !GetVProjectCmdLineValue() )
{
LaunchVConfig();
}
if ( g_FileSystemErrorMode == FS_ERRORMODE_AUTO || g_FileSystemErrorMode == FS_ERRORMODE_VCONFIG )
{
Error( "%s\n", g_FileSystemError );
}
return retVal;
}
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;
}
static void FileSystem_AddLoadedSearchPath(
CFSSearchPathsInit &initInfo,
const char *pPathID,
const char *fullLocationPath,
bool bLowViolence )
{
// Check for mounting LV game content in LV builds only
if ( V_stricmp( pPathID, "game_lv" ) == 0 )
{
// Not in LV build, don't mount
if ( !initInfo.m_bLowViolence )
return;
// Mount, as a game path
pPathID = "game";
}
// Check for mounting HD game content if enabled
if ( V_stricmp( pPathID, "game_hd" ) == 0 )
{
// Not in LV build, don't mount
if ( !initInfo.m_bMountHDContent )
return;
// Mount, as a game path
pPathID = "game";
}
// Special processing for ordinary game folders
if ( V_stristr( fullLocationPath, ".vpk" ) == NULL && Q_stricmp( pPathID, "game" ) == 0 )
{
if ( CommandLine()->FindParm( "-tempcontent" ) != 0 )
{
char szPath[MAX_PATH];
Q_snprintf( szPath, sizeof(szPath), "%s_tempcontent", fullLocationPath );
initInfo.m_pFileSystem->AddSearchPath( szPath, pPathID, PATH_ADD_TO_TAIL );
}
}
if ( initInfo.m_pLanguage &&
Q_stricmp( initInfo.m_pLanguage, "english" ) &&
V_strstr( fullLocationPath, "_english" ) != NULL )
{
char szPath[MAX_PATH];
char szLangString[MAX_PATH];
// Need to add a language version of this path first
Q_snprintf( szLangString, sizeof(szLangString), "_%s", initInfo.m_pLanguage);
V_StrSubst( fullLocationPath, "_english", szLangString, szPath, sizeof( szPath ), true );
initInfo.m_pFileSystem->AddSearchPath( szPath, pPathID, PATH_ADD_TO_TAIL );
}
initInfo.m_pFileSystem->AddSearchPath( fullLocationPath, pPathID, PATH_ADD_TO_TAIL );
}
static int SortStricmp( char * const * sz1, char * const * sz2 )
{
return V_stricmp( *sz1, *sz2 );
}
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 );
}
}
bool bLowViolence = initInfo.m_bLowViolence;
for ( KeyValues *pCur=pSearchPaths->GetFirstValue(); pCur; pCur=pCur->GetNextValue() )
{
const char *pLocation = pCur->GetString();
const char *pszBaseDir = baseDir;
if ( Q_stristr( pLocation, GAMEINFOPATH_TOKEN ) == pLocation )
{
pLocation += strlen( GAMEINFOPATH_TOKEN );
pszBaseDir = initInfo.m_pDirectoryName;
}
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.
pLocation += strlen( BASESOURCEPATHS_TOKEN );
}
CUtlStringList vecFullLocationPaths;
char szAbsSearchPath[MAX_PATH];
V_MakeAbsolutePath( szAbsSearchPath, sizeof( szAbsSearchPath ), pLocation, pszBaseDir );
// Now resolve any ./'s.
V_FixSlashes( szAbsSearchPath );
if ( !V_RemoveDotSlashes( szAbsSearchPath ) )
Error( "FileSystem_AddLoadedSearchPath - Can't resolve pathname for '%s'", szAbsSearchPath );
V_StripTrailingSlash( szAbsSearchPath );
// Don't bother doing any wildcard expansion unless it has wildcards. This avoids the weird
// thing with xxx_dir.vpk files being referred to simply as xxx.vpk.
if ( V_stristr( pLocation, "?") == NULL && V_stristr( pLocation, "*") == NULL )
{
vecFullLocationPaths.CopyAndAddToTail( szAbsSearchPath );
}
else
{
FileFindHandle_t findHandle = NULL;
const char *pszFoundShortName = initInfo.m_pFileSystem->FindFirst( szAbsSearchPath, &findHandle );
if ( pszFoundShortName )
{
do
{
// We only know how to mount VPK's and directories
if ( pszFoundShortName[0] != '.' && ( initInfo.m_pFileSystem->FindIsDirectory( findHandle ) || V_stristr( pszFoundShortName, ".vpk" ) ) )
{
char szAbsName[MAX_PATH];
V_ExtractFilePath( szAbsSearchPath, szAbsName, sizeof( szAbsName ) );
V_AppendSlash( szAbsName, sizeof(szAbsName) );
V_strcat_safe( szAbsName, pszFoundShortName );
vecFullLocationPaths.CopyAndAddToTail( szAbsName );
// Check for a common mistake
if (
!V_stricmp( pszFoundShortName, "materials" )
|| !V_stricmp( pszFoundShortName, "maps" )
|| !V_stricmp( pszFoundShortName, "resource" )
|| !V_stricmp( pszFoundShortName, "scripts" )
|| !V_stricmp( pszFoundShortName, "sound" )
|| !V_stricmp( pszFoundShortName, "models" ) )
{
char szReadme[MAX_PATH];
V_ExtractFilePath( szAbsSearchPath, szReadme, sizeof( szReadme ) );
V_AppendSlash( szReadme, sizeof(szReadme) );
V_strcat_safe( szReadme, "readme.txt" );
Error(
"Tried to add %s as a search path.\n"
"\nThis is probably not what you intended.\n"
"\nCheck %s for more info\n",
szAbsName, szReadme );
}
}
pszFoundShortName = initInfo.m_pFileSystem->FindNext( findHandle );
} while ( pszFoundShortName );
initInfo.m_pFileSystem->FindClose( findHandle );
}
// Sort alphabetically. Also note that this will put
// all the xxx_000.vpk packs just before the corresponding
// xxx_dir.vpk
vecFullLocationPaths.Sort( SortStricmp );
// Now for any _dir.vpk files, remove the _nnn.vpk ones.
int idx = vecFullLocationPaths.Count()-1;
while ( idx > 0 )
{
char szTemp[ MAX_PATH ];
V_strcpy_safe( szTemp, vecFullLocationPaths[ idx ] );
--idx;
char *szDirVpk = V_stristr( szTemp, "_dir.vpk" );
if ( szDirVpk != NULL )
{
*szDirVpk = '\0';
while ( idx >= 0 )
{
char *pszPath = vecFullLocationPaths[ idx ];
if ( V_stristr( pszPath, szTemp ) != pszPath )
break;
delete pszPath;
vecFullLocationPaths.Remove( idx );
--idx;
}
}
}
}
// Parse Path ID list
CUtlStringList vecPathIDs;
V_SplitString( pCur->GetName(), "+", vecPathIDs );
FOR_EACH_VEC( vecPathIDs, idxPathID )
{
Q_StripPrecedingAndTrailingWhitespace( vecPathIDs[ idxPathID ] );
}
// Mount them.
FOR_EACH_VEC( vecFullLocationPaths, idxLocation )
{
FOR_EACH_VEC( vecPathIDs, idxPathID )
{
FileSystem_AddLoadedSearchPath( initInfo, vecPathIDs[ idxPathID ], vecFullLocationPaths[ idxLocation ], 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( "download", true );
initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "mod", true );
initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "game_write", true );
initInfo.m_pFileSystem->MarkPathIDByRequestOnly( "mod_write", true );
#ifdef _DEBUG
// initInfo.m_pFileSystem->PrintSearchPaths();
#endif
return FS_OK;
}
bool DoesFileExistIn( const char *pDirectoryName, const char *pFilename )
{
char filename[MAX_PATH];
Q_strncpy( filename, pDirectoryName, sizeof( filename ) );
Q_AppendSlash( filename, sizeof( filename ) );
Q_strncat( filename, pFilename, sizeof( filename ), COPY_ALL_CHARACTERS );
Q_FixSlashes( filename );
bool bExist = ( _access( filename, 0 ) == 0 );
return ( bExist );
}
namespace
{
SuggestGameInfoDirFn_t & GetSuggestGameInfoDirFn( void )
{
static SuggestGameInfoDirFn_t s_pfnSuggestGameInfoDir = NULL;
return s_pfnSuggestGameInfoDir;
}
}; // `anonymous` namespace
SuggestGameInfoDirFn_t SetSuggestGameInfoDirFn( SuggestGameInfoDirFn_t pfnNewFn )
{
SuggestGameInfoDirFn_t &rfn = GetSuggestGameInfoDirFn();
SuggestGameInfoDirFn_t pfnOldFn = rfn;
rfn = pfnNewFn;
return pfnOldFn;
}
static FSReturnCode_t TryLocateGameInfoFile( char *pOutDir, int outDirLen, bool bBubbleDir )
{
// Retain a copy of suggested path for further attempts
CArrayAutoPtr < char > spchCopyNameBuffer( new char [ outDirLen ] );
Q_strncpy( spchCopyNameBuffer.Get(), pOutDir, outDirLen );
spchCopyNameBuffer[ outDirLen - 1 ] = 0;
// Make appropriate slashes ('/' - Linux style)
for ( char *pchFix = spchCopyNameBuffer.Get(),
*pchEnd = pchFix + outDirLen;
pchFix < pchEnd; ++ pchFix )
{
if ( '\\' == *pchFix )
{
*pchFix = '/';
}
}
// Have a look in supplied path
do
{
if ( DoesFileExistIn( pOutDir, GAMEINFO_FILENAME ) )
{
return FS_OK;
}
if ( IsX360() && DoesFileExistIn( pOutDir, GAMEINFO_FILENAME_ALTERNATE ) )
{
return FS_OK;
}
}
while ( bBubbleDir && Q_StripLastDir( pOutDir, outDirLen ) );
// Make an attempt to resolve from "content -> game" directory
Q_strncpy( pOutDir, spchCopyNameBuffer.Get(), outDirLen );
pOutDir[ outDirLen - 1 ] = 0;
if ( char *pchContentFix = Q_stristr( pOutDir, "/content/" ) )
{
sprintf( pchContentFix, "/game/" );
memmove( pchContentFix + 6, pchContentFix + 9, pOutDir + outDirLen - (pchContentFix + 9) );
// Try in the mapped "game" directory
do
{
if ( DoesFileExistIn( pOutDir, GAMEINFO_FILENAME ) )
{
return FS_OK;
}
if ( IsX360() && DoesFileExistIn( pOutDir, GAMEINFO_FILENAME_ALTERNATE ) )
{
return FS_OK;
}
}
while ( bBubbleDir && Q_StripLastDir( pOutDir, outDirLen ) );
}
// Could not find it here
return FS_MISSING_GAMEINFO_FILE;
}
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 );
}
bool DoesPathExistAlready( const char *pPathEnvVar, const char *pTestPath )
{
// Fix the slashes in the input arguments.
char correctedPathEnvVar[8192], correctedTestPath[MAX_PATH];
Q_strncpy( correctedPathEnvVar, pPathEnvVar, sizeof( correctedPathEnvVar ) );
Q_FixSlashes( correctedPathEnvVar );
pPathEnvVar = correctedPathEnvVar;
Q_strncpy( correctedTestPath, pTestPath, sizeof( correctedTestPath ) );
Q_FixSlashes( correctedTestPath );
if ( strlen( correctedTestPath ) > 0 && PATHSEPARATOR( correctedTestPath[strlen(correctedTestPath)-1] ) )
correctedTestPath[ strlen(correctedTestPath) - 1 ] = 0;
pTestPath = correctedTestPath;
const char *pCurPos = pPathEnvVar;
while ( 1 )
{
const char *pTestPos = Q_stristr( pCurPos, pTestPath );
if ( !pTestPos )
return false;
// Ok, we found pTestPath in the path, but it's only valid if it's followed by an optional slash and a semicolon.
pTestPos += strlen( pTestPath );
if ( pTestPos[0] == 0 || pTestPos[0] == ';' || (PATHSEPARATOR( pTestPos[0] ) && pTestPos[1] == ';') )
return true;
// Advance our marker..
pCurPos = pTestPos;
}
}
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_EXT_STRING;
#elif defined(POSIX)
// under osx the bin lives in the bin/ folder, so step back one
Q_StripLastDir( steamInstallPath, steamInstallPathLen );
const char *pchSteamDLL = "libsteam" DLL_EXT_STRING;
#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 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;
}
void SetSteamAppUser( KeyValues *pSteamInfo, const char *steamInstallPath, CSteamEnvVars &steamEnvVars )
{
// Always inherit the Steam user if it's already set, since it probably means we (or the
// the app that launched us) were launched from Steam.
char appUser[MAX_PATH];
if ( steamEnvVars.m_SteamAppUser.GetValue( appUser, sizeof( appUser ) ) )
return;
const char *pTempAppUser = NULL;
if ( pSteamInfo && (pTempAppUser = pSteamInfo->GetString( "SteamAppUser", NULL )) != NULL )
{
Q_strncpy( appUser, pTempAppUser, sizeof( appUser ) );
}
else
{
// They don't have SteamInfo.txt, or it's missing SteamAppUser. Try to figure out the user
// by looking in <steam install path>\config\SteamAppData.vdf.
char fullFilename[MAX_PATH];
Q_strncpy( fullFilename, steamInstallPath, sizeof( fullFilename ) );
Q_AppendSlash( fullFilename, sizeof( fullFilename ) );
Q_strncat( fullFilename, "config\\SteamAppData.vdf", sizeof( fullFilename ), COPY_ALL_CHARACTERS );
KeyValues *pSteamAppData = ReadKeyValuesFile( fullFilename );
if ( !pSteamAppData || (pTempAppUser = pSteamAppData->GetString( "AutoLoginUser", NULL )) == NULL )
{
Error( "Can't find steam app user info." );
}
Q_strncpy( appUser, pTempAppUser, sizeof( appUser ) );
pSteamAppData->deleteThis();
}
Q_strlower( appUser );
steamEnvVars.m_SteamAppUser.SetValue( "%s", appUser );
}
void SetSteamUserPassphrase( KeyValues *pSteamInfo, CSteamEnvVars &steamEnvVars )
{
// Always inherit the passphrase if it's already set, since it probably means we (or the
// the app that launched us) were launched from Steam.
char szPassPhrase[ MAX_PATH ];
if ( steamEnvVars.m_SteamUserPassphrase.GetValue( szPassPhrase, sizeof( szPassPhrase ) ) )
return;
// SteamUserPassphrase.
const char *pStr;
if ( pSteamInfo && (pStr = pSteamInfo->GetString( "SteamUserPassphrase", NULL )) != NULL )
{
steamEnvVars.m_SteamUserPassphrase.SetValue( "%s", pStr );
}
}
FSReturnCode_t SetupSteamStartupEnvironment( KeyValues *pFileSystemInfo, const char *pGameInfoDirectory, CSteamEnvVars &steamEnvVars )
{
// Ok, we're going to run Steam. See if they have SteamInfo.txt. If not, we'll try to deduce what we can.
char steamInfoFile[MAX_PATH];
Q_strncpy( steamInfoFile, pGameInfoDirectory, sizeof( steamInfoFile ) );
Q_AppendSlash( steamInfoFile, sizeof( steamInfoFile ) );
Q_strncat( steamInfoFile, "steaminfo.txt", sizeof( steamInfoFile ), COPY_ALL_CHARACTERS );
KeyValues *pSteamInfo = ReadKeyValuesFile( steamInfoFile );
char steamInstallPath[MAX_PATH];
FSReturnCode_t ret = SetSteamInstallPath( steamInstallPath, sizeof( steamInstallPath ), steamEnvVars, false );
if ( ret != FS_OK )
return ret;
SetSteamAppUser( pSteamInfo, steamInstallPath, steamEnvVars );
SetSteamUserPassphrase( pSteamInfo, steamEnvVars );
if ( pSteamInfo )
pSteamInfo->deleteThis();
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" );
if ( !FileSystem_GetBaseDir( executablePath, sizeof( executablePath ) ) )
return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "FileSystem_GetBaseDir failed." );
pFileSystem->AddSearchPath( executablePath, "BASE_PATH" );
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." );
// Assume we'll use local files
Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_stdio" DLL_EXT_STRING, executablePath, CORRECT_PATH_SEPARATOR );
#if !defined( _X360 )
// Use filsystem_steam if it exists?
#if defined( OSX ) || defined( LINUX )
struct stat statBuf;
#endif
if (
#if defined( OSX ) || defined( LINUX )
stat( pFileSystemDLL, &statBuf ) != 0
#else
_access( pFileSystemDLL, 0 ) != 0
#endif
) {
Q_snprintf( pFileSystemDLL, nMaxLen, "%s%cfilesystem_steam" DLL_EXT_STRING, executablePath, CORRECT_PATH_SEPARATOR );
bSteam = true;
}
#endif
return FS_OK;
}
//-----------------------------------------------------------------------------
// Sets up the steam.dll install path in our PATH env var (so you can then just
// LoadLibrary() on filesystem_steam.dll without having to copy steam.dll anywhere special )
//-----------------------------------------------------------------------------
FSReturnCode_t FileSystem_SetupSteamInstallPath()
{
CSteamEnvVars steamEnvVars;
char steamInstallPath[MAX_PATH];
FSReturnCode_t ret = SetSteamInstallPath( steamInstallPath, sizeof( steamInstallPath ), steamEnvVars, true );
steamEnvVars.m_Path.SetRestoreOriginalValue( false ); // We want to keep the change to the path going forward.
return ret;
}
//-----------------------------------------------------------------------------
// Sets up the steam environment + gets back the gameinfo.txt path
//-----------------------------------------------------------------------------
FSReturnCode_t FileSystem_SetupSteamEnvironment( CFSSteamSetupInfo &fsInfo )
{
// First, locate the directory with gameinfo.txt.
FSReturnCode_t ret = LocateGameInfoFile( fsInfo, fsInfo.m_GameInfoPath, sizeof( fsInfo.m_GameInfoPath ) );
if ( ret != FS_OK )
return ret;
// This is so that processes spawned by this application will have the same VPROJECT
#ifdef WIN32
char pEnvBuf[MAX_PATH+32];
Q_snprintf( pEnvBuf, sizeof(pEnvBuf), "%s=%s", GAMEDIR_TOKEN, fsInfo.m_GameInfoPath );
_putenv( pEnvBuf );
#else
setenv( GAMEDIR_TOKEN, fsInfo.m_GameInfoPath, 1 );
#endif
CSteamEnvVars steamEnvVars;
if ( fsInfo.m_bSteam )
{
if ( fsInfo.m_bToolsMode )
{
// Now, load gameinfo.txt (to make sure it's there)
KeyValues *pMainFile, *pFileSystemInfo, *pSearchPaths;
ret = LoadGameInfoFile( fsInfo.m_GameInfoPath, pMainFile, pFileSystemInfo, pSearchPaths );
if ( ret != FS_OK )
return ret;
// 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)
// Setup all the environment variables related to Steam so filesystem_steam.dll knows how to initialize Steam.
ret = SetupSteamStartupEnvironment( pFileSystemInfo, fsInfo.m_GameInfoPath, steamEnvVars );
if ( ret != FS_OK )
return ret;
steamEnvVars.m_SteamAppId.SetRestoreOriginalValue( false ); // We want to keep the change to the path going forward.
// We're done with main file
pMainFile->deleteThis();
}
else if ( fsInfo.m_bSetSteamDLLPath )
{
// This is used by the engine to automatically set the path to their steam.dll when running the engine,
// so they can debug it without having to copy steam.dll up into their hl2.exe folder.
char steamInstallPath[MAX_PATH];
ret = SetSteamInstallPath( steamInstallPath, sizeof( steamInstallPath ), steamEnvVars, true );
steamEnvVars.m_Path.SetRestoreOriginalValue( false ); // We want to keep the change to the path going forward.
}
}
return FS_OK;
}
//-----------------------------------------------------------------------------
// 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;
}
//-----------------------------------------------------------------------------
// Mounds a particular steam cache
//-----------------------------------------------------------------------------
FSReturnCode_t FileSystem_MountContent( CFSMountContentInfo &mountContentInfo )
{
// This part is Steam-only.
if ( mountContentInfo.m_pFileSystem->IsSteam() )
{
return SetupFileSystemError( false, FS_INVALID_PARAMETERS, "Should not be using filesystem_steam anymore!" );
// // 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 )
// {
// // !FIXME! Here we need to mount the tools content (VPK's) in some way...?
// }
//
// // 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 );
}
void FileSystem_SetErrorMode( FSErrorMode_t errorMode )
{
g_FileSystemErrorMode = errorMode;
}
void FileSystem_ClearSteamEnvVars()
{
CSteamEnvVars envVars;
// Change the values and don't restore the originals.
envVars.m_SteamAppId.SetValue( "" );
envVars.m_SteamUserPassphrase.SetValue( "" );
envVars.m_SteamAppUser.SetValue( "" );
envVars.SetRestoreOriginalValue_ALL( false );
}
//-----------------------------------------------------------------------------
// Adds the platform folder to the search path.
//-----------------------------------------------------------------------------
void FileSystem_AddSearchPath_Platform( IFileSystem *pFileSystem, const char *szGameInfoPath )
{
char platform[MAX_PATH];
Q_strncpy( platform, szGameInfoPath, MAX_PATH );
Q_StripTrailingSlash( platform );
Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH );
pFileSystem->AddSearchPath( platform, "PLATFORM" );
}