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.

383 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: .360 Creation for all studiomdl generated files (mdl, vvd, vtx, ani, phy)
  4. //
  5. //=====================================================================================//
  6. #include "MakeGameData.h"
  7. #include "filesystem.h"
  8. #include "../../common/bsplib.h"
  9. #include "ibsppack.h"
  10. #include "vtf/vtf.h"
  11. #include "../../game/server/ai_hull.h"
  12. #include "zip_utils.h"
  13. #define AINET_VERSION_NUMBER 37
  14. #define MAX_NODES 1500
  15. bool ReadBSPHeader( const char *pFilename, dheader_t *pHeader )
  16. {
  17. V_memset( pHeader, 0, sizeof( dheader_t ) );
  18. int handle = _open( pFilename, _O_RDONLY|_O_BINARY );
  19. if ( handle == -1 )
  20. {
  21. return false;
  22. }
  23. _read( handle, pHeader, sizeof( dheader_t ) );
  24. close( handle );
  25. return true;
  26. }
  27. //-----------------------------------------------------------------------------
  28. // Run possible lod culling fixup
  29. //-----------------------------------------------------------------------------
  30. bool ConvertVHV( const char *pVhvFilename, const char *pModelName, CUtlBuffer &sourceBuffer, CUtlBuffer &targetBuffer )
  31. {
  32. // find strip info from model
  33. char vsiFilename[MAX_PATH];
  34. V_strncpy( vsiFilename, pModelName, sizeof( vsiFilename ) );
  35. V_SetExtension( vsiFilename, ".vsi", sizeof( vsiFilename ) );
  36. CUtlBuffer vsiBuffer;
  37. if ( !g_pFullFileSystem->ReadFile( vsiFilename, NULL, vsiBuffer ) )
  38. {
  39. // cannot convert bsp's without model converions
  40. Msg( "Error! Missing expected model conversion file '%s'. Cannot perform VHV fixup.\n", vsiFilename );
  41. return false;
  42. }
  43. IMdlStripInfo *pMdlStripInfo = NULL;
  44. if ( !mdllib->CreateNewStripInfo( &pMdlStripInfo ) )
  45. {
  46. Msg( "Error! Failed to allocate strip info object\n" );
  47. return false;
  48. }
  49. if ( !pMdlStripInfo->UnSerialize( vsiBuffer ) )
  50. {
  51. Msg( "Error! Failed to unserialize strip info object '%s'\n", vsiFilename );
  52. pMdlStripInfo->DeleteThis();
  53. return false;
  54. }
  55. long originalChecksum = 0;
  56. long newChecksum = 0;
  57. if ( !pMdlStripInfo->GetCheckSum( &originalChecksum, &newChecksum ) )
  58. {
  59. Msg( "Error! Failed to get checksums from '%s'\n", vsiFilename );
  60. pMdlStripInfo->DeleteThis();
  61. return false;
  62. }
  63. HardwareVerts::FileHeader_t *pVHVhdr = (HardwareVerts::FileHeader_t*)sourceBuffer.Base();
  64. if ( pVHVhdr->m_nChecksum != originalChecksum )
  65. {
  66. // vhv file should have matching original checksums
  67. Msg( "Error! Mismatched checksums from '%s' and '%s'\n", vsiFilename, pVhvFilename );
  68. pMdlStripInfo->DeleteThis();
  69. return false;
  70. }
  71. targetBuffer.EnsureCapacity( sourceBuffer.TellMaxPut() );
  72. targetBuffer.Put( sourceBuffer.Base(), sourceBuffer.TellMaxPut() );
  73. if ( !pMdlStripInfo->StripHardwareVertsBuffer( targetBuffer ) )
  74. {
  75. pMdlStripInfo->DeleteThis();
  76. return false;
  77. }
  78. // success
  79. pMdlStripInfo->DeleteThis();
  80. return true;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Generate .360 bsp
  84. //-----------------------------------------------------------------------------
  85. bool CreateTargetFile_BSP( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
  86. {
  87. CUtlBuffer targetBuffer;
  88. CUtlBuffer zipBuffer;
  89. CUtlBuffer fileBuffer;
  90. CUtlBuffer tempBuffer;
  91. char tempZipName[MAX_PATH];
  92. char tempSwapName[MAX_PATH];
  93. tempZipName[0] = '\0';
  94. tempSwapName[0] = '\0';
  95. void *pPakData = NULL;
  96. int pakSize = 0;
  97. CXZipTool *pNewXZip = NULL;
  98. if ( !g_bModPathIsValid )
  99. {
  100. Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" );
  101. return false;
  102. }
  103. // Load bsppack.dll
  104. void *pBSPPack;
  105. CSysModule *pBSPModule;
  106. if ( !Sys_LoadInterface( "bsppack.dll", IBSPPACK_VERSION_STRING, &pBSPModule, &pBSPPack ) )
  107. {
  108. Msg( "Failed to load bsppack interface\n" );
  109. return false;
  110. }
  111. scriptlib->MakeTemporaryFilename( g_szModPath, tempSwapName, sizeof( tempSwapName ) );
  112. // Swaps the bsp directly to disk
  113. bool bOK = ((IBSPPack*)pBSPPack)->SwapBSPFile( g_pFullFileSystem, pSourceName, tempSwapName, false, ConvertVTFTo360Format, ConvertVHV, CompressCallback );
  114. if ( !bOK )
  115. {
  116. goto cleanUp;
  117. }
  118. // get the pak file from the swapped bsp
  119. bOK = ((IBSPPack*)pBSPPack)->GetPakFileLump( g_pFullFileSystem, tempSwapName, &pPakData, &pakSize );
  120. if ( !bOK )
  121. {
  122. goto cleanUp;
  123. }
  124. // build an xzip version of the pak file
  125. if ( pPakData && pakSize )
  126. {
  127. // mount current pak file
  128. IZip *pOldZip = IZip::CreateZip( false, true );
  129. pOldZip->ParseFromBuffer( pPakData, pakSize );
  130. // start a new xzip version
  131. scriptlib->MakeTemporaryFilename( g_szModPath, tempZipName, sizeof( tempZipName ) );
  132. pNewXZip = new CXZipTool;
  133. pNewXZip->Begin( tempZipName, XBOX_DVD_SECTORSIZE );
  134. // iterate each file in existing zip, add to new zip
  135. int zipIndex = -1;
  136. for ( ;; )
  137. {
  138. char filename[MAX_PATH];
  139. filename[0] = '\0';
  140. int fileSize = 0;
  141. zipIndex = pOldZip->GetNextFilename( zipIndex, filename, sizeof( filename ), fileSize );
  142. if ( zipIndex == -1 )
  143. {
  144. break;
  145. }
  146. fileBuffer.Purge();
  147. bOK = pOldZip->ReadFileFromZip( filename, false, fileBuffer );
  148. if ( !bOK )
  149. {
  150. goto cleanUp;
  151. }
  152. bOK = pNewXZip->AddBuffer( filename, fileBuffer, true );
  153. if ( !bOK )
  154. {
  155. goto cleanUp;
  156. }
  157. }
  158. IZip::ReleaseZip( pOldZip );
  159. pNewXZip->End();
  160. // read the new zip into memory
  161. bOK = scriptlib->ReadFileToBuffer( tempZipName, zipBuffer );
  162. if ( !bOK )
  163. {
  164. goto cleanUp;
  165. }
  166. // replace old pak lump with new zip
  167. bOK = ((IBSPPack*)pBSPPack)->SetPakFileLump( g_pFullFileSystem, tempSwapName, tempSwapName, zipBuffer.Base(), zipBuffer.TellMaxPut() );
  168. if ( !bOK )
  169. {
  170. goto cleanUp;
  171. }
  172. }
  173. bOK = scriptlib->ReadFileToBuffer( tempSwapName, targetBuffer );
  174. if ( !bOK )
  175. {
  176. goto cleanUp;
  177. }
  178. // never zip, always write local file
  179. bOK = WriteBufferToFile( pTargetName, targetBuffer, false, WRITE_TO_DISK_ALWAYS );
  180. cleanUp:
  181. if ( tempZipName[0] )
  182. {
  183. _unlink( tempZipName );
  184. }
  185. if ( tempSwapName[0] )
  186. {
  187. _unlink( tempSwapName );
  188. }
  189. Sys_UnloadModule( pBSPModule );
  190. if ( pPakData )
  191. {
  192. free( pPakData );
  193. }
  194. delete pNewXZip;
  195. return bOK;
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose: Generate .360 node graphs
  199. //-----------------------------------------------------------------------------
  200. bool CreateTargetFile_AIN( const char *pSourceName, const char *pTargetName, bool bWriteToZip )
  201. {
  202. CUtlBuffer sourceBuf;
  203. if ( !scriptlib->ReadFileToBuffer( pSourceName, sourceBuf ) )
  204. {
  205. return false;
  206. }
  207. // the pc ain is tied to the pc bsp and should have been generated after the bsp
  208. char szBspName[MAX_PATH];
  209. char szBspPath[MAX_PATH];
  210. V_FileBase( pSourceName, szBspName, sizeof( szBspName ) );
  211. V_ExtractFilePath( pSourceName, szBspPath, sizeof( szBspPath ) );
  212. V_AppendSlash( szBspPath, sizeof( szBspPath ) );
  213. V_strncat( szBspPath, "..\\", sizeof( szBspPath ) );
  214. V_strncat( szBspPath, szBspName, sizeof( szBspPath ) );
  215. V_strncat( szBspPath, ".bsp", sizeof( szBspPath ) );
  216. if ( scriptlib->CompareFileTime( pSourceName, szBspPath ) < 0 )
  217. {
  218. // ain has a smaller filetime, thus older than bsp
  219. Msg( "%s: Need to regenerate PC nodegraph (stale)\n", pSourceName );
  220. if ( !g_bForce )
  221. {
  222. return false;
  223. }
  224. }
  225. // Check the version
  226. if ( sourceBuf.GetChar() == 'V' && sourceBuf.GetChar() == 'e' && sourceBuf.GetChar() == 'r' )
  227. {
  228. Msg( "%s: Need to regenerate PC nodegraph (bad format)\n", pSourceName );
  229. return false;
  230. }
  231. // reset
  232. sourceBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  233. // Version number
  234. int version = sourceBuf.GetInt();
  235. if ( version != AINET_VERSION_NUMBER )
  236. {
  237. Msg( "%s: Need to regenerate PC nodegraph (got version '%d', expected '%d')\n", pSourceName, version, AINET_VERSION_NUMBER );
  238. return false;
  239. }
  240. // check the map revision
  241. int mapVersion = sourceBuf.GetInt();
  242. dheader_t bspHeader;
  243. if ( ReadBSPHeader( szBspPath, &bspHeader ) )
  244. {
  245. if ( mapVersion != bspHeader.mapRevision )
  246. {
  247. Msg( "%s: Need to regenerate PC nodegraph (ai revision '%d' does not match bsp revision '%d')\n", pSourceName, mapVersion, bspHeader.mapRevision );
  248. return false;
  249. }
  250. }
  251. else
  252. {
  253. Msg( "%s: Could not find expected bsp '%s'\n", pSourceName, szBspPath );
  254. }
  255. // Nodes
  256. int nodeCt = sourceBuf.GetInt();
  257. if ( nodeCt > MAX_NODES || nodeCt < 0 )
  258. {
  259. Msg( "%s: Need to regenerate PC nodegraph (corrupt)\n", pSourceName );
  260. return false;
  261. }
  262. CUtlBuffer targetBuf;
  263. targetBuf.ActivateByteSwapping( true );
  264. CByteswap swap;
  265. swap.ActivateByteSwapping( true );
  266. targetBuf.PutInt( version );
  267. targetBuf.PutInt( mapVersion );
  268. targetBuf.PutInt( nodeCt );
  269. int numFloats = NUM_HULLS + 4;
  270. for ( int node = 0; node < nodeCt; ++node )
  271. {
  272. targetBuf.EnsureCapacity( targetBuf.TellPut() + numFloats * sizeof( float ) );
  273. swap.SwapBufferToTargetEndian<float>( (float*)targetBuf.PeekPut(), (float*)sourceBuf.PeekGet(), numFloats );
  274. sourceBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, numFloats * sizeof( float ) );
  275. targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, numFloats * sizeof( float ) );
  276. targetBuf.PutChar( sourceBuf.GetChar() );
  277. // Align the remaining data
  278. targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, 3 );
  279. targetBuf.PutUnsignedShort( sourceBuf.GetUnsignedShort() );
  280. targetBuf.PutShort( sourceBuf.GetShort() );
  281. }
  282. // Node links
  283. int totalNumLinks = sourceBuf.GetInt();
  284. targetBuf.PutInt( totalNumLinks );
  285. for ( int link = 0; link < totalNumLinks; ++link )
  286. {
  287. targetBuf.PutShort( sourceBuf.GetShort() );
  288. targetBuf.PutShort( sourceBuf.GetShort() );
  289. targetBuf.Put( sourceBuf.PeekGet(), NUM_HULLS );
  290. sourceBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, NUM_HULLS );
  291. }
  292. // WC lookup table
  293. targetBuf.EnsureCapacity( targetBuf.TellPut() + nodeCt * sizeof( int ) );
  294. swap.SwapBufferToTargetEndian<int>( (int*)targetBuf.PeekPut(), (int*)sourceBuf.PeekGet(), nodeCt );
  295. targetBuf.SeekPut( CUtlBuffer::SEEK_CURRENT, nodeCt * sizeof( int ) );
  296. // Write the file out
  297. return WriteBufferToFile( pTargetName, targetBuf, bWriteToZip, WRITE_TO_DISK_ALWAYS );
  298. }
  299. bool GetDependants_BSP( const char *pBspName, CUtlVector< CUtlString > *pList )
  300. {
  301. if ( !g_bModPathIsValid )
  302. {
  303. Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" );
  304. return false;
  305. }
  306. // Load bsppack.dll
  307. void *pBSPPack;
  308. CSysModule *pBSPModule;
  309. if ( !Sys_LoadInterface( "bsppack.dll", IBSPPACK_VERSION_STRING, &pBSPModule, &pBSPPack ) )
  310. {
  311. Msg( "Failed to load bsppack interface\n" );
  312. return false;
  313. }
  314. // 360 builds a more complete reslist that includes bsp internal files
  315. // build full path to bsp file
  316. char szBspFilename[MAX_PATH];
  317. V_ComposeFileName( g_szGamePath, pBspName, szBspFilename, sizeof( szBspFilename ) );
  318. bool bOK = ((IBSPPack*)pBSPPack)->GetBSPDependants( g_pFullFileSystem, szBspFilename, pList );
  319. Sys_UnloadModule( pBSPModule );
  320. return bOK;
  321. }