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.

170 lines
4.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Exposes bsp tools to game for e.g. workshop use
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include <tier2/tier2.h>
  9. #include "filesystem.h"
  10. #include "bsp_utils.h"
  11. #include "utlbuffer.h"
  12. #include "igamesystem.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. bool BSP_SyncRepack( const char *pszInputMapFile,
  16. const char *pszOutputMapFile,
  17. IBSPPack::eRepackBSPFlags eRepackFlags )
  18. {
  19. // load the bsppack dll
  20. IBSPPack *libBSPPack = NULL;
  21. CSysModule *pModule = g_pFullFileSystem->LoadModule( "bsppack" );
  22. if ( pModule )
  23. {
  24. CreateInterfaceFn BSPPackFactory = Sys_GetFactory( pModule );
  25. if ( BSPPackFactory )
  26. {
  27. libBSPPack = ( IBSPPack * )BSPPackFactory( IBSPPACK_VERSION_STRING, NULL );
  28. }
  29. }
  30. if( !libBSPPack )
  31. {
  32. Warning( "Can't load bsppack library - unable to compress bsp\n" );
  33. return false;
  34. }
  35. Msg( "Repacking %s -> %s\n", pszInputMapFile, pszOutputMapFile );
  36. if ( !g_pFullFileSystem->FileExists( pszInputMapFile ) )
  37. {
  38. Warning( "Couldn't open input file %s - BSP recompress failed\n", pszInputMapFile );
  39. return false;
  40. }
  41. CUtlBuffer inputBuffer;
  42. if ( !g_pFullFileSystem->ReadFile( pszInputMapFile, NULL, inputBuffer ) )
  43. {
  44. Warning( "Couldn't read file %s - BSP compression failed\n", pszInputMapFile );
  45. return false;
  46. }
  47. CUtlBuffer outputBuffer;
  48. if ( !libBSPPack->RepackBSP( inputBuffer, outputBuffer, eRepackFlags ) )
  49. {
  50. Warning( "Internal error compressing BSP\n" );
  51. return false;
  52. }
  53. g_pFullFileSystem->WriteFile( pszOutputMapFile, NULL, outputBuffer );
  54. Msg( "Successfully repacked %s as %s -- %u -> %u bytes\n",
  55. pszInputMapFile, pszOutputMapFile, inputBuffer.TellPut(), outputBuffer.TellPut() );
  56. return true;
  57. }
  58. // Helper to create a thread that calls SyncCompressMap, and clean it up when it exists
  59. void BSP_BackgroundRepack( const char *pszInputMapFile,
  60. const char *pszOutputMapFile,
  61. IBSPPack::eRepackBSPFlags eRepackFlags )
  62. {
  63. // Make this a gamesystem and thread, so it can check for completion each frame and clean itself up. Run() is the
  64. // background thread, Update() is the main thread tick.
  65. class BackgroundBSPRepackThread : public CThread, public CAutoGameSystemPerFrame
  66. {
  67. public:
  68. BackgroundBSPRepackThread( const char *pszInputFile, const char *pszOutputFile, IBSPPack::eRepackBSPFlags eRepackFlags )
  69. : m_strInput( pszInputFile )
  70. , m_strOutput( pszOutputFile )
  71. , m_eRepackFlags( eRepackFlags )
  72. {
  73. Start();
  74. }
  75. // CThread job - returns 0 for success
  76. virtual int Run() OVERRIDE
  77. {
  78. return BSP_SyncRepack( m_strInput.Get(), m_strOutput.Get(), m_eRepackFlags ) ? 0 : 1;
  79. }
  80. // GameSystem
  81. virtual const char* Name( void ) OVERRIDE { return "BackgroundBSPRepackThread"; }
  82. // Runs on main thread
  83. void CheckFinished()
  84. {
  85. if ( !IsAlive() )
  86. {
  87. // Thread finished
  88. if ( GetResult() != 0 )
  89. {
  90. Warning( "Map compression thread failed :(\n" );
  91. }
  92. // AutoGameSystem deregisters itself on destruction, we're done
  93. delete this;
  94. }
  95. }
  96. #ifdef CLIENT_DLL
  97. virtual void Update( float frametime ) OVERRIDE { CheckFinished(); }
  98. #else // GAME DLL
  99. virtual void FrameUpdatePostEntityThink() OVERRIDE { CheckFinished(); }
  100. #endif
  101. private:
  102. CUtlString m_strInput;
  103. CUtlString m_strOutput;
  104. IBSPPack::eRepackBSPFlags m_eRepackFlags;
  105. };
  106. Msg( "Starting BSP repack job %s -> %s\n", pszInputMapFile, pszOutputMapFile );
  107. // Deletes itself up when done
  108. new BackgroundBSPRepackThread( pszInputMapFile, pszOutputMapFile, eRepackFlags );
  109. }
  110. CON_COMMAND( bsp_repack, "Repack and output a (re)compressed version of a bsp file" )
  111. {
  112. #ifdef GAME_DLL
  113. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  114. return;
  115. #endif
  116. // Handle -nocompress
  117. bool bCompress = true;
  118. const char *szInFilename = NULL;
  119. const char *szOutFilename = NULL;
  120. if ( args.ArgC() == 4 && V_strcasecmp( args.Arg( 1 ), "-nocompress" ) == 0 )
  121. {
  122. bCompress = false;
  123. szInFilename = args.Arg( 2 );
  124. szOutFilename = args.Arg( 3 );
  125. }
  126. else if ( args.ArgC() == 3 )
  127. {
  128. szInFilename = args.Arg( 1 );
  129. szOutFilename = args.Arg( 2 );
  130. }
  131. if ( !szInFilename || !szOutFilename || !strlen( szInFilename ) || !strlen( szOutFilename ) )
  132. {
  133. Msg( "Usage: bsp_repack [-nocompress] map.bsp output_map.bsp\n" );
  134. return;
  135. }
  136. if ( bCompress )
  137. {
  138. // Use default compress flags
  139. BSP_BackgroundRepack( szInFilename, szOutFilename );
  140. }
  141. else
  142. {
  143. // No compression
  144. BSP_BackgroundRepack( szInFilename, szOutFilename, (IBSPPack::eRepackBSPFlags)0 );
  145. }
  146. }