Skip to content

Commit 663aaa7

Browse files
committed
1 parent b6d471e commit 663aaa7

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed

game/quiver/info_changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Added the following Source SDK Pull Requests:
7575
- #1506: Make Killfeed use the Assisters team color if applicable instead of always using the Killers team color
7676
- #1508: Add C_BaseEntity::CanGlow to opt-out of glowing for Sentry Gun shield
7777
- #1509: Fix reanimator fast revive exploit
78+
- #1512: Explain client crash reason when malicious server sends CUtlVector length out of allowed range
7879

7980
Details:
8081
- Fixed a bug where the mini-crit damage effect doesn't show up when your shield breaks.

src/public/filesystem_init.cpp

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,174 @@ const Source1AppidInfo_t *GetKnownAppidInfo( uint32 nAppid )
640640
return nullptr;
641641
}
642642

643+
#ifdef BDSBASE
644+
#ifndef ENGINE_DLL
645+
//---------------------------------------------------------------------------------------------
646+
// Purpose: This function gets the Steam installation path. Calls for platform specific things.
647+
//---------------------------------------------------------------------------------------------
648+
static const char *GetSteamInstallationPath()
649+
{
650+
// Steam path to pass over
651+
static char szSteamPath[1024] = {};
652+
#ifdef WIN32
653+
// Open the registry to look for the Steam installation.
654+
HKEY hKey = nullptr;
655+
LSTATUS status = RegOpenKeyEx(
656+
HKEY_CURRENT_USER,
657+
TEXT( "SOFTWARE\\Valve\\Steam" ),
658+
0,
659+
KEY_READ,
660+
&hKey );
661+
662+
// Check result
663+
if( status != ERROR_SUCCESS )
664+
return nullptr;
665+
666+
// Query the SteamPath key
667+
char szPathBuf[1024] = {};
668+
DWORD dwBufSize = sizeof( szPathBuf );
669+
DWORD dwType = 0;
670+
LSTATUS result = RegQueryValueEx(
671+
hKey,
672+
"SteamPath",
673+
NULL,
674+
&dwType,
675+
reinterpret_cast<BYTE*>( szPathBuf ),
676+
&dwBufSize );
677+
678+
// check for the result
679+
if( result != ERROR_SUCCESS )
680+
return nullptr;
681+
682+
// Close the registry key, we're done with it
683+
RegCloseKey( hKey );
684+
685+
// Put this in the steam path var.
686+
Q_strncpy( szSteamPath, szPathBuf, sizeof( szSteamPath ) );
687+
#else
688+
// No registry on Linux, look for the symlink.
689+
const char *pszHomeDir = getenv( "HOME" );
690+
const char *pszSteamPath = "/.steam/steam";
691+
Q_snprintf( szSteamPath, sizeof( szSteamPath ), "%s%s", pszHomeDir, pszSteamPath );
692+
#endif // WIN32 ELSE !WIN32
693+
return szSteamPath;
694+
}
695+
696+
//-----------------------------------------------------------------------------
697+
// Purpose: Function for mod based projects to find installed game directories
698+
// Since non-engine mods don't have access to SteamApps, they can use this.
699+
// This goes through three steps:
700+
// 1. Finds the main Steam installation in GetSteamInstallationPath (queries registry on Windows, checks through symlink on others)
701+
// 2. Parse the libraryfolders.vdf file in Steam's config folder to find the appID
702+
// 3. Find the appmanifest_appID.acf file and look for the name. If so, return the folder name
703+
// Note: Slashes are fixed right before it's returned.
704+
// Input: game appID
705+
// Output: returns the install directory IF it's installed, otherwise returns nullptr
706+
//-----------------------------------------------------------------------------
707+
static const char *GetAppInstallDirNoSteam( int nAppID )
708+
{
709+
// First, get the Steam installation.
710+
char szSteamPath[1024] = {};
711+
Q_strncpy( szSteamPath, GetSteamInstallationPath(), sizeof( szSteamPath ) );
712+
if( !szSteamPath || szSteamPath[0] == '\0' )
713+
return nullptr;
714+
715+
// Second, go to the libraryfolders.vdf and look if the appid is in them.
716+
char szLibraryFoldersFile[1024] = {};
717+
Q_snprintf( szLibraryFoldersFile, sizeof( szLibraryFoldersFile ), "%s%s", szSteamPath, "/config/libraryfolders.vdf" );
718+
719+
// NOTE: ReadKeyValuesFile already deletes the KV if it doesn't exist
720+
// read the libraryfolders.vdf file
721+
KeyValues *pRootKV = ReadKeyValuesFile( szLibraryFoldersFile );
722+
if( !pRootKV )
723+
return nullptr;
724+
725+
// Get a string representation of the Steam AppID passed
726+
char szAppID[32] = {};
727+
Q_snprintf( szAppID, sizeof( szAppID ), "%d", nAppID );
728+
729+
// Path KV
730+
KeyValues *pPathKV = nullptr;
731+
732+
// Go thru each possible install path until we find the app.
733+
FOR_EACH_TRUE_SUBKEY( pRootKV, pKVPath )
734+
{
735+
// Check for the apps subkey
736+
KeyValues *pApps = pKVPath->FindKey( "apps" );
737+
if( !pApps )
738+
continue;
739+
740+
// Try to find the appid path
741+
if( pApps->FindKey( szAppID ) )
742+
{
743+
// Okay, we found the app id key. now use the path key from the root KV
744+
pPathKV = pKVPath->FindKey( "path" ); // This is null checked below.
745+
break;
746+
}
747+
}
748+
749+
// Error out if we can't find it
750+
if( !pPathKV )
751+
return nullptr;
752+
753+
// Look for the game that this mod asked for
754+
char szInstallationPath[1024] = {};
755+
// copy this string over since we're gonna delete the KV
756+
Q_strncpy( szInstallationPath, pPathKV->GetString(), sizeof( szInstallationPath ) );
757+
// If it's empty somehow, error out
758+
if( !szInstallationPath || szInstallationPath[0] == '\0' )
759+
{
760+
// Clear this keyvalue.
761+
pRootKV->deleteThis();
762+
pRootKV = nullptr;
763+
return nullptr;
764+
}
765+
766+
// we no longer need this KV
767+
pRootKV->deleteThis();
768+
pRootKV = nullptr;
769+
770+
// get the appmanifest_APPID.acf file
771+
char szAppManifestPath[1024] = {};
772+
Q_snprintf( szAppManifestPath, sizeof( szAppManifestPath ), "%s%s%s.acf", szInstallationPath, "/steamapps/appmanifest_", szAppID );
773+
// Reuse the root pointer to open the appmanifest file
774+
pRootKV = ReadKeyValuesFile( szAppManifestPath );
775+
776+
// Error out if this file can't be found
777+
if( !pRootKV )
778+
return nullptr;
779+
780+
// Find the install dir
781+
KeyValues *pInstallDirKV = pRootKV->FindKey( "installdir" );
782+
783+
// Error out if we can't find this key
784+
if( !pInstallDirKV )
785+
return nullptr;
786+
787+
// Get the game name to get it from the common dir.
788+
// Again, deleting the KV after this
789+
char szGameName[256] = {};
790+
Q_strncpy( szGameName, pInstallDirKV->GetString(), sizeof( szGameName ) );
791+
792+
if( !szGameName || szGameName[0] == '\0' )
793+
return nullptr;
794+
795+
// Not needed anymore
796+
pRootKV->deleteThis();
797+
pRootKV = nullptr;
798+
799+
// Now that we got everything, put it all together
800+
static char szAbsoluteGameDirPath[1024] = {};
801+
Q_snprintf( szAbsoluteGameDirPath, sizeof( szAbsoluteGameDirPath ), "%s%s%s", szInstallationPath, "/common/", szGameName );
802+
803+
// Fix the slashes before passing it
804+
V_FixDoubleSlashes( szAbsoluteGameDirPath );
805+
V_FixSlashes( szAbsoluteGameDirPath );
806+
return szAbsoluteGameDirPath;
807+
}
808+
#endif // ENGINE_DLL
809+
#endif
810+
643811
FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo )
644812
{
645813
if ( !initInfo.m_pFileSystem || !initInfo.m_pDirectoryName )
@@ -687,15 +855,86 @@ FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo )
687855
const char *pszPathID = pCur->GetName();
688856
const char *pLocation = pCur->GetString();
689857
const char *pszBaseDir = baseDir;
858+
#ifndef BDSBASE
690859
#ifdef ENGINE_DLL
691860
char szAppInstallDir[ 1024 ];
861+
#endif
692862
#endif
693863

