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.

526 lines
17 KiB

  1. //====== Copyright �, Valve Corporation, All rights reserved. =================
  2. //
  3. // Purpose: Defines a directory for all the GC processes for an app
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. #include "gcsdk/directory.h"
  8. namespace GCSDK
  9. {
  10. //-----------------------------------------------------------------------------
  11. // Purpose: Constructor
  12. //-----------------------------------------------------------------------------
  13. CGCDirTypeInstance::CGCDirTypeInstance( const char* pszTypeName, uint32 nType, uint32 nInstance, const KeyValues *pKVConfig, const CGCDirProcess* pProcess )
  14. : m_nType( nType )
  15. , m_sTypeName( pszTypeName )
  16. , m_nInstance( nInstance )
  17. , m_pProcess( pProcess )
  18. {
  19. m_pConfig = pKVConfig->MakeCopy();
  20. }
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Destructor
  23. //-----------------------------------------------------------------------------
  24. CGCDirTypeInstance::~CGCDirTypeInstance()
  25. {
  26. m_pConfig->deleteThis();
  27. }
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Returns the type for this GC
  30. //-----------------------------------------------------------------------------
  31. uint32 CGCDirTypeInstance::GetType() const
  32. {
  33. return m_nType;
  34. }
  35. //-----------------------------------------------------------------------------
  36. const char* CGCDirTypeInstance::GetTypeName() const
  37. {
  38. return m_sTypeName;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Returns the instance index for GCs of this type
  42. //-----------------------------------------------------------------------------
  43. uint32 CGCDirTypeInstance::GetInstance() const
  44. {
  45. return m_nInstance;
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose: Gets any additional configuration data for this GC
  49. //-----------------------------------------------------------------------------
  50. KeyValues * CGCDirTypeInstance::GetConfig() const
  51. {
  52. return m_pConfig;
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose: Gets the box that this GC was associated with
  56. //-----------------------------------------------------------------------------
  57. const CGCDirProcess* CGCDirTypeInstance::GetProcess( ) const
  58. {
  59. return m_pProcess;
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose: Constructor
  63. //-----------------------------------------------------------------------------
  64. CGCDirProcess::CGCDirProcess( uint32 nGCDirIndex, const char *pchName, const char* pchProcessType, const KeyValues *pKVConfig ) :
  65. m_iDirGC( nGCDirIndex ),
  66. m_sName( pchName ),
  67. m_sType( pchProcessType ),
  68. m_nTypeMask( 0 )
  69. {
  70. m_pConfig = pKVConfig->MakeCopy();
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Purpose: Destructor
  74. //-----------------------------------------------------------------------------
  75. CGCDirProcess::~CGCDirProcess()
  76. {
  77. // Don't need to delete our pointers. They were allocated by the directory
  78. // and will be cleaned up by the directory.
  79. }
  80. //-----------------------------------------------------------------------------
  81. // Purpose: Gets any additional configuration data for this GC
  82. //-----------------------------------------------------------------------------
  83. KeyValues * CGCDirProcess::GetConfig() const
  84. {
  85. return m_pConfig;
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose: Gets the name for this box
  89. //-----------------------------------------------------------------------------
  90. const char *CGCDirProcess::GetName() const
  91. {
  92. return m_sName.Get();
  93. }
  94. const char *CGCDirProcess::GetProcessType() const
  95. {
  96. return m_sType.Get();
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose: Gets the number of GCs assigned to this box
  100. //-----------------------------------------------------------------------------
  101. uint32 CGCDirProcess::GetTypeInstanceCount() const
  102. {
  103. return m_vecGCs.Count();
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Gets the specified GC definition
  107. //-----------------------------------------------------------------------------
  108. const CGCDirTypeInstance *CGCDirProcess::GetTypeInstance( uint32 nGCIndex ) const
  109. {
  110. bool bValidIndex = m_vecGCs.IsValidIndex( nGCIndex );
  111. Assert( bValidIndex );
  112. if ( !bValidIndex )
  113. return NULL;
  114. return m_vecGCs[ nGCIndex ];
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose: Adds a GC to this box
  118. //-----------------------------------------------------------------------------
  119. void CGCDirProcess::AddGC( CGCDirTypeInstance *pGC )
  120. {
  121. if ( !pGC )
  122. {
  123. Assert( false );
  124. return;
  125. }
  126. //set this within our type mask
  127. Assert( pGC->GetType() < 64 );
  128. m_nTypeMask |= ( uint64 )1 << pGC->GetType();
  129. m_vecGCs.AddToTail( pGC );
  130. if( !m_vecUniqueTypeList.HasElement( pGC->GetType() ) )
  131. {
  132. m_vecUniqueTypeList.Insert( pGC->GetType() );
  133. }
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose:
  137. //-----------------------------------------------------------------------------
  138. uint32 CGCDirProcess::GetGCDirIndex() const
  139. {
  140. return m_iDirGC;
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Purpose:
  144. //-----------------------------------------------------------------------------
  145. bool CGCDirProcess::HasInstanceOfType( uint32 nType ) const
  146. {
  147. return ( m_nTypeMask & ( ( uint64 )1 << nType ) ) != 0;
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose:
  151. //-----------------------------------------------------------------------------
  152. const CUtlSortVector< uint32 >& CGCDirProcess::GetUniqueTypeList() const
  153. {
  154. return m_vecUniqueTypeList;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose: Constructor
  158. //-----------------------------------------------------------------------------
  159. CDirectory::CDirectory()
  160. : m_bInitialized( false )
  161. , m_mapGCsByType( DefLessFunc( int32 ) )
  162. , m_mapRegisteredGCTypes( DefLessFunc( int32 ) )
  163. {
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose: Destructor
  167. //-----------------------------------------------------------------------------
  168. CDirectory::~CDirectory()
  169. {
  170. m_vecProcesses.PurgeAndDeleteElements();
  171. m_vecTypeInstances.PurgeAndDeleteElements();
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: Initializes the directory
  175. //-----------------------------------------------------------------------------
  176. bool CDirectory::BInit( KeyValues *pKVDirectory )
  177. {
  178. Assert( !m_bInitialized );
  179. if ( m_bInitialized )
  180. return false;
  181. if ( NULL == pKVDirectory )
  182. {
  183. AssertMsg( false, "Null KV passed to CDirectory::BInit()" );
  184. return false;
  185. }
  186. CUtlSymbolTable processNamesTable( 0, 16, true );
  187. FOR_EACH_TRUE_SUBKEY( pKVDirectory, pkvProcess )
  188. {
  189. if( 0 != Q_stricmp( pkvProcess->GetName( ), "process" ) )
  190. continue;
  191. //get the name of this process and ensure that it is unique
  192. const char *pchProcessName = pkvProcess->GetString( "name" );
  193. if( !pchProcessName || !pchProcessName[ 0 ] )
  194. {
  195. AssertMsg( false, "Process defined in the config with no name" );
  196. return false;
  197. }
  198. if( processNamesTable.Find( pchProcessName ).IsValid() )
  199. {
  200. AssertMsg( false, "Duplicate box \"%s\" encountered while parsing the config", pchProcessName );
  201. return false;
  202. }
  203. processNamesTable.AddString( pchProcessName );
  204. //get the type associated with this process
  205. const char *pchProcessType = pkvProcess->GetString( "type" );
  206. if( !pchProcessType || !pchProcessType[ 0 ] )
  207. {
  208. AssertMsg( false, "Process %s defined in the config with no process type associated with it", pchProcessName );
  209. return false;
  210. }
  211. //create our new process info
  212. CGCDirProcess *pProcess = new CGCDirProcess( m_vecProcesses.Count( ), pchProcessName, pchProcessType, pkvProcess );
  213. m_vecProcesses.AddToTail( pProcess );
  214. FOR_EACH_SUBKEY( pkvProcess, pkvType )
  215. {
  216. if( 0 != Q_stricmp( pkvType->GetName(), "gc" ) )
  217. continue;
  218. const char *pchGCType = NULL;
  219. if( pkvType->GetFirstSubKey() )
  220. {
  221. pchGCType = pkvType->GetString( "gc" );
  222. }
  223. else
  224. {
  225. pchGCType = pkvType->GetString( );
  226. }
  227. if ( !pchGCType || !pchGCType[0] )
  228. {
  229. AssertMsg( false, "GC defined on box \"%s\" in the config with no type", pchProcessName );
  230. return false;
  231. }
  232. int32 nGCType = GetGCTypeForName( pchGCType );
  233. if ( s_nInvalidGCType == nGCType )
  234. {
  235. AssertMsg( false, "GC defined on box \"%s\" with unknown type \"%s\" encountered while parsing the config", pchProcessName, pchGCType );
  236. return false;
  237. }
  238. //note that to get the count we can't call GetGCCountForType until after we register since otherwise we don't have a type entry
  239. int nGCTypeIndex = m_mapGCsByType.Find( nGCType );
  240. if ( !m_mapGCsByType.IsValidIndex( nGCType ) )
  241. {
  242. nGCTypeIndex = m_mapGCsByType.Insert( nGCType );
  243. }
  244. CGCDirTypeInstance *pGC = new CGCDirTypeInstance( pchGCType, nGCType, m_mapGCsByType[ nGCTypeIndex ].Count(), pkvType, pProcess );
  245. pProcess->AddGC( pGC );
  246. m_vecTypeInstances.AddToTail( pGC );
  247. m_mapGCsByType[ nGCTypeIndex ].AddToTail( pGC );
  248. }
  249. }
  250. // There must be exactly one master GC defined. Make sure it exists
  251. int32 nMasterType = GetGCTypeForName( "master" );
  252. if ( s_nInvalidGCType == nMasterType )
  253. {
  254. AssertMsg( false, "Master GC type is not registered" );
  255. return false;
  256. }
  257. if ( 1 != GetGCCountForType( nMasterType ) )
  258. {
  259. AssertMsg( false, "Incorrect number of master GCs in the config. Expected: 1 Actual: %d", GetGCCountForType( nMasterType ) );
  260. return false;
  261. }
  262. const CGCDirTypeInstance *pGC = GetGCInstanceForType( nMasterType, 0 );
  263. if ( 0 != pGC->GetProcess()->GetGCDirIndex() )
  264. {
  265. AssertMsg( false, "The master GC must be contained within the first GC defined." );
  266. return false;
  267. }
  268. m_bInitialized = true;
  269. return true;
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose: Registers a type of GC
  273. //-----------------------------------------------------------------------------
  274. void CDirectory::RegisterGCType( int32 nTypeID, const char *pchName )
  275. {
  276. Assert( s_nInvalidGCType != nTypeID );
  277. if ( s_nInvalidGCType == nTypeID )
  278. return;
  279. bool bHasElement = m_mapRegisteredGCTypes.IsValidIndex( m_mapRegisteredGCTypes.Find( nTypeID ) );
  280. AssertMsg( !bHasElement, "A GC of type %d has already been registered", nTypeID );
  281. if ( bHasElement )
  282. return;
  283. bHasElement = m_dictRegisteredGCNameToType.HasElement( pchName );
  284. AssertMsg( !bHasElement, "A GC type with name \"%s\" has already been registered", pchName );
  285. if ( bHasElement )
  286. return;
  287. RegisteredGCType_t &gcReg = m_mapRegisteredGCTypes[ m_mapRegisteredGCTypes.Insert( nTypeID ) ];
  288. gcReg.m_strName = pchName;
  289. m_dictRegisteredGCNameToType.Insert( pchName, nTypeID );
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose: Gets the number of boxes hosting GCs in the universe
  293. //-----------------------------------------------------------------------------
  294. uint32 CDirectory::GetProcessCount() const
  295. {
  296. return m_vecProcesses.Count();
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Purpose: Gets the definition for a particular box
  300. //-----------------------------------------------------------------------------
  301. const CGCDirProcess *CDirectory::GetProcess( int32 nIndex ) const
  302. {
  303. if( !m_vecProcesses.IsValidIndex( nIndex ) )
  304. {
  305. Assert( false );
  306. return NULL;
  307. }
  308. return m_vecProcesses[ nIndex ];
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose: Gets the number of GCs in the universe
  312. //-----------------------------------------------------------------------------
  313. uint32 CDirectory::GetGCTypeInstanceCount() const
  314. {
  315. return m_vecTypeInstances.Count();
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose: Destructor
  319. //-----------------------------------------------------------------------------
  320. const CGCDirTypeInstance *CDirectory::GetGCTypeInstance( uint32 iDirGC ) const
  321. {
  322. if( iDirGC >= ( uint32 )m_vecTypeInstances.Count() )
  323. {
  324. Assert( false );
  325. return NULL;
  326. }
  327. return m_vecTypeInstances[ iDirGC ];
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Purpose: Gets the number of GCs in the universe of the given type
  331. //-----------------------------------------------------------------------------
  332. int32 CDirectory::GetGCCountForType( int32 nTypeID ) const
  333. {
  334. int nIndex = m_mapGCsByType.Find( nTypeID );
  335. if ( !m_mapGCsByType.IsValidIndex( nIndex ) )
  336. {
  337. EmitWarning( SPEW_GC, 2, "CDirectory::GetGCCountForType() called with unregistered type %d (%s)\n", nTypeID, GetNameForGCType( nTypeID ) );
  338. return 0;
  339. }
  340. return m_mapGCsByType[nIndex].Count();
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose: Destructor
  344. //-----------------------------------------------------------------------------
  345. const CGCDirTypeInstance *CDirectory::GetGCInstanceForType( int32 nTypeID, int32 nInstance ) const
  346. {
  347. int nIndex = m_mapGCsByType.Find( nTypeID );
  348. if ( !m_mapGCsByType.IsValidIndex( nIndex ) )
  349. {
  350. EmitWarning( SPEW_GC, 2, "CDirectory::GetGCInstanceForType() called with unregistered type %d (%s)\n", nTypeID, GetNameForGCType( nTypeID ) );
  351. return NULL;
  352. }
  353. const CCopyableUtlVector<CGCDirTypeInstance *> &vecGCs = m_mapGCsByType[ nIndex ];
  354. bool bValidIndex = vecGCs.IsValidIndex( nInstance );
  355. Assert( bValidIndex );
  356. if ( !bValidIndex )
  357. return NULL;
  358. return vecGCs[ nInstance ];
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Purpose: Given a type and index, this will hash it to be a valid in-range index for that type and return the directory index
  362. //-----------------------------------------------------------------------------
  363. int32 CDirectory::GetGCDirIndexForInstance( int32 nTypeID, uint32 nInstanceIndex ) const
  364. {
  365. int nIndex = m_mapGCsByType.Find( nTypeID );
  366. if ( !m_mapGCsByType.IsValidIndex( nIndex ) )
  367. {
  368. EmitWarning( SPEW_GC, 2, "CDirectory::GetGCDirIndexForInstance() called with unregistered type %d (%s)\n", nTypeID, GetNameForGCType( nTypeID ) );
  369. return -1;
  370. }
  371. const CCopyableUtlVector<CGCDirTypeInstance *> &vecGCs = m_mapGCsByType[ nIndex ];
  372. uint32 nWrappedIndex = nInstanceIndex % vecGCs.Count();
  373. return vecGCs[ nWrappedIndex ]->GetProcess()->GetGCDirIndex();
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Purpose: given a GC type, this will add all of the GC indices associated with that type onto the provided vector
  377. //-----------------------------------------------------------------------------
  378. void CDirectory::GetGCDirIndicesForType( int32 nTypeID, CUtlVector< uint32 >& vecIndices ) const
  379. {
  380. int nIndex = m_mapGCsByType.Find( nTypeID );
  381. if ( m_mapGCsByType.IsValidIndex( nIndex ) )
  382. {
  383. const CCopyableUtlVector<CGCDirTypeInstance *> &vecGCs = m_mapGCsByType[ nIndex ];
  384. FOR_EACH_VEC( vecGCs, nGC )
  385. {
  386. vecIndices.AddToTail( vecGCs[ nGC ]->GetProcess()->GetGCDirIndex() );
  387. }
  388. }
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Purpose: Gets a name for a registered GC type
  392. //-----------------------------------------------------------------------------
  393. const char *CDirectory::GetNameForGCType( int32 nTypeID ) const
  394. {
  395. int nIndex = m_mapRegisteredGCTypes.Find( nTypeID );
  396. if ( !m_mapRegisteredGCTypes.IsValidIndex( nIndex ) )
  397. return "unknown";
  398. return m_mapRegisteredGCTypes[nIndex].m_strName.Get();
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose: Gets the creation factory for a registered GC types
  402. //-----------------------------------------------------------------------------
  403. CDirectory::GCFactory_t CDirectory::GetFactoryForProcessType( const char* pszProcessType ) const
  404. {
  405. int nIndex = m_dictProcessTypeToFactory.Find( pszProcessType );
  406. if( nIndex == m_dictProcessTypeToFactory.InvalidIndex() )
  407. return NULL;
  408. return m_dictProcessTypeToFactory[ nIndex ];
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Purpose: Registers a factory for a specific process type
  412. //-----------------------------------------------------------------------------
  413. void CDirectory::RegisterProcessTypeFactory( const char* pszProcessType, GCFactory_t pfnFactory )
  414. {
  415. m_dictProcessTypeToFactory.Insert( pszProcessType, pfnFactory );
  416. }
  417. //-----------------------------------------------------------------------------
  418. // Purpose: Gets the type for a GC given a name
  419. //-----------------------------------------------------------------------------
  420. int32 CDirectory::GetGCTypeForName( const char *pchName ) const
  421. {
  422. int nIndex = m_dictRegisteredGCNameToType.Find( pchName );
  423. if ( !m_dictRegisteredGCNameToType.IsValidIndex( nIndex ) )
  424. return s_nInvalidGCType;
  425. return m_dictRegisteredGCNameToType[nIndex];
  426. }
  427. //-----------------------------------------------------------------------------
  428. // Purpose: Gets the global directory singleton
  429. //-----------------------------------------------------------------------------
  430. CDirectory *GDirectory()
  431. {
  432. static CDirectory g_directory;
  433. return &g_directory;
  434. }
  435. } // namespace GCSDK