Improved bone cache invalidation

Also improved lag comp, for now animations won't be interpolated
This commit is contained in:
Kamay Xutax 2024-09-02 10:33:13 +02:00
parent b9586237f1
commit ece2f9a81f
10 changed files with 116 additions and 105 deletions

View file

@ -3012,8 +3012,18 @@ C_BaseAnimating* C_BaseAnimating::FindFollowedEntity()
void C_BaseAnimating::InvalidateBoneCache()
{
m_iMostRecentModelBoneCounter = g_iModelBoneCounter - 1;
m_flLastBoneSetupTime = -FLT_MAX;
m_iMostRecentModelBoneCounter = 0xFFFFFFFF;
m_flLastBoneSetupTime = -FLT_MAX;
if ( m_pBoneMergeCache )
{
delete m_pBoneMergeCache;
m_pBoneMergeCache = NULL;
// recreated in BuildTransformations
}
Studio_DestroyBoneCache( m_hitboxBoneCacheHandle );
m_hitboxBoneCacheHandle = 0;
}

View file

@ -535,7 +535,7 @@ protected:
float m_flFadeScale;
bool m_bClientSideAnimation;
private:
protected:
float m_flGroundSpeed; // computed linear movement rate for current sequence
float m_flLastEventCheck; // cycle index of when events were last checked

View file

