|
|
//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "ServerNetworkProperty.h"
#include "tier0/dbg.h"
#include "gameinterface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CTimedEventMgr g_NetworkPropertyEventMgr;
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC_NO_BASE( CServerNetworkProperty ) // DEFINE_FIELD( m_pOuter, FIELD_CLASSPTR ),
// DEFINE_FIELD( m_pPev, FIELD_CLASSPTR ),
// DEFINE_FIELD( m_PVSInfo, PVSInfo_t ),
// DEFINE_FIELD( m_pServerClass, FIELD_CLASSPTR ),
DEFINE_GLOBAL_FIELD( m_hParent, FIELD_EHANDLE ), // DEFINE_FIELD( m_TimerEvent, CEventRegister ),
// DEFINE_FIELD( m_bPendingStateChange, FIELD_BOOLEAN ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CServerNetworkProperty::CServerNetworkProperty() { Init( NULL ); }
CServerNetworkProperty::~CServerNetworkProperty() { /* Free our transmit proxy.
if ( m_pTransmitProxy ) { m_pTransmitProxy->Release(); }*/
engine->CleanUpEntityClusterList( &m_PVSInfo );
// remove the attached edict if it exists
DetachEdict(); }
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
void CServerNetworkProperty::Init( CBaseEntity *pEntity ) { // NOTE: We're in pEntity's constructor so we can't call virtual methods of pEntity here
m_pPev = NULL; m_pOuter = pEntity; m_pServerClass = NULL; // m_pTransmitProxy = NULL;
m_bPendingStateChange = false; m_PVSInfo.m_nClusterCount = 0; m_TimerEvent.Init( &g_NetworkPropertyEventMgr, this ); }
void CServerNetworkProperty::CacheServerClass() { m_pServerClass = m_pOuter->GetServerClass(); }
//-----------------------------------------------------------------------------
// Connects, disconnects edicts
//-----------------------------------------------------------------------------
void CServerNetworkProperty::AttachEdict( edict_t *pRequiredEdict ) { Assert ( !m_pPev );
// see if there is an edict allocated for it, otherwise get one from the engine
if ( !pRequiredEdict ) { pRequiredEdict = engine->CreateEdict(); }
m_pPev = pRequiredEdict; m_pPev->SetEdict( GetBaseEntity(), true ); }
void CServerNetworkProperty::DetachEdict() { if ( m_pPev ) { m_pPev->SetEdict( NULL, false ); engine->RemoveEdict( m_pPev ); m_pPev = NULL; } }
//-----------------------------------------------------------------------------
// Entity handles
//-----------------------------------------------------------------------------
IHandleEntity *CServerNetworkProperty::GetEntityHandle( ) { return m_pOuter; }
void CServerNetworkProperty::Release() { delete m_pOuter; }
//-----------------------------------------------------------------------------
// Returns the network parent
//-----------------------------------------------------------------------------
CServerNetworkProperty* CServerNetworkProperty::GetNetworkParent() { CBaseEntity *pParent = m_hParent.Get(); return pParent ? pParent->NetworkProp() : NULL; }
//-----------------------------------------------------------------------------
// Marks for deletion
//-----------------------------------------------------------------------------
void CServerNetworkProperty::MarkForDeletion() { m_pOuter->AddEFlags( EFL_KILLME ); }
bool CServerNetworkProperty::IsMarkedForDeletion() const { return ( m_pOuter->GetEFlags() & EFL_KILLME ) != 0; }
//-----------------------------------------------------------------------------
// PVS information
//-----------------------------------------------------------------------------
void CServerNetworkProperty::RecomputePVSInformation() { if ( m_pPev && ( ( m_pPev->m_fStateFlags & FL_EDICT_DIRTY_PVS_INFORMATION ) != 0 ) ) { m_pPev->m_fStateFlags &= ~FL_EDICT_DIRTY_PVS_INFORMATION; engine->BuildEntityClusterList( edict(), &m_PVSInfo ); } }
//-----------------------------------------------------------------------------
// Serverclass
//-----------------------------------------------------------------------------
ServerClass* CServerNetworkProperty::GetServerClass() { return m_pServerClass; }
const char* CServerNetworkProperty::GetClassName() const { return STRING(m_pOuter->m_iClassname); }
//-----------------------------------------------------------------------------
// Transmit proxies
/*-----------------------------------------------------------------------------
void CServerNetworkProperty::SetTransmitProxy( CBaseTransmitProxy *pProxy ) { if ( m_pTransmitProxy ) { m_pTransmitProxy->Release(); }
m_pTransmitProxy = pProxy; if ( m_pTransmitProxy ) { m_pTransmitProxy->AddRef(); } }*/
//-----------------------------------------------------------------------------
// PVS rules
//-----------------------------------------------------------------------------
bool CServerNetworkProperty::IsInPVS( const edict_t *pRecipient, const void *pvs, int pvssize ) { RecomputePVSInformation();
// ignore if not touching a PV leaf
// negative leaf count is a node number
// If no pvs, add any entity
Assert( pvs && ( edict() != pRecipient ) );
unsigned char *pPVS = ( unsigned char * )pvs; if ( m_PVSInfo.m_nClusterCount < 0 ) // too many clusters, use headnode
{ return ( engine->CheckHeadnodeVisible( m_PVSInfo.m_nHeadNode, pPVS, pvssize ) != 0); } for ( int i = 0; i < m_PVSInfo.m_nClusterCount; i++ ) { if (pPVS[m_PVSInfo.m_pClusters[i] >> 3] & (1 << (m_PVSInfo.m_pClusters[i] & 7) )) return true; }
return false; // not visible
}
//-----------------------------------------------------------------------------
// PVS: this function is called a lot, so it avoids function calls
//-----------------------------------------------------------------------------
bool CServerNetworkProperty::IsInPVS( const CCheckTransmitInfo *pInfo ) { // PVS data must be up to date
Assert( !m_pPev || ( ( m_pPev->m_fStateFlags & FL_EDICT_DIRTY_PVS_INFORMATION ) == 0 ) ); int i;
// Early out if the areas are connected
if ( !m_PVSInfo.m_nAreaNum2 ) { for ( i=0; i< pInfo->m_AreasNetworked; i++ ) { int clientArea = pInfo->m_Areas[i]; if ( clientArea == m_PVSInfo.m_nAreaNum || engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum ) ) break; } } else { // doors can legally straddle two areas, so
// we may need to check another one
for ( i=0; i< pInfo->m_AreasNetworked; i++ ) { int clientArea = pInfo->m_Areas[i]; if ( clientArea == m_PVSInfo.m_nAreaNum || clientArea == m_PVSInfo.m_nAreaNum2 ) break;
if ( engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum ) ) break;
if ( engine->CheckAreasConnected( clientArea, m_PVSInfo.m_nAreaNum2 ) ) break; } }
if ( i == pInfo->m_AreasNetworked ) { // areas not connected
return false; }
// ignore if not touching a PV leaf
// negative leaf count is a node number
// If no pvs, add any entity
Assert( edict() != pInfo->m_pClientEnt );
unsigned char *pPVS = ( unsigned char * )pInfo->m_PVS; if ( m_PVSInfo.m_nClusterCount < 0 ) // too many clusters, use headnode
{ return (engine->CheckHeadnodeVisible( m_PVSInfo.m_nHeadNode, pPVS, pInfo->m_nPVSSize ) != 0); } for ( i = m_PVSInfo.m_nClusterCount; --i >= 0; ) { int nCluster = m_PVSInfo.m_pClusters[i]; if ( ((int)(pPVS[nCluster >> 3])) & BitVec_BitInByte( nCluster ) ) return true; }
return false; // not visible
}
void CServerNetworkProperty::SetUpdateInterval( float val ) { if ( val == 0 ) m_TimerEvent.StopUpdates(); else m_TimerEvent.SetUpdateInterval( val ); }
void CServerNetworkProperty::FireEvent() { // Our timer went off. If our state has changed in the background, then
// trigger a state change in the edict.
if ( m_bPendingStateChange ) { m_pPev->StateChanged(); m_bPendingStateChange = false; } }
|