From f696159421b7a78b7edcefdcd98650d2e36299e3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 3 Sep 2024 22:44:31 +0200 Subject: [PATCH] Improved lag compensation for entities --- common/netmessages.cpp | 4 +- engine/cl_main.cpp | 2 +- game/client/c_baseanimating.h | 10 +- game/client/cstrike/c_cs_player.cpp | 31 +- game/client/cstrike/c_cs_player.h | 4 +- game/client/in_main.cpp | 20 +- game/server/BaseAnimatingOverlay.cpp | 2 +- game/server/baseanimating.cpp | 16 +- game/server/baseentity.h | 2 - game/server/cstrike/cs_player.cpp | 12 +- game/server/cstrike/cs_player.h | 3 - game/server/ilagcompensationmanager.h | 12 +- game/server/player.cpp | 19 +- game/server/player.h | 3 +- game/server/player_command.cpp | 6 +- game/server/player_lagcompensation.cpp | 643 ++++++++++------------- game/shared/cstrike/cs_player_shared.cpp | 4 +- game/shared/cstrike/fx_cs_shared.cpp | 13 +- game/shared/cstrike/weapon_knife.cpp | 7 - wscript | 2 +- 20 files changed, 381 insertions(+), 434 deletions(-) diff --git a/common/netmessages.cpp b/common/netmessages.cpp index aaf709c3cd..01a88b9f7d 100644 --- a/common/netmessages.cpp +++ b/common/netmessages.cpp @@ -78,7 +78,7 @@ bool CLC_Move::WriteToBuffer( bf_write &buffer ) buffer.WriteUBitLong( m_nNewCommands, NUM_NEW_COMMAND_BITS ); buffer.WriteUBitLong( m_nBackupCommands, NUM_BACKUP_COMMAND_BITS ); - buffer.WriteWord( m_nLength ); + buffer.WriteLong( m_nLength ); return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); } @@ -89,7 +89,7 @@ bool CLC_Move::ReadFromBuffer( bf_read &buffer ) m_nNewCommands = buffer.ReadUBitLong( NUM_NEW_COMMAND_BITS ); m_nBackupCommands = buffer.ReadUBitLong( NUM_BACKUP_COMMAND_BITS ); - m_nLength = buffer.ReadWord(); + m_nLength = buffer.ReadLong(); m_DataIn = buffer; return buffer.SeekRelative( m_nLength ); } diff --git a/engine/cl_main.cpp b/engine/cl_main.cpp index f7b7776038..24f4eaf40f 100644 --- a/engine/cl_main.cpp +++ b/engine/cl_main.cpp @@ -91,7 +91,7 @@ void WriteConfig_f( ConVar *var, const char *pOldString ); // If we get more than 250 messages in the incoming buffer queue, dump any above this # #define MAX_INCOMING_MESSAGES 250 // Size of command send buffer -#define MAX_CMD_BUFFER 0x10000 +#define MAX_CMD_BUFFER 0x100000 CGlobalVarsBase g_ClientGlobalVariables( true ); IVideoRecorder *g_pVideoRecorder = NULL; diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h index 3871b2b4bd..e64770a77f 100644 --- a/game/client/c_baseanimating.h +++ b/game/client/c_baseanimating.h @@ -106,7 +106,15 @@ public: C_BaseAnimating(); ~C_BaseAnimating(); - virtual C_BaseAnimating* GetBaseAnimating() { return this; } + virtual C_BaseAnimating* GetBaseAnimating() + { + return this; + } + + bool IsUsingClientSideAnimation() + { + return m_bClientSideAnimation; + } bool UsesPowerOfTwoFrameBufferTexture( void ); diff --git a/game/client/cstrike/c_cs_player.cpp b/game/client/cstrike/c_cs_player.cpp index a119b2dd91..13604e873a 100644 --- a/game/client/cstrike/c_cs_player.cpp +++ b/game/client/cstrike/c_cs_player.cpp @@ -690,7 +690,6 @@ IMPLEMENT_CLIENTCLASS_DT( C_CSPlayer, DT_CSPlayer, CCSPlayer ) RecvPropInt( RECVINFO( m_iClass ) ), RecvPropInt( RECVINFO( m_ArmorValue ) ), RecvPropQAngles( RECVINFO( m_angEyeAngles ) ), - RecvPropQAngles( RECVINFO( m_angRenderAngles ) ), RecvPropFloat( RECVINFO( m_flStamina ) ), RecvPropInt( RECVINFO( m_bHasDefuser ), 0, RecvProxy_HasDefuser ), RecvPropInt( RECVINFO( m_bNightVisionOn), 0, RecvProxy_NightVision ), @@ -736,10 +735,8 @@ C_CSPlayer::C_CSPlayer() : m_iv_angRenderAngles( "C_CSPlayer::m_iv_angRenderAngles" ) { m_angEyeAngles.Init(); - m_angRenderAngles.Init(); AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR ); - // AddVar( &m_angRenderAngles, &m_iv_angRenderAngles, LATCH_SIMULATION_VAR ); m_iLastAddonBits = m_iAddonBits = 0; m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE; @@ -890,7 +887,7 @@ const QAngle& C_CSPlayer::GetRenderAngles() } else { - return m_angRenderAngles; + return BaseClass::GetRenderAngles(); } } @@ -2183,7 +2180,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event ) C_AnimationLayer backupAnimLayers[C_BaseAnimatingOverlay::MAX_OVERLAYS]; Vector vecBackupPosition = player->GetAbsOrigin(); - QAngle angBackupAngles = player->GetRenderAngles(); + QAngle angBackupAngles = player->GetAbsAngles(); auto flOldCycle = player->GetCycle(); auto iOldSequence = player->GetSequence(); @@ -2208,9 +2205,9 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event ) event->GetFloat( "position_y" ), event->GetFloat( "position_z" ) ) ); - player->m_angRenderAngles = QAngle( event->GetFloat( "angle_x" ), - event->GetFloat( "angle_y" ), - event->GetFloat( "angle_z" ) ); + player->SetAbsAngles( QAngle( event->GetFloat( "angle_x" ), + event->GetFloat( "angle_y" ), + event->GetFloat( "angle_z" ) ) ); const auto numposeparams = event->GetInt( "num_poseparams" ); Assert( numposeparams == player->GetModelPtr()->GetNumPoseParameters() ); @@ -2314,17 +2311,19 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event ) pos++; } - if ( pRecord->m_angRenderAngles != player->m_angRenderAngles ) + auto angles = player->GetAbsAngles(); + + if ( pRecord->m_angAbsRotation != angles ) { char buffer[256]; V_sprintf_safe( buffer, "angles: %f != %f, %f != %f, %f != %f", - player->m_angRenderAngles.x, - pRecord->m_angRenderAngles.x, - player->m_angRenderAngles.y, - pRecord->m_angRenderAngles.y, - player->m_angRenderAngles.z, - pRecord->m_angRenderAngles.z ); + angles.x, + pRecord->m_angAbsRotation.x, + angles.y, + pRecord->m_angAbsRotation.y, + angles.z, + pRecord->m_angAbsRotation.z ); NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration ); pos++; @@ -2441,7 +2440,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event ) player->m_nSequence = iOldSequence; player->m_flCycle = flOldCycle; player->SetAbsOrigin( vecBackupPosition ); - player->m_angRenderAngles = angBackupAngles; + player->SetAbsAngles( angBackupAngles ); for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ ) { diff --git a/game/client/cstrike/c_cs_player.h b/game/client/cstrike/c_cs_player.h index 080114ce68..7ea2c6c0c8 100644 --- a/game/client/cstrike/c_cs_player.h +++ b/game/client/cstrike/c_cs_player.h @@ -325,9 +325,7 @@ private: bool m_bHasHelmet; int m_iClass; int m_ArmorValue; -public: QAngle m_angEyeAngles; - QAngle m_angRenderAngles; private: bool m_bHasDefuser; float m_fNextThinkPushAway; @@ -411,7 +409,7 @@ private: { int m_nAttackerTickBase; Vector m_vecAbsOrigin; - QAngle m_angRenderAngles; + QAngle m_angAbsRotation; float m_flSimulationTime; int m_nSequence; float m_flCycle; diff --git a/game/client/in_main.cpp b/game/client/in_main.cpp index 59830feb5c..4b0f1ece9f 100644 --- a/game/client/in_main.cpp +++ b/game/client/in_main.cpp @@ -1306,21 +1306,33 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo for ( int i = 0; i < MAX_EDICTS; i++ ) { - cmd->simulationdata[i].entityexists = false; + cmd->simulationdata[i] = {}; } // Send interpolated simulation time for lag compensation, let it also auto-vectorize this. for ( int i = 0; i < MAX_EDICTS; i++ ) { - auto pEntity = ClientEntityList().GetEnt( i ); + const auto pEntity = ClientEntityList().GetEnt( i ); if ( !pEntity ) { continue; } - cmd->simulationdata[pEntity->index].sim_time = pEntity->m_flInterpolatedSimulationTime; - cmd->simulationdata[pEntity->index].anim_time = pEntity->m_flAnimTime; + if ( pEntity->ShouldPredict() ) + { + continue; + } + + cmd->simulationdata[pEntity->index].sim_time = pEntity->m_flInterpolatedSimulationTime; + + auto pAnim = pEntity->GetBaseAnimating(); + + if ( pAnim && !pAnim->IsUsingClientSideAnimation() ) + { + cmd->simulationdata[pEntity->index].anim_time = pEntity->m_flAnimTime; + } + cmd->simulationdata[pEntity->index].entityexists = true; } diff --git a/game/server/BaseAnimatingOverlay.cpp b/game/server/BaseAnimatingOverlay.cpp index 929f251600..d0490c028e 100644 --- a/game/server/BaseAnimatingOverlay.cpp +++ b/game/server/BaseAnimatingOverlay.cpp @@ -480,7 +480,7 @@ void CBaseAnimatingOverlay::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Q if ( m_pIk ) { CIKContext auto_ik; - auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); + auto_ik.Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik ); } else diff --git a/game/server/baseanimating.cpp b/game/server/baseanimating.cpp index 5dc8be5b76..3eecf9a0fc 100644 --- a/game/server/baseanimating.cpp +++ b/game/server/baseanimating.cpp @@ -1670,7 +1670,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime ) // FIXME: trace based on gravity or trace based on angles? Vector up; - AngleVectors( GetRenderAngles(), NULL, NULL, &up ); + AngleVectors( GetAbsAngles(), NULL, NULL, &up ); // FIXME: check number of slots? float minHeight = FLT_MAX; @@ -1692,7 +1692,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime ) Vector p1, p2; // adjust ground to original ground position - estGround = (pTarget->est.pos - GetRenderOrigin()); + estGround = (pTarget->est.pos - GetAbsOrigin()); estGround = estGround - (estGround * up) * up; estGround = GetAbsOrigin() + estGround + pTarget->est.floor * up; @@ -1781,7 +1781,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime ) else if (trace.DidHitNonWorldEntity()) { pTarget->SetPos( trace.endpos ); - pTarget->SetAngles( GetRenderAngles() ); + pTarget->SetAngles( GetAbsAngles() ); // only do this on forward tracking or commited IK ground rules if (pTarget->est.release < 0.1) @@ -1815,7 +1815,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime ) else { pTarget->SetPos( trace.endpos ); - pTarget->SetAngles( GetRenderAngles() ); + pTarget->SetAngles( GetAbsAngles() ); pTarget->SetOnWorld( true ); } } @@ -2031,7 +2031,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) // FIXME: pass this into Studio_BuildMatrices to skip transforms CBoneBitList boneComputed; m_iIKCounter++; - m_pIk->Init( pStudioHdr, GetRenderAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask ); + m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask ); GetSkeleton( pStudioHdr, pos, q, boneMask ); UpdateIKLocks( gpGlobals->curtime ); @@ -2055,7 +2055,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) { BuildMatricesWithBoneMerge( pStudioHdr, - GetRenderAngles(), + GetAbsAngles(), adjOrigin, pos, q, @@ -2074,7 +2074,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) Studio_BuildMatrices( pStudioHdr, - GetRenderAngles(), + GetAbsAngles(), adjOrigin, pos, q, @@ -3036,7 +3036,7 @@ void CBaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaterni if ( m_pIk ) { CIKContext auto_ik; - auto_ik.Init( pStudioHdr, GetRenderAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); + auto_ik.Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik ); } else diff --git a/game/server/baseentity.h b/game/server/baseentity.h index 6592911a68..04d3861077 100644 --- a/game/server/baseentity.h +++ b/game/server/baseentity.h @@ -426,8 +426,6 @@ public: bool IsCurrentlyTouching( void ) const; const Vector& GetAbsOrigin( void ) const; const QAngle& GetAbsAngles( void ) const; - virtual const Vector& GetRenderOrigin( void ) const { return GetAbsOrigin(); } - virtual const QAngle& GetRenderAngles( void ) const { return GetAbsAngles(); } SolidType_t GetSolid() const; int GetSolidFlags( void ) const; diff --git a/game/server/cstrike/cs_player.cpp b/game/server/cstrike/cs_player.cpp index f8de625efa..e9adf4777d 100644 --- a/game/server/cstrike/cs_player.cpp +++ b/game/server/cstrike/cs_player.cpp @@ -302,7 +302,6 @@ IMPLEMENT_SERVERCLASS_ST( CCSPlayer, DT_CSPlayer ) SendPropInt( SENDINFO( m_iClass ), Q_log2( CS_NUM_CLASSES )+1, SPROP_UNSIGNED ), SendPropInt( SENDINFO( m_ArmorValue ), 8 ), SendPropQAngles(SENDINFO(m_angEyeAngles)), - SendPropQAngles(SENDINFO(m_angRenderAngles)), SendPropBool( SENDINFO( m_bHasDefuser ) ), SendPropBool( SENDINFO( m_bNightVisionOn ) ), //send as int so we can use a RecvProxy on the client SendPropBool( SENDINFO( m_bHasNightVision ) ), @@ -1164,7 +1163,7 @@ void CCSPlayer::Event_Killed( const CTakeDamageInfo &info ) { if ( RandomInt( 0, 100 ) < 20 ) { - CHolidayGift::Create( WorldSpaceCenter(), GetRenderAngles(), EyeAngles(), GetAbsVelocity(), this ); + CHolidayGift::Create( WorldSpaceCenter(), GetAbsAngles(), EyeAngles(), GetAbsVelocity(), this ); } } @@ -1455,7 +1454,7 @@ void CCSPlayer::UpdateRadar() WRITE_SBITLONG( pPlayer->GetAbsOrigin().x/4, COORD_INTEGER_BITS-1 ); WRITE_SBITLONG( pPlayer->GetAbsOrigin().y/4, COORD_INTEGER_BITS-1 ); WRITE_SBITLONG( pPlayer->GetAbsOrigin().z/4, COORD_INTEGER_BITS-1 ); - WRITE_SBITLONG( AngleNormalize( pPlayer->GetRenderAngles().y ), 9 ); + WRITE_SBITLONG( AngleNormalize( pPlayer->GetAbsAngles().y ), 9 ); } WRITE_BYTE( 0 ); // end marker @@ -1584,7 +1583,8 @@ void CCSPlayer::PostThink() m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] ); - m_angRenderAngles = m_PlayerAnimState->GetRenderAngles(); + // Use the m_angRotation instead. + SetAbsAngles( m_PlayerAnimState->GetRenderAngles() ); // check if we need to apply a deafness DSP effect. if ((m_applyDeafnessTime != 0.0f) && (m_applyDeafnessTime <= gpGlobals->curtime)) @@ -2780,7 +2780,7 @@ void CCSPlayer::DropShield( void ) #ifdef CS_SHIELD_ENABLED //Drop an item_defuser Vector vForward, vRight; - AngleVectors( GetRenderAngles(), &vForward, &vRight, NULL ); + AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL ); RemoveShield(); @@ -6719,7 +6719,7 @@ void CCSPlayer::DropWeapons( bool fromDeath, bool friendlyFire ) { //Drop an item_defuser Vector vForward, vRight; - AngleVectors( GetRenderAngles(), &vForward, &vRight, NULL ); + AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL ); CBaseAnimating *pDefuser = (CBaseAnimating *)CBaseEntity::Create( "item_defuser", WorldSpaceCenter(), GetLocalAngles(), this ); pDefuser->ApplyAbsVelocityImpulse( vForward * 200 + vRight * random->RandomFloat( -50, 50 ) ); diff --git a/game/server/cstrike/cs_player.h b/game/server/cstrike/cs_player.h index 70f6b3b386..617c9548b1 100644 --- a/game/server/cstrike/cs_player.h +++ b/game/server/cstrike/cs_player.h @@ -288,8 +288,6 @@ public: virtual int GetNextObserverSearchStartPoint( bool bReverse ); - virtual const QAngle& GetRenderAngles( void ) const { return m_angRenderAngles; } - // In shared code. public: @@ -816,7 +814,6 @@ public: // Copyed from EyeAngles() so we can send it to the client. CNetworkQAngle( m_angEyeAngles ); - CNetworkQAngle( m_angRenderAngles ); bool m_bVCollisionInitted; diff --git a/game/server/ilagcompensationmanager.h b/game/server/ilagcompensationmanager.h index 5970ce6137..e1e3a4c40a 100644 --- a/game/server/ilagcompensationmanager.h +++ b/game/server/ilagcompensationmanager.h @@ -7,11 +7,15 @@ #ifndef ILAGCOMPENSATIONMANAGER_H #define ILAGCOMPENSATIONMANAGER_H + #ifdef _WIN32 #pragma once #endif +#include "platform.h" + class CBasePlayer; +class CBaseEntity; class CUserCmd; //----------------------------------------------------------------------------- @@ -19,12 +23,10 @@ class CUserCmd; //----------------------------------------------------------------------------- abstract_class ILagCompensationManager { -public: + public: // Called during player movement to set up/restore after lag compensation - virtual void StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) = 0; - virtual void FinishLagCompensation(CBasePlayer *player) = 0; - virtual void BacktrackPlayer( CBasePlayer *player, CUserCmd *cmd ) = 0; - virtual void TrackPlayerData( CBasePlayer *pPlayer ) = 0; + virtual void StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ) = 0; + virtual void FinishLagCompensation( CBasePlayer* player ) = 0; }; extern ILagCompensationManager *lagcompensation; diff --git a/game/server/player.cpp b/game/server/player.cpp index 75b48a7a40..b04feed755 100644 --- a/game/server/player.cpp +++ b/game/server/player.cpp @@ -746,12 +746,17 @@ static void NormalizeAngles( QAngle& angles ) } } -bool CBasePlayer::WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec *pEntityTransmitBits ) +bool CBasePlayer::WantsLagCompensationOnEntity( const CBaseEntity *pEntity, const CUserCmd *pCmd, const CBitVec *pEntityTransmitBits ) { // Team members shouldn't be adjusted unless friendly fire is on. - if ( !friendlyfire.GetInt() && pPlayer->GetTeamNumber() == GetTeamNumber() ) + if ( !friendlyfire.GetInt() && pEntity->GetTeamNumber() == GetTeamNumber() ) return false; + if ( pEntity->GetOwnerEntity() == this ) + { + return false; + } + // NOTE: Do not check for this, it is possible to knife from behind in CS:S // Vector vShootPosition = Weapon_ShootPosition(); // const Vector &vHisOrigin = pPlayer->GetAbsOrigin(); @@ -7929,12 +7934,12 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data) // If HL2_DLL is defined, then baseflex.cpp already sends these. #ifndef HL2_DLL - SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 0), -1, 0, -32.0, 32.0f), - SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 1), -1, 0, -32.0, 32.0f), - SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 2), -1, 0, 0.0f, 256.0f), + SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 0)), + SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 1)), + SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 2)), #endif - SendPropFloat ( SENDINFO(m_flFriction), 8, SPROP_ROUNDDOWN, 0.0f, 4.0f), + SendPropFloat ( SENDINFO(m_flFriction) ), SendPropArray3 ( SENDINFO_ARRAY3(m_iAmmo), SendPropInt( SENDINFO_ARRAY(m_iAmmo), -1, SPROP_VARINT | SPROP_UNSIGNED ) ), @@ -7956,7 +7961,7 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data) SendPropVector ( SENDINFO( m_vecBaseVelocity ), -1, SPROP_NOSCALE ), #endif - SendPropEHandle ( SENDINFO( m_hConstraintEntity)), + SendPropEHandle ( SENDINFO( m_hConstraintEntity )), SendPropVector ( SENDINFO( m_vecConstraintCenter), 0, SPROP_NOSCALE ), SendPropFloat ( SENDINFO( m_flConstraintRadius ), 0, SPROP_NOSCALE ), SendPropFloat ( SENDINFO( m_flConstraintWidth ), 0, SPROP_NOSCALE ), diff --git a/game/server/player.h b/game/server/player.h index 0fca6d6c03..460a1ce616 100644 --- a/game/server/player.h +++ b/game/server/player.h @@ -6,6 +6,7 @@ #ifndef PLAYER_H #define PLAYER_H +#include "baseentity.h" #ifdef _WIN32 #pragma once #endif @@ -282,7 +283,7 @@ public: // Returns true if this player wants pPlayer to be moved back in time when this player runs usercmds. // Saves a lot of overhead on the server if we can cull out entities that don't need to lag compensate // (like team members, entities out of our PVS, etc). - virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec *pEntityTransmitBits ); + virtual bool WantsLagCompensationOnEntity( const CBaseEntity *pEntity, const CUserCmd *pCmd, const CBitVec *pEntityTransmitBits ); virtual void Spawn( void ); virtual void Activate( void ); diff --git a/game/server/player_command.cpp b/game/server/player_command.cpp index d529f88121..b6a1e35785 100644 --- a/game/server/player_command.cpp +++ b/game/server/player_command.cpp @@ -308,8 +308,12 @@ void CPlayerMove::RunPostThink( CBasePlayer *player ) { VPROF( "CPlayerMove::RunPostThink" ); + lagcompensation->StartLagCompensation( player, player->GetCurrentCommand() ); + // Run post-think player->PostThink(); + + lagcompensation->FinishLagCompensation( player ); } void CommentarySystem_PePlayerRunCommand( CBasePlayer *player, CUserCmd *ucmd ); @@ -467,6 +471,4 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper { player->m_nTickBase++; } - - lagcompensation->TrackPlayerData( player ); } diff --git a/game/server/player_lagcompensation.cpp b/game/server/player_lagcompensation.cpp index d08af9b61f..7379d94e6b 100644 --- a/game/server/player_lagcompensation.cpp +++ b/game/server/player_lagcompensation.cpp @@ -6,9 +6,6 @@ //=============================================================================// #include "cbase.h" -#ifdef CSTRIKE_DLL -#include "cs_player.h" -#endif #include "icvar.h" #include "player.h" #include "shareddefs.h" @@ -34,9 +31,10 @@ #define LC_ANIMATION_CHANGED ( 1 << 11 ) #define LC_POSE_PARAMS_CHANGED ( 1 << 12 ) #define LC_ENCD_CONS_CHANGED ( 1 << 13 ) +#define LC_ANIM_OVERS_CHANGED ( 1 << 14 ) // Default to 1 second max. -#define MAX_TICKS_SAVED 1000 +#define MAX_TICKS_SAVED 1024 ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" ); // Enable by default to avoid some bugs. @@ -53,84 +51,11 @@ struct LayerRecord float m_weight; int m_order; int m_flags; - - LayerRecord() - { - m_sequence = 0; - m_cycle = 0; - m_weight = 0; - m_order = 0; - m_flags = 0; - } }; struct LagRecord { public: - LagRecord() - { - m_fFlags = LC_NONE; - m_vecOrigin.Init(); - m_vecAngles.Init(); - m_vecMinsPreScaled.Init(); - m_vecMaxsPreScaled.Init(); - m_flSimulationTime = -1; - m_flAnimTime = -1; - m_masterSequence = 0; - m_masterCycle = 0; - - for ( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex ) - { - m_layerRecords[layerIndex] = {}; - } - - for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ ) - { - m_poseParameters[i] = 0; - } - - for ( int i = 0; i < MAXSTUDIOBONECTRLS; i++ ) - { - m_encodedControllers[i] = 0; - } -#ifdef CSTRIKE_DLL - m_angRenderAngles.Init(); -#endif - } - - LagRecord( const LagRecord& src ) - { - m_fFlags = src.m_fFlags; - m_vecOrigin = src.m_vecOrigin; - m_vecAngles = src.m_vecAngles; - m_vecMinsPreScaled = src.m_vecMinsPreScaled; - m_vecMaxsPreScaled = src.m_vecMaxsPreScaled; - m_flSimulationTime = src.m_flSimulationTime; - m_flAnimTime = src.m_flAnimTime; - - for ( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex ) - { - m_layerRecords[layerIndex] = src.m_layerRecords[layerIndex]; - } - - m_masterSequence = src.m_masterSequence; - m_masterCycle = src.m_masterCycle; - - for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ ) - { - m_poseParameters[i] = src.m_poseParameters[i]; - } - - for ( int i = 0; i < MAXSTUDIOBONECTRLS; i++ ) - { - m_encodedControllers[i] = src.m_encodedControllers[i]; - } - -#ifdef CSTRIKE_DLL - m_angRenderAngles = src.m_angRenderAngles; -#endif - } - // Did player die this frame int m_fFlags; @@ -149,9 +74,6 @@ struct LagRecord float m_masterCycle; float m_poseParameters[MAXSTUDIOPOSEPARAM]; float m_encodedControllers[MAXSTUDIOBONECTRLS]; -#ifdef CSTRIKE_DLL - QAngle m_angRenderAngles; -#endif }; // @@ -163,28 +85,28 @@ ConVar sv_unlag_debug( "sv_unlag_debug", "0" ); float g_flFractionScale = 0.95; -static void RestorePlayerTo( CBasePlayer* pPlayer, const Vector& vWantedPos ) +static void RestorePlayerTo( CBaseEntity* pEntity, const Vector& vWantedPos ) { // Try to move to the wanted position from our current position. trace_t tr; VPROF_BUDGET( "RestorePlayerTo", "CLagCompensationManager" ); - UTIL_TraceEntity( pPlayer, vWantedPos, vWantedPos, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &tr ); + UTIL_TraceEntity( pEntity, vWantedPos, vWantedPos, MASK_PLAYERSOLID, pEntity->GetRefEHandle().Get(), COLLISION_GROUP_PLAYER_MOVEMENT, &tr ); if ( tr.startsolid || tr.allsolid ) { if ( sv_unlag_debug.GetBool() ) { - DevMsg( "RestorePlayerTo() could not restore player position for client \"%s\" ( %.1f %.1f %.1f )\n", - pPlayer->GetPlayerName(), + DevMsg( "RestorePlayerTo() could not restore player position for client \"%i\" ( %.1f %.1f %.1f )\n", + pEntity->entindex(), vWantedPos.x, vWantedPos.y, vWantedPos.z ); } - UTIL_TraceEntity( pPlayer, - pPlayer->GetAbsOrigin(), + UTIL_TraceEntity( pEntity, + pEntity->GetAbsOrigin(), vWantedPos, MASK_PLAYERSOLID, - pPlayer, + pEntity->GetRefEHandle().Get(), COLLISION_GROUP_PLAYER_MOVEMENT, &tr ); if ( tr.startsolid || tr.allsolid ) @@ -200,8 +122,8 @@ static void RestorePlayerTo( CBasePlayer* pPlayer, const Vector& vWantedPos ) { // We can get to a valid place, but not all the way back to where we were. Vector vPos; - VectorLerp( pPlayer->GetAbsOrigin(), vWantedPos, tr.fraction * g_flFractionScale, vPos ); - UTIL_SetOrigin( pPlayer, vPos, true ); + VectorLerp( pEntity->GetAbsOrigin(), vWantedPos, tr.fraction * g_flFractionScale, vPos ); + UTIL_SetOrigin( pEntity, vPos, true ); if ( sv_unlag_debug.GetBool() ) { @@ -212,7 +134,7 @@ static void RestorePlayerTo( CBasePlayer* pPlayer, const Vector& vWantedPos ) else { // Cool, the player can go back to whence he came. - UTIL_SetOrigin( pPlayer, tr.endpos, true ); + UTIL_SetOrigin( pEntity, tr.endpos, true ); } } @@ -228,12 +150,12 @@ class CLagCompensationManager : public CAutoGameSystemPerFrame, } // IServerSystem stuff - virtual void Shutdown() + void Shutdown() override { ClearHistory(); } - virtual void LevelShutdownPostEntity() + void LevelShutdownPostEntity() override { ClearHistory(); } @@ -241,12 +163,10 @@ class CLagCompensationManager : public CAutoGameSystemPerFrame, // ILagCompensationManager stuff // Called during player movement to set up/restore after lag compensation - void StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ); - void FinishLagCompensation( CBasePlayer* player ); - virtual void TrackPlayerData( CBasePlayer* pPlayer ); - - private: - void BacktrackPlayer( CBasePlayer* player, CUserCmd* cmd ); + void StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ) override; + void FinishLagCompensation( CBasePlayer* player ) override; + void TrackEntities( void ); + inline void BacktrackEntity( CBaseEntity* pEntity, int loopIndex, CUserCmd* cmd ); void ClearHistory() { @@ -256,11 +176,16 @@ class CLagCompensationManager : public CAutoGameSystemPerFrame, } } + void FrameUpdatePostEntityThink() override + { + TrackEntities(); + } + // keep a list of lag records for each entities CUtlCircularBuffer< LagRecord, MAX_TICKS_SAVED > m_EntityTrack[MAX_EDICTS]; // Scratchpad for determining what needs to be restored - CBitVec< MAX_EDICTS > m_RestorePlayer; + CBitVec< MAX_EDICTS > m_RestoreEntity; bool m_bNeedToRestore; LagRecord m_RestoreData[MAX_EDICTS]; // entities data before we moved him back @@ -273,92 +198,95 @@ ILagCompensationManager* lagcompensation = &g_LagCompensationManager; //----------------------------------------------------------------------------- // Purpose: Called once per frame after all entities have had a chance to think //----------------------------------------------------------------------------- -void CLagCompensationManager::TrackPlayerData( CBasePlayer* pPlayer ) -{ - if ( ( gpGlobals->maxClients <= 1 ) || !sv_unlag.GetBool() ) +void CLagCompensationManager::TrackEntities() +{ + LagRecord record; + + if ( !sv_unlag.GetBool() ) { ClearHistory(); return; } - VPROF_BUDGET( "TrackPlayerData", "CLagCompensationManager" ); + VPROF_BUDGET( "TrackEntities", "CLagCompensationManager" ); - // remove all records before that time: - auto track = &m_EntityTrack[pPlayer->entindex()]; - - // add new record to player track - LagRecord record; - - record.m_fFlags = LC_NONE; - if ( pPlayer->IsAlive() ) + for ( int i = 0; i < MAX_EDICTS; i++ ) { - record.m_fFlags |= LC_ALIVE; - } + CBaseEntity* pEntity = UTIL_EntityByIndex( i ); - record.m_flSimulationTime = pPlayer->GetSimulationTime(); - record.m_flAnimTime = pPlayer->GetAnimTime(); - record.m_vecAngles = pPlayer->GetAbsAngles(); - record.m_vecOrigin = pPlayer->GetAbsOrigin(); - record.m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); - record.m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled(); - - int layerCount = pPlayer->GetNumAnimOverlays(); - - for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) - { - CAnimationLayer* currentLayer = pPlayer->GetAnimOverlay( layerIndex ); - if ( currentLayer ) + if ( !pEntity ) { - record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; - record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; - record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; - record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; - record.m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags; + continue; } - } - record.m_masterSequence = pPlayer->GetSequence(); - record.m_masterCycle = pPlayer->GetCycle(); + // remove all records before that time: + auto track = &m_EntityTrack[i]; - CStudioHdr* hdr = pPlayer->GetModelPtr(); + // add new record to player track - if ( hdr ) - { - for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) + record.m_fFlags = LC_NONE; + record.m_flSimulationTime = pEntity->GetSimulationTime(); + record.m_flAnimTime = pEntity->GetAnimTime(); + record.m_vecAngles = pEntity->GetAbsAngles(); + record.m_vecOrigin = pEntity->GetAbsOrigin(); + record.m_vecMinsPreScaled = pEntity->CollisionProp()->OBBMinsPreScaled(); + record.m_vecMaxsPreScaled = pEntity->CollisionProp()->OBBMaxsPreScaled(); + + auto pAnim = dynamic_cast< CBaseAnimating* >( pEntity ); + + if ( pAnim ) { - record.m_poseParameters[paramIndex] = pPlayer->GetPoseParameterArray()[paramIndex]; - } - } + record.m_masterSequence = pAnim->GetSequence(); + record.m_masterCycle = pAnim->GetCycle(); - if ( hdr ) - { - for ( int boneIndex = 0; boneIndex < hdr->GetNumBoneControllers(); boneIndex++ ) + CStudioHdr* hdr = pAnim->GetModelPtr(); + + if ( hdr ) + { + for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) + { + record.m_poseParameters[paramIndex] = pAnim->GetPoseParameterArray()[paramIndex]; + } + + for ( int boneIndex = 0; boneIndex < hdr->GetNumBoneControllers(); boneIndex++ ) + { + record.m_encodedControllers[boneIndex] = pAnim->GetBoneControllerArray()[boneIndex]; + } + } + } + + auto pAnimOverlay = dynamic_cast< CBaseAnimatingOverlay* >( pEntity ); + + if ( pAnimOverlay ) { - record.m_encodedControllers[boneIndex] = pPlayer->GetBoneControllerArray()[boneIndex]; + int layerCount = pAnimOverlay->GetNumAnimOverlays(); + + for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) + { + CAnimationLayer* currentLayer = pAnimOverlay->GetAnimOverlay( layerIndex ); + if ( currentLayer ) + { + record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; + record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; + record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; + record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; + record.m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags; + } + } } + + track->Push( record ); } - -#ifdef CSTRIKE_DLL - const auto csPlayer = ToCSPlayer( pPlayer ); - - if ( csPlayer ) - { - record.m_angRenderAngles = csPlayer->m_angRenderAngles; - } -#endif - - track->Push( record ); } // Called during player movement to set up/restore after lag compensation void CLagCompensationManager::StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ) { // Assume no players need to be restored - m_RestorePlayer.ClearAll(); + m_RestoreEntity.ClearAll(); m_bNeedToRestore = false; 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 @@ -374,56 +302,62 @@ void CLagCompensationManager::StartLagCompensation( CBasePlayer* player, CUserCm // Iterate all active players const CBitVec< MAX_EDICTS >* pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBasePlayer* pPlayer = UTIL_PlayerByIndex( i ); - if ( !pPlayer ) + for ( int i = 0; i < MAX_EDICTS; i++ ) + { + CBaseEntity* pEntity = UTIL_EntityByIndex( i ); + + if ( !pEntity ) { continue; } // Don't lag compensate yourself you loser... - if ( player == pPlayer ) + if ( player->entindex() == pEntity->entindex() ) { 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( pEntity, cmd, pEntityTransmitBits ) ) { continue; } // Move other player back in time - BacktrackPlayer( pPlayer, cmd ); + BacktrackEntity( pEntity, i, cmd ); } } -void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* cmd ) +inline void CLagCompensationManager::BacktrackEntity( CBaseEntity* pEntity, int loopindex, CUserCmd* cmd ) { - VPROF_BUDGET( "BacktrackPlayer", "CLagCompensationManager" ); + VPROF_BUDGET( "BacktrackEntity", "CLagCompensationManager" ); Vector org; Vector minsPreScaled; Vector maxsPreScaled; QAngle ang; -#ifdef CSTRIKE_DLL - QAngle renderAngles; -#endif + LagRecord* prevRecordSim; LagRecord* recordSim; LagRecord* recordAnim; -#ifdef CSTRIKE_DLL - auto csPlayer = ToCSPlayer( pPlayer ); -#endif - - int pl_index = pPlayer->entindex(); + int pl_index = loopindex; float flTargetSimTime = cmd->simulationdata[pl_index].sim_time; float flTargetAnimTime = cmd->simulationdata[pl_index].anim_time; + // Somehow the client didn't care. + if (flTargetSimTime == 0) + { + if ( sv_unlag_debug.GetBool() ) + { + DevMsg( "Client has refused to lag compensate this entity, probably already predicted ( %i )\n", pEntity->entindex() ); + } + + return; + } + // get track history of this player auto track = &m_EntityTrack[pl_index]; bool foundSim = false; @@ -438,11 +372,6 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c break; } - if ( !( recordSim->m_fFlags & LC_ALIVE ) ) - { - break; - } - if ( flTargetSimTime == recordSim->m_flSimulationTime ) { foundSim = true; @@ -457,33 +386,14 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c } } - for ( int i = 0; i < MAX_TICKS_SAVED; i++ ) - { - recordAnim = track->Get( i ); - - if ( !recordAnim ) - { - break; - } - - if ( recordAnim->m_flAnimTime == flTargetAnimTime ) - { - foundAnim = true; - break; - } - } - - Assert( recordAnim ); - Assert( recordSim ); - - if ( !foundAnim || !foundSim ) + if ( !foundSim ) { if ( sv_unlag_debug.GetBool() ) { - DevMsg( "No valid positions in history for BacktrackPlayer client ( %s )\n", pPlayer->GetPlayerName() ); + DevMsg( "No valid simulation in history for BacktrackPlayer client ( %i )\n", pEntity->entindex() ); } - return; // that should never happen + return; } float fracSim = 0.0f; @@ -522,40 +432,31 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c LagRecord* restore = &m_RestoreData[pl_index]; LagRecord* change = &m_ChangeData[pl_index]; - QAngle angdiff = pPlayer->GetAbsAngles() - ang; - Vector orgdiff = pPlayer->GetAbsOrigin() - org; + QAngle angdiff = pEntity->GetAbsAngles() - ang; + Vector orgdiff = pEntity->GetAbsOrigin() - org; // Always remember the pristine simulation time in case we need to restore it. - restore->m_flSimulationTime = pPlayer->GetSimulationTime(); - restore->m_flAnimTime = pPlayer->GetAnimTime(); - -#ifdef CSTRIKE_DLL - if ( csPlayer ) - { - renderAngles = recordAnim->m_angRenderAngles; - restore->m_angRenderAngles = csPlayer->m_angRenderAngles; - csPlayer->m_angRenderAngles = renderAngles; - } -#endif - + restore->m_flSimulationTime = pEntity->GetSimulationTime(); + restore->m_flAnimTime = pEntity->GetAnimTime(); + if ( angdiff.LengthSqr() > 0.0f ) { flags |= LC_ANGLES_CHANGED; - restore->m_vecAngles = pPlayer->GetAbsAngles(); - pPlayer->SetAbsAngles( ang ); + restore->m_vecAngles = pEntity->GetAbsAngles(); + pEntity->SetAbsAngles( ang ); change->m_vecAngles = ang; } // Use absolute equality here - if ( minsPreScaled != pPlayer->CollisionProp()->OBBMinsPreScaled() - || maxsPreScaled != pPlayer->CollisionProp()->OBBMaxsPreScaled() ) + if ( minsPreScaled != pEntity->CollisionProp()->OBBMinsPreScaled() + || maxsPreScaled != pEntity->CollisionProp()->OBBMaxsPreScaled() ) { flags |= LC_SIZE_CHANGED; - restore->m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); - restore->m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled(); + restore->m_vecMinsPreScaled = pEntity->CollisionProp()->OBBMinsPreScaled(); + restore->m_vecMaxsPreScaled = pEntity->CollisionProp()->OBBMaxsPreScaled(); - pPlayer->SetSize( minsPreScaled, maxsPreScaled ); + pEntity->SetSize( minsPreScaled, maxsPreScaled ); change->m_vecMinsPreScaled = minsPreScaled; change->m_vecMaxsPreScaled = maxsPreScaled; @@ -565,89 +466,150 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c if ( orgdiff.LengthSqr() > 0.0f ) { flags |= LC_ORIGIN_CHANGED; - restore->m_vecOrigin = pPlayer->GetAbsOrigin(); - pPlayer->SetAbsOrigin( org ); + restore->m_vecOrigin = pEntity->GetAbsOrigin(); + pEntity->SetAbsOrigin( org ); change->m_vecOrigin = org; } - // Sorry for the loss of the optimization for the case of people - // standing still, but you breathe even on the server. - // This is quicker than actually comparing all bazillion floats. - flags |= LC_ANIMATION_CHANGED; - restore->m_masterSequence = pPlayer->GetSequence(); - restore->m_masterCycle = pPlayer->GetCycle(); + auto pAnim = pEntity->GetBaseAnimating(); - pPlayer->SetSequence( recordAnim->m_masterSequence ); - pPlayer->SetCycle( recordAnim->m_masterCycle ); - - //////////////////////// - // Now do all the layers - int layerCount = pPlayer->GetNumAnimOverlays(); - for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) + auto Finish = [&]() { - CAnimationLayer* currentLayer = pPlayer->GetAnimOverlay( layerIndex ); - if ( currentLayer ) + if ( !flags ) { - restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; - restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; - restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; - restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; - restore->m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags; + return; // we didn't change anything + } - currentLayer->m_flCycle = recordAnim->m_layerRecords[layerIndex].m_cycle; - currentLayer->m_nOrder = recordAnim->m_layerRecords[layerIndex].m_order; - currentLayer->m_nSequence = recordAnim->m_layerRecords[layerIndex].m_sequence; - currentLayer->m_flWeight = recordAnim->m_layerRecords[layerIndex].m_weight; - currentLayer->m_fFlags = recordAnim->m_layerRecords[layerIndex].m_flags; + // Set lag compensated player's times + pEntity->SetSimulationTime( flTargetSimTime ); + pEntity->SetAnimTime( flTargetAnimTime ); + + if ( sv_lagflushbonecache.GetBool() ) + { + if ( pAnim ) + { + pAnim->InvalidateBoneCache(); + } + } + + m_RestoreEntity.Set( pl_index ); // remember that we changed this player + m_bNeedToRestore = true; // we changed at least one player + restore->m_fFlags = flags; // we need to restore these flags + change->m_fFlags = flags; // we have changed these flags + }; + + // Somehow the client didn't care. + if (flTargetAnimTime == 0) + { + if ( sv_unlag_debug.GetBool() && !pAnim ) + { + DevMsg( "Client has no anim time info ( %i )\n", pEntity->entindex() ); + } + + Finish(); + return; + } + + if ( pAnim ) + { + for ( int i = 0; i < MAX_TICKS_SAVED; i++ ) + { + recordAnim = track->Get( i ); + + if ( !recordAnim ) + { + break; + } + + if ( recordAnim->m_flAnimTime == flTargetAnimTime ) + { + foundAnim = true; + break; + } } } - flags |= LC_POSE_PARAMS_CHANGED; - - // Now do pose parameters - CStudioHdr* hdr = pPlayer->GetModelPtr(); - if ( hdr ) + if ( !foundAnim ) { - for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) + if ( sv_unlag_debug.GetBool() ) { - restore->m_poseParameters[paramIndex] = pPlayer->GetPoseParameterArray()[paramIndex]; - float poseParameter = recordAnim->m_poseParameters[paramIndex]; + DevMsg( "Can't lag compensate, no history for animation fpr client entity ( %i )\n", pEntity->entindex() ); + } - pPlayer->SetPoseParameterRaw( paramIndex, poseParameter ); + Finish(); + return; + } + + auto pAnimOverlay = dynamic_cast< CBaseAnimatingOverlay* >( pEntity ); + + if ( pAnim && foundAnim ) + { + // Sorry for the loss of the optimization for the case of people + // standing still, but you breathe even on the server. + // This is quicker than actually comparing all bazillion floats. + flags |= LC_ANIMATION_CHANGED; + restore->m_masterSequence = pAnim->GetSequence(); + restore->m_masterCycle = pAnim->GetCycle(); + + pAnim->SetSequence( recordAnim->m_masterSequence ); + pAnim->SetCycle( recordAnim->m_masterCycle ); + + // Now do pose parameters + CStudioHdr* hdr = pAnim->GetModelPtr(); + + if ( hdr ) + { + for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) + { + restore->m_poseParameters[paramIndex] = pAnim->GetPoseParameterArray()[paramIndex]; + float poseParameter = recordAnim->m_poseParameters[paramIndex]; + + pAnim->SetPoseParameterRaw( paramIndex, poseParameter ); + } + + flags |= LC_POSE_PARAMS_CHANGED; + + for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ ) + { + restore->m_encodedControllers[encIndex] = pAnim->GetBoneControllerArray()[encIndex]; + float encodedController = recordAnim->m_encodedControllers[encIndex]; + + pAnim->SetBoneControllerRaw( encIndex, encodedController ); + } + + flags |= LC_ENCD_CONS_CHANGED; } } - flags |= LC_ENCD_CONS_CHANGED; - - if ( hdr ) + if ( pAnimOverlay && foundAnim ) { - for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ ) + //////////////////////// + // Now do all the layers + int layerCount = pAnimOverlay->GetNumAnimOverlays(); + + for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { - restore->m_encodedControllers[encIndex] = pPlayer->GetBoneControllerArray()[encIndex]; - float encodedController = recordAnim->m_encodedControllers[encIndex]; + CAnimationLayer* currentLayer = pAnimOverlay->GetAnimOverlay( layerIndex ); + if ( currentLayer ) + { + restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; + restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; + restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; + restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; + restore->m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags; - pPlayer->SetBoneControllerRaw( encIndex, encodedController ); + currentLayer->m_flCycle = recordAnim->m_layerRecords[layerIndex].m_cycle; + currentLayer->m_nOrder = recordAnim->m_layerRecords[layerIndex].m_order; + currentLayer->m_nSequence = recordAnim->m_layerRecords[layerIndex].m_sequence; + currentLayer->m_flWeight = recordAnim->m_layerRecords[layerIndex].m_weight; + currentLayer->m_fFlags = recordAnim->m_layerRecords[layerIndex].m_flags; + } } + + flags |= LC_ANIM_OVERS_CHANGED; } - if ( !flags ) - { - return; // we didn't change anything - } - - // Set lag compensated player's times - pPlayer->SetSimulationTime( flTargetSimTime ); - pPlayer->SetAnimTime( flTargetAnimTime ); - - if ( sv_lagflushbonecache.GetBool() ) - { - pPlayer->InvalidateBoneCache(); - } - - m_RestorePlayer.Set( pl_index ); // remember that we changed this player - m_bNeedToRestore = true; // we changed at least one player - restore->m_fFlags = flags; // we need to restore these flags - change->m_fFlags = flags; // we have changed these flags + Finish(); } void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player ) @@ -662,16 +624,16 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player ) } // Iterate all active players - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + for ( int i = 0; i < MAX_EDICTS; i++ ) { - if ( !m_RestorePlayer.Get( i ) ) + if ( !m_RestoreEntity.Get( i ) ) { // player wasn't changed by lag compensation continue; } - CBasePlayer* pPlayer = UTIL_PlayerByIndex( i ); - if ( !pPlayer ) + CBaseEntity* pEntity = UTIL_EntityByIndex( i ); + if ( !pEntity ) { continue; } @@ -679,58 +641,61 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player ) LagRecord* restore = &m_RestoreData[i]; LagRecord* change = &m_ChangeData[i]; -#ifdef CSTRIKE_DLL - auto csPlayer = ToCSPlayer( pPlayer ); - - if ( csPlayer ) - { - csPlayer->m_angRenderAngles = restore->m_angRenderAngles; - } -#endif - if ( restore->m_fFlags & LC_SIZE_CHANGED ) { - // see if simulation made any changes, if no, then do the restore, otherwise, - // leave new values in - if ( pPlayer->CollisionProp()->OBBMinsPreScaled() == change->m_vecMinsPreScaled - && pPlayer->CollisionProp()->OBBMaxsPreScaled() == change->m_vecMaxsPreScaled ) - { - // Restore it - pPlayer->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled ); - } -#ifdef STAGING_ONLY - else - { - Warning( "Should we really not restore the size?\n" ); - } -#endif + pEntity->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled ); } if ( restore->m_fFlags & LC_ANGLES_CHANGED ) { - if ( pPlayer->GetAbsAngles() == change->m_vecAngles ) - { - pPlayer->SetAbsAngles( restore->m_vecAngles ); - } + pEntity->SetAbsAngles( restore->m_vecAngles ); } if ( restore->m_fFlags & LC_ORIGIN_CHANGED ) { - // Okay, let's see if we can do something reasonable with the change - Vector delta = pPlayer->GetAbsOrigin() - change->m_vecOrigin; - - RestorePlayerTo( pPlayer, restore->m_vecOrigin + delta ); + pEntity->SetAbsOrigin( restore->m_vecOrigin ); } - if ( restore->m_fFlags & LC_ANIMATION_CHANGED ) - { - pPlayer->SetSequence( restore->m_masterSequence ); - pPlayer->SetCycle( restore->m_masterCycle ); + auto pAnim = dynamic_cast< CBaseAnimating* >( pEntity ); + auto pAnimOverlay = dynamic_cast< CBaseAnimatingOverlay* >( pEntity ); + + if ( pAnim ) + { + if ( restore->m_fFlags & LC_ANIMATION_CHANGED ) + { + pAnim->SetSequence( restore->m_masterSequence ); + pAnim->SetCycle( restore->m_masterCycle ); + } + + CStudioHdr* hdr = pAnim->GetModelPtr(); + + if ( hdr ) + { + if ( restore->m_fFlags & LC_POSE_PARAMS_CHANGED ) + { + for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) + { + pAnim->SetPoseParameterRaw( paramIndex, restore->m_poseParameters[paramIndex] ); + } + } + + if ( restore->m_fFlags & LC_ENCD_CONS_CHANGED ) + { + for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ ) + { + pAnim->SetBoneControllerRaw( encIndex, restore->m_encodedControllers[encIndex] ); + } + } + } + } + + if ( restore->m_fFlags & LC_ANIM_OVERS_CHANGED && pAnimOverlay ) + { + int layerCount = pAnimOverlay->GetNumAnimOverlays(); - int layerCount = pPlayer->GetNumAnimOverlays(); for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { - CAnimationLayer* currentLayer = pPlayer->GetAnimOverlay( layerIndex ); + CAnimationLayer* currentLayer = pAnimOverlay->GetAnimOverlay( layerIndex ); if ( currentLayer ) { currentLayer->m_flCycle = restore->m_layerRecords[layerIndex].m_cycle; @@ -742,31 +707,7 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player ) } } - CStudioHdr* hdr = pPlayer->GetModelPtr(); - - if ( restore->m_fFlags & LC_POSE_PARAMS_CHANGED ) - { - if ( hdr ) - { - for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) - { - pPlayer->SetPoseParameterRaw( paramIndex, restore->m_poseParameters[paramIndex] ); - } - } - } - - if ( restore->m_fFlags & LC_ENCD_CONS_CHANGED ) - { - if ( hdr ) - { - for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ ) - { - pPlayer->SetBoneControllerRaw( encIndex, restore->m_encodedControllers[encIndex] ); - } - } - } - - pPlayer->SetSimulationTime( restore->m_flSimulationTime ); - pPlayer->SetAnimTime( restore->m_flAnimTime ); + pEntity->SetSimulationTime( restore->m_flSimulationTime ); + pEntity->SetAnimTime( restore->m_flAnimTime ); } } diff --git a/game/shared/cstrike/cs_player_shared.cpp b/game/shared/cstrike/cs_player_shared.cpp index 497ab32391..8f934f9e04 100644 --- a/game/shared/cstrike/cs_player_shared.cpp +++ b/game/shared/cstrike/cs_player_shared.cpp @@ -542,8 +542,8 @@ void CCSPlayer::FireBullet( QAngle angles[MAXSTUDIOBONES]; int indexes[MAXSTUDIOBONES]; - auto angle = lagPlayer->GetRenderAngles(); - auto position = lagPlayer->GetRenderOrigin(); + auto angle = lagPlayer->GetAbsAngles(); + auto position = lagPlayer->GetAbsOrigin(); event->SetFloat( "position_x", position.x ); event->SetFloat( "position_y", position.y ); diff --git a/game/shared/cstrike/fx_cs_shared.cpp b/game/shared/cstrike/fx_cs_shared.cpp index d7aabacf56..eab95327b8 100644 --- a/game/shared/cstrike/fx_cs_shared.cpp +++ b/game/shared/cstrike/fx_cs_shared.cpp @@ -297,11 +297,6 @@ void FX_FireBullets( pPlayer->StartNewBulletGroup(); #endif -#if !defined (CLIENT_DLL) - // Move other players back to history positions based on local player's lag - lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); -#endif - RandomSeed( iSeed ); // init random system with this seed // Get accuracy displacement @@ -340,8 +335,8 @@ void FX_FireBullets( C_CSPlayer::HitboxRecord record; - record.m_vecAbsOrigin = lagPlayer->GetRenderOrigin(); - record.m_angRenderAngles = lagPlayer->m_angRenderAngles; + record.m_vecAbsOrigin = lagPlayer->GetAbsOrigin(); + record.m_angAbsRotation = lagPlayer->GetAbsAngles(); record.m_nAttackerTickBase = pPlayer->m_nTickBase; record.m_flSimulationTime = lagPlayer->m_flInterpolatedSimulationTime; @@ -393,10 +388,6 @@ void FX_FireBullets( x0 + x1[iBullet], y0 + y1[iBullet] ); } -#if !defined (CLIENT_DLL) - lagcompensation->FinishLagCompensation( pPlayer ); -#endif - EndGroupingSounds(); } diff --git a/game/shared/cstrike/weapon_knife.cpp b/game/shared/cstrike/weapon_knife.cpp index 2d78d60e78..5945d7edd2 100644 --- a/game/shared/cstrike/weapon_knife.cpp +++ b/game/shared/cstrike/weapon_knife.cpp @@ -235,14 +235,7 @@ void CKnife::SecondaryAttack() CCSPlayer *pPlayer = GetPlayerOwner(); if ( pPlayer && !pPlayer->m_bIsDefusing && !CSGameRules()->IsFreezePeriod() ) { -#if !defined (CLIENT_DLL) - // Move other players back to history positions based on local player's lag - lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); -#endif SwingOrStab( true ); -#if !defined (CLIENT_DLL) - lagcompensation->FinishLagCompensation( pPlayer ); -#endif } } diff --git a/wscript b/wscript index f9b133a046..8b508c69cb 100644 --- a/wscript +++ b/wscript @@ -547,7 +547,7 @@ def configure(conf): '/arch:SSE' if conf.env.DEST_CPU == 'x86' else '/arch:AVX', '/GF', '/Gy', - '/fp:fast', + '/fp:precise', '/Zc:forScope', '/Zc:wchar_t', '/GR',