source-engine/utils/xbox/MakeGameData/MakeGameData.cpp
FluorescentCIAAfricanAmerican 3bf9df6b27 1
2020-04-22 12:56:21 -04:00

1175 lines
31 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Generates a file list based on command line wildcard spec and drives
// conversion routines based on file extension. The conversion routines should be
// !!!elsewhere!!! in libraries that the game also uses at runtime to convert data.
// This tool as spec'd should just be file iteration.
//
//=====================================================================================//
#include "MakeGameData.h"
// MAKESCENESIMAGE is defined for the external tool. In general, it only
// supports the -pcscenes option. This gets built into MakeScenesImage.exe.
//-----------------------------------------------------------------------------
// The application object
//-----------------------------------------------------------------------------
class MakeGameDataApp : public CDefaultAppSystemGroup< CSteamAppSystemGroup >
{
public:
// Methods of IApplication
virtual bool Create();
virtual bool PreInit( );
virtual int Main();
virtual void PostShutdown();
};
DEFINE_CONSOLE_STEAM_APPLICATION_OBJECT( MakeGameDataApp );
char g_szSourcePath[MAX_PATH];
char g_targetPath[MAX_PATH];
char g_zipPath[MAX_PATH];
bool g_bForce;
bool g_bTest;
bool g_bMakeZip;
CXZipTool g_MasterXZip;
DiskWriteMode_t g_WriteModeForConversions;
char g_szGamePath[MAX_PATH];
char g_szModPath[MAX_PATH];
bool g_bModPathIsValid;
bool g_bQuiet;
bool g_bMakeScenes;
bool g_bMakeScenesPC;
bool g_bIsPlatformZip;
bool g_bUseMapList;
IPhysicsCollision *g_pPhysicsCollision;
CSysModule *g_pPhysicsModule;
CUtlVector< CUtlString > g_ValidMapList;
CUtlVector< errorList_t > g_errorList;
const char *g_GameNames[] =
{
"ep2",
"episodic",
"hl2",
"portal",
"platform",
"tf",
NULL
};
// all known languages
const char *g_pLanguageSuffixes[] =
{
"_dannish",
"_dutch",
"_english",
"_finnish",
"_french",
"_german",
"_italian",
"_japanese",
"_korean",
"_koreana",
"_norwegian",
"_polish",
"_portuguese",
"_russian",
"_russion_buka",
"_schinese",
"_spanish",
"_swedish",
"_tchinese",
"_thai",
};
// 360 is shipping with support for only these languages
const char *g_pTargetLanguageSuffixes[] =
{
"_english.",
"_french.",
"_german.",
};
// Master list of files that can go into the zip
static char *s_AllowedExtensionsInZip[] =
{
// Explicitly lacking from this list, thus excluded from the zip
// .ain - AINs are external to the zip
// .bsp - BSPs are external to the zip
// .mp3 - MP3s aren't supported
// Extensions with conversions
// Purposely using .360 encoding to ensure pc versions don't leak in
".360.wav",
".360.vtf",
".360.mdl",
".360.ani",
".dx90.360.vtx",
".360.vvd",
".360.phy",
".360.dat",
".360.lst",
".360.vcs",
".360.image",
".360.pcf",
// Extensions without conversions (taken as is)
".rc",
".txt",
".cfg",
".res",
".vfe",
".vbf",
".vmt",
".raw",
".lst",
".bns",
};
//-----------------------------------------------------------------------------
// Determine game path
//-----------------------------------------------------------------------------
void GetGamePath()
{
GetCurrentDirectory( sizeof( g_szGamePath ), g_szGamePath );
char szFullPath[MAX_PATH];
if ( _fullpath( szFullPath, g_szGamePath, sizeof( szFullPath ) ) )
{
strcpy( g_szGamePath, szFullPath );
}
V_AppendSlash( g_szGamePath, sizeof( g_szGamePath ) );
char *pGameDir = V_stristr( g_szGamePath, "game\\" );
if ( !pGameDir )
{
Msg( "ERROR: Failed to determine game directory from current path. Expecting 'game' in current path." );
exit( 1 );
}
// kill any trailing dirs
pGameDir[4] = '\0';
}
//-----------------------------------------------------------------------------
// Determine mod path
//-----------------------------------------------------------------------------
bool GetModPath()
{
char szDirectory[MAX_PATH];
char szLastDirectory[MAX_PATH];
// non destructively determine the mod directory
bool bFound = false;
szLastDirectory[0] = '\0';
GetCurrentDirectory( sizeof( szDirectory ), szDirectory );
while ( 1 )
{
V_ComposeFileName( szDirectory, "gameinfo.txt", g_szModPath, sizeof( g_szModPath ) );
struct _stat statBuf;
if ( _stat( g_szModPath, &statBuf ) != -1 )
{
bFound = true;
V_strncpy( g_szModPath, szDirectory, sizeof( g_szModPath ) );
break;
}
// previous dir
V_ComposeFileName( szDirectory, "..", g_szModPath, sizeof( g_szModPath ) );
char fullPath[MAX_PATH];
if ( _fullpath( fullPath, g_szModPath, sizeof( fullPath ) ) )
{
strcpy( szDirectory, fullPath );
}
if ( !V_stricmp( szDirectory, szLastDirectory ) )
{
// can back up no further
break;
}
strcpy( szLastDirectory, szDirectory );
}
if ( !bFound )
{
// use current directory instead
GetCurrentDirectory( sizeof( g_szModPath ), g_szModPath );
}
return bFound;
}
//-----------------------------------------------------------------------------
// Setup File system and search paths
//-----------------------------------------------------------------------------
bool SetupFileSystem()
{
if ( g_bModPathIsValid )
{
CFSSteamSetupInfo steamInfo;
steamInfo.m_pDirectoryName = g_szModPath;
steamInfo.m_bOnlyUseDirectoryName = true;
steamInfo.m_bToolsMode = true;
steamInfo.m_bSetSteamDLLPath = true;
steamInfo.m_bSteam = false;
if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
return false;
CFSMountContentInfo fsInfo;
fsInfo.m_pFileSystem = g_pFullFileSystem;
fsInfo.m_bToolsMode = true;
fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
if ( FileSystem_MountContent( fsInfo ) != FS_OK )
return false;
// Finally, load the search paths for the "GAME" path.
CFSSearchPathsInit searchPathsInit;
searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath;
searchPathsInit.m_pFileSystem = fsInfo.m_pFileSystem;
if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
return false;
char platform[MAX_PATH];
Q_strncpy( platform, steamInfo.m_GameInfoPath, MAX_PATH );
Q_StripTrailingSlash( platform );
Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH );
fsInfo.m_pFileSystem->AddSearchPath( platform, "PLATFORM" );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Helper utility, read file into buffer
//-----------------------------------------------------------------------------
bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning )
{
return scriptlib->ReadFileToBuffer( pSourceName, buffer, bText, bNoOpenFailureWarning );
}
//-----------------------------------------------------------------------------
// Purpose: Helper utility, Write buffer to file
//-----------------------------------------------------------------------------
bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, bool bWriteToZip, DiskWriteMode_t writeMode )
{
if ( g_bTest )
return true;
bool bSuccess = scriptlib->WriteBufferToFile( pTargetName, buffer, writeMode );
bool bZipSuccess = true;
if ( bSuccess && g_bMakeZip && !g_bTest && bWriteToZip )
{
if ( !g_MasterXZip.AddBuffer( pTargetName, buffer, true ) )
{
Msg( "WriteBufferToFile(): Error adding file %s\n", pTargetName );
bZipSuccess = false;
}
}
return bSuccess && bZipSuccess;
}
//-----------------------------------------------------------------------------
// Compress data
//-----------------------------------------------------------------------------
bool CompressCallback( CUtlBuffer &inputBuffer, CUtlBuffer &outputBuffer )
{
if ( !inputBuffer.TellPut() )
{
// nothing to do
return false;
}
unsigned int compressedSize;
unsigned char *pCompressedOutput = LZMA_OpportunisticCompress( (unsigned char *)inputBuffer.Base() + inputBuffer.TellGet(), inputBuffer.TellPut() - inputBuffer.TellGet(), &compressedSize );
if ( pCompressedOutput )
{
outputBuffer.EnsureCapacity( compressedSize );
outputBuffer.Put( pCompressedOutput, compressedSize );
free( pCompressedOutput );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Some converters need to run a final pass.
//-----------------------------------------------------------------------------
void DoPostProcessingFunctions( bool bWriteToZip )
{
if ( g_bMakeScenes || g_bMakeScenesPC )
{
// scenes are converted and aggregated into one image
CreateSceneImageFile( g_szModPath, bWriteToZip, g_bMakeScenesPC, g_bQuiet, g_WriteModeForConversions );
}
ProcessDXSupportConfig( bWriteToZip );
}
//-----------------------------------------------------------------------------
// Startup any conversion modules.
//-----------------------------------------------------------------------------
bool InitConversionModules()
{
return true;
}
//-----------------------------------------------------------------------------
// Shutdown and cleanup any conversion modules.
//-----------------------------------------------------------------------------
void ShutdownConversionModules()
{
}
//-----------------------------------------------------------------------------
// Purpose: Distribute to worker function
//-----------------------------------------------------------------------------
bool CreateTargetFile( const char *pSourceName, const char *pTargetName, fileType_e fileType, bool bWriteToZip )
{
// resolve relative source to absolute path
// same workers use subdir name to determine conversion parameters
char fullSourcePath[MAX_PATH];
if ( _fullpath( fullSourcePath, pSourceName, sizeof( fullSourcePath ) ) )
{
pSourceName = fullSourcePath;
}
// distribute to actual worker
// workers can expect exact final decorated filenames
bool bSuccess = false;
switch ( fileType )
{
case FILETYPE_UNKNOWN:
break;
case FILETYPE_VTF:
bSuccess = CreateTargetFile_VTF( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_WAV:
bSuccess = CreateTargetFile_WAV( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_MDL:
case FILETYPE_ANI:
case FILETYPE_VTX:
case FILETYPE_VVD:
case FILETYPE_PHY:
bSuccess = CreateTargetFile_Model( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_BSP:
bSuccess = CreateTargetFile_BSP( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_AIN:
bSuccess = CreateTargetFile_AIN( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_CCDAT:
bSuccess = CreateTargetFile_CCDAT( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_MP3:
bSuccess = CreateTargetFile_MP3( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_RESLST:
bSuccess = CreateTargetFile_RESLST( pSourceName, pTargetName, bWriteToZip );
break;
case FILETYPE_PCF:
bSuccess = CreateTargetFile_PCF( pSourceName, pTargetName, bWriteToZip );
break;
// others...
}
return bSuccess;
}
//-----------------------------------------------------------------------------
// Purpose: Determine file type based on source extension. Generate .360.xxx
// target name.
//-----------------------------------------------------------------------------
fileType_e ResolveFileType( const char *pSourceName, char *pTargetName, int targetNameSize )
{
char szFullSourcePath[MAX_PATH];
_fullpath( szFullSourcePath, pSourceName, sizeof( szFullSourcePath ) );
char sourceExtension[MAX_PATH];
V_ExtractFileExtension( pSourceName, sourceExtension, sizeof( sourceExtension ) );
// default unrecognized
fileType_e fileType = FILETYPE_UNKNOWN;
if ( !V_stricmp( sourceExtension, "wav" ) )
{
fileType = FILETYPE_WAV;
}
else if ( !V_stricmp( sourceExtension, "vtf" ) )
{
fileType = FILETYPE_VTF;
}
else if ( !V_stricmp( sourceExtension, "mdl" ) )
{
fileType = FILETYPE_MDL;
}
else if ( !V_stricmp( sourceExtension, "ani" ) )
{
fileType = FILETYPE_ANI;
}
else if ( !V_stricmp( sourceExtension, "vvd" ) )
{
fileType = FILETYPE_VVD;
}
else if ( !V_stricmp( sourceExtension, "phy" ) )
{
fileType = FILETYPE_PHY;
}
else if ( !V_stricmp( sourceExtension, "bsp" ) )
{
fileType = FILETYPE_BSP;
}
else if ( !V_stricmp( sourceExtension, "ain" ) )
{
fileType = FILETYPE_AIN;
}
else if ( !V_stricmp( sourceExtension, "dat" ) )
{
if ( V_stristr( pSourceName, "closecaption_" ) )
{
// only want closecaption dat files, ignore all others
fileType = FILETYPE_CCDAT;
}
}
else if ( !V_stricmp( sourceExtension, "vtx" ) )
{
if ( V_stristr( pSourceName, ".dx90" ) )
{
// only want dx90 version, ignore all others
fileType = FILETYPE_VTX;
}
}
else if ( !V_stricmp( sourceExtension, "mp3" ) )
{
// mp3's are already pre-converted into .360.wav
// slam the expected name here to simplify the external logic which will do the right thing
V_StripExtension( pSourceName, pTargetName, targetNameSize );
V_strcat( pTargetName, ".360.wav", targetNameSize );
return FILETYPE_MP3;
}
else if ( !V_stricmp( sourceExtension, "lst" ) )
{
if ( V_stristr( szFullSourcePath, "reslists_xbox\\" ) )
{
// only want reslists map versions, due to special processing, ignore all others
fileType = FILETYPE_RESLST;
}
}
else if ( !V_stricmp( sourceExtension, "pcf" ) )
{
fileType = FILETYPE_PCF;
}
else if ( !V_stricmp( sourceExtension, "image" ) )
{
if ( V_stristr( szFullSourcePath, "scenes\\" ) )
{
// only want scene image, ignore all others
fileType = FILETYPE_SCENEIMAGE;
}
}
if ( fileType != FILETYPE_UNKNOWN && !V_stristr( pSourceName, ".360." ) )
{
char targetExtension[MAX_PATH];
sprintf( targetExtension, ".360.%s", sourceExtension );
V_StripExtension( pSourceName, pTargetName, targetNameSize );
V_strcat( pTargetName, targetExtension, targetNameSize );
}
else
{
// unknown or already converted, target is same as input
V_strncpy( pTargetName, pSourceName, targetNameSize );
}
return fileType;
}
//-----------------------------------------------------------------------------
// Purpose: Returns TRUE if file is a known localized file.
//-----------------------------------------------------------------------------
bool IsLocalizedFile( const char *pFileName )
{
for ( int i = 0; i<ARRAYSIZE( g_pLanguageSuffixes ); i++ )
{
if ( V_stristr( pFileName, g_pLanguageSuffixes[i] ) )
{
// a localized file
return true;
}
}
// not a known localized file
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Returns TRUE if file is a supported localization.
//-----------------------------------------------------------------------------
bool IsLocalizedFileValid( const char *pFileName, const char *pLanguageSuffix )
{
// file is a localized version
if ( pLanguageSuffix )
{
if ( V_stristr( pFileName, pLanguageSuffix ) )
{
// allow it
return true;
}
return false;
}
// must match the target supported languages
for ( int i = 0; i < ARRAYSIZE( g_pTargetLanguageSuffixes ); i++ )
{
if ( V_stristr( pFileName, g_pTargetLanguageSuffixes[i] ) )
{
// allow it
return true;
}
}
// does not match a target language, not allowed
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Check against a list of allowed filetypes for inclusion in the zip
//-----------------------------------------------------------------------------
bool IncludeInZip( const char *pSourceName )
{
if ( g_bIsPlatformZip )
{
// only allow known valid platform directories
if ( !V_stristr( pSourceName, "materials\\" ) &&
!V_stristr( pSourceName, "resource\\" ) &&
!V_stristr( pSourceName, "vgui\\" ) )
{
// exclude it
return false;
}
}
for ( int i = 0; i < ARRAYSIZE( s_AllowedExtensionsInZip ); ++i )
{
const char *pAllowedExtension = s_AllowedExtensionsInZip[i];
if ( !V_stristr( pSourceName, pAllowedExtension ) )
{
continue;
}
if ( !V_stricmp( pAllowedExtension, ".lst" ) )
{
// only want ???_exclude.lst files
if ( V_stristr( pSourceName, "_exclude.lst" ) )
{
return true;
}
return false;
}
if ( !V_stricmp( pAllowedExtension, ".txt" ) || !V_stricmp( pAllowedExtension, ".360.dat" ) )
{
if ( IsLocalizedFile( pSourceName ) && !IsLocalizedFileValid( pSourceName ) )
{
// exclude unsupported languages
return false;
}
if ( !V_stricmp( pAllowedExtension, ".txt" ) && V_stristr( pSourceName, "closecaption_" ) )
{
// exclude all the closecaption_<language>.txt files
return false;
}
}
return true;
}
// exclude it
return false;
}
//-----------------------------------------------------------------------------
// Returns true if map is in list, otherwise false
//-----------------------------------------------------------------------------
bool IsMapNameInList( const char *pMapName, CUtlVector< CUtlString > &mapList )
{
char szBaseName[MAX_PATH];
V_FileBase( pMapName, szBaseName, sizeof( szBaseName ) );
V_strlower( szBaseName );
if ( mapList.Find( szBaseName ) != mapList.InvalidIndex() )
{
// found
return true;
}
// not found
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Get the list of valid BSPs
//-----------------------------------------------------------------------------
void BuildValidMapList( CUtlVector< CUtlString > &mapList )
{
char szFilename[MAX_PATH];
V_ComposeFileName( g_szModPath, "maplist.txt", szFilename, sizeof( szFilename ) );
CUtlBuffer buffer;
if ( !ReadFileToBuffer( szFilename, buffer, true, true ) )
{
return;
}
characterset_t breakSet;
CharacterSetBuild( &breakSet, "" );
char szToken[MAX_PATH];
char szMapName[MAX_PATH];
for ( ;; )
{
int nTokenSize = buffer.ParseToken( &breakSet, szToken, sizeof( szToken ) );
if ( nTokenSize <= 0 )
{
break;
}
// reslists are pc built, filenames can be sloppy
V_FileBase( szToken, szMapName, sizeof( szMapName ) );
V_strlower( szMapName );
mapList.AddToTail( szMapName );
}
}
#define DO_UPDATE 0x01
#define DO_ZIP 0x02
//-----------------------------------------------------------------------------
// Purpose: drive the file creation
//-----------------------------------------------------------------------------
void GenerateTargetFiles( CUtlVector<fileList_t> &fileList )
{
char sourcePath[MAX_PATH];
char sourceFile[MAX_PATH];
char targetFile[MAX_PATH];
struct _stat sourceStatBuf;
struct _stat targetStatBuf;
strcpy( sourcePath, g_szSourcePath );
V_StripFilename( sourcePath );
if ( !sourcePath[0] )
strcpy( sourcePath, "." );
V_AppendSlash( sourcePath, sizeof( sourcePath ) );
// default is to update and zip
CUtlVector< int > updateList;
updateList.AddMultipleToTail( fileList.Count() );
for ( int i=0; i<fileList.Count(); i++ )
{
updateList[i] = DO_UPDATE|DO_ZIP;
}
int numMatches = 0;
// build update list
for ( int i=0; i<fileList.Count(); i++ )
{
if ( fileList[i].fileName.IsEmpty() )
{
// ignore entries that have been culled
updateList[i] = 0;
continue;
}
const char *ptr = fileList[i].fileName.String();
if ( !strnicmp( ptr, ".\\", 2 ) )
ptr += 2;
else if ( !strnicmp( ptr, sourcePath, strlen( sourcePath ) ) )
ptr += strlen( sourcePath );
strcpy( sourceFile, sourcePath );
strcat( sourceFile, ptr );
strcpy( targetFile, g_targetPath );
strcat( targetFile, ptr );
fileType_e fileType = ResolveFileType( sourceFile, targetFile, sizeof( targetFile ) );
// check the target name for inclusion due to extension modifications
if ( !IncludeInZip( targetFile ) )
{
// exclude from zip
updateList[i] &= ~DO_ZIP;
}
if ( fileType == FILETYPE_UNKNOWN )
{
// No conversion function, can't do anything
updateList[i] &= ~DO_UPDATE;
continue;
}
else
{
// known filetype, which has a conversion
// the wildcard match may catch existing converted files, which need to be rejected
// cull exisiting conversions from the work list
// the non-converted filename is part of the same wildcard match, gets caught and resolved
// the non-converted filename will then go through the proper conversion path
if ( V_stristr( sourceFile, ".360." ) )
{
// cull completely
updateList[i] = 0;
continue;
}
}
if ( fileType == FILETYPE_BSP || fileType == FILETYPE_AIN || fileType == FILETYPE_RESLST )
{
if ( g_ValidMapList.Count() && !IsMapNameInList( sourceFile, g_ValidMapList ) )
{
// cull completely
updateList[i] = 0;
continue;
}
}
int retVal = _stat( sourceFile, &sourceStatBuf );
if ( retVal != 0 )
{
// couldn't get source, skip update or zip
updateList[i] = 0;
continue;
}
retVal = _stat( targetFile, &targetStatBuf );
if ( retVal != 0 )
{
// target doesn't exit, update is required
continue;
}
// track valid candidates
numMatches++;
if ( fileType == FILETYPE_MDL || fileType == FILETYPE_ANI || fileType == FILETYPE_VTX || fileType == FILETYPE_VVD || fileType == FILETYPE_PHY )
{
// models are converted in a pre-pass
// let the update logic run and catch the conversions for zipping
continue;
}
if ( !g_bForce )
{
if ( difftime( sourceStatBuf.st_mtime, targetStatBuf.st_mtime ) <= 0 )
{
// target is same or older, no update
updateList[i] &= ~DO_UPDATE;
}
}
}
// cleanse and determine totals, makes succeeding logic simpler
int numWorkItems = 0;
int numFilesToUpdate = 0;
int numFilesToZip = 0;
for ( int i=0; i<fileList.Count(); i++ )
{
if ( updateList[i] & DO_UPDATE )
{
numFilesToUpdate++;
}
if ( g_bMakeZip && ( updateList[i] & DO_ZIP ) )
{
numFilesToZip++;
}
else
{
updateList[i] &= ~DO_ZIP;
}
if ( updateList[i] )
{
numWorkItems++;
}
}
Msg( "\n" );
Msg( "Matched %d/%d files.\n", numMatches, fileList.Count() );
Msg( "Creating or Updating %d files.\n", numFilesToUpdate );
if ( g_bMakeZip )
{
Msg( "Zipping %d files.\n", numFilesToZip );
}
InitConversionModules();
if ( numFilesToZip && !g_bTest )
{
Msg( "Creating Zip: %s\n", g_zipPath );
if ( !g_MasterXZip.Begin( g_zipPath, XBOX_DVD_SECTORSIZE ) )
{
Msg( "ERROR: Failed to open \"%s\" for writing.\n", g_zipPath );
return;
}
else
{
SetupCriticalPreloadScript( g_szModPath );
}
}
// iterate work list
int progress = 0;
for ( int i=0; i<fileList.Count(); i++ )
{
if ( !updateList[i] )
{
// no update or zip needed, skip
continue;
}
const char *ptr = fileList[i].fileName.String();
if ( !strnicmp( ptr, ".\\", 2 ) )
ptr += 2;
else if ( !strnicmp( ptr, sourcePath, strlen( sourcePath ) ) )
ptr += strlen( sourcePath );
strcpy( sourceFile, sourcePath );
strcat( sourceFile, ptr );
strcpy( targetFile, g_targetPath );
strcat( targetFile, ptr );
fileType_e fileType = ResolveFileType( sourceFile, targetFile, sizeof( targetFile ) );
if ( !g_bQuiet )
{
Msg( "%d/%d:%s -> %s\n", progress+1, numWorkItems, sourceFile, targetFile );
}
bool bSuccess = true;
if ( updateList[i] & DO_UPDATE )
{
// generate target file (and optionally zip output)
bSuccess = CreateTargetFile( sourceFile, targetFile, fileType, (updateList[i] & DO_ZIP) != 0 );
if ( !bSuccess )
{
// add to error list
int error = g_errorList.AddToTail();
g_errorList[error].result = false;
g_errorList[error].fileName.Set( sourceFile );
}
}
else if ( updateList[i] & DO_ZIP )
{
// existing target file is zipped
CUtlBuffer targetBuffer;
bSuccess = scriptlib->ReadFileToBuffer( targetFile, targetBuffer );
if ( bSuccess )
{
if ( !g_bTest )
{
bSuccess = g_MasterXZip.AddBuffer( targetFile, targetBuffer, true );
}
}
if ( !bSuccess )
{
// add to error list
int error = g_errorList.AddToTail();
g_errorList[error].result = false;
g_errorList[error].fileName.Set( targetFile );
}
}
progress++;
}
DoPostProcessingFunctions( !g_bTest );
ShutdownConversionModules();
if ( numFilesToZip && !g_bTest )
{
g_MasterXZip.End();
}
// iterate error list
Msg( "\n" );
for ( int i = 0; i < g_errorList.Count(); i++ )
{
Msg( "ERROR: could not process %s\n", g_errorList[i].fileName.String() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Spew Usage
//-----------------------------------------------------------------------------
void Usage()
{
Msg( "usage: MakeGameData [filemask] [options]\n" );
Msg( "options:\n" );
Msg( "[-v] Version\n" );
Msg( "[-q] Quiet (critical spew only)\n" );
Msg( "[-h] [-help] [-?] Help\n" );
Msg( "[-t targetPath] Alternate output path, will generate output at target\n" );
Msg( "[-r] [-recurse] Recurse into source directory\n" );
Msg( "[-f] [-force] Force update, otherwise checks timestamps\n" );
Msg( "[-test] Skip writing to disk\n" );
Msg( "[-z <zipname>] Generate zip file AND create or update stale conversions\n" );
Msg( "[-zo <zipname>] Generate zip file ONLY (existing stale conversions get updated, no new conversions are written)\n" );
Msg( "[-preloadinfo] Spew contents of preload section in zip\n" );
Msg( "[-xmaquality <quality>] XMA Encoding quality override, [0-100]\n" );
Msg( "[-scenes] Make 360 scene image cache.\n" );
Msg( "[-pcscenes] Make PC scene image cache.\n" );
Msg( "[-usemaplist] For BSP related conversions, restricts to maplist.txt.\n" );
exit( 1 );
}
//-----------------------------------------------------------------------------
// Purpose: default output func
//-----------------------------------------------------------------------------
SpewRetval_t OutputFunc( SpewType_t spewType, char const *pMsg )
{
printf( pMsg );
if ( spewType == SPEW_ERROR )
{
return SPEW_ABORT;
}
return ( spewType == SPEW_ASSERT ) ? SPEW_DEBUGGER : SPEW_CONTINUE;
}
//-----------------------------------------------------------------------------
// The application object
//-----------------------------------------------------------------------------
bool MakeGameDataApp::Create()
{
SpewOutputFunc( OutputFunc );
AppSystemInfo_t appSystems[] =
{
{ "mdllib.dll", MDLLIB_INTERFACE_VERSION },
{ "", "" } // Required to terminate the list
};
AddSystem( g_pDataModel, VDATAMODEL_INTERFACE_VERSION );
AddSystem( g_pDmSerializers, DMSERIALIZERS_INTERFACE_VERSION );
// Load vphysics.dll
if ( !Sys_LoadInterface( "vphysics.dll", VPHYSICS_COLLISION_INTERFACE_VERSION, &g_pPhysicsModule, (void**)&g_pPhysicsCollision ) )
{
Msg( "Failed to load vphysics interface\n" );
return false;
}
bool bOk = AddSystems( appSystems );
if ( !bOk )
return false;
return true;
}
bool MakeGameDataApp::PreInit()
{
CreateInterfaceFn factory = GetFactory();
ConnectTier1Libraries( &factory, 1 );
ConnectTier2Libraries( &factory, 1 );
if ( !g_pFullFileSystem || !g_pDataModel || !g_pPhysicsCollision || !mdllib )
{
Warning( "MakeGameData is missing a required interface!\n" );
return false;
}
return true;
}
void MakeGameDataApp::PostShutdown()
{
if ( g_pPhysicsModule )
{
Sys_UnloadModule( g_pPhysicsModule );
g_pPhysicsModule = NULL;
g_pPhysicsCollision = NULL;
}
DisconnectTier2Libraries();
DisconnectTier1Libraries();
}
//-----------------------------------------------------------------------------
// main
//
//-----------------------------------------------------------------------------
int MakeGameDataApp::Main()
{
int argnum;
// set the valve library printer
SpewOutputFunc( OutputFunc );
Msg( "\nMAKEGAMEDATA - Valve Xbox 360 Game Data Compiler (Build: %s %s)\n", __DATE__, __TIME__ );
Msg( "(C) Copyright 1996-2006, Valve Corporation, All rights reserved.\n\n" );
if ( CommandLine()->FindParm( "-v" ) || CommandLine()->FindParm( "-version" ) )
{
// spew just the version, used by batches for logging
return 0;
}
#ifndef MAKESCENESIMAGE
if ( CommandLine()->ParmCount() < 2 || CommandLine()->FindParm( "?" ) || CommandLine()->FindParm( "-h" ) || CommandLine()->FindParm( "-help" ) )
{
Usage();
}
#endif // MAKESCENESIMAGE
bool bHasFileMask = false;
const char *pFirstArg = CommandLine()->GetParm( 1 );
if ( pFirstArg[0] == '-' )
{
// first arg is an option, assume *.*
strcpy( g_szSourcePath, "*.*" );
}
else
{
strcpy( g_szSourcePath, pFirstArg );
bHasFileMask = true;
}
bool bRecurse = false;
#ifndef MAKESCENESIMAGE
bRecurse = CommandLine()->FindParm( "-recurse" ) || CommandLine()->FindParm( "-r" );
g_bForce = CommandLine()->FindParm( "-force" ) || CommandLine()->FindParm( "-f" );
g_bTest = CommandLine()->FindParm( "-test" ) != 0;
g_bQuiet = CommandLine()->FindParm( "-quiet" ) || CommandLine()->FindParm( "-q" );
g_bMakeScenes = CommandLine()->FindParm( "-scenes" ) != 0;
g_bMakeScenesPC = CommandLine()->FindParm( "-pcscenes" ) != 0;
#else
g_bMakeScenesPC = true;
#endif // MAKESCENESIMAGE
#ifndef MAKESCENESIMAGE
g_bUseMapList = CommandLine()->FindParm( "-usemaplist" ) != 0;
#endif // MAKESCENESIMAGE
// Set up zip file options
g_WriteModeForConversions = WRITE_TO_DISK_ALWAYS;
argnum = CommandLine()->FindParm( "-z" );
if ( argnum )
{
strcpy( g_szSourcePath, "*.*" );
g_bMakeZip = true;
g_bMakeScenes = true;
bRecurse = true;
}
else
{
argnum = CommandLine()->FindParm( "-zo" );
if ( argnum )
{
strcpy( g_szSourcePath, "*.*" );
g_bMakeZip = true;
g_bMakeScenes = true;
g_WriteModeForConversions = WRITE_TO_DISK_UPDATE;
bRecurse = true;
}
}
if ( g_bMakeZip )
{
strcat( g_zipPath, CommandLine()->GetParm( argnum + 1 ) );
}
// default target path is source
strcpy( g_targetPath, g_szSourcePath );
V_StripFilename( g_targetPath );
if ( !g_targetPath[0] )
{
strcpy( g_targetPath, "." );
}
// override via command line
argnum = CommandLine()->FindParm( "-t" );
if ( argnum )
{
V_strcpy_safe( g_targetPath, CommandLine()->GetParm( argnum + 1 ) );
}
V_AppendSlash( g_targetPath, sizeof( g_targetPath ) );
if ( CommandLine()->FindParm( "-preloadinfo" ) )
{
g_MasterXZip.SpewPreloadInfo( g_szSourcePath );
return 0;
}
#ifndef MAKESCENESIMAGE
GetGamePath();
#endif // MAKESCENESIMAGE
g_bModPathIsValid = GetModPath();
if ( !SetupFileSystem() )
{
Msg( "ERROR: Failed to setup file system.\n" );
exit( 1 );
}
// data model initialization
g_pDataModel->SetUndoEnabled( false );
g_pDataModel->OnlyCreateUntypedElements( true );
g_pDataModel->SetDefaultElementFactory( NULL );
g_bIsPlatformZip = g_bMakeZip && ( V_stristr( g_szModPath, "\\platform" ) != NULL );
// cleanup any zombie temp files left from a possible prior abort or error
scriptlib->DeleteTemporaryFiles( "mgd_*.tmp" );
if ( g_bMakeZip || g_bUseMapList )
{
// zips use the map list to narrow the bsp conversion to actual shipping maps
BuildValidMapList( g_ValidMapList );
}
CUtlVector<fileList_t> fileList;
if ( bHasFileMask || g_bMakeZip )
{
scriptlib->FindFiles( g_szSourcePath, bRecurse, fileList );
}
// model conversions require seperate pre-processing to achieve grouping
if ( !PreprocessModelFiles( fileList ) )
{
return 0;
}
GenerateTargetFiles( fileList );
return 0;
}