@ -10,6 +10,7 @@
#include "c_user_message_register.h"
#include "cdll_client_int.h"
#include "convar.h"
#include "datacache/imdlcache.h"
#include "dt_recv.h"
#include "iconvar.h"
#include "interpolatedvar.h"
@ -737,7 +738,7 @@ C_CSPlayer::C_CSPlayer() :
m_angRenderAngles.Init();
AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
AddVar( &m_angRenderAngles, &m_iv_angRenderAngles, LATCH_SIMULATION_VAR );
// AddVar( &m_angRenderAngles, &m_iv_angRenderAngles, LATCH_SIMULATION_VAR );
m_iLastAddonBits = m_iAddonBits = 0;
m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE;
@ -2131,8 +2132,11 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
bool shouldShowFireBulletHitboxes = cl_showfirebullethitboxes.GetInt() == 1
|| cl_showfirebullethitboxes.GetInt() == 3;
// TODO_ENHANCED: compare from client's prediction values !
const auto ShowEventHitboxes = [&]( float flDuration )
{
MDLCACHE_CRITICAL_SECTION();
const int index = event->GetInt( "userid" );
if ( index == GetUserID() && IsLocalPlayer() )
{
@ -2173,26 +2177,27 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
float flBackupBoneControllers[MAXSTUDIOBONECTRLS];
C_AnimationLayer backupAnimLayers[C_BaseAnimatingOverlay::MAX_OVERLAYS];
Vector vecBackupPosition = player->GetAbsOrigin();
QAngle angBackupAngles = player->m_angRenderAngles;
QAngle angBackupAngles = player->GetRenderAngles();
auto flOldCycle = GetCycle();
auto iOldSequence = GetSequence();
auto pStudioHdr = GetModelPtr();
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
{
flBackupPoseParams[i] = player->m_flPoseParameter[i];
}
player->GetPoseParameters( pStudioHdr, flBackupPoseParams );
player->GetBoneControllers( flBackupBoneControllers );
for ( int i = 0; i < MAXSTUDIOBONECTRLS; i++ )
{
flBackupBoneControllers[i] = player->m_flEncodedController[i];
}
for ( int i = 0; i < GetNumAnimOverlays(); i++ )
{
backupAnimLayers[i] = m_AnimOverlay[i];
backupAnimLayers[i] = *player->GetAnimOverlay(i);
}
player->SetSequence( event->GetInt( "sequence" ) );
player->SetCycle( event->GetFloat( "cycle" ) );
// printf("was sequence: %i, cycle: %f\n", player->GetSequence(), player->GetCycle() );
// Set setup bones modifiers
player->SetAbsOrigin( Vector( event->GetFloat( "position_x" ),
event->GetFloat( "position_y" ),
event->GetFloat( "position_z" ) ) );
@ -2209,9 +2214,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
char buffer[256];
V_sprintf_safe( buffer, "pose_param_%i", i );
player->SetPoseParameter( i, event->GetFloat( buffer ) );
// printf("pose_param_%i: %f\n", i, player->GetPoseParameter(i) );
player->m_flPoseParameter[i] = event->GetFloat( buffer );
}
const auto numbonecontrollers = event->GetInt( "num_bonecontrollers" );
@ -2222,11 +2225,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
char buffer[256];
V_sprintf_safe( buffer, "bone_controller_%i", i );
player->SetBoneController( i, event->GetFloat( buffer ) );
float tmp[MAXSTUDIOBONECTRLS];
player->GetBoneControllers( tmp );
// printf( "bone_controller_%i: %f\n", i, tmp[i] );
player->m_flEncodedController[i] = event->GetFloat( buffer );
}
auto numanimoverlays = event->GetInt( "num_anim_overlays" );
@ -2239,32 +2238,27 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
char buffer[256];
V_sprintf_safe( buffer, "anim_overlay_cycle_%i", i );
animOverlay->m_flCycle = event->GetFloat( buffer );
// printf( "anim_overlay_cycle_%i: %f\n", i, animOverlay->m_flCycle.GetRaw() );
V_sprintf_safe( buffer, "anim_overlay_sequence_%i", i );
animOverlay->m_nSequence = event->GetInt( buffer );
// printf( "anim_overlay_sequence_%i: %i\n", i, animOverlay->m_nSequence.GetRaw() );
V_sprintf_safe( buffer, "anim_overlay_weight_%i", i );
animOverlay->m_flWeight = event->GetFloat( buffer );
// printf( "anim_overlay_weight_%i: %f\n", i,animOverlay->m_flWeight.GetRaw() );
V_sprintf_safe( buffer, "anim_overlay_order_%i", i );
animOverlay->m_nOrder = event->GetInt( buffer );
// printf( "anim_overlay_order_%i: %i\n", i, animOverlay->m_nOrder );
V_sprintf_safe( buffer, "anim_overlay_flags_%i", i );
animOverlay->m_fFlags = event->GetInt( buffer );
}
PushAllowBoneAccess( true, false, "Lag compensation context" );
player->PushAllowBoneAccess( true, false, "Lag compensation context" );
// Be sure we setup the bones again.
player->InvalidateBoneCache();
player->SetupBones( NULL,
MAXSTUDIOBONES,
BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT | BONE_USED_BY_BONE_MERGE,
gpGlobals->curtime );
player->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
player->DrawClientHitboxes( cl_debug_duration.GetFloat(), false );
// Re-invalidate bone cache for the next frame
player->InvalidateBoneCache();
PopBoneAccess( "Lag compensation context" );
player->PopBoneAccess( "Lag compensation context" );
// Set back original stuff.
player->SetSequence( iOldSequence );
@ -2272,25 +2266,25 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
player->SetAbsOrigin( vecBackupPosition );
player->m_angRenderAngles = angBackupAngles;
for ( int i = 0; i < numposeparams; i++ )
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
{
player->SetPoseParameter( i, flBackupPoseParams[i] );
player->m_flPoseParameter[i] = flBackupPoseParams[i];
}
for ( int i = 0; i < numbonecontrollers; i++ )
for ( int i = 0; i < MAXSTUDIOBONECTRLS; i++ )
{
player->SetBoneController( i, flBackupBoneControllers[i] );
player->m_flEncodedController[i] = flBackupBoneControllers[i];
}
for ( int i = 0; i < numanimoverlays; i++ )
{
auto animOverlay = player->GetAnimOverlay( i );
animOverlay->m_flCycle = backupAnimLayers[i].m_flCycle;
animOverlay->m_nSequence = backupAnimLayers[i].m_nSequence;
animOverlay->m_flWeight = backupAnimLayers[i].m_flWeight;
animOverlay->m_nOrder = backupAnimLayers[i].m_nOrder;
*animOverlay = backupAnimLayers[i];
}
player->PushAllowBoneAccess( true, false, "Lag compensation context" );
player->InvalidateBoneCache();
player->PopBoneAccess( "Lag compensation context" );
}
}
};

