404 lines
14 KiB
C++
404 lines
14 KiB
C++
//========= 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 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<IEntityListener *> 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 <class T>
|
|
T *NextEntByClass(T *start) {
|
|
for (CBaseEntity *x = NextEnt(start); x; x = NextEnt(x)) {
|
|
start = dynamic_cast<T *>(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<IServerUnknown *>(LookupEntity(hEnt));
|
|
if (pUnk)
|
|
return pUnk->GetNetworkable()->GetEdict();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
inline CBaseNetworkable *CGlobalEntityList::GetBaseNetworkable(
|
|
CBaseHandle hEnt) const {
|
|
IServerUnknown *pUnk = static_cast<IServerUnknown *>(LookupEntity(hEnt));
|
|
if (pUnk)
|
|
return pUnk->GetNetworkable()->GetBaseNetworkable();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
inline IServerNetworkable *CGlobalEntityList::GetServerNetworkable(
|
|
CBaseHandle hEnt) const {
|
|
IServerUnknown *pUnk = static_cast<IServerUnknown *>(LookupEntity(hEnt));
|
|
if (pUnk)
|
|
return pUnk->GetNetworkable();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
inline CBaseEntity *CGlobalEntityList::GetBaseEntity(CBaseHandle hEnt) const {
|
|
IServerUnknown *pUnk = static_cast<IServerUnknown *>(LookupEntity(hEnt));
|
|
if (pUnk)
|
|
return pUnk->GetBaseEntity();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Common finds
|
|
#if 0
|
|
|
|
template <class ENT_TYPE>
|
|
inline bool FindEntityByName( const char *pszName, ENT_TYPE **ppResult)
|
|
{
|
|
CBaseEntity *pBaseEntity = gEntList.FindEntityByName( NULL, pszName );
|
|
|
|
if ( pBaseEntity )
|
|
*ppResult = dynamic_cast<ENT_TYPE *>( pBaseEntity );
|
|
else
|
|
*ppResult = NULL;
|
|
|
|
return ( *ppResult != NULL );
|
|
}
|
|
|
|
template <>
|
|
inline bool FindEntityByName<CBaseEntity>( const char *pszName, CBaseEntity **ppResult)
|
|
{
|
|
*ppResult = gEntList.FindEntityByName( NULL, pszName );
|
|
return ( *ppResult != NULL );
|
|
}
|
|
|
|
template <>
|
|
inline bool FindEntityByName<CAI_BaseNPC>( 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
|