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.

847 lines
26 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "usercmd.h"
  9. #include "igamesystem.h"
  10. #include "ilagcompensationmanager.h"
  11. #include "inetchannelinfo.h"
  12. #include "utllinkedlist.h"
  13. #include "BaseAnimatingOverlay.h"
  14. #include "tier0/vprof.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. #define LC_NONE 0
  18. #define LC_ALIVE (1<<0)
  19. #define LC_ORIGIN_CHANGED (1<<8)
  20. #define LC_ANGLES_CHANGED (1<<9)
  21. #define LC_SIZE_CHANGED (1<<10)
  22. #define LC_ANIMATION_CHANGED (1<<11)
  23. static ConVar sv_lagcompensation_teleport_dist( "sv_lagcompensation_teleport_dist", "64", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, "How far a player got moved by game code before we can't lag compensate their position back" );
  24. #define LAG_COMPENSATION_EPS_SQR ( 0.1f * 0.1f )
  25. // Allow 4 units of error ( about 1 / 8 bbox width )
  26. #define LAG_COMPENSATION_ERROR_EPS_SQR ( 4.0f * 4.0f )
  27. ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" );
  28. ConVar sv_maxunlag( "sv_maxunlag", "1.0", FCVAR_DEVELOPMENTONLY, "Maximum lag compensation in seconds", true, 0.0f, true, 1.0f );
  29. ConVar sv_lagflushbonecache( "sv_lagflushbonecache", "1", FCVAR_DEVELOPMENTONLY, "Flushes entity bone cache on lag compensation" );
  30. ConVar sv_showlagcompensation( "sv_showlagcompensation", "0", FCVAR_CHEAT, "Show lag compensated hitboxes whenever a player is lag compensated." );
  31. ConVar sv_unlag_fixstuck( "sv_unlag_fixstuck", "0", FCVAR_DEVELOPMENTONLY, "Disallow backtracking a player for lag compensation if it will cause them to become stuck" );
  32. //-----------------------------------------------------------------------------
  33. // Purpose:
  34. //-----------------------------------------------------------------------------
  35. #define MAX_LAYER_RECORDS (CBaseAnimatingOverlay::MAX_OVERLAYS)
  36. struct LayerRecord
  37. {
  38. int m_sequence;
  39. float m_cycle;
  40. float m_weight;
  41. int m_order;
  42. LayerRecord()
  43. {
  44. m_sequence = 0;
  45. m_cycle = 0;
  46. m_weight = 0;
  47. m_order = 0;
  48. }
  49. LayerRecord( const LayerRecord& src )
  50. {
  51. m_sequence = src.m_sequence;
  52. m_cycle = src.m_cycle;
  53. m_weight = src.m_weight;
  54. m_order = src.m_order;
  55. }
  56. };
  57. struct LagRecord
  58. {
  59. public:
  60. LagRecord()
  61. {
  62. m_fFlags = 0;
  63. m_vecOrigin.Init();
  64. m_vecAngles.Init();
  65. m_vecMinsPreScaled.Init();
  66. m_vecMaxsPreScaled.Init();
  67. m_flSimulationTime = -1;
  68. m_masterSequence = 0;
  69. m_masterCycle = 0;
  70. }
  71. LagRecord( const LagRecord& src )
  72. {
  73. m_fFlags = src.m_fFlags;
  74. m_vecOrigin = src.m_vecOrigin;
  75. m_vecAngles = src.m_vecAngles;
  76. m_vecMinsPreScaled = src.m_vecMinsPreScaled;
  77. m_vecMaxsPreScaled = src.m_vecMaxsPreScaled;
  78. m_flSimulationTime = src.m_flSimulationTime;
  79. for( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex )
  80. {
  81. m_layerRecords[layerIndex] = src.m_layerRecords[layerIndex];
  82. }
  83. m_masterSequence = src.m_masterSequence;
  84. m_masterCycle = src.m_masterCycle;
  85. }
  86. // Did player die this frame
  87. int m_fFlags;
  88. // Player position, orientation and bbox
  89. Vector m_vecOrigin;
  90. QAngle m_vecAngles;
  91. Vector m_vecMinsPreScaled;
  92. Vector m_vecMaxsPreScaled;
  93. float m_flSimulationTime;
  94. // Player animation details, so we can get the legs in the right spot.
  95. LayerRecord m_layerRecords[MAX_LAYER_RECORDS];
  96. int m_masterSequence;
  97. float m_masterCycle;
  98. };
  99. //
  100. // Try to take the player from his current origin to vWantedPos.
  101. // If it can't get there, leave the player where he is.
  102. //
  103. ConVar sv_unlag_debug( "sv_unlag_debug", "0", FCVAR_GAMEDLL | FCVAR_DEVELOPMENTONLY );
  104. float g_flFractionScale = 0.95;
  105. static void RestorePlayerTo( CBasePlayer *pPlayer, const Vector &vWantedPos )
  106. {
  107. // Try to move to the wanted position from our current position.
  108. trace_t tr;
  109. VPROF_BUDGET( "RestorePlayerTo", "CLagCompensationManager" );
  110. UTIL_TraceEntity( pPlayer, vWantedPos, vWantedPos, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
  111. if ( tr.startsolid || tr.allsolid )
  112. {
  113. if ( sv_unlag_debug.GetBool() )
  114. {
  115. DevMsg( "RestorePlayerTo() could not restore player position for client \"%s\" ( %.1f %.1f %.1f )\n",
  116. pPlayer->GetPlayerName(), vWantedPos.x, vWantedPos.y, vWantedPos.z );
  117. }
  118. UTIL_TraceEntity( pPlayer, pPlayer->GetLocalOrigin(), vWantedPos, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
  119. if ( tr.startsolid || tr.allsolid )
  120. {
  121. // In this case, the guy got stuck back wherever we lag compensated him to. Nasty.
  122. if ( sv_unlag_debug.GetBool() )
  123. DevMsg( " restore failed entirely\n" );
  124. }
  125. else
  126. {
  127. // We can get to a valid place, but not all the way back to where we were.
  128. Vector vPos;
  129. VectorLerp( pPlayer->GetLocalOrigin(), vWantedPos, tr.fraction * g_flFractionScale, vPos );
  130. UTIL_SetOrigin( pPlayer, vPos, true );
  131. if ( sv_unlag_debug.GetBool() )
  132. DevMsg( " restore got most of the way\n" );
  133. }
  134. }
  135. else
  136. {
  137. // Cool, the player can go back to whence he came.
  138. UTIL_SetOrigin( pPlayer, tr.endpos, true );
  139. }
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose:
  143. //-----------------------------------------------------------------------------
  144. class CLagCompensationManager : public CAutoGameSystemPerFrame, public ILagCompensationManager
  145. {
  146. public:
  147. CLagCompensationManager( char const *name ) : CAutoGameSystemPerFrame( name ), m_flTeleportDistanceSqr( 64 *64 )
  148. {
  149. m_isCurrentlyDoingCompensation = false;
  150. }
  151. // IServerSystem stuff
  152. virtual void Shutdown()
  153. {
  154. ClearHistory();
  155. }
  156. virtual void LevelShutdownPostEntity()
  157. {
  158. ClearHistory();
  159. }
  160. // called after entities think
  161. virtual void FrameUpdatePostEntityThink();
  162. // ILagCompensationManager stuff
  163. // Called during player movement to set up/restore after lag compensation
  164. void StartLagCompensation( CBasePlayer *player, CUserCmd *cmd );
  165. void FinishLagCompensation( CBasePlayer *player );
  166. bool IsCurrentlyDoingLagCompensation() const OVERRIDE { return m_isCurrentlyDoingCompensation; }
  167. private:
  168. void BacktrackPlayer( CBasePlayer *player, float flTargetTime );
  169. void ClearHistory()
  170. {
  171. for ( int i=0; i<MAX_PLAYERS; i++ )
  172. m_PlayerTrack[i].Purge();
  173. }
  174. // keep a list of lag records for each player
  175. CUtlFixedLinkedList< LagRecord > m_PlayerTrack[ MAX_PLAYERS ];
  176. // Scratchpad for determining what needs to be restored
  177. CBitVec<MAX_PLAYERS> m_RestorePlayer;
  178. bool m_bNeedToRestore;
  179. LagRecord m_RestoreData[ MAX_PLAYERS ]; // player data before we moved him back
  180. LagRecord m_ChangeData[ MAX_PLAYERS ]; // player data where we moved him back
  181. CBasePlayer *m_pCurrentPlayer; // The player we are doing lag compensation for
  182. float m_flTeleportDistanceSqr;
  183. bool m_isCurrentlyDoingCompensation; // Sentinel to prevent calling StartLagCompensation a second time before a Finish.
  184. };
  185. static CLagCompensationManager g_LagCompensationManager( "CLagCompensationManager" );
  186. ILagCompensationManager *lagcompensation = &g_LagCompensationManager;
  187. //-----------------------------------------------------------------------------
  188. // Purpose: Called once per frame after all entities have had a chance to think
  189. //-----------------------------------------------------------------------------
  190. void CLagCompensationManager::FrameUpdatePostEntityThink()
  191. {
  192. if ( (gpGlobals->maxClients <= 1) || !sv_unlag.GetBool() )
  193. {
  194. ClearHistory();
  195. return;
  196. }
  197. m_flTeleportDistanceSqr = sv_lagcompensation_teleport_dist.GetFloat() * sv_lagcompensation_teleport_dist.GetFloat();
  198. VPROF_BUDGET( "FrameUpdatePostEntityThink", "CLagCompensationManager" );
  199. // remove all records before that time:
  200. int flDeadtime = gpGlobals->curtime - sv_maxunlag.GetFloat();
  201. // Iterate all active players
  202. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  203. {
  204. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  205. CUtlFixedLinkedList< LagRecord > *track = &m_PlayerTrack[i-1];
  206. if ( !pPlayer )
  207. {
  208. if ( track->Count() > 0 )
  209. {
  210. track->RemoveAll();
  211. }
  212. continue;
  213. }
  214. Assert( track->Count() < 1000 ); // insanity check
  215. // remove tail records that are too old
  216. int tailIndex = track->Tail();
  217. while ( track->IsValidIndex( tailIndex ) )
  218. {
  219. LagRecord &tail = track->Element( tailIndex );
  220. // if tail is within limits, stop
  221. if ( tail.m_flSimulationTime >= flDeadtime )
  222. break;
  223. // remove tail, get new tail
  224. track->Remove( tailIndex );
  225. tailIndex = track->Tail();
  226. }
  227. // check if head has same simulation time
  228. if ( track->Count() > 0 )
  229. {
  230. LagRecord &head = track->Element( track->Head() );
  231. // check if player changed simulation time since last time updated
  232. if ( head.m_flSimulationTime >= pPlayer->GetSimulationTime() )
  233. continue; // don't add new entry for same or older time
  234. }
  235. // add new record to player track
  236. LagRecord &record = track->Element( track->AddToHead() );
  237. record.m_fFlags = 0;
  238. if ( pPlayer->IsAlive() )
  239. {
  240. record.m_fFlags |= LC_ALIVE;
  241. }
  242. record.m_flSimulationTime = pPlayer->GetSimulationTime();
  243. record.m_vecAngles = pPlayer->GetLocalAngles();
  244. record.m_vecOrigin = pPlayer->GetLocalOrigin();
  245. record.m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled();
  246. record.m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled();
  247. int layerCount = pPlayer->GetNumAnimOverlays();
  248. for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
  249. {
  250. CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex);
  251. if( currentLayer )
  252. {
  253. record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle;
  254. record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder;
  255. record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence;
  256. record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight;
  257. }
  258. }
  259. record.m_masterSequence = pPlayer->GetSequence();
  260. record.m_masterCycle = pPlayer->GetCycle();
  261. }
  262. //Clear the current player.
  263. m_pCurrentPlayer = NULL;
  264. }
  265. // Called during player movement to set up/restore after lag compensation
  266. void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCmd *cmd )
  267. {
  268. Assert( !m_isCurrentlyDoingCompensation );
  269. //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS
  270. //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG
  271. if ( m_pCurrentPlayer )
  272. {
  273. Assert( m_pCurrentPlayer == NULL );
  274. Warning( "Trying to start a new lag compensation session while one is already active!\n" );
  275. return;
  276. }
  277. // Assume no players need to be restored
  278. m_RestorePlayer.ClearAll();
  279. m_bNeedToRestore = false;
  280. m_pCurrentPlayer = player;
  281. if ( !player->m_bLagCompensation // Player not wanting lag compensation
  282. || (gpGlobals->maxClients <= 1) // no lag compensation in single player
  283. || !sv_unlag.GetBool() // disabled by server admin
  284. || player->IsBot() // not for bots
  285. || player->IsObserver() // not for spectators
  286. )
  287. return;
  288. // NOTE: Put this here so that it won't show up in single player mode.
  289. VPROF_BUDGET( "StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  290. Q_memset( m_RestoreData, 0, sizeof( m_RestoreData ) );
  291. Q_memset( m_ChangeData, 0, sizeof( m_ChangeData ) );
  292. m_isCurrentlyDoingCompensation = true;
  293. // Get true latency
  294. // correct is the amout of time we have to correct game time
  295. float correct = 0.0f;
  296. INetChannelInfo *nci = engine->GetPlayerNetInfo( player->entindex() );
  297. if ( nci )
  298. {
  299. // add network latency
  300. correct+= nci->GetLatency( FLOW_OUTGOING );
  301. }
  302. // calc number of view interpolation ticks - 1
  303. int lerpTicks = TIME_TO_TICKS( player->m_fLerpTime );
  304. // add view interpolation latency see C_BaseEntity::GetInterpolationAmount()
  305. correct += TICKS_TO_TIME( lerpTicks );
  306. // check bouns [0,sv_maxunlag]
  307. correct = clamp( correct, 0.0f, sv_maxunlag.GetFloat() );
  308. // correct tick send by player
  309. int targettick = cmd->tick_count - lerpTicks;
  310. // calc difference between tick send by player and our latency based tick
  311. float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick);
  312. if ( fabs( deltaTime ) > 0.2f )
  313. {
  314. // difference between cmd time and latency is too big > 200ms, use time correction based on latency
  315. // DevMsg("StartLagCompensation: delta too big (%.3f)\n", deltaTime );
  316. targettick = gpGlobals->tickcount - TIME_TO_TICKS( correct );
  317. }
  318. // Iterate all active players
  319. const CBitVec<MAX_EDICTS> *pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 );
  320. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  321. {
  322. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  323. if ( !pPlayer )
  324. {
  325. continue;
  326. }
  327. // Don't lag compensate yourself you loser...
  328. if ( player == pPlayer )
  329. {
  330. continue;
  331. }
  332. // Custom checks for if things should lag compensate (based on things like what team the player is on).
  333. if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) )
  334. continue;
  335. // Move other player back in time
  336. BacktrackPlayer( pPlayer, TICKS_TO_TIME( targettick ) );
  337. }
  338. }
  339. void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTargetTime )
  340. {
  341. Vector org;
  342. Vector minsPreScaled;
  343. Vector maxsPreScaled;
  344. QAngle ang;
  345. VPROF_BUDGET( "BacktrackPlayer", "CLagCompensationManager" );
  346. int pl_index = pPlayer->entindex() - 1;
  347. // get track history of this player
  348. CUtlFixedLinkedList< LagRecord > *track = &m_PlayerTrack[ pl_index ];
  349. // check if we have at leat one entry
  350. if ( track->Count() <= 0 )
  351. return;
  352. int curr = track->Head();
  353. LagRecord *prevRecord = NULL;
  354. LagRecord *record = NULL;
  355. Vector prevOrg = pPlayer->GetLocalOrigin();
  356. // Walk context looking for any invalidating event
  357. while( track->IsValidIndex(curr) )
  358. {
  359. // remember last record
  360. prevRecord = record;
  361. // get next record
  362. record = &track->Element( curr );
  363. if ( !(record->m_fFlags & LC_ALIVE) )
  364. {
  365. // player most be alive, lost track
  366. return;
  367. }
  368. Vector delta = record->m_vecOrigin - prevOrg;
  369. if ( delta.Length2DSqr() > m_flTeleportDistanceSqr )
  370. {
  371. // lost track, too much difference
  372. return;
  373. }
  374. // did we find a context smaller than target time ?
  375. if ( record->m_flSimulationTime <= flTargetTime )
  376. break; // hurra, stop
  377. prevOrg = record->m_vecOrigin;
  378. // go one step back
  379. curr = track->Next( curr );
  380. }
  381. Assert( record );
  382. if ( !record )
  383. {
  384. if ( sv_unlag_debug.GetBool() )
  385. {
  386. DevMsg( "No valid positions in history for BacktrackPlayer client ( %s )\n", pPlayer->GetPlayerName() );
  387. }
  388. return; // that should never happen
  389. }
  390. float frac = 0.0f;
  391. if ( prevRecord &&
  392. (record->m_flSimulationTime < flTargetTime) &&
  393. (record->m_flSimulationTime < prevRecord->m_flSimulationTime) )
  394. {
  395. // we didn't find the exact time but have a valid previous record
  396. // so interpolate between these two records;
  397. Assert( prevRecord->m_flSimulationTime > record->m_flSimulationTime );
  398. Assert( flTargetTime < prevRecord->m_flSimulationTime );
  399. // calc fraction between both records
  400. frac = ( flTargetTime - record->m_flSimulationTime ) /
  401. ( prevRecord->m_flSimulationTime - record->m_flSimulationTime );
  402. Assert( frac > 0 && frac < 1 ); // should never extrapolate
  403. ang = Lerp( frac, record->m_vecAngles, prevRecord->m_vecAngles );
  404. org = Lerp( frac, record->m_vecOrigin, prevRecord->m_vecOrigin );
  405. minsPreScaled = Lerp( frac, record->m_vecMinsPreScaled, prevRecord->m_vecMinsPreScaled );
  406. maxsPreScaled = Lerp( frac, record->m_vecMaxsPreScaled, prevRecord->m_vecMaxsPreScaled );
  407. }
  408. else
  409. {
  410. // we found the exact record or no other record to interpolate with
  411. // just copy these values since they are the best we have
  412. org = record->m_vecOrigin;
  413. ang = record->m_vecAngles;
  414. minsPreScaled = record->m_vecMinsPreScaled;
  415. maxsPreScaled = record->m_vecMaxsPreScaled;
  416. }
  417. // See if this is still a valid position for us to teleport to
  418. if ( sv_unlag_fixstuck.GetBool() )
  419. {
  420. // Try to move to the wanted position from our current position.
  421. trace_t tr;
  422. UTIL_TraceEntity( pPlayer, org, org, MASK_PLAYERSOLID, &tr );
  423. if ( tr.startsolid || tr.allsolid )
  424. {
  425. if ( sv_unlag_debug.GetBool() )
  426. DevMsg( "WARNING: BackupPlayer trying to back player into a bad position - client %s\n", pPlayer->GetPlayerName() );
  427. CBasePlayer *pHitPlayer = dynamic_cast<CBasePlayer *>( tr.m_pEnt );
  428. // don't lag compensate the current player
  429. if ( pHitPlayer && ( pHitPlayer != m_pCurrentPlayer ) )
  430. {
  431. // If we haven't backtracked this player, do it now
  432. // this deliberately ignores WantsLagCompensationOnEntity.
  433. if ( !m_RestorePlayer.Get( pHitPlayer->entindex() - 1 ) )
  434. {
  435. // prevent recursion - save a copy of m_RestorePlayer,
  436. // pretend that this player is off-limits
  437. int pl_index = pPlayer->entindex() - 1;
  438. // Temp turn this flag on
  439. m_RestorePlayer.Set( pl_index );
  440. BacktrackPlayer( pHitPlayer, flTargetTime );
  441. // Remove the temp flag
  442. m_RestorePlayer.Clear( pl_index );
  443. }
  444. }
  445. // now trace us back as far as we can go
  446. UTIL_TraceEntity( pPlayer, pPlayer->GetLocalOrigin(), org, MASK_PLAYERSOLID, &tr );
  447. if ( tr.startsolid || tr.allsolid )
  448. {
  449. // Our starting position is bogus
  450. if ( sv_unlag_debug.GetBool() )
  451. DevMsg( "Backtrack failed completely, bad starting position\n" );
  452. }
  453. else
  454. {
  455. // We can get to a valid place, but not all the way to the target
  456. Vector vPos;
  457. VectorLerp( pPlayer->GetLocalOrigin(), org, tr.fraction * g_flFractionScale, vPos );
  458. // This is as close as we're going to get
  459. org = vPos;
  460. if ( sv_unlag_debug.GetBool() )
  461. DevMsg( "Backtrack got most of the way\n" );
  462. }
  463. }
  464. }
  465. // See if this represents a change for the player
  466. int flags = 0;
  467. LagRecord *restore = &m_RestoreData[ pl_index ];
  468. LagRecord *change = &m_ChangeData[ pl_index ];
  469. QAngle angdiff = pPlayer->GetLocalAngles() - ang;
  470. Vector orgdiff = pPlayer->GetLocalOrigin() - org;
  471. // Always remember the pristine simulation time in case we need to restore it.
  472. restore->m_flSimulationTime = pPlayer->GetSimulationTime();
  473. if ( angdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR )
  474. {
  475. flags |= LC_ANGLES_CHANGED;
  476. restore->m_vecAngles = pPlayer->GetLocalAngles();
  477. pPlayer->SetLocalAngles( ang );
  478. change->m_vecAngles = ang;
  479. }
  480. // Use absolute equality here
  481. if ( minsPreScaled != pPlayer->CollisionProp()->OBBMinsPreScaled() || maxsPreScaled != pPlayer->CollisionProp()->OBBMaxsPreScaled() )
  482. {
  483. flags |= LC_SIZE_CHANGED;
  484. restore->m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled();
  485. restore->m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled();
  486. pPlayer->SetSize( minsPreScaled, maxsPreScaled );
  487. change->m_vecMinsPreScaled = minsPreScaled;
  488. change->m_vecMaxsPreScaled = maxsPreScaled;
  489. }
  490. // Note, do origin at end since it causes a relink into the k/d tree
  491. if ( orgdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR )
  492. {
  493. flags |= LC_ORIGIN_CHANGED;
  494. restore->m_vecOrigin = pPlayer->GetLocalOrigin();
  495. pPlayer->SetLocalOrigin( org );
  496. change->m_vecOrigin = org;
  497. }
  498. // Sorry for the loss of the optimization for the case of people
  499. // standing still, but you breathe even on the server.
  500. // This is quicker than actually comparing all bazillion floats.
  501. flags |= LC_ANIMATION_CHANGED;
  502. restore->m_masterSequence = pPlayer->GetSequence();
  503. restore->m_masterCycle = pPlayer->GetCycle();
  504. bool interpolationAllowed = false;
  505. if( prevRecord && (record->m_masterSequence == prevRecord->m_masterSequence) )
  506. {
  507. // If the master state changes, all layers will be invalid too, so don't interp (ya know, interp barely ever happens anyway)
  508. interpolationAllowed = true;
  509. }
  510. ////////////////////////
  511. // First do the master settings
  512. bool interpolatedMasters = false;
  513. if( frac > 0.0f && interpolationAllowed )
  514. {
  515. interpolatedMasters = true;
  516. pPlayer->SetSequence( Lerp( frac, record->m_masterSequence, prevRecord->m_masterSequence ) );
  517. pPlayer->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) );
  518. if( record->m_masterCycle > prevRecord->m_masterCycle )
  519. {
  520. // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0
  521. // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example.
  522. float newCycle = Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle + 1 );
  523. pPlayer->SetCycle(newCycle < 1 ? newCycle : newCycle - 1 );// and make sure .9 to 1.2 does not end up 1.05
  524. }
  525. else
  526. {
  527. pPlayer->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) );
  528. }
  529. }
  530. if( !interpolatedMasters )
  531. {
  532. pPlayer->SetSequence(record->m_masterSequence);
  533. pPlayer->SetCycle(record->m_masterCycle);
  534. }
  535. ////////////////////////
  536. // Now do all the layers
  537. int layerCount = pPlayer->GetNumAnimOverlays();
  538. for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
  539. {
  540. CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex);
  541. if( currentLayer )
  542. {
  543. restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle;
  544. restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder;
  545. restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence;
  546. restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight;
  547. bool interpolated = false;
  548. if( (frac > 0.0f) && interpolationAllowed )
  549. {
  550. LayerRecord &recordsLayerRecord = record->m_layerRecords[layerIndex];
  551. LayerRecord &prevRecordsLayerRecord = prevRecord->m_layerRecords[layerIndex];
  552. if( (recordsLayerRecord.m_order == prevRecordsLayerRecord.m_order)
  553. && (recordsLayerRecord.m_sequence == prevRecordsLayerRecord.m_sequence)
  554. )
  555. {
  556. // We can't interpolate across a sequence or order change
  557. interpolated = true;
  558. if( recordsLayerRecord.m_cycle > prevRecordsLayerRecord.m_cycle )
  559. {
  560. // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0
  561. // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example.
  562. float newCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle + 1 );
  563. currentLayer->m_flCycle = newCycle < 1 ? newCycle : newCycle - 1;// and make sure .9 to 1.2 does not end up 1.05
  564. }
  565. else
  566. {
  567. currentLayer->m_flCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle );
  568. }
  569. currentLayer->m_nOrder = recordsLayerRecord.m_order;
  570. currentLayer->m_nSequence = recordsLayerRecord.m_sequence;
  571. currentLayer->m_flWeight = Lerp( frac, recordsLayerRecord.m_weight, prevRecordsLayerRecord.m_weight );
  572. }
  573. }
  574. if( !interpolated )
  575. {
  576. //Either no interp, or interp failed. Just use record.
  577. currentLayer->m_flCycle = record->m_layerRecords[layerIndex].m_cycle;
  578. currentLayer->m_nOrder = record->m_layerRecords[layerIndex].m_order;
  579. currentLayer->m_nSequence = record->m_layerRecords[layerIndex].m_sequence;
  580. currentLayer->m_flWeight = record->m_layerRecords[layerIndex].m_weight;
  581. }
  582. }
  583. }
  584. if ( !flags )
  585. return; // we didn't change anything
  586. if ( sv_lagflushbonecache.GetBool() )
  587. pPlayer->InvalidateBoneCache();
  588. /*char text[256]; Q_snprintf( text, sizeof(text), "time %.2f", flTargetTime );
  589. pPlayer->DrawServerHitboxes( 10 );
  590. NDebugOverlay::Text( org, text, false, 10 );
  591. NDebugOverlay::EntityBounds( pPlayer, 255, 0, 0, 32, 10 ); */
  592. m_RestorePlayer.Set( pl_index ); //remember that we changed this player
  593. m_bNeedToRestore = true; // we changed at least one player
  594. restore->m_fFlags = flags; // we need to restore these flags
  595. change->m_fFlags = flags; // we have changed these flags
  596. if( sv_showlagcompensation.GetInt() == 1 )
  597. {
  598. pPlayer->DrawServerHitboxes(4, true);
  599. }
  600. }
  601. void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player )
  602. {
  603. VPROF_BUDGET_FLAGS( "FinishLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING, BUDGETFLAG_CLIENT|BUDGETFLAG_SERVER );
  604. m_pCurrentPlayer = NULL;
  605. if ( !m_bNeedToRestore )
  606. {
  607. m_isCurrentlyDoingCompensation = false;
  608. return; // no player was changed at all
  609. }
  610. // Iterate all active players
  611. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  612. {
  613. int pl_index = i - 1;
  614. if ( !m_RestorePlayer.Get( pl_index ) )
  615. {
  616. // player wasn't changed by lag compensation
  617. continue;
  618. }
  619. CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  620. if ( !pPlayer )
  621. {
  622. continue;
  623. }
  624. LagRecord *restore = &m_RestoreData[ pl_index ];
  625. LagRecord *change = &m_ChangeData[ pl_index ];
  626. bool restoreSimulationTime = false;
  627. if ( restore->m_fFlags & LC_SIZE_CHANGED )
  628. {
  629. restoreSimulationTime = true;
  630. // see if simulation made any changes, if no, then do the restore, otherwise,
  631. // leave new values in
  632. if ( pPlayer->CollisionProp()->OBBMinsPreScaled() == change->m_vecMinsPreScaled &&
  633. pPlayer->CollisionProp()->OBBMaxsPreScaled() == change->m_vecMaxsPreScaled )
  634. {
  635. // Restore it
  636. pPlayer->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled );
  637. }
  638. #ifdef STAGING_ONLY
  639. else
  640. {
  641. Warning( "Should we really not restore the size?\n" );
  642. }
  643. #endif
  644. }
  645. if ( restore->m_fFlags & LC_ANGLES_CHANGED )
  646. {
  647. restoreSimulationTime = true;
  648. if ( pPlayer->GetLocalAngles() == change->m_vecAngles )
  649. {
  650. pPlayer->SetLocalAngles( restore->m_vecAngles );
  651. }
  652. }
  653. if ( restore->m_fFlags & LC_ORIGIN_CHANGED )
  654. {
  655. restoreSimulationTime = true;
  656. // Okay, let's see if we can do something reasonable with the change
  657. Vector delta = pPlayer->GetLocalOrigin() - change->m_vecOrigin;
  658. // If it moved really far, just leave the player in the new spot!!!
  659. if ( delta.Length2DSqr() < m_flTeleportDistanceSqr )
  660. {
  661. RestorePlayerTo( pPlayer, restore->m_vecOrigin + delta );
  662. }
  663. }
  664. if( restore->m_fFlags & LC_ANIMATION_CHANGED )
  665. {
  666. restoreSimulationTime = true;
  667. pPlayer->SetSequence(restore->m_masterSequence);
  668. pPlayer->SetCycle(restore->m_masterCycle);
  669. int layerCount = pPlayer->GetNumAnimOverlays();
  670. for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
  671. {
  672. CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex);
  673. if( currentLayer )
  674. {
  675. currentLayer->m_flCycle = restore->m_layerRecords[layerIndex].m_cycle;
  676. currentLayer->m_nOrder = restore->m_layerRecords[layerIndex].m_order;
  677. currentLayer->m_nSequence = restore->m_layerRecords[layerIndex].m_sequence;
  678. currentLayer->m_flWeight = restore->m_layerRecords[layerIndex].m_weight;
  679. }
  680. }
  681. }
  682. if ( restoreSimulationTime )
  683. {
  684. pPlayer->SetSimulationTime( restore->m_flSimulationTime );
  685. }
  686. }
  687. m_isCurrentlyDoingCompensation = false;
  688. }