!F (Profiling) (DEV-7030) Rewrite of the profiling system to have a unified interface...
[CRYENGINE.git] / Code / CryEngine / CrySystem / System.cpp
blob17c0783448d8d872e565e5f7af5ee3c99b355aa9
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "System.h"
5 #include <time.h>
6 //#include "ini_vars.h"
7 #include <CryCore/Platform/CryLibrary.h>
9 #if defined(_RELEASE) && CRY_PLATFORM_DURANGO //note: check if orbis needs this
10 //exclude some not needed functionality for release console builds
11 #define EXCLUDE_UPDATE_ON_CONSOLE
12 #endif
14 #if CRY_PLATFORM_LINUX
15 #include <execinfo.h> // for backtrace
16 #endif
18 #if CRY_PLATFORM_ANDROID
19 #include <unwind.h> // for _Unwind_Backtrace and _Unwind_GetIP
20 #endif
22 #include <CryNetwork/INetwork.h>
23 #include <Cry3DEngine/I3DEngine.h>
24 #include <CryAISystem/IAISystem.h>
25 #include <CryRenderer/IRenderer.h>
26 #include <CrySystem/File/ICryPak.h>
27 #include <CryMovie/IMovieSystem.h>
28 #include <ServiceNetwork.h>
29 #include <CryEntitySystem/IEntitySystem.h>
30 #include <CryInput/IInput.h>
31 #include <CrySystem/ILog.h>
32 #include <CryAudio/IAudioSystem.h>
33 #include <CryAnimation/ICryAnimation.h>
34 #include <CryScriptSystem/IScriptSystem.h>
35 #include <CrySystem/IProcess.h>
36 #include <CrySystem/IBudgetingSystem.h>
37 #include <CryGame/IGameFramework.h>
38 #include <CryNetwork/INotificationNetwork.h>
39 #include <CrySystem/ICodeCheckpointMgr.h>
40 #include <CrySystem/Profilers/IStatoscope.h>
41 #ifdef CRY_TESTING
42 #include "TestSystem.h"
43 #endif // CRY_TESTING
44 #include "VisRegTest.h"
45 #include <CryDynamicResponseSystem/IDynamicResponseSystem.h>
46 #include <Cry3DEngine/ITimeOfDay.h>
47 #include <CryMono/IMonoRuntime.h>
48 #include <CrySchematyc/ICore.h>
49 #include <CrySchematyc2/IFramework.h>
51 #include "CryPak.h"
52 #include "XConsole.h"
53 #include "CrySizerStats.h"
54 #include "CrySizerImpl.h"
55 #include "NotificationNetwork.h"
56 #include <CryString/CryPath.h>
58 #include "XML/xml.h"
59 #include "XML/ReadWriteXMLSink.h"
61 #include "StreamEngine/StreamEngine.h"
62 #include "PhysRenderer.h"
64 #include "LocalizedStringManager.h"
65 #include "XML/XmlUtils.h"
66 #include "Serialization/ArchiveHost.h"
67 #include <CrySystem/Profilers/IDiskProfiler.h>
68 #include "SystemEventDispatcher.h"
69 #include "HardwareMouse.h"
70 #include "ServerThrottle.h"
71 #include <CryMemory/ILocalMemoryUsage.h>
72 #include "ResourceManager.h"
73 #include "MemoryManager.h"
74 #include <CryLiveCreate/ILiveCreateHost.h>
75 #include <CryLiveCreate/ILiveCreateManager.h>
76 #include "OverloadSceneManager/OverloadSceneManager.h"
77 #include <CryThreading/IThreadManager.h>
78 #include <CryReflection/IModule.h>
79 #include <CryUDR/InterfaceIncludes.h>
81 #include <CrySystem/ZLib/IZLibCompressor.h>
82 #include <CrySystem/ZLib/IZlibDecompressor.h>
83 #include <CrySystem/ZLib/ILZ4Decompressor.h>
84 #include <zlib.h>
85 #include "RemoteConsole/RemoteConsole.h"
86 #include "ImeManager.h"
87 #include "BootProfiler.h"
88 #if ALLOW_BROFILER
89 # include <Cry_Brofiler.h>
90 # include "Profiling/CryBrofiler.h"
91 #endif
92 #include "Profiling/PlatformProfiler.h"
93 #include "Profiling/ProfilingRenderer.h"
94 #include "Profiling/CryProfilingSystem.h"
95 #include "Watchdog.h"
96 #include "NullImplementation/NULLAudioSystems.h"
97 #include "NullImplementation/NULLRenderAuxGeom.h"
99 #include <CryMath/PNoise3.h>
100 #include <CryString/StringUtils.h>
101 #include <CrySystem/Scaleform/IFlashUI.h>
102 #include "CryWaterMark.h"
104 #include "ExtensionSystem/CryPluginManager.h"
105 #include "ProjectManager/ProjectManager.h"
106 #include "UserAnalytics/UserAnalyticsSystem.h"
108 #include "DebugCallStack.h"
109 #include "ManualFrameStep.h"
111 WATERMARKDATA(_m);
113 #if defined(INCLUDE_SCALEFORM_SDK) || defined(CRY_FEATURE_SCALEFORM_HELPER)
114 #include <CrySystem/Scaleform/IScaleformHelper.h>
115 #endif
117 #include "HMDManager.h"
119 #include <../CryAction/ILevelSystem.h>
120 #include <../CryAction/IViewSystem.h>
122 #include <CryCore/CrtDebugStats.h>
123 #include "Interprocess/StatsAgent.h"
125 #if CRY_PLATFORM_WINDOWS
126 #include <timeapi.h>
127 #include <algorithm>
128 #endif
130 // Define global cvars.
131 SSystemCVars g_cvars;
133 #include <CrySystem/ITextModeConsole.h>
135 extern int CryMemoryGetAllocatedSize();
137 // these heaps are used by underlying System structures
138 // to allocate, accordingly, small (like elements of std::set<..*>) and big (like memory for reading files) objects
139 // hopefully someday we'll have standard MT-safe heap
140 //CMTSafeHeap g_pakHeap;
141 CMTSafeHeap* g_pPakHeap = 0;// = &g_pakHeap;
143 //////////////////////////////////////////////////////////////////////////
144 #include "Validator.h"
145 #include "CPUDetect.h"
146 #include <CrySystem/CVarOverride.h>
147 #include "CmdLine.h"
148 #include <CryMath/Random.h>
150 #if CRY_PLATFORM_ANDROID
151 namespace
153 struct Callstack
155 Callstack()
156 : addrs(NULL)
157 , ignore(0)
158 , count(0)
161 Callstack(void** addrs, size_t ignore, size_t count)
163 this->addrs = addrs;
164 this->ignore = ignore;
165 this->count = count;
167 void** addrs;
168 size_t ignore;
169 size_t count;
172 static _Unwind_Reason_Code trace_func(struct _Unwind_Context* context, void* arg)
174 Callstack* cs = static_cast<Callstack*>(arg);
175 if (cs->count)
177 void* ip = (void*) _Unwind_GetIP(context);
178 if (ip)
180 if (cs->ignore)
182 cs->ignore--;
184 else
186 cs->addrs[0] = ip;
187 cs->addrs++;
188 cs->count--;
192 return _URC_NO_REASON;
195 static int Backtrace(void** addrs, size_t ignore, size_t size)
197 Callstack cs(addrs, ignore, size);
198 _Unwind_Backtrace(trace_func, (void*) &cs);
199 return size - cs.count;
202 #endif
204 #if defined(CVARS_WHITELIST)
205 struct SCVarsWhitelistConfigSink : public ILoadConfigurationEntrySink
207 virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup)
209 if (gEnv->pSystem->IsCVarWhitelisted(szKey, false))
211 gEnv->pConsole->LoadConfigVar(szKey, szValue);
214 } g_CVarsWhitelistConfigSink;
215 #endif // defined(CVARS_WHITELIST)
217 /////////////////////////////////////////////////////////////////////////////////
218 // System Implementation.
219 //////////////////////////////////////////////////////////////////////////
220 CSystem::CSystem(const SSystemInitParams& startupParams)
221 #if defined(SYS_ENV_AS_STRUCT)
222 : m_env(gEnv)
223 #elif !defined(CRY_IS_MONOLITHIC_BUILD)
224 : m_gameLibrary(nullptr)
225 #endif
227 MEMSTAT_CONTEXT(EMemStatContextType::Other, "CSystem Constructor");
229 m_pSystemEventDispatcher = new CSystemEventDispatcher(); // Must be first.
230 m_pSystemEventDispatcher->RegisterListener(this, "CSystem");
232 //////////////////////////////////////////////////////////////////////////
233 // Clear environment.
234 //////////////////////////////////////////////////////////////////////////
235 memset(&m_env, 0, sizeof(m_env));
237 //////////////////////////////////////////////////////////////////////////
238 // Reset handles.
239 memset(&m_dll, 0, sizeof(m_dll));
240 //////////////////////////////////////////////////////////////////////////
242 //////////////////////////////////////////////////////////////////////////
243 // Initialize global environment interface pointers.
244 m_env.pSystem = this;
245 m_env.pTimer = &m_Time;
246 m_env.pNameTable = &m_nameTable;
247 m_env.bServer = false;
248 m_env.bMultiplayer = false;
249 m_env.bHostMigrating = false;
250 m_env.startProfilingSection = CCryProfilingSystemImpl::StartSectionStaticDummy;
251 m_env.endProfilingSection = CCryProfilingSystemImpl::EndSectionStaticDummy;
252 m_env.recordProfilingMarker = CCryProfilingSystemImpl::RecordMarkerStaticDummy;
254 m_env.bUnattendedMode = false;
255 m_env.bTesting = false;
257 #if CRY_PLATFORM_DURANGO
258 m_env.ePLM_State = EPLM_UNDEFINED;
259 #endif
261 m_env.SetFMVIsPlaying(false);
262 m_env.SetCutsceneIsPlaying(false);
264 m_env.szDebugStatus[0] = '\0';
266 #if CRY_PLATFORM_DESKTOP
267 m_env.SetIsClient(false);
268 #endif
269 #if !defined(SYS_ENV_AS_STRUCT)
270 gEnv = &m_env;
271 #endif
272 //////////////////////////////////////////////////////////////////////////
274 m_randomGenerator.SetState(m_Time.GetAsyncTime().GetMicroSecondsAsInt64());
276 m_pStreamEngine = nullptr;
277 m_PhysThread = nullptr;
279 m_pIFont = nullptr;
280 #ifdef CRY_TESTING
281 m_pTestSystem = nullptr;
282 #endif
283 m_pVisRegTest = nullptr;
284 m_rIntialWindowSizeRatio = nullptr;
285 m_rWidth = nullptr;
286 m_rHeight = nullptr;
287 m_rColorBits = nullptr;
288 m_rDepthBits = nullptr;
289 m_cvSSInfo = nullptr;
290 m_rStencilBits = nullptr;
291 m_rFullscreen = nullptr;
292 m_rDriver = nullptr;
293 m_pPhysicsLibrary = nullptr;
294 m_sysNoUpdate = nullptr;
295 m_pMemoryManager = nullptr;
296 m_pProcess = nullptr;
297 m_pMtState = nullptr;
299 m_pValidator = nullptr;
300 m_pCmdLine = nullptr;
301 m_pDefaultValidator = nullptr;
302 m_pIBudgetingSystem = nullptr;
303 m_pIZLibCompressor = nullptr;
304 m_pIZLibDecompressor = nullptr;
305 m_pILZ4Decompressor = nullptr;
306 m_pNULLRenderAuxGeom = nullptr;
307 m_pLocalizationManager = nullptr;
308 m_sys_physics_enable_MT = nullptr;
309 m_sys_min_step = nullptr;
310 m_sys_max_step = nullptr;
312 m_pNotificationNetwork = nullptr;
314 m_cvAIUpdate = nullptr;
316 m_pUserCallback = nullptr;
317 #if defined(CVARS_WHITELIST)
318 m_pCVarsWhitelistConfigSink = &g_CVarsWhitelistConfigSink;
319 #endif // defined(CVARS_WHITELIST)
320 m_sys_memory_debug = nullptr;
321 m_sysWarnings = nullptr;
322 m_sysKeyboard = nullptr;
323 m_sys_profile_watchdog_timeout = nullptr;
324 m_sys_job_system_filter = nullptr;
325 m_sys_job_system_enable = nullptr;
326 m_sys_job_system_profiler = nullptr;
327 m_sys_job_system_max_worker = nullptr;
328 m_sys_job_system_worker_boost_enabled = nullptr;
329 m_sys_spec = nullptr;
330 m_sys_firstlaunch = nullptr;
331 m_sys_enable_budgetmonitoring = nullptr;
332 m_sys_use_Mono = nullptr;
333 m_sys_dll_ai = nullptr;
334 m_sys_dll_response_system = nullptr;
335 m_sys_user_folder = nullptr;
337 #if !defined(_RELEASE)
338 m_sys_resource_cache_folder = nullptr;
339 #endif
341 m_sys_initpreloadpacks = nullptr;
342 m_sys_menupreloadpacks = nullptr;
344 // m_sys_filecache = nullptr;
345 m_gpu_particle_physics = nullptr;
346 m_pCpu = nullptr;
348 m_bQuit = false;
349 m_bShaderCacheGenMode = false;
350 m_bRelaunch = false;
351 m_iLoadingMode = 0;
352 m_bPreviewMode = false;
353 m_bIgnoreUpdates = false;
354 m_bNoCrashDialog = false;
356 #ifndef _RELEASE
357 m_checkpointLoadCount = 0;
358 m_loadOrigin = eLLO_Unknown;
359 m_hasJustResumed = false;
360 m_expectingMapCommand = false;
361 #endif
363 m_nStrangeRatio = 1000;
364 // no mem stats at the moment
365 m_pMemStats = nullptr;
366 m_pSizer = nullptr;
367 m_pCVarQuit = nullptr;
369 m_pDownloadManager = nullptr;
370 m_bForceNonDevMode = false;
371 m_bWasInDevMode = false;
372 m_bInDevMode = false;
373 m_bGameFolderWritable = false;
375 m_nServerConfigSpec = CONFIG_VERYHIGH_SPEC;
376 m_nMaxConfigSpec = CONFIG_ORBIS;
378 //m_hPhysicsThread = INVALID_HANDLE_VALUE;
379 //m_hPhysicsActive = INVALID_HANDLE_VALUE;
380 //m_bStopPhysics = 0;
381 //m_bPhysicsActive = 0;
383 m_pProgressListener = nullptr;
385 m_bPaused = false;
386 m_bNoUpdate = false;
387 m_nUpdateCounter = 0;
388 m_iApplicationInstance = -1;
390 m_pPhysRenderer = nullptr;
392 m_root = PathUtil::AddSlash(PathUtil::GetEnginePath());
394 m_pXMLUtils = new CXmlUtils(this);
395 m_pArchiveHost = Serialization::CreateArchiveHost();
397 m_pMemoryManager = CryGetIMemoryManager();
398 m_pResourceManager = new CResourceManager;
399 m_pTextModeConsole = nullptr;
400 m_pDiskProfiler = nullptr;
401 m_ttMemStatSS = 0;
403 m_pLegacyProfiler = nullptr;
404 m_pProfilingSystem = nullptr;
405 m_pProfileRenderer = nullptr;
407 #ifdef ENABLE_PROFILING_CODE
408 const bool enableBootProfiler = (strstr(startupParams.szSystemCmdLine, "-bootprofiler") != nullptr);
409 const bool enableBrofiler = (strstr(startupParams.szSystemCmdLine, "-brofiler") != nullptr);
410 const bool enablePlatformProfiler = (strstr(startupParams.szSystemCmdLine, "-platformprofiler") != nullptr);
412 const char* szVerbosity = strstr(startupParams.szSystemCmdLine, "-profile_verbosity=");
413 if (szVerbosity != nullptr)
415 szVerbosity += sizeof("-profile_verbosity=") - 1;
416 int verbosity = atoi(szVerbosity);
417 if (verbosity > 0)
418 CCryProfilingSystem::s_verbosity = verbosity;
421 #ifndef RELEASE
422 if (enableBootProfiler + enableBrofiler + enablePlatformProfiler > 1)
423 __debugbreak(); // may only choose one
424 #endif
426 #if ALLOW_BROFILER
427 if (enableBrofiler)
429 m_pProfilingSystem = new CBrofiler;
430 m_env.startProfilingSection = CBrofiler::StartSectionStatic;
431 m_env.endProfilingSection = CBrofiler::EndSectionStatic;
432 // no markers on Brofiler
434 else
435 #endif
436 #if USE_PLATFORM_PROFILER
437 if (enablePlatformProfiler)
439 m_pProfilingSystem = new CPlatformProfiler;
440 m_env.startProfilingSection = CPlatformProfiler::StartSectionStatic;
441 m_env.endProfilingSection = CPlatformProfiler::EndSectionStatic;
442 m_env.recordProfilingMarker = CPlatformProfiler::RecordMarkerStatic;
444 else
445 #endif
447 m_pLegacyProfiler = new CCryProfilingSystem;
448 m_pProfilingSystem = m_pLegacyProfiler;
449 m_env.startProfilingSection = CCryProfilingSystem::StartSectionStatic;
450 m_env.endProfilingSection = CCryProfilingSystem::EndSectionStatic;
451 m_env.recordProfilingMarker = CCryProfilingSystem::RecordMarkerStatic;
453 #if defined(ENABLE_LOADING_PROFILER)
454 if (!startupParams.bShaderCacheGen)
456 CBootProfiler::GetInstance().Init(this, startupParams.szSystemCmdLine);
458 m_pLegacyProfiler->SetBootProfiler(&CBootProfiler::GetInstance());
459 #endif
460 m_pProfileRenderer = new CProfilingRenderer;
462 #endif
464 InitThreadSystem();
466 #ifdef CRY_TESTING
467 m_pTestSystem = stl::make_unique<CryTest::CTestSystem>(this);
468 #endif
470 LOADING_TIME_PROFILE_SECTION_NAMED("CSystem Boot");
472 m_pMiniGUI = nullptr;
473 m_pPerfHUD = nullptr;
475 m_pHmdManager = nullptr;
476 m_sys_vr_support = nullptr;
478 g_pPakHeap = new CMTSafeHeap;
480 m_bUIFrameworkMode = false;
482 m_PlatformOSCreateFlags = 0;
484 // create job manager
485 m_env.pJobManager = GetJobManagerInterface();
487 m_UpdateTimesIdx = 0U;
489 m_PlatformOSCreateFlags = 0;
491 m_bHasRenderedErrorMessage = false;
493 m_pImeManager = nullptr;
494 RegisterWindowMessageHandler(this);
496 m_env.pConsole = new CXConsole(*this);
497 if (startupParams.pPrintSync)
498 m_env.pConsole->AddOutputPrintSink(startupParams.pPrintSync);
500 if(m_pProfilingSystem)
501 m_pProfilingSystem->RegisterCVars();
503 m_pPluginManager = new CCryPluginManager(startupParams);
505 m_pUserAnalyticsSystem = new CUserAnalyticsSystem();
508 /////////////////////////////////////////////////////////////////////////////////
509 /////////////////////////////////////////////////////////////////////////////////
510 CSystem::~CSystem()
512 ShutDown();
514 SAFE_DELETE(m_pImeManager);
515 UnregisterWindowMessageHandler(this);
517 FreeLib(m_dll.hNetwork);
518 FreeLib(m_dll.hAI);
519 FreeLib(m_dll.hInput);
520 FreeLib(m_dll.hScript);
521 FreeLib(m_dll.hPhysics);
522 FreeLib(m_dll.hEntitySystem);
523 FreeLib(m_dll.hRenderer);
524 FreeLib(m_dll.hFlash);
525 FreeLib(m_dll.hFont);
526 FreeLib(m_dll.hMovie);
527 FreeLib(m_dll.hIndoor);
528 FreeLib(m_dll.h3DEngine);
529 FreeLib(m_dll.hAnimation);
530 FreeLib(m_dll.hGame);
531 FreeLib(m_dll.hSound);
532 SAFE_DELETE(m_pVisRegTest);
533 #if defined(USE_DISK_PROFILER)
534 SAFE_DELETE(m_pDiskProfiler);
535 #endif
536 SAFE_DELETE(m_pXMLUtils);
537 SAFE_DELETE(m_pArchiveHost);
538 SAFE_DELETE(m_pResourceManager);
539 SAFE_DELETE(m_pSystemEventDispatcher);
540 // SAFE_DELETE(m_pMemoryManager);
541 SAFE_DELETE(m_pNULLRenderAuxGeom);
543 #ifdef CRY_TESTING
544 m_pTestSystem.reset();
545 #endif
547 gEnv->pThreadManager->UnRegisterThirdPartyThread("Main");
548 ShutDownThreadSystem();
550 SAFE_DELETE(g_pPakHeap);
552 m_env.startProfilingSection = CCryProfilingSystemImpl::StartSectionStaticDummy;
553 m_env.endProfilingSection = CCryProfilingSystemImpl::EndSectionStaticDummy;
554 m_env.recordProfilingMarker = CCryProfilingSystemImpl::RecordMarkerStaticDummy;
555 SAFE_DELETE(m_pProfilingSystem);
557 m_env.pSystem = nullptr;
558 #if !defined(SYS_ENV_AS_STRUCT)
559 gEnv = 0;
560 #endif
562 #if CRY_PLATFORM_WINDOWS
563 ((DebugCallStack*)IDebugCallStack::instance())->uninstallErrorHandler();
564 #endif
567 //////////////////////////////////////////////////////////////////////////
568 void CSystem::FreeLib(WIN_HMODULE hLibModule)
570 if (hLibModule)
572 CryFreeLibrary(hLibModule);
576 //////////////////////////////////////////////////////////////////////////
577 IStreamEngine* CSystem::GetStreamEngine()
579 return m_pStreamEngine;
582 //////////////////////////////////////////////////////////////////////////
583 IRemoteConsole* CSystem::GetIRemoteConsole()
585 return CRemoteConsole::GetInst();
588 //////////////////////////////////////////////////////////////////////////
589 void CSystem::SetForceNonDevMode(const bool bValue)
591 m_bForceNonDevMode = bValue;
592 if (bValue)
593 SetDevMode(false);
596 //////////////////////////////////////////////////////////////////////////
597 bool CSystem::GetForceNonDevMode() const
599 return m_bForceNonDevMode;
602 //////////////////////////////////////////////////////////////////////////
603 void CSystem::SetDevMode(bool bEnable)
605 if (bEnable)
606 m_bWasInDevMode = true;
607 m_bInDevMode = bEnable;
610 void LvlRes_export(IConsoleCmdArgs* pParams);
612 ///////////////////////////////////////////////////
613 void CSystem::ShutDown()
615 CryLogAlways("System Shutdown");
617 SAFE_DELETE(m_pManualFrameStepController);
619 if (m_pSystemEventDispatcher)
621 m_pSystemEventDispatcher->RemoveListener(this);
624 if (m_pUserCallback)
625 m_pUserCallback->OnShutdown();
627 GetIRemoteConsole()->Stop();
629 SAFE_DELETE(m_pTextModeConsole);
631 //////////////////////////////////////////////////////////////////////////
632 // Interprocess Communication
633 //////////////////////////////////////////////////////////////////////////
634 #if defined(ENABLE_STATS_AGENT)
635 CStatsAgent::ClosePipe();
636 #endif
638 KillPhysicsThread();
640 if (m_sys_firstlaunch)
641 m_sys_firstlaunch->Set(0);
643 if (m_env.IsEditor())
645 // restore the old saved cvars
646 if (m_env.pConsole->GetCVar("r_Width"))
647 m_env.pConsole->GetCVar("r_Width")->Set(m_iWidth);
648 if (m_env.pConsole->GetCVar("r_Height"))
649 m_env.pConsole->GetCVar("r_Height")->Set(m_iHeight);
650 if (m_env.pConsole->GetCVar("r_ColorBits"))
651 m_env.pConsole->GetCVar("r_ColorBits")->Set(m_iColorBits);
654 if (m_env.IsEditor() && !m_bRelaunch)
656 SaveConfiguration();
659 //if (!m_bEditor && !bRelaunch)
660 #if !CRY_PLATFORM_DURANGO && !CRY_PLATFORM_ORBIS
661 if (!m_env.IsEditor())
663 if (m_pCVarQuit && m_pCVarQuit->GetIVal())
665 SaveConfiguration();
667 // Dispatch the fast-shutdown event so other systems can do any last minute processing.
668 if (m_pSystemEventDispatcher != NULL)
670 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_FAST_SHUTDOWN, 0, 0);
673 if (m_env.pNetwork != NULL)
675 m_env.pNetwork->FastShutdown();
678 SAFE_RELEASE(m_env.pRenderer);
679 FreeLib(m_dll.hRenderer);
681 // Shut down audio as late as possible but before the console gets released!
682 SAFE_RELEASE(m_env.pAudioSystem);
684 // Log must be last thing released.
685 m_env.pLog->FlushAndClose();
686 SAFE_RELEASE(m_env.pLog); // creates log backup
688 #if CRY_PLATFORM_WINDOWS
689 ((DebugCallStack*)IDebugCallStack::instance())->uninstallErrorHandler();
690 #endif
692 #if CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID
693 return; //safe clean return
694 #else
695 // Commit files changes to the disk.
696 _flushall();
697 _exit(EXIT_SUCCESS);
698 #endif
701 #endif
703 // Dispatch the full-shutdown event in case this is not a fast-shutdown.
704 if (m_pSystemEventDispatcher != NULL)
706 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_FULL_SHUTDOWN, 0, 0);
709 //////////////////////////////////////////////////////////////////////////
710 // Release Game.
711 //////////////////////////////////////////////////////////////////////////
713 if (m_env.pGameFramework)
715 m_env.pGameFramework->ShutDown();
716 #if !defined(CRY_IS_MONOLITHIC_BUILD)
717 // This handle keeps gamedll loaded, it must be emptied on shutdown in order to properly clean up
718 m_gameLibrary.Set(nullptr);
719 #endif
722 if (m_env.pEntitySystem)
723 m_env.pEntitySystem->Unload();
725 if (m_env.pPhysicalWorld)
727 m_env.pPhysicalWorld->SetPhysicsStreamer(0);
728 m_env.pPhysicalWorld->SetPhysicsEventClient(0);
731 UnloadSchematycModule();
733 UnloadEngineModule("CryAction");
734 UnloadEngineModule("CryFlowGraph");
735 SAFE_DELETE(m_pPluginManager);
737 m_pPlatformOS.reset();
739 if (gEnv->pMonoRuntime != nullptr)
741 gEnv->pMonoRuntime->Shutdown();
744 SAFE_DELETE(m_pUserAnalyticsSystem);
745 if (m_sys_dll_response_system != nullptr)
747 UnloadEngineModule(m_sys_dll_response_system->GetString());
750 #if defined(INCLUDE_SCALEFORM_SDK) || defined(CRY_FEATURE_SCALEFORM_HELPER)
751 if (m_env.pRenderer)
752 m_env.pRenderer->FlushRTCommands(true, true, true);
754 if (!gEnv->IsDedicated() && gEnv->pScaleformHelper)
756 gEnv->pScaleformHelper->Destroy();
757 gEnv->pScaleformHelper = nullptr;
759 #endif
761 //////////////////////////////////////////////////////////////////////////
762 // Clear 3D Engine resources.
763 if (m_env.p3DEngine)
764 m_env.p3DEngine->ShutDown();
765 //////////////////////////////////////////////////////////////////////////
767 // Shutdown resource manager.
768 m_pResourceManager->Shutdown();
770 // The LiveCreate module must be deleted here since at shutdown, it's using other modules, please keep this location
771 SAFE_DELETE(m_env.pLiveCreateHost);
772 SAFE_DELETE(m_env.pLiveCreateManager);
773 SAFE_RELEASE(m_env.pHardwareMouse);
774 UnloadEngineModule("CryMovie");
775 SAFE_DELETE(m_env.pServiceNetwork);
776 UnloadEngineModule("CryAISystem");
777 UnloadEngineModule("CryFont");
778 UnloadEngineModule("CryNetwork");
779 // SAFE_RELEASE(m_env.pCharacterManager);
780 UnloadEngineModule("CryAnimation");
781 UnloadEngineModule("Cry3DEngine"); // depends on EntitySystem
782 UnloadEngineModule("CryEntitySystem");
784 SAFE_DELETE(m_pPhysRenderer); // Must be destroyed before unloading CryPhysics as it holds memory that was allocated by that module
785 UnloadEngineModule("CryPhysics");
787 UnloadEngineModule("CryMonoBridge");
789 if (m_env.pConsole)
790 ((CXConsole*)m_env.pConsole)->FreeRenderResources();
791 SAFE_RELEASE(m_pIZLibCompressor);
792 SAFE_RELEASE(m_pIZLibDecompressor);
793 SAFE_RELEASE(m_pILZ4Decompressor);
794 SAFE_RELEASE(m_pIBudgetingSystem);
796 SAFE_RELEASE(m_env.pRenderer);
798 if (ICVar* pDriverCVar = m_env.pConsole->GetCVar("r_driver"))
800 const char* szRenderDriver = pDriverCVar->GetString();
801 CloseRenderLibrary(szRenderDriver);
804 SAFE_RELEASE(m_env.pCodeCheckpointMgr);
806 if (m_env.pLog)
807 m_env.pLog->UnregisterConsoleVariables();
809 GetIRemoteConsole()->UnregisterConsoleVariables();
811 // Release console variables.
813 SAFE_RELEASE(m_pCVarQuit);
814 SAFE_RELEASE(m_rIntialWindowSizeRatio);
815 SAFE_RELEASE(m_rWidth);
816 SAFE_RELEASE(m_rHeight);
817 SAFE_RELEASE(m_rColorBits);
818 SAFE_RELEASE(m_rDepthBits);
819 SAFE_RELEASE(m_cvSSInfo);
820 SAFE_RELEASE(m_rStencilBits);
821 SAFE_RELEASE(m_rFullscreen);
822 SAFE_RELEASE(m_rDriver);
823 SAFE_RELEASE(m_pPhysicsLibrary);
825 SAFE_RELEASE(m_sysWarnings);
826 SAFE_RELEASE(m_sysKeyboard);
827 SAFE_RELEASE(m_sys_profile_watchdog_timeout);
828 SAFE_RELEASE(m_sys_job_system_filter);
829 SAFE_RELEASE(m_sys_job_system_enable);
830 SAFE_RELEASE(m_sys_job_system_profiler);
831 SAFE_RELEASE(m_sys_job_system_max_worker);
832 SAFE_RELEASE(m_sys_job_system_worker_boost_enabled);
833 SAFE_RELEASE(m_sys_spec);
834 SAFE_RELEASE(m_sys_firstlaunch);
835 SAFE_RELEASE(m_sys_enable_budgetmonitoring);
836 SAFE_RELEASE(m_sys_physics_enable_MT);
837 SAFE_RELEASE(m_sys_min_step);
838 SAFE_RELEASE(m_sys_max_step);
840 //Purposely leaking the object as we do not want to block the MainThread waiting for the Watchdog thread to join
841 if (m_pWatchdog != nullptr)
842 m_pWatchdog->SignalStopWork();
844 if (m_env.pInput)
846 m_env.pInput->ShutDown();
847 m_env.pInput = NULL;
849 UnloadEngineModule("CryInput");
851 SAFE_RELEASE(m_pNotificationNetwork);
852 UnloadEngineModule("CryScriptSystem");
854 SAFE_DELETE(m_pMemStats);
855 SAFE_DELETE(m_pSizer);
857 SAFE_DELETE(m_env.pOverloadSceneManager);
859 // [VR] specific
860 // CHmdManager shuts down the HDM devices on destruction.
861 // It must happen AFTER m_env.pRenderer: the renderer may consult info
862 // about the current HMD Device.
863 // It should happen AFTER m_env.pInput: as CryInput may use elements controlled
864 // by CHmdManager.
865 SAFE_DELETE(m_pHmdManager);
867 #ifdef DOWNLOAD_MANAGER
868 SAFE_RELEASE(m_pDownloadManager);
869 #endif //DOWNLOAD_MANAGER
871 SAFE_DELETE(m_pLocalizationManager);
873 //DebugStats(false, false);//true);
874 //CryLogAlways("");
875 //CryLogAlways("release mode memory manager stats:");
876 //DumpMMStats(true);
878 SAFE_DELETE(m_pCpu);
880 SAFE_DELETE(m_pCmdLine);
882 // Shut down audio as late as possible but before the streaming system and console get released!
883 SAFE_RELEASE(m_env.pAudioSystem);
884 UnloadEngineModule("CryAudioSystem");
886 SAFE_DELETE(m_pProjectManager);
888 // Shut down the CryPak system after audio!
889 SAFE_DELETE(m_env.pCryPak);
891 // Shut down the streaming system and console as late as possible and after audio!
892 SAFE_DELETE(m_pStreamEngine);
894 // Shut down UDR before the console gets released as it accesses it during destruction!
895 UnloadEngineModule("CryUDR");
897 SAFE_RELEASE(m_env.pConsole);
899 // Log must be last thing released.
900 m_env.pLog->FlushAndClose();
901 SAFE_RELEASE(m_env.pLog); // creates log backup
903 // DefaultValidator is used by the logging system, make sure to delete this member after logging system!
904 SAFE_DELETE(m_pDefaultValidator);
906 #if defined(MAP_LOADING_SLICING)
907 delete gEnv->pSystemScheduler;
908 #endif // defined(MAP_LOADING_SLICING)
910 UnloadEngineModule("CryReflection");
912 #if CAPTURE_REPLAY_LOG
913 CryGetIMemReplay()->Stop();
914 #endif
916 #if CRY_PLATFORM_LINUX
917 // Delete lock file
918 if (m_iApplicationInstance != -1)
920 // In case of a crash this will not get called
921 // but the OS clears the directory on reboot so
922 // "leaking" the file is not that bad
924 string path;
925 path.Format("/tmp/CrytekApplication%d.lock", m_iApplicationInstance);
926 remove(path.c_str());
927 m_iApplicationInstance = -1;
929 #endif // CRY_PLATFORM_LINUX
931 // Fix to improve wait() time within third party APIs using sleep()
932 #if CRY_PLATFORM_WINDOWS
933 TIMECAPS tc;
934 if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
936 CryFatalError("Error while changing the system timer resolution!");
938 timeEndPeriod(tc.wPeriodMin);
939 #endif // CRY_PLATFORM_WINDOWS
942 /////////////////////////////////////////////////////////////////////////////////
943 /////////////////////////////////////////////////////////////////////////////////
944 void CSystem::Quit()
946 CryLog("CSystem::Quit invoked from thread %" PRI_THREADID " (main is %" PRI_THREADID ")", GetCurrentThreadId(), gEnv->mMainThreadId);
947 m_bQuit = true;
949 if (m_pUserCallback)
950 m_pUserCallback->OnQuit();
951 if (gEnv->pCryPak && gEnv->pCryPak->GetLvlResStatus())
952 LvlRes_export(0); // executable was started with -LvlRes so it should export lvlres file on quit
953 // Fast Quit.
955 // clean up properly the console
956 if (m_pTextModeConsole)
957 m_pTextModeConsole->OnShutdown();
959 if (m_env.pRenderer)
961 ICVar* pCVarGamma = m_env.pConsole->GetCVar("r_Gamma");
962 if (pCVarGamma)
963 pCVarGamma->Set(1.0f); // prevent mysterious gamma snap back on quit (CE-15284)
964 m_env.pRenderer->RestoreGamma();
967 if (m_pCVarQuit && m_pCVarQuit->GetIVal() != 0)
969 // Dispatch the fast-shutdown event so other systems can do any last minute processing.
970 if (m_pSystemEventDispatcher != NULL)
972 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_FAST_SHUTDOWN, 0, 0);
975 if (m_env.pNetwork)
976 m_env.pNetwork->FastShutdown();
978 // HACK! to save cvars on quit.
979 SaveConfiguration();
981 if (gEnv->pFlashUI)
982 gEnv->pFlashUI->Shutdown();
984 if (m_env.pRenderer)
986 m_env.pRenderer->StopRenderIntroMovies(false);
987 m_env.pRenderer->StopLoadtimeFlashPlayback();
990 #if defined(INCLUDE_SCALEFORM_SDK) || defined(CRY_FEATURE_SCALEFORM_HELPER)
991 if (m_env.pRenderer)
992 m_env.pRenderer->FlushRTCommands(true, true, true);
994 if (gEnv->pScaleformHelper)
996 gEnv->pScaleformHelper->Destroy();
997 gEnv->pScaleformHelper = nullptr;
999 #endif
1001 if (m_env.pRenderer)
1002 m_env.pRenderer->ShutDownFast();
1004 CryLogAlways("System:Quit");
1006 // Shut down audio as late as possible but before the streaming system and console get released!
1007 SAFE_RELEASE(m_env.pAudioSystem);
1009 // Shut down the streaming system as late as possible and after audio!
1010 if (m_pStreamEngine)
1011 m_pStreamEngine->Shutdown();
1013 // Commit files changes to the disk.
1014 #if CRY_PLATFORM_LINUX || CRY_PLATFORM_ANDROID
1015 fflush(NULL);
1016 #else
1017 _flushall();
1018 #endif
1019 //////////////////////////////////////////////////////////////////////////
1020 // Support relaunching for windows media center edition.
1021 //////////////////////////////////////////////////////////////////////////
1022 #if CRY_PLATFORM_WINDOWS
1023 if (m_pCmdLine && strstr(m_pCmdLine->GetCommandLine(), "ReLaunchMediaCenter") != 0)
1025 ReLaunchMediaCenter();
1027 #endif
1029 #if CAPTURE_REPLAY_LOG
1030 CryGetIMemReplay()->Stop();
1031 #endif
1033 GetIRemoteConsole()->Stop();
1035 //////////////////////////////////////////////////////////////////////////
1036 // [marco] in test mode, kill the process and quit without performing full C libs cleanup
1037 // (for faster closing of application)
1038 CRY_ASSERT(m_pCVarQuit->GetIVal());
1039 #if CRY_PLATFORM_ORBIS
1040 _Exit(0);
1041 #elif CRY_PLATFORM_WINDOWS
1042 TerminateProcess(GetCurrentProcess(), 0);
1043 #else
1044 _exit(0);
1045 #endif
1047 #if !CRY_PLATFORM_LINUX && !CRY_PLATFORM_ANDROID && !CRY_PLATFORM_APPLE && !CRY_PLATFORM_DURANGO && !CRY_PLATFORM_ORBIS
1048 PostQuitMessage(0);
1049 #endif
1051 /////////////////////////////////////////////////////////////////////////////////
1052 /////////////////////////////////////////////////////////////////////////////////
1053 bool CSystem::IsQuitting() const
1055 return m_bQuit;
1058 //////////////////////////////////////////////////////////////////////////
1059 void CSystem::SetIProcess(IProcess* process)
1061 m_pProcess = process;
1062 //if (m_pProcess)
1063 //m_pProcess->SetPMessage("");
1066 void CSystem::StartBootProfilerSession(const char* szName)
1068 #ifdef ENABLE_LOADING_PROFILER
1069 CBootProfiler::GetInstance().StartSession(szName);
1070 #endif
1073 void CSystem::EndBootProfilerSession()
1075 #ifdef ENABLE_LOADING_PROFILER
1076 CBootProfiler::GetInstance().StopSession();
1077 #endif
1080 //////////////////////////////////////////////////////////////////////////
1081 // Physics thread task
1082 //////////////////////////////////////////////////////////////////////////
1084 class IPhysicsThreadTask : public IThread
1086 public:
1087 virtual ~IPhysicsThreadTask()
1090 // Start accepting work on thread
1091 virtual void ThreadEntry() = 0;
1093 // Signals the thread that it should not accept anymore work and exit
1094 virtual void SignalStopWork() = 0;
1097 class CPhysicsThreadTask : public IPhysicsThreadTask
1099 public:
1101 CPhysicsThreadTask()
1103 m_bStopRequested = 0;
1104 m_bIsActive = 0;
1105 m_stepRequested = 0;
1106 m_bProcessing = 0;
1107 m_doZeroStep = 0;
1108 m_lastStepTimeTaken = 0U;
1109 m_lastWaitTimeTaken = 0U;
1112 virtual ~CPhysicsThreadTask()
1116 //////////////////////////////////////////////////////////////////////////
1117 // IThread implementation.
1118 //////////////////////////////////////////////////////////////////////////
1119 // Start accepting work on thread
1120 virtual void ThreadEntry()
1122 m_bStopRequested = 0;
1123 m_bIsActive = 1;
1125 float step, timeTaken, kSlowdown = 1.0f;
1126 int nSlowFrames = 0;
1127 int64 timeStart;
1128 #ifdef ENABLE_LW_PROFILERS
1129 LARGE_INTEGER stepStart, stepEnd;
1130 #endif
1131 LARGE_INTEGER waitStart, waitEnd;
1133 while (true)
1136 CRY_PROFILE_REGION_WAITING(PROFILE_PHYSICS, "Wait - Physics Update");
1138 QueryPerformanceCounter(&waitStart);
1139 m_FrameEvent.Wait(); // Wait until new frame
1140 QueryPerformanceCounter(&waitEnd);
1144 CRY_PROFILE_REGION(PROFILE_PHYSICS, "Physics Update");
1146 m_lastWaitTimeTaken = waitEnd.QuadPart - waitStart.QuadPart;
1148 if (m_bStopRequested)
1150 return;
1152 bool stepped = false;
1153 #ifdef ENABLE_LW_PROFILERS
1154 QueryPerformanceCounter(&stepStart);
1155 #endif
1156 IGameFramework* pIGameFramework = gEnv->pGameFramework;
1157 while ((step = m_stepRequested) > 0 || m_doZeroStep)
1159 stepped = true;
1160 m_stepRequested = 0;
1161 m_bProcessing = 1;
1162 m_doZeroStep = 0;
1164 PhysicsVars* pVars = gEnv->pPhysicalWorld->GetPhysVars();
1165 pVars->bMultithreaded = 1;
1166 gEnv->pPhysicalWorld->TracePendingRays();
1167 if (kSlowdown != 1.0f)
1169 step = max(1, FtoI(step * kSlowdown * 50 - 0.5f)) * 0.02f;
1170 pVars->timeScalePlayers = 1.0f / max(kSlowdown, 0.2f);
1172 else
1173 pVars->timeScalePlayers = 1.0f;
1174 step = min(step, pVars->maxWorldStep);
1175 timeStart = CryGetTicks();
1176 pIGameFramework->PrePhysicsTimeStep(step);
1177 gEnv->pPhysicalWorld->TimeStep(step);
1178 timeTaken = gEnv->pTimer->TicksToSeconds(CryGetTicks() - timeStart);
1179 if (timeTaken > step * 0.9f)
1181 if (++nSlowFrames > 5)
1182 kSlowdown = step * 0.9f / timeTaken;
1184 else
1185 kSlowdown = 1.0f, nSlowFrames = 0;
1186 gEnv->pPhysicalWorld->TracePendingRays(2);
1187 m_bProcessing = 0;
1188 //int timeSleep = (int)((m_timeTarget-gEnv->pTimer->GetAsyncTime()).GetMilliSeconds()*0.9f);
1189 //Sleep(max(0,timeSleep));
1191 if (!stepped) CrySleep(0);
1192 m_FrameDone.Set();
1193 #ifdef ENABLE_LW_PROFILERS
1194 QueryPerformanceCounter(&stepEnd);
1195 m_lastStepTimeTaken = stepEnd.QuadPart - stepStart.QuadPart;
1196 #endif
1201 // Signals the thread that it should not accept anymore work and exit
1202 virtual void SignalStopWork()
1204 Pause();
1205 m_bStopRequested = 1;
1206 m_FrameEvent.Set();
1207 m_bIsActive = 0;
1210 int Pause()
1212 if (m_bIsActive)
1214 PhysicsVars* vars = gEnv->pPhysicalWorld->GetPhysVars();
1215 vars->lastTimeStep = 0;
1216 m_bIsActive = 0;
1217 m_stepRequested = 0;
1218 while (m_bProcessing);
1219 return 1;
1221 gEnv->pPhysicalWorld->GetPhysVars()->lastTimeStep = 0;
1222 return 0;
1224 int Resume()
1226 if (!m_bIsActive)
1228 m_bIsActive = 1;
1229 return 1;
1231 return 0;
1233 int IsActive() { return m_bIsActive; }
1234 int RequestStep(float dt)
1236 if (m_bIsActive && dt > FLT_EPSILON)
1238 m_stepRequested += dt;
1239 m_stepRequested = min((float)m_stepRequested, 10.f * gEnv->pPhysicalWorld->GetPhysVars()->maxWorldStep);
1240 if (dt <= 0.0f)
1241 m_doZeroStep = 1;
1242 m_FrameEvent.Set();
1245 return m_bProcessing;
1247 float GetRequestedStep() { return m_stepRequested; }
1249 uint64 LastStepTaken() const
1251 return m_lastStepTimeTaken;
1254 uint64 LastWaitTime() const
1256 return m_lastWaitTimeTaken;
1259 void EnsureStepDone()
1261 CRY_PROFILE_REGION_WAITING(PROFILE_SYSTEM, "SysUpdate:PhysicsEnsureDone");
1263 if (m_bIsActive)
1265 while (m_stepRequested > 0.0f || m_bProcessing)
1267 m_FrameDone.Wait();
1272 protected:
1274 volatile int m_bStopRequested;
1275 volatile int m_bIsActive;
1276 volatile float m_stepRequested;
1277 volatile int m_bProcessing;
1278 volatile int m_doZeroStep;
1279 volatile uint64 m_lastStepTimeTaken;
1280 volatile uint64 m_lastWaitTimeTaken;
1282 CryEvent m_FrameEvent;
1283 CryEvent m_FrameDone;
1286 void CSystem::CreatePhysicsThread()
1288 if (!m_PhysThread)
1290 m_PhysThread = new CPhysicsThreadTask;
1291 if (!gEnv->pThreadManager->SpawnThread(m_PhysThread, "Physics"))
1293 CryFatalError("Error spawning \"Physics\" thread.");
1297 if (g_cvars.sys_limit_phys_thread_count)
1299 PhysicsVars* pVars = gEnv->pPhysicalWorld->GetPhysVars();
1300 pVars->numThreads = max(1, min(pVars->numThreads, (int)m_pCpu->GetLogicalCPUCount() - 1));
1304 void CSystem::KillPhysicsThread()
1306 if (m_PhysThread)
1308 m_PhysThread->SignalStopWork();
1309 gEnv->pThreadManager->JoinThread(m_PhysThread, eJM_Join);
1310 delete m_PhysThread;
1311 m_PhysThread = 0;
1315 //////////////////////////////////////////////////////////////////////////
1316 int CSystem::SetThreadState(ESubsystem subsys, bool bActive)
1318 switch (subsys)
1320 case ESubsys_Physics:
1322 if (m_PhysThread)
1324 return bActive ? ((CPhysicsThreadTask*)m_PhysThread)->Resume() : ((CPhysicsThreadTask*)m_PhysThread)->Pause();
1327 break;
1329 return 0;
1332 //////////////////////////////////////////////////////////////////////////
1333 void CSystem::SleepIfNeeded()
1335 CRY_PROFILE_FUNCTION(PROFILE_SYSTEM)
1337 static ICVar * pSysMaxFPS = NULL;
1338 static ICVar* pVSync = NULL;
1340 if (pSysMaxFPS == NULL && gEnv && gEnv->pConsole)
1341 pSysMaxFPS = gEnv->pConsole->GetCVar("sys_MaxFPS");
1342 if (pVSync == NULL && gEnv && gEnv->pConsole)
1343 pVSync = gEnv->pConsole->GetCVar("r_Vsync");
1345 int32 maxFPS = 0;
1347 if (m_env.IsDedicated())
1349 const float maxRate = m_svDedicatedMaxRate->GetFVal();
1350 maxFPS = int32(maxRate);
1352 else
1354 if (pSysMaxFPS && pVSync)
1356 uint32 vSync = pVSync->GetIVal();
1357 if (vSync == 0)
1359 maxFPS = pSysMaxFPS->GetIVal();
1360 if (maxFPS == 0)
1362 const bool bInLoading = (ESYSTEM_GLOBAL_STATE_RUNNING != m_systemGlobalState);
1363 if (bInLoading || IsPaused() || m_throttleFPS)
1365 maxFPS = 60;
1372 if (maxFPS > 0)
1374 const int64 safeMarginMS = 5; // microseconds
1375 const int64 thresholdMs = (1000 * 1000) / (maxFPS);
1377 ITimer* pTimer = gEnv->pTimer;
1378 static int64 sTimeLast = pTimer->GetAsyncTime().GetMicroSecondsAsInt64();
1379 int64 currentTime = pTimer->GetAsyncTime().GetMicroSecondsAsInt64();
1380 for (;;)
1382 const int64 frameTime = currentTime - sTimeLast;
1383 if (frameTime >= thresholdMs)
1384 break;
1385 if (thresholdMs - frameTime > 10 * 1000)
1386 CrySleep(1);
1387 else
1388 CrySleep(0);
1390 currentTime = pTimer->GetAsyncTime().GetMicroSecondsAsInt64();
1393 m_lastTickTime = pTimer->GetAsyncTime();
1394 sTimeLast = m_lastTickTime.GetMicroSecondsAsInt64() + safeMarginMS;
1398 //////////////////////////////////////////////////////////////////////
1399 #if CRY_PLATFORM_WINDOWS
1400 HWND g_hBreakWnd;
1401 WNDPROC g_prevWndProc;
1402 LRESULT CALLBACK BreakWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1404 if (msg == WM_HOTKEY)
1405 __debugbreak();
1406 return CallWindowProc(g_prevWndProc, hWnd, msg, wParam, lParam);
1409 struct SBreakHotKeyThread : public IThread
1411 SBreakHotKeyThread()
1412 : m_bRun(true)
1416 // Start accepting work on thread
1417 virtual void ThreadEntry()
1419 g_hBreakWnd = CreateWindowExW(0, L"Message", L"", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, 0, GetModuleHandleW(0), 0);
1420 g_prevWndProc = (WNDPROC)SetWindowLongPtrW(g_hBreakWnd, GWLP_WNDPROC, (LONG_PTR)BreakWndProc);
1421 RegisterHotKey(g_hBreakWnd, 0, 0, VK_PAUSE);
1422 MSG msg;
1423 while (GetMessage(&msg, g_hBreakWnd, 0, 0) && m_bRun)
1425 TranslateMessage(&msg);
1426 DispatchMessageW(&msg);
1428 UnregisterHotKey(g_hBreakWnd, 0);
1431 // Signals the thread that it should not accept anymore work and exit
1432 void SignalStopWork()
1434 m_bRun = false;
1437 protected:
1438 volatile bool m_bRun;
1441 SBreakHotKeyThread* g_pBreakHotkeyThread;
1442 #endif
1444 class BreakListener : public IInputEventListener
1446 bool OnInputEvent(const SInputEvent& ie)
1448 if (ie.deviceType == eIDT_Keyboard && ie.keyId == eKI_Pause && ie.state & (eIS_Pressed | eIS_Down))
1449 __debugbreak();
1450 return true;
1452 } g_BreakListener;
1454 volatile int g_lockInput = 0;
1456 struct SBreakListenerTask : public IThread
1458 SBreakListenerTask()
1460 m_bStop = 0;
1461 m_nBreakIdle = 0;
1463 // Start accepting work on thread
1464 virtual void ThreadEntry()
1468 CrySleep(200);
1469 if (++m_nBreakIdle > 1)
1471 WriteLock lock(g_lockInput);
1472 gEnv->pInput->Update(true);
1473 m_nBreakIdle = 0;
1476 while (!m_bStop);
1478 // Signals the thread that it should not accept anymore work and exit
1479 void SignalStopWork()
1481 m_bStop = 1;
1483 volatile int m_bStop;
1484 int m_nBreakIdle;
1486 SBreakListenerTask g_BreakListenerTask;
1487 bool g_breakListenerOn = false;
1489 extern DWORD g_idDebugThreads[];
1490 extern int g_nDebugThreads;
1491 int prev_sys_float_exceptions = -1;
1493 //////////////////////////////////////////////////////////////////////
1494 void CSystem::PrePhysicsUpdate()
1496 CRY_PROFILE_REGION(PROFILE_SYSTEM, "System::PrePhysicsUpdate");
1498 if (m_env.pGameFramework)
1500 m_env.pGameFramework->PrePhysicsUpdate();
1503 if (m_pPluginManager)
1505 m_pPluginManager->UpdateBeforePhysics();
1508 //////////////////////////////////////////////////////////////////////
1509 //update entity system
1510 if (m_env.pEntitySystem && g_cvars.sys_entitysystem)
1512 if (gEnv->pSchematyc != nullptr)
1514 gEnv->pSchematyc->PrePhysicsUpdate();
1517 if (gEnv->pSchematyc2 != nullptr)
1519 gEnv->pSchematyc2->PrePhysicsUpdate();
1522 m_env.pEntitySystem->PrePhysicsUpdate();
1526 void CSystem::RunMainLoop()
1528 MEMSTAT_CONTEXT(EMemStatContextType::Other, "CSystem::MainLoop");
1530 if (m_bShaderCacheGenMode)
1532 return;
1535 #if CRY_PLATFORM_WINDOWS
1536 if (!(gEnv && m_env.pSystem) || (!m_env.IsEditor() && !m_env.IsDedicated()))
1538 if (m_env.pHardwareMouse != nullptr)
1540 m_env.pHardwareMouse->DecrementCounter();
1542 else
1544 ::ShowCursor(FALSE);
1547 #else
1548 if (gEnv && m_env.pHardwareMouse)
1549 m_env.pHardwareMouse->DecrementCounter();
1550 #endif
1552 for (;;)
1554 #if CRY_PLATFORM_DURANGO
1555 Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
1556 #endif
1557 if (!DoFrame())
1559 break;
1564 //////////////////////////////////////////////////////////////////////
1565 bool CSystem::DoFrame(const SDisplayContextKey& displayContextKey, const SGraphicsPipelineKey& graphicsPipelineKey, CEnumFlags<ESystemUpdateFlags> updateFlags)
1567 if(m_pProfilingSystem && !updateFlags.Check(ESYSUPDATE_EDITOR))
1568 m_pProfilingSystem->StartFrame();
1569 #if ALLOW_BROFILER
1570 BROFILER_FRAME("Main");
1571 #endif
1573 if (m_pManualFrameStepController != nullptr && m_pManualFrameStepController->Update() == EManualFrameStepResult::Block)
1575 // Skip frame update
1576 return true;
1579 CRY_PROFILE_REGION(PROFILE_SYSTEM, __FUNC__);
1580 #if defined(JOBMANAGER_SUPPORT_PROFILING)
1581 m_env.GetJobManager()->SetFrameStartTime(m_env.pTimer->GetAsyncTime());
1582 #endif
1584 if (m_env.pGameFramework != nullptr)
1586 m_env.pGameFramework->PreSystemUpdate();
1589 if (!(updateFlags & ESYSUPDATE_EDITOR))
1591 m_pPluginManager->UpdateBeforeSystem();
1594 if (ITextModeConsole* pTextModeConsole = GetITextModeConsole())
1596 pTextModeConsole->BeginDraw();
1599 // Tell the network to go to sleep
1600 if (m_env.pNetwork)
1602 m_env.pNetwork->SyncWithGame(eNGS_SleepNetwork);
1605 if (!m_env.IsEditing()) // Editor calls its own rendering update
1606 RenderBegin(displayContextKey, graphicsPipelineKey);
1608 bool continueRunning = true;
1610 // The Editor is responsible for updating the system manually, so we should skip in that case.
1611 if (!(updateFlags & ESYSUPDATE_EDITOR))
1613 int pauseMode;
1615 if (m_env.pRenderer != nullptr && m_env.pRenderer->IsPost3DRendererEnabled())
1617 pauseMode = 0;
1618 updateFlags |= ESYSUPDATE_IGNORE_AI;
1620 else if (m_env.pGameFramework != nullptr)
1622 pauseMode = (m_env.pGameFramework->IsGamePaused() || !m_env.pGameFramework->IsGameStarted()) ? 1 : 0;
1624 else
1626 pauseMode = 0;
1629 if (!Update(updateFlags, pauseMode))
1631 continueRunning = false;
1635 if (m_env.pGameFramework != nullptr)
1637 if (!m_env.pGameFramework->PostSystemUpdate(m_hasWindowFocus, updateFlags))
1639 continueRunning = false;
1643 if (!(updateFlags & ESYSUPDATE_EDITOR))
1645 m_pPluginManager->UpdateAfterSystem();
1648 // Synchronize all animations to ensure that their computation has finished
1649 // Has to be done before view update, in case camera depends on a joint
1650 if (m_env.pCharacterManager && !IsLoading())
1652 m_env.pCharacterManager->SyncAllAnimations();
1655 if (m_env.pGameFramework != nullptr && !updateFlags.Check(ESYSUPDATE_EDITOR_ONLY) && !updateFlags.Check(ESYSUPDATE_EDITOR_AI_PHYSICS))
1657 m_env.pGameFramework->PreFinalizeCamera(updateFlags);
1660 if (!(updateFlags & ESYSUPDATE_EDITOR))
1662 m_pPluginManager->UpdateBeforeFinalizeCamera();
1665 ICVar* pCameraFreeze = gEnv->pConsole->GetCVar("e_CameraFreeze");
1666 const bool isCameraFrozen = pCameraFreeze && pCameraFreeze->GetIVal() != 0;
1668 const CCamera& rCameraToSet = isCameraFrozen ? m_env.p3DEngine->GetRenderingCamera() : m_ViewCamera;
1669 m_env.p3DEngine->PrepareOcclusion(rCameraToSet, SGraphicsPipelineKey::BaseGraphicsPipelineKey);
1671 if (m_env.pGameFramework != nullptr)
1673 m_env.pGameFramework->PreRender();
1676 if (!(updateFlags & ESYSUPDATE_EDITOR))
1678 m_pPluginManager->UpdateBeforeRender();
1681 Render(graphicsPipelineKey);
1683 if (m_env.pGameFramework != nullptr)
1685 m_env.pGameFramework->PostRender(updateFlags);
1688 if (!(updateFlags & ESYSUPDATE_EDITOR))
1690 m_pPluginManager->UpdateAfterRender();
1693 if (updateFlags & ESYSUPDATE_EDITOR_AI_PHYSICS)
1695 return continueRunning;
1698 #if !defined(_RELEASE) && !CRY_PLATFORM_DURANGO
1699 RenderPhysicsHelpers();
1700 #endif
1702 RenderEnd();
1704 if (m_env.pGameFramework != nullptr)
1706 m_env.pGameFramework->PostRenderSubmit();
1709 if (!(updateFlags & ESYSUPDATE_EDITOR))
1711 m_pPluginManager->UpdateAfterRenderSubmit();
1714 if (!(updateFlags & ESYSUPDATE_EDITOR))
1716 if (m_env.pStatoscope)
1718 m_env.pStatoscope->Tick();
1721 if (ITextModeConsole* pTextModeConsole = GetITextModeConsole())
1723 pTextModeConsole->EndDraw();
1726 m_env.p3DEngine->SyncProcessStreamingUpdate();
1728 if(m_pProfilingSystem)
1729 m_pProfilingSystem->EndFrame();
1732 SleepIfNeeded();
1733 return continueRunning;
1736 //////////////////////////////////////////////////////////////////////
1737 bool CSystem::Update(CEnumFlags<ESystemUpdateFlags> updateFlags, int nPauseMode)
1739 CRY_PROFILE_REGION(PROFILE_SYSTEM, "System: Update");
1740 CRY_PROFILE_FUNCTION(PROFILE_SYSTEM)
1741 MEMSTAT_CONTEXT(EMemStatContextType::Other, "CSystem::Update");
1743 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
1744 // do the dedicated sleep earlier than the frame profiler to avoid having it counted
1745 if (gEnv->IsDedicated())
1747 #if defined(MAP_LOADING_SLICING)
1748 gEnv->pSystemScheduler->SchedulingSleepIfNeeded();
1749 #endif // defined(MAP_LOADING_SLICING)
1751 #endif //EXCLUDE_UPDATE_ON_CONSOLE
1752 #if CAPTURE_REPLAY_LOG
1753 if (CryGetIMemoryManager() && CryGetIMemReplay())
1755 CryGetIMemReplay()->AddFrameStart();
1756 if ((--m_ttMemStatSS) <= 0)
1758 CryGetIMemReplay()->AddScreenshot();
1759 m_ttMemStatSS = 30;
1762 #endif //CAPTURE_REPLAY_LOG
1764 gEnv->pOverloadSceneManager->Update();
1766 m_pPlatformOS->Tick(m_Time.GetRealFrameTime());
1768 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
1769 if (g_cvars.sys_keyboard_break && !g_breakListenerOn)
1771 #if CRY_PLATFORM_WINDOWS
1772 if (m_env.IsEditor() && !g_pBreakHotkeyThread)
1774 g_pBreakHotkeyThread = new SBreakHotKeyThread();
1775 if (!gEnv->pThreadManager->SpawnThread(g_pBreakHotkeyThread, "WINAPI_BreakHotkeyListener"))
1777 CryFatalError("Error spawning \"WINAPI_BreakHotkeyListener\" thread.");
1780 #endif
1781 if (!gEnv->pThreadManager->SpawnThread(&g_BreakListenerTask, "BreakListener"))
1783 CryFatalError("Error spawning \"BreakListener\" thread.");
1785 gEnv->pInput->AddEventListener(&g_BreakListener);
1786 g_breakListenerOn = true;
1788 else if (!g_cvars.sys_keyboard_break && g_breakListenerOn)
1790 #if CRY_PLATFORM_WINDOWS
1791 if (g_pBreakHotkeyThread)
1792 g_pBreakHotkeyThread->SignalStopWork();
1793 #endif
1794 gEnv->pInput->RemoveEventListener(&g_BreakListener);
1795 g_BreakListenerTask.SignalStopWork();
1796 g_breakListenerOn = false;
1798 #endif //EXCLUDE_UPDATE_ON_CONSOLE
1800 m_nUpdateCounter++;
1801 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
1802 if (!m_sDelayedScreeenshot.empty())
1804 gEnv->pRenderer->ScreenShot(m_sDelayedScreeenshot.c_str());
1805 m_sDelayedScreeenshot.clear();
1808 if (m_pUserCallback)
1809 m_pUserCallback->OnUpdate();
1811 //////////////////////////////////////////////////////////////////////////
1812 // Enable/Disable floating exceptions.
1813 //////////////////////////////////////////////////////////////////////////
1814 prev_sys_float_exceptions += 1 + g_cvars.sys_float_exceptions & prev_sys_float_exceptions >> 31;
1815 if (prev_sys_float_exceptions != g_cvars.sys_float_exceptions)
1817 prev_sys_float_exceptions = g_cvars.sys_float_exceptions;
1818 m_env.pThreadManager->EnableFloatExceptions((EFPE_Severity) g_cvars.sys_float_exceptions); // Set FP Exceptions for this thread
1819 m_env.pThreadManager->EnableFloatExceptionsForEachOtherThread((EFPE_Severity)g_cvars.sys_float_exceptions); // Set FP Exceptions for all other threads
1821 #endif //EXCLUDE_UPDATE_ON_CONSOLE
1822 //////////////////////////////////////////////////////////////////////////
1824 CTimeValue updateStart = gEnv->pTimer->GetAsyncTime();
1826 if (m_env.pLog)
1828 MEMSTAT_CONTEXT(EMemStatContextType::Other, "Log::Update");
1829 m_env.pLog->Update();
1832 #if !defined(RELEASE) || defined(RELEASE_LOGGING)
1833 GetIRemoteConsole()->Update();
1834 #endif
1836 if (gEnv->pLocalMemoryUsage != NULL)
1838 gEnv->pLocalMemoryUsage->OnUpdate();
1841 if (!gEnv->IsEditor() && gEnv->pRenderer)
1843 CCamera rCamera = GetViewCamera();
1845 // if aspect ratio changes or is different from default we need to update camera
1846 const float fNewAspectRatio = gEnv->pRenderer->GetPixelAspectRatio();
1847 const int nNewWidth = gEnv->pRenderer->GetOverlayWidth();
1848 const int nNewHeight = gEnv->pRenderer->GetOverlayHeight();
1850 if ((fNewAspectRatio != rCamera.GetPixelAspectRatio()) ||
1851 (nNewWidth != rCamera.GetViewSurfaceX()) ||
1852 (nNewHeight != rCamera.GetViewSurfaceZ()))
1854 rCamera.SetFrustum(
1855 nNewWidth,
1856 nNewHeight,
1857 rCamera.GetFov(),
1858 rCamera.GetNearPlane(),
1859 rCamera.GetFarPlane(),
1860 fNewAspectRatio);
1862 SetViewCamera(rCamera);
1866 #if defined (CRY_TESTING) && !defined(EXCLUDE_UPDATE_ON_CONSOLE)
1867 if (m_pTestSystem)
1868 m_pTestSystem->Update();
1869 #endif
1870 if (nPauseMode != 0)
1871 m_bPaused = true;
1872 else
1873 m_bPaused = false;
1875 if (m_pStreamEngine)
1877 m_pStreamEngine->Update();
1879 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
1880 if (m_bIgnoreUpdates)
1881 return true;
1882 #endif //EXCLUDE_UPDATE_ON_CONSOLE
1884 const bool bNotLoading = !IsLoading();
1886 if (m_env.pCharacterManager)
1888 if (bNotLoading)
1890 m_env.pCharacterManager->Update(nPauseMode != 0);
1892 else
1894 m_env.pCharacterManager->DummyUpdate();
1898 bool bNoUpdate = false;
1899 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
1900 //check what is the current process
1901 IProcess* pProcess = GetIProcess();
1902 if (!pProcess)
1903 return (true); //should never happen
1905 if (m_sysNoUpdate && m_sysNoUpdate->GetIVal())
1907 bNoUpdate = true;
1908 updateFlags = { ESYSUPDATE_IGNORE_AI, ESYSUPDATE_IGNORE_PHYSICS };
1911 m_bNoUpdate = bNoUpdate;
1912 #endif //EXCLUDE_UPDATE_ON_CONSOLE
1913 //check if we are quitting from the game
1914 if (IsQuitting())
1915 return (false);
1917 #if CRY_PLATFORM_WINDOWS
1918 // process window messages
1920 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:PeekMessageW");
1922 if (m_hWnd && ::IsWindow((HWND)m_hWnd))
1924 PumpWindowMessage(true, m_hWnd);
1927 #endif
1929 //////////////////////////////////////////////////////////////////////
1930 //update time subsystem
1931 m_Time.UpdateOnFrameStart();
1933 // Don't do a thing if we're not in a level
1934 if (m_env.p3DEngine && bNotLoading)
1935 m_env.p3DEngine->OnFrameStart();
1937 //////////////////////////////////////////////////////////////////////
1938 // update rate limiter for dedicated server
1939 if (m_pServerThrottle.get())
1940 m_pServerThrottle->Update();
1942 //////////////////////////////////////////////////////////////////////
1943 // initial network update
1944 if (m_env.pNetwork)
1946 m_env.pNetwork->SyncWithGame(eNGS_FrameStart);
1949 //////////////////////////////////////////////////////////////////////////
1950 // Update script system.
1951 if (m_env.pScriptSystem && bNotLoading)
1953 m_env.pScriptSystem->Update();
1956 if (m_env.pInput)
1958 bool updateInput =
1959 !(updateFlags & ESYSUPDATE_EDITOR) ||
1960 (updateFlags & ESYSUPDATE_EDITOR_AI_PHYSICS);
1961 if (updateInput)
1963 //////////////////////////////////////////////////////////////////////
1964 //update input system
1965 #if !CRY_PLATFORM_WINDOWS
1966 m_env.pInput->Update(true);
1967 #else
1968 bool bFocus = (::GetForegroundWindow() == m_hWnd) || m_env.IsEditor();
1970 WriteLock lock(g_lockInput);
1971 m_env.pInput->Update(bFocus);
1972 g_BreakListenerTask.m_nBreakIdle = 0;
1974 #endif
1978 if (m_pHmdManager && m_sys_vr_support->GetIVal())
1980 m_pHmdManager->UpdateTracking(eVRComponent_All);
1983 if (m_env.pPhysicalWorld && m_env.pPhysicalWorld->GetPhysVars()->bForceSyncPhysics)
1985 if (m_PhysThread)
1986 static_cast<CPhysicsThreadTask*>(m_PhysThread)->EnsureStepDone();
1989 //////////////////////////////////////////////////////////////////////////
1990 //update the dynamic response system.
1991 if (m_env.pDynamicResponseSystem)
1993 m_env.pDynamicResponseSystem->Update();
1996 //////////////////////////////////////////////////////////////////////////
1997 //update the mono runtime
1998 if (m_env.pMonoRuntime)
2000 m_env.pMonoRuntime->Update(updateFlags.UnderlyingValue(), nPauseMode);
2003 //////////////////////////////////////////////////////////////////////
2004 //update console system
2005 if (m_env.pConsole)
2007 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:Console");
2009 if (!(updateFlags & ESYSUPDATE_EDITOR))
2010 m_env.pConsole->Update();
2012 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
2013 //////////////////////////////////////////////////////////////////////
2014 //update notification network system
2015 if (m_pNotificationNetwork)
2017 m_pNotificationNetwork->Update();
2019 #endif //EXCLUDE_UPDATE_ON_CONSOLE
2021 // When in Editor and outside of Game Mode we will need to update the listeners here.
2022 // But when in Editor and in Game Mode the ViewSystem will update the listeners.
2023 if (!m_env.IsEditorGameMode())
2025 if (updateFlags.Check(ESYSUPDATE_EDITOR) && !bNoUpdate && nPauseMode != 1)
2027 gEnv->pGameFramework->GetIViewSystem()->UpdateAudioListeners();
2031 //////////////////////////////////////////////////////////////////////////
2032 // Update Resource Manager.
2033 //////////////////////////////////////////////////////////////////////////
2034 m_pResourceManager->Update();
2036 //////////////////////////////////////////////////////////////////////
2037 // update physic system
2038 //static float time_zero = 0;
2039 if (!m_bUIFrameworkMode && bNotLoading)
2041 if (m_sys_physics_enable_MT->GetIVal() > 0 && !gEnv->IsDedicated())
2042 CreatePhysicsThread();
2043 else
2044 KillPhysicsThread();
2046 static int g_iPausedPhys = 0;
2047 PhysicsVars* pVars = m_env.pPhysicalWorld->GetPhysVars();
2048 pVars->threadLag = 0;
2050 CPhysicsThreadTask* pPhysicsThreadTask = ((CPhysicsThreadTask*)m_PhysThread);
2051 if (!pPhysicsThreadTask)
2053 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SystemUpdate: AllAIAndPhysics");
2055 //////////////////////////////////////////////////////////////////////
2056 // update entity system (a little bit) before physics
2057 if (nPauseMode != 1 && !bNoUpdate)
2059 PrePhysicsUpdate();
2062 // intermingle physics/AI updates so that if we get a big timestep (frame rate glitch etc) the
2063 // AI gets to steer entities before they travel over cliffs etc.
2064 float maxTimeStep = 0.0f;
2065 if (m_env.pAISystem)
2066 maxTimeStep = m_env.pAISystem->GetUpdateInterval();
2067 else
2068 maxTimeStep = 0.25f;
2069 int maxSteps = 1;
2070 float fCurTime = m_Time.GetCurrTime();
2071 //float fPrevTime = m_env.pPhysicalWorld->GetPhysicsTime();
2072 float timeToDo = m_Time.GetFrameTime();//fCurTime - fPrevTime;
2073 if (m_env.bMultiplayer)
2074 timeToDo = m_Time.GetRealFrameTime();
2075 m_env.pPhysicalWorld->TracePendingRays();
2077 while (timeToDo > 0.0001f && maxSteps-- > 0)
2079 float thisStep = min(maxTimeStep, timeToDo);
2080 timeToDo -= thisStep;
2082 if ((nPauseMode != 1) && !(updateFlags & ESYSUPDATE_IGNORE_PHYSICS) && g_cvars.sys_physics && !bNoUpdate)
2084 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:Physics");
2086 //int iPrevTime = m_env.pPhysicalWorld->GetiPhysicsTime();
2087 //float fPrevTime=m_env.pPhysicalWorld->GetPhysicsTime();
2088 pVars->bMultithreaded = 0;
2089 pVars->timeScalePlayers = 1.0f;
2090 if (!(updateFlags & ESYSUPDATE_MULTIPLAYER))
2091 m_env.pPhysicalWorld->TimeStep(thisStep);
2092 else
2094 //@TODO: fixed step in game.
2096 if (m_env.pGame->UseFixedStep())
2098 m_env.pPhysicalWorld->TimeStep(fCurTime-fPrevTime, 0);
2099 int iCurTime = m_env.pPhysicalWorld->GetiPhysicsTime();
2101 m_env.pPhysicalWorld->SetiPhysicsTime(m_env.pGame->SnapTime(iPrevTime));
2102 int i, iStep=m_env.pGame->GetiFixedStep();
2103 float fFixedStep = m_env.pGame->GetFixedStep();
2104 for(i=min(20*iStep,m_env.pGame->SnapTime(iCurTime)-m_pGame->SnapTime(iPrevTime)); i>0; i-=iStep)
2106 m_env.pGame->ExecuteScheduledEvents();
2107 m_env.pPhysicalWorld->TimeStep(fFixedStep, ent_rigid|ent_skip_flagged);
2110 m_env.pPhysicalWorld->SetiPhysicsTime(iPrevTime);
2111 m_env.pPhysicalWorld->TimeStep(fCurTime-fPrevTime, ent_rigid|ent_flagged_only);
2113 m_env.pPhysicalWorld->SetiPhysicsTime(iPrevTime);
2114 m_env.pPhysicalWorld->TimeStep(fCurTime-fPrevTime, ent_living|ent_independent|ent_deleted);
2116 else
2118 m_env.pPhysicalWorld->TimeStep(thisStep);
2121 g_iPausedPhys = 0;
2123 else if (!(g_iPausedPhys++ & 31))
2124 m_env.pPhysicalWorld->TimeStep(0); // make sure objects get all notifications; flush deleted ents
2125 gEnv->pPhysicalWorld->TracePendingRays(2);
2127 if (bNotLoading)
2129 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:PumpLoggedEvents");
2130 m_env.pPhysicalWorld->PumpLoggedEvents();
2133 // now AI
2134 if ((nPauseMode == 0) && !(updateFlags & ESYSUPDATE_IGNORE_AI) && g_cvars.sys_ai && !bNoUpdate)
2136 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:AI");
2137 //////////////////////////////////////////////////////////////////////
2138 //update AI system - match physics
2139 if (m_env.pAISystem && !m_cvAIUpdate->GetIVal() && g_cvars.sys_ai)
2140 m_env.pAISystem->Update(gEnv->pTimer->GetFrameStartTime(), gEnv->pTimer->GetFrameTime());
2144 // Make sure we don't lag too far behind
2145 if ((nPauseMode != 1) && !(updateFlags & ESYSUPDATE_IGNORE_PHYSICS))
2147 if (fabsf(m_env.pPhysicalWorld->GetPhysicsTime() - fCurTime) > 0.01f)
2149 //GetILog()->LogToConsole("Adjusting physical world clock by %.5f", fCurTime-m_env.pPhysicalWorld->GetPhysicsTime());
2150 m_env.pPhysicalWorld->SetPhysicsTime(fCurTime);
2154 else
2156 if (bNotLoading)
2158 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:PumpLoggedEvents");
2159 m_env.pPhysicalWorld->PumpLoggedEvents();
2162 //////////////////////////////////////////////////////////////////////
2163 // update entity system (a little bit) before physics
2164 if (nPauseMode != 1 && !bNoUpdate)
2166 PrePhysicsUpdate();
2169 if ((nPauseMode != 1) && !(updateFlags & ESYSUPDATE_IGNORE_PHYSICS))
2171 pPhysicsThreadTask->Resume();
2172 float lag = pPhysicsThreadTask->GetRequestedStep();
2174 if (pPhysicsThreadTask->RequestStep(m_Time.GetFrameTime()))
2176 pVars->threadLag = lag + m_Time.GetFrameTime();
2177 //GetILog()->Log("Physics thread lags behind; accum time %.3f", pVars->threadLag);
2180 else
2182 pPhysicsThreadTask->Pause();
2183 m_env.pPhysicalWorld->TracePendingRays();
2184 m_env.pPhysicalWorld->TracePendingRays(2);
2185 m_env.pPhysicalWorld->TimeStep(0);
2187 if ((nPauseMode == 0) && !(updateFlags & ESYSUPDATE_IGNORE_AI) && g_cvars.sys_ai && !bNoUpdate)
2189 CRY_PROFILE_REGION(PROFILE_SYSTEM, "SysUpdate:AI");
2190 //////////////////////////////////////////////////////////////////////
2191 //update AI system
2192 if (m_env.pAISystem && !m_cvAIUpdate->GetIVal())
2193 m_env.pAISystem->Update(gEnv->pTimer->GetFrameStartTime(), gEnv->pTimer->GetFrameTime());
2196 pe_params_waterman pwm;
2197 pwm.posViewer = GetViewCamera().GetPosition();
2198 m_env.pPhysicalWorld->SetWaterManagerParams(&pwm);
2201 // Use UI timer for CryMovie, because it should not be affected by pausing game time
2202 const float fMovieFrameTime = m_Time.GetFrameTime(ITimer::ETIMER_UI);
2204 // Run movie system pre-update
2205 if (!bNoUpdate)
2207 UpdateMovieSystem(updateFlags.UnderlyingValue(), fMovieFrameTime, true);
2210 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
2211 if (nPauseMode != 1)
2212 #endif //EXCLUDE_UPDATE_ON_CONSOLE
2214 //////////////////////////////////////////////////////////////////////
2215 //update entity system
2216 if (m_env.pEntitySystem && !bNoUpdate && g_cvars.sys_entitysystem)
2218 m_env.pEntitySystem->Update();
2222 // Run movie system post-update
2223 if (!bNoUpdate)
2225 UpdateMovieSystem(updateFlags.UnderlyingValue(), fMovieFrameTime, false);
2228 //////////////////////////////////////////////////////////////////////
2229 //update process (3D engine)
2230 if (!(updateFlags & ESYSUPDATE_EDITOR) && !bNoUpdate)
2232 if (ITimeOfDay* pTOD = m_env.p3DEngine->GetTimeOfDay())
2233 pTOD->Tick();
2235 if (m_env.p3DEngine)
2236 m_env.p3DEngine->Tick(); // clear per frame temp data
2238 if (m_pProcess && (m_pProcess->GetFlags() & PROC_3DENGINE))
2240 if ((nPauseMode != 1))
2241 if (!IsEquivalent(m_ViewCamera.GetPosition(), Vec3(0, 0, 0), VEC_EPSILON))
2243 if (m_env.p3DEngine)
2245 // m_env.p3DEngine->SetCamera(m_ViewCamera);
2246 m_pProcess->Update();
2247 #ifndef EXCLUDE_UPDATE_ON_CONSOLE
2248 //////////////////////////////////////////////////////////////////////////
2249 // Strange, !do not remove... ask Timur for the meaning of this.
2250 //////////////////////////////////////////////////////////////////////////
2251 if (m_nStrangeRatio > 32767)
2253 gEnv->pScriptSystem->SetGCFrequency(-1); // lets get nasty.
2255 //////////////////////////////////////////////////////////////////////////
2256 // Strange, !do not remove... ask Timur for the meaning of this.
2257 //////////////////////////////////////////////////////////////////////////
2258 if (m_nStrangeRatio > 1000)
2260 if (m_pProcess && (m_pProcess->GetFlags() & PROC_3DENGINE))
2261 m_nStrangeRatio += cry_random(1, 11);
2263 #endif //EXCLUDE_UPDATE_ON_CONSOLE
2264 //////////////////////////////////////////////////////////////////////////
2268 else
2270 if (m_pProcess)
2271 m_pProcess->Update();
2275 //////////////////////////////////////////////////////////////////////
2276 //update sound system part 2
2277 if (!bNoUpdate)
2279 UpdateAudioSystems();
2282 //////////////////////////////////////////////////////////////////////
2283 // final network update
2284 if (m_env.pNetwork)
2286 m_env.pNetwork->SyncWithGame(eNGS_FrameEnd);
2287 m_env.pNetwork->SyncWithGame(eNGS_DisplayDebugInfo);
2288 m_env.pNetwork->SyncWithGame(eNGS_WakeNetwork); // This will wake the network thread up
2291 #ifdef DOWNLOAD_MANAGER
2292 if (m_pDownloadManager && !bNoUpdate)
2294 m_pDownloadManager->Update();
2296 #endif //DOWNLOAD_MANAGER
2297 #if !CRY_PLATFORM_LINUX && !CRY_PLATFORM_ANDROID && !CRY_PLATFORM_ORBIS
2298 if (m_sys_SimulateTask->GetIVal() > 0)
2300 // have a chance to win longest Pi calculation content
2301 int64 delay = m_sys_SimulateTask->GetIVal();
2302 int64 start = CryGetTicks();
2303 double a = 1.0, b = 1.0 / sqrt(2.0), t = 1.0 / 4.0, p = 1.0, an, bn, tn, pn, Pi = 0.0;
2304 while (CryGetTicks() - start < delay)
2306 // do something
2307 an = (a + b) / 2.0;
2308 bn = sqrt(a * b);
2309 tn = t - p * (a - an) * (a - an);
2310 pn = 2 * p;
2312 a = an;
2313 b = bn;
2314 t = tn;
2315 p = pn;
2317 Pi = (a + b) * (a + b) / 4 / t;
2319 //CryLog("Task calculate PI = %f ", Pi); // Thats funny , but it works :-)
2321 #endif
2323 //////////////////////////////////////////////////////////////////////////
2324 //update stats agent
2325 #ifdef ENABLE_STATS_AGENT
2326 CStatsAgent::Update();
2327 #endif // #ifdef ENABLE_STATS_AGENT
2329 m_pSystemEventDispatcher->Update();
2331 if (gEnv->pSchematyc != nullptr)
2333 gEnv->pSchematyc->Update();
2336 if (gEnv->pSchematyc2 != nullptr)
2338 gEnv->pSchematyc2->Update();
2341 if (m_env.pHardwareMouse != nullptr)
2343 m_env.pHardwareMouse->Update();
2346 //Now update frame statistics
2347 CTimeValue cur_time = gEnv->pTimer->GetAsyncTime();
2349 CTimeValue a_second(g_cvars.sys_update_profile_time);
2350 std::vector<std::pair<CTimeValue, float>>::iterator it = m_updateTimes.begin();
2351 for (std::vector<std::pair<CTimeValue, float>>::iterator eit = m_updateTimes.end(); it != eit; ++it)
2352 if ((cur_time - it->first) < a_second)
2353 break;
2355 if (it != m_updateTimes.begin())
2356 m_updateTimes.erase(m_updateTimes.begin(), it);
2358 float updateTime = (cur_time - updateStart).GetMilliSeconds();
2359 m_updateTimes.push_back(std::make_pair(cur_time, updateTime));
2361 UpdateUpdateTimes();
2363 return !m_bQuit;
2366 IManualFrameStepController* CSystem::GetManualFrameStepController() const
2368 return m_pManualFrameStepController;
2371 bool CSystem::UpdateLoadtime()
2373 m_pPlatformOS->Tick(m_Time.GetRealFrameTime());
2376 // uncomment this code if input processing is required
2377 // during level loading
2378 if (m_env.pInput)
2380 //////////////////////////////////////////////////////////////////////
2381 //update input system
2382 #if !CRY_PLATFORM_WINDOWS
2383 m_env.pInput->Update(true);
2384 #else
2385 bool bFocus = (GetFocus()==m_hWnd) || m_bEditor;
2387 WriteLock lock(g_lockInput);
2388 m_env.pInput->Update(bFocus);
2389 g_BreakListenerTask.m_nBreakIdle = 0;
2391 #endif
2395 return !m_bQuit;
2398 void CSystem::UpdateAudioSystems()
2400 const bool isLoadInProgress = m_systemGlobalState > ESYSTEM_GLOBAL_STATE_INIT &&
2401 m_systemGlobalState <= ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END;
2403 if (m_env.pAudioSystem != nullptr && !isLoadInProgress) //do not update pAudioSystem during async level load
2405 CRY_PROFILE_SECTION(PROFILE_SYSTEM, "UpdateAudioSystems");
2407 m_env.pAudioSystem->ExternalUpdate();
2411 //////////////////////////////////////////////////////////////////////////
2412 void CSystem::GetUpdateStats(SSystemUpdateStats& stats)
2414 if (m_updateTimes.empty())
2416 stats = SSystemUpdateStats();
2418 else
2420 stats.avgUpdateTime = 0;
2421 stats.maxUpdateTime = -FLT_MAX;
2422 stats.minUpdateTime = +FLT_MAX;
2423 for (std::vector<std::pair<CTimeValue, float>>::const_iterator it = m_updateTimes.begin(), eit = m_updateTimes.end(); it != eit; ++it)
2425 const float t = it->second;
2426 stats.avgUpdateTime += t;
2427 stats.maxUpdateTime = max(stats.maxUpdateTime, t);
2428 stats.minUpdateTime = min(stats.minUpdateTime, t);
2430 stats.avgUpdateTime /= m_updateTimes.size();
2432 size_t sz = m_updateTimes.size();
2433 if (sz > 1)
2435 const std::pair<CTimeValue, float> head = m_updateTimes.front();
2436 const std::pair<CTimeValue, float> tail = m_updateTimes.back();
2437 stats.avgUpdateRate = (sz - 1) / (tail.first - head.first).GetSeconds();
2439 else
2441 stats.avgUpdateRate = 0.0f;
2446 //////////////////////////////////////////////////////////////////////////
2447 void CSystem::UpdateMovieSystem(const int updateFlags, const float fFrameTime, const bool bPreUpdate)
2449 if (m_env.pMovieSystem && !(updateFlags & ESYSUPDATE_EDITOR) && g_cvars.sys_trackview)
2451 float fMovieFrameTime = fFrameTime;
2453 if (fMovieFrameTime > g_cvars.sys_maxTimeStepForMovieSystem)
2454 fMovieFrameTime = g_cvars.sys_maxTimeStepForMovieSystem;
2456 if (bPreUpdate)
2458 m_env.pMovieSystem->PreUpdate(fMovieFrameTime);
2460 else
2462 m_env.pMovieSystem->PostUpdate(fMovieFrameTime);
2467 //////////////////////////////////////////////////////////////////////////
2468 // XML stuff
2469 //////////////////////////////////////////////////////////////////////////
2471 //////////////////////////////////////////////////////////////////////////
2472 XmlNodeRef CSystem::CreateXmlNode(const char* sNodeName, bool bReuseStrings)
2474 return new CXmlNode(sNodeName, bReuseStrings);
2477 //////////////////////////////////////////////////////////////////////////
2478 IXmlUtils* CSystem::GetXmlUtils()
2480 return m_pXMLUtils;
2483 //////////////////////////////////////////////////////////////////////////
2484 void CSystem::SetViewCamera(CCamera& Camera)
2486 m_ViewCamera = Camera;
2487 m_ViewCamera.CalculateRenderMatrices();
2490 //////////////////////////////////////////////////////////////////////////
2491 XmlNodeRef CSystem::LoadXmlFromFile(const char* sFilename, bool bReuseStrings)
2493 LOADING_TIME_PROFILE_SECTION_ARGS(sFilename);
2495 return m_pXMLUtils->LoadXmlFromFile(sFilename, bReuseStrings);
2498 //////////////////////////////////////////////////////////////////////////
2499 XmlNodeRef CSystem::LoadXmlFromBuffer(const char* buffer, size_t size, bool bReuseStrings)
2501 LOADING_TIME_PROFILE_SECTION
2502 return m_pXMLUtils->LoadXmlFromBuffer(buffer, size, bReuseStrings);
2505 //////////////////////////////////////////////////////////////////////////
2506 bool CSystem::CheckLogVerbosity(int verbosity)
2508 if (verbosity <= m_env.pLog->GetVerbosityLevel())
2509 return true;
2510 return false;
2513 //////////////////////////////////////////////////////////////////////////
2514 void CSystem::Warning(EValidatorModule module, EValidatorSeverity severity, int flags, const char* file, const char* format, ...)
2516 va_list args;
2517 va_start(args, format);
2518 WarningV(module, severity, flags, file, format, args);
2519 va_end(args);
2522 //////////////////////////////////////////////////////////////////////////
2523 void CSystem::WarningOnce(EValidatorModule module, EValidatorSeverity severity, int flags, const char* file, const char* format, ...)
2525 char szBuffer[MAX_WARNING_LENGTH];
2526 va_list args;
2527 va_start(args, format);
2528 cry_vsprintf(szBuffer, format, args);
2529 va_end(args);
2531 CryAutoLock<CryMutex> lock(m_mapWarningOnceMutex);
2532 uint32 crc = CCrc32::ComputeLowercase(szBuffer);
2533 if (m_mapWarningOnceAlreadyPrinted.find(crc) == m_mapWarningOnceAlreadyPrinted.end())
2535 m_mapWarningOnceAlreadyPrinted[crc] = true;
2537 Warning(VALIDATOR_MODULE_ANIMATION, VALIDATOR_WARNING, VALIDATOR_FLAG_FILE, 0, szBuffer);
2541 inline const char* ValidatorModuleToString(EValidatorModule module)
2543 switch (module)
2545 case VALIDATOR_MODULE_RENDERER:
2546 return "Renderer";
2547 case VALIDATOR_MODULE_3DENGINE:
2548 return "3DEngine";
2549 case VALIDATOR_MODULE_ASSETS:
2550 return "Assets";
2551 case VALIDATOR_MODULE_AI:
2552 return "AI";
2553 case VALIDATOR_MODULE_ANIMATION:
2554 return "Animation";
2555 case VALIDATOR_MODULE_ENTITYSYSTEM:
2556 return "EntitySystem";
2557 case VALIDATOR_MODULE_SCRIPTSYSTEM:
2558 return "Script";
2559 case VALIDATOR_MODULE_SYSTEM:
2560 return "System";
2561 case VALIDATOR_MODULE_AUDIO:
2562 return "Audio";
2563 case VALIDATOR_MODULE_GAME:
2564 return "Game";
2565 case VALIDATOR_MODULE_MOVIE:
2566 return "Movie";
2567 case VALIDATOR_MODULE_EDITOR:
2568 return "Editor";
2569 case VALIDATOR_MODULE_NETWORK:
2570 return "Network";
2571 case VALIDATOR_MODULE_PHYSICS:
2572 return "Physics";
2573 case VALIDATOR_MODULE_FLOWGRAPH:
2574 return "FlowGraph";
2575 case VALIDATOR_MODULE_ONLINE:
2576 return "Online";
2577 case VALIDATOR_MODULE_DRS:
2578 return "DynamicResponseSystem";
2580 return "";
2583 //////////////////////////////////////////////////////////////////////////
2584 void CSystem::WarningV(EValidatorModule module, EValidatorSeverity severity, int flags, const char* file, const char* format, va_list args)
2586 // Fran: No logging in a testing environment
2587 if (m_env.pLog == 0)
2589 return;
2592 const char* sModuleFilter = m_env.pLog->GetModuleFilter();
2593 if (sModuleFilter && *sModuleFilter != 0)
2595 const char* sModule = ValidatorModuleToString(module);
2596 if (strlen(sModule) > 1 || CryStringUtils::stristr(sModule, sModuleFilter) == 0)
2598 // Filter out warnings from other modules.
2599 return;
2603 bool bDbgBreak = false;
2604 if (severity == VALIDATOR_ERROR_DBGBRK)
2606 bDbgBreak = true;
2607 severity = VALIDATOR_ERROR; // change it to a standard VALIDATOR_ERROR for simplicity in the rest of the system
2610 IMiniLog::ELogType ltype = ILog::eComment;
2611 switch (severity)
2613 case VALIDATOR_ERROR:
2614 ltype = ILog::eError;
2615 break;
2616 case VALIDATOR_WARNING:
2617 ltype = ILog::eWarning;
2618 break;
2619 case VALIDATOR_COMMENT:
2620 ltype = ILog::eComment;
2621 break;
2622 case VALIDATOR_ASSERT:
2623 ltype = ILog::eAssert;
2624 break;
2625 default:
2626 break;
2628 char szBuffer[MAX_WARNING_LENGTH];
2629 cry_vsprintf(szBuffer, format, args);
2631 if (file && *file)
2633 CryFixedStringT<MAX_WARNING_LENGTH> fmt = szBuffer;
2634 fmt += " [File=";
2635 fmt += file;
2636 fmt += "]";
2638 m_env.pLog->LogWithType(ltype, flags | VALIDATOR_FLAG_SKIP_VALIDATOR, "%s", fmt.c_str());
2640 else
2642 m_env.pLog->LogWithType(ltype, flags | VALIDATOR_FLAG_SKIP_VALIDATOR, "%s", szBuffer);
2645 //if(file)
2646 //m_env.pLog->LogWithType( ltype, " ... caused by file '%s'",file);
2648 if (m_pValidator && (flags & VALIDATOR_FLAG_SKIP_VALIDATOR) == 0)
2650 SValidatorRecord record;
2651 record.file = file;
2652 record.text = szBuffer;
2653 record.module = module;
2654 record.severity = severity;
2655 record.flags = flags;
2656 record.assetScope = m_env.pLog->GetAssetScopeString();
2657 m_pValidator->Report(record);
2660 #if !defined(_RELEASE)
2661 if (bDbgBreak && g_cvars.sys_error_debugbreak)
2662 __debugbreak();
2663 #endif
2666 //////////////////////////////////////////////////////////////////////////
2667 void CSystem::Deltree(const char* szFolder, bool bRecurse)
2669 __finddata64_t fd;
2670 string filespec = szFolder;
2671 filespec += "*.*";
2673 intptr_t hfil = 0;
2674 if ((hfil = _findfirst64(filespec.c_str(), &fd)) == -1)
2676 return;
2681 if (fd.attrib & _A_SUBDIR)
2683 string name = fd.name;
2685 if ((name != ".") && (name != ".."))
2687 if (bRecurse)
2689 name = szFolder;
2690 name += fd.name;
2691 name += "/";
2693 Deltree(name.c_str(), bRecurse);
2697 else
2699 string name = szFolder;
2701 name += fd.name;
2703 DeleteFile(name.c_str());
2707 while (!_findnext64(hfil, &fd));
2709 _findclose(hfil);
2711 RemoveDirectory(szFolder);
2714 //////////////////////////////////////////////////////////////////////////
2715 void CSystem::GetLocalizedPath(char const* const szLanguage, string& szLocalizedPath)
2717 string pakSuffix = (g_cvars.sys_localization_pak_suffix) ? g_cvars.sys_localization_pak_suffix->GetString() : "";
2718 szLocalizedPath = PathUtil::GetLocalizationFolder() + CRY_NATIVE_PATH_SEPSTR + szLanguage + pakSuffix + ".pak";
2721 //////////////////////////////////////////////////////////////////////////
2722 void CSystem::GetLocalizedAudioPath(char const* const szLanguage, string& szLocalizedPath)
2724 szLocalizedPath = PathUtil::GetLocalizationFolder() + CRY_NATIVE_PATH_SEPSTR + szLanguage + ".pak";
2727 //////////////////////////////////////////////////////////////////////////
2728 void CSystem::CloseLanguagePak(char const* const szLanguage)
2730 string szLocalizedPath;
2731 GetLocalizedPath(szLanguage, szLocalizedPath);
2732 m_env.pCryPak->ClosePacks(szLocalizedPath);
2735 //////////////////////////////////////////////////////////////////////////
2736 void CSystem::CloseLanguageAudioPak(char const* const szLanguage)
2738 string szLocalizedPath;
2739 GetLocalizedAudioPath(szLanguage, szLocalizedPath);
2740 m_env.pCryPak->ClosePacks(szLocalizedPath);
2743 #if CRY_PLATFORM_DURANGO
2744 //////////////////////////////////////////////////////////////////////////
2745 void CSystem::OnPLMEvent(EPLM_Event event)
2748 switch (event)
2750 case EPLMEV_ON_RESUMING:
2752 CryLogAlways("CSystem::OnPLMEvent --- OnResuming");
2753 if (m_pSystemEventDispatcher)
2754 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_PLM_ON_RESUMING, 0, 0);
2755 if (gEnv->pRenderer)
2756 gEnv->pRenderer->ResumeDevice();
2757 gEnv->ePLM_State = EPLM_RUNNING;
2758 break;
2761 case EPLMEV_ON_SUSPENDING:
2763 CryLogAlways("CSystem::OnPLMEvent --- OnSuspending");
2764 if (m_pSystemEventDispatcher)
2765 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_PLM_ON_SUSPENDING, 0, 0);
2766 if (gEnv->pRenderer)
2767 gEnv->pRenderer->SuspendDevice();
2768 gEnv->ePLM_State = EPLM_SUSPENDED;
2769 break;
2772 case EPLMEV_ON_CONSTRAINED:
2774 CryLogAlways("CSystem::OnPLMEvent --- OnConstrained");
2775 if (m_pSystemEventDispatcher)
2776 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_PLM_ON_CONSTRAINED, 0, 0);
2777 gEnv->ePLM_State = EPLM_CONSTRAINED;
2778 break;
2781 case EPLMEV_ON_FULL:
2783 CryLogAlways("CSystem::OnPLMEvent --- OnFull");
2784 if (m_pSystemEventDispatcher)
2785 m_pSystemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_PLM_ON_FULL, 0, 0);
2786 gEnv->ePLM_State = EPLM_RUNNING;
2787 break;
2790 default:
2792 CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Unhandled PLM Event!");
2793 break;
2797 #endif
2799 //////////////////////////////////////////////////////////////////////////
2800 void CSystem::UnloadSchematycModule()
2802 UnloadEngineModule("CrySchematyc");
2803 UnloadEngineModule("CrySchematyc2");
2805 gEnv->pSchematyc2 = nullptr;
2808 //////////////////////////////////////////////////////////////////////////
2809 void CSystem::Strange()
2811 m_nStrangeRatio += cry_random(1, 101);
2814 //////////////////////////////////////////////////////////////////////////
2815 void CSystem::Relaunch(bool bRelaunch)
2817 if (m_sys_firstlaunch)
2818 m_sys_firstlaunch->Set(0);
2820 m_bRelaunch = bRelaunch;
2821 SaveConfiguration();
2824 //////////////////////////////////////////////////////////////////////////
2825 ICrySizer* CSystem::CreateSizer()
2827 return new CrySizerImpl;
2830 //////////////////////////////////////////////////////////////////////////
2831 uint32 CSystem::GetUsedMemory()
2833 return CryMemoryGetAllocatedSize();
2836 //////////////////////////////////////////////////////////////////////////
2837 ILocalizationManager* CSystem::GetLocalizationManager()
2839 return m_pLocalizationManager;
2842 //////////////////////////////////////////////////////////////////////////
2843 IResourceManager* CSystem::GetIResourceManager()
2845 return m_pResourceManager;
2848 //////////////////////////////////////////////////////////////////////////
2849 void CSystem::debug_GetCallStackRaw(void** callstack, uint32& callstackLength)
2851 #if CRY_PLATFORM_ORBIS || CRY_PLATFORM_WINAPI
2852 uint32 callstackCapacity = callstackLength;
2853 #endif
2855 #if CRY_PLATFORM_WINAPI
2856 uint32 nNumStackFramesToSkip = 1;
2857 #endif
2859 memset(callstack, 0, sizeof(void*) * callstackLength);
2861 #if !CRY_PLATFORM_ANDROID
2862 callstackLength = 0;
2863 #endif
2865 #if CRY_PLATFORM_ORBIS
2866 uint csLength = 0;
2867 void** stack = NULL;
2868 __asm__ __volatile__ ("mov %%rbp, %0" : "=r" (stack)); // WARNING: This could be brittle
2869 while (csLength < callstackCapacity && stack)
2871 callstack[csLength] = stack[1];
2872 stack = (void**)stack[0];
2873 csLength++;
2875 callstackLength = csLength;
2876 #elif CRY_PLATFORM_WINAPI
2877 if (callstackCapacity > 0x40)
2878 callstackCapacity = 0x40;
2879 callstackLength = RtlCaptureStackBackTrace(nNumStackFramesToSkip, callstackCapacity, callstack, NULL);
2880 #endif
2882 static int aaa = 0;
2883 aaa++;
2885 if ((aaa & 0xF) == 0)
2887 CryLogAlways( "RtlCaptureStackBackTrace = (%d)",callstackLength );
2888 for (int i=0; i<callstackLength; i++)
2890 CryLogAlways( " [%d] = (%X)",i,callstack[i] );
2894 callstackLength = IDebugCallStack::instance()->CollectCallStackFrames( callstack,callstackCapacity );
2895 if ((aaa & 0xF) == 0)
2897 CryLogAlways( "StackWalk64 = (%d)",callstackLength );
2898 for (int i=0; i<callstackLength; i++)
2900 CryLogAlways( " [%d] = (%X)",i,callstack[i] );
2905 if (callstackLength > 0)
2907 std::reverse(callstack, callstack + callstackLength);
2911 //////////////////////////////////////////////////////////////////////////
2912 void CSystem::ExecuteCommandLine()
2914 LOADING_TIME_PROFILE_SECTION;
2915 // should only be called once
2917 static bool bCalledAlready = false;
2918 assert(!bCalledAlready);
2919 bCalledAlready = true;
2922 // auto detect system spec (overrides profile settings)
2923 if (m_pCmdLine->FindArg(eCLAT_Pre, "autodetect"))
2924 AutoDetectSpec(false);
2926 // execute command line arguments e.g. +g_gametype ASSAULT +map "testy"
2928 ICmdLine* pCmdLine = GetICmdLine();
2929 assert(pCmdLine);
2931 const int iCnt = pCmdLine->GetArgCount();
2933 for (int i = 0; i < iCnt; ++i)
2935 const ICmdLineArg* pCmd = pCmdLine->GetArg(i);
2937 if (pCmd->GetType() == eCLAT_Post)
2939 string sLine = pCmd->GetName();
2941 if (gEnv->pSystem->IsCVarWhitelisted(sLine.c_str(), false))
2943 if (pCmd->GetValue())
2944 sLine += string(" ") + pCmd->GetValue();
2946 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)
2947 GetIConsole()->ExecuteString(sLine.c_str(), false, !m_bShaderCacheGenMode);
2949 #if defined(DEDICATED_SERVER)
2950 else
2952 GetILog()->LogError("Failed to execute command: '%s' as it is not whitelisted\n", sLine.c_str());
2954 #endif
2958 //gEnv->pConsole->ExecuteString("sys_RestoreSpec test*"); // to get useful debugging information about current spec settings to the log file
2961 ITextModeConsole* CSystem::GetITextModeConsole()
2963 if (m_env.IsDedicated())
2964 return m_pTextModeConsole;
2966 return 0;
2969 //////////////////////////////////////////////////////////////////////////
2970 ESystemConfigSpec CSystem::GetConfigSpec(bool bClient)
2972 if (bClient)
2974 if (m_sys_spec)
2975 return (ESystemConfigSpec)m_sys_spec->GetIVal();
2976 return CONFIG_VERYHIGH_SPEC; // highest spec.
2978 else
2979 return m_nServerConfigSpec;
2982 //////////////////////////////////////////////////////////////////////////
2983 void CSystem::SetConfigSpec(ESystemConfigSpec spec, bool bClient)
2985 if (bClient)
2987 if (m_sys_spec)
2988 m_sys_spec->Set((int)spec);
2990 else
2992 m_nServerConfigSpec = spec;
2996 //////////////////////////////////////////////////////////////////////////
2997 ESystemConfigSpec CSystem::GetMaxConfigSpec() const
2999 return m_nMaxConfigSpec;
3002 //////////////////////////////////////////////////////////////////////////
3003 Cry::IProjectManager* CSystem::GetIProjectManager()
3005 return m_pProjectManager;
3008 //////////////////////////////////////////////////////////////////////////
3009 CPNoise3* CSystem::GetNoiseGen()
3011 static CPNoise3 m_pNoiseGen;
3012 return &m_pNoiseGen;
3015 //////////////////////////////////////////////////////////////////////////
3016 sUpdateTimes& CSystem::GetCurrentUpdateTimeStats()
3018 return m_UpdateTimes[m_UpdateTimesIdx];
3021 //////////////////////////////////////////////////////////////////////////
3022 const sUpdateTimes* CSystem::GetUpdateTimeStats(uint32& index, uint32& num)
3024 index = m_UpdateTimesIdx;
3025 num = NUM_UPDATE_TIMES;
3026 return m_UpdateTimes;
3029 void CSystem::FillRandomMT(uint32* pOutWords, uint32 numWords)
3031 AUTO_LOCK(m_mtLock);
3032 if (!m_pMtState)
3034 struct TicksTime
3036 int64 ticks;
3037 time_t tm;
3040 TicksTime tt = { CryGetTicks(), time(nullptr) };
3041 m_pMtState = new CMTRand_int32(reinterpret_cast<uint32*>(&tt), sizeof(tt) / sizeof(uint32));
3044 for (uint32 i = 0; i < numWords; ++i)
3045 pOutWords[i] = m_pMtState->GenerateUint32();
3048 void CSystem::UpdateUpdateTimes()
3050 sUpdateTimes& sample = m_UpdateTimes[m_UpdateTimesIdx];
3051 if (m_PhysThread)
3053 static uint64 lastMainTime = 0U;
3054 static uint64 lastPhysWait = 0U;
3055 uint64 physTime = 0, mainTime = 0;
3056 uint32 yields = 0;
3057 physTime = ((CPhysicsThreadTask*)m_PhysThread)->LastStepTaken();
3058 mainTime = CryGetTicks() - lastMainTime;
3059 lastMainTime = mainTime;
3060 lastPhysWait = ((CPhysicsThreadTask*)m_PhysThread)->LastWaitTime();
3061 sample.PhysStepTime = physTime;
3062 sample.SysUpdateTime = mainTime;
3063 sample.PhysYields = yields;
3064 sample.physWaitTime = lastPhysWait;
3066 ++m_UpdateTimesIdx;
3067 if (m_UpdateTimesIdx >= NUM_UPDATE_TIMES) m_UpdateTimesIdx = 0;
3070 IPhysicsDebugRenderer* CSystem::GetIPhysicsDebugRenderer()
3072 return m_pPhysRenderer;
3075 IPhysRenderer* CSystem::GetIPhysRenderer()
3077 return m_pPhysRenderer;
3080 ICryProfilingSystem* CSystem::GetProfilingSystem()
3082 return m_pProfilingSystem;
3085 ILegacyProfiler* CSystem::GetLegacyProfilerInterface()
3087 return m_pLegacyProfiler;
3090 #ifndef _RELEASE
3091 void CSystem::GetCheckpointData(ICheckpointData& data)
3093 data.m_totalLoads = m_checkpointLoadCount;
3094 data.m_loadOrigin = m_loadOrigin;
3097 void CSystem::IncreaseCheckpointLoadCount()
3099 if (!m_hasJustResumed)
3100 ++m_checkpointLoadCount;
3102 m_hasJustResumed = false;
3105 void CSystem::SetLoadOrigin(LevelLoadOrigin origin)
3107 switch (origin)
3109 case eLLO_NewLevel: // Intentional fall through
3110 case eLLO_Level2Level:
3111 m_expectingMapCommand = true;
3112 break;
3114 case eLLO_Resumed:
3115 m_hasJustResumed = true;
3116 break;
3118 case eLLO_MapCmd:
3119 if (m_expectingMapCommand)
3121 // We knew a map command was coming, so don't process this.
3122 m_expectingMapCommand = false;
3123 return;
3125 break;
3128 m_loadOrigin = origin;
3129 m_checkpointLoadCount = 0;
3131 #endif
3133 //////////////////////////////////////////////////////////////////////
3134 void CSystem::OnLanguageCVarChanged(ICVar* const pLanguage)
3136 if (pLanguage != nullptr && pLanguage->GetType() == ECVarType::String)
3138 CSystem* const pSystem = static_cast<CSystem*>(gEnv->pSystem);
3140 if (pSystem != nullptr)
3142 CLocalizedStringsManager* const pLocalizationManager = static_cast<CLocalizedStringsManager* const>(pSystem->GetLocalizationManager());
3144 if (pLocalizationManager != nullptr)
3146 char const* const szCurrentLanguage = pLocalizationManager->GetLanguage();
3148 if (szCurrentLanguage != nullptr && szCurrentLanguage[0] != '\0')
3150 pSystem->CloseLanguagePak(szCurrentLanguage);
3153 CLocalizedStringsManager::TLocalizationTagVec tags;
3154 pLocalizationManager->GetLoadedTags(tags);
3155 pLocalizationManager->FreeLocalizationData();
3157 char const* const szNewLanguage = pLanguage->GetString();
3158 pSystem->OpenLanguagePak(szNewLanguage);
3159 pLocalizationManager->SetLanguage(szNewLanguage);
3161 for (auto& tag : tags)
3163 pLocalizationManager->LoadLocalizationDataByTag(tag.c_str());
3166 #if defined(INCLUDE_SCALEFORM_SDK) || defined(CRY_FEATURE_SCALEFORM_HELPER)
3167 if (gEnv->pScaleformHelper)
3169 gEnv->pScaleformHelper->SetTranslatorDirty(true);
3171 #endif
3177 //////////////////////////////////////////////////////////////////////
3178 void CSystem::OnLanguageAudioCVarChanged(ICVar* const pLanguageAudio)
3180 if (pLanguageAudio != nullptr && pLanguageAudio->GetType() == ECVarType::String)
3182 CSystem* const pSystem = static_cast<CSystem*>(gEnv->pSystem);
3184 if (pSystem != nullptr)
3186 char const* const szNewLanguage = pLanguageAudio->GetString();
3188 if (!pSystem->m_currentLanguageAudio.empty())
3190 pSystem->CloseLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());
3193 pSystem->OpenLanguageAudioPak(szNewLanguage);
3194 pSystem->m_currentLanguageAudio = szNewLanguage;
3196 pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_AUDIO_LANGUAGE_CHANGED, 0, 0);
3201 //////////////////////////////////////////////////////////////////////////
3202 void CSystem::OnLocalizationFolderCVarChanged(ICVar* const pLocalizationFolder)
3204 if (pLocalizationFolder && pLocalizationFolder->GetType() == ECVarType::String)
3206 CSystem* const pSystem = static_cast<CSystem* const>(gEnv->pSystem);
3208 if (pSystem != NULL && gEnv->pCryPak != NULL)
3210 CLocalizedStringsManager* const pLocalizationManager = static_cast<CLocalizedStringsManager* const>(pSystem->GetLocalizationManager());
3212 if (pLocalizationManager)
3214 // Get what is currently loaded
3215 CLocalizedStringsManager::TLocalizationTagVec tags;
3216 pLocalizationManager->GetLoadedTags(tags);
3218 // Release the old localization data.
3219 for (auto& tag : tags)
3221 pLocalizationManager->ReleaseLocalizationDataByTag(tag.c_str());
3224 // Close the paks situated in the previous localization folder.
3225 pSystem->CloseLanguagePak(pLocalizationManager->GetLanguage());
3226 pSystem->CloseLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());
3228 // Set the new localization folder.
3229 gEnv->pCryPak->SetLocalizationFolder(pLocalizationFolder->GetString());
3231 // Now open the paks situated in the new localization folder.
3232 pSystem->OpenLanguagePak(pLocalizationManager->GetLanguage());
3233 pSystem->OpenLanguageAudioPak(pSystem->m_currentLanguageAudio.c_str());
3235 // And load the new data.
3236 for (auto& tag : tags)
3238 pLocalizationManager->LoadLocalizationDataByTag(tag.c_str());
3245 void CSystem::OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam)
3247 switch (event)
3249 case ESYSTEM_EVENT_LEVEL_LOAD_END:
3251 SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END);
3253 break;
3254 case ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN:
3255 case ESYSTEM_EVENT_LEVEL_UNLOAD:
3257 gEnv->pCryPak->DisableRuntimeFileAccess(false);
3259 break;
3260 case ESYSTEM_EVENT_LEVEL_PRECACHE_END:
3262 if (!gEnv->IsEditing())
3264 gEnv->pCryPak->DisableRuntimeFileAccess(true);
3267 break;
3271 ESystemGlobalState CSystem::GetSystemGlobalState(void)
3273 return m_systemGlobalState;
3276 const char* CSystem::GetSystemGlobalStateName(const ESystemGlobalState systemGlobalState)
3278 static const char* const s_systemGlobalStateNames[] = {
3279 "INIT", // ESYSTEM_GLOBAL_STATE_INIT,
3280 "LEVEL_LOAD_PREPARE", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PREPARE,
3281 "LEVEL_LOAD_START", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START,
3282 "LEVEL_LOAD_MATERIALS", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_MATERIALS,
3283 "LEVEL_LOAD_OBJECTS", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_OBJECTS,
3284 "LEVEL_LOAD_CHARACTERS", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_CHARACTERS,
3285 "LEVEL_LOAD_STATIC_WORLD", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_STATIC_WORLD,
3286 "LEVEL_LOAD_ENTITIES", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_ENTITIES,
3287 "LEVEL_LOAD_PRECACHE", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PRECACHE,
3288 "LEVEL_LOAD_TEXTURES", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_TEXTURES,
3289 "LEVEL_LOAD_END", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_END,
3290 "LEVEL_LOAD_ENDING", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_ENDING,
3291 "LEVEL_LOAD_COMPLETE", // ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE
3292 "RUNNING", // ESYSTEM_GLOBAL_STATE_RUNNING,
3294 const size_t numElements = CRY_ARRAY_COUNT(s_systemGlobalStateNames);
3295 const size_t index = (size_t)systemGlobalState;
3296 if (index >= numElements)
3298 return "INVALID INDEX";
3300 return s_systemGlobalStateNames[index];
3303 void CSystem::SetSystemGlobalState(const ESystemGlobalState systemGlobalState)
3305 static CTimeValue s_startTime = CTimeValue();
3306 if (systemGlobalState != m_systemGlobalState)
3308 if (gEnv && gEnv->pTimer)
3310 #if !defined(EXCLUDE_NORMAL_LOG)
3311 const CTimeValue endTime = gEnv->pTimer->GetAsyncTime();
3312 const float numSeconds = endTime.GetDifferenceInSeconds(s_startTime);
3313 #endif
3314 CryLog("SetGlobalState %d->%d '%s'->'%s' %3.1f seconds",
3315 m_systemGlobalState, systemGlobalState,
3316 CSystem::GetSystemGlobalStateName(m_systemGlobalState), CSystem::GetSystemGlobalStateName(systemGlobalState),
3317 numSeconds);
3318 s_startTime = gEnv->pTimer->GetAsyncTime();
3321 m_systemGlobalState = systemGlobalState;
3324 //////////////////////////////////////////////////////////////////////////
3325 void CSystem::RegisterWindowMessageHandler(IWindowMessageHandler* pHandler)
3327 assert(pHandler && !stl::find(m_windowMessageHandlers, pHandler) && "This IWindowMessageHandler is already registered");
3328 m_windowMessageHandlers.push_back(pHandler);
3331 //////////////////////////////////////////////////////////////////////////
3332 void CSystem::UnregisterWindowMessageHandler(IWindowMessageHandler* pHandler)
3334 #if defined(USE_CRY_ASSERT)
3335 bool bRemoved = stl::find_and_erase(m_windowMessageHandlers, pHandler);
3336 assert(pHandler && bRemoved && "This IWindowMessageHandler was not registered");
3337 #else
3338 stl::find_and_erase(m_windowMessageHandlers, pHandler);
3339 #endif
3342 //////////////////////////////////////////////////////////////////////////
3343 int CSystem::PumpWindowMessage(bool bAll, CRY_HWND opaqueHWnd)
3345 #if CRY_PLATFORM_WINDOWS
3346 int count = 0;
3347 const HWND hWnd = (HWND)opaqueHWnd;
3348 const bool bUnicode = hWnd != NULL ?
3349 IsWindowUnicode(hWnd) != FALSE :
3350 !(gEnv && gEnv->IsEditor());
3351 #if defined(UNICODE) || defined(_UNICODE)
3352 // Once we compile as Unicode app on Windows, we should detect non-Unicode windows
3353 assert(bUnicode && "The window is not Unicode, this is most likely a bug");
3354 #endif
3356 // Pick the correct function for handling messages
3357 typedef BOOL (WINAPI * PeekMessageFunc)(MSG*, HWND, UINT, UINT, UINT);
3358 typedef LRESULT (WINAPI * DispatchMessageFunc)(const MSG*);
3359 const PeekMessageFunc pfnPeekMessage = bUnicode ? PeekMessageW : PeekMessageA;
3360 const DispatchMessageFunc pfnDispatchMessage = bUnicode ? DispatchMessageW : DispatchMessageA;
3364 // Get a new message
3365 MSG msg;
3366 BOOL bHasMessage = pfnPeekMessage(&msg, hWnd, 0, 0, PM_REMOVE);
3367 if (bHasMessage == FALSE) break;
3368 ++count;
3370 // Special case for WM_QUIT
3371 if (msg.message == WM_QUIT)
3373 return -1;
3376 if (msg.message == WM_ACTIVATE)
3378 if (msg.wParam != WA_INACTIVE)
3379 m_hWndActive = msg.hwnd;
3380 else
3381 m_hWndActive = (CRY_HWND)msg.lParam;
3383 // During the time demo, do not sleep even in inactive window.
3384 if (!gEnv->pGameFramework || !gEnv->pGameFramework->IsInTimeDemo())
3385 // use sys_maxFPS to throttle the engine
3386 m_throttleFPS = msg.wParam != WA_INACTIVE;
3389 // Pre-process the message for IME
3390 if (msg.hwnd == m_hWnd)
3392 for (std::vector<IWindowMessageHandler*>::const_iterator it = m_windowMessageHandlers.begin(); it != m_windowMessageHandlers.end(); ++it)
3394 IWindowMessageHandler* pHandler = *it;
3395 pHandler->PreprocessMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
3399 // Dispatch the message
3400 TranslateMessage(&msg);
3401 pfnDispatchMessage(&msg);
3403 while (bAll);
3405 return count;
3406 #else
3407 // No window message support on this platform
3408 return 0;
3409 #endif
3412 //////////////////////////////////////////////////////////////////////////
3413 bool CSystem::IsImeSupported() const
3415 assert(m_pImeManager != NULL);
3416 return m_pImeManager->IsImeSupported();
3419 //////////////////////////////////////////////////////////////////////////
3420 bool CSystem::IsCVarWhitelisted(const char* szName, bool silent) const
3422 CRY_ASSERT(szName != nullptr);
3424 if (szName[0] == '?')
3426 return true;
3429 if (szName[0] == '+')
3431 ++szName;
3434 const char* pNameEnd = std::max(strchr(szName, ' '), strchr(szName, '='));
3435 if (pNameEnd == nullptr)
3437 return ::IsCVarWhitelisted(szName);
3439 else
3441 const string name(szName, pNameEnd);
3442 return ::IsCVarWhitelisted(name.c_str());
3446 //////////////////////////////////////////////////////////////////////////
3447 #if CRY_PLATFORM_WINDOWS
3449 enum class EMouseWheelOrigin
3451 ScreenSpace,
3452 WindowSpace,
3453 WindowSpaceClamped
3456 #ifndef GET_X_LPARAM
3457 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
3458 #endif
3459 #ifndef GET_Y_LPARAM
3460 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
3461 #endif
3463 bool CSystem::HandleMessage(CRY_HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
3465 static bool sbInSizingModalLoop;
3466 int x = GET_X_LPARAM(lParam);
3467 int y = GET_Y_LPARAM(lParam);
3468 EHARDWAREMOUSEEVENT event = (EHARDWAREMOUSEEVENT)-1;
3469 *pResult = 0;
3470 switch (uMsg)
3472 // System event translation
3473 case WM_CLOSE:
3474 Quit();
3475 return false;
3476 case WM_MOVE:
3477 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_MOVE, x, y);
3478 return false;
3479 case WM_SIZE:
3480 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_RESIZE, x, y);
3481 return false;
3482 case WM_WINDOWPOSCHANGED:
3483 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_POS_CHANGED, 1, 0);
3484 return false;
3485 case WM_STYLECHANGED:
3486 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_STYLE_CHANGED, 1, 0);
3487 return false;
3488 case WM_ACTIVATE:
3489 // Pass HIWORD(wParam) as well to indicate whether this window is minimized or not
3490 // HIWORD(wParam) != 0 is minimized, HIWORD(wParam) == 0 is not minimized
3491 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_ACTIVATE, LOWORD(wParam) != WA_INACTIVE, HIWORD(wParam));
3492 return true;
3493 case WM_SETFOCUS:
3494 case WM_KILLFOCUS:
3495 m_hasWindowFocus = uMsg == WM_SETFOCUS;
3496 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_CHANGE_FOCUS, m_hasWindowFocus, 0);
3497 return false;
3498 case WM_INPUTLANGCHANGE:
3499 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LANGUAGE_CHANGE, wParam, lParam);
3500 return false;
3501 case WM_DISPLAYCHANGE:
3502 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_DISPLAY_CHANGED, wParam, lParam);
3503 return false;
3504 case WM_DEVICECHANGE:
3505 GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_DEVICE_CHANGED, wParam, lParam);
3506 return false;
3508 case WM_SYSCOMMAND:
3509 if ((wParam & 0xFFF0) == SC_SCREENSAVE)
3511 // Check if screen saver is allowed
3512 IConsole* const pConsole = gEnv->pConsole;
3513 const ICVar* const pVar = pConsole ? pConsole->GetCVar("sys_screensaver_allowed") : 0;
3514 return pVar && pVar->GetIVal() == 0;
3516 return false;
3518 // Mouse activation
3519 case WM_MOUSEACTIVATE:
3520 *pResult = MA_ACTIVATEANDEAT;
3521 return true;
3523 // Hardware mouse counters
3524 case WM_ENTERSIZEMOVE:
3525 sbInSizingModalLoop = true;
3526 // Fall through intended
3527 case WM_ENTERMENULOOP:
3529 IHardwareMouse* const pMouse = GetIHardwareMouse();
3530 if (pMouse)
3532 pMouse->IncrementCounter();
3535 return true;
3536 case WM_CAPTURECHANGED:
3537 // If WM_CAPTURECHANGED is received after WM_ENTERSIZEMOVE (ie, moving/resizing begins).
3538 // but no matching WM_EXITSIZEMOVE is received (this can happen if the window is not actually moved).
3539 // we still need to decrement the hardware mouse counter that was incremented when WM_ENTERSIZEMOVE was seen.
3540 // So in this case, we effectively treat WM_CAPTURECHANGED as if it was the WM_EXITSIZEMOVE message.
3541 // This behavior has only been reproduced the window is deactivated during the modal loop (ie, breakpoint triggered and focus moves to VS).
3542 case WM_EXITSIZEMOVE:
3543 if (!sbInSizingModalLoop)
3545 return false;
3547 sbInSizingModalLoop = false;
3548 // Fall through intended
3549 case WM_EXITMENULOOP:
3551 IHardwareMouse* const pMouse = GetIHardwareMouse();
3552 if (pMouse)
3554 pMouse->DecrementCounter();
3557 return (uMsg != WM_CAPTURECHANGED);
3559 // Events that should be forwarded to the hardware mouse
3560 case WM_MOUSEMOVE:
3561 event = HARDWAREMOUSEEVENT_MOVE;
3562 break;
3563 case WM_LBUTTONDOWN:
3564 event = HARDWAREMOUSEEVENT_LBUTTONDOWN;
3565 break;
3566 case WM_LBUTTONUP:
3567 event = HARDWAREMOUSEEVENT_LBUTTONUP;
3568 break;
3569 case WM_LBUTTONDBLCLK:
3570 event = HARDWAREMOUSEEVENT_LBUTTONDOUBLECLICK;
3571 break;
3572 case WM_RBUTTONDOWN:
3573 event = HARDWAREMOUSEEVENT_RBUTTONDOWN;
3574 break;
3575 case WM_RBUTTONUP:
3576 event = HARDWAREMOUSEEVENT_RBUTTONUP;
3577 break;
3578 case WM_RBUTTONDBLCLK:
3579 event = HARDWAREMOUSEEVENT_RBUTTONDOUBLECLICK;
3580 break;
3581 case WM_MBUTTONDOWN:
3582 event = HARDWAREMOUSEEVENT_MBUTTONDOWN;
3583 break;
3584 case WM_MBUTTONUP:
3585 event = HARDWAREMOUSEEVENT_MBUTTONUP;
3586 break;
3587 case WM_MBUTTONDBLCLK:
3588 event = HARDWAREMOUSEEVENT_MBUTTONDOUBLECLICK;
3589 break;
3590 case WM_MOUSEWHEEL:
3592 event = HARDWAREMOUSEEVENT_WHEEL;
3593 ICVar* cv = gEnv->pConsole->GetCVar("i_mouse_scroll_coordinate_origin");
3594 if (cv)
3596 switch ((EMouseWheelOrigin)cv->GetIVal())
3598 case EMouseWheelOrigin::ScreenSpace:
3599 // Windows default - do nothing
3600 break;
3601 case EMouseWheelOrigin::WindowSpace:
3603 POINT p{ x, y };
3604 ScreenToClient((HWND)hWnd, &p);
3605 x = p.x;
3606 y = p.y;
3607 break;
3609 case EMouseWheelOrigin::WindowSpaceClamped:
3611 POINT p{ x, y };
3612 ScreenToClient((HWND)hWnd, &p);
3613 RECT r;
3614 GetClientRect((HWND)hWnd, &r);
3615 x = crymath::clamp<int>(p.x, 0, r.right - r.left);
3616 y = crymath::clamp<int>(p.y, 0, r.bottom - r.top);
3617 break;
3619 default:
3620 CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "i_mouse_scroll_coordinate_origin out of range");
3621 break;
3624 break;
3627 // Any other event doesn't interest us
3628 default:
3629 return false;
3632 // This is an event that should be forwarded to the hardware mouse.
3633 // Note: This code has been moved from the GameDLL into here.
3634 // However, maybe it should be re-factored to be driven by CryInput mouse events (or implemented there).
3635 assert(event != -1 && "Logic problem in hardware mouse event handler");
3636 IHardwareMouse* pMouse = GetIHardwareMouse();
3637 if (pMouse)
3639 int wheel = uMsg == WM_MOUSEWHEEL ? GET_WHEEL_DELTA_WPARAM(wParam) : 0;
3640 pMouse->Event(x, y, event, wheel);
3642 return true;
3645 #endif
3647 //////////////////////////////////////////////////////////////////////////
3648 #if CRY_PLATFORM_WINDOWS
3649 static LRESULT WINAPI WndProc(CRY_HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3651 CSystem* pSystem = 0;
3652 if (gEnv)
3654 pSystem = static_cast<CSystem*>(gEnv->pSystem);
3656 if (pSystem && !pSystem->m_bQuit)
3658 LRESULT result;
3659 bool bAny = false;
3660 for (std::vector<IWindowMessageHandler*>::const_iterator it = pSystem->m_windowMessageHandlers.begin(); it != pSystem->m_windowMessageHandlers.end(); ++it)
3662 IWindowMessageHandler* pHandler = *it;
3663 LRESULT maybeResult = 0xDEADDEAD;
3664 if (pHandler->HandleMessage(hWnd, uMsg, wParam, lParam, &maybeResult))
3666 assert(maybeResult != 0xDEADDEAD && "Message handler indicated a resulting value, but no value was written");
3667 if (bAny)
3669 assert(result == maybeResult && "Two window message handlers tried to return different result values");
3671 else
3673 bAny = true;
3674 result = maybeResult;
3678 if (bAny)
3680 // One of the registered handlers returned something
3681 return result;
3685 // Handle with the default procedure
3686 #if defined(UNICODE) || defined(_UNICODE)
3687 assert(IsWindowUnicode((HWND)hWnd) && "Window should be Unicode when compiling with UNICODE");
3688 #else
3689 if (!IsWindowUnicode((HWND)hWnd))
3691 return DefWindowProcA((HWND)hWnd, uMsg, wParam, lParam);
3693 #endif
3694 return DefWindowProcW((HWND)hWnd, uMsg, wParam, lParam);
3696 #endif
3698 //////////////////////////////////////////////////////////////////////////
3699 void* CSystem::GetRootWindowMessageHandler()
3701 #if CRY_PLATFORM_WINDOWS
3702 return &WndProc;
3703 #else
3704 assert(false && "This platform does not support window message handlers");
3705 return NULL;
3706 #endif
3709 ICmdLine* CSystem::GetICmdLine()
3711 return m_pCmdLine;
3714 IUserAnalyticsSystem* CSystem::GetIUserAnalyticsSystem()
3716 return m_pUserAnalyticsSystem;
3719 Cry::IPluginManager* CSystem::GetIPluginManager()
3721 return m_pPluginManager;
3724 uint32 CSystem::GetCPUFlags()
3726 return m_pCpu ? m_pCpu->GetFeatures() : 0;
3729 int CSystem::GetLogicalCPUCount()
3731 return m_pCpu ? m_pCpu->GetLogicalCPUCount() : 0;
3734 #undef EXCLUDE_UPDATE_ON_CONSOLE