Files
o3de/Code/Legacy/CrySystem/SystemInit.cpp
T
Artur K 56904d1799 Cry Legacy: the Lessening (#5961)
* Generic Cleanup

Removals:

* Unused cvars,member variables and defines
* Windows media center edition support routines
* CSystem - removed debug_GetCallStackRaw/GetRootWindowMessageHandler/
UnloadDLL/ShutdownModuleLibraries

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Fix CryMessageBox return values in Windows build

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove named selection group and a few smaller unused functionalities

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove ObjectManager export functionality + 2 deprecated functions

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove object legacy freeze/hide support from ObjectManager

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove ObjectManager duplicate name dection, as well as object renaming

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove ObjectManager serialization and selection callbacks

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* ObjectManager - remove MoveObjects/HitTestObject/EndEditParams and related members/functions

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove a bunch of unused clone related functionality + misc

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* ObjectManager - misc removals

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* ObjectManager - more removals

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove unused object selection/retrieval in ObjectManager and LoadObjects in ObjectLoader

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject - remove unused material layers mask support

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* More CBaseObject cleanups.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject - remove SubObj functions and IMouseCreateCallback

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove unused procedural floor management, helper scale and tags.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject - remove more unused methods.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Removals in multiple places.

CBaseObject - unused `OBJTYPE_DUMMY` flag removed, member `IsSameClass`
CObjectArchive removed unused methods/members
CObjectManager removed unused `Update` method

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* More removals

IDisplayViewport - HitTestLine/GetGridStep/setHitcontext/
GetConstructionPlane
Unused Cry_Matrix44 template specializations.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* O3DE.exe Project-Centric "Open Editor" fix (#5852)

* The O3DE.exe Open Editor button now attempts to open the Editor in the
build directory of the project being opened.

If their is no Editor within the build directory of the Project, it uses
the Editor.exe in the current O3DE.exe executable directory if it exists

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Engine .gitignore now ignores the build directory if placed in the
AutomatedTesting project

Previously it was just ignoring a `[Bb]uild` directory if it was
directly within the engine root.
This change matches the behavior of the project templates.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Renamed the ProjectUtils GetEditorDirectory function to
GetEditorExecutablePath

Added a platform specific implementation for retrieving the path to the
Editor executable in the GetEditorExectuablePath function.

It first attempts to locate the Editor via checking the project build
directory for an Editor executable before falling back to checking the
binary directory of the currently running O3DE executable.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Correct the MacOS GetEditorExecutablePath to return the Editor path

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Adding missing C++20 std::erase implementations (#5735)

There were already implementations for std::erase_if.
This adds the counterpart AZStd::erase versions

resolves #5734

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* More removals and refactors

`ShowMessage` and `CryMessageBox` return void now
Simplify code in `CSystem::WarningV`
Remove unused `CryGetTicksPerSec`
Remove unused WinBase functionality
Replace `nanosleep` call in WinBase with `std::this_thread::sleep_for`
Remove unused Win32Wrapper routines
Remove unused IFunctorBase.h and IEntityObjectListener.h
Fix VectorAndArray.cpp compilation
Use QMessageBox instead of CryMessageBox in the editor.
Remove empty ArchiveVars platform specific files

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Fix test code.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove an unused  function

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject and undo description removals.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* A bunch of removals

* Remove IRenderNode
* Remove editor's KDTree
* Remove StatObjBus, InstanceStatObjEventBus::ReleaseData is redundant (
same functionality in the only available handler is triggered by
`OnCryEditorCloseScene`)
* Remove CExportManager::AddStatObj/AddMeshes/AddMesh,
IExportManager::ExportSingleStatObj
* Remove CIconManager/IIconManager::GetObject
* Remove CBaseObject::IntersectRayMesh
* Remove IIndexedMesh and related structs.
* Unused IUndoObject::GetDescription and all derived implementations.
* Unused CUndoBaseLibrary/CUndoBaseLibraryManager
* Unused Matrix34_tpl typedefs
* Legacy Xml classes cleanup

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove unused `Vec3ToVector3D` helper

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* fix - remove unused static variable

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
2021-11-29 11:21:06 -07:00

1489 lines
54 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "CrySystem_precompiled.h"
#include "System.h"
#if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
#undef AZ_RESTRICTED_SECTION
#define SYSTEMINIT_CPP_SECTION_2 2
#define SYSTEMINIT_CPP_SECTION_3 3
#define SYSTEMINIT_CPP_SECTION_4 4
#define SYSTEMINIT_CPP_SECTION_5 5
#define SYSTEMINIT_CPP_SECTION_6 6
#define SYSTEMINIT_CPP_SECTION_7 7
#define SYSTEMINIT_CPP_SECTION_8 8
#define SYSTEMINIT_CPP_SECTION_9 9
#define SYSTEMINIT_CPP_SECTION_10 10
#define SYSTEMINIT_CPP_SECTION_11 11
#define SYSTEMINIT_CPP_SECTION_12 12
#define SYSTEMINIT_CPP_SECTION_13 13
#define SYSTEMINIT_CPP_SECTION_14 14
#define SYSTEMINIT_CPP_SECTION_15 15
#define SYSTEMINIT_CPP_SECTION_16 16
#define SYSTEMINIT_CPP_SECTION_17 17
#endif
#include "CryPath.h"
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
#include <AzCore/IO/Streamer/Streamer.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/Asset/AssetProcessorMessages.h>
#include <AzFramework/Asset/AssetSystemBus.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzFramework/API/ApplicationAPI.h>
#include "AZCoreLogSink.h"
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzFramework/Archive/INestedArchive.h>
#include <AzFramework/Archive/ArchiveFileIO.h>
#include <LoadScreenBus.h>
#include <LyShine/Bus/UiSystemBus.h>
#include <AzFramework/Logging/MissingAssetLogger.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Utils/Utils.h>
#if defined(APPLE) || defined(LINUX)
#include <dlfcn.h>
#include <cstdlib>
#endif
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include <float.h>
#endif //WIN32
#include <IRenderer.h>
#include <AzCore/IO/FileIO.h>
#include <IMovieSystem.h>
#include <ILog.h>
#include <IAudioSystem.h>
#include <ICmdLine.h>
#include <IProcess.h>
#include <LyShine/ILyShine.h>
#include <AzFramework/Archive/Archive.h>
#include "XConsole.h"
#include "Log.h"
#include "XML/xml.h"
#include "LocalizedStringManager.h"
#include "SystemEventDispatcher.h"
#include "LevelSystem/LevelSystem.h"
#include "LevelSystem/SpawnableLevelSystem.h"
#include <CrySystemBus.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Jobs/JobManagerBus.h>
#if defined(ANDROID)
#include <AzCore/Android/Utils.h>
#endif
#if defined(EXTERNAL_CRASH_REPORTING)
#include <CrashHandler.h>
#endif
// select the asset processor based on cvars and defines.
// uncomment the following and edit the path where it is instantiated if you'd like to use the test file client
//#define USE_TEST_FILE_CLIENT
#if defined(REMOTE_ASSET_PROCESSOR)
// Over here, we'd put the header to the Remote Asset Processor interface (as opposed to the Local built in version below)
# include <AzFramework/Network/AssetProcessorConnection.h>
#endif
#ifdef WIN32
extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers);
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_14
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
#endif
#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER
#include <execinfo.h>
#include <signal.h>
void CryEngineSignalHandler(int signal)
{
char resolvedPath[_MAX_PATH];
// it is assumed that @log@ points at the appropriate place (so for apple, to the user profile dir)
if (AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath("@log@/crash.log", resolvedPath, _MAX_PATH))
{
fprintf(stderr, "Crash Signal Handler - logged to %s\n", resolvedPath);
FILE* file = fopen(resolvedPath, "a");
if (file)
{
char sTime[128];
time_t ltime;
time(&ltime);
struct tm* today = localtime(&ltime);
strftime(sTime, 40, "<%Y-%m-%d %H:%M:%S> ", today);
fprintf(file, "%s: Error: signal %s:\n", sTime, strsignal(signal));
fflush(file);
void* array[100];
int s = backtrace(array, 100);
backtrace_symbols_fd(array, s, fileno(file));
fclose(file);
CryLogAlways("Successfully recorded crash file: '%s'", resolvedPath);
abort();
}
}
CryLogAlways("Could not record crash file...");
abort();
}
#endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER
//////////////////////////////////////////////////////////////////////////
#define DEFAULT_LOG_FILENAME "@log@/Log.txt"
#define CRYENGINE_ENGINE_FOLDER "Engine"
//////////////////////////////////////////////////////////////////////////
#define CRYENGINE_DEFAULT_LOCALIZATION_LANG "en-US"
#define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml"
#define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow()
#ifdef WIN32
extern HMODULE gDLLHandle;
#endif
//static int g_sysSpecChanged = false;
struct SCVarsClientConfigSink
: public ILoadConfigurationEntrySink
{
virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, [[maybe_unused]] const char* szGroup)
{
gEnv->pConsole->SetClientDataProbeString(szKey, szValue);
}
};
//////////////////////////////////////////////////////////////////////////
static inline void InlineInitializationProcessing([[maybe_unused]] const char* sDescription)
{
if (gEnv->pLog)
{
gEnv->pLog->UpdateLoadingScreen(0);
}
}
//////////////////////////////////////////////////////////////////////////
AZ_PUSH_DISABLE_WARNING(4723, "-Wunknown-warning-option") // potential divide by 0 (needs to wrap the function)
static void CmdCrashTest(IConsoleCmdArgs* pArgs)
{
assert(pArgs);
if (pArgs->GetArgCount() == 2)
{
//This method intentionally crashes, a lot.
int crashType = atoi(pArgs->GetArg(1));
switch (crashType)
{
case 1:
{
int* p = 0;
*p = 0xABCD;
}
break;
case 2:
{
float a = 1.0f;
memset(&a, 0, sizeof(a));
[[maybe_unused]] float* b = &a;
[[maybe_unused]] float c = 3;
CryLog("%f", (c / *b));
}
break;
case 3:
while (true)
{
new char[10240];
}
break;
case 4:
CryFatalError("sys_crashtest 4");
break;
case 5:
while (true)
{
new char[128]; //testing the crash handler an exception in the cry memory allocation occurred
}
case 6:
{
AZ_Assert(false, "Testing assert for testing crashes");
}
break;
case 7:
__debugbreak();
break;
case 8:
CrySleep(1000 * 60 * 10);
break;
}
}
}
AZ_POP_DISABLE_WARNING
static ESystemConfigPlatform GetDevicePlatform()
{
#if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX)
return CONFIG_PC;
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_PLATFORM_ANDROID)
return CONFIG_ANDROID;
#elif defined(AZ_PLATFORM_IOS)
return CONFIG_IOS;
#elif defined(AZ_PLATFORM_MAC)
return CONFIG_OSX_METAL;
#else
AZ_Assert(false, "Platform not supported");
return CONFIG_INVALID_PLATFORM;
#endif
}
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
bool CSystem::InitConsole()
{
if (m_env.pConsole)
{
m_env.pConsole->Init(this);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// attaches the given variable to the given container;
// recreates the variable if necessary
ICVar* CSystem::attachVariable (const char* szVarName, int* pContainer, const char* szComment, int dwFlags)
{
IConsole* pConsole = GetIConsole();
ICVar* pOldVar = pConsole->GetCVar (szVarName);
int nDefault = 0;
if (pOldVar)
{
nDefault = pOldVar->GetIVal();
pConsole->UnregisterVariable(szVarName, true);
}
// NOTE: maybe we should preserve the actual value of the variable across the registration,
// because of the strange architecture of IConsole that converts int->float->int
REGISTER_CVAR2(szVarName, pContainer, *pContainer, dwFlags, szComment);
ICVar* pVar = pConsole->GetCVar(szVarName);
#ifdef _DEBUG
// test if the variable really has this container
assert (*pContainer == pVar->GetIVal());
++*pContainer;
assert (*pContainer == pVar->GetIVal());
--*pContainer;
#endif
if (pOldVar)
{
// carry on the default value from the old variable anyway
pVar->Set(nDefault);
}
return pVar;
}
/////////////////////////////////////////////////////////////////////////////////
bool CSystem::InitFileSystem()
{
using namespace AzFramework::AssetSystem;
if (m_pUserCallback)
{
m_pUserCallback->OnInitProgress("Initializing File System...");
}
m_env.pCryPak = AZ::Interface<AZ::IO::IArchive>::Get();
m_env.pFileIO = AZ::IO::FileIOBase::GetInstance();
AZ_Assert(m_env.pCryPak, "CryPak has not been initialized on AZ::Interface");
AZ_Assert(m_env.pFileIO, "FileIOBase has not been initialized");
if (m_bEditor)
{
m_env.pCryPak->RecordFileOpen(AZ::IO::IArchive::RFOM_EngineStartup);
}
// Now that file systems are init, we will clear any events that have arrived
// during file system init, so that systems do not reload assets that were already compiled in the
// critical compilation section.
AzFramework::LegacyAssetEventBus::ClearQueuedEvents();
//we are good to go
return true;
}
void CSystem::ShutdownFileSystem()
{
m_env.pFileIO = nullptr;
}
/////////////////////////////////////////////////////////////////////////////////
bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
{
LoadConfiguration(m_systemConfigName.c_str());
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Loading system configuration from %s...", m_systemConfigName.c_str());
#if defined(AZ_PLATFORM_ANDROID)
AZ::Android::Utils::SetLoadFilesToMemory(m_sys_load_files_to_memory->GetString());
#endif
GetISystem()->SetConfigPlatform(GetDevicePlatform());
auto projectPath = AZ::Utils::GetProjectPath();
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Path: %s\n", projectPath.empty() ? "None specified" : projectPath.c_str());
auto projectName = AZ::Utils::GetProjectName();
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str());
OpenPlatformPaks();
// Load game-specific folder.
LoadConfiguration("game.cfg");
// Load the client/sever-specific configuration
static const char* g_additionalConfig = gEnv->IsDedicated() ? "server_cfg" : "client_cfg";
LoadConfiguration(g_additionalConfig, nullptr, false);
// We do not use CVar groups on the consoles
AddCVarGroupDirectory("Config/CVarGroups");
return (true);
}
//////////////////////////////////////////////////////////////////////////
bool CSystem::InitAudioSystem(const SSystemInitParams& initParams)
{
if (!Audio::Gem::AudioSystemGemRequestBus::HasHandlers())
{
// AudioSystem Gem has not been enabled for this project.
// This should not generate an error, but calling scope will warn.
return false;
}
bool useRealAudioSystem = false;
if (!initParams.bPreview
&& !m_bDedicatedServer
&& m_sys_audio_disable->GetIVal() == 0)
{
useRealAudioSystem = true;
}
bool result = false;
if (useRealAudioSystem)
{
Audio::Gem::AudioSystemGemRequestBus::BroadcastResult(result, &Audio::Gem::AudioSystemGemRequestBus::Events::Initialize, &initParams);
}
else
{
Audio::Gem::AudioSystemGemRequestBus::BroadcastResult(result, &Audio::Gem::AudioSystemGemRequestBus::Events::Initialize, nullptr);
}
if (result)
{
AZ_Assert(Audio::AudioSystemRequestBus::HasHandlers(),
"Initialization of the Audio System succeeded, but the Audio System EBus is not connected!\n");
}
else
{
AZ_Error(AZ_TRACE_SYSTEM_WINDOW, result, "The Audio System did not initialize correctly!\n");
}
return result;
}
//////////////////////////////////////////////////////////////////////////
void CSystem::InitLocalization()
{
// Set the localization folder
ICVar* pCVar = m_env.pConsole != 0 ? m_env.pConsole->GetCVar("sys_localization_folder") : 0;
if (pCVar)
{
static_cast<AZ::IO::Archive* const>(m_env.pCryPak)->SetLocalizationFolder(g_cvars.sys_localization_folder->GetString());
}
// Removed line that assigned language based on a #define
if (m_pLocalizationManager == nullptr)
{
m_pLocalizationManager = new CLocalizedStringsManager(this);
}
// Platform-specific implementation of getting the system language
ILocalizationManager::EPlatformIndependentLanguageID languageID = m_pLocalizationManager->GetSystemLanguage();
if (!m_pLocalizationManager->IsLanguageSupported(languageID))
{
languageID = ILocalizationManager::EPlatformIndependentLanguageID::ePILID_English_US;
}
AZStd::string language = m_pLocalizationManager->LangNameFromPILID(languageID);
m_pLocalizationManager->SetLanguage(language.c_str());
if (m_pLocalizationManager->GetLocalizationFormat() == 1)
{
AZStd::string translationsListXML = LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME;
m_pLocalizationManager->InitLocalizationData(translationsListXML.c_str());
m_pLocalizationManager->LoadAllLocalizationData();
}
else
{
// if the language value cannot be found, let's default to the english pak
OpenLanguagePak(language.c_str());
}
if (auto console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
{
AZ::CVarFixedString languageAudio;
console->GetCvarValue("g_languageAudio", languageAudio);
if (languageAudio.empty())
{
console->PerformCommand(AZStd::string::format("g_languageAudio %s", language.c_str()).c_str());
}
else
{
language.assign(languageAudio.data(), languageAudio.size());
}
}
OpenLanguageAudioPak(language.c_str());
}
void CSystem::OpenPlatformPaks()
{
static bool bPlatformPaksLoaded = false;
if (bPlatformPaksLoaded)
{
return;
}
bPlatformPaksLoaded = true;
//////////////////////////////////////////////////////////////////////////
// Open engine packs
//////////////////////////////////////////////////////////////////////////
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
#endif
#ifdef AZ_PLATFORM_ANDROID
const char* const assetsDir = "@products@";
// Load Android Obb files if available
const char* obbStorage = AZ::Android::Utils::GetObbStoragePath();
AZStd::string mainObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(true)));
AZStd::string patchObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(false)));
m_env.pCryPak->OpenPack(assetsDir, mainObbPath.c_str());
m_env.pCryPak->OpenPack(assetsDir, patchObbPath.c_str());
#endif //AZ_PLATFORM_ANDROID
InlineInitializationProcessing("CSystem::OpenPlatformPaks OpenPacks( Engine... )");
}
//////////////////////////////////////////////////////////////////////////
void CSystem::OpenLanguagePak(const char* sLanguage)
{
// Don't attempt to open a language PAK file if the game doesn't have a
// loc folder configured.
bool projUsesLocalization = false;
LocalizationManagerRequestBus::BroadcastResult(projUsesLocalization, &LocalizationManagerRequestBus::Events::ProjectUsesLocalization);
if (!projUsesLocalization)
{
return;
}
// Initialize languages.
// Omit the trailing slash!
AZStd::string sLocalizationFolder = PathUtil::GetLocalizationFolder();
// load xml pak with full filenames to perform wildcard searches.
AZStd::string sLocalizedPath;
GetLocalizedPath(sLanguage, sLocalizedPath);
if (!m_env.pCryPak->OpenPacks({ sLocalizationFolder.c_str(), sLocalizationFolder.size() }, { sLocalizedPath.c_str(), sLocalizedPath.size() }, 0))
{
// make sure the localized language is found - not really necessary, for TC
AZ_Printf("Localization", "Localized language content(%s) not available or modified from the original installation.", sLanguage);
}
}
//////////////////////////////////////////////////////////////////////////
void CSystem::OpenLanguageAudioPak([[maybe_unused]] const char* sLanguage)
{
// Don't attempt to open a language PAK file if the game doesn't have a
// loc folder configured.
bool projUsesLocalization = false;
LocalizationManagerRequestBus::BroadcastResult(projUsesLocalization, &LocalizationManagerRequestBus::Events::ProjectUsesLocalization);
if (!projUsesLocalization)
{
return;
}
// Initialize languages.
// Omit the trailing slash!
AZStd::string sLocalizationFolder(AZStd::string().assign(PathUtil::GetLocalizationFolder(), 0, PathUtil::GetLocalizationFolder().size() - 1));
if (!AZ::StringFunc::Equal(sLocalizationFolder, "Languages", false))
{
sLocalizationFolder = "@products@";
}
// load localized pak with crc32 filenames on consoles to save memory.
AZStd::string sLocalizedPath = "loc.pak";
if (!m_env.pCryPak->OpenPacks(sLocalizationFolder.c_str(), sLocalizedPath.c_str()))
{
// make sure the localized language is found - not really necessary, for TC
AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "Localized language content(%s) not available or modified from the original installation.", sLanguage);
}
}
AZStd::string GetUniqueLogFileName(AZStd::string logFileName)
{
AZStd::string logFileNamePrefix = logFileName;
if ((logFileNamePrefix[0] != '@') && (AzFramework::StringFunc::Path::IsRelative(logFileNamePrefix.c_str())))
{
logFileNamePrefix = "@log@/";
logFileNamePrefix += logFileName;
}
char resolvedLogFilePathBuffer[AZ_MAX_PATH_LEN] = { 0 };
AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(logFileNamePrefix.c_str(), resolvedLogFilePathBuffer, AZ_MAX_PATH_LEN);
int instance = gEnv->pSystem->GetApplicationLogInstance(resolvedLogFilePathBuffer);
if (instance == 0)
{
return logFileNamePrefix;
}
AZStd::string logFileExtension;
size_t extensionIndex = logFileName.find_last_of('.');
if (extensionIndex != AZStd::string::npos)
{
logFileExtension = logFileName.substr(extensionIndex, logFileName.length() - extensionIndex);
logFileNamePrefix = logFileName.substr(0, extensionIndex);
}
logFileName = AZStd::string::format("%s(%d)%s", logFileNamePrefix.c_str(), instance, logFileExtension.c_str()).c_str();
return logFileName;
}
class AzConsoleToCryConsoleBinder final
{
public:
static void OnInvoke(IConsoleCmdArgs* args)
{
std::string command = args->GetCommandLine();
const size_t delim = command.find_first_of('=');
if (delim != std::string::npos)
{
// All Cry executed cfg files will come in through this pathway in addition to regular commands
// We strip out the = sign at this layer to maintain compatibility with cvars that use the '=' as a separator
// Swap the '=' character for a space
command[delim] = ' ';
}
AZ::Interface<AZ::IConsole>::Get()->PerformCommand(command.c_str(), AZ::ConsoleSilentMode::Silent, AZ::ConsoleInvokedFrom::CryBinding);
}
static void OnVarChanged(ICVar* cvar)
{
AZ::CVarFixedString command = AZ::CVarFixedString::format("%s %s", cvar->GetName(), cvar->GetString());
AZ::Interface<AZ::IConsole>::Get()->PerformCommand(command.c_str(), AZ::ConsoleSilentMode::Silent, AZ::ConsoleInvokedFrom::CryBinding);
}
static void Visit(AZ::ConsoleFunctorBase* functor)
{
if (gEnv->pConsole == nullptr)
{
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Cry console was NULL while attempting to register Az CVars and CFuncs.\n");
return;
}
int32_t cryFlags = VF_NET_SYNCED;
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::DontReplicate) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags = VF_NULL;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::ServerOnly) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_DEDI_ONLY;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::ReadOnly) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_READONLY;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsCheat) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_CHEAT;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsInvisible) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_INVISIBLE;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::IsDeprecated) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_DEPRECATED;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::NeedsReload) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_REQUIRE_APP_RESTART;
}
if ((functor->GetFlags() & AZ::ConsoleFunctorFlags::AllowClientSet) != AZ::ConsoleFunctorFlags::Null)
{
cryFlags |= VF_DEV_ONLY;
}
gEnv->pConsole->RemoveCommand(functor->GetName());
if (functor->GetTypeId() != AZ::TypeId::CreateNull())
{
AZ::CVarFixedString value;
functor->GetValue(value);
gEnv->pConsole->RegisterString(functor->GetName(), value.c_str(), cryFlags, functor->GetDesc(), AzConsoleToCryConsoleBinder::OnVarChanged);
}
else
{
gEnv->pConsole->AddCommand(functor->GetName(), AzConsoleToCryConsoleBinder::OnInvoke, cryFlags, functor->GetDesc());
}
}
using CommandRegisteredHandler = AZ::IConsole::ConsoleCommandRegisteredEvent::Handler;
static inline CommandRegisteredHandler s_commandRegisteredHandler = CommandRegisteredHandler([](AZ::ConsoleFunctorBase* functor) { Visit(functor); });
};
// System initialization
/////////////////////////////////////////////////////////////////////////////////
// INIT
/////////////////////////////////////////////////////////////////////////////////
bool CSystem::Init(const SSystemInitParams& startupParams)
{
#if AZ_TRAIT_USE_CRY_SIGNAL_HANDLER
signal(SIGSEGV, CryEngineSignalHandler);
signal(SIGTRAP, CryEngineSignalHandler);
signal(SIGILL, CryEngineSignalHandler);
#endif // AZ_TRAIT_USE_CRY_SIGNAL_HANDLER
// Temporary Fix for an issue accessing gEnv from this object instance. The gEnv is not resolving to the
// global gEnv, instead its resolving an some uninitialized gEnv elsewhere (NULL). Since gEnv is
// initialized to this instance's SSystemGlobalEnvironment (m_env), we will force set it again here
// to m_env
if (!gEnv)
{
gEnv = &m_env;
}
SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_INIT);
gEnv->mMainThreadId = GetCurrentThreadId(); //Set this ASAP on startup
InlineInitializationProcessing("CSystem::Init start");
m_env.bNoAssertDialog = false;
m_bNoCrashDialog = gEnv->IsDedicated();
if (startupParams.bUnattendedMode)
{
m_bNoCrashDialog = true;
m_env.bNoAssertDialog = true; //this also suppresses CryMessageBox
g_cvars.sys_no_crash_dialog = true;
}
#if defined(AZ_PLATFORM_LINUX)
// Linux is all console for now and so no room for dialog boxes!
m_env.bNoAssertDialog = true;
#endif
m_pCmdLine = new CCmdLine(startupParams.szSystemCmdLine);
AZCoreLogSink::Connect();
// Registers all AZ Console Variables functors specified within CrySystem
if (auto azConsole = AZ::Interface<AZ::IConsole>::Get(); azConsole)
{
azConsole->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
}
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
{
AZ::SettingsRegistryInterface::FixedValueString assetPlatform;
if (!AZ::SettingsRegistryMergeUtils::PlatformGet(*settingsRegistry, assetPlatform,
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey, "assets"))
{
assetPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME);
AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, R"(A valid asset platform is missing in "%s/assets" key in the SettingsRegistry.)""\n"
R"(This typically done by setting the "assets" field within a .setreg file)""\n"
R"(A fallback of %s will be used.)",
AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey,
assetPlatform.c_str());
}
m_systemConfigName = "system_" AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER "_";
m_systemConfigName += assetPlatform.c_str();
m_systemConfigName += ".cfg";
}
#if defined(WIN32) || defined(WIN64)
// check OS version - we only want to run on XP or higher - talk to Martin Mittring if you want to change this
{
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
GetVersionExW(&osvi);
AZ_POP_DISABLE_WARNING
bool bIsWindowsXPorLater = osvi.dwMajorVersion > 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1);
if (!bIsWindowsXPorLater)
{
AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "Open 3D Engine requires an OS version of Windows XP or later.");
return false;
}
}
#endif
// Get file version information.
QueryVersionInfo();
DetectGameFolderAccessRights();
m_bEditor = startupParams.bEditor;
m_bPreviewMode = startupParams.bPreview;
m_bTestMode = startupParams.bTestMode;
m_pUserCallback = startupParams.pUserCallback;
m_bDedicatedServer = startupParams.bDedicatedServer;
m_currentLanguageAudio = "";
#if !defined(CONSOLE)
m_env.SetIsEditor(m_bEditor);
m_env.SetIsEditorGameMode(false);
m_env.SetIsEditorSimulationMode(false);
#endif
m_env.SetToolMode(startupParams.bToolMode);
if (m_bEditor)
{
m_bInDevMode = true;
}
if (!gEnv->IsDedicated())
{
const ICmdLineArg* crashdialog = m_pCmdLine->FindArg(eCLAT_Post, "sys_no_crash_dialog");
if (crashdialog)
{
m_bNoCrashDialog = true;
}
}
#if !defined(_RELEASE)
if (!m_bDedicatedServer)
{
const ICmdLineArg* dedicated = m_pCmdLine->FindArg(eCLAT_Pre, "dedicated");
if (dedicated)
{
m_bDedicatedServer = true;
}
}
#endif // !defined(_RELEASE)
#if !defined(CONSOLE)
gEnv->SetIsDedicated(m_bDedicatedServer);
#endif
{
EBUS_EVENT(CrySystemEventBus, OnCrySystemPreInitialize, *this, startupParams);
//////////////////////////////////////////////////////////////////////////
// File system, must be very early
//////////////////////////////////////////////////////////////////////////
if (!InitFileSystem())
{
return false;
}
//////////////////////////////////////////////////////////////////////////
InlineInitializationProcessing("CSystem::Init InitFileSystem");
m_missingAssetLogger = AZStd::make_unique<AzFramework::MissingAssetLogger>();
//////////////////////////////////////////////////////////////////////////
// Logging is only available after file system initialization.
//////////////////////////////////////////////////////////////////////////
if (!startupParams.pLog)
{
m_env.pLog = new CLog(this);
if (startupParams.pLogCallback)
{
m_env.pLog->AddCallback(startupParams.pLogCallback);
}
const ICmdLineArg* logfile = m_pCmdLine->FindArg(eCLAT_Pre, "logfile"); //see if the user specified a log name, if so use it
if (logfile && strlen(logfile->GetValue()) > 0)
{
m_env.pLog->SetFileName(logfile->GetValue(), startupParams.autoBackupLogs);
}
else if (startupParams.sLogFileName) //otherwise see if the startup params has a log file name, if so use it
{
const AZStd::string sUniqueLogFileName = GetUniqueLogFileName(startupParams.sLogFileName);
m_env.pLog->SetFileName(sUniqueLogFileName.c_str(), startupParams.autoBackupLogs);
}
else//use the default log name
{
m_env.pLog->SetFileName(DEFAULT_LOG_FILENAME, startupParams.autoBackupLogs);
}
}
else
{
m_env.pLog = startupParams.pLog;
}
// The log backup system expects the version number to be the first line of the log
// so we log this immediately after setting the log filename
LogVersion();
bool devModeEnable = true;
#if defined(_RELEASE)
// disable devmode by default in release builds outside the editor
devModeEnable = m_bEditor;
#endif
// disable devmode in launcher if someone really wants to (even in non release builds)
if (!m_bEditor && m_pCmdLine->FindArg(eCLAT_Pre, "nodevmode"))
{
devModeEnable = false;
}
SetDevMode(devModeEnable);
//////////////////////////////////////////////////////////////////////////
// CREATE CONSOLE
//////////////////////////////////////////////////////////////////////////
if (!startupParams.bSkipConsole)
{
m_env.pConsole = new CXConsole;
if (startupParams.pPrintSync)
{
m_env.pConsole->AddOutputPrintSink(startupParams.pPrintSync);
}
}
//////////////////////////////////////////////////////////////////////////
if (m_pUserCallback)
{
m_pUserCallback->OnInit(this);
}
m_env.pLog->RegisterConsoleVariables();
GetIRemoteConsole()->RegisterConsoleVariables();
if (!startupParams.bSkipConsole)
{
// Register system console variables.
CreateSystemVars();
// Register Audio-related system CVars
CreateAudioVars();
// Register any AZ CVar commands created above with the AZ Console system.
AZ::ConsoleFunctorBase*& deferredHead = AZ::ConsoleFunctorBase::GetDeferredHead();
AZ::Interface<AZ::IConsole>::Get()->LinkDeferredFunctors(deferredHead);
// Callback
if (m_pUserCallback && m_env.pConsole)
{
m_pUserCallback->OnConsoleCreated(m_env.pConsole);
}
// Let listeners know its safe to register cvars
EBUS_EVENT(CrySystemEventBus, OnCrySystemCVarRegistry);
}
// Set this as soon as the system cvars got initialized.
static_cast<AZ::IO::Archive* const>(m_env.pCryPak)->SetLocalizationFolder(g_cvars.sys_localization_folder->GetString());
InlineInitializationProcessing("CSystem::Init Create console");
InitFileSystem_LoadEngineFolders(startupParams);
#if !defined(RELEASE) || defined(RELEASE_LOGGING)
// now that the system cfgs have been loaded, we can start the remote console
GetIRemoteConsole()->Update();
#endif
InlineInitializationProcessing("CSystem::Init Load Engine Folders");
//////////////////////////////////////////////////////////////////////////
//Load config files
//////////////////////////////////////////////////////////////////////////
// tools may not interact with @user@
if (!gEnv->IsInToolMode())
{
if (m_pCmdLine->FindArg(eCLAT_Pre, "ResetProfile") == 0)
{
LoadConfiguration("@user@/game.cfg", 0, false);
}
}
{
// We have to load this file again since first time we did it without devmode
LoadConfiguration(m_systemConfigName.c_str());
// Optional user defined overrides
LoadConfiguration("user.cfg");
#if defined(ENABLE_STATS_AGENT)
if (m_pCmdLine->FindArg(eCLAT_Pre, "useamblecfg"))
{
LoadConfiguration("amble.cfg");
}
#endif
}
//////////////////////////////////////////////////////////////////////////
if (g_cvars.sys_asserts == 0)
{
gEnv->bIgnoreAllAsserts = true;
}
if (g_cvars.sys_asserts == 2)
{
gEnv->bNoAssertDialog = true;
}
LogBuildInfo();
InlineInitializationProcessing("CSystem::Init LoadConfigurations");
#ifdef WIN32
if (g_cvars.sys_WER)
{
SetUnhandledExceptionFilter(CryEngineExceptionFilterWER);
}
#endif
//////////////////////////////////////////////////////////////////////////
// Localization
//////////////////////////////////////////////////////////////////////////
{
InitLocalization();
}
InlineInitializationProcessing("CSystem::Init InitLocalizations");
//////////////////////////////////////////////////////////////////////////
// Open basic pak files after intro movie playback started
//////////////////////////////////////////////////////////////////////////
OpenPlatformPaks();
//////////////////////////////////////////////////////////////////////////
// AUDIO
//////////////////////////////////////////////////////////////////////////
{
if (InitAudioSystem(startupParams))
{
// Pump the Log - Audio initialization happened on a non-main thread, there may be log messages queued up.
gEnv->pLog->Update();
}
else
{
// Failure to initialize audio system is no longer a fatal or an error. A warning is sufficient.
AZ_Warning(AZ_TRACE_SYSTEM_WINDOW, false, "<Audio>: Running without any AudioSystem!");
}
}
// Compiling the default system textures can be the lengthiest portion of
// editor initialization, so it is useful to inform users that they are waiting on
// the necessary default textures to compile.
if (m_pUserCallback)
{
m_pUserCallback->OnInitProgress("First time asset processing - may take a minute...");
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// System cursor
//////////////////////////////////////////////////////////////////////////
// - Dedicated server is in console mode by default (system cursor is always shown when console is)
// - System cursor is always visible by default in Editor (we never start directly in Game Mode)
// - System cursor has to be enabled manually by the Game if needed; the custom UiCursor will typically be used instead
if (!gEnv->IsDedicated() &&
!gEnv->IsEditor())
{
AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id,
&AzFramework::InputSystemCursorRequests::SetSystemCursorState,
AzFramework::SystemCursorState::ConstrainedAndHidden);
}
// CONSOLE
//////////////////////////////////////////////////////////////////////////
if (!InitConsole())
{
return false;
}
if (m_pUserCallback)
{
m_pUserCallback->OnInitProgress("Initializing additional systems...");
}
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Initializing additional systems");
InlineInitializationProcessing("CSystem::Init AIInit");
//////////////////////////////////////////////////////////////////////////
// LEVEL SYSTEM
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
if (usePrefabSystemForLevels)
{
m_pLevelSystem = new LegacyLevelSystem::SpawnableLevelSystem(this);
}
else
{
// [LYN-2376] Remove once legacy slice support is removed
m_pLevelSystem = new LegacyLevelSystem::CLevelSystem(this, ILevelSystem::GetLevelsDirectoryName());
}
InlineInitializationProcessing("CSystem::Init Level System");
if (m_env.pLyShine)
{
m_env.pLyShine->PostInit();
}
InlineInitializationProcessing("CSystem::Init InitLmbrAWS");
// Az to Cry console binding
AZ::Interface<AZ::IConsole>::Get()->VisitRegisteredFunctors([](AZ::ConsoleFunctorBase* functor) { AzConsoleToCryConsoleBinder::Visit(functor); });
AzConsoleToCryConsoleBinder::s_commandRegisteredHandler.Connect(AZ::Interface<AZ::IConsole>::Get()->GetConsoleCommandRegisteredEvent());
if (g_cvars.sys_float_exceptions > 0)
{
if (g_cvars.sys_float_exceptions == 3 && gEnv->IsEditor()) // Turn off float exceptions in editor if sys_float_exceptions = 3
{
g_cvars.sys_float_exceptions = 0;
}
if (g_cvars.sys_float_exceptions > 0)
{
AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "Enabled float exceptions(sys_float_exceptions %d). This makes the performance slower.", g_cvars.sys_float_exceptions);
}
}
EnableFloatExceptions(g_cvars.sys_float_exceptions);
}
InlineInitializationProcessing("CSystem::Init End");
#if defined(IS_PROSDK)
SDKEvaluation::InitSDKEvaluation(gEnv, &m_pUserCallback);
#endif
InlineInitializationProcessing("CSystem::Init End");
// Send out EBus event
EBUS_EVENT(CrySystemEventBus, OnCrySystemInitialized, *this, startupParams);
// Execute any deferred commands that uses the CVar commands that were just registered
AZ::Interface<AZ::IConsole>::Get()->ExecuteDeferredConsoleCommands();
// Verify that the Maestro Gem initialized the movie system correctly. This can be removed if and when Maestro is not a required Gem
if (gEnv->IsEditor() && !gEnv->pMovieSystem)
{
AZ_Assert(false, "Error initializing the Cinematic System. Please check that the Maestro Gem is enabled for this project.");
return false;
}
if (ISystemEventDispatcher* systemEventDispatcher = GetISystemEventDispatcher())
{
systemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_GAME_POST_INIT, 0, 0);
systemEventDispatcher->OnSystemEvent(ESYSTEM_EVENT_GAME_POST_INIT_DONE, 0, 0);
}
m_bInitializedSuccessfully = true;
return true;
}
static void LoadConfigurationCmd(IConsoleCmdArgs* pParams)
{
assert(pParams);
if (pParams->GetArgCount() != 2)
{
gEnv->pLog->LogError("LoadConfiguration failed, one parameter needed");
return;
}
GetISystem()->LoadConfiguration((AZStd::string("Config/") + pParams->GetArg(1)).c_str());
}
// --------------------------------------------------------------------------------------------------------------------------
static AZStd::string ConcatPath(const char* szPart1, const char* szPart2)
{
if (szPart1[0] == 0)
{
return szPart2;
}
AZStd::string ret;
ret.reserve(strlen(szPart1) + 1 + strlen(szPart2));
ret = szPart1;
ret += "/";
ret += szPart2;
return ret;
}
//////////////////////////////////////////////////////////////////////////
void CSystem::CreateSystemVars()
{
assert(gEnv);
assert(gEnv->pConsole);
#if AZ_LOADSCREENCOMPONENT_ENABLED
m_game_load_screen_uicanvas_path = REGISTER_STRING("game_load_screen_uicanvas_path", "", 0, "Game load screen UiCanvas path.");
m_level_load_screen_uicanvas_path = REGISTER_STRING("level_load_screen_uicanvas_path", "", 0, "Level load screen UiCanvas path.");
m_game_load_screen_sequence_to_auto_play = REGISTER_STRING("game_load_screen_sequence_to_auto_play", "", 0, "Game load screen UiCanvas animation sequence to play on load.");
m_level_load_screen_sequence_to_auto_play = REGISTER_STRING("level_load_screen_sequence_to_auto_play", "", 0, "Level load screen UiCanvas animation sequence to play on load.");
m_game_load_screen_sequence_fixed_fps = REGISTER_FLOAT("game_load_screen_sequence_fixed_fps", 60.0f, 0, "Fixed frame rate fed to updates of the game load screen sequence.");
m_level_load_screen_sequence_fixed_fps = REGISTER_FLOAT("level_load_screen_sequence_fixed_fps", 60.0f, 0, "Fixed frame rate fed to updates of the level load screen sequence.");
m_game_load_screen_max_fps = REGISTER_FLOAT("game_load_screen_max_fps", 30.0f, 0, "Max frame rate to update the game load screen sequence.");
m_level_load_screen_max_fps = REGISTER_FLOAT("level_load_screen_max_fps", 30.0f, 0, "Max frame rate to update the level load screen sequence.");
m_game_load_screen_minimum_time = REGISTER_FLOAT("game_load_screen_minimum_time", 0.0f, 0, "Minimum amount of time to show the game load screen. Important to prevent short loads from flashing the load screen. 0 means there is no limit.");
m_level_load_screen_minimum_time = REGISTER_FLOAT("level_load_screen_minimum_time", 0.0f, 0, "Minimum amount of time to show the level load screen. Important to prevent short loads from flashing the load screen. 0 means there is no limit.");
#endif // if AZ_LOADSCREENCOMPONENT_ENABLED
REGISTER_INT("cvDoVerboseWindowTitle", 0, VF_NULL, "");
// Register an AZ Console command to quit the engine.
// The command is available even in Release builds.
static AZ::ConsoleFunctor<void, false> s_functorQuit
(
"quit",
"Quit/Shutdown the engine",
AZ::ConsoleFunctorFlags::AllowClientSet | AZ::ConsoleFunctorFlags::DontReplicate,
AZ::TypeId::CreateNull(),
[]([[maybe_unused]] const AZ::ConsoleCommandContainer& params) { GetISystem()->Quit(); }
);
m_sys_load_files_to_memory = REGISTER_STRING("sys_load_files_to_memory", "shadercache.pak", 0,
"Specify comma separated list of filenames that need to be loaded to memory.\n"
"Partial names also work. Eg. \"shader\" will load:\n"
"shaders.pak, shadercache.pak, and shadercachestartup.pak");
#ifndef _RELEASE
REGISTER_STRING_CB("sys_version", "", VF_CHEAT, "Override system file/product version", SystemVersionChanged);
#endif // #ifndef _RELEASE
attachVariable("sys_PakSaveLevelResourceList", &g_cvars.archiveVars.nSaveLevelResourceList, "Save resource list when loading level");
attachVariable("sys_PakLogInvalidFileAccess", &g_cvars.archiveVars.nLogInvalidFileAccess, "Log synchronous file access when in game");
m_sysNoUpdate = REGISTER_INT("sys_noupdate", 0, VF_CHEAT,
"Toggles updating of system with sys_script_debugger.\n"
"Usage: sys_noupdate [0/1]\n"
"Default is 0 (system updates during debug).");
#if defined(_RELEASE) && defined(CONSOLE) && !defined(ENABLE_LW_PROFILERS)
enum
{
e_sysKeyboardDefault = 0
};
#else
enum
{
e_sysKeyboardDefault = 1
};
#endif
m_svDedicatedMaxRate = REGISTER_FLOAT("sv_DedicatedMaxRate", 30.0f, 0,
"Sets the maximum update rate when running as a dedicated server.\n"
"Usage: sv_DedicatedMaxRate [5..500]\n"
"Default is 30.");
REGISTER_FLOAT("sv_DedicatedCPUPercent", 0.0f, 0,
"Sets the target CPU usage when running as a dedicated server, or disable this feature if it's zero.\n"
"Usage: sv_DedicatedCPUPercent [0..100]\n"
"Default is 0 (disabled).");
REGISTER_FLOAT("sv_DedicatedCPUVariance", 10.0f, 0,
"Sets how much the CPU can vary from sv_DedicateCPU (up or down) without adjusting the framerate.\n"
"Usage: sv_DedicatedCPUVariance [5..50]\n"
"Default is 10.");
m_sys_firstlaunch = REGISTER_INT("sys_firstlaunch", 0, 0,
"Indicates that the game was run for the first time.");
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_12
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_17
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
# define SYS_STREAMING_CPU_DEFAULT_VALUE 1
# define SYS_STREAMING_CPU_WORKER_DEFAULT_VALUE 5
#endif
#define DEFAULT_USE_OPTICAL_DRIVE_THREAD (gEnv->IsDedicated() ? 0 : 1)
const char* localizeFolder = "Localization";
g_cvars.sys_localization_folder = REGISTER_STRING_CB("sys_localization_folder", localizeFolder, VF_NULL,
"Sets the folder where to look for localized data.\n"
"This cvar allows for backwards compatibility so localized data under the game folder can still be found.\n"
"Usage: sys_localization_folder <folder name>\n"
"Default: Localization\n",
CSystem::OnLocalizationFolderCVarChanged);
#if (defined(WIN32) || defined(WIN64)) && defined(_DEBUG)
REGISTER_CVAR2("sys_float_exceptions", &g_cvars.sys_float_exceptions, 2, 0, "Use or not use floating point exceptions.");
#else // Float exceptions by default disabled for console builds.
REGISTER_CVAR2("sys_float_exceptions", &g_cvars.sys_float_exceptions, 0, 0, "Use or not use floating point exceptions.");
#endif
REGISTER_CVAR2("sys_update_profile_time", &g_cvars.sys_update_profile_time, 1.0f, 0, "Time to keep updates timings history for.");
REGISTER_CVAR2("sys_no_crash_dialog", &g_cvars.sys_no_crash_dialog, m_bNoCrashDialog, VF_NULL, "Whether to disable the crash dialog window");
REGISTER_CVAR2("sys_no_error_report_window", &g_cvars.sys_no_error_report_window, m_bNoErrorReportWindow, VF_NULL, "Whether to disable the error report list");
#if defined(_RELEASE)
if (!gEnv->IsDedicated())
{
REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 1, 0, "Enables Windows Error Reporting");
}
#else
REGISTER_CVAR2("sys_WER", &g_cvars.sys_WER, 0, 0, "Enables Windows Error Reporting");
#endif
const int DEFAULT_DUMP_TYPE = 2;
REGISTER_CVAR2("sys_dump_type", &g_cvars.sys_dump_type, DEFAULT_DUMP_TYPE, VF_NULL,
"Specifies type of crash dump to create - see MINIDUMP_TYPE in dbghelp.h for full list of values\n"
"0: Do not create a minidump\n"
"1: Create a small minidump (stacktrace)\n"
"2: Create a medium minidump (+ some variables)\n"
"3: Create a full minidump (+ all memory)\n"
);
REGISTER_CVAR2("sys_dump_aux_threads", &g_cvars.sys_dump_aux_threads, 1, VF_NULL, "Dumps callstacks of other threads in case of a crash");
#if (defined(WIN32) || defined(WIN64)) && defined(_RELEASE)
const int DEFAULT_SYS_MAX_FPS = 0;
#else
const int DEFAULT_SYS_MAX_FPS = -1;
#endif
REGISTER_CVAR2("sys_MaxFPS", &g_cvars.sys_MaxFPS, DEFAULT_SYS_MAX_FPS, VF_NULL, "Limits the frame rate to specified number n (if n>0 and if vsync is disabled).\n"
" 0 = on PC if vsync is off auto throttles fps while in menu or game is paused (default)\n"
"-1 = off");
REGISTER_CVAR2("sys_maxTimeStepForMovieSystem", &g_cvars.sys_maxTimeStepForMovieSystem, 0.1f, VF_NULL, "Caps the time step for the movie system so that a cut-scene won't be jumped in the case of an extreme stall.");
REGISTER_CVAR2("sys_report_files_not_found_in_paks", &g_cvars.sys_report_files_not_found_in_paks, 0, VF_NULL, "Reports when files are searched for in paks and not found. 1 = log, 2 = warning, 3 = error");
REGISTER_COMMAND("sys_crashtest", CmdCrashTest, VF_CHEAT, "Make the game crash\n"
"0=off\n"
"1=null pointer exception\n"
"2=floating point exception\n"
"3=memory allocation exception\n"
"4=cry fatal error is called\n"
"5=memory allocation for small blocks\n"
"6=assert\n"
"7=debugbreak\n"
"8=10min sleep"
);
REGISTER_FLOAT("sys_scale3DMouseTranslation", 0.2f, 0, "Scales translation speed of supported 3DMouse devices.");
REGISTER_FLOAT("sys_Scale3DMouseYPR", 0.05f, 0, "Scales rotation speed of supported 3DMouse devices.");
REGISTER_INT("capture_frames", 0, 0, "Enables capturing of frames. 0=off, 1=on");
REGISTER_STRING("capture_folder", "CaptureOutput", 0, "Specifies sub folder to write captured frames.");
REGISTER_INT("capture_frame_once", 0, 0, "Makes capture single frame only");
REGISTER_STRING("capture_file_name", "", 0, "If set, specifies the path and name to use for the captured frame");
REGISTER_STRING("capture_file_prefix", "", 0, "If set, specifies the prefix to use for the captured frame instead of the default 'Frame'.");
m_gpu_particle_physics = REGISTER_INT("gpu_particle_physics", 0, VF_REQUIRE_APP_RESTART, "Enable GPU physics if available (0=off / 1=enabled).");
assert(m_gpu_particle_physics);
REGISTER_COMMAND("LoadConfig", &LoadConfigurationCmd, 0,
"Load .cfg file from disk (from the {Game}/Config directory)\n"
"e.g. LoadConfig lowspec.cfg\n"
"Usage: LoadConfig <filename>");
assert(m_env.pConsole);
m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F12", "Screenshot");
m_env.pConsole->CreateKeyBind("alt_keyboard_key_function_F11", "RecordClip");
/*
// experimental feature? - needs to be created very early
m_sys_filecache = REGISTER_INT("sys_FileCache",0,0,
"To speed up loading from non HD media\n"
"0=off / 1=enabled");
*/
REGISTER_CVAR2("sys_trackview", &g_cvars.sys_trackview, 1, 0, "Enables TrackView Update");
//Defines selected language.
REGISTER_STRING_CB("g_language", "", VF_NULL, "Defines which language pak is loaded", CSystem::OnLanguageCVarChanged);
// adding CVAR to toggle assert verbosity level
const int defaultAssertValue = 1;
REGISTER_CVAR2_CB("sys_asserts", &g_cvars.sys_asserts, defaultAssertValue, VF_CHEAT,
"0 = Suppress Asserts\n"
"1 = Log Asserts\n"
"2 = Show Assert Dialog\n"
"3 = Crashes the Application on Assert\n"
"Note: when set to '0 = Suppress Asserts', assert expressions are still evaluated. To turn asserts into a no-op, undefine AZ_ENABLE_TRACING and recompile.",
OnAssertLevelCvarChanged);
CSystem::SetAssertLevel(defaultAssertValue);
REGISTER_CVAR2("sys_error_debugbreak", &g_cvars.sys_error_debugbreak, 0, VF_CHEAT, "__debugbreak() if a VALIDATOR_ERROR_DBGBREAK message is hit");
REGISTER_STRING("dlc_directory", "", 0, "Holds the path to the directory where DLC should be installed to and read from");
#if defined(WIN32) || defined(WIN64)
REGISTER_INT("sys_screensaver_allowed", 0, VF_NULL, "Specifies if screen saver is allowed to start up while the game is running.");
#endif
// Since the UI Canvas Editor is incomplete, we have a variable to enable it.
// By default it is now enabled. Modify system.cfg or game.cfg to disable it
REGISTER_INT("sys_enableCanvasEditor", 1, VF_NULL, "Enables the UI Canvas Editor");
}
//////////////////////////////////////////////////////////////////////////
void CSystem::CreateAudioVars()
{
assert(gEnv);
assert(gEnv->pConsole);
m_sys_audio_disable = REGISTER_INT("sys_audio_disable", 0, VF_REQUIRE_APP_RESTART,
"Specifies whether to use the NULLAudioSystem in place of the regular AudioSystem\n"
"Usage: sys_audio_disable [0/1]\n"
"0: use regular AudioSystem.\n"
"1: use NullAudioSystem (disable all audio functionality).\n"
"Default: 0 (enable audio functionality)");
}
/////////////////////////////////////////////////////////////////////
void CSystem::AddCVarGroupDirectory(const AZStd::string& sPath)
{
CryLog("creating CVarGroups from directory '%s' ...", sPath.c_str());
INDENT_LOG_DURING_SCOPE();
AZ::IO::ArchiveFileIterator handle = gEnv->pCryPak->FindFirst(ConcatPath(sPath.c_str(), "*.cfg").c_str());
if (!handle)
{
return;
}
do
{
if ((handle.m_fileDesc.nAttrib & AZ::IO::FileDesc::Attribute::Subdirectory) == AZ::IO::FileDesc::Attribute::Subdirectory)
{
if (handle.m_filename != "." && handle.m_filename != "..")
{
AddCVarGroupDirectory(ConcatPath(sPath.c_str(), handle.m_filename.data()));
}
}
} while (handle = gEnv->pCryPak->FindNext(handle));
gEnv->pCryPak->FindClose(handle);
}
bool CSystem::RegisterErrorObserver(IErrorObserver* errorObserver)
{
return stl::push_back_unique(m_errorObservers, errorObserver);
}
bool CSystem::UnregisterErrorObserver(IErrorObserver* errorObserver)
{
return stl::find_and_erase(m_errorObservers, errorObserver);
}
void CSystem::OnAssert(const char* condition, const char* message, const char* fileName, unsigned int fileLineNumber)
{
if (g_cvars.sys_asserts == 0)
{
return;
}
std::vector<IErrorObserver*>::const_iterator end = m_errorObservers.end();
for (std::vector<IErrorObserver*>::const_iterator it = m_errorObservers.begin(); it != end; ++it)
{
(*it)->OnAssert(condition, message, fileName, fileLineNumber);
}
if (g_cvars.sys_asserts > 1)
{
CryFatalError("<assert> %s\r\n%s\r\n%s (%d)\r\n", condition, message, fileName, fileLineNumber);
}
}
void CSystem::OnFatalError(const char* message)
{
std::vector<IErrorObserver*>::const_iterator end = m_errorObservers.end();
for (std::vector<IErrorObserver*>::const_iterator it = m_errorObservers.begin(); it != end; ++it)
{
(*it)->OnFatalError(message);
}
}
bool CSystem::IsAssertDialogVisible() const
{
return m_bIsAsserting;
}
void CSystem::SetAssertVisible(bool bAssertVisble)
{
m_bIsAsserting = bAssertVisble;
}