//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifndef GAMETRACE_H #define GAMETRACE_H #ifdef _WIN32 #pragma once #endif #include "cmodel.h" #include "Color.h" #include "entity2/entityinstance.h" #include "mathlib/transform.h" #include "tier1/generichash.h" #include "tier1/utlvector.h" #include "tier1/utlstring.h" #include "ispatialpartition.h" class IPhysicsBody; class IPhysicsShape; typedef IPhysicsBody* HPhysicsBody; typedef IPhysicsShape* HPhysicsShape; enum CollisionFunctionMask_t { FCOLLISION_FUNC_ENABLE_SOLID_CONTACT = (1<<0), FCOLLISION_FUNC_ENABLE_TRACE_QUERY = (1<<1), FCOLLISION_FUNC_ENABLE_TOUCH_EVENT = (1<<2), FCOLLISION_FUNC_ENABLE_SELF_COLLISIONS = (1<<3), FCOLLISION_FUNC_IGNORE_FOR_HITBOX_TEST = (1<<4), FCOLLISION_FUNC_ENABLE_TOUCH_PERSISTS = (1<<5), }; // these are on by default #define FCOLLISION_FUNC_DEFAULT (FCOLLISION_FUNC_ENABLE_SOLID_CONTACT | FCOLLISION_FUNC_ENABLE_TRACE_QUERY | FCOLLISION_FUNC_ENABLE_TOUCH_EVENT) enum RnQueryObjectSet { // AMNOTE: // RNQUERY_OBJECTS_STATIC (0x1) is used in // CLightQueryGameSystem::OnPostSimulate // ray test by loading rays.bin // CBaePlayerPawn::IsPlayerAimingAtTarget // CBaseRagdoll related // CSoundOpvarSetAutoRoomEntity::Spawn // CNavSpaceBuildTreeJob // RNQUERY_OBJECTS_STATIC | RNQUERY_OBJECTS_KEYFRAMED (0x3) is used in // when decoy hit entity isn't player pawn // RNQUERY_OBJECTS_KEYFRAMED | RNQUERY_OBJECTS_DYNAMIC (0x6) is used in // checking if a grenade projectile has hit any player // filtering bullet trace result // checking if hit entity is a *_door_rotating // checking if player is aiming at a CPointCommentaryNode // RNQUERY_OBJECTS_LOCATABLE (0x8) is used in // checking if a CSmokeGrenadeProjectile is exploded from inferno // CGamePhysicsQueryInterface::EntitiesAlong* to add g_LocatableEntities to results // RNQUERY_OBJECTS_KEYFRAMED | RNQUERY_OBJECTS_DYNAMIC | RNQUERY_OBJECTS_LOCATABLE (0xE) is used in // CBotBreakableEnumerator // CInferno::Think damage // CBombTarget // UTIL_EntitiesAlongRay // CEnvShake::ApplyShake with type rumble // CBaseFilter Think // RNQUERY_OBJECTS_STATIC | RNQUERY_OBJECTS_KEYFRAMED | RNQUERY_OBJECTS_DYNAMIC | RNQUERY_OBJECTS_LOCATABLE (0xF) is used in pretty much every trace filter RNQUERY_OBJECTS_STATIC = (1 << 0), // static body RNQUERY_OBJECTS_KEYFRAMED = (1 << 1), // keyframed body RNQUERY_OBJECTS_DYNAMIC = (1 << 2), // dynamic body RNQUERY_OBJECTS_LOCATABLE = (1 << 3), RNQUERY_OBJECTS_ALL_GAME_ENTITIES = RNQUERY_OBJECTS_KEYFRAMED | RNQUERY_OBJECTS_DYNAMIC | RNQUERY_OBJECTS_LOCATABLE, RNQUERY_OBJECTS_ALL = RNQUERY_OBJECTS_STATIC | RNQUERY_OBJECTS_ALL_GAME_ENTITIES, }; enum HitGroup_t { HITGROUP_INVALID = -1, HITGROUP_GENERIC = 0, HITGROUP_HEAD, HITGROUP_CHEST, HITGROUP_STOMACH, HITGROUP_LEFTARM, HITGROUP_RIGHTARM, HITGROUP_LEFTLEG, HITGROUP_RIGHTLEG, HITGROUP_NECK, HITGROUP_UNUSED, HITGROUP_GEAR, HITGROUP_SPECIAL, HITGROUP_COUNT, }; enum HitboxShapeType_t { HITBOX_SHAPE_HULL = 0, HITBOX_SHAPE_SPHERE, HITBOX_SHAPE_CAPSULE, }; class CPhysSurfacePropertiesPhysics { public: CPhysSurfacePropertiesPhysics() { m_friction = 0.0f; m_elasticity = 0.0f; m_density = 0.0f; m_thickness = 0.1f; m_softContactFrequency = 0.0f; m_softContactDampingRatio = 0.0f; } public: float m_friction; float m_elasticity; float m_density; float m_thickness; float m_softContactFrequency; float m_softContactDampingRatio; }; class CPhysSurfacePropertiesVehicle { public: CPhysSurfacePropertiesVehicle() { m_wheelDrag = 0.0f; m_wheelFrictionScale = 0.0f; } public: float m_wheelDrag; float m_wheelFrictionScale; }; class CPhysSurfacePropertiesSoundNames { public: CPhysSurfacePropertiesSoundNames() { m_meleeImpact = ""; m_pushOff = ""; m_skidStop = ""; } public: CUtlString m_impactSoft; CUtlString m_impactHard; CUtlString m_scrapeSmooth; CUtlString m_scrapeRough; CUtlString m_bulletImpact; CUtlString m_rolling; CUtlString m_break; CUtlString m_strain; CUtlString m_meleeImpact; CUtlString m_pushOff; CUtlString m_skidStop; CUtlString m_resonant; }; class CPhysSurfacePropertiesAudio { public: CPhysSurfacePropertiesAudio() { m_reflectivity = 0.0f; m_hardnessFactor = 0.0f; m_roughnessFactor = 0.0f; m_roughThreshold = 0.0f; m_hardThreshold = 0.0f; m_hardVelocityThreshold = 0.0f; m_flStaticImpactVolume = 0.0f; m_flOcclusionFactor = 0.0f; } public: float m_reflectivity; float m_hardnessFactor; float m_roughnessFactor; float m_roughThreshold; float m_hardThreshold; float m_hardVelocityThreshold; float m_flStaticImpactVolume; float m_flOcclusionFactor; }; class CPhysSurfaceProperties { public: CPhysSurfaceProperties() { m_bHidden = false; } public: CUtlString m_name; uint32 m_nameHash; uint32 m_baseNameHash; int32 m_nListIndex; int32 m_nBaseListIndex; bool m_bHidden; CUtlString m_description; CPhysSurfacePropertiesPhysics m_physics; CPhysSurfacePropertiesVehicle m_vehicleParams; CPhysSurfacePropertiesSoundNames m_audioSounds; CPhysSurfacePropertiesAudio m_audioParams; }; class CHitBox { public: CHitBox() { m_vMinBounds.Init(); m_vMaxBounds.Init(); m_nGroupId = HITGROUP_GENERIC; m_nShapeType = HITBOX_SHAPE_HULL; m_bTranslationOnly = false; m_CRC = 0; m_cRenderColor.SetColor( 255, 255, 255, 255 ); m_nHitBoxIndex = 0; m_bForcedTransform = false; m_forcedTransform.SetToIdentity(); } public: CUtlString m_name; CUtlString m_sSurfaceProperty; CUtlString m_sBoneName; Vector m_vMinBounds; Vector m_vMaxBounds; float m_flShapeRadius; CUtlStringToken m_nBoneNameHash; int32 m_nGroupId; uint8 m_nShapeType; bool m_bTranslationOnly; uint32 m_CRC; Color m_cRenderColor; uint16 m_nHitBoxIndex; bool m_bForcedTransform; CTransform m_forcedTransform; }; class CDefaultHitbox : public CHitBox { public: CDefaultHitbox() { V_strncpy( m_tempName, "invalid_hitbox", sizeof( m_tempName ) ); V_strncpy( m_tempBoneName, "invalid_bone", sizeof( m_tempBoneName ) ); V_strncpy( m_tempSurfaceProp, "default", sizeof( m_tempSurfaceProp ) ); m_name = m_tempName; m_sSurfaceProperty = m_tempSurfaceProp; m_sBoneName = m_tempBoneName; m_nBoneNameHash = MakeStringToken( m_tempBoneName ); m_cRenderColor.SetColor( 0, 0, 0, 0 ); } public: char m_tempName[16]; char m_tempBoneName[16]; char m_tempSurfaceProp[16]; }; struct RnQueryShapeAttr_t { public: RnQueryShapeAttr_t() { m_nInteractsWith = 0; m_nInteractsExclude = 0; m_nInteractsAs = 0; m_nEntityIdsToIgnore[0] = -1; m_nEntityIdsToIgnore[1] = -1; m_nOwnerIdsToIgnore[0] = -1; m_nOwnerIdsToIgnore[1] = -1; m_nHierarchyIds[0] = 0; m_nHierarchyIds[1] = 0; m_nObjectSetMask = RNQUERY_OBJECTS_ALL; m_nCollisionGroup = COLLISION_GROUP_ALWAYS; m_bHitSolid = true; m_bHitSolidRequiresGenerateContacts = false; m_bHitTrigger = false; m_bShouldIgnoreDisabledPairs = true; m_bIgnoreIfBothInteractWithHitboxes = false; m_bForceHitEverything = false; m_bUnknown = true; } bool HasInteractsAsLayer( int nLayerIndex ) const { return ( m_nInteractsAs & ( 1ull << nLayerIndex ) ) != 0; } bool HasInteractsWithLayer( int nLayerIndex ) const { return ( m_nInteractsWith & ( 1ull << nLayerIndex ) ) != 0; } bool HasInteractsExcludeLayer( int nLayerIndex ) const { return ( m_nInteractsExclude & ( 1ull << nLayerIndex ) ) != 0; } void EnableInteractsAsLayer( int nLayer ) { m_nInteractsAs |= ( 1ull << nLayer ); } void EnableInteractsWithLayer( int nLayer ) { m_nInteractsWith |= ( 1ull << nLayer ); } void EnableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude |= ( 1ull << nLayer ); } void DisableInteractsAsLayer( int nLayer ) { m_nInteractsAs &= ~( 1ull << nLayer ); } void DisableInteractsWithLayer( int nLayer ) { m_nInteractsWith &= ~( 1ull << nLayer ); } void DisableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude &= ~( 1ull << nLayer ); } public: // Which interaction layers do I interact or collide with? (e.g. I collide with LAYER_INDEX_CONTENTS_PASS_BULLETS because I am not a bullet) // NOTE: This is analogous to the "solid mask" or "trace mask" in source 1 (bit mask of CONTENTS_* or 1<GetRefEHandle().ToInt() : -1; } void SetPassEntity2( CEntityInstance* pEntity ) { m_nEntityIdsToIgnore[1] = pEntity ? pEntity->GetRefEHandle().ToInt() : -1; } void SetPassEntityOwner1( CEntityInstance* pOwner ) { m_nOwnerIdsToIgnore[0] = pOwner ? pOwner->GetRefEHandle().ToInt() : -1; } void SetPassEntityOwner2( CEntityInstance* pOwner ) { m_nOwnerIdsToIgnore[1] = pOwner ? pOwner->GetRefEHandle().ToInt() : -1; } virtual ~CTraceFilter() {} virtual bool ShouldHitEntity( CEntityInstance* pEntity ) { return true; } public: bool m_bIterateEntities; // if true then calls ShouldHitEntity for each hit entity }; struct RnCollisionAttr_t { public: RnCollisionAttr_t() { m_nInteractsAs = 0; m_nInteractsWith = 0; m_nInteractsExclude = 0; m_nEntityId = 0; m_nOwnerId = -1; m_nHierarchyId = 0; m_nCollisionGroup = COLLISION_GROUP_ALWAYS; m_nCollisionFunctionMask = FCOLLISION_FUNC_DEFAULT; } bool IsSolidContactEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_SOLID_CONTACT ) != 0; } bool IsTraceAndQueryEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_TRACE_QUERY ) != 0; } bool IsTouchEventEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_TOUCH_EVENT ) != 0; } bool IsSelfCollisionsEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_SELF_COLLISIONS ) != 0; } bool ShouldIgnoreForHitboxTest() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_IGNORE_FOR_HITBOX_TEST ) != 0; } bool IsTouchPersistsEnabled() const { return ( m_nCollisionFunctionMask & FCOLLISION_FUNC_ENABLE_TOUCH_PERSISTS ) != 0; } bool HasInteractsAsLayer( int nLayerIndex ) const { return ( m_nInteractsAs & ( 1ull << nLayerIndex ) ) != 0; } bool HasInteractsWithLayer( int nLayerIndex ) const { return ( m_nInteractsWith & ( 1ull << nLayerIndex ) ) != 0; } bool HasInteractsExcludeLayer( int nLayerIndex ) const { return ( m_nInteractsExclude & ( 1ull << nLayerIndex ) ) != 0; } void EnableInteractsAsLayer( int nLayer ) { m_nInteractsAs |= ( 1ull << nLayer ); } void EnableInteractsWithLayer( int nLayer ) { m_nInteractsWith |= ( 1ull << nLayer ); } void EnableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude |= ( 1ull << nLayer ); } void DisableInteractsAsLayer( int nLayer ) { m_nInteractsAs &= ~( 1ull << nLayer ); } void DisableInteractsWithLayer( int nLayer ) { m_nInteractsWith &= ~( 1ull << nLayer ); } void DisableInteractsExcludeLayer( int nLayer ) { m_nInteractsExclude &= ~( 1ull << nLayer ); } public: // Which interaction layers do I represent? (e.g. I am a LAYER_INDEX_CONTENTS_PLAYER_CLIP volume) // NOTE: This is analogous to "contents" in source 1 (bit mask of CONTENTS_* or 1<