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.

414 lines
11 KiB

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