Counter Strike : Global Offensive Source Code
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.

358 lines
9.5 KiB

  1. //========= Copyright � 1996-2005, 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, bool bLocalNetworkBackDoor );
  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 = 64
  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. bool m_bLocalNetworkBackDoor;
  57. };
  58. inline bool CDatatableStack::IsPropProxyValid(int iProp ) const
  59. {
  60. return m_pProxies[m_pPrecalc->m_PropProxyIndices[iProp]] != 0;
  61. }
  62. inline bool CDatatableStack::IsCurProxyValid() const
  63. {
  64. return m_pProxies[m_pPrecalc->m_PropProxyIndices[m_iCurProp]] != 0;
  65. }
  66. inline int CDatatableStack::GetCurPropIndex() const
  67. {
  68. return m_iCurProp;
  69. }
  70. inline unsigned char* CDatatableStack::GetCurStructBase() const
  71. {
  72. return m_pProxies[m_pPrecalc->m_PropProxyIndices[m_iCurProp]];
  73. }
  74. inline void CDatatableStack::SeekToProp( int iProp )
  75. {
  76. Assert( m_bInitted );
  77. m_iCurProp = iProp;
  78. m_pCurProp = m_pPrecalc->GetProp( iProp );
  79. }
  80. inline int CDatatableStack::GetObjectID() const
  81. {
  82. return m_ObjectID;
  83. }
  84. // This can be used IF you called Init() with true for bExplicitRoutes.
  85. // It is faster to use this route if you only are going to ask for a couple props.
  86. // If you're going to ask for all the props, then you shouldn't use the "explicit" route.
  87. template< class DTStack, class ProxyCaller >
  88. inline unsigned char* UpdateRoutesExplicit_Template( DTStack *pStack, ProxyCaller *caller )
  89. {
  90. // Early out.
  91. unsigned short iPropProxyIndex = pStack->m_pPrecalc->m_PropProxyIndices[pStack->m_iCurProp];
  92. unsigned char **pTest = &pStack->m_pProxies[iPropProxyIndex];
  93. if ( *pTest != (unsigned char*)0xFFFFFFFF )
  94. return *pTest;
  95. // Ok.. setup this proxy.
  96. unsigned char *pStructBase = pStack->m_pStructBase;
  97. CSendTablePrecalc::CProxyPath &proxyPath = pStack->m_pPrecalc->m_ProxyPaths[iPropProxyIndex];
  98. for ( unsigned short i=0; i < proxyPath.m_nEntries; i++ )
  99. {
  100. CSendTablePrecalc::CProxyPathEntry *pEntry = &pStack->m_pPrecalc->m_ProxyPathEntries[proxyPath.m_iFirstEntry + i];
  101. int iProxy = pEntry->m_iProxy;
  102. if ( pStack->m_pProxies[iProxy] == (unsigned char*)0xFFFFFFFF )
  103. {
  104. pStack->m_pProxies[iProxy] = ProxyCaller::CallProxy( pStack, pStructBase, pEntry->m_iDatatableProp );
  105. if ( !pStack->m_pProxies[iProxy] )
  106. {
  107. *pTest = NULL;
  108. pStructBase = NULL;
  109. break;
  110. }
  111. }
  112. pStructBase = pStack->m_pProxies[iProxy];
  113. }
  114. return pStructBase;
  115. }
  116. // ------------------------------------------------------------------------------------ //
  117. // The datatable stack for a RecvTable.
  118. // ------------------------------------------------------------------------------------ //
  119. class CClientDatatableStack : public CDatatableStack
  120. {
  121. public:
  122. CClientDatatableStack( CRecvDecoder *pDecoder, unsigned char *pStructBase, int objectID ) :
  123. CDatatableStack( &pDecoder->m_Precalc, pStructBase, objectID )
  124. {
  125. m_pDecoder = pDecoder;
  126. }
  127. inline unsigned char* CallPropProxy( CSendNode *pNode, int iProp, unsigned char *pStructBase )
  128. {
  129. const RecvProp *pProp = m_pDecoder->GetDatatableProp( iProp );
  130. void *pVal = NULL;
  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, CUtlMemory< CSendProxyRecipients > *pRecipients = NULL ) :
  183. CDatatableStack( pPrecalc, pStructBase, objectID )
  184. {
  185. m_pPrecalc = pPrecalc;
  186. m_pRecipients = pRecipients;
  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. if ( m_bLocalNetworkBackDoor && (pRecipients != &s_Recipients) && !pRecipients->m_Bits.IsBitSet( 0 ) )
  211. return NULL;
  212. return pRet;
  213. }
  214. virtual void RecurseAndCallProxies( CSendNode *pNode, unsigned char *pStructBase )
  215. {
  216. // Remember where the game code pointed us for this datatable's data so
  217. m_pProxies[pNode->GetRecursiveProxyIndex()] = pStructBase;
  218. for ( int iChild=0; iChild < pNode->GetNumChildren(); iChild++ )
  219. {
  220. CSendNode *pCurChild = pNode->GetChild( iChild );
  221. unsigned char *pNewStructBase = NULL;
  222. if ( pStructBase )
  223. {
  224. pNewStructBase = CallPropProxy( pCurChild, pCurChild->m_iDatatableProp, pStructBase );
  225. }
  226. RecurseAndCallProxies( pCurChild, pNewStructBase );
  227. }
  228. }
  229. // This can be used IF you called Init() with true for bExplicitRoutes.
  230. // It is faster to use this route if you only are going to ask for a couple props.
  231. // If you're going to ask for all the props, then you shouldn't use the "explicit" route.
  232. class CSendProxyCaller
  233. {
  234. public:
  235. static inline unsigned char* CallProxy( CServerDatatableStack *pStack, unsigned char *pStructBase, unsigned short iDatatableProp )
  236. {
  237. const SendProp *pProp = pStack->m_pPrecalc->GetDatatableProp( iDatatableProp );
  238. CSendProxyRecipients *pRecipients;
  239. if ( pStack->m_bLocalNetworkBackDoor && pStack->m_pRecipients && pStack->m_pRecipients->Count() > 0 )
  240. {
  241. // set recipients pointer and all clients by default
  242. pRecipients = &pStack->m_pRecipients->Element( 0 );//pNode->GetDataTableProxyIndex() );
  243. pRecipients->SetAllRecipients();
  244. }
  245. else
  246. {
  247. // we don't care about recipients, just provide a valid pointer
  248. pRecipients = &s_Recipients;
  249. }
  250. unsigned char *pRet = (unsigned char*)pProp->GetDataTableProxyFn()(
  251. pProp,
  252. pStructBase,
  253. pStructBase + pProp->GetOffset(),
  254. pRecipients,
  255. pStack->GetObjectID()
  256. );
  257. if ( pStack->m_bLocalNetworkBackDoor && (pRecipients != &s_Recipients) && !pRecipients->m_Bits.IsBitSet( 0 ) )
  258. return NULL;
  259. return pRet;
  260. }
  261. };
  262. inline unsigned char* UpdateRoutesExplicit()
  263. {
  264. return UpdateRoutesExplicit_Template( this, (CSendProxyCaller*)NULL );
  265. }
  266. const SendProp* GetCurProp() const;
  267. public:
  268. CSendTablePrecalc *m_pPrecalc;
  269. CUtlMemory<CSendProxyRecipients> *m_pRecipients;
  270. };
  271. inline const SendProp* CServerDatatableStack::GetCurProp() const
  272. {
  273. return m_pPrecalc->GetProp( GetCurPropIndex() );
  274. }
  275. #endif // DATATABLE_STACK_H