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.

578 lines
16 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "server_pch.h"
  8. #include <utllinkedlist.h>
  9. #include "hltvserver.h"
  10. #if defined( REPLAY_ENABLED )
  11. #include "replayserver.h"
  12. #endif
  13. #include "framesnapshot.h"
  14. #include "sys_dll.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. DEFINE_FIXEDSIZE_ALLOCATOR( CFrameSnapshot, 64, 64 );
  18. static ConVar sv_creationtickcheck( "sv_creationtickcheck", "1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Do extended check for encoding of timestamps against tickcount" );
  19. extern CGlobalVars g_ServerGlobalVariables;
  20. // Expose interface
  21. static CFrameSnapshotManager g_FrameSnapshotManager;
  22. CFrameSnapshotManager *framesnapshotmanager = &g_FrameSnapshotManager;
  23. //-----------------------------------------------------------------------------
  24. // Purpose:
  25. //-----------------------------------------------------------------------------
  26. CFrameSnapshotManager::CFrameSnapshotManager( void ) : m_PackedEntitiesPool( MAX_EDICTS / 16, CUtlMemoryPool::GROW_SLOW )
  27. {
  28. COMPILE_TIME_ASSERT( INVALID_PACKED_ENTITY_HANDLE == 0 );
  29. Assert( INVALID_PACKED_ENTITY_HANDLE == m_PackedEntities.InvalidIndex() );
  30. Q_memset( m_pLastPackedData, 0x00, MAX_EDICTS * sizeof(PackedEntityHandle_t) );
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose:
  34. //-----------------------------------------------------------------------------
  35. CFrameSnapshotManager::~CFrameSnapshotManager( void )
  36. {
  37. #ifdef _DEBUG
  38. if ( IsInErrorExit() )
  39. {
  40. // These may have been freed already. Don't crash when freeing these.
  41. Q_memset( &m_PackedEntities, 0, sizeof( m_PackedEntities ) );
  42. }
  43. else
  44. {
  45. Assert( m_FrameSnapshots.Count() == 0 );
  46. Assert( m_PackedEntities.Count() == 0 );
  47. }
  48. #endif
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Called when a level change happens
  52. //-----------------------------------------------------------------------------
  53. void CFrameSnapshotManager::LevelChanged()
  54. {
  55. // Clear all lists...
  56. Assert( m_FrameSnapshots.Count() == 0 );
  57. // Release the most recent snapshot...
  58. m_PackedEntities.RemoveAll();
  59. m_PackedEntitiesPool.Clear();
  60. m_PackedEntityCache.RemoveAll();
  61. COMPILE_TIME_ASSERT( INVALID_PACKED_ENTITY_HANDLE == 0 );
  62. Q_memset( m_pLastPackedData, 0x00, MAX_EDICTS * sizeof(PackedEntityHandle_t) );
  63. }
  64. CFrameSnapshot *CFrameSnapshotManager::NextSnapshot( CFrameSnapshot *pSnapshot )
  65. {
  66. if ( !pSnapshot || ((unsigned short)pSnapshot->m_ListIndex == m_FrameSnapshots.InvalidIndex()) )
  67. return NULL;
  68. int next = m_FrameSnapshots.Next(pSnapshot->m_ListIndex);
  69. if ( next == m_FrameSnapshots.InvalidIndex() )
  70. return NULL;
  71. // return next element in list
  72. return m_FrameSnapshots[ next ];
  73. }
  74. CFrameSnapshot* CFrameSnapshotManager::CreateEmptySnapshot(
  75. #ifdef DEBUG_SNAPSHOT_REFERENCES
  76. char const *szDebugName,
  77. #endif
  78. int tickcount, int maxEntities, uint32 nSnapshotSet )
  79. {
  80. CFrameSnapshot *snap = NULL;
  81. {
  82. AUTO_LOCK_FM( m_FrameSnapshotsWriteMutex );
  83. snap = new CFrameSnapshot;
  84. snap->AddReference();
  85. }
  86. #ifdef DEBUG_SNAPSHOT_REFERENCES
  87. Q_strncpy( snap->m_chDebugSnapshotName, szDebugName, sizeof( snap->m_chDebugSnapshotName ) );
  88. #endif
  89. snap->m_nSnapshotSet = nSnapshotSet;
  90. snap->m_nTickCount = tickcount;
  91. snap->m_nNumEntities = maxEntities;
  92. snap->m_nValidEntities = 0;
  93. snap->m_pValidEntities = NULL;
  94. snap->m_pHLTVEntityData = NULL;
  95. #if defined( REPLAY_ENABLED )
  96. snap->m_pReplayEntityData = NULL;
  97. #endif
  98. snap->m_pEntities = new CFrameSnapshotEntry[maxEntities];
  99. CFrameSnapshotEntry *entry = snap->m_pEntities;
  100. // clear entries
  101. for ( int i=0; i < maxEntities; i++)
  102. {
  103. entry->m_pClass = NULL;
  104. entry->m_nSerialNumber = -1;
  105. entry->m_pPackedData = INVALID_PACKED_ENTITY_HANDLE;
  106. entry++;
  107. }
  108. {
  109. AUTO_LOCK_FM( m_FrameSnapshotsWriteMutex );
  110. snap->m_ListIndex = m_FrameSnapshots.AddToTail( snap );
  111. }
  112. return snap;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. // Input : framenumber -
  117. //-----------------------------------------------------------------------------
  118. CFrameSnapshot* CFrameSnapshotManager::TakeTickSnapshot(
  119. #ifdef DEBUG_SNAPSHOT_REFERENCES
  120. char const *szDebugName,
  121. #endif
  122. int tickcount, uint32 nSnapshotSet )
  123. {
  124. unsigned short nValidEntities[MAX_EDICTS];
  125. SNPROF( __FUNCTION__ );
  126. CFrameSnapshot *snap = CreateEmptySnapshot(
  127. #ifdef DEBUG_SNAPSHOT_REFERENCES
  128. szDebugName,
  129. #endif
  130. tickcount, sv.num_edicts, nSnapshotSet );
  131. int maxclients = sv.GetClientCount();
  132. CFrameSnapshotEntry *entry = snap->m_pEntities - 1;
  133. edict_t *edict= sv.edicts - 1;
  134. // Build the snapshot.
  135. for ( int i = 0; i < sv.num_edicts; i++ )
  136. {
  137. edict++;
  138. entry++;
  139. if ( IsGameConsole() && edict->GetNetworkable() )
  140. {
  141. PREFETCH360( edict->GetNetworkable(), 0 );
  142. }
  143. IServerUnknown *pUnk = edict->GetUnknown();
  144. if ( !pUnk )
  145. continue;
  146. if ( edict->IsFree() )
  147. continue;
  148. // We don't want entities from inactive clients in the fullpack,
  149. if ( i > 0 && i <= maxclients )
  150. {
  151. // this edict is a client
  152. if ( !sv.GetClient(i-1)->IsActive() )
  153. continue;
  154. }
  155. // entity exists and is not marked as 'free'
  156. Assert( edict->m_NetworkSerialNumber != -1 );
  157. Assert( edict->GetNetworkable() );
  158. Assert( edict->GetNetworkable()->GetServerClass() );
  159. entry->m_nSerialNumber = edict->m_NetworkSerialNumber;
  160. entry->m_pClass = edict->GetNetworkable()->GetServerClass();
  161. nValidEntities[snap->m_nValidEntities++] = i;
  162. }
  163. // create dynamic valid entities array and copy indices
  164. snap->m_pValidEntities = new unsigned short[snap->m_nValidEntities];
  165. Q_memcpy( snap->m_pValidEntities, nValidEntities, snap->m_nValidEntities * sizeof(unsigned short) );
  166. if ( IsHltvActive() )
  167. {
  168. snap->m_pHLTVEntityData = new CHLTVEntityData[snap->m_nValidEntities];
  169. Q_memset( snap->m_pHLTVEntityData, 0, snap->m_nValidEntities * sizeof(CHLTVEntityData) );
  170. }
  171. #if defined( REPLAY_ENABLED )
  172. if ( replay && replay->IsActive() )
  173. {
  174. snap->m_pReplayEntityData = new CReplayEntityData[snap->m_nValidEntities];
  175. Q_memset( snap->m_pReplayEntityData, 0, snap->m_nValidEntities * sizeof(CReplayEntityData) );
  176. }
  177. #endif
  178. snap->m_iExplicitDeleteSlots.CopyArray( m_iExplicitDeleteSlots.Base(), m_iExplicitDeleteSlots.Count() );
  179. m_iExplicitDeleteSlots.Purge();
  180. return snap;
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Cleans up packed entity data
  184. //-----------------------------------------------------------------------------
  185. void CFrameSnapshotManager::DeleteFrameSnapshot( CFrameSnapshot* pSnapshot )
  186. {
  187. // Decrement reference counts of all packed entities
  188. for (int i = 0; i < pSnapshot->m_nNumEntities; ++i)
  189. {
  190. if ( pSnapshot->m_pEntities[i].m_pPackedData != INVALID_PACKED_ENTITY_HANDLE )
  191. {
  192. RemoveEntityReference( pSnapshot->m_pEntities[i].m_pPackedData );
  193. }
  194. }
  195. m_FrameSnapshots.Remove( pSnapshot->m_ListIndex );
  196. delete pSnapshot;
  197. }
  198. void CFrameSnapshotManager::RemoveEntityReference( PackedEntityHandle_t handle )
  199. {
  200. Assert( handle != INVALID_PACKED_ENTITY_HANDLE );
  201. PackedEntity *packedEntity = m_PackedEntities[ handle ];
  202. if ( --packedEntity->m_ReferenceCount <= 0)
  203. {
  204. AUTO_LOCK_FM( m_WriteMutex );
  205. m_PackedEntities.Remove( handle );
  206. m_PackedEntitiesPool.Free( packedEntity );
  207. // if we have a uncompression cache, remove reference too
  208. FOR_EACH_VEC( m_PackedEntityCache, i )
  209. {
  210. UnpackedDataCache_t &pdc = m_PackedEntityCache[i];
  211. if ( pdc.pEntity == packedEntity )
  212. {
  213. pdc.pEntity = NULL;
  214. pdc.counter = 0;
  215. break;
  216. }
  217. }
  218. }
  219. }
  220. void CFrameSnapshotManager::AddEntityReference( PackedEntityHandle_t handle )
  221. {
  222. Assert( handle != INVALID_PACKED_ENTITY_HANDLE );
  223. m_PackedEntities[ handle ]->m_ReferenceCount++;
  224. }
  225. void CFrameSnapshotManager::AddExplicitDelete( int iSlot )
  226. {
  227. AUTO_LOCK_FM( m_WriteMutex );
  228. if ( m_iExplicitDeleteSlots.Find(iSlot) == m_iExplicitDeleteSlots.InvalidIndex() )
  229. {
  230. m_iExplicitDeleteSlots.AddToTail( iSlot );
  231. }
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose: Returns true if the "basis" for encoding m_flAnimTime, m_flSimulationTime has changed
  235. // since the time this entity was packed to the time we're trying to re-use the packing.
  236. //-----------------------------------------------------------------------------
  237. bool CFrameSnapshotManager::ShouldForceRepack( CFrameSnapshot* pSnapshot, int entity, PackedEntityHandle_t handle )
  238. {
  239. if ( sv_creationtickcheck.GetBool() )
  240. {
  241. PackedEntity *pe = m_PackedEntities[ handle ];
  242. Assert( pe );
  243. if ( pe && pe->ShouldCheckCreationTick() )
  244. {
  245. int nCurrentNetworkBase = g_ServerGlobalVariables.GetNetworkBase( pSnapshot->m_nTickCount, entity );
  246. int nPackedEntityNetworkBase = g_ServerGlobalVariables.GetNetworkBase( pe->GetSnapshotCreationTick(), entity );
  247. if ( nCurrentNetworkBase != nPackedEntityNetworkBase )
  248. {
  249. return true;
  250. }
  251. }
  252. }
  253. return false;
  254. }
  255. bool CFrameSnapshotManager::UsePreviouslySentPacket( CFrameSnapshot* pSnapshot,
  256. int entity, int entSerialNumber )
  257. {
  258. PackedEntityHandle_t handle = m_pLastPackedData[entity];
  259. if ( handle != INVALID_PACKED_ENTITY_HANDLE )
  260. {
  261. // NOTE: We can't use the previously sent packet if there was a
  262. // serial number change....
  263. if ( m_pSerialNumber[entity] == entSerialNumber )
  264. {
  265. // Check if we need to re-pack entity due to encoding against gpGlobals->tickcount
  266. if ( framesnapshotmanager->ShouldForceRepack( pSnapshot, entity, handle ) )
  267. {
  268. return false;
  269. }
  270. Assert( entity < pSnapshot->m_nNumEntities );
  271. pSnapshot->m_pEntities[entity].m_pPackedData = handle;
  272. m_PackedEntities[handle]->m_ReferenceCount++;
  273. return true;
  274. }
  275. else
  276. {
  277. return false;
  278. }
  279. }
  280. return false;
  281. }
  282. PackedEntity* CFrameSnapshotManager::GetPreviouslySentPacket( int iEntity, int iSerialNumber )
  283. {
  284. PackedEntityHandle_t handle = m_pLastPackedData[iEntity];
  285. if ( handle != INVALID_PACKED_ENTITY_HANDLE )
  286. {
  287. // NOTE: We can't use the previously sent packet if there was a
  288. // serial number change....
  289. if ( m_pSerialNumber[iEntity] == iSerialNumber )
  290. {
  291. return m_PackedEntities[handle];
  292. }
  293. else
  294. {
  295. return NULL;
  296. }
  297. }
  298. return NULL;
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Returns the pack data for a particular entity for a particular snapshot
  302. //-----------------------------------------------------------------------------
  303. PackedEntity* CFrameSnapshotManager::CreatePackedEntity( CFrameSnapshot* pSnapshot, int entity )
  304. {
  305. PackedEntity* pNewEntity = CreateLocalPackedEntity( pSnapshot, entity );
  306. // Add a reference into the global list of last entity packets seen...
  307. // and remove the reference to the last entity packet we saw
  308. if (m_pLastPackedData[entity] != INVALID_PACKED_ENTITY_HANDLE )
  309. {
  310. RemoveEntityReference( m_pLastPackedData[entity] );
  311. }
  312. m_pLastPackedData[entity] = pSnapshot->m_pEntities[entity].m_pPackedData;
  313. m_pSerialNumber[entity] = pSnapshot->m_pEntities[entity].m_nSerialNumber;
  314. pNewEntity->m_ReferenceCount++;
  315. pNewEntity->SetSnapshotCreationTick( pSnapshot->m_nTickCount );
  316. return pNewEntity;
  317. }
  318. PackedEntity* CFrameSnapshotManager::CreateLocalPackedEntity( CFrameSnapshot* pSnapshot, int entity )
  319. {
  320. MEM_ALLOC_CREDIT();
  321. m_WriteMutex.Lock();
  322. PackedEntity *packedEntity = m_PackedEntitiesPool.Alloc();
  323. PackedEntityHandle_t handle = m_PackedEntities.AddToTail( packedEntity );
  324. m_WriteMutex.Unlock();
  325. Assert( entity < pSnapshot->m_nNumEntities );
  326. Assert( entity >= 0 && entity < ARRAYSIZE(m_pLastPackedData) );
  327. packedEntity->m_ReferenceCount = 1;
  328. packedEntity->m_nEntityIndex = entity;
  329. pSnapshot->m_pEntities[entity].m_pPackedData = handle;
  330. return packedEntity;
  331. }
  332. // ------------------------------------------------------------------------------------------------ //
  333. // purpose: lookup cache if we have an uncompressed version of this packed entity
  334. // ------------------------------------------------------------------------------------------------ //
  335. UnpackedDataCache_t *CFrameSnapshotManager::GetCachedUncompressedEntity( PackedEntity *packedEntity )
  336. {
  337. if ( m_PackedEntityCache.Count() == 0 )
  338. {
  339. // ops, we have no cache yet, create one and reset counter
  340. m_nPackedEntityCacheCounter = 0;
  341. m_PackedEntityCache.SetCount( 128 );
  342. FOR_EACH_VEC( m_PackedEntityCache, i )
  343. {
  344. m_PackedEntityCache[i].pEntity = NULL;
  345. m_PackedEntityCache[i].counter = 0;
  346. }
  347. }
  348. m_nPackedEntityCacheCounter++;
  349. // remember oldest cache entry
  350. UnpackedDataCache_t *pdcOldest = NULL;
  351. int oldestValue = m_nPackedEntityCacheCounter;
  352. FOR_EACH_VEC( m_PackedEntityCache, i )
  353. {
  354. UnpackedDataCache_t *pdc = &m_PackedEntityCache[i];
  355. if ( pdc->pEntity == packedEntity )
  356. {
  357. // hit, found it, update counter
  358. pdc->counter = m_nPackedEntityCacheCounter;
  359. return pdc;
  360. }
  361. if( pdc->counter < oldestValue )
  362. {
  363. oldestValue = pdc->counter;
  364. pdcOldest = pdc;
  365. }
  366. }
  367. Assert ( pdcOldest );
  368. // hmm, not in cache, clear & return oldest one
  369. pdcOldest->counter = m_nPackedEntityCacheCounter;
  370. pdcOldest->bits = -1; // important, this is the signal for the caller to fill this structure
  371. pdcOldest->pEntity = packedEntity;
  372. return pdcOldest;
  373. }
  374. void CFrameSnapshotManager::BuildSnapshotList( CFrameSnapshot *pCurrentSnapshot, CFrameSnapshot *pLastSnapshot, uint32 nSnapshotSet, CReferencedSnapshotList &list )
  375. {
  376. // Keep list building thread-safe
  377. AUTO_LOCK_FM( m_FrameSnapshotsWriteMutex );
  378. int nInsanity = 0;
  379. CFrameSnapshot *pSnapshot;
  380. if ( pLastSnapshot )
  381. {
  382. pSnapshot = NextSnapshot( pLastSnapshot );
  383. }
  384. else
  385. {
  386. pSnapshot = pCurrentSnapshot;
  387. }
  388. while ( pSnapshot )
  389. {
  390. //only add snapshots that match the desired set to the list
  391. if( pSnapshot->m_nSnapshotSet == nSnapshotSet )
  392. {
  393. pSnapshot->AddReference();
  394. list.m_vecSnapshots.AddToTail( pSnapshot );
  395. }
  396. ++nInsanity;
  397. if ( nInsanity > 100000 )
  398. {
  399. Error( "CFrameSnapshotManager::BuildSnapshotList: infinite loop building list!!!" );
  400. }
  401. if ( pSnapshot == pCurrentSnapshot )
  402. break;
  403. // got to next snapshot
  404. pSnapshot = NextSnapshot( pSnapshot );
  405. }
  406. }
  407. // ------------------------------------------------------------------------------------------------ //
  408. // CFrameSnapshot
  409. // ------------------------------------------------------------------------------------------------ //
  410. #if defined( _DEBUG )
  411. int g_nAllocatedSnapshots = 0;
  412. #endif
  413. CFrameSnapshot::CFrameSnapshot()
  414. {
  415. m_nTempEntities = 0;
  416. m_pTempEntities = NULL;
  417. m_pValidEntities = NULL;
  418. m_nReferences = 0;
  419. #if defined( _DEBUG )
  420. ++g_nAllocatedSnapshots;
  421. Assert( g_nAllocatedSnapshots < 80000 ); // this probably would indicate a memory leak.
  422. #endif
  423. #ifdef DEBUG_SNAPSHOT_REFERENCES
  424. Q_memset( m_chDebugSnapshotName, 0, sizeof( m_chDebugSnapshotName ) );
  425. #endif
  426. }
  427. CFrameSnapshot::~CFrameSnapshot()
  428. {
  429. delete [] m_pValidEntities;
  430. delete [] m_pEntities;
  431. if ( m_pTempEntities )
  432. {
  433. Assert( m_nTempEntities>0 );
  434. for (int i = 0; i < m_nTempEntities; i++ )
  435. {
  436. delete m_pTempEntities[i];
  437. }
  438. delete [] m_pTempEntities;
  439. }
  440. if ( m_pHLTVEntityData )
  441. {
  442. delete [] m_pHLTVEntityData;
  443. }
  444. #if defined( REPLAY_ENABLED )
  445. if ( m_pReplayEntityData )
  446. {
  447. delete [] m_pReplayEntityData;
  448. }
  449. #endif
  450. Assert ( m_nReferences == 0 );
  451. #if defined( _DEBUG )
  452. --g_nAllocatedSnapshots;
  453. Assert( g_nAllocatedSnapshots >= 0 );
  454. #endif
  455. }
  456. void CFrameSnapshot::AddReference()
  457. {
  458. Assert( m_nReferences < 0xFFFF );
  459. ++m_nReferences;
  460. }
  461. void CFrameSnapshot::ReleaseReference()
  462. {
  463. // Keep list building thread-safe
  464. // This lock was moved to to fix bug https://bugbait.valvesoftware.com/show_bug.cgi?id=53403
  465. // Crash in CFrameSnapshotManager::GetPackedEntity where a CBaseClient's m_pBaseline snapshot could be removed the CReferencedSnapshotList destructor
  466. // for another client that is in WriteTempEntities
  467. //
  468. AUTO_LOCK_FM( framesnapshotmanager->m_FrameSnapshotsWriteMutex );
  469. Assert( m_nReferences > 0 );
  470. --m_nReferences;
  471. if ( m_nReferences == 0 )
  472. {
  473. g_FrameSnapshotManager.DeleteFrameSnapshot( this );
  474. }
  475. }