mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Game: properly implement entity list base classes
Properly implemented and now mostly useable in the SDK.
This commit is contained in:
parent
892f415425
commit
084f94aefd
@ -8,9 +8,6 @@
|
||||
//===========================================================================//
|
||||
#if !defined( CLIENTENTITYLIST_H )
|
||||
#define CLIENTENTITYLIST_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utllinkedlist.h"
|
||||
|
||||
@ -28,6 +25,10 @@ public:
|
||||
virtual void OnEntityDeleted(C_BaseEntity* pEntity) {};
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: a global list of all the entities in the game. All iteration through
|
||||
// entities is done through this object.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CClientEntityList : public C_BaseEntityList, public IClientEntityList
|
||||
{
|
||||
protected:
|
||||
@ -56,7 +57,6 @@ private:
|
||||
// For fast iteration.
|
||||
CUtlLinkedList<C_BaseEntity*, unsigned short> m_BaseEntities;
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(CClientEntityList) == 0x3800C0);
|
||||
|
||||
inline IClientEntityList* g_pClientEntityList = nullptr;
|
||||
|
@ -18,6 +18,27 @@ public:
|
||||
class C_BaseEntityList
|
||||
{
|
||||
public:
|
||||
// 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(const 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(const int edictIndex) const;
|
||||
|
||||
// Use these to iterate over all the entities.
|
||||
CBaseHandle FirstHandle() const;
|
||||
CBaseHandle NextHandle(const CBaseHandle& hEnt) const;
|
||||
static CBaseHandle InvalidHandle();
|
||||
|
||||
const C_EntInfo* FirstEntInfo() const;
|
||||
const C_EntInfo* NextEntInfo(const C_EntInfo* pInfo) const;
|
||||
const C_EntInfo* GetEntInfoPtr(const CBaseHandle& hEnt) const;
|
||||
const C_EntInfo* GetEntInfoPtrByIndex(const 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(const int iEntIndex, const int iSerialNumber);
|
||||
|
||||
// Overridables.
|
||||
protected:
|
||||
@ -33,7 +54,11 @@ private:
|
||||
class C_EntInfoList
|
||||
{
|
||||
public:
|
||||
C_EntInfoList();
|
||||
C_EntInfoList()
|
||||
{
|
||||
m_pHead = NULL;
|
||||
m_pTail = NULL;
|
||||
}
|
||||
|
||||
const C_EntInfo* Head() const { return m_pHead; }
|
||||
const C_EntInfo* Tail() const { return m_pTail; }
|
||||
@ -52,6 +77,8 @@ private:
|
||||
C_EntInfo* m_pTail;
|
||||
};
|
||||
|
||||
int GetEntInfoIndex(const C_EntInfo* pEntInfo) const;
|
||||
|
||||
// The first MAX_EDICTS entities are networkable. The rest are client-only.
|
||||
C_EntInfo m_EntPtrArray[NUM_ENT_ENTRIES];
|
||||
C_EntInfoList m_activeList;
|
||||
@ -63,4 +90,101 @@ private:
|
||||
ssize_t m_soundEntCount;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// Inlines.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
inline int C_BaseEntityList::GetEntInfoIndex(const C_EntInfo* pEntInfo) const
|
||||
{
|
||||
Assert(pEntInfo);
|
||||
const int index = (int)(pEntInfo - m_EntPtrArray);
|
||||
Assert(index >= 0 && index < NUM_ENT_ENTRIES);
|
||||
return index;
|
||||
}
|
||||
|
||||
inline CBaseHandle C_BaseEntityList::GetNetworkableHandle(const 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* C_BaseEntityList::LookupEntity(const CBaseHandle& handle) const
|
||||
{
|
||||
if (handle.m_Index == INVALID_EHANDLE_INDEX)
|
||||
return NULL;
|
||||
|
||||
const C_EntInfo* pInfo = &m_EntPtrArray[handle.GetEntryIndex()];
|
||||
if (pInfo->m_SerialNumber == handle.GetSerialNumber())
|
||||
return pInfo->m_pEntity;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline IHandleEntity* C_BaseEntityList::LookupEntityByNetworkIndex(const int edictIndex) const
|
||||
{
|
||||
// (Legacy support).
|
||||
if (edictIndex < 0)
|
||||
return NULL;
|
||||
|
||||
Assert(edictIndex < NUM_ENT_ENTRIES);
|
||||
return m_EntPtrArray[edictIndex].m_pEntity;
|
||||
}
|
||||
|
||||
|
||||
inline CBaseHandle C_BaseEntityList::FirstHandle() const
|
||||
{
|
||||
if (!m_activeList.Head())
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
|
||||
const int index = GetEntInfoIndex(m_activeList.Head());
|
||||
return CBaseHandle(index, m_EntPtrArray[index].m_SerialNumber);
|
||||
}
|
||||
|
||||
inline CBaseHandle C_BaseEntityList::NextHandle(const CBaseHandle& hEnt) const
|
||||
{
|
||||
const int iSlot = hEnt.GetEntryIndex();
|
||||
const C_EntInfo* pNext = m_EntPtrArray[iSlot].m_pNext;
|
||||
if (!pNext)
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
|
||||
const int index = GetEntInfoIndex(pNext);
|
||||
|
||||
return CBaseHandle(index, m_EntPtrArray[index].m_SerialNumber);
|
||||
}
|
||||
|
||||
inline CBaseHandle C_BaseEntityList::InvalidHandle()
|
||||
{
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
inline const C_EntInfo* C_BaseEntityList::FirstEntInfo() const
|
||||
{
|
||||
return m_activeList.Head();
|
||||
}
|
||||
|
||||
inline const C_EntInfo* C_BaseEntityList::NextEntInfo(const C_EntInfo* pInfo) const
|
||||
{
|
||||
return pInfo->m_pNext;
|
||||
}
|
||||
|
||||
inline const C_EntInfo* C_BaseEntityList::GetEntInfoPtr(const CBaseHandle& hEnt) const
|
||||
{
|
||||
const int iSlot = hEnt.GetEntryIndex();
|
||||
return &m_EntPtrArray[iSlot];
|
||||
}
|
||||
|
||||
inline const C_EntInfo* C_BaseEntityList::GetEntInfoPtrByIndex(const int index) const
|
||||
{
|
||||
return &m_EntPtrArray[index];
|
||||
}
|
||||
|
||||
inline void C_BaseEntityList::ForceEntSerialNumber(const int iEntIndex, const int iSerialNumber)
|
||||
{
|
||||
m_EntPtrArray[iEntIndex].m_SerialNumber = iSerialNumber;
|
||||
}
|
||||
|
||||
#endif // ENTITYLIST_CLIENTBASE_H
|
||||
|
@ -6,12 +6,8 @@
|
||||
#include "core/stdafx.h"
|
||||
#include "entitylist.h"
|
||||
|
||||
IHandleEntity* LookupEntityByIndex(int iEntity)
|
||||
{
|
||||
Assert(iEntity >= 0 && iEntity < NUM_ENT_ENTRIES); // Programmer error!
|
||||
|
||||
IHandleEntity* pHandle = reinterpret_cast<IHandleEntity*>(*&g_pEntityList[6 * iEntity]);
|
||||
return pHandle; // !TODO: implement CBaseEntityList properly.
|
||||
}
|
||||
|
||||
CEntInfo** g_pEntityList = nullptr;
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: a global list of all the entities in the game. All iteration through
|
||||
// entities is done through this object.
|
||||
//-----------------------------------------------------------------------------
|
||||
CGlobalEntityList* g_serverEntityList = nullptr;
|
@ -37,13 +37,9 @@ private:
|
||||
bool m_bClearingEntities;
|
||||
CUtlVector<IEntityListener*> m_entityListeners;
|
||||
};
|
||||
COMPILE_TIME_ASSERT(sizeof(CGlobalEntityList) == 0x380088);
|
||||
|
||||
|
||||
IHandleEntity* LookupEntityByIndex(int iEntity);
|
||||
|
||||
|
||||
|
||||
extern CEntInfo** g_pEntityList;
|
||||
extern CGlobalEntityList* g_serverEntityList;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -51,14 +47,13 @@ class VServerEntityList : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogVarAdr("g_serverEntityList", g_pEntityList);
|
||||
LogVarAdr("g_serverEntityList", g_serverEntityList);
|
||||
}
|
||||
virtual void GetFun(void) const { }
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
void* CBaseEntity__GetBaseEntity;
|
||||
g_GameDll.FindPatternSIMD("8B 91 ?? ?? ?? ?? 83 FA FF 74 1F 0F B7 C2 48 8D 0D ?? ?? ?? ?? C1 EA 10 48 8D 04 40 48 03 C0 39 54 C1 08 75 05 48 8B 04 C1 C3 33 C0 C3 CC CC CC 48 8B 41 30").GetPtr(CBaseEntity__GetBaseEntity);
|
||||
g_pEntityList = CMemory(CBaseEntity__GetBaseEntity).FindPattern("48 8D 0D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<CEntInfo**>();
|
||||
g_GameDll.FindPatternSIMD("48 8D 0D ?? ?? ?? ?? 66 0F 7F 05 ?? ?? ?? ?? 44 89 0D").
|
||||
ResolveRelativeAddressSelf(3, 7).ResolveRelativeAddressSelf(3, 7).GetPtr(g_serverEntityList);
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const { }
|
||||
|
@ -21,6 +21,27 @@ public:
|
||||
class CBaseEntityList
|
||||
{
|
||||
public:
|
||||
// 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(const 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(const int edictIndex) const;
|
||||
|
||||
// Use these to iterate over all the entities.
|
||||
CBaseHandle FirstHandle() const;
|
||||
CBaseHandle NextHandle(const 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(const 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(const int iEntIndex, const int iSerialNumber);
|
||||
|
||||
// Overridables.
|
||||
protected:
|
||||
@ -36,7 +57,11 @@ private:
|
||||
class CEntInfoList
|
||||
{
|
||||
public:
|
||||
CEntInfoList();
|
||||
CEntInfoList()
|
||||
{
|
||||
m_pHead = NULL;
|
||||
m_pTail = NULL;
|
||||
}
|
||||
|
||||
const CEntInfo* Head() const { return m_pHead; }
|
||||
const CEntInfo* Tail() const { return m_pTail; }
|
||||
@ -55,6 +80,8 @@ private:
|
||||
CEntInfo* m_pTail;
|
||||
};
|
||||
|
||||
int GetEntInfoIndex(const CEntInfo* pEntInfo) const;
|
||||
|
||||
// The first MAX_EDICTS entities are networkable. The rest are server-only.
|
||||
CEntInfo m_EntPtrArray[NUM_ENT_ENTRIES];
|
||||
CEntInfoList m_activeList;
|
||||
@ -66,4 +93,101 @@ private:
|
||||
ssize_t m_soundEntCount;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// Inlines.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
inline int CBaseEntityList::GetEntInfoIndex(const CEntInfo* pEntInfo) const
|
||||
{
|
||||
Assert(pEntInfo);
|
||||
const int index = (int)(pEntInfo - m_EntPtrArray);
|
||||
Assert(index >= 0 && index < NUM_ENT_ENTRIES);
|
||||
return index;
|
||||
}
|
||||
|
||||
inline CBaseHandle CBaseEntityList::GetNetworkableHandle(const 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;
|
||||
|
||||
const CEntInfo* pInfo = &m_EntPtrArray[handle.GetEntryIndex()];
|
||||
if (pInfo->m_SerialNumber == handle.GetSerialNumber())
|
||||
return pInfo->m_pEntity;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline IHandleEntity* CBaseEntityList::LookupEntityByNetworkIndex(const int edictIndex) const
|
||||
{
|
||||
// (Legacy support).
|
||||
if (edictIndex < 0)
|
||||
return NULL;
|
||||
|
||||
Assert(edictIndex < NUM_ENT_ENTRIES);
|
||||
return m_EntPtrArray[edictIndex].m_pEntity;
|
||||
}
|
||||
|
||||
|
||||
inline CBaseHandle CBaseEntityList::FirstHandle() const
|
||||
{
|
||||
if (!m_activeList.Head())
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
|
||||
const int index = GetEntInfoIndex(m_activeList.Head());
|
||||
return CBaseHandle(index, m_EntPtrArray[index].m_SerialNumber);
|
||||
}
|
||||
|
||||
inline CBaseHandle CBaseEntityList::NextHandle(const CBaseHandle& hEnt) const
|
||||
{
|
||||
const int iSlot = hEnt.GetEntryIndex();
|
||||
const CEntInfo* pNext = m_EntPtrArray[iSlot].m_pNext;
|
||||
if (!pNext)
|
||||
return INVALID_EHANDLE_INDEX;
|
||||
|
||||
const 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(const int index) const
|
||||
{
|
||||
return &m_EntPtrArray[index];
|
||||
}
|
||||
|
||||
inline void CBaseEntityList::ForceEntSerialNumber(const int iEntIndex, const int iSerialNumber)
|
||||
{
|
||||
m_EntPtrArray[iEntIndex].m_SerialNumber = iSerialNumber;
|
||||
}
|
||||
|
||||
#endif // ENTITYLIST_SERVERBASE_H
|
||||
|
@ -118,8 +118,8 @@ void __fastcall CServerGameDLL::OnReceivedSayTextMessage(void* thisptr, int send
|
||||
|
||||
void DrawServerHitbox(int iEntity)
|
||||
{
|
||||
IHandleEntity* pEntity = LookupEntityByIndex(iEntity);
|
||||
CBaseAnimating* pAnimating = dynamic_cast<CBaseAnimating*>(pEntity);
|
||||
const CEntInfo* pInfo = g_serverEntityList->GetEntInfoPtrByIndex(iEntity);
|
||||
CBaseAnimating* pAnimating = dynamic_cast<CBaseAnimating*>(pInfo->m_pEntity);
|
||||
|
||||
if (pAnimating)
|
||||
{
|
||||
|
@ -120,7 +120,8 @@ inline const CHandle<CBaseEntity> &variant_t::Entity( void ) const
|
||||
if ( fieldType == FIELD_EHANDLE )
|
||||
return eVal;
|
||||
|
||||
static const CHandle<CBaseEntity> hNull( INVALID_EHANDLE );
|
||||
static CHandle<CBaseEntity> hNull;
|
||||
hNull.Set(NULL);
|
||||
return(hNull);
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,8 @@ public:
|
||||
|
||||
CHandle();
|
||||
CHandle( int iEntry, int iSerialNumber );
|
||||
/*implicit*/ CHandle( T *pVal );
|
||||
/*implicit*/ CHandle( INVALID_EHANDLE_tag );
|
||||
CHandle( const CBaseHandle &handle );
|
||||
CHandle( T *pVal );
|
||||
|
||||
// NOTE: The following two constructor functions are not type-safe, and can allow creating a
|
||||
// CHandle<T> that doesn't actually point to an object of type T.
|
||||
@ -90,18 +90,19 @@ inline CHandle<T>::CHandle()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline CHandle<T>::CHandle( INVALID_EHANDLE_tag )
|
||||
: CBaseHandle( INVALID_EHANDLE )
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline CHandle<T>::CHandle( int iEntry, int iSerialNumber )
|
||||
{
|
||||
Init( iEntry, iSerialNumber );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CHandle<T>::CHandle( const CBaseHandle &handle )
|
||||
: CBaseHandle( handle )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline CHandle<T>::CHandle( T *pObj )
|
||||
: CBaseHandle( INVALID_EHANDLE )
|
||||
|
@ -22,19 +22,15 @@ class IHandleEntity;
|
||||
// CBaseHandle.
|
||||
// -------------------------------------------------------------------------------------------------- //
|
||||
|
||||
enum INVALID_EHANDLE_tag
|
||||
{
|
||||
INVALID_EHANDLE
|
||||
};
|
||||
|
||||
class CBaseHandle
|
||||
{
|
||||
friend class CBaseEntityList;
|
||||
friend class C_BaseEntityList;
|
||||
|
||||
public:
|
||||
|
||||
CBaseHandle();
|
||||
CBaseHandle( INVALID_EHANDLE_tag );
|
||||
CBaseHandle( unsigned long value );
|
||||
CBaseHandle( const CBaseHandle &other );
|
||||
explicit CBaseHandle( IHandleEntity* pHandleObj );
|
||||
CBaseHandle( int iEntry, int iSerialNumber );
|
||||
@ -89,11 +85,12 @@ inline CBaseHandle::CBaseHandle()
|
||||
m_Index = INVALID_EHANDLE_INDEX;
|
||||
}
|
||||
|
||||
inline CBaseHandle::CBaseHandle( INVALID_EHANDLE_tag )
|
||||
inline CBaseHandle::CBaseHandle( unsigned long value )
|
||||
{
|
||||
m_Index = INVALID_EHANDLE_INDEX;
|
||||
m_Index = value;
|
||||
}
|
||||
|
||||
|
||||
inline CBaseHandle::CBaseHandle( const CBaseHandle &other )
|
||||
{
|
||||
m_Index = other.m_Index;
|
||||
@ -138,7 +135,7 @@ inline int CBaseHandle::GetEntryIndex() const
|
||||
{
|
||||
// There is a hack here: due to a bug in the original implementation of the
|
||||
// entity handle system, an attempt to look up an invalid entity index in
|
||||
// certain cirumstances might fall through to the the mask operation below.
|
||||
// certain circumstances might fall through to the mask operation below.
|
||||
// This would mask an invalid index to be in fact a lookup of entity number
|
||||
// NUM_ENT_ENTRIES, so invalid ent indexes end up actually looking up the
|
||||
// last slot in the entities array. Since this slot is always empty, the
|
||||
@ -150,7 +147,7 @@ inline int CBaseHandle::GetEntryIndex() const
|
||||
// retains the prior (bug-submarining) behavior.
|
||||
if ( !IsValid() )
|
||||
return NUM_ENT_ENTRIES-1;
|
||||
return m_Index & ENT_ENTRY_MASK;
|
||||
return m_Index;
|
||||
}
|
||||
|
||||
inline int CBaseHandle::GetSerialNumber() const
|
||||
@ -193,12 +190,12 @@ inline bool CBaseHandle::operator <( const CBaseHandle &other ) const
|
||||
// uint32 otherIndex = (pEntity) ? pEntity->GetRefEHandle().m_Index : INVALID_EHANDLE_INDEX;
|
||||
// return m_Index < otherIndex;
|
||||
//}
|
||||
|
||||
inline const CBaseHandle& CBaseHandle::operator=( const IHandleEntity *pEntity )
|
||||
{
|
||||
return Set( pEntity );
|
||||
}
|
||||
|
||||
//
|
||||
//inline const CBaseHandle& CBaseHandle::operator=( const IHandleEntity *pEntity )
|
||||
//{
|
||||
// return Set( pEntity );
|
||||
//}
|
||||
//
|
||||
//inline const CBaseHandle& CBaseHandle::Set( const IHandleEntity *pEntity )
|
||||
//{
|
||||
// if ( pEntity )
|
||||
|
Loading…
x
Reference in New Issue
Block a user