View file

@ -1319,9 +1319,9 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo
continue;
}
cmd->simulationdata[pEntity->index].lerp_time = pEntity->m_flInterpolatedSimulationTime;
cmd->simulationdata[pEntity->index].animated_sim_time = pEntity->m_flAnimTime;
cmd->simulationdata[pEntity->index].entityexists = true;
cmd->simulationdata[pEntity->index].sim_time = pEntity->m_flInterpolatedSimulationTime;
cmd->simulationdata[pEntity->index].anim_time = pEntity->m_flAnimTime;
cmd->simulationdata[pEntity->index].entityexists = true;
}
#ifdef CSTRIKE_DLL

View file

@ -1615,6 +1615,10 @@ public:
}
};
//-----------------------------------------------------------------------------
// Purpose: update latched IK contacts if they're in a moving reference frame.
//-----------------------------------------------------------------------------
void CBaseAnimating::UpdateIKLocks( float currentTime )
{
if (!m_pIk)
@ -1643,9 +1647,7 @@ void CBaseAnimating::UpdateIKLocks( float currentTime )
}
//-----------------------------------------------------------------------------
// Purpose: Find IK collisions with world
// Input :
// Output : fills out m_pIk targets, calcs floor offset for rendering
// Purpose: Find the ground or external attachment points needed by IK rules
//-----------------------------------------------------------------------------
void CBaseAnimating::CalculateIKLocks( float currentTime )
@ -1668,7 +1670,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
// FIXME: trace based on gravity or trace based on angles?
Vector up;
AngleVectors( GetAbsAngles(), NULL, NULL, &up );
AngleVectors( GetRenderAngles(), NULL, NULL, &up );
// FIXME: check number of slots?
float minHeight = FLT_MAX;
@ -1690,7 +1692,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
Vector p1, p2;
// adjust ground to original ground position
estGround = (pTarget->est.pos - GetAbsOrigin());
estGround = (pTarget->est.pos - GetRenderOrigin());
estGround = estGround - (estGround * up) * up;
estGround = GetAbsOrigin() + estGround + pTarget->est.floor * up;
@ -1779,7 +1781,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
else if (trace.DidHitNonWorldEntity())
{
pTarget->SetPos( trace.endpos );
pTarget->SetAngles( GetAbsAngles() );
pTarget->SetAngles( GetRenderAngles() );
// only do this on forward tracking or commited IK ground rules
if (pTarget->est.release < 0.1)
@ -1813,7 +1815,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
else
{
pTarget->SetPos( trace.endpos );
pTarget->SetAngles( GetAbsAngles() );
pTarget->SetAngles( GetRenderAngles() );
pTarget->SetOnWorld( true );
}
}
@ -1872,7 +1874,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
}
}
#if defined( HL2_DLL )
#if defined( HL2_CLIENT_DLL )
if (minHeight < FLT_MAX)
{
input->AddIKGroundContactInfo( entindex(), minHeight, maxHeight );
@ -2854,6 +2856,7 @@ CBoneCache *CBaseAnimating::GetBoneCache( void )
void CBaseAnimating::InvalidateBoneCache( void )
{
Studio_InvalidateBoneCache( m_boneCacheHandle );
m_boneCacheHandle = 0;
}
bool CBaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )

View file

