Improved lag compensation for animations

Now we can debug properly lag compensation for animations and make it
more perfect without using the CUserCmd struct
For now it's used to sync better with client but in theory this can be
removed soon.
There's a lot of work to do in anim layers too.
This commit is contained in:
Kamay Xutax 2024-07-10 16:10:00 +02:00
parent 197a93b274
commit 9d17d2252c
15 changed files with 472 additions and 522 deletions

View file

@ -8,6 +8,7 @@
#include "c_baseanimating.h"
#include "c_sprite.h"
#include "cdll_client_int.h"
#include "interpolatedvar.h"
#include "model_types.h"
#include "bone_setup.h"
#include "ivrenderview.h"
@ -658,8 +659,8 @@ class C_BaseAnimatingGameSystem : public CAutoGameSystem
//-----------------------------------------------------------------------------
// Purpose: convert axis rotations to a quaternion
//-----------------------------------------------------------------------------
C_BaseAnimating::C_BaseAnimating() :
m_iv_flCycle( "C_BaseAnimating::m_iv_flCycle" ),
C_BaseAnimating::C_BaseAnimating()
: m_iv_flCycle( "C_BaseAnimating::m_iv_flCycle" ),
m_iv_flPoseParameter( "C_BaseAnimating::m_iv_flPoseParameter" ),
m_iv_flEncodedController("C_BaseAnimating::m_iv_flEncodedController")
{
@ -867,31 +868,16 @@ void C_BaseAnimating::UpdateRelevantInterpolatedVars()
void C_BaseAnimating::AddBaseAnimatingInterpolatedVars()
{
AddVar( m_flEncodedController, &m_iv_flEncodedController, LATCH_ANIMATION_VAR, true );
AddVar( m_flPoseParameter, &m_iv_flPoseParameter, LATCH_ANIMATION_VAR, true );
int flags = LATCH_ANIMATION_VAR;
if ( m_bClientSideAnimation )
flags |= EXCLUDE_AUTO_INTERPOLATE;
AddVar( &m_flCycle, &m_iv_flCycle, flags, true );
AddVar( m_flEncodedController, &m_iv_flEncodedController, LATCH_SIMULATION_VAR, true );
AddVar( m_flPoseParameter, &m_iv_flPoseParameter, LATCH_SIMULATION_VAR, true );
AddVar( &m_flCycle, &m_iv_flCycle, LATCH_SIMULATION_VAR, true );
}
void C_BaseAnimating::RemoveBaseAnimatingInterpolatedVars()
{
RemoveVar( m_flEncodedController, false );
RemoveVar( m_flPoseParameter, false );
#ifdef HL2MP
// HACK: Don't want to remove interpolation for predictables in hl2dm, though
// The animation state stuff sets the pose parameters -- so they should interp
// but m_flCycle is not touched, so it's only set during prediction (which occurs on tick boundaries)
// and so needs to continue to be interpolated for smooth rendering of the lower body of the local player in third person, etc.
if ( !GetPredictable() )
#endif
{
RemoveVar( &m_flCycle, false );
}
RemoveVar( &m_flCycle, false );
}
void C_BaseAnimating::StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flCycleDelta )
@ -1134,13 +1120,10 @@ CStudioHdr *C_BaseAnimating::OnNewModel()
Assert( hdr->GetNumPoseParameters() <= ARRAYSIZE( m_flPoseParameter ) );
m_iv_flPoseParameter.SetMaxCount( hdr->GetNumPoseParameters() );
int i;
for ( i = 0; i < hdr->GetNumPoseParameters() ; i++ )
{
const mstudioposeparamdesc_t &Pose = hdr->pPoseParameter( i );
m_iv_flPoseParameter.SetLooping( Pose.loop != 0.0f, i );
// Note: We can't do this since if we get a DATA_UPDATE_CREATED (i.e., new entity) with both a new model and some valid pose parameters this will slam the
// pose parameters to zero and if the model goes dormant the pose parameter field will never be set to the true value. We shouldn't have to zero these out
// as they are under the control of the server and should be properly set
@ -1152,12 +1135,9 @@ CStudioHdr *C_BaseAnimating::OnNewModel()
int boneControllerCount = MIN( hdr->numbonecontrollers(), ARRAYSIZE( m_flEncodedController ) );
m_iv_flEncodedController.SetMaxCount( boneControllerCount );
for ( i = 0; i < boneControllerCount ; i++ )
{
bool loop = (hdr->pBonecontroller( i )->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) != 0;
m_iv_flEncodedController.SetLooping( loop, i );
SetBoneController( i, 0.0 );
}
@ -1978,7 +1958,9 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat
// debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%30s %6.2f : %6.2f", hdr->pSeqdesc( GetSequence() )->pszLabel( ), fCycle, 1.0 );
MaintainSequenceTransitions( boneSetup, fCycle, currentTime, pos, q );
// TODO_ENHANCED: Do that only for client side animations
// if (m_bClientSideAnimation)
MaintainSequenceTransitions( boneSetup, fCycle, currentTime, pos, q );
AccumulateLayers( boneSetup, pos, q, currentTime );
@ -2685,8 +2667,6 @@ void C_BaseAnimating::ControlMouth( CStudioHdr *pstudiohdr )
//Adrian - Set the pose parameter value.
//It has to be called "mouth".
SetPoseParameter( pstudiohdr, index, value );
// Reset interpolation here since the client is controlling this rather than the server...
m_iv_flPoseParameter.SetHistoryValuesForItem( index, raw );
}
}
@ -4358,9 +4338,6 @@ bool C_BaseAnimating::Interpolate( float flCurrentTime )
float flOldCycle = GetCycle();
int nChangeFlags = 0;
if ( !m_bClientSideAnimation )
m_iv_flCycle.SetLooping( IsSequenceLooping( GetSequence() ) );
int bNoMoreChanges;
int retVal = BaseInterpolatePart1( flCurrentTime, oldOrigin, oldAngles, oldVel, bNoMoreChanges );
if ( retVal == INTERPOLATE_STOP )
@ -4623,20 +4600,6 @@ void C_BaseAnimating::PostDataUpdate( DataUpdateType_t updateType )
ClientSideAnimationChanged();
}
}
// reset prev cycle if new sequence
if (m_nNewSequenceParity != m_nPrevNewSequenceParity)
{
// It's important not to call Reset() on a static prop, because if we call
// Reset(), then the entity will stay in the interpolated entities list
// forever, wasting CPU.
MDLCACHE_CRITICAL_SECTION();
CStudioHdr *hdr = GetModelPtr();
if ( hdr && !( hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP ) )
{
m_iv_flCycle.Reset();
}
}
}
//-----------------------------------------------------------------------------

