Team Fortress 2 Source Code as on 22/4/2020
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.

1091 lines
30 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Clones a physics object (usually with a matrix transform applied)
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "physicsshadowclone.h"
  9. #include "portal_util_shared.h"
  10. #include "vphysics/object_hash.h"
  11. #include "trains.h"
  12. #include "props.h"
  13. #include "model_types.h"
  14. #include "portal/weapon_physcannon.h" //grab controllers
  15. #include "PortalSimulation.h"
  16. #define MAX_SHADOW_CLONE_COUNT 200
  17. static int g_iShadowCloneCount = 0;
  18. ConVar sv_debug_physicsshadowclones("sv_debug_physicsshadowclones", "0", FCVAR_REPLICATED );
  19. ConVar sv_use_shadow_clones( "sv_use_shadow_clones", "1", FCVAR_REPLICATED | FCVAR_CHEAT ); //should we create shadow clones?
  20. static void DrawDebugOverlayForShadowClone( CPhysicsShadowClone *pClone );
  21. LINK_ENTITY_TO_CLASS( physicsshadowclone, CPhysicsShadowClone );
  22. static CUtlVector<CPhysicsShadowClone *> s_ActiveShadowClones;
  23. CUtlVector<CPhysicsShadowClone *> const &CPhysicsShadowClone::g_ShadowCloneList = s_ActiveShadowClones;
  24. static bool s_IsShadowClone[MAX_EDICTS] = { false };
  25. static CPhysicsShadowCloneLL *s_EntityClones[MAX_EDICTS] = { NULL };
  26. struct ShadowCloneLLEntryManager
  27. {
  28. CPhysicsShadowCloneLL m_ShadowCloneLLEntries[MAX_SHADOW_CLONE_COUNT];
  29. CPhysicsShadowCloneLL *m_pFreeShadowCloneLLEntries[MAX_SHADOW_CLONE_COUNT];
  30. int m_iUsedEntryIndex;
  31. ShadowCloneLLEntryManager( void )
  32. {
  33. m_iUsedEntryIndex = 0;
  34. for( int i = 0; i != MAX_SHADOW_CLONE_COUNT; ++i )
  35. {
  36. m_pFreeShadowCloneLLEntries[i] = &m_ShadowCloneLLEntries[i];
  37. }
  38. }
  39. inline CPhysicsShadowCloneLL *Alloc( void )
  40. {
  41. return m_pFreeShadowCloneLLEntries[m_iUsedEntryIndex++];
  42. }
  43. inline void Free( CPhysicsShadowCloneLL *pFree )
  44. {
  45. m_pFreeShadowCloneLLEntries[--m_iUsedEntryIndex] = pFree;
  46. }
  47. };
  48. static ShadowCloneLLEntryManager s_SCLLManager;
  49. CPhysicsShadowClone::CPhysicsShadowClone( void )
  50. {
  51. m_matrixShadowTransform.Identity();
  52. m_matrixShadowTransform_Inverse.Identity();
  53. m_bShadowTransformIsIdentity = true;
  54. s_ActiveShadowClones.AddToTail( this );
  55. }
  56. CPhysicsShadowClone::~CPhysicsShadowClone( void )
  57. {
  58. VPhysicsDestroyObject();
  59. VPhysicsSetObject( NULL );
  60. m_hClonedEntity = NULL;
  61. s_ActiveShadowClones.FindAndRemove( this ); //also removed in UpdateOnRemove()
  62. Assert( s_IsShadowClone[entindex()] == true );
  63. s_IsShadowClone[entindex()] = false;
  64. }
  65. void CPhysicsShadowClone::UpdateOnRemove( void )
  66. {
  67. CBaseEntity *pSource = m_hClonedEntity;
  68. if( pSource )
  69. {
  70. CPhysicsShadowCloneLL *pCloneListHead = s_EntityClones[pSource->entindex()];
  71. Assert( pCloneListHead != NULL );
  72. CPhysicsShadowCloneLL *pFind = pCloneListHead;
  73. CPhysicsShadowCloneLL *pLast = pFind;
  74. while( pFind->pClone != this )
  75. {
  76. pLast = pFind;
  77. Assert( pFind->pNext != NULL );
  78. pFind = pFind->pNext;
  79. }
  80. if( pFind == pCloneListHead )
  81. {
  82. s_EntityClones[pSource->entindex()] = pFind->pNext;
  83. }
  84. else
  85. {
  86. pLast->pNext = pFind->pNext;
  87. }
  88. s_SCLLManager.Free( pFind );
  89. }
  90. #ifdef _DEBUG
  91. else
  92. {
  93. //verify that it didn't weasel into a list somewhere and get left behind
  94. for( int i = 0; i != MAX_SHADOW_CLONE_COUNT; ++i )
  95. {
  96. CPhysicsShadowCloneLL *pCloneSearch = s_EntityClones[i];
  97. while( pCloneSearch )
  98. {
  99. Assert( pCloneSearch->pClone != this );
  100. pCloneSearch = pCloneSearch->pNext;
  101. }
  102. }
  103. }
  104. #endif
  105. VPhysicsDestroyObject();
  106. VPhysicsSetObject( NULL );
  107. m_hClonedEntity = NULL;
  108. s_ActiveShadowClones.FindAndRemove( this ); //also removed in Destructor
  109. BaseClass::UpdateOnRemove();
  110. }
  111. void CPhysicsShadowClone::Spawn( void )
  112. {
  113. AddFlag( FL_DONTTOUCH );
  114. AddEffects( EF_NODRAW | EF_NOSHADOW | EF_NORECEIVESHADOW );
  115. FullSync( false );
  116. m_bInAssumedSyncState = false;
  117. BaseClass::Spawn();
  118. s_IsShadowClone[entindex()] = true;
  119. }
  120. void CPhysicsShadowClone::FullSync( bool bAllowAssumedSync )
  121. {
  122. Assert( IsMarkedForDeletion() == false );
  123. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  124. if( pClonedEntity == NULL )
  125. {
  126. AssertMsg( VPhysicsGetObject() != NULL, "Been linkless for more than this update, something should have killed this clone." );
  127. SetMoveType( MOVETYPE_NONE );
  128. SetSolid( SOLID_NONE );
  129. SetSolidFlags( 0 );
  130. SetCollisionGroup( COLLISION_GROUP_NONE );
  131. VPhysicsDestroyObject();
  132. return;
  133. }
  134. SetGroundEntity( NULL );
  135. bool bIsSynced = bAllowAssumedSync;
  136. bool bBigChanges = true; //assume there are, and be proven wrong
  137. if( bAllowAssumedSync )
  138. {
  139. IPhysicsObject *pSourceObjects[1024];
  140. int iObjectCount = pClonedEntity->VPhysicsGetObjectList( pSourceObjects, 1024 );
  141. //scan for really big differences that would definitely require a full sync
  142. bBigChanges = ( iObjectCount != m_CloneLinks.Count() );
  143. if( !bBigChanges )
  144. {
  145. for( int i = 0; i != iObjectCount; ++i )
  146. {
  147. IPhysicsObject *pSourcePhysics = pSourceObjects[i];
  148. IPhysicsObject *pClonedPhysics = m_CloneLinks[i].pClone;
  149. if( (pSourcePhysics != m_CloneLinks[i].pSource) ||
  150. (pSourcePhysics->IsCollisionEnabled() != pClonedPhysics->IsCollisionEnabled()) )
  151. {
  152. bBigChanges = true;
  153. bIsSynced = false;
  154. break;
  155. }
  156. Vector ptSourcePosition, ptClonePosition;
  157. pSourcePhysics->GetPosition( &ptSourcePosition, NULL );
  158. if( !m_bShadowTransformIsIdentity )
  159. ptSourcePosition = m_matrixShadowTransform * ptSourcePosition;
  160. pClonedPhysics->GetPosition( &ptClonePosition, NULL );
  161. if( (ptClonePosition - ptSourcePosition).LengthSqr() > 2500.0f )
  162. {
  163. bBigChanges = true;
  164. bIsSynced = false;
  165. break;
  166. }
  167. //Vector vSourceVelocity, vCloneVelocity;
  168. if( !pSourcePhysics->IsAsleep() ) //only allow full syncrosity if the source entity is entirely asleep
  169. bIsSynced = false;
  170. if( m_bInAssumedSyncState && !pClonedPhysics->IsAsleep() )
  171. bIsSynced = false;
  172. }
  173. }
  174. else
  175. {
  176. bIsSynced = false;
  177. }
  178. bIsSynced = false;
  179. if( bIsSynced )
  180. {
  181. //good enough to skip a full update
  182. if( !m_bInAssumedSyncState )
  183. {
  184. //do one last sync
  185. PartialSync( true );
  186. //if we don't do this, objects just fall out of the world (it happens, I swear)
  187. for( int i = m_CloneLinks.Count(); --i >= 0; )
  188. {
  189. if( (m_CloneLinks[i].pSource->GetShadowController() == NULL) && m_CloneLinks[i].pClone->IsMotionEnabled() )
  190. {
  191. //m_CloneLinks[i].pClone->SetVelocityInstantaneous( &vec3_origin, &vec3_origin );
  192. //m_CloneLinks[i].pClone->SetVelocity( &vec3_origin, &vec3_origin );
  193. m_CloneLinks[i].pClone->EnableGravity( false );
  194. m_CloneLinks[i].pClone->EnableMotion( false );
  195. m_CloneLinks[i].pClone->Sleep();
  196. }
  197. }
  198. m_bInAssumedSyncState = true;
  199. }
  200. if( sv_debug_physicsshadowclones.GetBool() )
  201. DrawDebugOverlayForShadowClone( this );
  202. return;
  203. }
  204. }
  205. m_bInAssumedSyncState = false;
  206. //past this point, we're committed to a broad update
  207. if( bBigChanges )
  208. {
  209. MoveType_t sourceMoveType = pClonedEntity->GetMoveType();
  210. IPhysicsObject *pPhysObject = pClonedEntity->VPhysicsGetObject();
  211. if( (sourceMoveType == MOVETYPE_CUSTOM) ||
  212. (sourceMoveType == MOVETYPE_STEP) ||
  213. (sourceMoveType == MOVETYPE_WALK) ||
  214. (pPhysObject &&
  215. (
  216. (pPhysObject->GetGameFlags() & FVPHYSICS_PLAYER_HELD) ||
  217. (pPhysObject->GetShadowController() != NULL)
  218. )
  219. )
  220. )
  221. {
  222. //#ifdef _DEBUG
  223. SetMoveType( MOVETYPE_NONE ); //to kill an assert
  224. //#endif
  225. //PUSH should be used sparingly, you can't stand on a MOVETYPE_PUSH object :/
  226. SetMoveType( MOVETYPE_VPHYSICS, pClonedEntity->GetMoveCollide() ); //either an unclonable movetype, or a shadow/held object
  227. }
  228. /*else if(sourceMoveType == MOVETYPE_STEP)
  229. {
  230. //SetMoveType( MOVETYPE_NONE ); //to kill an assert
  231. SetMoveType( MOVETYPE_VPHYSICS, pClonedEntity->GetMoveCollide() );
  232. }*/
  233. else
  234. {
  235. //if( m_bShadowTransformIsIdentity )
  236. SetMoveType( sourceMoveType, pClonedEntity->GetMoveCollide() );
  237. //else
  238. //{
  239. // SetMoveType( MOVETYPE_NONE ); //to kill an assert
  240. // SetMoveType( MOVETYPE_PUSH, pClonedEntity->GetMoveCollide() );
  241. //}
  242. }
  243. SolidType_t sourceSolidType = pClonedEntity->GetSolid();
  244. if( sourceSolidType == SOLID_BBOX )
  245. SetSolid( SOLID_VPHYSICS );
  246. else
  247. SetSolid( sourceSolidType );
  248. //SetSolid( SOLID_VPHYSICS );
  249. SetElasticity( pClonedEntity->GetElasticity() );
  250. SetFriction( pClonedEntity->GetFriction() );
  251. int iSolidFlags = pClonedEntity->GetSolidFlags() | FSOLID_CUSTOMRAYTEST;
  252. if( m_bShadowTransformIsIdentity )
  253. iSolidFlags |= FSOLID_CUSTOMBOXTEST; //need this at least for the player or they get stuck in themselves
  254. else
  255. iSolidFlags &= ~FSOLID_FORCE_WORLD_ALIGNED;
  256. /*if( pClonedEntity->IsPlayer() )
  257. {
  258. iSolidFlags |= FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST;
  259. }*/
  260. SetSolidFlags( iSolidFlags );
  261. SetEffects( pClonedEntity->GetEffects() | (EF_NODRAW | EF_NOSHADOW | EF_NORECEIVESHADOW) );
  262. SetCollisionGroup( pClonedEntity->GetCollisionGroup() );
  263. SetModelIndex( pClonedEntity->GetModelIndex() );
  264. SetModelName( pClonedEntity->GetModelName() );
  265. if( modelinfo->GetModelType( pClonedEntity->GetModel() ) == mod_studio )
  266. SetModel( STRING( pClonedEntity->GetModelName() ) );
  267. CCollisionProperty *pClonedCollisionProp = pClonedEntity->CollisionProp();
  268. SetSize( pClonedCollisionProp->OBBMins(), pClonedCollisionProp->OBBMaxs() );
  269. }
  270. FullSyncClonedPhysicsObjects( bBigChanges );
  271. SyncEntity( true );
  272. if( bBigChanges )
  273. CollisionRulesChanged();
  274. if( sv_debug_physicsshadowclones.GetBool() )
  275. DrawDebugOverlayForShadowClone( this );
  276. }
  277. void CPhysicsShadowClone::SyncEntity( bool bPullChanges )
  278. {
  279. m_bShouldUpSync = false;
  280. CBaseEntity *pSource, *pDest;
  281. VMatrix *pTransform;
  282. if( bPullChanges )
  283. {
  284. pSource = m_hClonedEntity.Get();
  285. pDest = this;
  286. pTransform = &m_matrixShadowTransform;
  287. if( pSource == NULL )
  288. return;
  289. }
  290. else
  291. {
  292. pSource = this;
  293. pDest = m_hClonedEntity.Get();
  294. pTransform = &m_matrixShadowTransform_Inverse;
  295. if( pDest == NULL )
  296. return;
  297. }
  298. Vector ptOrigin, vVelocity;
  299. QAngle qAngles;
  300. ptOrigin = pSource->GetAbsOrigin();
  301. qAngles = pSource->GetAbsAngles();
  302. vVelocity = pSource->GetAbsVelocity();
  303. if( !m_bShadowTransformIsIdentity )
  304. {
  305. ptOrigin = (*pTransform) * ptOrigin;
  306. qAngles = TransformAnglesToWorldSpace( qAngles, pTransform->As3x4() );
  307. vVelocity = pTransform->ApplyRotation( vVelocity );
  308. }
  309. //else
  310. //{
  311. // pDest->SetGroundEntity( pSource->GetGroundEntity() );
  312. //}
  313. if( (ptOrigin != pDest->GetAbsOrigin()) || (qAngles != pDest->GetAbsAngles()) )
  314. {
  315. pDest->Teleport( &ptOrigin, &qAngles, NULL );
  316. }
  317. if( vVelocity != pDest->GetAbsVelocity() )
  318. {
  319. //pDest->IncrementInterpolationFrame();
  320. pDest->SetAbsVelocity( vec3_origin ); //the two step process helps, I don't know why, but it does
  321. pDest->ApplyAbsVelocityImpulse( vVelocity );
  322. }
  323. }
  324. static void FullSyncPhysicsObject( IPhysicsObject *pSource, IPhysicsObject *pDest, const VMatrix *pTransform, bool bTeleport )
  325. {
  326. CGrabController *pGrabController = NULL;
  327. if( !pSource->IsAsleep() )
  328. pDest->Wake();
  329. float fSavedMass = 0.0f, fSavedRotationalDamping; //setting mass to 0.0f purely to kill a warning that I can't seem to kill with pragmas
  330. if( pSource->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
  331. {
  332. //CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
  333. //Assert( pPlayer );
  334. CBaseEntity *pLookingForEntity = (CBaseEntity *)pSource->GetGameData();
  335. CBasePlayer *pHoldingPlayer = GetPlayerHoldingEntity( pLookingForEntity );
  336. if( pHoldingPlayer )
  337. {
  338. pGrabController = GetGrabControllerForPlayer( pHoldingPlayer );
  339. if ( !pGrabController )
  340. pGrabController = GetGrabControllerForPhysCannon( pHoldingPlayer->GetActiveWeapon() );
  341. }
  342. AssertMsg( pGrabController, "Physics object is held, but we can't find the holding controller." );
  343. GetSavedParamsForCarriedPhysObject( pGrabController, pSource, &fSavedMass, &fSavedRotationalDamping );
  344. }
  345. //Boiler plate
  346. {
  347. pDest->SetGameIndex( pSource->GetGameIndex() ); //what's it do?
  348. pDest->SetCallbackFlags( pSource->GetCallbackFlags() ); //wise?
  349. pDest->SetGameFlags( pSource->GetGameFlags() | FVPHYSICS_NO_SELF_COLLISIONS | FVPHYSICS_IS_SHADOWCLONE );
  350. pDest->SetMaterialIndex( pSource->GetMaterialIndex() );
  351. pDest->SetContents( pSource->GetContents() );
  352. pDest->EnableCollisions( pSource->IsCollisionEnabled() );
  353. pDest->EnableGravity( pSource->IsGravityEnabled() );
  354. pDest->EnableDrag( pSource->IsDragEnabled() );
  355. pDest->EnableMotion( pSource->IsMotionEnabled() );
  356. }
  357. //Damping
  358. {
  359. float fSpeedDamp, fRotDamp;
  360. if( pGrabController )
  361. {
  362. pSource->GetDamping( &fSpeedDamp, NULL );
  363. pDest->SetDamping( &fSpeedDamp, &fSavedRotationalDamping );
  364. }
  365. else
  366. {
  367. pSource->GetDamping( &fSpeedDamp, &fRotDamp );
  368. pDest->SetDamping( &fSpeedDamp, &fRotDamp );
  369. }
  370. }
  371. //stuff that we really care about
  372. {
  373. if( pGrabController )
  374. pDest->SetMass( fSavedMass );
  375. else
  376. pDest->SetMass( pSource->GetMass() );
  377. Vector ptOrigin, vVelocity, vAngularVelocity, vInertia;
  378. QAngle qAngles;
  379. pSource->GetPosition( &ptOrigin, &qAngles );
  380. pSource->GetVelocity( &vVelocity, &vAngularVelocity );
  381. vInertia = pSource->GetInertia();
  382. if( pTransform )
  383. {
  384. #if 0
  385. pDest->SetPositionMatrix( pTransform->As3x4(), true ); //works like we think?
  386. #else
  387. ptOrigin = (*pTransform) * ptOrigin;
  388. qAngles = TransformAnglesToWorldSpace( qAngles, pTransform->As3x4() );
  389. vVelocity = pTransform->ApplyRotation( vVelocity );
  390. vAngularVelocity = pTransform->ApplyRotation( vAngularVelocity );
  391. #endif
  392. }
  393. //avoid oversetting variables (I think that even setting them to the same value they already are disrupts the delicate physics balance)
  394. if( vInertia != pDest->GetInertia() )
  395. pDest->SetInertia( vInertia );
  396. Vector ptDestOrigin, vDestVelocity, vDestAngularVelocity;
  397. QAngle qDestAngles;
  398. pDest->GetPosition( &ptDestOrigin, &qDestAngles );
  399. if( (ptOrigin != ptDestOrigin) || (qAngles != qDestAngles) )
  400. pDest->SetPosition( ptOrigin, qAngles, bTeleport );
  401. //pDest->SetVelocityInstantaneous( &vec3_origin, &vec3_origin );
  402. //pDest->Sleep();
  403. pDest->GetVelocity( &vDestVelocity, &vDestAngularVelocity );
  404. if( (vVelocity != vDestVelocity) || (vAngularVelocity != vDestAngularVelocity) )
  405. pDest->SetVelocityInstantaneous( &vVelocity, &vAngularVelocity );
  406. IPhysicsShadowController *pSourceController = pSource->GetShadowController();
  407. if( pSourceController == NULL )
  408. {
  409. if( pDest->GetShadowController() != NULL )
  410. {
  411. //we don't need a shadow controller anymore
  412. pDest->RemoveShadowController();
  413. }
  414. }
  415. else
  416. {
  417. IPhysicsShadowController *pDestController = pDest->GetShadowController();
  418. if( pDestController == NULL )
  419. {
  420. //we need a shadow controller
  421. float fMaxSpeed, fMaxAngularSpeed;
  422. pSourceController->GetMaxSpeed( &fMaxSpeed, &fMaxAngularSpeed );
  423. pDest->SetShadow( fMaxSpeed, fMaxAngularSpeed, pSourceController->AllowsTranslation(), pSourceController->AllowsRotation() );
  424. pDestController = pDest->GetShadowController();
  425. pDestController->SetTeleportDistance( pSourceController->GetTeleportDistance() );
  426. pDestController->SetPhysicallyControlled( pSourceController->IsPhysicallyControlled() );
  427. }
  428. //sync shadow controllers
  429. float fTimeOffset;
  430. Vector ptTargetPosition;
  431. QAngle qTargetAngles;
  432. fTimeOffset = pSourceController->GetTargetPosition( &ptTargetPosition, &qTargetAngles );
  433. if( pTransform )
  434. {
  435. ptTargetPosition = (*pTransform) * ptTargetPosition;
  436. qTargetAngles = TransformAnglesToWorldSpace( qTargetAngles, pTransform->As3x4() );
  437. }
  438. pDestController->Update( ptTargetPosition, qTargetAngles, fTimeOffset );
  439. }
  440. }
  441. //pDest->RecheckContactPoints();
  442. }
  443. static void PartialSyncPhysicsObject( IPhysicsObject *pSource, IPhysicsObject *pDest, const VMatrix *pTransform )
  444. {
  445. Vector ptOrigin, vVelocity, vAngularVelocity, vInertia;
  446. QAngle qAngles;
  447. pSource->GetPosition( &ptOrigin, &qAngles );
  448. pSource->GetVelocity( &vVelocity, &vAngularVelocity );
  449. vInertia = pSource->GetInertia();
  450. if( pTransform )
  451. {
  452. #if 0
  453. //pDest->SetPositionMatrix( matTransform.As3x4(), true ); //works like we think?
  454. #else
  455. ptOrigin = (*pTransform) * ptOrigin;
  456. qAngles = TransformAnglesToWorldSpace( qAngles, pTransform->As3x4() );
  457. vVelocity = pTransform->ApplyRotation( vVelocity );
  458. vAngularVelocity = pTransform->ApplyRotation( vAngularVelocity );
  459. #endif
  460. }
  461. //avoid oversetting variables (I think that even setting them to the same value they already are disrupts the delicate physics balance)
  462. if( vInertia != pDest->GetInertia() )
  463. pDest->SetInertia( vInertia );
  464. Vector ptDestOrigin, vDestVelocity, vDestAngularVelocity;
  465. QAngle qDestAngles;
  466. pDest->GetPosition( &ptDestOrigin, &qDestAngles );
  467. pDest->GetVelocity( &vDestVelocity, &vDestAngularVelocity );
  468. if( (ptOrigin != ptDestOrigin) || (qAngles != qDestAngles) )
  469. pDest->SetPosition( ptOrigin, qAngles, false );
  470. if( (vVelocity != vDestVelocity) || (vAngularVelocity != vDestAngularVelocity) )
  471. pDest->SetVelocity( &vVelocity, &vAngularVelocity );
  472. pDest->EnableCollisions( pSource->IsCollisionEnabled() );
  473. }
  474. void CPhysicsShadowClone::FullSyncClonedPhysicsObjects( bool bTeleport )
  475. {
  476. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  477. if( pClonedEntity == NULL )
  478. {
  479. VPhysicsDestroyObject();
  480. return;
  481. }
  482. VMatrix *pTransform;
  483. if( m_bShadowTransformIsIdentity )
  484. pTransform = NULL;
  485. else
  486. pTransform = &m_matrixShadowTransform;
  487. IPhysicsObject *(pSourceObjects[1024]);
  488. int iObjectCount = pClonedEntity->VPhysicsGetObjectList( pSourceObjects, 1024 );
  489. //easy out if nothing has changed
  490. if( iObjectCount == m_CloneLinks.Count() )
  491. {
  492. int i;
  493. for( i = 0; i != iObjectCount; ++i )
  494. {
  495. if( pSourceObjects[i] == NULL )
  496. break;
  497. if( pSourceObjects[i] != m_CloneLinks[i].pSource )
  498. break;
  499. }
  500. if( i == iObjectCount ) //no changes
  501. {
  502. for( i = 0; i != iObjectCount; ++i )
  503. FullSyncPhysicsObject( m_CloneLinks[i].pSource, m_CloneLinks[i].pClone, pTransform, bTeleport );
  504. return;
  505. }
  506. }
  507. //copy the existing list of clone links to a temp array, we're going to be starting from scratch and copying links as we need them
  508. PhysicsObjectCloneLink_t *pExistingLinks = NULL;
  509. int iExistingLinkCount = m_CloneLinks.Count();
  510. if( iExistingLinkCount != 0 )
  511. {
  512. pExistingLinks = (PhysicsObjectCloneLink_t *)stackalloc( sizeof(PhysicsObjectCloneLink_t) * m_CloneLinks.Count() );
  513. memcpy( pExistingLinks, m_CloneLinks.Base(), sizeof(PhysicsObjectCloneLink_t) * m_CloneLinks.Count() );
  514. }
  515. m_CloneLinks.RemoveAll();
  516. //now, go over the object list we just got from the source entity, and either copy or create links as necessary
  517. int i;
  518. for( i = 0; i != iObjectCount; ++i )
  519. {
  520. IPhysicsObject *pSource = pSourceObjects[i];
  521. if( pSource == NULL ) //this really shouldn't happen, but it does >_<
  522. continue;
  523. PhysicsObjectCloneLink_t cloneLink;
  524. int j;
  525. for( j = 0; j != iExistingLinkCount; ++j )
  526. {
  527. if( pExistingLinks[j].pSource == pSource )
  528. break;
  529. }
  530. if( j != iExistingLinkCount )
  531. {
  532. //copyable link found
  533. cloneLink = pExistingLinks[j];
  534. memset( &pExistingLinks[j], 0, sizeof( PhysicsObjectCloneLink_t ) ); //zero out this slot so we don't destroy it in cleanup
  535. }
  536. else
  537. {
  538. //no link found to copy, create a new one
  539. cloneLink.pSource = pSource;
  540. //apparently some collision code gets called on creation before we've set extra game flags, so we're going to cheat a bit and temporarily set our extra flags on the source
  541. unsigned int iOldGameFlags = pSource->GetGameFlags();
  542. pSource->SetGameFlags( iOldGameFlags | FVPHYSICS_IS_SHADOWCLONE );
  543. unsigned int size = physenv->GetObjectSerializeSize(pSource);
  544. byte *pBuffer = (byte *)stackalloc(size);
  545. memset( pBuffer, 0, size );
  546. physenv->SerializeObjectToBuffer( pSource, pBuffer, size ); //this should work across physics environments because the serializer doesn't write anything about itself to the template
  547. pSource->SetGameFlags( iOldGameFlags );
  548. cloneLink.pClone = m_pOwnerPhysEnvironment->UnserializeObjectFromBuffer( this, pBuffer, size, false ); //unserializer has to be in the target environment
  549. assert( cloneLink.pClone ); //there should be absolutely no case where we can't clone a valid existing physics object
  550. stackfree(pBuffer);
  551. }
  552. FullSyncPhysicsObject( cloneLink.pSource, cloneLink.pClone, pTransform, bTeleport );
  553. //cloneLink.pClone->Wake();
  554. m_CloneLinks.AddToTail( cloneLink );
  555. }
  556. //now go over the existing links, if any of them haven't been nullified, they need to be deleted
  557. for( i = 0; i != iExistingLinkCount; ++i )
  558. {
  559. if( pExistingLinks[i].pClone )
  560. m_pOwnerPhysEnvironment->DestroyObject( pExistingLinks[i].pClone ); //also destroys shadow controller
  561. }
  562. VPhysicsSetObject( NULL );
  563. IPhysicsObject *pSource = m_hClonedEntity->VPhysicsGetObject();
  564. for( i = m_CloneLinks.Count(); --i >= 0; )
  565. {
  566. if( m_CloneLinks[i].pSource == pSource )
  567. {
  568. //m_CloneLinks[i].pClone->Wake();
  569. VPhysicsSetObject( m_CloneLinks[i].pClone );
  570. break;
  571. }
  572. }
  573. if( (i < 0) && (m_CloneLinks.Count() != 0) )
  574. {
  575. VPhysicsSetObject( m_CloneLinks[0].pClone );
  576. }
  577. stackfree( pExistingLinks );
  578. //CollisionRulesChanged();
  579. }
  580. void CPhysicsShadowClone::PartialSync( bool bPullChanges )
  581. {
  582. VMatrix *pTransform;
  583. if( bPullChanges )
  584. {
  585. if( m_bShadowTransformIsIdentity )
  586. pTransform = NULL;
  587. else
  588. pTransform = &m_matrixShadowTransform;
  589. for( int i = m_CloneLinks.Count(); --i >= 0; )
  590. PartialSyncPhysicsObject( m_CloneLinks[i].pSource, m_CloneLinks[i].pClone, pTransform );
  591. }
  592. else
  593. {
  594. if( m_bShadowTransformIsIdentity )
  595. pTransform = NULL;
  596. else
  597. pTransform = &m_matrixShadowTransform_Inverse;
  598. for( int i = m_CloneLinks.Count(); --i >= 0; )
  599. PartialSyncPhysicsObject( m_CloneLinks[i].pClone, m_CloneLinks[i].pSource, pTransform );
  600. }
  601. SyncEntity( bPullChanges );
  602. }
  603. int CPhysicsShadowClone::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  604. {
  605. int iCountStop = m_CloneLinks.Count();
  606. if( iCountStop > listMax )
  607. iCountStop = listMax;
  608. for( int i = 0; i != iCountStop; ++i, ++pList )
  609. *pList = m_CloneLinks[i].pClone;
  610. return iCountStop;
  611. }
  612. void CPhysicsShadowClone::VPhysicsDestroyObject( void )
  613. {
  614. VPhysicsSetObject( NULL );
  615. for( int i = m_CloneLinks.Count(); --i >= 0; )
  616. {
  617. Assert( m_CloneLinks[i].pClone != NULL );
  618. m_pOwnerPhysEnvironment->DestroyObject( m_CloneLinks[i].pClone );
  619. }
  620. m_CloneLinks.RemoveAll();
  621. SetMoveType( MOVETYPE_NONE );
  622. SetSolid( SOLID_NONE );
  623. SetSolidFlags( 0 );
  624. SetCollisionGroup( COLLISION_GROUP_NONE );
  625. BaseClass::VPhysicsDestroyObject();
  626. }
  627. bool CPhysicsShadowClone::ShouldCollide( int collisionGroup, int contentsMask ) const
  628. {
  629. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  630. if( pClonedEntity )
  631. return pClonedEntity->ShouldCollide( collisionGroup, contentsMask );
  632. else
  633. return false;
  634. }
  635. bool CPhysicsShadowClone::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& trace )
  636. {
  637. return false;
  638. /*CBaseEntity *pSourceEntity = m_hClonedEntity.Get();
  639. if( pSourceEntity == NULL )
  640. return false;
  641. enginetrace->ClipRayToEntity( ray, fContentsMask, pSourceEntity, &trace );
  642. return trace.DidHit();*/
  643. }
  644. int CPhysicsShadowClone::ObjectCaps( void )
  645. {
  646. return ((BaseClass::ObjectCaps() | FCAP_DONT_SAVE) & ~(FCAP_FORCE_TRANSITION | FCAP_ACROSS_TRANSITION | FCAP_MUST_SPAWN | FCAP_SAVE_NON_NETWORKABLE));
  647. }
  648. void CPhysicsShadowClone::SetCloneTransformationMatrix( const matrix3x4_t &sourceMatrix )
  649. {
  650. m_matrixShadowTransform = sourceMatrix;
  651. m_bShadowTransformIsIdentity = m_matrixShadowTransform.IsIdentity();
  652. if( m_matrixShadowTransform.InverseGeneral( m_matrixShadowTransform_Inverse ) == false )
  653. {
  654. m_matrixShadowTransform.InverseTR( m_matrixShadowTransform_Inverse ); //probably not the right matrix, but we're out of options
  655. }
  656. FullSync();
  657. //PartialSync( true );
  658. }
  659. void CPhysicsShadowClone::SetClonedEntity( EHANDLE hEntToClone )
  660. {
  661. VPhysicsDestroyObject();
  662. m_hClonedEntity = hEntToClone;
  663. //FullSyncClonedPhysicsObjects();
  664. }
  665. EHANDLE CPhysicsShadowClone::GetClonedEntity( void )
  666. {
  667. return m_hClonedEntity;
  668. }
  669. //damage relays to source entity
  670. bool CPhysicsShadowClone::PassesDamageFilter( const CTakeDamageInfo &info )
  671. {
  672. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  673. if( pClonedEntity )
  674. return pClonedEntity->PassesDamageFilter( info );
  675. else
  676. return BaseClass::PassesDamageFilter( info );
  677. }
  678. bool CPhysicsShadowClone::CanBeHitByMeleeAttack( CBaseEntity *pAttacker )
  679. {
  680. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  681. if( pClonedEntity )
  682. return pClonedEntity->CanBeHitByMeleeAttack( pAttacker );
  683. else
  684. return BaseClass::CanBeHitByMeleeAttack( pAttacker );
  685. }
  686. int CPhysicsShadowClone::OnTakeDamage( const CTakeDamageInfo &info )
  687. {
  688. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  689. if( pClonedEntity )
  690. return pClonedEntity->OnTakeDamage( info );
  691. else
  692. return BaseClass::OnTakeDamage( info );
  693. }
  694. int CPhysicsShadowClone::TakeHealth( float flHealth, int bitsDamageType )
  695. {
  696. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  697. if( pClonedEntity )
  698. return pClonedEntity->TakeHealth( flHealth, bitsDamageType );
  699. else
  700. return BaseClass::TakeHealth( flHealth, bitsDamageType );
  701. }
  702. void CPhysicsShadowClone::Event_Killed( const CTakeDamageInfo &info )
  703. {
  704. CBaseEntity *pClonedEntity = m_hClonedEntity.Get();
  705. if( pClonedEntity )
  706. pClonedEntity->Event_Killed( info );
  707. else
  708. BaseClass::Event_Killed( info );
  709. }
  710. CPhysicsShadowClone *CPhysicsShadowClone::CreateShadowClone( IPhysicsEnvironment *pInPhysicsEnvironment, EHANDLE hEntToClone, const char *szDebugMarker, const matrix3x4_t *pTransformationMatrix /*= NULL*/ )
  711. {
  712. AssertMsg( szDebugMarker != NULL, "All shadow clones must have a debug marker for where it came from in debug builds." );
  713. if( !sv_use_shadow_clones.GetBool() )
  714. return NULL;
  715. CBaseEntity *pClonedEntity = hEntToClone.Get();
  716. if( pClonedEntity == NULL )
  717. return NULL;
  718. AssertMsg( IsShadowClone( pClonedEntity ) == false, "Shouldn't attempt to clone clones" );
  719. if( pClonedEntity->IsMarkedForDeletion() )
  720. return NULL;
  721. //if( pClonedEntity->IsPlayer() )
  722. // return NULL;
  723. IPhysicsObject *pPhysics = pClonedEntity->VPhysicsGetObject();
  724. if( pPhysics == NULL )
  725. return NULL;
  726. if( pPhysics->IsStatic() )
  727. return NULL;
  728. if( pClonedEntity->GetSolid() == SOLID_BSP )
  729. return NULL;
  730. if( pClonedEntity->GetSolidFlags() & (FSOLID_NOT_SOLID | FSOLID_TRIGGER) )
  731. return NULL;
  732. if( pClonedEntity->GetFlags() & (FL_WORLDBRUSH | FL_STATICPROP) )
  733. return NULL;
  734. /*if( FClassnameIs( pClonedEntity, "func_door" ) )
  735. {
  736. //only clone func_door's that are in front of the portal
  737. return NULL;
  738. }*/
  739. // Too many shadow clones breaks the game (too many entities)
  740. if( g_iShadowCloneCount >= MAX_SHADOW_CLONE_COUNT )
  741. {
  742. AssertMsg( false, "Too many shadow clones, consider upping the limit or reducing the level's physics props" );
  743. return NULL;
  744. }
  745. ++g_iShadowCloneCount;
  746. CPhysicsShadowClone *pClone = (CPhysicsShadowClone*)CreateEntityByName("physicsshadowclone");
  747. s_IsShadowClone[pClone->entindex()] = true;
  748. pClone->m_pOwnerPhysEnvironment = pInPhysicsEnvironment;
  749. pClone->m_hClonedEntity = hEntToClone;
  750. DBG_CODE_NOSCOPE( pClone->m_szDebugMarker = szDebugMarker; );
  751. CPhysicsShadowCloneLL *pCloneLLEntry = s_SCLLManager.Alloc();
  752. pCloneLLEntry->pClone = pClone;
  753. pCloneLLEntry->pNext = s_EntityClones[pClonedEntity->entindex()];
  754. s_EntityClones[pClonedEntity->entindex()] = pCloneLLEntry;
  755. if( pTransformationMatrix )
  756. {
  757. pClone->m_matrixShadowTransform = *pTransformationMatrix;
  758. pClone->m_bShadowTransformIsIdentity = pClone->m_matrixShadowTransform.IsIdentity();
  759. if( !pClone->m_bShadowTransformIsIdentity )
  760. {
  761. if( pClone->m_matrixShadowTransform.InverseGeneral( pClone->m_matrixShadowTransform_Inverse ) == false )
  762. {
  763. pClone->m_matrixShadowTransform.InverseTR( pClone->m_matrixShadowTransform_Inverse ); //probably not the right matrix, but we're out of options
  764. }
  765. }
  766. }
  767. DispatchSpawn( pClone );
  768. return pClone;
  769. }
  770. void CPhysicsShadowClone::Free( void )
  771. {
  772. VPhysicsDestroyObject();
  773. UTIL_Remove( this );
  774. //Too many shadow clones breaks the game (too many entities)
  775. --g_iShadowCloneCount;
  776. }
  777. void CPhysicsShadowClone::FullSyncAllClones( void )
  778. {
  779. for( int i = s_ActiveShadowClones.Count(); --i >= 0; )
  780. {
  781. s_ActiveShadowClones[i]->FullSync( true );
  782. }
  783. }
  784. IPhysicsObject *CPhysicsShadowClone::TranslatePhysicsToClonedEnt( const IPhysicsObject *pPhysics )
  785. {
  786. if( m_hClonedEntity.Get() != NULL )
  787. {
  788. for( int i = m_CloneLinks.Count(); --i >= 0; )
  789. {
  790. if( m_CloneLinks[i].pClone == pPhysics )
  791. return m_CloneLinks[i].pSource;
  792. }
  793. }
  794. return NULL;
  795. }
  796. void CPhysicsShadowClone::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
  797. {
  798. //the baseclass just screenshakes, makes sounds, and outputs dust, we rely on the original entity to do this when applicable
  799. }
  800. bool CPhysicsShadowClone::IsShadowClone( const CBaseEntity *pEntity )
  801. {
  802. return s_IsShadowClone[pEntity->entindex()];
  803. }
  804. CPhysicsShadowCloneLL *CPhysicsShadowClone::GetClonesOfEntity( const CBaseEntity *pEntity )
  805. {
  806. return s_EntityClones[pEntity->entindex()];
  807. }
  808. static void DrawDebugOverlayForShadowClone( CPhysicsShadowClone *pClone )
  809. {
  810. unsigned char iColorIntensity = (pClone->IsInAssumedSyncState())?(127):(255);
  811. int iRed = (pClone->IsUntransformedClone())?(0):(iColorIntensity);
  812. int iGreen = iColorIntensity;
  813. int iBlue = iColorIntensity;
  814. NDebugOverlay::EntityBounds( pClone, iRed, iGreen, iBlue, (iColorIntensity>>2), 0.05f );
  815. }
  816. bool CTraceFilterTranslateClones::ShouldHitEntity( IHandleEntity *pEntity, int contentsMask )
  817. {
  818. CBaseEntity *pEnt = EntityFromEntityHandle( pEntity );
  819. if( CPhysicsShadowClone::IsShadowClone( pEnt ) )
  820. {
  821. CBaseEntity *pClonedEntity = ((CPhysicsShadowClone *)pEnt)->GetClonedEntity();
  822. CPortalSimulator *pSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pClonedEntity );
  823. if( pSimulator->m_DataAccess.Simulation.Dynamic.EntFlags[pClonedEntity->entindex()] & PSEF_IS_IN_PORTAL_HOLE )
  824. return m_pActualFilter->ShouldHitEntity( pClonedEntity, contentsMask );
  825. else
  826. return false;
  827. }
  828. else
  829. {
  830. return m_pActualFilter->ShouldHitEntity( pEntity, contentsMask );
  831. }
  832. }
  833. TraceType_t CTraceFilterTranslateClones::GetTraceType() const
  834. {
  835. return m_pActualFilter->GetTraceType();
  836. }