mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-01-09 10:39:03 +08:00
7931af02fa
Add CConcreteEntityList, CEntityComponent, CScriptComponent, CGameEntitySystem, rewrite IHandleEntity to use CEntityHandle instead of CBaseHandle, update NUM_SERIAL_NUM_BITS, comment out old CBaseEntity, obsolete basehandle.h
228 lines
6.7 KiB
C++
228 lines
6.7 KiB
C++
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||
//
|
||
// Purpose:
|
||
//
|
||
//=============================================================================//
|
||
|
||
#ifndef ENTITYLIST_BASE_H
|
||
#define ENTITYLIST_BASE_H
|
||
#ifdef _WIN32
|
||
#pragma once
|
||
#endif
|
||
|
||
|
||
#include "const.h"
|
||
#include "entityhandle.h"
|
||
#include "tier1/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;
|
||
|
||
// 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 );
|
||
|
||
// 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;
|
||
|
||
// 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" );
|
||
*/
|
||
|
||
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];
|
||
}
|
||
|
||
inline void CBaseEntityList::ForceEntSerialNumber( int iEntIndex, int iSerialNumber )
|
||
{
|
||
m_EntPtrArray[iEntIndex].m_SerialNumber = iSerialNumber;
|
||
}
|
||
|
||
extern CBaseEntityList *g_pEntityList;
|
||
|
||
#endif // ENTITYLIST_BASE_H
|