📄 vmapbuilder.cpp
字号:
// This program is meant to be left running on a machine.
// It sits in a while loop doing these steps:
// - Read the vmapbuilder.cfg file, which has a list of .vmf files, their matching .bsp files,
// and .vmf file dates telling the last time vmapbuilder built the file.
// - Grab the top filename, move it to the bottom, and re-save the cfg file.
// - Grab the .VMF file. If its date does not match the one from the .cfg file, then proceed,
// otherwise, start back at step 1.
// - Grab the HL2 or TF2 trees.
// - Run vbsp, vrad, and vvis on the map.
// - Checks out and checks in the .bsp.
// Note: the way the program reads and writes the .cfg file allows there to be any
// number of machines processing the list of maps, as long as they all are reading
// from the same vmapbuilder.cfg file. This can reduce turnaround time greatly.
#include "stdafx.h"
#include "utlvector.h"
#define MAX_FILENAME_LEN 256
HANDLE g_hOutputFile = 0;
// -------------------------------------------------------------------------------- //
// Config file reader.
// -------------------------------------------------------------------------------- //
class CConfigFile
{
public:
class EMailAddress
{
public:
char m_EMailAddress[MAX_FILENAME_LEN];
};
class Entry
{
public:
enum {MAX_EMAIL_ADDRESSES=128};
Entry()
{
m_nEMailAddresses = 0;
m_bFastVis = false;
}
EMailAddress m_EMailAddresses[MAX_EMAIL_ADDRESSES];
int m_nEMailAddresses;
char m_Filename[MAX_FILENAME_LEN];
char m_VMFPath[MAX_FILENAME_LEN];
long m_VMFTime; // Last time the VMF file was successfully reprocessed.
bool m_bFastVis;
};
public:
void Term();
bool Read( char const *pFilename );
bool Write( char const *pFilename );
Entry* FindEntryByFilename( char const *pFilename );
public:
char m_SSDatabase[MAX_FILENAME_LEN]; // \\jeeves\hl2vss
char m_SSResourcePath[MAX_FILENAME_LEN]; // $/HL2/Release/Dev
char m_SSBSPPath[MAX_FILENAME_LEN]; // $/HL2/Release/Dev/hl2/maps
CUtlVector<Entry> m_Entries;
private:
// Fill in pDest with the next token. Return false if there is no next token.
bool GetNextToken( FILE *fp, char *pDest, int destLen );
// Return true if the next token is equal to pTest.
bool VerifyNextToken( FILE *fp, char const *pTest );
bool IsWhitespace( char ch );
};
void CConfigFile::Term()
{
m_Entries.Purge();
m_SSDatabase[0] = m_SSResourcePath[0] = m_SSBSPPath[0] = 0;
}
bool CConfigFile::Read( char const *pFilename )
{
Term();
// Read in the whole file.
FILE *fp = fopen( pFilename, "rt" );
if( !fp )
return false;
int iCurPos = 0;
if( !VerifyNextToken( fp, "ssdatabase" ) ||
!GetNextToken( fp, m_SSDatabase, sizeof(m_SSDatabase) ) )
{
fclose( fp );
return false;
}
if( !VerifyNextToken( fp, "resourcepath" ) ||
!GetNextToken( fp, m_SSResourcePath, sizeof(m_SSResourcePath) ) )
{
fclose( fp );
return false;
}
if( !VerifyNextToken( fp, "bsppath" ) ||
!GetNextToken( fp, m_SSBSPPath, sizeof(m_SSBSPPath) ) )
{
fclose( fp );
return false;
}
while( VerifyNextToken( fp, "file" ) )
{
CConfigFile::Entry entry;
char timeStr[512];
if( !GetNextToken( fp, entry.m_Filename, sizeof(entry.m_Filename) ) ||
!GetNextToken( fp, entry.m_VMFPath, sizeof(entry.m_VMFPath) ) ||
!GetNextToken( fp, timeStr, sizeof(timeStr) )
)
{
fclose( fp );
return false;
}
entry.m_VMFTime = atoi( timeStr );
// Read the email addresses.
while(1)
{
char token[1024];
int curPos = ftell( fp );
if( entry.m_nEMailAddresses < CConfigFile::Entry::MAX_EMAIL_ADDRESSES &&
GetNextToken( fp, token, sizeof(token) ) )
{
if( stricmp( token, "-email" ) == 0 )
{
CConfigFile::EMailAddress *addr = &entry.m_EMailAddresses[entry.m_nEMailAddresses];
if( !GetNextToken( fp, addr->m_EMailAddress, sizeof(addr->m_EMailAddress) ) )
{
delete addr;
fclose( fp );
return false;
}
++entry.m_nEMailAddresses;
continue;
}
else if( stricmp( token, "-fast" ) == 0 )
{
entry.m_bFastVis = true;
continue;
}
}
// No more options..
fseek( fp, curPos, SEEK_SET );
break;
}
m_Entries.AddToTail( entry );
}
fclose( fp );
return true;
}
bool CConfigFile::Write( char const *pFilename )
{
FILE *fp = fopen( pFilename, "wt" );
if( !fp )
return false;
fprintf( fp, "ssdatabase %s\n", m_SSDatabase );
fprintf( fp, "resourcepath %s\n", m_SSResourcePath );
fprintf( fp, "bsppath %s\n", m_SSBSPPath );
for( int i=0; i < m_Entries.Size(); i++ )
{
CConfigFile::Entry *pEntry = &m_Entries[i];
fprintf( fp, "file %s %s %d", pEntry->m_Filename, pEntry->m_VMFPath, pEntry->m_VMFTime );
for( int e=0; e < pEntry->m_nEMailAddresses; e++ )
fprintf( fp, " -email %s", pEntry->m_EMailAddresses[e].m_EMailAddress );
if( pEntry->m_bFastVis )
fprintf( fp, " -fast" );
fprintf( fp, "\n" );
}
fclose( fp );
return true;
}
CConfigFile::Entry* CConfigFile::FindEntryByFilename( char const *pFilename )
{
for( int i=0; i < m_Entries.Size(); i++ )
{
if( stricmp( m_Entries[i].m_Filename, pFilename ) == 0 )
return &m_Entries[i];
}
return NULL;
}
bool CConfigFile::GetNextToken( FILE *fp, char *pDest, int destLen )
{
// Eat up whitespace..
char ch = 0;
while( IsWhitespace( ch = fgetc(fp) ) )
{
;
}
if( ch == EOF )
return false;
int iDestPos = 0;
while( iDestPos < destLen )
{
pDest[iDestPos] = ch;
++iDestPos;
ch = fgetc( fp );
if( IsWhitespace( ch ) || ch == EOF )
{
pDest[iDestPos] = 0;
return true;
}
}
return false;
}
bool CConfigFile::VerifyNextToken( FILE *fp, char const *pTest )
{
char token[2048];
if( !GetNextToken( fp, token, sizeof(token) ) )
return false;
return stricmp( token, pTest ) == 0;
}
bool CConfigFile::IsWhitespace( char ch )
{
return ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t';
}
// -------------------------------------------------------------------------------- //
// Global code.
// -------------------------------------------------------------------------------- //
// Send an email to someone..
typedef ULONG (FAR PASCAL *MAPISendMailFn)(
LHANDLE lhSession,
ULONG ulUIParam,
lpMapiMessage lpMessage,
FLAGS flFlags,
ULONG ulReserved
);
bool SendMail( char *pTo, char *pSubject, char *pText )
{
char const *pLib = "MAPI32.DLL";
char to[1024];
_snprintf( to, sizeof(to), "SMTP:%s", pTo );
HINSTANCE hMAPI = LoadLibrary( pLib );
if( !hMAPI )
return false;
MAPISendMailFn fn = (MAPISendMailFn)GetProcAddress( hMAPI, "MAPISendMail" );
if( !fn )
{
FreeLibrary( hMAPI );
return false;
}
MapiRecipDesc recip =
{
0, // reserved
MAPI_TO, // who it goes to
to,
to,
0,
0
};
MapiMessage note = {0, // reserved, must be 0
(char*)pSubject, // subject
(char*)pText, // note text
NULL, // NULL = interpersonal message
NULL, // no date; MAPISendMail ignores it
NULL, // no conversation ID
0L, // no flags, MAPISendMail ignores it
NULL, // no originator, this is ignored too
1, // one recipient
&recip, // NULL recipient array
0, // no attachment
NULL }; // the attachment structure
// Store this off..
char workingDir[256];
GetCurrentDirectory( sizeof(workingDir), workingDir );
long bRet = fn(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -