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.

828 lines
21 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "utlpriorityqueue.h"
  9. #include "utlmap.h"
  10. #include "isaverestore.h"
  11. #include "physics.h"
  12. #include "physics_saverestore.h"
  13. #include "saverestoretypes.h"
  14. #include "gamestringpool.h"
  15. #include "datacache/imdlcache.h"
  16. #if !defined( CLIENT_DLL )
  17. #include "entitylist.h"
  18. #endif
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. static short PHYS_SAVE_RESTORE_VERSION = 5;
  23. struct PhysBlockHeader_t
  24. {
  25. int nSaved;
  26. IPhysicsObject *pWorldObject;
  27. inline void Clear()
  28. {
  29. nSaved = 0;
  30. pWorldObject = 0;
  31. }
  32. DECLARE_SIMPLE_DATADESC();
  33. };
  34. BEGIN_SIMPLE_DATADESC( PhysBlockHeader_t )
  35. DEFINE_FIELD( nSaved, FIELD_INTEGER ),
  36. // NOTE: We want to save the actual address here for remapping, so use an integer
  37. DEFINE_FIELD( pWorldObject, FIELD_INTEGER ),
  38. END_DATADESC()
  39. #if defined(_STATIC_LINKED) && defined(CLIENT_DLL)
  40. const char *g_ppszPhysTypeNames[PIID_NUM_TYPES] =
  41. {
  42. "Unknown",
  43. "IPhysicsObject",
  44. "IPhysicsFluidController",
  45. "IPhysicsSpring",
  46. "IPhysicsConstraintGroup",
  47. "IPhysicsConstraint",
  48. "IPhysicsShadowController",
  49. "IPhysicsPlayerController",
  50. "IPhysicsMotionController",
  51. "IPhysicsVehicleController",
  52. };
  53. #endif
  54. //-----------------------------------------------------------------------------
  55. struct BBox_t
  56. {
  57. Vector mins, maxs;
  58. };
  59. struct Sphere_t
  60. {
  61. float radius;
  62. };
  63. struct PhysObjectHeader_t
  64. {
  65. PhysObjectHeader_t()
  66. {
  67. memset( this, 0, sizeof(*this) );
  68. }
  69. PhysInterfaceId_t type;
  70. EHANDLE hEntity;
  71. string_t fieldName;
  72. int nObjects;
  73. string_t modelName;
  74. BBox_t bbox;
  75. Sphere_t sphere;
  76. int iCollide;
  77. DECLARE_SIMPLE_DATADESC();
  78. };
  79. BEGIN_SIMPLE_DATADESC( PhysObjectHeader_t )
  80. DEFINE_FIELD( type, FIELD_INTEGER ),
  81. DEFINE_FIELD( hEntity, FIELD_EHANDLE ),
  82. DEFINE_FIELD( fieldName, FIELD_STRING ),
  83. DEFINE_FIELD( nObjects, FIELD_INTEGER ),
  84. DEFINE_FIELD( modelName, FIELD_STRING ),
  85. // Silence, Classcheck!
  86. // DEFINE_FIELD( bbox, BBox_t ),
  87. // DEFINE_FIELD( sphere, Sphere_t ),
  88. DEFINE_FIELD( bbox.mins, FIELD_VECTOR ),
  89. DEFINE_FIELD( bbox.maxs, FIELD_VECTOR ),
  90. DEFINE_FIELD( sphere.radius, FIELD_FLOAT ),
  91. DEFINE_FIELD( iCollide, FIELD_INTEGER ),
  92. END_DATADESC()
  93. //-----------------------------------------------------------------------------
  94. // Purpose: The central manager of physics save/load
  95. //
  96. class CPhysSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler,
  97. public IPhysSaveRestoreManager
  98. #if !defined( CLIENT_DLL )
  99. , public IEntityListener
  100. #endif
  101. {
  102. struct QueuedItem_t;
  103. public:
  104. CPhysSaveRestoreBlockHandler()
  105. {
  106. m_QueuedSaves.SetLessFunc( SaveQueueFunc );
  107. SetDefLessFunc( m_QueuedRestores );
  108. SetDefLessFunc( m_PhysObjectModels );
  109. SetDefLessFunc( m_PhysObjectCustomModels );
  110. SetDefLessFunc( m_PhysCollideBBoxModels );
  111. }
  112. const char *GetBlockName()
  113. {
  114. return "Physics";
  115. }
  116. //---------------------------------
  117. virtual void PreSave( CSaveRestoreData * )
  118. {
  119. m_blockHeader.Clear();
  120. }
  121. //---------------------------------
  122. virtual void Save( ISave *pSave )
  123. {
  124. m_blockHeader.pWorldObject = g_PhysWorldObject;
  125. m_blockHeader.nSaved = m_QueuedSaves.Count();
  126. while ( m_QueuedSaves.Count() )
  127. {
  128. const QueuedItem_t &item = m_QueuedSaves.ElementAtHead();
  129. CBaseEntity *pOwner = item.header.hEntity.Get();
  130. if ( pOwner )
  131. {
  132. pSave->WriteAll( &item.header );
  133. pSave->StartBlock(); // Need block here in case entity is NULL on load
  134. if ( item.header.nObjects )
  135. {
  136. for ( int i = 0; i < item.header.nObjects; i++ )
  137. {
  138. // Starting a block here allows the implementation of any individual physics
  139. // class save/load to change non-trivially while retaining the overall
  140. // integrity of the savefile.
  141. pSave->StartBlock();
  142. SavePhysicsObject( pSave, pOwner, item.ppPhysObj[i], item.header.type );
  143. pSave->EndBlock();
  144. }
  145. }
  146. // else, it will simply be recreated on restore
  147. pSave->EndBlock();
  148. }
  149. m_QueuedSaves.RemoveAtHead();
  150. }
  151. }
  152. //---------------------------------
  153. virtual void WriteSaveHeaders( ISave *pSave )
  154. {
  155. pSave->WriteShort( &PHYS_SAVE_RESTORE_VERSION );
  156. pSave->WriteAll( &m_blockHeader );
  157. }
  158. //---------------------------------
  159. virtual void PostSave()
  160. {
  161. m_QueuedSaves.Purge();
  162. }
  163. //---------------------------------
  164. virtual void PreRestore()
  165. {
  166. #if !defined( CLIENT_DLL )
  167. gEntList.AddListenerEntity( this );
  168. #endif
  169. // UNDONE: This never runs!!!!
  170. if ( physenv )
  171. {
  172. physprerestoreparams_t params;
  173. params.recreatedObjectCount = 0;
  174. physenv->PreRestore( params );
  175. }
  176. }
  177. //---------------------------------
  178. virtual void ReadRestoreHeaders( IRestore *pRestore )
  179. {
  180. // No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
  181. short version = pRestore->ReadShort();
  182. m_fDoLoad = ( version == PHYS_SAVE_RESTORE_VERSION );
  183. pRestore->ReadAll( &m_blockHeader );
  184. }
  185. //---------------------------------
  186. virtual void Restore( IRestore *pRestore, bool )
  187. {
  188. if ( m_fDoLoad )
  189. {
  190. if ( physenv )
  191. {
  192. physprerestoreparams_t params;
  193. params.recreatedObjectCount = 1;
  194. params.recreatedObjectList[0].pNewObject = g_PhysWorldObject;
  195. params.recreatedObjectList[0].pOldObject = m_blockHeader.pWorldObject;
  196. physenv->PreRestore( params );
  197. }
  198. PhysObjectHeader_t header;
  199. while ( m_blockHeader.nSaved-- )
  200. {
  201. pRestore->ReadAll( &header );
  202. pRestore->StartBlock();
  203. if ( header.hEntity != NULL )
  204. {
  205. RestoreBlock( pRestore, header );
  206. }
  207. pRestore->EndBlock();
  208. }
  209. }
  210. }
  211. //---------------------------------
  212. void RestoreBlock( IRestore *pRestore, const PhysObjectHeader_t &header )
  213. {
  214. CBaseEntity * pOwner = header.hEntity.Get();
  215. unsigned short iQueued = m_QueuedRestores.Find( pOwner );
  216. if ( iQueued != m_QueuedRestores.InvalidIndex() )
  217. {
  218. MDLCACHE_CRITICAL_SECTION();
  219. if ( pOwner->ShouldSavePhysics() && header.nObjects > 0 )
  220. {
  221. QueuedItem_t *pItem = m_QueuedRestores[iQueued]->FindItem( header.fieldName );
  222. if ( pItem )
  223. {
  224. int nObjects = MIN( header.nObjects, pItem->header.nObjects );
  225. if ( pItem->header.type == PIID_IPHYSICSOBJECT && nObjects == 1 )
  226. {
  227. RestorePhysicsObjectAndModel( pRestore, header, pItem, nObjects );
  228. }
  229. else
  230. {
  231. void **ppPhysObj = pItem->ppPhysObj;
  232. for ( int i = 0; i < nObjects; i++ )
  233. {
  234. pRestore->StartBlock();
  235. RestorePhysicsObject( pRestore, header, ppPhysObj + i );
  236. pRestore->EndBlock();
  237. if ( header.type == PIID_IPHYSICSMOTIONCONTROLLER )
  238. {
  239. void *pObj = ppPhysObj[i];
  240. IPhysicsMotionController *pController = (IPhysicsMotionController *)pObj;
  241. if ( pController )
  242. {
  243. // If the entity is the motion callback handler, then automatically set it
  244. // NOTE: This is usually the case
  245. IMotionEvent *pEvent = dynamic_cast<IMotionEvent *>(pOwner);
  246. if ( pEvent )
  247. {
  248. pController->SetEventHandler( pEvent );
  249. }
  250. }
  251. }
  252. }
  253. }
  254. }
  255. }
  256. else
  257. pOwner->CreateVPhysics();
  258. }
  259. }
  260. //---------------------------------
  261. void RestorePhysicsObjectAndModel( IRestore *pRestore, const PhysObjectHeader_t &header, CPhysSaveRestoreBlockHandler::QueuedItem_t *pItem, int nObjects )
  262. {
  263. if ( nObjects == 1 )
  264. {
  265. pRestore->StartBlock();
  266. CPhysCollide *pPhysCollide = NULL;
  267. int modelIndex = -1;
  268. bool fCustomCollide = false;
  269. if ( header.modelName != NULL_STRING )
  270. {
  271. CBaseEntity *pGlobalEntity = header.hEntity;
  272. #if !defined( CLIENT_DLL )
  273. if ( NULL_STRING != pGlobalEntity->m_iGlobalname )
  274. {
  275. modelIndex = pGlobalEntity->GetModelIndex();
  276. }
  277. else
  278. #endif
  279. {
  280. modelIndex = modelinfo->GetModelIndex( STRING( header.modelName ) );
  281. pGlobalEntity = NULL;
  282. }
  283. if ( modelIndex != -1 )
  284. {
  285. vcollide_t *pCollide = modelinfo->GetVCollide( modelIndex );
  286. if ( pCollide )
  287. {
  288. if ( pCollide->solidCount > 0 && pCollide->solids && header.iCollide < pCollide->solidCount )
  289. pPhysCollide = pCollide->solids[header.iCollide];
  290. }
  291. }
  292. }
  293. else if ( header.bbox.mins != vec3_origin || header.bbox.maxs != vec3_origin )
  294. {
  295. pPhysCollide = PhysCreateBbox( header.bbox.mins, header.bbox.maxs );
  296. fCustomCollide = true;
  297. }
  298. else if ( header.sphere.radius != 0 )
  299. {
  300. // HACKHACK: Handle spheres here!!!
  301. if ( !(*pItem->ppPhysObj) )
  302. {
  303. RestorePhysicsObject( pRestore, header, pItem->ppPhysObj, NULL );
  304. }
  305. return;
  306. }
  307. if ( pPhysCollide )
  308. {
  309. if ( !(*pItem->ppPhysObj) )
  310. {
  311. RestorePhysicsObject( pRestore, header, pItem->ppPhysObj, pPhysCollide );
  312. if ( (*pItem->ppPhysObj) )
  313. {
  314. IPhysicsObject *pObject = (IPhysicsObject *)(*pItem->ppPhysObj);
  315. if ( !fCustomCollide )
  316. {
  317. AssociateModel( pObject, modelIndex );
  318. }
  319. else
  320. {
  321. AssociateModel( pObject, pPhysCollide );
  322. }
  323. }
  324. else
  325. DevMsg( "Failed to restore physics object\n" );
  326. }
  327. else
  328. DevMsg( "Physics object pointer unexpectedly non-null before restore. Should be creating physics object in CreatePhysics()?\n" );
  329. }
  330. else
  331. DevMsg( "Failed to reestablish collision model for object\n" );
  332. pRestore->EndBlock();
  333. }
  334. else
  335. DevMsg( "Don't know how to reconsitite models for physobj array \n" );
  336. }
  337. //---------------------------------
  338. virtual void PostRestore()
  339. {
  340. if ( physenv )
  341. physenv->PostRestore();
  342. unsigned short i = m_QueuedRestores.FirstInorder();
  343. while ( i != m_QueuedRestores.InvalidIndex() )
  344. {
  345. delete m_QueuedRestores[i];
  346. i = m_QueuedRestores.NextInorder( i );
  347. }
  348. m_QueuedRestores.RemoveAll();
  349. #if !defined( CLIENT_DLL )
  350. gEntList.RemoveListenerEntity( this );
  351. #endif
  352. }
  353. //---------------------------------
  354. void QueueSave( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type )
  355. {
  356. if ( !pOwner )
  357. return;
  358. bool fOnlyNotingExistence = !pOwner->ShouldSavePhysics();
  359. QueuedItem_t item;
  360. item.ppPhysObj = ppPhysObj;
  361. item.header.hEntity = pOwner;
  362. item.header.type = type;
  363. item.header.nObjects = ( !fOnlyNotingExistence ) ? pTypeDesc->fieldSize : 0;
  364. item.header.fieldName = AllocPooledString( pTypeDesc->fieldName );
  365. // A pooled string is used here because there is no way
  366. // right now to save a non-string_t string and have it
  367. // compressed in the save symbol tables. Furthermore,
  368. // the field name would normally be in the string
  369. // pool anyway. (toml 12-10-02)
  370. item.header.modelName = NULL_STRING;
  371. memset( &item.header.bbox, 0, sizeof( item.header.bbox ) );
  372. item.header.sphere.radius = 0;
  373. if ( !fOnlyNotingExistence && type == PIID_IPHYSICSOBJECT )
  374. {
  375. // Don't doing the box thing for things like wheels on cars
  376. IPhysicsObject *pPhysObj = (IPhysicsObject *)(*ppPhysObj);
  377. if ( pPhysObj )
  378. {
  379. item.header.modelName = GetModelName( pPhysObj );
  380. item.header.iCollide = physcollision->CollideIndex( pPhysObj->GetCollide() );
  381. if ( item.header.modelName == NULL_STRING )
  382. {
  383. BBox_t *pBBox = GetBBox( pPhysObj );
  384. if ( pBBox != NULL )
  385. {
  386. item.header.bbox = *pBBox;
  387. }
  388. else
  389. {
  390. if ( pPhysObj && pPhysObj->GetSphereRadius() != 0 )
  391. {
  392. item.header.sphere.radius = pPhysObj->GetSphereRadius();
  393. }
  394. else
  395. {
  396. DevMsg( "Don't know how to save model for physics object (class \"%s\")\n", pOwner->GetClassname() );
  397. }
  398. }
  399. }
  400. }
  401. }
  402. m_QueuedSaves.Insert( item );
  403. }
  404. //---------------------------------
  405. void QueueRestore( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type )
  406. {
  407. CEntityRestoreSet *pEntitySet = NULL;
  408. unsigned short iEntitySet = m_QueuedRestores.Find( pOwner );
  409. if ( iEntitySet != m_QueuedRestores.InvalidIndex() )
  410. {
  411. pEntitySet = m_QueuedRestores[iEntitySet];
  412. }
  413. else
  414. {
  415. pEntitySet = new CEntityRestoreSet;
  416. m_QueuedRestores.Insert( pOwner, pEntitySet );
  417. }
  418. pEntitySet->Add( pOwner, pTypeDesc, ppPhysObj, type );
  419. memset( ppPhysObj, 0, pTypeDesc->fieldSize * sizeof( void * ) );
  420. }
  421. //---------------------------------
  422. void SavePhysicsObject( ISave *pSave, CBaseEntity *pOwner, void *pObject, PhysInterfaceId_t type )
  423. {
  424. if ( physenv )
  425. {
  426. if ( !pObject )
  427. return;
  428. physsaveparams_t params = { pSave, pObject, type };
  429. physenv->Save( params );
  430. }
  431. }
  432. //---------------------------------
  433. void RestorePhysicsObject( IRestore *pRestore, const PhysObjectHeader_t &header, void **ppObject, const CPhysCollide *pCollide = NULL )
  434. {
  435. if ( physenv )
  436. {
  437. physrestoreparams_t params = { pRestore, ppObject, header.type, header.hEntity.Get(), STRING(header.modelName), pCollide, physenv, physgametrace };
  438. physenv->Restore( params );
  439. }
  440. }
  441. #if !defined( CLIENT_DLL )
  442. //-----------------------------------------------------
  443. // IEntityListener methods
  444. // This object is only a listener during restore
  445. virtual void OnEntityCreated( CBaseEntity *pEntity )
  446. {
  447. }
  448. //---------------------------------
  449. virtual void OnEntityDeleted( CBaseEntity *pEntity )
  450. {
  451. unsigned short iEntitySet = m_QueuedRestores.Find( pEntity );
  452. if ( iEntitySet != m_QueuedRestores.InvalidIndex() )
  453. {
  454. delete m_QueuedRestores[iEntitySet];
  455. m_QueuedRestores.RemoveAt( iEntitySet );
  456. }
  457. }
  458. #endif
  459. //-----------------------------------------------------
  460. // IPhysSaveRestoreManager methods
  461. virtual void NoteBBox( const Vector &mins, const Vector &maxs, CPhysCollide *pCollide )
  462. {
  463. if ( pCollide && m_PhysCollideBBoxModels.Find( pCollide ) == m_PhysCollideBBoxModels.InvalidIndex() )
  464. {
  465. BBox_t box;
  466. box.mins = mins;
  467. box.maxs = maxs;
  468. m_PhysCollideBBoxModels.Insert( pCollide, box );
  469. }
  470. }
  471. //---------------------------------
  472. virtual void AssociateModel( IPhysicsObject *pObject, int modelIndex )
  473. {
  474. Assert( m_PhysObjectModels.Find( pObject ) == m_PhysObjectModels.InvalidIndex() );
  475. m_PhysObjectModels.Insert( pObject, modelIndex );
  476. }
  477. //---------------------------------
  478. virtual void AssociateModel( IPhysicsObject *pObject, const CPhysCollide *pModel )
  479. {
  480. Assert( m_PhysObjectCustomModels.Find( pObject ) == m_PhysObjectCustomModels.InvalidIndex() );
  481. m_PhysObjectCustomModels.Insert( pObject, pModel );
  482. }
  483. //---------------------------------
  484. virtual void ForgetModel( IPhysicsObject *pObject )
  485. {
  486. if ( !m_PhysObjectModels.Remove( pObject ) )
  487. m_PhysObjectCustomModels.Remove( pObject );
  488. }
  489. //---------------------------------
  490. virtual void ForgetAllModels()
  491. {
  492. m_PhysObjectModels.RemoveAll();
  493. m_PhysObjectCustomModels.RemoveAll();
  494. m_PhysCollideBBoxModels.RemoveAll();
  495. }
  496. //---------------------------------
  497. string_t GetModelName( IPhysicsObject *pObject )
  498. {
  499. int i = m_PhysObjectModels.Find( pObject );
  500. if ( i == m_PhysObjectModels.InvalidIndex() )
  501. return NULL_STRING;
  502. return AllocPooledString( modelinfo->GetModelName( modelinfo->GetModel( m_PhysObjectModels[i] ) ) );
  503. }
  504. //---------------------------------
  505. BBox_t * GetBBox( IPhysicsObject *pObject )
  506. {
  507. int i = m_PhysObjectCustomModels.Find( pObject );
  508. if ( i == m_PhysObjectCustomModels.InvalidIndex() )
  509. return NULL;
  510. i = m_PhysCollideBBoxModels.Find( m_PhysObjectCustomModels[i] );
  511. if ( i == m_PhysCollideBBoxModels.InvalidIndex() )
  512. return NULL;
  513. return &(m_PhysCollideBBoxModels[i]);
  514. }
  515. //---------------------------------
  516. private:
  517. struct QueuedItem_t
  518. {
  519. PhysObjectHeader_t header;
  520. void ** ppPhysObj;
  521. };
  522. class CEntityRestoreSet : public CUtlVector<QueuedItem_t>
  523. {
  524. public:
  525. int Add( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type )
  526. {
  527. int i = AddToTail();
  528. Assert( ppPhysObj );
  529. Assert( *ppPhysObj == NULL ); // expected field to have been cleared
  530. Assert( pOwner );
  531. QueuedItem_t &item = Element( i );
  532. item.ppPhysObj = ppPhysObj;
  533. item.header.hEntity = pOwner;
  534. item.header.type = type;
  535. item.header.nObjects = pTypeDesc->fieldSize;
  536. item.header.fieldName = AllocPooledString( pTypeDesc->fieldName ); // See comment in CPhysSaveRestoreBlockHandler::QueueSave()
  537. return i;
  538. }
  539. QueuedItem_t *FindItem( string_t itemFieldName )
  540. {
  541. // generally, the set is very small, usually one, so linear search is not too gruesome;
  542. for ( int i = 0; i < Count(); i++ )
  543. {
  544. string_t testName = Element(i).header.fieldName;
  545. Assert( ( testName == itemFieldName && strcmp( STRING( testName ), STRING( itemFieldName ) ) == 0 ) ||
  546. ( testName != itemFieldName && strcmp( STRING( testName ), STRING( itemFieldName ) ) != 0 ) );
  547. if ( testName == itemFieldName )
  548. return &(Element(i));
  549. }
  550. return NULL;
  551. }
  552. };
  553. //---------------------------------
  554. static bool SaveQueueFunc( const QueuedItem_t &left, const QueuedItem_t &right )
  555. {
  556. if ( left.header.type == right.header.type )
  557. return ( left.header.hEntity->entindex() > right.header.hEntity->entindex() );
  558. return ( left.header.type > right.header.type );
  559. }
  560. //---------------------------------
  561. CUtlPriorityQueue<QueuedItem_t> m_QueuedSaves;
  562. CUtlMap<CBaseEntity *, CEntityRestoreSet *> m_QueuedRestores;
  563. bool m_fDoLoad;
  564. //---------------------------------
  565. CUtlMap<IPhysicsObject *, int> m_PhysObjectModels;
  566. CUtlMap<IPhysicsObject *, const CPhysCollide *> m_PhysObjectCustomModels;
  567. CUtlMap<const CPhysCollide *, BBox_t> m_PhysCollideBBoxModels;
  568. //---------------------------------
  569. PhysBlockHeader_t m_blockHeader;
  570. };
  571. //-----------------------------------------------------------------------------
  572. CPhysSaveRestoreBlockHandler g_PhysSaveRestoreBlockHandler;
  573. IPhysSaveRestoreManager *g_pPhysSaveRestoreManager = &g_PhysSaveRestoreBlockHandler;
  574. //-------------------------------------
  575. ISaveRestoreBlockHandler *GetPhysSaveRestoreBlockHandler()
  576. {
  577. return &g_PhysSaveRestoreBlockHandler;
  578. }
  579. static bool IsValidEntityPointer( void *ptr )
  580. {
  581. #if !defined( CLIENT_DLL )
  582. return gEntList.IsEntityPtr( ptr );
  583. #else
  584. // Walk entities looking for pointer
  585. int c = ClientEntityList().GetHighestEntityIndex();
  586. for ( int i = 0; i <= c; i++ )
  587. {
  588. CBaseEntity *e = ClientEntityList().GetBaseEntity( i );
  589. if ( !e )
  590. continue;
  591. if ( e == ptr )
  592. return true;
  593. }
  594. return false;
  595. #endif
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Purpose: Classifies field and queues it up for physics save/restore.
  599. //
  600. class CPhysObjSaveRestoreOps : public CDefSaveRestoreOps
  601. {
  602. public:
  603. virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
  604. {
  605. CBaseEntity *pOwnerEntity = pSave->GetGameSaveRestoreInfo()->GetCurrentEntityContext();
  606. bool bFoundEntity = true;
  607. if ( IsValidEntityPointer(pOwnerEntity) == false )
  608. {
  609. bFoundEntity = false;
  610. #if defined( CLIENT_DLL )
  611. pOwnerEntity = ClientEntityList().GetBaseEntityFromHandle( pOwnerEntity->GetRefEHandle() );
  612. if ( pOwnerEntity )
  613. {
  614. bFoundEntity = true;
  615. }
  616. #endif
  617. }
  618. AssertMsg( pOwnerEntity && bFoundEntity == true, "Physics save/load is only suitable for entities" );
  619. if ( m_type == PIID_UNKNOWN )
  620. {
  621. AssertMsg( 0, "Unknown physics save/load type");
  622. return;
  623. }
  624. g_PhysSaveRestoreBlockHandler.QueueSave( pOwnerEntity, fieldInfo.pTypeDesc, (void **)fieldInfo.pField, m_type );
  625. }
  626. virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
  627. {
  628. CBaseEntity *pOwnerEntity = pRestore->GetGameSaveRestoreInfo()->GetCurrentEntityContext();
  629. bool bFoundEntity = true;
  630. if ( IsValidEntityPointer(pOwnerEntity) == false )
  631. {
  632. bFoundEntity = false;
  633. #if defined( CLIENT_DLL )
  634. pOwnerEntity = ClientEntityList().GetBaseEntityFromHandle( pOwnerEntity->GetRefEHandle() );
  635. if ( pOwnerEntity )
  636. {
  637. bFoundEntity = true;
  638. }
  639. #endif
  640. }
  641. AssertMsg( pOwnerEntity && bFoundEntity == true, "Physics save/load is only suitable for entities" );
  642. if ( m_type == PIID_UNKNOWN )
  643. {
  644. AssertMsg( 0, "Unknown physics save/load type");
  645. return;
  646. }
  647. g_PhysSaveRestoreBlockHandler.QueueRestore( pOwnerEntity, fieldInfo.pTypeDesc, (void **)fieldInfo.pField, m_type );
  648. }
  649. virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  650. {
  651. memset( fieldInfo.pField, 0, fieldInfo.pTypeDesc->fieldSize * sizeof( void * ) );
  652. }
  653. virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  654. {
  655. void **ppPhysObj = (void **)fieldInfo.pField;
  656. int nObjects = fieldInfo.pTypeDesc->fieldSize;
  657. for ( int i = 0; i < nObjects; i++ )
  658. {
  659. if ( ppPhysObj[i] != NULL )
  660. return false;
  661. }
  662. return true;
  663. }
  664. PhysInterfaceId_t m_type;
  665. };
  666. //-----------------------------------------------------------------------------
  667. CPhysObjSaveRestoreOps g_PhysObjSaveRestoreOps[PIID_NUM_TYPES];
  668. //-------------------------------------
  669. ISaveRestoreOps *GetPhysObjSaveRestoreOps( PhysInterfaceId_t type )
  670. {
  671. static bool inited;
  672. if ( !inited )
  673. {
  674. inited = true;
  675. for ( int i = 0; i < PIID_NUM_TYPES; i++ )
  676. {
  677. g_PhysObjSaveRestoreOps[i].m_type = (PhysInterfaceId_t)i;
  678. }
  679. }
  680. return &g_PhysObjSaveRestoreOps[type];
  681. }
  682. //=============================================================================