diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/shared/physics_saverestore.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/shared/physics_saverestore.cpp')
| -rw-r--r-- | mp/src/game/shared/physics_saverestore.cpp | 828 |
1 files changed, 828 insertions, 0 deletions
diff --git a/mp/src/game/shared/physics_saverestore.cpp b/mp/src/game/shared/physics_saverestore.cpp new file mode 100644 index 00000000..14892ab7 --- /dev/null +++ b/mp/src/game/shared/physics_saverestore.cpp @@ -0,0 +1,828 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+
+#include "utlpriorityqueue.h"
+#include "utlmap.h"
+#include "isaverestore.h"
+#include "physics.h"
+#include "physics_saverestore.h"
+#include "saverestoretypes.h"
+#include "gamestringpool.h"
+#include "datacache/imdlcache.h"
+
+#if !defined( CLIENT_DLL )
+#include "entitylist.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+
+static short PHYS_SAVE_RESTORE_VERSION = 5;
+
+struct PhysBlockHeader_t
+{
+ int nSaved;
+ IPhysicsObject *pWorldObject;
+
+ inline void Clear()
+ {
+ nSaved = 0;
+ pWorldObject = 0;
+ }
+
+ DECLARE_SIMPLE_DATADESC();
+};
+BEGIN_SIMPLE_DATADESC( PhysBlockHeader_t )
+ DEFINE_FIELD( nSaved, FIELD_INTEGER ),
+ // NOTE: We want to save the actual address here for remapping, so use an integer
+ DEFINE_FIELD( pWorldObject, FIELD_INTEGER ),
+END_DATADESC()
+
+#if defined(_STATIC_LINKED) && defined(CLIENT_DLL)
+const char *g_ppszPhysTypeNames[PIID_NUM_TYPES] =
+{
+ "Unknown",
+ "IPhysicsObject",
+ "IPhysicsFluidController",
+ "IPhysicsSpring",
+ "IPhysicsConstraintGroup",
+ "IPhysicsConstraint",
+ "IPhysicsShadowController",
+ "IPhysicsPlayerController",
+ "IPhysicsMotionController",
+ "IPhysicsVehicleController",
+};
+#endif
+
+//-----------------------------------------------------------------------------
+
+struct BBox_t
+{
+ Vector mins, maxs;
+};
+
+struct Sphere_t
+{
+ float radius;
+};
+
+
+struct PhysObjectHeader_t
+{
+ PhysObjectHeader_t()
+ {
+ memset( this, 0, sizeof(*this) );
+ }
+
+ PhysInterfaceId_t type;
+ EHANDLE hEntity;
+ string_t fieldName;
+ int nObjects;
+ string_t modelName;
+ BBox_t bbox;
+ Sphere_t sphere;
+ int iCollide;
+
+ DECLARE_SIMPLE_DATADESC();
+};
+
+BEGIN_SIMPLE_DATADESC( PhysObjectHeader_t )
+ DEFINE_FIELD( type, FIELD_INTEGER ),
+ DEFINE_FIELD( hEntity, FIELD_EHANDLE ),
+ DEFINE_FIELD( fieldName, FIELD_STRING ),
+ DEFINE_FIELD( nObjects, FIELD_INTEGER ),
+ DEFINE_FIELD( modelName, FIELD_STRING ),
+
+ // Silence, Classcheck!
+ // DEFINE_FIELD( bbox, BBox_t ),
+ // DEFINE_FIELD( sphere, Sphere_t ),
+
+ DEFINE_FIELD( bbox.mins, FIELD_VECTOR ),
+ DEFINE_FIELD( bbox.maxs, FIELD_VECTOR ),
+ DEFINE_FIELD( sphere.radius, FIELD_FLOAT ),
+ DEFINE_FIELD( iCollide, FIELD_INTEGER ),
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose: The central manager of physics save/load
+//
+
+class CPhysSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler,
+ public IPhysSaveRestoreManager
+#if !defined( CLIENT_DLL )
+ , public IEntityListener
+#endif
+{
+ struct QueuedItem_t;
+public:
+ CPhysSaveRestoreBlockHandler()
+ {
+ m_QueuedSaves.SetLessFunc( SaveQueueFunc );
+ SetDefLessFunc( m_QueuedRestores );
+ SetDefLessFunc( m_PhysObjectModels );
+ SetDefLessFunc( m_PhysObjectCustomModels );
+ SetDefLessFunc( m_PhysCollideBBoxModels );
+ }
+
+ const char *GetBlockName()
+ {
+ return "Physics";
+ }
+
+ //---------------------------------
+
+ virtual void PreSave( CSaveRestoreData * )
+ {
+ m_blockHeader.Clear();
+ }
+
+ //---------------------------------
+
+ virtual void Save( ISave *pSave )
+ {
+ m_blockHeader.pWorldObject = g_PhysWorldObject;
+ m_blockHeader.nSaved = m_QueuedSaves.Count();
+
+ while ( m_QueuedSaves.Count() )
+ {
+ const QueuedItem_t &item = m_QueuedSaves.ElementAtHead();
+
+ CBaseEntity *pOwner = item.header.hEntity.Get();
+
+ if ( pOwner )
+ {
+ pSave->WriteAll( &item.header );
+ pSave->StartBlock(); // Need block here in case entity is NULL on load
+ if ( item.header.nObjects )
+ {
+ for ( int i = 0; i < item.header.nObjects; i++ )
+ {
+ // Starting a block here allows the implementation of any individual physics
+ // class save/load to change non-trivially while retaining the overall
+ // integrity of the savefile.
+ pSave->StartBlock();
+ SavePhysicsObject( pSave, pOwner, item.ppPhysObj[i], item.header.type );
+ pSave->EndBlock();
+ }
+ }
+ // else, it will simply be recreated on restore
+ pSave->EndBlock();
+ }
+ m_QueuedSaves.RemoveAtHead();
+ }
+ }
+
+ //---------------------------------
+
+ virtual void WriteSaveHeaders( ISave *pSave )
+ {
+ pSave->WriteShort( &PHYS_SAVE_RESTORE_VERSION );
+ pSave->WriteAll( &m_blockHeader );
+ }
+
+ //---------------------------------
+
+ virtual void PostSave()
+ {
+ m_QueuedSaves.Purge();
+ }
+
+ //---------------------------------
+
+ virtual void PreRestore()
+ {
+#if !defined( CLIENT_DLL )
+ gEntList.AddListenerEntity( this );
+#endif
+
+ // UNDONE: This never runs!!!!
+ if ( physenv )
+ {
+ physprerestoreparams_t params;
+ params.recreatedObjectCount = 0;
+ physenv->PreRestore( params );
+ }
+ }
+
+ //---------------------------------
+
+ virtual void ReadRestoreHeaders( IRestore *pRestore )
+ {
+ // No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
+ short version = pRestore->ReadShort();
+ m_fDoLoad = ( version == PHYS_SAVE_RESTORE_VERSION );
+
+ pRestore->ReadAll( &m_blockHeader );
+ }
+
+ //---------------------------------
+
+ virtual void Restore( IRestore *pRestore, bool )
+ {
+ if ( m_fDoLoad )
+ {
+ if ( physenv )
+ {
+ physprerestoreparams_t params;
+ params.recreatedObjectCount = 1;
+ params.recreatedObjectList[0].pNewObject = g_PhysWorldObject;
+ params.recreatedObjectList[0].pOldObject = m_blockHeader.pWorldObject;
+ physenv->PreRestore( params );
+ }
+
+ PhysObjectHeader_t header;
+
+ while ( m_blockHeader.nSaved-- )
+ {
+ pRestore->ReadAll( &header );
+ pRestore->StartBlock();
+
+ if ( header.hEntity != NULL )
+ {
+ RestoreBlock( pRestore, header );
+ }
+
+ pRestore->EndBlock();
+ }
+ }
+ }
+
+ //---------------------------------
+
+ void RestoreBlock( IRestore *pRestore, const PhysObjectHeader_t &header )
+ {
+ CBaseEntity * pOwner = header.hEntity.Get();
+ unsigned short iQueued = m_QueuedRestores.Find( pOwner );
+
+ if ( iQueued != m_QueuedRestores.InvalidIndex() )
+ {
+ MDLCACHE_CRITICAL_SECTION();
+ if ( pOwner->ShouldSavePhysics() && header.nObjects > 0 )
+ {
+ QueuedItem_t *pItem = m_QueuedRestores[iQueued]->FindItem( header.fieldName );
+
+ if ( pItem )
+ {
+ int nObjects = MIN( header.nObjects, pItem->header.nObjects );
+ if ( pItem->header.type == PIID_IPHYSICSOBJECT && nObjects == 1 )
+ {
+ RestorePhysicsObjectAndModel( pRestore, header, pItem, nObjects );
+ }
+ else
+ {
+ void **ppPhysObj = pItem->ppPhysObj;
+
+ for ( int i = 0; i < nObjects; i++ )
+ {
+ pRestore->StartBlock();
+ RestorePhysicsObject( pRestore, header, ppPhysObj + i );
+ pRestore->EndBlock();
+ if ( header.type == PIID_IPHYSICSMOTIONCONTROLLER )
+ {
+ void *pObj = ppPhysObj[i];
+ IPhysicsMotionController *pController = (IPhysicsMotionController *)pObj;
+ if ( pController )
+ {
+ // If the entity is the motion callback handler, then automatically set it
+ // NOTE: This is usually the case
+ IMotionEvent *pEvent = dynamic_cast<IMotionEvent *>(pOwner);
+ if ( pEvent )
+ {
+ pController->SetEventHandler( pEvent );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ pOwner->CreateVPhysics();
+ }
+ }
+
+
+ //---------------------------------
+
+ void RestorePhysicsObjectAndModel( IRestore *pRestore, const PhysObjectHeader_t &header, CPhysSaveRestoreBlockHandler::QueuedItem_t *pItem, int nObjects )
+ {
+ if ( nObjects == 1 )
+ {
+ pRestore->StartBlock();
+
+ CPhysCollide *pPhysCollide = NULL;
+ int modelIndex = -1;
+ bool fCustomCollide = false;
+
+ if ( header.modelName != NULL_STRING )
+ {
+ CBaseEntity *pGlobalEntity = header.hEntity;
+#if !defined( CLIENT_DLL )
+ if ( NULL_STRING != pGlobalEntity->m_iGlobalname )
+ {
+ modelIndex = pGlobalEntity->GetModelIndex();
+ }
+ else
+#endif
+ {
+ modelIndex = modelinfo->GetModelIndex( STRING( header.modelName ) );
+ pGlobalEntity = NULL;
+ }
+
+ if ( modelIndex != -1 )
+ {
+ vcollide_t *pCollide = modelinfo->GetVCollide( modelIndex );
+ if ( pCollide )
+ {
+ if ( pCollide->solidCount > 0 && pCollide->solids && header.iCollide < pCollide->solidCount )
+ pPhysCollide = pCollide->solids[header.iCollide];
+ }
+ }
+ }
+ else if ( header.bbox.mins != vec3_origin || header.bbox.maxs != vec3_origin )
+ {
+ pPhysCollide = PhysCreateBbox( header.bbox.mins, header.bbox.maxs );
+ fCustomCollide = true;
+ }
+ else if ( header.sphere.radius != 0 )
+ {
+ // HACKHACK: Handle spheres here!!!
+ if ( !(*pItem->ppPhysObj) )
+ {
+ RestorePhysicsObject( pRestore, header, pItem->ppPhysObj, NULL );
+ }
+ return;
+ }
+
+ if ( pPhysCollide )
+ {
+ if ( !(*pItem->ppPhysObj) )
+ {
+ RestorePhysicsObject( pRestore, header, pItem->ppPhysObj, pPhysCollide );
+ if ( (*pItem->ppPhysObj) )
+ {
+ IPhysicsObject *pObject = (IPhysicsObject *)(*pItem->ppPhysObj);
+ if ( !fCustomCollide )
+ {
+ AssociateModel( pObject, modelIndex );
+ }
+ else
+ {
+ AssociateModel( pObject, pPhysCollide );
+ }
+ }
+ else
+ DevMsg( "Failed to restore physics object\n" );
+ }
+ else
+ DevMsg( "Physics object pointer unexpectedly non-null before restore. Should be creating physics object in CreatePhysics()?\n" );
+ }
+ else
+ DevMsg( "Failed to reestablish collision model for object\n" );
+
+ pRestore->EndBlock();
+ }
+ else
+ DevMsg( "Don't know how to reconsitite models for physobj array \n" );
+ }
+
+ //---------------------------------
+
+ virtual void PostRestore()
+ {
+ if ( physenv )
+ physenv->PostRestore();
+
+ unsigned short i = m_QueuedRestores.FirstInorder();
+ while ( i != m_QueuedRestores.InvalidIndex() )
+ {
+ delete m_QueuedRestores[i];
+ i = m_QueuedRestores.NextInorder( i );
+ }
+
+ m_QueuedRestores.RemoveAll();
+#if !defined( CLIENT_DLL )
+ gEntList.RemoveListenerEntity( this );
+#endif
+ }
+
+ //---------------------------------
+
+ void QueueSave( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type )
+ {
+ if ( !pOwner )
+ return;
+
+ bool fOnlyNotingExistence = !pOwner->ShouldSavePhysics();
+
+ QueuedItem_t item;
+
+ item.ppPhysObj = ppPhysObj;
+ item.header.hEntity = pOwner;
+ item.header.type = type;
+ item.header.nObjects = ( !fOnlyNotingExistence ) ? pTypeDesc->fieldSize : 0;
+ item.header.fieldName = AllocPooledString( pTypeDesc->fieldName );
+ // A pooled string is used here because there is no way
+ // right now to save a non-string_t string and have it
+ // compressed in the save symbol tables. Furthermore,
+ // the field name would normally be in the string
+ // pool anyway. (toml 12-10-02)
+ item.header.modelName = NULL_STRING;
+ memset( &item.header.bbox, 0, sizeof( item.header.bbox ) );
+ item.header.sphere.radius = 0;
+
+ if ( !fOnlyNotingExistence && type == PIID_IPHYSICSOBJECT )
+ {
+ // Don't doing the box thing for things like wheels on cars
+ IPhysicsObject *pPhysObj = (IPhysicsObject *)(*ppPhysObj);
+
+ if ( pPhysObj )
+ {
+ item.header.modelName = GetModelName( pPhysObj );
+ item.header.iCollide = physcollision->CollideIndex( pPhysObj->GetCollide() );
+ if ( item.header.modelName == NULL_STRING )
+ {
+ BBox_t *pBBox = GetBBox( pPhysObj );
+ if ( pBBox != NULL )
+ {
+ item.header.bbox = *pBBox;
+ }
+ else
+ {
+ if ( pPhysObj && pPhysObj->GetSphereRadius() != 0 )
+ {
+ item.header.sphere.radius = pPhysObj->GetSphereRadius();
+ }
+ else
+ {
+ DevMsg( "Don't know how to save model for physics object (class \"%s\")\n", pOwner->GetClassname() );
+ }
+ }
+ }
+ }
+ }
+
+ m_QueuedSaves.Insert( item );
+ }
+
+ //---------------------------------
+
+ void QueueRestore( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type )
+ {
+ CEntityRestoreSet *pEntitySet = NULL;
+ unsigned short iEntitySet = m_QueuedRestores.Find( pOwner );
+
+ if ( iEntitySet != m_QueuedRestores.InvalidIndex() )
+ {
+ pEntitySet = m_QueuedRestores[iEntitySet];
+ }
+ else
+ {
+ pEntitySet = new CEntityRestoreSet;
+ m_QueuedRestores.Insert( pOwner, pEntitySet );
+ }
+
+ pEntitySet->Add( pOwner, pTypeDesc, ppPhysObj, type );
+
+ memset( ppPhysObj, 0, pTypeDesc->fieldSize * sizeof( void * ) );
+ }
+
+ //---------------------------------
+
+ void SavePhysicsObject( ISave *pSave, CBaseEntity *pOwner, void *pObject, PhysInterfaceId_t type )
+ {
+ if ( physenv )
+ {
+ if ( !pObject )
+ return;
+ physsaveparams_t params = { pSave, pObject, type };
+ physenv->Save( params );
+ }
+ }
+
+ //---------------------------------
+
+ void RestorePhysicsObject( IRestore *pRestore, const PhysObjectHeader_t &header, void **ppObject, const CPhysCollide *pCollide = NULL )
+ {
+ if ( physenv )
+ {
+ physrestoreparams_t params = { pRestore, ppObject, header.type, header.hEntity.Get(), STRING(header.modelName), pCollide, physenv, physgametrace };
+ physenv->Restore( params );
+ }
+ }
+#if !defined( CLIENT_DLL )
+ //-----------------------------------------------------
+ // IEntityListener methods
+ // This object is only a listener during restore
+ virtual void OnEntityCreated( CBaseEntity *pEntity )
+ {
+ }
+
+ //---------------------------------
+
+ virtual void OnEntityDeleted( CBaseEntity *pEntity )
+ {
+ unsigned short iEntitySet = m_QueuedRestores.Find( pEntity );
+
+ if ( iEntitySet != m_QueuedRestores.InvalidIndex() )
+ {
+ delete m_QueuedRestores[iEntitySet];
+ m_QueuedRestores.RemoveAt( iEntitySet );
+ }
+ }
+#endif
+
+ //-----------------------------------------------------
+ // IPhysSaveRestoreManager methods
+
+ virtual void NoteBBox( const Vector &mins, const Vector &maxs, CPhysCollide *pCollide )
+ {
+ if ( pCollide && m_PhysCollideBBoxModels.Find( pCollide ) == m_PhysCollideBBoxModels.InvalidIndex() )
+ {
+ BBox_t box;
+ box.mins = mins;
+ box.maxs = maxs;
+ m_PhysCollideBBoxModels.Insert( pCollide, box );
+ }
+ }
+
+ //---------------------------------
+
+ virtual void AssociateModel( IPhysicsObject *pObject, int modelIndex )
+ {
+ Assert( m_PhysObjectModels.Find( pObject ) == m_PhysObjectModels.InvalidIndex() );
+ m_PhysObjectModels.Insert( pObject, modelIndex );
+ }
+
+ //---------------------------------
+
+ virtual void AssociateModel( IPhysicsObject *pObject, const CPhysCollide *pModel )
+ {
+ Assert( m_PhysObjectCustomModels.Find( pObject ) == m_PhysObjectCustomModels.InvalidIndex() );
+ m_PhysObjectCustomModels.Insert( pObject, pModel );
+ }
+
+ //---------------------------------
+
+ virtual void ForgetModel( IPhysicsObject *pObject )
+ {
+ if ( !m_PhysObjectModels.Remove( pObject ) )
+ m_PhysObjectCustomModels.Remove( pObject );
+ }
+
+ //---------------------------------
+
+ virtual void ForgetAllModels()
+ {
+ m_PhysObjectModels.RemoveAll();
+ m_PhysObjectCustomModels.RemoveAll();
+ m_PhysCollideBBoxModels.RemoveAll();
+ }
+
+ //---------------------------------
+
+ string_t GetModelName( IPhysicsObject *pObject )
+ {
+ int i = m_PhysObjectModels.Find( pObject );
+ if ( i == m_PhysObjectModels.InvalidIndex() )
+ return NULL_STRING;
+ return AllocPooledString( modelinfo->GetModelName( modelinfo->GetModel( m_PhysObjectModels[i] ) ) );
+ }
+
+ //---------------------------------
+
+ BBox_t * GetBBox( IPhysicsObject *pObject )
+ {
+ int i = m_PhysObjectCustomModels.Find( pObject );
+ if ( i == m_PhysObjectCustomModels.InvalidIndex() )
+ return NULL;
+ i = m_PhysCollideBBoxModels.Find( m_PhysObjectCustomModels[i] );
+ if ( i == m_PhysCollideBBoxModels.InvalidIndex() )
+ return NULL;
+ return &(m_PhysCollideBBoxModels[i]);
+ }
+
+ //---------------------------------
+
+private:
+ struct QueuedItem_t
+ {
+ PhysObjectHeader_t header;
+ void ** ppPhysObj;
+ };
+
+ class CEntityRestoreSet : public CUtlVector<QueuedItem_t>
+ {
+ public:
+ int Add( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type )
+ {
+ int i = AddToTail();
+
+ Assert( ppPhysObj );
+ Assert( *ppPhysObj == NULL ); // expected field to have been cleared
+ Assert( pOwner );
+
+ QueuedItem_t &item = Element( i );
+
+ item.ppPhysObj = ppPhysObj;
+ item.header.hEntity = pOwner;
+ item.header.type = type;
+ item.header.nObjects = pTypeDesc->fieldSize;
+ item.header.fieldName = AllocPooledString( pTypeDesc->fieldName ); // See comment in CPhysSaveRestoreBlockHandler::QueueSave()
+
+ return i;
+ }
+
+ QueuedItem_t *FindItem( string_t itemFieldName )
+ {
+ // generally, the set is very small, usually one, so linear search is not too gruesome;
+ for ( int i = 0; i < Count(); i++ )
+ {
+ string_t testName = Element(i).header.fieldName;
+ Assert( ( testName == itemFieldName && strcmp( STRING( testName ), STRING( itemFieldName ) ) == 0 ) ||
+ ( testName != itemFieldName && strcmp( STRING( testName ), STRING( itemFieldName ) ) != 0 ) );
+
+ if ( testName == itemFieldName )
+ return &(Element(i));
+ }
+ return NULL;
+ }
+ };
+
+ //---------------------------------
+
+ static bool SaveQueueFunc( const QueuedItem_t &left, const QueuedItem_t &right )
+ {
+ if ( left.header.type == right.header.type )
+ return ( left.header.hEntity->entindex() > right.header.hEntity->entindex() );
+
+ return ( left.header.type > right.header.type );
+ }
+
+ //---------------------------------
+
+ CUtlPriorityQueue<QueuedItem_t> m_QueuedSaves;
+ CUtlMap<CBaseEntity *, CEntityRestoreSet *> m_QueuedRestores;
+ bool m_fDoLoad;
+
+ //---------------------------------
+
+ CUtlMap<IPhysicsObject *, int> m_PhysObjectModels;
+ CUtlMap<IPhysicsObject *, const CPhysCollide *> m_PhysObjectCustomModels;
+ CUtlMap<const CPhysCollide *, BBox_t> m_PhysCollideBBoxModels;
+
+ //---------------------------------
+
+ PhysBlockHeader_t m_blockHeader;
+};
+
+//-----------------------------------------------------------------------------
+
+CPhysSaveRestoreBlockHandler g_PhysSaveRestoreBlockHandler;
+
+IPhysSaveRestoreManager *g_pPhysSaveRestoreManager = &g_PhysSaveRestoreBlockHandler;
+
+//-------------------------------------
+
+ISaveRestoreBlockHandler *GetPhysSaveRestoreBlockHandler()
+{
+ return &g_PhysSaveRestoreBlockHandler;
+}
+
+static bool IsValidEntityPointer( void *ptr )
+{
+#if !defined( CLIENT_DLL )
+ return gEntList.IsEntityPtr( ptr );
+#else
+ // Walk entities looking for pointer
+ int c = ClientEntityList().GetHighestEntityIndex();
+ for ( int i = 0; i <= c; i++ )
+ {
+ CBaseEntity *e = ClientEntityList().GetBaseEntity( i );
+ if ( !e )
+ continue;
+
+ if ( e == ptr )
+ return true;
+ }
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Classifies field and queues it up for physics save/restore.
+//
+
+class CPhysObjSaveRestoreOps : public CDefSaveRestoreOps
+{
+public:
+ virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
+ {
+ CBaseEntity *pOwnerEntity = pSave->GetGameSaveRestoreInfo()->GetCurrentEntityContext();
+
+ bool bFoundEntity = true;
+
+ if ( IsValidEntityPointer(pOwnerEntity) == false )
+ {
+ bFoundEntity = false;
+
+#if defined( CLIENT_DLL )
+ pOwnerEntity = ClientEntityList().GetBaseEntityFromHandle( pOwnerEntity->GetRefEHandle() );
+
+ if ( pOwnerEntity )
+ {
+ bFoundEntity = true;
+ }
+#endif
+ }
+
+ AssertMsg( pOwnerEntity && bFoundEntity == true, "Physics save/load is only suitable for entities" );
+
+ if ( m_type == PIID_UNKNOWN )
+ {
+ AssertMsg( 0, "Unknown physics save/load type");
+ return;
+ }
+ g_PhysSaveRestoreBlockHandler.QueueSave( pOwnerEntity, fieldInfo.pTypeDesc, (void **)fieldInfo.pField, m_type );
+ }
+
+ virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
+ {
+ CBaseEntity *pOwnerEntity = pRestore->GetGameSaveRestoreInfo()->GetCurrentEntityContext();
+
+ bool bFoundEntity = true;
+
+ if ( IsValidEntityPointer(pOwnerEntity) == false )
+ {
+ bFoundEntity = false;
+
+#if defined( CLIENT_DLL )
+ pOwnerEntity = ClientEntityList().GetBaseEntityFromHandle( pOwnerEntity->GetRefEHandle() );
+
+ if ( pOwnerEntity )
+ {
+ bFoundEntity = true;
+ }
+#endif
+ }
+
+ AssertMsg( pOwnerEntity && bFoundEntity == true, "Physics save/load is only suitable for entities" );
+
+ if ( m_type == PIID_UNKNOWN )
+ {
+ AssertMsg( 0, "Unknown physics save/load type");
+ return;
+ }
+
+ g_PhysSaveRestoreBlockHandler.QueueRestore( pOwnerEntity, fieldInfo.pTypeDesc, (void **)fieldInfo.pField, m_type );
+ }
+
+ virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
+ {
+ memset( fieldInfo.pField, 0, fieldInfo.pTypeDesc->fieldSize * sizeof( void * ) );
+ }
+
+ virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
+ {
+ void **ppPhysObj = (void **)fieldInfo.pField;
+ int nObjects = fieldInfo.pTypeDesc->fieldSize;
+ for ( int i = 0; i < nObjects; i++ )
+ {
+ if ( ppPhysObj[i] != NULL )
+ return false;
+ }
+ return true;
+ }
+
+ PhysInterfaceId_t m_type;
+};
+
+//-----------------------------------------------------------------------------
+
+CPhysObjSaveRestoreOps g_PhysObjSaveRestoreOps[PIID_NUM_TYPES];
+
+//-------------------------------------
+
+ISaveRestoreOps *GetPhysObjSaveRestoreOps( PhysInterfaceId_t type )
+{
+ static bool inited;
+ if ( !inited )
+ {
+ inited = true;
+ for ( int i = 0; i < PIID_NUM_TYPES; i++ )
+ {
+ g_PhysObjSaveRestoreOps[i].m_type = (PhysInterfaceId_t)i;
+ }
+ }
+ return &g_PhysObjSaveRestoreOps[type];
+}
+
+//=============================================================================
|