@@ -1092,6 +1092,7 @@ CStudioHdr *C_BaseAnimating::OnNewModel()
10921092 }
10931093 }
10941094 m_BoneAccessor.Init ( this , m_CachedBoneData.Base () ); // Always call this in case the studiohdr_t has changed.
1095+ m_iAccumulatedBoneMask = 0 ; // Reset the accumulated bone mask.
10951096
10961097 // Free any IK data
10971098 if (m_pIk)
@@ -2029,18 +2030,24 @@ bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentTo
20292030 return false ;
20302031
20312032 CAttachmentData *pAtt = &m_Attachments[number-1 ];
2032- if ( gpGlobals->frametime > 0 && pAtt->m_nLastFramecount > 0 && pAtt->m_nLastFramecount == gpGlobals->framecount - 1 )
2033+ if ( gpGlobals->frametime > 0 && pAtt->m_nLastFramecount > 0 && pAtt->m_nLastFramecount < gpGlobals->framecount )
20332034 {
20342035 Vector vecPreviousOrigin, vecOrigin;
20352036 MatrixPosition ( pAtt->m_AttachmentToWorld , vecPreviousOrigin );
20362037 MatrixPosition ( attachmentToWorld, vecOrigin );
2037- pAtt->m_vOriginVelocity = (vecOrigin - vecPreviousOrigin) / gpGlobals->frametime ;
2038+ // compensate for the fact that the previous origin could have been multiple frames behind
2039+ pAtt->m_vOriginVelocity = (vecOrigin - vecPreviousOrigin) / (gpGlobals->frametime * (gpGlobals->framecount - pAtt->m_nLastFramecount ));
2040+ // only update the frame count if the position changed, so we don't have to recompute attachments
2041+ if ( !pAtt->m_vOriginVelocity .IsZero (0 .00001f ) )
2042+ {
2043+ pAtt->m_nLastFramecount = gpGlobals->framecount ;
2044+ }
20382045 }
20392046 else
20402047 {
20412048 pAtt->m_vOriginVelocity .Init ();
2049+ pAtt->m_nLastFramecount = gpGlobals->framecount ;
20422050 }
2043- pAtt->m_nLastFramecount = gpGlobals->framecount ;
20442051 pAtt->m_bAnglesComputed = false ;
20452052 pAtt->m_AttachmentToWorld = attachmentToWorld;
20462053
@@ -2051,6 +2058,20 @@ bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentTo
20512058 return true ;
20522059}
20532060
2061+ bool C_BaseAnimating::GetAttachmentDeferred ( int number, matrix3x4_t & matrix )
2062+ {
2063+ if (number < 1 || number > m_Attachments.Count ())
2064+ return false ;
2065+
2066+ // allow visual effects (eg. particles) to be a frame behind bone setup so that there are not messy dependencies.
2067+ CAttachmentData* pAtt = &m_Attachments[number - 1 ];
2068+ const bool bShouldUpdate = pAtt->m_nLastFramecount < gpGlobals->framecount - 1 ;
2069+ if ( bShouldUpdate && !CalcAttachments () )
2070+ return false ;
2071+
2072+ matrix = pAtt->m_AttachmentToWorld ;
2073+ return true ;
2074+ }
20542075
20552076bool C_BaseAnimating::SetupBones_AttachmentHelper ( CStudioHdr *hdr )
20562077{
@@ -2896,7 +2917,9 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i
28962917 m_flLastBoneSetupTime = currentTime;
28972918 }
28982919 m_iPrevBoneMask = m_iAccumulatedBoneMask;
2899- m_iAccumulatedBoneMask = 0 ;
2920+ // Keep record of the fact that we've used attachments. Because of deferred attachments, we can't keep track from the previous frame.
2921+ // m_iAccumulatedBoneMask = 0;
2922+ m_iAccumulatedBoneMask = m_iAccumulatedBoneMask & BONE_USED_BY_ATTACHMENT;
29002923
29012924#ifdef STUDIO_ENABLE_PERF_COUNTERS
29022925 CStudioHdr *hdr = GetModelPtr ();
0 commit comments