View file

@ -499,6 +499,7 @@ public:
int m_nHitboxSet;
CSequenceTransitioner m_SequenceTransitioner;
int m_iIKCounter;
protected:
CIKContext *m_pIk;

View file

@ -8,6 +8,7 @@
#include "cbase.h"
#include "c_baseanimatingoverlay.h"
#include "bone_setup.h"
#include "interpolatedvar.h"
#include "studio.h"
#include "tier0/vprof.h"
#include "engine/ivdebugoverlay.h"
@ -105,16 +106,15 @@ void ResizeAnimationLayerCallback( void *pStruct, int offsetToUtlVector, int len
{
IInterpolatedVar *pWatcher = &pVecIV->Element( i );
pWatcher->SetDebugName( s_m_iv_AnimOverlayNames[i] );
pEnt->AddVar( &pVec->Element( i ), pWatcher, LATCH_ANIMATION_VAR, true );
pEnt->AddVar( &pVec->Element( i ), pWatcher, LATCH_SIMULATION_VAR, true );
}
// FIXME: need to set historical values of nOrder in pVecIV to MAX_OVERLAY
}
BEGIN_RECV_TABLE_NOBASE( C_BaseAnimatingOverlay, DT_OverlayVars )
RecvPropUtlVector(
RECVINFO_UTLVECTOR_SIZEFN( m_AnimOverlay, ResizeAnimationLayerCallback ),
RECVINFO_UTLVECTOR( m_AnimOverlay ),
C_BaseAnimatingOverlay::MAX_OVERLAYS,
RecvPropDataTable(NULL, 0, 0, &REFERENCE_RECV_TABLE( DT_Animationlayer ) ) )
END_RECV_TABLE()
@ -203,228 +203,33 @@ void C_BaseAnimatingOverlay::GetRenderBounds( Vector& theMins, Vector& theMaxs )
}
}
void C_BaseAnimatingOverlay::CheckForLayerChanges( CStudioHdr *hdr, float currentTime )
{
CDisableRangeChecks disableRangeChecks;
bool bLayersChanged = false;
// FIXME: damn, there has to be a better way than this.
int i;
for (i = 0; i < m_iv_AnimOverlay.Count(); i++)
{
CDisableRangeChecks disableRangeChecks;
int iHead, iPrev1, iPrev2;
m_iv_AnimOverlay[i].GetInterpolationInfo( currentTime, &iHead, &iPrev1, &iPrev2 );
// fake up previous cycle values.
float t0;
C_AnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 );
// reset previous
float t1;
C_AnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 );
// reset previous previous
float t2;
C_AnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 );
if ( pHead && pPrev1 && pHead->m_nSequence != pPrev1->m_nSequence )
{
bLayersChanged = true;
#if 1 // _DEBUG
if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex())
{
DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t0, hdr->pSeqdesc( pHead->m_nSequence ).pszLabel(), (float)pHead->m_flCycle, (float)pHead->m_flWeight, i );
DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t1, hdr->pSeqdesc( pPrev1->m_nSequence ).pszLabel(), (float)pPrev1->m_flCycle, (float)pPrev1->m_flWeight, i );
if (pPrev2)
DevMsgRT( "(%7.4f : %30s : %5.3f : %4.2f : %1d)\n", t2, hdr->pSeqdesc( pPrev2->m_nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev2->m_flWeight, i );
}
#endif
if (pPrev1)
{
pPrev1->m_nSequence = pHead->m_nSequence;
pPrev1->m_flCycle = pHead->m_flPrevCycle;
pPrev1->m_flWeight = pHead->m_flWeight;
}
if (pPrev2)
{
float num = 0;
if ( fabs( t0 - t1 ) > 0.001f )
num = (t2 - t1) / (t0 - t1);
pPrev2->m_nSequence = pHead->m_nSequence;
float flTemp;
if (IsSequenceLooping( hdr, pHead->m_nSequence ))
{
flTemp = LoopingLerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle );
}
else
{
flTemp = Lerp( num, (float)pHead->m_flPrevCycle, (float)pHead->m_flCycle );
}
pPrev2->m_flCycle = flTemp;
pPrev2->m_flWeight = pHead->m_flWeight;
}
/*
if (stricmp( r_seq_overlay_debug.GetString(), hdr->name ) == 0)
{
DevMsgRT( "(%30s %6.2f : %6.2f : %6.2f)\n", hdr->pSeqdesc( pHead->nSequence ).pszLabel(), (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle );
}
*/
m_iv_AnimOverlay[i].SetLooping( IsSequenceLooping( hdr, pHead->m_nSequence ) );
m_iv_AnimOverlay[i].Interpolate( currentTime );
// reset event indexes
m_flOverlayPrevEventCycle[i] = pHead->m_flPrevCycle - 0.01;
}
}
if (bLayersChanged)
{
// render bounds may have changed
UpdateVisibility();
}
}
void C_BaseAnimatingOverlay::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
{
BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime );
int i;
BaseClass::AccumulateLayers(boneSetup, pos, q, currentTime);
// resort the layers
int layer[MAX_OVERLAYS];
for (i = 0; i < MAX_OVERLAYS; i++)
// sort the layers
int layer[MAX_OVERLAYS] = {};
int i;
for (i = 0; i < m_AnimOverlay.Count(); i++)
{
layer[i] = MAX_OVERLAYS;
}
for (i = 0; i < m_AnimOverlay.Count(); i++)
{
if (m_AnimOverlay[i].m_nOrder < MAX_OVERLAYS)
CAnimationLayer &pLayer = m_AnimOverlay[i];
if( (pLayer.m_flWeight > 0) && pLayer.IsActive() && pLayer.m_nOrder >= 0 && pLayer.m_nOrder < m_AnimOverlay.Count())
{
/*
Assert( layer[m_AnimOverlay[i].m_nOrder] == MAX_OVERLAYS );
layer[m_AnimOverlay[i].m_nOrder] = i;
*/
// hacky code until initialization of new layers is finished
if (layer[m_AnimOverlay[i].m_nOrder] != MAX_OVERLAYS)
{
m_AnimOverlay[i].m_nOrder = MAX_OVERLAYS;
}
else
{
layer[m_AnimOverlay[i].m_nOrder] = i;
}
layer[pLayer.m_nOrder] = i;
}
}
CheckForLayerChanges( boneSetup.GetStudioHdr(), currentTime );
int nSequences = boneSetup.GetStudioHdr()->GetNumSeq();
// add in the overlay layers
int j;
for (j = 0; j < MAX_OVERLAYS; j++)
for (i = 0; i < m_AnimOverlay.Count(); i++)
{
i = layer[ j ];
if (i < m_AnimOverlay.Count())
if (layer[i] >= 0 && layer[i] < m_AnimOverlay.Count())
{
if ( m_AnimOverlay[i].m_nSequence >= nSequences )
{
continue;
}
/*
DevMsgRT( 1 , "%.3f %.3f %.3f\n", currentTime, fWeight, dadt );
debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), -j - 1, 0,
"%2d(%s) : %6.2f : %6.2f",
m_AnimOverlay[i].m_nSequence,
hdr->pSeqdesc( m_AnimOverlay[i].m_nSequence )->pszLabel(),
m_AnimOverlay[i].m_flCycle,
m_AnimOverlay[i].m_flWeight
);
*/
m_AnimOverlay[i].BlendWeight();
float fWeight = m_AnimOverlay[i].m_flWeight;
if (fWeight > 0)
{
// check to see if the sequence changed
// FIXME: move this to somewhere more reasonable
// do a nice spline interpolation of the values
// if ( m_AnimOverlay[i].m_nSequence != m_iv_AnimOverlay.GetPrev( i )->nSequence )
float fCycle = m_AnimOverlay[ i ].m_flCycle;
fCycle = ClampCycle( fCycle, IsSequenceLooping( m_AnimOverlay[i].m_nSequence ) );
if (fWeight > 1)
fWeight = 1;
boneSetup.AccumulatePose( pos, q, m_AnimOverlay[i].m_nSequence, fCycle, fWeight, currentTime, m_pIk );
#if 1 // _DEBUG
if (/* Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex())
{
if (1)
{
DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i );
}
else
{
int iHead, iPrev1, iPrev2;
m_iv_AnimOverlay[i].GetInterpolationInfo( currentTime, &iHead, &iPrev1, &iPrev2 );
// fake up previous cycle values.
float t0;
C_AnimationLayer *pHead = m_iv_AnimOverlay[i].GetHistoryValue( iHead, t0 );
// reset previous
float t1;
C_AnimationLayer *pPrev1 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev1, t1 );
// reset previous previous
float t2;
C_AnimationLayer *pPrev2 = m_iv_AnimOverlay[i].GetHistoryValue( iPrev2, t2 );
if ( pHead && pPrev1 && pPrev2 )
{
DevMsgRT( "%6.2f : %30s %6.2f (%6.2f:%6.2f:%6.2f) : %6.2f (%6.2f:%6.2f:%6.2f) : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(),
fCycle, (float)pPrev2->m_flCycle, (float)pPrev1->m_flCycle, (float)pHead->m_flCycle,
fWeight, (float)pPrev2->m_flWeight, (float)pPrev1->m_flWeight, (float)pHead->m_flWeight,
i );
}
else
{
DevMsgRT( "%6.2f : %30s %6.2f : %6.2f : %1d\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i );
}
}
}
#endif
//#define DEBUG_TF2_OVERLAYS
#if defined( DEBUG_TF2_OVERLAYS )
engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", boneSetup.GetStudioHdr()->pSeqdesc( m_AnimOverlay[i].m_nSequence ).pszLabel(), fCycle, fWeight, i );
}
else
{
engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i );
#endif
}
CAnimationLayer &pLayer = m_AnimOverlay[layer[i]];
// UNDONE: Is it correct to use overlay weight for IK too?
boneSetup.AccumulatePose( pos, q, pLayer.m_nSequence, pLayer.m_flCycle, pLayer.m_flWeight, currentTime, m_pIk );
}
#if defined( DEBUG_TF2_OVERLAYS )
else
{
engine->Con_NPrintf( 10 + j, "%30s %6.2f : %6.2f : %1d", " ", 0.f, 0.f, i );
}
#endif
}
}
@ -441,8 +246,6 @@ void C_BaseAnimatingOverlay::DoAnimationEvents( CStudioHdr *pStudioHdr )
bool watch = false; // Q_strstr( hdr->name, "rifle" ) ? true : false;
CheckForLayerChanges( pStudioHdr, gpGlobals->curtime ); // !!!
int j;
for (j = 0; j < m_AnimOverlay.Count(); j++)
{

View file

@ -35,8 +35,6 @@ public:
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
void CheckForLayerChanges( CStudioHdr *hdr, float currentTime );
// model specific
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
virtual void DoAnimationEvents( CStudioHdr *pStudioHdr );
@ -48,9 +46,7 @@ public:
};
CUtlVector < C_AnimationLayer > m_AnimOverlay;
CUtlVector < CInterpolatedVar< C_AnimationLayer > > m_iv_AnimOverlay;
float m_flOverlayPrevEventCycle[ MAX_OVERLAYS ];
private:

View file

@ -7,6 +7,9 @@
#include "cbase.h"
#include "c_cs_player.h"
#include "c_user_message_register.h"
#include "cdll_client_int.h"
#include "shareddefs.h"
#include "studio.h"
#include "view.h"
#include "iclientvehicle.h"
#include "ivieweffects.h"
@ -2533,6 +2536,101 @@ float C_CSPlayer::GetDeathCamInterpolationTime()
}
ConVar cl_cs_player_setupbones("cl_cs_player_setupbones", "1");
bool C_CSPlayer::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
{
if (cl_cs_player_setupbones.GetBool())
{
AUTO_LOCK( m_BoneSetupLock );
MDLCACHE_CRITICAL_SECTION();
Assert( GetModelPtr() );
CStudioHdr *pStudioHdr = GetModelPtr( );
if(!pStudioHdr)
{
Assert(!"C_BaseAnimating::GetSkeleton() without a model");
return false;
}
Assert( !IsEFlagSet( EFL_SETTING_UP_BONES ) );
AddEFlags( EFL_SETTING_UP_BONES );
Vector pos[MAXSTUDIOBONES];
Quaternion q[MAXSTUDIOBONES];
// adjust hit boxes based on IK driven offset
Vector adjOrigin = GetRenderOrigin();
if ( m_pIk )
{
// FIXME: pass this into Studio_BuildMatrices to skip transforms
CBoneBitList boneComputed;
m_iIKCounter++;
m_pIk->Init( pStudioHdr, GetRenderAngles(), adjOrigin, currentTime, m_iIKCounter, boneMask );
GetSkeleton( pStudioHdr, pos, q, boneMask, currentTime );
m_pIk->UpdateTargets( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
CalculateIKLocks( currentTime );
m_pIk->SolveDependencies( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
}
else
{
// Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
GetSkeleton( pStudioHdr, pos, q, boneMask, currentTime );
}
CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() );
if ( pParent )
{
// We're doing bone merging, so do special stuff here.
CBoneCache *pParentCache = pParent->GetBoneCache(pParent->GetModelPtr());
if ( pParentCache )
{
BuildMatricesWithBoneMerge(
pStudioHdr,
GetRenderAngles(),
adjOrigin,
pos,
q,
m_BoneAccessor.GetBoneArrayForWrite(),
pParent,
pParentCache );
RemoveEFlags( EFL_SETTING_UP_BONES );
return true;
}
}
Studio_BuildMatrices(
pStudioHdr,
GetRenderAngles(),
adjOrigin,
pos,
q,
-1,
GetModelScale(), // Scaling
m_BoneAccessor.GetBoneArrayForWrite(),
boneMask );
RemoveEFlags(EFL_SETTING_UP_BONES);
if ( pBoneToWorldOut )
{
memcpy( pBoneToWorldOut, m_BoneAccessor.GetBoneArrayForWrite(), sizeof( matrix3x4_t ) * MAXSTUDIOBONES );
}
return true;
}
else
{
return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
}
}
//=============================================================================
// HPE_END

View file

@ -150,6 +150,7 @@ public:
virtual void CalcFreezeCamView( Vector& eyeOrigin, QAngle& eyeAngles, float& fov );
virtual float GetDeathCamInterpolationTime();
virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
//=============================================================================
// HPE_END
//=============================================================================
@ -378,7 +379,6 @@ private:
float m_serverIntendedCycle; // server periodically updates this to fix up our anims, here it is the float we want, or -1 for no override
//=============================================================================
// HPE_BEGIN:
// [tj] Network variables that track who are dominating and being dominated by

View file

@ -9,6 +9,12 @@
#include "cbase.h"
#include <cmath>
#include <cstdio>
#include "bone_setup.h"
#include "util_shared.h"
#include "c_baseplayer.h"
#include "c_baseentity.h"
#include "cdll_bounded_cvars.h"
#include "cdll_client_int.h"
#include "cdll_util.h"
@ -1289,17 +1295,70 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo
m_EntityGroundContact.RemoveAll();
#endif
// Send interpolated simulation time for lag compensation
for (int i = 0; i <= MAX_PLAYERS; i++)
{
auto pPlayer = UTIL_PlayerByIndex(i);
for (int i = 0; i < MAX_EDICTS; i++)
{
cmd->has_simulation[i] = false;
cmd->has_animation[i] = false;
}
if (pPlayer)
{
cmd->simulationtimes[pPlayer->index] = pPlayer->m_flInterpolatedSimulationTime;
cmd->animtimes[pPlayer->index] = pPlayer->m_flInterpolatedAnimTime;
// Send interpolated simulation time for lag compensation
for (int i = 0; i <= gpGlobals->maxClients; i++)
{
auto pEntity = ClientEntityList().GetEnt(i);
if (!pEntity)
{
continue;
}
cmd->has_simulation[pEntity->index] = true;
cmd->simulationtimes[pEntity->index] = pEntity->m_flInterpolatedSimulationTime;
if (pEntity->index < 1 and pEntity->index > MAX_PLAYERS)
{
continue;
}
}
auto pBasePlayer = ToBasePlayer(pEntity);
if (!pBasePlayer)
{
continue;
}
if (pBasePlayer->IsLocalPlayer())
{
continue;
}
if (!pBasePlayer->GetModelPtr())
{
continue;
}
cmd->has_animation[pBasePlayer->index] = true;
cmd->animationdata[pBasePlayer->index].m_flAnimTime = pBasePlayer->m_flInterpolatedAnimTime;
pBasePlayer->GetBoneControllers(cmd->animationdata[pBasePlayer->index].m_encodedControllers);
pBasePlayer->GetPoseParameters(pBasePlayer->GetModelPtr(),
cmd->animationdata[pBasePlayer->index].m_poseParameters);
cmd->animationdata[pBasePlayer->index].m_masterCycle = pBasePlayer->GetCycle();
cmd->animationdata[pBasePlayer->index].m_masterSequence = pBasePlayer->GetSequence();
for (int j = 0; j < pBasePlayer->GetNumAnimOverlays(); j++)
{
cmd->animationdata[pBasePlayer->index].m_layerRecords[j].m_cycle =
pBasePlayer->GetAnimOverlay(j)->m_flCycle;
cmd->animationdata[pBasePlayer->index].m_layerRecords[j].m_sequence =
pBasePlayer->GetAnimOverlay(j)->m_nSequence;
cmd->animationdata[pBasePlayer->index].m_layerRecords[j].m_order =
pBasePlayer->GetAnimOverlay(j)->m_nOrder;
cmd->animationdata[pBasePlayer->index].m_layerRecords[j].m_weight =
pBasePlayer->GetAnimOverlay(j)->m_flWeight;
}
}
pVerified->m_cmd = *cmd;
pVerified->m_crc = cmd->GetChecksum();

View file

@ -148,6 +148,8 @@ public:
inline float SetPoseParameter( const char *szName, float flValue ) { return SetPoseParameter( GetModelPtr(), szName, flValue ); }
float SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue );
inline float SetPoseParameter( int iParameter, float flValue ) { return SetPoseParameter( GetModelPtr(), iParameter, flValue ); }
inline void SetPoseParameterRaw(int iParameter, float flValue) { m_flPoseParameter.Set(iParameter, flValue); };
inline void SetBoneControllerRaw(int i, float flValue) { m_flEncodedController.Set(i, flValue); }
float GetPoseParameter( const char *szName );
float GetPoseParameter( int iParameter );
@ -316,7 +318,7 @@ public:
CBaseEntity *GetLightingOrigin();
const float* GetPoseParameterArray() { return m_flPoseParameter.Base(); }
const float* GetEncodedControllerArray() { return m_flEncodedController.Base(); }
const float *GetEncodedControllerArray() { return m_flEncodedController.Base(); }
void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles,
const Vector& origin, const Vector pos[MAXSTUDIOBONES],

View file

@ -209,7 +209,7 @@ public:
SetAbsVelocity( m_hPlayer->GetAbsVelocity() );
AddSolidFlags( FSOLID_NOT_SOLID );
ChangeTeam( m_hPlayer->GetTeamNumber() );
UseClientSideAnimation();
// UseClientSideAnimation();
}
public:
@ -418,6 +418,7 @@ CCSPlayer::CCSPlayer()
{
m_PlayerAnimState = CreatePlayerAnimState( this, this, LEGANIM_9WAY, true );
// TODO: one day we need to remove this shit.
// UseClientSideAnimation();
m_iLastWeaponFireUsercmd = 0;

View file

@ -105,7 +105,7 @@ CHostage::CHostage()
m_PlayerAnimState = CreateHostageAnimState( this, this, LEGANIM_8WAY, false );
// ENHANCED_TODO: remove this
UseClientSideAnimation();
// UseClientSideAnimation();
SetBloodColor( BLOOD_COLOR_RED );
}

View file

@ -38,33 +38,6 @@ ConVar sv_unlag_fixstuck( "sv_unlag_fixstuck", "0", FCVAR_DEVELOPMENTONLY, "Disa
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#define MAX_LAYER_RECORDS (CBaseAnimatingOverlay::MAX_OVERLAYS)
#define MAX_POSE_PARAMETERS (CBaseAnimating::NUM_POSEPAREMETERS)
#define MAX_ENCODED_CONTROLLERS (MAXSTUDIOBONECTRLS)
struct LayerRecord
{
int m_sequence;
float m_cycle;
float m_weight;
int m_order;
LayerRecord()
{
m_sequence = 0;
m_cycle = 0;
m_weight = 0;
m_order = 0;
}
LayerRecord( const LayerRecord& src )
{
m_sequence = src.m_sequence;
m_cycle = src.m_cycle;
m_weight = src.m_weight;
m_order = src.m_order;
}
};
struct LagRecord
{
@ -137,6 +110,8 @@ public:
float m_masterCycle;
float m_poseParameters[MAX_POSE_PARAMETERS];
float m_encodedControllers[MAX_ENCODED_CONTROLLERS];
// TODO: do proper eyeAngles lag compensation
QAngle m_angEyeAngles;
};
@ -426,11 +401,10 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
int pl_index = pPlayer->entindex() - 1;
float flTargetSimulationTime = cmd->simulationtimes[pl_index + 1];
float flTargetAnimTime = cmd->animtimes[pl_index + 1];
auto animationData = &cmd->animationdata[pl_index + 1];
// get track history of this player
CUtlFixedLinkedList< LagRecord > *trackSim = &m_PlayerTrack[ pl_index ];
// CUtlFixedLinkedList< LagRecord > *trackAnim = &m_PlayerTrack[ pl_index ];
// check if we have at leat one entry
if ( trackSim->Count() <= 0 )
@ -470,37 +444,6 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
currSim = trackSim->Next( currSim );
}
// intp currAnim = trackSim->Head();
// 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 )
@ -545,24 +488,6 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
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() )
{
@ -672,39 +597,8 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
restore->m_masterSequence = pPlayer->GetSequence();
restore->m_masterCycle = pPlayer->GetCycle();
bool interpolationAllowed = false;
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;
}
////////////////////////
// First do the master settings
bool interpolatedMasters = false;
if( fracSim > 0.0f && interpolationAllowed )
{
interpolatedMasters = true;
pPlayer->SetSequence( Lerp( fracSim, recordSim->m_masterSequence, prevRecordSim->m_masterSequence ) );
pPlayer->SetCycle( Lerp( fracSim, recordSim->m_masterCycle, prevRecordSim->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( 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( fracSim, recordSim->m_masterCycle, prevRecordSim->m_masterCycle ) );
}
}
if( !interpolatedMasters )
{
pPlayer->SetSequence(recordSim->m_masterSequence);
pPlayer->SetCycle(recordSim->m_masterCycle);
}
pPlayer->SetSequence(animationData->m_masterSequence);
pPlayer->SetCycle(animationData->m_masterCycle);
////////////////////////
// Now do all the layers
@ -717,44 +611,14 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
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_weight = currentLayer
->m_flWeight;
bool interpolated = false;
if( (fracSim > 0.0f) && interpolationAllowed )
{
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)
)
{
// We can't interpolate across a sequence or order change
interpolated = true;
if( recordsLayerRecord.m_cycle > prevRecordsLayerRecord.m_cycle )
{
// 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( 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( fracSim, recordsLayerRecord.m_cycle, prevRecordsLayerRecord.m_cycle );
}
currentLayer->m_nOrder = recordsLayerRecord.m_order;
currentLayer->m_nSequence = recordsLayerRecord.m_sequence;
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 = 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;
}
}
currentLayer->m_flCycle = animationData->m_layerRecords[layerIndex].m_cycle;
currentLayer->m_nOrder = animationData->m_layerRecords[layerIndex].m_order;
currentLayer->m_nSequence = animationData->m_layerRecords[layerIndex].m_sequence;
currentLayer->m_flWeight = animationData->m_layerRecords[layerIndex].m_weight;
}
}
flags |= LC_POSE_PARAMS_CHANGED;
@ -766,19 +630,9 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
for( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ )
{
restore->m_poseParameters[paramIndex] = pPlayer->GetPoseParameter(paramIndex);
float poseParameter = recordSim->m_poseParameters[paramIndex];
float poseParameter = animationData->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 = prevRecordSim->m_poseParameters[paramIndex];
pPlayer->SetPoseParameter( paramIndex, Lerp( fracSim, poseParameter, prevPoseParameter ) );
}
else
{
pPlayer->SetPoseParameter( paramIndex, poseParameter );
}
pPlayer->SetPoseParameterRaw( paramIndex, poseParameter );
}
}
@ -789,19 +643,9 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
for( int paramIndex = 0; paramIndex < hdr->GetNumBoneControllers(); paramIndex++ )
{
restore->m_encodedControllers[paramIndex] = pPlayer->GetBoneController(paramIndex);
float encodedController = recordSim->m_encodedControllers[paramIndex];
float encodedController = animationData->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 );
}
pPlayer->SetBoneControllerRaw( paramIndex, encodedController );
}
}
@ -810,7 +654,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
// Set lag compensated player's times
pPlayer->SetSimulationTime(flTargetSimulationTime);
pPlayer->SetAnimTime(flTargetAnimTime);
pPlayer->SetAnimTime(animationData->m_flAnimTime);
if ( sv_lagflushbonecache.GetBool() )
pPlayer->InvalidateBoneCache();
@ -827,7 +671,7 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer *pPlayer, CUserCmd *c
if( sv_showlagcompensation.GetInt() == pPlayer->entindex() )
{
pPlayer->DrawServerHitboxes(60, false);
pPlayer->DrawServerHitboxes(60, true);
}
static ConVar *sv_showplayerhitboxes = g_pCVar->FindVar("sv_showplayerhitboxes");

View file

@ -669,41 +669,6 @@ void CBasePlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr )
{
GetOuter()->SetPoseParameter( pStudioHdr, iMoveYaw, flYaw );
m_flLastMoveYaw = flYaw;
// Now blend in his idle animation.
// This makes the 8-way blend act like a 9-way blend by blending to
// an idle sequence as he slows down.
#if defined(CLIENT_DLL)
bool bIsMoving;
CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( MAIN_IDLE_SEQUENCE_LAYER );
pLayer->m_flWeight = 1 - CalcMovementPlaybackRate( &bIsMoving );
if ( !bIsMoving )
{
pLayer->m_flWeight = 1;
}
if ( ShouldChangeSequences() )
{
// Whenever this layer stops blending, we can choose a new idle sequence to blend to, so he
// doesn't always use the same idle.
if ( pLayer->m_flWeight < 0.02f || m_iCurrent8WayIdleSequence == -1 )
{
m_iCurrent8WayIdleSequence = m_pOuter->SelectWeightedSequence( ACT_IDLE );
m_iCurrent8WayCrouchIdleSequence = m_pOuter->SelectWeightedSequence( ACT_CROUCHIDLE );
}
if ( m_eCurrentMainSequenceActivity == ACT_CROUCHIDLE || m_eCurrentMainSequenceActivity == ACT_RUN_CROUCH )
pLayer->m_nSequence = m_iCurrent8WayCrouchIdleSequence;
else
pLayer->m_nSequence = m_iCurrent8WayIdleSequence;
}
pLayer->m_flPlaybackRate = 1;
pLayer->m_flCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, pLayer->m_nSequence ) * gpGlobals->frametime;
pLayer->m_flCycle = fmod( pLayer->m_flCycle, 1 );
pLayer->m_nOrder = MAIN_IDLE_SEQUENCE_LAYER;
#endif
}
}
}
@ -919,7 +884,7 @@ const QAngle& CBasePlayerAnimState::GetRenderAngles()
void CBasePlayerAnimState::GetOuterAbsVelocity( Vector& vel ) const
{
#if defined( CLIENT_DLL )
GetOuter()->EstimateAbsVelocity( vel );
vel = GetOuter()->GetAbsVelocity();
#else
vel = GetOuter()->GetAbsVelocity();
#endif

View file

@ -507,7 +507,7 @@ void CCSPlayer::FireBullet(
if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() )
{
CBasePlayer *player = ToBasePlayer( tr.m_pEnt );
player->DrawServerHitboxes( 4, true );
player->DrawServerHitboxes( 60, false );
}
}
#endif

View file

@ -9,6 +9,7 @@
#include "usercmd.h"
#include "bitbuf.h"
#include "checksum_md5.h"
#include "const.h"
// memdbgon must be the last include file in a .cpp file!!!
#ifdef CLIENT_DLL
@ -177,8 +178,15 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from )
buf->WriteOneBit( 0 );
}
for (int i = 0; i <= MAX_PLAYERS; i++)
{
for (int i = 0; i < MAX_EDICTS; i++)
{
buf->WriteOneBit(to->has_simulation[i]);
if (!to->has_simulation[i])
{
continue;
}
if (to->simulationtimes[i] != from->simulationtimes[i])
{
buf->WriteOneBit( 1 );
@ -187,20 +195,113 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from )
else
{
buf->WriteOneBit(0);
}
}
}
for (int i = 0; i <= MAX_PLAYERS; i++)
{
if (to->animtimes[i] != from->animtimes[i])
buf->WriteOneBit(to->has_animation[i]);
if (!to->has_animation[i])
{
continue;
}
if (to->animationdata[i].m_flAnimTime != from->animationdata[i].m_flAnimTime)
{
buf->WriteOneBit( 1 );
buf->WriteFloat( to->animtimes[i] );
buf->WriteFloat( to->animationdata[i].m_flAnimTime );
}
else
{
buf->WriteOneBit(0);
}
if (to->animationdata[i].m_masterSequence != from->animationdata[i].m_masterSequence)
{
buf->WriteOneBit( 1 );
buf->WriteVarInt32( to->animationdata[i].m_masterSequence );
}
else
{
buf->WriteOneBit(0);
}
if (to->animationdata[i].m_masterCycle != from->animationdata[i].m_masterCycle)
{
buf->WriteOneBit( 1 );
buf->WriteFloat( to->animationdata[i].m_masterCycle );
}
else
{
buf->WriteOneBit(0);
}
for (int j = 0; j < MAX_POSE_PARAMETERS; j++)
{
if (to->animationdata[i].m_poseParameters[j] != from->animationdata[i].m_poseParameters[j])
{
buf->WriteOneBit( 1 );
buf->WriteFloat( to->animationdata[i].m_poseParameters[j] );
}
else
{
buf->WriteOneBit(0);
}
}
for (int j = 0; j < MAX_ENCODED_CONTROLLERS; j++)
{
if (to->animationdata[i].m_encodedControllers[j] != from->animationdata[i].m_encodedControllers[j])
{
buf->WriteOneBit( 1 );
buf->WriteFloat( to->animationdata[i].m_encodedControllers[j] );
}
else
{
buf->WriteOneBit(0);
}
}
for (int j = 0; j < MAX_LAYER_RECORDS; j++)
{
if (to->animationdata[i].m_layerRecords[j].m_cycle != from->animationdata[i].m_layerRecords[j].m_cycle)
{
buf->WriteOneBit( 1 );
buf->WriteFloat( to->animationdata[i].m_layerRecords[j].m_cycle );
}
else
{
buf->WriteOneBit(0);
}
if (to->animationdata[i].m_layerRecords[j].m_order != from->animationdata[i].m_layerRecords[j].m_order)
{
buf->WriteOneBit( 1 );
buf->WriteVarInt32( to->animationdata[i].m_layerRecords[j].m_order );
}
else
{
buf->WriteOneBit(0);
}
if (to->animationdata[i].m_layerRecords[j].m_sequence != from->animationdata[i].m_layerRecords[j].m_sequence)
{
buf->WriteOneBit( 1 );
buf->WriteVarInt32( to->animationdata[i].m_layerRecords[j].m_sequence );
}
else
{
buf->WriteOneBit(0);
}
if (to->animationdata[i].m_layerRecords[j].m_weight != from->animationdata[i].m_layerRecords[j].m_weight)
{
buf->WriteOneBit( 1 );
buf->WriteFloat( to->animationdata[i].m_layerRecords[j].m_weight );
}
else
{
buf->WriteOneBit(0);
}
}
}
#if defined( HL2_CLIENT_DLL )
@ -323,21 +424,81 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from )
move->mousedy = buf->ReadShort();
}
for (int i = 0; i <= MAX_PLAYERS; i++)
{
// Simulation time changed unexpectedly ?
for (int i = 0; i < MAX_EDICTS; i++)
{
// Has simulation ?
move->has_simulation[i] = buf->ReadOneBit();
if (!move->has_simulation[i])
{
continue;
}
if (buf->ReadOneBit())
{
move->simulationtimes[i] = buf->ReadFloat();
}
}
}
// Has animation ?
move->has_animation[i] = buf->ReadOneBit();
if (!move->has_animation[i])
{
continue;
}
for (int i = 0; i <= MAX_PLAYERS; i++)
{
// Simulation time changed unexpectedly ?
if (buf->ReadOneBit())
{
move->animtimes[i] = buf->ReadFloat();
move->animationdata[i].m_flAnimTime = buf->ReadFloat();
}
if (buf->ReadOneBit())
{
move->animationdata[i].m_masterSequence = buf->ReadVarInt32();
}
if (buf->ReadOneBit())
{
move->animationdata[i].m_masterCycle = buf->ReadFloat();
}
for (int j = 0; j < MAX_POSE_PARAMETERS; j++)
{
if (buf->ReadOneBit())
{
move->animationdata[i].m_poseParameters[j] = buf->ReadFloat();
}
}
for (int j = 0; j < MAX_ENCODED_CONTROLLERS; j++)
{
if (buf->ReadOneBit())
{
move->animationdata[i].m_encodedControllers[j] = buf->ReadFloat();
}
}
for (int j = 0; j < MAX_LAYER_RECORDS; j++)
{
if (buf->ReadOneBit())
{
move->animationdata[i].m_layerRecords[j].m_cycle = buf->ReadFloat();
}
if (buf->ReadOneBit())
{
move->animationdata[i].m_layerRecords[j].m_order = buf->ReadVarInt32();
}
if (buf->ReadOneBit())
{
move->animationdata[i].m_layerRecords[j].m_sequence = buf->ReadVarInt32();
}
if (buf->ReadOneBit())
{
move->animationdata[i].m_layerRecords[j].m_weight = buf->ReadFloat();
}
}
}

View file

@ -1,10 +1,13 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifdef CLIENT_DLL
#include "cbase.h"
#endif
#include "shareddefs.h"
#if !defined( USERCMD_H )
#define USERCMD_H
@ -17,10 +20,49 @@
#include "imovehelper.h"
#include "checksum_crc.h"
#ifndef CLIENT_DLL
#include "baseanimating.h"
#include "BaseAnimatingOverlay.h"
#else
#include "c_baseanimating.h"
#include "c_baseanimatingoverlay.h"
#endif
#define MAX_LAYER_RECORDS (CBaseAnimatingOverlay::MAX_OVERLAYS)
#define MAX_POSE_PARAMETERS (CBaseAnimating::NUM_POSEPAREMETERS)
#define MAX_ENCODED_CONTROLLERS (MAXSTUDIOBONECTRLS)
class bf_read;
class bf_write;
struct LayerRecord
{
int m_sequence;
float m_cycle;
float m_weight;
int m_order;
LayerRecord()
{
m_sequence = 0;
m_cycle = 0;
m_weight = 0;
m_order = 0;
}
};
struct ClientSideAnimationData
{
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];
};
class CEntityGroundContact
{
public:
@ -57,11 +99,17 @@ public:
hasbeenpredicted = false;
for (int i = 0; i <= MAX_PLAYERS; i++)
simulationtimes[i] = 0.0f;
for (int i = 0; i < MAX_EDICTS; i++)
{
simulationtimes[i] = 0.0f;
has_simulation[i] = false;
has_animation[i] = false;
}
for (int i = 0; i <= MAX_PLAYERS; i++)
animtimes[i] = 0.0f;
for (int i = 0; i <= MAX_PLAYERS; i++)
{
animationdata[i] = {};
}
#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )
entitygroundcontact.RemoveAll();
@ -89,12 +137,17 @@ public:
hasbeenpredicted = src.hasbeenpredicted;
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];
for (int i = 0; i < MAX_EDICTS; i++)
{
simulationtimes[i] = src.simulationtimes[i];
has_simulation[i] = src.has_simulation[i];
has_animation[i] = src.has_animation[i];
}
for (int i = 0; i <= MAX_PLAYERS; i++)
{
animationdata[i] = src.animationdata[i];
}
#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )
entitygroundcontact = src.entitygroundcontact;
#endif
@ -124,9 +177,11 @@ public:
CRC32_ProcessBuffer( &crc, &weaponsubtype, sizeof( weaponsubtype ) );
CRC32_ProcessBuffer( &crc, &random_seed, sizeof( random_seed ) );
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_ProcessBuffer(&crc, &mousedy, sizeof(mousedy));
CRC32_ProcessBuffer(&crc, has_simulation, sizeof(has_simulation));
CRC32_ProcessBuffer(&crc, has_animation, sizeof(has_animation));
CRC32_ProcessBuffer( &crc, simulationtimes, sizeof( simulationtimes ) );
CRC32_ProcessBuffer(&crc, animationdata, sizeof(animationdata));
CRC32_Final( &crc );
return crc;
@ -174,10 +229,12 @@ public:
// Client only, tracks whether we've predicted this command at least once
bool hasbeenpredicted;
// 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];
// TODO_ENHANCED: Lag compensate also other entities when needed.
// Send simulation times for each players for lag compensation.
bool has_simulation[MAX_EDICTS];
bool has_animation[MAX_EDICTS];
float simulationtimes[MAX_EDICTS];
ClientSideAnimationData animationdata[MAX_PLAYERS+1];
// Back channel to communicate IK state
#if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )