From 1da7d763feffaecdbb5c6f25bf52dbac0da2577a Mon Sep 17 00:00:00 2001 From: Kamay Xutax Date: Thu, 22 Aug 2024 23:55:21 +0200 Subject: [PATCH] Fixed server side setupbones --- game/client/c_baseanimating.cpp | 86 ++---------------------- game/client/c_baseanimating.h | 9 +-- game/client/c_baseanimatingoverlay.cpp | 63 ----------------- game/client/c_baseanimatingoverlay.h | 1 - game/client/c_baseentity.cpp | 13 ++-- game/client/cstrike/c_cs_hostage.cpp | 7 +- game/client/cstrike/c_cs_player.cpp | 93 +------------------------- game/server/baseanimating.cpp | 53 +++++++++------ game/server/baseanimating.h | 10 ++- 9 files changed, 63 insertions(+), 272 deletions(-) diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index 97634c31ae..e5f20ccf12 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -1972,8 +1972,10 @@ 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 ); // TODO_ENHANCED: Do that only for client side animations - // if (m_bClientSideAnimation) + if (m_bClientSideAnimation) + { MaintainSequenceTransitions( boneSetup, fCycle, currentTime, pos, q ); + } AccumulateLayers( boneSetup, pos, q, currentTime ); @@ -2743,82 +2745,6 @@ void C_BaseAnimating::ThreadedBoneSetup() g_PreviousBoneSetups.RemoveAll(); } -void C_BaseAnimating::BuildMatricesWithBoneMerge( - const CStudioHdr *pStudioHdr, - const QAngle& angles, - const Vector& origin, - const Vector pos[MAXSTUDIOBONES], - const Quaternion q[MAXSTUDIOBONES], - matrix3x4_t bonetoworld[MAXSTUDIOBONES], - C_BaseAnimating *pParent, - CBoneCache *pParentCache - ) -{ - CStudioHdr *fhdr = pParent->GetModelPtr(); - mstudiobone_t *pbones = pStudioHdr->pBone( 0 ); - - matrix3x4_t rotationmatrix; // model to world transformation - AngleMatrix( angles, origin, rotationmatrix); - - for ( int i=0; i < pStudioHdr->numbones(); i++ ) - { - // Now find the bone in the parent entity. - bool merged = false; - int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() ); - if ( parentBoneIndex >= 0 ) - { - matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex ); - if ( pMat ) - { - MatrixCopy( *pMat, bonetoworld[ i ] ); - merged = true; - } - } - - if ( !merged ) - { - // If we get down here, then the bone wasn't merged. - matrix3x4_t bonematrix; - QuaternionMatrix( q[i], pos[i], bonematrix ); - - if (pbones[i].parent == -1) - { - ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]); - } - else - { - ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]); - } - } - } -} - -void C_BaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ) -{ - if(!pStudioHdr) - { - Assert(!"C_BaseAnimating::GetSkeleton() without a model"); - return; - } - - IBoneSetup boneSetup( pStudioHdr, boneMask, m_flPoseParameter ); - boneSetup.InitPose( pos, q ); - - boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, currentTime, m_pIk ); - - if ( m_pIk ) - { - CIKContext auto_ik; - auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), currentTime, 0, boneMask ); - boneSetup.CalcAutoplaySequences( pos, q, currentTime, &auto_ik ); - } - else - { - boneSetup.CalcAutoplaySequences( pos, q, currentTime, NULL ); - } - boneSetup.CalcBoneAdj( pos, q, m_flEncodedController ); -} - bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); @@ -2972,8 +2898,10 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated if ( !IsModelScaled() ) { - // only allocate an ik block if the npc can use it - if ( !m_pIk && hdr->numikchains() > 0 && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) ) + // only allocate an ik block if the npc can use it + // The flag is now completely ignored to match server bones! + // If it doesn't work well, blame models. + if ( !m_pIk && hdr->numikchains() > 0 /* && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) */ ) { m_pIk = new CIKContext; } diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h index 0d9fb02190..7126e8d897 100644 --- a/game/client/c_baseanimating.h +++ b/game/client/c_baseanimating.h @@ -99,8 +99,8 @@ public: enum { - NUM_POSEPAREMETERS = 24, - NUM_BONECTRLS = 4 + NUM_POSEPAREMETERS = MAXSTUDIOPOSEPARAM, + NUM_BONECTRLS = MAXSTUDIOBONECTRLS }; C_BaseAnimating(); @@ -144,11 +144,6 @@ public: virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); // model specific - void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles, - const Vector& origin, const Vector pos[MAXSTUDIOBONES], - const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], - CBaseAnimating *pParent, CBoneCache *pParentCache ); - virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ); virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); virtual void UpdateIKLocks( float currentTime ); virtual void CalculateIKLocks( float currentTime ); diff --git a/game/client/c_baseanimatingoverlay.cpp b/game/client/c_baseanimatingoverlay.cpp index 4f9dc37bd4..cbd5ff9804 100644 --- a/game/client/c_baseanimatingoverlay.cpp +++ b/game/client/c_baseanimatingoverlay.cpp @@ -369,67 +369,4 @@ CStudioHdr *C_BaseAnimatingOverlay::OnNewModel() } return hdr; -} - -void C_BaseAnimatingOverlay::GetSkeleton( CStudioHdr* pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ) -{ - if(!pStudioHdr) - { - Assert(!"C_BaseAnimating::GetSkeleton() without a model"); - return; - } - - if (!pStudioHdr->SequencesAvailable()) - { - return; - } - - float poseparameters[MAXSTUDIOPOSEPARAM]; - GetPoseParameters(pStudioHdr, poseparameters); - - IBoneSetup boneSetup( pStudioHdr, boneMask, poseparameters ); - boneSetup.InitPose( pos, q ); - - boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, currentTime, m_pIk ); - - // 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++) - { - CAnimationLayer &pLayer = m_AnimOverlay[i]; - if( (pLayer.m_flWeight > 0) && pLayer.IsActive() && pLayer.m_nOrder >= 0 && pLayer.m_nOrder < m_AnimOverlay.Count()) - { - layer[pLayer.m_nOrder] = i; - } - } - for (i = 0; i < m_AnimOverlay.Count(); i++) - { - if (layer[i] >= 0 && layer[i] < m_AnimOverlay.Count()) - { - 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 ( m_pIk ) - { - CIKContext auto_ik; - auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), currentTime, 0, boneMask ); - boneSetup.CalcAutoplaySequences( pos, q, currentTime, &auto_ik ); - } - else - { - boneSetup.CalcAutoplaySequences(pos, q, currentTime, NULL); - } - - float controllers[MAXSTUDIOBONECTRLS]; - GetBoneControllers(controllers); - - boneSetup.CalcBoneAdj( pos, q, controllers ); } \ No newline at end of file diff --git a/game/client/c_baseanimatingoverlay.h b/game/client/c_baseanimatingoverlay.h index f82def41b1..8c971ed370 100644 --- a/game/client/c_baseanimatingoverlay.h +++ b/game/client/c_baseanimatingoverlay.h @@ -38,7 +38,6 @@ public: // model specific virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); - virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ); enum { diff --git a/game/client/c_baseentity.cpp b/game/client/c_baseentity.cpp index bb5a96c68a..2ba5bd8d16 100644 --- a/game/client/c_baseentity.cpp +++ b/game/client/c_baseentity.cpp @@ -4293,12 +4293,13 @@ void C_BaseEntity::CalcAbsolutePosition( ) NormalizeAngles( m_angAbsRotation ); return; } - - if ( IsEffectActive(EF_BONEMERGE) ) - { - MoveToAimEnt(); - return; - } + + // TODO_ENHANCED: this should be safe to remove. + // if ( IsEffectActive(EF_BONEMERGE) ) + // { + // MoveToAimEnt(); + // return; + // } // Construct the entity-to-world matrix // Start with making an entity-to-parent matrix diff --git a/game/client/cstrike/c_cs_hostage.cpp b/game/client/cstrike/c_cs_hostage.cpp index afbfe773e9..6dfbd0d100 100644 --- a/game/client/cstrike/c_cs_hostage.cpp +++ b/game/client/cstrike/c_cs_hostage.cpp @@ -202,9 +202,10 @@ C_CHostage::C_CHostage() m_flDeadOrRescuedTime = 0.0; m_flLastBodyYaw = 0; m_createdLowViolenceRagdoll = false; - - // TODO: Get IK working on the steep slopes CS has, then enable it on characters. - m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK; + + // TODO: Get IK working on the steep slopes CS has, then enable it on characters. + // Breaks server side setup bones ! + // m_EntClientFlags |= ENTCLIENTFLAG_DONTUSEIK; // set the model so the PlayerAnimState uses the Hostage activities/sequences SetModelName( "models/Characters/Hostage_01.mdl" ); diff --git a/game/client/cstrike/c_cs_player.cpp b/game/client/cstrike/c_cs_player.cpp index 6c618cd771..c60eddab22 100644 --- a/game/client/cstrike/c_cs_player.cpp +++ b/game/client/cstrike/c_cs_player.cpp @@ -2601,100 +2601,9 @@ float C_CSPlayer::GetDeathCamInterpolationTime() } -ConVar cl_server_setup_bones("cl_server_setup_bones", "1"); - bool C_CSPlayer::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { - if (cl_server_setup_bones.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 ); - } + return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ); } //============================================================================= diff --git a/game/server/baseanimating.cpp b/game/server/baseanimating.cpp index 5b3d3a11c4..5ad1d2f057 100644 --- a/game/server/baseanimating.cpp +++ b/game/server/baseanimating.cpp @@ -1800,31 +1800,46 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) // adjust hit boxes based on IK driven offset Vector adjOrigin = GetAbsOrigin() + Vector( 0, 0, m_flEstIkOffset ); - if ( CanSkipAnimation() ) + // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated + if ( !IsModelScaled() ) { - IBoneSetup boneSetup( pStudioHdr, boneMask, GetPoseParameterArray() ); - boneSetup.InitPose( pos, q ); - // Msg( "%.03f : %s:%s not in pvs\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); + // only allocate an ik block if the npc can use it + if ( !m_pIk && pStudioHdr->numikchains() > 0 ) + { + m_pIk = new CIKContext; + } } - else + else { + // Reset the IK if ( m_pIk ) { - // FIXME: pass this into Studio_BuildMatrices to skip transforms - CBoneBitList boneComputed; - m_iIKCounter++; - m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask ); - GetSkeleton( pStudioHdr, pos, q, boneMask ); + delete m_pIk; + m_pIk = NULL; + } + } - m_pIk->UpdateTargets( pos, q, pBoneToWorld, boneComputed ); - CalculateIKLocks( gpGlobals->curtime ); - m_pIk->SolveDependencies( pos, q, pBoneToWorld, boneComputed ); - } - else - { - // Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); - GetSkeleton( pStudioHdr, pos, q, boneMask ); - } + if ( m_pIk ) + { + m_pIk->Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); + } + + if ( m_pIk ) + { + // FIXME: pass this into Studio_BuildMatrices to skip transforms + CBoneBitList boneComputed; + m_iIKCounter++; + m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask ); + GetSkeleton( pStudioHdr, pos, q, boneMask ); + + m_pIk->UpdateTargets( pos, q, pBoneToWorld, boneComputed ); + CalculateIKLocks( gpGlobals->curtime ); + m_pIk->SolveDependencies( pos, q, pBoneToWorld, boneComputed ); + } + else + { + // Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); + GetSkeleton( pStudioHdr, pos, q, boneMask ); } CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() ); diff --git a/game/server/baseanimating.h b/game/server/baseanimating.h index d96d01e697..f64a5a8dbc 100644 --- a/game/server/baseanimating.h +++ b/game/server/baseanimating.h @@ -41,8 +41,8 @@ public: enum { - NUM_POSEPAREMETERS = 24, - NUM_BONECTRLS = 4 + NUM_POSEPAREMETERS = MAXSTUDIOPOSEPARAM, + NUM_BONECTRLS = MAXSTUDIOBONECTRLS }; DECLARE_DATADESC(); @@ -161,6 +161,8 @@ public: bool HasPoseParameter( int iSequence, int iParameter ); float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f ); + inline bool IsModelScaled() const; + protected: // The modus operandi for pose parameters is that you should not use the const char * version of the functions // in general code -- it causes many many string comparisons, which is slower than you think. Better is to @@ -518,6 +520,10 @@ inline void CBaseAnimating::SetCycle( float flCycle ) m_flCycle = flCycle; } +inline bool CBaseAnimating::IsModelScaled() const +{ + return ( m_flModelScale > 1.0f+FLT_EPSILON || m_flModelScale < 1.0f-FLT_EPSILON ); +} EXTERN_SEND_TABLE(DT_BaseAnimating);