summaryrefslogtreecommitdiff
path: root/engine/dt_stack.h
diff options
context:
space:
mode:
Diffstat (limited to 'engine/dt_stack.h')
-rw-r--r--engine/dt_stack.h337
1 files changed, 337 insertions, 0 deletions
diff --git a/engine/dt_stack.h b/engine/dt_stack.h
new file mode 100644
index 0000000..9fa48d4
--- /dev/null
+++ b/engine/dt_stack.h
@@ -0,0 +1,337 @@
+//========= 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