From 799b7117620948bd696386a1f0f166ad2cfb419f Mon Sep 17 00:00:00 2001 From: dr3murr Date: Tue, 25 Feb 2025 12:42:09 -0500 Subject: [PATCH 01/12] fix debug crash --- src/game/shared/tf/tf_item_inventory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/shared/tf/tf_item_inventory.cpp b/src/game/shared/tf/tf_item_inventory.cpp index 2206f003a02..cab73fb0634 100644 --- a/src/game/shared/tf/tf_item_inventory.cpp +++ b/src/game/shared/tf/tf_item_inventory.cpp @@ -964,7 +964,7 @@ void CTFPlayerInventory::LoadLocalLoadout() m_LoadoutItems[iClass][iSlot] = uItemId; CEconItemView *pItem = GetInventoryItemByItemID(uItemId); - if (pItem) { + if (pItem && pItem->GetSOCData()) { pItem->GetSOCData()->Equip(iClass, iSlot); } } From f7b988d468c6b2fa71b4cd8b11edf62256975269 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Tue, 25 Feb 2025 13:07:55 -0500 Subject: [PATCH 02/12] add subtick stuff --- src/game/client/c_baseplayer.h | 13 +++- src/game/client/in_main.cpp | 62 +++++++++++++++++ src/game/client/prediction.cpp | 6 ++ src/game/server/player.h | 14 +++- src/game/server/player_command.cpp | 8 ++- src/game/server/player_lagcompensation.cpp | 80 ++++++++++++---------- src/game/shared/baseplayer_shared.cpp | 63 +++++++++++++++-- src/game/shared/usercmd.cpp | 16 +++++ src/game/shared/usercmd.h | 3 +- 9 files changed, 221 insertions(+), 44 deletions(-) diff --git a/src/game/client/c_baseplayer.h b/src/game/client/c_baseplayer.h index 11a7fabca88..f421281483b 100644 --- a/src/game/client/c_baseplayer.h +++ b/src/game/client/c_baseplayer.h @@ -399,7 +399,13 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener void SetFiredWeapon( bool bFlag ) { m_bFiredWeapon = bFlag; } virtual bool CanUseFirstPersonCommand( void ){ return true; } - + void SetAttackInterpolationData(const QAngle& viewAngles, float interpolationAmount); + void GetAttackInterpolationData(QAngle& viewAngles, float& lerpTime); + bool HasAttackInterpolationData() const; + void ClearAttackInterpolationData(); + void SetInPostThink(bool inPostThink); + bool IsInPostThink() const; + Vector GetInterpolatedEyePosition(); protected: fogparams_t m_CurrentFog; EHANDLE m_hOldFogController; @@ -623,6 +629,11 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener #endif private: + QAngle m_angAttackViewAngles; // Stored view angles during attack + float m_flAttackInterpolationAmount; // Interpolation amount when attack was issued + bool m_bHasAttackInterpolationData; // Whether we have valid data + float m_flAttackLerpTime; // Calculated lerp time for the attack + bool m_bInPostThink; // Flag for post-think state struct StepSoundCache_t { diff --git a/src/game/client/in_main.cpp b/src/game/client/in_main.cpp index 5d2c6b0ee22..06683f7c828 100644 --- a/src/game/client/in_main.cpp +++ b/src/game/client/in_main.cpp @@ -1061,6 +1061,31 @@ void CInput::ExtraMouseSample( float frametime, bool active ) cmd->buttons = GetButtonBits( 0 ); #endif + // Check if this is an attack frame + bool bIsAttackFrame = false; + + C_BaseCombatWeapon* pWeapon = NULL; + C_BasePlayer* pPlayer = CBasePlayer::GetLocalPlayer(); + if (pPlayer) + pWeapon = pPlayer->GetActiveWeapon(); + + if (pWeapon) { + // Check primary attack + if ((cmd->buttons & IN_ATTACK) && pWeapon->m_flNextPrimaryAttack <= (gpGlobals->curtime + (gpGlobals->interpolation_amount * gpGlobals->interval_per_tick))) { + bIsAttackFrame = true; + } + // Check secondary attack + else if ((cmd->buttons & IN_ATTACK2) && pWeapon->m_flNextSecondaryAttack <= (gpGlobals->curtime + (gpGlobals->interpolation_amount * gpGlobals->interval_per_tick))) { + bIsAttackFrame = true; + } + } + + if (bIsAttackFrame && !pPlayer->HasAttackInterpolationData()) { + // Store attack data + pPlayer->SetAttackInterpolationData(viewangles, gpGlobals->interpolation_amount); + } + + // Use new view angles if alive, otherwise user last angles we stored off. if ( g_iAlive ) { @@ -1161,6 +1186,7 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo ResetMouse(); } } + // Retreive view angles from engine ( could have been set in IN_AdjustAngles above ) engine->GetViewAngles( viewangles ); @@ -1271,6 +1297,42 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo cmd->random_seed = MD5_PseudoRandom( sequence_number ) & 0x7fffffff; + C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); + bool bUseAttackData = pPlayer && pPlayer->HasAttackInterpolationData(); + + // If we have attack data, use it + if (bUseAttackData) { + QAngle attackAngles; + float lerpTime; + + pPlayer->GetAttackInterpolationData(attackAngles, lerpTime); + + // Store original angles before applying stored attack angles + QAngle currentAngles = viewangles; + + // Apply attack data to command + cmd->viewangles = attackAngles; + cmd->lerp_time = lerpTime; + + // Fix movement commands for new viewangles + float deltaYaw = DEG2RAD(viewangles[YAW] - currentAngles[YAW]); + float s = sin(deltaYaw); + float c = cos(deltaYaw); + + // Store original movement values + float forwardmove = cmd->forwardmove; + float sidemove = cmd->sidemove; + + // Adjust movement values based on angle change + cmd->forwardmove = (c * forwardmove) - (s * sidemove); + cmd->sidemove = (s * forwardmove) + (c * sidemove); + + pPlayer->ClearAttackInterpolationData(); + } + else { + cmd->lerp_time = 1.0f; + } + HLTVCamera()->CreateMove( cmd ); #if defined( REPLAY_ENABLED ) ReplayCamera()->CreateMove( cmd ); diff --git a/src/game/client/prediction.cpp b/src/game/client/prediction.cpp index b73f41d9aef..cbd81acb852 100644 --- a/src/game/client/prediction.cpp +++ b/src/game/client/prediction.cpp @@ -830,8 +830,14 @@ void CPrediction::RunPostThink( C_BasePlayer *player ) #if !defined( NO_ENTITY_PREDICTION ) VPROF( "CPrediction::RunPostThink" ); + // Mark that we're in post-think + player->SetInPostThink(true); + // Run post-think player->PostThink(); + + // Clear post-think flag + player->SetInPostThink(false); #endif } diff --git a/src/game/server/player.h b/src/game/server/player.h index 902e0e627ca..4cce0b64db3 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -844,7 +844,13 @@ class CBasePlayer : public CBaseCombatCharacter // How long since this player last interacted with something the game considers an objective/target/goal float GetTimeSinceLastObjective( void ) const { return ( m_flLastObjectiveTime == -1.f ) ? 999.f : gpGlobals->curtime - m_flLastObjectiveTime; } void SetLastObjectiveTime( float flTime ) { m_flLastObjectiveTime = flTime; } - + void SetAttackInterpolationData(const QAngle& viewAngles, float interpolationAmount); + void GetAttackInterpolationData(QAngle& viewAngles, float& lerpTime); + bool HasAttackInterpolationData() const; + void ClearAttackInterpolationData(); + void SetInPostThink(bool inPostThink); + bool IsInPostThink() const; + Vector GetInterpolatedEyePosition(); // Used by gamemovement to check if the entity is stuck. int m_StuckLast; @@ -1262,6 +1268,12 @@ class CBasePlayer : public CBaseCombatCharacter // used to prevent achievement announcement spam CUtlVector< float > m_flAchievementTimes; + QAngle m_angAttackViewAngles; // Stored view angles during attack + float m_flAttackInterpolationAmount; // Interpolation amount when attack was issued + bool m_bHasAttackInterpolationData; // Whether we have valid data + int m_nAttackButtons; // Buttons pressed during attack + float m_flAttackLerpTime; // Calculated lerp time for the attack + bool m_bInPostThink; // Flag for post-think state public: virtual unsigned int PlayerSolidMask( bool brushOnly = false ) const; // returns the solid mask for the given player, so bots can have a more-restrictive set diff --git a/src/game/server/player_command.cpp b/src/game/server/player_command.cpp index a8469d6ff92..59ef639f2fb 100644 --- a/src/game/server/player_command.cpp +++ b/src/game/server/player_command.cpp @@ -300,8 +300,14 @@ void CPlayerMove::RunPostThink( CBasePlayer *player ) { VPROF( "CPlayerMove::RunPostThink" ); + // Mark that we're in post-think + player->SetInPostThink(true); // Run post-think player->PostThink(); + + // Clear post-think flag + player->SetInPostThink(false); + player->ClearAttackInterpolationData(); } void CommentarySystem_PePlayerRunCommand( CBasePlayer *player, CUserCmd *ucmd ); @@ -446,7 +452,7 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper VPROF_SCOPE_BEGIN( "moveHelper->ProcessImpacts" ); moveHelper->ProcessImpacts(); VPROF_SCOPE_END(); - + player->SetAttackInterpolationData(ucmd->viewangles, ucmd->lerp_time); RunPostThink( player ); g_pGameMovement->FinishTrackPredictionErrors( player ); diff --git a/src/game/server/player_lagcompensation.cpp b/src/game/server/player_lagcompensation.cpp index 5192a46bbff..d3f4038f155 100644 --- a/src/game/server/player_lagcompensation.cpp +++ b/src/game/server/player_lagcompensation.cpp @@ -342,16 +342,16 @@ void CLagCompensationManager::FrameUpdatePostEntityThink() } // Called during player movement to set up/restore after lag compensation -void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) +void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd* cmd) { - Assert( !m_isCurrentlyDoingCompensation ); + Assert(!m_isCurrentlyDoingCompensation); //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG - if ( m_pCurrentPlayer ) + if (m_pCurrentPlayer) { - Assert( m_pCurrentPlayer == NULL ); - Warning( "Trying to start a new lag compensation session while one is already active!\n" ); + Assert(m_pCurrentPlayer == NULL); + Warning("Trying to start a new lag compensation session while one is already active!\n"); return; } @@ -360,80 +360,90 @@ void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCm m_bNeedToRestore = false; m_pCurrentPlayer = player; - - if ( !player->m_bLagCompensation // Player not wanting lag compensation - || (gpGlobals->maxClients <= 1) // no lag compensation in single player - || !sv_unlag.GetBool() // disabled by server admin - || player->IsBot() // not for bots - || player->IsObserver() // not for spectators + + if (!player->m_bLagCompensation // Player not wanting lag compensation + || (gpGlobals->maxClients <= 1) // no lag compensation in single player + || !sv_unlag.GetBool() // disabled by server admin + || player->IsBot() // not for bots + || player->IsObserver() // not for spectators ) return; // NOTE: Put this here so that it won't show up in single player mode. - VPROF_BUDGET( "StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING ); - Q_memset( m_RestoreData, 0, sizeof( m_RestoreData ) ); - Q_memset( m_ChangeData, 0, sizeof( m_ChangeData ) ); + VPROF_BUDGET("StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING); + Q_memset(m_RestoreData, 0, sizeof(m_RestoreData)); + Q_memset(m_ChangeData, 0, sizeof(m_ChangeData)); m_isCurrentlyDoingCompensation = true; // Get true latency - // correct is the amout of time we have to correct game time + // correct is the amount of time we have to correct game time float correct = 0.0f; - INetChannelInfo *nci = engine->GetPlayerNetInfo( player->entindex() ); + INetChannelInfo* nci = engine->GetPlayerNetInfo(player->entindex()); - if ( nci ) + if (nci) { // add network latency - correct+= nci->GetLatency( FLOW_OUTGOING ); + correct += nci->GetLatency(FLOW_OUTGOING); } // calc number of view interpolation ticks - 1 - int lerpTicks = TIME_TO_TICKS( player->m_fLerpTime ); + int lerpTicks = TIME_TO_TICKS(player->m_fLerpTime); // add view interpolation latency see C_BaseEntity::GetInterpolationAmount() - correct += TICKS_TO_TIME( lerpTicks ); - - // check bouns [0,sv_maxunlag] - correct = clamp( correct, 0.0f, sv_maxunlag.GetFloat() ); + correct += TICKS_TO_TIME(lerpTicks); + + // check bounds [0,sv_maxunlag] + correct = clamp(correct, 0.0f, sv_maxunlag.GetFloat()); + + // adjust attack timing if we have valid interpolation data + float extraTime = 0.0f; + if (cmd->lerp_time > 0.0f && cmd->lerp_time <= 1.0f) + { + // Add fraction of a tick based on lerp_time + extraTime = cmd->lerp_time * TICK_INTERVAL; + } // correct tick send by player int targettick = cmd->tick_count - lerpTicks; // calc difference between tick send by player and our latency based tick - float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); + float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); - if ( fabs( deltaTime ) > 0.2f ) + if (fabs(deltaTime) > 0.2f) { // difference between cmd time and latency is too big > 200ms, use time correction based on latency - // DevMsg("StartLagCompensation: delta too big (%.3f)\n", deltaTime ); - targettick = gpGlobals->tickcount - TIME_TO_TICKS( correct ); + targettick = gpGlobals->tickcount - TIME_TO_TICKS(correct); } - + + // Add the interpolation amount + float targettime = TICKS_TO_TIME(targettick) + extraTime; + // Iterate all active players - const CBitVec *pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + const CBitVec* pEntityTransmitBits = engine->GetEntityTransmitBitsForClient(player->entindex() - 1); + for (int i = 1; i <= gpGlobals->maxClients; i++) { - CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + CBasePlayer* pPlayer = UTIL_PlayerByIndex(i); - if ( !pPlayer ) + if (!pPlayer) { continue; } // Don't lag compensate yourself you loser... - if ( player == pPlayer ) + if (player == pPlayer) { continue; } // Custom checks for if things should lag compensate (based on things like what team the player is on). - if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) ) + if (!player->WantsLagCompensationOnEntity(pPlayer, cmd, pEntityTransmitBits)) continue; // Move other player back in time - BacktrackPlayer( pPlayer, TICKS_TO_TIME( targettick ) ); + BacktrackPlayer(pPlayer, targettime); } } diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index abbd3196495..2c4104e37ec 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -329,9 +329,14 @@ const QAngle &CBasePlayer::LocalEyeAngles() //----------------------------------------------------------------------------- // Actual Eye position + angles //----------------------------------------------------------------------------- -Vector CBasePlayer::EyePosition( ) +Vector CBasePlayer::EyePosition() { - if ( GetVehicle() != NULL ) + if (IsInPostThink() && HasAttackInterpolationData()) + { + return GetInterpolatedEyePosition(); + } + + if (GetVehicle() != NULL) { // Return the cached result CacheVehicleView(); @@ -340,11 +345,11 @@ Vector CBasePlayer::EyePosition( ) else { #ifdef CLIENT_DLL - if ( IsObserver() ) + if (IsObserver()) { - if ( GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_POI ) + if (GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_POI) { - if ( IsLocalPlayer() ) + if (IsLocalPlayer()) { return MainViewOrigin(); } @@ -2096,3 +2101,51 @@ bool fogparams_t::operator !=( const fogparams_t& other ) const return false; } +void CBasePlayer::SetAttackInterpolationData(const QAngle& viewAngles, float interpolationAmount) +{ + m_angAttackViewAngles = viewAngles; + m_flAttackInterpolationAmount = interpolationAmount; + m_bHasAttackInterpolationData = true; + + // Calculate lerp time, clamped between 0 and 1 + m_flAttackLerpTime = clamp(interpolationAmount, 0.0f, 1.0f); +} + +void CBasePlayer::GetAttackInterpolationData(QAngle& viewAngles, float& lerpTime) +{ + viewAngles = m_angAttackViewAngles; + lerpTime = m_flAttackLerpTime; +} + +bool CBasePlayer::HasAttackInterpolationData() const +{ + return m_bHasAttackInterpolationData; +} + +void CBasePlayer::ClearAttackInterpolationData() +{ + m_bHasAttackInterpolationData = false; +} + +void CBasePlayer::SetInPostThink(bool inPostThink) +{ + m_bInPostThink = inPostThink; +} + +bool CBasePlayer::IsInPostThink() const +{ + return m_bInPostThink; +} + +Vector CBasePlayer::GetInterpolatedEyePosition() +{ + if (!IsInPostThink() || !HasAttackInterpolationData()) + return EyePosition(); + + // Interpolate between last tick's position and current position + Vector lastPos = GetPreviouslyPredictedOrigin() + GetViewOffset(); + SetInPostThink(false); // so we don't overflow here + Vector currentPos = EyePosition(); + SetInPostThink(true); + return lastPos + (currentPos - lastPos) * m_flAttackLerpTime; +} \ No newline at end of file diff --git a/src/game/shared/usercmd.cpp b/src/game/shared/usercmd.cpp index 84ffa243141..f5a98c5c90f 100644 --- a/src/game/shared/usercmd.cpp +++ b/src/game/shared/usercmd.cpp @@ -169,6 +169,7 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ) buf->WriteOneBit( 0 ); } + #if defined( HL2_CLIENT_DLL ) if ( to->entitygroundcontact.Count() != 0 ) { @@ -187,6 +188,16 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ) buf->WriteOneBit( 0 ); } #endif + + if (to->lerp_time != from->lerp_time) + { + buf->WriteOneBit(1); + buf->WriteFloat(to->lerp_time); + } + else + { + buf->WriteOneBit(0); + } } //----------------------------------------------------------------------------- @@ -289,6 +300,7 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ) move->mousedy = buf->ReadShort(); } + #if defined( HL2_DLL ) if ( buf->ReadOneBit() ) { @@ -303,4 +315,8 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ) } } #endif + if (buf->ReadOneBit()) + { + move->lerp_time = buf->ReadFloat(); + } } diff --git a/src/game/shared/usercmd.h b/src/game/shared/usercmd.h index 0005bde99f5..176881326b7 100644 --- a/src/game/shared/usercmd.h +++ b/src/game/shared/usercmd.h @@ -171,7 +171,8 @@ class CUserCmd #if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) CUtlVector< CEntityGroundContact > entitygroundcontact; #endif - + // Attack lerp time + double lerp_time; }; void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ); From 24b8dbdd1cf84820dcc629030c1c7a09a88884b9 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Tue, 25 Feb 2025 19:43:09 -0500 Subject: [PATCH 03/12] Fix up some frame order issues --- src/game/client/c_baseplayer.h | 3 ++ src/game/server/player.h | 3 ++ src/game/server/player_lagcompensation.cpp | 29 ++------------------ src/game/shared/baseplayer_shared.cpp | 32 ++++++++++++++++++---- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/game/client/c_baseplayer.h b/src/game/client/c_baseplayer.h index f421281483b..ceb1ec89ef4 100644 --- a/src/game/client/c_baseplayer.h +++ b/src/game/client/c_baseplayer.h @@ -634,6 +634,9 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener bool m_bHasAttackInterpolationData; // Whether we have valid data float m_flAttackLerpTime; // Calculated lerp time for the attack bool m_bInPostThink; // Flag for post-think state + int m_nLastTickCount; // The tick count from the last time we processed + Vector m_vecLastTickEyePosition; // Eye position from the last tick + Vector m_vecCurrentTickEyePosition; // Current eye position for this tick struct StepSoundCache_t { diff --git a/src/game/server/player.h b/src/game/server/player.h index 4cce0b64db3..b4c0c6779b8 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -1274,6 +1274,9 @@ class CBasePlayer : public CBaseCombatCharacter int m_nAttackButtons; // Buttons pressed during attack float m_flAttackLerpTime; // Calculated lerp time for the attack bool m_bInPostThink; // Flag for post-think state + int m_nLastTickCount; // The tick count from the last time we processed + Vector m_vecLastTickEyePosition; // Eye position from the last tick + Vector m_vecCurrentTickEyePosition; // Current eye position for this tick public: virtual unsigned int PlayerSolidMask( bool brushOnly = false ) const; // returns the solid mask for the given player, so bots can have a more-restrictive set diff --git a/src/game/server/player_lagcompensation.cpp b/src/game/server/player_lagcompensation.cpp index d3f4038f155..2d2113a6e3f 100644 --- a/src/game/server/player_lagcompensation.cpp +++ b/src/game/server/player_lagcompensation.cpp @@ -345,7 +345,6 @@ void CLagCompensationManager::FrameUpdatePostEntityThink() void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd* cmd) { Assert(!m_isCurrentlyDoingCompensation); - //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG if (m_pCurrentPlayer) @@ -354,13 +353,10 @@ void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd Warning("Trying to start a new lag compensation session while one is already active!\n"); return; } - // Assume no players need to be restored m_RestorePlayer.ClearAll(); m_bNeedToRestore = false; - m_pCurrentPlayer = player; - if (!player->m_bLagCompensation // Player not wanting lag compensation || (gpGlobals->maxClients <= 1) // no lag compensation in single player || !sv_unlag.GetBool() // disabled by server admin @@ -368,36 +364,26 @@ void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd || player->IsObserver() // not for spectators ) return; - // NOTE: Put this here so that it won't show up in single player mode. VPROF_BUDGET("StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING); Q_memset(m_RestoreData, 0, sizeof(m_RestoreData)); Q_memset(m_ChangeData, 0, sizeof(m_ChangeData)); - m_isCurrentlyDoingCompensation = true; - // Get true latency - // correct is the amount of time we have to correct game time float correct = 0.0f; - INetChannelInfo* nci = engine->GetPlayerNetInfo(player->entindex()); - if (nci) { // add network latency correct += nci->GetLatency(FLOW_OUTGOING); } - // calc number of view interpolation ticks - 1 - int lerpTicks = TIME_TO_TICKS(player->m_fLerpTime); - - // add view interpolation latency see C_BaseEntity::GetInterpolationAmount() - correct += TICKS_TO_TIME(lerpTicks); + // add view interpolation latency directly using player's lerp time + correct += player->m_fLerpTime; // check bounds [0,sv_maxunlag] correct = clamp(correct, 0.0f, sv_maxunlag.GetFloat()); - // adjust attack timing if we have valid interpolation data float extraTime = 0.0f; if (cmd->lerp_time > 0.0f && cmd->lerp_time <= 1.0f) @@ -405,43 +391,34 @@ void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd // Add fraction of a tick based on lerp_time extraTime = cmd->lerp_time * TICK_INTERVAL; } - // correct tick send by player - int targettick = cmd->tick_count - lerpTicks; - + int targettick = cmd->tick_count - TIME_TO_TICKS(player->m_fLerpTime); // calc difference between tick send by player and our latency based tick float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); - if (fabs(deltaTime) > 0.2f) { // difference between cmd time and latency is too big > 200ms, use time correction based on latency targettick = gpGlobals->tickcount - TIME_TO_TICKS(correct); } - // Add the interpolation amount float targettime = TICKS_TO_TIME(targettick) + extraTime; - // Iterate all active players const CBitVec* pEntityTransmitBits = engine->GetEntityTransmitBitsForClient(player->entindex() - 1); for (int i = 1; i <= gpGlobals->maxClients; i++) { CBasePlayer* pPlayer = UTIL_PlayerByIndex(i); - if (!pPlayer) { continue; } - // Don't lag compensate yourself you loser... if (player == pPlayer) { continue; } - // Custom checks for if things should lag compensate (based on things like what team the player is on). if (!player->WantsLagCompensationOnEntity(pPlayer, cmd, pEntityTransmitBits)) continue; - // Move other player back in time BacktrackPlayer(pPlayer, targettime); } diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 2c4104e37ec..79e8db4683b 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -2142,10 +2142,32 @@ Vector CBasePlayer::GetInterpolatedEyePosition() if (!IsInPostThink() || !HasAttackInterpolationData()) return EyePosition(); - // Interpolate between last tick's position and current position - Vector lastPos = GetPreviouslyPredictedOrigin() + GetViewOffset(); - SetInPostThink(false); // so we don't overflow here - Vector currentPos = EyePosition(); + int currentTickCount = gpGlobals->tickcount; + SetInPostThink(false); + Vector currentEyePosition = EyePosition(); SetInPostThink(true); - return lastPos + (currentPos - lastPos) * m_flAttackLerpTime; + + // First call or tick count dropped + if (m_nLastTickCount <= 0 || currentTickCount < m_nLastTickCount) + { + // Initialize both positions + m_nLastTickCount = currentTickCount; + m_vecLastTickEyePosition = currentEyePosition; + m_vecCurrentTickEyePosition = currentEyePosition; + return currentEyePosition; + } + + // If this is a new tick + if (currentTickCount > m_nLastTickCount) + { + // Update the last tick's position + m_vecLastTickEyePosition = m_vecCurrentTickEyePosition; + m_nLastTickCount = currentTickCount; + } + + // Update the current eye position + m_vecCurrentTickEyePosition = currentEyePosition; + + // Interpolate between the last tick's position and the current position + return m_vecLastTickEyePosition + (m_vecCurrentTickEyePosition - m_vecLastTickEyePosition) * m_flAttackLerpTime; } \ No newline at end of file From fbccbf57e4625d52d231a008cebc42813879fa94 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Wed, 26 Feb 2025 01:35:22 -0500 Subject: [PATCH 04/12] more usercmd stuff --- src/game/client/c_baseplayer.h | 6 ++--- src/game/client/in_main.cpp | 2 +- src/game/server/player.h | 7 +++--- src/game/server/player_command.cpp | 1 + src/game/shared/baseplayer_shared.cpp | 34 ++++++++++++++++++++++++--- src/game/shared/usercmd.h | 4 ++-- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/game/client/c_baseplayer.h b/src/game/client/c_baseplayer.h index ceb1ec89ef4..649a5ba1652 100644 --- a/src/game/client/c_baseplayer.h +++ b/src/game/client/c_baseplayer.h @@ -630,9 +630,9 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener private: QAngle m_angAttackViewAngles; // Stored view angles during attack - float m_flAttackInterpolationAmount; // Interpolation amount when attack was issued - bool m_bHasAttackInterpolationData; // Whether we have valid data - float m_flAttackLerpTime; // Calculated lerp time for the attack + float m_flAttackInterpolationAmount = 1.0f; // Interpolation amount when attack was issued + bool m_bHasAttackInterpolationData = false; // Whether we have valid data + float m_flAttackLerpTime = 1.0f; // Calculated lerp time for the attack bool m_bInPostThink; // Flag for post-think state int m_nLastTickCount; // The tick count from the last time we processed Vector m_vecLastTickEyePosition; // Eye position from the last tick diff --git a/src/game/client/in_main.cpp b/src/game/client/in_main.cpp index 06683f7c828..8a6186b6ac1 100644 --- a/src/game/client/in_main.cpp +++ b/src/game/client/in_main.cpp @@ -1332,7 +1332,7 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo else { cmd->lerp_time = 1.0f; } - + //Msg("CreateMove lerp_time was: %f\n", cmd->lerp_time); HLTVCamera()->CreateMove( cmd ); #if defined( REPLAY_ENABLED ) ReplayCamera()->CreateMove( cmd ); diff --git a/src/game/server/player.h b/src/game/server/player.h index b4c0c6779b8..d857a8bd597 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -1269,10 +1269,9 @@ class CBasePlayer : public CBaseCombatCharacter // used to prevent achievement announcement spam CUtlVector< float > m_flAchievementTimes; QAngle m_angAttackViewAngles; // Stored view angles during attack - float m_flAttackInterpolationAmount; // Interpolation amount when attack was issued - bool m_bHasAttackInterpolationData; // Whether we have valid data - int m_nAttackButtons; // Buttons pressed during attack - float m_flAttackLerpTime; // Calculated lerp time for the attack + float m_flAttackInterpolationAmount = 1.0f; // Interpolation amount when attack was issued + bool m_bHasAttackInterpolationData = false; // Whether we have valid data + float m_flAttackLerpTime = 1.0f; // Calculated lerp time for the attack bool m_bInPostThink; // Flag for post-think state int m_nLastTickCount; // The tick count from the last time we processed Vector m_vecLastTickEyePosition; // Eye position from the last tick diff --git a/src/game/server/player_command.cpp b/src/game/server/player_command.cpp index 59ef639f2fb..93da80fe694 100644 --- a/src/game/server/player_command.cpp +++ b/src/game/server/player_command.cpp @@ -452,6 +452,7 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper VPROF_SCOPE_BEGIN( "moveHelper->ProcessImpacts" ); moveHelper->ProcessImpacts(); VPROF_SCOPE_END(); + //Msg("CPlayerMove::RunCommand lerp_time was: %f\n", ucmd->lerp_time); player->SetAttackInterpolationData(ucmd->viewangles, ucmd->lerp_time); RunPostThink( player ); diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 79e8db4683b..0a33b0c9679 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -2136,7 +2136,6 @@ bool CBasePlayer::IsInPostThink() const { return m_bInPostThink; } - Vector CBasePlayer::GetInterpolatedEyePosition() { if (!IsInPostThink() || !HasAttackInterpolationData()) @@ -2169,5 +2168,34 @@ Vector CBasePlayer::GetInterpolatedEyePosition() m_vecCurrentTickEyePosition = currentEyePosition; // Interpolate between the last tick's position and the current position - return m_vecLastTickEyePosition + (m_vecCurrentTickEyePosition - m_vecLastTickEyePosition) * m_flAttackLerpTime; -} \ No newline at end of file + Vector interpolatedPosition = m_vecLastTickEyePosition + (m_vecCurrentTickEyePosition - m_vecLastTickEyePosition) * m_flAttackLerpTime; + + // Calculate the distance between interpolated position and regular eye position + float distance = (interpolatedPosition - currentEyePosition).Length(); + + // Log the distance using Msg() + //Msg("Interpolated eye position distance from regular eye position: %.3f units, m_flAttackLerpTime: %f\n", distance, m_flAttackLerpTime); + + return interpolatedPosition; +} +/* +Vector CBasePlayer::GetInterpolatedEyePosition() +{ + if (!IsInPostThink() || !HasAttackInterpolationData()) + return EyePosition(); + + int currentTickCount = gpGlobals->tickcount; + SetInPostThink(false); + Vector currentEyePosition = EyePosition(); + SetInPostThink(true); + + Vector interpolatedPosition = (GetPreviouslyPredictedOrigin() + GetViewOffset()) + (currentEyePosition - (GetPreviouslyPredictedOrigin() + GetViewOffset())) * m_flAttackLerpTime; + + // Calculate the distance between interpolated position and regular eye position + float distance = (interpolatedPosition - currentEyePosition).Length(); + + // Log the distance using Msg() + Msg("Interpolated eye position distance from regular eye position: %.3f units, m_flAttackLerpTime: %f\n", distance, m_flAttackLerpTime); + + return interpolatedPosition; +}*/ \ No newline at end of file diff --git a/src/game/shared/usercmd.h b/src/game/shared/usercmd.h index 176881326b7..8c6974e5453 100644 --- a/src/game/shared/usercmd.h +++ b/src/game/shared/usercmd.h @@ -56,7 +56,7 @@ class CUserCmd #endif mousedx = 0; mousedy = 0; - + lerp_time = 1.0f; hasbeenpredicted = false; #if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) entitygroundcontact.RemoveAll(); @@ -84,7 +84,7 @@ class CUserCmd #endif mousedx = src.mousedx; mousedy = src.mousedy; - + lerp_time = src.lerp_time; hasbeenpredicted = src.hasbeenpredicted; #if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) From 85c8d8ebe4f2b6078210a4be718adc8dd626ee46 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 00:50:54 -0500 Subject: [PATCH 05/12] netvar stuff --- src/game/client/c_baseplayer.cpp | 2 + src/game/client/c_baseplayer.h | 9 +++-- src/game/client/prediction.cpp | 3 +- src/game/server/player.cpp | 2 + src/game/server/player.h | 8 ++-- src/game/server/player_command.cpp | 2 +- src/game/shared/baseplayer_shared.cpp | 57 ++++++--------------------- 7 files changed, 29 insertions(+), 54 deletions(-) diff --git a/src/game/client/c_baseplayer.cpp b/src/game/client/c_baseplayer.cpp index 534d4a2c876..c75aade68a9 100644 --- a/src/game/client/c_baseplayer.cpp +++ b/src/game/client/c_baseplayer.cpp @@ -244,6 +244,7 @@ END_RECV_TABLE() RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, RecvProxy_LocalVelocityZ ), RecvPropVector ( RECVINFO( m_vecBaseVelocity ) ), + RecvPropVector(RECVINFO(m_vecPreviouslyPreviouslyPredictedEyePosition)), RecvPropEHandle ( RECVINFO( m_hConstraintEntity)), RecvPropVector ( RECVINFO( m_vecConstraintCenter) ), @@ -399,6 +400,7 @@ BEGIN_PREDICTION_DATA( C_BasePlayer ) // DEFINE_FIELD( m_pEnvironmentLight, dlight_t* ), // DEFINE_FIELD( m_pBrightLight, dlight_t* ), DEFINE_PRED_FIELD( m_hLastWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD(m_vecPreviouslyPreviouslyPredictedEyePosition, FIELD_POSITION_VECTOR, FTYPEDESC_INSENDTABLE), DEFINE_PRED_FIELD( m_nTickBase, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), diff --git a/src/game/client/c_baseplayer.h b/src/game/client/c_baseplayer.h index 649a5ba1652..6bb0715ebd1 100644 --- a/src/game/client/c_baseplayer.h +++ b/src/game/client/c_baseplayer.h @@ -334,7 +334,10 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener float GetDeathTime( void ) { return m_flDeathTime; } void SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin ); + void SetPreviouslyPreviouslyPredictedEyePosition(const Vector& vecAbsOrigin); + const Vector &GetPreviouslyPredictedOrigin() const; + const Vector& GetPreviouslyPreviouslyPredictedEyePosition() const; // CS wants to allow small FOVs for zoomed-in AWPs. virtual float GetMinFOV() const; @@ -606,7 +609,8 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener float m_flPredictionErrorTime; Vector m_vecPreviouslyPredictedOrigin; // Used to determine if non-gamemovement game code has teleported, or tweaked the player's origin - + Vector m_vecPreviouslyPreviouslyPredictedEyePosition; // Used for attack interpolation + char m_szLastPlaceName[MAX_PLACE_NAME_LENGTH]; // received from the server // Texture names and surface data, used by CGameMovement @@ -634,9 +638,6 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener bool m_bHasAttackInterpolationData = false; // Whether we have valid data float m_flAttackLerpTime = 1.0f; // Calculated lerp time for the attack bool m_bInPostThink; // Flag for post-think state - int m_nLastTickCount; // The tick count from the last time we processed - Vector m_vecLastTickEyePosition; // Eye position from the last tick - Vector m_vecCurrentTickEyePosition; // Current eye position for this tick struct StepSoundCache_t { diff --git a/src/game/client/prediction.cpp b/src/game/client/prediction.cpp index cbd81acb852..26b8e8fa901 100644 --- a/src/game/client/prediction.cpp +++ b/src/game/client/prediction.cpp @@ -618,7 +618,7 @@ void CPrediction::SetupMove( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper * { move->m_bGameCodeMovedPlayer = true; } - + player->SetPreviouslyPreviouslyPredictedEyePosition(player->GetAbsOrigin() + player->GetViewOffset()); move->m_nPlayerHandle = player->GetClientHandle(); move->m_vecVelocity = player->GetAbsVelocity(); move->SetAbsOrigin( player->GetNetworkOrigin() ); @@ -708,6 +708,7 @@ void CPrediction::FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *m player->SetAbsVelocity( move->m_vecVelocity ); player->m_vecNetworkOrigin = move->GetAbsOrigin(); + player->SetPreviouslyPreviouslyPredictedEyePosition(player->GetPreviouslyPreviouslyPredictedEyePosition()); player->SetPreviouslyPredictedOrigin( move->GetAbsOrigin() ); player->m_Local.m_nOldButtons = move->m_nButtons; diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index ffe892dfa0b..dacc5486b88 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -457,6 +457,7 @@ BEGIN_DATADESC( CBasePlayer ) DEFINE_FIELD( m_flForwardMove, FIELD_FLOAT ), DEFINE_FIELD( m_flSideMove, FIELD_FLOAT ), DEFINE_FIELD( m_vecPreviouslyPredictedOrigin, FIELD_POSITION_VECTOR ), + DEFINE_FIELD(m_vecPreviouslyPreviouslyPredictedEyePosition, FIELD_POSITION_VECTOR), DEFINE_FIELD( m_nNumCrateHudHints, FIELD_INTEGER ), @@ -8159,6 +8160,7 @@ void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const voi SendPropFloat ( SENDINFO_VECTORELEM(m_vecVelocity, 2), 32, SPROP_NOSCALE|SPROP_CHANGES_OFTEN ), SendPropVector ( SENDINFO( m_vecBaseVelocity ), 32, SPROP_NOSCALE ), + SendPropVector(SENDINFO(m_vecPreviouslyPreviouslyPredictedEyePosition), 32, SPROP_NOSCALE | SPROP_CHANGES_OFTEN), SendPropEHandle ( SENDINFO( m_hConstraintEntity)), SendPropVector ( SENDINFO( m_vecConstraintCenter), 0, SPROP_NOSCALE ), diff --git a/src/game/server/player.h b/src/game/server/player.h index d857a8bd597..d6d441f5486 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -914,7 +914,10 @@ class CBasePlayer : public CBaseCombatCharacter void ClearZoomOwner( void ); void SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin ); + void SetPreviouslyPreviouslyPredictedEyePosition(const Vector& vecAbsOrigin); const Vector &GetPreviouslyPredictedOrigin() const; + const Vector& GetPreviouslyPreviouslyPredictedEyePosition() const; + float GetFOVTime( void ){ return m_flFOVTime; } void AdjustDrownDmg( int nAmount ); @@ -1197,8 +1200,10 @@ class CBasePlayer : public CBaseCombatCharacter int m_nVehicleViewSavedFrame; // Used to mark which frame was the last one the view was calculated for Vector m_vecPreviouslyPredictedOrigin; // Used to determine if non-gamemovement game code has teleported, or tweaked the player's origin + CNetworkVar( Vector, m_vecPreviouslyPreviouslyPredictedEyePosition); // Used for attack interpolation int m_nBodyPitchPoseParam; + CNetworkString( m_szLastPlaceName, MAX_PLACE_NAME_LENGTH ); char m_szNetworkIDString[MAX_NETWORKID_LENGTH]; @@ -1273,9 +1278,6 @@ class CBasePlayer : public CBaseCombatCharacter bool m_bHasAttackInterpolationData = false; // Whether we have valid data float m_flAttackLerpTime = 1.0f; // Calculated lerp time for the attack bool m_bInPostThink; // Flag for post-think state - int m_nLastTickCount; // The tick count from the last time we processed - Vector m_vecLastTickEyePosition; // Eye position from the last tick - Vector m_vecCurrentTickEyePosition; // Current eye position for this tick public: virtual unsigned int PlayerSolidMask( bool brushOnly = false ) const; // returns the solid mask for the given player, so bots can have a more-restrictive set diff --git a/src/game/server/player_command.cpp b/src/game/server/player_command.cpp index 93da80fe694..c6d01d84aaf 100644 --- a/src/game/server/player_command.cpp +++ b/src/game/server/player_command.cpp @@ -141,7 +141,7 @@ void CPlayerMove::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *p { move->m_bGameCodeMovedPlayer = true; } - + player->SetPreviouslyPreviouslyPredictedEyePosition(player->GetAbsOrigin() + player->GetViewOffset()); // Prepare the usercmd fields move->m_nImpulseCommand = ucmd->impulse; move->m_vecViewAngles = ucmd->viewangles; diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 0a33b0c9679..50e95c17787 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -2073,11 +2073,21 @@ void CBasePlayer::SetPreviouslyPredictedOrigin( const Vector &vecAbsOrigin ) m_vecPreviouslyPredictedOrigin = vecAbsOrigin; } +void CBasePlayer::SetPreviouslyPreviouslyPredictedEyePosition(const Vector& vecAbsOrigin) +{ + m_vecPreviouslyPreviouslyPredictedEyePosition = vecAbsOrigin; +} + const Vector &CBasePlayer::GetPreviouslyPredictedOrigin() const { return m_vecPreviouslyPredictedOrigin; } +const Vector& CBasePlayer::GetPreviouslyPreviouslyPredictedEyePosition() const +{ + return m_vecPreviouslyPreviouslyPredictedEyePosition; +} + bool fogparams_t::operator !=( const fogparams_t& other ) const { if ( this->enable != other.enable || @@ -2141,61 +2151,18 @@ Vector CBasePlayer::GetInterpolatedEyePosition() if (!IsInPostThink() || !HasAttackInterpolationData()) return EyePosition(); - int currentTickCount = gpGlobals->tickcount; SetInPostThink(false); Vector currentEyePosition = EyePosition(); SetInPostThink(true); - // First call or tick count dropped - if (m_nLastTickCount <= 0 || currentTickCount < m_nLastTickCount) - { - // Initialize both positions - m_nLastTickCount = currentTickCount; - m_vecLastTickEyePosition = currentEyePosition; - m_vecCurrentTickEyePosition = currentEyePosition; - return currentEyePosition; - } - - // If this is a new tick - if (currentTickCount > m_nLastTickCount) - { - // Update the last tick's position - m_vecLastTickEyePosition = m_vecCurrentTickEyePosition; - m_nLastTickCount = currentTickCount; - } - - // Update the current eye position - m_vecCurrentTickEyePosition = currentEyePosition; - // Interpolate between the last tick's position and the current position - Vector interpolatedPosition = m_vecLastTickEyePosition + (m_vecCurrentTickEyePosition - m_vecLastTickEyePosition) * m_flAttackLerpTime; + Vector interpolatedPosition = GetPreviouslyPreviouslyPredictedEyePosition() + (currentEyePosition - GetPreviouslyPreviouslyPredictedEyePosition()) * m_flAttackLerpTime; // Calculate the distance between interpolated position and regular eye position float distance = (interpolatedPosition - currentEyePosition).Length(); // Log the distance using Msg() - //Msg("Interpolated eye position distance from regular eye position: %.3f units, m_flAttackLerpTime: %f\n", distance, m_flAttackLerpTime); + //ConDMsg("Interpolated eye position distance from regular eye position: %.3f units, m_flAttackLerpTime: %f\n", distance, m_flAttackLerpTime); return interpolatedPosition; } -/* -Vector CBasePlayer::GetInterpolatedEyePosition() -{ - if (!IsInPostThink() || !HasAttackInterpolationData()) - return EyePosition(); - - int currentTickCount = gpGlobals->tickcount; - SetInPostThink(false); - Vector currentEyePosition = EyePosition(); - SetInPostThink(true); - - Vector interpolatedPosition = (GetPreviouslyPredictedOrigin() + GetViewOffset()) + (currentEyePosition - (GetPreviouslyPredictedOrigin() + GetViewOffset())) * m_flAttackLerpTime; - - // Calculate the distance between interpolated position and regular eye position - float distance = (interpolatedPosition - currentEyePosition).Length(); - - // Log the distance using Msg() - Msg("Interpolated eye position distance from regular eye position: %.3f units, m_flAttackLerpTime: %f\n", distance, m_flAttackLerpTime); - - return interpolatedPosition; -}*/ \ No newline at end of file From f500a873cf5c5f47893cc8033e6266c50d258f68 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 01:17:13 -0500 Subject: [PATCH 06/12] Remove extra whitespace in player_lagcompensation.cpp --- src/game/server/player_lagcompensation.cpp | 68 +++++++++++++--------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/src/game/server/player_lagcompensation.cpp b/src/game/server/player_lagcompensation.cpp index 2d2113a6e3f..0449dec3495 100644 --- a/src/game/server/player_lagcompensation.cpp +++ b/src/game/server/player_lagcompensation.cpp @@ -342,41 +342,51 @@ void CLagCompensationManager::FrameUpdatePostEntityThink() } // Called during player movement to set up/restore after lag compensation -void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd* cmd) +void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) { - Assert(!m_isCurrentlyDoingCompensation); + Assert( !m_isCurrentlyDoingCompensation ); + //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG - if (m_pCurrentPlayer) + if ( m_pCurrentPlayer ) { - Assert(m_pCurrentPlayer == NULL); - Warning("Trying to start a new lag compensation session while one is already active!\n"); + Assert( m_pCurrentPlayer == NULL ); + Warning( "Trying to start a new lag compensation session while one is already active!\n" ); return; } + // Assume no players need to be restored m_RestorePlayer.ClearAll(); m_bNeedToRestore = false; + m_pCurrentPlayer = player; - if (!player->m_bLagCompensation // Player not wanting lag compensation - || (gpGlobals->maxClients <= 1) // no lag compensation in single player - || !sv_unlag.GetBool() // disabled by server admin - || player->IsBot() // not for bots - || player->IsObserver() // not for spectators + + if ( !player->m_bLagCompensation // Player not wanting lag compensation + || (gpGlobals->maxClients <= 1) // no lag compensation in single player + || !sv_unlag.GetBool() // disabled by server admin + || player->IsBot() // not for bots + || player->IsObserver() // not for spectators ) return; + // NOTE: Put this here so that it won't show up in single player mode. - VPROF_BUDGET("StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING); - Q_memset(m_RestoreData, 0, sizeof(m_RestoreData)); - Q_memset(m_ChangeData, 0, sizeof(m_ChangeData)); + VPROF_BUDGET( "StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING ); + Q_memset( m_RestoreData, 0, sizeof( m_RestoreData ) ); + Q_memset( m_ChangeData, 0, sizeof( m_ChangeData ) ); + m_isCurrentlyDoingCompensation = true; + // Get true latency - // correct is the amount of time we have to correct game time + + // correct is the amout of time we have to correct game time float correct = 0.0f; - INetChannelInfo* nci = engine->GetPlayerNetInfo(player->entindex()); - if (nci) + + INetChannelInfo *nci = engine->GetPlayerNetInfo( player->entindex() ); + + if ( nci ) { // add network latency - correct += nci->GetLatency(FLOW_OUTGOING); + correct+= nci->GetLatency( FLOW_OUTGOING ); } // add view interpolation latency directly using player's lerp time @@ -394,31 +404,37 @@ void CLagCompensationManager::StartLagCompensation(CBasePlayer* player, CUserCmd // correct tick send by player int targettick = cmd->tick_count - TIME_TO_TICKS(player->m_fLerpTime); // calc difference between tick send by player and our latency based tick - float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); - if (fabs(deltaTime) > 0.2f) + float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); + + if ( fabs( deltaTime ) > 0.2f ) { // difference between cmd time and latency is too big > 200ms, use time correction based on latency - targettick = gpGlobals->tickcount - TIME_TO_TICKS(correct); + // DevMsg("StartLagCompensation: delta too big (%.3f)\n", deltaTime ); + targettick = gpGlobals->tickcount - TIME_TO_TICKS( correct ); } // Add the interpolation amount float targettime = TICKS_TO_TIME(targettick) + extraTime; // Iterate all active players - const CBitVec* pEntityTransmitBits = engine->GetEntityTransmitBitsForClient(player->entindex() - 1); - for (int i = 1; i <= gpGlobals->maxClients; i++) + const CBitVec *pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { - CBasePlayer* pPlayer = UTIL_PlayerByIndex(i); - if (!pPlayer) + CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); + + if ( !pPlayer ) { continue; } + // Don't lag compensate yourself you loser... - if (player == pPlayer) + if ( player == pPlayer ) { continue; } + // Custom checks for if things should lag compensate (based on things like what team the player is on). - if (!player->WantsLagCompensationOnEntity(pPlayer, cmd, pEntityTransmitBits)) + if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) ) continue; + // Move other player back in time BacktrackPlayer(pPlayer, targettime); } From 1f0b74ec8213d2ba4b2e623142452a40cd54dc0c Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 01:19:31 -0500 Subject: [PATCH 07/12] Remove extra whitespace in baseplayer_shared.cpp --- src/game/shared/baseplayer_shared.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 50e95c17787..1ec178ba061 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -336,7 +336,7 @@ Vector CBasePlayer::EyePosition() return GetInterpolatedEyePosition(); } - if (GetVehicle() != NULL) + if ( GetVehicle() != NULL ) { // Return the cached result CacheVehicleView(); @@ -345,11 +345,11 @@ Vector CBasePlayer::EyePosition() else { #ifdef CLIENT_DLL - if (IsObserver()) + if ( IsObserver() ) { - if (GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_POI) + if ( GetObserverMode() == OBS_MODE_CHASE || GetObserverMode() == OBS_MODE_POI ) { - if (IsLocalPlayer()) + if ( IsLocalPlayer() ) { return MainViewOrigin(); } From 74f2b5418aa4a169c94451c0760148b823b26233 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 01:33:28 -0500 Subject: [PATCH 08/12] Fix movefix --- src/game/client/in_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/client/in_main.cpp b/src/game/client/in_main.cpp index 8a6186b6ac1..7fcf3aff3af 100644 --- a/src/game/client/in_main.cpp +++ b/src/game/client/in_main.cpp @@ -1315,7 +1315,7 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo cmd->lerp_time = lerpTime; // Fix movement commands for new viewangles - float deltaYaw = DEG2RAD(viewangles[YAW] - currentAngles[YAW]); + float deltaYaw = DEG2RAD(cmd->viewangles[YAW] - currentAngles[YAW]); float s = sin(deltaYaw); float c = cos(deltaYaw); From bd836de65798fc0553368f9cae6995d4d55e24ae Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 01:34:13 -0500 Subject: [PATCH 09/12] fix recursion --- src/game/shared/baseplayer_shared.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 1ec178ba061..3f7c60a6652 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -2148,12 +2148,13 @@ bool CBasePlayer::IsInPostThink() const } Vector CBasePlayer::GetInterpolatedEyePosition() { - if (!IsInPostThink() || !HasAttackInterpolationData()) - return EyePosition(); - SetInPostThink(false); Vector currentEyePosition = EyePosition(); SetInPostThink(true); + + if (!IsInPostThink() || !HasAttackInterpolationData()) { + return currentEyePosition; + } // Interpolate between the last tick's position and the current position Vector interpolatedPosition = GetPreviouslyPreviouslyPredictedEyePosition() + (currentEyePosition - GetPreviouslyPreviouslyPredictedEyePosition()) * m_flAttackLerpTime; From 500e60020ce6ac7a6487a057f85a711470885ef1 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 01:34:49 -0500 Subject: [PATCH 10/12] fix recursion fix (i forgot to preserve state) --- src/game/shared/baseplayer_shared.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/game/shared/baseplayer_shared.cpp b/src/game/shared/baseplayer_shared.cpp index 3f7c60a6652..059d8d7ccfb 100644 --- a/src/game/shared/baseplayer_shared.cpp +++ b/src/game/shared/baseplayer_shared.cpp @@ -2148,9 +2148,10 @@ bool CBasePlayer::IsInPostThink() const } Vector CBasePlayer::GetInterpolatedEyePosition() { + bool wasInPostThink = IsInPostThink(); SetInPostThink(false); Vector currentEyePosition = EyePosition(); - SetInPostThink(true); + SetInPostThink(wasInPostThink); if (!IsInPostThink() || !HasAttackInterpolationData()) { return currentEyePosition; From b0682b406398ec26543f3c221a57cfb7000b8245 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 01:45:59 -0500 Subject: [PATCH 11/12] fix movefix (i had the sign backwards) --- src/game/client/in_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/client/in_main.cpp b/src/game/client/in_main.cpp index 7fcf3aff3af..f5b748c7b24 100644 --- a/src/game/client/in_main.cpp +++ b/src/game/client/in_main.cpp @@ -1315,7 +1315,7 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo cmd->lerp_time = lerpTime; // Fix movement commands for new viewangles - float deltaYaw = DEG2RAD(cmd->viewangles[YAW] - currentAngles[YAW]); + float deltaYaw = DEG2RAD(currentAngles[YAW] - cmd->viewangles[YAW]); float s = sin(deltaYaw); float c = cos(deltaYaw); From b1b2f88ebd7423c2602757063da489a5e7805403 Mon Sep 17 00:00:00 2001 From: dr3murr Date: Thu, 27 Feb 2025 02:03:00 -0500 Subject: [PATCH 12/12] remove extra line by mistake lol --- src/game/client/prediction.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/game/client/prediction.cpp b/src/game/client/prediction.cpp index 26b8e8fa901..3aff217c278 100644 --- a/src/game/client/prediction.cpp +++ b/src/game/client/prediction.cpp @@ -708,7 +708,6 @@ void CPrediction::FinishMove( C_BasePlayer *player, CUserCmd *ucmd, CMoveData *m player->SetAbsVelocity( move->m_vecVelocity ); player->m_vecNetworkOrigin = move->GetAbsOrigin(); - player->SetPreviouslyPreviouslyPredictedEyePosition(player->GetPreviouslyPreviouslyPredictedEyePosition()); player->SetPreviouslyPredictedOrigin( move->GetAbsOrigin() ); player->m_Local.m_nOldButtons = move->m_nButtons;