System.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : CryENGINE system core-handle all subsystems
  9. #include "CrySystem_precompiled.h"
  10. #include "System.h"
  11. #include <time.h>
  12. #include <AzCore/Console/Console.h>
  13. #include <AzCore/IO/IStreamer.h>
  14. #include <AzCore/IO/SystemFile.h>
  15. #include <AzCore/Debug/Budget.h>
  16. #include <CryPath.h>
  17. #include <CrySystemBus.h>
  18. #include <CryCommon/IFont.h>
  19. #include <CryCommon/MiniQueue.h>
  20. #include <AzFramework/API/ApplicationAPI.h>
  21. #include <AzFramework/API/ApplicationAPI_Platform.h>
  22. #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
  23. #include <AzFramework/Spawnable/RootSpawnableInterface.h>
  24. #include <AzCore/Debug/Profiler.h>
  25. #include <AzCore/Debug/Trace.h>
  26. #include <AzCore/Interface/Interface.h>
  27. #include <AzCore/std/algorithm.h>
  28. #include <AzCore/Time/ITime.h>
  29. #include <AzFramework/Logging/MissingAssetLogger.h>
  30. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  31. #include <AzCore/Interface/Interface.h>
  32. AZ_DEFINE_BUDGET(CrySystem);
  33. #if defined(AZ_RESTRICTED_PLATFORM)
  34. #undef AZ_RESTRICTED_SECTION
  35. #define SYSTEM_CPP_SECTION_1 1
  36. #define SYSTEM_CPP_SECTION_2 2
  37. #define SYSTEM_CPP_SECTION_3 3
  38. #define SYSTEM_CPP_SECTION_4 4
  39. #define SYSTEM_CPP_SECTION_5 5
  40. #define SYSTEM_CPP_SECTION_6 6
  41. #define SYSTEM_CPP_SECTION_7 7
  42. #define SYSTEM_CPP_SECTION_8 8
  43. #define SYSTEM_CPP_SECTION_9 9
  44. #endif
  45. #if defined(_RELEASE) && AZ_LEGACY_CRYSYSTEM_TRAIT_USE_EXCLUDEUPDATE_ON_CONSOLE
  46. //exclude some not needed functionality for release console builds
  47. #define EXCLUDE_UPDATE_ON_CONSOLE
  48. #endif
  49. #ifdef WIN32
  50. #include <AzCore/PlatformIncl.h>
  51. LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  52. {
  53. CSystem* pSystem = 0;
  54. if (gEnv)
  55. {
  56. pSystem = static_cast<CSystem*>(gEnv->pSystem);
  57. }
  58. if (pSystem && !pSystem->IsQuitting())
  59. {
  60. LRESULT result = 0;
  61. bool bAny = false;
  62. for (std::vector<IWindowMessageHandler*>::const_iterator it = pSystem->m_windowMessageHandlers.begin(); it != pSystem->m_windowMessageHandlers.end(); ++it)
  63. {
  64. IWindowMessageHandler* pHandler = *it;
  65. LRESULT maybeResult = 0xDEADDEAD;
  66. if (pHandler->HandleMessage(hWnd, uMsg, wParam, lParam, &maybeResult))
  67. {
  68. assert(maybeResult != 0xDEADDEAD && "Message handler indicated a resulting value, but no value was written");
  69. if (bAny)
  70. {
  71. assert(result == maybeResult && "Two window message handlers tried to return different result values");
  72. }
  73. else
  74. {
  75. bAny = true;
  76. result = maybeResult;
  77. }
  78. }
  79. }
  80. if (bAny)
  81. {
  82. // One of the registered handlers returned something
  83. return result;
  84. }
  85. }
  86. // Handle with the default procedure
  87. assert(IsWindowUnicode(hWnd) && "Window should be Unicode when compiling with UNICODE");
  88. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  89. }
  90. #endif
  91. #if defined(LINUX) && !defined(ANDROID)
  92. #include <execinfo.h> // for backtrace
  93. #endif
  94. #if defined(ANDROID)
  95. #include <unwind.h> // for _Unwind_Backtrace and _Unwind_GetIP
  96. #endif
  97. #if defined(AZ_RESTRICTED_PLATFORM)
  98. #define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_1
  99. #include AZ_RESTRICTED_FILE(System_cpp)
  100. #endif
  101. #include <IRenderer.h>
  102. #include <IMovieSystem.h>
  103. #include <ILog.h>
  104. #include <IAudioSystem.h>
  105. #include <LoadScreenBus.h>
  106. #include <AzFramework/Archive/Archive.h>
  107. #include "XConsole.h"
  108. #include "Log.h"
  109. #include "XML/xml.h"
  110. #include "LocalizedStringManager.h"
  111. #include "XML/XmlUtils.h"
  112. #include "SystemEventDispatcher.h"
  113. #include "RemoteConsole/RemoteConsole.h"
  114. #include <PNoise3.h>
  115. #include <AzFramework/Asset/AssetSystemBus.h>
  116. #include <AzFramework/Input/Buses/Requests/InputSystemRequestBus.h>
  117. #ifdef WIN32
  118. #include <AzFramework/Input/Buses/Notifications/RawInputNotificationBus_Platform.h>
  119. #include <process.h>
  120. #include <malloc.h>
  121. #endif
  122. #include <ILevelSystem.h>
  123. #include <AzFramework/IO/LocalFileIO.h>
  124. // Define global cvars.
  125. SSystemCVars g_cvars;
  126. #include <AzCore/Module/Environment.h>
  127. #include <AzCore/Component/ComponentApplication.h>
  128. #include "AZCoreLogSink.h"
  129. namespace
  130. {
  131. float GetMovieFrameDeltaTime()
  132. {
  133. // Use GetRealTickDeltaTimeUs for CryMovie, because it should not be affected by pausing game time
  134. const AZ::TimeUs delta = AZ::GetRealTickDeltaTimeUs();
  135. return AZ::TimeUsToSeconds(delta);
  136. }
  137. }
  138. /////////////////////////////////////////////////////////////////////////////////
  139. // System Implementation.
  140. //////////////////////////////////////////////////////////////////////////
  141. CSystem::CSystem()
  142. {
  143. CrySystemRequestBus::Handler::BusConnect();
  144. m_systemGlobalState = ESYSTEM_GLOBAL_STATE_UNKNOWN;
  145. m_iHeight = 0;
  146. m_iWidth = 0;
  147. m_iColorBits = 0;
  148. // CRT ALLOCATION threshold
  149. m_bIsAsserting = false;
  150. m_pSystemEventDispatcher = new CSystemEventDispatcher(); // Must be first.
  151. if (m_pSystemEventDispatcher)
  152. {
  153. m_pSystemEventDispatcher->RegisterListener(this);
  154. }
  155. //////////////////////////////////////////////////////////////////////////
  156. // Clear environment.
  157. //////////////////////////////////////////////////////////////////////////
  158. memset(&m_env, 0, sizeof(m_env));
  159. //////////////////////////////////////////////////////////////////////////
  160. // Initialize global environment interface pointers.
  161. m_env.pSystem = this;
  162. m_env.bIgnoreAllAsserts = false;
  163. m_env.bNoAssertDialog = false;
  164. //////////////////////////////////////////////////////////////////////////
  165. m_sysNoUpdate = NULL;
  166. m_pCmdLine = NULL;
  167. m_pLevelSystem = NULL;
  168. m_pLocalizationManager = NULL;
  169. #if defined(AZ_RESTRICTED_PLATFORM)
  170. #define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_2
  171. #include AZ_RESTRICTED_FILE(System_cpp)
  172. #endif
  173. m_pUserCallback = NULL;
  174. m_sys_firstlaunch = NULL;
  175. m_gpu_particle_physics = NULL;
  176. m_bInitializedSuccessfully = false;
  177. m_bRelaunch = false;
  178. m_iLoadingMode = 0;
  179. m_bTestMode = false;
  180. m_bEditor = false;
  181. m_bPreviewMode = false;
  182. m_bIgnoreUpdates = false;
  183. m_bNoCrashDialog = false;
  184. m_bNoErrorReportWindow = false;
  185. m_bInDevMode = false;
  186. m_bGameFolderWritable = false;
  187. m_bPaused = false;
  188. m_bNoUpdate = false;
  189. m_iApplicationInstance = -1;
  190. m_pXMLUtils = new CXmlUtils(this);
  191. m_eRuntimeState = ESYSTEM_EVENT_LEVEL_UNLOAD;
  192. m_bHasRenderedErrorMessage = false;
  193. #if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_MESSAGE_HANDLER
  194. RegisterWindowMessageHandler(this);
  195. #endif
  196. m_ConfigPlatform = CONFIG_INVALID_PLATFORM;
  197. }
  198. /////////////////////////////////////////////////////////////////////////////////
  199. /////////////////////////////////////////////////////////////////////////////////
  200. CSystem::~CSystem()
  201. {
  202. ShutDown();
  203. #if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_MESSAGE_HANDLER
  204. UnregisterWindowMessageHandler(this);
  205. #endif
  206. CRY_ASSERT(m_windowMessageHandlers.empty() && "There exists a dangling window message handler somewhere");
  207. SAFE_DELETE(m_pXMLUtils);
  208. SAFE_DELETE(m_pSystemEventDispatcher);
  209. AZCoreLogSink::Disconnect();
  210. m_env.pSystem = 0;
  211. gEnv = 0;
  212. }
  213. //////////////////////////////////////////////////////////////////////////
  214. void CSystem::Release()
  215. {
  216. delete this;
  217. }
  218. //////////////////////////////////////////////////////////////////////////
  219. IRemoteConsole* CSystem::GetIRemoteConsole()
  220. {
  221. return CRemoteConsole::GetInst();
  222. }
  223. //////////////////////////////////////////////////////////////////////////
  224. void CSystem::SetDevMode(bool bEnable)
  225. {
  226. m_bInDevMode = bEnable;
  227. }
  228. ///////////////////////////////////////////////////
  229. void CSystem::ShutDown()
  230. {
  231. CryLogAlways("System Shutdown");
  232. // Disconnect any networking connections at the beginning of shutting down.
  233. // This needs to happen before unloading the level because the network connection might queue
  234. // references to entities and assets that could prevent cleanup from happening during the level unload.
  235. if (const auto console = AZ::Interface<AZ::IConsole>::Get())
  236. {
  237. console->PerformCommand("disconnect");
  238. }
  239. // On shutdown, we need to start by unloading the level spawnable and processing the spawnable queue
  240. // to clean up any remaining references. Otherwise, we'll get lots of errors on shutdown due to assets still
  241. // being in use as various subsystems get shut down. By the time the spawnable system shuts down, it will try
  242. // to clean up the assets, but the asset handlers for those assets will also be deregistered and destroyed by then,
  243. // causing even more errors.
  244. // By unloading the level before shutting down any subsystems, we can avoid the cascade of errors.
  245. ILevelSystem* levelSystem = GetILevelSystem();
  246. if (levelSystem)
  247. {
  248. levelSystem->UnloadLevel();
  249. if (auto spawnableInterface = AzFramework::RootSpawnableInterface::Get(); spawnableInterface)
  250. {
  251. spawnableInterface->ProcessSpawnableQueueUntilEmpty();
  252. }
  253. }
  254. // don't broadcast OnCrySystemShutdown unless
  255. // we'd previously broadcast OnCrySystemInitialized
  256. if (m_bInitializedSuccessfully)
  257. {
  258. EBUS_EVENT(CrySystemEventBus, OnCrySystemShutdown, *this);
  259. }
  260. if (m_pUserCallback)
  261. {
  262. m_pUserCallback->OnShutdown();
  263. }
  264. if (GetIRemoteConsole()->IsStarted())
  265. {
  266. GetIRemoteConsole()->Stop();
  267. }
  268. if (m_sys_firstlaunch)
  269. {
  270. m_sys_firstlaunch->Set("0");
  271. }
  272. if ((m_bEditor) && (m_env.pConsole))
  273. {
  274. // restore the old saved cvars
  275. if (m_env.pConsole->GetCVar("r_Width"))
  276. {
  277. m_env.pConsole->GetCVar("r_Width")->Set(m_iWidth);
  278. }
  279. if (m_env.pConsole->GetCVar("r_Height"))
  280. {
  281. m_env.pConsole->GetCVar("r_Height")->Set(m_iHeight);
  282. }
  283. if (m_env.pConsole->GetCVar("r_ColorBits"))
  284. {
  285. m_env.pConsole->GetCVar("r_ColorBits")->Set(m_iColorBits);
  286. }
  287. }
  288. if (m_bEditor && !m_bRelaunch)
  289. {
  290. SaveConfiguration();
  291. }
  292. // Dispatch the full-shutdown event in case this is not a fast-shutdown.
  293. if (m_pSystemEventDispatcher != NULL)
  294. {
  295. m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_FULL_SHUTDOWN, 0, 0);
  296. }
  297. SAFE_RELEASE(m_env.pMovieSystem);
  298. SAFE_RELEASE(m_env.pCryFont);
  299. if (m_env.pConsole)
  300. {
  301. ((CXConsole*)m_env.pConsole)->FreeRenderResources();
  302. }
  303. SAFE_RELEASE(m_pLevelSystem);
  304. if (m_env.pLog)
  305. {
  306. m_env.pLog->UnregisterConsoleVariables();
  307. }
  308. GetIRemoteConsole()->UnregisterConsoleVariables();
  309. // Release console variables.
  310. SAFE_RELEASE(m_sys_firstlaunch);
  311. #if defined(AZ_RESTRICTED_PLATFORM)
  312. #define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_3
  313. #include AZ_RESTRICTED_FILE(System_cpp)
  314. #endif
  315. SAFE_DELETE(m_pLocalizationManager);
  316. delete m_pCmdLine;
  317. m_pCmdLine = 0;
  318. // Audio System Shutdown!
  319. // Shut down audio as late as possible but before the streaming system and console get released!
  320. Audio::Gem::SystemRequestBus::Broadcast(&Audio::Gem::SystemRequestBus::Events::Release);
  321. // Shut down console as late as possible and after audio!
  322. SAFE_RELEASE(m_env.pConsole);
  323. // Log must be last thing released.
  324. if (m_env.pLog)
  325. {
  326. m_env.pLog->Flush();
  327. }
  328. SAFE_RELEASE(m_env.pLog); // creates log backup
  329. ShutdownFileSystem();
  330. EBUS_EVENT(CrySystemEventBus, OnCrySystemPostShutdown);
  331. }
  332. /////////////////////////////////////////////////////////////////////////////////
  333. /////////////////////////////////////////////////////////////////////////////////
  334. void CSystem::Quit()
  335. {
  336. CryLogAlways("CSystem::Quit invoked from thread %" PRI_THREADID " (main is %" PRI_THREADID ")", GetCurrentThreadId(), gEnv->mMainThreadId);
  337. AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
  338. // If this was set from anywhere but the main thread, bail and let the main thread handle shutdown
  339. if (GetCurrentThreadId() != gEnv->mMainThreadId)
  340. {
  341. return;
  342. }
  343. if (m_pUserCallback)
  344. {
  345. m_pUserCallback->OnQuit();
  346. }
  347. gEnv->pLog->Flush();
  348. #ifdef WIN32
  349. //Post a WM_QUIT message to the Win32 api which causes the message loop to END
  350. //This is not the same as handling a WM_DESTROY event which destroys a window
  351. //but keeps the message loop alive.
  352. PostQuitMessage(0);
  353. #endif
  354. }
  355. /////////////////////////////////////////////////////////////////////////////////
  356. /////////////////////////////////////////////////////////////////////////////////
  357. bool CSystem::IsQuitting() const
  358. {
  359. bool wasExitMainLoopRequested = false;
  360. AzFramework::ApplicationRequests::Bus::BroadcastResult(wasExitMainLoopRequested, &AzFramework::ApplicationRequests::WasExitMainLoopRequested);
  361. return wasExitMainLoopRequested;
  362. }
  363. //////////////////////////////////////////////////////////////////////////
  364. ISystem* CSystem::GetCrySystem()
  365. {
  366. return this;
  367. }
  368. //////////////////////////////////////////////////////////////////////////
  369. void CSystem::SleepIfNeeded()
  370. {
  371. static bool firstCall = true;
  372. typedef MiniQueue<CTimeValue, 32> PrevNow;
  373. static PrevNow prevNow;
  374. if (firstCall)
  375. {
  376. const AZ::TimeMs timeMs = AZ::GetRealElapsedTimeMs();
  377. const double timeSec = AZ::TimeMsToSecondsDouble(timeMs);
  378. m_lastTickTime = CTimeValue(timeSec);
  379. prevNow.Push(m_lastTickTime);
  380. firstCall = false;
  381. return;
  382. }
  383. const float maxRate = m_svDedicatedMaxRate->GetFVal();
  384. const float minTime = 1.0f / maxRate;
  385. const AZ::TimeMs nowTimeMs = AZ::GetRealElapsedTimeMs();
  386. const double nowTimeSec = AZ::TimeMsToSecondsDouble(nowTimeMs);
  387. const CTimeValue now = CTimeValue(nowTimeSec);
  388. const float elapsed = (now - m_lastTickTime).GetSeconds();
  389. if (prevNow.Full())
  390. {
  391. prevNow.Pop();
  392. }
  393. prevNow.Push(now);
  394. static bool allowStallCatchup = true;
  395. if (elapsed > minTime && allowStallCatchup)
  396. {
  397. allowStallCatchup = false;
  398. const AZ::TimeMs lastTimeMs = AZ::GetRealElapsedTimeMs();
  399. const double lastTimeSec = AZ::TimeMsToSecondsDouble(lastTimeMs);
  400. m_lastTickTime = CTimeValue(lastTimeSec);
  401. return;
  402. }
  403. allowStallCatchup = true;
  404. float totalElapsed = (now - prevNow.Front()).GetSeconds();
  405. float wantSleepTime = AZStd::clamp(minTime * (prevNow.Size() - 1) - totalElapsed, 0.0f, (minTime - elapsed) * 0.9f);
  406. static float sleepTime = 0;
  407. sleepTime = (15 * sleepTime + wantSleepTime) / 16;
  408. int sleepMS = (int)(1000.0f * sleepTime + 0.5f);
  409. if (sleepMS > 0)
  410. {
  411. AZ_PROFILE_FUNCTION(CrySystem);
  412. Sleep(sleepMS);
  413. }
  414. const AZ::TimeMs lastTimeMs = AZ::GetRealElapsedTimeMs();
  415. const double lastTimeSec = AZ::TimeMsToSecondsDouble(lastTimeMs);
  416. m_lastTickTime = CTimeValue(lastTimeSec);
  417. }
  418. extern DWORD g_idDebugThreads[];
  419. extern int g_nDebugThreads;
  420. int prev_sys_float_exceptions = -1;
  421. //////////////////////////////////////////////////////////////////////
  422. bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
  423. {
  424. // If we detect the quit flag at the start of Update, that means it was set
  425. // from another thread, and we should quit immediately. Otherwise, it will
  426. // be set by game logic or the console during Update and we will quit later
  427. if (IsQuitting())
  428. {
  429. Quit();
  430. return false;
  431. }
  432. #ifndef EXCLUDE_UPDATE_ON_CONSOLE
  433. // do the dedicated sleep earlier than the frame profiler to avoid having it counted
  434. if (gEnv->IsDedicated())
  435. {
  436. SleepIfNeeded();
  437. }
  438. #endif //EXCLUDE_UPDATE_ON_CONSOLE
  439. #ifdef WIN32
  440. // enable/disable SSE fp exceptions (#nan and /0)
  441. // need to do it each frame since sometimes they are being reset
  442. _mm_setcsr(_mm_getcsr() & ~0x280 | (g_cvars.sys_float_exceptions > 0 ? 0 : 0x280));
  443. #endif //WIN32
  444. AZ_PROFILE_FUNCTION(CrySystem);
  445. #ifndef EXCLUDE_UPDATE_ON_CONSOLE
  446. if (m_pUserCallback)
  447. {
  448. m_pUserCallback->OnUpdate();
  449. }
  450. //////////////////////////////////////////////////////////////////////////
  451. // Enable/Disable floating exceptions.
  452. //////////////////////////////////////////////////////////////////////////
  453. prev_sys_float_exceptions += 1 + g_cvars.sys_float_exceptions & prev_sys_float_exceptions >> 31;
  454. if (prev_sys_float_exceptions != g_cvars.sys_float_exceptions)
  455. {
  456. prev_sys_float_exceptions = g_cvars.sys_float_exceptions;
  457. EnableFloatExceptions(g_cvars.sys_float_exceptions);
  458. }
  459. #endif //EXCLUDE_UPDATE_ON_CONSOLE
  460. //////////////////////////////////////////////////////////////////////////
  461. if (m_env.pLog)
  462. {
  463. m_env.pLog->Update();
  464. }
  465. #ifdef USE_REMOTE_CONSOLE
  466. GetIRemoteConsole()->Update();
  467. #endif
  468. if (nPauseMode != 0)
  469. {
  470. m_bPaused = true;
  471. }
  472. else
  473. {
  474. m_bPaused = false;
  475. }
  476. #ifndef EXCLUDE_UPDATE_ON_CONSOLE
  477. if (m_bIgnoreUpdates)
  478. {
  479. return true;
  480. }
  481. #endif //EXCLUDE_UPDATE_ON_CONSOLE
  482. //static bool sbPause = false;
  483. //bool bPause = false;
  484. bool bNoUpdate = false;
  485. #ifndef EXCLUDE_UPDATE_ON_CONSOLE
  486. if (m_sysNoUpdate && m_sysNoUpdate->GetIVal())
  487. {
  488. bNoUpdate = true;
  489. }
  490. m_bNoUpdate = bNoUpdate;
  491. #endif //EXCLUDE_UPDATE_ON_CONSOLE
  492. //check if we are quitting from the game
  493. if (IsQuitting())
  494. {
  495. Quit();
  496. return (false);
  497. }
  498. //limit frame rate if vsync is turned off
  499. //for consoles this is done inside renderthread to be vsync dependent
  500. {
  501. static ICVar* pSysMaxFPS = NULL;
  502. static ICVar* pVSync = NULL;
  503. if (pSysMaxFPS == NULL && gEnv && gEnv->pConsole)
  504. {
  505. pSysMaxFPS = gEnv->pConsole->GetCVar("sys_MaxFPS");
  506. }
  507. if (pVSync == NULL && gEnv && gEnv->pConsole)
  508. {
  509. pVSync = gEnv->pConsole->GetCVar("vsync_interval");
  510. }
  511. if (pSysMaxFPS && pVSync)
  512. {
  513. int32 maxFPS = pSysMaxFPS->GetIVal();
  514. uint32 vSync = pVSync->GetIVal();
  515. if (maxFPS == 0 && vSync == 0)
  516. {
  517. ILevelSystem* pLvlSys = GetILevelSystem();
  518. const bool inLevel = pLvlSys && pLvlSys->IsLevelLoaded();
  519. maxFPS = !inLevel || IsPaused() ? 60 : 0;
  520. }
  521. if (maxFPS > 0 && vSync == 0)
  522. {
  523. const float safeMarginFPS = 0.5f;//save margin to not drop below 30 fps
  524. static AZ::TimeMs sTimeLast = AZ::GetRealElapsedTimeMs();
  525. const AZ::TimeMs timeFrameMax(static_cast<AZ::TimeMs>(
  526. (int64)(1000.f / ((float)maxFPS + safeMarginFPS))
  527. ));
  528. const AZ::TimeMs timeLast = timeFrameMax + sTimeLast;
  529. while (timeLast > AZ::GetRealElapsedTimeMs())
  530. {
  531. CrySleep(0);
  532. }
  533. sTimeLast = AZ::GetRealElapsedTimeMs();
  534. }
  535. }
  536. }
  537. //////////////////////////////////////////////////////////////////////
  538. //update console system
  539. if (m_env.pConsole)
  540. {
  541. m_env.pConsole->Update();
  542. }
  543. if (IsQuitting())
  544. {
  545. Quit();
  546. return false;
  547. }
  548. // Run movie system pre-update
  549. if (!bNoUpdate)
  550. {
  551. UpdateMovieSystem(updateFlags, GetMovieFrameDeltaTime(), true);
  552. }
  553. return !IsQuitting();
  554. }
  555. //////////////////////////////////////////////////////////////////////
  556. bool CSystem::UpdatePostTickBus(int updateFlags, int /*nPauseMode*/)
  557. {
  558. const AZ::TimeMs updateStartTimeMs = AZ::GetRealElapsedTimeMs();
  559. const double updateStartTimeSec = AZ::TimeMsToSecondsDouble(updateStartTimeMs);
  560. const CTimeValue updateStart(updateStartTimeSec);
  561. // Run movie system post-update
  562. if (!m_bNoUpdate)
  563. {
  564. UpdateMovieSystem(updateFlags, GetMovieFrameDeltaTime(), false);
  565. }
  566. //////////////////////////////////////////////////////////////////////
  567. // Update sound system
  568. if (!m_bNoUpdate)
  569. {
  570. UpdateAudioSystems();
  571. }
  572. //Now update frame statistics
  573. const AZ::TimeMs curTimeMs = AZ::GetRealElapsedTimeMs();
  574. const double curTimeSec = AZ::TimeMsToSecondsDouble(curTimeMs);
  575. const CTimeValue cur_time(curTimeSec);
  576. CTimeValue a_second(g_cvars.sys_update_profile_time);
  577. std::vector< std::pair<CTimeValue, float> >::iterator it = m_updateTimes.begin();
  578. for (std::vector< std::pair<CTimeValue, float> >::iterator eit = m_updateTimes.end(); it != eit; ++it)
  579. {
  580. if ((cur_time - it->first) < a_second)
  581. {
  582. break;
  583. }
  584. }
  585. {
  586. if (it != m_updateTimes.begin())
  587. {
  588. m_updateTimes.erase(m_updateTimes.begin(), it);
  589. }
  590. float updateTime = (cur_time - updateStart).GetMilliSeconds();
  591. m_updateTimes.push_back(std::make_pair(cur_time, updateTime));
  592. }
  593. m_pSystemEventDispatcher->Update();
  594. if (!gEnv->IsEditing() && m_eRuntimeState == ESYSTEM_EVENT_LEVEL_GAMEPLAY_START)
  595. {
  596. gEnv->pCryPak->DisableRuntimeFileAccess(true);
  597. }
  598. // Also broadcast for anyone else that needs to draw global debug to do so now
  599. AzFramework::DebugDisplayEventBus::Broadcast(&AzFramework::DebugDisplayEvents::DrawGlobalDebugInfo);
  600. return !IsQuitting();
  601. }
  602. bool CSystem::UpdateLoadtime()
  603. {
  604. return !IsQuitting();
  605. }
  606. void CSystem::UpdateAudioSystems()
  607. {
  608. if (auto audioSystem = AZ::Interface<Audio::IAudioSystem>::Get(); audioSystem != nullptr)
  609. {
  610. audioSystem->ExternalUpdate();
  611. }
  612. }
  613. //////////////////////////////////////////////////////////////////////////
  614. void CSystem::GetUpdateStats(SSystemUpdateStats& stats)
  615. {
  616. if (m_updateTimes.empty())
  617. {
  618. stats = SSystemUpdateStats();
  619. }
  620. else
  621. {
  622. stats.avgUpdateTime = 0;
  623. stats.maxUpdateTime = -FLT_MAX;
  624. stats.minUpdateTime = +FLT_MAX;
  625. for (std::vector< std::pair<CTimeValue, float> >::const_iterator it = m_updateTimes.begin(), eit = m_updateTimes.end(); it != eit; ++it)
  626. {
  627. const float t = it->second;
  628. stats.avgUpdateTime += t;
  629. stats.maxUpdateTime = max(stats.maxUpdateTime, t);
  630. stats.minUpdateTime = min(stats.minUpdateTime, t);
  631. }
  632. stats.avgUpdateTime /= m_updateTimes.size();
  633. }
  634. }
  635. //////////////////////////////////////////////////////////////////////////
  636. void CSystem::UpdateMovieSystem(const int updateFlags, const float fFrameTime, const bool bPreUpdate)
  637. {
  638. if (m_env.pMovieSystem && !(updateFlags & ESYSUPDATE_EDITOR) && g_cvars.sys_trackview)
  639. {
  640. float fMovieFrameTime = fFrameTime;
  641. if (fMovieFrameTime > g_cvars.sys_maxTimeStepForMovieSystem)
  642. {
  643. fMovieFrameTime = g_cvars.sys_maxTimeStepForMovieSystem;
  644. }
  645. if (bPreUpdate)
  646. {
  647. m_env.pMovieSystem->PreUpdate(fMovieFrameTime);
  648. }
  649. else
  650. {
  651. m_env.pMovieSystem->PostUpdate(fMovieFrameTime);
  652. }
  653. }
  654. }
  655. //////////////////////////////////////////////////////////////////////////
  656. // XML stuff
  657. //////////////////////////////////////////////////////////////////////////
  658. //////////////////////////////////////////////////////////////////////////
  659. XmlNodeRef CSystem::CreateXmlNode(const char* sNodeName, bool bReuseStrings, bool bIsProcessingInstruction)
  660. {
  661. return new CXmlNode(sNodeName, bReuseStrings, bIsProcessingInstruction);
  662. }
  663. //////////////////////////////////////////////////////////////////////////
  664. IXmlUtils* CSystem::GetXmlUtils()
  665. {
  666. return m_pXMLUtils;
  667. }
  668. //////////////////////////////////////////////////////////////////////////
  669. XmlNodeRef CSystem::LoadXmlFromFile(const char* sFilename, bool bReuseStrings)
  670. {
  671. return m_pXMLUtils->LoadXmlFromFile(sFilename, bReuseStrings);
  672. }
  673. //////////////////////////////////////////////////////////////////////////
  674. XmlNodeRef CSystem::LoadXmlFromBuffer(const char* buffer, size_t size, bool bReuseStrings, bool bSuppressWarnings)
  675. {
  676. return m_pXMLUtils->LoadXmlFromBuffer(buffer, size, bReuseStrings, bSuppressWarnings);
  677. }
  678. //////////////////////////////////////////////////////////////////////////
  679. bool CSystem::CheckLogVerbosity(int verbosity)
  680. {
  681. if (verbosity <= m_env.pLog->GetVerbosityLevel())
  682. {
  683. return true;
  684. }
  685. return false;
  686. }
  687. //////////////////////////////////////////////////////////////////////////
  688. void CSystem::Warning(EValidatorModule module, EValidatorSeverity severity, int flags, const char* file, const char* format, ...)
  689. {
  690. va_list args;
  691. va_start(args, format);
  692. WarningV(module, severity, flags, file, format, args);
  693. va_end(args);
  694. }
  695. //////////////////////////////////////////////////////////////////////////
  696. void CSystem::ShowMessage(const char* text, const char* caption, unsigned int uType)
  697. {
  698. if (m_pUserCallback)
  699. {
  700. m_pUserCallback->ShowMessage(text, caption, uType);
  701. }
  702. else
  703. {
  704. CryMessageBox(text, caption, uType);
  705. }
  706. }
  707. inline const char* ValidatorModuleToString(EValidatorModule module)
  708. {
  709. switch (module)
  710. {
  711. case VALIDATOR_MODULE_RENDERER:
  712. return "Renderer";
  713. case VALIDATOR_MODULE_3DENGINE:
  714. return "3DEngine";
  715. case VALIDATOR_MODULE_ASSETS:
  716. return "Assets";
  717. case VALIDATOR_MODULE_SYSTEM:
  718. return "System";
  719. case VALIDATOR_MODULE_AUDIO:
  720. return "Audio";
  721. case VALIDATOR_MODULE_MOVIE:
  722. return "Movie";
  723. case VALIDATOR_MODULE_EDITOR:
  724. return "Editor";
  725. case VALIDATOR_MODULE_NETWORK:
  726. return "Network";
  727. case VALIDATOR_MODULE_PHYSICS:
  728. return "Physics";
  729. case VALIDATOR_MODULE_ONLINE:
  730. return "Online";
  731. case VALIDATOR_MODULE_FEATURETESTS:
  732. return "FeatureTests";
  733. case VALIDATOR_MODULE_SHINE:
  734. return "UI";
  735. }
  736. return "";
  737. }
  738. //////////////////////////////////////////////////////////////////////////
  739. void CSystem::WarningV(EValidatorModule module, EValidatorSeverity severity, int flags, const char* file, const char* format, va_list args)
  740. {
  741. // Fran: No logging in a testing environment
  742. if (m_env.pLog == 0)
  743. {
  744. return;
  745. }
  746. const char* sModuleFilter = m_env.pLog->GetModuleFilter();
  747. if (sModuleFilter && *sModuleFilter != 0)
  748. {
  749. const char* sModule = ValidatorModuleToString(module);
  750. if (strlen(sModule) > 1 || AZ::StringFunc::Find(sModule, sModuleFilter) == AZStd::string::npos)
  751. {
  752. // Filter out warnings from other modules.
  753. return;
  754. }
  755. }
  756. bool bDbgBreak = false;
  757. if (severity == VALIDATOR_ERROR_DBGBRK)
  758. {
  759. bDbgBreak = true;
  760. severity = VALIDATOR_ERROR; // change it to a standard VALIDATOR_ERROR for simplicity in the rest of the system
  761. }
  762. IMiniLog::ELogType ltype = ILog::eComment;
  763. switch (severity)
  764. {
  765. case VALIDATOR_ERROR:
  766. ltype = ILog::eError;
  767. break;
  768. case VALIDATOR_WARNING:
  769. ltype = ILog::eWarning;
  770. break;
  771. case VALIDATOR_COMMENT:
  772. ltype = ILog::eComment;
  773. break;
  774. default:
  775. break;
  776. }
  777. AZStd::fixed_string<MAX_WARNING_LENGTH> fmt;
  778. vsnprintf_s(fmt.data(), MAX_WARNING_LENGTH, MAX_WARNING_LENGTH - 1, format, args);
  779. if (file && *file)
  780. {
  781. fmt += " [File=";
  782. fmt += file;
  783. fmt += "]";
  784. }
  785. m_env.pLog->LogWithType(ltype, flags | VALIDATOR_FLAG_SKIP_VALIDATOR, "%s", fmt.c_str());
  786. if (bDbgBreak && g_cvars.sys_error_debugbreak)
  787. {
  788. AZ::Debug::Trace::Instance().Break();
  789. }
  790. }
  791. //////////////////////////////////////////////////////////////////////////
  792. void CSystem::GetLocalizedPath(const char* sLanguage, AZStd::string& sLocalizedPath)
  793. {
  794. // Omit the trailing slash!
  795. AZStd::string sLocalizationFolder(PathUtil::GetLocalizationFolder());
  796. sLocalizationFolder.pop_back();
  797. int locFormat = 0;
  798. LocalizationManagerRequestBus::BroadcastResult(locFormat, &LocalizationManagerRequestBus::Events::GetLocalizationFormat);
  799. if(locFormat == 1)
  800. {
  801. sLocalizedPath = sLocalizationFolder + "/" + sLanguage + ".loc.agsxml";
  802. }
  803. else
  804. {
  805. if (AZ::StringFunc::Equal(sLocalizationFolder, "Languages", false))
  806. {
  807. sLocalizedPath = sLocalizationFolder + "/" + sLanguage + "_xml.pak";
  808. }
  809. else
  810. {
  811. sLocalizedPath = AZStd::string("Localized/") + sLanguage + "_xml.pak";
  812. }
  813. }
  814. }
  815. //////////////////////////////////////////////////////////////////////////
  816. void CSystem::GetLocalizedAudioPath(const char* sLanguage, AZStd::string& sLocalizedPath)
  817. {
  818. // Omit the trailing slash!
  819. AZStd::string sLocalizationFolder(PathUtil::GetLocalizationFolder());
  820. sLocalizationFolder.pop_back();
  821. if (AZ::StringFunc::Equal(sLocalizationFolder, "Languages", false))
  822. {
  823. sLocalizedPath = sLocalizationFolder + "/" + sLanguage + ".pak";
  824. }
  825. else
  826. {
  827. sLocalizedPath = AZStd::string("Localized/") + sLanguage + ".pak";
  828. }
  829. }
  830. //////////////////////////////////////////////////////////////////////////
  831. void CSystem::CloseLanguagePak(const char* sLanguage)
  832. {
  833. AZStd::string sLocalizedPath;
  834. GetLocalizedPath(sLanguage, sLocalizedPath);
  835. m_env.pCryPak->ClosePacks({ sLocalizedPath.c_str(), sLocalizedPath.size() });
  836. }
  837. //////////////////////////////////////////////////////////////////////////
  838. void CSystem::CloseLanguageAudioPak(const char* sLanguage)
  839. {
  840. AZStd::string sLocalizedPath;
  841. GetLocalizedAudioPath(sLanguage, sLocalizedPath);
  842. m_env.pCryPak->ClosePacks({ sLocalizedPath.c_str(), sLocalizedPath.size() });
  843. }
  844. //////////////////////////////////////////////////////////////////////////
  845. void CSystem::Relaunch(bool bRelaunch)
  846. {
  847. if (m_sys_firstlaunch)
  848. {
  849. m_sys_firstlaunch->Set("0");
  850. }
  851. m_bRelaunch = bRelaunch;
  852. SaveConfiguration();
  853. }
  854. //////////////////////////////////////////////////////////////////////////
  855. ILocalizationManager* CSystem::GetLocalizationManager()
  856. {
  857. return m_pLocalizationManager;
  858. }
  859. //////////////////////////////////////////////////////////////////////////
  860. void CSystem::ExecuteCommandLine(bool deferred)
  861. {
  862. if (m_executedCommandLine)
  863. {
  864. return;
  865. }
  866. m_executedCommandLine = true;
  867. // execute command line arguments e.g. +g_gametype ASSAULT +LoadLevel "testy"
  868. ICmdLine* pCmdLine = GetICmdLine();
  869. assert(pCmdLine);
  870. const int iCnt = pCmdLine->GetArgCount();
  871. for (int i = 0; i < iCnt; ++i)
  872. {
  873. const ICmdLineArg* pCmd = pCmdLine->GetArg(i);
  874. if (pCmd->GetType() == eCLAT_Post)
  875. {
  876. AZStd::string sLine = pCmd->GetName();
  877. {
  878. if (pCmd->GetValue())
  879. {
  880. sLine += AZStd::string(" ") + pCmd->GetValue();
  881. }
  882. GetILog()->Log("Executing command from command line: \n%s\n", sLine.c_str()); // - the actual command might be executed much later (e.g. level load pause)
  883. GetIConsole()->ExecuteString(sLine.c_str(), false, deferred);
  884. }
  885. }
  886. }
  887. //gEnv->pConsole->ExecuteString("sys_RestoreSpec test*"); // to get useful debugging information about current spec settings to the log file
  888. }
  889. //////////////////////////////////////////////////////////////////////////
  890. void CSystem::SetConfigPlatform(const ESystemConfigPlatform platform)
  891. {
  892. m_ConfigPlatform = platform;
  893. }
  894. //////////////////////////////////////////////////////////////////////////
  895. ESystemConfigPlatform CSystem::GetConfigPlatform() const
  896. {
  897. return m_ConfigPlatform;
  898. }
  899. //////////////////////////////////////////////////////////////////////////
  900. CPNoise3* CSystem::GetNoiseGen()
  901. {
  902. static CPNoise3 m_pNoiseGen;
  903. return &m_pNoiseGen;
  904. }
  905. //////////////////////////////////////////////////////////////////////
  906. void CSystem::OnLanguageCVarChanged(ICVar* language)
  907. {
  908. if (language && language->GetType() == CVAR_STRING)
  909. {
  910. CSystem* pSys = static_cast<CSystem*>(gEnv->pSystem);
  911. if (pSys && pSys->GetLocalizationManager())
  912. {
  913. const char* lang = language->GetString();
  914. // Hook up Localization initialization
  915. int locFormat = 0;
  916. LocalizationManagerRequestBus::BroadcastResult(locFormat, &LocalizationManagerRequestBus::Events::GetLocalizationFormat);
  917. if (locFormat == 0)
  918. {
  919. const char* locLanguage = nullptr;
  920. LocalizationManagerRequestBus::BroadcastResult(locLanguage, &LocalizationManagerRequestBus::Events::GetLanguage);
  921. pSys->OpenLanguagePak(lang);
  922. }
  923. LocalizationManagerRequestBus::Broadcast(&LocalizationManagerRequestBus::Events::SetLanguage, lang);
  924. LocalizationManagerRequestBus::Broadcast(&LocalizationManagerRequestBus::Events::ReloadData);
  925. }
  926. }
  927. }
  928. //////////////////////////////////////////////////////////////////////////
  929. void CSystem::OnLocalizationFolderCVarChanged(ICVar* const pLocalizationFolder)
  930. {
  931. if (pLocalizationFolder && pLocalizationFolder->GetType() == CVAR_STRING)
  932. {
  933. CSystem* const pSystem = static_cast<CSystem* const>(gEnv->pSystem);
  934. if (pSystem != NULL && gEnv->pCryPak != NULL)
  935. {
  936. CLocalizedStringsManager* const pLocalizationManager = static_cast<CLocalizedStringsManager* const>(pSystem->GetLocalizationManager());
  937. if (pLocalizationManager)
  938. {
  939. // Get what is currently loaded
  940. CLocalizedStringsManager::TLocalizationTagVec tagVec;
  941. pLocalizationManager->GetLoadedTags(tagVec);
  942. // Release the old localization data.
  943. CLocalizedStringsManager::TLocalizationTagVec::const_iterator end = tagVec.end();
  944. for (CLocalizedStringsManager::TLocalizationTagVec::const_iterator it = tagVec.begin(); it != end; ++it)
  945. {
  946. pLocalizationManager->ReleaseLocalizationDataByTag(it->c_str());
  947. }
  948. // Close the paks situated in the previous localization folder.
  949. pSystem->CloseLanguagePak(pLocalizationManager->GetLanguage());
  950. pSystem->CloseLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());
  951. // Set the new localization folder.
  952. gEnv->pCryPak->SetLocalizationFolder(pLocalizationFolder->GetString());
  953. // Now open the paks situated in the new localization folder.
  954. pSystem->OpenLanguagePak(pLocalizationManager->GetLanguage());
  955. pSystem->OpenLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());
  956. // And load the new data.
  957. for (CLocalizedStringsManager::TLocalizationTagVec::const_iterator it = tagVec.begin(); it != end; ++it)
  958. {
  959. pLocalizationManager->LoadLocalizationDataByTag(it->c_str());
  960. }
  961. }
  962. }
  963. }
  964. }
  965. // Catch changes to assert verbosity and update the global used to track it
  966. void CSystem::SetAssertLevel(int _assertlevel)
  967. {
  968. AZ::EnvironmentVariable<int> assertVerbosityLevel = AZ::Environment::FindVariable<int>("assertVerbosityLevel");
  969. if (assertVerbosityLevel)
  970. {
  971. assertVerbosityLevel.Set(_assertlevel);
  972. }
  973. }
  974. void CSystem::OnAssertLevelCvarChanged(ICVar* pArgs)
  975. {
  976. SetAssertLevel(pArgs->GetIVal());
  977. }
  978. void CSystem::SetLogLevel(int _loglevel)
  979. {
  980. AZ::EnvironmentVariable<int> logVerbosityLevel = AZ::Environment::FindVariable<int>("sys_LogLevel");
  981. if (logVerbosityLevel.IsConstructed())
  982. {
  983. logVerbosityLevel.Set(_loglevel);
  984. }
  985. }
  986. void CSystem::OnLogLevelCvarChanged(ICVar* pArgs)
  987. {
  988. if (pArgs)
  989. {
  990. SetLogLevel(pArgs->GetIVal());
  991. }
  992. }
  993. void CSystem::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
  994. {
  995. switch (event)
  996. {
  997. case ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN:
  998. case ESYSTEM_EVENT_LEVEL_UNLOAD:
  999. gEnv->pCryPak->DisableRuntimeFileAccess(false);
  1000. case ESYSTEM_EVENT_LEVEL_GAMEPLAY_START:
  1001. m_eRuntimeState = event;
  1002. break;
  1003. }
  1004. }
  1005. ESystemGlobalState CSystem::GetSystemGlobalState(void)
  1006. {
  1007. return m_systemGlobalState;
  1008. }
  1009. const char* CSystem::GetSystemGlobalStateName(const ESystemGlobalState systemGlobalState)
  1010. {
  1011. static const char* const s_systemGlobalStateNames[] = {
  1012. "UNKNOWN", // ESYSTEM_GLOBAL_STATE_UNKNOWN,
  1013. "INIT", // ESYSTEM_GLOBAL_STATE_INIT,
  1014. "RUNNING", // ESYSTEM_GLOBAL_STATE_RUNNING,
  1015. "LEVEL_LOAD_PREPARE", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PREPARE,
  1016. "LEVEL_LOAD_START", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START,
  1017. "LEVEL_LOAD_MATERIALS", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_MATERIALS,
  1018. "LEVEL_LOAD_OBJECTS", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_OBJECTS,
  1019. "LEVEL_LOAD_STATIC_WORLD", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_STATIC_WORLD,
  1020. "LEVEL_LOAD_PRECACHE", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PRECACHE,
  1021. "LEVEL_LOAD_TEXTURES", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_TEXTURES,
  1022. "LEVEL_LOAD_END", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END,
  1023. "LEVEL_LOAD_COMPLETE" // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE
  1024. };
  1025. const size_t numElements = sizeof(s_systemGlobalStateNames) / sizeof(s_systemGlobalStateNames[0]);
  1026. const size_t index = (size_t)systemGlobalState;
  1027. if (index >= numElements)
  1028. {
  1029. return "INVALID INDEX";
  1030. }
  1031. return s_systemGlobalStateNames[index];
  1032. }
  1033. void CSystem::SetSystemGlobalState(const ESystemGlobalState systemGlobalState)
  1034. {
  1035. static AZ::TimeMs s_startTime = AZ::Time::ZeroTimeMs;
  1036. if (systemGlobalState != m_systemGlobalState)
  1037. {
  1038. const AZ::TimeMs endTime = AZ::GetRealElapsedTimeMs();
  1039. [[maybe_unused]] const double numSeconds = AZ::TimeMsToSecondsDouble(endTime - s_startTime);
  1040. CryLog("SetGlobalState %d->%d '%s'->'%s' %3.1f seconds",
  1041. m_systemGlobalState, systemGlobalState,
  1042. CSystem::GetSystemGlobalStateName(m_systemGlobalState), CSystem::GetSystemGlobalStateName(systemGlobalState),
  1043. numSeconds);
  1044. s_startTime = AZ::GetRealElapsedTimeMs();
  1045. }
  1046. m_systemGlobalState = systemGlobalState;
  1047. #if AZ_LOADSCREENCOMPONENT_ENABLED
  1048. if (m_systemGlobalState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE)
  1049. {
  1050. EBUS_EVENT(LoadScreenBus, Stop);
  1051. }
  1052. #endif // if AZ_LOADSCREENCOMPONENT_ENABLED
  1053. }
  1054. //////////////////////////////////////////////////////////////////////////
  1055. void CSystem::RegisterWindowMessageHandler(IWindowMessageHandler* pHandler)
  1056. {
  1057. #if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_MESSAGE_HANDLER
  1058. assert(pHandler && !stl::find(m_windowMessageHandlers, pHandler) && "This IWindowMessageHandler is already registered");
  1059. m_windowMessageHandlers.push_back(pHandler);
  1060. #else
  1061. CRY_ASSERT(false && "This platform does not support window message handlers");
  1062. #endif
  1063. }
  1064. //////////////////////////////////////////////////////////////////////////
  1065. void CSystem::UnregisterWindowMessageHandler(IWindowMessageHandler* pHandler)
  1066. {
  1067. #if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_MESSAGE_HANDLER
  1068. [[maybe_unused]] bool bRemoved = stl::find_and_erase(m_windowMessageHandlers, pHandler);
  1069. assert(pHandler && bRemoved && "This IWindowMessageHandler was not registered");
  1070. #else
  1071. CRY_ASSERT(false && "This platform does not support window message handlers");
  1072. #endif
  1073. }
  1074. //////////////////////////////////////////////////////////////////////////
  1075. #if defined(WIN32)
  1076. bool CSystem::HandleMessage([[maybe_unused]] HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  1077. {
  1078. static bool sbInSizingModalLoop;
  1079. int x = LOWORD(lParam);
  1080. int y = HIWORD(lParam);
  1081. *pResult = 0;
  1082. switch (uMsg)
  1083. {
  1084. // System event translation
  1085. case WM_CLOSE:
  1086. /*
  1087. Trigger CSystem to call Quit() the next time
  1088. it calls Update(). HandleMessages can get messages
  1089. pumped to it from SyncMainWithRender which would
  1090. be called recurively by Quit(). Doing so would
  1091. cause the render thread to deadlock and the main
  1092. thread to spin in SRenderThread::WaitFlushFinishedCond.
  1093. */
  1094. AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
  1095. return false;
  1096. case WM_MOVE:
  1097. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_MOVE, x, y);
  1098. return false;
  1099. case WM_SIZE:
  1100. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RESIZE, x, y);
  1101. switch (wParam)
  1102. {
  1103. case SIZE_MINIMIZED:
  1104. EBUS_EVENT(AzFramework::WindowsLifecycleEvents::Bus, OnMinimized);
  1105. break;
  1106. case SIZE_MAXIMIZED:
  1107. EBUS_EVENT(AzFramework::WindowsLifecycleEvents::Bus, OnMaximized);
  1108. break;
  1109. case SIZE_RESTORED:
  1110. EBUS_EVENT(AzFramework::WindowsLifecycleEvents::Bus, OnRestored);
  1111. break;
  1112. }
  1113. return false;
  1114. case WM_WINDOWPOSCHANGED:
  1115. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_POS_CHANGED, 1, 0);
  1116. return false;
  1117. case WM_STYLECHANGED:
  1118. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_STYLE_CHANGED, 1, 0);
  1119. return false;
  1120. case WM_ACTIVATE:
  1121. // Pass HIWORD(wParam) as well to indicate whether this window is minimized or not
  1122. // HIWORD(wParam) != 0 is minimized, HIWORD(wParam) == 0 is not minimized
  1123. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_ACTIVATE, LOWORD(wParam) != WA_INACTIVE, HIWORD(wParam));
  1124. return true;
  1125. case WM_SETFOCUS:
  1126. EBUS_EVENT(AzFramework::WindowsLifecycleEvents::Bus, OnSetFocus);
  1127. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_CHANGE_FOCUS, 1, 0);
  1128. return false;
  1129. case WM_KILLFOCUS:
  1130. EBUS_EVENT(AzFramework::WindowsLifecycleEvents::Bus, OnKillFocus);
  1131. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_CHANGE_FOCUS, 0, 0);
  1132. return false;
  1133. case WM_INPUTLANGCHANGE:
  1134. GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LANGUAGE_CHANGE, wParam, lParam);
  1135. return false;
  1136. case WM_SYSCOMMAND:
  1137. if ((wParam & 0xFFF0) == SC_SCREENSAVE)
  1138. {
  1139. // Check if screen saver is allowed
  1140. IConsole* const pConsole = gEnv->pConsole;
  1141. const ICVar* const pVar = pConsole ? pConsole->GetCVar("sys_screensaver_allowed") : 0;
  1142. return pVar && pVar->GetIVal() == 0;
  1143. }
  1144. return false;
  1145. // Mouse activation
  1146. case WM_MOUSEACTIVATE:
  1147. *pResult = MA_ACTIVATEANDEAT;
  1148. return true;
  1149. // Hardware mouse counters
  1150. case WM_ENTERSIZEMOVE:
  1151. sbInSizingModalLoop = true;
  1152. // Fall through intended
  1153. case WM_ENTERMENULOOP:
  1154. {
  1155. return true;
  1156. }
  1157. case WM_CAPTURECHANGED:
  1158. // If WM_CAPTURECHANGED is received after WM_ENTERSIZEMOVE (ie, moving/resizing begins).
  1159. // but no matching WM_EXITSIZEMOVE is received (this can happen if the window is not actually moved).
  1160. // we still need to decrement the hardware mouse counter that was incremented when WM_ENTERSIZEMOVE was seen.
  1161. // So in this case, we effectively treat WM_CAPTURECHANGED as if it was the WM_EXITSIZEMOVE message.
  1162. // This behavior has only been reproduced the window is deactivated during the modal loop (ie, breakpoint triggered and focus moves to VS).
  1163. case WM_EXITSIZEMOVE:
  1164. if (!sbInSizingModalLoop)
  1165. {
  1166. return false;
  1167. }
  1168. sbInSizingModalLoop = false;
  1169. // Fall through intended
  1170. case WM_EXITMENULOOP:
  1171. {
  1172. return (uMsg != WM_CAPTURECHANGED);
  1173. }
  1174. case WM_SYSKEYUP:
  1175. case WM_SYSKEYDOWN:
  1176. {
  1177. const bool bAlt = (lParam & (1 << 29)) != 0;
  1178. if (bAlt && wParam == VK_F4)
  1179. {
  1180. return false; // Pass though ALT+F4
  1181. }
  1182. // Prevent game from entering menu loop! Editor does allow menu loop.
  1183. return !m_bEditor;
  1184. }
  1185. case WM_INPUT:
  1186. {
  1187. UINT rawInputSize;
  1188. const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER);
  1189. GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize);
  1190. AZStd::array<BYTE, sizeof(RAWINPUT)> rawInputBytesArray;
  1191. LPBYTE rawInputBytes = rawInputBytesArray.data();
  1192. [[maybe_unused]] const UINT bytesCopied = GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
  1193. CRY_ASSERT(bytesCopied == rawInputSize);
  1194. [[maybe_unused]] RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
  1195. CRY_ASSERT(rawInput);
  1196. AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput);
  1197. return false;
  1198. }
  1199. case WM_DEVICECHANGE:
  1200. {
  1201. if (wParam == 0x0007) // DBT_DEVNODES_CHANGED
  1202. {
  1203. AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent);
  1204. }
  1205. return true;
  1206. }
  1207. case WM_CHAR:
  1208. {
  1209. const unsigned short codeUnitUTF16 = static_cast<unsigned short>(wParam);
  1210. AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputCodeUnitUTF16Event, codeUnitUTF16);
  1211. return true;
  1212. }
  1213. // Any other event doesn't interest us
  1214. default:
  1215. return false;
  1216. }
  1217. }
  1218. #endif
  1219. ILevelSystem* CSystem::GetILevelSystem()
  1220. {
  1221. return m_pLevelSystem;
  1222. }
  1223. #undef EXCLUDE_UPDATE_ON_CONSOLE