@ -39,7 +39,8 @@
#define MAX_TICKS_SAVED 1000
ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" );
ConVar sv_lagflushbonecache( "sv_lagflushbonecache", "0", 0, "Flushes entity bone cache on lag compensation" );
// Enable by default to avoid some bugs.
ConVar sv_lagflushbonecache( "sv_lagflushbonecache", "1", 0, "Flushes entity bone cache on lag compensation" );
//-----------------------------------------------------------------------------
// Purpose:
@ -420,8 +421,8 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
int pl_index = pPlayer->entindex();
float flTargetLerpSimTime = cmd->simulationdata[pl_index].lerp_time;
float flTargetAnimatedSimulationTime = cmd->simulationdata[pl_index].animated_sim_time;
float flTargetSimTime = cmd->simulationdata[pl_index].sim_time;
float flTargetAnimTime = cmd->simulationdata[pl_index].anim_time;
// get track history of this player
auto track = &m_EntityTrack[pl_index];
@ -440,12 +441,12 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
break;
}
if ( flTargetLerpSimTime == recordSim->m_flSimulationTime )
if ( flTargetSimTime == recordSim->m_flSimulationTime )
{
break;
}
if ( recordSim->m_flSimulationTime < flTargetLerpSimTime )
if ( recordSim->m_flSimulationTime < flTargetSimTime )
{
prevRecordSim = track->Get( i - 1 );
break;
@ -461,7 +462,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
break;
}
if ( recordAnim->m_flAnimTime == flTargetAnimatedSimulationTime )
if ( recordAnim->m_flAnimTime == flTargetAnimTime )
{
break;
}
@ -481,7 +482,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
}
float fracSim = 0.0f;
if ( prevRecordSim && ( recordSim->m_flSimulationTime < flTargetLerpSimTime )
if ( prevRecordSim && ( recordSim->m_flSimulationTime < flTargetSimTime )
&& ( recordSim->m_flSimulationTime < prevRecordSim->m_flSimulationTime ) )
{
// we didn't find the exact time but have a valid previous record
@ -491,7 +492,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
Assert( flTargetLerpSimTime < prevRecordSim->m_flSimulationTime );
// calc fraction between both records
fracSim = float( ( double( flTargetLerpSimTime ) - double( recordSim->m_flSimulationTime ) )
fracSim = float( ( double( flTargetSimTime ) - double( recordSim->m_flSimulationTime ) )
/ ( double( prevRecordSim->m_flSimulationTime ) - double( recordSim->m_flSimulationTime ) ) );
Assert( fracSim > 0 && fracSim < 1 ); // should never extrapolate
@ -500,12 +501,6 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
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 );
#ifdef CSTRIKE_DLL
if ( csPlayer )
{
renderAngles = Lerp( fracSim, recordSim->m_angRenderAngles, prevRecordSim->m_angRenderAngles );
}
#endif
}
else
{
@ -515,9 +510,6 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
ang = recordSim->m_vecAngles;
minsPreScaled = recordSim->m_vecMinsPreScaled;
maxsPreScaled = recordSim->m_vecMaxsPreScaled;
#ifdef CSTRIKE_DLL
renderAngles = recordSim->m_angRenderAngles;
#endif
}
// See if this represents a change for the player
@ -535,6 +527,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
#ifdef CSTRIKE_DLL
if ( csPlayer )
{
renderAngles = recordAnim->m_angRenderAngles;
restore->m_angRenderAngles = csPlayer->m_angRenderAngles;
csPlayer->m_angRenderAngles = renderAngles;
}
@ -638,8 +631,8 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
}
// Set lag compensated player's times
pPlayer->SetSimulationTime( flTargetLerpSimTime );
// pPlayer->SetAnimTime(animationData->m_flAnimTime);
pPlayer->SetSimulationTime( flTargetSimTime );
pPlayer->SetAnimTime( flTargetAnimTime );
if ( sv_lagflushbonecache.GetBool() )
{

View file

@ -618,6 +618,9 @@ void CCSPlayer::FireBullet(
V_sprintf_safe( buffer, "anim_overlay_order_%i", i );
event->SetInt( buffer, animOverlay->m_nOrder.Get() );
V_sprintf_safe( buffer, "anim_overlay_flags_%i", i );
event->SetInt( buffer, animOverlay->m_fFlags.Get() );
}
gameeventmanager->FireEvent( event );

View file

@ -613,40 +613,48 @@ int CCSPlayerAnimState::CalcReloadLayerSequence( PlayerAnimEvent_t event )
return -1;
}
void CCSPlayerAnimState::UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd )
void CCSPlayerAnimState::UpdateLayerSequenceGeneric( CStudioHdr* pStudioHdr,
int iLayer,
bool& bEnabled,
float& flCurCycle,
int& iSequence,
bool bWaitAtEnd )
{
if ( !bEnabled || iSequence < 0 )
{
return;
}
// Increment the fire sequence's cycle.
flCurCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, iSequence ) * gpGlobals->frametime;
if ( flCurCycle > 1 )
// Increment the fire sequence's cycle.
flCurCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, iSequence ) * gpGlobals->frametime;
if ( flCurCycle > 1 )
{
if ( bWaitAtEnd )
{
if ( bWaitAtEnd )
{
flCurCycle = 1;
}
else
{
// Not firing anymore.
bEnabled = false;
iSequence = 0;
return;
}
flCurCycle = 1;
}
else
{
// Not firing anymore.
bEnabled = false;
iSequence = 0;
CAnimationLayer* pLayer = m_pOuter->GetAnimOverlay( iLayer );
pLayer->m_fFlags = 0;
return;
}
}
// Now dump the state into its animation layer.
CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iLayer );
CAnimationLayer* pLayer = m_pOuter->GetAnimOverlay( iLayer );
pLayer->m_flCycle = flCurCycle;
pLayer->m_nSequence = iSequence;
pLayer->m_flPlaybackRate = 1.0f;
pLayer->m_flWeight = 1.0f;
pLayer->m_nOrder = iLayer;
#ifndef CLIENT_DLL
pLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
#endif
pLayer->m_flCycle = flCurCycle;
pLayer->m_nSequence = iSequence;
pLayer->m_flPlaybackRate = 1.0f;
pLayer->m_flWeight = 1.0f;
pLayer->m_nOrder = iLayer;
pLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
}
bool CCSPlayerAnimState::IsOuterGrenadePrimed()

