//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef ENTITYLIST_H #define ENTITYLIST_H #ifdef _WIN32 #pragma once #endif class CBaseEntity; class IEntityListener; abstract_class CBaseEntityClassList { public: CBaseEntityClassList(); ~CBaseEntityClassList(); virtual void LevelShutdownPostEntity() = 0; CBaseEntityClassList *m_pNextClassList; }; template< class T > class CEntityClassList : public CBaseEntityClassList { public: virtual void LevelShutdownPostEntity() { m_pClassList = NULL; } void Insert( T *pEntity ) { pEntity->m_pNext = m_pClassList; m_pClassList = pEntity; } void Remove( T *pEntity ) { T **pPrev = &m_pClassList; T *pCur = *pPrev; while ( pCur ) { if ( pCur == pEntity ) { *pPrev = pCur->m_pNext; return; } pPrev = &pCur->m_pNext; pCur = *pPrev; } } static T *m_pClassList; }; // Derive a class from this if you want to filter entity list searches abstract_class IEntityFindFilter { public: virtual bool ShouldFindEntity( CBaseEntity *pEntity ) = 0; virtual CBaseEntity *GetFilterResult( void ) = 0; }; //----------------------------------------------------------------------------- // Purpose: a global list of all the entities in the game. All iteration through // entities is done through this object. //----------------------------------------------------------------------------- class CGlobalEntityList : public CBaseEntityList { public: private: int m_iHighestEnt; // the topmost used array index int m_iNumEnts; int m_iNumEdicts; bool m_bClearingEntities; CUtlVector m_entityListeners; public: CBaseHandle AddNetworkableEntity( IHandleEntity *pEnt, int index, int iForcedSerialNum = -1 ); CBaseHandle AddNonNetworkableEntity( IHandleEntity *pEnt ); void UpdateName( IHandleEntity *pEnt, CBaseHandle hEnt ); void UpdateName( IHandleEntity *pEnt ); IServerNetworkable* GetServerNetworkable( CBaseHandle hEnt ) const; CBaseNetworkable* GetBaseNetworkable( CBaseHandle hEnt ) const; CBaseEntity* GetBaseEntity( CBaseHandle hEnt ) const; edict_t* GetEdict( CBaseHandle hEnt ) const; int NumberOfEntities( void ); int NumberOfEdicts( void ); // mark an entity as deleted void AddToDeleteList( IServerNetworkable *ent ); // call this before and after each frame to delete all of the marked entities. void CleanupDeleteList( void ); int ResetDeleteList( void ); // frees all entities in the game void Clear( void ); // Returns true while in the Clear() call. bool IsClearingEntities() {return m_bClearingEntities;} // add a class that gets notified of entity events void AddListenerEntity( IEntityListener *pListener ); void RemoveListenerEntity( IEntityListener *pListener ); void ReportEntityFlagsChanged( CBaseEntity *pEntity, unsigned int flagsOld, unsigned int flagsNow ); // Schedule this entity for notification once client messages have been sent void AddPostClientMessageEntity( CBaseEntity *pEntity ); void PostClientMessagesSent(); // entity is about to be removed, notify the listeners void NotifyCreateEntity( CBaseEntity *pEnt ); void NotifySpawn( CBaseEntity *pEnt ); void NotifyRemoveEntity( CBaseEntity *pEnt ); // iteration functions // returns the next entity after pCurrentEnt; if pCurrentEnt is NULL, return the first entity CBaseEntity *NextEnt( CBaseEntity *pCurrentEnt ); CBaseEntity *FirstEnt() { return NextEnt(NULL); } // returns the next entity of the specified class, using RTTI template< class T > T *NextEntByClass( T *start ) { for ( CBaseEntity *x = NextEnt( start ); x; x = NextEnt( x ) ) { start = dynamic_cast( x ); if ( start ) return start; } return NULL; } // search functions bool IsEntityPtr( void *pTest ); CBaseEntity *FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ); CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL ); CBaseEntity *FindEntityByName( CBaseEntity *pStartEntity, string_t iszName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL, IEntityFindFilter *pFilter = NULL ) { return FindEntityByName( pStartEntity, STRING(iszName), pSearchingEntity, pActivator, pCaller, pFilter ); } CBaseEntity *FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ); CBaseEntity *FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName ); CBaseEntity *FindEntityByModel( CBaseEntity *pStartEntity, const char *szModelName ); CBaseEntity *FindEntityByOutputTarget( CBaseEntity *pStartEntity, string_t iTarget ); CBaseEntity *FindEntityByNameNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius ); CBaseEntity *FindEntityByClassnameNearest2D( const char *szName, const Vector &vecSrc, float flRadius ); CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecSrc, float flRadius ); CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecMins, const Vector &vecMaxs ); CBaseEntity *FindEntityGeneric( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityGenericWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityGenericNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityNearestFacing( const Vector &origin, const Vector &facing, float threshold); CBaseEntity *FindEntityClassNearestFacing( const Vector &origin, const Vector &facing, float threshold, char *classname); CBaseEntity *FindEntityByNetname( CBaseEntity *pStartEntity, const char *szModelName ); CBaseEntity *FindEntityProcedural( const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); // Fast versions that require a (real) string_t, and won't do wildcarding CBaseEntity *FindEntityByClassnameFast( CBaseEntity *pStartEntity, string_t iszClassname ); CBaseEntity *FindEntityByClassnameNearestFast( string_t iszClassname, const Vector &vecSrc, float flRadius ); CBaseEntity *FindEntityByNameFast( CBaseEntity *pStartEntity, string_t iszName ); CGlobalEntityList(); // CBaseEntityList overrides. protected: virtual void OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle ); virtual void OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle ); }; extern CGlobalEntityList gEntList; //----------------------------------------------------------------------------- // Inlines. //----------------------------------------------------------------------------- inline CBaseHandle CGlobalEntityList::AddNetworkableEntity( IHandleEntity *pEnt, int index, int iForcedSerialNum ) { CBaseHandle h = CBaseEntityList::AddNetworkableEntity( pEnt, index, iForcedSerialNum ); UpdateName( pEnt, h ); return h; } inline CBaseHandle CGlobalEntityList::AddNonNetworkableEntity( IHandleEntity *pEnt ) { CBaseHandle h = CBaseEntityList::AddNonNetworkableEntity( pEnt ); UpdateName( pEnt, h ); return h; } inline edict_t* CGlobalEntityList::GetEdict( CBaseHandle hEnt ) const { IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); if ( pUnk ) return pUnk->GetNetworkable()->GetEdict(); else return NULL; } inline CBaseNetworkable* CGlobalEntityList::GetBaseNetworkable( CBaseHandle hEnt ) const { IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); if ( pUnk ) return pUnk->GetNetworkable()->GetBaseNetworkable(); else return NULL; } inline IServerNetworkable* CGlobalEntityList::GetServerNetworkable( CBaseHandle hEnt ) const { IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); if ( pUnk ) return pUnk->GetNetworkable(); else return NULL; } inline CBaseEntity* CGlobalEntityList::GetBaseEntity( CBaseHandle hEnt ) const { IServerUnknown *pUnk = static_cast(LookupEntity( hEnt )); if ( pUnk ) return pUnk->GetBaseEntity(); else return NULL; } //----------------------------------------------------------------------------- // Common finds #if 0 template inline bool FindEntityByName( const char *pszName, ENT_TYPE **ppResult) { CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName ); if ( pBaseEntity ) *ppResult = dynamic_cast( pBaseEntity ); else *ppResult = NULL; return ( *ppResult != NULL ); } template <> inline bool FindEntityByName( const char *pszName, CBaseEntity **ppResult) { *ppResult = gEntList.FindEntityByName( NULL, pszName ); return ( *ppResult != NULL ); } template <> inline bool FindEntityByName( const char *pszName, CAI_BaseNPC **ppResult) { CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName ); if ( pBaseEntity ) *ppResult = pBaseEntity->MyNPCPointer(); else *ppResult = NULL; return ( *ppResult != NULL ); } #endif //----------------------------------------------------------------------------- // Purpose: Simple object for storing a list of objects //----------------------------------------------------------------------------- struct entitem_t { EHANDLE hEnt; struct entitem_t *pNext; // uses pool memory static void* operator new( size_t stAllocateBlock ); static void *operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ); static void operator delete( void *pMem ); static void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ) { operator delete( pMem ); } }; class CEntityList { public: CEntityList(); ~CEntityList(); int m_iNumItems; entitem_t *m_pItemList; // null terminated singly-linked list void AddEntity( CBaseEntity * ); void DeleteEntity( CBaseEntity * ); }; enum notify_system_event_t { NOTIFY_EVENT_TELEPORT = 0, NOTIFY_EVENT_DESTROY, }; struct notify_teleport_params_t { Vector prevOrigin; QAngle prevAngles; bool physicsRotate; }; struct notify_destroy_params_t { }; struct notify_system_event_params_t { union { const notify_teleport_params_t *pTeleport; const notify_destroy_params_t *pDestroy; }; notify_system_event_params_t( const notify_teleport_params_t *pInTeleport ) { pTeleport = pInTeleport; } notify_system_event_params_t( const notify_destroy_params_t *pInDestroy ) { pDestroy = pInDestroy; } }; abstract_class INotify { public: // Add notification for an entity virtual void AddEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) = 0; // Remove notification for an entity virtual void RemoveEntity( CBaseEntity *pNotify, CBaseEntity *pWatched ) = 0; // Call the named input in each entity who is watching pEvent's status virtual void ReportNamedEvent( CBaseEntity *pEntity, const char *pEventName ) = 0; // System events don't make sense as inputs, so are handled through a generic notify function virtual void ReportSystemEvent( CBaseEntity *pEntity, notify_system_event_t eventType, const notify_system_event_params_t ¶ms ) = 0; inline void ReportDestroyEvent( CBaseEntity *pEntity ) { notify_destroy_params_t destroy; ReportSystemEvent( pEntity, NOTIFY_EVENT_DESTROY, notify_system_event_params_t(&destroy) ); } inline void ReportTeleportEvent( CBaseEntity *pEntity, const Vector &prevOrigin, const QAngle &prevAngles, bool physicsRotate ) { notify_teleport_params_t teleport; teleport.prevOrigin = prevOrigin; teleport.prevAngles = prevAngles; teleport.physicsRotate = physicsRotate; ReportSystemEvent( pEntity, NOTIFY_EVENT_TELEPORT, notify_system_event_params_t(&teleport) ); } // Remove this entity from the notify list virtual void ClearEntity( CBaseEntity *pNotify ) = 0; }; // Implement this class and register with gEntList to receive entity create/delete notification class IEntityListener { public: virtual void OnEntityCreated( CBaseEntity *pEntity ) {}; virtual void OnEntitySpawned( CBaseEntity *pEntity ) {}; virtual void OnEntityDeleted( CBaseEntity *pEntity ) {}; }; // singleton extern INotify *g_pNotify; void EntityTouch_Add( CBaseEntity *pEntity ); void EntityTouch_Remove( CBaseEntity *pEntity ); int AimTarget_ListCount(); int AimTarget_ListCopy( CBaseEntity *pList[], int listMax ); CBaseEntity *AimTarget_ListElement( int iIndex ); void AimTarget_ForceRepopulateList(); void SimThink_EntityChanged( CBaseEntity *pEntity ); int SimThink_ListCount(); int SimThink_ListCopy( CBaseEntity *pList[], int listMax ); #endif // ENTITYLIST_H