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

450 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // The copyright to the contents herein is the property of Valve, L.L.C.
  4. // The contents may be used and/or copied only with the written permission of
  5. // Valve, L.L.C., or in accordance with the terms and conditions stipulated in
  6. // the agreement/contract under which the contents have been supplied.
  7. //
  8. // $Header: $
  9. // $NoKeywords: $
  10. //
  11. //=============================================================================
  12. // NOTE: We specifically don't want to include *any* valve libraries
  13. // because this is expected to be run on a customer's machine and we
  14. // don't want to have to deal with any strange path stuff
  15. #include <windows.h>
  16. #include <stdio.h>
  17. //-----------------------------------------------------------------------------
  18. // Print help
  19. //-----------------------------------------------------------------------------
  20. void PrintHelp( )
  21. {
  22. printf( "Usage: rpt -i <in .csv file> -m <.mdl relative path> -o <output dir>\n" );
  23. printf( " [-f <fac output dir>] [-p] [-w] [-r <sample rate in hz>] [-s <sample filter size>]\n" );
  24. printf( " [-nop4] [-vproject <path to gameinfo.txt>]\n" );
  25. printf( "\t-h,-help,-?\t:Displays this help message.\n" );
  26. printf( "\t-m\t: Indicates the path of the .mdl file under game/mod/models/ to use in the sfm files.\n" );
  27. printf( "\t-o\t: Indicates output directory to place generated files in.\n" );
  28. printf( "\t-f\t: [Optional] Indicates that facial files should be created in the specified fac output dir.\n" );
  29. printf( "\t-p\t: [Optional] Indicates the extracted phonemes should be written into the wav file.\n" );
  30. printf( "\t-w\t: [Optional] Indicates the phonemes should be read from the wav file. Cannot also have -p specified.\n" );
  31. printf( "\t-r\t: [Optional] Specifies the phoneme extraction sample rate (default = 20)\n" );
  32. printf( "\t-s\t: [Optional] Specifies the phoneme extraction sample filter size (default = 0.08)\n" );
  33. printf( "\t-nop4\t: Disables auto perforce checkout/add.\n" );
  34. printf( "\t-vproject\t: Specifies path to a gameinfo.txt file (which mod to build for).\n" );
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Used to parse the commandline
  38. //-----------------------------------------------------------------------------
  39. static int FindParm( const char *pParam, int argc, char **argv )
  40. {
  41. // Start at 1 so as to not search the exe name
  42. for ( int i = 1; i < argc; ++i )
  43. {
  44. if ( !strcmp( pParam, argv[i] ) )
  45. return i;
  46. }
  47. return 0;
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Strips the last file from a filename, returns int offset of string end
  51. //-----------------------------------------------------------------------------
  52. static size_t StripFileName( char *pFileName )
  53. {
  54. // In this case, we queried the key properly. Strip off the steamclient.dll name
  55. // to make a good full path to steam.exe
  56. char *pSlash = strrchr( pFileName, '\\' );
  57. char *pSlash2 = strrchr( pFileName, '/' );
  58. if ( pSlash2 > pSlash )
  59. {
  60. pSlash = pSlash2;
  61. }
  62. if ( !pSlash )
  63. {
  64. pSlash = pFileName;
  65. }
  66. else
  67. {
  68. ++pSlash;
  69. }
  70. *pSlash = 0;
  71. size_t nLen = (size_t)pSlash - (size_t)pFileName;
  72. return nLen;
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Used to detect where steam is running from
  76. //-----------------------------------------------------------------------------
  77. static DWORD GetActiveSteamPID( )
  78. {
  79. HKEY hKey;
  80. LONG hResult = RegOpenKey( HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", &hKey );
  81. if ( hResult != ERROR_SUCCESS )
  82. return 0;
  83. DWORD nType;
  84. char pTempBuf[256];
  85. DWORD nLen = sizeof(pTempBuf);
  86. hResult = RegQueryValueEx( hKey, "pid", NULL, &nType, (unsigned char *)pTempBuf, &nLen );
  87. RegCloseKey( hKey );
  88. if ( hResult != ERROR_SUCCESS || nLen == 0 )
  89. return 0;
  90. switch( nType )
  91. {
  92. case REG_DWORD:
  93. return *(DWORD*)pTempBuf;
  94. case REG_QWORD:
  95. return (DWORD)( *(__int64*)pTempBuf );
  96. case REG_SZ:
  97. case REG_EXPAND_SZ:
  98. return atoi( pTempBuf );
  99. }
  100. return 0;
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Used to detect where steam is running from
  104. //-----------------------------------------------------------------------------
  105. static bool DetectSteamPath( char *pFileName, int nBufLen )
  106. {
  107. *pFileName = 0;
  108. DWORD nLen;
  109. // First check to see if there's an active process
  110. HKEY hKey;
  111. LONG hResult = RegOpenKey( HKEY_CURRENT_USER, "Software\\Valve\\Steam\\ActiveProcess", &hKey );
  112. if ( hResult == ERROR_SUCCESS )
  113. {
  114. nLen = (DWORD)nBufLen;
  115. hResult = RegQueryValueEx( hKey, "SteamClientDll", NULL, NULL, (LPBYTE)pFileName, &nLen );
  116. RegCloseKey( hKey );
  117. if ( hResult == ERROR_SUCCESS )
  118. {
  119. // In this case, we queried the key properly. Strip off the steamclient.dll name
  120. // to make a good full path to steam.exe
  121. size_t nUsed = StripFileName( pFileName );
  122. strncpy( &pFileName[nUsed], "steam.exe", nBufLen - nUsed );
  123. return true;
  124. }
  125. }
  126. // If not, then get the default install location
  127. hResult = RegOpenKey( HKEY_CURRENT_USER, "Software\\Valve\\Steam", &hKey );
  128. if ( hResult != ERROR_SUCCESS )
  129. return false;
  130. nLen = (DWORD)nBufLen;
  131. hResult = RegQueryValueEx( hKey, "SteamExe", NULL, NULL, (LPBYTE)pFileName, &nLen );
  132. RegCloseKey( hKey );
  133. return ( hResult == ERROR_SUCCESS && nLen != 0 );
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Displays a windows error
  137. //-----------------------------------------------------------------------------
  138. static void DisplayWindowsError( const char *pMessage )
  139. {
  140. DWORD dw = GetLastError();
  141. char pErrorMessage[2048];
  142. FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  143. pErrorMessage, sizeof(pErrorMessage), NULL );
  144. printf( "%s\n%s\n", pMessage, pErrorMessage );
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Deletes steam.cfg
  148. //-----------------------------------------------------------------------------
  149. static void DeleteCfgFile( const char *pFullPath )
  150. {
  151. remove( pFullPath );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Launches steam.exe, returns process ID (0 if failed)
  155. //-----------------------------------------------------------------------------
  156. static DWORD LaunchSteam( const char *pFullPath, const char *pArgs )
  157. {
  158. // Try to launch steam, shutting down any existing instance.
  159. STARTUPINFO si;
  160. memset( &si, 0, sizeof si );
  161. si.cb = sizeof(si);
  162. PROCESS_INFORMATION pi;
  163. if ( !CreateProcess( pFullPath, (char*)pArgs, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi ) )
  164. return 0;
  165. return pi.dwProcessId;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Is process active?
  169. //-----------------------------------------------------------------------------
  170. static bool IsSteamProcessActive( DWORD nProcessID )
  171. {
  172. if ( nProcessID == 0 )
  173. return false;
  174. HANDLE hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, nProcessID );
  175. bool bProcessActive = ( hProcess != 0 );
  176. if ( bProcessActive )
  177. {
  178. DWORD nExitCode;
  179. BOOL bOk = GetExitCodeProcess( hProcess, &nExitCode );
  180. if ( !bOk || ( nExitCode != STILL_ACTIVE ) )
  181. {
  182. bProcessActive = false;
  183. }
  184. }
  185. CloseHandle( hProcess );
  186. return bProcessActive;
  187. }
  188. static void TerminateSteamProcess( DWORD nProcessID )
  189. {
  190. if ( nProcessID == 0 )
  191. return;
  192. HANDLE hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, nProcessID );
  193. if ( hProcess != 0 )
  194. {
  195. TerminateProcess( hProcess, 0 );
  196. CloseHandle( hProcess );
  197. }
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Shuts down existing steam process
  201. //-----------------------------------------------------------------------------
  202. static bool ShutdownExistingSteamProcess( const char *pSteamPath )
  203. {
  204. DWORD nSteamPID = GetActiveSteamPID( );
  205. // Ensure the process is actually running.
  206. // The registry simply stores the last run steam process id
  207. if ( !IsSteamProcessActive( nSteamPID ) )
  208. {
  209. nSteamPID = 0;
  210. }
  211. // Try to shut down existing instances of steam
  212. if ( nSteamPID == 0 )
  213. return true;
  214. if ( !LaunchSteam( pSteamPath, "-shutdown" ) )
  215. {
  216. DisplayWindowsError( "rpt: Unable to shutdown existing steam process!" );
  217. return false;
  218. }
  219. // Wait for the old process to terminate
  220. // Wait for at least 30 seconds. If it doesn't start by that time,
  221. // then kill the existing process.
  222. DWORD nStartTime = GetTickCount();
  223. DWORD nTestTime = 30;
  224. while ( IsSteamProcessActive( nSteamPID ) )
  225. {
  226. Sleep( 1000 );
  227. DWORD dt = ( GetTickCount() - nStartTime ) / 1000;
  228. if ( dt <= nTestTime )
  229. continue;
  230. TerminateSteamProcess( nSteamPID );
  231. break;
  232. }
  233. return true;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Copies test files into position
  237. //-----------------------------------------------------------------------------
  238. bool CopyFilesRecursively( const char *pSrcPath, const char *pDestPath )
  239. {
  240. // Create a file that makes steam not delete different DLLs
  241. char pSearchStr[MAX_PATH];
  242. _snprintf( pSearchStr, sizeof(pSearchStr), "%s*", pSrcPath );
  243. WIN32_FIND_DATA find;
  244. HANDLE hFind = FindFirstFile( pSearchStr, &find );
  245. if( INVALID_HANDLE_VALUE == hFind )
  246. return true;
  247. // Make sure the dest path exists
  248. if ( ( GetFileAttributes( pDestPath ) & FILE_ATTRIBUTE_DIRECTORY ) == 0 )
  249. {
  250. if ( !CreateDirectory( pDestPath, NULL ) )
  251. {
  252. printf( "Unable to create directory %s\n", pDestPath );
  253. return false;
  254. }
  255. }
  256. // Display each file and ask for the next.
  257. do
  258. {
  259. // Skip . and ..
  260. if ( !strcmp( find.cFileName, "." ) || !strcmp( find.cFileName, ".." ) )
  261. continue;
  262. char pSrcChildPath[MAX_PATH];
  263. char pDestChildPath[MAX_PATH];
  264. // Deal with directories
  265. if ( ( find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) && ( ( find.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) == 0 ) )
  266. {
  267. _snprintf( pSrcChildPath, sizeof(pSrcChildPath), "%s%s\\", pSrcPath, find.cFileName );
  268. _snprintf( pDestChildPath, sizeof(pDestChildPath), "%s%s\\", pDestPath, find.cFileName );
  269. if ( !CopyFilesRecursively( pSrcChildPath, pDestChildPath ) )
  270. return false;
  271. continue;
  272. }
  273. _snprintf( pSrcChildPath, sizeof(pSrcChildPath), "%s%s", pSrcPath, find.cFileName );
  274. _snprintf( pDestChildPath, sizeof(pDestChildPath), "%s%s", pDestPath, find.cFileName );
  275. // Copy everything else
  276. // NOTE: This may fail if the file isn't already there
  277. SetFileAttributes( pDestChildPath, FILE_ATTRIBUTE_NORMAL );
  278. if ( CopyFile( pSrcChildPath, pDestChildPath, FALSE ) == 0 )
  279. {
  280. printf( "Unable to copy file %s to %s\n", pSrcChildPath, pDestChildPath );
  281. return false;
  282. }
  283. if ( !SetFileAttributes( pDestChildPath, FILE_ATTRIBUTE_READONLY ) )
  284. {
  285. printf( "Unable to make file %s read only.\n", pDestChildPath );
  286. return false;
  287. }
  288. } while( FindNextFile( hFind, &find ) );
  289. // Close the find handle.
  290. FindClose( hFind );
  291. return true;
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Copies test files into position
  295. //-----------------------------------------------------------------------------
  296. static bool CopyFilesIntoPosition( const char *pSteamPath )
  297. {
  298. // Create a file that makes steam not delete different DLLs
  299. char pSteamRoot[MAX_PATH];
  300. strncpy( pSteamRoot, pSteamPath, sizeof(pSteamRoot) );
  301. StripFileName( pSteamRoot );
  302. char pSrcRoot[MAX_PATH];
  303. if ( !::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), pSrcRoot, sizeof(pSrcRoot) ) )
  304. {
  305. printf( "Unable to find rpt launch path!\n" );
  306. return false;
  307. }
  308. StripFileName( pSrcRoot );
  309. return CopyFilesRecursively( pSrcRoot, pSteamRoot );
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Launches new steam process
  313. //-----------------------------------------------------------------------------
  314. static bool LaunchNewSteamProcess( const char *pSteamPath )
  315. {
  316. // Create a file that makes steam not delete different DLLs
  317. char pCfgPath[MAX_PATH];
  318. strncpy( pCfgPath, pSteamPath, sizeof(pCfgPath) );
  319. size_t nUsed = StripFileName( pCfgPath );
  320. strncpy( &pCfgPath[nUsed], "steam.cfg", sizeof(pCfgPath) - nUsed );
  321. FILE* fp = fopen( pCfgPath, "wt" );
  322. if ( !fp )
  323. {
  324. printf( "rpt: Unable to relaunch steam! Aborting...\n" );
  325. return false;
  326. }
  327. fprintf( fp, "MinFootprintAutoRefresh = disable\n" );
  328. fclose( fp );
  329. // Launch a new instance of steam
  330. DWORD nNewPID = LaunchSteam( pSteamPath, "" );
  331. // Wait for the new process to start.
  332. // Wait for at least 30 seconds. If it doesn't start by that time,
  333. // stop what we're doing.
  334. DWORD nStartTime = GetTickCount();
  335. DWORD nTestTime = 30;
  336. while ( GetActiveSteamPID( ) != nNewPID )
  337. {
  338. Sleep( 1000 );
  339. DWORD dt = ( GetTickCount() - nStartTime ) / 1000;
  340. if ( dt <= nTestTime )
  341. continue;
  342. TerminateSteamProcess( nNewPID );
  343. DeleteCfgFile( pCfgPath );
  344. printf( "rpt: Unable to launch new steam process!" );
  345. return false;
  346. }
  347. DeleteCfgFile( pCfgPath );
  348. return true;
  349. }
  350. //-----------------------------------------------------------------------------
  351. // The application object
  352. //-----------------------------------------------------------------------------
  353. int main( int argc, char **argv )
  354. {
  355. if ( FindParm( "-h", argc, argv ) || FindParm( "-help", argc, argv ) || FindParm( "-?", argc, argv ) )
  356. {
  357. PrintHelp();
  358. return 0;
  359. }
  360. // Detect the currently running version of steam
  361. char pSteamPath[MAX_PATH];
  362. if ( !DetectSteamPath( pSteamPath, sizeof(pSteamPath) ) )
  363. {
  364. printf( "rpt: Unable to detect steam installation path! Aborting...\n" );
  365. return 0;
  366. }
  367. if ( !ShutdownExistingSteamProcess( pSteamPath ) )
  368. return 0;
  369. if ( !CopyFilesIntoPosition( pSteamPath ) )
  370. return 0;
  371. if ( !LaunchNewSteamProcess( pSteamPath ) )
  372. return 0;
  373. return -1;
  374. }