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.

976 lines
28 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "server_pch.h"
  8. #include <eiface.h>
  9. #include <dt_send.h>
  10. #include <utllinkedlist.h>
  11. #include "dt_send_eng.h"
  12. #include "dt.h"
  13. #include "net_synctags.h"
  14. #include "dt_instrumentation_server.h"
  15. #include "LocalNetworkBackdoor.h"
  16. #include "ents_shared.h"
  17. #include "hltvserver.h"
  18. #if defined( REPLAY_ENABLED )
  19. #include "replayserver.h"
  20. #endif
  21. #include "framesnapshot.h"
  22. #include "changeframelist.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. extern ConVar g_CV_DTWatchEnt;
  26. //-----------------------------------------------------------------------------
  27. // Delta timing stuff.
  28. //-----------------------------------------------------------------------------
  29. static ConVar sv_deltatime( "sv_deltatime", "0", 0, "Enable profiling of CalcDelta calls" );
  30. static ConVar sv_deltaprint( "sv_deltaprint", "0", 0, "Print accumulated CalcDelta profiling data (only if sv_deltatime is on)" );
  31. #if defined( DEBUG_NETWORKING )
  32. ConVar sv_packettrace( "sv_packettrace", "1", 0, "For debugging, print entity creation/deletion info to console." );
  33. #endif
  34. class CChangeTrack
  35. {
  36. public:
  37. char *m_pName;
  38. int m_nChanged;
  39. int m_nUnchanged;
  40. CCycleCount m_Count;
  41. CCycleCount m_EncodeCount;
  42. };
  43. static CUtlLinkedList<CChangeTrack*, int> g_Tracks;
  44. // These are the main variables used by the SV_CreatePacketEntities function.
  45. // The function is split up into multiple smaller ones and they pass this structure around.
  46. class CEntityWriteInfo : public CEntityInfo
  47. {
  48. public:
  49. bf_write *m_pBuf;
  50. int m_nClientEntity;
  51. const PackedEntity *m_pOldPack;
  52. const PackedEntity *m_pNewPack;
  53. // For each entity handled in the to packet, mark that's it has already been deleted if that's the case
  54. CBitVec<MAX_EDICTS> m_DeletionFlags;
  55. CFrameSnapshot *m_pFromSnapshot; // = m_pFrom->GetSnapshot();
  56. CFrameSnapshot *m_pToSnapshot; // = m_pTo->GetSnapshot();
  57. CFrameSnapshot *m_pBaseline; // the clients baseline
  58. CBaseServer *m_pServer; // the server who writes this entity
  59. int m_nFullProps; // number of properties send as full update (Enter PVS)
  60. bool m_bCullProps; // filter props by clients in recipient lists
  61. /* Some profiling data
  62. int m_nTotalGap;
  63. int m_nTotalGapCount; */
  64. };
  65. //-----------------------------------------------------------------------------
  66. // Delta timing helpers.
  67. //-----------------------------------------------------------------------------
  68. CChangeTrack* GetChangeTrack( const char *pName )
  69. {
  70. FOR_EACH_LL( g_Tracks, i )
  71. {
  72. CChangeTrack *pCur = g_Tracks[i];
  73. if ( stricmp( pCur->m_pName, pName ) == 0 )
  74. return pCur;
  75. }
  76. CChangeTrack *pCur = new CChangeTrack;
  77. int len = strlen(pName)+1;
  78. pCur->m_pName = new char[len];
  79. Q_strncpy( pCur->m_pName, pName, len );
  80. pCur->m_nChanged = pCur->m_nUnchanged = 0;
  81. g_Tracks.AddToTail( pCur );
  82. return pCur;
  83. }
  84. void PrintChangeTracks()
  85. {
  86. ConMsg( "\n\n" );
  87. ConMsg( "------------------------------------------------------------------------\n" );
  88. ConMsg( "CalcDelta MS / %% time / Encode MS / # Changed / # Unchanged / Class Name\n" );
  89. ConMsg( "------------------------------------------------------------------------\n" );
  90. CCycleCount total, encodeTotal;
  91. FOR_EACH_LL( g_Tracks, i )
  92. {
  93. CChangeTrack *pCur = g_Tracks[i];
  94. CCycleCount::Add( pCur->m_Count, total, total );
  95. CCycleCount::Add( pCur->m_EncodeCount, encodeTotal, encodeTotal );
  96. }
  97. FOR_EACH_LL( g_Tracks, j )
  98. {
  99. CChangeTrack *pCur = g_Tracks[j];
  100. ConMsg( "%6.2fms %5.2f %6.2fms %4d %4d %s\n",
  101. pCur->m_Count.GetMillisecondsF(),
  102. pCur->m_Count.GetMillisecondsF() * 100.0f / total.GetMillisecondsF(),
  103. pCur->m_EncodeCount.GetMillisecondsF(),
  104. pCur->m_nChanged,
  105. pCur->m_nUnchanged,
  106. pCur->m_pName
  107. );
  108. }
  109. ConMsg( "\n\n" );
  110. ConMsg( "Total CalcDelta MS: %.2f\n\n", total.GetMillisecondsF() );
  111. ConMsg( "Total Encode MS: %.2f\n\n", encodeTotal.GetMillisecondsF() );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose: Entity wasn't dealt with in packet, but it has been deleted, we'll flag
  115. // the entity for destruction
  116. // Input : type -
  117. // entnum -
  118. // *from -
  119. // *to -
  120. // Output : Returns true on success, false on failure.
  121. //-----------------------------------------------------------------------------
  122. static inline bool SV_NeedsExplicitDestroy( int entnum, CFrameSnapshot *from, CFrameSnapshot *to )
  123. {
  124. // Never on uncompressed packet
  125. if( entnum >= to->m_nNumEntities || to->m_pEntities[entnum].m_pClass == NULL ) // doesn't exits in new
  126. {
  127. if ( entnum >= from->m_nNumEntities )
  128. return false; // didn't exist in old
  129. // in old, but not in new, destroy.
  130. if( from->m_pEntities[ entnum ].m_pClass != NULL )
  131. {
  132. return true;
  133. }
  134. }
  135. return false;
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose: Creates a delta header for the entity
  139. //-----------------------------------------------------------------------------
  140. static inline void SV_UpdateHeaderDelta(
  141. CEntityWriteInfo &u,
  142. int entnum )
  143. {
  144. // Profiling info
  145. // u.m_nTotalGap += entnum - u.m_nHeaderBase;
  146. // u.m_nTotalGapCount++;
  147. // Keep track of number of headers so we can tell the client
  148. u.m_nHeaderCount++;
  149. u.m_nHeaderBase = entnum;
  150. }
  151. //
  152. // Write the delta header. Also update the header delta info if bUpdateHeaderDelta is true.
  153. //
  154. // There are some cases where you want to tenatively write a header, then possibly back it out.
  155. // In these cases:
  156. // - pass in false for bUpdateHeaderDelta
  157. // - store the return value from SV_WriteDeltaHeader
  158. // - call SV_UpdateHeaderDelta ONLY if you want to keep the delta header it wrote
  159. //
  160. static inline void SV_WriteDeltaHeader(
  161. CEntityWriteInfo &u,
  162. int entnum,
  163. int flags )
  164. {
  165. bf_write *pBuf = u.m_pBuf;
  166. // int startbit = pBuf->GetNumBitsWritten();
  167. int offset = entnum - u.m_nHeaderBase - 1;
  168. Assert ( offset >= 0 );
  169. SyncTag_Write( u.m_pBuf, "Hdr" );
  170. pBuf->WriteUBitVar( offset );
  171. if ( flags & FHDR_LEAVEPVS )
  172. {
  173. pBuf->WriteOneBit( 1 ); // leave PVS bit
  174. pBuf->WriteOneBit( flags & FHDR_DELETE );
  175. }
  176. else
  177. {
  178. pBuf->WriteOneBit( 0 ); // delta or enter PVS
  179. pBuf->WriteOneBit( flags & FHDR_ENTERPVS );
  180. }
  181. SV_UpdateHeaderDelta( u, entnum );
  182. }
  183. ConVar sv_show_cull_props( "sv_show_cull_props", "0", FCVAR_RELEASE, "Print out props that are being culled/added by recipent proxies." );
  184. // NOTE: to optimize this, it could store the bit offsets of each property in the packed entity.
  185. // It would only have to store the offsets for the entities for each frame, since it only reaches
  186. // into the current frame's entities here.
  187. static inline void SV_WritePropsFromPackedEntity( CEntityWriteInfo &u, CalcDeltaResultsList_t &checkProps, CHLTVServer *hltv )
  188. {
  189. const PackedEntity * pTo = u.m_pNewPack;
  190. const PackedEntity * pFrom = u.m_pOldPack;
  191. SendTable *pSendTable = pTo->m_pServerClass->m_pTable;
  192. CServerDTITimer timer( pSendTable, SERVERDTI_WRITE_DELTA_PROPS );
  193. #if defined( REPLAY_ENABLED )
  194. if ( g_bServerDTIEnabled && !u.m_pServer->IsHLTV() && !u.m_pServer->IsReplay() )
  195. #else
  196. if ( g_bServerDTIEnabled && !u.m_pServer->IsHLTV() )
  197. #endif
  198. {
  199. ICollideable *pEnt = sv.edicts[pTo->m_nEntityIndex].GetCollideable();
  200. ICollideable *pClientEnt = sv.edicts[u.m_nClientEntity].GetCollideable();
  201. if ( pEnt && pClientEnt )
  202. {
  203. float flDist = (pEnt->GetCollisionOrigin() - pClientEnt->GetCollisionOrigin()).Length();
  204. ServerDTI_AddEntityEncodeEvent( pSendTable, flDist );
  205. }
  206. }
  207. SerializedEntityHandle_t toEntity = pTo->GetPackedData();
  208. Assert( toEntity != SERIALIZED_ENTITY_HANDLE_INVALID );
  209. // Cull out the properties that their proxies said not to send to this client.
  210. CalcDeltaResultsList_t sendProps;
  211. bf_write bufStart;
  212. // cull properties that are removed by SendProxies for this client.
  213. // don't do that for HLTV relay proxies
  214. if ( u.m_bCullProps )
  215. {
  216. SendTable_CullPropsFromProxies(
  217. pSendTable,
  218. checkProps,
  219. u.m_nClientEntity-1,
  220. pFrom->GetRecipients(),
  221. pFrom->GetNumRecipients(),
  222. pTo->GetRecipients(),
  223. pTo->GetNumRecipients(),
  224. sendProps
  225. );
  226. if ( sv_show_cull_props.GetBool() )
  227. {
  228. // find difference
  229. CalcDeltaResultsList_t culledProps;
  230. CalcDeltaResultsList_t addProps;
  231. FOR_EACH_VEC( checkProps, i )
  232. {
  233. if ( sendProps.Find( checkProps[i] ) == -1 )
  234. {
  235. culledProps.AddToTail( checkProps[i] );
  236. }
  237. }
  238. FOR_EACH_VEC( sendProps, i )
  239. {
  240. if ( checkProps.Find( sendProps[i] ) == -1 )
  241. {
  242. addProps.AddToTail( sendProps[i] );
  243. }
  244. }
  245. if ( culledProps.Count() || addProps.Count() )
  246. {
  247. Msg("CullPropsFromProxies for class %s, client=%d:\n", pSendTable->GetName(), u.m_nClientEntity - 1 );
  248. FOR_EACH_VEC( culledProps, i )
  249. {
  250. const SendProp *pProp = pSendTable->m_pPrecalc->GetProp( culledProps[i] );
  251. if ( pProp )
  252. {
  253. Msg(" CULL: %s type=%d\n", pProp->GetName(), (int)pProp->GetType() );
  254. }
  255. }
  256. FOR_EACH_VEC( addProps, i )
  257. {
  258. const SendProp *pProp = pSendTable->m_pPrecalc->GetProp( addProps[i] );
  259. if ( pProp )
  260. {
  261. Msg(" ADD: %s type=%d\n", pProp->GetName(), (int)pProp->GetType() );
  262. }
  263. }
  264. }
  265. }
  266. }
  267. else
  268. {
  269. // this is a HLTV relay proxy
  270. bufStart = *u.m_pBuf;
  271. sendProps.CopyArray( checkProps.Base(), checkProps.Count() );
  272. }
  273. SendTable_WritePropList(
  274. pSendTable,
  275. toEntity,
  276. u.m_pBuf,
  277. pTo->m_nEntityIndex,
  278. &sendProps
  279. );
  280. if ( !u.m_bCullProps )
  281. {
  282. if( hltv )
  283. {
  284. // this is a HLTV relay proxy, cache delta bits
  285. int nBits = u.m_pBuf->GetNumBitsWritten() - bufStart.GetNumBitsWritten();
  286. hltv->m_DeltaCache.AddDeltaBits( pTo->m_nEntityIndex, u.m_pFromSnapshot->m_nTickCount, nBits, &bufStart );
  287. }
  288. #if defined( REPLAY_ENABLED )
  289. if ( replay )
  290. {
  291. // this is a replay relay proxy, cache delta bits
  292. int nBits = u.m_pBuf->GetNumBitsWritten() - bufStart.GetNumBitsWritten();
  293. replay->m_DeltaCache.AddDeltaBits( pTo->m_nEntityIndex, u.m_pFromSnapshot->m_nTickCount, nBits, &bufStart );
  294. }
  295. #endif
  296. }
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Purpose: See if the entity needs a "hard" reset ( i.e., and explicit creation tag )
  300. // This should only occur if the entity slot deleted and re-created an entity faster than
  301. // the last two updates toa player. Should never or almost never occur. You never know though.
  302. // Input : type -
  303. // entnum -
  304. // *from -
  305. // *to -
  306. // Output : Returns true on success, false on failure.
  307. //-----------------------------------------------------------------------------
  308. static inline bool SV_NeedsExplicitCreate( CEntityWriteInfo &u )
  309. {
  310. // Never on uncompressed packet
  311. if ( !u.m_bAsDelta )
  312. {
  313. return false;
  314. }
  315. const int index = u.m_nNewEntity;
  316. if ( index >= u.m_pFromSnapshot->m_nNumEntities )
  317. return true; // entity didn't exist in old frame, so create
  318. // Server thinks the entity was continues, but the serial # changed, so we might need to destroy and recreate it
  319. const CFrameSnapshotEntry *pFromEnt = &u.m_pFromSnapshot->m_pEntities[index];
  320. const CFrameSnapshotEntry *pToEnt = &u.m_pToSnapshot->m_pEntities[index];
  321. bool bNeedsExplicitCreate = (pFromEnt->m_pClass == NULL) || pFromEnt->m_nSerialNumber != pToEnt->m_nSerialNumber;
  322. #ifdef _DEBUG
  323. if ( !bNeedsExplicitCreate )
  324. {
  325. // If it doesn't need explicit create, then the classnames should match.
  326. // This assert is analagous to the "Server / Client mismatch" one on the client.
  327. static int nWhines = 0;
  328. if ( pFromEnt->m_pClass->GetName() != pToEnt->m_pClass->GetName() )
  329. {
  330. if ( ++nWhines < 4 )
  331. {
  332. Msg( "ERROR in SV_NeedsExplicitCreate: ent %d from/to classname (%s/%s) mismatch.\n", u.m_nNewEntity, pFromEnt->m_pClass->GetName(), pToEnt->m_pClass->GetName() );
  333. }
  334. }
  335. }
  336. #endif
  337. return bNeedsExplicitCreate;
  338. }
  339. //given a packed entity, this will determine how many properties have a change flag, or -1 if there is no change flag set
  340. static int GetPackedEntityChangedProps( const PackedEntity* pEntity, int nTick, CalcDeltaResultsList_t& Results )
  341. {
  342. const CChangeFrameList* pChangeList = pEntity->GetChangeFrameList();
  343. if( !pChangeList )
  344. return -1;
  345. //note that this is called a LOT (by each client for each changed object) so performance is very important in here
  346. const int* RESTRICT pCurrBucket = pChangeList->GetBucketChangeTicks();
  347. const int* RESTRICT pEndBucket = pCurrBucket + pChangeList->GetNumBuckets();
  348. const int* RESTRICT pStartProps = pChangeList->GetChangeTicks();
  349. const int* RESTRICT pCurrProp = pStartProps;
  350. const int* RESTRICT pEndProps = pCurrProp + pChangeList->GetNumProps();
  351. //go through each bucket, which has the maximum tick count of the properties in its range
  352. for( ; pCurrBucket != pEndBucket; ++pCurrBucket )
  353. {
  354. //if the bucket hasn't changed since the time we care about, we can just ignore the bucket and carry on (big win! X props skipped with 1 check!)
  355. if( *pCurrBucket > nTick )
  356. {
  357. //we have a change in our bucket we need to find, so scan through each prop in the bucket range
  358. const int* RESTRICT pPropBucketEnd = MIN( pCurrProp + CChangeFrameList::knBucketSize, pEndProps );
  359. for( ; pCurrProp != pPropBucketEnd; ++pCurrProp )
  360. {
  361. if( *pCurrProp > nTick )
  362. Results.AddToTail( pCurrProp - pStartProps );
  363. }
  364. }
  365. else
  366. {
  367. //no changed props in our bucket, so skip ahead
  368. pCurrProp += CChangeFrameList::knBucketSize;
  369. }
  370. }
  371. return Results.Count();
  372. }
  373. static inline void SV_DetermineUpdateType( CEntityWriteInfo &u, CHLTVServer *hltv )
  374. {
  375. // Figure out how we want to update the entity.
  376. if( u.m_nNewEntity < u.m_nOldEntity )
  377. {
  378. // If the entity was not in the old packet (oldnum == 9999), then
  379. // delta from the baseline since this is a new entity.
  380. u.m_UpdateType = EnterPVS;
  381. return;
  382. }
  383. if( u.m_nNewEntity > u.m_nOldEntity )
  384. {
  385. // If the entity was in the old list, but is not in the new list
  386. // (newnum == 9999), then construct a special remove message.
  387. u.m_UpdateType = LeavePVS;
  388. return;
  389. }
  390. Assert( u.m_pToSnapshot->m_pEntities[ u.m_nNewEntity ].m_pClass );
  391. bool recreate = SV_NeedsExplicitCreate( u );
  392. if ( recreate )
  393. {
  394. u.m_UpdateType = EnterPVS;
  395. return;
  396. }
  397. // These should be the same! If they're not, then it should detect an explicit create message.
  398. Assert( u.m_pOldPack->m_pServerClass == u.m_pNewPack->m_pServerClass);
  399. // We can early out with the delta bits if we are using the same pack handles...
  400. if ( u.m_pOldPack == u.m_pNewPack )
  401. {
  402. Assert( u.m_pOldPack != NULL );
  403. u.m_UpdateType = PreserveEnt;
  404. return;
  405. }
  406. #ifndef _X360
  407. if ( !u.m_bCullProps )
  408. {
  409. int nBits = 0;
  410. Assert( u.m_pServer->IsHLTV() ); // because !u.m_bCullProps only happens when u.m_pServer->IsHLTV() AND sv is INactive, at least currently.So, replay should never play a role... ?
  411. unsigned char *pBuffer = hltv ? hltv->m_DeltaCache.FindDeltaBits( u.m_nNewEntity, u.m_pFromSnapshot->m_nTickCount, nBits ) :
  412. #if defined( REPLAY_ENABLED )
  413. replay ? replay->m_DeltaCache.FindDeltaBits( u.m_nNewEntity, u.m_pFromSnapshot->m_nTickCount, nBits ) :
  414. #else
  415. NULL;
  416. #endif
  417. if ( pBuffer )
  418. {
  419. if ( nBits > 0 )
  420. {
  421. // Write a header.
  422. SV_WriteDeltaHeader( u, u.m_nNewEntity, FHDR_ZERO );
  423. // just write the cached bit stream
  424. u.m_pBuf->WriteBits( pBuffer, nBits );
  425. u.m_UpdateType = DeltaEnt;
  426. }
  427. else
  428. {
  429. u.m_UpdateType = PreserveEnt;
  430. }
  431. return; // we used the cache, great
  432. }
  433. }
  434. #endif
  435. CalcDeltaResultsList_t checkProps;
  436. int nCheckProps = GetPackedEntityChangedProps( u.m_pNewPack, u.m_pFromSnapshot->m_nTickCount, checkProps );
  437. if ( nCheckProps == -1 )
  438. {
  439. // check failed, we have to recalc delta props based on from & to snapshot
  440. // that should happen only in HLTV/Replay demo playback mode, this code is really expensive
  441. SendTable_CalcDelta(
  442. u.m_pOldPack->m_pServerClass->m_pTable,
  443. u.m_pOldPack->GetPackedData(),
  444. u.m_pNewPack->GetPackedData(),
  445. u.m_nNewEntity, checkProps
  446. );
  447. }
  448. if ( nCheckProps > 0 )
  449. {
  450. // Write a header.
  451. SV_WriteDeltaHeader( u, u.m_nNewEntity, FHDR_ZERO );
  452. #if defined( DEBUG_NETWORKING )
  453. int startBit = u.m_pBuf->GetNumBitsWritten();
  454. #endif
  455. SV_WritePropsFromPackedEntity( u, checkProps, hltv );
  456. #if defined( DEBUG_NETWORKING )
  457. int endBit = u.m_pBuf->GetNumBitsWritten();
  458. TRACE_PACKET( ( " Delta Bits (%d) = %d (%d bytes)\n", u.m_nNewEntity, (endBit - startBit), ( (endBit - startBit) + 7 ) / 8 ) );
  459. #endif
  460. // If the numbers are the same, then the entity was in the old and new packet.
  461. // Just delta compress the differences.
  462. u.m_UpdateType = DeltaEnt;
  463. }
  464. else
  465. {
  466. #ifndef _X360
  467. if ( !u.m_bCullProps )
  468. {
  469. if ( hltv )
  470. {
  471. // no bits changed, PreserveEnt
  472. hltv->m_DeltaCache.AddDeltaBits( u.m_nNewEntity, u.m_pFromSnapshot->m_nTickCount, 0, NULL );
  473. }
  474. #if defined( REPLAY_ENABLED )
  475. if ( replay )
  476. {
  477. // no bits changed, PreserveEnt
  478. replay->m_DeltaCache.AddDeltaBits( u.m_nNewEntity, u.m_pFromSnapshot->m_nTickCount, 0, NULL );
  479. }
  480. #endif
  481. }
  482. #endif
  483. u.m_UpdateType = PreserveEnt;
  484. }
  485. }
  486. static inline ServerClass* GetEntServerClass(edict_t *pEdict)
  487. {
  488. return pEdict->GetNetworkable()->GetServerClass();
  489. }
  490. static inline void SV_WriteEnterPVS( CEntityWriteInfo &u )
  491. {
  492. TRACE_PACKET(( " SV Enter PVS (%d) %s\n", u.m_nNewEntity, u.m_pNewPack->m_pServerClass->m_pNetworkName ) );
  493. SV_WriteDeltaHeader( u, u.m_nNewEntity, FHDR_ENTERPVS );
  494. Assert( u.m_nNewEntity < u.m_pToSnapshot->m_nNumEntities );
  495. CFrameSnapshotEntry *entry = &u.m_pToSnapshot->m_pEntities[u.m_nNewEntity];
  496. ServerClass *pClass = entry->m_pClass;
  497. if ( !pClass )
  498. {
  499. Host_Error("SV_CreatePacketEntities: GetEntServerClass failed for ent %d.\n", u.m_nNewEntity);
  500. }
  501. TRACE_PACKET(( " SV Enter Class %s\n", pClass->m_pNetworkName ) );
  502. if ( pClass->m_ClassID >= u.m_pServer->serverclasses )
  503. {
  504. ConMsg( "pClass->m_ClassID(%i) >= %i\n", pClass->m_ClassID, u.m_pServer->serverclasses );
  505. Assert( 0 );
  506. }
  507. u.m_pBuf->WriteUBitLong( pClass->m_ClassID, u.m_pServer->serverclassbits );
  508. // Write some of the serial number's bits.
  509. u.m_pBuf->WriteUBitLong( entry->m_nSerialNumber, NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS );
  510. // Get the baseline.
  511. // Since the ent is in the fullpack, then it must have either a static or an instance baseline.
  512. PackedEntity *pBaseline = ( u.m_bAsDelta && u.m_pBaseline ) ? framesnapshotmanager->GetPackedEntity( *u.m_pBaseline, u.m_nNewEntity ) : NULL;
  513. SerializedEntityHandle_t fromEntity = SERIALIZED_ENTITY_HANDLE_INVALID;
  514. if ( pBaseline && (pBaseline->m_pServerClass == u.m_pNewPack->m_pServerClass) )
  515. {
  516. fromEntity = pBaseline->GetPackedData();
  517. }
  518. else
  519. {
  520. // Since the ent is in the fullpack, then it must have either a static or an instance baseline.
  521. if ( !u.m_pServer->GetClassBaseline( pClass, &fromEntity ) )
  522. {
  523. Error( "SV_WriteEnterPVS: missing instance baseline for '%s'.", pClass->m_pNetworkName );
  524. }
  525. ErrorIfNot( fromEntity != SERIALIZED_ENTITY_HANDLE_INVALID,
  526. ("SV_WriteEnterPVS: missing pFromData for '%s'.", pClass->m_pNetworkName)
  527. );
  528. }
  529. if ( u.m_pTo->from_baseline )
  530. {
  531. // remember that we sent this entity as full update from entity baseline
  532. u.m_pTo->from_baseline->Set( u.m_nNewEntity );
  533. }
  534. SerializedEntityHandle_t toEntity = u.m_pNewPack->GetPackedData();
  535. Assert( SERIALIZED_ENTITY_HANDLE_INVALID != toEntity );
  536. // send all changed properties when entering PVS (no SendProxy culling since we may use it as baseline
  537. u.m_nFullProps += SendTable_WriteAllDeltaProps( pClass->m_pTable, fromEntity, toEntity, u.m_pNewPack->m_nEntityIndex, u.m_pBuf );
  538. if ( u.m_nNewEntity == u.m_nOldEntity )
  539. u.NextOldEntity(); // this was a entity recreate
  540. u.NextNewEntity();
  541. }
  542. static inline void SV_WriteLeavePVS( CEntityWriteInfo &u )
  543. {
  544. int headerflags = FHDR_LEAVEPVS;
  545. bool deleteentity = false;
  546. if ( u.m_bAsDelta )
  547. {
  548. deleteentity = SV_NeedsExplicitDestroy( u.m_nOldEntity, u.m_pFromSnapshot, u.m_pToSnapshot );
  549. }
  550. if ( deleteentity )
  551. {
  552. // Mark that we handled deletion of this index
  553. u.m_DeletionFlags.Set( u.m_nOldEntity );
  554. headerflags |= FHDR_DELETE;
  555. }
  556. TRACE_PACKET( ( " SV Leave PVS (%d) %s %s\n", u.m_nOldEntity,
  557. deleteentity ? "deleted" : "left pvs",
  558. u.m_pOldPack->m_pServerClass->m_pNetworkName ) );
  559. SV_WriteDeltaHeader( u, u.m_nOldEntity, headerflags );
  560. u.NextOldEntity();
  561. }
  562. static inline void SV_WriteDeltaEnt( CEntityWriteInfo &u )
  563. {
  564. TRACE_PACKET( ( " SV Delta PVS (%d %d) %s\n", u.m_nNewEntity, u.m_nOldEntity, u.m_pOldPack->m_pServerClass->m_pNetworkName ) );
  565. // NOTE: it was already written in DetermineUpdateType. By doing it this way, we avoid an expensive
  566. // (non-byte-aligned) copy of the data.
  567. u.NextOldEntity();
  568. u.NextNewEntity();
  569. }
  570. static inline void SV_PreserveEnt( CEntityWriteInfo &u )
  571. {
  572. TRACE_PACKET( ( " SV Preserve PVS (%d) %s\n", u.m_nOldEntity, u.m_pOldPack->m_pServerClass->m_pNetworkName ) );
  573. // updateType is preserveEnt. The client will detect this because our next entity will have a newnum
  574. // that is greater than oldnum, in which case the client just keeps the current entity alive.
  575. u.NextOldEntity();
  576. u.NextNewEntity();
  577. }
  578. static inline void SV_WriteEntityUpdate( CEntityWriteInfo &u )
  579. {
  580. switch( u.m_UpdateType )
  581. {
  582. case EnterPVS:
  583. {
  584. SV_WriteEnterPVS( u );
  585. }
  586. break;
  587. case LeavePVS:
  588. {
  589. SV_WriteLeavePVS( u );
  590. }
  591. break;
  592. case DeltaEnt:
  593. {
  594. SV_WriteDeltaEnt( u );
  595. }
  596. break;
  597. case PreserveEnt:
  598. {
  599. SV_PreserveEnt( u );
  600. }
  601. break;
  602. }
  603. }
  604. static inline int SV_WriteDeletions( CEntityWriteInfo &u )
  605. {
  606. if( !u.m_bAsDelta )
  607. return 0;
  608. CFrameSnapshot *pFromSnapShot = u.m_pFromSnapshot;
  609. CFrameSnapshot *pToSnapShot = u.m_pToSnapshot;
  610. CUtlVector< int > deletions;
  611. int nLast = MAX( pFromSnapShot->m_nNumEntities, pToSnapShot->m_nNumEntities );
  612. for ( int i = 0; i < nLast; i++ )
  613. {
  614. // Packet update didn't clear it out expressly
  615. if ( u.m_DeletionFlags.Get( i ) )
  616. continue;
  617. // Looks like it should be gone
  618. bool bNeedsExplicitDelete = SV_NeedsExplicitDestroy( i, pFromSnapShot, pToSnapShot );
  619. if ( !bNeedsExplicitDelete && u.m_pTo )
  620. {
  621. bNeedsExplicitDelete = (pToSnapShot->m_iExplicitDeleteSlots.Find(i) != pToSnapShot->m_iExplicitDeleteSlots.InvalidIndex() );
  622. if ( bNeedsExplicitDelete )
  623. {
  624. const CFrameSnapshotEntry *pFromEnt = ( i < pFromSnapShot->m_nNumEntities ) ? &pFromSnapShot->m_pEntities[i] : NULL;
  625. const CFrameSnapshotEntry *pToEnt = ( i < pToSnapShot->m_nNumEntities ) ? &pToSnapShot->m_pEntities[i] : NULL;
  626. if ( pFromEnt && pToEnt )
  627. {
  628. bool bWillBeExplicitlyCreated = (pFromEnt->m_pClass == NULL) || pFromEnt->m_nSerialNumber != pToEnt->m_nSerialNumber;
  629. if ( bWillBeExplicitlyCreated && u.m_pTo->transmit_entity.Get(i) )
  630. {
  631. //Warning("Entity %d is being explicitly deleted, but it will be explicitly created.\n", i );
  632. bNeedsExplicitDelete = false;
  633. }
  634. else
  635. {
  636. //Warning("Entity %d is being explicitly deleted.\n", i );
  637. }
  638. }
  639. }
  640. }
  641. // Check conditions
  642. if ( bNeedsExplicitDelete )
  643. {
  644. TRACE_PACKET( ( " SV Explicit Destroy (%d)\n", i ) );
  645. Assert( !u.m_pTo->transmit_entity.Get(i) );
  646. deletions.AddToTail( i );
  647. }
  648. }
  649. u.m_pBuf->WriteUBitVar( deletions.Count() );
  650. int nBase = -1;
  651. FOR_EACH_VEC( deletions, i )
  652. {
  653. int nSlot = deletions[ i ];
  654. int nDelta = nSlot - nBase;
  655. u.m_pBuf->WriteUBitVar( nDelta );
  656. nBase = nSlot;
  657. }
  658. return deletions.Count();
  659. }
  660. //internal implementation of writing the delta entities. This takes a buffer to use for writing the message to, in order to handle variable sized buffers more efficiently, and will return whether or not the message was able to fit into the
  661. //provided buffer or not
  662. static bool InternalWriteDeltaEntities( CBaseServer* pServer, CBaseClient *client, CClientFrame *to, CClientFrame *from, CSVCMsg_PacketEntities_t &msg, uint8* pScratchBuffer, uint32 nScratchBufferSize )
  663. {
  664. VPROF_BUDGET( "WriteDeltaEntities", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  665. msg.Clear();
  666. // allocate the temp buffer for the packet ents
  667. bf_write entity_data_buf( pScratchBuffer, nScratchBufferSize );
  668. //note that we can intentionally overflow in certain cases, so turn off asserts
  669. entity_data_buf.SetAssertOnOverflow( false );
  670. // Setup the CEntityWriteInfo structure.
  671. CEntityWriteInfo u;
  672. u.m_pBuf = &entity_data_buf;
  673. u.m_pTo = to;
  674. u.m_pToSnapshot = to->GetSnapshot();
  675. u.m_pBaseline = client->m_pBaseline;
  676. u.m_nFullProps = 0;
  677. u.m_pServer = pServer;
  678. u.m_nClientEntity = client->GetPropCullClient()->m_nEntityIndex;
  679. CHLTVServer *hltv = pServer->IsHLTV() ? static_cast< CHLTVServer* >( pServer ) : NULL;
  680. #ifndef _XBOX
  681. #if defined( REPLAY_ENABLED )
  682. if ( hltv || pServer->IsReplay() )
  683. #else
  684. if ( hltv )
  685. #endif
  686. {
  687. // cull props only on master proxy
  688. u.m_bCullProps = sv.IsActive();
  689. }
  690. else
  691. #endif
  692. {
  693. u.m_bCullProps = true; // always cull props for players
  694. }
  695. if ( from != NULL )
  696. {
  697. u.m_bAsDelta = true;
  698. u.m_pFrom = from;
  699. u.m_pFromSnapshot = from->GetSnapshot();
  700. Assert( u.m_pFromSnapshot );
  701. }
  702. else
  703. {
  704. u.m_bAsDelta = false;
  705. u.m_pFrom = NULL;
  706. u.m_pFromSnapshot = NULL;
  707. }
  708. u.m_nHeaderCount = 0;
  709. // Write the header, TODO use class SVC_PacketEntities
  710. TRACE_PACKET(( "WriteDeltaEntities (%d)\n", u.m_pToSnapshot->m_nNumEntities ));
  711. msg.set_max_entries( u.m_pToSnapshot->m_nNumEntities );
  712. msg.set_is_delta( u.m_bAsDelta );
  713. if ( u.m_bAsDelta )
  714. {
  715. msg.set_delta_from( u.m_pFrom->tick_count ); // This is the sequence # that we are updating from.
  716. }
  717. msg.set_baseline( client->m_nBaselineUsed );
  718. #ifndef NO_SERVER_NET
  719. // Don't work too hard if we're using the optimized single-player mode.
  720. if ( !g_pLocalNetworkBackdoor )
  721. {
  722. // Iterate through the in PVS bitfields until we find an entity
  723. // that was either in the old pack or the new pack
  724. u.NextOldEntity();
  725. u.NextNewEntity();
  726. while ( (u.m_nOldEntity != ENTITY_SENTINEL) || (u.m_nNewEntity != ENTITY_SENTINEL) )
  727. {
  728. u.m_pNewPack = (u.m_nNewEntity != ENTITY_SENTINEL) ? framesnapshotmanager->GetPackedEntity( *u.m_pToSnapshot, u.m_nNewEntity ) : NULL;
  729. u.m_pOldPack = (u.m_nOldEntity != ENTITY_SENTINEL) ? framesnapshotmanager->GetPackedEntity( *u.m_pFromSnapshot, u.m_nOldEntity ) : NULL;
  730. // Figure out how we want to write this entity.
  731. SV_DetermineUpdateType( u, hltv );
  732. SV_WriteEntityUpdate( u );
  733. }
  734. // Now write out the express deletions
  735. SV_WriteDeletions( u );
  736. }
  737. #endif //NO_SERVER_NET
  738. msg.set_updated_entries( u.m_nHeaderCount );
  739. if( u.m_pBuf->IsOverflowed() )
  740. {
  741. return false;
  742. }
  743. // resize the buffer to the actual byte size
  744. int nBytesWritten = Bits2Bytes( u.m_pBuf->GetNumBitsWritten() );
  745. msg.mutable_entity_data()->assign( (const char*)pScratchBuffer, nBytesWritten);
  746. bool bUpdateBaseline = ( (client->m_nBaselineUpdateTick == -1) &&
  747. (u.m_nFullProps > 0 || !u.m_bAsDelta) );
  748. if ( bUpdateBaseline && u.m_pBaseline )
  749. {
  750. // tell client to use this snapshot as baseline update
  751. msg.set_update_baseline( true );
  752. client->m_nBaselineUpdateTick = to->tick_count;
  753. }
  754. else
  755. {
  756. msg.set_update_baseline( false );
  757. }
  758. return true;
  759. }
  760. /*
  761. =============
  762. WritePacketEntities
  763. Computes either a compressed, or uncompressed delta buffer for the client.
  764. Returns the size IN BITS of the message buffer created.
  765. =============
  766. */
  767. static ConVar sv_delta_entity_buffer_size( "sv_delta_entity_full_buffer_size", "196608", 0, "Buffer size for delta entities" );
  768. void CBaseServer::WriteDeltaEntities( CBaseClient *client, CClientFrame *to, CClientFrame *from, CSVCMsg_PacketEntities_t &msg )
  769. {
  770. // set from_baseline pointer if this snapshot may become a baseline update
  771. if ( client->m_nBaselineUpdateTick == -1 )
  772. {
  773. client->m_BaselinesSent.ClearAll();
  774. to->from_baseline = &client->m_BaselinesSent;
  775. }
  776. net_scratchbuffer_t scratch;
  777. int nScratchUseSize = MIN( scratch.Size(), sv_delta_entity_buffer_size.GetInt() );
  778. bool bFitIntoBuffer = InternalWriteDeltaEntities( this, client, to, from, msg, scratch.GetBuffer(), nScratchUseSize );
  779. if( !bFitIntoBuffer )
  780. {
  781. static double s_dblLastWriteDeltaEntitiesError = 0;
  782. double dblPlatFloatTime = Plat_FloatTime();
  783. if ( dblPlatFloatTime > s_dblLastWriteDeltaEntitiesError + 10 )
  784. {
  785. s_dblLastWriteDeltaEntitiesError = dblPlatFloatTime;
  786. Warning( "Cannot write delta entity message for client %s<%i><%s>, try increasing sv_delta_entity_full_buffer_size\n", client->GetClientName(), client->m_nEntityIndex, client->GetNetworkIDString() );
  787. }
  788. //perform overflow handling here
  789. AssertMsg1( bFitIntoBuffer, "Error: Unable to fit a delta entity message into the %d bytes. Try upping the variable sv_delta_entity_full_buffer_size.", nScratchUseSize );
  790. }
  791. }