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. //=============================================================================//
  6. #include "LocalNetworkBackdoor.h"
  7. #include "server_class.h"
  8. #include "client_class.h"
  9. #include "server.h"
  10. #include "eiface.h"
  11. #include "cdll_engine_int.h"
  12. #include "dt_localtransfer.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. CLocalNetworkBackdoor *g_pLocalNetworkBackdoor = NULL;
  16. #ifndef SWDS
  17. // This is called
  18. void CLocalNetworkBackdoor::InitFastCopy()
  19. {
  20. if ( !cl.m_NetChannel->IsLoopback() )
  21. return;
  22. const CStandardSendProxies *pSendProxies = NULL;
  23. // If the game server is greater than v4, then it is using the new proxy format.
  24. if ( g_iServerGameDLLVersion >= 5 ) // check server version
  25. {
  26. pSendProxies = serverGameDLL->GetStandardSendProxies();
  27. }
  28. else
  29. {
  30. // If the game server is older than v4, it is using the old proxy; we set the new proxy members to the
  31. // engine's copy.
  32. static CStandardSendProxies compatSendProxy = *serverGameDLL->GetStandardSendProxies();
  33. compatSendProxy.m_DataTableToDataTable = g_StandardSendProxies.m_DataTableToDataTable;
  34. compatSendProxy.m_SendLocalDataTable = g_StandardSendProxies.m_SendLocalDataTable;
  35. compatSendProxy.m_ppNonModifiedPointerProxies = g_StandardSendProxies.m_ppNonModifiedPointerProxies;
  36. pSendProxies = &compatSendProxy;
  37. }
  38. const CStandardRecvProxies *pRecvProxies = g_ClientDLL->GetStandardRecvProxies();
  39. int nFastCopyProps = 0;
  40. int nSlowCopyProps = 0;
  41. for ( int iClass=0; iClass < cl.m_nServerClasses; iClass++ )
  42. {
  43. ClientClass *pClientClass = cl.GetClientClass(iClass);
  44. if ( !pClientClass )
  45. Error( "InitFastCopy - missing client class %d (Should be equivelent of server class: %s)", iClass, cl.m_pServerClasses[iClass].m_ClassName );
  46. ServerClass *pServerClass = SV_FindServerClass( pClientClass->GetName() );
  47. if ( !pServerClass )
  48. Error( "InitFastCopy - missing server class %s", pClientClass->GetName() );
  49. LocalTransfer_InitFastCopy(
  50. pServerClass->m_pTable,
  51. pSendProxies,
  52. pClientClass->m_pRecvTable,
  53. pRecvProxies,
  54. nSlowCopyProps,
  55. nFastCopyProps
  56. );
  57. }
  58. int percentFast = (nFastCopyProps * 100 ) / (nSlowCopyProps + nFastCopyProps + 1);
  59. if ( percentFast <= 55 )
  60. {
  61. // This may not be a real problem, but at the time this code was added, 67% of the
  62. // properties were able to be copied without proxies. If percentFast goes to 0 or some
  63. // really low number suddenly, then something probably got screwed up.
  64. Assert( false );
  65. Warning( "InitFastCopy: only %d%% fast props. Bug?\n", percentFast );
  66. }
  67. }
  68. #endif
  69. void CLocalNetworkBackdoor::StartEntityStateUpdate()
  70. {
  71. m_EntsAlive.ClearAll();
  72. m_nEntsCreated = 0;
  73. m_nEntsChanged = 0;
  74. // signal client that we start updating entities
  75. ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_START );
  76. }
  77. void CLocalNetworkBackdoor::EndEntityStateUpdate()
  78. {
  79. ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_POSTDATAUPDATE_START );
  80. // Handle entities created.
  81. int i;
  82. for ( i=0; i < m_nEntsCreated; i++ )
  83. {
  84. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  85. int iEdict = m_EntsCreatedIndices[i];
  86. CCachedEntState *pCached = &m_CachedEntState[iEdict];
  87. IClientNetworkable *pNet = pCached->m_pNetworkable;
  88. pNet->PostDataUpdate( DATA_UPDATE_CREATED );
  89. pNet->NotifyShouldTransmit( SHOULDTRANSMIT_START );
  90. pCached->m_bDormant = false;
  91. }
  92. // Handle entities changed.
  93. for ( i=0; i < m_nEntsChanged; i++ )
  94. {
  95. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  96. int iEdict = m_EntsChangedIndices[i];
  97. m_CachedEntState[iEdict].m_pNetworkable->PostDataUpdate( DATA_UPDATE_DATATABLE_CHANGED );
  98. }
  99. ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_POSTDATAUPDATE_END );
  100. // Handle entities removed (= SV_WriteDeletions() in normal mode)
  101. int nDWords = m_PrevEntsAlive.GetNumDWords();
  102. // Handle entities removed.
  103. for ( i=0; i < nDWords; i++ )
  104. {
  105. unsigned long prevEntsAlive = m_PrevEntsAlive.GetDWord( i );
  106. unsigned long entsAlive = m_EntsAlive.GetDWord( i );
  107. unsigned long toDelete = (prevEntsAlive ^ entsAlive) & prevEntsAlive;
  108. if ( toDelete )
  109. {
  110. for ( int iBit=0; iBit < 32; iBit++ )
  111. {
  112. if ( toDelete & (1 << iBit) )
  113. {
  114. int iEdict = (i<<5) + iBit;
  115. if ( iEdict >= 0 && iEdict < MAX_EDICTS )
  116. {
  117. if ( m_CachedEntState[iEdict].m_pNetworkable )
  118. {
  119. m_CachedEntState[iEdict].m_pNetworkable->Release();
  120. m_CachedEntState[iEdict].m_pNetworkable = NULL;
  121. }
  122. else
  123. {
  124. AssertOnce( !"EndEntityStateUpdate: Would have crashed with NULL m_pNetworkable\n" );
  125. }
  126. }
  127. else
  128. {
  129. AssertOnce( !"EndEntityStateUpdate: Would have crashed with entity out of range\n" );
  130. }
  131. }
  132. }
  133. }
  134. }
  135. // Remember the previous state of which entities were around.
  136. m_PrevEntsAlive = m_EntsAlive;
  137. // end of all entity update activity
  138. ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_END );
  139. /*
  140. #ifdef _DEBUG
  141. for ( i=0; i <= highest_index; i++ )
  142. {
  143. if ( !( m_EntsAlive[i>>5] & (1 << (i & 31)) ) )
  144. Assert( !m_CachedEntState[i].m_pNetworkable );
  145. if ( ( m_EntsAlive[i>>5] & (1 << (i & 31)) ) &&
  146. ( m_EntsCreated[i>>5] & (1 << (i & 31)) ) )
  147. {
  148. Assert( FindInList( m_EntsCreatedIndices, m_nEntsCreated, i ) );
  149. }
  150. if ( (m_EntsAlive[i>>5] & (1 << (i & 31))) &&
  151. !(m_EntsCreated[i>>5] & (1 << (i & 31))) &&
  152. (m_EntsChanged[i>>5] & (1 << (i & 31)))
  153. )
  154. {
  155. Assert( FindInList( m_EntsChangedIndices, m_nEntsChanged, i ) );
  156. }
  157. }
  158. #endif
  159. */
  160. }
  161. void CLocalNetworkBackdoor::EntityDormant( int iEnt, int iSerialNum )
  162. {
  163. CCachedEntState *pCached = &m_CachedEntState[iEnt];
  164. IClientNetworkable *pNet = pCached->m_pNetworkable;
  165. Assert( pNet == entitylist->GetClientNetworkable( iEnt ) );
  166. if ( pNet )
  167. {
  168. Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
  169. if ( pCached->m_iSerialNumber == iSerialNum )
  170. {
  171. m_EntsAlive.Set( iEnt );
  172. // Tell the game code that this guy is now dormant.
  173. Assert( pCached->m_bDormant == pNet->IsDormant() );
  174. if ( !pCached->m_bDormant )
  175. {
  176. pNet->NotifyShouldTransmit( SHOULDTRANSMIT_END );
  177. pCached->m_bDormant = true;
  178. }
  179. }
  180. else
  181. {
  182. pNet->Release();
  183. pCached->m_pNetworkable = NULL;
  184. m_PrevEntsAlive.Clear( iEnt );
  185. }
  186. }
  187. }
  188. void CLocalNetworkBackdoor::AddToPendingDormantEntityList( unsigned short iEdict )
  189. {
  190. edict_t *e = &sv.edicts[iEdict];
  191. if ( !( e->m_fStateFlags & FL_EDICT_PENDING_DORMANT_CHECK ) )
  192. {
  193. e->m_fStateFlags |= FL_EDICT_PENDING_DORMANT_CHECK;
  194. m_PendingDormantEntities.AddToTail( iEdict );
  195. }
  196. }
  197. void CLocalNetworkBackdoor::ProcessDormantEntities()
  198. {
  199. FOR_EACH_LL( m_PendingDormantEntities, i )
  200. {
  201. int iEdict = m_PendingDormantEntities[i];
  202. edict_t *e = &sv.edicts[iEdict];
  203. // Make sure the entity still exists and stil has the dontsend flag set.
  204. if ( e->IsFree() || !(e->m_fStateFlags & FL_EDICT_DONTSEND) )
  205. {
  206. e->m_fStateFlags &= ~FL_EDICT_PENDING_DORMANT_CHECK;
  207. continue;
  208. }
  209. EntityDormant( iEdict, e->m_NetworkSerialNumber );
  210. e->m_fStateFlags &= ~FL_EDICT_PENDING_DORMANT_CHECK;
  211. }
  212. m_PendingDormantEntities.Purge();
  213. }
  214. void CLocalNetworkBackdoor::EntState(
  215. int iEnt,
  216. int iSerialNum,
  217. int iClass,
  218. const SendTable *pSendTable,
  219. const void *pSourceEnt,
  220. bool bChanged,
  221. bool bShouldTransmit )
  222. {
  223. CCachedEntState *pCached = &m_CachedEntState[iEnt];
  224. // Remember that this ent is alive.
  225. m_EntsAlive.Set(iEnt);
  226. ClientClass *pClientClass = cl.GetClientClass(iClass);
  227. if ( !pClientClass )
  228. Error( "CLocalNetworkBackdoor::EntState - missing client class %d", iClass );
  229. IClientNetworkable *pNet = pCached->m_pNetworkable;
  230. Assert( pNet == entitylist->GetClientNetworkable( iEnt ) );
  231. if ( !bShouldTransmit )
  232. {
  233. if ( pNet )
  234. {
  235. Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
  236. if ( pCached->m_iSerialNumber == iSerialNum )
  237. {
  238. // Tell the game code that this guy is now dormant.
  239. Assert( pCached->m_bDormant == pNet->IsDormant() );
  240. if ( !pCached->m_bDormant )
  241. {
  242. pNet->NotifyShouldTransmit( SHOULDTRANSMIT_END );
  243. pCached->m_bDormant = true;
  244. }
  245. }
  246. else
  247. {
  248. pNet->Release();
  249. pNet = NULL;
  250. pCached->m_pNetworkable = NULL;
  251. // Since we set this above, need to clear it now to avoid assertion in EndEntityStateUpdate()
  252. m_EntsAlive.Clear(iEnt);
  253. m_PrevEntsAlive.Clear( iEnt );
  254. }
  255. }
  256. else
  257. {
  258. m_EntsAlive.Clear( iEnt );
  259. }
  260. return;
  261. }
  262. // Do we have an entity here already?
  263. bool bExistedAndWasDormant = false;
  264. if ( pNet )
  265. {
  266. // If the serial numbers are different, make it recreate the ent.
  267. Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
  268. if ( iSerialNum == pCached->m_iSerialNumber )
  269. {
  270. bExistedAndWasDormant = pCached->m_bDormant;
  271. }
  272. else
  273. {
  274. pNet->Release();
  275. pNet = NULL;
  276. m_PrevEntsAlive.Clear(iEnt);
  277. }
  278. }
  279. // Create the entity?
  280. bool bCreated = false;
  281. DataUpdateType_t updateType;
  282. if ( pNet )
  283. {
  284. updateType = DATA_UPDATE_DATATABLE_CHANGED;
  285. }
  286. else
  287. {
  288. updateType = DATA_UPDATE_CREATED;
  289. pNet = pClientClass->m_pCreateFn( iEnt, iSerialNum );
  290. bCreated = true;
  291. m_EntsCreatedIndices[m_nEntsCreated++] = iEnt;
  292. pCached->m_iSerialNumber = iSerialNum;
  293. pCached->m_pDataPointer = pNet->GetDataTableBasePtr();
  294. pCached->m_pNetworkable = pNet;
  295. // Tracker 73192: ywb 8/1/07: We used to get an assertion that the pCached->m_bDormant was not equal to pNet->IsDormant() in ProcessDormantEntities.
  296. // This appears to be the case if when we get here, the entity is set for Transmit still, but is a dormant entity on the server.
  297. // Seems safe to go ahead an fill in the cache with the correct data. Probably was just an oversight.
  298. pCached->m_bDormant = pNet->IsDormant();
  299. }
  300. if ( bChanged || bCreated || bExistedAndWasDormant )
  301. {
  302. pNet->PreDataUpdate( updateType );
  303. Assert( pCached->m_pDataPointer == pNet->GetDataTableBasePtr() );
  304. LocalTransfer_TransferEntity(
  305. &sv.edicts[iEnt],
  306. pSendTable,
  307. pSourceEnt,
  308. pClientClass->m_pRecvTable,
  309. pCached->m_pDataPointer,
  310. bCreated,
  311. bExistedAndWasDormant,
  312. iEnt );
  313. if ( bExistedAndWasDormant )
  314. {
  315. // Set this so we use DATA_UPDATE_CREATED logic
  316. m_EntsCreatedIndices[m_nEntsCreated++] = iEnt;
  317. }
  318. else
  319. {
  320. if ( !bCreated )
  321. {
  322. m_EntsChangedIndices[m_nEntsChanged++] = iEnt;
  323. }
  324. }
  325. }
  326. }
  327. void CLocalNetworkBackdoor::ClearState()
  328. {
  329. // Clear the cache for all the entities.
  330. for ( int i=0; i < MAX_EDICTS; i++ )
  331. {
  332. CCachedEntState &ces = m_CachedEntState[i];
  333. ces.m_pNetworkable = NULL;
  334. ces.m_iSerialNumber = -1;
  335. ces.m_bDormant = false;
  336. ces.m_pDataPointer = NULL;
  337. }
  338. m_PrevEntsAlive.ClearAll();
  339. }
  340. void CLocalNetworkBackdoor::StartBackdoorMode()
  341. {
  342. ClearState();
  343. for ( int i=0; i < MAX_EDICTS; i++ )
  344. {
  345. IClientNetworkable *pNet = entitylist->GetClientNetworkable( i );
  346. CCachedEntState &ces = m_CachedEntState[i];
  347. if ( pNet )
  348. {
  349. ces.m_pNetworkable = pNet;
  350. ces.m_iSerialNumber = pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber();
  351. ces.m_bDormant = pNet->IsDormant();
  352. ces.m_pDataPointer = pNet->GetDataTableBasePtr();
  353. m_PrevEntsAlive.Set( i );
  354. }
  355. }
  356. }
  357. void CLocalNetworkBackdoor::StopBackdoorMode()
  358. {
  359. ClearState();
  360. }