Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

337 lines
8.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef DATATABLE_STACK_H
  8. #define DATATABLE_STACK_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "dt.h"
  13. #include "dt_recv_decoder.h"
  14. class CSendNode;
  15. static CSendProxyRecipients s_Recipients; // avoid calling constructor each time
  16. // ----------------------------------------------------------------------------- //
  17. //
  18. // CDatatableStack
  19. //
  20. // CDatatableStack is used to walk through a datatable's tree, calling proxies
  21. // along the way to update the current data pointer.
  22. //
  23. // ----------------------------------------------------------------------------- //
  24. abstract_class CDatatableStack
  25. {
  26. public:
  27. CDatatableStack( CSendTablePrecalc *pPrecalc, unsigned char *pStructBase, int objectID );
  28. // This must be called before accessing properties.
  29. void Init( bool bExplicitRoutes=false );
  30. // The stack is meant to be used by calling SeekToProp with increasing property
  31. // numbers.
  32. void SeekToProp( int iProp );
  33. bool IsCurProxyValid() const;
  34. bool IsPropProxyValid(int iProp ) const;
  35. int GetCurPropIndex() const;
  36. unsigned char* GetCurStructBase() const;
  37. int GetObjectID() const;
  38. // Derived classes must implement this. The server gets one and the client gets one.
  39. // It calls the proxy to move to the next datatable's data.
  40. virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase ) = 0;
  41. public:
  42. CSendTablePrecalc *m_pPrecalc;
  43. enum
  44. {
  45. MAX_PROXY_RESULTS = 256
  46. };
  47. // These point at the various values that the proxies returned. They are setup once, then
  48. // the properties index them.
  49. unsigned char *m_pProxies[MAX_PROXY_RESULTS];
  50. unsigned char *m_pStructBase;
  51. int m_iCurProp;
  52. protected:
  53. const SendProp *m_pCurProp;
  54. int m_ObjectID;
  55. bool m_bInitted;
  56. };
  57. inline bool CDatatableStack::IsPropProxyValid(int iProp ) const
  58. {
  59. return m_pProxies[m_pPrecalc->m_PropProxyIndices[iProp]] != 0;
  60. }
  61. inline bool CDatatableStack::IsCurProxyValid() const
  62. {
  63. return m_pProxies[m_pPrecalc->m_PropProxyIndices[m_iCurProp]] != 0;
  64. }
  65. inline int CDatatableStack::GetCurPropIndex() const
  66. {
  67. return m_iCurProp;
  68. }
  69. inline unsigned char* CDatatableStack::GetCurStructBase() const
  70. {
  71. return m_pProxies[m_pPrecalc->m_PropProxyIndices[m_iCurProp]];
  72. }
  73. inline void CDatatableStack::SeekToProp( int iProp )
  74. {
  75. Assert( m_bInitted );
  76. m_iCurProp = iProp;
  77. m_pCurProp = m_pPrecalc->GetProp( iProp );
  78. }
  79. inline int CDatatableStack::GetObjectID() const
  80. {
  81. return m_ObjectID;
  82. }
  83. // This can be used IF you called Init() with true for bExplicitRoutes.
  84. // It is faster to use this route if you only are going to ask for a couple props.
  85. // If you're going to ask for all the props, then you shouldn't use the "explicit" route.
  86. template< class DTStack, class ProxyCaller >
  87. inline unsigned char* UpdateRoutesExplicit_Template( DTStack *pStack, ProxyCaller *caller )
  88. {
  89. // Early out.
  90. unsigned short iPropProxyIndex = pStack->m_pPrecalc->m_PropProxyIndices[pStack->m_iCurProp];
  91. unsigned char **pTest = &pStack->m_pProxies[iPropProxyIndex];
  92. if ( *pTest != (unsigned char*)0xFFFFFFFF )
  93. return *pTest;
  94. // Ok.. setup this proxy.
  95. unsigned char *pStructBase = pStack->m_pStructBase;
  96. CSendTablePrecalc::CProxyPath &proxyPath = pStack->m_pPrecalc->m_ProxyPaths[iPropProxyIndex];
  97. for ( unsigned short i=0; i < proxyPath.m_nEntries; i++ )
  98. {
  99. CSendTablePrecalc::CProxyPathEntry *pEntry = &pStack->m_pPrecalc->m_ProxyPathEntries[proxyPath.m_iFirstEntry + i];
  100. int iProxy = pEntry->m_iProxy;
  101. if ( pStack->m_pProxies[iProxy] == (unsigned char*)0xFFFFFFFF )
  102. {
  103. pStack->m_pProxies[iProxy] = ProxyCaller::CallProxy( pStack, pStructBase, pEntry->m_iDatatableProp );
  104. if ( !pStack->m_pProxies[iProxy] )
  105. {
  106. *pTest = NULL;
  107. break;
  108. }
  109. }
  110. pStructBase = pStack->m_pProxies[iProxy];
  111. }
  112. return pStructBase;
  113. }
  114. // ------------------------------------------------------------------------------------ //
  115. // The datatable stack for a RecvTable.
  116. // ------------------------------------------------------------------------------------ //
  117. class CClientDatatableStack : public CDatatableStack
  118. {
  119. public:
  120. CClientDatatableStack( CRecvDecoder *pDecoder, unsigned char *pStructBase, int objectID ) :
  121. CDatatableStack( &pDecoder->m_Precalc, pStructBase, objectID )
  122. {
  123. m_pDecoder = pDecoder;
  124. }
  125. inline unsigned char* CallPropProxy( CSendNode *pNode, int iProp, unsigned char *pStructBase )
  126. {
  127. const RecvProp *pProp = m_pDecoder->GetDatatableProp( iProp );
  128. void *pVal = NULL;
  129. Assert( pProp );
  130. // We may crash later for doing this, but at least this will allow users to watch their demos
  131. if ( !pProp )
  132. return NULL;
  133. pProp->GetDataTableProxyFn()(
  134. pProp,
  135. &pVal,
  136. pStructBase + pProp->GetOffset(),
  137. GetObjectID()
  138. );
  139. return (unsigned char*)pVal;
  140. }
  141. virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase )
  142. {
  143. // Remember where the game code pointed us for this datatable's data so
  144. m_pProxies[pNode->GetRecursiveProxyIndex()] = pStructBase;
  145. for ( int iChild=0; iChild < pNode->GetNumChildren(); iChild++ )
  146. {
  147. CSendNode *pCurChild = pNode->GetChild( iChild );
  148. unsigned char *pNewStructBase = NULL;
  149. if ( pStructBase )
  150. {
  151. pNewStructBase = CallPropProxy( pCurChild, pCurChild->m_iDatatableProp, pStructBase );
  152. }
  153. RecurseAndCallProxies( pCurChild, pNewStructBase );
  154. }
  155. }
  156. class CRecvProxyCaller
  157. {
  158. public:
  159. static inline unsigned char* CallProxy( CClientDatatableStack *pStack, unsigned char *pStructBase, unsigned short iDatatableProp )
  160. {
  161. const RecvProp *pProp = pStack->m_pDecoder->GetDatatableProp( iDatatableProp );
  162. void *pVal = NULL;
  163. pProp->GetDataTableProxyFn()(
  164. pProp,
  165. &pVal,
  166. pStructBase + pProp->GetOffset(),
  167. pStack->m_ObjectID
  168. );
  169. return (unsigned char*)pVal;
  170. }
  171. };
  172. inline unsigned char* UpdateRoutesExplicit()
  173. {
  174. return UpdateRoutesExplicit_Template( this, (CRecvProxyCaller*)NULL );
  175. }
  176. public:
  177. CRecvDecoder *m_pDecoder;
  178. };
  179. class CServerDatatableStack : public CDatatableStack
  180. {
  181. public:
  182. CServerDatatableStack( CSendTablePrecalc *pPrecalc, unsigned char *pStructBase, int objectID ) :
  183. CDatatableStack( pPrecalc, pStructBase, objectID )
  184. {
  185. m_pPrecalc = pPrecalc;
  186. m_pRecipients = NULL;
  187. }
  188. inline unsigned char* CallPropProxy( CSendNode *pNode, int iProp, unsigned char *pStructBase )
  189. {
  190. const SendProp *pProp = m_pPrecalc->GetDatatableProp( iProp );
  191. CSendProxyRecipients *pRecipients;
  192. if ( m_pRecipients && pNode->GetDataTableProxyIndex() != DATATABLE_PROXY_INDEX_NOPROXY )
  193. {
  194. // set recipients pointer and all clients by default
  195. pRecipients = &m_pRecipients->Element( pNode->GetDataTableProxyIndex() );
  196. pRecipients->SetAllRecipients();
  197. }
  198. else
  199. {
  200. // we don't care about recipients, just provide a valid pointer
  201. pRecipients = &s_Recipients;
  202. }
  203. unsigned char *pRet = (unsigned char*)pProp->GetDataTableProxyFn()(
  204. pProp,
  205. pStructBase,
  206. pStructBase + pProp->GetOffset(),
  207. pRecipients,
  208. GetObjectID()
  209. );
  210. return pRet;
  211. }
  212. virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase )
  213. {
  214. // Remember where the game code pointed us for this datatable's data so
  215. m_pProxies[pNode->GetRecursiveProxyIndex()] = pStructBase;
  216. for ( int iChild=0; iChild < pNode->GetNumChildren(); iChild++ )
  217. {
  218. CSendNode *pCurChild = pNode->GetChild( iChild );
  219. unsigned char *pNewStructBase = NULL;
  220. if ( pStructBase )
  221. {
  222. pNewStructBase = CallPropProxy( pCurChild, pCurChild->m_iDatatableProp, pStructBase );
  223. }
  224. RecurseAndCallProxies( pCurChild, pNewStructBase );
  225. }
  226. }
  227. // This can be used IF you called Init() with true for bExplicitRoutes.
  228. // It is faster to use this route if you only are going to ask for a couple props.
  229. // If you're going to ask for all the props, then you shouldn't use the "explicit" route.
  230. class CSendProxyCaller
  231. {
  232. public:
  233. static inline unsigned char* CallProxy( CServerDatatableStack *pStack, unsigned char *pStructBase, unsigned short iDatatableProp )
  234. {
  235. const SendProp *pProp = pStack->m_pPrecalc->GetDatatableProp( iDatatableProp );
  236. return (unsigned char*)pProp->GetDataTableProxyFn()(
  237. pProp,
  238. pStructBase,
  239. pStructBase + pProp->GetOffset(),
  240. &s_Recipients,
  241. pStack->GetObjectID()
  242. );
  243. }
  244. };
  245. inline unsigned char* UpdateRoutesExplicit()
  246. {
  247. return UpdateRoutesExplicit_Template( this, (CSendProxyCaller*)NULL );
  248. }
  249. const SendProp* GetCurProp() const;
  250. public:
  251. CSendTablePrecalc *m_pPrecalc;
  252. CUtlMemory<CSendProxyRecipients> *m_pRecipients;
  253. };
  254. inline const SendProp* CServerDatatableStack::GetCurProp() const
  255. {
  256. return m_pPrecalc->GetProp( GetCurPropIndex() );
  257. }
  258. #endif // DATATABLE_STACK_H