|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DATATABLE_STACK_H
#define DATATABLE_STACK_H
#ifdef _WIN32
#pragma once
#endif
#include "dt.h"
#include "dt_recv_decoder.h"
class CSendNode; static CSendProxyRecipients s_Recipients; // avoid calling constructor each time
// ----------------------------------------------------------------------------- //
//
// CDatatableStack
//
// CDatatableStack is used to walk through a datatable's tree, calling proxies
// along the way to update the current data pointer.
//
// ----------------------------------------------------------------------------- //
abstract_class CDatatableStack { public: CDatatableStack( CSendTablePrecalc *pPrecalc, unsigned char *pStructBase, int objectID );
// This must be called before accessing properties.
void Init( bool bExplicitRoutes=false );
// The stack is meant to be used by calling SeekToProp with increasing property
// numbers.
void SeekToProp( int iProp );
bool IsCurProxyValid() const; bool IsPropProxyValid(int iProp ) const; int GetCurPropIndex() const; unsigned char* GetCurStructBase() const; int GetObjectID() const;
// Derived classes must implement this. The server gets one and the client gets one.
// It calls the proxy to move to the next datatable's data.
virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase ) = 0;
public: CSendTablePrecalc *m_pPrecalc; enum { MAX_PROXY_RESULTS = 256 };
// These point at the various values that the proxies returned. They are setup once, then
// the properties index them.
unsigned char *m_pProxies[MAX_PROXY_RESULTS]; unsigned char *m_pStructBase; int m_iCurProp;
protected:
const SendProp *m_pCurProp; int m_ObjectID;
bool m_bInitted; };
inline bool CDatatableStack::IsPropProxyValid(int iProp ) const { return m_pProxies[m_pPrecalc->m_PropProxyIndices[iProp]] != 0; }
inline bool CDatatableStack::IsCurProxyValid() const { return m_pProxies[m_pPrecalc->m_PropProxyIndices[m_iCurProp]] != 0; }
inline int CDatatableStack::GetCurPropIndex() const { return m_iCurProp; }
inline unsigned char* CDatatableStack::GetCurStructBase() const { return m_pProxies[m_pPrecalc->m_PropProxyIndices[m_iCurProp]]; }
inline void CDatatableStack::SeekToProp( int iProp ) { Assert( m_bInitted ); m_iCurProp = iProp; m_pCurProp = m_pPrecalc->GetProp( iProp ); }
inline int CDatatableStack::GetObjectID() const { return m_ObjectID; }
// This can be used IF you called Init() with true for bExplicitRoutes.
// It is faster to use this route if you only are going to ask for a couple props.
// If you're going to ask for all the props, then you shouldn't use the "explicit" route.
template< class DTStack, class ProxyCaller > inline unsigned char* UpdateRoutesExplicit_Template( DTStack *pStack, ProxyCaller *caller ) { // Early out.
unsigned short iPropProxyIndex = pStack->m_pPrecalc->m_PropProxyIndices[pStack->m_iCurProp]; unsigned char **pTest = &pStack->m_pProxies[iPropProxyIndex]; if ( *pTest != (unsigned char*)0xFFFFFFFF ) return *pTest; // Ok.. setup this proxy.
unsigned char *pStructBase = pStack->m_pStructBase; CSendTablePrecalc::CProxyPath &proxyPath = pStack->m_pPrecalc->m_ProxyPaths[iPropProxyIndex]; for ( unsigned short i=0; i < proxyPath.m_nEntries; i++ ) { CSendTablePrecalc::CProxyPathEntry *pEntry = &pStack->m_pPrecalc->m_ProxyPathEntries[proxyPath.m_iFirstEntry + i]; int iProxy = pEntry->m_iProxy; if ( pStack->m_pProxies[iProxy] == (unsigned char*)0xFFFFFFFF ) { pStack->m_pProxies[iProxy] = ProxyCaller::CallProxy( pStack, pStructBase, pEntry->m_iDatatableProp ); if ( !pStack->m_pProxies[iProxy] ) { *pTest = NULL; break; } } pStructBase = pStack->m_pProxies[iProxy]; } return pStructBase; }
// ------------------------------------------------------------------------------------ //
// The datatable stack for a RecvTable.
// ------------------------------------------------------------------------------------ //
class CClientDatatableStack : public CDatatableStack { public: CClientDatatableStack( CRecvDecoder *pDecoder, unsigned char *pStructBase, int objectID ) : CDatatableStack( &pDecoder->m_Precalc, pStructBase, objectID ) { m_pDecoder = pDecoder; }
inline unsigned char* CallPropProxy( CSendNode *pNode, int iProp, unsigned char *pStructBase ) { const RecvProp *pProp = m_pDecoder->GetDatatableProp( iProp );
void *pVal = NULL;
Assert( pProp );
// We may crash later for doing this, but at least this will allow users to watch their demos
if ( !pProp ) return NULL;
pProp->GetDataTableProxyFn()( pProp, &pVal, pStructBase + pProp->GetOffset(), GetObjectID() );
return (unsigned char*)pVal; }
virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase ) { // Remember where the game code pointed us for this datatable's data so
m_pProxies[pNode->GetRecursiveProxyIndex()] = pStructBase;
for ( int iChild=0; iChild < pNode->GetNumChildren(); iChild++ ) { CSendNode *pCurChild = pNode->GetChild( iChild ); unsigned char *pNewStructBase = NULL; if ( pStructBase ) { pNewStructBase = CallPropProxy( pCurChild, pCurChild->m_iDatatableProp, pStructBase ); }
RecurseAndCallProxies( pCurChild, pNewStructBase ); } }
class CRecvProxyCaller { public: static inline unsigned char* CallProxy( CClientDatatableStack *pStack, unsigned char *pStructBase, unsigned short iDatatableProp ) { const RecvProp *pProp = pStack->m_pDecoder->GetDatatableProp( iDatatableProp );
void *pVal = NULL; pProp->GetDataTableProxyFn()( pProp, &pVal, pStructBase + pProp->GetOffset(), pStack->m_ObjectID ); return (unsigned char*)pVal; } }; inline unsigned char* UpdateRoutesExplicit() { return UpdateRoutesExplicit_Template( this, (CRecvProxyCaller*)NULL ); }
public: CRecvDecoder *m_pDecoder; };
class CServerDatatableStack : public CDatatableStack { public: CServerDatatableStack( CSendTablePrecalc *pPrecalc, unsigned char *pStructBase, int objectID ) : CDatatableStack( pPrecalc, pStructBase, objectID ) { m_pPrecalc = pPrecalc; m_pRecipients = NULL; }
inline unsigned char* CallPropProxy( CSendNode *pNode, int iProp, unsigned char *pStructBase ) { const SendProp *pProp = m_pPrecalc->GetDatatableProp( iProp );
CSendProxyRecipients *pRecipients;
if ( m_pRecipients && pNode->GetDataTableProxyIndex() != DATATABLE_PROXY_INDEX_NOPROXY ) { // set recipients pointer and all clients by default
pRecipients = &m_pRecipients->Element( pNode->GetDataTableProxyIndex() ); pRecipients->SetAllRecipients(); } else { // we don't care about recipients, just provide a valid pointer
pRecipients = &s_Recipients; }
unsigned char *pRet = (unsigned char*)pProp->GetDataTableProxyFn()( pProp, pStructBase, pStructBase + pProp->GetOffset(), pRecipients, GetObjectID() ); return pRet; }
virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase ) { // Remember where the game code pointed us for this datatable's data so
m_pProxies[pNode->GetRecursiveProxyIndex()] = pStructBase;
for ( int iChild=0; iChild < pNode->GetNumChildren(); iChild++ ) { CSendNode *pCurChild = pNode->GetChild( iChild ); unsigned char *pNewStructBase = NULL; if ( pStructBase ) { pNewStructBase = CallPropProxy( pCurChild, pCurChild->m_iDatatableProp, pStructBase ); }
RecurseAndCallProxies( pCurChild, pNewStructBase ); } }
// This can be used IF you called Init() with true for bExplicitRoutes.
// It is faster to use this route if you only are going to ask for a couple props.
// If you're going to ask for all the props, then you shouldn't use the "explicit" route.
class CSendProxyCaller { public: static inline unsigned char* CallProxy( CServerDatatableStack *pStack, unsigned char *pStructBase, unsigned short iDatatableProp ) { const SendProp *pProp = pStack->m_pPrecalc->GetDatatableProp( iDatatableProp ); return (unsigned char*)pProp->GetDataTableProxyFn()( pProp, pStructBase, pStructBase + pProp->GetOffset(), &s_Recipients, pStack->GetObjectID() ); } }; inline unsigned char* UpdateRoutesExplicit() { return UpdateRoutesExplicit_Template( this, (CSendProxyCaller*)NULL ); }
const SendProp* GetCurProp() const;
public: CSendTablePrecalc *m_pPrecalc; CUtlMemory<CSendProxyRecipients> *m_pRecipients; };
inline const SendProp* CServerDatatableStack::GetCurProp() const { return m_pPrecalc->GetProp( GetCurPropIndex() ); }
#endif // DATATABLE_STACK_H
|