From ae99eb3817bdf97f254fc2e37c1c04a6758fe861 Mon Sep 17 00:00:00 2001 From: Kamay Xutax Date: Sat, 27 Jan 2024 22:11:01 +0100 Subject: [PATCH] Modified lag compensation suit better our needs --- game/client/c_baseentity.cpp | 8 +- game/client/c_baseentity.h | 2 + game/client/cdll_bounded_cvars.cpp | 6 +- game/client/in_main.cpp | 43 ++-- game/client/physics.cpp | 3 +- game/server/player_lagcompensation.cpp | 266 ++++++++++++++++------- game/shared/cstrike/cs_player_shared.cpp | 4 +- game/shared/usercmd.cpp | 22 ++ game/shared/usercmd.h | 9 + 9 files changed, 261 insertions(+), 102 deletions(-) diff --git a/game/client/c_baseentity.cpp b/game/client/c_baseentity.cpp index bedeba6684..54c7ed1f41 100644 --- a/game/client/c_baseentity.cpp +++ b/game/client/c_baseentity.cpp @@ -829,12 +829,14 @@ C_BaseEntity::C_BaseEntity() : m_iv_vecOrigin( "C_BaseEntity::m_iv_vecOrigin" ), m_iv_angRotation( "C_BaseEntity::m_iv_angRotation" ), m_iv_vecVelocity( "C_BaseEntity::m_iv_vecVelocity" ), - m_iv_flSimulationTime( "C_BaseEntity::m_iv_flSimulationTime" ) + m_iv_flSimulationTime( "C_BaseEntity::m_iv_flSimulationTime" ), + m_iv_flAnimTime( "C_BaseEntity::m_iv_flAnimTime" ) { AddVar( &m_vecOrigin, &m_iv_vecOrigin, LATCH_SIMULATION_VAR ); AddVar( &m_angRotation, &m_iv_angRotation, LATCH_SIMULATION_VAR ); // Needed for lag compensation AddVar( &m_flInterpolatedSimulationTime, &m_iv_flSimulationTime, LATCH_SIMULATION_VAR ); + AddVar( &m_flInterpolatedAnimTime, &m_iv_flAnimTime, LATCH_ANIMATION_VAR ); // Removing this until we figure out why velocity introduces view hitching. // One possible fix is removing the player->ResetLatched() call in CGameMovement::FinishDuck(), // but that re-introduces a third-person hitching bug. One possible cause is the abrupt change @@ -952,6 +954,7 @@ void C_BaseEntity::Clear( void ) m_flAnimTime = 0; m_flSimulationTime = 0; m_flInterpolatedSimulationTime = 0; + m_flInterpolatedAnimTime = 0; SetSolid( SOLID_NONE ); SetSolidFlags( 0 ); SetMoveCollide( MOVECOLLIDE_DEFAULT ); @@ -2495,6 +2498,9 @@ void C_BaseEntity::PostDataUpdate( DataUpdateType_t updateType ) if (simTimeChanged) m_flInterpolatedSimulationTime = m_flSimulationTime; + if (animTimeChanged) + m_flInterpolatedAnimTime = m_flAnimTime; + // Detect simulation changes bool simulationChanged = originChanged || anglesChanged || simTimeChanged; diff --git a/game/client/c_baseentity.h b/game/client/c_baseentity.h index c7265fc79f..e1c1173314 100644 --- a/game/client/c_baseentity.h +++ b/game/client/c_baseentity.h @@ -1284,6 +1284,8 @@ public: // Time animation sequence or frame was last changed float m_flAnimTime; float m_flOldAnimTime; + float m_flInterpolatedAnimTime; + CInterpolatedVar m_iv_flAnimTime; float m_flSimulationTime; float m_flOldSimulationTime; diff --git a/game/client/cdll_bounded_cvars.cpp b/game/client/cdll_bounded_cvars.cpp index 01c98360bb..e79454209b 100644 --- a/game/client/cdll_bounded_cvars.cpp +++ b/game/client/cdll_bounded_cvars.cpp @@ -66,8 +66,8 @@ class CBoundedCvar_InterpRatio : public ConVar_ServerBounded public: CBoundedCvar_InterpRatio() : ConVar_ServerBounded( "cl_interp_ratio", - "1.0", - FCVAR_USERINFO | FCVAR_NOT_CONNECTED, + "2.0", + FCVAR_USERINFO, "Sets the interpolation amount (final amount is cl_interp_ratio / cl_updaterate)." ) { } @@ -101,7 +101,7 @@ public: CBoundedCvar_Interp() : ConVar_ServerBounded( "cl_interp", "0.0", - FCVAR_USERINFO | FCVAR_NOT_CONNECTED, + FCVAR_USERINFO, "Sets the interpolation amount (bounded on low side by server interp ratio settings).", true, 0.0f, true, 0.5f ) { } diff --git a/game/client/in_main.cpp b/game/client/in_main.cpp index df4451057b..fee9916bdb 100644 --- a/game/client/in_main.cpp +++ b/game/client/in_main.cpp @@ -1289,30 +1289,30 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo m_EntityGroundContact.RemoveAll(); #endif - // static bool firstTime = false; + static bool firstTime = false; - // if (cmd->buttons & IN_ATTACK) - // { - // if (!firstTime) - // { - // for (int i = 0; i <= MAX_PLAYERS; i++) - // { - // auto pPlayer = UTIL_PlayerByIndex(i); + if (cmd->buttons & IN_ATTACK) + { + if (!firstTime) + { + for (int i = 0; i <= MAX_PLAYERS; i++) + { + auto pPlayer = UTIL_PlayerByIndex(i); - // if (pPlayer) - // { - // const auto &origin = pPlayer->GetAbsOrigin(); - // DevMsg("Movement: %s => %f %f %f => %f\n", pPlayer->GetPlayerName(), origin.x, origin.y, origin.z, pPlayer->m_flInterpolatedSimulationTime); - // } - // } + if (pPlayer) + { + const auto &origin = pPlayer->GetAbsOrigin(); + DevMsg("Movement: %s => %f %f %f => %f\n", pPlayer->GetPlayerName(), origin.x, origin.y, origin.z, pPlayer->m_flInterpolatedSimulationTime); + } + } - // firstTime = true; - // } - // } - // else - // { - // firstTime = false; - // } + firstTime = true; + } + } + else + { + firstTime = false; + } // Send interpolated simulation time for lag compensation for (int i = 0; i <= MAX_PLAYERS; i++) @@ -1322,6 +1322,7 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo if (pPlayer) { cmd->simulationtimes[pPlayer->index] = pPlayer->m_flInterpolatedSimulationTime; + cmd->animtimes[pPlayer->index] = pPlayer->m_flInterpolatedAnimTime; } } diff --git a/game/client/physics.cpp b/game/client/physics.cpp index a5cd2dcd52..908829206f 100644 --- a/game/client/physics.cpp +++ b/game/client/physics.cpp @@ -6,6 +6,7 @@ //=============================================================================// #include "cbase.h" +#include "shareddefs.h" #include "vcollide_parse.h" #include "filesystem.h" #include "engine/IStaticPropMgr.h" @@ -177,7 +178,7 @@ void PhysicsLevelInit( void ) physenv->SetGravity( Vector(0, 0, -GetCurrentGravity() ) ); // 15 ms per tick // NOTE: Always run client physics at this rate - helps keep ragdolls stable - physenv->SetSimulationTimestep( IsXbox() ? DEFAULT_XBOX_CLIENT_VPHYSICS_TICK : DEFAULT_TICK_INTERVAL ); + physenv->SetSimulationTimestep( IsXbox() ? DEFAULT_XBOX_CLIENT_VPHYSICS_TICK : TICK_INTERVAL ); physenv->SetCollisionEventHandler( &g_Collisions ); physenv->SetCollisionSolver( &g_Collisions ); diff --git a/game/server/player_lagcompensation.cpp b/game/server/player_lagcompensation.cpp index 1c107d1362..a1cce1ffcc 100644 --- a/game/server/player_lagcompensation.cpp +++ b/game/server/player_lagcompensation.cpp @@ -25,6 +25,7 @@ #define LC_SIZE_CHANGED (1<<10) #define LC_ANIMATION_CHANGED (1<<11) #define LC_POSE_PARAMS_CHANGED (1<<12) +#define LC_ENCD_CONS_CHANGED (1<<13) #define LAG_COMPENSATION_EPS_SQR ( 0.1f * 0.1f ) // Allow 4 units of error ( about 1 / 8 bbox width ) @@ -42,6 +43,7 @@ ConVar sv_unlag_fixstuck( "sv_unlag_fixstuck", "0", FCVAR_DEVELOPMENTONLY, "Disa //----------------------------------------------------------------------------- #define MAX_LAYER_RECORDS (CBaseAnimatingOverlay::MAX_OVERLAYS) #define MAX_POSE_PARAMETERS (CBaseAnimating::NUM_POSEPAREMETERS) +#define MAX_ENCODED_CONTROLLERS (MAXSTUDIOBONECTRLS) struct LayerRecord { @@ -78,8 +80,19 @@ public: m_vecMinsPreScaled.Init(); m_vecMaxsPreScaled.Init(); m_flSimulationTime = -1; + m_flAnimTime = -1; m_masterSequence = 0; m_masterCycle = 0; + + for (int i = 0; i < MAX_LAYER_RECORDS; i++) + { + m_poseParameters[i] = -1; + } + + for (int i = 0; i < MAX_ENCODED_CONTROLLERS; i++) + { + m_encodedControllers[i] = -1; + } } LagRecord( const LagRecord& src ) @@ -90,12 +103,23 @@ public: 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 < MAX_LAYER_RECORDS; i++) + { + m_poseParameters[i] = src.m_poseParameters[i]; + } + + for (int i = 0; i < MAX_LAYER_RECORDS; i++) + { + m_encodedControllers[i] = src.m_encodedControllers[i]; + } } // Did player die this frame @@ -107,13 +131,15 @@ public: Vector m_vecMinsPreScaled; Vector m_vecMaxsPreScaled; - float m_flSimulationTime; + float m_flSimulationTime; + float m_flAnimTime; // Player animation details, so we can get the legs in the right spot. LayerRecord m_layerRecords[MAX_LAYER_RECORDS]; int m_masterSequence; float m_masterCycle; float m_poseParameters[MAX_POSE_PARAMETERS]; + float m_encodedControllers[MAX_ENCODED_CONTROLLERS]; }; @@ -197,7 +223,7 @@ public: void FinishLagCompensation( CBasePlayer *player ); private: - void BacktrackPlayer( CBasePlayer *player, float flTargetTime ); + void BacktrackPlayer( CBasePlayer *player, CUserCmd *cmd ); void ClearHistory() { @@ -292,6 +318,7 @@ void CLagCompensationManager::FrameUpdatePostEntityThink() } record.m_flSimulationTime = pPlayer->GetSimulationTime(); + record.m_flAnimTime = pPlayer->GetAnimTime(); record.m_vecAngles = pPlayer->GetLocalAngles(); record.m_vecOrigin = pPlayer->GetLocalOrigin(); record.m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); @@ -320,6 +347,14 @@ void CLagCompensationManager::FrameUpdatePostEntityThink() record.m_poseParameters[paramIndex] = pPlayer->GetPoseParameter( paramIndex ); } } + + if( hdr ) + { + for( int paramIndex = 0; paramIndex < hdr->GetNumBoneControllers(); paramIndex++ ) + { + record.m_encodedControllers[paramIndex] = pPlayer->GetBoneController( paramIndex ); + } + } } //Clear the current player. @@ -379,11 +414,11 @@ void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCm continue; // Move other player back in time - BacktrackPlayer( pPlayer, cmd->simulationtimes[i] ); + BacktrackPlayer( pPlayer, cmd ); } } -void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTargetTime ) +void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *cmd ) { Vector org; Vector minsPreScaled; @@ -393,30 +428,34 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar VPROF_BUDGET( "BacktrackPlayer", "CLagCompensationManager" ); int pl_index = pPlayer->entindex() - 1; + float flTargetSimulationTime = cmd->simulationtimes[pl_index + 1]; + float flTargetAnimTime = cmd->animtimes[pl_index + 1]; + // get track history of this player - CUtlFixedLinkedList< LagRecord > *track = &m_PlayerTrack[ pl_index ]; + CUtlFixedLinkedList< LagRecord > *trackSim = &m_PlayerTrack[ pl_index ]; + // CUtlFixedLinkedList< LagRecord > *trackAnim = &m_PlayerTrack[ pl_index ]; // check if we have at leat one entry - if ( track->Count() <= 0 ) + if ( trackSim->Count() <= 0 ) return; - intp curr = track->Head(); + intp currSim = trackSim->Head(); - LagRecord *prevRecord = NULL; - LagRecord *record = NULL; + LagRecord *prevRecordSim = NULL; + LagRecord *recordSim = NULL; Vector prevOrg = pPlayer->GetLocalOrigin(); // Walk context looking for any invalidating event - while( track->IsValidIndex(curr) ) + while( trackSim->IsValidIndex(currSim) ) { // remember last record - prevRecord = record; + prevRecordSim = recordSim; // get next record - record = &track->Element( curr ); + recordSim = &trackSim->Element( currSim ); - if ( !(record->m_fFlags & LC_ALIVE) ) + if ( !(recordSim->m_fFlags & LC_ALIVE) ) { // player most be alive, lost track return; @@ -425,18 +464,49 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar // TODO: do proper teleportation checks. // did we find a context smaller than target time ? - if ( record->m_flSimulationTime <= flTargetTime ) + if ( recordSim->m_flSimulationTime <= flTargetSimulationTime ) break; // hurra, stop - prevOrg = record->m_vecOrigin; + prevOrg = recordSim->m_vecOrigin; // go one step back - curr = track->Next( curr ); + currSim = trackSim->Next( currSim ); } - Assert( record ); + // intp currAnim = trackSim->Head(); - if ( !record ) + // LagRecord *prevRecordAnim = NULL; + // LagRecord *recordAnim = NULL; + + // // Walk context looking for any invalidating event + // while( trackAnim->IsValidIndex(currAnim) ) + // { + // // remember last record + // prevRecordAnim = recordAnim; + + // // get next record + // recordAnim = &trackAnim->Element( currAnim ); + + // if ( !(recordAnim->m_fFlags & LC_ALIVE) ) + // { + // // player most be alive, lost track + // return; + // } + + // // TODO: do proper teleportation checks. + + // // did we find a context smaller than target time ? + // if ( recordAnim->m_flAnimTime <= flTargetAnimTime ) + // break; // hurra, stop + + // // go one step back + // currAnim = trackAnim->Next( currAnim ); + // } + + // Assert( recordAnim ); + Assert( recordSim ); + + if ( !recordSim ) { if ( sv_unlag_debug.GetBool() ) { @@ -446,38 +516,56 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar return; // that should never happen } - float frac = 0.0f; - if ( prevRecord && - (record->m_flSimulationTime < flTargetTime) && - (record->m_flSimulationTime < prevRecord->m_flSimulationTime) ) + float fracSim = 0.0f; + if ( prevRecordSim && + (recordSim->m_flSimulationTime < flTargetSimulationTime) && + (recordSim->m_flSimulationTime < prevRecordSim->m_flSimulationTime) ) { // we didn't find the exact time but have a valid previous record // so interpolate between these two records; Assert( prevRecord->m_flSimulationTime > record->m_flSimulationTime ); - Assert( flTargetTime < prevRecord->m_flSimulationTime ); + Assert( flTargetSimulationTime < prevRecord->m_flSimulationTime ); // calc fraction between both records - frac = ( flTargetTime - record->m_flSimulationTime ) / - ( prevRecord->m_flSimulationTime - record->m_flSimulationTime ); + fracSim = ( flTargetSimulationTime - recordSim->m_flSimulationTime ) / + ( prevRecordSim->m_flSimulationTime - recordSim->m_flSimulationTime ); - Assert( frac > 0 && frac < 1 ); // should never extrapolate + Assert( fracSim > 0 && fracSim < 1 ); // should never extrapolate - ang = Lerp( frac, record->m_vecAngles, prevRecord->m_vecAngles ); - org = Lerp( frac, record->m_vecOrigin, prevRecord->m_vecOrigin ); - minsPreScaled = Lerp( frac, record->m_vecMinsPreScaled, prevRecord->m_vecMinsPreScaled ); - maxsPreScaled = Lerp( frac, record->m_vecMaxsPreScaled, prevRecord->m_vecMaxsPreScaled ); + ang = Lerp( fracSim, recordSim->m_vecAngles, prevRecordSim->m_vecAngles ); + org = Lerp( fracSim, recordSim->m_vecOrigin, prevRecordSim->m_vecOrigin ); + minsPreScaled = Lerp( fracSim, recordSim->m_vecMinsPreScaled, prevRecordSim->m_vecMinsPreScaled ); + maxsPreScaled = Lerp( fracSim, recordSim->m_vecMaxsPreScaled, prevRecordSim->m_vecMaxsPreScaled ); } else { // we found the exact record or no other record to interpolate with // just copy these values since they are the best we have - org = record->m_vecOrigin; - ang = record->m_vecAngles; - minsPreScaled = record->m_vecMinsPreScaled; - maxsPreScaled = record->m_vecMaxsPreScaled; + org = recordSim->m_vecOrigin; + ang = recordSim->m_vecAngles; + minsPreScaled = recordSim->m_vecMinsPreScaled; + maxsPreScaled = recordSim->m_vecMaxsPreScaled; } + // float fracAnim = 0.0f; + // if ( prevRecordAnim && + // (recordAnim->m_flAnimTime < flTargetAnimTime) && + // (recordAnim->m_flAnimTime < prevRecordAnim->m_flAnimTime) ) + // { + // // we didn't find the exact time but have a valid previous record + // // so interpolate between these two records; + + // Assert( prevRecord->m_flAnimTime > record->m_flAnimTime ); + // Assert( flTargetAnimTime < prevRecord->m_flAnimTime ); + + // // calc fraction between both records + // fracAnim = ( flTargetAnimTime - recordAnim->m_flAnimTime ) / + // ( prevRecordAnim->m_flAnimTime - recordAnim->m_flAnimTime ); + + // Assert( fracAnim > 0 && fracAnim < 1 ); // should never extrapolate + // } + // See if this is still a valid position for us to teleport to if ( sv_unlag_fixstuck.GetBool() ) { @@ -505,7 +593,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar // Temp turn this flag on m_RestorePlayer.Set( pl_index ); - BacktrackPlayer( pHitPlayer, flTargetTime ); + BacktrackPlayer( pHitPlayer, cmd ); // Remove the temp flag m_RestorePlayer.Clear( pl_index ); @@ -547,6 +635,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar // Always remember the pristine simulation time in case we need to restore it. restore->m_flSimulationTime = pPlayer->GetSimulationTime(); + restore->m_flAnimTime = pPlayer->GetAnimTime(); if ( angdiff.LengthSqr() > LAG_COMPENSATION_EPS_SQR ) { @@ -587,7 +676,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar restore->m_masterCycle = pPlayer->GetCycle(); bool interpolationAllowed = false; - if( prevRecord && (record->m_masterSequence == prevRecord->m_masterSequence) ) + if( prevRecordSim && (recordSim->m_masterSequence == prevRecordSim->m_masterSequence) ) { // If the master state changes, all layers will be invalid too, so don't interp (ya know, interp barely ever happens anyway) interpolationAllowed = true; @@ -596,28 +685,28 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar //////////////////////// // First do the master settings bool interpolatedMasters = false; - if( frac > 0.0f && interpolationAllowed ) + if( fracSim > 0.0f && interpolationAllowed ) { interpolatedMasters = true; - pPlayer->SetSequence( Lerp( frac, record->m_masterSequence, prevRecord->m_masterSequence ) ); - pPlayer->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) ); + pPlayer->SetSequence( Lerp( fracSim, recordSim->m_masterSequence, prevRecordSim->m_masterSequence ) ); + pPlayer->SetCycle( Lerp( fracSim, recordSim->m_masterCycle, prevRecordSim->m_masterCycle ) ); - if( record->m_masterCycle > prevRecord->m_masterCycle ) + if( recordSim->m_masterCycle > prevRecordSim->m_masterCycle ) { // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0 // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example. - float newCycle = Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle + 1 ); + float newCycle = Lerp( fracSim, recordSim->m_masterCycle, prevRecordSim->m_masterCycle + 1 ); pPlayer->SetCycle(newCycle < 1 ? newCycle : newCycle - 1 );// and make sure .9 to 1.2 does not end up 1.05 } else { - pPlayer->SetCycle( Lerp( frac, record->m_masterCycle, prevRecord->m_masterCycle ) ); + pPlayer->SetCycle( Lerp( fracSim, recordSim->m_masterCycle, prevRecordSim->m_masterCycle ) ); } } if( !interpolatedMasters ) { - pPlayer->SetSequence(record->m_masterSequence); - pPlayer->SetCycle(record->m_masterCycle); + pPlayer->SetSequence(recordSim->m_masterSequence); + pPlayer->SetCycle(recordSim->m_masterCycle); } //////////////////////// @@ -634,10 +723,10 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; bool interpolated = false; - if( (frac > 0.0f) && interpolationAllowed ) + if( (fracSim > 0.0f) && interpolationAllowed ) { - LayerRecord &recordsLayerRecord = record->m_layerRecords[layerIndex]; - LayerRecord &prevRecordsLayerRecord = prevRecord->m_layerRecords[layerIndex]; + LayerRecord &recordsLayerRecord = recordSim->m_layerRecords[layerIndex]; + LayerRecord &prevRecordsLayerRecord = prevRecordSim->m_layerRecords[layerIndex]; if( (recordsLayerRecord.m_order == prevRecordsLayerRecord.m_order) && (recordsLayerRecord.m_sequence == prevRecordsLayerRecord.m_sequence) ) @@ -648,42 +737,46 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar { // the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0 // add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example. - float newCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle + 1 ); + float newCycle = Lerp( fracSim, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle + 1 ); currentLayer->m_flCycle = newCycle < 1 ? newCycle : newCycle - 1;// and make sure .9 to 1.2 does not end up 1.05 } else { - currentLayer->m_flCycle = Lerp( frac, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle ); + currentLayer->m_flCycle = Lerp( fracSim, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle ); } currentLayer->m_nOrder = recordsLayerRecord.m_order; currentLayer->m_nSequence = recordsLayerRecord.m_sequence; - currentLayer->m_flWeight = Lerp( frac, recordsLayerRecord.m_weight, prevRecordsLayerRecord.m_weight ); + currentLayer->m_flWeight = Lerp( fracSim, recordsLayerRecord.m_weight, prevRecordsLayerRecord.m_weight ); } } if( !interpolated ) { //Either no interp, or interp failed. Just use record. - currentLayer->m_flCycle = record->m_layerRecords[layerIndex].m_cycle; - currentLayer->m_nOrder = record->m_layerRecords[layerIndex].m_order; - currentLayer->m_nSequence = record->m_layerRecords[layerIndex].m_sequence; - currentLayer->m_flWeight = record->m_layerRecords[layerIndex].m_weight; + currentLayer->m_flCycle = recordSim->m_layerRecords[layerIndex].m_cycle; + currentLayer->m_nOrder = recordSim->m_layerRecords[layerIndex].m_order; + currentLayer->m_nSequence = recordSim->m_layerRecords[layerIndex].m_sequence; + currentLayer->m_flWeight = recordSim->m_layerRecords[layerIndex].m_weight; } } } + flags |= LC_POSE_PARAMS_CHANGED; + // Now do pose parameters CStudioHdr *hdr = pPlayer->GetModelPtr(); if( hdr ) { for( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) { - float poseParameter = record->m_poseParameters[paramIndex]; - if( (frac > 0.0f) && interpolationAllowed ) + restore->m_poseParameters[paramIndex] = pPlayer->GetPoseParameter(paramIndex); + float poseParameter = recordSim->m_poseParameters[paramIndex]; + + if( (fracSim > 0.0f) && interpolationAllowed ) { // These could wrap like cycles, but there's no way to know. In the most common case // (move_x/move_y) it's correct to just lerp. Interpolation almost never happens anyways. - float prevPoseParameter = prevRecord->m_poseParameters[paramIndex]; - pPlayer->SetPoseParameter( paramIndex, Lerp( frac, poseParameter, prevPoseParameter ) ); + float prevPoseParameter = prevRecordSim->m_poseParameters[paramIndex]; + pPlayer->SetPoseParameter( paramIndex, Lerp( fracSim, poseParameter, prevPoseParameter ) ); } else { @@ -692,9 +785,36 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar } } + flags |= LC_ENCD_CONS_CHANGED; + + if( hdr ) + { + for( int paramIndex = 0; paramIndex < hdr->GetNumBoneControllers(); paramIndex++ ) + { + restore->m_encodedControllers[paramIndex] = pPlayer->GetBoneController(paramIndex); + float encodedController = recordSim->m_encodedControllers[paramIndex]; + + if( (fracSim > 0.0f) && interpolationAllowed ) + { + // These could wrap like cycles, but there's no way to know. In the most common case + // (move_x/move_y) it's correct to just lerp. Interpolation almost never happens anyways. + float prevEncodedController = prevRecordSim->m_encodedControllers[paramIndex]; + pPlayer->SetBoneController( paramIndex, Lerp( fracSim, encodedController, prevEncodedController ) ); + } + else + { + pPlayer->SetBoneController( paramIndex, encodedController ); + } + } + } + if ( !flags ) return; // we didn't change anything + // Set lag compensated player's times + pPlayer->SetSimulationTime(flTargetSimulationTime); + pPlayer->SetAnimTime(flTargetAnimTime); + if ( sv_lagflushbonecache.GetBool() ) pPlayer->InvalidateBoneCache(); @@ -713,7 +833,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, float flTar pPlayer->DrawServerHitboxes(4, true); } - // DevMsg("Server: %s => %f %f %f => %f (frac: %f)\n", pPlayer->GetPlayerName(), change->m_vecOrigin.x, change->m_vecOrigin.y, change->m_vecOrigin.z, flTargetTime, frac); + DevMsg("Server: %s => %f %f %f => %f (frac: %f)\n", pPlayer->GetPlayerName(), change->m_vecOrigin.x, change->m_vecOrigin.y, change->m_vecOrigin.z, flTargetSimulationTime, fracSim); } @@ -747,12 +867,8 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) LagRecord *restore = &m_RestoreData[ pl_index ]; LagRecord *change = &m_ChangeData[ pl_index ]; - bool restoreSimulationTime = false; - if ( restore->m_fFlags & LC_SIZE_CHANGED ) { - restoreSimulationTime = true; - // see if simulation made any changes, if no, then do the restore, otherwise, // leave new values in if ( pPlayer->CollisionProp()->OBBMinsPreScaled() == change->m_vecMinsPreScaled && @@ -770,9 +886,7 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) } if ( restore->m_fFlags & LC_ANGLES_CHANGED ) - { - restoreSimulationTime = true; - + { if ( pPlayer->GetLocalAngles() == change->m_vecAngles ) { pPlayer->SetLocalAngles( restore->m_vecAngles ); @@ -781,8 +895,6 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) if ( restore->m_fFlags & LC_ORIGIN_CHANGED ) { - restoreSimulationTime = true; - // Okay, let's see if we can do something reasonable with the change Vector delta = pPlayer->GetLocalOrigin() - change->m_vecOrigin; @@ -791,8 +903,6 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) if( restore->m_fFlags & LC_ANIMATION_CHANGED ) { - restoreSimulationTime = true; - pPlayer->SetSequence(restore->m_masterSequence); pPlayer->SetCycle(restore->m_masterCycle); @@ -812,8 +922,6 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) if( restore->m_fFlags & LC_POSE_PARAMS_CHANGED ) { - restoreSimulationTime = true; - CStudioHdr *hdr = pPlayer->GetModelPtr(); if( hdr ) { @@ -824,10 +932,20 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer *player ) } } - if ( restoreSimulationTime ) + if( restore->m_fFlags & LC_ENCD_CONS_CHANGED ) { - pPlayer->SetSimulationTime( restore->m_flSimulationTime ); + CStudioHdr *hdr = pPlayer->GetModelPtr(); + if( hdr ) + { + for( int paramIndex = 0; paramIndex < hdr->GetNumBoneControllers(); paramIndex++ ) + { + pPlayer->SetBoneController( paramIndex, restore->m_encodedControllers[paramIndex] ); + } + } } + + pPlayer->SetSimulationTime( restore->m_flSimulationTime ); + pPlayer->SetAnimTime( restore->m_flAnimTime ); } } diff --git a/game/shared/cstrike/cs_player_shared.cpp b/game/shared/cstrike/cs_player_shared.cpp index b46003f87c..62a40a00f3 100644 --- a/game/shared/cstrike/cs_player_shared.cpp +++ b/game/shared/cstrike/cs_player_shared.cpp @@ -417,8 +417,8 @@ void CCSPlayer::FireBullet( { #ifdef CLIENT_DLL lagPlayer->DrawClientHitboxes(4, true); - //DevMsg("Client: %s => %f %f %f => %f\n", lagPlayer->GetPlayerName(), lagPlayer->GetAbsOrigin().x, lagPlayer->GetAbsOrigin().y, lagPlayer->GetAbsOrigin().z, - // lagPlayer->m_flInterpolatedSimulationTime); + DevMsg("Client: %s => %f %f %f => %f\n", lagPlayer->GetPlayerName(), lagPlayer->GetAbsOrigin().x, lagPlayer->GetAbsOrigin().y, lagPlayer->GetAbsOrigin().z, + lagPlayer->m_flInterpolatedSimulationTime); #else lagPlayer->DrawServerHitboxes(4, true); #endif diff --git a/game/shared/usercmd.cpp b/game/shared/usercmd.cpp index 436840de8b..56447f8ab7 100644 --- a/game/shared/usercmd.cpp +++ b/game/shared/usercmd.cpp @@ -190,6 +190,19 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from ) } } + for (int i = 0; i <= MAX_PLAYERS; i++) + { + if (to->animtimes[i] != from->animtimes[i]) + { + buf->WriteOneBit( 1 ); + buf->WriteFloat( to->animtimes[i] ); + } + else + { + buf->WriteOneBit(0); + } + } + #if defined( HL2_CLIENT_DLL ) if ( to->entitygroundcontact.Count() != 0 ) { @@ -319,6 +332,15 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from ) } } + for (int i = 0; i <= MAX_PLAYERS; i++) + { + // Simulation time changed unexpectedly ? + if (buf->ReadOneBit()) + { + move->animtimes[i] = buf->ReadFloat(); + } + } + #if defined( HL2_DLL ) if ( buf->ReadOneBit() ) { diff --git a/game/shared/usercmd.h b/game/shared/usercmd.h index 6982e6c373..c603e06d47 100644 --- a/game/shared/usercmd.h +++ b/game/shared/usercmd.h @@ -60,6 +60,9 @@ public: for (int i = 0; i <= MAX_PLAYERS; i++) simulationtimes[i] = 0.0f; + for (int i = 0; i <= MAX_PLAYERS; i++) + animtimes[i] = 0.0f; + #if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) entitygroundcontact.RemoveAll(); #endif @@ -88,6 +91,10 @@ public: for (int i = 0; i <= MAX_PLAYERS; i++) simulationtimes[i] = src.simulationtimes[i]; + + for (int i = 0; i <= MAX_PLAYERS; i++) + animtimes[i] = src.animtimes[i]; + #if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL ) entitygroundcontact = src.entitygroundcontact; #endif @@ -119,6 +126,7 @@ public: CRC32_ProcessBuffer( &crc, &mousedx, sizeof( mousedx ) ); CRC32_ProcessBuffer( &crc, &mousedy, sizeof( mousedy ) ); CRC32_ProcessBuffer( &crc, &simulationtimes, sizeof( simulationtimes ) ); + CRC32_ProcessBuffer( &crc, &animtimes, sizeof( animtimes ) ); CRC32_Final( &crc ); return crc; @@ -169,6 +177,7 @@ public: // TODO_ENHANCED: Lag compensate also other entities when needed. // Send simulation times for each players for lag compensation. float simulationtimes[MAX_PLAYERS+1]; + float animtimes[MAX_PLAYERS+1]; // Back channel to communicate IK state #if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )