source-engine/game/shared/entitylist_base.h

228 lines
6.4 KiB
C
Raw Normal View History

2023-10-03 14:23:56 +00:00
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
2020-04-22 16:56:21 +00:00
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYLIST_BASE_H
#define ENTITYLIST_BASE_H
#ifdef _WIN32
#pragma once
#endif
#include "const.h"
#include "basehandle.h"
#include "utllinkedlist.h"
#include "ihandleentity.h"
class CEntInfo
{
public:
IHandleEntity *m_pEntity;
int m_SerialNumber;
CEntInfo *m_pPrev;
CEntInfo *m_pNext;
void ClearLinks();
};
class CBaseEntityList
{
public:
CBaseEntityList();
~CBaseEntityList();
// Add and remove entities. iForcedSerialNum should only be used on the client. The server
// gets to dictate what the networkable serial numbers are on the client so it can send
// ehandles over and they work.
CBaseHandle AddNetworkableEntity( IHandleEntity *pEnt, int index, int iForcedSerialNum = -1 );
CBaseHandle AddNonNetworkableEntity( IHandleEntity *pEnt );
void RemoveEntity( CBaseHandle handle );
// Get an ehandle from a networkable entity's index (note: if there is no entity in that slot,
// then the ehandle will be invalid and produce NULL).
CBaseHandle GetNetworkableHandle( int iEntity ) const;
// ehandles use this in their Get() function to produce a pointer to the entity.
IHandleEntity* LookupEntity( const CBaseHandle &handle ) const;
IHandleEntity* LookupEntityByNetworkIndex( int edictIndex ) const;
// Use these to iterate over all the entities.
CBaseHandle FirstHandle() const;
CBaseHandle NextHandle( CBaseHandle hEnt ) const;
static CBaseHandle InvalidHandle();
const CEntInfo *FirstEntInfo() const;
const CEntInfo *NextEntInfo( const CEntInfo *pInfo ) const;
const CEntInfo *GetEntInfoPtr( const CBaseHandle &hEnt ) const;
const CEntInfo *GetEntInfoPtrByIndex( int index ) const;
2023-10-03 14:23:56 +00:00
// Used by Foundry when an entity is respawned/edited.
// We force the new entity's ehandle to be the same so anyone pointing at it still gets a valid CBaseEntity out of their ehandle.
void ForceEntSerialNumber( int iEntIndex, int iSerialNumber );
2020-04-22 16:56:21 +00:00
// Overridables.
protected:
// These are notifications to the derived class. It can cache info here if it wants.
virtual void OnAddEntity( IHandleEntity *pEnt, CBaseHandle handle );
// It is safe to delete the entity here. We won't be accessing the pointer after
// calling OnRemoveEntity.
virtual void OnRemoveEntity( IHandleEntity *pEnt, CBaseHandle handle );
private:
CBaseHandle AddEntityAtSlot( IHandleEntity *pEnt, int iSlot, int iForcedSerialNum );
void RemoveEntityAtSlot( int iSlot );
private:
class CEntInfoList
{
public:
CEntInfoList();
const CEntInfo *Head() const { return m_pHead; }
const CEntInfo *Tail() const { return m_pTail; }
CEntInfo *Head() { return m_pHead; }
CEntInfo *Tail() { return m_pTail; }
void AddToHead( CEntInfo *pElement ) { LinkAfter( NULL, pElement ); }
void AddToTail( CEntInfo *pElement ) { LinkBefore( NULL, pElement ); }
void LinkBefore( CEntInfo *pBefore, CEntInfo *pElement );
void LinkAfter( CEntInfo *pBefore, CEntInfo *pElement );
void Unlink( CEntInfo *pElement );
bool IsInList( CEntInfo *pElement );
private:
CEntInfo *m_pHead;
CEntInfo *m_pTail;
};
int GetEntInfoIndex( const CEntInfo *pEntInfo ) const;
// The first MAX_EDICTS entities are networkable. The rest are client-only or server-only.
CEntInfo m_EntPtrArray[NUM_ENT_ENTRIES];
CEntInfoList m_activeList;
CEntInfoList m_freeNonNetworkableList;
};
// ------------------------------------------------------------------------------------ //
// Inlines.
// ------------------------------------------------------------------------------------ //
inline int CBaseEntityList::GetEntInfoIndex( const CEntInfo *pEntInfo ) const
{
Assert( pEntInfo );
int index = (int)(pEntInfo - m_EntPtrArray);
Assert( index >= 0 && index < NUM_ENT_ENTRIES );
return index;
}
inline CBaseHandle CBaseEntityList::GetNetworkableHandle( int iEntity ) const
{
Assert( iEntity >= 0 && iEntity < MAX_EDICTS );
if ( m_EntPtrArray[iEntity].m_pEntity )
return CBaseHandle( iEntity, m_EntPtrArray[iEntity].m_SerialNumber );
else
return CBaseHandle();
}
inline IHandleEntity* CBaseEntityList::LookupEntity( const CBaseHandle &handle ) const
{
if ( handle.m_Index == INVALID_EHANDLE_INDEX )
return NULL;
2023-10-03 14:23:56 +00:00
// You can use this to determine when something is trying to resolve
// handles to static props as if they were handles to ordinary props,
// but in practice this is done a great deal and seems benign.
/*
// 0x40000000 = STATICPROP_EHANDLE_MASK
AssertMsg( ( handle.GetSerialNumber() != (0x40000000 >> NUM_SERIAL_NUM_SHIFT_BITS) ) ,
"Tried to look up a static prop as if it was a regular entity, a bad pointer and doom are the result.\n" );
*/
2020-04-22 16:56:21 +00:00
const CEntInfo *pInfo = &m_EntPtrArray[ handle.GetEntryIndex() ];
if ( pInfo->m_SerialNumber == handle.GetSerialNumber() )
return (IHandleEntity*)pInfo->m_pEntity;
else
return NULL;
}
inline IHandleEntity* CBaseEntityList::LookupEntityByNetworkIndex( int edictIndex ) const
{
// (Legacy support).
if ( edictIndex < 0 )
return NULL;
Assert( edictIndex < NUM_ENT_ENTRIES );
return (IHandleEntity*)m_EntPtrArray[edictIndex].m_pEntity;
}
inline CBaseHandle CBaseEntityList::FirstHandle() const
{
if ( !m_activeList.Head() )
return INVALID_EHANDLE_INDEX;
int index = GetEntInfoIndex( m_activeList.Head() );
return CBaseHandle( index, m_EntPtrArray[index].m_SerialNumber );
}
inline CBaseHandle CBaseEntityList::NextHandle( CBaseHandle hEnt ) const
{
int iSlot = hEnt.GetEntryIndex();
CEntInfo *pNext = m_EntPtrArray[iSlot].m_pNext;
if ( !pNext )
return INVALID_EHANDLE_INDEX;
int index = GetEntInfoIndex( pNext );
return CBaseHandle( index, m_EntPtrArray[index].m_SerialNumber );
}
inline CBaseHandle CBaseEntityList::InvalidHandle()
{
return INVALID_EHANDLE_INDEX;
}
inline const CEntInfo *CBaseEntityList::FirstEntInfo() const
{
return m_activeList.Head();
}
inline const CEntInfo *CBaseEntityList::NextEntInfo( const CEntInfo *pInfo ) const
{
return pInfo->m_pNext;
}
inline const CEntInfo *CBaseEntityList::GetEntInfoPtr( const CBaseHandle &hEnt ) const
{
int iSlot = hEnt.GetEntryIndex();
return &m_EntPtrArray[iSlot];
}
inline const CEntInfo *CBaseEntityList::GetEntInfoPtrByIndex( int index ) const
{
return &m_EntPtrArray[index];
}
2023-10-03 14:23:56 +00:00
inline void CBaseEntityList::ForceEntSerialNumber( int iEntIndex, int iSerialNumber )
{
m_EntPtrArray[iEntIndex].m_SerialNumber = iSerialNumber;
}
2020-04-22 16:56:21 +00:00
extern CBaseEntityList *g_pEntityList;
#endif // ENTITYLIST_BASE_H