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.

420 lines
11 KiB

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