summaryrefslogtreecommitdiff
path: root/appframework/AppSystemGroup.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /appframework/AppSystemGroup.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'appframework/AppSystemGroup.cpp')
-rw-r--r--appframework/AppSystemGroup.cpp573
1 files changed, 573 insertions, 0 deletions
diff --git a/appframework/AppSystemGroup.cpp b/appframework/AppSystemGroup.cpp
new file mode 100644
index 0000000..196bd80
--- /dev/null
+++ b/appframework/AppSystemGroup.cpp
@@ -0,0 +1,573 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Defines a group of app systems that all have the same lifetime
+// that need to be connected/initialized, etc. in a well-defined order
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "appframework/IAppSystemGroup.h"
+#include "appframework/IAppSystem.h"
+#include "interface.h"
+#include "filesystem.h"
+#include "filesystem_init.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+//extern ILoggingListener *g_pDefaultLoggingListener;
+
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+CAppSystemGroup::CAppSystemGroup( CAppSystemGroup *pAppSystemParent ) : m_SystemDict(false, 0, 16)
+{
+ m_pParentAppSystem = pAppSystemParent;
+}
+
+
+//-----------------------------------------------------------------------------
+// Actually loads a DLL
+//-----------------------------------------------------------------------------
+CSysModule *CAppSystemGroup::LoadModuleDLL( const char *pDLLName )
+{
+ return Sys_LoadModule( pDLLName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods to load + unload DLLs
+//-----------------------------------------------------------------------------
+AppModule_t CAppSystemGroup::LoadModule( const char *pDLLName )
+{
+ // Remove the extension when creating the name.
+ int nLen = Q_strlen( pDLLName ) + 1;
+ char *pModuleName = (char*)stackalloc( nLen );
+ Q_StripExtension( pDLLName, pModuleName, nLen );
+
+ // See if we already loaded it...
+ for ( int i = m_Modules.Count(); --i >= 0; )
+ {
+ if ( m_Modules[i].m_pModuleName )
+ {
+ if ( !Q_stricmp( pModuleName, m_Modules[i].m_pModuleName ) )
+ return i;
+ }
+ }
+
+ CSysModule *pSysModule = LoadModuleDLL( pDLLName );
+ if (!pSysModule)
+ {
+ Warning("AppFramework : Unable to load module %s!\n", pDLLName );
+ return APP_MODULE_INVALID;
+ }
+
+ int nIndex = m_Modules.AddToTail();
+ m_Modules[nIndex].m_pModule = pSysModule;
+ m_Modules[nIndex].m_Factory = 0;
+ m_Modules[nIndex].m_pModuleName = (char*)malloc( nLen );
+ Q_strncpy( m_Modules[nIndex].m_pModuleName, pModuleName, nLen );
+
+ return nIndex;
+}
+
+AppModule_t CAppSystemGroup::LoadModule( CreateInterfaceFn factory )
+{
+ if (!factory)
+ {
+ Warning("AppFramework : Unable to load module %p!\n", factory );
+ return APP_MODULE_INVALID;
+ }
+
+ // See if we already loaded it...
+ for ( int i = m_Modules.Count(); --i >= 0; )
+ {
+ if ( m_Modules[i].m_Factory )
+ {
+ if ( m_Modules[i].m_Factory == factory )
+ return i;
+ }
+ }
+
+ int nIndex = m_Modules.AddToTail();
+ m_Modules[nIndex].m_pModule = NULL;
+ m_Modules[nIndex].m_Factory = factory;
+ m_Modules[nIndex].m_pModuleName = NULL;
+ return nIndex;
+}
+
+void CAppSystemGroup::UnloadAllModules()
+{
+ // NOTE: Iterate in reverse order so they are unloaded in opposite order
+ // from loading
+ for (int i = m_Modules.Count(); --i >= 0; )
+ {
+ if ( m_Modules[i].m_pModule )
+ {
+ Sys_UnloadModule( m_Modules[i].m_pModule );
+ }
+ if ( m_Modules[i].m_pModuleName )
+ {
+ free( m_Modules[i].m_pModuleName );
+ }
+ }
+ m_Modules.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods to add/remove various global singleton systems
+//-----------------------------------------------------------------------------
+IAppSystem *CAppSystemGroup::AddSystem( AppModule_t module, const char *pInterfaceName )
+{
+ if (module == APP_MODULE_INVALID)
+ return NULL;
+
+ Assert( (module >= 0) && (module < m_Modules.Count()) );
+ CreateInterfaceFn pFactory = m_Modules[module].m_pModule ? Sys_GetFactory( m_Modules[module].m_pModule ) : m_Modules[module].m_Factory;
+
+ int retval;
+ void *pSystem = pFactory( pInterfaceName, &retval );
+ if ((retval != IFACE_OK) || (!pSystem))
+ {
+ Warning("AppFramework : Unable to create system %s!\n", pInterfaceName );
+ return NULL;
+ }
+
+ IAppSystem *pAppSystem = static_cast<IAppSystem*>(pSystem);
+
+ int sysIndex = m_Systems.AddToTail( pAppSystem );
+
+ // Inserting into the dict will help us do named lookup later
+ MEM_ALLOC_CREDIT();
+ m_SystemDict.Insert( pInterfaceName, sysIndex );
+ return pAppSystem;
+}
+
+static char const *g_StageLookup[] =
+{
+ "CREATION",
+ "CONNECTION",
+ "PREINITIALIZATION",
+ "INITIALIZATION",
+ "SHUTDOWN",
+ "POSTSHUTDOWN",
+ "DISCONNECTION",
+ "DESTRUCTION",
+ "NONE",
+};
+
+void CAppSystemGroup::ReportStartupFailure( int nErrorStage, int nSysIndex )
+{
+ char const *pszStageDesc = "Unknown";
+ if ( nErrorStage >= 0 && nErrorStage < ARRAYSIZE( g_StageLookup ) )
+ {
+ pszStageDesc = g_StageLookup[ nErrorStage ];
+ }
+
+ char const *pszSystemName = "(Unknown)";
+ for ( int i = m_SystemDict.First(); i != m_SystemDict.InvalidIndex(); i = m_SystemDict.Next( i ) )
+ {
+ if ( m_SystemDict[ i ] != nSysIndex )
+ continue;
+
+ pszSystemName = m_SystemDict.GetElementName( i );
+ break;
+ }
+
+ // Walk the dictionary
+ Warning( "System (%s) failed during stage %s\n", pszSystemName, pszStageDesc );
+}
+
+void CAppSystemGroup::AddSystem( IAppSystem *pAppSystem, const char *pInterfaceName )
+{
+ if ( !pAppSystem )
+ return;
+
+ int sysIndex = m_Systems.AddToTail( pAppSystem );
+
+ // Inserting into the dict will help us do named lookup later
+ MEM_ALLOC_CREDIT();
+ m_SystemDict.Insert( pInterfaceName, sysIndex );
+}
+
+void CAppSystemGroup::RemoveAllSystems()
+{
+ // NOTE: There's no deallcation here since we don't really know
+ // how the allocation has happened. We could add a deallocation method
+ // to the code in interface.h; although when the modules are unloaded
+ // the deallocation will happen anyways
+ m_Systems.RemoveAll();
+ m_SystemDict.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Simpler method of doing the LoadModule/AddSystem thing.
+//-----------------------------------------------------------------------------
+bool CAppSystemGroup::AddSystems( AppSystemInfo_t *pSystemList )
+{
+ while ( pSystemList->m_pModuleName[0] )
+ {
+ AppModule_t module = LoadModule( pSystemList->m_pModuleName );
+ IAppSystem *pSystem = AddSystem( module, pSystemList->m_pInterfaceName );
+ if ( !pSystem )
+ {
+ Warning( "Unable to load interface %s from %s\n", pSystemList->m_pInterfaceName, pSystemList->m_pModuleName );
+ return false;
+ }
+ ++pSystemList;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods to find various global singleton systems
+//-----------------------------------------------------------------------------
+void *CAppSystemGroup::FindSystem( const char *pSystemName )
+{
+ unsigned short i = m_SystemDict.Find( pSystemName );
+ if (i != m_SystemDict.InvalidIndex())
+ return m_Systems[m_SystemDict[i]];
+
+ // If it's not an interface we know about, it could be an older
+ // version of an interface, or maybe something implemented by
+ // one of the instantiated interfaces...
+
+ // QUESTION: What order should we iterate this in?
+ // It controls who wins if multiple ones implement the same interface
+ for ( i = 0; i < m_Systems.Count(); ++i )
+ {
+ void *pInterface = m_Systems[i]->QueryInterface( pSystemName );
+ if (pInterface)
+ return pInterface;
+ }
+
+ if ( m_pParentAppSystem )
+ {
+ void* pInterface = m_pParentAppSystem->FindSystem( pSystemName );
+ if ( pInterface )
+ return pInterface;
+ }
+
+ // No dice..
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at the parent appsystem group
+//-----------------------------------------------------------------------------
+CAppSystemGroup *CAppSystemGroup::GetParent()
+{
+ return m_pParentAppSystem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Method to connect/disconnect all systems
+//-----------------------------------------------------------------------------
+bool CAppSystemGroup::ConnectSystems()
+{
+ for (int i = 0; i < m_Systems.Count(); ++i )
+ {
+ IAppSystem *sys = m_Systems[i];
+
+ if (!sys->Connect( GetFactory() ))
+ {
+ ReportStartupFailure( CONNECTION, i );
+ return false;
+ }
+ }
+ return true;
+}
+
+void CAppSystemGroup::DisconnectSystems()
+{
+ // Disconnect in reverse order of connection
+ for (int i = m_Systems.Count(); --i >= 0; )
+ {
+ m_Systems[i]->Disconnect();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Method to initialize/shutdown all systems
+//-----------------------------------------------------------------------------
+InitReturnVal_t CAppSystemGroup::InitSystems()
+{
+ for (int i = 0; i < m_Systems.Count(); ++i )
+ {
+ InitReturnVal_t nRetVal = m_Systems[i]->Init();
+ if ( nRetVal != INIT_OK )
+ {
+ ReportStartupFailure( INITIALIZATION, i );
+ return nRetVal;
+ }
+ }
+ return INIT_OK;
+}
+
+void CAppSystemGroup::ShutdownSystems()
+{
+ // Shutdown in reverse order of initialization
+ for (int i = m_Systems.Count(); --i >= 0; )
+ {
+ m_Systems[i]->Shutdown();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the stage at which the app system group ran into an error
+//-----------------------------------------------------------------------------
+CAppSystemGroup::AppSystemGroupStage_t CAppSystemGroup::GetErrorStage() const
+{
+ return m_nErrorStage;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at a factory that works just like FindSystem
+//-----------------------------------------------------------------------------
+// This function is used to make this system appear to the outside world to
+// function exactly like the currently existing factory system
+CAppSystemGroup *s_pCurrentAppSystem;
+void *AppSystemCreateInterfaceFn(const char *pName, int *pReturnCode)
+{
+ void *pInterface = s_pCurrentAppSystem->FindSystem( pName );
+ if ( pReturnCode )
+ {
+ *pReturnCode = pInterface ? IFACE_OK : IFACE_FAILED;
+ }
+ return pInterface;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at a class factory for the topmost appsystem group in an appsystem stack
+//-----------------------------------------------------------------------------
+CreateInterfaceFn CAppSystemGroup::GetFactory()
+{
+ return AppSystemCreateInterfaceFn;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main application loop
+//-----------------------------------------------------------------------------
+int CAppSystemGroup::Run()
+{
+ // The factory now uses this app system group
+ s_pCurrentAppSystem = this;
+
+ // Load, connect, init
+ int nRetVal = OnStartup();
+ if ( m_nErrorStage != NONE )
+ return nRetVal;
+
+ // Main loop implemented by the application
+ // FIXME: HACK workaround to avoid vgui porting
+ nRetVal = Main();
+
+ // Shutdown, disconnect, unload
+ OnShutdown();
+
+ // The factory now uses the parent's app system group
+ s_pCurrentAppSystem = GetParent();
+
+ return nRetVal;
+}
+
+
+//-----------------------------------------------------------------------------
+// Virtual methods for override
+//-----------------------------------------------------------------------------
+int CAppSystemGroup::Startup()
+{
+ return OnStartup();
+}
+
+void CAppSystemGroup::Shutdown()
+{
+ return OnShutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Use this version in cases where you can't control the main loop and
+// expect to be ticked
+//-----------------------------------------------------------------------------
+int CAppSystemGroup::OnStartup()
+{
+ // The factory now uses this app system group
+ s_pCurrentAppSystem = this;
+
+ m_nErrorStage = NONE;
+
+ // Call an installed application creation function
+ if ( !Create() )
+ {
+ m_nErrorStage = CREATION;
+ return -1;
+ }
+
+ // Let all systems know about each other
+ if ( !ConnectSystems() )
+ {
+ m_nErrorStage = CONNECTION;
+ return -1;
+ }
+
+ // Allow the application to do some work before init
+ if ( !PreInit() )
+ {
+ m_nErrorStage = PREINITIALIZATION;
+ return -1;
+ }
+
+ // Call Init on all App Systems
+ int nRetVal = InitSystems();
+ if ( nRetVal != INIT_OK )
+ {
+ m_nErrorStage = INITIALIZATION;
+ return -1;
+ }
+
+ return nRetVal;
+}
+
+void CAppSystemGroup::OnShutdown()
+{
+ // The factory now uses this app system group
+ s_pCurrentAppSystem = this;
+
+ switch( m_nErrorStage )
+ {
+ case NONE:
+ break;
+
+ case PREINITIALIZATION:
+ case INITIALIZATION:
+ goto disconnect;
+
+ case CREATION:
+ case CONNECTION:
+ goto destroy;
+ }
+
+ // Cal Shutdown on all App Systems
+ ShutdownSystems();
+
+ // Allow the application to do some work after shutdown
+ PostShutdown();
+
+disconnect:
+ // Systems should disconnect from each other
+ DisconnectSystems();
+
+destroy:
+ // Unload all DLLs loaded in the AppCreate block
+ RemoveAllSystems();
+
+ // Have to do this because the logging listeners & response policies may live in modules which are being unloaded
+ // @TODO: this seems like a bad legacy practice... app systems should unload their spew handlers gracefully.
+// LoggingSystem_ResetCurrentLoggingState();
+// Assert( g_pDefaultLoggingListener != NULL );
+// LoggingSystem_RegisterLoggingListener( g_pDefaultLoggingListener );
+
+ UnloadAllModules();
+
+ // Call an installed application destroy function
+ Destroy();
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// This class represents a group of app systems that are loaded through steam
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CSteamAppSystemGroup::CSteamAppSystemGroup( IFileSystem *pFileSystem, CAppSystemGroup *pAppSystemParent )
+{
+ m_pFileSystem = pFileSystem;
+ m_pGameInfoPath[0] = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used by CSteamApplication to set up necessary pointers if we can't do it in the constructor
+//-----------------------------------------------------------------------------
+void CSteamAppSystemGroup::Setup( IFileSystem *pFileSystem, CAppSystemGroup *pParentAppSystem )
+{
+ m_pFileSystem = pFileSystem;
+ m_pParentAppSystem = pParentAppSystem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the module from Steam
+//-----------------------------------------------------------------------------
+CSysModule *CSteamAppSystemGroup::LoadModuleDLL( const char *pDLLName )
+{
+ return m_pFileSystem->LoadModule( pDLLName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the game info path
+//-----------------------------------------------------------------------------
+const char *CSteamAppSystemGroup::GetGameInfoPath() const
+{
+ return m_pGameInfoPath;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the search paths
+//-----------------------------------------------------------------------------
+bool CSteamAppSystemGroup::SetupSearchPaths( const char *pStartingDir, bool bOnlyUseStartingDir, bool bIsTool )
+{
+ CFSSteamSetupInfo steamInfo;
+ steamInfo.m_pDirectoryName = pStartingDir;
+ steamInfo.m_bOnlyUseDirectoryName = bOnlyUseStartingDir;
+ steamInfo.m_bToolsMode = bIsTool;
+ steamInfo.m_bSetSteamDLLPath = true;
+ steamInfo.m_bSteam = m_pFileSystem->IsSteam();
+ if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
+ return false;
+
+ CFSMountContentInfo fsInfo;
+ fsInfo.m_pFileSystem = m_pFileSystem;
+ fsInfo.m_bToolsMode = bIsTool;
+ fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
+
+ if ( FileSystem_MountContent( fsInfo ) != FS_OK )
+ return false;
+
+ // Finally, load the search paths for the "GAME" path.
+ CFSSearchPathsInit searchPathsInit;
+ searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath;
+ searchPathsInit.m_pFileSystem = fsInfo.m_pFileSystem;
+ if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
+ return false;
+
+ FileSystem_AddSearchPath_Platform( fsInfo.m_pFileSystem, steamInfo.m_GameInfoPath );
+ Q_strncpy( m_pGameInfoPath, steamInfo.m_GameInfoPath, sizeof(m_pGameInfoPath) );
+ return true;
+}