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.

488 lines
13 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "dt_stack.h"
  9. #include "client.h"
  10. #include "host.h"
  11. #include "utllinkedlist.h"
  12. #include "server.h"
  13. #include "server_class.h"
  14. #include "eiface.h"
  15. #include "demo.h"
  16. #include "sv_packedentities.h"
  17. #include "tier0/icommandline.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. extern CUtlLinkedList< CClientSendTable*, unsigned short > g_ClientSendTables;
  21. extern CUtlLinkedList< CRecvDecoder *, unsigned short > g_RecvDecoders;
  22. RecvTable* FindRecvTable( const char *pName );
  23. bool DataTable_SetupReceiveTableFromSendTable( SendTable *sendTable, bool bNeedsDecoder )
  24. {
  25. CClientSendTable *pClientSendTable = new CClientSendTable;
  26. SendTable *pTable = &pClientSendTable->m_SendTable;
  27. g_ClientSendTables.AddToTail( pClientSendTable );
  28. // Read the name.
  29. pTable->m_pNetTableName = COM_StringCopy( sendTable->m_pNetTableName );
  30. // Create a decoder for it if necessary.
  31. if ( bNeedsDecoder )
  32. {
  33. // Make a decoder for it.
  34. CRecvDecoder *pDecoder = new CRecvDecoder;
  35. g_RecvDecoders.AddToTail( pDecoder );
  36. RecvTable *pRecvTable = FindRecvTable( pTable->m_pNetTableName );
  37. if ( !pRecvTable )
  38. {
  39. DataTable_Warning( "No matching RecvTable for SendTable '%s'.\n", pTable->m_pNetTableName );
  40. return false;
  41. }
  42. pRecvTable->m_pDecoder = pDecoder;
  43. pDecoder->m_pTable = pRecvTable;
  44. pDecoder->m_pClientSendTable = pClientSendTable;
  45. pDecoder->m_Precalc.m_pSendTable = pClientSendTable->GetSendTable();
  46. pClientSendTable->GetSendTable()->m_pPrecalc = &pDecoder->m_Precalc;
  47. // Initialize array properties.
  48. SetupArrayProps_R<RecvTable, RecvTable::PropType>( pRecvTable );
  49. }
  50. // Read the property list.
  51. pTable->m_nProps = sendTable->m_nProps;
  52. pTable->m_pProps = pTable->m_nProps ? new SendProp[ pTable->m_nProps ] : 0;
  53. pClientSendTable->m_Props.SetSize( pTable->m_nProps );
  54. for ( int iProp=0; iProp < pTable->m_nProps; iProp++ )
  55. {
  56. CClientSendProp *pClientProp = &pClientSendTable->m_Props[iProp];
  57. SendProp *pProp = &pTable->m_pProps[iProp];
  58. const SendProp *pSendTableProp = &sendTable->m_pProps[ iProp ];
  59. pProp->m_Type = (SendPropType)pSendTableProp->m_Type;
  60. pProp->m_pVarName = COM_StringCopy( pSendTableProp->GetName() );
  61. pProp->SetFlags( pSendTableProp->GetFlags() );
  62. pProp->SetPriority( pSendTableProp->GetPriority() );
  63. if ( CommandLine()->FindParm("-dti" ) && pSendTableProp->GetParentArrayPropName() )
  64. {
  65. pProp->m_pParentArrayPropName = COM_StringCopy( pSendTableProp->GetParentArrayPropName() );
  66. }
  67. if ( pProp->m_Type == DPT_DataTable )
  68. {
  69. char *pDTName = pSendTableProp->m_pExcludeDTName; // HACK
  70. if ( pSendTableProp->GetDataTable() )
  71. pDTName = pSendTableProp->GetDataTable()->m_pNetTableName;
  72. Assert( pDTName && Q_strlen(pDTName) > 0 );
  73. pClientProp->SetTableName( COM_StringCopy( pDTName ) );
  74. // Normally we wouldn't care about this but we need to compare it against
  75. // proxies in the server DLL in SendTable_BuildHierarchy.
  76. pProp->SetDataTableProxyFn( pSendTableProp->GetDataTableProxyFn() );
  77. pProp->SetOffset( pSendTableProp->GetOffset() );
  78. }
  79. else
  80. {
  81. if ( pProp->IsExcludeProp() )
  82. {
  83. pProp->m_pExcludeDTName = COM_StringCopy( pSendTableProp->GetExcludeDTName() );
  84. }
  85. else if ( pProp->GetType() == DPT_Array )
  86. {
  87. pProp->SetNumElements( pSendTableProp->GetNumElements() );
  88. }
  89. else
  90. {
  91. pProp->m_fLowValue = pSendTableProp->m_fLowValue;
  92. pProp->m_fHighValue = pSendTableProp->m_fHighValue;
  93. pProp->m_nBits = pSendTableProp->m_nBits;
  94. }
  95. }
  96. }
  97. return true;
  98. }
  99. // If the table's ID is -1, writes its info into the buffer and increments curID.
  100. void DataTable_MaybeCreateReceiveTable( CUtlVector< SendTable * >& visited, SendTable *pTable, bool bNeedDecoder )
  101. {
  102. // Already sent?
  103. if ( visited.Find( pTable ) != visited.InvalidIndex() )
  104. return;
  105. visited.AddToTail( pTable );
  106. DataTable_SetupReceiveTableFromSendTable( pTable, bNeedDecoder );
  107. }
  108. void DataTable_MaybeCreateReceiveTable_R( CUtlVector< SendTable * >& visited, SendTable *pTable )
  109. {
  110. DataTable_MaybeCreateReceiveTable( visited, pTable, false );
  111. // Make sure we send child send tables..
  112. for(int i=0; i < pTable->m_nProps; i++)
  113. {
  114. SendProp *pProp = &pTable->m_pProps[i];
  115. if( pProp->m_Type == DPT_DataTable )
  116. {
  117. DataTable_MaybeCreateReceiveTable_R( visited, pProp->GetDataTable() );
  118. }
  119. }
  120. }
  121. void DataTable_CreateClientTablesFromServerTables()
  122. {
  123. if ( !serverGameDLL )
  124. {
  125. Sys_Error( "DataTable_CreateClientTablesFromServerTables: No serverGameDLL loaded!" );
  126. }
  127. ServerClass *pClasses = serverGameDLL->GetAllServerClasses();
  128. ServerClass *pCur;
  129. CUtlVector< SendTable * > visited;
  130. // First, we send all the leaf classes. These are the ones that will need decoders
  131. // on the client.
  132. for ( pCur=pClasses; pCur; pCur=pCur->m_pNext )
  133. {
  134. DataTable_MaybeCreateReceiveTable( visited, pCur->m_pTable, true );
  135. }
  136. // Now, we send their base classes. These don't need decoders on the client
  137. // because we will never send these SendTables by themselves.
  138. for ( pCur=pClasses; pCur; pCur=pCur->m_pNext )
  139. {
  140. DataTable_MaybeCreateReceiveTable_R( visited, pCur->m_pTable );
  141. }
  142. }
  143. void DataTable_CreateClientClassInfosFromServerClasses( CBaseClientState *pState )
  144. {
  145. if ( !serverGameDLL )
  146. {
  147. Sys_Error( "DataTable_CreateClientClassInfosFromServerClasses: No serverGameDLL loaded!" );
  148. }
  149. ServerClass *pClasses = serverGameDLL->GetAllServerClasses();
  150. // Count the number of classes.
  151. int nClasses = 0;
  152. for ( ServerClass *pCount=pClasses; pCount; pCount=pCount->m_pNext )
  153. {
  154. ++nClasses;
  155. }
  156. // Remove old
  157. if ( pState->m_pServerClasses )
  158. {
  159. delete [] pState->m_pServerClasses;
  160. }
  161. Assert( nClasses > 0 );
  162. pState->m_nServerClasses = nClasses;
  163. pState->m_pServerClasses = new C_ServerClassInfo[ pState->m_nServerClasses ];
  164. if ( !pState->m_pServerClasses )
  165. {
  166. Host_EndGame(true, "CL_ParseClassInfo: can't allocate %d C_ServerClassInfos.\n", pState->m_nServerClasses);
  167. return;
  168. }
  169. // Now fill in the entries
  170. int curID = 0;
  171. for ( ServerClass *pClass=pClasses; pClass; pClass=pClass->m_pNext )
  172. {
  173. Assert( pClass->m_ClassID >= 0 && pClass->m_ClassID < nClasses );
  174. pClass->m_ClassID = curID++;
  175. pState->m_pServerClasses[ pClass->m_ClassID ].m_ClassName = COM_StringCopy( pClass->m_pNetworkName );
  176. pState->m_pServerClasses[ pClass->m_ClassID ].m_DatatableName = COM_StringCopy( pClass->m_pTable->GetName() );
  177. }
  178. }
  179. // If the table's ID is -1, writes its info into the buffer and increments curID.
  180. static void DataTable_MaybeWriteSendTableBuffer( SendTable *pTable, bf_write *pBuf, bool bNeedDecoder )
  181. {
  182. // Already sent?
  183. if ( pTable->GetWriteFlag() )
  184. return;
  185. pTable->SetWriteFlag( true );
  186. SendTable_WriteInfos( pTable, *pBuf, bNeedDecoder, false );
  187. }
  188. // Calls DataTable_MaybeWriteSendTable recursively.
  189. void DataTable_MaybeWriteSendTableBuffer_R( SendTable *pTable, bf_write *pBuf )
  190. {
  191. DataTable_MaybeWriteSendTableBuffer( pTable, pBuf, false );
  192. // Make sure we send child send tables..
  193. for(int i=0; i < pTable->m_nProps; i++)
  194. {
  195. SendProp *pProp = &pTable->m_pProps[i];
  196. if( pProp->m_Type == DPT_DataTable )
  197. {
  198. DataTable_MaybeWriteSendTableBuffer_R( pProp->GetDataTable(), pBuf );
  199. }
  200. }
  201. }
  202. #ifdef _DEBUG
  203. // If the table's ID is -1, writes its info into the buffer and increments curID.
  204. void DataTable_MaybeDumpSendTable( SendTable *pTable, bool bNeedDecoder )
  205. {
  206. // Already sent?
  207. if ( pTable->GetWriteFlag() )
  208. return;
  209. pTable->SetWriteFlag( true );
  210. Msg( "\t%s has %d props:\n", pTable->GetName(), pTable->GetNumProps() );
  211. for ( int iProp=0; iProp < pTable->m_nProps; iProp++ )
  212. {
  213. const SendProp *pProp = &pTable->m_pProps[iProp];
  214. Msg( "\t\t%s\n", pProp->GetName() );
  215. }
  216. }
  217. // Calls DataTable_MaybeWriteSendTable recursively.
  218. void DataTable_MaybeDumpSendTable_R( SendTable *pTable )
  219. {
  220. DataTable_MaybeDumpSendTable( pTable, false );
  221. // Make sure we send child send tables..
  222. for(int i=0; i < pTable->m_nProps; i++)
  223. {
  224. SendProp *pProp = &pTable->m_pProps[i];
  225. if( pProp->m_Type == DPT_DataTable )
  226. {
  227. DataTable_MaybeDumpSendTable_R( pProp->GetDataTable() );
  228. }
  229. }
  230. }
  231. #endif
  232. void DataTable_ClearWriteFlags_R( SendTable *pTable )
  233. {
  234. pTable->SetWriteFlag( false );
  235. for(int i=0; i < pTable->m_nProps; i++)
  236. {
  237. SendProp *pProp = &pTable->m_pProps[i];
  238. if( pProp->m_Type == DPT_DataTable )
  239. {
  240. DataTable_ClearWriteFlags_R( pProp->GetDataTable() );
  241. }
  242. }
  243. }
  244. void DataTable_ClearWriteFlags( ServerClass *pClasses )
  245. {
  246. for ( ServerClass *pCur=pClasses; pCur; pCur=pCur->m_pNext )
  247. {
  248. DataTable_ClearWriteFlags_R( pCur->m_pTable );
  249. }
  250. }
  251. void DataTable_WriteSendTablesBuffer( ServerClass *pClasses, bf_write *pBuf )
  252. {
  253. ServerClass *pCur;
  254. DataTable_ClearWriteFlags( pClasses );
  255. // First, we send all the leaf classes. These are the ones that will need decoders
  256. // on the client.
  257. for ( pCur=pClasses; pCur; pCur=pCur->m_pNext )
  258. {
  259. DataTable_MaybeWriteSendTableBuffer( pCur->m_pTable, pBuf, true );
  260. }
  261. // Now, we send their base classes. These don't need decoders on the client
  262. // because we will never send these SendTables by themselves.
  263. for ( pCur=pClasses; pCur; pCur=pCur->m_pNext )
  264. {
  265. DataTable_MaybeWriteSendTableBuffer_R( pCur->m_pTable, pBuf );
  266. }
  267. // Signal no more send tables.
  268. SendTable_WriteInfos( NULL, *pBuf, false, true );
  269. }
  270. #ifdef _DEBUG
  271. void DataTable_DumpSendTables( ServerClass *pClasses )
  272. {
  273. ServerClass *pCur;
  274. DataTable_ClearWriteFlags( pClasses );
  275. // First, we send all the leaf classes. These are the ones that will need decoders
  276. // on the client.
  277. for ( pCur=pClasses; pCur; pCur=pCur->m_pNext )
  278. {
  279. DataTable_MaybeDumpSendTable( pCur->m_pTable, true );
  280. }
  281. // Now, we send their base classes. These don't need decoders on the client
  282. // because we will never send these SendTables by themselves.
  283. for ( pCur=pClasses; pCur; pCur=pCur->m_pNext )
  284. {
  285. DataTable_MaybeDumpSendTable_R( pCur->m_pTable );
  286. }
  287. }
  288. #endif
  289. void DataTable_WriteClassInfosBuffer(ServerClass *pClasses, bf_write *pBuf )
  290. {
  291. int count = 0;
  292. ServerClass *pClass = pClasses;
  293. // first count total number of classes in list
  294. while ( pClass != NULL )
  295. {
  296. pClass=pClass->m_pNext;
  297. count++;
  298. }
  299. // write number of classes
  300. pBuf->WriteShort( count );
  301. pClass = pClasses; // go back to first class
  302. // write each class info
  303. while ( pClass != NULL )
  304. {
  305. pBuf->WriteShort( pClass->m_ClassID );
  306. pBuf->WriteString( pClass->m_pNetworkName );
  307. pBuf->WriteString( pClass->m_pTable->GetName() );
  308. pClass=pClass->m_pNext;
  309. }
  310. }
  311. #ifdef _DEBUG
  312. void DataTable_DumpClassInfos(ServerClass *pClasses )
  313. {
  314. int count = 0;
  315. ServerClass *pClass = pClasses;
  316. // first count total number of classes in list
  317. while ( pClass != NULL )
  318. {
  319. pClass=pClass->m_pNext;
  320. count++;
  321. }
  322. // write number of classes
  323. Msg( "%d ClassInfos\n", count );
  324. pClass = pClasses; // go back to first class
  325. // write each class info
  326. while ( pClass != NULL )
  327. {
  328. Msg( "\t%d: %s / %s\n", pClass->m_ClassID, pClass->m_pNetworkName, pClass->m_pTable->GetName() );
  329. pClass=pClass->m_pNext;
  330. }
  331. }
  332. #endif
  333. bool DataTable_ParseClassInfosFromBuffer( CClientState *pState, bf_read *pBuf )
  334. {
  335. if(pState->m_pServerClasses)
  336. {
  337. delete [] pState->m_pServerClasses;
  338. }
  339. pState->m_nServerClasses = pBuf->ReadShort();
  340. Assert( pState->m_nServerClasses );
  341. pState->m_pServerClasses = new C_ServerClassInfo[pState->m_nServerClasses];
  342. if ( !pState->m_pServerClasses )
  343. {
  344. Host_EndGame(true, "CL_ParseClassInfo: can't allocate %d C_ServerClassInfos.\n", pState->m_nServerClasses);
  345. return false;
  346. }
  347. for ( int i = 0; i < pState->m_nServerClasses; i++ )
  348. {
  349. int classID = pBuf->ReadShort();
  350. if( classID >= pState->m_nServerClasses )
  351. {
  352. Host_EndGame(true, "DataTable_ParseClassInfosFromBuffer: invalid class index (%d).\n", classID);
  353. return false;
  354. }
  355. pState->m_pServerClasses[classID].m_ClassName = pBuf->ReadAndAllocateString();
  356. pState->m_pServerClasses[classID].m_DatatableName = pBuf->ReadAndAllocateString();
  357. }
  358. return true;
  359. }
  360. bool DataTable_LoadDataTablesFromBuffer( bf_read *pBuf, int nDemoProtocol )
  361. {
  362. // Okay, read them out of the buffer since they weren't recorded into the main network stream during recording
  363. CSVCMsg_SendTable_t msg;
  364. // Create all of the send tables locally
  365. // was DataTable_ParseClientTablesFromBuffer()
  366. while ( 1 )
  367. {
  368. int type = pBuf->ReadVarInt32();
  369. if( !msg.ReadFromBuffer( *pBuf ) )
  370. {
  371. Host_Error( "DataTable_ParseClientTablesFromBuffer ReadFromBuffer failed.\n" );
  372. return false;
  373. }
  374. int msgType = msg.GetType();
  375. if ( msgType != type )
  376. {
  377. Host_Error( "DataTable_ParseClientTablesFromBuffer ReadFromBuffer failed.\n" );
  378. return false;
  379. }
  380. if( msg.is_end() )
  381. break;
  382. if ( !RecvTable_RecvClassInfos( msg, nDemoProtocol ) )
  383. {
  384. Host_Error( "DataTable_ParseClientTablesFromBuffer failed.\n" );
  385. return false;
  386. }
  387. }
  388. #ifndef DEDICATED
  389. // Now create all of the server classes locally, too
  390. return DataTable_ParseClassInfosFromBuffer( &GetBaseLocalClient(), pBuf );
  391. #else
  392. return false;
  393. #endif
  394. }