SystemInit.cpp 54 KB

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