287 lines
9.3 KiB
C++
287 lines
9.3 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $Workfile: $
|
|
// $Date: $
|
|
// $NoKeywords: $
|
|
//===========================================================================//
|
|
#if !defined(CLIENTENTITYLIST_H)
|
|
#define CLIENTENTITYLIST_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "../../public/icliententitylist.h"
|
|
#include "../../public/iclientunknown.h"
|
|
#include "../../public/ispatialpartition.h"
|
|
#include "../../public/tier0/dbg.h"
|
|
#include "../../public/tier1/utllinkedlist.h"
|
|
#include "../../public/tier1/utlmap.h"
|
|
#include "../../public/tier1/utlvector.h"
|
|
#include "../shared/entitylist_base.h"
|
|
#include "cdll_util.h"
|
|
#include "icliententityinternal.h"
|
|
|
|
class C_Beam;
|
|
class C_BaseViewModel;
|
|
class C_BaseEntity;
|
|
|
|
#define INPVS_YES 0x0001 // The entity thinks it's in the PVS.
|
|
#define INPVS_THISFRAME \
|
|
0x0002 // Accumulated as different views are rendered during the frame and
|
|
// used to notify the entity if it is not in the PVS anymore (at the
|
|
// end of the frame).
|
|
#define INPVS_NEEDSNOTIFY 0x0004 // The entity thinks it's in the PVS.
|
|
|
|
class IClientEntityListener;
|
|
|
|
abstract_class C_BaseEntityClassList {
|
|
public:
|
|
C_BaseEntityClassList();
|
|
~C_BaseEntityClassList();
|
|
virtual void LevelShutdown() = 0;
|
|
|
|
C_BaseEntityClassList *m_pNextClassList;
|
|
};
|
|
|
|
template <class T>
|
|
class C_EntityClassList : public C_BaseEntityClassList {
|
|
public:
|
|
virtual void LevelShutdown() { 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;
|
|
};
|
|
|
|
// Maximum size of entity list
|
|
#define INVALID_CLIENTENTITY_HANDLE CBaseHandle(INVALID_EHANDLE_INDEX)
|
|
|
|
//
|
|
// This is the IClientEntityList implemenation. It serves two functions:
|
|
//
|
|
// 1. It converts server entity indices into IClientNetworkables for the engine.
|
|
//
|
|
// 2. It provides a place to store IClientUnknowns and gives out
|
|
// ClientEntityHandle_t's
|
|
// so they can be indexed and retreived. For example, this is how static
|
|
// props are referenced by the spatial partition manager - it doesn't know
|
|
// what is being inserted, so it's
|
|
// given ClientEntityHandle_t's, and the handlers for spatial partition
|
|
//callbacks can
|
|
// use the client entity list to look them up and check for supported
|
|
// interfaces.
|
|
//
|
|
class CClientEntityList : public CBaseEntityList, public IClientEntityList {
|
|
friend class C_BaseEntityIterator;
|
|
friend class C_AllBaseEntityIterator;
|
|
|
|
public:
|
|
// Constructor, destructor
|
|
CClientEntityList(void);
|
|
virtual ~CClientEntityList(void);
|
|
|
|
void Release(); // clears everything and releases entities
|
|
|
|
// Implement IClientEntityList
|
|
public:
|
|
virtual IClientNetworkable *GetClientNetworkable(int entnum);
|
|
virtual IClientEntity *GetClientEntity(int entnum);
|
|
|
|
virtual int NumberOfEntities(bool bIncludeNonNetworkable = false);
|
|
|
|
virtual IClientUnknown *GetClientUnknownFromHandle(
|
|
ClientEntityHandle_t hEnt);
|
|
virtual IClientNetworkable *GetClientNetworkableFromHandle(
|
|
ClientEntityHandle_t hEnt);
|
|
virtual IClientEntity *GetClientEntityFromHandle(ClientEntityHandle_t hEnt);
|
|
|
|
virtual int GetHighestEntityIndex(void);
|
|
|
|
virtual void SetMaxEntities(int maxents);
|
|
virtual int GetMaxEntities();
|
|
|
|
// CBaseEntityList overrides.
|
|
protected:
|
|
virtual void OnAddEntity(IHandleEntity *pEnt, CBaseHandle handle);
|
|
virtual void OnRemoveEntity(IHandleEntity *pEnt, CBaseHandle handle);
|
|
|
|
// Internal to client DLL.
|
|
public:
|
|
// All methods of accessing specialized IClientUnknown's go through here.
|
|
IClientUnknown *GetListedEntity(int entnum);
|
|
|
|
// Simple wrappers for convenience..
|
|
C_BaseEntity *GetBaseEntity(int entnum);
|
|
ICollideable *GetCollideable(int entnum);
|
|
|
|
IClientRenderable *GetClientRenderableFromHandle(ClientEntityHandle_t hEnt);
|
|
C_BaseEntity *GetBaseEntityFromHandle(ClientEntityHandle_t hEnt);
|
|
ICollideable *GetCollideableFromHandle(ClientEntityHandle_t hEnt);
|
|
IClientThinkable *GetClientThinkableFromHandle(ClientEntityHandle_t hEnt);
|
|
|
|
// Convenience methods to convert between entindex + ClientEntityHandle_t
|
|
ClientEntityHandle_t EntIndexToHandle(int entnum);
|
|
int HandleToEntIndex(ClientEntityHandle_t handle);
|
|
|
|
// Is a handle valid?
|
|
bool IsHandleValid(ClientEntityHandle_t handle) const;
|
|
|
|
// For backwards compatibility...
|
|
C_BaseEntity *GetEnt(int entnum) { return GetBaseEntity(entnum); }
|
|
|
|
void RecomputeHighestEntityUsed(void);
|
|
|
|
// Use this to iterate over all the C_BaseEntities.
|
|
C_BaseEntity *FirstBaseEntity() const;
|
|
C_BaseEntity *NextBaseEntity(C_BaseEntity *pEnt) const;
|
|
|
|
class CPVSNotifyInfo {
|
|
public:
|
|
IPVSNotify *m_pNotify;
|
|
IClientRenderable *m_pRenderable;
|
|
unsigned char m_InPVSStatus; // Combination of the INPVS_ flags.
|
|
unsigned short m_PVSNotifiersLink; // Into m_PVSNotifyInfos.
|
|
};
|
|
|
|
// Get the list of all PVS notifiers.
|
|
CUtlLinkedList<CPVSNotifyInfo, unsigned short> &GetPVSNotifiers();
|
|
|
|
CUtlVector<IClientEntityListener *> m_entityListeners;
|
|
|
|
// add a class that gets notified of entity events
|
|
void AddListenerEntity(IClientEntityListener *pListener);
|
|
void RemoveListenerEntity(IClientEntityListener *pListener);
|
|
|
|
void NotifyCreateEntity(C_BaseEntity *pEnt);
|
|
void NotifyRemoveEntity(C_BaseEntity *pEnt);
|
|
|
|
private:
|
|
// Cached info for networked entities.
|
|
struct EntityCacheInfo_t {
|
|
// Cached off because GetClientNetworkable is called a *lot*
|
|
IClientNetworkable *m_pNetworkable;
|
|
unsigned short
|
|
m_BaseEntitiesIndex; // Index into m_BaseEntities (or
|
|
// m_BaseEntities.InvalidIndex() if none).
|
|
};
|
|
|
|
// Current count
|
|
int m_iNumServerEnts;
|
|
// Max allowed
|
|
int m_iMaxServerEnts;
|
|
|
|
int m_iNumClientNonNetworkable;
|
|
|
|
// Current last used slot
|
|
int m_iMaxUsedServerIndex;
|
|
|
|
// This holds fast lookups for special edicts.
|
|
EntityCacheInfo_t m_EntityCacheInfo[NUM_ENT_ENTRIES];
|
|
|
|
// For fast iteration.
|
|
CUtlLinkedList<C_BaseEntity *, unsigned short> m_BaseEntities;
|
|
|
|
private:
|
|
void AddPVSNotifier(IClientUnknown *pUnknown);
|
|
void RemovePVSNotifier(IClientUnknown *pUnknown);
|
|
|
|
// These entities want to know when they enter and leave the PVS (server
|
|
// entities already can get the equivalent notification with
|
|
// NotifyShouldTransmit, but client entities have to get it this way).
|
|
CUtlLinkedList<CPVSNotifyInfo, unsigned short> m_PVSNotifyInfos;
|
|
CUtlMap<IClientUnknown *, unsigned short, unsigned short>
|
|
m_PVSNotifierMap; // Maps IClientUnknowns to indices into
|
|
// m_PVSNotifyInfos.
|
|
};
|
|
|
|
// Use this to iterate over *all* (even dormant) the C_BaseEntities in the
|
|
// client entity list.
|
|
class C_AllBaseEntityIterator {
|
|
public:
|
|
C_AllBaseEntityIterator();
|
|
|
|
void Restart();
|
|
C_BaseEntity *Next(); // keep calling this until it returns null.
|
|
|
|
private:
|
|
unsigned short m_CurBaseEntity;
|
|
};
|
|
|
|
class C_BaseEntityIterator {
|
|
public:
|
|
C_BaseEntityIterator();
|
|
|
|
void Restart();
|
|
C_BaseEntity *Next(); // keep calling this until it returns null.
|
|
|
|
private:
|
|
unsigned short m_CurBaseEntity;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Inline methods
|
|
//-----------------------------------------------------------------------------
|
|
inline bool CClientEntityList::IsHandleValid(
|
|
ClientEntityHandle_t handle) const {
|
|
return handle.Get() != 0;
|
|
}
|
|
|
|
inline IClientUnknown *CClientEntityList::GetListedEntity(int entnum) {
|
|
return (IClientUnknown *)LookupEntityByNetworkIndex(entnum);
|
|
}
|
|
|
|
inline IClientUnknown *CClientEntityList::GetClientUnknownFromHandle(
|
|
ClientEntityHandle_t hEnt) {
|
|
return (IClientUnknown *)LookupEntity(hEnt);
|
|
}
|
|
|
|
inline CUtlLinkedList<CClientEntityList::CPVSNotifyInfo, unsigned short>
|
|
&CClientEntityList::GetPVSNotifiers() {
|
|
return m_PVSNotifyInfos;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Convenience methods to convert between entindex + ClientEntityHandle_t
|
|
//-----------------------------------------------------------------------------
|
|
inline ClientEntityHandle_t CClientEntityList::EntIndexToHandle(int entnum) {
|
|
if (entnum < -1) return INVALID_EHANDLE_INDEX;
|
|
IClientUnknown *pUnk = GetListedEntity(entnum);
|
|
return pUnk ? pUnk->GetRefEHandle() : INVALID_EHANDLE_INDEX;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Returns the client entity list
|
|
//-----------------------------------------------------------------------------
|
|
extern CClientEntityList *cl_entitylist;
|
|
|
|
inline CClientEntityList &ClientEntityList() { return *cl_entitylist; }
|
|
|
|
// Implement this class and register with entlist to receive entity
|
|
// create/delete notification
|
|
class IClientEntityListener {
|
|
public:
|
|
virtual void OnEntityCreated(C_BaseEntity *pEntity){};
|
|
// virtual void OnEntitySpawned( C_BaseEntity *pEntity ) {};
|
|
virtual void OnEntityDeleted(C_BaseEntity *pEntity){};
|
|
};
|
|
|
|
#endif // CLIENTENTITYLIST_H
|