Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
15 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "bone_setup.h"
  10. #include "physics_bone_follower.h"
  11. #include "vcollide_parse.h"
  12. #include "saverestore_utlvector.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. BEGIN_SIMPLE_DATADESC( physfollower_t )
  16. DEFINE_FIELD( boneIndex, FIELD_INTEGER ),
  17. DEFINE_FIELD( hFollower, FIELD_EHANDLE ),
  18. END_DATADESC()
  19. BEGIN_SIMPLE_DATADESC( CBoneFollowerManager )
  20. DEFINE_GLOBAL_FIELD( m_iNumBones, FIELD_INTEGER ),
  21. DEFINE_GLOBAL_UTLVECTOR( m_physBones, FIELD_EMBEDDED ),
  22. END_DATADESC()
  23. //================================================================================================================
  24. // BONE FOLLOWER MANAGER
  25. //================================================================================================================
  26. CBoneFollowerManager::CBoneFollowerManager()
  27. {
  28. m_iNumBones = 0;
  29. }
  30. CBoneFollowerManager::~CBoneFollowerManager()
  31. {
  32. // if this fires then someone isn't destroying their bonefollowers in UpdateOnRemove
  33. Assert(m_iNumBones==0);
  34. DestroyBoneFollowers();
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. // Input : *pEntity -
  39. // iNumBones -
  40. // **pFollowerBoneNames -
  41. //-----------------------------------------------------------------------------
  42. void CBoneFollowerManager::InitBoneFollowers( CBaseAnimating *pParentEntity, int iNumBones, const char **pFollowerBoneNames )
  43. {
  44. m_iNumBones = iNumBones;
  45. m_physBones.EnsureCount( iNumBones );
  46. // Now init all the bones
  47. for ( int i = 0; i < iNumBones; i++ )
  48. {
  49. CreatePhysicsFollower( pParentEntity, m_physBones[i], pFollowerBoneNames[i], NULL );
  50. }
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose:
  54. //-----------------------------------------------------------------------------
  55. void CBoneFollowerManager::AddBoneFollower( CBaseAnimating *pParentEntity, const char *pFollowerBoneName, solid_t *pSolid )
  56. {
  57. m_iNumBones++;
  58. int iIndex = m_physBones.AddToTail();
  59. CreatePhysicsFollower( pParentEntity, m_physBones[iIndex], pFollowerBoneName, pSolid );
  60. }
  61. // walk the hitboxes and find the first one that is attached to the physics bone in question
  62. // return the hitgroup of that box
  63. static int HitGroupFromPhysicsBone( CBaseAnimating *pAnim, int physicsBone )
  64. {
  65. CStudioHdr *pStudioHdr = pAnim->GetModelPtr( );
  66. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnim->m_nHitboxSet );
  67. for ( int i = 0; i < set->numhitboxes; i++ )
  68. {
  69. if ( pStudioHdr->pBone( set->pHitbox(i)->bone )->physicsbone == physicsBone )
  70. {
  71. return set->pHitbox(i)->group;
  72. }
  73. }
  74. return 0;
  75. }
  76. //-----------------------------------------------------------------------------
  77. // Purpose:
  78. // Input : &follow -
  79. // *pBoneName -
  80. // Output : Returns true on success, false on failure.
  81. //-----------------------------------------------------------------------------
  82. bool CBoneFollowerManager::CreatePhysicsFollower( CBaseAnimating *pParentEntity, physfollower_t &follow, const char *pBoneName, solid_t *pSolid )
  83. {
  84. CStudioHdr *pStudioHdr = pParentEntity->GetModelPtr();
  85. matrix3x4_t boneToWorld;
  86. solid_t solidTmp;
  87. Vector bonePosition;
  88. QAngle boneAngles;
  89. int boneIndex = Studio_BoneIndexByName( pStudioHdr, pBoneName );
  90. if ( boneIndex >= 0 )
  91. {
  92. const mstudiobone_t *pBone = pStudioHdr->pBone( boneIndex );
  93. int physicsBone = pBone->physicsbone;
  94. if ( !pSolid )
  95. {
  96. if ( !PhysModelParseSolidByIndex( solidTmp, pParentEntity, pParentEntity->GetModelIndex(), physicsBone ) )
  97. return false;
  98. pSolid = &solidTmp;
  99. }
  100. // fixup in case ragdoll is assigned to a parent of the requested follower bone
  101. follow.boneIndex = Studio_BoneIndexByName( pStudioHdr, pSolid->name );
  102. if ( follow.boneIndex < 0 )
  103. {
  104. follow.boneIndex = boneIndex;
  105. }
  106. pParentEntity->GetBoneTransform( follow.boneIndex, boneToWorld );
  107. MatrixAngles( boneToWorld, boneAngles, bonePosition );
  108. follow.hFollower = CBoneFollower::Create( pParentEntity, STRING(pParentEntity->GetModelName()), *pSolid, bonePosition, boneAngles );
  109. follow.hFollower->SetTraceData( physicsBone, HitGroupFromPhysicsBone( pParentEntity, physicsBone ) );
  110. follow.hFollower->SetBlocksLOS( pParentEntity->BlocksLOS() );
  111. return true;
  112. }
  113. else
  114. {
  115. Warning( "ERROR: Tried to create bone follower on invalid bone %s\n", pBoneName );
  116. }
  117. return false;
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Purpose:
  121. //-----------------------------------------------------------------------------
  122. void CBoneFollowerManager::UpdateBoneFollowers( CBaseAnimating *pParentEntity )
  123. {
  124. if ( m_iNumBones )
  125. {
  126. matrix3x4_t boneToWorld;
  127. Vector bonePosition;
  128. QAngle boneAngles;
  129. for ( int i = 0; i < m_iNumBones; i++ )
  130. {
  131. if ( !m_physBones[i].hFollower )
  132. continue;
  133. pParentEntity->GetBoneTransform( m_physBones[i].boneIndex, boneToWorld );
  134. MatrixAngles( boneToWorld, boneAngles, bonePosition );
  135. m_physBones[i].hFollower->UpdateFollower( bonePosition, boneAngles, 0.1 );
  136. }
  137. }
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose:
  141. //-----------------------------------------------------------------------------
  142. void CBoneFollowerManager::DestroyBoneFollowers( void )
  143. {
  144. for ( int i = 0; i < m_iNumBones; i++ )
  145. {
  146. if ( !m_physBones[i].hFollower )
  147. continue;
  148. UTIL_Remove( m_physBones[i].hFollower );
  149. m_physBones[i].hFollower = NULL;
  150. }
  151. m_physBones.Purge();
  152. m_iNumBones = 0;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. //-----------------------------------------------------------------------------
  157. physfollower_t *CBoneFollowerManager::GetBoneFollower( int iFollowerIndex )
  158. {
  159. Assert( iFollowerIndex >= 0 && iFollowerIndex < m_iNumBones );
  160. if ( iFollowerIndex >= 0 && iFollowerIndex < m_iNumBones )
  161. return &m_physBones[iFollowerIndex];
  162. return NULL;
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: Retrieve the index for a supplied bone follower
  166. // Input : *pFollower - Bone follower to look up
  167. // Output : -1 if not found, otherwise the index of the bone follower
  168. //-----------------------------------------------------------------------------
  169. int CBoneFollowerManager::GetBoneFollowerIndex( CBoneFollower *pFollower )
  170. {
  171. if ( pFollower == NULL )
  172. return -1;
  173. for ( int i = 0; i < m_iNumBones; i++ )
  174. {
  175. if ( !m_physBones[i].hFollower )
  176. continue;
  177. if ( m_physBones[i].hFollower == pFollower )
  178. return i;
  179. }
  180. return -1;
  181. }
  182. //================================================================================================================
  183. // BONE FOLLOWER
  184. //================================================================================================================
  185. //---------------------------------------------------------
  186. // Save/Restore
  187. //---------------------------------------------------------
  188. BEGIN_DATADESC( CBoneFollower )
  189. DEFINE_FIELD( m_modelIndex, FIELD_MODELINDEX ),
  190. DEFINE_FIELD( m_solidIndex, FIELD_INTEGER ),
  191. DEFINE_FIELD( m_physicsBone, FIELD_INTEGER ),
  192. DEFINE_FIELD( m_hitGroup, FIELD_INTEGER ),
  193. END_DATADESC()
  194. IMPLEMENT_SERVERCLASS_ST( CBoneFollower, DT_BoneFollower )
  195. SendPropModelIndex(SENDINFO(m_modelIndex)),
  196. SendPropInt(SENDINFO(m_solidIndex), 6, SPROP_UNSIGNED ),
  197. END_SEND_TABLE()
  198. bool CBoneFollower::Init( CBaseEntity *pOwner, const char *pModelName, solid_t &solid, const Vector &position, const QAngle &orientation )
  199. {
  200. SetOwnerEntity( pOwner );
  201. UTIL_SetModel( this, pModelName );
  202. AddEffects( EF_NODRAW ); // invisible
  203. m_modelIndex = modelinfo->GetModelIndex( pModelName );
  204. m_solidIndex = solid.index;
  205. SetAbsOrigin( position );
  206. SetAbsAngles( orientation );
  207. SetMoveType( MOVETYPE_PUSH );
  208. SetSolid( SOLID_VPHYSICS );
  209. SetCollisionGroup( pOwner->GetCollisionGroup() );
  210. AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );
  211. solid.params.pGameData = (void *)this;
  212. IPhysicsObject *pPhysics = VPhysicsInitShadow( false, false, &solid );
  213. if ( !pPhysics )
  214. return false;
  215. PhysSetGameFlags( pPhysics, FVPHYSICS_PUSH_PLAYER );
  216. // we can't use the default model bounds because each entity is only one bone of the model
  217. // so compute the OBB of the physics model and use that.
  218. Vector mins, maxs;
  219. physcollision->CollideGetAABB( &mins, &maxs, pPhysics->GetCollide(), vec3_origin, vec3_angle );
  220. SetCollisionBounds( mins, maxs );
  221. pPhysics->SetCallbackFlags( pPhysics->GetCallbackFlags() | CALLBACK_GLOBAL_TOUCH );
  222. pPhysics->EnableGravity( false );
  223. // This is not a normal shadow controller that is trying to go to a space occupied by an entity in the game physics
  224. // This entity is not running PhysicsPusher(), so Vphysics is supposed to move it
  225. // This line of code informs vphysics of that fact
  226. if ( pOwner->IsNPC() )
  227. {
  228. pPhysics->GetShadowController()->SetPhysicallyControlled( true );
  229. }
  230. return true;
  231. }
  232. int CBoneFollower::UpdateTransmitState()
  233. {
  234. // Send to the client for client-side collisions and visualization
  235. return SetTransmitState( FL_EDICT_PVSCHECK );
  236. }
  237. void CBoneFollower::VPhysicsUpdate( IPhysicsObject *pPhysics )
  238. {
  239. Vector origin;
  240. QAngle angles;
  241. pPhysics->GetPosition( &origin, &angles );
  242. SetAbsOrigin( origin );
  243. SetAbsAngles( angles );
  244. }
  245. // a little helper class to temporarily change the physics object
  246. // for an entity - and change it back when it goes out of scope.
  247. class CPhysicsSwapTemp
  248. {
  249. public:
  250. CPhysicsSwapTemp( CBaseEntity *pEntity, IPhysicsObject *pTmpPhysics )
  251. {
  252. Assert(pEntity);
  253. Assert(pTmpPhysics);
  254. m_pEntity = pEntity;
  255. m_pPhysics = m_pEntity->VPhysicsGetObject();
  256. if ( m_pPhysics )
  257. {
  258. m_pEntity->VPhysicsSwapObject( pTmpPhysics );
  259. }
  260. else
  261. {
  262. m_pEntity->VPhysicsSetObject( pTmpPhysics );
  263. }
  264. }
  265. ~CPhysicsSwapTemp()
  266. {
  267. m_pEntity->VPhysicsSwapObject( m_pPhysics );
  268. }
  269. private:
  270. CBaseEntity *m_pEntity;
  271. IPhysicsObject *m_pPhysics;
  272. };
  273. void CBoneFollower::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
  274. {
  275. CBaseEntity *pOwner = GetOwnerEntity();
  276. if ( pOwner )
  277. {
  278. CPhysicsSwapTemp tmp(pOwner, pEvent->pObjects[index] );
  279. pOwner->VPhysicsCollision( index, pEvent );
  280. }
  281. }
  282. void CBoneFollower::VPhysicsShadowCollision( int index, gamevcollisionevent_t *pEvent )
  283. {
  284. CBaseEntity *pOwner = GetOwnerEntity();
  285. if ( pOwner )
  286. {
  287. CPhysicsSwapTemp tmp(pOwner, pEvent->pObjects[index] );
  288. pOwner->VPhysicsShadowCollision( index, pEvent );
  289. }
  290. }
  291. void CBoneFollower::VPhysicsFriction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit )
  292. {
  293. CBaseEntity *pOwner = GetOwnerEntity();
  294. if ( pOwner )
  295. {
  296. CPhysicsSwapTemp tmp(pOwner, pObject );
  297. pOwner->VPhysicsFriction( pObject, energy, surfaceProps, surfacePropsHit );
  298. }
  299. }
  300. bool CBoneFollower::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
  301. {
  302. vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
  303. Assert( pCollide && pCollide->solidCount > m_solidIndex );
  304. UTIL_ClearTrace( trace );
  305. physcollision->TraceBox( ray, pCollide->solids[m_solidIndex], GetAbsOrigin(), GetAbsAngles(), &trace );
  306. if ( trace.fraction >= 1 )
  307. return false;
  308. // return owner as trace hit
  309. trace.m_pEnt = GetOwnerEntity();
  310. trace.hitgroup = m_hitGroup;
  311. trace.physicsbone = m_physicsBone;
  312. return true;
  313. }
  314. void CBoneFollower::UpdateFollower( const Vector &position, const QAngle &orientation, float flInterval )
  315. {
  316. // UNDONE: Shadow update needs timing info?
  317. VPhysicsGetObject()->UpdateShadow( position, orientation, false, flInterval );
  318. }
  319. void CBoneFollower::SetTraceData( int physicsBone, int hitGroup )
  320. {
  321. m_hitGroup = hitGroup;
  322. m_physicsBone = physicsBone;
  323. }
  324. CBoneFollower *CBoneFollower::Create( CBaseEntity *pOwner, const char *pModelName, solid_t &solid, const Vector &position, const QAngle &orientation )
  325. {
  326. CBoneFollower *pFollower = (CBoneFollower *)CreateEntityByName( "phys_bone_follower" );
  327. if ( pFollower )
  328. {
  329. pFollower->Init( pOwner, pModelName, solid, position, orientation );
  330. }
  331. return pFollower;
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose:
  335. //-----------------------------------------------------------------------------
  336. int CBoneFollower::ObjectCaps()
  337. {
  338. CBaseEntity *pOwner = GetOwnerEntity();
  339. if ( pOwner )
  340. {
  341. if( pOwner->m_iGlobalname != NULL_STRING )
  342. {
  343. int caps = BaseClass::ObjectCaps() | pOwner->ObjectCaps();
  344. caps &= ~FCAP_ACROSS_TRANSITION;
  345. return caps;
  346. }
  347. }
  348. return BaseClass::ObjectCaps();
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose:
  352. //-----------------------------------------------------------------------------
  353. void CBoneFollower::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  354. {
  355. CBaseEntity *pOwner = GetOwnerEntity();
  356. if ( pOwner )
  357. {
  358. pOwner->Use( pActivator, pCaller, useType, value );
  359. return;
  360. }
  361. BaseClass::Use( pActivator, pCaller, useType, value );
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Pass on Touch calls to the entity we're following
  365. //-----------------------------------------------------------------------------
  366. void CBoneFollower::Touch( CBaseEntity *pOther )
  367. {
  368. CBaseEntity *pOwner = GetOwnerEntity();
  369. if ( pOwner )
  370. {
  371. //TODO: fill in the touch trace with the hitbox number associated with this bone
  372. pOwner->Touch( pOther );
  373. return;
  374. }
  375. BaseClass::Touch( pOther );
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Purpose: Pass on trace attack calls to the entity we're following
  379. //-----------------------------------------------------------------------------
  380. void CBoneFollower::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
  381. {
  382. CBaseEntity *pOwner = GetOwnerEntity();
  383. if ( pOwner )
  384. {
  385. pOwner->DispatchTraceAttack( info, vecDir, ptr );
  386. return;
  387. }
  388. BaseClass::TraceAttack( info, vecDir, ptr );
  389. }
  390. LINK_ENTITY_TO_CLASS( phys_bone_follower, CBoneFollower );
  391. // create a manager and a list of followers directly from a ragdoll
  392. void CreateBoneFollowersFromRagdoll( CBaseAnimating *pEntity, CBoneFollowerManager *pManager, vcollide_t *pCollide )
  393. {
  394. IVPhysicsKeyParser *pParse = physcollision->VPhysicsKeyParserCreate( pCollide );
  395. while ( !pParse->Finished() )
  396. {
  397. const char *pBlock = pParse->GetCurrentBlockName();
  398. if ( !strcmpi( pBlock, "solid" ) )
  399. {
  400. solid_t solid;
  401. pParse->ParseSolid( &solid, NULL );
  402. // collisions are off by default, turn them on
  403. solid.params.enableCollisions = true;
  404. solid.params.pName = STRING(pEntity->GetModelName());
  405. pManager->AddBoneFollower( pEntity, solid.name, &solid );
  406. }
  407. else
  408. {
  409. pParse->SkipBlock();
  410. }
  411. }
  412. physcollision->VPhysicsKeyParserDestroy( pParse );
  413. }