//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef ENTITYLIST_H #define ENTITYLIST_H #ifdef _WIN32 #pragma once #endif #include "baseentity.h" class IEntityListener; abstract_class CBaseEntityClassList { public: CBaseEntityClassList(); ~CBaseEntityClassList(); virtual void LevelShutdownPostEntity() = 0; CBaseEntityClassList *m_pNextClassList; }; template 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: 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); // entity is about to be removed, notify the listeners void NotifyCreateEntity(CBaseEntity *pEnt); void NotifySpawn(CBaseEntity *pEnt); void NotifyRemoveEntity(CBaseHandle hEnt); // 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 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 *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 *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 *FindEntityProcedural(const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL); CGlobalEntityList(); // CBaseEntityList overrides. protected: virtual void OnAddEntity(IHandleEntity *pEnt, CBaseHandle handle); virtual void OnRemoveEntity(IHandleEntity *pEnt, CBaseHandle handle); }; extern CGlobalEntityList gEntList; //----------------------------------------------------------------------------- // Inlines. //----------------------------------------------------------------------------- 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); int AimTarget_ListCount(); int AimTarget_ListCopy(CBaseEntity *pList[], int listMax); void AimTarget_ForceRepopulateList(); void SimThink_EntityChanged(CBaseEntity *pEntity); int SimThink_ListCount(); int SimThink_ListCopy(CBaseEntity *pList[], int listMax); #endif // ENTITYLIST_H