SystemInit.cpp 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496
  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. m_sys_load_files_to_memory = REGISTER_STRING(
  1024. "sys_load_files_to_memory",
  1025. "shadercache.pak",
  1026. 0,
  1027. "Specify comma separated list of filenames that need to be loaded to memory.\n"
  1028. "Partial names also work. Eg. \"shader\" will load:\n"
  1029. "shaders.pak, shadercache.pak, and shadercachestartup.pak");
  1030. #ifndef _RELEASE
  1031. REGISTER_STRING_CB("sys_version", "", VF_CHEAT, "Override system file/product version", SystemVersionChanged);
  1032. #endif // #ifndef _RELEASE
  1033. attachVariable("sys_PakSaveLevelResourceList", &g_cvars.archiveVars.nSaveLevelResourceList, "Save resource list when loading level");
  1034. attachVariable("sys_PakLogInvalidFileAccess", &g_cvars.archiveVars.nLogInvalidFileAccess, "Log synchronous file access when in game");
  1035. m_sysNoUpdate = REGISTER_INT(
  1036. "sys_noupdate",
  1037. 0,
  1038. VF_CHEAT,
  1039. "Toggles updating of system with sys_script_debugger.\n"
  1040. "Usage: sys_noupdate [0/1]\n"
  1041. "Default is 0 (system updates during debug).");
  1042. #if defined(_RELEASE) && defined(CONSOLE) && !defined(ENABLE_LW_PROFILERS)
  1043. enum
  1044. {
  1045. e_sysKeyboardDefault = 0
  1046. };
  1047. #else
  1048. enum
  1049. {
  1050. e_sysKeyboardDefault = 1
  1051. };
  1052. #endif
  1053. m_svDedicatedMaxRate = REGISTER_FLOAT(
  1054. "sv_DedicatedMaxRate",
  1055. 30.0f,
  1056. 0,
  1057. "Sets the maximum update rate when running as a dedicated server.\n"
  1058. "Usage: sv_DedicatedMaxRate [5..500]\n"
  1059. "Default is 30.");
  1060. REGISTER_FLOAT(
  1061. "sv_DedicatedCPUPercent",
  1062. 0.0f,
  1063. 0,
  1064. "Sets the target CPU usage when running as a dedicated server, or disable this feature if it's zero.\n"
  1065. "Usage: sv_DedicatedCPUPercent [0..100]\n"
  1066. "Default is 0 (disabled).");
  1067. REGISTER_FLOAT(
  1068. "sv_DedicatedCPUVariance",
  1069. 10.0f,
  1070. 0,
  1071. "Sets how much the CPU can vary from sv_DedicateCPU (up or down) without adjusting the framerate.\n"
  1072. "Usage: sv_DedicatedCPUVariance [5..50]\n"
  1073. "Default is 10.");
  1074. m_sys_firstlaunch = REGISTER_INT("sys_firstlaunch", 0, 0, "Indicates that the game was run for the first time.");
  1075. #if defined(AZ_RESTRICTED_PLATFORM)
  1076. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_12
  1077. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  1078. #endif
  1079. #if defined(AZ_RESTRICTED_PLATFORM)
  1080. #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_17
  1081. #include AZ_RESTRICTED_FILE(SystemInit_cpp)
  1082. #endif
  1083. #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
  1084. #undef AZ_RESTRICTED_SECTION_IMPLEMENTED
  1085. #else
  1086. #define SYS_STREAMING_CPU_DEFAULT_VALUE 1
  1087. #define SYS_STREAMING_CPU_WORKER_DEFAULT_VALUE 5
  1088. #endif
  1089. #define DEFAULT_USE_OPTICAL_DRIVE_THREAD (gEnv->IsDedicated() ? 0 : 1)
  1090. const char* localizeFolder = "Localization";
  1091. g_cvars.sys_localization_folder = REGISTER_STRING_CB(
  1092. "sys_localization_folder",
  1093. localizeFolder,
  1094. VF_NULL,
  1095. "Sets the folder where to look for localized data.\n"
  1096. "This cvar allows for backwards compatibility so localized data under the game folder can still be found.\n"
  1097. "Usage: sys_localization_folder <folder name>\n"
  1098. "Default: Localization\n",
  1099. CSystem::OnLocalizationFolderCVarChanged);
  1100. REGISTER_CVAR2("sys_float_exceptions", &g_cvars.sys_float_exceptions, 0, 0, "Use or not use floating point exceptions.");
  1101. REGISTER_CVAR2("sys_update_profile_time", &g_cvars.sys_update_profile_time, 1.0f, 0, "Time to keep updates timings history for.");
  1102. REGISTER_CVAR2(
  1103. "sys_no_crash_dialog", &g_cvars.sys_no_crash_dialog, m_bNoCrashDialog, VF_NULL, "Whether to disable the crash dialog window");
  1104. REGISTER_CVAR2(
  1105. "sys_no_error_report_window",
  1106. &g_cvars.sys_no_error_report_window,
  1107. m_bNoErrorReportWindow,
  1108. VF_NULL,
  1109. "Whether to disable the error report list");
  1110. #if defined(_RELEASE)
  1111. if (!gEnv->IsDedicated())
  1112. {
  1113. REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 1, 0, "Enables Windows Error Reporting");
  1114. }
  1115. #else
  1116. REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 0, 0, "Enables Windows Error Reporting");
  1117. #endif
  1118. const int DEFAULT_DUMP_TYPE = 2;
  1119. REGISTER_CVAR2(
  1120. "sys_dump_type",
  1121. &g_cvars.sys_dump_type,
  1122. DEFAULT_DUMP_TYPE,
  1123. VF_NULL,
  1124. "Specifies type of crash dump to create - see MINIDUMP_TYPE in dbghelp.h for full list of values\n"
  1125. "0: Do not create a minidump\n"
  1126. "1: Create a small minidump (stacktrace)\n"
  1127. "2: Create a medium minidump (+ some variables)\n"
  1128. "3: Create a full minidump (+ all memory)\n");
  1129. REGISTER_CVAR2(
  1130. "sys_dump_aux_threads", &g_cvars.sys_dump_aux_threads, 1, VF_NULL, "Dumps callstacks of other threads in case of a crash");
  1131. #if (defined(WIN32) || defined(WIN64)) && defined(_RELEASE)
  1132. const int DEFAULT_SYS_MAX_FPS = 0;
  1133. #else
  1134. const int DEFAULT_SYS_MAX_FPS = -1;
  1135. #endif
  1136. REGISTER_CVAR2(
  1137. "sys_MaxFPS",
  1138. &g_cvars.sys_MaxFPS,
  1139. DEFAULT_SYS_MAX_FPS,
  1140. VF_NULL,
  1141. "Limits the frame rate to specified number n (if n>0 and if vsync is disabled).\n"
  1142. " 0 = on PC if vsync is off auto throttles fps while in menu or game is paused (default)\n"
  1143. "-1 = off");
  1144. REGISTER_CVAR2(
  1145. "sys_maxTimeStepForMovieSystem",
  1146. &g_cvars.sys_maxTimeStepForMovieSystem,
  1147. 0.1f,
  1148. VF_NULL,
  1149. "Caps the time step for the movie system so that a cut-scene won't be jumped in the case of an extreme stall.");
  1150. REGISTER_COMMAND(
  1151. "sys_crashtest",
  1152. CmdCrashTest,
  1153. VF_CHEAT,
  1154. "Make the game crash\n"
  1155. "0=off\n"
  1156. "1=null pointer exception\n"
  1157. "2=floating point exception\n"
  1158. "3=memory allocation exception\n"
  1159. "4=cry fatal error is called\n"
  1160. "5=memory allocation for small blocks\n"
  1161. "6=assert\n"
  1162. "7=debugbreak\n"
  1163. "8=10min sleep");
  1164. REGISTER_FLOAT("sys_scale3DMouseTranslation", 0.2f, 0, "Scales translation speed of supported 3DMouse devices.");
  1165. REGISTER_FLOAT("sys_Scale3DMouseYPR", 0.05f, 0, "Scales rotation speed of supported 3DMouse devices.");
  1166. REGISTER_INT("capture_frames", 0, 0, "Enables capturing of frames. 0=off, 1=on");
  1167. REGISTER_STRING("capture_folder", "CaptureOutput", 0, "Specifies sub folder to write captured frames.");
  1168. REGISTER_INT("capture_frame_once", 0, 0, "Makes capture single frame only");
  1169. REGISTER_STRING("capture_file_name", "", 0, "If set, specifies the path and name to use for the captured frame");
  1170. REGISTER_STRING(
  1171. "capture_file_prefix", "", 0, "If set, specifies the prefix to use for the captured frame instead of the default 'Frame'.");
  1172. m_gpu_particle_physics =
  1173. REGISTER_INT("gpu_particle_physics", 0, VF_REQUIRE_APP_RESTART, "Enable GPU physics if available (0=off / 1=enabled).");
  1174. assert(m_gpu_particle_physics);
  1175. REGISTER_COMMAND(
  1176. "LoadConfig",
  1177. &LoadConfigurationCmd,
  1178. 0,
  1179. "Load .cfg file from disk (from the {Game}/Config directory)\n"
  1180. "e.g. LoadConfig lowspec.cfg\n"
  1181. "Usage: LoadConfig <filename>");
  1182. assert(m_env.pConsole);
  1183. m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F12", "Screenshot");
  1184. m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F11", "RecordClip");
  1185. REGISTER_CVAR2("sys_trackview", &g_cvars.sys_trackview, 1, 0, "Enables TrackView Update");
  1186. // Defines selected language.
  1187. REGISTER_STRING_CB("g_language", "", VF_NULL, "Defines which language pak is loaded", CSystem::OnLanguageCVarChanged);
  1188. // adding CVAR to toggle assert verbosity level
  1189. const int defaultAssertValue = 1;
  1190. REGISTER_CVAR2_CB(
  1191. "sys_asserts",
  1192. &g_cvars.sys_asserts,
  1193. defaultAssertValue,
  1194. VF_CHEAT,
  1195. "0 = Suppress Asserts\n"
  1196. "1 = Log Asserts\n"
  1197. "2 = Show Assert Dialog\n"
  1198. "3 = Crashes the Application on Assert\n"
  1199. "Note: when set to '0 = Suppress Asserts', assert expressions are still evaluated. To turn asserts into a no-op, undefine "
  1200. "AZ_ENABLE_TRACING and recompile.",
  1201. OnAssertLevelCvarChanged);
  1202. CSystem::SetAssertLevel(defaultAssertValue);
  1203. REGISTER_CVAR2(
  1204. "sys_error_debugbreak", &g_cvars.sys_error_debugbreak, 0, VF_CHEAT, "__debugbreak() if a VALIDATOR_ERROR_DBGBREAK message is hit");
  1205. REGISTER_STRING("dlc_directory", "", 0, "Holds the path to the directory where DLC should be installed to and read from");
  1206. #if defined(WIN32) || defined(WIN64)
  1207. REGISTER_INT("sys_screensaver_allowed", 0, VF_NULL, "Specifies if screen saver is allowed to start up while the game is running.");
  1208. #endif
  1209. }
  1210. /////////////////////////////////////////////////////////////////////
  1211. void CSystem::AddCVarGroupDirectory(const AZStd::string& sPath)
  1212. {
  1213. CryLog("creating CVarGroups from directory '%s' ...", sPath.c_str());
  1214. INDENT_LOG_DURING_SCOPE();
  1215. AZ::IO::ArchiveFileIterator handle = gEnv->pCryPak->FindFirst(ConcatPath(sPath.c_str(), "*.cfg").c_str());
  1216. if (!handle)
  1217. {
  1218. return;
  1219. }
  1220. do
  1221. {
  1222. if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
  1223. {
  1224. if (handle.m_filename != "." && handle.m_filename != "..")
  1225. {
  1226. AddCVarGroupDirectory(ConcatPath(sPath.c_str(), handle.m_filename.data()));
  1227. }
  1228. }
  1229. } while (handle = gEnv->pCryPak->FindNext(handle));
  1230. gEnv->pCryPak->FindClose(handle);
  1231. }
  1232. bool CSystem::RegisterErrorObserver(IErrorObserver* errorObserver)
  1233. {
  1234. return stl::push_back_unique(m_errorObservers, errorObserver);
  1235. }
  1236. bool CSystem::UnregisterErrorObserver(IErrorObserver* errorObserver)
  1237. {
  1238. return stl::find_and_erase(m_errorObservers, errorObserver);
  1239. }
  1240. void CSystem::OnAssert(const char* condition, const char* message, const char* fileName, unsigned int fileLineNumber)
  1241. {
  1242. if (g_cvars.sys_asserts == 0)
  1243. {
  1244. return;
  1245. }
  1246. std::vector<IErrorObserver*>::const_iterator end = m_errorObservers.end();
  1247. for (std::vector<IErrorObserver*>::const_iterator it = m_errorObservers.begin(); it != end; ++it)
  1248. {
  1249. (*it)->OnAssert(condition, message, fileName, fileLineNumber);
  1250. }
  1251. if (g_cvars.sys_asserts > 1)
  1252. {
  1253. CryFatalError("<assert> %s\r\n%s\r\n%s (%d)\r\n", condition, message, fileName, fileLineNumber);
  1254. }
  1255. }
  1256. void CSystem::OnFatalError(const char* message)
  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)->OnFatalError(message);
  1262. }
  1263. }
  1264. bool CSystem::IsAssertDialogVisible() const
  1265. {
  1266. return m_bIsAsserting;
  1267. }
  1268. void CSystem::SetAssertVisible(bool bAssertVisble)
  1269. {
  1270. m_bIsAsserting = bAssertVisble;
  1271. }