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.

519 lines
14 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. //-----------------------------------------------------------------------------
  9. // Purpose: a global list of all the entities in the game. All iteration through
  10. // entities is done through this object.
  11. //-----------------------------------------------------------------------------
  12. #include "cbase.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. // Globals
  17. //-----------------------------------------------------------------------------
  18. // Create interface
  19. static CClientEntityList s_EntityList;
  20. CBaseEntityList *g_pEntityList = &s_EntityList;
  21. // Expose list to engine
  22. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CClientEntityList, IClientEntityList, VCLIENTENTITYLIST_INTERFACE_VERSION, s_EntityList );
  23. // Store local pointer to interface for rest of client .dll only
  24. // (CClientEntityList instead of IClientEntityList )
  25. CClientEntityList *cl_entitylist = &s_EntityList;
  26. bool PVSNotifierMap_LessFunc( IClientUnknown* const &a, IClientUnknown* const &b )
  27. {
  28. return a < b;
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Purpose:
  32. //-----------------------------------------------------------------------------
  33. CClientEntityList::CClientEntityList( void ) :
  34. m_PVSNotifierMap( 0, 0, PVSNotifierMap_LessFunc )
  35. {
  36. m_iMaxUsedServerIndex = -1;
  37. m_iMaxServerEnts = 0;
  38. Release();
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. //-----------------------------------------------------------------------------
  43. CClientEntityList::~CClientEntityList( void )
  44. {
  45. Release();
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose: Clears all entity lists and releases entities
  49. //-----------------------------------------------------------------------------
  50. void CClientEntityList::Release( void )
  51. {
  52. // Free all the entities.
  53. ClientEntityHandle_t iter = FirstHandle();
  54. while( iter != InvalidHandle() )
  55. {
  56. // Try to call release on anything we can.
  57. IClientNetworkable *pNet = GetClientNetworkableFromHandle( iter );
  58. if ( pNet )
  59. {
  60. pNet->Release();
  61. }
  62. else
  63. {
  64. // Try to call release on anything we can.
  65. IClientThinkable *pThinkable = GetClientThinkableFromHandle( iter );
  66. if ( pThinkable )
  67. {
  68. pThinkable->Release();
  69. }
  70. }
  71. RemoveEntity( iter );
  72. iter = FirstHandle();
  73. }
  74. m_iNumServerEnts = 0;
  75. m_iMaxServerEnts = 0;
  76. m_iNumClientNonNetworkable = 0;
  77. m_iMaxUsedServerIndex = -1;
  78. }
  79. IClientNetworkable* CClientEntityList::GetClientNetworkable( int entnum )
  80. {
  81. Assert( entnum >= 0 );
  82. Assert( entnum < MAX_EDICTS );
  83. return m_EntityCacheInfo[entnum].m_pNetworkable;
  84. }
  85. EntityCacheInfo_t *CClientEntityList::GetClientNetworkableArray()
  86. {
  87. PREFETCH360(m_EntityCacheInfo, 0);
  88. return m_EntityCacheInfo;
  89. }
  90. void CClientEntityList::SetDormant( int entityIndex, bool bDormant )
  91. {
  92. Assert( entityIndex >= 0 );
  93. Assert( entityIndex < MAX_EDICTS );
  94. m_EntityCacheInfo[entityIndex].m_bDormant = bDormant;
  95. }
  96. IClientEntity* CClientEntityList::GetClientEntity( int entnum )
  97. {
  98. IClientUnknown *pEnt = GetListedEntity( entnum );
  99. return pEnt ? pEnt->GetIClientEntity() : 0;
  100. }
  101. int CClientEntityList::NumberOfEntities( bool bIncludeNonNetworkable )
  102. {
  103. if ( bIncludeNonNetworkable == true )
  104. return m_iNumServerEnts + m_iNumClientNonNetworkable;
  105. return m_iNumServerEnts;
  106. }
  107. void CClientEntityList::SetMaxEntities( int maxents )
  108. {
  109. m_iMaxServerEnts = maxents;
  110. }
  111. int CClientEntityList::GetMaxEntities( void )
  112. {
  113. return m_iMaxServerEnts;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Convenience methods to convert between entindex + ClientEntityHandle_t
  117. //-----------------------------------------------------------------------------
  118. int CClientEntityList::HandleToEntIndex( ClientEntityHandle_t handle )
  119. {
  120. if ( handle == INVALID_EHANDLE )
  121. return -1;
  122. C_BaseEntity *pEnt = GetBaseEntityFromHandle( handle );
  123. return pEnt ? pEnt->entindex() : -1;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose: Because m_iNumServerEnts != last index
  127. // Output : int
  128. //-----------------------------------------------------------------------------
  129. int CClientEntityList::GetHighestEntityIndex( void )
  130. {
  131. return m_iMaxUsedServerIndex;
  132. }
  133. void CClientEntityList::RecomputeHighestEntityUsed( void )
  134. {
  135. m_iMaxUsedServerIndex = -1;
  136. // Walk backward looking for first valid index
  137. int i;
  138. for ( i = MAX_EDICTS - 1; i >= 0; i-- )
  139. {
  140. if ( GetListedEntity( i ) != NULL )
  141. {
  142. m_iMaxUsedServerIndex = i;
  143. break;
  144. }
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose: Add a raw C_BaseEntity to the entity list.
  149. // Input : index -
  150. //-----------------------------------------------------------------------------
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. // Input : index -
  154. //-----------------------------------------------------------------------------
  155. C_BaseEntity* CClientEntityList::GetBaseEntity( int entnum )
  156. {
  157. IClientUnknown *pEnt = GetListedEntity( entnum );
  158. return pEnt ? pEnt->GetBaseEntity() : 0;
  159. }
  160. ICollideable* CClientEntityList::GetCollideable( int entnum )
  161. {
  162. IClientUnknown *pEnt = GetListedEntity( entnum );
  163. return pEnt ? pEnt->GetCollideable() : 0;
  164. }
  165. IClientNetworkable* CClientEntityList::GetClientNetworkableFromHandle( ClientEntityHandle_t hEnt )
  166. {
  167. IClientUnknown *pEnt = GetClientUnknownFromHandle( hEnt );
  168. return pEnt ? pEnt->GetClientNetworkable() : 0;
  169. }
  170. IClientEntity* CClientEntityList::GetClientEntityFromHandle( ClientEntityHandle_t hEnt )
  171. {
  172. IClientUnknown *pEnt = GetClientUnknownFromHandle( hEnt );
  173. return pEnt ? pEnt->GetIClientEntity() : 0;
  174. }
  175. IClientRenderable* CClientEntityList::GetClientRenderableFromHandle( ClientEntityHandle_t hEnt )
  176. {
  177. IClientUnknown *pEnt = GetClientUnknownFromHandle( hEnt );
  178. return pEnt ? pEnt->GetClientRenderable() : 0;
  179. }
  180. C_BaseEntity* CClientEntityList::GetBaseEntityFromHandle( ClientEntityHandle_t hEnt )
  181. {
  182. IClientUnknown *pEnt = GetClientUnknownFromHandle( hEnt );
  183. return pEnt ? pEnt->GetBaseEntity() : 0;
  184. }
  185. ICollideable* CClientEntityList::GetCollideableFromHandle( ClientEntityHandle_t hEnt )
  186. {
  187. IClientUnknown *pEnt = GetClientUnknownFromHandle( hEnt );
  188. return pEnt ? pEnt->GetCollideable() : 0;
  189. }
  190. IClientThinkable* CClientEntityList::GetClientThinkableFromHandle( ClientEntityHandle_t hEnt )
  191. {
  192. IClientUnknown *pEnt = GetClientUnknownFromHandle( hEnt );
  193. return pEnt ? pEnt->GetClientThinkable() : 0;
  194. }
  195. void CClientEntityList::AddPVSNotifier( IClientUnknown *pUnknown )
  196. {
  197. IClientRenderable *pRen = pUnknown->GetClientRenderable();
  198. if ( pRen )
  199. {
  200. IPVSNotify *pNotify = pRen->GetPVSNotifyInterface();
  201. if ( pNotify )
  202. {
  203. unsigned short index = m_PVSNotifyInfos.AddToTail();
  204. CPVSNotifyInfo *pInfo = &m_PVSNotifyInfos[index];
  205. pInfo->m_pNotify = pNotify;
  206. pInfo->m_pRenderable = pRen;
  207. pInfo->m_InPVSStatus = 0;
  208. pInfo->m_PVSNotifiersLink = index;
  209. m_PVSNotifierMap.Insert( pUnknown, index );
  210. }
  211. }
  212. }
  213. void CClientEntityList::RemovePVSNotifier( IClientUnknown *pUnknown )
  214. {
  215. IClientRenderable *pRenderable = pUnknown->GetClientRenderable();
  216. if ( pRenderable )
  217. {
  218. IPVSNotify *pNotify = pRenderable->GetPVSNotifyInterface();
  219. if ( pNotify )
  220. {
  221. unsigned short index = m_PVSNotifierMap.Find( pUnknown );
  222. if ( !m_PVSNotifierMap.IsValidIndex( index ) )
  223. {
  224. Warning( "PVS notifier not in m_PVSNotifierMap\n" );
  225. Assert( false );
  226. return;
  227. }
  228. unsigned short indexIntoPVSNotifyInfos = m_PVSNotifierMap[index];
  229. Assert( m_PVSNotifyInfos[indexIntoPVSNotifyInfos].m_pNotify == pNotify );
  230. Assert( m_PVSNotifyInfos[indexIntoPVSNotifyInfos].m_pRenderable == pRenderable );
  231. m_PVSNotifyInfos.Remove( indexIntoPVSNotifyInfos );
  232. m_PVSNotifierMap.RemoveAt( index );
  233. return;
  234. }
  235. }
  236. // If it didn't report itself as a notifier, let's hope it's not in the notifier list now
  237. // (which would mean that it reported itself as a notifier earlier, but not now).
  238. #ifdef _DEBUG
  239. unsigned short index = m_PVSNotifierMap.Find( pUnknown );
  240. Assert( !m_PVSNotifierMap.IsValidIndex( index ) );
  241. #endif
  242. }
  243. void CClientEntityList::AddListenerEntity( IClientEntityListener *pListener )
  244. {
  245. if ( m_entityListeners.Find( pListener ) >= 0 )
  246. {
  247. AssertMsg( 0, "Can't add listeners multiple times\n" );
  248. return;
  249. }
  250. m_entityListeners.AddToTail( pListener );
  251. }
  252. void CClientEntityList::RemoveListenerEntity( IClientEntityListener *pListener )
  253. {
  254. m_entityListeners.FindAndRemove( pListener );
  255. }
  256. void CClientEntityList::OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle )
  257. {
  258. int entnum = handle.GetEntryIndex();
  259. EntityCacheInfo_t *pCache = &m_EntityCacheInfo[entnum];
  260. if ( entnum >= 0 && entnum < MAX_EDICTS )
  261. {
  262. // Update our counters.
  263. m_iNumServerEnts++;
  264. if ( entnum > m_iMaxUsedServerIndex )
  265. {
  266. m_iMaxUsedServerIndex = entnum;
  267. }
  268. // Cache its networkable pointer.
  269. Assert( dynamic_cast< IClientUnknown* >( pEnt ) );
  270. Assert( ((IClientUnknown*)pEnt)->GetClientNetworkable() ); // Server entities should all be networkable.
  271. pCache->m_pNetworkable = ((IClientUnknown*)pEnt)->GetClientNetworkable();
  272. pCache->m_bDormant = true;
  273. }
  274. IClientUnknown *pUnknown = (IClientUnknown*)pEnt;
  275. // If this thing wants PVS notifications, hook it up.
  276. AddPVSNotifier( pUnknown );
  277. // Store it in a special list for fast iteration if it's a C_BaseEntity.
  278. C_BaseEntity *pBaseEntity = pUnknown->GetBaseEntity();
  279. if ( pBaseEntity )
  280. {
  281. pCache->m_BaseEntitiesIndex = m_BaseEntities.AddToTail( pBaseEntity );
  282. if ( pBaseEntity->ObjectCaps() & FCAP_SAVE_NON_NETWORKABLE )
  283. {
  284. m_iNumClientNonNetworkable++;
  285. }
  286. //DevMsg(2,"Created %s\n", pBaseEnt->GetClassname() );
  287. for ( int i = m_entityListeners.Count()-1; i >= 0; i-- )
  288. {
  289. m_entityListeners[i]->OnEntityCreated( pBaseEntity );
  290. }
  291. }
  292. else
  293. {
  294. pCache->m_BaseEntitiesIndex = m_BaseEntities.InvalidIndex();
  295. }
  296. }
  297. void CClientEntityList::OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle )
  298. {
  299. int entnum = handle.GetEntryIndex();
  300. EntityCacheInfo_t *pCache = &m_EntityCacheInfo[entnum];
  301. if ( entnum >= 0 && entnum < MAX_EDICTS )
  302. {
  303. // This is a networkable ent. Clear out our cache info for it.
  304. pCache->m_pNetworkable = NULL;
  305. m_iNumServerEnts--;
  306. if ( entnum >= m_iMaxUsedServerIndex )
  307. {
  308. RecomputeHighestEntityUsed();
  309. }
  310. }
  311. IClientUnknown *pUnknown = (IClientUnknown*)pEnt;
  312. // If this is a PVS notifier, remove it.
  313. RemovePVSNotifier( pUnknown );
  314. C_BaseEntity *pBaseEntity = pUnknown->GetBaseEntity();
  315. if ( pBaseEntity )
  316. {
  317. if ( pBaseEntity->ObjectCaps() & FCAP_SAVE_NON_NETWORKABLE )
  318. {
  319. m_iNumClientNonNetworkable--;
  320. }
  321. //DevMsg(2,"Deleted %s\n", pBaseEnt->GetClassname() );
  322. for ( int i = m_entityListeners.Count()-1; i >= 0; i-- )
  323. {
  324. m_entityListeners[i]->OnEntityDeleted( pBaseEntity );
  325. }
  326. }
  327. if ( pCache->m_BaseEntitiesIndex != m_BaseEntities.InvalidIndex() )
  328. m_BaseEntities.Remove( pCache->m_BaseEntitiesIndex );
  329. pCache->m_BaseEntitiesIndex = m_BaseEntities.InvalidIndex();
  330. }
  331. // Use this to iterate over all the C_BaseEntities.
  332. C_BaseEntity* CClientEntityList::FirstBaseEntity() const
  333. {
  334. const CEntInfo *pList = FirstEntInfo();
  335. while ( pList )
  336. {
  337. if ( pList->m_pEntity )
  338. {
  339. IClientUnknown *pUnk = static_cast<IClientUnknown*>( pList->m_pEntity );
  340. C_BaseEntity *pRet = pUnk->GetBaseEntity();
  341. if ( pRet )
  342. return pRet;
  343. }
  344. pList = pList->m_pNext;
  345. }
  346. return NULL;
  347. }
  348. C_BaseEntity* CClientEntityList::NextBaseEntity( C_BaseEntity *pEnt ) const
  349. {
  350. if ( pEnt == NULL )
  351. return FirstBaseEntity();
  352. // Run through the list until we get a C_BaseEntity.
  353. const CEntInfo *pList = GetEntInfoPtr( pEnt->GetRefEHandle() );
  354. if ( pList )
  355. {
  356. pList = NextEntInfo(pList);
  357. }
  358. while ( pList )
  359. {
  360. if ( pList->m_pEntity )
  361. {
  362. IClientUnknown *pUnk = static_cast<IClientUnknown*>( pList->m_pEntity );
  363. C_BaseEntity *pRet = pUnk->GetBaseEntity();
  364. if ( pRet )
  365. return pRet;
  366. }
  367. pList = pList->m_pNext;
  368. }
  369. return NULL;
  370. }
  371. // -------------------------------------------------------------------------------------------------- //
  372. // C_AllBaseEntityIterator
  373. // -------------------------------------------------------------------------------------------------- //
  374. C_AllBaseEntityIterator::C_AllBaseEntityIterator()
  375. {
  376. Restart();
  377. }
  378. void C_AllBaseEntityIterator::Restart()
  379. {
  380. m_CurBaseEntity = ClientEntityList().m_BaseEntities.Head();
  381. }
  382. C_BaseEntity* C_AllBaseEntityIterator::Next()
  383. {
  384. if ( m_CurBaseEntity == ClientEntityList().m_BaseEntities.InvalidIndex() )
  385. return NULL;
  386. C_BaseEntity *pRet = ClientEntityList().m_BaseEntities[m_CurBaseEntity];
  387. m_CurBaseEntity = ClientEntityList().m_BaseEntities.Next( m_CurBaseEntity );
  388. return pRet;
  389. }
  390. // -------------------------------------------------------------------------------------------------- //
  391. // C_BaseEntityIterator
  392. // -------------------------------------------------------------------------------------------------- //
  393. C_BaseEntityIterator::C_BaseEntityIterator()
  394. {
  395. Restart();
  396. }
  397. void C_BaseEntityIterator::Restart()
  398. {
  399. m_CurBaseEntity = ClientEntityList().m_BaseEntities.Head();
  400. }
  401. C_BaseEntity* C_BaseEntityIterator::Next()
  402. {
  403. // Skip dormant entities
  404. while ( m_CurBaseEntity != ClientEntityList().m_BaseEntities.InvalidIndex() )
  405. {
  406. C_BaseEntity *pRet = ClientEntityList().m_BaseEntities[m_CurBaseEntity];
  407. m_CurBaseEntity = ClientEntityList().m_BaseEntities.Next( m_CurBaseEntity );
  408. if (!pRet->IsDormant())
  409. return pRet;
  410. }
  411. return NULL;
  412. }