View file

@ -162,20 +162,20 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from )
// Write finally simulation data with entity index
for ( unsigned int i = 0; i <= highestEntityIndex; i++ )
{
if ( from->simulationdata[i].lerp_time != to->simulationdata[i].lerp_time )
if ( from->simulationdata[i].sim_time != to->simulationdata[i].sim_time )
{
buf->WriteOneBit( 1 );
buf->WriteBitFloat( to->simulationdata[i].lerp_time );
buf->WriteBitFloat( to->simulationdata[i].sim_time );
}
else
{
buf->WriteOneBit( 0 );
}
if ( from->simulationdata[i].animated_sim_time != to->simulationdata[i].animated_sim_time )
if ( from->simulationdata[i].anim_time != to->simulationdata[i].anim_time )
{
buf->WriteOneBit( 1 );
buf->WriteBitFloat( to->simulationdata[i].animated_sim_time );
buf->WriteBitFloat( to->simulationdata[i].anim_time );
}
else
{
@ -309,12 +309,12 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from )
{
if (buf->ReadOneBit())
{
move->simulationdata[i].lerp_time = buf->ReadBitFloat();
move->simulationdata[i].sim_time = buf->ReadBitFloat();
}
if (buf->ReadOneBit())
{
move->simulationdata[i].animated_sim_time = buf->ReadBitFloat();
move->simulationdata[i].anim_time = buf->ReadBitFloat();
}
}

View file

@ -41,8 +41,8 @@ struct SimulationData
// TODO_ENHANCED:
// For now we send the last received update for animations.
// anim time is unreliable on low fps.
float lerp_time;
float animated_sim_time;
float sim_time;
float anim_time;
bool entityexists;
};