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.

932 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: vcd_sound_check.cpp : Defines the entry point for the console application.
  4. //
  5. //=============================================================================//
  6. #include <stdio.h>
  7. #include <windows.h>
  8. #include "tier0/dbg.h"
  9. #include "tier1/utldict.h"
  10. #include "filesystem.h"
  11. #include "FileSystem_Tools.h"
  12. #include "tier1/KeyValues.h"
  13. #include "cmdlib.h"
  14. #include "scriplib.h"
  15. #include "vstdlib/random.h"
  16. #include "choreoscene.h"
  17. #include "choreoevent.h"
  18. #include "iscenetokenprocessor.h"
  19. #include "tier1/utlbuffer.h"
  20. #include "tier1/checksum_crc.h"
  21. #include "pacifier.h"
  22. #include "SceneCache.h"
  23. #include "SoundEmitterSystem/isoundemittersystembase.h"
  24. #include "ModelSoundsCache.h"
  25. #include "Datacache/imdlcache.h"
  26. #include "datacache/idatacache.h"
  27. #include "studio.h"
  28. #include "appframework/appframework.h"
  29. #include "tier0/icommandline.h"
  30. #include "istudiorender.h"
  31. #include "materialsystem/imaterialsystem.h"
  32. #include "vphysics_interface.h"
  33. #include "icvar.h"
  34. #include "vstdlib/cvar.h"
  35. #include "eventlist.h"
  36. // #define TESTING 1
  37. bool uselogfile = false;
  38. bool modelsoundscache = false;
  39. bool scenecache = false;
  40. bool virtualmodel = false;
  41. bool buildxcds = false;
  42. struct AnalysisData
  43. {
  44. CUtlSymbolTable symbols;
  45. };
  46. static AnalysisData g_Analysis;
  47. static char g_szCurrentGameDir[ 512 ];
  48. IFileSystem *filesystem = NULL;
  49. IMDLCache *g_pMDLCache = NULL;
  50. ISoundEmitterSystemBase *soundemitterbase = NULL;
  51. static CUniformRandomStream g_Random;
  52. IUniformRandomStream *random = &g_Random;
  53. static bool spewed = false;
  54. static CUtlCachedFileData< CSceneCache > g_SceneCache( "scene.cache", SCENECACHE_VERSION, 0, UTL_CACHED_FILE_USE_FILESIZE );
  55. static CUtlCachedFileData< CModelSoundsCache > g_ModelSoundsCache( "modelsounds.cache", MODELSOUNDSCACHE_VERSION, 0, UTL_CACHED_FILE_USE_FILESIZE );
  56. //-----------------------------------------------------------------------------
  57. // FIXME: This trashy glue code is really not acceptable. Figure out a way of making it unnecessary.
  58. //-----------------------------------------------------------------------------
  59. const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName ) const
  60. {
  61. MDLHandle_t handle = g_pMDLCache->FindMDL( pModelName );
  62. *cache = (void*)handle;
  63. return g_pMDLCache->GetStudioHdr( handle );
  64. }
  65. virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const
  66. {
  67. return g_pMDLCache->GetVirtualModel( (MDLHandle_t)virtualModel );
  68. }
  69. byte *studiohdr_t::GetAnimBlock( int i ) const
  70. {
  71. return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i );
  72. }
  73. int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const
  74. {
  75. return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut );
  76. }
  77. const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const
  78. {
  79. return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache );
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Helper for parsing scene data file
  83. //-----------------------------------------------------------------------------
  84. class CSceneTokenProcessor : public ISceneTokenProcessor
  85. {
  86. public:
  87. const char *CurrentToken( void );
  88. bool GetToken( bool crossline );
  89. bool TokenAvailable( void );
  90. void Error( const char *fmt, ... );
  91. };
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. // Output : const char
  95. //-----------------------------------------------------------------------------
  96. const char *CSceneTokenProcessor::CurrentToken( void )
  97. {
  98. return token;
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. // Input : crossline -
  103. // Output : Returns true on success, false on failure.
  104. //-----------------------------------------------------------------------------
  105. bool CSceneTokenProcessor::GetToken( bool crossline )
  106. {
  107. return ::GetToken( crossline ) ? true : false;
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose:
  111. // Output : Returns true on success, false on failure.
  112. //-----------------------------------------------------------------------------
  113. bool CSceneTokenProcessor::TokenAvailable( void )
  114. {
  115. return ::TokenAvailable() ? true : false;
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Purpose:
  119. // Input : *fmt -
  120. // ... -
  121. //-----------------------------------------------------------------------------
  122. void CSceneTokenProcessor::Error( const char *fmt, ... )
  123. {
  124. char string[ 2048 ];
  125. va_list argptr;
  126. va_start( argptr, fmt );
  127. Q_vsnprintf( string, sizeof(string), fmt, argptr );
  128. va_end( argptr );
  129. Warning( "%s", string );
  130. Assert(0);
  131. }
  132. static CSceneTokenProcessor g_TokenProcessor;
  133. SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
  134. {
  135. spewed = true;
  136. printf( "%s", pMsg );
  137. OutputDebugString( pMsg );
  138. if ( type == SPEW_ERROR )
  139. {
  140. printf( "\n" );
  141. OutputDebugString( "\n" );
  142. }
  143. return SPEW_CONTINUE;
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose:
  147. // Input : depth -
  148. // *fmt -
  149. // ... -
  150. //-----------------------------------------------------------------------------
  151. void vprint( int depth, const char *fmt, ... )
  152. {
  153. char string[ 8192 ];
  154. va_list va;
  155. va_start( va, fmt );
  156. vsprintf( string, fmt, va );
  157. va_end( va );
  158. FILE *fp = NULL;
  159. if ( uselogfile )
  160. {
  161. fp = fopen( "log.txt", "ab" );
  162. }
  163. while ( depth-- > 0 )
  164. {
  165. printf( " " );
  166. OutputDebugString( " " );
  167. if ( fp )
  168. {
  169. fprintf( fp, " " );
  170. }
  171. }
  172. ::printf( "%s", string );
  173. OutputDebugString( string );
  174. if ( fp )
  175. {
  176. char *p = string;
  177. while ( *p )
  178. {
  179. if ( *p == '\n' )
  180. {
  181. fputc( '\r', fp );
  182. }
  183. fputc( *p, fp );
  184. p++;
  185. }
  186. fclose( fp );
  187. }
  188. }
  189. void logprint( char const *logfile, const char *fmt, ... )
  190. {
  191. char string[ 8192 ];
  192. va_list va;
  193. va_start( va, fmt );
  194. vsprintf( string, fmt, va );
  195. va_end( va );
  196. FILE *fp = NULL;
  197. static bool first = true;
  198. if ( first )
  199. {
  200. first = false;
  201. fp = fopen( logfile, "wb" );
  202. }
  203. else
  204. {
  205. fp = fopen( logfile, "ab" );
  206. }
  207. if ( fp )
  208. {
  209. char *p = string;
  210. while ( *p )
  211. {
  212. if ( *p == '\n' )
  213. {
  214. fputc( '\r', fp );
  215. }
  216. fputc( *p, fp );
  217. p++;
  218. }
  219. fclose( fp );
  220. }
  221. }
  222. void Con_Printf( const char *fmt, ... )
  223. {
  224. va_list args;
  225. static char output[1024];
  226. va_start( args, fmt );
  227. vprintf( fmt, args );
  228. vsprintf( output, fmt, args );
  229. vprint( 0, output );
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose:
  233. //-----------------------------------------------------------------------------
  234. void printusage( void )
  235. {
  236. vprint( 0, "usage: makexvcd [options] -game gamedir\n\
  237. \t-v = verbose output\n\
  238. \t-m = rebuild modelsounds.cache\n\
  239. \t-x = rebuild .xcd files\n\
  240. \t-s = rebuild scene.cache\n\
  241. \t-z = rebuild virtualmodel.cache (xbox only)\n\
  242. \t-l = log to file log.txt\n\
  243. \ne.g.: makexvcd -s -m -game episodic\n" );
  244. // Exit app
  245. exit( 1 );
  246. }
  247. void BuildFileList_R( CUtlVector< CUtlSymbol >& files, char const *dir, char const *extension )
  248. {
  249. WIN32_FIND_DATA wfd;
  250. char directory[ 256 ];
  251. char filename[ 256 ];
  252. HANDLE ff;
  253. Q_snprintf( directory, sizeof( directory ), "%s\\*.*", dir );
  254. #if defined( TESTING )
  255. if ( files.Count() > 100 )
  256. return;
  257. #endif
  258. if ( ( ff = FindFirstFile( directory, &wfd ) ) == INVALID_HANDLE_VALUE )
  259. return;
  260. int extlen = strlen( extension );
  261. do
  262. {
  263. #if defined( TESTING )
  264. if ( files.Count() > 100 )
  265. return;
  266. #endif
  267. if ( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  268. {
  269. if ( wfd.cFileName[ 0 ] == '.' )
  270. continue;
  271. // Recurse down directory
  272. Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName );
  273. BuildFileList_R( files, filename, extension );
  274. }
  275. else
  276. {
  277. int len = strlen( wfd.cFileName );
  278. if ( len > extlen )
  279. {
  280. if ( !stricmp( &wfd.cFileName[ len - extlen ], extension ) )
  281. {
  282. char filename[ MAX_PATH ];
  283. Q_snprintf( filename, sizeof( filename ), "%s\\%s", dir, wfd.cFileName );
  284. _strlwr( filename );
  285. Q_FixSlashes( filename );
  286. CUtlSymbol sym = g_Analysis.symbols.AddString( filename );
  287. files.AddToTail( sym );
  288. if ( !( files.Count() % 3000 ) )
  289. {
  290. vprint( 0, "...found %i .%s files\n", files.Count(), extension );
  291. }
  292. }
  293. }
  294. }
  295. } while ( FindNextFile( ff, &wfd ) );
  296. }
  297. void BuildFileList( char const *basedir, CUtlVector< CUtlSymbol >& files, char const *rootdir, char const *extension )
  298. {
  299. files.RemoveAll();
  300. char root[ 512 ];
  301. Q_snprintf( root, sizeof( root ), "%s\\%s", basedir, rootdir );
  302. BuildFileList_R( files, root, extension );
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Purpose:
  306. //-----------------------------------------------------------------------------
  307. void CheckLogFile( void )
  308. {
  309. if ( uselogfile )
  310. {
  311. _unlink( "log.txt" );
  312. vprint( 0, " Outputting to log.txt\n" );
  313. }
  314. }
  315. void PrintHeader()
  316. {
  317. vprint( 0, "Valve Software - CompileVCD.exe (%s)\n", __DATE__ );
  318. vprint( 0, "--- Binary .vcd compiler ---\n" );
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: For each .wav file in the list, see if any vcd file in the list references it
  322. // First build an index of .wav to .vcd mappings, then search wav list and print results
  323. // Input : vcdfiles -
  324. // wavfiles -
  325. //-----------------------------------------------------------------------------
  326. struct VCDList
  327. {
  328. VCDList()
  329. {
  330. }
  331. VCDList( const VCDList& src )
  332. {
  333. int c = src.vcds.Count();
  334. for ( int i = 0 ; i < c; i++ )
  335. {
  336. vcds.AddToTail( src.vcds[ i ] );
  337. }
  338. }
  339. VCDList& operator =( const VCDList& src )
  340. {
  341. if ( this == &src )
  342. return *this;
  343. int c = src.vcds.Count();
  344. for ( int i = 0 ; i < c; i++ )
  345. {
  346. vcds.AddToTail( src.vcds[ i ] );
  347. }
  348. return *this;
  349. }
  350. CUtlVector< CUtlSymbol > vcds;
  351. };
  352. void AppendDisposition( CUtlVector< CUtlSymbol >& disposition, char const *fmt, ... )
  353. {
  354. char string[ 2048 ];
  355. va_list argptr;
  356. va_start( argptr, fmt );
  357. _vsnprintf( string, sizeof( string ), fmt, argptr );
  358. va_end( argptr );
  359. CUtlSymbol sym;
  360. sym = string;
  361. disposition.AddToTail( sym );
  362. }
  363. CChoreoScene *BlockingLoadScene( char const *vcdname )
  364. {
  365. // Load the .vcd
  366. char scenefile[ MAX_PATH ];
  367. Q_snprintf( scenefile, sizeof( scenefile ), "%s\\%s", g_szCurrentGameDir, vcdname );
  368. LoadScriptFile( scenefile );
  369. CChoreoScene *scene = ChoreoLoadScene( scenefile, NULL, &g_TokenProcessor, Con_Printf );
  370. return scene;
  371. }
  372. void ProcessVCD( char const *vcdname, CUtlVector< CUtlSymbol >& disposition )
  373. {
  374. if ( verbose )
  375. {
  376. vprint( 0, "Processing '%s'\n", vcdname );
  377. }
  378. bool rebuild = false;
  379. FileHandle_t fh = filesystem->Open( vcdname, "rb", "GAME" );
  380. if ( fh == FILESYSTEM_INVALID_HANDLE )
  381. {
  382. Error( "Couldn't open '%s' for reading.", vcdname );
  383. return;
  384. }
  385. size_t bufSize = filesystem->Size( fh );
  386. char *buffer = new char[ bufSize + 1 ];
  387. filesystem->Read( buffer, bufSize, fh );
  388. filesystem->Close( fh );
  389. buffer[ bufSize ] = 0;
  390. CRC32_t crc;
  391. CRC32_Init( &crc );
  392. CRC32_ProcessBuffer( &crc, buffer, bufSize );
  393. CRC32_Final( &crc );
  394. delete[] buffer;
  395. // Now load the file as a binary if it exists...
  396. char binfile[ 512 ];
  397. Q_strncpy( binfile, vcdname, sizeof( binfile ) );
  398. Q_SetExtension( binfile, ".xcd", sizeof( binfile ) );
  399. if ( buildxcds )
  400. {
  401. fh = filesystem->Open( binfile, "rb", "GAME" );
  402. if ( fh == FILESYSTEM_INVALID_HANDLE )
  403. {
  404. AppendDisposition( disposition, "Built '%s'\n", binfile );
  405. rebuild = true;
  406. }
  407. else
  408. {
  409. // Read the first bit of data and check
  410. char crcdata[ 12 ];
  411. filesystem->Read( crcdata, sizeof( crcdata ), fh );
  412. filesystem->Close( fh );
  413. CUtlBuffer buf;
  414. buf.Put( crcdata, sizeof( crcdata ) );
  415. CRC32_t fileCRC = 0;
  416. if ( !CChoreoScene::GetCRCFromBuffer( buf, (unsigned int &)fileCRC ) )
  417. {
  418. AppendDisposition( disposition, "Rebuilt '%s' due to version change\n", binfile );
  419. rebuild = true;
  420. }
  421. else
  422. {
  423. if ( fileCRC != crc )
  424. {
  425. AppendDisposition( disposition, "Rebuilt '%s' due to crc change\n", binfile );
  426. rebuild = true;
  427. }
  428. }
  429. }
  430. }
  431. // Validate the scene cache
  432. g_SceneCache.RebuildItem( vcdname + strlen( g_szCurrentGameDir ) + 1 );
  433. if ( !rebuild )
  434. return;
  435. // Remove current binary
  436. if ( filesystem->FileExists( binfile, "GAME" ) )
  437. {
  438. _unlink( binfile );
  439. }
  440. // Load the .vcd
  441. LoadScriptFile( (char *)vcdname );
  442. CChoreoScene *scene = ChoreoLoadScene( vcdname, NULL, &g_TokenProcessor, Con_Printf );
  443. if ( scene )
  444. {
  445. scene->SaveBinary( binfile, NULL, crc );
  446. delete scene;
  447. }
  448. }
  449. void CompileVCDs( CUtlVector< CUtlSymbol >& vcds )
  450. {
  451. CUtlVector< CUtlSymbol > disposition;
  452. StartPacifier( "CompileVCDs" );
  453. int i;
  454. int c = vcds.Count();
  455. for ( i = 0 ; i < c; ++i )
  456. {
  457. UpdatePacifier( (float)i / (float)c );
  458. ProcessVCD( g_Analysis.symbols.String( vcds[ i ] ), disposition );
  459. }
  460. EndPacifier();
  461. if ( verbose )
  462. {
  463. c = disposition.Count();
  464. for ( i = 0; i < c; ++i )
  465. {
  466. Warning( "%s", disposition[ i ].String() );
  467. }
  468. }
  469. }
  470. static CUtlMap< CStudioHdr *, MDLHandle_t > g_ModelMap( 0, 0, DefLessFunc( CStudioHdr * ) );
  471. CStudioHdr *ModelSoundsCache_LoadModel( char const *filename )
  472. {
  473. MDLHandle_t handle = g_pMDLCache->FindMDL( filename );
  474. CStudioHdr *studioHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( handle ), g_pMDLCache );
  475. g_ModelMap.Insert( studioHdr, handle );
  476. if ( studioHdr->IsValid() )
  477. return studioHdr;
  478. return NULL;
  479. }
  480. void ModelSoundsCache_FinishModel( CStudioHdr *hdr )
  481. {
  482. int idx = g_ModelMap.Find( hdr );
  483. if ( idx != g_ModelMap.InvalidIndex() )
  484. {
  485. g_pMDLCache->Release( g_ModelMap[ idx ] );
  486. g_ModelMap.RemoveAt( idx );
  487. }
  488. delete hdr;
  489. }
  490. void ModelSoundsCache_PrecacheScriptSound( const char *soundname )
  491. {
  492. }
  493. void ProcessMDL( char const *mdlname, CUtlVector< CUtlSymbol >& disposition )
  494. {
  495. if ( verbose )
  496. {
  497. vprint( 0, "Processing '%s'\n", mdlname );
  498. }
  499. if ( Q_stristr( mdlname, "ghostanim" ) )
  500. {
  501. int n =3 ;
  502. }
  503. // Validate the model sounds cache
  504. g_ModelSoundsCache.RebuildItem( mdlname + strlen( g_szCurrentGameDir ) + 1 );
  505. }
  506. void CompileMDLs( CUtlVector< CUtlSymbol >& mdls )
  507. {
  508. CUtlVector< CUtlSymbol > disposition;
  509. StartPacifier( "CompileMDLs" );
  510. int i;
  511. int c = mdls.Count();
  512. for ( i = 0 ; i < c; ++i )
  513. {
  514. UpdatePacifier( (float)i / (float)c );
  515. ProcessMDL( g_Analysis.symbols.String( mdls[ i ] ), disposition );
  516. }
  517. EndPacifier();
  518. c = disposition.Count();
  519. for ( i = 0; i < c; ++i )
  520. {
  521. Warning( "%s", disposition[ i ].String() );
  522. }
  523. }
  524. //-----------------------------------------------------------------------------
  525. // The application object
  526. //-----------------------------------------------------------------------------
  527. class CMakeCachesApp : public CSteamAppSystemGroup
  528. {
  529. public:
  530. // Methods of IApplication
  531. virtual bool Create();
  532. virtual bool PreInit();
  533. virtual int Main();
  534. virtual void PostShutdown();
  535. virtual void Destroy();
  536. private:
  537. // Sets up the search paths
  538. bool SetupSearchPaths();
  539. };
  540. bool CMakeCachesApp::Create()
  541. {
  542. SpewOutputFunc( SpewFunc );
  543. SpewActivate( "makexvcd", 2 );
  544. // Add in the cvar factory
  545. AppModule_t cvarModule = LoadModule( VStdLib_GetICVarFactory() );
  546. AddSystem( cvarModule, VENGINE_CVAR_INTERFACE_VERSION );
  547. AppSystemInfo_t appSystems[] =
  548. {
  549. { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
  550. { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
  551. { "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
  552. { "datacache.dll", DATACACHE_INTERFACE_VERSION },
  553. { "datacache.dll", MDLCACHE_INTERFACE_VERSION },
  554. { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION },
  555. { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
  556. { "", "" } // Required to terminate the list
  557. };
  558. if ( !AddSystems( appSystems ) )
  559. return false;
  560. g_pFileSystem = filesystem = (IFileSystem*)FindSystem( FILESYSTEM_INTERFACE_VERSION );
  561. g_pMDLCache = (IMDLCache*)FindSystem( MDLCACHE_INTERFACE_VERSION );
  562. soundemitterbase = (ISoundEmitterSystemBase*)FindSystem(SOUNDEMITTERSYSTEM_INTERFACE_VERSION);
  563. g_pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
  564. if ( !soundemitterbase || !g_pMDLCache || !filesystem || !g_pMaterialSystem )
  565. {
  566. Error("Unable to load required library interface!\n");
  567. }
  568. g_pMaterialSystem->SetShaderAPI( "shaderapiempty.dll" );
  569. return true;
  570. }
  571. void CMakeCachesApp::Destroy()
  572. {
  573. g_pFileSystem = filesystem = NULL;
  574. soundemitterbase = NULL;
  575. g_pMDLCache = NULL;
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Sets up the game path
  579. //-----------------------------------------------------------------------------
  580. bool CMakeCachesApp::SetupSearchPaths()
  581. {
  582. CFSSteamSetupInfo steamInfo;
  583. steamInfo.m_pDirectoryName = NULL;
  584. steamInfo.m_bOnlyUseDirectoryName = false;
  585. steamInfo.m_bToolsMode = true;
  586. steamInfo.m_bSetSteamDLLPath = true;
  587. steamInfo.m_bSteam = filesystem->IsSteam();
  588. if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
  589. return false;
  590. CFSMountContentInfo fsInfo;
  591. fsInfo.m_pFileSystem = filesystem;
  592. fsInfo.m_bToolsMode = true;
  593. fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
  594. if ( FileSystem_MountContent( fsInfo ) != FS_OK )
  595. return false;
  596. // Finally, load the search paths for the "GAME" path.
  597. CFSSearchPathsInit searchPathsInit;
  598. searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath;
  599. searchPathsInit.m_pFileSystem = fsInfo.m_pFileSystem;
  600. if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
  601. return false;
  602. char platform[MAX_PATH];
  603. Q_strncpy( platform, steamInfo.m_GameInfoPath, MAX_PATH );
  604. Q_StripTrailingSlash( platform );
  605. Q_strncat( platform, "/../platform", MAX_PATH, MAX_PATH );
  606. fsInfo.m_pFileSystem->AddSearchPath( platform, "PLATFORM" );
  607. // Set gamedir.
  608. Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), steamInfo.m_GameInfoPath );
  609. Q_AppendSlash( gamedir, sizeof( gamedir ) );
  610. return true;
  611. }
  612. //-----------------------------------------------------------------------------
  613. // Init, shutdown
  614. //-----------------------------------------------------------------------------
  615. bool CMakeCachesApp::PreInit( )
  616. {
  617. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  618. filesystem->SetWarningFunc( Warning );
  619. // Add paths...
  620. if ( !SetupSearchPaths() )
  621. return false;
  622. return true;
  623. }
  624. void CMakeCachesApp::PostShutdown()
  625. {
  626. }
  627. //-----------------------------------------------------------------------------
  628. // main application
  629. //-----------------------------------------------------------------------------
  630. int CMakeCachesApp::Main()
  631. {
  632. for ( int i=1 ; i<CommandLine()->ParmCount() ; i++)
  633. {
  634. if ( CommandLine()->GetParm( i )[ 0 ] == '-' )
  635. {
  636. switch( CommandLine()->GetParm( i )[ 1 ] )
  637. {
  638. case 'l':
  639. uselogfile = true;
  640. break;
  641. case 'v':
  642. verbose = true;
  643. break;
  644. case 'g': // -game
  645. ++i;
  646. break;
  647. case 'm':
  648. modelsoundscache = true;
  649. break;
  650. case 's':
  651. scenecache = true;
  652. break;
  653. case 'x':
  654. buildxcds = true;
  655. break;
  656. case 'z':
  657. virtualmodel = true;
  658. break;
  659. default:
  660. printusage();
  661. break;
  662. }
  663. }
  664. }
  665. if ( CommandLine()->ParmCount() < 2 || ( i != CommandLine()->ParmCount() ) )
  666. {
  667. PrintHeader();
  668. printusage();
  669. }
  670. CheckLogFile();
  671. PrintHeader();
  672. vprint( 0, " Compiling binary .vcd files to .xvcd ...\n" );
  673. char vcddir[ 256 ];
  674. char modelsdir[ 256 ];
  675. Q_snprintf( vcddir, sizeof( vcddir ), "scenes", CommandLine()->GetParm( i - 1 ) );
  676. Q_snprintf( modelsdir, sizeof( modelsdir ), "models", CommandLine()->GetParm( i - 1 ) );
  677. if ( !strstr( vcddir, "scenes" ) )
  678. {
  679. vprint( 0, ".vcd dir %s looks invalid (format: u:/game/hl2/scenes)\n", vcddir );
  680. return 0;
  681. }
  682. if ( !strstr( modelsdir, "models" ) )
  683. {
  684. vprint( 0, ".mdl dir %s looks invalid (format: u:/game/hl2/models)\n", modelsdir );
  685. return 0;
  686. }
  687. char binaries[MAX_PATH];
  688. Q_strncpy( binaries, gamedir, MAX_PATH );
  689. Q_StripTrailingSlash( binaries );
  690. Q_strncat( binaries, "/../bin", MAX_PATH, MAX_PATH );
  691. filesystem->AddSearchPath( binaries, "EXECUTABLE_PATH");
  692. soundemitterbase->ModInit();
  693. // Delete the scene cache file
  694. if ( scenecache ) filesystem->RemoveFile( "scene.cache", "MOD" );
  695. if ( modelsoundscache ) filesystem->RemoveFile( "modelsounds.cache", "MOD" );
  696. if ( virtualmodel ) filesystem->RemoveFile( "virtualmodel.cache", "MOD" );
  697. CUtlSymbolTable pathStrings;
  698. CUtlVector< CUtlSymbol > searchList;
  699. char searchPaths[ 512 ];
  700. filesystem->GetSearchPath( "GAME", true, searchPaths, sizeof( searchPaths ) );
  701. // We want to walk them in reverse order so newer files are "overrides" for older ones, so we add them to a list in reverse order
  702. for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) )
  703. {
  704. char dir[ 512 ];
  705. Q_strncpy( dir, path, sizeof( dir ) );
  706. Q_FixSlashes( dir );
  707. Q_strlower( dir );
  708. Q_StripTrailingSlash( dir );
  709. CUtlSymbol sym = pathStrings.AddString( dir );
  710. // Push them on head so we can walk them in reverse order
  711. searchList.AddToHead( sym );
  712. }
  713. if ( scenecache )
  714. {
  715. g_SceneCache.Init();
  716. }
  717. if ( modelsoundscache )
  718. {
  719. g_ModelSoundsCache.Init();
  720. g_pMDLCache->InitPreloadData( true );
  721. }
  722. EventList_RegisterSharedEvents();
  723. for ( int sp = 0; sp < searchList.Count(); ++sp )
  724. {
  725. char const *basedir = pathStrings.String( searchList[ sp ] );
  726. Q_strncpy( g_szCurrentGameDir, basedir, sizeof( g_szCurrentGameDir ) );
  727. vprint( 0, "Processing gamedir %s\n", basedir );
  728. if ( scenecache )
  729. {
  730. vprint( 1, "Building list of .vcd files\n" );
  731. CUtlVector< CUtlSymbol > vcdfiles;
  732. BuildFileList( basedir, vcdfiles, vcddir, ".vcd" );
  733. vprint( 1, "found %i .vcd files\n", vcdfiles.Count() );
  734. CompileVCDs( vcdfiles );
  735. }
  736. if ( modelsoundscache )
  737. {
  738. vprint( 1, "Building list of .mdl files\n" );
  739. CUtlVector< CUtlSymbol > mdlfiles;
  740. BuildFileList( basedir, mdlfiles, modelsdir, ".mdl" );
  741. vprint( 1, "found %i .mdl files\n", mdlfiles.Count() );
  742. CompileMDLs( mdlfiles );
  743. }
  744. }
  745. if ( scenecache )
  746. {
  747. if ( g_SceneCache.IsDirty() )
  748. {
  749. g_SceneCache.Save();
  750. }
  751. g_SceneCache.Shutdown();
  752. }
  753. if ( modelsoundscache )
  754. {
  755. if ( g_ModelSoundsCache.IsDirty() )
  756. {
  757. g_ModelSoundsCache.Save();
  758. }
  759. g_ModelSoundsCache.Shutdown();
  760. g_pMDLCache->ShutdownPreloadData();
  761. }
  762. soundemitterbase->ModShutdown();
  763. return 0;
  764. }
  765. //-----------------------------------------------------------------------------
  766. // Purpose:
  767. // Input : argc -
  768. // argv[] -
  769. // Output : int
  770. //-----------------------------------------------------------------------------
  771. int main( int argc, char* argv[] )
  772. {
  773. CommandLine()->CreateCmdLine( argc, argv );
  774. CMakeCachesApp sceneManagerApp;
  775. CSteamApplication steamApplication( &sceneManagerApp );
  776. int nRetVal = steamApplication.Run();
  777. return nRetVal;
  778. }