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.

982 lines
29 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Defines a group of app systems that all have the same lifetime
  4. // that need to be connected/initialized, etc. in a well-defined order
  5. //
  6. // $Revision: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "tier0/platform.h"
  10. #include "appframework/ilaunchermgr.h"
  11. #if defined( PLATFORM_PS3)
  12. #include "ps3/ps3_helpers.h"
  13. #endif
  14. #include "tier0/platwindow.h"
  15. #include "appframework/IAppSystemGroup.h"
  16. #include "appframework/iappsystem.h"
  17. #include "interface.h"
  18. #include "filesystem.h"
  19. #include "filesystem_init.h"
  20. #include <algorithm>
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. //-----------------------------------------------------------------------------
  24. // constructor, destructor
  25. //-----------------------------------------------------------------------------
  26. extern ILoggingListener *g_pDefaultLoggingListener;
  27. //-----------------------------------------------------------------------------
  28. // constructor, destructor
  29. //-----------------------------------------------------------------------------
  30. CAppSystemGroup::CAppSystemGroup( CAppSystemGroup *pAppSystemParent ) : m_SystemDict(false, 0, 16)
  31. {
  32. m_pParentAppSystem = pAppSystemParent;
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Actually loads a DLL
  36. //-----------------------------------------------------------------------------
  37. CSysModule *CAppSystemGroup::LoadModuleDLL( const char *pDLLName )
  38. {
  39. return Sys_LoadModule( pDLLName );
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Methods to load + unload DLLs
  43. //-----------------------------------------------------------------------------
  44. AppModule_t CAppSystemGroup::LoadModule( const char *pDLLName )
  45. {
  46. // Remove the extension when creating the name.
  47. int nLen = Q_strlen( pDLLName ) + 1;
  48. char *pModuleName = (char*)stackalloc( nLen );
  49. Q_StripExtension( pDLLName, pModuleName, nLen );
  50. // See if we already loaded it...
  51. for ( int i = m_Modules.Count(); --i >= 0; )
  52. {
  53. if ( m_Modules[i].m_pModuleName )
  54. {
  55. if ( !Q_stricmp( pModuleName, m_Modules[i].m_pModuleName ) )
  56. return i;
  57. }
  58. }
  59. CSysModule *pSysModule = LoadModuleDLL( pDLLName );
  60. if (!pSysModule)
  61. {
  62. #ifdef _X360
  63. Warning("AppFramework : Unable to load module %s! (err #%d)\n", pDLLName, GetLastError() );
  64. #else
  65. Warning("AppFramework : Unable to load module %s!\n", pDLLName );
  66. #endif
  67. return APP_MODULE_INVALID;
  68. }
  69. int nIndex = m_Modules.AddToTail();
  70. m_Modules[nIndex].m_pModule = pSysModule;
  71. m_Modules[nIndex].m_Factory = 0;
  72. m_Modules[nIndex].m_pModuleName = (char*)malloc( nLen );
  73. Q_strncpy( m_Modules[nIndex].m_pModuleName, pModuleName, nLen );
  74. return nIndex;
  75. }
  76. int CAppSystemGroup::ReloadModule( const char * pDLLName )
  77. {
  78. // Remove the extension when creating the name.
  79. int nLen = Q_strlen( pDLLName ) + 1;
  80. char *pModuleName = (char*)stackalloc( nLen );
  81. Q_StripExtension( pDLLName, pModuleName, nLen );
  82. // See if we already loaded it...
  83. for ( int i = m_Modules.Count(); --i >= 0; )
  84. {
  85. Module_t &module = m_Modules[i];
  86. if ( module.m_pModuleName && !Q_stricmp( pModuleName, module.m_pModuleName ) )
  87. {
  88. // found the module, reload
  89. Msg("Unloading module %s, dll %s\n", pModuleName, pDLLName );
  90. Sys_UnloadModule( m_Modules[i].m_pModule );
  91. Msg("Module %s unloaded, reloading\n", pModuleName );
  92. CSysModule *pSysModule = NULL;
  93. CreateInterfaceFn fnFactory = NULL;
  94. while( !pSysModule )
  95. {
  96. pSysModule = LoadModuleDLL( pDLLName );
  97. if( !pSysModule )
  98. {
  99. Warning("Cannot load, retrying in 5 seconds..\n");
  100. ThreadSleep( 5000 );
  101. }
  102. fnFactory = Sys_GetFactory( pSysModule ) ;
  103. if( !fnFactory )
  104. {
  105. Error( "Could not get factory from %s\n", pModuleName );
  106. }
  107. ( *fnFactory )( "Reload Interface", NULL ); // let the CreateInterface function work and do after-reload stuff
  108. }
  109. Msg( "Reload complete, module %p->%p, factory %llx->%llx\n", module.m_pModule, pSysModule, (uint64)(uintp)module.m_Factory, (uint64)(uintp)fnFactory );
  110. module.m_pModule = pSysModule;
  111. if( module.m_Factory )
  112. { // don't reload factory pointer unless it was initialized to non-NULL
  113. module.m_Factory = fnFactory;
  114. }
  115. return 0; // no error
  116. }
  117. }
  118. Warning( "No such module: '%s' in appsystem @%p. Dumping available modules:\n", pModuleName, this );
  119. for ( int i = 0; i < m_Modules.Count(); ++i )
  120. {
  121. Module_t &module = m_Modules[i];
  122. #ifdef _PS3
  123. Msg( "%25s %llx %p %6d %6d bytes\n", module.m_pModuleName, (uint64)module.m_Factory, module.m_pModule, ( ( PS3_PrxLoadParametersBase_t *)module.m_pModule )->sysPrxId, ( ( PS3_PrxLoadParametersBase_t *)module.m_pModule )->cbSize );
  124. #else
  125. Msg("%25s %p %p\n", module.m_pModuleName, (void*)module.m_Factory, module.m_pModule );
  126. #endif
  127. }
  128. return m_pParentAppSystem ? m_pParentAppSystem->ReloadModule( pDLLName ) : -1;
  129. }
  130. AppModule_t CAppSystemGroup::LoadModule( CreateInterfaceFn factory )
  131. {
  132. if (!factory)
  133. {
  134. Warning("AppFramework : Unable to load module %p!\n", factory );
  135. return APP_MODULE_INVALID;
  136. }
  137. // See if we already loaded it...
  138. for ( int i = m_Modules.Count(); --i >= 0; )
  139. {
  140. if ( m_Modules[i].m_Factory )
  141. {
  142. if ( m_Modules[i].m_Factory == factory )
  143. return i;
  144. }
  145. }
  146. int nIndex = m_Modules.AddToTail();
  147. m_Modules[nIndex].m_pModule = NULL;
  148. m_Modules[nIndex].m_Factory = factory;
  149. m_Modules[nIndex].m_pModuleName = NULL;
  150. return nIndex;
  151. }
  152. void CAppSystemGroup::UnloadAllModules()
  153. {
  154. // NOTE: Iterate in reverse order so they are unloaded in opposite order
  155. // from loading
  156. for (int i = m_Modules.Count(); --i >= 0; )
  157. {
  158. if ( m_Modules[i].m_pModule )
  159. {
  160. Sys_UnloadModule( m_Modules[i].m_pModule );
  161. }
  162. if ( m_Modules[i].m_pModuleName )
  163. {
  164. free( m_Modules[i].m_pModuleName );
  165. }
  166. }
  167. m_Modules.RemoveAll();
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Methods to add/remove various global singleton systems
  171. //-----------------------------------------------------------------------------
  172. IAppSystem *CAppSystemGroup::AddSystem( AppModule_t module, const char *pInterfaceName )
  173. {
  174. if (module == APP_MODULE_INVALID)
  175. return NULL;
  176. int nFoundIndex = m_SystemDict.Find( pInterfaceName );
  177. if ( nFoundIndex != m_SystemDict.InvalidIndex() )
  178. {
  179. Warning("AppFramework : Attempted to add two systems with the same interface name %s!\n", pInterfaceName );
  180. return m_Systems[ m_SystemDict[nFoundIndex] ];
  181. }
  182. Assert( (module >= 0) && (module < m_Modules.Count()) );
  183. CreateInterfaceFn pFactory = m_Modules[module].m_pModule ? Sys_GetFactory( m_Modules[module].m_pModule ) : m_Modules[module].m_Factory;
  184. int retval;
  185. void *pSystem = pFactory( pInterfaceName, &retval );
  186. if ((retval != IFACE_OK) || (!pSystem))
  187. {
  188. Warning("AppFramework : Unable to create system %s!\n", pInterfaceName );
  189. return NULL;
  190. }
  191. IAppSystem *pAppSystem = static_cast<IAppSystem*>(pSystem);
  192. int sysIndex = m_Systems.AddToTail( pAppSystem );
  193. // Inserting into the dict will help us do named lookup later
  194. MEM_ALLOC_CREDIT();
  195. m_SystemDict.Insert( pInterfaceName, sysIndex );
  196. return pAppSystem;
  197. }
  198. static const char *g_StageLookup[] =
  199. {
  200. "CREATION",
  201. "LOADING DEPENDENCIES",
  202. "CONNECTION",
  203. "PREINITIALIZATION",
  204. "INITIALIZATION",
  205. "POSTINITIALIZATION",
  206. "RUNNING",
  207. "PRESHUTDOWN",
  208. "SHUTDOWN",
  209. "POSTSHUTDOWN",
  210. "DISCONNECTION",
  211. "DESTRUCTION",
  212. };
  213. void CAppSystemGroup::ReportStartupFailure( int nErrorStage, int nSysIndex )
  214. {
  215. COMPILE_TIME_ASSERT( APPSYSTEM_GROUP_STAGE_COUNT == ARRAYSIZE( g_StageLookup ) );
  216. const char *pszStageDesc = "Unknown";
  217. if ( nErrorStage >= 0 && nErrorStage < ( int )ARRAYSIZE( g_StageLookup ) )
  218. {
  219. pszStageDesc = g_StageLookup[ nErrorStage ];
  220. }
  221. const char *pszSystemName = "(Unknown)";
  222. for ( int i = m_SystemDict.First(); i != m_SystemDict.InvalidIndex(); i = m_SystemDict.Next( i ) )
  223. {
  224. if ( m_SystemDict[ i ] != nSysIndex )
  225. continue;
  226. pszSystemName = m_SystemDict.GetElementName( i );
  227. break;
  228. }
  229. // Walk the dictionary
  230. Warning( "System (%s) failed during stage %s\n", pszSystemName, pszStageDesc );
  231. }
  232. void CAppSystemGroup::AddSystem( IAppSystem *pAppSystem, const char *pInterfaceName )
  233. {
  234. if ( !pAppSystem )
  235. return;
  236. int sysIndex = m_Systems.AddToTail( pAppSystem );
  237. // Inserting into the dict will help us do named lookup later
  238. MEM_ALLOC_CREDIT();
  239. m_SystemDict.Insert( pInterfaceName, sysIndex );
  240. }
  241. void CAppSystemGroup::RemoveAllSystems()
  242. {
  243. // NOTE: There's no deallcation here since we don't really know
  244. // how the allocation has happened. We could add a deallocation method
  245. // to the code in interface.h; although when the modules are unloaded
  246. // the deallocation will happen anyways
  247. m_Systems.RemoveAll();
  248. m_SystemDict.RemoveAll();
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Simpler method of doing the LoadModule/AddSystem thing.
  252. //-----------------------------------------------------------------------------
  253. bool CAppSystemGroup::AddSystems( AppSystemInfo_t *pSystemList )
  254. {
  255. while ( pSystemList->m_pModuleName[0] )
  256. {
  257. AppModule_t module = LoadModule( pSystemList->m_pModuleName );
  258. IAppSystem *pSystem = AddSystem( module, pSystemList->m_pInterfaceName );
  259. if ( !pSystem )
  260. {
  261. Warning( "Unable to load interface %s from %s, requested from EXE.\n", pSystemList->m_pInterfaceName, pSystemList->m_pModuleName );
  262. return false;
  263. }
  264. ++pSystemList;
  265. }
  266. return true;
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Methods to find various global singleton systems
  270. //-----------------------------------------------------------------------------
  271. void *CAppSystemGroup::FindSystem( const char *pSystemName )
  272. {
  273. unsigned short i = m_SystemDict.Find( pSystemName );
  274. if (i != m_SystemDict.InvalidIndex())
  275. return m_Systems[m_SystemDict[i]];
  276. // If it's not an interface we know about, it could be an older
  277. // version of an interface, or maybe something implemented by
  278. // one of the instantiated interfaces...
  279. // QUESTION: What order should we iterate this in?
  280. // It controls who wins if multiple ones implement the same interface
  281. for ( i = 0; i < m_Systems.Count(); ++i )
  282. {
  283. void *pInterface = m_Systems[i]->QueryInterface( pSystemName );
  284. if (pInterface)
  285. return pInterface;
  286. }
  287. int nExternalCount = m_NonAppSystemFactories.Count();
  288. for ( i = 0; i < nExternalCount; ++i )
  289. {
  290. void *pInterface = m_NonAppSystemFactories[i]( pSystemName, NULL );
  291. if (pInterface)
  292. return pInterface;
  293. }
  294. if ( m_pParentAppSystem )
  295. {
  296. void* pInterface = m_pParentAppSystem->FindSystem( pSystemName );
  297. if ( pInterface )
  298. return pInterface;
  299. }
  300. // No dice..
  301. return NULL;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Adds a factory to the system so other stuff can query it. Triggers a connect systems
  305. //-----------------------------------------------------------------------------
  306. void CAppSystemGroup::AddNonAppSystemFactory( CreateInterfaceFn fn )
  307. {
  308. m_NonAppSystemFactories.AddToTail( fn );
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Removes a factory, triggers a disconnect call if it succeeds
  312. //-----------------------------------------------------------------------------
  313. void CAppSystemGroup::RemoveNonAppSystemFactory( CreateInterfaceFn fn )
  314. {
  315. m_NonAppSystemFactories.FindAndRemove( fn );
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Causes the systems to reconnect to an interface
  319. //-----------------------------------------------------------------------------
  320. void CAppSystemGroup::ReconnectSystems( const char *pInterfaceName )
  321. {
  322. // Let the libraries regrab the specified interface
  323. for (int i = 0; i < m_Systems.Count(); ++i )
  324. {
  325. IAppSystem *pSystem = m_Systems[i];
  326. pSystem->Reconnect( GetFactory(), pInterfaceName );
  327. }
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Gets at the parent appsystem group
  331. //-----------------------------------------------------------------------------
  332. CAppSystemGroup *CAppSystemGroup::GetParent()
  333. {
  334. return m_pParentAppSystem;
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Deals with sorting dependencies and finding circular dependencies
  338. //-----------------------------------------------------------------------------
  339. void CAppSystemGroup::ComputeDependencies( LibraryDependencies_t &depend )
  340. {
  341. bool bDone = false;
  342. while ( !bDone )
  343. {
  344. bDone = true;
  345. // If i depends on j, then i depends on what j depends on
  346. // Add secondary dependencies to i. We stop when no dependencies are added
  347. int nCount = depend.GetNumStrings();
  348. for ( int i = 0; i < nCount; ++i )
  349. {
  350. int nDependentCount = depend[i].GetNumStrings();
  351. for ( int j = 0; j < nDependentCount; ++j )
  352. {
  353. int nIndex = depend.Find( depend[i].String( j ) );
  354. if ( nIndex == UTL_INVAL_SYMBOL )
  355. continue;
  356. int nSecondaryDepCount = depend[nIndex].GetNumStrings();
  357. for ( int k = 0; k < nSecondaryDepCount; ++k )
  358. {
  359. // Don't bother if we already contain the secondary dependency
  360. const char *pSecondaryDependency = depend[nIndex].String( k );
  361. if ( depend[i].Find( pSecondaryDependency ) != UTL_INVAL_SYMBOL )
  362. continue;
  363. // Check for circular dependency
  364. if ( !Q_stricmp( pSecondaryDependency, depend.String( i ) ) )
  365. {
  366. Warning( "Encountered a circular dependency with library %s!\n", pSecondaryDependency );
  367. continue;
  368. }
  369. bDone = false;
  370. depend[i].AddString( pSecondaryDependency );
  371. nDependentCount = depend[i].GetNumStrings();
  372. }
  373. }
  374. }
  375. }
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Sorts dependencies
  379. //-----------------------------------------------------------------------------
  380. CAppSystemGroup::LibraryDependencies_t *CAppSystemGroup::sm_pSortDependencies;
  381. bool CAppSystemGroup::SortLessFunc( const int &left, const int &right )
  382. {
  383. const char *pLeftInterface = sm_pSortDependencies->String( left );
  384. const char *pRightInterface = sm_pSortDependencies->String( right );
  385. bool bRightDependsOnLeft = ( (*sm_pSortDependencies)[pRightInterface].Find( pLeftInterface ) != UTL_INVAL_SYMBOL );
  386. return ( bRightDependsOnLeft );
  387. }
  388. void CAppSystemGroup::SortDependentLibraries( LibraryDependencies_t &depend )
  389. {
  390. int nCount = depend.GetNumStrings();
  391. int *pIndices = (int*)stackalloc( depend.GetNumStrings() * sizeof(int) );
  392. for ( int i = 0; i < nCount; ++i )
  393. {
  394. pIndices[i] = i;
  395. }
  396. // Sort by dependency. Can't use fancy stl algorithms here because the sort func isn't strongly transitive.
  397. // Using lame bubble sort instead. We could speed this up using a proper depth-first graph walk, but it's not worth the effort.
  398. sm_pSortDependencies = &depend;
  399. bool bChanged = true;
  400. while ( bChanged )
  401. {
  402. bChanged = false;
  403. for ( int i = 1; i < nCount; i++ )
  404. {
  405. for ( int j = 0; j < i; j++ )
  406. {
  407. if ( SortLessFunc( pIndices[i], pIndices[j] ) )
  408. {
  409. int nTmp = pIndices[i];
  410. pIndices[i] = pIndices[j];
  411. pIndices[j] = nTmp;
  412. bChanged = true;
  413. }
  414. }
  415. }
  416. }
  417. sm_pSortDependencies = NULL;
  418. // This logic will make it so it respects the specified initialization order
  419. // in the face of no dependencies telling the system otherwise.
  420. // Doing this just for safety to reduce the amount of changed code
  421. bool bDone = false;
  422. while ( !bDone )
  423. {
  424. bDone = true;
  425. for ( int i = 1; i < nCount; ++i )
  426. {
  427. int nLeft = pIndices[i-1];
  428. int nRight = pIndices[i];
  429. if ( nRight > nLeft )
  430. continue;
  431. const char *pLeftInterface = depend.String( nLeft );
  432. const char *pRightInterface = depend.String( nRight );
  433. bool bRightDependsOnLeft = ( depend[pRightInterface].Find( pLeftInterface ) != UTL_INVAL_SYMBOL );
  434. if ( bRightDependsOnLeft )
  435. continue;
  436. Assert ( UTL_INVAL_SYMBOL == depend[pRightInterface].Find( pLeftInterface ) );
  437. V_swap( pIndices[i], pIndices[i-1] );
  438. bDone = false;
  439. }
  440. }
  441. // Reorder appsystem list + dictionary indexing
  442. Assert( m_Systems.Count() == nCount );
  443. int nTempSize = nCount * sizeof(IAppSystem*);
  444. IAppSystem **pTemp = (IAppSystem**)stackalloc( nTempSize );
  445. memcpy( pTemp, m_Systems.Base(), nTempSize );
  446. for ( int i = 0; i < nCount; ++i )
  447. {
  448. m_Systems[i] = pTemp[ pIndices[i] ];
  449. }
  450. // Remap system indices
  451. for ( uint16 i = m_SystemDict.First(); i != m_SystemDict.InvalidIndex(); i = m_SystemDict.Next( i ) )
  452. {
  453. int j = 0;
  454. for ( ; j < nCount; ++j )
  455. {
  456. if ( pIndices[j] == m_SystemDict[i] )
  457. {
  458. m_SystemDict[i] = j;
  459. break;
  460. }
  461. }
  462. Assert( j != nCount );
  463. }
  464. ( void )stackfree( pTemp );
  465. ( void )stackfree( pIndices );
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Finds appsystem names
  469. //-----------------------------------------------------------------------------
  470. const char *CAppSystemGroup::FindSystemName( int nIndex )
  471. {
  472. for ( uint16 i = m_SystemDict.First(); i != m_SystemDict.InvalidIndex(); i = m_SystemDict.Next( i ) )
  473. {
  474. if ( m_SystemDict[i] == nIndex )
  475. return m_SystemDict.GetElementName( i );
  476. }
  477. return NULL;
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Method to load all dependent systems
  481. //-----------------------------------------------------------------------------
  482. bool CAppSystemGroup::LoadDependentSystems()
  483. {
  484. LibraryDependencies_t dependencies;
  485. // First, load dependencies.
  486. for ( int i = 0; i < m_Systems.Count(); ++i )
  487. {
  488. IAppSystem *pSystem = m_Systems[i];
  489. const char *pInterfaceName = FindSystemName( i );
  490. dependencies.AddString( pInterfaceName );
  491. const AppSystemInfo_t *pDependencies = pSystem->GetDependencies();
  492. if ( !pDependencies )
  493. continue;
  494. for ( ; pDependencies->m_pInterfaceName && pDependencies->m_pInterfaceName[0]; ++pDependencies )
  495. {
  496. dependencies[ pInterfaceName ].AddString( pDependencies->m_pInterfaceName );
  497. CreateInterfaceFn factory = GetFactory();
  498. if ( factory( pDependencies->m_pInterfaceName, NULL ) )
  499. continue;
  500. AppModule_t module = LoadModule( pDependencies->m_pModuleName );
  501. IAppSystem *pSystem = AddSystem( module, pDependencies->m_pInterfaceName );
  502. if ( !pSystem )
  503. {
  504. Warning( "Unable to load interface %s from %s (Dependency of %s)\n", pDependencies->m_pInterfaceName, pDependencies->m_pModuleName, pInterfaceName );
  505. return false;
  506. }
  507. }
  508. }
  509. ComputeDependencies( dependencies );
  510. SortDependentLibraries( dependencies );
  511. return true;
  512. }
  513. //-----------------------------------------------------------------------------
  514. // Method to connect/disconnect all systems
  515. //-----------------------------------------------------------------------------
  516. bool CAppSystemGroup::ConnectSystems()
  517. {
  518. // Let the libraries grab any other interfaces they may need
  519. for (int i = 0; i < m_Systems.Count(); ++i )
  520. {
  521. IAppSystem *pSystem = m_Systems[i];
  522. if ( !pSystem->Connect( GetFactory() ) )
  523. {
  524. ReportStartupFailure( CONNECTION, i );
  525. return false;
  526. }
  527. }
  528. return true;
  529. }
  530. void CAppSystemGroup::DisconnectSystems()
  531. {
  532. // Disconnect in reverse order of connection
  533. for (int i = m_Systems.Count(); --i >= 0; )
  534. {
  535. m_Systems[i]->Disconnect();
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Method to initialize/shutdown all systems
  540. //-----------------------------------------------------------------------------
  541. InitReturnVal_t CAppSystemGroup::InitSystems()
  542. {
  543. for (int nSystemsInitialized = 0; nSystemsInitialized < m_Systems.Count(); ++nSystemsInitialized )
  544. {
  545. InitReturnVal_t nRetVal = m_Systems[nSystemsInitialized]->Init();
  546. if ( nRetVal != INIT_OK )
  547. {
  548. for( int nSystemsRewind = nSystemsInitialized; nSystemsRewind-->0; )
  549. {
  550. m_Systems[nSystemsRewind]->Shutdown();
  551. }
  552. ReportStartupFailure( INITIALIZATION, nSystemsInitialized );
  553. return nRetVal;
  554. }
  555. }
  556. return INIT_OK;
  557. }
  558. void CAppSystemGroup::ShutdownSystems()
  559. {
  560. // Shutdown in reverse order of initialization
  561. for (int i = m_Systems.Count(); --i >= 0; )
  562. {
  563. m_Systems[i]->Shutdown();
  564. }
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Window management
  568. //-----------------------------------------------------------------------------
  569. void* CAppSystemGroup::CreateAppWindow( void *hInstance, const char *pTitle, bool bWindowed, int w, int h, bool bResizing )
  570. {
  571. #if defined( PLATFORM_WINDOWS ) || defined( PLATFORM_OSX )
  572. int nFlags = 0;
  573. if ( !bWindowed )
  574. {
  575. nFlags |= WINDOW_CREATE_FULLSCREEN;
  576. }
  577. if ( bResizing )
  578. {
  579. nFlags |= WINDOW_CREATE_RESIZING;
  580. }
  581. PlatWindow_t hWnd = Plat_CreateWindow( hInstance, pTitle, w, h, nFlags );
  582. if ( hWnd == PLAT_WINDOW_INVALID )
  583. return NULL;
  584. int CenterX, CenterY;
  585. Plat_GetDesktopResolution( &CenterX, &CenterY );
  586. CenterX = ( CenterX - w ) / 2;
  587. CenterY = ( CenterY - h ) / 2;
  588. CenterX = (CenterX < 0) ? 0: CenterX;
  589. CenterY = (CenterY < 0) ? 0: CenterY;
  590. // In VCR modes, keep it in the upper left so mouse coordinates are always relative to the window.
  591. Plat_SetWindowPos( hWnd, CenterX, CenterY );
  592. return hWnd;
  593. #elif defined( PLATFORM_OSX )
  594. extern ICocoaMgr *g_pCocoaMgr;
  595. g_pCocoaMgr->CreateGameWindow( pTitle, bWindowed, w, h );
  596. return (void*)Sys_GetFactoryThis(); // Other stuff will query for ICocoaBridge out of this.
  597. #elif defined( PLATFORM_LINUX )
  598. #ifndef DEDICATED
  599. // PBTODO
  600. // extern IGLXMgr *g_pGLXMgr;
  601. // g_pGLXMgr->CreateWindow( pTitle, bWindowed, w, h );
  602. return (void*)Sys_GetFactoryThis(); // Other stuff will query for ICocoaBridge out of this.
  603. #endif
  604. #endif
  605. return NULL;
  606. }
  607. void CAppSystemGroup::SetAppWindowTitle( void* hWnd, const char *pTitle )
  608. {
  609. Plat_SetWindowTitle( (PlatWindow_t)hWnd, pTitle );
  610. }
  611. //-----------------------------------------------------------------------------
  612. // Returns the stage at which the app system group ran into an error
  613. //-----------------------------------------------------------------------------
  614. CAppSystemGroup::AppSystemGroupStage_t CAppSystemGroup::GetCurrentStage() const
  615. {
  616. return m_nCurrentStage;
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Gets at a factory that works just like FindSystem
  620. //-----------------------------------------------------------------------------
  621. // This function is used to make this system appear to the outside world to
  622. // function exactly like the currently existing factory system
  623. CAppSystemGroup *s_pCurrentAppSystem;
  624. void *AppSystemCreateInterfaceFn(const char *pName, int *pReturnCode)
  625. {
  626. void *pInterface = s_pCurrentAppSystem->FindSystem( pName );
  627. if ( pReturnCode )
  628. {
  629. *pReturnCode = pInterface ? IFACE_OK : IFACE_FAILED;
  630. }
  631. return pInterface;
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Gets at a class factory for the topmost appsystem group in an appsystem stack
  635. //-----------------------------------------------------------------------------
  636. CreateInterfaceFn CAppSystemGroup::GetFactory()
  637. {
  638. return AppSystemCreateInterfaceFn;
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Main application loop
  642. //-----------------------------------------------------------------------------
  643. int CAppSystemGroup::Run()
  644. {
  645. // The factory now uses this app system group
  646. s_pCurrentAppSystem = this;
  647. // Load, connect, init
  648. int nRetVal = OnStartup();
  649. // NOTE: In case of OnStartup Failure
  650. // On PS/3, not unloading the PRXes in order will cause crashes on quit, which is a TRC failure
  651. // We probably should, but don't have to do this on all platforms, since it's not required to clean-up crash-free.
  652. if ( m_nCurrentStage == RUNNING )
  653. {
  654. // Main loop implemented by the application
  655. // FIXME: HACK workaround to avoid vgui porting
  656. nRetVal = Main();
  657. }
  658. // Shutdown, disconnect, unload
  659. OnShutdown();
  660. // The factory now uses the parent's app system group
  661. s_pCurrentAppSystem = GetParent();
  662. return nRetVal;
  663. }
  664. //-----------------------------------------------------------------------------
  665. // Virtual methods for override
  666. //-----------------------------------------------------------------------------
  667. int CAppSystemGroup::Startup()
  668. {
  669. return OnStartup();
  670. }
  671. void CAppSystemGroup::Shutdown()
  672. {
  673. return OnShutdown();
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Use this version in cases where you can't control the main loop and
  677. // expect to be ticked
  678. //-----------------------------------------------------------------------------
  679. int CAppSystemGroup::OnStartup()
  680. {
  681. // The factory now uses this app system group
  682. s_pCurrentAppSystem = this;
  683. // Call an installed application creation function
  684. m_nCurrentStage = CREATION;
  685. if ( !Create() )
  686. return -1;
  687. // Load dependent libraries
  688. m_nCurrentStage = DEPENDENCIES;
  689. if ( !LoadDependentSystems() )
  690. return -1;
  691. // Let all systems know about each other
  692. m_nCurrentStage = CONNECTION;
  693. if ( !ConnectSystems() )
  694. return -1;
  695. // Allow the application to do some work before init
  696. m_nCurrentStage = PREINITIALIZATION;
  697. if ( !PreInit() )
  698. return -1;
  699. // Call Init on all App Systems
  700. m_nCurrentStage = INITIALIZATION;
  701. int nRetVal = InitSystems();
  702. if ( nRetVal != INIT_OK )
  703. return -1;
  704. m_nCurrentStage = POSTINITIALIZATION;
  705. if ( !PostInit() )
  706. return -1;
  707. m_nCurrentStage = RUNNING;
  708. return nRetVal;
  709. }
  710. void CAppSystemGroup::OnShutdown()
  711. {
  712. // The factory now uses this app system group
  713. s_pCurrentAppSystem = this;
  714. switch( m_nCurrentStage )
  715. {
  716. case RUNNING:
  717. case POSTINITIALIZATION:
  718. break;
  719. case PREINITIALIZATION:
  720. case INITIALIZATION:
  721. goto disconnect;
  722. case CREATION:
  723. case DEPENDENCIES:
  724. case CONNECTION:
  725. goto destroy;
  726. default:
  727. break;
  728. }
  729. // Allow the application to do some work before shutdown
  730. m_nCurrentStage = PRESHUTDOWN;
  731. PreShutdown();
  732. // Cal Shutdown on all App Systems
  733. m_nCurrentStage = SHUTDOWN;
  734. ShutdownSystems();
  735. // Allow the application to do some work after shutdown
  736. m_nCurrentStage = POSTSHUTDOWN;
  737. PostShutdown();
  738. disconnect:
  739. // Systems should disconnect from each other
  740. m_nCurrentStage = DISCONNECTION;
  741. DisconnectSystems();
  742. destroy:
  743. // Unload all DLLs loaded in the AppCreate block
  744. m_nCurrentStage = DESTRUCTION;
  745. RemoveAllSystems();
  746. // Have to do this because the logging listeners & response policies may live in modules which are being unloaded
  747. // @TODO: this seems like a bad legacy practice... app systems should unload their spew handlers gracefully.
  748. LoggingSystem_ResetCurrentLoggingState();
  749. Assert( g_pDefaultLoggingListener != NULL );
  750. LoggingSystem_RegisterLoggingListener( g_pDefaultLoggingListener );
  751. UnloadAllModules();
  752. // Call an installed application destroy function
  753. Destroy();
  754. }
  755. //-----------------------------------------------------------------------------
  756. //
  757. // This class represents a group of app systems that are loaded through steam
  758. //
  759. //-----------------------------------------------------------------------------
  760. //-----------------------------------------------------------------------------
  761. // Constructor
  762. //-----------------------------------------------------------------------------
  763. CSteamAppSystemGroup::CSteamAppSystemGroup( IFileSystem *pFileSystem, CAppSystemGroup *pAppSystemParent )
  764. {
  765. m_pFileSystem = pFileSystem;
  766. m_pGameInfoPath[0] = 0;
  767. }
  768. //-----------------------------------------------------------------------------
  769. // Used by CSteamApplication to set up necessary pointers if we can't do it in the constructor
  770. //-----------------------------------------------------------------------------
  771. void CSteamAppSystemGroup::Setup( IFileSystem *pFileSystem, CAppSystemGroup *pParentAppSystem )
  772. {
  773. m_pFileSystem = pFileSystem;
  774. m_pParentAppSystem = pParentAppSystem;
  775. }
  776. //-----------------------------------------------------------------------------
  777. // Loads the module from Steam
  778. //-----------------------------------------------------------------------------
  779. CSysModule *CSteamAppSystemGroup::LoadModuleDLL( const char *pDLLName )
  780. {
  781. return m_pFileSystem->LoadModule( pDLLName );
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Returns the game info path
  785. //-----------------------------------------------------------------------------
  786. const char *CSteamAppSystemGroup::GetGameInfoPath() const
  787. {
  788. return m_pGameInfoPath;
  789. }
  790. //-----------------------------------------------------------------------------
  791. // Sets up the search paths
  792. //-----------------------------------------------------------------------------
  793. bool CSteamAppSystemGroup::SetupSearchPaths( const char *pStartingDir, bool bOnlyUseStartingDir, bool bIsTool )
  794. {
  795. CFSSteamSetupInfo steamInfo;
  796. steamInfo.m_pDirectoryName = pStartingDir;
  797. steamInfo.m_bOnlyUseDirectoryName = bOnlyUseStartingDir;
  798. steamInfo.m_bToolsMode = bIsTool;
  799. steamInfo.m_bSetSteamDLLPath = true;
  800. steamInfo.m_bSteam = m_pFileSystem->IsSteam();
  801. if ( FileSystem_SetupSteamEnvironment( steamInfo ) != FS_OK )
  802. return false;
  803. CFSMountContentInfo fsInfo;
  804. fsInfo.m_pFileSystem = m_pFileSystem;
  805. fsInfo.m_bToolsMode = bIsTool;
  806. fsInfo.m_pDirectoryName = steamInfo.m_GameInfoPath;
  807. if ( FileSystem_MountContent( fsInfo ) != FS_OK )
  808. return false;
  809. // Finally, load the search paths for the "GAME" path.
  810. CFSSearchPathsInit searchPathsInit;
  811. searchPathsInit.m_pDirectoryName = steamInfo.m_GameInfoPath;
  812. searchPathsInit.m_pFileSystem = fsInfo.m_pFileSystem;
  813. if ( FileSystem_LoadSearchPaths( searchPathsInit ) != FS_OK )
  814. return false;
  815. FileSystem_AddSearchPath_Platform( fsInfo.m_pFileSystem, steamInfo.m_GameInfoPath );
  816. Q_strncpy( m_pGameInfoPath, steamInfo.m_GameInfoPath, sizeof(m_pGameInfoPath) );
  817. return true;
  818. }