diff options
Diffstat (limited to 'game/server/baseanimating.h')
| -rw-r--r-- | game/server/baseanimating.h | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/game/server/baseanimating.h b/game/server/baseanimating.h new file mode 100644 index 0000000..0550683 --- /dev/null +++ b/game/server/baseanimating.h @@ -0,0 +1,536 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASEANIMATING_H +#define BASEANIMATING_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseentity.h" +#include "entityoutput.h" +#include "studio.h" +#include "datacache/idatacache.h" +#include "tier0/threadtools.h" + + +struct animevent_t; +struct matrix3x4_t; +class CIKContext; +class KeyValues; +FORWARD_DECLARE_HANDLE( memhandle_t ); + +#define BCF_NO_ANIMATION_SKIP ( 1 << 0 ) // Do not allow PVS animation skipping (mostly for attachments being critical to an entity) +#define BCF_IS_IN_SPAWN ( 1 << 1 ) // Is currently inside of spawn, always evaluate animations + +class CBaseAnimating : public CBaseEntity +{ +public: + DECLARE_CLASS( CBaseAnimating, CBaseEntity ); + + CBaseAnimating(); + ~CBaseAnimating(); + + DECLARE_PREDICTABLE(); + + enum + { + NUM_POSEPAREMETERS = 24, + NUM_BONECTRLS = 4 + }; + + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + virtual void SetModel( const char *szModelName ); + virtual void Activate(); + virtual void Spawn(); + virtual void Precache(); + virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ); + + virtual int Restore( IRestore &restore ); + virtual void OnRestore(); + + CStudioHdr *GetModelPtr( void ); + void InvalidateMdlCache(); + + virtual CStudioHdr *OnNewModel(); + + virtual CBaseAnimating* GetBaseAnimating() { return this; } + + // Cycle access + void SetCycle( float flCycle ); + float GetCycle() const; + + float GetAnimTimeInterval( void ) const; + + // Call this in your constructor to tell it that you will not use animtime. Then the + // interpolation will be done correctly on the client. + // This defaults to off. + void UseClientSideAnimation(); + + // Tells whether or not we're using client-side animation. Used for controlling + // the transmission of animtime. + bool IsUsingClientSideAnimation() { return m_bClientSideAnimation; } + + + // Basic NPC Animation functions + virtual float GetIdealSpeed( ) const; + virtual float GetIdealAccel( ) const; + virtual void StudioFrameAdvance(); // advance animation frame to some time in the future + void StudioFrameAdvanceManual( float flInterval ); + bool IsValidSequence( int iSequence ); + + inline float GetPlaybackRate(); + inline void SetPlaybackRate( float rate ); + + inline int GetSequence() { return m_nSequence; } + virtual void SetSequence(int nSequence); + /* inline */ void ResetSequence(int nSequence); + // FIXME: push transitions support down into CBaseAnimating? + virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; } + inline bool IsSequenceFinished( void ) { return m_bSequenceFinished; } + inline bool SequenceLoops( void ) { return m_bSequenceLoops; } + bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence ); + inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); } + inline float SequenceDuration( void ) { return SequenceDuration( m_nSequence ); } + float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence ); + inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); } + float GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceCycleRate( int iSequence ) { return GetSequenceCycleRate(GetModelPtr(),iSequence); } + float GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence ); + virtual float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); } + void ResetActivityIndexes ( void ); + void ResetEventIndexes ( void ); + int SelectWeightedSequence ( Activity activity ); + int SelectWeightedSequence ( Activity activity, int curSequence ); + int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount ); + int SelectHeaviestSequence ( Activity activity ); + int LookupActivity( const char *label ); + int LookupSequence ( const char *label ); + KeyValues *GetSequenceKeyValues( int iSequence ); + + float GetSequenceMoveYaw( int iSequence ); + float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence ); + inline float GetSequenceMoveDist( int iSequence ) { return GetSequenceMoveDist(GetModelPtr(),iSequence);} + void GetSequenceLinearMotion( int iSequence, Vector *pVec ); + const char *GetSequenceName( int iSequence ); + const char *GetSequenceActivityName( int iSequence ); + Activity GetSequenceActivity( int iSequence ); + + void ResetSequenceInfo ( ); + // This will stop animation until you call ResetSequenceInfo() at some point in the future + inline void StopAnimation( void ) { m_flPlaybackRate = 0; } + + virtual void ClampRagdollForce( const Vector &vecForceIn, Vector *vecForceOut ) { *vecForceOut = vecForceIn; } // Base class does nothing. + virtual bool BecomeRagdollOnClient( const Vector &force ); + virtual bool IsRagdoll(); + virtual bool CanBecomeRagdoll( void ); //Check if this entity will ragdoll when dead. + + virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask ); + + virtual void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ); + virtual void SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ); + virtual void CalculateIKLocks( float currentTime ); + virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); + + bool HasAnimEvent( int nSequence, int nEvent ); + virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future + virtual void HandleAnimEvent( animevent_t *pEvent ); + + int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); + inline int LookupPoseParameter( const char *szName ) { return LookupPoseParameter(GetModelPtr(), szName); } + + float SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue ); + 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 ); } + + float GetPoseParameter( const char *szName ); + float GetPoseParameter( int iParameter ); + bool GetPoseParameterRange( int index, float &minValue, float &maxValue ); + bool HasPoseParameter( int iSequence, const char *szName ); + bool HasPoseParameter( int iSequence, int iParameter ); + float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f ); + +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 + // save off your pose parameters in member variables in your derivation of this function: + virtual void PopulatePoseParameters( void ); + + +public: + + int LookupBone( const char *szName ); + void GetBonePosition( const char *szName, Vector &origin, QAngle &angles ); + void GetBonePosition( int iBone, Vector &origin, QAngle &angles ); + int GetPhysicsBone( int boneIndex ); + + int GetNumBones ( void ); + + int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir ); + bool GotoSequence( int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &iNextSequence, float &flCycle, int &iDir ); + int GetEntryNode( int iSequence ); + int GetExitNode( int iSequence ); + + void GetEyeballs( Vector &origin, QAngle &angles ); // ?? remove ?? + + int LookupAttachment( const char *szName ); + + // These return the attachment in world space + bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles ); + bool GetAttachment( int iAttachment, Vector &absOrigin, QAngle &absAngles ); + int GetAttachmentBone( int iAttachment ); + virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld ); + + // These return the attachment in the space of the entity + bool GetAttachmentLocal( const char *szName, Vector &origin, QAngle &angles ); + bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles ); + bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal ); + + // Non-angle versions of the attachments in world space + bool GetAttachment( const char *szName, Vector &absOrigin, Vector *forward = NULL, Vector *right = NULL, Vector *up = NULL ); + bool GetAttachment( int iAttachment, Vector &absOrigin, Vector *forward = NULL, Vector *right = NULL, Vector *up = NULL ); + + void SetBodygroup( int iGroup, int iValue ); + int GetBodygroup( int iGroup ); + + const char *GetBodygroupName( int iGroup ); + int FindBodygroupByName( const char *name ); + int GetBodygroupCount( int iGroup ); + int GetNumBodyGroups( void ); + + void SetHitboxSet( int setnum ); + void SetHitboxSetByName( const char *setname ); + int GetHitboxSet( void ); + char const *GetHitboxSetName( void ); + int GetHitboxSetCount( void ); + int GetHitboxBone( int hitboxIndex ); + bool LookupHitbox( const char *szName, int& outSet, int& outBox ); + + // Computes a box that surrounds all hitboxes + bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + + // Clone a CBaseAnimating from another (copies model & sequence data) + void CopyAnimationDataFrom( CBaseAnimating *pSource ); + + int ExtractBbox( int sequence, Vector& mins, Vector& maxs ); + void SetSequenceBox( void ); + int RegisterPrivateActivity( const char *pszActivityName ); + + void ResetClientsideFrame( void ); + +// Controllers. + virtual void InitBoneControllers ( void ); + + // Return's the controller's angle/position in bone space. + float GetBoneController ( int iController ); + + // Maps the angle/position value you specify into the bone's start/end and sets the specified controller to the value. + float SetBoneController ( int iController, float flValue ); + + void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity); + + // these two need to move somewhere else + LocalFlexController_t GetNumFlexControllers( void ); + const char *GetFlexDescFacs( int iFlexDesc ); + const char *GetFlexControllerName( LocalFlexController_t iFlexController ); + const char *GetFlexControllerType( LocalFlexController_t iFlexController ); + + virtual Vector GetGroundSpeedVelocity( void ); + + bool GetIntervalMovement( float flIntervalUsed, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles ); + bool GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles ); + float GetInstantaneousVelocity( float flInterval = 0.0 ); + float GetEntryVelocity( int iSequence ); + float GetExitVelocity( int iSequence ); + float GetMovementFrame( float flDist ); + bool HasMovement( int iSequence ); + + void ReportMissingActivity( int iActivity ); + virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ); + class CBoneCache *GetBoneCache( void ); + void InvalidateBoneCache(); + void InvalidateBoneCacheIfOlderThan( float deltaTime ); + virtual int DrawDebugTextOverlays( void ); + + // See note in code re: bandwidth usage!!! + void DrawServerHitboxes( float duration = 0.0f, bool monocolor = false ); + void DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, bool noDepthTest = true, float duration = 0.0f, bool monocolor = false ); + + void SetModelScale( float scale, float change_duration = 0.0f ); + float GetModelScale() const { return m_flModelScale; } + + void UpdateModelScale(); + virtual void RefreshCollisionBounds( void ); + + // also calculate IK on server? (always done on client) + void EnableServerIK(); + void DisableServerIK(); + + // for ragdoll vs. car + int GetHitboxesFrontside( int *boxList, int boxMax, const Vector &normal, float dist ); + + void GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles ); + + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + + // Send a muzzle flash event to the client for this entity. + void DoMuzzleFlash(); + + // Fire + virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false ); + virtual void IgniteLifetime( float flFlameLifetime ); + virtual void IgniteNumHitboxFires( int iNumHitBoxFires ); + virtual void IgniteHitboxFireScale( float flHitboxFireScale ); + virtual void Extinguish() { RemoveFlag( FL_ONFIRE ); } + bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); } + void Scorch( int rate, int floor ); + void InputIgnite( inputdata_t &inputdata ); + void InputIgniteLifetime( inputdata_t &inputdata ); + void InputIgniteNumHitboxFires( inputdata_t &inputdata ); + void InputIgniteHitboxFireScale( inputdata_t &inputdata ); + void InputBecomeRagdoll( inputdata_t &inputdata ); + + // Dissolve, returns true if the ragdoll has been created + bool Dissolve( const char *pMaterialName, float flStartTime, bool bNPCOnly = true, int nDissolveType = 0, Vector vDissolverOrigin = vec3_origin, int iMagnitude = 0 ); + bool IsDissolving() { return ( (GetFlags() & FL_DISSOLVING) != 0 ); } + void TransferDissolveFrom( CBaseAnimating *pAnim ); + + // animation needs + float m_flGroundSpeed; // computed linear movement rate for current sequence + float m_flLastEventCheck; // cycle index of when events were last checked + + virtual void SetLightingOriginRelative( CBaseEntity *pLightingOriginRelative ); + void SetLightingOriginRelative( string_t strLightingOriginRelative ); + CBaseEntity *GetLightingOriginRelative(); + + virtual void SetLightingOrigin( CBaseEntity *pLightingOrigin ); + void SetLightingOrigin( string_t strLightingOrigin ); + CBaseEntity *GetLightingOrigin(); + + const float* GetPoseParameterArray() { return m_flPoseParameter.Base(); } + const float* GetEncodedControllerArray() { return m_flEncodedController.Base(); } + + 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 ); + + void SetFadeDistance( float minFadeDist, float maxFadeDist ); + + int GetBoneCacheFlags( void ) { return m_fBoneCacheFlags; } + inline void SetBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags |= fFlag; } + inline void ClearBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags &= ~fFlag; } + + bool PrefetchSequence( int iSequence ); + +private: + void LockStudioHdr(); + void UnlockStudioHdr(); + + void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval ); + void InputSetLightingOriginRelative( inputdata_t &inputdata ); + void InputSetLightingOrigin( inputdata_t &inputdata ); + void InputSetModelScale( inputdata_t &inputdata ); + + bool CanSkipAnimation( void ); + +public: + CNetworkVar( int, m_nForceBone ); + CNetworkVector( m_vecForce ); + + CNetworkVar( int, m_nSkin ); + CNetworkVar( int, m_nBody ); + CNetworkVar( int, m_nHitboxSet ); + + // For making things thin during barnacle swallowing, e.g. + CNetworkVar( float, m_flModelScale ); + + // was pev->framerate + CNetworkVar( float, m_flPlaybackRate ); + +public: + void InitStepHeightAdjust( void ); + void SetIKGroundContactInfo( float minHeight, float maxHeight ); + void UpdateStepOrigin( void ); + +protected: + float m_flIKGroundContactTime; + float m_flIKGroundMinHeight; + float m_flIKGroundMaxHeight; + + float m_flEstIkFloor; // debounced + float m_flEstIkOffset; + + CIKContext *m_pIk; + int m_iIKCounter; + +public: + Vector GetStepOrigin( void ) const; + QAngle GetStepAngles( void ) const; + +private: + bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry + bool m_bSequenceLoops; // true if the sequence loops + bool m_bResetSequenceInfoOnLoad; // true if a ResetSequenceInfo was queued up during dynamic load + float m_flDissolveStartTime; + + // was pev->frame + CNetworkVar( float, m_flCycle ); + CNetworkVar( int, m_nSequence ); + CNetworkArray( float, m_flPoseParameter, NUM_POSEPAREMETERS ); // must be private so manual mode works! + CNetworkArray( float, m_flEncodedController, NUM_BONECTRLS ); // bone controller setting (0..1) + + // Client-side animation (useful for looping animation objects) + CNetworkVar( bool, m_bClientSideAnimation ); + CNetworkVar( bool, m_bClientSideFrameReset ); + + CNetworkVar( int, m_nNewSequenceParity ); + CNetworkVar( int, m_nResetEventsParity ); + + // Incremented each time the entity is told to do a muzzle flash. + // The client picks up the change and draws the flash. + CNetworkVar( unsigned char, m_nMuzzleFlashParity ); + + CNetworkHandle( CBaseEntity, m_hLightingOrigin ); + CNetworkHandle( CBaseEntity, m_hLightingOriginRelative ); + + string_t m_iszLightingOriginRelative; // for reading from the file only + string_t m_iszLightingOrigin; // for reading from the file only + + memhandle_t m_boneCacheHandle; + unsigned short m_fBoneCacheFlags; // Used for bone cache state on model + +protected: + CNetworkVar( float, m_fadeMinDist ); // Point at which fading is absolute + CNetworkVar( float, m_fadeMaxDist ); // Point at which fading is inactive + CNetworkVar( float, m_flFadeScale ); // Scale applied to min / max + +public: + COutputEvent m_OnIgnite; + +private: + CStudioHdr *m_pStudioHdr; + CThreadFastMutex m_StudioHdrInitLock; + CThreadFastMutex m_BoneSetupMutex; + +// FIXME: necessary so that cyclers can hack m_bSequenceFinished +friend class CFlexCycler; +friend class CCycler; +friend class CBlendingCycler; +}; + +//----------------------------------------------------------------------------- +// Purpose: return a pointer to an updated studiomdl cache cache +//----------------------------------------------------------------------------- +inline CStudioHdr *CBaseAnimating::GetModelPtr( void ) +{ + if ( IsDynamicModelLoading() ) + return NULL; + +#ifdef _DEBUG + if ( !HushAsserts() ) + { + // GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance. + static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" ); + AssertOnce( pModelCache->IsFrameLocking() ); + } +#endif + + if ( !m_pStudioHdr && GetModel() ) + { + LockStudioHdr(); + } + return ( m_pStudioHdr && m_pStudioHdr->IsValid() ) ? m_pStudioHdr : NULL; +} + +inline void CBaseAnimating::InvalidateMdlCache() +{ + UnlockStudioHdr(); + if ( m_pStudioHdr != NULL ) + { + delete m_pStudioHdr; + m_pStudioHdr = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Serves the 90% case of calling SetSequence / ResetSequenceInfo. +//----------------------------------------------------------------------------- + +/* +inline void CBaseAnimating::ResetSequence(int nSequence) +{ + m_nSequence = nSequence; + ResetSequenceInfo(); +} +*/ + +inline float CBaseAnimating::GetPlaybackRate() +{ + return m_flPlaybackRate; +} + +inline void CBaseAnimating::SetPlaybackRate( float rate ) +{ + m_flPlaybackRate = rate; +} + +inline void CBaseAnimating::SetLightingOrigin( CBaseEntity *pLightingOrigin ) +{ + m_hLightingOrigin = pLightingOrigin; +} + +inline CBaseEntity *CBaseAnimating::GetLightingOrigin() +{ + return m_hLightingOrigin; +} + +inline void CBaseAnimating::SetLightingOriginRelative( CBaseEntity *pLightingOriginRelative ) +{ + m_hLightingOriginRelative = pLightingOriginRelative; +} + +inline CBaseEntity *CBaseAnimating::GetLightingOriginRelative() +{ + return m_hLightingOriginRelative; +} + +//----------------------------------------------------------------------------- +// Cycle access +//----------------------------------------------------------------------------- +inline float CBaseAnimating::GetCycle() const +{ + return m_flCycle; +} + +inline void CBaseAnimating::SetCycle( float flCycle ) +{ + m_flCycle = flCycle; +} + + +EXTERN_SEND_TABLE(DT_BaseAnimating); + + + +#define ANIMATION_SEQUENCE_BITS 12 // 4096 sequences +#define ANIMATION_SKIN_BITS 10 // 1024 body skin selections FIXME: this seems way high +#define ANIMATION_BODY_BITS 32 // body combinations +#define ANIMATION_HITBOXSET_BITS 2 // hit box sets +#if defined( TF_DLL ) +#define ANIMATION_POSEPARAMETER_BITS 8 // pose parameter resolution +#else +#define ANIMATION_POSEPARAMETER_BITS 11 // pose parameter resolution +#endif +#define ANIMATION_PLAYBACKRATE_BITS 8 // default playback rate, only used on leading edge detect sequence changes + +#endif // BASEANIMATING_H |