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.

1636 lines
43 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "entitylist.h"
  9. #include "utlvector.h"
  10. #include "igamesystem.h"
  11. #include "collisionutils.h"
  12. #include "UtlSortVector.h"
  13. #include "tier0/vprof.h"
  14. #include "mapentities.h"
  15. #include "client.h"
  16. #include "ai_initutils.h"
  17. #include "globalstate.h"
  18. #include "datacache/imdlcache.h"
  19. #ifdef HL2_DLL
  20. #include "npc_playercompanion.h"
  21. #endif // HL2_DLL
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. CBaseEntity *FindPickerEntity( CBasePlayer *pPlayer );
  25. void SceneManager_ClientActive( CBasePlayer *player );
  26. static CUtlVector<IServerNetworkable*> g_DeleteList;
  27. CGlobalEntityList gEntList;
  28. CBaseEntityList *g_pEntityList = &gEntList;
  29. class CAimTargetManager : public IEntityListener
  30. {
  31. public:
  32. // Called by CEntityListSystem
  33. void LevelInitPreEntity()
  34. {
  35. gEntList.AddListenerEntity( this );
  36. Clear();
  37. }
  38. void LevelShutdownPostEntity()
  39. {
  40. gEntList.RemoveListenerEntity( this );
  41. Clear();
  42. }
  43. void Clear()
  44. {
  45. m_targetList.Purge();
  46. }
  47. void ForceRepopulateList()
  48. {
  49. Clear();
  50. CBaseEntity *pEnt = gEntList.FirstEnt();
  51. while( pEnt )
  52. {
  53. if( ShouldAddEntity(pEnt) )
  54. AddEntity(pEnt);
  55. pEnt = gEntList.NextEnt( pEnt );
  56. }
  57. }
  58. bool ShouldAddEntity( CBaseEntity *pEntity )
  59. {
  60. return ((pEntity->GetFlags() & FL_AIMTARGET) != 0);
  61. }
  62. // IEntityListener
  63. virtual void OnEntityCreated( CBaseEntity *pEntity ) {}
  64. virtual void OnEntityDeleted( CBaseEntity *pEntity )
  65. {
  66. if ( !(pEntity->GetFlags() & FL_AIMTARGET) )
  67. return;
  68. RemoveEntity(pEntity);
  69. }
  70. void AddEntity( CBaseEntity *pEntity )
  71. {
  72. if ( pEntity->IsMarkedForDeletion() )
  73. return;
  74. m_targetList.AddToTail( pEntity );
  75. }
  76. void RemoveEntity( CBaseEntity *pEntity )
  77. {
  78. int index = m_targetList.Find( pEntity );
  79. if ( m_targetList.IsValidIndex(index) )
  80. {
  81. m_targetList.FastRemove( index );
  82. }
  83. }
  84. int ListCount() { return m_targetList.Count(); }
  85. int ListCopy( CBaseEntity *pList[], int listMax )
  86. {
  87. int count = MIN(listMax, ListCount() );
  88. memcpy( pList, m_targetList.Base(), sizeof(CBaseEntity *) * count );
  89. return count;
  90. }
  91. private:
  92. CUtlVector<CBaseEntity *> m_targetList;
  93. };
  94. static CAimTargetManager g_AimManager;
  95. int AimTarget_ListCount()
  96. {
  97. return g_AimManager.ListCount();
  98. }
  99. int AimTarget_ListCopy( CBaseEntity *pList[], int listMax )
  100. {
  101. return g_AimManager.ListCopy( pList, listMax );
  102. }
  103. void AimTarget_ForceRepopulateList()
  104. {
  105. g_AimManager.ForceRepopulateList();
  106. }
  107. // Manages a list of all entities currently doing game simulation or thinking
  108. // NOTE: This is usually a small subset of the global entity list, so it's
  109. // an optimization to maintain this list incrementally rather than polling each
  110. // frame.
  111. struct simthinkentry_t
  112. {
  113. unsigned short entEntry;
  114. unsigned short unused0;
  115. int nextThinkTick;
  116. };
  117. class CSimThinkManager : public IEntityListener
  118. {
  119. public:
  120. CSimThinkManager()
  121. {
  122. Clear();
  123. }
  124. void Clear()
  125. {
  126. m_simThinkList.Purge();
  127. for ( int i = 0; i < ARRAYSIZE(m_entinfoIndex); i++ )
  128. {
  129. m_entinfoIndex[i] = 0xFFFF;
  130. }
  131. }
  132. void LevelInitPreEntity()
  133. {
  134. gEntList.AddListenerEntity( this );
  135. }
  136. void LevelShutdownPostEntity()
  137. {
  138. gEntList.RemoveListenerEntity( this );
  139. Clear();
  140. }
  141. void OnEntityCreated( CBaseEntity *pEntity )
  142. {
  143. Assert( m_entinfoIndex[pEntity->GetRefEHandle().GetEntryIndex()] == 0xFFFF );
  144. }
  145. void OnEntityDeleted( CBaseEntity *pEntity )
  146. {
  147. RemoveEntinfoIndex( pEntity->GetRefEHandle().GetEntryIndex() );
  148. }
  149. void RemoveEntinfoIndex( int index )
  150. {
  151. int listHandle = m_entinfoIndex[index];
  152. // If this guy is in the active list, remove him
  153. if ( listHandle != 0xFFFF )
  154. {
  155. Assert(m_simThinkList[listHandle].entEntry == index);
  156. m_simThinkList.FastRemove( listHandle );
  157. m_entinfoIndex[index] = 0xFFFF;
  158. // fast remove shifted someone, update that someone
  159. if ( listHandle < m_simThinkList.Count() )
  160. {
  161. m_entinfoIndex[m_simThinkList[listHandle].entEntry] = listHandle;
  162. }
  163. }
  164. }
  165. int ListCount()
  166. {
  167. return m_simThinkList.Count();
  168. }
  169. int ListCopy( CBaseEntity *pList[], int listMax )
  170. {
  171. int count = MIN(listMax, ListCount());
  172. int out = 0;
  173. for ( int i = 0; i < count; i++ )
  174. {
  175. // only copy out entities that will simulate or think this frame
  176. if ( m_simThinkList[i].nextThinkTick <= gpGlobals->tickcount )
  177. {
  178. Assert(m_simThinkList[i].nextThinkTick>=0);
  179. int entinfoIndex = m_simThinkList[i].entEntry;
  180. const CEntInfo *pInfo = gEntList.GetEntInfoPtrByIndex( entinfoIndex );
  181. pList[out] = (CBaseEntity *)pInfo->m_pEntity;
  182. Assert(m_simThinkList[i].nextThinkTick==0 || pList[out]->GetFirstThinkTick()==m_simThinkList[i].nextThinkTick);
  183. Assert( gEntList.IsEntityPtr( pList[out] ) );
  184. out++;
  185. }
  186. }
  187. return out;
  188. }
  189. void EntityChanged( CBaseEntity *pEntity )
  190. {
  191. // might change after deletion, don't put back into the list
  192. if ( pEntity->IsMarkedForDeletion() )
  193. return;
  194. const CBaseHandle &eh = pEntity->GetRefEHandle();
  195. if ( !eh.IsValid() )
  196. return;
  197. int index = eh.GetEntryIndex();
  198. if ( pEntity->IsEFlagSet( EFL_NO_THINK_FUNCTION ) && pEntity->IsEFlagSet( EFL_NO_GAME_PHYSICS_SIMULATION ) )
  199. {
  200. RemoveEntinfoIndex( index );
  201. }
  202. else
  203. {
  204. // already in the list? (had think or sim last time, now has both - or had both last time, now just one)
  205. if ( m_entinfoIndex[index] == 0xFFFF )
  206. {
  207. MEM_ALLOC_CREDIT();
  208. m_entinfoIndex[index] = m_simThinkList.AddToTail();
  209. m_simThinkList[m_entinfoIndex[index]].entEntry = (unsigned short)index;
  210. m_simThinkList[m_entinfoIndex[index]].nextThinkTick = 0;
  211. if ( pEntity->IsEFlagSet(EFL_NO_GAME_PHYSICS_SIMULATION) )
  212. {
  213. m_simThinkList[m_entinfoIndex[index]].nextThinkTick = pEntity->GetFirstThinkTick();
  214. Assert(m_simThinkList[m_entinfoIndex[index]].nextThinkTick>=0);
  215. }
  216. }
  217. else
  218. {
  219. // updating existing entry - if no sim, reset think time
  220. if ( pEntity->IsEFlagSet(EFL_NO_GAME_PHYSICS_SIMULATION) )
  221. {
  222. m_simThinkList[m_entinfoIndex[index]].nextThinkTick = pEntity->GetFirstThinkTick();
  223. Assert(m_simThinkList[m_entinfoIndex[index]].nextThinkTick>=0);
  224. }
  225. else
  226. {
  227. m_simThinkList[m_entinfoIndex[index]].nextThinkTick = 0;
  228. }
  229. }
  230. }
  231. }
  232. private:
  233. unsigned short m_entinfoIndex[NUM_ENT_ENTRIES];
  234. CUtlVector<simthinkentry_t> m_simThinkList;
  235. };
  236. CSimThinkManager g_SimThinkManager;
  237. int SimThink_ListCount()
  238. {
  239. return g_SimThinkManager.ListCount();
  240. }
  241. int SimThink_ListCopy( CBaseEntity *pList[], int listMax )
  242. {
  243. return g_SimThinkManager.ListCopy( pList, listMax );
  244. }
  245. void SimThink_EntityChanged( CBaseEntity *pEntity )
  246. {
  247. g_SimThinkManager.EntityChanged( pEntity );
  248. }
  249. static CBaseEntityClassList *s_pClassLists = NULL;
  250. CBaseEntityClassList::CBaseEntityClassList()
  251. {
  252. m_pNextClassList = s_pClassLists;
  253. s_pClassLists = this;
  254. }
  255. CBaseEntityClassList::~CBaseEntityClassList()
  256. {
  257. }
  258. CGlobalEntityList::CGlobalEntityList()
  259. {
  260. m_iHighestEnt = m_iNumEnts = m_iNumEdicts = 0;
  261. m_bClearingEntities = false;
  262. }
  263. // removes the entity from the global list
  264. // only called from with the CBaseEntity destructor
  265. static bool g_fInCleanupDelete;
  266. // mark an entity as deleted
  267. void CGlobalEntityList::AddToDeleteList( IServerNetworkable *ent )
  268. {
  269. if ( ent && ent->GetEntityHandle()->GetRefEHandle() != INVALID_EHANDLE_INDEX )
  270. {
  271. g_DeleteList.AddToTail( ent );
  272. }
  273. }
  274. extern bool g_bDisableEhandleAccess;
  275. // call this before and after each frame to delete all of the marked entities.
  276. void CGlobalEntityList::CleanupDeleteList( void )
  277. {
  278. VPROF( "CGlobalEntityList::CleanupDeleteList" );
  279. g_fInCleanupDelete = true;
  280. // clean up the vphysics delete list as well
  281. PhysOnCleanupDeleteList();
  282. g_bDisableEhandleAccess = true;
  283. for ( int i = 0; i < g_DeleteList.Count(); i++ )
  284. {
  285. g_DeleteList[i]->Release();
  286. }
  287. g_bDisableEhandleAccess = false;
  288. g_DeleteList.RemoveAll();
  289. g_fInCleanupDelete = false;
  290. }
  291. int CGlobalEntityList::ResetDeleteList( void )
  292. {
  293. int result = g_DeleteList.Count();
  294. g_DeleteList.RemoveAll();
  295. return result;
  296. }
  297. // add a class that gets notified of entity events
  298. void CGlobalEntityList::AddListenerEntity( IEntityListener *pListener )
  299. {
  300. if ( m_entityListeners.Find( pListener ) >= 0 )
  301. {
  302. AssertMsg( 0, "Can't add listeners multiple times\n" );
  303. return;
  304. }
  305. m_entityListeners.AddToTail( pListener );
  306. }
  307. void CGlobalEntityList::RemoveListenerEntity( IEntityListener *pListener )
  308. {
  309. m_entityListeners.FindAndRemove( pListener );
  310. }
  311. void CGlobalEntityList::Clear( void )
  312. {
  313. m_bClearingEntities = true;
  314. // Add all remaining entities in the game to the delete list and call appropriate UpdateOnRemove
  315. CBaseHandle hCur = FirstHandle();
  316. while ( hCur != InvalidHandle() )
  317. {
  318. IServerNetworkable *ent = GetServerNetworkable( hCur );
  319. if ( ent )
  320. {
  321. MDLCACHE_CRITICAL_SECTION();
  322. // Force UpdateOnRemove to be called
  323. UTIL_Remove( ent );
  324. }
  325. hCur = NextHandle( hCur );
  326. }
  327. CleanupDeleteList();
  328. // free the memory
  329. g_DeleteList.Purge();
  330. CBaseEntity::m_nDebugPlayer = -1;
  331. CBaseEntity::m_bInDebugSelect = false;
  332. m_iHighestEnt = 0;
  333. m_iNumEnts = 0;
  334. m_bClearingEntities = false;
  335. }
  336. int CGlobalEntityList::NumberOfEntities( void )
  337. {
  338. return m_iNumEnts;
  339. }
  340. int CGlobalEntityList::NumberOfEdicts( void )
  341. {
  342. return m_iNumEdicts;
  343. }
  344. CBaseEntity *CGlobalEntityList::NextEnt( CBaseEntity *pCurrentEnt )
  345. {
  346. if ( !pCurrentEnt )
  347. {
  348. const CEntInfo *pInfo = FirstEntInfo();
  349. if ( !pInfo )
  350. return NULL;
  351. return (CBaseEntity *)pInfo->m_pEntity;
  352. }
  353. // Run through the list until we get a CBaseEntity.
  354. const CEntInfo *pList = GetEntInfoPtr( pCurrentEnt->GetRefEHandle() );
  355. if ( pList )
  356. pList = NextEntInfo(pList);
  357. while ( pList )
  358. {
  359. #if 0
  360. if ( pList->m_pEntity )
  361. {
  362. IServerUnknown *pUnk = static_cast<IServerUnknown*>(const_cast<IHandleEntity*>(pList->m_pEntity));
  363. CBaseEntity *pRet = pUnk->GetBaseEntity();
  364. if ( pRet )
  365. return pRet;
  366. }
  367. #else
  368. return (CBaseEntity *)pList->m_pEntity;
  369. #endif
  370. pList = pList->m_pNext;
  371. }
  372. return NULL;
  373. }
  374. void CGlobalEntityList::ReportEntityFlagsChanged( CBaseEntity *pEntity, unsigned int flagsOld, unsigned int flagsNow )
  375. {
  376. if ( pEntity->IsMarkedForDeletion() )
  377. return;
  378. // UNDONE: Move this into IEntityListener instead?
  379. unsigned int flagsChanged = flagsOld ^ flagsNow;
  380. if ( flagsChanged & FL_AIMTARGET )
  381. {
  382. unsigned int flagsAdded = flagsNow & flagsChanged;
  383. unsigned int flagsRemoved = flagsOld & flagsChanged;
  384. if ( flagsAdded & FL_AIMTARGET )
  385. {
  386. g_AimManager.AddEntity( pEntity );
  387. }
  388. if ( flagsRemoved & FL_AIMTARGET )
  389. {
  390. g_AimManager.RemoveEntity( pEntity );
  391. }
  392. }
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Purpose: Used to confirm a pointer is a pointer to an entity, useful for
  396. // asserts.
  397. //-----------------------------------------------------------------------------
  398. bool CGlobalEntityList::IsEntityPtr( void *pTest )
  399. {
  400. if ( pTest )
  401. {
  402. const CEntInfo *pInfo = FirstEntInfo();
  403. for ( ;pInfo; pInfo = pInfo->m_pNext )
  404. {
  405. if ( pTest == (void *)pInfo->m_pEntity )
  406. return true;
  407. }
  408. }
  409. return false;
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Purpose: Iterates the entities with a given classname.
  413. // Input : pStartEntity - Last entity found, NULL to start a new iteration.
  414. // szName - Classname to search for.
  415. //-----------------------------------------------------------------------------
  416. CBaseEntity *CGlobalEntityList::FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName )
  417. {
  418. const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
  419. for ( ;pInfo; pInfo = pInfo->m_pNext )
  420. {
  421. CBaseEntity *pEntity = (CBaseEntity *)pInfo->m_pEntity;
  422. if ( !pEntity )
  423. {
  424. DevWarning( "NULL entity in global entity list!\n" );
  425. continue;
  426. }
  427. if ( pEntity->ClassMatches(szName) )
  428. return pEntity;
  429. }
  430. return NULL;
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Purpose: Finds an entity given a procedural name.
  434. // Input : szName - The procedural name to search for, should start with '!'.
  435. // pSearchingEntity -
  436. // pActivator - The activator entity if this was called from an input
  437. // or Use handler.
  438. //-----------------------------------------------------------------------------
  439. CBaseEntity *CGlobalEntityList::FindEntityProcedural( const char *szName, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
  440. {
  441. //
  442. // Check for the name escape character.
  443. //
  444. if ( szName[0] == '!' )
  445. {
  446. const char *pName = szName + 1;
  447. //
  448. // It is a procedural name, look for the ones we understand.
  449. //
  450. if ( FStrEq( pName, "player" ) )
  451. {
  452. return (CBaseEntity *)UTIL_PlayerByIndex( 1 );
  453. }
  454. else if ( FStrEq( pName, "pvsplayer" ) )
  455. {
  456. if ( pSearchingEntity )
  457. {
  458. return CBaseEntity::Instance( UTIL_FindClientInPVS( pSearchingEntity->edict() ) );
  459. }
  460. else if ( pActivator )
  461. {
  462. // FIXME: error condition?
  463. return CBaseEntity::Instance( UTIL_FindClientInPVS( pActivator->edict() ) );
  464. }
  465. else
  466. {
  467. // FIXME: error condition?
  468. return (CBaseEntity *)UTIL_PlayerByIndex( 1 );
  469. }
  470. }
  471. else if ( FStrEq( pName, "activator" ) )
  472. {
  473. return pActivator;
  474. }
  475. else if ( FStrEq( pName, "caller" ) )
  476. {
  477. return pCaller;
  478. }
  479. else if ( FStrEq( pName, "picker" ) )
  480. {
  481. return FindPickerEntity( UTIL_PlayerByIndex(1) );
  482. }
  483. else if ( FStrEq( pName, "self" ) )
  484. {
  485. return pSearchingEntity;
  486. }
  487. else
  488. {
  489. Warning( "Invalid entity search name %s\n", szName );
  490. Assert(0);
  491. }
  492. }
  493. return NULL;
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Purpose: Iterates the entities with a given name.
  497. // Input : pStartEntity - Last entity found, NULL to start a new iteration.
  498. // szName - Name to search for.
  499. // pActivator - Activator entity if this was called from an input
  500. // handler or Use handler.
  501. //-----------------------------------------------------------------------------
  502. CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller, IEntityFindFilter *pFilter )
  503. {
  504. if ( !szName || szName[0] == 0 )
  505. return NULL;
  506. if ( szName[0] == '!' )
  507. {
  508. //
  509. // Avoid an infinite loop, only find one match per procedural search!
  510. //
  511. if (pStartEntity == NULL)
  512. return FindEntityProcedural( szName, pSearchingEntity, pActivator, pCaller );
  513. return NULL;
  514. }
  515. const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
  516. for ( ;pInfo; pInfo = pInfo->m_pNext )
  517. {
  518. CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
  519. if ( !ent )
  520. {
  521. DevWarning( "NULL entity in global entity list!\n" );
  522. continue;
  523. }
  524. if ( !ent->m_iName )
  525. continue;
  526. if ( ent->NameMatches( szName ) )
  527. {
  528. if ( pFilter && !pFilter->ShouldFindEntity(ent) )
  529. continue;
  530. return ent;
  531. }
  532. }
  533. return NULL;
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose:
  537. // Input : pStartEntity -
  538. // szModelName -
  539. //-----------------------------------------------------------------------------
  540. CBaseEntity *CGlobalEntityList::FindEntityByModel( CBaseEntity *pStartEntity, const char *szModelName )
  541. {
  542. const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
  543. for ( ;pInfo; pInfo = pInfo->m_pNext )
  544. {
  545. CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
  546. if ( !ent )
  547. {
  548. DevWarning( "NULL entity in global entity list!\n" );
  549. continue;
  550. }
  551. if ( !ent->edict() || !ent->GetModelName() )
  552. continue;
  553. if ( FStrEq( STRING(ent->GetModelName()), szModelName ) )
  554. return ent;
  555. }
  556. return NULL;
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose: Iterates the entities with a given target.
  560. // Input : pStartEntity -
  561. // szName -
  562. //-----------------------------------------------------------------------------
  563. // FIXME: obsolete, remove
  564. CBaseEntity *CGlobalEntityList::FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName )
  565. {
  566. const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
  567. for ( ;pInfo; pInfo = pInfo->m_pNext )
  568. {
  569. CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
  570. if ( !ent )
  571. {
  572. DevWarning( "NULL entity in global entity list!\n" );
  573. continue;
  574. }
  575. if ( !ent->m_target )
  576. continue;
  577. if ( FStrEq( STRING(ent->m_target), szName ) )
  578. return ent;
  579. }
  580. return NULL;
  581. }
  582. //-----------------------------------------------------------------------------
  583. // Purpose: Used to iterate all the entities within a sphere.
  584. // Input : pStartEntity -
  585. // vecCenter -
  586. // flRadius -
  587. //-----------------------------------------------------------------------------
  588. CBaseEntity *CGlobalEntityList::FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius )
  589. {
  590. const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
  591. for ( ;pInfo; pInfo = pInfo->m_pNext )
  592. {
  593. CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
  594. if ( !ent )
  595. {
  596. DevWarning( "NULL entity in global entity list!\n" );
  597. continue;
  598. }
  599. if ( !ent->edict() )
  600. continue;
  601. Vector vecRelativeCenter;
  602. ent->CollisionProp()->WorldToCollisionSpace( vecCenter, &vecRelativeCenter );
  603. if ( !IsBoxIntersectingSphere( ent->CollisionProp()->OBBMins(), ent->CollisionProp()->OBBMaxs(), vecRelativeCenter, flRadius ) )
  604. continue;
  605. return ent;
  606. }
  607. // nothing found
  608. return NULL;
  609. }
  610. //-----------------------------------------------------------------------------
  611. // Purpose: Finds the nearest entity by name within a radius
  612. // Input : szName - Entity name to search for.
  613. // vecSrc - Center of search radius.
  614. // flRadius - Search radius for classname search, 0 to search everywhere.
  615. // pSearchingEntity - The entity that is doing the search.
  616. // pActivator - The activator entity if this was called from an input
  617. // or Use handler, NULL otherwise.
  618. // Output : Returns a pointer to the found entity, NULL if none.
  619. //-----------------------------------------------------------------------------
  620. CBaseEntity *CGlobalEntityList::FindEntityByNameNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
  621. {
  622. CBaseEntity *pEntity = NULL;
  623. //
  624. // Check for matching class names within the search radius.
  625. //
  626. float flMaxDist2 = flRadius * flRadius;
  627. if (flMaxDist2 == 0)
  628. {
  629. flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH;
  630. }
  631. CBaseEntity *pSearch = NULL;
  632. while ((pSearch = gEntList.FindEntityByName( pSearch, szName, pSearchingEntity, pActivator, pCaller )) != NULL)
  633. {
  634. if ( !pSearch->edict() )
  635. continue;
  636. float flDist2 = (pSearch->GetAbsOrigin() - vecSrc).LengthSqr();
  637. if (flMaxDist2 > flDist2)
  638. {
  639. pEntity = pSearch;
  640. flMaxDist2 = flDist2;
  641. }
  642. }
  643. return pEntity;
  644. }
  645. //-----------------------------------------------------------------------------
  646. // Purpose: Finds the first entity by name within a radius
  647. // Input : pStartEntity - The entity to start from when doing the search.
  648. // szName - Entity name to search for.
  649. // vecSrc - Center of search radius.
  650. // flRadius - Search radius for classname search, 0 to search everywhere.
  651. // pSearchingEntity - The entity that is doing the search.
  652. // pActivator - The activator entity if this was called from an input
  653. // or Use handler, NULL otherwise.
  654. // Output : Returns a pointer to the found entity, NULL if none.
  655. //-----------------------------------------------------------------------------
  656. CBaseEntity *CGlobalEntityList::FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
  657. {
  658. //
  659. // Check for matching class names within the search radius.
  660. //
  661. CBaseEntity *pEntity = pStartEntity;
  662. float flMaxDist2 = flRadius * flRadius;
  663. if (flMaxDist2 == 0)
  664. {
  665. return gEntList.FindEntityByName( pEntity, szName, pSearchingEntity, pActivator, pCaller );
  666. }
  667. while ((pEntity = gEntList.FindEntityByName( pEntity, szName, pSearchingEntity, pActivator, pCaller )) != NULL)
  668. {
  669. if ( !pEntity->edict() )
  670. continue;
  671. float flDist2 = (pEntity->GetAbsOrigin() - vecSrc).LengthSqr();
  672. if (flMaxDist2 > flDist2)
  673. {
  674. return pEntity;
  675. }
  676. }
  677. return NULL;
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Purpose: Finds the nearest entity by class name withing given search radius.
  681. // Input : szName - Entity name to search for. Treated as a target name first,
  682. // then as an entity class name, ie "info_target".
  683. // vecSrc - Center of search radius.
  684. // flRadius - Search radius for classname search, 0 to search everywhere.
  685. // Output : Returns a pointer to the found entity, NULL if none.
  686. //-----------------------------------------------------------------------------
  687. CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius )
  688. {
  689. CBaseEntity *pEntity = NULL;
  690. //
  691. // Check for matching class names within the search radius.
  692. //
  693. float flMaxDist2 = flRadius * flRadius;
  694. if (flMaxDist2 == 0)
  695. {
  696. flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH;
  697. }
  698. CBaseEntity *pSearch = NULL;
  699. while ((pSearch = gEntList.FindEntityByClassname( pSearch, szName )) != NULL)
  700. {
  701. if ( !pSearch->edict() )
  702. continue;
  703. float flDist2 = (pSearch->GetAbsOrigin() - vecSrc).LengthSqr();
  704. if (flMaxDist2 > flDist2)
  705. {
  706. pEntity = pSearch;
  707. flMaxDist2 = flDist2;
  708. }
  709. }
  710. return pEntity;
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Purpose: Finds the first entity within radius distance by class name.
  714. // Input : pStartEntity - The entity to start from when doing the search.
  715. // szName - Entity class name, ie "info_target".
  716. // vecSrc - Center of search radius.
  717. // flRadius - Search radius for classname search, 0 to search everywhere.
  718. // Output : Returns a pointer to the found entity, NULL if none.
  719. //-----------------------------------------------------------------------------
  720. CBaseEntity *CGlobalEntityList::FindEntityByClassnameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius )
  721. {
  722. //
  723. // Check for matching class names within the search radius.
  724. //
  725. CBaseEntity *pEntity = pStartEntity;
  726. float flMaxDist2 = flRadius * flRadius;
  727. if (flMaxDist2 == 0)
  728. {
  729. return gEntList.FindEntityByClassname( pEntity, szName );
  730. }
  731. while ((pEntity = gEntList.FindEntityByClassname( pEntity, szName )) != NULL)
  732. {
  733. if ( !pEntity->edict() )
  734. continue;
  735. float flDist2 = (pEntity->GetAbsOrigin() - vecSrc).LengthSqr();
  736. if (flMaxDist2 > flDist2)
  737. {
  738. return pEntity;
  739. }
  740. }
  741. return NULL;
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Purpose: Finds the first entity within an extent by class name.
  745. // Input : pStartEntity - The entity to start from when doing the search.
  746. // szName - Entity class name, ie "info_target".
  747. // vecMins - Search mins.
  748. // vecMaxs - Search maxs.
  749. // Output : Returns a pointer to the found entity, NULL if none.
  750. //-----------------------------------------------------------------------------
  751. CBaseEntity *CGlobalEntityList::FindEntityByClassnameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecMins, const Vector &vecMaxs )
  752. {
  753. //
  754. // Check for matching class names within the search radius.
  755. //
  756. CBaseEntity *pEntity = pStartEntity;
  757. while ((pEntity = gEntList.FindEntityByClassname( pEntity, szName )) != NULL)
  758. {
  759. if ( !pEntity->edict() && !pEntity->IsEFlagSet( EFL_SERVER_ONLY ) )
  760. continue;
  761. // check if the aabb intersects the search aabb.
  762. Vector entMins, entMaxs;
  763. pEntity->CollisionProp()->WorldSpaceAABB( &entMins, &entMaxs );
  764. if ( IsBoxIntersectingBox( vecMins, vecMaxs, entMins, entMaxs ) )
  765. {
  766. return pEntity;
  767. }
  768. }
  769. return NULL;
  770. }
  771. //-----------------------------------------------------------------------------
  772. // Purpose: Finds an entity by target name or class name.
  773. // Input : pStartEntity - The entity to start from when doing the search.
  774. // szName - Entity name to search for. Treated as a target name first,
  775. // then as an entity class name, ie "info_target".
  776. // vecSrc - Center of search radius.
  777. // flRadius - Search radius for classname search, 0 to search everywhere.
  778. // pSearchingEntity - The entity that is doing the search.
  779. // pActivator - The activator entity if this was called from an input
  780. // or Use handler, NULL otherwise.
  781. // Output : Returns a pointer to the found entity, NULL if none.
  782. //-----------------------------------------------------------------------------
  783. CBaseEntity *CGlobalEntityList::FindEntityGeneric( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
  784. {
  785. CBaseEntity *pEntity = NULL;
  786. pEntity = gEntList.FindEntityByName( pStartEntity, szName, pSearchingEntity, pActivator, pCaller );
  787. if (!pEntity)
  788. {
  789. pEntity = gEntList.FindEntityByClassname( pStartEntity, szName );
  790. }
  791. return pEntity;
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Purpose: Finds the first entity by target name or class name within a radius
  795. // Input : pStartEntity - The entity to start from when doing the search.
  796. // szName - Entity name to search for. Treated as a target name first,
  797. // then as an entity class name, ie "info_target".
  798. // vecSrc - Center of search radius.
  799. // flRadius - Search radius for classname search, 0 to search everywhere.
  800. // pSearchingEntity - The entity that is doing the search.
  801. // pActivator - The activator entity if this was called from an input
  802. // or Use handler, NULL otherwise.
  803. // Output : Returns a pointer to the found entity, NULL if none.
  804. //-----------------------------------------------------------------------------
  805. CBaseEntity *CGlobalEntityList::FindEntityGenericWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
  806. {
  807. CBaseEntity *pEntity = NULL;
  808. pEntity = gEntList.FindEntityByNameWithin( pStartEntity, szName, vecSrc, flRadius, pSearchingEntity, pActivator, pCaller );
  809. if (!pEntity)
  810. {
  811. pEntity = gEntList.FindEntityByClassnameWithin( pStartEntity, szName, vecSrc, flRadius );
  812. }
  813. return pEntity;
  814. }
  815. //-----------------------------------------------------------------------------
  816. // Purpose: Finds the nearest entity by target name or class name within a radius.
  817. // Input : pStartEntity - The entity to start from when doing the search.
  818. // szName - Entity name to search for. Treated as a target name first,
  819. // then as an entity class name, ie "info_target".
  820. // vecSrc - Center of search radius.
  821. // flRadius - Search radius for classname search, 0 to search everywhere.
  822. // pSearchingEntity - The entity that is doing the search.
  823. // pActivator - The activator entity if this was called from an input
  824. // or Use handler, NULL otherwise.
  825. // Output : Returns a pointer to the found entity, NULL if none.
  826. //-----------------------------------------------------------------------------
  827. CBaseEntity *CGlobalEntityList::FindEntityGenericNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
  828. {
  829. CBaseEntity *pEntity = NULL;
  830. pEntity = gEntList.FindEntityByNameNearest( szName, vecSrc, flRadius, pSearchingEntity, pActivator, pCaller );
  831. if (!pEntity)
  832. {
  833. pEntity = gEntList.FindEntityByClassnameNearest( szName, vecSrc, flRadius );
  834. }
  835. return pEntity;
  836. }
  837. //-----------------------------------------------------------------------------
  838. // Purpose: Find the nearest entity along the facing direction from the given origin
  839. // within the angular threshold (ignores worldspawn) with the
  840. // given classname.
  841. // Input : origin -
  842. // facing -
  843. // threshold -
  844. // classname -
  845. //-----------------------------------------------------------------------------
  846. CBaseEntity *CGlobalEntityList::FindEntityClassNearestFacing( const Vector &origin, const Vector &facing, float threshold, char *classname)
  847. {
  848. float bestDot = threshold;
  849. CBaseEntity *best_ent = NULL;
  850. const CEntInfo *pInfo = FirstEntInfo();
  851. for ( ;pInfo; pInfo = pInfo->m_pNext )
  852. {
  853. CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
  854. if ( !ent )
  855. {
  856. DevWarning( "NULL entity in global entity list!\n" );
  857. continue;
  858. }
  859. // FIXME: why is this skipping pointsize entities?
  860. if (ent->IsPointSized() )
  861. continue;
  862. // Make vector to entity
  863. Vector to_ent = (ent->GetAbsOrigin() - origin);
  864. VectorNormalize( to_ent );
  865. float dot = DotProduct (facing , to_ent );
  866. if (dot > bestDot)
  867. {
  868. if (FClassnameIs(ent,classname))
  869. {
  870. // Ignore if worldspawn
  871. if (!FClassnameIs( ent, "worldspawn" ) && !FClassnameIs( ent, "soundent"))
  872. {
  873. bestDot = dot;
  874. best_ent = ent;
  875. }
  876. }
  877. }
  878. }
  879. return best_ent;
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Purpose: Find the nearest entity along the facing direction from the given origin
  883. // within the angular threshold (ignores worldspawn)
  884. // Input : origin -
  885. // facing -
  886. // threshold -
  887. //-----------------------------------------------------------------------------
  888. CBaseEntity *CGlobalEntityList::FindEntityNearestFacing( const Vector &origin, const Vector &facing, float threshold)
  889. {
  890. float bestDot = threshold;
  891. CBaseEntity *best_ent = NULL;
  892. const CEntInfo *pInfo = FirstEntInfo();
  893. for ( ;pInfo; pInfo = pInfo->m_pNext )
  894. {
  895. CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
  896. if ( !ent )
  897. {
  898. DevWarning( "NULL entity in global entity list!\n" );
  899. continue;
  900. }
  901. // Ignore logical entities
  902. if (!ent->edict())
  903. continue;
  904. // Make vector to entity
  905. Vector to_ent = ent->WorldSpaceCenter() - origin;
  906. VectorNormalize(to_ent);
  907. float dot = DotProduct( facing, to_ent );
  908. if (dot <= bestDot)
  909. continue;
  910. // Ignore if worldspawn
  911. if (!FStrEq( STRING(ent->m_iClassname), "worldspawn") && !FStrEq( STRING(ent->m_iClassname), "soundent"))
  912. {
  913. bestDot = dot;
  914. best_ent = ent;
  915. }
  916. }
  917. return best_ent;
  918. }
  919. void CGlobalEntityList::OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle )
  920. {
  921. int i = handle.GetEntryIndex();
  922. // record current list details
  923. m_iNumEnts++;
  924. if ( i > m_iHighestEnt )
  925. m_iHighestEnt = i;
  926. // If it's a CBaseEntity, notify the listeners.
  927. CBaseEntity *pBaseEnt = static_cast<IServerUnknown*>(pEnt)->GetBaseEntity();
  928. if ( pBaseEnt->edict() )
  929. m_iNumEdicts++;
  930. // NOTE: Must be a CBaseEntity on server
  931. Assert( pBaseEnt );
  932. //DevMsg(2,"Created %s\n", pBaseEnt->GetClassname() );
  933. for ( i = m_entityListeners.Count()-1; i >= 0; i-- )
  934. {
  935. m_entityListeners[i]->OnEntityCreated( pBaseEnt );
  936. }
  937. }
  938. void CGlobalEntityList::OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle )
  939. {
  940. #ifdef DBGFLAG_ASSERT
  941. if ( !g_fInCleanupDelete )
  942. {
  943. int i;
  944. for ( i = 0; i < g_DeleteList.Count(); i++ )
  945. {
  946. if ( g_DeleteList[i]->GetEntityHandle() == pEnt )
  947. {
  948. g_DeleteList.FastRemove( i );
  949. Msg( "ERROR: Entity being destroyed but previously threaded on g_DeleteList\n" );
  950. break;
  951. }
  952. }
  953. }
  954. #endif
  955. CBaseEntity *pBaseEnt = static_cast<IServerUnknown*>(pEnt)->GetBaseEntity();
  956. if ( pBaseEnt->edict() )
  957. m_iNumEdicts--;
  958. m_iNumEnts--;
  959. }
  960. void CGlobalEntityList::NotifyCreateEntity( CBaseEntity *pEnt )
  961. {
  962. if ( !pEnt )
  963. return;
  964. //DevMsg(2,"Deleted %s\n", pBaseEnt->GetClassname() );
  965. for ( int i = m_entityListeners.Count()-1; i >= 0; i-- )
  966. {
  967. m_entityListeners[i]->OnEntityCreated( pEnt );
  968. }
  969. }
  970. void CGlobalEntityList::NotifySpawn( CBaseEntity *pEnt )
  971. {
  972. if ( !pEnt )
  973. return;
  974. //DevMsg(2,"Deleted %s\n", pBaseEnt->GetClassname() );
  975. for ( int i = m_entityListeners.Count()-1; i >= 0; i-- )
  976. {
  977. m_entityListeners[i]->OnEntitySpawned( pEnt );
  978. }
  979. }
  980. // NOTE: This doesn't happen in OnRemoveEntity() specifically because
  981. // listeners may want to reference the object as it's being deleted
  982. // OnRemoveEntity isn't called until the destructor and all data is invalid.
  983. void CGlobalEntityList::NotifyRemoveEntity( CBaseHandle hEnt )
  984. {
  985. CBaseEntity *pBaseEnt = GetBaseEntity( hEnt );
  986. if ( !pBaseEnt )
  987. return;
  988. //DevMsg(2,"Deleted %s\n", pBaseEnt->GetClassname() );
  989. for ( int i = m_entityListeners.Count()-1; i >= 0; i-- )
  990. {
  991. m_entityListeners[i]->OnEntityDeleted( pBaseEnt );
  992. }
  993. }
  994. //-----------------------------------------------------------------------------
  995. // NOTIFY LIST
  996. //
  997. // Allows entities to get events fired when another entity changes
  998. //-----------------------------------------------------------------------------
  999. struct entitynotify_t
  1000. {
  1001. CBaseEntity *pNotify;
  1002. CBaseEntity *pWatched;
  1003. };
  1004. class CNotifyList : public INotify, public IEntityListener
  1005. {
  1006. public:
  1007. // INotify
  1008. void AddEntity( CBaseEntity *pNotify, CBaseEntity *pWatched );
  1009. void RemoveEntity( CBaseEntity *pNotify, CBaseEntity *pWatched );
  1010. void ReportNamedEvent( CBaseEntity *pEntity, const char *pEventName );
  1011. void ClearEntity( CBaseEntity *pNotify );
  1012. void ReportSystemEvent( CBaseEntity *pEntity, notify_system_event_t eventType, const notify_system_event_params_t &params );
  1013. // IEntityListener
  1014. virtual void OnEntityCreated( CBaseEntity *pEntity );
  1015. virtual void OnEntityDeleted( CBaseEntity *pEntity );
  1016. // Called from CEntityListSystem
  1017. void LevelInitPreEntity();
  1018. void LevelShutdownPreEntity();
  1019. private:
  1020. CUtlVector<entitynotify_t> m_notifyList;
  1021. };
  1022. void CNotifyList::AddEntity( CBaseEntity *pNotify, CBaseEntity *pWatched )
  1023. {
  1024. // OPTIMIZE: Also flag pNotify for faster "RemoveAllNotify" ?
  1025. pWatched->AddEFlags( EFL_NOTIFY );
  1026. int index = m_notifyList.AddToTail();
  1027. entitynotify_t &notify = m_notifyList[index];
  1028. notify.pNotify = pNotify;
  1029. notify.pWatched = pWatched;
  1030. }
  1031. // Remove noitfication for an entity
  1032. void CNotifyList::RemoveEntity( CBaseEntity *pNotify, CBaseEntity *pWatched )
  1033. {
  1034. for ( int i = m_notifyList.Count(); --i >= 0; )
  1035. {
  1036. if ( m_notifyList[i].pNotify == pNotify && m_notifyList[i].pWatched == pWatched)
  1037. {
  1038. m_notifyList.FastRemove(i);
  1039. }
  1040. }
  1041. }
  1042. void CNotifyList::ReportNamedEvent( CBaseEntity *pEntity, const char *pInputName )
  1043. {
  1044. variant_t emptyVariant;
  1045. if ( !pEntity->IsEFlagSet(EFL_NOTIFY) )
  1046. return;
  1047. for ( int i = 0; i < m_notifyList.Count(); i++ )
  1048. {
  1049. if ( m_notifyList[i].pWatched == pEntity )
  1050. {
  1051. m_notifyList[i].pNotify->AcceptInput( pInputName, pEntity, pEntity, emptyVariant, 0 );
  1052. }
  1053. }
  1054. }
  1055. void CNotifyList::LevelInitPreEntity()
  1056. {
  1057. gEntList.AddListenerEntity( this );
  1058. }
  1059. void CNotifyList::LevelShutdownPreEntity( void )
  1060. {
  1061. gEntList.RemoveListenerEntity( this );
  1062. m_notifyList.Purge();
  1063. }
  1064. void CNotifyList::OnEntityCreated( CBaseEntity *pEntity )
  1065. {
  1066. }
  1067. void CNotifyList::OnEntityDeleted( CBaseEntity *pEntity )
  1068. {
  1069. ReportDestroyEvent( pEntity );
  1070. ClearEntity( pEntity );
  1071. }
  1072. // UNDONE: Slow linear search?
  1073. void CNotifyList::ClearEntity( CBaseEntity *pNotify )
  1074. {
  1075. for ( int i = m_notifyList.Count(); --i >= 0; )
  1076. {
  1077. if ( m_notifyList[i].pNotify == pNotify || m_notifyList[i].pWatched == pNotify)
  1078. {
  1079. m_notifyList.FastRemove(i);
  1080. }
  1081. }
  1082. }
  1083. void CNotifyList::ReportSystemEvent( CBaseEntity *pEntity, notify_system_event_t eventType, const notify_system_event_params_t &params )
  1084. {
  1085. if ( !pEntity->IsEFlagSet(EFL_NOTIFY) )
  1086. return;
  1087. for ( int i = 0; i < m_notifyList.Count(); i++ )
  1088. {
  1089. if ( m_notifyList[i].pWatched == pEntity )
  1090. {
  1091. m_notifyList[i].pNotify->NotifySystemEvent( pEntity, eventType, params );
  1092. }
  1093. }
  1094. }
  1095. static CNotifyList g_NotifyList;
  1096. INotify *g_pNotify = &g_NotifyList;
  1097. class CEntityTouchManager : public IEntityListener
  1098. {
  1099. public:
  1100. // called by CEntityListSystem
  1101. void LevelInitPreEntity()
  1102. {
  1103. gEntList.AddListenerEntity( this );
  1104. Clear();
  1105. }
  1106. void LevelShutdownPostEntity()
  1107. {
  1108. gEntList.RemoveListenerEntity( this );
  1109. Clear();
  1110. }
  1111. void FrameUpdatePostEntityThink();
  1112. void Clear()
  1113. {
  1114. m_updateList.Purge();
  1115. }
  1116. // IEntityListener
  1117. virtual void OnEntityCreated( CBaseEntity *pEntity ) {}
  1118. virtual void OnEntityDeleted( CBaseEntity *pEntity )
  1119. {
  1120. if ( !pEntity->GetCheckUntouch() )
  1121. return;
  1122. int index = m_updateList.Find( pEntity );
  1123. if ( m_updateList.IsValidIndex(index) )
  1124. {
  1125. m_updateList.FastRemove( index );
  1126. }
  1127. }
  1128. void AddEntity( CBaseEntity *pEntity )
  1129. {
  1130. if ( pEntity->IsMarkedForDeletion() )
  1131. return;
  1132. m_updateList.AddToTail( pEntity );
  1133. }
  1134. private:
  1135. CUtlVector<CBaseEntity *> m_updateList;
  1136. };
  1137. static CEntityTouchManager g_TouchManager;
  1138. void EntityTouch_Add( CBaseEntity *pEntity )
  1139. {
  1140. g_TouchManager.AddEntity( pEntity );
  1141. }
  1142. void CEntityTouchManager::FrameUpdatePostEntityThink()
  1143. {
  1144. VPROF( "CEntityTouchManager::FrameUpdatePostEntityThink" );
  1145. // Loop through all entities again, checking their untouch if flagged to do so
  1146. int count = m_updateList.Count();
  1147. if ( count )
  1148. {
  1149. // copy off the list
  1150. CBaseEntity **ents = (CBaseEntity **)stackalloc( sizeof(CBaseEntity *) * count );
  1151. memcpy( ents, m_updateList.Base(), sizeof(CBaseEntity *) * count );
  1152. // clear it
  1153. m_updateList.RemoveAll();
  1154. // now update those ents
  1155. for ( int i = 0; i < count; i++ )
  1156. {
  1157. //Assert( ents[i]->GetCheckUntouch() );
  1158. if ( ents[i]->GetCheckUntouch() )
  1159. {
  1160. ents[i]->PhysicsCheckForEntityUntouch();
  1161. }
  1162. }
  1163. stackfree( ents );
  1164. }
  1165. }
  1166. class CRespawnEntitiesFilter : public IMapEntityFilter
  1167. {
  1168. public:
  1169. virtual bool ShouldCreateEntity( const char *pClassname )
  1170. {
  1171. // Create everything but the world
  1172. return Q_stricmp( pClassname, "worldspawn" ) != 0;
  1173. }
  1174. virtual CBaseEntity* CreateNextEntity( const char *pClassname )
  1175. {
  1176. return CreateEntityByName( pClassname );
  1177. }
  1178. };
  1179. // One hook to rule them all...
  1180. // Since most of the little list managers in here only need one or two of the game
  1181. // system callbacks, this hook is a game system that passes them the appropriate callbacks
  1182. class CEntityListSystem : public CAutoGameSystemPerFrame
  1183. {
  1184. public:
  1185. CEntityListSystem( char const *name ) : CAutoGameSystemPerFrame( name )
  1186. {
  1187. m_bRespawnAllEntities = false;
  1188. }
  1189. void LevelInitPreEntity()
  1190. {
  1191. g_NotifyList.LevelInitPreEntity();
  1192. g_TouchManager.LevelInitPreEntity();
  1193. g_AimManager.LevelInitPreEntity();
  1194. g_SimThinkManager.LevelInitPreEntity();
  1195. #ifdef HL2_DLL
  1196. OverrideMoveCache_LevelInitPreEntity();
  1197. #endif // HL2_DLL
  1198. }
  1199. void LevelShutdownPreEntity()
  1200. {
  1201. g_NotifyList.LevelShutdownPreEntity();
  1202. }
  1203. void LevelShutdownPostEntity()
  1204. {
  1205. g_TouchManager.LevelShutdownPostEntity();
  1206. g_AimManager.LevelShutdownPostEntity();
  1207. g_SimThinkManager.LevelShutdownPostEntity();
  1208. #ifdef HL2_DLL
  1209. OverrideMoveCache_LevelShutdownPostEntity();
  1210. #endif // HL2_DLL
  1211. CBaseEntityClassList *pClassList = s_pClassLists;
  1212. while ( pClassList )
  1213. {
  1214. pClassList->LevelShutdownPostEntity();
  1215. pClassList = pClassList->m_pNextClassList;
  1216. }
  1217. }
  1218. void FrameUpdatePostEntityThink()
  1219. {
  1220. g_TouchManager.FrameUpdatePostEntityThink();
  1221. if ( m_bRespawnAllEntities )
  1222. {
  1223. m_bRespawnAllEntities = false;
  1224. // Don't change globalstate owing to deletion here
  1225. GlobalEntity_EnableStateUpdates( false );
  1226. // Remove all entities
  1227. int nPlayerIndex = -1;
  1228. CBaseEntity *pEnt = gEntList.FirstEnt();
  1229. while ( pEnt )
  1230. {
  1231. CBaseEntity *pNextEnt = gEntList.NextEnt( pEnt );
  1232. if ( pEnt->IsPlayer() )
  1233. {
  1234. nPlayerIndex = pEnt->entindex();
  1235. }
  1236. if ( !pEnt->IsEFlagSet( EFL_KEEP_ON_RECREATE_ENTITIES ) )
  1237. {
  1238. UTIL_Remove( pEnt );
  1239. }
  1240. pEnt = pNextEnt;
  1241. }
  1242. gEntList.CleanupDeleteList();
  1243. GlobalEntity_EnableStateUpdates( true );
  1244. // Allows us to immediately re-use the edict indices we just freed to avoid edict overflow
  1245. engine->AllowImmediateEdictReuse();
  1246. // Reset node counter used during load
  1247. CNodeEnt::m_nNodeCount = 0;
  1248. CRespawnEntitiesFilter filter;
  1249. MapEntity_ParseAllEntities( engine->GetMapEntitiesString(), &filter, true );
  1250. // Allocate a CBasePlayer for pev, and call spawn
  1251. if ( nPlayerIndex >= 0 )
  1252. {
  1253. edict_t *pEdict = engine->PEntityOfEntIndex( nPlayerIndex );
  1254. ClientPutInServer( pEdict, "unnamed" );
  1255. ClientActive( pEdict, false );
  1256. CBasePlayer *pPlayer = ( CBasePlayer * )CBaseEntity::Instance( pEdict );
  1257. SceneManager_ClientActive( pPlayer );
  1258. }
  1259. }
  1260. }
  1261. bool m_bRespawnAllEntities;
  1262. };
  1263. static CEntityListSystem g_EntityListSystem( "CEntityListSystem" );
  1264. //-----------------------------------------------------------------------------
  1265. // Respawns all entities in the level
  1266. //-----------------------------------------------------------------------------
  1267. void RespawnEntities()
  1268. {
  1269. g_EntityListSystem.m_bRespawnAllEntities = true;
  1270. }
  1271. static ConCommand restart_entities( "respawn_entities", RespawnEntities, "Respawn all the entities in the map.", FCVAR_CHEAT | FCVAR_SPONLY );
  1272. class CSortedEntityList
  1273. {
  1274. public:
  1275. CSortedEntityList() : m_sortedList(), m_emptyCount(0) {}
  1276. typedef CBaseEntity *ENTITYPTR;
  1277. class CEntityReportLess
  1278. {
  1279. public:
  1280. bool Less( const ENTITYPTR &src1, const ENTITYPTR &src2, void *pCtx )
  1281. {
  1282. if ( stricmp( src1->GetClassname(), src2->GetClassname() ) < 0 )
  1283. return true;
  1284. return false;
  1285. }
  1286. };
  1287. void AddEntityToList( CBaseEntity *pEntity )
  1288. {
  1289. if ( !pEntity )
  1290. {
  1291. m_emptyCount++;
  1292. }
  1293. else
  1294. {
  1295. m_sortedList.Insert( pEntity );
  1296. }
  1297. }
  1298. void ReportEntityList()
  1299. {
  1300. const char *pLastClass = "";
  1301. int count = 0;
  1302. int edicts = 0;
  1303. for ( int i = 0; i < m_sortedList.Count(); i++ )
  1304. {
  1305. CBaseEntity *pEntity = m_sortedList[i];
  1306. if ( !pEntity )
  1307. continue;
  1308. if ( pEntity->edict() )
  1309. edicts++;
  1310. const char *pClassname = pEntity->GetClassname();
  1311. if ( !FStrEq( pClassname, pLastClass ) )
  1312. {
  1313. if ( count )
  1314. {
  1315. Msg("Class: %s (%d)\n", pLastClass, count );
  1316. }
  1317. pLastClass = pClassname;
  1318. count = 1;
  1319. }
  1320. else
  1321. count++;
  1322. }
  1323. if ( pLastClass[0] != 0 && count )
  1324. {
  1325. Msg("Class: %s (%d)\n", pLastClass, count );
  1326. }
  1327. if ( m_sortedList.Count() )
  1328. {
  1329. Msg("Total %d entities (%d empty, %d edicts)\n", m_sortedList.Count(), m_emptyCount, edicts );
  1330. }
  1331. }
  1332. private:
  1333. CUtlSortVector< CBaseEntity *, CEntityReportLess > m_sortedList;
  1334. int m_emptyCount;
  1335. };
  1336. CON_COMMAND(report_entities, "Lists all entities")
  1337. {
  1338. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  1339. return;
  1340. CSortedEntityList list;
  1341. CBaseEntity *pEntity = gEntList.FirstEnt();
  1342. while ( pEntity )
  1343. {
  1344. list.AddEntityToList( pEntity );
  1345. pEntity = gEntList.NextEnt( pEntity );
  1346. }
  1347. list.ReportEntityList();
  1348. }
  1349. CON_COMMAND(report_touchlinks, "Lists all touchlinks")
  1350. {
  1351. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  1352. return;
  1353. CSortedEntityList list;
  1354. CBaseEntity *pEntity = gEntList.FirstEnt();
  1355. const char *pClassname = NULL;
  1356. if ( args.ArgC() > 1 )
  1357. {
  1358. pClassname = args.Arg(1);
  1359. }
  1360. while ( pEntity )
  1361. {
  1362. if ( !pClassname || FClassnameIs(pEntity, pClassname) )
  1363. {
  1364. touchlink_t *root = ( touchlink_t * )pEntity->GetDataObject( TOUCHLINK );
  1365. if ( root )
  1366. {
  1367. touchlink_t *link = root->nextLink;
  1368. while ( link != root )
  1369. {
  1370. list.AddEntityToList( link->entityTouched );
  1371. link = link->nextLink;
  1372. }
  1373. }
  1374. }
  1375. pEntity = gEntList.NextEnt( pEntity );
  1376. }
  1377. list.ReportEntityList();
  1378. }
  1379. CON_COMMAND(report_simthinklist, "Lists all simulating/thinking entities")
  1380. {
  1381. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  1382. return;
  1383. CBaseEntity *pTmp[NUM_ENT_ENTRIES];
  1384. int count = SimThink_ListCopy( pTmp, ARRAYSIZE(pTmp) );
  1385. CSortedEntityList list;
  1386. for ( int i = 0; i < count; i++ )
  1387. {
  1388. if ( !pTmp[i] )
  1389. continue;
  1390. list.AddEntityToList( pTmp[i] );
  1391. }
  1392. list.ReportEntityList();
  1393. }