444 lines
13 KiB
C++
444 lines
13 KiB
C++
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Deals with singleton
|
|
//
|
|
// $Revision: $
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "igamesystem.h"
|
|
#include "datacache/imdlcache.h"
|
|
#include "utlvector.h"
|
|
#include "vprof.h"
|
|
#if defined( _X360 )
|
|
#include "xbox/xbox_console.h"
|
|
#endif
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
// enable this #define (here or in your vpc) to have
|
|
// each GameSystem accounted for individually in the vprof.
|
|
// You must enable VPROF_LEVEL 1 too.
|
|
// #define VPROF_ACCOUNT_GAMESYSTEMS
|
|
|
|
// Pointer to a member method of IGameSystem
|
|
typedef void (IGameSystem::*GameSystemFunc_t)();
|
|
|
|
// Pointer to a member method of IGameSystem
|
|
typedef void (IGameSystemPerFrame::*PerFrameGameSystemFunc_t)();
|
|
|
|
// Used to invoke a method of all added Game systems in order
|
|
static void InvokeMethod( GameSystemFunc_t f, char const *timed = 0 );
|
|
// Used to invoke a method of all added Game systems in order
|
|
static void InvokeMethodTickProgress( GameSystemFunc_t f, char const *timed = 0 );
|
|
// Used to invoke a method of all added Game systems in reverse order
|
|
static void InvokeMethodReverseOrder( GameSystemFunc_t f );
|
|
|
|
// Used to invoke a method of all added Game systems in order
|
|
static void InvokePerFrameMethod( PerFrameGameSystemFunc_t f, char const *timed = 0 );
|
|
|
|
static bool s_bSystemsInitted = false;
|
|
|
|
// List of all installed Game systems
|
|
static CUtlVector<IGameSystem*> s_GameSystems( 0, 4 );
|
|
// List of all installed Game systems
|
|
static CUtlVector<IGameSystemPerFrame*> s_GameSystemsPerFrame( 0, 4 );
|
|
|
|
// The map name
|
|
static char* s_pMapName = 0;
|
|
|
|
static CBasePlayer *s_pRunCommandPlayer = NULL;
|
|
static CUserCmd *s_pRunCommandUserCmd = NULL;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Auto-registration of game systems
|
|
//-----------------------------------------------------------------------------
|
|
static CAutoGameSystem *s_pSystemList = NULL;
|
|
|
|
CAutoGameSystem::CAutoGameSystem( char const *name ) :
|
|
m_pszName( name )
|
|
{
|
|
// If s_GameSystems hasn't been initted yet, then add ourselves to the global list
|
|
// because we don't know if the constructor for s_GameSystems has happened yet.
|
|
// Otherwise, we can add ourselves right into that list.
|
|
if ( s_bSystemsInitted )
|
|
{
|
|
Add( this );
|
|
}
|
|
else
|
|
{
|
|
m_pNext = s_pSystemList;
|
|
s_pSystemList = this;
|
|
}
|
|
}
|
|
|
|
static CAutoGameSystemPerFrame *s_pPerFrameSystemList = NULL;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: This is a CAutoGameSystem which also cares about the "per frame" hooks
|
|
//-----------------------------------------------------------------------------
|
|
CAutoGameSystemPerFrame::CAutoGameSystemPerFrame( char const *name ) :
|
|
m_pszName( name )
|
|
{
|
|
// If s_GameSystems hasn't been initted yet, then add ourselves to the global list
|
|
// because we don't know if the constructor for s_GameSystems has happened yet.
|
|
// Otherwise, we can add ourselves right into that list.
|
|
if ( s_bSystemsInitted )
|
|
{
|
|
Add( this );
|
|
}
|
|
else
|
|
{
|
|
m_pNext = s_pPerFrameSystemList;
|
|
s_pPerFrameSystemList = this;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// destructor, cleans up automagically....
|
|
//-----------------------------------------------------------------------------
|
|
IGameSystem::~IGameSystem()
|
|
{
|
|
Remove( this );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// destructor, cleans up automagically....
|
|
//-----------------------------------------------------------------------------
|
|
IGameSystemPerFrame::~IGameSystemPerFrame()
|
|
{
|
|
Remove( this );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Adds a system to the list of systems to run
|
|
//-----------------------------------------------------------------------------
|
|
void IGameSystem::Add( IGameSystem* pSys )
|
|
{
|
|
s_GameSystems.AddToTail( pSys );
|
|
if ( dynamic_cast< IGameSystemPerFrame * >( pSys ) != NULL )
|
|
{
|
|
s_GameSystemsPerFrame.AddToTail( static_cast< IGameSystemPerFrame * >( pSys ) );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Removes a system from the list of systems to update
|
|
//-----------------------------------------------------------------------------
|
|
void IGameSystem::Remove( IGameSystem* pSys )
|
|
{
|
|
s_GameSystems.FindAndRemove( pSys );
|
|
if ( dynamic_cast< IGameSystemPerFrame * >( pSys ) != NULL )
|
|
{
|
|
s_GameSystemsPerFrame.FindAndRemove( static_cast< IGameSystemPerFrame * >( pSys ) );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Removes *all* systems from the list of systems to update
|
|
//-----------------------------------------------------------------------------
|
|
void IGameSystem::RemoveAll( )
|
|
{
|
|
s_GameSystems.RemoveAll();
|
|
s_GameSystemsPerFrame.RemoveAll();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Client systems can use this to get at the map name
|
|
//-----------------------------------------------------------------------------
|
|
char const* IGameSystem::MapName()
|
|
{
|
|
return s_pMapName;
|
|
}
|
|
|
|
#ifndef CLIENT_DLL
|
|
CBasePlayer *IGameSystem::RunCommandPlayer()
|
|
{
|
|
return s_pRunCommandPlayer;
|
|
}
|
|
|
|
CUserCmd *IGameSystem::RunCommandUserCmd()
|
|
{
|
|
return s_pRunCommandUserCmd;
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Invokes methods on all installed game systems
|
|
//-----------------------------------------------------------------------------
|
|
bool IGameSystem::InitAllSystems()
|
|
{
|
|
int i;
|
|
|
|
{
|
|
// first add any auto systems to the end
|
|
CAutoGameSystem *pSystem = s_pSystemList;
|
|
while ( pSystem )
|
|
{
|
|
if ( s_GameSystems.Find( pSystem ) == s_GameSystems.InvalidIndex() )
|
|
{
|
|
Add( pSystem );
|
|
}
|
|
else
|
|
{
|
|
DevWarning( 1, "AutoGameSystem already added to game system list!!!\n" );
|
|
}
|
|
pSystem = pSystem->m_pNext;
|
|
}
|
|
s_pSystemList = NULL;
|
|
}
|
|
|
|
{
|
|
CAutoGameSystemPerFrame *pSystem = s_pPerFrameSystemList;
|
|
while ( pSystem )
|
|
{
|
|
if ( s_GameSystems.Find( pSystem ) == s_GameSystems.InvalidIndex() )
|
|
{
|
|
Add( pSystem );
|
|
}
|
|
else
|
|
{
|
|
DevWarning( 1, "AutoGameSystem already added to game system list!!!\n" );
|
|
}
|
|
|
|
pSystem = pSystem->m_pNext;
|
|
}
|
|
s_pSystemList = NULL;
|
|
}
|
|
// Now remember that we are initted so new CAutoGameSystems will add themselves automatically.
|
|
s_bSystemsInitted = true;
|
|
|
|
for ( i = 0; i < s_GameSystems.Count(); ++i )
|
|
{
|
|
MDLCACHE_COARSE_LOCK();
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
|
|
IGameSystem *sys = s_GameSystems[i];
|
|
|
|
#if defined( _X360 )
|
|
char sz[128];
|
|
Q_snprintf( sz, sizeof( sz ), "%s->Init():Start", sys->Name() );
|
|
XBX_rTimeStampLog( Plat_FloatTime(), sz );
|
|
#endif
|
|
bool valid = sys->Init();
|
|
|
|
#if defined( _X360 )
|
|
Q_snprintf( sz, sizeof( sz ), "%s->Init():Finish", sys->Name() );
|
|
XBX_rTimeStampLog( Plat_FloatTime(), sz );
|
|
#endif
|
|
if ( !valid )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void IGameSystem::PostInitAllSystems( void )
|
|
{
|
|
InvokeMethod( &IGameSystem::PostInit, "PostInit" );
|
|
}
|
|
|
|
void IGameSystem::ShutdownAllSystems()
|
|
{
|
|
InvokeMethodReverseOrder( &IGameSystem::Shutdown );
|
|
}
|
|
|
|
void IGameSystem::LevelInitPreEntityAllSystems( char const* pMapName )
|
|
{
|
|
// Store off the map name
|
|
if ( s_pMapName )
|
|
{
|
|
delete[] s_pMapName;
|
|
}
|
|
|
|
int len = Q_strlen(pMapName) + 1;
|
|
s_pMapName = new char [ len ];
|
|
Q_strncpy( s_pMapName, pMapName, len );
|
|
|
|
InvokeMethodTickProgress( &IGameSystem::LevelInitPreEntity, "LevelInitPreEntity" );
|
|
}
|
|
|
|
void IGameSystem::LevelInitPostEntityAllSystems( void )
|
|
{
|
|
InvokeMethod( &IGameSystem::LevelInitPostEntity, "LevelInitPostEntity" );
|
|
}
|
|
|
|
void IGameSystem::LevelShutdownPreEntityAllSystems()
|
|
{
|
|
InvokeMethodReverseOrder( &IGameSystem::LevelShutdownPreEntity );
|
|
}
|
|
|
|
void IGameSystem::LevelShutdownPostEntityAllSystems()
|
|
{
|
|
InvokeMethodReverseOrder( &IGameSystem::LevelShutdownPostEntity );
|
|
|
|
if ( s_pMapName )
|
|
{
|
|
delete[] s_pMapName;
|
|
s_pMapName = 0;
|
|
}
|
|
}
|
|
|
|
void IGameSystem::OnSaveAllSystems()
|
|
{
|
|
InvokeMethod( &IGameSystem::OnSave );
|
|
}
|
|
|
|
void IGameSystem::OnRestoreAllSystems()
|
|
{
|
|
InvokeMethod( &IGameSystem::OnRestore );
|
|
}
|
|
|
|
void IGameSystem::SafeRemoveIfDesiredAllSystems()
|
|
{
|
|
InvokeMethodReverseOrder( &IGameSystem::SafeRemoveIfDesired );
|
|
}
|
|
|
|
#ifdef CLIENT_DLL
|
|
|
|
void IGameSystem::PreRenderAllSystems()
|
|
{
|
|
VPROF("IGameSystem::PreRenderAllSystems");
|
|
InvokePerFrameMethod( &IGameSystemPerFrame::PreRender );
|
|
}
|
|
|
|
void IGameSystem::UpdateAllSystems( float frametime )
|
|
{
|
|
SafeRemoveIfDesiredAllSystems();
|
|
|
|
int i;
|
|
int c = s_GameSystemsPerFrame.Count();
|
|
for ( i = 0; i < c; ++i )
|
|
{
|
|
IGameSystemPerFrame *sys = s_GameSystemsPerFrame[i];
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
sys->Update( frametime );
|
|
}
|
|
}
|
|
|
|
void IGameSystem::PostRenderAllSystems()
|
|
{
|
|
InvokePerFrameMethod( &IGameSystemPerFrame::PostRender );
|
|
}
|
|
|
|
#else
|
|
|
|
void IGameSystem::FrameUpdatePreEntityThinkAllSystems()
|
|
{
|
|
VPROF("FrameUpdatePreEntityThinkAllSystems");
|
|
InvokePerFrameMethod( &IGameSystemPerFrame::FrameUpdatePreEntityThink );
|
|
}
|
|
|
|
void IGameSystem::FrameUpdatePostEntityThinkAllSystems()
|
|
{
|
|
VPROF("FrameUpdatePostEntityThinkAllSystems");
|
|
SafeRemoveIfDesiredAllSystems();
|
|
|
|
InvokePerFrameMethod( &IGameSystemPerFrame::FrameUpdatePostEntityThink );
|
|
}
|
|
|
|
void IGameSystem::PreClientUpdateAllSystems()
|
|
{
|
|
VPROF("PreClientUpdateAllSystems");
|
|
InvokePerFrameMethod( &IGameSystemPerFrame::PreClientUpdate );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Invokes a method on all installed game systems in proper order
|
|
//-----------------------------------------------------------------------------
|
|
void InvokeMethod( GameSystemFunc_t f, char const *timed /*=0*/ )
|
|
{
|
|
NOTE_UNUSED( timed );
|
|
|
|
int i;
|
|
int c = s_GameSystems.Count();
|
|
for ( i = 0; i < c ; ++i )
|
|
{
|
|
IGameSystem *sys = s_GameSystems[i];
|
|
|
|
MDLCACHE_COARSE_LOCK();
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
|
|
(sys->*f)();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Invokes a method on all installed game systems in proper order
|
|
//-----------------------------------------------------------------------------
|
|
void InvokeMethodTickProgress( GameSystemFunc_t f, char const *timed /*=0*/ )
|
|
{
|
|
NOTE_UNUSED( timed );
|
|
|
|
int i;
|
|
int c = s_GameSystems.Count();
|
|
for ( i = 0; i < c ; ++i )
|
|
{
|
|
IGameSystem *sys = s_GameSystems[i];
|
|
|
|
MDLCACHE_COARSE_LOCK();
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
#if defined( CLIENT_DLL )
|
|
engine->TickProgressBar();
|
|
#endif
|
|
(sys->*f)();
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Invokes a method on all installed game systems in proper order
|
|
//-----------------------------------------------------------------------------
|
|
void InvokePerFrameMethod( PerFrameGameSystemFunc_t f, char const *timed /*=0*/ )
|
|
{
|
|
NOTE_UNUSED( timed );
|
|
|
|
int i;
|
|
int c = s_GameSystemsPerFrame.Count();
|
|
for ( i = 0; i < c ; ++i )
|
|
{
|
|
IGameSystemPerFrame *sys = s_GameSystemsPerFrame[i];
|
|
#if (VPROF_LEVEL > 0) && defined(VPROF_ACCOUNT_GAMESYSTEMS) // make sure each game system is individually attributed
|
|
// because vprof nodes must really be constructed with a pointer to a static
|
|
// string, we can't create a temporary char[] here and sprintf a distinctive
|
|
// V_snprintf( buf, 63, "gamesys_preframe_%s", sys->Name() ). We'll have to
|
|
// settle for just the system name, and distinguish between pre and post frame
|
|
// in hierarchy.
|
|
VPROF( sys->Name() );
|
|
#endif
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
(sys->*f)();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Invokes a method on all installed game systems in reverse order
|
|
//-----------------------------------------------------------------------------
|
|
void InvokeMethodReverseOrder( GameSystemFunc_t f )
|
|
{
|
|
int i;
|
|
int c = s_GameSystems.Count();
|
|
for ( i = c; --i >= 0; )
|
|
{
|
|
IGameSystem *sys = s_GameSystems[i];
|
|
#if (VPROF_LEVEL > 0) && defined(VPROF_ACCOUNT_GAMESYSTEMS) // make sure each game system is individually attributed
|
|
// because vprof nodes must really be constructed with a pointer to a static
|
|
// string, we can't create a temporary char[] here and sprintf a distinctive
|
|
// V_snprintf( buf, 63, "gamesys_preframe_%s", sys->Name() ). We'll have to
|
|
// settle for just the system name, and distinguish between pre and post frame
|
|
// in hierarchy.
|
|
VPROF( sys->Name() );
|
|
#endif
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
(sys->*f)();
|
|
}
|
|
}
|
|
|
|
|