SystemInit.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "CrySystem_precompiled.h"
  9. #include "System.h"
  10. #if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
  11. #undef AZ_RESTRICTED_SECTION
  12. #define SYSTEMINIT_CPP_SECTION_2 2
  13. #define SYSTEMINIT_CPP_SECTION_3 3
  14. #define SYSTEMINIT_CPP_SECTION_4 4
  15. #define SYSTEMINIT_CPP_SECTION_5 5
  16. #define SYSTEMINIT_CPP_SECTION_6 6
  17. #define SYSTEMINIT_CPP_SECTION_7 7
  18. #define SYSTEMINIT_CPP_SECTION_8 8
  19. #define SYSTEMINIT_CPP_SECTION_9 9
  20. #define SYSTEMINIT_CPP_SECTION_10 10
  21. #define SYSTEMINIT_CPP_SECTION_11 11
  22. #define SYSTEMINIT_CPP_SECTION_12 12
  23. #define SYSTEMINIT_CPP_SECTION_13 13
  24. #define SYSTEMINIT_CPP_SECTION_14 14
  25. #define SYSTEMINIT_CPP_SECTION_15 15
  26. #define SYSTEMINIT_CPP_SECTION_16 16
  27. #define SYSTEMINIT_CPP_SECTION_17 17
  28. #endif
  29. #include "CryPath.h"
  30. #include <AzFramework/IO/LocalFileIO.h>
  31. #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
  32. #include <AzFramework/Quality/QualitySystemBus.h>
  33. #include "AZCoreLogSink.h"
  34. #include <AzCore/Component/ComponentApplicationBus.h>
  35. #include <AzCore/IO/Streamer/Streamer.h>
  36. #include <AzCore/IO/Streamer/StreamerComponent.h>
  37. #include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
  38. #include <AzCore/Math/MathUtils.h>
  39. #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
  40. #include <AzFramework/Archive/ArchiveFileIO.h>
  41. #include <AzFramework/Archive/INestedArchive.h>
  42. #include <AzFramework/Asset/AssetCatalogBus.h>
  43. #include <AzFramework/Asset/AssetProcessorMessages.h>
  44. #include <AzFramework/Asset/AssetSystemBus.h>
  45. #include <AzFramework/StringFunc/StringFunc.h>
  46. #include <AzCore/Console/ConsoleDataWrapper.h>
  47. #include <AzCore/Interface/Interface.h>
  48. #include <AzCore/Utils/Utils.h>
  49. #include <AzFramework/Logging/MissingAssetLogger.h>
  50. #include <AzFramework/Platform/PlatformDefaults.h>
  51. #include <CryCommon/LoadScreenBus.h>
  52. #if defined(APPLE) || defined(LINUX)
  53. #include <cstdlib>
  54. #include <dlfcn.h>
  55. #endif
  56. #ifdef WIN32
  57. #define WIN32_LEAN_AND_MEAN
  58. #include "windows.h"
  59. #include <float.h>
  60. #endif // WIN32
  61. #include <AzCore/IO/FileIO.h>
  62. #include <IAudioSystem.h>
  63. #include <ICmdLine.h>
  64. #include <ILog.h>
  65. #include <IMovieSystem.h>
  66. #include <IRenderer.h>
  67. #include "LevelSystem/LevelSystem.h"
  68. #include "LevelSystem/SpawnableLevelSystem.h"
  69. #include "LocalizedStringManager.h"
  70. #include "Log.h"
  71. #include "SystemEventDispatcher.h"
  72. #include "XConsole.h"
  73. #include "XML/xml.h"
  74. #include <AzCore/Jobs/JobFunction.h>
  75. #include <AzCore/Jobs/JobManagerBus.h>
  76. #include <AzFramework/Archive/Archive.h>
  77. #include <CrySystemBus.h>
  78. #if defined(ANDROID)
  79. #include <AzCore/Android/Utils.h>
  80. #endif
  81. #if defined(EXTERNAL_CRASH_REPORTING)
  82. #include <CrashHandler.h>
  83. #endif
  84. // select the asset processor based on cvars and defines.
  85. // uncomment the following and edit the path where it is instantiated if you'd like to use the test file client
  86. // #define USE_TEST_FILE_CLIENT
  87. #if defined(REMOTE_ASSET_PROCESSOR)
  88. // Over here, we'd put the header to the Remote Asset Processor interface (as opposed to the Local built in version below)
  89. #include <AzFramework/Network/AssetProcessorConnection.h>
  90. #endif
  91. #ifdef WIN32
  92. extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers);
  93. #endif
  94. #if defined(AZ_RESTRICTED_PLATFORM)
  95. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_14
  96. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  97. #endif
  98. //////////////////////////////////////////////////////////////////////////
  99. #define DEFAULT_LOG_FILENAME "@log@/Log.txt"
  100. #define CRYENGINE_ENGINE_FOLDER "Engine"
  101. //////////////////////////////////////////////////////////////////////////
  102. #define CRYENGINE_DEFAULT_LOCALIZATION_LANG "en-US"
  103. #define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml"
  104. #define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow()
  105. #ifdef WIN32
  106. extern HMODULE gDLLHandle;
  107. #endif
  108. // static int g_sysSpecChanged = false;
  109. struct SCVarsClientConfigSink : public ILoadConfigurationEntrySink
  110. {
  111. virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, [[maybe_unused]] const char* szGroup)
  112. {
  113. gEnv->pConsole->SetClientDataProbeString(szKey, szValue);
  114. }
  115. };
  116. //////////////////////////////////////////////////////////////////////////
  117. static inline void InlineInitializationProcessing([[maybe_unused]] const char* sDescription)
  118. {
  119. if (gEnv->pLog)
  120. {
  121. gEnv->pLog->UpdateLoadingScreen(0);
  122. }
  123. }
  124. //////////////////////////////////////////////////////////////////////////
  125. AZ_PUSH_DISABLE_WARNING(4723, "-Wunknown-warning-option") // potential divide by 0 (needs to wrap the function)
  126. static void CmdCrashTest(IConsoleCmdArgs* pArgs)
  127. {
  128. assert(pArgs);
  129. if (pArgs->GetArgCount() == 2)
  130. {
  131. // This method intentionally crashes, a lot.
  132. int crashType = atoi(pArgs->GetArg(1));
  133. switch (crashType)
  134. {
  135. case 1:
  136. {
  137. int* p = 0;
  138. *p = 0xABCD;
  139. }
  140. break;
  141. case 2:
  142. {
  143. float a = 1.0f;
  144. memset(&a, 0, sizeof(a));
  145. [[maybe_unused]] float* b = &a;
  146. [[maybe_unused]] float c = 3;
  147. CryLog("%f", (c / *b));
  148. }
  149. break;
  150. case 3:
  151. while (true)
  152. {
  153. new char[10240];
  154. }
  155. break;
  156. case 4:
  157. CryFatalError("sys_crashtest 4");
  158. break;
  159. case 5:
  160. while (true)
  161. {
  162. new char[128]; // testing the crash handler an exception in the cry memory allocation occurred
  163. }
  164. case 6:
  165. {
  166. AZ_Assert(false, "Testing assert for testing crashes");
  167. }
  168. break;
  169. case 7:
  170. __debugbreak();
  171. break;
  172. case 8:
  173. CrySleep(1000 * 60 * 10);
  174. break;
  175. }
  176. }
  177. }
  178. AZ_POP_DISABLE_WARNING
  179. static ESystemConfigPlatform GetDevicePlatform()
  180. {
  181. #if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX)
  182. return CONFIG_PC;
  183. #define AZ_RESTRICTED_SECTION_IMPLEMENTED
  184. #elif defined(AZ_RESTRICTED_PLATFORM)
  185. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_2
  186. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  187. #endif
  188. #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
  189. #undef AZ_RESTRICTED_SECTION_IMPLEMENTED
  190. #elif defined(AZ_PLATFORM_ANDROID)
  191. return CONFIG_ANDROID;
  192. #elif defined(AZ_PLATFORM_IOS)
  193. return CONFIG_IOS;
  194. #elif defined(AZ_PLATFORM_MAC)
  195. return CONFIG_OSX_METAL;
  196. #else
  197. AZ_Assert(false, "Platform not supported");
  198. return CONFIG_INVALID_PLATFORM;
  199. #endif
  200. }
  201. /////////////////////////////////////////////////////////////////////////////////
  202. /////////////////////////////////////////////////////////////////////////////////
  203. bool CSystem::InitConsole()
  204. {
  205. if (m_env.pConsole)
  206. {
  207. m_env.pConsole->Init(this);
  208. }
  209. return true;
  210. }
  211. //////////////////////////////////////////////////////////////////////////
  212. // attaches the given variable to the given container;
  213. // recreates the variable if necessary
  214. ICVar* CSystem::attachVariable(const char* szVarName, int* pContainer, const char* szComment, int dwFlags)
  215. {
  216. IConsole* pConsole = GetIConsole();
  217. ICVar* pOldVar = pConsole->GetCVar(szVarName);
  218. int nDefault = 0;
  219. if (pOldVar)
  220. {
  221. nDefault = pOldVar->GetIVal();
  222. pConsole->UnregisterVariable(szVarName, true);
  223. }
  224. // NOTE: maybe we should preserve the actual value of the variable across the registration,
  225. // because of the strange architecture of IConsole that converts int->float->int
  226. REGISTER_CVAR2(szVarName, pContainer, *pContainer, dwFlags, szComment);
  227. ICVar* pVar = pConsole->GetCVar(szVarName);
  228. #ifdef _DEBUG
  229. // test if the variable really has this container
  230. assert(*pContainer == pVar->GetIVal());
  231. ++*pContainer;
  232. assert(*pContainer == pVar->GetIVal());
  233. --*pContainer;
  234. #endif
  235. if (pOldVar)
  236. {
  237. // carry on the default value from the old variable anyway
  238. pVar->Set(nDefault);
  239. }
  240. return pVar;
  241. }
  242. /////////////////////////////////////////////////////////////////////////////////
  243. bool CSystem::InitFileSystem()
  244. {
  245. using namespace AzFramework::AssetSystem;
  246. if (m_pUserCallback)
  247. {
  248. m_pUserCallback->OnInitProgress("Initializing File System...");
  249. }
  250. m_env.pCryPak = AZ::Interface<AZ::IO::IArchive>::Get();
  251. m_env.pFileIO = AZ::IO::FileIOBase::GetInstance();
  252. AZ_Assert(m_env.pCryPak, "CryPak has not been initialized on AZ::Interface");
  253. AZ_Assert(m_env.pFileIO, "FileIOBase has not been initialized");
  254. if (m_bEditor)
  255. {
  256. m_env.pCryPak->RecordFileOpen(AZ::IO::IArchive::RFOM_EngineStartup);
  257. }
  258. // Now that file systems are init, we will clear any events that have arrived
  259. // during file system init, so that systems do not reload assets that were already compiled in the
  260. // critical compilation section.
  261. AzFramework::LegacyAssetEventBus::ClearQueuedEvents();
  262. // we are good to go
  263. return true;
  264. }
  265. void CSystem::ShutdownFileSystem()
  266. {
  267. m_env.pFileIO = nullptr;
  268. }
  269. /////////////////////////////////////////////////////////////////////////////////
  270. bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
  271. {
  272. #if defined(AZ_PLATFORM_ANDROID)
  273. AZ::Android::Utils::SetLoadFilesToMemory(m_sys_load_files_to_memory->GetString());
  274. #endif
  275. GetISystem()->SetConfigPlatform(GetDevicePlatform());
  276. auto projectPath = AZ::Utils::GetProjectPath();
  277. AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Path: %s\n", projectPath.empty() ? "None specified" : projectPath.c_str());
  278. auto projectName = AZ::Utils::GetProjectName();
  279. AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str());
  280. OpenPlatformPaks();
  281. // Load game-specific folder.
  282. LoadConfiguration("game.cfg");
  283. // Load the client/sever-specific configuration
  284. static const char* g_additionalConfig = gEnv->IsDedicated() ? "server_cfg" : "client_cfg";
  285. LoadConfiguration(g_additionalConfig, nullptr, false);
  286. // We do not use CVar groups on the consoles
  287. AddCVarGroupDirectory("Config/CVarGroups");
  288. return (true);
  289. }
  290. //////////////////////////////////////////////////////////////////////////
  291. bool CSystem::InitAudioSystem()
  292. {
  293. if (!Audio::Gem::SystemRequestBus::HasHandlers())
  294. {
  295. // AudioSystem Gem has not been enabled for this project/configuration (e.g. Server).
  296. // This should not generate an error, but calling scope will warn.
  297. return false;
  298. }
  299. bool result = false;
  300. Audio::Gem::SystemRequestBus::BroadcastResult(result, &Audio::Gem::SystemRequestBus::Events::Initialize);
  301. if (result)
  302. {
  303. AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Audio System is initialized and ready!\n");
  304. }
  305. else
  306. {
  307. AZ_Error(AZ_TRACE_SYSTEM_WINDOW, result, "The Audio System did not initialize correctly!\n");
  308. }
  309. return result;
  310. }
  311. //////////////////////////////////////////////////////////////////////////
  312. void CSystem::InitLocalization()
  313. {
  314. // Set the localization folder
  315. ICVar* pCVar = m_env.pConsole != 0 ? m_env.pConsole->GetCVar("sys_localization_folder") : 0;
  316. if (pCVar)
  317. {
  318. static_cast<AZ::IO::Archive* const>(m_env.pCryPak)->SetLocalizationFolder(g_cvars.sys_localization_folder->GetString());
  319. }
  320. // Removed line that assigned language based on a #define
  321. if (m_pLocalizationManager == nullptr)
  322. {
  323. m_pLocalizationManager = new CLocalizedStringsManager(this);
  324. }
  325. // Platform-specific implementation of getting the system language
  326. ILocalizationManager::EPlatformIndependentLanguageID languageID = m_pLocalizationManager->GetSystemLanguage();
  327. if (!m_pLocalizationManager->IsLanguageSupported(languageID))
  328. {
  329. languageID = ILocalizationManager::EPlatformIndependentLanguageID::ePILID_English_US;
  330. }
  331. AZStd::string language = m_pLocalizationManager->LangNameFromPILID(languageID);
  332. m_pLocalizationManager->SetLanguage(language.c_str());
  333. if (m_pLocalizationManager->GetLocalizationFormat() == 1)
  334. {
  335. AZStd::string translationsListXML = LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME;
  336. m_pLocalizationManager->InitLocalizationData(translationsListXML.c_str());
  337. m_pLocalizationManager->LoadAllLocalizationData();
  338. }
  339. else
  340. {
  341. // if the language value cannot be found, let's default to the english pak
  342. OpenLanguagePak(language.c_str());
  343. }
  344. if (auto console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
  345. {
  346. AZ::CVarFixedString languageAudio;
  347. console->GetCvarValue("g_languageAudio", languageAudio);
  348. if (languageAudio.empty())
  349. {
  350. console->PerformCommand(AZStd::string::format("g_languageAudio %s", language.c_str()).c_str());
  351. }
  352. else
  353. {
  354. language.assign(languageAudio.data(), languageAudio.size());
  355. }
  356. }
  357. OpenLanguageAudioPak(language.c_str());
  358. }
  359. void CSystem::OpenPlatformPaks()
  360. {
  361. static bool bPlatformPaksLoaded = false;
  362. if (bPlatformPaksLoaded)
  363. {
  364. return;
  365. }
  366. bPlatformPaksLoaded = true;
  367. //////////////////////////////////////////////////////////////////////////
  368. // Open engine packs
  369. //////////////////////////////////////////////////////////////////////////
  370. #if defined(AZ_RESTRICTED_PLATFORM)
  371. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15
  372. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  373. #endif
  374. #ifdef AZ_PLATFORM_ANDROID
  375. const char* const assetsDir = "@products@";
  376. // Load Android Obb files if available
  377. const char* obbStorage = AZ::Android::Utils::GetObbStoragePath();
  378. AZStd::string mainObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(true)));
  379. AZStd::string patchObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(false)));
  380. m_env.pCryPak->OpenPack(assetsDir, mainObbPath.c_str());
  381. m_env.pCryPak->OpenPack(assetsDir, patchObbPath.c_str());
  382. #endif // AZ_PLATFORM_ANDROID
  383. InlineInitializationProcessing("CSystem::OpenPlatformPaks OpenPacks( Engine... )");
  384. }
  385. //////////////////////////////////////////////////////////////////////////
  386. void CSystem::OpenLanguagePak(const char* sLanguage)
  387. {
  388. // Don't attempt to open a language PAK file if the game doesn't have a
  389. // loc folder configured.
  390. bool projUsesLocalization = false;
  391. LocalizationManagerRequestBus::BroadcastResult(projUsesLocalization, &LocalizationManagerRequestBus::Events::ProjectUsesLocalization);
  392. if (!projUsesLocalization)
  393. {
  394. return;
  395. }
  396. // Initialize languages.
  397. // Omit the trailing slash!
  398. AZStd::string sLocalizationFolder = PathUtil::GetLocalizationFolder();
  399. // load xml pak with full filenames to perform wildcard searches.
  400. AZStd::string sLocalizedPath;
  401. GetLocalizedPath(sLanguage, sLocalizedPath);
  402. if (!m_env.pCryPak->OpenPacks(
  403. { sLocalizationFolder.c_str(), sLocalizationFolder.size() }, { sLocalizedPath.c_str(), sLocalizedPath.size() }, 0))
  404. {
  405. // make sure the localized language is found - not really necessary, for TC
  406. AZ_Printf("Localization", "Localized language content(%s) not available or modified from the original installation.", sLanguage);
  407. }
  408. }
  409. //////////////////////////////////////////////////////////////////////////
  410. void CSystem::OpenLanguageAudioPak([[maybe_unused]] const char* sLanguage)
  411. {
  412. // Don't attempt to open a language PAK file if the game doesn't have a
  413. // loc folder configured.
  414. bool projUsesLocalization = false;
  415. LocalizationManagerRequestBus::BroadcastResult(projUsesLocalization, &LocalizationManagerRequestBus::Events::ProjectUsesLocalization);
  416. if (!projUsesLocalization)
  417. {
  418. return;
  419. }
  420. // Initialize languages.
  421. // Omit the trailing slash!
  422. AZStd::string sLocalizationFolder(
  423. AZStd::string().assign(PathUtil::GetLocalizationFolder(), 0, PathUtil::GetLocalizationFolder().size() - 1));
  424. if (!AZ::StringFunc::Equal(sLocalizationFolder, "Languages", false))
  425. {
  426. sLocalizationFolder = "@products@";
  427. }
  428. // load localized pak with crc32 filenames on consoles to save memory.
  429. AZStd::string sLocalizedPath = "loc.pak";
  430. if (!m_env.pCryPak->OpenPacks(sLocalizationFolder.c_str(), sLocalizedPath.c_str()))
  431. {
  432. // make sure the localized language is found - not really necessary, for TC
  433. AZ_Error(
  434. AZ_TRACE_SYSTEM_WINDOW,
  435. false,
  436. "Localized language content(%s) not available or modified from the original installation.",
  437. sLanguage);
  438. }
  439. }
  440. AZStd::string GetUniqueLogFileName(AZStd::string logFileName)
  441. {
  442. AZStd::string logFileNamePrefix = logFileName;
  443. if ((logFileNamePrefix[0] != '@') && (AzFramework::StringFunc::Path::IsRelative(logFileNamePrefix.c_str())))
  444. {
  445. logFileNamePrefix = "@log@/";
  446. logFileNamePrefix += logFileName;
  447. }
  448. char resolvedLogFilePathBuffer[AZ_MAX_PATH_LEN] = { 0 };
  449. AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(logFileNamePrefix.c_str(), resolvedLogFilePathBuffer, AZ_MAX_PATH_LEN);
  450. int instance = gEnv->pSystem->GetApplicationLogInstance(resolvedLogFilePathBuffer);
  451. if (instance == 0)
  452. {
  453. return logFileNamePrefix;
  454. }
  455. AZStd::string logFileExtension;
  456. size_t extensionIndex = logFileName.find_last_of('.');
  457. if (extensionIndex != AZStd::string::npos)
  458. {
  459. logFileExtension = logFileName.substr(extensionIndex, logFileName.length() - extensionIndex);
  460. logFileNamePrefix = logFileName.substr(0, extensionIndex);
  461. }
  462. logFileName = AZStd::string::format("%s(%d)%s", logFileNamePrefix.c_str(), instance, logFileExtension.c_str()).c_str();
  463. return logFileName;
  464. }
  465. namespace AZ
  466. {
  467. // Purposely Null Uuid, so it isn't aggregated into the ConsoleDataWrapper Uuid
  468. AZ_TYPE_INFO_SPECIALIZE(AZ::ThreadSafety, AZ::Uuid{});
  469. AZ_TYPE_INFO_TEMPLATE_WITH_NAME(AZ::ConsoleDataWrapper, "ConsoleDataWrapper", "{1E5AB0FC-83FF-4715-BBE9-348B880613B0}", AZ_TYPE_INFO_CLASS, AZ_TYPE_INFO_AUTO);
  470. } // namespace AZ
  471. class AzConsoleToCryConsoleBinder final
  472. {
  473. public:
  474. static void OnInvoke(IConsoleCmdArgs* args)
  475. {
  476. std::string command = args->GetCommandLine();
  477. const size_t delim = command.find_first_of('=');
  478. if (delim != std::string::npos)
  479. {
  480. // All Cry executed cfg files will come in through this pathway in addition to regular commands
  481. // We strip out the = sign at this layer to maintain compatibility with cvars that use the '=' as a separator
  482. // Swap the '=' character for a space
  483. command[delim] = ' ';
  484. }
  485. AZ::Interface<AZ::IConsole>::Get()->PerformCommand(
  486. command.c_str(), AZ::ConsoleSilentMode::Silent, AZ::ConsoleInvokedFrom::CryBinding);
  487. }
  488. static void OnVarChanged(ICVar* cvar)
  489. {
  490. AZ::CVarFixedString command = AZ::CVarFixedString::format("%s %s", cvar->GetName(), cvar->GetString());
  491. AZ::Interface<AZ::IConsole>::Get()->PerformCommand(
  492. command.c_str(), AZ::ConsoleSilentMode::Silent, AZ::ConsoleInvokedFrom::CryBinding);
  493. }
  494. static void Visit(AZ::ConsoleFunctorBase* functor)
  495. {
  496. if (gEnv->pConsole == nullptr)
  497. {
  498. AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Cry console was NULL while attempting to register Az CVars and CFuncs.\n");
  499. return;
  500. }
  501. int32_t cryFlags = VF_NET_SYNCED;
  502. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::DontReplicate) != AZ::ConsoleFunctorFlags::Null)
  503. {
  504. cryFlags = VF_NULL;
  505. }
  506. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::ServerOnly) != AZ::ConsoleFunctorFlags::Null)
  507. {
  508. cryFlags |= VF_DEDI_ONLY;
  509. }
  510. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::ReadOnly) != AZ::ConsoleFunctorFlags::Null)
  511. {
  512. cryFlags |= VF_READONLY;
  513. }
  514. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsCheat) != AZ::ConsoleFunctorFlags::Null)
  515. {
  516. cryFlags |= VF_CHEAT;
  517. }
  518. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsInvisible) != AZ::ConsoleFunctorFlags::Null)
  519. {
  520. cryFlags |= VF_INVISIBLE;
  521. }
  522. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsDeprecated) != AZ::ConsoleFunctorFlags::Null)
  523. {
  524. cryFlags |= VF_DEPRECATED;
  525. }
  526. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::NeedsReload) != AZ::ConsoleFunctorFlags::Null)
  527. {
  528. cryFlags |= VF_REQUIRE_APP_RESTART;
  529. }
  530. if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::AllowClientSet) != AZ::ConsoleFunctorFlags::Null)
  531. {
  532. cryFlags |= VF_DEV_ONLY;
  533. }
  534. // only add CVar versions if they are not already present
  535. auto existingCVar = gEnv->pConsole->GetCVar(functor->GetName());
  536. if (!existingCVar)
  537. {
  538. const auto typeId = functor->GetTypeId();
  539. if (typeId != AZ::TypeId::CreateNull())
  540. {
  541. auto registerType = [&typeId, &functor, &cryFlags](auto value) -> bool
  542. {
  543. using type = decltype(value);
  544. using consoleDataWrapperType = AZ::ConsoleDataWrapper<type, ConsoleThreadSafety<type>>;
  545. if (typeId == azrtti_typeid<type>() || typeId == azrtti_typeid<consoleDataWrapperType>())
  546. {
  547. functor->GetValue(value);
  548. if constexpr (AZStd::is_same_v<type, bool>)
  549. {
  550. AZ::CVarFixedString valueString;
  551. functor->GetValue(valueString);
  552. return (
  553. gEnv->pConsole->RegisterString(
  554. functor->GetName(),
  555. valueString.c_str(),
  556. cryFlags,
  557. functor->GetDesc(),
  558. AzConsoleToCryConsoleBinder::OnVarChanged) != nullptr);
  559. }
  560. else if constexpr (AZStd::is_integral_v<type>)
  561. {
  562. return (
  563. gEnv->pConsole->RegisterInt(
  564. functor->GetName(),
  565. static_cast<int>(value),
  566. cryFlags,
  567. functor->GetDesc(),
  568. AzConsoleToCryConsoleBinder::OnVarChanged) != nullptr);
  569. }
  570. else if constexpr (AZStd::is_floating_point_v<type>)
  571. {
  572. return (
  573. gEnv->pConsole->RegisterFloat(
  574. functor->GetName(),
  575. static_cast<float>(value),
  576. cryFlags,
  577. functor->GetDesc(),
  578. AzConsoleToCryConsoleBinder::OnVarChanged) != nullptr);
  579. }
  580. }
  581. return false;
  582. };
  583. // register fundamental types
  584. bool registered = registerType(bool()) || registerType(AZ::s32()) || registerType(AZ::u32()) || registerType(float()) ||
  585. registerType(double()) || registerType(AZ::s16()) || registerType(AZ::u16()) || registerType(AZ::s64()) ||
  586. registerType(AZ::u64()) || registerType(AZ::s8()) || registerType(AZ::u8());
  587. if (!registered)
  588. {
  589. // register all other types as strings, if possible
  590. AZ::CVarFixedString value;
  591. functor->GetValue(value);
  592. gEnv->pConsole->RegisterString(
  593. functor->GetName(), value.c_str(), cryFlags, functor->GetDesc(), AzConsoleToCryConsoleBinder::OnVarChanged);
  594. }
  595. }
  596. else
  597. {
  598. gEnv->pConsole->RemoveCommand(functor->GetName());
  599. gEnv->pConsole->AddCommand(functor->GetName(), AzConsoleToCryConsoleBinder::OnInvoke, cryFlags, functor->GetDesc());
  600. }
  601. }
  602. else
  603. {
  604. existingCVar->AddOnChangeFunctor(
  605. AZ::Name("AZCryBinder"),
  606. [existingCVar]()
  607. {
  608. AzConsoleToCryConsoleBinder::OnVarChanged(existingCVar);
  609. });
  610. }
  611. }
  612. using CommandRegisteredHandler = AZ::IConsole::ConsoleCommandRegisteredEvent::Handler;
  613. static inline CommandRegisteredHandler s_commandRegisteredHandler = CommandRegisteredHandler(
  614. [](AZ::ConsoleFunctorBase* functor)
  615. {
  616. Visit(functor);
  617. });
  618. };
  619. // System initialization
  620. /////////////////////////////////////////////////////////////////////////////////
  621. // INIT
  622. /////////////////////////////////////////////////////////////////////////////////
  623. bool CSystem::Init(const SSystemInitParams& startupParams)
  624. {
  625. // Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the
  626. // global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is
  627. // initialized to this instance's SSystemGlobalEnvironment (m_env), we will force set it again here
  628. // to m_env
  629. if (!gEnv)
  630. {
  631. gEnv = &m_env;
  632. }
  633. SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_INIT);
  634. gEnv->mMainThreadId = GetCurrentThreadId(); // Set this ASAP on startup
  635. InlineInitializationProcessing("CSystem::Init start");
  636. m_env.bNoAssertDialog = false;
  637. m_bNoCrashDialog = gEnv->IsDedicated();
  638. if (startupParams.bUnattendedMode)
  639. {
  640. m_bNoCrashDialog = true;
  641. m_env.bNoAssertDialog = true; // this also suppresses CryMessageBox
  642. g_cvars.sys_no_crash_dialog = true;
  643. }
  644. #if defined(AZ_PLATFORM_LINUX)
  645. // Linux is all console for now and so no room for dialog boxes!
  646. m_env.bNoAssertDialog = true;
  647. #endif
  648. m_pCmdLine = new CCmdLine(startupParams.szSystemCmdLine);
  649. // Init AZCoreLogSink. Don't suppress system output if we're running as an editor-server
  650. bool suppressSystemOutput = true;
  651. if (const ICmdLineArg* isEditorServerArg = m_pCmdLine->FindArg(eCLAT_Pre, "editorsv_isDedicated"))
  652. {
  653. bool editorsv_isDedicated = false;
  654. if (isEditorServerArg->GetBoolValue(editorsv_isDedicated) && editorsv_isDedicated)
  655. {
  656. suppressSystemOutput = false;
  657. }
  658. }
  659. AZCoreLogSink::Connect(suppressSystemOutput);
  660. // Registers all AZ Console Variables functors specified within CrySystem
  661. if (auto azConsole = AZ::Interface<AZ::IConsole>::Get(); azConsole)
  662. {
  663. azConsole->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
  664. }
  665. #if defined(WIN32) || defined(WIN64)
  666. // check OS version - we only want to run on XP or higher - talk to Martin Mittring if you want to change this
  667. {
  668. OSVERSIONINFO osvi;
  669. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  670. AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
  671. GetVersionExW(&osvi);
  672. AZ_POP_DISABLE_WARNING
  673. bool bIsWindowsXPorLater = osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1);
  674. if (!bIsWindowsXPorLater)
  675. {
  676. AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "Open 3D Engine requires an OS version of Windows XP or later.");
  677. return false;
  678. }
  679. }
  680. #endif
  681. // Get file version information.
  682. QueryVersionInfo();
  683. DetectGameFolderAccessRights();
  684. m_bEditor = startupParams.bEditor;
  685. m_bPreviewMode = startupParams.bPreview;
  686. m_bTestMode = startupParams.bTestMode;
  687. m_pUserCallback = startupParams.pUserCallback;
  688. m_bDedicatedServer = startupParams.bDedicatedServer;
  689. m_currentLanguageAudio = "";
  690. #if !defined(CONSOLE)
  691. m_env.SetIsEditor(m_bEditor);
  692. m_env.SetIsEditorGameMode(false);
  693. m_env.SetIsEditorSimulationMode(false);
  694. #endif
  695. m_env.SetToolMode(startupParams.bToolMode);
  696. if (m_bEditor)
  697. {
  698. m_bInDevMode = true;
  699. }
  700. if (!gEnv->IsDedicated())
  701. {
  702. const ICmdLineArg* crashdialog = m_pCmdLine->FindArg(eCLAT_Post, "sys_no_crash_dialog");
  703. if (crashdialog)
  704. {
  705. m_bNoCrashDialog = true;
  706. }
  707. }
  708. #if !defined(_RELEASE)
  709. if (!m_bDedicatedServer)
  710. {
  711. const ICmdLineArg* dedicated = m_pCmdLine->FindArg(eCLAT_Pre, "dedicated");
  712. if (dedicated)
  713. {
  714. m_bDedicatedServer = true;
  715. }
  716. }
  717. #endif // !defined(_RELEASE)
  718. #if !defined(CONSOLE)
  719. gEnv->SetIsDedicated(m_bDedicatedServer);
  720. #endif
  721. {
  722. EBUS_EVENT(CrySystemEventBus, OnCrySystemPreInitialize, *this, startupParams);
  723. //////////////////////////////////////////////////////////////////////////
  724. // File system, must be very early
  725. //////////////////////////////////////////////////////////////////////////
  726. if (!InitFileSystem())
  727. {
  728. return false;
  729. }
  730. //////////////////////////////////////////////////////////////////////////
  731. InlineInitializationProcessing("CSystem::Init InitFileSystem");
  732. m_missingAssetLogger = AZStd::make_unique<AzFramework::MissingAssetLogger>();
  733. //////////////////////////////////////////////////////////////////////////
  734. // Logging is only available after file system initialization.
  735. //////////////////////////////////////////////////////////////////////////
  736. if (!startupParams.pLog)
  737. {
  738. m_env.pLog = new CLog(this);
  739. if (startupParams.pLogCallback)
  740. {
  741. m_env.pLog->AddCallback(startupParams.pLogCallback);
  742. }
  743. const ICmdLineArg* logfile = m_pCmdLine->FindArg(eCLAT_Pre, "logfile"); // see if the user specified a log name, if so use it
  744. if (logfile && strlen(logfile->GetValue()) > 0)
  745. {
  746. m_env.pLog->SetFileName(logfile->GetValue(), startupParams.autoBackupLogs);
  747. }
  748. else if (startupParams.sLogFileName) // otherwise see if the startup params has a log file name, if so use it
  749. {
  750. const AZStd::string sUniqueLogFileName = GetUniqueLogFileName(startupParams.sLogFileName);
  751. m_env.pLog->SetFileName(sUniqueLogFileName.c_str(), startupParams.autoBackupLogs);
  752. }
  753. else // use the default log name
  754. {
  755. m_env.pLog->SetFileName(DEFAULT_LOG_FILENAME, startupParams.autoBackupLogs);
  756. }
  757. }
  758. else
  759. {
  760. m_env.pLog = startupParams.pLog;
  761. }
  762. // The log backup system expects the version number to be the first line of the log
  763. // so we log this immediately after setting the log filename
  764. LogVersion();
  765. bool devModeEnable = true;
  766. #if defined(_RELEASE)
  767. // disable devmode by default in release builds outside the editor
  768. devModeEnable = m_bEditor;
  769. #endif
  770. // disable devmode in launcher if someone really wants to (even in non release builds)
  771. if (!m_bEditor && m_pCmdLine->FindArg(eCLAT_Pre, "nodevmode"))
  772. {
  773. devModeEnable = false;
  774. }
  775. SetDevMode(devModeEnable);
  776. //////////////////////////////////////////////////////////////////////////
  777. // CREATE CONSOLE
  778. //////////////////////////////////////////////////////////////////////////
  779. if (!startupParams.bSkipConsole)
  780. {
  781. m_env.pConsole = new CXConsole;
  782. if (startupParams.pPrintSync)
  783. {
  784. m_env.pConsole->AddOutputPrintSink(startupParams.pPrintSync);
  785. }
  786. }
  787. //////////////////////////////////////////////////////////////////////////
  788. if (m_pUserCallback)
  789. {
  790. m_pUserCallback->OnInit(this);
  791. }
  792. m_env.pLog->RegisterConsoleVariables();
  793. GetIRemoteConsole()->RegisterConsoleVariables();
  794. if (!startupParams.bSkipConsole)
  795. {
  796. // Register system console variables.
  797. CreateSystemVars();
  798. // Register any AZ CVar commands created above with the AZ Console system.
  799. AZ::ConsoleFunctorBase*& deferredHead = AZ::ConsoleFunctorBase::GetDeferredHead();
  800. AZ::Interface<AZ::IConsole>::Get()->LinkDeferredFunctors(deferredHead);
  801. // Callback
  802. if (m_pUserCallback && m_env.pConsole)
  803. {
  804. m_pUserCallback->OnConsoleCreated(m_env.pConsole);
  805. }
  806. // Let listeners know its safe to register cvars
  807. EBUS_EVENT(CrySystemEventBus, OnCrySystemCVarRegistry);
  808. }
  809. // Set this as soon as the system cvars got initialized.
  810. static_cast<AZ::IO::Archive* const>(m_env.pCryPak)->SetLocalizationFolder(g_cvars.sys_localization_folder->GetString());
  811. InlineInitializationProcessing("CSystem::Init Create console");
  812. InitFileSystem_LoadEngineFolders(startupParams);
  813. #if !defined(RELEASE) || defined(RELEASE_LOGGING)
  814. // now that the system cfgs have been loaded, we can start the remote console
  815. GetIRemoteConsole()->Update();
  816. #endif
  817. InlineInitializationProcessing("CSystem::Init Load Engine Folders");
  818. //////////////////////////////////////////////////////////////////////////
  819. // Load config files
  820. //////////////////////////////////////////////////////////////////////////
  821. // tools may not interact with @user@
  822. if (!gEnv->IsInToolMode())
  823. {
  824. if (m_pCmdLine->FindArg(eCLAT_Pre, "ResetProfile") == 0)
  825. {
  826. LoadConfiguration("@user@/game.cfg", 0, false);
  827. }
  828. }
  829. {
  830. // Optional user defined overrides
  831. LoadConfiguration("user.cfg");
  832. #if defined(ENABLE_STATS_AGENT)
  833. if (m_pCmdLine->FindArg(eCLAT_Pre, "useamblecfg"))
  834. {
  835. LoadConfiguration("amble.cfg");
  836. }
  837. #endif
  838. }
  839. //////////////////////////////////////////////////////////////////////////
  840. if (g_cvars.sys_asserts == 0)
  841. {
  842. gEnv->bIgnoreAllAsserts = true;
  843. }
  844. if (g_cvars.sys_asserts == 2)
  845. {
  846. gEnv->bNoAssertDialog = true;
  847. }
  848. LogBuildInfo();
  849. InlineInitializationProcessing("CSystem::Init LoadConfigurations");
  850. #ifdef WIN32
  851. if (g_cvars.sys_WER)
  852. {
  853. SetUnhandledExceptionFilter(CryEngineExceptionFilterWER);
  854. }
  855. #endif
  856. //////////////////////////////////////////////////////////////////////////
  857. // Localization
  858. //////////////////////////////////////////////////////////////////////////
  859. {
  860. InitLocalization();
  861. }
  862. InlineInitializationProcessing("CSystem::Init InitLocalizations");
  863. //////////////////////////////////////////////////////////////////////////
  864. // Open basic pak files after intro movie playback started
  865. //////////////////////////////////////////////////////////////////////////
  866. OpenPlatformPaks();
  867. //////////////////////////////////////////////////////////////////////////
  868. // AUDIO
  869. //////////////////////////////////////////////////////////////////////////
  870. {
  871. [[maybe_unused]] bool audioInitResult = InitAudioSystem();
  872. // Getting false here is not an error, the engine may run fine without it so a warning here is sufficient.
  873. // But if there were errors internally during initialization, those would be reported above this.
  874. AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, audioInitResult, "<Audio>: Running without any AudioSystem!");
  875. }
  876. // Compiling the default system textures can be the lengthiest portion of
  877. // editor initialization, so it is useful to inform users that they are waiting on
  878. // the necessary default textures to compile.
  879. if (m_pUserCallback)
  880. {
  881. m_pUserCallback->OnInitProgress("First time asset processing - may take a minute...");
  882. }
  883. //////////////////////////////////////////////////////////////////////////
  884. //////////////////////////////////////////////////////////////////////////
  885. // System cursor
  886. //////////////////////////////////////////////////////////////////////////
  887. // - Dedicated server is in console mode by default (system cursor is always shown when console is)
  888. // - System cursor is always visible by default in Editor (we never start directly in Game Mode)
  889. // - System cursor has to be enabled manually by the Game if needed; the custom UiCursor will typically be used instead
  890. if (!gEnv->IsDedicated() && !gEnv->IsEditor())
  891. {
  892. AzFramework::InputSystemCursorRequestBus::Event(
  893. AzFramework::InputDeviceMouse::Id,
  894. &AzFramework::InputSystemCursorRequests::SetSystemCursorState,
  895. AzFramework::SystemCursorState::ConstrainedAndHidden);
  896. }
  897. // CONSOLE
  898. //////////////////////////////////////////////////////////////////////////
  899. if (!InitConsole())
  900. {
  901. return false;
  902. }
  903. if (m_pUserCallback)
  904. {
  905. m_pUserCallback->OnInitProgress("Initializing additional systems...");
  906. }
  907. AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Initializing additional systems\n");
  908. //////////////////////////////////////////////////////////////////////////
  909. // LEVEL SYSTEM
  910. m_pLevelSystem = new LegacyLevelSystem::SpawnableLevelSystem(this);
  911. InlineInitializationProcessing("CSystem::Init Level System");
  912. // Az to Cry console binding
  913. AZ::Interface<AZ::IConsole>::Get()->VisitRegisteredFunctors(
  914. [](AZ::ConsoleFunctorBase* functor)
  915. {
  916. AzConsoleToCryConsoleBinder::Visit(functor);
  917. });
  918. AzConsoleToCryConsoleBinder::s_commandRegisteredHandler.Connect(
  919. AZ::Interface<AZ::IConsole>::Get()->GetConsoleCommandRegisteredEvent());
  920. if (g_cvars.sys_float_exceptions > 0)
  921. {
  922. if (g_cvars.sys_float_exceptions == 3 && gEnv->IsEditor()) // Turn off float exceptions in editor if sys_float_exceptions = 3
  923. {
  924. g_cvars.sys_float_exceptions = 0;
  925. }
  926. if (g_cvars.sys_float_exceptions > 0)
  927. {
  928. AZ_TracePrintf(
  929. AZ_TRACE_SYSTEM_WINDOW,
  930. "Enabled float exceptions(sys_float_exceptions %d). This makes the performance slower.",
  931. g_cvars.sys_float_exceptions);
  932. }
  933. }
  934. EnableFloatExceptions(g_cvars.sys_float_exceptions);
  935. }
  936. InlineInitializationProcessing("CSystem::Init End");
  937. // All CVARs should now be registered, load and apply quality settings for the default quality group
  938. // using device rules to auto-detected the correct quality level
  939. AzFramework::QualitySystemEvents::Bus::Broadcast(
  940. &AzFramework::QualitySystemEvents::LoadDefaultQualityGroup,
  941. AzFramework::QualityLevel::LevelFromDeviceRules);
  942. // Send out EBus event
  943. EBUS_EVENT(CrySystemEventBus, OnCrySystemInitialized, *this, startupParams);
  944. // Execute any deferred commands that uses the CVar commands that were just registered
  945. AZ::Interface<AZ::IConsole>::Get()->ExecuteDeferredConsoleCommands();
  946. if (ISystemEventDispatcher* systemEventDispatcher = GetISystemEventDispatcher())
  947. {
  948. systemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_GAME_POST_INIT, 0, 0);
  949. systemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_GAME_POST_INIT_DONE, 0, 0);
  950. }
  951. m_bInitializedSuccessfully = true;
  952. return true;
  953. }
  954. static void LoadConfigurationCmd(IConsoleCmdArgs* pParams)
  955. {
  956. assert(pParams);
  957. if (pParams->GetArgCount() != 2)
  958. {
  959. gEnv->pLog->LogError("LoadConfiguration failed, one parameter needed");
  960. return;
  961. }
  962. GetISystem()->LoadConfiguration((AZStd::string("Config/") + pParams->GetArg(1)).c_str());
  963. }
  964. // --------------------------------------------------------------------------------------------------------------------------
  965. static AZStd::string ConcatPath(const char* szPart1, const char* szPart2)
  966. {
  967. if (szPart1[0] == 0)
  968. {
  969. return szPart2;
  970. }
  971. AZStd::string ret;
  972. ret.reserve(strlen(szPart1) + 1 + strlen(szPart2));
  973. ret = szPart1;
  974. ret += "/";
  975. ret += szPart2;
  976. return ret;
  977. }
  978. //////////////////////////////////////////////////////////////////////////
  979. void CSystem::CreateSystemVars()
  980. {
  981. assert(gEnv);
  982. assert(gEnv->pConsole);
  983. #if AZ_LOADSCREENCOMPONENT_ENABLED
  984. m_game_load_screen_uicanvas_path = REGISTER_STRING("game_load_screen_uicanvas_path", "", 0, "Game load screen UiCanvas path.");
  985. m_level_load_screen_uicanvas_path = REGISTER_STRING("level_load_screen_uicanvas_path", "", 0, "Level load screen UiCanvas path.");
  986. m_game_load_screen_sequence_to_auto_play =
  987. REGISTER_STRING("game_load_screen_sequence_to_auto_play", "", 0, "Game load screen UiCanvas animation sequence to play on load.");
  988. m_level_load_screen_sequence_to_auto_play =
  989. REGISTER_STRING("level_load_screen_sequence_to_auto_play", "", 0, "Level load screen UiCanvas animation sequence to play on load.");
  990. m_game_load_screen_sequence_fixed_fps = REGISTER_FLOAT(
  991. "game_load_screen_sequence_fixed_fps", 60.0f, 0, "Fixed frame rate fed to updates of the game load screen sequence.");
  992. m_level_load_screen_sequence_fixed_fps = REGISTER_FLOAT(
  993. "level_load_screen_sequence_fixed_fps", 60.0f, 0, "Fixed frame rate fed to updates of the level load screen sequence.");
  994. m_game_load_screen_max_fps =
  995. REGISTER_FLOAT("game_load_screen_max_fps", 30.0f, 0, "Max frame rate to update the game load screen sequence.");
  996. m_level_load_screen_max_fps =
  997. REGISTER_FLOAT("level_load_screen_max_fps", 30.0f, 0, "Max frame rate to update the level load screen sequence.");
  998. m_game_load_screen_minimum_time = REGISTER_FLOAT(
  999. "game_load_screen_minimum_time",
  1000. 0.0f,
  1001. 0,
  1002. "Minimum amount of time to show the game load screen. Important to prevent short loads from flashing the load screen. 0 means "
  1003. "there is no limit.");
  1004. m_level_load_screen_minimum_time = REGISTER_FLOAT(
  1005. "level_load_screen_minimum_time",
  1006. 0.0f,
  1007. 0,
  1008. "Minimum amount of time to show the level load screen. Important to prevent short loads from flashing the load screen. 0 means "
  1009. "there is no limit.");
  1010. #endif // if AZ_LOADSCREENCOMPONENT_ENABLED
  1011. REGISTER_INT("cvDoVerboseWindowTitle", 0, VF_NULL, "");
  1012. // Register an AZ Console command to quit the engine.
  1013. // The command is available even in Release builds.
  1014. static AZ::ConsoleFunctor<void, false> s_functorQuit(
  1015. "quit",
  1016. "Quit/Shutdown the engine",
  1017. AZ::ConsoleFunctorFlags::AllowClientSet | AZ::ConsoleFunctorFlags::DontReplicate,
  1018. AZ::TypeId::CreateNull(),
  1019. []([[maybe_unused]] const AZ::ConsoleCommandContainer& params)
  1020. {
  1021. GetISystem()->Quit();
  1022. });
  1023. static AZ::ConsoleFunctor<void, false> s_functorCrash(
  1024. "crash",
  1025. "Crash the engine",
  1026. AZ::ConsoleFunctorFlags::IsInvisible | AZ::ConsoleFunctorFlags::DontReplicate,
  1027. AZ::TypeId::CreateNull(),
  1028. []([[maybe_unused]] const AZ::ConsoleCommandContainer& params)
  1029. {
  1030. AZ_Crash();
  1031. });
  1032. m_sys_load_files_to_memory = REGISTER_STRING(
  1033. "sys_load_files_to_memory",
  1034. "shadercache.pak",
  1035. 0,
  1036. "Specify comma separated list of filenames that need to be loaded to memory.\n"
  1037. "Partial names also work. Eg. \"shader\" will load:\n"
  1038. "shaders.pak, shadercache.pak, and shadercachestartup.pak");
  1039. #ifndef _RELEASE
  1040. REGISTER_STRING_CB("sys_version", "", VF_CHEAT, "Override system file/product version", SystemVersionChanged);
  1041. #endif // #ifndef _RELEASE
  1042. attachVariable("sys_PakSaveLevelResourceList", &g_cvars.archiveVars.nSaveLevelResourceList, "Save resource list when loading level");
  1043. attachVariable("sys_PakLogInvalidFileAccess", &g_cvars.archiveVars.nLogInvalidFileAccess, "Log synchronous file access when in game");
  1044. m_sysNoUpdate = REGISTER_INT(
  1045. "sys_noupdate",
  1046. 0,
  1047. VF_CHEAT,
  1048. "Toggles updating of system with sys_script_debugger.\n"
  1049. "Usage: sys_noupdate [0/1]\n"
  1050. "Default is 0 (system updates during debug).");
  1051. #if defined(_RELEASE) && defined(CONSOLE) && !defined(ENABLE_LW_PROFILERS)
  1052. enum
  1053. {
  1054. e_sysKeyboardDefault = 0
  1055. };
  1056. #else
  1057. enum
  1058. {
  1059. e_sysKeyboardDefault = 1
  1060. };
  1061. #endif
  1062. m_svDedicatedMaxRate = REGISTER_FLOAT(
  1063. "sv_DedicatedMaxRate",
  1064. 30.0f,
  1065. 0,
  1066. "Sets the maximum update rate when running as a dedicated server.\n"
  1067. "Usage: sv_DedicatedMaxRate [5..500]\n"
  1068. "Default is 30.");
  1069. REGISTER_FLOAT(
  1070. "sv_DedicatedCPUPercent",
  1071. 0.0f,
  1072. 0,
  1073. "Sets the target CPU usage when running as a dedicated server, or disable this feature if it's zero.\n"
  1074. "Usage: sv_DedicatedCPUPercent [0..100]\n"
  1075. "Default is 0 (disabled).");
  1076. REGISTER_FLOAT(
  1077. "sv_DedicatedCPUVariance",
  1078. 10.0f,
  1079. 0,
  1080. "Sets how much the CPU can vary from sv_DedicateCPU (up or down) without adjusting the framerate.\n"
  1081. "Usage: sv_DedicatedCPUVariance [5..50]\n"
  1082. "Default is 10.");
  1083. m_sys_firstlaunch = REGISTER_INT("sys_firstlaunch", 0, 0, "Indicates that the game was run for the first time.");
  1084. #if defined(AZ_RESTRICTED_PLATFORM)
  1085. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_12
  1086. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  1087. #endif
  1088. #if defined(AZ_RESTRICTED_PLATFORM)
  1089. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_17
  1090. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  1091. #endif
  1092. #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
  1093. #undef AZ_RESTRICTED_SECTION_IMPLEMENTED
  1094. #else
  1095. #define SYS_STREAMING_CPU_DEFAULT_VALUE 1
  1096. #define SYS_STREAMING_CPU_WORKER_DEFAULT_VALUE 5
  1097. #endif
  1098. #define DEFAULT_USE_OPTICAL_DRIVE_THREAD (gEnv->IsDedicated() ? 0 : 1)
  1099. const char* localizeFolder = "Localization";
  1100. g_cvars.sys_localization_folder = REGISTER_STRING_CB(
  1101. "sys_localization_folder",
  1102. localizeFolder,
  1103. VF_NULL,
  1104. "Sets the folder where to look for localized data.\n"
  1105. "This cvar allows for backwards compatibility so localized data under the game folder can still be found.\n"
  1106. "Usage: sys_localization_folder <folder name>\n"
  1107. "Default: Localization\n",
  1108. CSystem::OnLocalizationFolderCVarChanged);
  1109. REGISTER_CVAR2("sys_float_exceptions", &g_cvars.sys_float_exceptions, 0, 0, "Use or not use floating point exceptions.");
  1110. REGISTER_CVAR2("sys_update_profile_time", &g_cvars.sys_update_profile_time, 1.0f, 0, "Time to keep updates timings history for.");
  1111. REGISTER_CVAR2(
  1112. "sys_no_crash_dialog", &g_cvars.sys_no_crash_dialog, m_bNoCrashDialog, VF_NULL, "Whether to disable the crash dialog window");
  1113. REGISTER_CVAR2(
  1114. "sys_no_error_report_window",
  1115. &g_cvars.sys_no_error_report_window,
  1116. m_bNoErrorReportWindow,
  1117. VF_NULL,
  1118. "Whether to disable the error report list");
  1119. #if defined(_RELEASE)
  1120. if (!gEnv->IsDedicated())
  1121. {
  1122. REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 1, 0, "Enables Windows Error Reporting");
  1123. }
  1124. #else
  1125. REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 0, 0, "Enables Windows Error Reporting");
  1126. #endif
  1127. const int DEFAULT_DUMP_TYPE = 2;
  1128. REGISTER_CVAR2(
  1129. "sys_dump_type",
  1130. &g_cvars.sys_dump_type,
  1131. DEFAULT_DUMP_TYPE,
  1132. VF_NULL,
  1133. "Specifies type of crash dump to create - see MINIDUMP_TYPE in dbghelp.h for full list of values\n"
  1134. "0: Do not create a minidump\n"
  1135. "1: Create a small minidump (stacktrace)\n"
  1136. "2: Create a medium minidump (+ some variables)\n"
  1137. "3: Create a full minidump (+ all memory)\n");
  1138. REGISTER_CVAR2(
  1139. "sys_dump_aux_threads", &g_cvars.sys_dump_aux_threads, 1, VF_NULL, "Dumps callstacks of other threads in case of a crash");
  1140. #if (defined(WIN32) || defined(WIN64)) && defined(_RELEASE)
  1141. const int DEFAULT_SYS_MAX_FPS = 0;
  1142. #else
  1143. const int DEFAULT_SYS_MAX_FPS = -1;
  1144. #endif
  1145. REGISTER_CVAR2(
  1146. "sys_MaxFPS",
  1147. &g_cvars.sys_MaxFPS,
  1148. DEFAULT_SYS_MAX_FPS,
  1149. VF_NULL,
  1150. "Limits the frame rate to specified number n (if n>0 and if vsync is disabled).\n"
  1151. " 0 = on PC if vsync is off auto throttles fps while in menu or game is paused (default)\n"
  1152. "-1 = off");
  1153. REGISTER_CVAR2(
  1154. "sys_maxTimeStepForMovieSystem",
  1155. &g_cvars.sys_maxTimeStepForMovieSystem,
  1156. 0.1f,
  1157. VF_NULL,
  1158. "Caps the time step for the movie system so that a cut-scene won't be jumped in the case of an extreme stall.");
  1159. REGISTER_COMMAND(
  1160. "sys_crashtest",
  1161. CmdCrashTest,
  1162. VF_CHEAT,
  1163. "Make the game crash\n"
  1164. "0=off\n"
  1165. "1=null pointer exception\n"
  1166. "2=floating point exception\n"
  1167. "3=memory allocation exception\n"
  1168. "4=cry fatal error is called\n"
  1169. "5=memory allocation for small blocks\n"
  1170. "6=assert\n"
  1171. "7=debugbreak\n"
  1172. "8=10min sleep");
  1173. REGISTER_FLOAT("sys_scale3DMouseTranslation", 0.2f, 0, "Scales translation speed of supported 3DMouse devices.");
  1174. REGISTER_FLOAT("sys_Scale3DMouseYPR", 0.05f, 0, "Scales rotation speed of supported 3DMouse devices.");
  1175. REGISTER_INT("capture_frames", 0, 0, "Enables capturing of frames. 0=off, 1=on");
  1176. REGISTER_STRING("capture_folder", "CaptureOutput", 0, "Specifies sub folder to write captured frames.");
  1177. REGISTER_INT("capture_frame_once", 0, 0, "Makes capture single frame only");
  1178. REGISTER_STRING("capture_file_name", "", 0, "If set, specifies the path and name to use for the captured frame");
  1179. REGISTER_STRING(
  1180. "capture_file_prefix", "", 0, "If set, specifies the prefix to use for the captured frame instead of the default 'Frame'.");
  1181. m_gpu_particle_physics =
  1182. REGISTER_INT("gpu_particle_physics", 0, VF_REQUIRE_APP_RESTART, "Enable GPU physics if available (0=off / 1=enabled).");
  1183. assert(m_gpu_particle_physics);
  1184. REGISTER_COMMAND(
  1185. "LoadConfig",
  1186. &LoadConfigurationCmd,
  1187. 0,
  1188. "Load .cfg file from disk (from the {Game}/Config directory)\n"
  1189. "e.g. LoadConfig lowspec.cfg\n"
  1190. "Usage: LoadConfig <filename>");
  1191. assert(m_env.pConsole);
  1192. m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F12", "Screenshot");
  1193. m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F11", "RecordClip");
  1194. REGISTER_CVAR2("sys_trackview", &g_cvars.sys_trackview, 1, 0, "Enables TrackView Update");
  1195. // Defines selected language.
  1196. REGISTER_STRING_CB("g_language", "", VF_NULL, "Defines which language pak is loaded", CSystem::OnLanguageCVarChanged);
  1197. // adding CVAR to toggle assert verbosity level
  1198. const int defaultAssertValue = 1;
  1199. REGISTER_CVAR2_CB(
  1200. "sys_asserts",
  1201. &g_cvars.sys_asserts,
  1202. defaultAssertValue,
  1203. VF_CHEAT,
  1204. "0 = Suppress Asserts\n"
  1205. "1 = Log Asserts\n"
  1206. "2 = Show Assert Dialog\n"
  1207. "3 = Crashes the Application on Assert\n"
  1208. "Note: when set to '0 = Suppress Asserts', assert expressions are still evaluated. To turn asserts into a no-op, undefine "
  1209. "AZ_ENABLE_TRACING and recompile.",
  1210. OnAssertLevelCvarChanged);
  1211. CSystem::SetAssertLevel(defaultAssertValue);
  1212. REGISTER_CVAR2(
  1213. "sys_error_debugbreak", &g_cvars.sys_error_debugbreak, 0, VF_CHEAT, "__debugbreak() if a VALIDATOR_ERROR_DBGBREAK message is hit");
  1214. REGISTER_STRING("dlc_directory", "", 0, "Holds the path to the directory where DLC should be installed to and read from");
  1215. #if defined(WIN32) || defined(WIN64)
  1216. REGISTER_INT("sys_screensaver_allowed", 0, VF_NULL, "Specifies if screen saver is allowed to start up while the game is running.");
  1217. #endif
  1218. }
  1219. /////////////////////////////////////////////////////////////////////
  1220. void CSystem::AddCVarGroupDirectory(const AZStd::string& sPath)
  1221. {
  1222. CryLog("creating CVarGroups from directory '%s' ...", sPath.c_str());
  1223. INDENT_LOG_DURING_SCOPE();
  1224. AZ::IO::ArchiveFileIterator handle = gEnv->pCryPak->FindFirst(ConcatPath(sPath.c_str(), "*.cfg").c_str());
  1225. if (!handle)
  1226. {
  1227. return;
  1228. }
  1229. do
  1230. {
  1231. if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
  1232. {
  1233. if (handle.m_filename != "." && handle.m_filename != "..")
  1234. {
  1235. AddCVarGroupDirectory(ConcatPath(sPath.c_str(), handle.m_filename.data()));
  1236. }
  1237. }
  1238. } while (handle = gEnv->pCryPak->FindNext(handle));
  1239. gEnv->pCryPak->FindClose(handle);
  1240. }
  1241. bool CSystem::RegisterErrorObserver(IErrorObserver* errorObserver)
  1242. {
  1243. return stl::push_back_unique(m_errorObservers, errorObserver);
  1244. }
  1245. bool CSystem::UnregisterErrorObserver(IErrorObserver* errorObserver)
  1246. {
  1247. return stl::find_and_erase(m_errorObservers, errorObserver);
  1248. }
  1249. void CSystem::OnAssert(const char* condition, const char* message, const char* fileName, unsigned int fileLineNumber)
  1250. {
  1251. if (g_cvars.sys_asserts == 0)
  1252. {
  1253. return;
  1254. }
  1255. std::vector<IErrorObserver*>::const_iterator end = m_errorObservers.end();
  1256. for (std::vector<IErrorObserver*>::const_iterator it = m_errorObservers.begin(); it != end; ++it)
  1257. {
  1258. (*it)->OnAssert(condition, message, fileName, fileLineNumber);
  1259. }
  1260. if (g_cvars.sys_asserts > 1)
  1261. {
  1262. CryFatalError("<assert> %s\r\n%s\r\n%s (%d)\r\n", condition, message, fileName, fileLineNumber);
  1263. }
  1264. }
  1265. void CSystem::OnFatalError(const char* message)
  1266. {
  1267. std::vector<IErrorObserver*>::const_iterator end = m_errorObservers.end();
  1268. for (std::vector<IErrorObserver*>::const_iterator it = m_errorObservers.begin(); it != end; ++it)
  1269. {
  1270. (*it)->OnFatalError(message);
  1271. }
  1272. }
  1273. bool CSystem::IsAssertDialogVisible() const
  1274. {
  1275. return m_bIsAsserting;
  1276. }
  1277. void CSystem::SetAssertVisible(bool bAssertVisble)
  1278. {
  1279. m_bIsAsserting = bAssertVisble;
  1280. }