Counter Strike : Global Offensive Source Code
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.

567 lines
16 KiB

  1. #include "vbsp.h"
  2. #include "map_shared.h"
  3. #include "fgdlib/fgdlib.h"
  4. #include "manifest.h"
  5. #include "windows.h"
  6. //-----------------------------------------------------------------------------
  7. // Purpose: default constructor
  8. //-----------------------------------------------------------------------------
  9. CManifestMap::CManifestMap( void )
  10. {
  11. m_RelativeMapFileName[ 0 ] = 0;
  12. m_bTopLevelMap = false;
  13. }
  14. //-----------------------------------------------------------------------------
  15. // Purpose: default constructor
  16. //-----------------------------------------------------------------------------
  17. CManifest::CManifest( void )
  18. {
  19. m_InstancePath[ 0 ] = 0;
  20. m_bIsCordoning = false;
  21. m_CordoningMapEnt = NULL;
  22. }
  23. //-----------------------------------------------------------------------------
  24. // Purpose: this function will parse through the known keys for the manifest map entry
  25. // Input : szKey - the key name
  26. // szValue - the value
  27. // pManifestMap - the manifest map this belongs to
  28. // Output : ChunkFileResult_t - result of the parsing
  29. //-----------------------------------------------------------------------------
  30. ChunkFileResult_t CManifest::LoadManifestMapKeyCallback( const char *szKey, const char *szValue, CManifestMap *pManifestMap )
  31. {
  32. if ( !stricmp( szKey, "Name" ) )
  33. {
  34. // pManifestMap->m_FriendlyName = szValue;
  35. }
  36. else if ( !stricmp( szKey, "File" ) )
  37. {
  38. strcpy( pManifestMap->m_RelativeMapFileName, szValue );
  39. }
  40. else if ( !stricmp( szKey, "IsPrimary" ) )
  41. {
  42. // pManifestMap->m_bPrimaryMap = ( atoi( szValue ) == 1 );
  43. }
  44. else if ( !stricmp( szKey, "IsProtected" ) )
  45. {
  46. // pManifestMap->m_bCanBeModified = ( atoi( szValue ) != 1 );
  47. }
  48. else if ( !stricmp( szKey, "TopLevel" ) )
  49. {
  50. pManifestMap->m_bTopLevelMap = ( atoi( szValue ) == 1 );
  51. }
  52. return ChunkFile_Ok;
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose: this function is responsible for setting up the manifest map about to be read in
  56. // Input : pFile - the chunk file being read
  57. // pDoc - the owning manifest document
  58. // Output : ChunkFileResult_t - result of the parsing
  59. //-----------------------------------------------------------------------------
  60. ChunkFileResult_t CManifest::LoadManifestVMFCallback( CChunkFile *pFile, CManifest *pManifest )
  61. {
  62. CManifestMap *pManifestMap = new CManifestMap();
  63. pManifest->m_Maps.AddToTail( pManifestMap );
  64. ChunkFileResult_t eResult = pFile->ReadChunk( ( KeyHandler_t )LoadManifestMapKeyCallback, pManifestMap );
  65. return( eResult );
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: this function will load the VMF chunk
  69. // Input : pFile - the chunk file being read
  70. // pDoc - the owning manifest document
  71. // Output : ChunkFileResult_t - result of the parsing
  72. //-----------------------------------------------------------------------------
  73. ChunkFileResult_t CManifest::LoadManifestMapsCallback( CChunkFile *pFile, CManifest *pManifest )
  74. {
  75. CChunkHandlerMap Handlers;
  76. Handlers.AddHandler( "VMF", ( ChunkHandler_t )LoadManifestVMFCallback, pManifest );
  77. pFile->PushHandlers(&Handlers);
  78. ChunkFileResult_t eResult = ChunkFile_Ok;
  79. eResult = pFile->ReadChunk();
  80. pFile->PopHandlers();
  81. return( eResult );
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose:
  85. // Input :
  86. // Output :
  87. //-----------------------------------------------------------------------------
  88. ChunkFileResult_t CManifest::LoadCordonBoxCallback( CChunkFile *pFile, Cordon_t *pCordon )
  89. {
  90. // Add a box to this cordon.
  91. pCordon->m_Boxes.AddToTail();
  92. BoundBox &box = pCordon->m_Boxes.Tail();
  93. // Fill it in with the data from the VMF.
  94. return pFile->ReadChunk( (KeyHandler_t)LoadCordonBoxKeyCallback, (void *)&box );
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. // Input :
  99. // Output :
  100. //-----------------------------------------------------------------------------
  101. ChunkFileResult_t CManifest::LoadCordonBoxKeyCallback( const char *szKey, const char *szValue, BoundBox *pBox )
  102. {
  103. if (!stricmp(szKey, "mins"))
  104. {
  105. CChunkFile::ReadKeyValuePoint(szValue, pBox->bmins);
  106. }
  107. else if (!stricmp(szKey, "maxs"))
  108. {
  109. CChunkFile::ReadKeyValuePoint(szValue, pBox->bmaxs);
  110. }
  111. return ChunkFile_Ok;
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose:
  115. // Input :
  116. // Output :
  117. //-----------------------------------------------------------------------------
  118. ChunkFileResult_t CManifest::LoadCordonKeyCallback( const char *szKey, const char *szValue, Cordon_t *pCordon )
  119. {
  120. if (!stricmp(szKey, "name"))
  121. {
  122. pCordon->m_szName.Set( szValue );
  123. }
  124. // Whether this particular cordon volume is active.
  125. else if (!stricmp(szKey, "active"))
  126. {
  127. CChunkFile::ReadKeyValueBool(szValue, pCordon->m_bActive);
  128. }
  129. return ChunkFile_Ok;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. // Input :
  134. // Output :
  135. //-----------------------------------------------------------------------------
  136. ChunkFileResult_t CManifest::LoadCordonCallback( CChunkFile *pFile, CManifest *pManifest )
  137. {
  138. // Add a new cordon which will be filled in by the key callback
  139. pManifest->m_Cordons.AddToTail();
  140. Cordon_t &cordon = pManifest->m_Cordons.Tail();
  141. CChunkHandlerMap Handlers;
  142. Handlers.AddHandler( "box", (ChunkHandler_t)CManifest::LoadCordonBoxCallback, (void *)&cordon );
  143. pFile->PushHandlers(&Handlers);
  144. ChunkFileResult_t eResult = pFile->ReadChunk( (KeyHandler_t)LoadCordonKeyCallback, (void *)&cordon );
  145. pFile->PopHandlers();
  146. return(eResult);
  147. }
  148. //-----------------------------------------------------------------------------------------------------------
  149. // Parses keys that are applicable to all cordons in the map.
  150. //-----------------------------------------------------------------------------
  151. ChunkFileResult_t CManifest::LoadCordonsKeyCallback( const char *szKey, const char *szValue, CManifest *pManifest )
  152. {
  153. // Whether the cordoning system is enabled or disabled.
  154. if ( !stricmp( szKey, "active" ) )
  155. {
  156. CChunkFile::ReadKeyValueBool( szValue, pManifest->m_bIsCordoning );
  157. }
  158. return ChunkFile_Ok;
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Parses the VMF chunk that pertains to all the cordons in the map:
  162. //
  163. // cordons
  164. // {
  165. // "active" "true"
  166. // cordon
  167. // {
  168. // "active" "true"
  169. // "box"
  170. // {
  171. // "mins" "-1024, -1024, -1024"
  172. // "maxs" "1024, 1024, 1024"
  173. // }
  174. // ...may be more boxes...
  175. // }
  176. // ...may be more cordons...
  177. // }
  178. //
  179. //-----------------------------------------------------------------------------
  180. ChunkFileResult_t CManifest::LoadCordonsCallback( CChunkFile *pFile, CManifest *pManifest )
  181. {
  182. CChunkHandlerMap Handlers;
  183. Handlers.AddHandler( "cordon", (ChunkHandler_t)CManifest::LoadCordonCallback, pManifest );
  184. pFile->PushHandlers(&Handlers);
  185. ChunkFileResult_t eResult = pFile->ReadChunk( (KeyHandler_t)LoadCordonsKeyCallback, pManifest );
  186. pFile->PopHandlers();
  187. return(eResult);
  188. }
  189. extern ChunkFileResult_t LoadSolidCallback(CChunkFile *pFile, LoadEntity_t *pLoadEntity);
  190. ChunkFileResult_t CManifest::LoadManifestCordoningPrefsCallback( CChunkFile *pFile, CManifest *pDoc )
  191. {
  192. pDoc->m_CordoningMapEnt = &g_MainMap->entities[g_MainMap->num_entities];
  193. g_MainMap->num_entities++;
  194. memset( pDoc->m_CordoningMapEnt, 0, sizeof( *pDoc->m_CordoningMapEnt ) );
  195. pDoc->m_CordoningMapEnt->firstbrush = g_MainMap->nummapbrushes;
  196. pDoc->m_CordoningMapEnt->numbrushes = 0;
  197. LoadEntity_t LoadEntity;
  198. LoadEntity.pEntity = pDoc->m_CordoningMapEnt;
  199. // No default flags/contents
  200. LoadEntity.nBaseFlags = 0;
  201. LoadEntity.nBaseContents = 0;
  202. //
  203. // Set up handlers for the subchunks that we are interested in.
  204. //
  205. CChunkHandlerMap Handlers;
  206. Handlers.AddHandler( "cordons", ( ChunkHandler_t )CManifest::LoadCordonsCallback, pDoc );
  207. Handlers.AddHandler("solid", (ChunkHandler_t)::LoadSolidCallback, &LoadEntity);
  208. pFile->PushHandlers(&Handlers);
  209. ChunkFileResult_t eResult = ChunkFile_Ok;
  210. eResult = pFile->ReadChunk();
  211. pFile->PopHandlers();
  212. return( eResult );
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: this function will create a new entity pair
  216. // Input : pKey - the key of the pair
  217. // pValue - the value of the pair
  218. // Output : returns a newly created epair structure
  219. //-----------------------------------------------------------------------------
  220. epair_t *CManifest::CreateEPair( char *pKey, char *pValue )
  221. {
  222. epair_t *pEPair = new epair_t;
  223. pEPair->key = new char[ strlen( pKey ) + 1 ];
  224. pEPair->value = new char[ strlen( pValue ) + 1 ];
  225. strcpy( pEPair->key, pKey );
  226. strcpy( pEPair->value, pValue );
  227. return pEPair;
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose: this function will load in all of the submaps belonging to this manifest,
  231. // except for the top level map, which is loaded separately.
  232. // Input : pMapFile - the top level map that was previously loaded
  233. // pszFileName - the absolute file name of the top level map file
  234. // Output : returns true if all submaps were loaded
  235. //-----------------------------------------------------------------------------
  236. bool CManifest::LoadSubMaps( CMapFile *pMapFile, const char *pszFileName )
  237. {
  238. entity_t *InstanceEntity;
  239. epair_t *pEPair;
  240. InstanceEntity = &pMapFile->entities[ pMapFile->num_entities ];
  241. pMapFile->num_entities++;
  242. memset( InstanceEntity, 0, sizeof( *InstanceEntity ) );
  243. InstanceEntity->origin.Init( 0.0f, 0.0f, 0.0f );
  244. pEPair = CreateEPair( "classname", "worldspawn" );
  245. pEPair->next = InstanceEntity->epairs;
  246. InstanceEntity->epairs = pEPair;
  247. for( int i = 0; i < m_Maps.Count(); i++ )
  248. {
  249. // if ( m_Maps[ i ]->m_bTopLevelMap == false )
  250. {
  251. char FileName[ MAX_PATH ];
  252. sprintf( FileName, "%s%s", m_InstancePath, m_Maps[ i ]->m_RelativeMapFileName );
  253. InstanceEntity = &pMapFile->entities[ pMapFile->num_entities ];
  254. pMapFile->num_entities++;
  255. memset( InstanceEntity, 0, sizeof( *InstanceEntity ) );
  256. InstanceEntity->origin.Init( 0.0f, 0.0f, 0.0f );
  257. pEPair = CreateEPair( "angles", "0 0 0" );
  258. pEPair->next = InstanceEntity->epairs;
  259. InstanceEntity->epairs = pEPair;
  260. char temp[ 128 ];
  261. sprintf( temp, "%d", GameData::NAME_FIXUP_NONE );
  262. pEPair = CreateEPair( "fixup_style", temp );
  263. pEPair->next = InstanceEntity->epairs;
  264. InstanceEntity->epairs = pEPair;
  265. pEPair = CreateEPair( "classname", "func_instance" );
  266. pEPair->next = InstanceEntity->epairs;
  267. InstanceEntity->epairs = pEPair;
  268. pEPair = CreateEPair( "file", m_Maps[ i ]->m_RelativeMapFileName );
  269. pEPair->next = InstanceEntity->epairs;
  270. InstanceEntity->epairs = pEPair;
  271. if ( m_Maps[ i ]->m_bTopLevelMap == true )
  272. {
  273. pEPair = CreateEPair( "toplevel", "1" );
  274. pEPair->next = InstanceEntity->epairs;
  275. InstanceEntity->epairs = pEPair;
  276. }
  277. }
  278. }
  279. return true;
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose:
  283. // Input :
  284. // Output :
  285. //-----------------------------------------------------------------------------
  286. bool CManifest::LoadVMFManifestUserPrefs( const char *pszFileName )
  287. {
  288. char UserName[ MAX_PATH ], FileName[ MAX_PATH ], UserPrefsFileName[ MAX_PATH ];
  289. DWORD UserNameSize;
  290. UserNameSize = sizeof( UserName );
  291. if ( GetUserName( UserName, &UserNameSize ) == 0 )
  292. {
  293. strcpy( UserPrefsFileName, "default" );
  294. }
  295. sprintf( UserPrefsFileName, "\\%s.vmm_prefs", UserName );
  296. V_StripExtension( pszFileName, FileName, sizeof( FileName ) );
  297. strcat( FileName, UserPrefsFileName );
  298. FILE *fp = fopen( FileName, "rb" );
  299. if ( !fp )
  300. {
  301. return false;
  302. }
  303. CChunkFile File;
  304. ChunkFileResult_t eResult = File.Open( FileName, ChunkFile_Read );
  305. if ( eResult == ChunkFile_Ok )
  306. {
  307. //
  308. // Set up handlers for the subchunks that we are interested in.
  309. //
  310. CChunkHandlerMap Handlers;
  311. Handlers.AddHandler( "cordoning", ( ChunkHandler_t )CManifest::LoadManifestCordoningPrefsCallback, this );
  312. // Handlers.SetErrorHandler( ( ChunkErrorHandler_t )CMapDoc::HandleLoadError, this);
  313. File.PushHandlers(&Handlers);
  314. while( eResult == ChunkFile_Ok )
  315. {
  316. eResult = File.ReadChunk();
  317. }
  318. if ( eResult == ChunkFile_EOF )
  319. {
  320. eResult = ChunkFile_Ok;
  321. }
  322. File.PopHandlers();
  323. }
  324. if ( eResult == ChunkFile_Ok )
  325. {
  326. }
  327. else
  328. {
  329. // no pref message for now
  330. // GetMainWnd()->MessageBox( File.GetErrorText( eResult ), "Error loading manifest!", MB_OK | MB_ICONEXCLAMATION );
  331. }
  332. return true;
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose: Loads a .VMM file.
  336. // Input : pszFileName - Full path of the map file to load.
  337. //-----------------------------------------------------------------------------
  338. bool CManifest::LoadVMFManifest( const char *pszFileName )
  339. {
  340. V_StripExtension( pszFileName, m_InstancePath, sizeof( m_InstancePath ) );
  341. strcat( m_InstancePath, "\\" );
  342. CChunkFile File;
  343. ChunkFileResult_t eResult = File.Open( pszFileName, ChunkFile_Read );
  344. if ( eResult != ChunkFile_Ok )
  345. {
  346. g_MapError.ReportError( File.GetErrorText( eResult ) );
  347. return false;
  348. }
  349. CChunkHandlerMap Handlers;
  350. Handlers.AddHandler( "Maps", ( ChunkHandler_t )LoadManifestMapsCallback, this );
  351. File.PushHandlers(&Handlers);
  352. while (eResult == ChunkFile_Ok)
  353. {
  354. eResult = File.ReadChunk();
  355. }
  356. if (eResult == ChunkFile_EOF)
  357. {
  358. eResult = ChunkFile_Ok;
  359. }
  360. File.PopHandlers();
  361. if ( eResult == ChunkFile_Ok )
  362. {
  363. int index = g_Maps.AddToTail( new CMapFile() );
  364. g_LoadingMap = g_Maps[ index ];
  365. if ( g_MainMap == NULL )
  366. {
  367. g_MainMap = g_LoadingMap;
  368. }
  369. LoadSubMaps( g_LoadingMap, pszFileName );
  370. LoadVMFManifestUserPrefs( pszFileName );
  371. }
  372. return ( eResult == ChunkFile_Ok );
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Purpose:
  376. // Input :
  377. // Output :
  378. //-----------------------------------------------------------------------------
  379. void CManifest::CordonWorld( )
  380. {
  381. if ( m_bIsCordoning == false )
  382. {
  383. return;
  384. }
  385. for ( int i = 0; i < g_MainMap->num_entities; i++ )
  386. {
  387. if ( i == 0 )
  388. { // for world spawn, we look at brushes
  389. for( int nBrushNum = 0; nBrushNum < g_MainMap->entities[ i ].numbrushes; nBrushNum++ )
  390. {
  391. int nIndex = g_MainMap->entities[ i ].firstbrush + nBrushNum;
  392. bool bRemove = true;
  393. for( int nCordon = 0; nCordon < m_Cordons.Count(); nCordon++ )
  394. {
  395. if ( m_Cordons[ nCordon ].m_bActive == false )
  396. {
  397. continue;
  398. }
  399. for( int nBox = 0; nBox < m_Cordons[ nCordon ].m_Boxes.Count(); nBox++ )
  400. {
  401. if ( m_Cordons[ nCordon ].m_Boxes[ nBox ].IsIntersectingBox( g_MainMap->mapbrushes[ nIndex ].mins, g_MainMap->mapbrushes[ nIndex ].maxs ) == true )
  402. {
  403. bRemove = false;
  404. break;
  405. }
  406. }
  407. if ( bRemove == false )
  408. {
  409. break;
  410. }
  411. }
  412. if ( bRemove )
  413. {
  414. int nSize = ( g_MainMap->entities[ i ].numbrushes - nBrushNum - 1 ) * sizeof( g_MainMap->mapbrushes[ 0 ] );
  415. memmove( &g_MainMap->mapbrushes[ nIndex ], &g_MainMap->mapbrushes[ nIndex + 1 ], nSize );
  416. g_MainMap->entities[ i ].numbrushes--;
  417. nBrushNum--;
  418. }
  419. }
  420. }
  421. else if ( &g_MainMap->entities[ i ] != m_CordoningMapEnt )
  422. { // for all other entities, even if they include brushes, we look at origin
  423. if ( g_MainMap->entities[ i ].numbrushes == 0 && g_MainMap->entities[ i ].epairs == NULL )
  424. {
  425. continue;
  426. }
  427. bool bRemove = true;
  428. for( int nCordon = 0; nCordon < m_Cordons.Count(); nCordon++ )
  429. {
  430. if ( m_Cordons[ nCordon ].m_bActive == false )
  431. {
  432. continue;
  433. }
  434. for( int nBox = 0; nBox < m_Cordons[ nCordon ].m_Boxes.Count(); nBox++ )
  435. {
  436. if ( m_Cordons[ nCordon ].m_Boxes[ nBox ].ContainsPoint( g_MainMap->entities[ i ].origin ) == true )
  437. {
  438. bRemove = false;
  439. break;
  440. }
  441. }
  442. if ( bRemove == false )
  443. {
  444. break;
  445. }
  446. }
  447. if ( bRemove )
  448. {
  449. g_MainMap->entities[ i ].numbrushes = 0;
  450. g_MainMap->entities[ i ].epairs = NULL;
  451. }
  452. }
  453. }
  454. if ( m_CordoningMapEnt )
  455. {
  456. g_MainMap->MoveBrushesToWorldGeneral( m_CordoningMapEnt );
  457. m_CordoningMapEnt->numbrushes = 0;
  458. m_CordoningMapEnt->epairs = NULL;
  459. }
  460. }