int main(int argc, char* argv[]) { char cmd[512]; int ret; if( argc < 2 ) { return PrintUsage(); } // All output gets redirected to this file. SECURITY_ATTRIBUTES fileAttribs; fileAttribs.nLength = sizeof(fileAttribs); fileAttribs.lpSecurityDescriptor = NULL; fileAttribs.bInheritHandle = TRUE; g_hOutputFile = CreateFile( "vmapbuilder.out", GENERIC_WRITE, FILE_SHARE_READ, &fileAttribs, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH|FILE_ATTRIBUTE_NORMAL, NULL ); // Low priority.. SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS ); bool bSave = !FindArg( "-nosave" ); bool bNoVis = !!FindArg( "-novis" ); bool bNoRad = !!FindArg( "-norad" ); char const *pCFGFile = argv[1]; while( 1 ) { DWORD startTime = GetTickCount(); CConfigFile file; if( file.Read( pCFGFile ) && file.m_Entries.Size() > 0 ) { // Move the first entry in the file to the end. CConfigFile::Entry entry = file.m_Entries[0]; file.m_Entries.Remove( 0 ); file.m_Entries.AddToTail( entry ); if( bSave ) { file.Write( pCFGFile ); } char ssCmd[256]; _snprintf( ssCmd, sizeof(ssCmd), "%s\\win32\\ss.exe", file.m_SSDatabase ); // Grab the SourceSafe tree. AppPrint( "\n\n-------------------------------------------------------------\n" ); AppPrint( "Processing %s\n", entry.m_Filename ); AppPrint( "-------------------------------------------------------------\n" ); AppPrint( "Grabbing resources in %s\n", file.m_SSDatabase ); sprintf( cmd, "ssdir=%s", file.m_SSDatabase ); ret = _putenv( cmd ); // Get the VMF. char vmfFilename[512]; sprintf( vmfFilename, "%s/%s.vmf", entry.m_VMFPath, entry.m_Filename ); sprintf( cmd, "%s get %s -I-", ssCmd, vmfFilename ); ret = RunProcess( cmd ); // Check the timestamp (don't reprocess if it's up-to-date). sprintf( vmfFilename, "%s.vmf", entry.m_Filename ); struct _stat fileStat; ret = _stat( vmfFilename, &fileStat ); long vmfTime = fileStat.st_mtime; if( vmfTime == entry.m_VMFTime ) { AppPrint( "%s is up-to-date\n", vmfFilename ); } else { char localBSPFilename[512]; sprintf( localBSPFilename, "%s.bsp", entry.m_Filename ); // Attrib the bsp if it exists. sprintf( cmd, "attrib -r %s", localBSPFilename ); RunProcess( cmd ); sprintf( cmd, "%s cp %s", ssCmd, file.m_SSResourcePath ); ret = RunProcess( cmd ); if( !FindArg( "-noget" ) ) { sprintf( cmd, "%s get * -R -I-", ssCmd ); ret = RunProcess( cmd ); } // run each tool. char vbspCommand[256], vradCommand[256], vvisCommand[256]; sprintf( vbspCommand, "bin\\vbsp -low %s", entry.m_Filename ); if( entry.m_bFastVis ) sprintf( vvisCommand, "bin\\vvis -fast -low %s", entry.m_Filename ); else sprintf( vvisCommand, "bin\\vvis -low %s", entry.m_Filename ); sprintf( vradCommand, "bin\\vrad -low %s", entry.m_Filename ); if( !RunProcess( vbspCommand ) && (bNoVis || !RunProcess( vvisCommand )) && (bNoRad || !RunProcess( vradCommand )) ) { // Check in the BSP file. char bspFilename[512]; sprintf( bspFilename, "%s/%s.bsp", file.m_SSBSPPath, entry.m_Filename ); // First, try to add it to SS because it may not exist yet. sprintf( cmd, "%s cp %s", ssCmd, file.m_SSBSPPath ); RunProcess(cmd); sprintf( cmd, "%s add %s.bsp -I-", ssCmd, entry.m_Filename ); ret = RunProcess(cmd); // Store off the BSP file temporarily.. char tempFilename[512]; sprintf( localBSPFilename, "%s.bsp", entry.m_Filename ); sprintf( tempFilename, "%s.TEMP", entry.m_Filename ); sprintf( cmd, "del /f %s", tempFilename ); system( cmd ); sprintf( cmd, "attrib -r %s", localBSPFilename ); system( cmd ); ret = MoveFile( localBSPFilename, tempFilename ); if( ret ) { char undoCmd[512]; sprintf( undoCmd, "%s undocheckout %s -I-", ssCmd, bspFilename ); sprintf( cmd, "%s checkout %s -I-", ssCmd, bspFilename ); ret = RunProcess( cmd ); if( !ret ) { // Copy the new BSP file over. DeleteFile( localBSPFilename ); ret = MoveFile( tempFilename, localBSPFilename ); if( ret ) { sprintf( cmd, "%s checkin %s -I-", ssCmd, bspFilename ); ret = RunProcess( cmd ); if( !ret ) { while( !file.Read( pCFGFile ) ) { Sleep( 300 ); } if( bSave ) { CConfigFile::Entry *pEntry = file.FindEntryByFilename( entry.m_Filename ); if( pEntry ) { pEntry->m_VMFTime = vmfTime; while( !file.Write( pCFGFile ) ) { Sleep( 300 ); } } } // Update the timestamp in the config file. AppPrint( "Completed '%s' successfully!\n", entry.m_Filename ); // Send emails. char computerName[256] = {0}; DWORD len = sizeof(computerName); GetComputerName( computerName, &len ); DWORD elapsed = GetTickCount() - startTime; char timeStr[256]; BuildTimeDurationString( elapsed, timeStr ); char subject[1024]; _snprintf( subject, sizeof(subject), "[vmapbuilder] completed '%s' on '%s' in %s", entry.m_Filename, computerName, timeStr ); for( int e=0; e < entry.m_nEMailAddresses; e++ ) { char *pAddr = entry.m_EMailAddresses[e].m_EMailAddress; if( !SendMail( pAddr, subject, subject ) ) { AppPrint( "Unable to send confirmation email to %s\n", pAddr ); } } } else { AppPrint( "ERROR: Can't checkin %s\n", bspFilename ); RunProcess( undoCmd ); } } else { AppPrint( "ERROR: Can't copy back the BSP file %s\n", localBSPFilename ); RunProcess( undoCmd ); } } else { AppPrint( "ERROR: Can't checkout %s\n", bspFilename ); } } else { AppPrint( "ERROR: Can't create temporary file %s\n", tempFilename ); } } else { AppPrint( "Command '%s' failed\n", cmd ); } } } else { AppPrint( "Can't read maplist file: %s\n", pCFGFile ); } // Sleep for a bit in case all maps are processed so we don't kill the network. Sleep( 2000 ); } CloseHandle( g_hOutputFile ); return 0; }