//----------------------------------------------------------------------------- // ExcludePathsDlg_Setup // //----------------------------------------------------------------------------- void ExcludePathsDlg_Setup( HWND hWnd ) { TreeView_SetBkColor( GetDlgItem( hWnd, IDC_PATHS_TREE ), g_backgroundColor ); CheckDlgButton( hWnd, IDC_PATHS_LINKGAMEDIRS, g_bLinkGameDirs ? BST_CHECKED : BST_UNCHECKED ); // read the exisiting exclude paths g_ExcludePaths.Purge(); char szFilename[MAX_PATH]; V_ComposeFileName( g_localPath, EXCLUDEPATHS_FILE, szFilename, sizeof( szFilename ) ); if ( Sys_Exists( szFilename ) ) { Sys_LoadScriptFile( szFilename ); while ( 1 ) { char *pToken = Sys_GetToken( true ); if ( !pToken || !pToken[0] ) { break; } Sys_StripQuotesFromToken( pToken ); if ( !stricmp( pToken, "*" ) ) { pToken = ""; } else if ( pToken[0] == '\\' ) { pToken++; } char szPath[MAX_PATH]; V_ComposeFileName( ROOT_NAME, pToken, szPath, sizeof( szPath ) ); V_FixSlashes( szPath ); g_ExcludePaths.AddToTail( szPath ); } } }
void SendPatchCommandToUIs( DWORD dwInstallerProcessId ) { Msg( "SendPatchCommandToUIs\n "); CUtlVector<char> data; data.AddToTail( VMPI_SERVICE_UI_PROTOCOL_VERSION ); data.AddToTail( VMPI_SERVICE_TO_UI_PATCHING ); // This arg tells the UI whether to exit after running the command or not. data.AddToTail( 1 ); // First argument is the working directory, which is the cache path in this case. data.AddMultipleToTail( V_strlen( g_FileCachePath ) + 1, g_FileCachePath ); // Second argument is the command line. char waitAndRestartExe[MAX_PATH], serviceUIExe[MAX_PATH], commandLine[1024 * 8]; V_ComposeFileName( g_FileCachePath, "WaitAndRestart.exe", waitAndRestartExe, sizeof( waitAndRestartExe ) ); V_ComposeFileName( g_BaseAppPath, "vmpi_service_ui.exe", serviceUIExe, sizeof( serviceUIExe ) ); // We're running the UI from the same directory this exe is in. char strSeconds[64]; V_snprintf( strSeconds, sizeof( strSeconds ), "*%lu", dwInstallerProcessId ); // IMPORTANT to use BuildCommandLineFromArgs here because it'll handle slashes and quotes correctly. // If we don't do that, the command often won't work. CUtlVector<char*> args; args.AddToTail( waitAndRestartExe ); args.AddToTail( strSeconds ); args.AddToTail( g_BaseAppPath ); args.AddToTail( serviceUIExe ); BuildCommandLineFromArgs( args, commandLine, sizeof( commandLine ) ); data.AddMultipleToTail( V_strlen( commandLine ) + 1, commandLine ); if ( g_pConnMgr ) { g_pConnMgr->SendPacket( -1, data.Base(), data.Count() ); Sleep( 1000 ); // Make sure this packet goes out. } }
//----------------------------------------------------------------------------- // Purpose: Given an absolute path, do a find first find next on it and build // a list of files. Physical file system only //----------------------------------------------------------------------------- static void FindFileAbsoluteList( CUtlVector< CUtlString > &outAbsolutePathNames, const char *pszFindName ) { char szPath[MAX_PATH]; V_strncpy( szPath, pszFindName, sizeof( szPath ) ); V_StripFilename( szPath ); char szResult[MAX_PATH]; FileFindHandle_t hFile = FILESYSTEM_INVALID_FIND_HANDLE; for ( const char *pszFoundFile = g_pFullFileSystem->FindFirst( pszFindName, &hFile ); pszFoundFile && hFile != FILESYSTEM_INVALID_FIND_HANDLE; pszFoundFile = g_pFullFileSystem->FindNext( hFile ) ) { V_ComposeFileName( szPath, pszFoundFile, szResult, sizeof( szResult ) ); outAbsolutePathNames.AddToTail( szResult ); } g_pFullFileSystem->FindClose( hFile ); }
//----------------------------------------------------------------------------- // ExcludePathsDlg_SaveChanges // //----------------------------------------------------------------------------- void ExcludePathsDlg_SaveChanges( HWND hWnd ) { g_ExcludePaths.Purge(); HWND hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); ExcludePathsDlg_BuildExcludeList_r( hWndTree, TreeView_GetRoot( hWndTree ), 0, "" ); char szPath[MAX_PATH]; V_ComposeFileName( g_localPath, EXCLUDEPATHS_FILE, szPath, sizeof( szPath ) ); if ( !g_ExcludePaths.Count() ) { // no exclude paths unlink( szPath ); } else { FILE *fp = fopen( szPath, "wt" ); if ( !fp ) { Sys_MessageBox( "Error", "Could not open '%s' for writing\n", szPath ); return; } fprintf( fp, "// Auto-Generated by VXConsole - DO NOT MODIFY!\n" ); for ( int i = 0; i < g_ExcludePaths.Count(); i++ ) { // strip expected root path const char *pPath = g_ExcludePaths[i].String(); pPath += strlen( ROOT_NAME ); if ( !pPath[0] ) { // special code for root fprintf( fp, "*\n" ); break; } fprintf( fp, "\"\\%s\"\n", pPath ); } fclose( fp ); } }
static HANDLE CreateTempFile( CUtlString &WritePath, CUtlString &FileName ) { char tempFileName[MAX_PATH]; if ( WritePath.IsEmpty() ) { // use a safe name in the cwd char *pBuffer = tmpnam( NULL ); if ( !pBuffer ) { return INVALID_HANDLE_VALUE; } if ( pBuffer[0] == '\\' ) { pBuffer++; } if ( pBuffer[strlen( pBuffer )-1] == '.' ) { pBuffer[strlen( pBuffer )-1] = '\0'; } V_snprintf( tempFileName, sizeof( tempFileName ), "_%s.tmp", pBuffer ); } else { // generate safe name at the desired prefix char uniqueFilename[MAX_PATH]; SYSTEMTIME sysTime; \ GetLocalTime( &sysTime ); sprintf( uniqueFilename, "%d_%d_%d_%d_%d.tmp", sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds ); \ V_ComposeFileName( WritePath.String(), uniqueFilename, tempFileName, sizeof( tempFileName ) ); } FileName = tempFileName; HANDLE hFile = CreateFile( tempFileName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); return hFile; }
static HANDLE CreateTempFile( CUtlString &WritePath, CUtlString &FileName ) { char tempFileName[MAX_PATH]; if ( WritePath.IsEmpty() ) { // use a safe name in the cwd char *pBuffer = tmpnam( NULL ); if ( !pBuffer ) { return INVALID_HANDLE_VALUE; } if ( pBuffer[0] == '\\' ) { pBuffer++; } if ( pBuffer[strlen( pBuffer )-1] == '.' ) { pBuffer[strlen( pBuffer )-1] = '\0'; } V_snprintf( tempFileName, sizeof( tempFileName ), "_%s.tmp", pBuffer ); } else { char uniqueFilename[MAX_PATH]; static int counter = 0; time_t now = time( NULL ); struct tm *tm = localtime( &now ); sprintf( uniqueFilename, "%d_%d_%d_%d_%d.tmp", tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec, ++counter ); \ V_ComposeFileName( WritePath.String(), uniqueFilename, tempFileName, sizeof( tempFileName ) ); } FileName = tempFileName; FILE *hFile = fopen( tempFileName, "rw+" ); return (HANDLE)hFile; }
bool F_Compose_File_Path(PCHARS szProjFilePath, PCHARS fileExtensionWithDot, ANSICHAR (&destBuf)[BUF_SIZE]) { AssertPtr( szProjFilePath ); AssertPtr( destBuf ); StaticAssert( BUF_SIZE > 0 ); // pure name (e.g. "MyProject") ANSICHAR projName[ 128 ]; V_FileBase( szProjFilePath, projName, NUMBER_OF(projName) ); // path relative to exe (e.g. "Projects/MyProject/") ANSICHAR projFilePath[ FS_MAX_PATH ]; VRET_FALSE_IF_NOT( V_ExtractFilePath( szProjFilePath, projFilePath, NUMBER_OF(projFilePath) ) ); // path to .INI file relative to exe (e.g. "Projects/MyProject/MyProject.INI") ANSICHAR outFilePath[ FS_MAX_PATH ]; V_ComposeFileName( projFilePath, projName, outFilePath, NUMBER_OF(outFilePath) ); V_SetExtension( outFilePath, fileExtensionWithDot, NUMBER_OF(outFilePath) ); mxStrCpyNAnsi( destBuf, outFilePath, NUMBER_OF(destBuf) ); return true; }
CUtlString CUtlString::PathJoin( const char *pStr1, const char *pStr2 ) { char szPath[MAX_PATH]; V_ComposeFileName( pStr1, pStr2, szPath, sizeof( szPath ) ); return CUtlString( szPath ); }
//----------------------------------------------------------------------------- // Generate a tree containing files from a reslist. Returns TRUE if successful. //----------------------------------------------------------------------------- bool LoadReslist( const char *pReslistName, CUtlRBTree< CUtlString, int > *pTree ) { CUtlBuffer buffer; if ( !scriptlib->ReadFileToBuffer( pReslistName, buffer, true ) ) { return false; } char szBasename[MAX_PATH]; V_FileBase( pReslistName, szBasename, sizeof( szBasename ) ); characterset_t breakSet; CharacterSetBuild( &breakSet, "" ); // parse reslist char szToken[MAX_PATH]; char szBspName[MAX_PATH]; szBspName[0] = '\0'; for ( ;; ) { int nTokenSize = buffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); if ( nTokenSize <= 0 ) { break; } // reslists are pc built, filenames can be sloppy V_strlower( szToken ); V_FixSlashes( szToken ); V_RemoveDotSlashes( szToken ); // can safely cull filetypes that are ignored by queued loader at runtime bool bKeep = false; const char *pExt = V_GetFileExtension( szToken ); if ( !pExt ) { // unknown continue; } else if ( !V_stricmp( pExt, "vmt" ) || !V_stricmp( pExt, "vhv" ) || !V_stricmp( pExt, "mdl" ) || !V_stricmp( pExt, "raw" ) || !V_stricmp( pExt, "wav" ) ) { bKeep = true; } else if ( !V_stricmp( pExt, "mp3" ) ) { // change to .wav V_SetExtension( szToken, ".wav", sizeof( szToken ) ); bKeep = true; } else if ( !V_stricmp( pExt, "bsp" ) ) { // reslists erroneously have multiple bsps if ( !V_stristr( szToken, szBasename ) ) { // wrong one, cull it continue; } else { // right one, save it strcpy( szBspName, szToken ); bKeep = true; } } if ( bKeep ) { FindOrAddFileToResourceList( szToken, pTree ); } } if ( !szBspName[0] ) { // reslist is not bsp derived, nothing more to do return true; } CUtlVector< CUtlString > bspList; bool bOK = GetDependants_BSP( szBspName, &bspList ); if ( !bOK ) { return false; } // add all the bsp dependants to the resource list for ( int i=0; i<bspList.Count(); i++ ) { FindOrAddFileToResourceList( bspList[i].String(), pTree ); } // iterate all the models in the resource list, get all their dependents CUtlVector< CUtlString > modelList; for ( int i = pTree->FirstInorder(); i != pTree->InvalidIndex(); i = pTree->NextInorder( i ) ) { const char *pExt = V_GetFileExtension( pTree->Element( i ).String() ); if ( !pExt || V_stricmp( pExt, "mdl" ) ) { continue; } if ( !GetDependants_MDL( pTree->Element( i ).String(), &modelList ) ) { return false; } } // add all the model dependents to the resource list for ( int i=0; i<modelList.Count(); i++ ) { FindOrAddFileToResourceList( modelList[i].String(), pTree ); } // check for optional commentary, include wav dependencies char szCommentaryName[MAX_PATH]; V_ComposeFileName( g_szGamePath, szBspName, szCommentaryName, sizeof( szCommentaryName ) ); V_StripExtension( szCommentaryName, szCommentaryName, sizeof( szCommentaryName ) ); V_strncat( szCommentaryName, "_commentary.txt", sizeof( szCommentaryName ) ); CUtlBuffer commentaryBuffer; if ( ReadFileToBuffer( szCommentaryName, commentaryBuffer, true, true ) ) { // any single token may be quite large to due to text char szCommentaryToken[8192]; for ( ;; ) { int nTokenSize = commentaryBuffer.ParseToken( &breakSet, szCommentaryToken, sizeof( szCommentaryToken ) ); if ( nTokenSize < 0 ) { break; } if ( nTokenSize > 0 && !V_stricmp( szCommentaryToken, "commentaryfile" ) ) { // get the commentary file nTokenSize = commentaryBuffer.ParseToken( &breakSet, szCommentaryToken, sizeof( szCommentaryToken ) ); if ( nTokenSize > 0 ) { // skip past sound chars char *pName = szCommentaryToken; while ( *pName && IsSoundChar( *pName ) ) { pName++; } char szWavFile[MAX_PATH]; V_snprintf( szWavFile, sizeof( szWavFile ), "sound/%s", pName ); FindOrAddFileToResourceList( szWavFile, pTree ); } } } } // check for optional blacklist char szBlacklist[MAX_PATH]; V_ComposeFileName( g_szGamePath, "reslistfixes_xbox.xsc", szBlacklist, sizeof( szBlacklist ) ); CUtlBuffer blacklistBuffer; if ( ReadFileToBuffer( szBlacklist, blacklistBuffer, true, true ) ) { for ( ;; ) { int nTokenSize = blacklistBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); if ( nTokenSize <= 0 ) { break; } bool bAdd; if ( !V_stricmp( szToken, "-" ) ) { bAdd = false; } else if ( !V_stricmp( szToken, "+" ) ) { bAdd = true; } else { // bad syntax, skip line Msg( "Bad Syntax, expecting '+' or '-' as first token in reslist fixup file '%s'.\n", szBlacklist ); continue; } // get entry nTokenSize = blacklistBuffer.ParseToken( &breakSet, szToken, sizeof( szToken ) ); if ( nTokenSize <= 0 ) { break; } if ( bAdd ) { FindOrAddFileToResourceList( szToken, pTree ); } else { RemoveFileFromResourceList( szToken, pTree ); } } } return true; }
// -------------------------------------------------------------------------------- // // Purpose: Launches vmpi_transfer.exe to download the required // files from the master so we can launch. // // If successful, it sets hProcess to the process handle of the downloader. // When that process terminates, we look for [cache dir]\ReadyToGo.txt and if it's // there, then we start the job. // -------------------------------------------------------------------------------- // bool StartDownloadingAppFiles( CUtlVector<char*> &newArgv, char *cacheDir, int cacheDirLen, bool bShowAppWindow, HANDLE *hProcess, bool bPatching ) { *hProcess = NULL; V_strncpy( cacheDir, g_FileCachePath, cacheDirLen ); // For now, cache dir is always the same. It's [current directory]\cache. if ( _access( cacheDir, 0 ) != 0 ) { if ( !CreateDirectory( cacheDir, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS ) { Warning( "Unable to create cache directory: %s.\n", cacheDir ); return false; } } // Clear all the files in the directory. char searchStr[MAX_PATH]; V_ComposeFileName( cacheDir, "*.*", searchStr, sizeof( searchStr ) ); _finddata_t findData; intptr_t ret = _findfirst( searchStr, &findData ); if ( ret != -1 ) { do { if ( findData.name[0] == '.' ) continue; char fullFilename[MAX_PATH]; V_ComposeFileName( cacheDir, findData.name, fullFilename, sizeof( fullFilename ) ); if ( _unlink( fullFilename ) != 0 ) { Warning( "_unlink( %s ) failed.\n", fullFilename ); return false; } } while ( _findnext( ret, &findData ) == 0 ); _findclose( ret ); } // Change the EXE name to an absolute path to exactly where it is in the cache directory. int maxExeNameLen = 1024; char *pExeName = new char[maxExeNameLen]; if ( bPatching ) { V_ComposeFileName( cacheDir, "vmpi_service_install.exe", pExeName, maxExeNameLen ); // Add args for the installer. newArgv.InsertAfter( 0, CopyString( "-DontTouchUI" ) ); // When patching, we can't start the UI and the installer can't because we're running in the local system account // and the UI is running on the account of whoever logged in. So what we do is send a message to the UI telling it // to run <cacheDir>\WaitAndRestart and restart itself in N seconds. newArgv.InsertAfter( 0, CopyString( "-Install_Quiet" ) ); } else { V_ComposeFileName( cacheDir, newArgv[0], pExeName, maxExeNameLen ); } delete newArgv[0]; newArgv[0] = pExeName; char fullExeFilename[MAX_PATH]; V_ComposeFileName( g_BaseAppPath, "vmpi_transfer.exe", fullExeFilename, sizeof( fullExeFilename ) ); CUtlVector<char*> downloaderArgs; downloaderArgs.AddToTail( fullExeFilename ); #if defined( _DEBUG ) downloaderArgs.AddToTail( "-allowdebug" ); #endif downloaderArgs.AddToTail( "-CachePath" ); // Tell it where to download the files to. downloaderArgs.AddToTail( cacheDir ); // Pass all the -mpi_worker, -mpi_file, -mpi_filebase args into the downloader app. for ( int i=1; i < (int)newArgv.Count()-1; i++ ) { if ( V_stricmp( newArgv[i], "-mpi_filebase" ) == 0 || V_stricmp( newArgv[i], "-mpi_file" ) == 0 ) { downloaderArgs.AddToTail( newArgv[i] ); downloaderArgs.AddToTail( newArgv[i+1] ); newArgv.Remove( i ); newArgv.Remove( i ); --i; } else if ( V_stricmp( newArgv[i], "-mpi_worker" ) == 0 ) { // We need this arg so it knows what IP to connect to, but we want to leave it in the final launch args too. downloaderArgs.AddToTail( newArgv[i] ); downloaderArgs.AddToTail( newArgv[i+1] ); ++i; } } // Transfer each file. PROCESS_INFORMATION pi; if ( !RunProcessFromArgs( downloaderArgs, bShowAppWindow, false, g_BaseAppPath, &pi ) ) return false; *hProcess = pi.hProcess; return true; }
//----------------------------------------------------------------------------- // ExcludePathsDlg_Find_r // //----------------------------------------------------------------------------- HTREEITEM ExcludePathsDlg_Find_r( HWND hWndTree, HTREEITEM hTree, int depth, const char *pBasePath, const char *pFindPath ) { TVITEM tvi = { 0 }; char szName[MAX_PATH]; tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT; tvi.hItem = hTree; tvi.pszText = szName; tvi.cchTextMax = sizeof( szName ); if ( !TreeView_GetItem( hWndTree, &tvi ) ) { return NULL; } char szPath[MAX_PATH]; V_ComposeFileName( pBasePath, szName, szPath, sizeof( szPath ) ); if ( !stricmp( szPath, pFindPath ) ) { return hTree; } if ( tvi.cChildren ) { HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); if ( hChild ) { HTREEITEM hFindTree = ExcludePathsDlg_Find_r( hWndTree, hChild, depth+1, szPath, pFindPath ); if ( hFindTree ) { return hFindTree; } } } if ( !depth ) { // only iterate siblings of the parent's child return NULL; } // iterate siblings HTREEITEM hSibling = hTree; while ( 1 ) { hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); if ( !hSibling ) { break; } tvi.hItem = hSibling; if ( !TreeView_GetItem( hWndTree, &tvi ) ) { break; } V_ComposeFileName( pBasePath, szName, szPath, sizeof( szPath ) ); if ( !stricmp( szPath, pFindPath ) ) { return hSibling; } if ( tvi.cChildren ) { HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); if ( hChild ) { HTREEITEM hFindTree = ExcludePathsDlg_Find_r( hWndTree, hChild, depth+1, szPath, pFindPath ); if ( hFindTree ) { return hFindTree; } } } } return NULL; }
//----------------------------------------------------------------------------- // The DX Support file is a very fat expensive KV file, causes a run-time startup slowdown. // Becauase it normally lives in the game\bin directory, it can't be in the zip or preloaded. // Thus, it gets reprocessed into just the trivial 360 portion and placed into the platform.zip // Yes, it's evil. //----------------------------------------------------------------------------- bool ProcessDXSupportConfig( bool bWriteToZip ) { if ( !g_bIsPlatformZip ) { // only relevant when building platform zip, otherwise no-op return false; } const char *pConfigName = "dxsupport.cfg"; char szTempPath[MAX_PATH]; char szSourcePath[MAX_PATH]; V_ComposeFileName( g_szModPath, "../bin", szTempPath, sizeof( szTempPath ) ); V_ComposeFileName( szTempPath, pConfigName, szSourcePath, sizeof( szSourcePath ) ); CUtlBuffer sourceBuf( 0, 0, CUtlBuffer::TEXT_BUFFER ); if ( !g_pFullFileSystem->ReadFile( szSourcePath, NULL, sourceBuf ) ) { Msg( "Error! Couldn't open file '%s'!\n", pConfigName ); return false; } KeyValues *pKV = new KeyValues( "" ); if ( !pKV->LoadFromBuffer( "dxsupport.cfg", sourceBuf ) ) { Msg( "Error! Couldn't parse config file '%s'!\n", pConfigName ); pKV->deleteThis(); return false; } // only care about the xbox specific dxlevel 98 block KeyValues *pXboxSubKey = NULL; for ( KeyValues *pSubKey = pKV->GetFirstSubKey(); pSubKey != NULL && pXboxSubKey == NULL; pSubKey = pSubKey->GetNextKey() ) { // descend each sub block for ( KeyValues *pKey = pSubKey->GetFirstSubKey(); pKey != NULL && pXboxSubKey == NULL; pKey = pKey->GetNextKey() ) { if ( !V_stricmp( pKey->GetName(), "name" ) && pKey->GetInt( (const char *)NULL ) == 98 ) { pXboxSubKey = pSubKey; } } } if ( !pXboxSubKey ) { Msg( "Error! Couldn't find expected dxlevel 98 in config file '%s'!\n", pConfigName ); pKV->deleteThis(); return false; } CUtlBuffer kvBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER ); kvBuffer.Printf( "\"dxsupport\"\n" ); kvBuffer.Printf( "{\n" ); kvBuffer.Printf( "\t\"0\"\n" ); kvBuffer.Printf( "\t{\n" ); for ( KeyValues *pKey = pXboxSubKey->GetFirstSubKey(); pKey != NULL; pKey = pKey->GetNextKey() ) { kvBuffer.Printf( "\t\t\"%s\" \"%s\"\n", pKey->GetName(), pKey->GetString( (const char *)NULL ) ); } kvBuffer.Printf( "\t}\n" ); kvBuffer.Printf( "}\n" ); CUtlBuffer targetBuf( 0, 0, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::CONTAINS_CRLF ); kvBuffer.ConvertCRLF( targetBuf ); // only appears in zip file bool bSuccess = WriteBufferToFile( pConfigName, targetBuf, bWriteToZip, WRITE_TO_DISK_NEVER ); pKV->deleteThis(); return bSuccess; }
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Hook spew output. SpewOutputFunc( MySpewOutputFunc ); // Get access to the registry.. RegCreateKey( HKEY_LOCAL_MACHINE, VMPI_SERVICE_KEY, &g_hVMPIServiceKey ); // Setup our version string. LoadString( hInstance, VMPI_SERVICE_IDS_VERSION_STRING, g_VersionString, sizeof( g_VersionString ) ); // Setup the base app path. if ( !GetModuleFileName( GetModuleHandle( NULL ), g_BaseAppPath, sizeof( g_BaseAppPath ) ) ) { Warning( "GetModuleFileName failed.\n" ); return false; } V_StripLastDir( g_BaseAppPath, sizeof( g_BaseAppPath ) ); // Setup the cache path. V_ComposeFileName( g_BaseAppPath, "vmpi_service_cache", g_FileCachePath, sizeof( g_FileCachePath ) ); const char *pArg = FindArg( __argc, __argv, "-mpi_pw", NULL ); SetPassword( pArg ); if ( FindArg( __argc, __argv, "-console" ) ) { g_RunMode = RUNMODE_CONSOLE; } else { g_RunMode = RUNMODE_SERVICE; } if ( FindArg( __argc, __argv, "-superdebug" ) ) g_bSuperDebugMode = true; g_AppStartTime = GetTickCount(); g_bMinimized = FindArg( __argc, __argv, "-minimized" ) != NULL; ServiceHelpers_Init(); g_hInstance = hInstance; LoadStateFromRegistry(); // Install the service? if ( g_RunMode == RUNMODE_CONSOLE ) { RunAsNonServiceApp(); } else { RunService(); } return 0; }
// Returns true if the service was just patched and should exit. bool CheckDownloaderFinished() { if ( !g_Waiting_hProcess ) return false; // Check if the downloader has timed out and kill it if necessary. if ( Plat_FloatTime() - g_Waiting_StartTime > MAX_DOWNLOADER_TIME_ALLOWED ) { TerminateProcess( g_Waiting_hProcess, 1 ); CloseHandle( g_Waiting_hProcess ); g_Waiting_hProcess = NULL; return false; } // Check if it's done. if ( WaitForSingleObject( g_Waiting_hProcess, 0 ) != WAIT_OBJECT_0 ) return false; CloseHandle( g_Waiting_hProcess ); g_Waiting_hProcess = NULL; // Ok, it's done. Did it finish successfully? char testFilename[MAX_PATH]; V_ComposeFileName( g_FileCachePath, "ReadyToGo.txt", testFilename, sizeof( testFilename ) ); if ( _access( testFilename, 0 ) != 0 ) return false; // Ok, the downloader finished successfully. Run the worker app. if ( g_bSuperDebugMode ) AdjustSuperDebugArgs( g_Waiting_Argv ); // Figure out the name of the master machine. V_strncpy( g_CurMasterName, "<unknown>", sizeof( g_CurMasterName ) ); for ( int iArg=1; iArg < g_Waiting_Argv.Count()-1; iArg++ ) { if ( stricmp( g_Waiting_Argv[iArg], "-mpi_MasterName" ) == 0 ) { Q_strncpy( g_CurMasterName, g_Waiting_Argv[iArg+1], sizeof( g_CurMasterName ) ); } } char DLLFilename[MAX_PATH]; if ( FindArg( __argc, __argv, "-TryDLLMode" ) && g_RunMode == RUNMODE_CONSOLE && GetDLLFilename( g_Waiting_Argv, DLLFilename ) && !g_Waiting_bPatching ) { // This is just a helper for debugging. If it's VRAD, we can run it // in-process as a DLL instead of running it as a separate EXE. RunInDLL( DLLFilename, g_Waiting_Argv ); } else { // Run the (hopefully!) MPI app they specified. RunProcessAtCommandLine( g_Waiting_Argv, g_Waiting_bShowAppWindow, g_Waiting_bPatching, g_Waiting_Priority ); if ( g_Waiting_bPatching ) { // Tell any currently-running UI apps to patch themselves and quit ASAP so the installer can finish. SendPatchCommandToUIs( g_dwRunningProcessId ); ResumeThread( g_hRunningThread ); // We started the installer suspended so we could make sure we'd send out the patch command. // We just ran the installer, but let's forget about it, otherwise we'll kill its process when we exit here. CloseHandle( g_hRunningProcess ); CloseHandle( g_hRunningThread ) ; g_hRunningProcess = g_hRunningThread = NULL; g_RunningProcess_ExeName[0] = 0; g_RunningProcess_MapName[0] = 0; ServiceHelpers_ExitEarly(); return true; } } g_Waiting_Argv.PurgeAndDeleteElements(); return false; }
//---------------------------------------------------------------------- // Get list of files that a model requires. //---------------------------------------------------------------------- bool GetDependants_MDL( const char *pModelName, CUtlVector< CUtlString > *pList ) { if ( !g_bModPathIsValid ) { Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" ); return false; } CUtlBuffer sourceBuf; if ( !g_pFullFileSystem->ReadFile( pModelName, "GAME", sourceBuf ) ) { Msg( "Error! Couldn't open file '%s'!\n", pModelName ); return false; } studiohdr_t *pStudioHdr = (studiohdr_t *)sourceBuf.Base(); Studio_ConvertStudioHdrToNewVersion( pStudioHdr ); if ( pStudioHdr->version != STUDIO_VERSION ) { Msg( "Error! Bad Model '%s', Expecting Version (%d), got (%d)\n", pModelName, STUDIO_VERSION, pStudioHdr->version ); return false; } char szOutName[MAX_PATH]; if ( pStudioHdr->flags & STUDIOHDR_FLAGS_OBSOLETE ) { V_strncpy( szOutName, "materials/sprites/obsolete.vmt", sizeof( szOutName ) ); V_FixSlashes( szOutName ); pList->AddToTail( szOutName ); } else if ( pStudioHdr->textureindex != 0 ) { // iterate each texture int i; int j; for ( i = 0; i < pStudioHdr->numtextures; i++ ) { // iterate through all directories until a valid material is found bool bFound = false; for ( j = 0; j < pStudioHdr->numcdtextures; j++ ) { char szPath[MAX_PATH]; V_ComposeFileName( "materials", pStudioHdr->pCdtexture( j ), szPath, sizeof( szPath ) ); // should have been fixed in studiomdl // some mdls are ending up with double slashes, borking loads int len = strlen( szPath ); if ( len > 2 && szPath[len-2] == '\\' && szPath[len-1] == '\\' ) { szPath[len-1] = '\0'; } V_ComposeFileName( szPath, pStudioHdr->pTexture( i )->pszName(), szOutName, sizeof( szOutName ) ); V_SetExtension( szOutName, ".vmt", sizeof( szOutName ) ); if ( g_pFullFileSystem->FileExists( szOutName, "GAME" ) ) { bFound = true; break; } } if ( bFound ) { pList->AddToTail( szOutName ); } } } return true; }
//----------------------------------------------------------------------------- // ExcludePathsDlg_BuildExcludeList_r // // An exclude path represents the path head, and thus does not need to iterate its children // if they are deemed to the same exclusion state. //----------------------------------------------------------------------------- void ExcludePathsDlg_BuildExcludeList_r( HWND hWndTree, HTREEITEM hTree, int depth, const char *pPath ) { int checkState = -1; bool bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hTree, 0, &checkState ); if ( checkState == -1 ) { return; } TVITEM tvi = { 0 }; char szName[MAX_PATH]; tvi.mask = TVIF_HANDLE | TVIF_CHILDREN | TVIF_TEXT; tvi.hItem = hTree; tvi.pszText = szName; tvi.cchTextMax = sizeof( szName ); if ( !TreeView_GetItem( hWndTree, &tvi ) ) { return; } char szPath[MAX_PATH]; V_ComposeFileName( pPath, szName, szPath, sizeof( szPath ) ); if ( checkState == 1 && ( bStateIsSame || !tvi.cChildren ) ) { // add to exclude list g_ExcludePaths.AddToTail( szPath ); } if ( !bStateIsSame && tvi.cChildren ) { // mixed states, must recurse to resolve HTREEITEM hChild = TreeView_GetChild( hWndTree, hTree ); if ( hChild ) { ExcludePathsDlg_BuildExcludeList_r( hWndTree, hChild, depth+1, szPath ); } } if ( !depth ) { // only iterate siblings of the parent's child return; } // iterate siblings HTREEITEM hSibling = hTree; while ( 1 ) { hSibling = TreeView_GetNextSibling( hWndTree, hSibling ); if ( !hSibling ) { break; } checkState = -1; bStateIsSame = ExcludePathsDlg_GetCheckState_r( hWndTree, hSibling, 0, &checkState ); if ( checkState == -1 ) { break; } tvi.hItem = hSibling; if ( !TreeView_GetItem( hWndTree, &tvi ) ) { break; } V_ComposeFileName( pPath, szName, szPath, sizeof( szPath ) ); if ( checkState == 1 && ( bStateIsSame || !tvi.cChildren ) ) { // add to exclude list g_ExcludePaths.AddToTail( szPath ); } if ( !bStateIsSame && tvi.cChildren ) { HTREEITEM hChild = TreeView_GetChild( hWndTree, hSibling ); if ( hChild ) { ExcludePathsDlg_BuildExcludeList_r( hWndTree, hChild, depth+1, szPath ); } } } }
//----------------------------------------------------------------------------- // A Scene image file contains all the compiled .XCD //----------------------------------------------------------------------------- bool CSceneImage::CreateSceneImageFile( CUtlBuffer &targetBuffer, char const *pchModPath, bool bLittleEndian, bool bQuiet, ISceneCompileStatus *pStatus ) { CUtlVector<fileList_t> vcdFileList; CUtlSymbolTable vcdSymbolTable( 0, 32, true ); Msg( "\n" ); // get all the VCD files according to the seacrh paths char searchPaths[512]; g_pFullFileSystem->GetSearchPath( "GAME", false, searchPaths, sizeof( searchPaths ) ); char *pPath = strtok( searchPaths, ";" ); while ( pPath ) { int currentCount = vcdFileList.Count(); char szPath[MAX_PATH]; V_ComposeFileName( pPath, "scenes/*.vcd", szPath, sizeof( szPath ) ); scriptlib->FindFiles( szPath, true, vcdFileList ); Msg( "Scenes: Searching '%s' - Found %d scenes.\n", szPath, vcdFileList.Count() - currentCount ); pPath = strtok( NULL, ";" ); } if ( !vcdFileList.Count() ) { Msg( "Scenes: No Scene Files found!\n" ); return false; } // iterate and convert all the VCD files bool bGameIsTF = V_stristr( pchModPath, "\\tf" ) != NULL; for ( int i=0; i<vcdFileList.Count(); i++ ) { const char *pFilename = vcdFileList[i].fileName.String(); const char *pSceneName = V_stristr( pFilename, "scenes\\" ); if ( !pSceneName ) { continue; } if ( !bLittleEndian && bGameIsTF && V_stristr( pSceneName, "high\\" ) ) { continue; } // process files in order they would be found in search paths // i.e. skipping later processed files that match an earlier conversion UtlSymId_t symbol = vcdSymbolTable.Find( pSceneName ); if ( symbol == UTL_INVAL_SYMBOL ) { vcdSymbolTable.AddString( pSceneName ); pStatus->UpdateStatus( pFilename, bQuiet, i, vcdFileList.Count() ); if ( !CreateTargetFile_VCD( pFilename, "", false, bLittleEndian ) ) { Error( "CreateSceneImageFile: Failed on '%s' conversion!\n", pFilename ); } } } if ( !g_SceneFiles.Count() ) { // nothing to do return true; } Msg( "Scenes: Finalizing %d unique scenes.\n", g_SceneFiles.Count() ); // get the string pool CUtlVector< unsigned int > stringOffsets; CUtlBuffer stringPool; g_ChoreoStringPool.GetTableAndPool( stringOffsets, stringPool ); if ( !bQuiet ) { Msg( "Scenes: String Table: %d bytes\n", stringOffsets.Count() * sizeof( int ) ); Msg( "Scenes: String Pool: %d bytes\n", stringPool.TellMaxPut() ); } // first header, then lookup table, then string pool blob int stringPoolStart = sizeof( SceneImageHeader_t ) + stringOffsets.Count() * sizeof( int ); // then directory int sceneEntryStart = stringPoolStart + stringPool.TellMaxPut(); // then variable sized summaries int sceneSummaryStart = sceneEntryStart + g_SceneFiles.Count() * sizeof( SceneImageEntry_t ); // then variable sized compiled binary scene data int sceneDataStart = 0; // construct header SceneImageHeader_t imageHeader = { 0 }; imageHeader.nId = SCENE_IMAGE_ID; imageHeader.nVersion = SCENE_IMAGE_VERSION; imageHeader.nNumScenes = g_SceneFiles.Count(); imageHeader.nNumStrings = stringOffsets.Count(); imageHeader.nSceneEntryOffset = sceneEntryStart; if ( !bLittleEndian ) { imageHeader.nId = BigLong( imageHeader.nId ); imageHeader.nVersion = BigLong( imageHeader.nVersion ); imageHeader.nNumScenes = BigLong( imageHeader.nNumScenes ); imageHeader.nNumStrings = BigLong( imageHeader.nNumStrings ); imageHeader.nSceneEntryOffset = BigLong( imageHeader.nSceneEntryOffset ); } targetBuffer.Put( &imageHeader, sizeof( imageHeader ) ); // header is immediately followed by string table and pool for ( int i = 0; i < stringOffsets.Count(); i++ ) { unsigned int offset = stringPoolStart + stringOffsets[i]; if ( !bLittleEndian ) { offset = BigLong( offset ); } targetBuffer.PutInt( offset ); } Assert( stringPoolStart == targetBuffer.TellMaxPut() ); targetBuffer.Put( stringPool.Base(), stringPool.TellMaxPut() ); // construct directory CUtlSortVector< SceneImageEntry_t, CSceneImageEntryLessFunc > imageDirectory; imageDirectory.EnsureCapacity( g_SceneFiles.Count() ); // build directory // directory is linear sorted by filename checksum for later binary search for ( int i = 0; i < g_SceneFiles.Count(); i++ ) { SceneImageEntry_t imageEntry = { 0 }; // name needs to be normalized for determinstic later CRC name calc // calc crc based on scenes\anydir\anyscene.vcd char szCleanName[MAX_PATH]; V_strncpy( szCleanName, g_SceneFiles[i].fileName.String(), sizeof( szCleanName ) ); V_strlower( szCleanName ); V_FixSlashes( szCleanName ); char *pName = V_stristr( szCleanName, "scenes\\" ); if ( !pName ) { // must have scenes\ in filename Error( "CreateSceneImageFile: Unexpected lack of scenes prefix on %s\n", g_SceneFiles[i].fileName.String() ); } CRC32_t crcFilename = CRC32_ProcessSingleBuffer( pName, strlen( pName ) ); imageEntry.crcFilename = crcFilename; // temp store an index to its file, fixup later, necessary to access post sort imageEntry.nDataOffset = i; if ( imageDirectory.Find( imageEntry ) != imageDirectory.InvalidIndex() ) { // filename checksums must be unique or runtime binary search would be bogus Error( "CreateSceneImageFile: Unexpected filename checksum collision!\n" ); } imageDirectory.Insert( imageEntry ); } // determine sort order and start of data after dynamic summaries CUtlVector< int > writeOrder; writeOrder.EnsureCapacity( g_SceneFiles.Count() ); sceneDataStart = sceneSummaryStart; for ( int i = 0; i < imageDirectory.Count(); i++ ) { // reclaim offset, indicates write order of scene file int iScene = imageDirectory[i].nDataOffset; writeOrder.AddToTail( iScene ); // march past each variable sized summary to determine start of scene data int numSounds = g_SceneFiles[iScene].soundList.Count(); sceneDataStart += sizeof( SceneImageSummary_t ) + ( numSounds - 1 ) * sizeof( int ); } // finalize and write directory Assert( sceneEntryStart == targetBuffer.TellMaxPut() ); int nSummaryOffset = sceneSummaryStart; int nDataOffset = sceneDataStart; for ( int i = 0; i < imageDirectory.Count(); i++ ) { int iScene = writeOrder[i]; imageDirectory[i].nDataOffset = nDataOffset; imageDirectory[i].nDataLength = g_SceneFiles[iScene].compiledBuffer.TellMaxPut(); imageDirectory[i].nSceneSummaryOffset = nSummaryOffset; if ( !bLittleEndian ) { imageDirectory[i].crcFilename = BigLong( imageDirectory[i].crcFilename ); imageDirectory[i].nDataOffset = BigLong( imageDirectory[i].nDataOffset ); imageDirectory[i].nDataLength = BigLong( imageDirectory[i].nDataLength ); imageDirectory[i].nSceneSummaryOffset = BigLong( imageDirectory[i].nSceneSummaryOffset ); } targetBuffer.Put( &imageDirectory[i], sizeof( SceneImageEntry_t ) ); int numSounds = g_SceneFiles[iScene].soundList.Count(); nSummaryOffset += sizeof( SceneImageSummary_t ) + (numSounds - 1) * sizeof( int ); nDataOffset += g_SceneFiles[iScene].compiledBuffer.TellMaxPut(); } // finalize and write summaries Assert( sceneSummaryStart == targetBuffer.TellMaxPut() ); for ( int i = 0; i < imageDirectory.Count(); i++ ) { int iScene = writeOrder[i]; int msecs = g_SceneFiles[iScene].msecs; int soundCount = g_SceneFiles[iScene].soundList.Count(); if ( !bLittleEndian ) { msecs = BigLong( msecs ); soundCount = BigLong( soundCount ); } targetBuffer.PutInt( msecs ); targetBuffer.PutInt( soundCount ); for ( int j = 0; j < g_SceneFiles[iScene].soundList.Count(); j++ ) { int soundId = g_SceneFiles[iScene].soundList[j]; if ( !bLittleEndian ) { soundId = BigLong( soundId ); } targetBuffer.PutInt( soundId ); } } // finalize and write data Assert( sceneDataStart == targetBuffer.TellMaxPut() ); for ( int i = 0; i < imageDirectory.Count(); i++ ) { int iScene = writeOrder[i]; targetBuffer.Put( g_SceneFiles[iScene].compiledBuffer.Base(), g_SceneFiles[iScene].compiledBuffer.TellMaxPut() ); } if ( !bQuiet ) { Msg( "Scenes: Final size: %.2f MB\n", targetBuffer.TellMaxPut() / (1024.0f * 1024.0f ) ); } // cleanup g_SceneFiles.Purge(); return true; }