694864
if ( !FileSystem_AllowedSearchPath( pLocation ) )
695865
continue;
696866

697867
if ( Q_stristr( pLocation, APPID_PREFIX_TOKEN ) == pLocation )
698868
{
869+
#ifdef BDSBASE
870+
Location += strlen( APPID_PREFIX_TOKEN );
871+
const char *pNumberLoc = pLocation;
872+
int nAppId = V_atoi( pNumberLoc );
873+
pLocation = Q_stristr( pLocation, "|" );
874+
if ( !pLocation )
875+
{
876+
Error( "Malformed gameinfo.txt" );
877+
}
878+
pLocation += strlen( "|" );
879+
880+
if ( !nAppId )
881+
{
882+
Error( "Can't mount content from invalid appid." );
883+
}
884+
885+
// Get the known appid info
886+
const Source1AppidInfo_t *pKnownAppid = GetKnownAppidInfo( nAppId );
887+
const char *pszAppName = pKnownAppid ? pKnownAppid->pszName : "Unknown";
888+
889+
// Store the app install directory here.
890+
char szAppInstallDir[1024] = {};
891+
#ifdef ENGINE_DLL
892+
if ( !SteamApps() )
893+
{
894+
Error( "No SteamApps connection." );
895+
}
896+
897+
if ( !SteamApps()->BIsSubscribedApp( nAppId ) )
898+
{
899+
char szStoreCommand[4096];
900+
V_sprintf_safe( szStoreCommand, "steam://store/%d", nAppId );
901+
Plat_OpenURL( szStoreCommand );
902+
903+
Error( "This mod requires that you own %s (%d). Please purchase it, and install it to play this mod.", pszAppName, nAppId );
904+
}
905+
906+
if ( !SteamApps()->BIsAppInstalled( nAppId ) )
907+
{
908+
char szInstallCommand[4096];
909+
V_sprintf_safe( szInstallCommand, "steam://install/%d", nAppId );
910+
Plat_OpenURL( szInstallCommand );
911+
912+
Error( "This mod requires %s (%d) to be installed. Please install it to play this mod.", pszAppName, nAppId );
913+
}
914+
915+
uint32 unLength = SteamApps()->GetAppInstallDir( nAppId, szAppInstallDir, sizeof( szAppInstallDir ) );
916+
if ( !unLength )
917+
{
918+
Error( "Couldn't get install dir for appid: %d", nAppId );
919+
}
920+
#else
921+
// Get the install directory.
922+
const char *pszAppDir = GetAppInstallDirNoSteam( nAppId );
923+
if( !pszAppDir || pszAppDir[0] == '\0' )
924+
{
925+
// Tell them to install this mod, but we don't have SteamApps here, so let them see the
926+
// "no licenses error" if they don't own this game.
927+
char szInstallCommand[4096] = {};
928+
V_sprintf_safe( szInstallCommand, "steam://install/%d", nAppId );
929+
Plat_OpenURL( szInstallCommand );
930+
Error( "This mod requires %s (%d) to be installed. Please install it to play this mod.", pszAppName, nAppId );
931+
}
932+
933+
// Copy the result over to szAppInstallDir.
934+
V_strncpy( szAppInstallDir, pszAppDir, sizeof( szAppInstallDir ) );
935+
#endif // ENGINE_DLL ELSE !ENGINE_DLL
936+
pszBaseDir = szAppInstallDir;
937+
#else
699938
#ifdef ENGINE_DLL
700939
pLocation += strlen( APPID_PREFIX_TOKEN );
701940
const char *pNumberLoc = pLocation;
@@ -747,6 +986,7 @@ FSReturnCode_t FileSystem_LoadSearchPaths( CFSSearchPathsInit &initInfo )
747986
pszBaseDir = szAppInstallDir;
748987
#else
749988
Error( "Appid based mounting is not supported on non-engine DLL projects." );
989+
#endif
750990
#endif
751991
}
752992
else if ( Q_stristr( pLocation, GAMEINFOPATH_TOKEN ) == pLocation )

0 commit comments

Comments
 (0)