Files
GTASource/game/physics/gtaInst.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

498 lines
17 KiB
C++

//
// physics/inst.h
//
#ifndef GTA_PHYSICS_INST_H
#define GTA_PHYSICS_INST_H
#include "debug\debug.h"
#include "fragment\instance.h"
#include "fragment\manager.h"
#include "phframework\fraginst.h"
#include "phframework\inst.h"
#include "phglass\glassinstance.h"
#include "physics\inst.h"
#include "scene\RegdRefTypes.h"
#include "fwtl/pool.h"
#if __WIN32
#pragma warning (push)
#endif
#define ART_MONOLITHIC_STATIC
#define NMUTILS_NODLL
#include "fragmentnm\instance.h"
#include "art\artfeedback.h"
#if __WIN32
#pragma warning (pop)
#endif
class CEntity;
class CPed;
class CPhysical;
namespace rage
{
class crClip;
}
////////////////////////////////////////////////////////////
// instance type info
// Please copy any changes to this inst type enum to the identical one in NmRsCharacter.h in the ART namespace
enum
{
PH_INST_GTA = fragInst::PH_INST_GDF_LAST+1, // marker for start of GTA phInst's
PH_INST_MAPCOL,
PH_INST_BUILDING,
PH_INST_VEH,
PH_INST_PED,
PH_INST_OBJECT,
PH_INST_PROJECTILE,
PH_INST_EXPLOSION,
PH_INST_PED_LEGS,
PH_INST_FRAG_GTA, // marker for start of GTA fragInst's
PH_INST_FRAG_VEH,
PH_INST_FRAG_PED,
PH_INST_FRAG_OBJECT,
PH_INST_FRAG_BUILDING,
PH_INST_FRAG_CACHE_OBJECT,
PH_INST_FRAG_LAST
};
enum
{
FRAG_IMPULSE_SOURCE_TYPE_FLAG_PED=1<<0,
FRAG_IMPULSE_SOURCE_TYPE_FLAG_VEHICLE=1<<1,
FRAG_IMPULSE_SOURCE_TYPE_FLAG_WEAPON=1<<2,
FRAG_IMPULSE_SOURCE_TYPE_FLAG_EXPLOSION=1<<3
};
// PURPOSE
// Physics instances for GTA entity types derived from RAGE physics phInst
// derivation primarily to impliment virtual functions to provide specific collision behaviors
// and to allow collision response
//
class phInstGta: public phfwInst
{
public:
enum eGtaInstFlags
{
// compile time assert in gtaInst.cpp to make sure the first value is equal to phfwInst::FLAG_USER_0
FLAG_USERDATA_PARENT_INST = BIT(10), // user data contains fragment parent (thing we broke off) entity pointer
FLAG_NO_COLLISION = BIT(11), // turn off collision for this inst
FLAG_IS_DOOR = BIT(12), // flag as a door (don't collide with other doors)
FLAG_UNUSED = BIT(13), // don't allow any fragment breaking
FLAG_BEING_DELETED = BIT(14), // identify when instances are being deleted, so we can skip certain asserts
FLAG_NM_NO_PLAYER_PED_ACTIVATE = BIT(15), // ragdoll activation control flags
// only 16 bits available for inst flags
};
phInstGta (s32 nInstType);
phInstGta (datResource & rsc);
virtual ~phInstGta();
FW_REGISTER_CLASS_POOL(phInstGta);
// Helper function called from ShouldFindImpacts() if the instance is a door, shared with fragInstGta.
static bool ShouldFindImpactsDoorHelper(const phInst* pOtherInst);
////////////////////////////////////////////////////////////
// overridden phInst functions
virtual bool ShouldFindImpacts(const phInst* pInst) const;
virtual void PreComputeImpacts (phContactIterator impacts);
virtual Vec3V_Out GetExternallyControlledVelocity () const;
virtual Vec3V_Out GetExternallyControlledAngVelocity () const;
virtual phInst *PrepareForActivation(phCollider **collider, phInst* otherInst, const phConstraintBase * constraint);
virtual void OnActivate(phInst* otherInst);
virtual bool PrepareForDeactivation(bool colliderManagedBySim, bool forceDeactivate);
virtual void OnDeactivate();
#if __DEV
PH_NON_SPU_VIRTUAL void InvalidStateDump() const;
#endif // __DEV
};
// check we're using the correct first available user data flag
CompileTimeAssert(phfwInst::eInstFlags(phInstGta::FLAG_USERDATA_PARENT_INST) == phfwInst::FLAG_USER_0);
// gta's version of a fragmentable instance (see above for virtual function explanations)
class fragInstGta: public phfwFragInst
{
public:
fragInstGta (s32 nInstType, const fragType* type, const Matrix34& matrix, u32 guid = 0);
fragInstGta ();
virtual ~fragInstGta();
FW_REGISTER_CLASS_POOL(fragInstGta);
static void LoadVehicleFragImpulseFunction();
#if __BANK
static void SaveVehicleFragImpulseFunction();
#endif
static void ReleaseVehicleFragImpulseFunction();
static void AddVehicleFragImpulseFunctionWidgets(bkBank& bank);
////////////////////////////////////////////////////////////
// overridden Inst functions
bool GetDontBreakFlag(s64 nFlag) const {return 0!=(m_nDontBreakCompFlags & nFlag);}
void SetDontBreakFlag(s64 nFlag) {m_nDontBreakCompFlags |= nFlag;}
void ClearDontBreakFlag(s64 nFlag) {m_nDontBreakCompFlags &= ~nFlag;}
void SetDontBreakFlagAllChildren(s64 nChild);
void ClearDontBreakFlagAllChildren(s64 nChild);
virtual bool ShouldFindImpacts(const phInst* pInst) const;
virtual void PreComputeImpacts (phContactIterator impacts);
virtual phInst *PrepareForActivation(phCollider **collider, phInst* otherInst, const phConstraintBase * constraint);
virtual bool PrepareForDeactivation(bool colliderManagedBySim, bool forceDeactivate);
virtual void OnActivate(phInst* otherInst);
virtual void OnDeactivate();
virtual void PrepareBrokenInst(fragInst *brokenInst) const;
virtual void PartsBrokeOff(const ComponentBits& brokenGroups, phInst* newInst);
virtual void PartsRestored(const ComponentBits& restoredGroups);
virtual void CollisionDamage(const Collision& msg, phContactIterator *impacts);
virtual bool IsBreakable(phInst* otherInst) const;
virtual bool FindBreakStrength(const Vector3* componentImpulses, const Vector4* componentPositions, float* breakStrength, phBreakData* breakData) const;
virtual bool ShouldBeInCacheToDraw() const;
virtual void LosingCacheEntry();
virtual fragCacheEntry* PutIntoCache();
virtual bool IsGroupBreakable(int nGroupIndex) const;
virtual Mat34V_ConstRef GetLastMatrix() const;
virtual Vec3V_Out GetExternallyControlledVelocity () const;
virtual Vec3V_Out GetExternallyControlledAngVelocity () const;
virtual ScalarV_Out GetInvTimeStepForComponentExternalVelocity () const;
virtual ScalarV_Out ModifyImpulseMag (int iMyComponent, int iOtherComponent, int iNumComponentImpulses, ScalarV_In fImpulseMagSquared, const phInst* otherInst) const;
virtual int GetClassType () const { return m_classType; }
void SetClassType (int type) { m_classType = type; }
#if __DEV
PH_NON_SPU_VIRTUAL void InvalidStateDump() const;
#endif // __DEV
private:
s64 m_nDontBreakCompFlags;
int m_classType;
//Called locally on a frag to detect if the destroy event should be triggered.
// - It check's to see if the object has a damage entity set (is only set for the parent object)
// and check's if that entity is the player.
bool TriggerEventEntityDestroyed(CPhysical* entity);
};
class ARTFeedbackInterfaceGta : public ART::ARTFeedbackInterface
{
public:
ARTFeedbackInterfaceGta();
virtual ~ARTFeedbackInterfaceGta();
void SetParentInst(phInst* pParent) {m_pParentInst = pParent;}
phInst* GetParentInst() {return m_pParentInst;}
virtual int onBehaviourFailure();
virtual int onBehaviourSuccess();
virtual int onBehaviourStart();
virtual int onBehaviourFinish();
virtual int onBehaviourEvent();
//virtual int onBehaviourRequest() { return -1; }
private:
phInst* m_pParentInst;
};
enum eNMAssetId
{
NM_ASSET_FRED = 0,
NM_ASSET_WILMA = 1,
NM_ASSET_FRED_LARGE = 2,
NM_ASSET_WILMA_LARGE = 3,
NM_ASSET_ALIEN = 4
};
//class CBulletForce
//{
//public:
// enum eBulletForceFlags
// {
// LOCAL_POS = BIT(0),
// SPREAD_UP1 = BIT(1),
// SPREAD_DOWN1 = BIT(2),
// SPREAD_DOWN2 = BIT(3)
// };
//
// CBulletForce();
//
// void InitPedImpact(CPed* pPed, float fMomentum, const Vector3& vecDir, const Vector3& vecWorldPos, int nComponent, u32 nWeaponHash);
// void ProcessPhysics(float fTimeStep);
// bool IsActive() const {return m_pTarget != NULL;}
// void Reset();
//private:
// RegdPhy m_pTarget;
// Vector3 m_vecForce;
// Vector3 m_vecPos;
// float m_fTime;
// float m_fMassMult;
//
// u16 m_nComponent;
// u16 m_nFlags;
//
//public:
// static float ms_fPedBulletApplyTime;
// static float ms_fPedMeleeApplyTime;
// static float ms_fPedBulletMassMult;
// static float ms_fPedMeleeMassMult;
//};
//
//#define NUM_BULLET_FORCES (128)
// natural motion should only be compiled on specific platforms
// but fragInstNMGta is primarily the ped specific fragInst type
class fragInstNMGta: public fragInstNM
{
public:
fragInstNMGta (s32 nInstType, const fragType* type, const Matrix34& matrix, u32 guid = 0);
fragInstNMGta (datResource & rsc);
virtual ~fragInstNMGta ();
enum eBodyPartGroup
{
kSpine = 0,
kNeck,
kLimb,
kInvalidPartGroup
};
enum eRampType
{
kStiffness = 0,
kProportionalGain,
kInvalidRampType
};
FW_REGISTER_CLASS_POOL(fragInstNMGta);
// gta instances use the user data pointer to store their parent entity (may be null)
void SetEntity(CEntity *pEnt) { SetUserData((void*)pEnt); }
////////////////////////////////////////////////////////////
// overridden Inst functions
virtual int GetClassType () const { return m_nType; }
virtual bool ShouldFindImpacts(const phInst* pInst) const;
virtual void PreComputeImpacts (phContactIterator impacts);
bool CheckCanActivate(const CPed* pPed, bool bAssert) const;
virtual void OnActivate(phInst* otherInst);
virtual void OnDeactivate();
virtual phInst *PrepareForActivation(phCollider **collider, phInst* otherInst, const phConstraintBase * constraint);
virtual bool PrepareForDeactivation(bool colliderManagedBySim, bool forceDeactivate);
#if __BANK
void CheckRagdollsUsedDebug();
#endif
virtual bool ShouldBeInCacheToDraw() const;
virtual void LosingCacheEntry();
virtual fragCacheEntry* PutIntoCache();
virtual Vec3V_Out GetExternallyControlledVelocity () const;
virtual bool FindBreakStrength(const Vector3* componentImpulses, const Vector4* componentPositions, float* breakStrength, phBreakData* breakData) const;
virtual bool IsBreakable(phInst* otherInst) const;
void SetActivePoseFromClip(const crClip* pClip, float fPhase=0.0f, bool bUseWorldCoords=false);
void SetIncomingTransformsFromAnim(const crClip* pClip, const float fPhase=0.0f);
void SetActivePoseFromSkel(const crSkeleton* pSkel);
virtual void PoseBoundsFromSkeleton(bool onlyAdjustForInternalMotion, bool updateLastBoundsMatrices, bool fullBvhRebuild = true, s8 numFragsToDisable = 0, const s8 *pFragsToDisable = NULL);
Vec3V_Out SendAnimationAverageVelToNM(float fTimeStep);
void SetARTFeedbackInterfaceGta();
void ScaleImpulseByComponentMass(Vector3& vecImpulse, int nComponent, float fMassInfluence);
float ScaleImpulseByComponentMass(int nComponent, float fMassInfluence);
//CBulletForce* GetBulletForce() {return &m_BulletForce;}
void ApplyBulletForce(CPed* pPed, float fMomentum, const Vector3& vecWorldNormal, const Vector3& vecWorldPos, int nComponent, u32 nWeaponHash);
void SetDontZeroMatricesOnActivation() {m_bDontZeroMatricesOnActivation = true;}
void ProcessRagdoll(float fTimeStep);
//static bool UseBulletForces() {return ms_bUseBulletForces;}
inline void SetDisableCollisionMask(u32 iNewMask) { m_iDisableCollisionMask = iNewMask; }
inline u32 GetDisableCollisionMask() { return m_iDisableCollisionMask;}
inline u32 GetActivationStartTime() { return m_fActivationStartTime; }
void SetPendingImpulseModifier(float set) { m_PendingImpulseModifier = set; }
void SetAllowDeadPedActivationThisFrame(bool set) { m_AllowDeadPedActivationThisFrame = set; }
// If the scale is 0.0, then we also set the average animation velocity to 0 in order to have the ragdoll
// start with zero velocity, as that seems to be the desired use case.
void SetIncomingAnimVelocityScaleReset(float set) { m_IncomingAnimVelocityScaleReset = set; }
void UpdateCounterImpulse(CPed* pPed, bool bHurriedCounterImpulse = false);
bool GetBulletLoosenessActive() const { return m_bBulletLoosenessActive; }
// Used to track impact damage from a particular source over a short amount of time, so that impact damage gets applied more consistently
void SetImpactDamageEntity(CEntity *entity);
void SetAccumulatedImpactDamageFromLastEntity(float damage) { m_fAccumulatedImpactDamage = damage; }
CEntity * GetLastImpactDamageEntity() const { return m_pLastImpactDamageEntity; }
float GetAccumulatedImpactDamageFromLastEntity() const { return m_fAccumulatedImpactDamage; }
u32 GetTimeSinceImpactDamage() const;
void SetNMAssetSize(int newSize);
virtual void SetCurrentPhysicsLOD(ePhysicsLOD set);
inline bool GetSuppressHighRagdollLODOnActivation() const { return m_SuppressHighRagdollLODOnActivation; }
inline void SetSuppressHighRagdollLODOnActivation(const bool b) { m_SuppressHighRagdollLODOnActivation = b; }
inline void RequestPhysicsLODChangeOnActivation(s8 requestedLOD) { m_RequestedPhysicsLODOnActivation = requestedLOD; }
// Functions associated with ejecting from a vehicle
void CheckForVehicleAssociation();
void SetAssociatedWithVehicle(CVehicle *pVehicle);
bool IsAssociatedWithVehicle(CVehicle *pVehicle) const;
void SetRagdollEjectedFromVehicle(CVehicle *vehicle);
inline bool IsEjectingFromVehicle() { return m_EjectedFromVehicleFrames > 0; }
inline CVehicle* GetEjectingVehicle() { return m_VehicleBeingEjectedFrom; }
void ProcessVehicleEjection(float fTimeStep);
void ResetVehicleEjectionMembers();
// Functions associated with wheel impacts
void SetContactedWheel(bool set) { m_ContactedWheel = set; }
void SetTimeTireImpulseWasApplied(u32 set) { m_uTimeTireImpulseWasApplied = set; }
u32 GetTimeTireImpulseWasApplied() const { return m_uTimeTireImpulseWasApplied; }
void SetTireImpulseAppliedRatio(float set) { m_fTireImpulseAppliedRatio = set; }
float GetTireImpulseAppliedRatio() const { return m_fTireImpulseAppliedRatio; }
void SetWheelTwitchStarted(bool set) { m_WheelTwitchStarted = set; }
bool GetWheelTwitchStarted() const { return m_WheelTwitchStarted; }
// Functions related to ramping joint values (stiffness, drive gains, etc.) in two stages
eBodyPartGroup GetBodyPartGroup(int component);
void ProcessTwoStageRamp(fragInstNMGta::eRampType type, fragInstNMGta::eBodyPartGroup partGroup, float startStifness, float midStifness,
float endStiffness, float durationStartToMid, float durationMidToEnd, float timeElapsed);
#if __DEV
PH_NON_SPU_VIRTUAL void InvalidStateDump() const;
#endif // __DEV
void GrabRootFrame();
private:
//This will save the root bone position each time the bounds are updated from the skeleton
// and then reset it upon ragdoll activation. This compensates for animation bugs where the skeleton root
// gets modified in between the last UpdateBoundsFromSkeleton call and before the ragdoll gets activated.
Vec3V m_RootBonePosAtBoundsUpdate;
ARTFeedbackInterfaceGta m_feedbackInterfaceGta;
s32 m_nType;
float m_ImpulseModifier;
float m_PendingImpulseModifier;
float m_IncomingAnimVelocityScaleReset;
// Time since the last bullet hit this rage ragdoll (not used for NM agents)
u32 m_LastRRApplyBulletTime;
int m_CounterImpulseCount;
// Mask to disable impacts with certain component
// More convenient to do here as opposed to using type and include flags
// because NM bounds are not owned by us
u32 m_iDisableCollisionMask;
u32 m_fActivationStartTime;
RegdVeh m_VehicleBeingEjectedFrom;
// Used to track impact damage from a particular source over a short amount of time, so that impact damage gets applied more consistently
RegdEnt m_pLastImpactDamageEntity;
u32 m_uTimeSinceImpactDamage;
float m_fAccumulatedImpactDamage;
u32 m_uTimeTireImpulseWasApplied;
float m_fTireImpulseAppliedRatio;
s8 m_RequestedPhysicsLODOnActivation;
s8 m_EjectedFromVehicleFrames;
bool m_bDontZeroMatricesOnActivation : 1;
bool m_AllowDeadPedActivationThisFrame : 1;
bool m_SuppressHighRagdollLODOnActivation : 1;
bool m_bBulletLoosenessActive : 1;
bool m_ContactedWheel : 1;
bool m_WheelTwitchStarted : 1;
//static bool ms_bUseBulletForces;
public:
static bool ms_bLogRagdollForces;
static dev_float ms_fVehiclePedActivationSpeed;
static dev_float ms_fVehiclePlayerActivationSpeed;
static dev_float ms_fPlayerPedActivationSpeed;
static dev_float ms_fPlayerGroupPedActivationSpeed;
static float m_ArmedPedBumpResistance;
#if __BANK
// Variables used to track the number of ragdolls that get used per level
static bool ms_bLogUsedRagdolls;
static int ms_MaxNMAgentsUsedCurrentLevel;
static int ms_MaxRageRagdollsUsedCurrentLevel;
static int ms_MaxNMAgentsUsedInComboCurrentLevel;
static int ms_MaxRageRagdollsUsedInComboCurrentLevel;
static int ms_MaxTotalRagdollsUsedCurrentLevel;
static int ms_NumFallbackAnimsUsedCurrentLevel;
static int ms_MaxNMAgentsUsedGlobally;
static int ms_MaxRageRagdollsUsedGlobally;
static int ms_MaxNMAgentsUsedInComboGlobally;
static int ms_MaxRageRagdollsUsedInComboGlobally;
static int ms_MaxTotalRagdollsUsedGlobally;
static int ms_NumFallbackAnimsUsedGlobally;
#endif
};
// find out if a phInst is actually a fragInst (i.e. can be safely cast to a fragInst)
__forceinline bool IsFragInst(const phInst* pInst)
{
if (pInst)
{
int classType = pInst->GetClassType();
return classType == fragInst::PH_FRAG_INST || (classType >= PH_INST_FRAG_GTA && classType <= PH_INST_FRAG_CACHE_OBJECT);
}
return false;
}
__forceinline bool IsFragInstClassType(int instClassType)
{
return instClassType == fragInst::PH_FRAG_INST || (instClassType >= PH_INST_FRAG_GTA && instClassType <= PH_INST_FRAG_CACHE_OBJECT);
}
#endif // end #ifndef GTA_PHYSICS_INST_H