diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index 6c145f39dd..4575ff2787 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -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(); - } - } } //----------------------------------------------------------------------------- diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h index 4a4d19e177..5c04414c1d 100644 --- a/game/client/c_baseanimating.h +++ b/game/client/c_baseanimating.h @@ -499,6 +499,7 @@ public: int m_nHitboxSet; CSequenceTransitioner m_SequenceTransitioner; + int m_iIKCounter; protected: CIKContext *m_pIk; diff --git a/game/client/c_baseanimatingoverlay.cpp b/game/client/c_baseanimatingoverlay.cpp index 9edf0bda22..525b638443 100644 --- a/game/client/c_baseanimatingoverlay.cpp +++ b/game/client/c_baseanimatingoverlay.cpp @@ -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++) { diff --git a/game/client/c_baseanimatingoverlay.h b/game/client/c_baseanimatingoverlay.h index 44263d36ae..f82def41b1 100644 --- a/game/client/c_baseanimatingoverlay.h +++ b/game/client/c_baseanimatingoverlay.h @@ -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: diff --git a/game/client/cstrike/c_cs_player.cpp b/game/client/cstrike/c_cs_player.cpp index fcc3df063a..74c87ad9b7 100644 --- a/game/client/cstrike/c_cs_player.cpp +++ b/game/client/cstrike/c_cs_player.cpp @@ -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 diff --git a/game/client/cstrike/c_cs_player.h b/game/client/cstrike/c_cs_player.h index acfbba014e..cbf975b203 100644 --- a/game/client/cstrike/c_cs_player.h +++ b/game/client/cstrike/c_cs_player.h @@ -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 diff --git a/game/client/in_main.cpp b/game/client/in_main.cpp index 956254158d..4bae678489 100644 --- a/game/client/in_main.cpp +++ b/game/client/in_main.cpp @@ -9,6 +9,12 @@ #include "cbase.h" +#include +#include +#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(); diff --git a/game/server/baseanimating.h b/game/server/baseanimating.h index 75300e8ea1..e46e850552 100644 --- a/game/server/baseanimating.h +++ b/game/server/baseanimating.h @@ -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], diff --git a/game/server/cstrike/cs_player.cpp b/game/server/cstrike/cs_player.cpp index 53fbf13cdd..f493abeba8 100644 --- a/game/server/cstrike/cs_player.cpp +++ b/game/server/cstrike/cs_player.cpp @@ -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; diff --git a/game/server/cstrike/hostage/cs_simple_hostage.cpp b/game/server/cstrike/hostage/cs_simple_hostage.cpp index 4f0ea2c817..d6374100fa 100644 --- a/game/server/cstrike/hostage/cs_simple_hostage.cpp +++ b/game/server/cstrike/hostage/cs_simple_hostage.cpp @@ -105,7 +105,7 @@ CHostage::CHostage() m_PlayerAnimState = CreateHostageAnimState( this, this, LEGANIM_8WAY, false ); // ENHANCED_TODO: remove this - UseClientSideAnimation(); + // UseClientSideAnimation(); SetBloodColor( BLOOD_COLOR_RED ); } diff --git a/game/server/player_lagcompensation.cpp b/game/server/player_lagcompensation.cpp index b7aacf6225..6cc2cac1cf 100644 --- a/game/server/player_lagcompensation.cpp +++ b/game/server/player_lagcompensation.cpp @@ -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"); diff --git a/game/shared/base_playeranimstate.cpp b/game/shared/base_playeranimstate.cpp index d90655ac53..5f04bf84ca 100644 --- a/game/shared/base_playeranimstate.cpp +++ b/game/shared/base_playeranimstate.cpp @@ -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 diff --git a/game/shared/cstrike/cs_player_shared.cpp b/game/shared/cstrike/cs_player_shared.cpp index d020758554..2c4717a8e7 100644 --- a/game/shared/cstrike/cs_player_shared.cpp +++ b/game/shared/cstrike/cs_player_shared.cpp @@ -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 diff --git a/game/shared/usercmd.cpp b/game/shared/usercmd.cpp index 56447f8ab7..ef2abc66a1 100644 --- a/game/shared/usercmd.cpp +++ b/game/shared/usercmd.cpp @@ -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(); + } } } diff --git a/game/shared/usercmd.h b/game/shared/usercmd.h index c603e06d47..070edd273c 100644 --- a/game/shared/usercmd.h +++ b/game/shared/usercmd.h @@ -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 )