Integrating latest from github/staging
Integrating up through commit 5e1bdae
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
|
||||
#include <AzCore/Debug/LocalFileEventLogger.h>
|
||||
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
|
||||
#include <AzCore/Memory/OverrunDetectionAllocator.h>
|
||||
@@ -99,6 +101,18 @@ namespace AZ
|
||||
return environment ? environment->Get() : nullptr;
|
||||
}
|
||||
|
||||
ComponentApplication::EventLoggerDeleter::EventLoggerDeleter() noexcept= default;
|
||||
ComponentApplication::EventLoggerDeleter::EventLoggerDeleter(bool skipDelete) noexcept
|
||||
: m_skipDelete{skipDelete}
|
||||
{}
|
||||
void ComponentApplication::EventLoggerDeleter::operator()(AZ::Debug::LocalFileEventLogger* ptr)
|
||||
{
|
||||
if (!m_skipDelete)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// ComponentApplication::Descriptor
|
||||
// [5/30/2012]
|
||||
@@ -159,6 +173,80 @@ namespace AZ
|
||||
return true;
|
||||
};
|
||||
|
||||
//! SettingsRegistry notifier handler which updates relevant registry settings based
|
||||
//! on an update to '/Amazon/AzCore/Bootstrap/project_path' key.
|
||||
struct UpdateProjectSettingsEventHandler
|
||||
{
|
||||
UpdateProjectSettingsEventHandler(AZ::SettingsRegistryInterface& registry)
|
||||
: m_registry{ registry }
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(AZStd::string_view path, AZ::SettingsRegistryInterface::Type)
|
||||
{
|
||||
UpdateProjectSpecializationInRegistry(path);
|
||||
}
|
||||
|
||||
//! Add the project name as a specialization underneath the /Amazon/AzCore/Settings/Specializations path
|
||||
//! and remove the current project name specialization if one exists.
|
||||
void UpdateProjectSpecializationInRegistry(AZStd::string_view path)
|
||||
{
|
||||
auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
|
||||
+ "/project_path";
|
||||
if (path == projectPathKey)
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString newProjectPath;
|
||||
if (m_registry.Get(newProjectPath, path) && !newProjectPath.empty())
|
||||
{
|
||||
// Make the path absolute by appending to app root, in case project path is relative.
|
||||
// If the project path is already absolute it will remain the same.
|
||||
// If we turn it from a relative path to an absolute path, write-back the absolute path to the registry.
|
||||
AZ::IO::FixedMaxPath projectPath = AZ::SettingsRegistryMergeUtils::FindEngineRoot(m_registry) / newProjectPath;
|
||||
if (projectPath.Compare(newProjectPath.c_str()))
|
||||
{
|
||||
m_registry.Set(path, projectPath.Native());
|
||||
}
|
||||
|
||||
// Merge the project.json file into settings registry under ProjectSettingsRootKey path.
|
||||
AZ::IO::FixedMaxPath projectMetadataFile{ projectPath };
|
||||
projectMetadataFile /= "project.json";
|
||||
m_registry.MergeSettingsFile(projectMetadataFile.Native(),
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey);
|
||||
|
||||
// Get the 'project_name' value from what was in the 'project.json' file...
|
||||
auto projectNameKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
|
||||
+ "/project_name";
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectSpecialization;
|
||||
if (m_registry.Get(projectSpecialization, projectNameKey))
|
||||
{
|
||||
auto specializationKey = AZ::SettingsRegistryInterface::FixedValueString::format(
|
||||
"%s/%s", AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, projectSpecialization.c_str());
|
||||
if (m_currentSpecialization != specializationKey)
|
||||
{
|
||||
m_registry.Set(specializationKey, true);
|
||||
if (!m_currentSpecialization.empty())
|
||||
{
|
||||
// Remove the previous Project Name from the specialization path if it was set.
|
||||
m_registry.Remove(m_currentSpecialization);
|
||||
}
|
||||
m_currentSpecialization = specializationKey;
|
||||
|
||||
// Update all the runtime file paths based on the new "project_path" value.
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AZ::SettingsRegistryInterface::FixedValueString m_currentSpecialization;
|
||||
AZ::SettingsRegistryInterface& m_registry;
|
||||
};
|
||||
|
||||
void ComponentApplication::Descriptor::AllocatorRemapping::Reflect(ReflectContext* context, ComponentApplication* app)
|
||||
{
|
||||
(void)app;
|
||||
@@ -276,6 +364,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
ComponentApplication::ComponentApplication(int argC, char** argV)
|
||||
: m_eventLogger{}
|
||||
{
|
||||
if (argV)
|
||||
{
|
||||
@@ -284,11 +373,23 @@ namespace AZ
|
||||
}
|
||||
else
|
||||
{
|
||||
azstrcpy(m_commandLineBuffer, AZ_ARRAY_SIZE(m_commandLineBuffer), "no_argv_supplied");
|
||||
azstrcpy(m_commandLineBuffer, AZ_ARRAY_SIZE(m_commandLineBuffer), "no_argv_supplied");
|
||||
// use a "valid" value here. This is because Qt and potentially other third party libraries require
|
||||
// that ArgC be 'at least 1' and that (*argV)[0] be a valid pointer to a real null terminated string.
|
||||
m_argC = 1;
|
||||
m_argV = &m_commandLineBufferAddress;
|
||||
m_argC = 1;
|
||||
m_argV = &m_commandLineBufferAddress;
|
||||
}
|
||||
|
||||
// Create the Event logger if it doesn't exist, otherwise reuse the one registered
|
||||
// with the AZ::Interface
|
||||
if (AZ::Interface<AZ::Debug::IEventLogger>::Get() == nullptr)
|
||||
{
|
||||
m_eventLogger.reset(new AZ::Debug::LocalFileEventLogger);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_eventLogger = EventLoggerPtr(static_cast<AZ::Debug::LocalFileEventLogger*>(AZ::Interface<AZ::Debug::IEventLogger>::Get()),
|
||||
EventLoggerDeleter{ true });
|
||||
}
|
||||
|
||||
// Initializes the OSAllocator and SystemAllocator as soon as possible
|
||||
@@ -297,6 +398,7 @@ namespace AZ
|
||||
|
||||
// Now that the Allocators are initialized, the Command Line parameters can be parsed
|
||||
m_commandLine.Parse(m_argC, m_argV);
|
||||
ParseCommandLine(m_commandLine);
|
||||
|
||||
// Create the settings registry and register it with the AZ interface system
|
||||
// This is done after the AppRoot has been calculated so that the Bootstrap.cfg
|
||||
@@ -304,62 +406,34 @@ namespace AZ
|
||||
m_settingsRegistry = AZStd::make_unique<SettingsRegistryImpl>();
|
||||
|
||||
// Register the Settings Registry with the AZ Interface if there isn't one registered already
|
||||
if (AZ::SettingsRegistry::Get() == nullptr)
|
||||
if (SettingsRegistry::Get() == nullptr)
|
||||
{
|
||||
SettingsRegistry::Register(m_settingsRegistry.get());
|
||||
}
|
||||
|
||||
// Add the Command Line arguments into the SettingsRegistry
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_StoreCommandLine(*m_settingsRegistry, m_commandLine);
|
||||
SettingsRegistryMergeUtils::StoreCommandLineToRegistry(*m_settingsRegistry, m_commandLine);
|
||||
|
||||
// Merge Command Line arguments
|
||||
constexpr bool executeRegDumpCommands = false;
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
|
||||
|
||||
// Query for the Executable Path using OS specific functions
|
||||
CalculateExecutablePath();
|
||||
|
||||
// Determine the path to the engine
|
||||
CalculateEngineRoot();
|
||||
|
||||
// If the current platform returns an engaged optional from Utils::GetDefaultAppRootPath(), that is used
|
||||
// for the application root other the application root is found by scanning upwards from the Executable Directory
|
||||
// for a bootstrap.cfg file
|
||||
CalculateAppRoot(nullptr);
|
||||
// for the application root.
|
||||
CalculateAppRoot();
|
||||
|
||||
// Add a notifier to update the /Amazon/AzCore/Settings/Specializations
|
||||
// when the sys_game_folder property changes within the SettingsRegistry
|
||||
|
||||
// currentGameName is bound by value in order to allow the lambda to have a member variable that
|
||||
// can track the current game specialization before it changes
|
||||
AZ::SettingsRegistryInterface::FixedValueString currentGameSpecialization;
|
||||
auto GameProjectChanged = [currentGameSpecialization](AZStd::string_view path, AZ::SettingsRegistryInterface::Type type) mutable
|
||||
{
|
||||
constexpr auto projectKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
|
||||
+ "/sys_game_folder";
|
||||
if (projectKey == path && type == AZ::SettingsRegistryInterface::Type::String)
|
||||
{
|
||||
auto registry = AZ::SettingsRegistry::Get();
|
||||
AZ::SettingsRegistryInterface::FixedValueString newGameName;
|
||||
if (registry && registry->Get(newGameName, path) && !newGameName.empty())
|
||||
{
|
||||
auto specializationKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
|
||||
AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, newGameName.c_str());
|
||||
|
||||
if (currentGameSpecialization != specializationKey)
|
||||
{
|
||||
registry->Set(specializationKey, true);
|
||||
if (!currentGameSpecialization.empty())
|
||||
{
|
||||
// Remove the previous Game Name from the specialization path if it was set
|
||||
registry->Remove(currentGameSpecialization);
|
||||
}
|
||||
// Update the currentGameSpecialization
|
||||
currentGameSpecialization = specializationKey;
|
||||
|
||||
// Update all the runtime filepaths based on the new "sys_game_folder" value
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
m_gameProjectChangedHandler = m_settingsRegistry->RegisterNotifier(AZStd::move(GameProjectChanged));
|
||||
// when the 'project_path' property changes within the SettingsRegistry
|
||||
m_projectChangedHandler = m_settingsRegistry->RegisterNotifier(UpdateProjectSettingsEventHandler{ *m_settingsRegistry });
|
||||
|
||||
// Merge the bootstrap.cfg file into the Settings Registry as soon as the OSAllocator has been created.
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(*m_settingsRegistry);
|
||||
constexpr bool executeRegDumpCommands = false;
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry);
|
||||
|
||||
@@ -391,11 +465,11 @@ namespace AZ
|
||||
Destroy();
|
||||
}
|
||||
|
||||
// The m_gameProjectChangedHandler stores an AZStd::function internally
|
||||
// The m_projectChangedHandler stores an AZStd::function internally
|
||||
// which allocates using the AZ SystemAllocator
|
||||
// m_gameProjectChangedHandler is being default value initialized
|
||||
// m_projectChangedHandler is being default value initialized
|
||||
// to clear out the AZStd::function
|
||||
m_gameProjectChangedHandler = {};
|
||||
m_projectChangedHandler = {};
|
||||
|
||||
// Delete the AZ::IConsole if it was created by this application instance
|
||||
if (m_ownsConsole)
|
||||
@@ -412,6 +486,10 @@ namespace AZ
|
||||
}
|
||||
m_settingsRegistry.reset();
|
||||
|
||||
// Set AZ::CommandLine to an empty object to clear out allocated memory before the allocators
|
||||
// are destroyed
|
||||
m_commandLine = {};
|
||||
|
||||
DestroyAllocator();
|
||||
}
|
||||
|
||||
@@ -421,17 +499,6 @@ namespace AZ
|
||||
AZ_Assert(!m_isStarted, "Component application already started!");
|
||||
|
||||
m_startupParameters = startupParameters;
|
||||
// Invokes CalculateAppRoot() again this time with the appRootOverride startup parameter
|
||||
// supplied in order to allow overriding the AppRoot calculated in the constructor
|
||||
if (m_startupParameters.m_appRootOverride)
|
||||
{
|
||||
CalculateAppRoot(m_startupParameters.m_appRootOverride);
|
||||
// Re-check for the bootstrap.cfg file again using the appRoot override and update the file paths
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(*m_settingsRegistry);
|
||||
constexpr bool executeRegDumpCommands = false;
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry);
|
||||
}
|
||||
|
||||
m_descriptor = descriptor;
|
||||
|
||||
@@ -461,20 +528,14 @@ namespace AZ
|
||||
void ComponentApplication::CreateCommon()
|
||||
{
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString registryValue;
|
||||
m_settingsRegistry->Get(registryValue, AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage);
|
||||
AZ::IO::FixedMaxPath outputPath{ registryValue };
|
||||
AZ::IO::FixedMaxPath outputPath;
|
||||
m_settingsRegistry->Get(outputPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage);
|
||||
outputPath /= "eventlogger";
|
||||
|
||||
registryValue.clear();
|
||||
|
||||
AZ::IO::FixedMaxPathString baseFileName{ "EventLog" }; // default name
|
||||
if (m_settingsRegistry->Get(registryValue, AZ::SettingsRegistryMergeUtils::BuildTargetNameKey))
|
||||
{
|
||||
baseFileName = registryValue;
|
||||
}
|
||||
m_settingsRegistry->Get(baseFileName, AZ::SettingsRegistryMergeUtils::BuildTargetNameKey);
|
||||
|
||||
m_eventLogger.Start(outputPath.c_str(), baseFileName.c_str());
|
||||
m_eventLogger->Start(outputPath.Native(), baseFileName);
|
||||
}
|
||||
|
||||
CreateDrillers();
|
||||
@@ -515,7 +576,9 @@ namespace AZ
|
||||
LoadModules();
|
||||
|
||||
// Execute user.cfg after modules have been loaded but before processing any command-line overrides
|
||||
m_console->ExecuteConfigFile("@root@/user.cfg");
|
||||
AZ::IO::FixedMaxPath platformCachePath;
|
||||
m_settingsRegistry->Get(platformCachePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder);
|
||||
m_console->ExecuteConfigFile((platformCachePath / "user.cfg").Native());
|
||||
|
||||
// Parse the command line parameters for console commands after modules have loaded
|
||||
m_console->ExecuteCommandLine(m_commandLine);
|
||||
@@ -601,7 +664,7 @@ namespace AZ
|
||||
m_drillerManager = nullptr;
|
||||
}
|
||||
|
||||
m_eventLogger.Stop();
|
||||
m_eventLogger->Stop();
|
||||
|
||||
// Clear the descriptor to deallocate all strings (owned by ModuleDescriptor)
|
||||
m_descriptor = Descriptor();
|
||||
@@ -775,6 +838,46 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentApplication::ParseCommandLine(const AZ::CommandLine& commandLine)
|
||||
{
|
||||
struct OptionKeyToRegsetKey
|
||||
{
|
||||
AZStd::string_view m_optionKey;
|
||||
AZStd::string m_regsetKey;
|
||||
};
|
||||
|
||||
// Provide overrides for the engine root, the project root and the project cache root
|
||||
AZStd::array commandOptions = {
|
||||
OptionKeyToRegsetKey{ "engine-path", AZStd::string::format("%s/engine_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) },
|
||||
OptionKeyToRegsetKey{ "project-path", AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) },
|
||||
OptionKeyToRegsetKey{ "project-cache-path", AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) }
|
||||
};
|
||||
|
||||
AZStd::fixed_vector<AZStd::string, commandOptions.size()> overrideArgs;
|
||||
|
||||
for (auto&& [optionKey, regsetKey] : commandOptions)
|
||||
{
|
||||
if (size_t optionCount = commandLine.GetNumSwitchValues(optionKey); optionCount > 0)
|
||||
{
|
||||
// Use the last supplied command option value to override previous values
|
||||
auto overrideArg = AZStd::string::format(R"(--regset="%s=%s")", regsetKey.c_str(),
|
||||
commandLine.GetSwitchValue(optionKey, optionCount - 1).c_str());
|
||||
overrideArgs.emplace_back(AZStd::move(overrideArg));
|
||||
}
|
||||
}
|
||||
|
||||
if (!overrideArgs.empty())
|
||||
{
|
||||
// Dump the input command line, add the additional option overrides
|
||||
// and Parse the new command line into the Component Application command line
|
||||
AZ::CommandLine::ParamContainer commandLineArgs;
|
||||
commandLine.Dump(commandLineArgs);
|
||||
commandLineArgs.insert(commandLineArgs.end(), AZStd::make_move_iterator(overrideArgs.begin()),
|
||||
AZStd::make_move_iterator(overrideArgs.end()));
|
||||
m_commandLine.Parse(commandLineArgs);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentApplication::MergeSettingsToRegistry(SettingsRegistryInterface& registry)
|
||||
{
|
||||
SettingsRegistryInterface::Specializations specializations;
|
||||
@@ -788,14 +891,14 @@ namespace AZ
|
||||
// In development builds apply the developer registry and the command line to allow early overrides. This will
|
||||
// allow developers to override things like default paths or Asset Processor connection settings. Any additional
|
||||
// values will be replaced by later loads, so this step will happen again at the end of loading.
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_DevRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
|
||||
#endif
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_DevRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_UserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
|
||||
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true);
|
||||
#endif
|
||||
}
|
||||
@@ -1013,7 +1116,7 @@ namespace AZ
|
||||
struct GemModuleLoadData
|
||||
{
|
||||
AZ::OSString m_gemName;
|
||||
AZ::OSString m_dynamicLibraryPath;
|
||||
AZStd::vector<AZ::OSString> m_dynamicLibraryPaths;
|
||||
bool m_autoLoad{ true };
|
||||
};
|
||||
|
||||
@@ -1069,19 +1172,18 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override
|
||||
void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override
|
||||
{
|
||||
if (valueName == "Module" && !value.empty())
|
||||
// Remove last path segment and check if the key corresponds to the Modules array
|
||||
AZStd::optional<AZStd::string_view> moduleIndex = AZ::StringFunc::TokenizeLast(path, "/");
|
||||
if (path.ends_with("/Modules"))
|
||||
{
|
||||
// Strip off the Module entry from the path
|
||||
auto moduleKey = AZ::StringFunc::TokenizeLast(path, "/");
|
||||
if (!moduleKey)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Remove the "Modules" path segment to be at the GemName key
|
||||
AZ::StringFunc::TokenizeLast(path, "/");
|
||||
if (auto moduleLoadData = FindGemModuleEntry(path); moduleLoadData != nullptr)
|
||||
{
|
||||
moduleLoadData->m_dynamicLibraryPath = value;
|
||||
// Just use Json Serialization to load all the array elements
|
||||
moduleLoadData->m_dynamicLibraryPaths.emplace_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1111,30 +1213,41 @@ namespace AZ
|
||||
}
|
||||
};
|
||||
|
||||
constexpr size_t RegistryKeySize = 64;
|
||||
auto gemModuleKey = AZStd::fixed_string<RegistryKeySize>::format("%s/Gems", AZ::SettingsRegistryMergeUtils::OrganizationRootKey);
|
||||
auto gemModuleKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/Gems", AZ::SettingsRegistryMergeUtils::OrganizationRootKey);
|
||||
ModuleDescriptorList gemModules;
|
||||
{
|
||||
GemModuleVisitor moduleVisitor;
|
||||
m_settingsRegistry->Visit(moduleVisitor, gemModuleKey);
|
||||
m_settingsRegistry->Visit(moduleVisitor, gemModuleKey);
|
||||
for (GemModuleLoadData& moduleLoadData : moduleVisitor.m_modulesLoadData)
|
||||
{
|
||||
// Add all auto loadable non-asset gems to the list of gem modules to load
|
||||
if (moduleLoadData.m_autoLoad && !moduleLoadData.m_dynamicLibraryPath.empty())
|
||||
if (!moduleLoadData.m_autoLoad)
|
||||
{
|
||||
gemModules.emplace_back(DynamicModuleDescriptor{ AZStd::move(moduleLoadData.m_dynamicLibraryPath) });
|
||||
break;
|
||||
}
|
||||
for (AZ::OSString& dynamicLibraryPath : moduleLoadData.m_dynamicLibraryPaths)
|
||||
{
|
||||
auto CompareDynamicModuleDescriptor = [&dynamicLibraryPath](const DynamicModuleDescriptor& entry)
|
||||
{
|
||||
return entry.m_dynamicLibraryPath.contains(dynamicLibraryPath);
|
||||
};
|
||||
if (auto moduleIter = AZStd::find_if(gemModules.begin(), gemModules.end(), CompareDynamicModuleDescriptor);
|
||||
moduleIter == gemModules.end())
|
||||
{
|
||||
gemModules.emplace_back(DynamicModuleDescriptor{ AZStd::move(dynamicLibraryPath) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The settings registry in the settings registry are prioritized to load before the modules in the ComponetnApplication descriptor
|
||||
// The modules in the settings registry are prioritized to load before the modules in the ComponentApplication descriptor
|
||||
// in the order in which they were found
|
||||
for (auto&& moduleDescriptor : m_descriptor.m_modules)
|
||||
{
|
||||
// Append new dynamic library modules to the descriptor array
|
||||
auto CompareDynamicModuleDescriptor = [&moduleDescriptor](const DynamicModuleDescriptor& entry)
|
||||
{
|
||||
return entry.m_dynamicLibraryPath.find(moduleDescriptor.m_dynamicLibraryPath) != AZStd::string_view::npos;
|
||||
return entry.m_dynamicLibraryPath.contains(moduleDescriptor.m_dynamicLibraryPath);
|
||||
};
|
||||
if (auto foundModuleIter = AZStd::find_if(gemModules.begin(), gemModules.end(), CompareDynamicModuleDescriptor);
|
||||
foundModuleIter == gemModules.end())
|
||||
@@ -1260,17 +1373,8 @@ namespace AZ
|
||||
m_exeDirectory.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
}
|
||||
|
||||
void ComponentApplication::CalculateAppRoot(const char* appRootOverride)
|
||||
void ComponentApplication::CalculateAppRoot()
|
||||
{
|
||||
if (appRootOverride)
|
||||
{
|
||||
m_appRoot = appRootOverride;
|
||||
if (!m_appRoot.empty() && !m_appRoot.ends_with(AZ_CORRECT_FILESYSTEM_SEPARATOR))
|
||||
{
|
||||
m_appRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (AZStd::optional<AZ::StringFunc::Path::FixedString> appRootPath = Utils::GetDefaultAppRootPath(); appRootPath)
|
||||
{
|
||||
m_appRoot = AZStd::move(*appRootPath);
|
||||
@@ -1279,26 +1383,14 @@ namespace AZ
|
||||
m_appRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_appRoot = AZ::SettingsRegistryMergeUtils::GetAppRoot(m_settingsRegistry.get()).Native();
|
||||
m_appRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// CheckEngineMarkerFile
|
||||
//=========================================================================
|
||||
bool ComponentApplication::CheckPathForEngineMarker(const char* fullPath) const
|
||||
void ComponentApplication::CalculateEngineRoot()
|
||||
{
|
||||
static const char* engineMarkerFileName = "engine.json";
|
||||
char engineMarkerFullPathToCheck[AZ_MAX_PATH_LEN] = "";
|
||||
|
||||
azstrcpy(engineMarkerFullPathToCheck, AZ_ARRAY_SIZE(engineMarkerFullPathToCheck), fullPath);
|
||||
azstrcat(engineMarkerFullPathToCheck, AZ_ARRAY_SIZE(engineMarkerFullPathToCheck), "/");
|
||||
azstrcat(engineMarkerFullPathToCheck, AZ_ARRAY_SIZE(engineMarkerFullPathToCheck), engineMarkerFileName);
|
||||
|
||||
return AZ::IO::SystemFile::Exists(engineMarkerFullPathToCheck);
|
||||
if (m_engineRoot = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*m_settingsRegistry).Native(); !m_engineRoot.empty())
|
||||
{
|
||||
m_engineRoot.push_back(AZ_CORRECT_FILESYSTEM_SEPARATOR);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentApplication::ResolveModulePath([[maybe_unused]] AZ::OSString& modulePath)
|
||||
|
||||
@@ -9,15 +9,13 @@
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#ifndef AZCORE_COMPONENT_APPLICATION_H
|
||||
#define AZCORE_COMPONENT_APPLICATION_H
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Debug/ProfileModuleInit.h>
|
||||
#include <AzCore/Debug/LocalFileEventLogger.h>
|
||||
#include <AzCore/Memory/AllocationRecords.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
@@ -40,12 +38,15 @@ namespace AZ
|
||||
class IConsole;
|
||||
class Module;
|
||||
class ModuleManager;
|
||||
}
|
||||
namespace AZ::Debug
|
||||
{
|
||||
class DrillerManager;
|
||||
class LocalFileEventLogger;
|
||||
}
|
||||
|
||||
namespace Debug
|
||||
{
|
||||
class DrillerManager;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectionEnvironment
|
||||
{
|
||||
public:
|
||||
@@ -167,15 +168,6 @@ namespace AZ
|
||||
//! \note Dynamic AZ::Modules are specified in the ComponentApplication::Descriptor.
|
||||
CreateStaticModulesCallback m_createStaticModulesCallback = nullptr;
|
||||
|
||||
//! If set, this is used as the app root folder instead of it being calculated.
|
||||
const char* m_appRootOverride = nullptr;
|
||||
|
||||
//! The path to root of the asset cache folder. For instance: ./cache/<project>/pc
|
||||
const char* m_cacheRootPath = nullptr;
|
||||
|
||||
//! The path to the project in the asset cache folder. For instance: ./cache/<project>/pc/<project>
|
||||
const char* m_cacheProjectPath = nullptr;
|
||||
|
||||
//! Specifies which system components to create & activate. If no tags specified, all system components are used. Specify as comma separated list.
|
||||
const char* m_systemComponentTags = nullptr;
|
||||
|
||||
@@ -226,6 +218,8 @@ namespace AZ
|
||||
/// Returns the working root folder that has been registered with the app, if there is one.
|
||||
/// It's expected that derived applications will implement an application root.
|
||||
const char* GetAppRoot() const override { return m_appRoot.c_str(); }
|
||||
/// Returns the path to the engine.
|
||||
const char* GetEngineRoot() const override { return m_engineRoot.c_str(); }
|
||||
/// Returns the path to the folder the executable is in.
|
||||
const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); }
|
||||
|
||||
@@ -331,6 +325,9 @@ namespace AZ
|
||||
/// Create the drillers
|
||||
void CreateDrillers();
|
||||
|
||||
/// Parse ComponentApplication specific command line arguments
|
||||
void ParseCommandLine(const AZ::CommandLine& commandLine);
|
||||
|
||||
virtual void MergeSettingsToRegistry(SettingsRegistryInterface& registry);
|
||||
|
||||
//! Sets the specializations that will be used when loading the Settings Registry. Extend this in derived
|
||||
@@ -363,17 +360,11 @@ namespace AZ
|
||||
/// Calculates the directory the application executable comes from.
|
||||
void CalculateExecutablePath();
|
||||
|
||||
/// Calculates the directory where the bootstrap.cfg file resides.
|
||||
void CalculateAppRoot(const char* appRootOverride = {});
|
||||
/// Calculates the root directory of the engine.
|
||||
void CalculateEngineRoot();
|
||||
|
||||
/**
|
||||
* Check/verify a given path for the engine marker (file) so that we can identify that
|
||||
* a given path is the engine root. This is only valid for target platforms that are built
|
||||
* for the host platform and not deployable (ie windows, mac).
|
||||
* @param fullPath The full path to look for the engine marker
|
||||
* @return true if the input path contains the engine marker file, false if not
|
||||
*/
|
||||
virtual bool CheckPathForEngineMarker(const char* fullPath) const;
|
||||
/// Calculates the directory where the bootstrap.cfg file resides.
|
||||
void CalculateAppRoot();
|
||||
|
||||
template<typename Iterator>
|
||||
static void NormalizePath(Iterator begin, Iterator end, bool doLowercase = true)
|
||||
@@ -398,10 +389,11 @@ namespace AZ
|
||||
void* m_fixedMemoryBlock{ nullptr }; //!< Pointer to the memory block allocator, so we can free it OnDestroy.
|
||||
IAllocatorAllocate* m_osAllocator{ nullptr };
|
||||
EntitySetType m_entities;
|
||||
AZ::StringFunc::Path::FixedString m_exeDirectory;
|
||||
AZ::StringFunc::Path::FixedString m_appRoot;
|
||||
AZ::IO::FixedMaxPathString m_exeDirectory;
|
||||
AZ::IO::FixedMaxPathString m_engineRoot;
|
||||
AZ::IO::FixedMaxPathString m_appRoot;
|
||||
|
||||
AZ::SettingsRegistryInterface::NotifyEventHandler m_gameProjectChangedHandler;
|
||||
AZ::SettingsRegistryInterface::NotifyEventHandler m_projectChangedHandler;
|
||||
|
||||
// ConsoleFunctorHandle is responsible for unregistering the Settings Registry Console
|
||||
// from the m_console member when it goes out of scope
|
||||
@@ -427,9 +419,15 @@ namespace AZ
|
||||
// Created early to allow events to be logged before anything else. These will be kept in memory until
|
||||
// a file is associated with the logger. The internal buffer is limited to 64kb and once full unexpected
|
||||
// behavior may happen. The LocalFileEventLogger will register itself automatically with AZ::Interface<IEventLogger>.
|
||||
AZ::Debug::LocalFileEventLogger m_eventLogger;
|
||||
|
||||
struct EventLoggerDeleter
|
||||
{
|
||||
EventLoggerDeleter() noexcept;
|
||||
EventLoggerDeleter(bool skipDelete) noexcept;
|
||||
void operator()(AZ::Debug::LocalFileEventLogger* ptr);
|
||||
bool m_skipDelete{};
|
||||
};
|
||||
using EventLoggerPtr = AZStd::unique_ptr<AZ::Debug::LocalFileEventLogger, EventLoggerDeleter>;
|
||||
EventLoggerPtr m_eventLogger;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AZCORE_COMPONENT_APPLICATION_H
|
||||
#pragma once
|
||||
|
||||
@@ -183,6 +183,11 @@ namespace AZ
|
||||
* @return A pointer to the name of the app's root folder, if a root folder was registered.
|
||||
*/
|
||||
virtual const char* GetAppRoot() const = 0;
|
||||
/**
|
||||
* Gets the path of the working engine folder that the app is a part of.
|
||||
* @return A pointer to the engine path.
|
||||
*/
|
||||
virtual const char* GetEngineRoot() const = 0;
|
||||
/**
|
||||
* Gets the path to the directory that contains the application's executable.
|
||||
* @return A pointer to the name of the path that contains the application's executable.
|
||||
|
||||
@@ -161,9 +161,11 @@ namespace AZ
|
||||
|
||||
void Console::ExecuteCommandLine(const AZ::CommandLine& commandLine)
|
||||
{
|
||||
for (const auto& [switchKey, switchValues] : commandLine.GetSwitchList())
|
||||
for (auto&& commandArgument : commandLine)
|
||||
{
|
||||
ConsoleCommandContainer commandArgs(switchValues.begin(), switchValues.end());
|
||||
const auto& switchKey = commandArgument.m_option;
|
||||
const auto& switchValue = commandArgument.m_value;
|
||||
ConsoleCommandContainer commandArgs{ switchValue };
|
||||
PerformCommand(switchKey, commandArgs, ConsoleSilentMode::NotSilent, ConsoleInvokedFrom::AzConsole, ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,25 +67,7 @@ namespace AZ
|
||||
return a != OpenMode::Invalid;
|
||||
}
|
||||
|
||||
inline OpenMode operator | (OpenMode a, OpenMode b)
|
||||
{
|
||||
return static_cast<OpenMode>(static_cast<AZ::u32>(a) | static_cast<AZ::u32>(b));
|
||||
}
|
||||
|
||||
inline OpenMode operator & (OpenMode a, OpenMode b)
|
||||
{
|
||||
return static_cast<OpenMode>(static_cast<AZ::u32>(a) & static_cast<AZ::u32>(b));
|
||||
}
|
||||
|
||||
inline OpenMode& operator |= (OpenMode& a, OpenMode b)
|
||||
{
|
||||
return a = a | b;
|
||||
}
|
||||
|
||||
inline OpenMode& operator &= (OpenMode& a, OpenMode b)
|
||||
{
|
||||
return a = a & b;
|
||||
}
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(OpenMode)
|
||||
|
||||
OpenMode GetOpenModeFromStringMode(const char* mode);
|
||||
|
||||
@@ -250,12 +232,14 @@ namespace AZ
|
||||
virtual bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const = 0;
|
||||
AZStd::optional<AZ::IO::FixedMaxPath> ConvertToAlias(const AZ::IO::PathView& path) const;
|
||||
|
||||
/// ResolvePath - Replaces any aliases in path with their values and stores the result in resolvedPath,
|
||||
/// also ensures that the path is absolute
|
||||
/// returns true if path was resolved, false otherwise
|
||||
/// note that all of the above file-finding and opening functions automatically resolve the path before operating
|
||||
/// so you should not need to call this except in very exceptional circumstances where you absolutely need to
|
||||
/// hit a physical file and don't want to use SystemFile
|
||||
//! ResolvePath - Replaces any aliases in path with their values and stores the result in resolvedPath,
|
||||
//! also ensures that the path is absolute
|
||||
//! NOTE: If the path does not start with an alias then the resolved value of the @assets@ is used
|
||||
//! which has the effect of making the path relative to the @assets@/ folder
|
||||
//! returns true if path was resolved, false otherwise
|
||||
//! note that all of the above file-finding and opening functions automatically resolve the path before operating
|
||||
//! so you should not need to call this except in very exceptional circumstances where you absolutely need to
|
||||
//! hit a physical file and don't want to use SystemFile
|
||||
virtual bool ResolvePath(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const = 0;
|
||||
|
||||
//! ResolvePath - Replaces any @ aliases in the supplied path with their the resolved alias values
|
||||
@@ -265,6 +249,11 @@ namespace AZ
|
||||
virtual bool ResolvePath(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path) const = 0;
|
||||
AZStd::optional<AZ::IO::FixedMaxPath> ResolvePath(const AZ::IO::PathView& path) const;
|
||||
|
||||
//! ReplaceAliases - If the path starts with an @...@ alias it is substituted with the alias value
|
||||
//! otherwise the path is copied as is to the resolvedAlias path value
|
||||
//! returns true if the resulting path can fit within AZ::IO::FixedMaxPath buffer
|
||||
virtual bool ReplaceAlias(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path) const = 0;
|
||||
|
||||
/// Divulge the filename used to originally open that handle.
|
||||
virtual bool GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const = 0;
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace AZ::IO
|
||||
//! Check whether the path is not absolute
|
||||
[[nodiscard]] constexpr bool IsRelative() const;
|
||||
//! Check whether the path is relative to the base path
|
||||
[[nodiscard]] constexpr bool IsRelativeTo(const PathView & base) const;
|
||||
[[nodiscard]] constexpr bool IsRelativeTo(const PathView& base) const;
|
||||
|
||||
//! Normalizes a path in a purely lexical manner.
|
||||
//! # Path separators are converted to their preferred path separator
|
||||
@@ -517,7 +517,7 @@ namespace AZ::IO
|
||||
//! Checks if the path has a root directory
|
||||
[[nodiscard]] constexpr bool HasRootDirectory() const;
|
||||
//! Checks whether the entire root path portion of the path is empty
|
||||
//! The root portion ofthe path is made up of root_name() / root_directory()
|
||||
//! The root portion of the path is made up of root_name() / root_directory()
|
||||
[[nodiscard]] constexpr bool HasRootPath() const;
|
||||
//! checks whether the relative part of path is empty
|
||||
//! (C:\\ lumberyard\dev\)
|
||||
@@ -539,8 +539,8 @@ namespace AZ::IO
|
||||
[[nodiscard]] constexpr bool IsAbsolute() const;
|
||||
//! Check whether the path is not absolute
|
||||
[[nodiscard]] constexpr bool IsRelative() const;
|
||||
//! Check whether the path is relative to the input path
|
||||
[[nodiscard]] constexpr bool IsRelativeTo() const;
|
||||
//! Check whether the path is relative to the base path
|
||||
[[nodiscard]] constexpr bool IsRelativeTo(const PathView& base) const;
|
||||
|
||||
// decomposition
|
||||
//! Given a windows path of "C:\lumberyard\foo\bar\name.txt" and a posix path of
|
||||
|
||||
@@ -1035,7 +1035,7 @@ namespace AZ::IO
|
||||
// move the parser from the end to a valid filename by decrementing
|
||||
for(--pathParserEnd, --patternParserEnd; pathParserEnd && patternParserEnd; --pathParserEnd, --patternParserEnd)
|
||||
{
|
||||
if (!AZStd::wildcard_match(*patternParserEnd, *pathParserEnd))
|
||||
if (!AZStd::wildcard_match_case(*patternParserEnd, *pathParserEnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1830,9 +1830,9 @@ namespace AZ::IO
|
||||
}
|
||||
|
||||
template <typename StringType>
|
||||
[[nodiscard]] constexpr bool BasicPath<StringType>::IsRelativeTo() const
|
||||
[[nodiscard]] constexpr bool BasicPath<StringType>::IsRelativeTo(const PathView& base) const
|
||||
{
|
||||
return static_cast<PathView>(*this).IsRelative();
|
||||
return static_cast<PathView>(*this).IsRelativeTo(base);
|
||||
}
|
||||
|
||||
template <typename StringType>
|
||||
|
||||
@@ -369,6 +369,7 @@ namespace AZ
|
||||
context.Serializer<JsonVector2Serializer>()->HandlesType<Vector2>();
|
||||
context.Serializer<JsonVector3Serializer>()->HandlesType<Vector3>();
|
||||
context.Serializer<JsonVector4Serializer>()->HandlesType<Vector4>();
|
||||
context.Serializer<JsonQuaternionSerializer>()->HandlesType<Quaternion>();
|
||||
}
|
||||
|
||||
void MathReflect(ReflectContext* context)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Vector4.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Math/MathVectorSerializer.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
@@ -238,4 +239,56 @@ namespace AZ
|
||||
{
|
||||
return JsonMathVectorSerializerInternal::Store<Vector4, 4>(outputValue, inputValue, defaultValue, valueTypeId, context);
|
||||
}
|
||||
|
||||
// Quaternion
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonQuaternionSerializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonQuaternionSerializer::Load(void* outputValue, const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
// check for "yaw, pitch, roll" object
|
||||
if (inputValue.IsObject())
|
||||
{
|
||||
if (inputValue.GetObject().ObjectEmpty())
|
||||
{
|
||||
Quaternion* outQuaternion = reinterpret_cast<Quaternion*>(outputValue);
|
||||
*outQuaternion = Quaternion::CreateIdentity();
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Using identity quaternion for empty object.");
|
||||
}
|
||||
|
||||
AZ::BaseJsonSerializer* floatSerializer = context.GetRegistrationContext()->GetSerializerForType(azrtti_typeid<float>());
|
||||
if (!floatSerializer)
|
||||
{
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "Failed to find the json float serializer.");
|
||||
}
|
||||
|
||||
constexpr const char* names[3] = {"yaw", "pitch", "roll"};
|
||||
float values[3];
|
||||
int i = 0;
|
||||
for (auto itr = inputValue.MemberBegin(); itr != inputValue.MemberEnd(); ++i, ++itr)
|
||||
{
|
||||
ScopedContextPath subPath(context, names[i]);
|
||||
JSR::Result intermediate = floatSerializer->Load(values + i, azrtti_typeid<float>(), itr->value, context);
|
||||
if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediate;
|
||||
}
|
||||
}
|
||||
|
||||
auto eulerAnglesDegrees = Vector3::CreateFromFloat3(values);
|
||||
reinterpret_cast<Quaternion*>(outputValue)->SetFromEulerDegrees(eulerAnglesDegrees);
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read quaternion.");
|
||||
}
|
||||
|
||||
return JsonMathVectorSerializerInternal::Load<Quaternion, 4>(outputValue, outputValueTypeId, inputValue, context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonQuaternionSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
|
||||
const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
return JsonMathVectorSerializerInternal::Store<Quaternion, 4>(outputValue, inputValue, defaultValue, valueTypeId, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,4 +51,16 @@ namespace AZ
|
||||
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
class JsonQuaternionSerializer
|
||||
: public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonQuaternionSerializer, "{18604375-3606-49AC-B366-0F6DF9149FF3}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Settings/CommandLine.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/AzCore_Traits_Platform.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/string/conversions.h>
|
||||
#include <AzCore/Settings/CommandLine.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -29,6 +29,21 @@ namespace AZ
|
||||
|
||||
return lowerStr;
|
||||
}
|
||||
|
||||
AZStd::string_view UnquoteArgument(AZStd::string_view arg)
|
||||
{
|
||||
if (arg.size() < 2)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
return arg.front() == '"' && arg.back() == '"' ? AZStd::string_view{ arg.begin() + 1, arg.end() - 1 } : arg;
|
||||
}
|
||||
|
||||
AZStd::string QuoteArgument(AZStd::string_view arg)
|
||||
{
|
||||
return !arg.empty() ? AZStd::string::format(R"("%.*s")", aznumeric_cast<int>(arg.size()), arg.data()) : AZStd::string{ arg };
|
||||
}
|
||||
}
|
||||
|
||||
CommandLine::CommandLine()
|
||||
@@ -41,15 +56,62 @@ namespace AZ
|
||||
{
|
||||
}
|
||||
|
||||
void CommandLine::AddArgument(AZStd::string currentArg, AZStd::string& currentSwitch)
|
||||
void CommandLine::ParseOptionArgument(AZStd::string_view newOption, AZStd::string_view newValue,
|
||||
CommandArgument* inProgressArgument)
|
||||
{
|
||||
StringFunc::Strip(currentArg, " ", false, true, true);
|
||||
// Allow argument values wrapped in quotes at both ends to become the value within the quotes
|
||||
AZStd::string_view unquotedValue = UnquoteArgument(newValue);
|
||||
if (unquotedValue != newValue)
|
||||
{
|
||||
// Update the inProgressArgument before adding new arguments
|
||||
if(inProgressArgument)
|
||||
{
|
||||
inProgressArgument->m_value = unquotedValue;
|
||||
// Set the inProgressArgument to nullptr to indicate that the inProgressArgument has been fulfilled
|
||||
inProgressArgument = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_allValues.push_back({ newOption, unquotedValue });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZStd::vector<AZStd::string_view> tokens;
|
||||
auto splitArgument = [&tokens](AZStd::string_view token)
|
||||
{
|
||||
tokens.emplace_back(AZ::StringFunc::StripEnds(token));
|
||||
};
|
||||
AZ::StringFunc::TokenizeVisitor(newValue, splitArgument, ",;");
|
||||
|
||||
// we do it this way because you are allowed to do odd things like
|
||||
// -root=abc -root=hij,klm -root whee -root fun;days
|
||||
// and roots value should be { abc, hij, klm, whee, fun, days }
|
||||
for (AZStd::string_view optionValue : tokens)
|
||||
{
|
||||
if (inProgressArgument)
|
||||
{
|
||||
inProgressArgument->m_value = optionValue;
|
||||
// Set the inProgressArgument to nullptr to indicate that the inProgressArgument has been fulfilled
|
||||
inProgressArgument = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_allValues.push_back({ newOption, optionValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLine::AddArgument(AZStd::string_view currentArg, AZStd::string& currentSwitch)
|
||||
{
|
||||
currentArg = AZ::StringFunc::StripEnds(currentArg);
|
||||
if (!currentArg.empty())
|
||||
{
|
||||
if (AZStd::string_view(currentArg.begin(), currentArg.begin() + 1).find_first_of(m_commandLineOptionPrefix) != AZStd::string_view::npos)
|
||||
if (m_commandLineOptionPrefix.contains(currentArg.front()))
|
||||
{
|
||||
// its possible that its a key-value-pair like /blah=whatever
|
||||
// we support this too, for compatibilty.
|
||||
// its possible that its a key-value-pair like -blah=whatever
|
||||
// we support this too, for compatibility.
|
||||
|
||||
currentArg = currentArg.substr(1);
|
||||
if (currentArg[0] == '-') // for -- extra
|
||||
@@ -57,93 +119,41 @@ namespace AZ
|
||||
currentArg = currentArg.substr(1);
|
||||
}
|
||||
|
||||
AZStd::size_t foundPos = StringFunc::Find(currentArg.c_str(), '=');
|
||||
AZStd::size_t foundPos = AZ::StringFunc::Find(currentArg, "=");
|
||||
if (foundPos != AZStd::string::npos)
|
||||
{
|
||||
// Allow argument values wrapped in quotes at both ends to become the value within the quotes
|
||||
if (currentArg.length() > (foundPos + 2) && currentArg[foundPos + 1] == '"' && currentArg[currentArg.length() - 1] == '"')
|
||||
{
|
||||
AZStd::string argName = currentArg.substr(0, foundPos);
|
||||
argName = ToLower(argName);
|
||||
StringFunc::Strip(argName, " ", false, true, true);
|
||||
m_switches[argName].emplace_back(currentArg.substr(foundPos + 2, currentArg.length() - (foundPos + 2) - 1));
|
||||
currentSwitch.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// its in '=' format
|
||||
AZStd::vector<AZStd::string> tokens;
|
||||
StringFunc::Tokenize(currentArg.substr(foundPos + 1).c_str(), tokens, ",;");
|
||||
currentArg.resize(foundPos);
|
||||
currentArg = ToLower(currentArg);
|
||||
StringFunc::Strip(currentArg, " ", false, true, true);
|
||||
m_switches.insert_key(currentArg); // returns pair<iter, bool>
|
||||
// we do it this way because you are allowed to do odd things like
|
||||
// /root=abc /root=hij,klm /root whee /root fun;days
|
||||
// and roots value should be { abc, hij, klm, whee, fun, days }
|
||||
for (AZStd::string& switchValue : tokens)
|
||||
{
|
||||
StringFunc::Strip(switchValue, " ", false, true, true);
|
||||
m_switches[currentArg].push_back(switchValue);
|
||||
}
|
||||
AZStd::string_view argumentView{ currentArg };
|
||||
AZStd::string_view option = AZ::StringFunc::StripEnds(argumentView.substr(0, foundPos));
|
||||
AZStd::string_view value = AZ::StringFunc::StripEnds(argumentView.substr(foundPos + 1));
|
||||
ParseOptionArgument(ToLower(option), value, nullptr);
|
||||
currentSwitch.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// its in this format /switchName switchvalue
|
||||
// its in this format -switchName switchvalue
|
||||
// (no equals)
|
||||
currentSwitch = currentArg;
|
||||
currentSwitch = ToLower(currentSwitch);
|
||||
m_switches.insert_key(currentSwitch);
|
||||
currentSwitch = ToLower(currentArg);
|
||||
m_allValues.push_back({ currentSwitch, "" });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentSwitch.empty())
|
||||
{
|
||||
m_miscValues.push_back(currentArg);
|
||||
m_allValues.push_back({ "", UnquoteArgument(currentArg) });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allow argument values wrapped in quotes at both ends to become the value within the quotes
|
||||
if (currentArg[0] == '"' && currentArg.length() >= 2 && currentArg[currentArg.length() - 1] == '"')
|
||||
{
|
||||
m_switches[currentSwitch].emplace_back(currentArg.substr(1, currentArg.length() - 2));
|
||||
currentSwitch.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::vector<AZStd::string> tokens;
|
||||
StringFunc::Tokenize(currentArg.c_str(), tokens, ",;");
|
||||
for (AZStd::string& switchValue : tokens)
|
||||
{
|
||||
StringFunc::Strip(switchValue, " ", false, true, true);
|
||||
m_switches[currentSwitch].push_back(switchValue);
|
||||
}
|
||||
|
||||
ParseOptionArgument(currentSwitch, currentArg, &m_allValues.back());
|
||||
currentSwitch.clear();
|
||||
}
|
||||
|
||||
currentSwitch.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLine::Parse(const ParamContainer& commandLine)
|
||||
{
|
||||
m_switches.clear();
|
||||
m_miscValues.clear();
|
||||
|
||||
AZStd::string currentSwitch;
|
||||
for (int i = 1; i < commandLine.size(); ++i)
|
||||
{
|
||||
AddArgument(commandLine[i], currentSwitch);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLine::Parse(int argc, char** argv)
|
||||
{
|
||||
m_switches.clear();
|
||||
m_miscValues.clear();
|
||||
m_allValues.clear();
|
||||
|
||||
AZStd::string currentSwitch;
|
||||
// Start on 1 because 0 is the executable name
|
||||
@@ -157,91 +167,145 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLine::Dump(ParamContainer& commandLineDumpOutput)
|
||||
void CommandLine::Parse(const ParamContainer& commandLine)
|
||||
{
|
||||
// Push back an empty argument as the Parse function always skips parsing the first argument
|
||||
commandLineDumpOutput.emplace_back(AZStd::string());
|
||||
for (const AZStd::string& miscValue : m_miscValues)
|
||||
{
|
||||
commandLineDumpOutput.push_back(miscValue);
|
||||
}
|
||||
m_allValues.clear();
|
||||
|
||||
if (!m_commandLineOptionPrefix.empty())
|
||||
// This version of Parse does not skip over 0th index
|
||||
AZStd::string currentSwitch;
|
||||
for (int i = 0; i < commandLine.size(); ++i)
|
||||
{
|
||||
for (const auto& [switchKey, switchValues] : m_switches)
|
||||
{
|
||||
AZStd::string prefixSwitchKey = m_commandLineOptionPrefix.front() + switchKey;
|
||||
if (switchValues.empty())
|
||||
{
|
||||
// There are no value for the switch so just push it back of the command line dump output
|
||||
commandLineDumpOutput.emplace_back(prefixSwitchKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& switchValue : switchValues)
|
||||
{
|
||||
commandLineDumpOutput.emplace_back(prefixSwitchKey);
|
||||
commandLineDumpOutput.emplace_back(switchValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
AddArgument(commandLine[i], currentSwitch);
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
void CommandLine::Dump(ParamContainer& commandLineDumpOutput) const
|
||||
{
|
||||
AZ_Error("CommandLine", !m_commandLineOptionPrefix.empty(),
|
||||
"Cannot dump command line switches from a command line with an empty option prefix");
|
||||
|
||||
for (const CommandArgument& argument : m_allValues)
|
||||
{
|
||||
AZ_Error("CommandLine", false, "Cannot dump command line switches from a command line with an empty option prefix");
|
||||
if (!argument.m_option.empty())
|
||||
{
|
||||
commandLineDumpOutput.emplace_back(m_commandLineOptionPrefix.front() + argument.m_option);
|
||||
}
|
||||
if (!argument.m_value.empty())
|
||||
{
|
||||
commandLineDumpOutput.emplace_back(QuoteArgument(argument.m_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandLine::HasSwitch(AZStd::string_view switchName) const
|
||||
{
|
||||
return m_switches.find(ToLower(switchName)) != m_switches.end();
|
||||
auto commandArgumentIter = AZStd::find_if(m_allValues.begin(), m_allValues.end(),
|
||||
[optionName = ToLower(switchName)](const CommandArgument& argument) { return argument.m_option == optionName; });
|
||||
return commandArgumentIter != m_allValues.end();
|
||||
}
|
||||
|
||||
AZStd::size_t CommandLine::GetNumSwitchValues(AZStd::string_view switchName) const
|
||||
{
|
||||
ParamMap::const_iterator switchFound = m_switches.find(ToLower(switchName));
|
||||
if (switchFound == m_switches.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return switchFound->second.size();
|
||||
return AZStd::count_if(m_allValues.begin(), m_allValues.end(),
|
||||
[optionName = ToLower(switchName)](const CommandArgument& argument) { return argument.m_option == optionName; });
|
||||
}
|
||||
|
||||
const AZStd::string& CommandLine::GetSwitchValue(AZStd::string_view switchName, AZStd::size_t index) const
|
||||
{
|
||||
ParamMap::const_iterator switchFound = m_switches.find(ToLower(switchName));
|
||||
if (switchFound == m_switches.end())
|
||||
AZStd::string optionName = ToLower(switchName);
|
||||
size_t currentPosIndex{};
|
||||
auto findArgumentAt = [&optionName, index, ¤tPosIndex](const CommandArgument& argument)
|
||||
{
|
||||
if (argument.m_option == optionName)
|
||||
{
|
||||
return currentPosIndex++ == index;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
auto commandArgumentIter = AZStd::find_if(m_allValues.begin(), m_allValues.end(), findArgumentAt);
|
||||
if (!optionName.empty())
|
||||
{
|
||||
AZ_Assert(index < currentPosIndex, R"(Invalid Command line optional argument lookup of "%s" at index %zu)",
|
||||
optionName.c_str(), index);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(index < currentPosIndex, R"(Invalid Command line positional argument lookup at index %zu)", index);
|
||||
}
|
||||
if (commandArgumentIter == m_allValues.end())
|
||||
{
|
||||
return m_emptyValue;
|
||||
}
|
||||
|
||||
AZ_Assert(index < switchFound->second.size(), "Invalid Command line switch lookup");
|
||||
if (index >= switchFound->second.size())
|
||||
{
|
||||
return m_emptyValue;
|
||||
}
|
||||
|
||||
return switchFound->second.at(index);
|
||||
return commandArgumentIter->m_value;
|
||||
}
|
||||
|
||||
AZStd::size_t CommandLine::GetNumMiscValues() const
|
||||
{
|
||||
return m_miscValues.size();
|
||||
return GetNumSwitchValues("");
|
||||
}
|
||||
|
||||
const AZStd::string& CommandLine::GetMiscValue(AZStd::size_t index) const
|
||||
{
|
||||
AZ_Assert(index < m_miscValues.size(), "Invalid Command line lookup");
|
||||
if (index >= m_miscValues.size())
|
||||
{
|
||||
return m_emptyValue;
|
||||
}
|
||||
return m_miscValues[index];
|
||||
// Positional arguments option value is an empty string
|
||||
return GetSwitchValue("", index);
|
||||
}
|
||||
|
||||
const CommandLine::ParamMap& CommandLine::GetSwitchList() const
|
||||
[[nodiscard]] bool CommandLine::empty() const
|
||||
{
|
||||
return m_switches;
|
||||
return m_allValues.empty();
|
||||
}
|
||||
|
||||
auto CommandLine::size() const -> ArgumentVector::size_type
|
||||
{
|
||||
return m_allValues.size();
|
||||
}
|
||||
auto CommandLine::begin() -> ArgumentVector::iterator
|
||||
{
|
||||
return m_allValues.begin();
|
||||
}
|
||||
auto CommandLine::begin() const -> ArgumentVector::const_iterator
|
||||
{
|
||||
return m_allValues.begin();
|
||||
}
|
||||
auto CommandLine::cbegin() const -> ArgumentVector::const_iterator
|
||||
{
|
||||
return m_allValues.cbegin();
|
||||
}
|
||||
auto CommandLine::end() -> ArgumentVector::iterator
|
||||
{
|
||||
return m_allValues.end();
|
||||
}
|
||||
auto CommandLine::end() const -> ArgumentVector::const_iterator
|
||||
{
|
||||
return m_allValues.end();
|
||||
}
|
||||
auto CommandLine::cend() const -> ArgumentVector::const_iterator
|
||||
{
|
||||
return m_allValues.cend();
|
||||
}
|
||||
auto CommandLine::rbegin() -> ArgumentVector::reverse_iterator
|
||||
{
|
||||
return m_allValues.rbegin();
|
||||
}
|
||||
auto CommandLine::rbegin() const -> ArgumentVector::const_reverse_iterator
|
||||
{
|
||||
return m_allValues.rbegin();
|
||||
}
|
||||
auto CommandLine::crbegin() const -> ArgumentVector::const_reverse_iterator
|
||||
{
|
||||
return m_allValues.crbegin();
|
||||
}
|
||||
auto CommandLine::rend() -> ArgumentVector::reverse_iterator
|
||||
{
|
||||
return m_allValues.rend();
|
||||
}
|
||||
auto CommandLine::rend() const -> ArgumentVector::const_reverse_iterator
|
||||
{
|
||||
return m_allValues.rend();
|
||||
}
|
||||
auto CommandLine::crend() const -> ArgumentVector::const_reverse_iterator
|
||||
{
|
||||
return m_allValues.crend();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,36 +36,47 @@ namespace AZ
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(CommandLine, AZ::SystemAllocator, 0);
|
||||
|
||||
using ParamContainer = AZStd::vector<AZStd::string>;
|
||||
|
||||
struct CommandArgument
|
||||
{
|
||||
AZStd::string m_option;
|
||||
AZStd::string m_value;
|
||||
};
|
||||
using ArgumentVector = AZStd::vector<CommandArgument>;
|
||||
|
||||
CommandLine();
|
||||
|
||||
/**
|
||||
* Initializes a CommandLine instance which uses the provided commandLineOptionPreix for parsing switches
|
||||
*/
|
||||
CommandLine(AZStd::string_view commandLineOptionPrefix);
|
||||
|
||||
using ParamContainer = AZStd::vector<AZStd::string>;
|
||||
using ParamMap = AZStd::unordered_map<AZStd::string, ParamContainer>;
|
||||
/**
|
||||
* Construct a command line parser.
|
||||
* It will load parameters from the given ARGC/ARGV parameters instead of process command line.
|
||||
* Skips over the first parameter as it assumes it is the executable name
|
||||
*/
|
||||
void Parse(int argc, char** argv);
|
||||
/**
|
||||
* Parses each element of the command line as parameter.
|
||||
* Unlike the ARGC/ARGV version above, this function doesn't skip over the first parameter
|
||||
* It allows for round trip conversion with the Dump() method
|
||||
*/
|
||||
void Parse(const ParamContainer& commandLine);
|
||||
|
||||
/**
|
||||
* Will dump command line parameters from the CommandLine in a format such that switches
|
||||
* are prefixed with the option prefix followed by their value(s) which are comma separated
|
||||
* The result of this function can be supplied to Parse() to re-create an eqiuvlanet command line obect
|
||||
* The result of this function can be supplied to Parse() to re-create an equivalent command line object
|
||||
* Ex, If the command line has the current list of parsed miscellaneous values and switches of
|
||||
* MiscValue = ["Foo", "Bat"]
|
||||
* Switches = ["GameFolder" : [], "RemoteIp" : ["10.0.0.1"], "ScanFolders" : ["\a\b\c", "\d\e\f"]
|
||||
* CommandLineOptionPrefix = "-/"
|
||||
*
|
||||
* Then the resulting dumped value would be
|
||||
* Dump = ["", "Foo", "Bat", "-GameFolder", "-RemoteIp", "10.0.0.1", "-ScanFolders", "\a\b\c", "-ScanFolders", "\d\e\f"]
|
||||
* NOTE: The first parameter is always empty string as the Parse function skips over it
|
||||
* Dump = ["Foo", "Bat", "-GameFolder", "-RemoteIp", "10.0.0.1", "-ScanFolders", "\a\b\c", "-ScanFolders", "\d\e\f"]
|
||||
*/
|
||||
void Dump(ParamContainer& commandLineDumpOutput);
|
||||
void Dump(ParamContainer& commandLineDumpOutput) const;
|
||||
|
||||
/**
|
||||
* Determines whether a switch is present in the command line
|
||||
@@ -97,16 +108,28 @@ namespace AZ
|
||||
*/
|
||||
const AZStd::string& GetMiscValue(AZStd::size_t index) const;
|
||||
|
||||
/*
|
||||
* Return the list of parsed switches
|
||||
*/
|
||||
const ParamMap& GetSwitchList() const;
|
||||
|
||||
// Range accessors
|
||||
[[nodiscard]] bool empty() const;
|
||||
auto size() const -> ArgumentVector::size_type;
|
||||
auto begin() -> ArgumentVector::iterator;
|
||||
auto begin() const -> ArgumentVector::const_iterator;
|
||||
auto cbegin() const -> ArgumentVector::const_iterator;
|
||||
auto end() -> ArgumentVector::iterator;
|
||||
auto end() const -> ArgumentVector::const_iterator;
|
||||
auto cend() const -> ArgumentVector::const_iterator;
|
||||
auto rbegin() -> ArgumentVector::reverse_iterator;
|
||||
auto rbegin() const -> ArgumentVector::const_reverse_iterator;
|
||||
auto crbegin() const -> ArgumentVector::const_reverse_iterator;
|
||||
auto rend() -> ArgumentVector::reverse_iterator;
|
||||
auto rend() const -> ArgumentVector::const_reverse_iterator;
|
||||
auto crend() const -> ArgumentVector::const_reverse_iterator;
|
||||
|
||||
private:
|
||||
void AddArgument(AZStd::string currentArg, AZStd::string& currentSwitch);
|
||||
void AddArgument(AZStd::string_view currentArg, AZStd::string& currentSwitch);
|
||||
void ParseOptionArgument(AZStd::string_view newOption, AZStd::string_view newValue, CommandArgument* inProgressArgument);
|
||||
|
||||
ParamMap m_switches;
|
||||
ParamContainer m_miscValues;
|
||||
ArgumentVector m_allValues;
|
||||
AZStd::string m_emptyValue;
|
||||
|
||||
inline static constexpr size_t MaxCommandOptionPrefixes = 8;
|
||||
|
||||
@@ -173,7 +173,15 @@ namespace AZ
|
||||
path.remove_prefix(1); // Remove the leading slash as the StackedString will add this back in.
|
||||
jsonPath.Push(path);
|
||||
}
|
||||
Visit(visitor, jsonPath, "", *value);
|
||||
// Extract the last token of the JSON pointer to use as the valueName
|
||||
AZStd::string_view valueName;
|
||||
size_t pointerTokenCount = pointer.GetTokenCount();
|
||||
if (pointerTokenCount > 0)
|
||||
{
|
||||
const rapidjson::Pointer::Token& lastToken = pointer.GetTokens()[pointerTokenCount - 1];
|
||||
valueName = AZStd::string_view(lastToken.name, lastToken.length);
|
||||
}
|
||||
Visit(visitor, jsonPath, valueName, *value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,68 +41,197 @@ namespace AZ::Internal
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString GetEngineMonikerForProject(
|
||||
SettingsRegistryInterface& settingsRegistry, const AZ::IO::FixedMaxPath& projectPath)
|
||||
{
|
||||
// projectPath needs to be an absolute path here.
|
||||
using namespace AZ::SettingsRegistryMergeUtils;
|
||||
bool projectJsonMerged = false;
|
||||
auto projectJsonPath = projectPath / "project.json";
|
||||
if (AZ::IO::SystemFile::Exists(projectJsonPath.c_str()))
|
||||
{
|
||||
projectJsonMerged = settingsRegistry.MergeSettingsFile(
|
||||
projectJsonPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, ProjectSettingsRootKey);
|
||||
}
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString engineMoniker;
|
||||
if (projectJsonMerged)
|
||||
{
|
||||
// In project.json look for the "engine" key.
|
||||
auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine", ProjectSettingsRootKey);
|
||||
settingsRegistry.Get(engineMoniker, engineMonikerKey);
|
||||
}
|
||||
|
||||
return engineMoniker;
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath ReconcileEngineRootFromProjectPath(SettingsRegistryInterface& settingsRegistry, const AZ::IO::FixedMaxPath& projectPath)
|
||||
{
|
||||
// Find the engine root via the engine manifest file and project.json
|
||||
// Locate the engine manifest file and merge it to settings registry.
|
||||
// Visit over the engine paths list and merge the engine.json files to settings registry.
|
||||
// Merge project.json to settings registry. That will give us an "engine" key.
|
||||
// When we find a match for "engine_name" value against the "engine" value from before, we can stop and use that engine root.
|
||||
// Finally set the BootstrapSettingsRootKey/engine_path setting so that subsequent calls to GetEngineRoot will use that
|
||||
// and avoid all this logic.
|
||||
|
||||
using namespace AZ::SettingsRegistryMergeUtils;
|
||||
|
||||
AZ::IO::FixedMaxPath engineRoot;
|
||||
if (auto engineManifestPath = AZ::Utils::GetEngineManifestPath(); !engineManifestPath.empty())
|
||||
{
|
||||
bool manifestLoaded{false};
|
||||
|
||||
if (AZ::IO::SystemFile::Exists(engineManifestPath.c_str()))
|
||||
{
|
||||
manifestLoaded = settingsRegistry.MergeSettingsFile(
|
||||
engineManifestPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineManifestRootKey);
|
||||
}
|
||||
|
||||
struct EngineInfo
|
||||
{
|
||||
AZ::IO::FixedMaxPath m_path;
|
||||
AZ::SettingsRegistryInterface::FixedValueString m_moniker;
|
||||
};
|
||||
|
||||
struct EnginePathsVisitor : public AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
void Visit(
|
||||
[[maybe_unused]] AZStd::string_view path, [[maybe_unused]] AZStd::string_view valueName,
|
||||
[[maybe_unused]] AZ::SettingsRegistryInterface::Type type, AZStd::string_view value) override
|
||||
{
|
||||
m_enginePaths.emplace_back(EngineInfo{AZ::IO::FixedMaxPath{value}.LexicallyNormal(), {}});
|
||||
}
|
||||
|
||||
AZStd::vector<EngineInfo> m_enginePaths{};
|
||||
};
|
||||
|
||||
EnginePathsVisitor pathVisitor;
|
||||
if (manifestLoaded)
|
||||
{
|
||||
auto enginePathsKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engines", EngineManifestRootKey);
|
||||
settingsRegistry.Visit(pathVisitor, enginePathsKey);
|
||||
}
|
||||
|
||||
const auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine_name", EngineSettingsRootKey);
|
||||
|
||||
for (EngineInfo& engineInfo : pathVisitor.m_enginePaths)
|
||||
{
|
||||
AZ::IO::FixedMaxPath engineSettingsPath{engineInfo.m_path};
|
||||
engineSettingsPath /= "engine.json";
|
||||
|
||||
if (AZ::IO::SystemFile::Exists(engineSettingsPath.c_str()))
|
||||
{
|
||||
if (settingsRegistry.MergeSettingsFile(
|
||||
engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineSettingsRootKey))
|
||||
{
|
||||
settingsRegistry.Get(engineInfo.m_moniker, engineMonikerKey);
|
||||
}
|
||||
}
|
||||
|
||||
auto engineMoniker = Internal::GetEngineMonikerForProject(settingsRegistry, engineInfo.m_path / projectPath);
|
||||
if (!engineMoniker.empty() && engineMoniker == engineInfo.m_moniker)
|
||||
{
|
||||
engineRoot = engineInfo.m_path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return engineRoot;
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath ScanUpRootLocator(AZStd::string_view rootFileToLocate)
|
||||
{
|
||||
|
||||
AZStd::fixed_string<AZ::IO::MaxPathLength> executableDir;
|
||||
if (Utils::GetExecutableDirectory(executableDir.data(), executableDir.capacity()) == Utils::ExecutablePathResult::Success)
|
||||
{
|
||||
// Update the size value of the executable directory fixed string to correctly be the length of the null-terminated string
|
||||
// stored within it
|
||||
executableDir.resize_no_construct(AZStd::char_traits<char>::length(executableDir.data()));
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath engineRootCandidate{ executableDir };
|
||||
|
||||
bool rootPathVisited = false;
|
||||
do
|
||||
{
|
||||
if (AZ::IO::SystemFile::Exists((engineRootCandidate / rootFileToLocate).c_str()))
|
||||
{
|
||||
return engineRootCandidate;
|
||||
}
|
||||
|
||||
// Note for posix filesystems the parent directory of '/' is '/' and for windows
|
||||
// the parent directory of 'C:\\' is 'C:\\'
|
||||
|
||||
// Validate that the parent directory isn't itself, that would imply
|
||||
// that it is the filesystem root path
|
||||
AZ::IO::PathView parentPath = engineRootCandidate.ParentPath();
|
||||
rootPathVisited = (engineRootCandidate == parentPath);
|
||||
// Recurse upwards one directory
|
||||
engineRootCandidate = AZStd::move(parentPath);
|
||||
|
||||
} while (!rootPathVisited);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace AZ::Internal
|
||||
|
||||
namespace AZ::SettingsRegistryMergeUtils
|
||||
{
|
||||
AZ::IO::FixedMaxPath GetAppRoot(SettingsRegistryInterface* settingsRegistry)
|
||||
AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry)
|
||||
{
|
||||
constexpr size_t MaxAppRootPathsToScan = 16;
|
||||
AZStd::fixed_vector<AZStd::string_view, MaxAppRootPathsToScan> appRootScanPaths;
|
||||
AZ::IO::FixedMaxPath engineRoot;
|
||||
|
||||
// Check the commandLine for --app-root parameter
|
||||
// If it exist use that instead
|
||||
auto appRootOverrideKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/app-root", AZ::SettingsRegistryMergeUtils::CommandLineSwitchRootKey);
|
||||
if (settingsRegistry)
|
||||
// This is the 'external' engine root key, as in passed from command-line or .setreg files.
|
||||
auto engineRootKey = SettingsRegistryInterface::FixedValueString::format("%s/engine_path", BootstrapSettingsRootKey);
|
||||
if (settingsRegistry.Get(engineRoot.Native(), engineRootKey); !engineRoot.empty())
|
||||
{
|
||||
AZ::IO::FixedMaxPath appRootOverridePath;
|
||||
if (settingsRegistry->Get(appRootOverridePath.Native(), appRootOverrideKey))
|
||||
{
|
||||
return appRootOverridePath;
|
||||
}
|
||||
return engineRoot;
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::fixed_string<AZ::IO::MaxPathLength>> appRootPath = Utils::GetDefaultAppRootPath();
|
||||
if (appRootPath.has_value())
|
||||
// We can scan up from exe directory to find engine.json, use that for engine root if it exists.
|
||||
if (engineRoot = Internal::ScanUpRootLocator("engine.json"); !engineRoot.empty())
|
||||
{
|
||||
appRootScanPaths.push_back(*appRootPath);
|
||||
settingsRegistry.Set(engineRootKey, engineRoot.c_str());
|
||||
return engineRoot;
|
||||
}
|
||||
AZStd::fixed_string<AZ::IO::MaxPathLength> executableDir;
|
||||
AZ::Utils::ExecutablePathResult pathResult = Utils::GetExecutableDirectory(executableDir.data(), executableDir.capacity());
|
||||
if (pathResult == Utils::ExecutablePathResult::Success)
|
||||
|
||||
AZ::IO::FixedMaxPath projectRoot = FindProjectRoot(settingsRegistry);
|
||||
if (projectRoot.empty())
|
||||
{
|
||||
// Update the size value of the executable directory fixed string to correctly be the length of the null-terminated string stored within it
|
||||
executableDir.resize_no_construct(AZStd::char_traits<char>::length(executableDir.data()));
|
||||
if (auto foundIt = AZStd::find(appRootScanPaths.begin(), appRootScanPaths.end(), executableDir);
|
||||
foundIt == appRootScanPaths.end())
|
||||
{
|
||||
appRootScanPaths.push_back(executableDir);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
for (AZStd::string_view appRootScanPath : appRootScanPaths)
|
||||
|
||||
// Use the project.json and engine manifest to locate the engine root.
|
||||
if (engineRoot = Internal::ReconcileEngineRootFromProjectPath(settingsRegistry, projectRoot); !engineRoot.empty())
|
||||
{
|
||||
AZ::IO::FixedMaxPath appRootCandidate{ appRootScanPath };
|
||||
|
||||
// Search for the application root
|
||||
bool rootPathVisited = false;
|
||||
do
|
||||
{
|
||||
if (AZ::IO::SystemFile::Exists((appRootCandidate / "bootstrap.cfg").c_str()))
|
||||
{
|
||||
return appRootCandidate;
|
||||
}
|
||||
|
||||
// Validate that the parent directory isn't itself, that would imply
|
||||
// that it is the root path
|
||||
AZ::IO::PathView parentPath = appRootCandidate.ParentPath();
|
||||
rootPathVisited = appRootCandidate == parentPath;
|
||||
// Recurse upwards one directory
|
||||
appRootCandidate = AZStd::move(parentPath);
|
||||
|
||||
} while (!rootPathVisited);
|
||||
// Note for posix filesystems the parent directory of '/' is '/' and for windows
|
||||
// the parent directory of 'C:\\' is 'C:\\'
|
||||
settingsRegistry.Set(engineRootKey, engineRoot.c_str());
|
||||
return engineRoot;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry)
|
||||
{
|
||||
AZ::IO::FixedMaxPath projectRoot;
|
||||
// This is the 'external' project root key, as in passed from command-line or .setreg files.
|
||||
auto projectRootKey = SettingsRegistryInterface::FixedValueString::format("%s/project_path", BootstrapSettingsRootKey);
|
||||
if (settingsRegistry.Get(projectRoot.Native(), projectRootKey))
|
||||
{
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
if (projectRoot = Internal::ScanUpRootLocator("project.json"); !projectRoot.empty())
|
||||
{
|
||||
settingsRegistry.Set(projectRootKey, projectRoot.c_str());
|
||||
return projectRoot;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -111,9 +240,9 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
constexpr AZStd::string_view commentPrefixes = ";#";
|
||||
for (char commentPrefix : commentPrefixes)
|
||||
{
|
||||
if (line.starts_with(commentPrefix))
|
||||
if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos)
|
||||
{
|
||||
return {};
|
||||
return line.substr(0, commentOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +252,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
AZStd::string_view ConfigParserSettings::DefaultSectionHeaderFilter(AZStd::string_view line)
|
||||
{
|
||||
AZStd::string_view sectionName;
|
||||
constexpr char sectionHeaderStart= '[';
|
||||
constexpr char sectionHeaderStart = '[';
|
||||
constexpr char sectionHeaderEnd = ']';
|
||||
if (line.starts_with(sectionHeaderStart) && line.ends_with(sectionHeaderEnd))
|
||||
{
|
||||
@@ -184,7 +313,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
|
||||
void QuerySpecializationsFromRegistry(SettingsRegistryInterface& registry, SettingsRegistryInterface::Specializations& specializations)
|
||||
{
|
||||
// Append any specializations stored in the registry
|
||||
// Append any specializations stored in the registry
|
||||
struct SpecializationsVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
@@ -222,7 +351,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
bool MergeSettingsToRegistry_ConfigFile(SettingsRegistryInterface& registry, AZStd::string_view filePath,
|
||||
const ConfigParserSettings& configParserSettings)
|
||||
{
|
||||
auto configPath = GetAppRoot(®istry) / filePath;
|
||||
auto configPath = FindEngineRoot(registry) / filePath;
|
||||
IO::SystemFile configFile;
|
||||
if (!configFile.Open(configPath.c_str(), IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY))
|
||||
{
|
||||
@@ -348,9 +477,13 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
ConfigParserSettings parserSettings;
|
||||
parserSettings.m_commentPrefixFunc = [](AZStd::string_view line) -> AZStd::string_view
|
||||
{
|
||||
if (line.starts_with("--") || line.starts_with(';') || line.starts_with('#'))
|
||||
constexpr AZStd::string_view commentPrefixes[]{ "--", ";","#" };
|
||||
for (AZStd::string_view commentPrefix : commentPrefixes)
|
||||
{
|
||||
return {};
|
||||
if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos)
|
||||
{
|
||||
return line.substr(0, commentOffset);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
};
|
||||
@@ -365,71 +498,104 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
registry.Set(FilePathKey_BinaryFolder, path.LexicallyNormal().Native());
|
||||
|
||||
// Engine root folder - corresponds to the @engroot@ and @devroot@ aliases
|
||||
AZ::IO::FixedMaxPath appRoot = GetAppRoot(®istry);
|
||||
registry.Set(FilePathKey_EngineRootFolder, appRoot.LexicallyNormal().Native());
|
||||
AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry);
|
||||
registry.Set(FilePathKey_EngineRootFolder, engineRoot.LexicallyNormal().Native());
|
||||
|
||||
constexpr size_t bufferSize = 64;
|
||||
auto buffer = AZStd::fixed_string<bufferSize>::format("%s/sys_game_folder", BootstrapSettingsRootKey);
|
||||
auto buffer = AZStd::fixed_string<bufferSize>::format("%s/project_path", BootstrapSettingsRootKey);
|
||||
|
||||
AZStd::string_view projectPath(buffer);
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectPathKey(buffer);
|
||||
SettingsRegistryInterface::FixedValueString projectPathValue;
|
||||
if (registry.Get(projectPathValue, projectPath))
|
||||
if (registry.Get(projectPathValue, projectPathKey))
|
||||
{
|
||||
// Cache folder
|
||||
// Get the name of the asset platform assigned by the bootstrap. First check for platform version such as "windows_assets"
|
||||
// and if that's missing just get "asset".
|
||||
// and if that's missing just get "assets".
|
||||
constexpr char platformName[] = AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER;
|
||||
|
||||
SettingsRegistryInterface::FixedValueString assetPlatform;
|
||||
buffer = AZStd::fixed_string<bufferSize>::format("%s/%s_assets", BootstrapSettingsRootKey, platformName);
|
||||
AZStd::string_view assetPlatformatPath(buffer);
|
||||
if (!registry.Get(assetPlatform, assetPlatformatPath))
|
||||
AZStd::string_view assetPlatformKey(buffer);
|
||||
if (!registry.Get(assetPlatform, assetPlatformKey))
|
||||
{
|
||||
buffer = AZStd::fixed_string<bufferSize>::format("%s/assets", BootstrapSettingsRootKey);
|
||||
assetPlatformatPath = AZStd::string_view(buffer);
|
||||
if (!registry.Get(assetPlatform, assetPlatformatPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
assetPlatformKey = AZStd::string_view(buffer);
|
||||
registry.Get(assetPlatform, assetPlatformKey);
|
||||
}
|
||||
|
||||
// Source game folder - corresponds to the @devassets@ alias
|
||||
path = appRoot / projectPathValue;
|
||||
// Project path - corresponds to the @devassets@ alias
|
||||
// NOTE: Here we append to engineRoot, but if projectPathValue is absolute then engineRoot is discarded.
|
||||
path = engineRoot / projectPathValue;
|
||||
|
||||
AZ_Warning("SettingsRegistryMergeUtils", AZ::IO::SystemFile::Exists(path.c_str()),
|
||||
R"(Project Path "%s" does not exist. Is the "sys_game_folder" entry set to valid project folder?)"
|
||||
, path.c_str());
|
||||
registry.Set(FilePathKey_SourceGameFolder, path.LexicallyNormal().Native());
|
||||
R"(Project path "%s" does not exist. Is the "%.*s" registry setting set to valid absolute path?)"
|
||||
, path.c_str(), aznumeric_cast<int>(projectPathKey.size()), projectPathKey.data());
|
||||
|
||||
// Source game name - The filename of the project directory and the name of the project
|
||||
registry.Set(FilePathKey_SourceGameName, path.Filename().Native());
|
||||
AZ::IO::FixedMaxPath normalizedProjectPath = path.LexicallyNormal();
|
||||
registry.Set(FilePathKey_ProjectPath, normalizedProjectPath.Native());
|
||||
|
||||
// Cache root folder - corresponds to the @root@ alias
|
||||
#if AZ_TRAIT_USE_ASSET_CACHE_FOLDER
|
||||
path = appRoot / "Cache" / projectPathValue / assetPlatform;
|
||||
#else
|
||||
// Use the Engine Root/App Root as the Asset root directory in this case
|
||||
path = appRoot;
|
||||
#endif
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
|
||||
// check for a default write storage path, fall back to the cache root if not
|
||||
// Add an alias to the project "user" directory
|
||||
AZ::IO::FixedMaxPath projectUserPath = (normalizedProjectPath / "user").LexicallyNormal();
|
||||
registry.Set(FilePathKey_ProjectUserPath, projectUserPath.Native());
|
||||
// check for a default write storage path, fall back to the project's user/ directory if not
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> devWriteStorage = Utils::GetDevWriteStoragePath();
|
||||
registry.Set(FilePathKey_DevWriteStorage,
|
||||
devWriteStorage.has_value() ?
|
||||
devWriteStorage.value() :
|
||||
path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_DevWriteStorage, devWriteStorage.has_value()
|
||||
? devWriteStorage.value()
|
||||
: projectUserPath.Native());
|
||||
|
||||
// Cache game folder - corresponds to the @assets@ alias
|
||||
AZStd::to_lower(projectPathValue.begin(), projectPathValue.end());
|
||||
path /= projectPathValue;
|
||||
registry.Set(FilePathKey_CacheGameFolder, path.LexicallyNormal().Native());
|
||||
// Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name.
|
||||
auto projectNameKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
|
||||
+ "/project_name";
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectName;
|
||||
if (!registry.Get(projectName, projectNameKey))
|
||||
{
|
||||
projectName = path.Filename().Native();
|
||||
registry.Set(projectNameKey, projectName);
|
||||
}
|
||||
|
||||
// Cache folders - sets up various paths in registry for the cache.
|
||||
// Make sure the asset platform is set before setting these cache paths.
|
||||
if (!assetPlatform.empty())
|
||||
{
|
||||
// Cache: project root - no corresponding fileIO alias, but this is where the asset database lives.
|
||||
// A registry override is accepted using the "project_cache_path" key.
|
||||
buffer = AZStd::fixed_string<bufferSize>::format("%s/project_cache_path", BootstrapSettingsRootKey);
|
||||
AZStd::string_view projectCacheRootOverrideKey(buffer);
|
||||
// Clear path to make sure that the `project_cache_path` value isn't concatenated to the project path
|
||||
path.clear();
|
||||
if (registry.Get(path.Native(), projectCacheRootOverrideKey))
|
||||
{
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native());
|
||||
path /= assetPlatform;
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cache: root - same as the @root@ alias, this is the starting path for cache files.
|
||||
path = normalizedProjectPath / "Cache";
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native());
|
||||
path /= assetPlatform;
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_TracePrintf("SettingsRegistryMergeUtils",
|
||||
R"(Current Project game folder "%.*s" isn't set in the Settings Registry. Project-related filepaths will not be set)" "\n",
|
||||
aznumeric_cast<int>(projectPath.size()), projectPath.data());
|
||||
R"(Project path isn't set in the Settings Registry at "%.*s". Project-related filepaths will not be set)" "\n",
|
||||
aznumeric_cast<int>(projectPathKey.size()), projectPathKey.data());
|
||||
}
|
||||
|
||||
#if !AZ_TRAIT_USE_ASSET_CACHE_FOLDER
|
||||
// Setup the cache and user paths for Platforms where the Asset Cache Folder isn't used
|
||||
path = engineRoot;
|
||||
registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_CacheRootFolder, path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_DevWriteStorage, path.LexicallyNormal().Native());
|
||||
registry.Set(FilePathKey_ProjectUserPath, (path / "user").LexicallyNormal().Native());
|
||||
#endif // AZ_TRAIT_USE_ASSET_CACHE_FOLDER
|
||||
}
|
||||
|
||||
void MergeSettingsToRegistry_TargetBuildDependencyRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
@@ -535,7 +701,7 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
const SettingsRegistryInterface::Specializations& specializations, AZStd::vector<char>* scratchBuffer)
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString sourceGamePath;
|
||||
if (registry.Get(sourceGamePath, FilePathKey_SourceGameFolder))
|
||||
if (registry.Get(sourceGamePath, FilePathKey_ProjectPath))
|
||||
{
|
||||
AZ::IO::FixedMaxPath mergePath{ sourceGamePath };
|
||||
mergePath /= SettingsRegistryInterface::RegistryFolder;
|
||||
@@ -543,26 +709,41 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
}
|
||||
}
|
||||
|
||||
void MergeSettingsToRegistry_DevRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
void MergeSettingsToRegistry_UserRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
const SettingsRegistryInterface::Specializations& specializations, AZStd::vector<char>* scratchBuffer)
|
||||
{
|
||||
// Unlike other paths, the path can't be overwritten by the dev settings because that would create a circular dependency.
|
||||
auto mergePath = GetAppRoot(®istry);
|
||||
mergePath /= SettingsRegistryInterface::DevUserRegistryFolder;
|
||||
registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer);
|
||||
AZ::IO::FixedMaxPath projectUserPath;
|
||||
if (registry.Get(projectUserPath.Native(), FilePathKey_ProjectPath))
|
||||
{
|
||||
projectUserPath /= SettingsRegistryInterface::DevUserRegistryFolder;
|
||||
registry.MergeSettingsFolder(projectUserPath.Native(), specializations, platform, "", scratchBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine, bool executeCommands)
|
||||
{
|
||||
const size_t regsetSwitchValues = commandLine.GetNumSwitchValues("regset");
|
||||
for (size_t regsetIndex = 0; regsetIndex < regsetSwitchValues; ++regsetIndex)
|
||||
// Iterate over all the command line options in order to parse the --regset and --regremove
|
||||
// arguments in the order they were supplied
|
||||
for (const CommandLine::CommandArgument& commandArgument : commandLine)
|
||||
{
|
||||
AZStd::string_view regsetValue = commandLine.GetSwitchValue("regset", regsetIndex);
|
||||
if (!registry.MergeCommandLineArgument(regsetValue, AZStd::string_view{}))
|
||||
if (commandArgument.m_option == "regset")
|
||||
{
|
||||
AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to parse argument for --regset with value of %.*s.",
|
||||
aznumeric_cast<int>(regsetValue.size()), regsetValue.data());
|
||||
continue;
|
||||
if (!registry.MergeCommandLineArgument(commandArgument.m_value, AZStd::string_view{}))
|
||||
{
|
||||
AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to parse argument for --regset with value of %s.",
|
||||
commandArgument.m_value.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (commandArgument.m_option == "regremove")
|
||||
{
|
||||
if (!registry.Remove(commandArgument.m_value))
|
||||
{
|
||||
AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to remove value at JSON Pointer %s for --regremove.",
|
||||
commandArgument.m_value.data());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,16 +766,8 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
DumpSettingsRegistryToStream(registry, regdumpValue, outputStream, dumperSettings);
|
||||
}
|
||||
|
||||
const size_t regdumpallSwitchValues = commandLine.GetNumSwitchValues("regdumpall");
|
||||
if (regdumpallSwitchValues > 0)
|
||||
if (commandLine.HasSwitch("regdumpall"))
|
||||
{
|
||||
AZStd::string_view regdumpallValue = commandLine.GetSwitchValue("regdumpall", 0);
|
||||
if (regdumpallValue.empty())
|
||||
{
|
||||
AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to parse argument for --regdumpall with value of %.*s.",
|
||||
aznumeric_cast<int>(regdumpallValue.size()), regdumpallValue.data());
|
||||
}
|
||||
|
||||
DumperSettings dumperSettings{ prettifyOutput };
|
||||
AZ::IO::StdoutStream outputStream;
|
||||
DumpSettingsRegistryToStream(registry, "", outputStream, dumperSettings);
|
||||
@@ -602,85 +775,77 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
}
|
||||
}
|
||||
|
||||
void MergeSettingsToRegistry_StoreCommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine)
|
||||
void StoreCommandLineToRegistry(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine)
|
||||
{
|
||||
// Clear out any existing CommandLine settings
|
||||
registry.Remove(CommandLineRootKey);
|
||||
// Add the positional arguments into the Settings Registry
|
||||
AZ::SettingsRegistryInterface::FixedValueString miscValueKey{ CommandLineMiscValuesRootKey };
|
||||
size_t miscKeyRootSize = miscValueKey.size();
|
||||
for (size_t miscIndex = 0; miscIndex < commandLine.GetNumMiscValues(); ++miscIndex)
|
||||
{
|
||||
// Push an array for each positional entry
|
||||
miscValueKey += AZ::SettingsRegistryInterface::FixedValueString::format("/%zu", miscIndex);
|
||||
registry.Set(miscValueKey, commandLine.GetMiscValue(miscIndex));
|
||||
miscValueKey.resize(miscKeyRootSize);
|
||||
}
|
||||
// Add the option arguments into the SettingsRegistry
|
||||
for (const auto& [commandOption, value] : commandLine.GetSwitchList())
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString switchKey{ CommandLineSwitchRootKey };
|
||||
switchKey += '/';
|
||||
switchKey += commandOption;
|
||||
size_t switchKeyRootSize = switchKey.size();
|
||||
// Associate an empty array with the commandOption by default
|
||||
rapidjson::Document commandSwitchDocument;
|
||||
rapidjson::Pointer pointer(switchKey.c_str(), switchKey.length());
|
||||
pointer.Set(commandSwitchDocument, rapidjson::Value(rapidjson::kArrayType));;
|
||||
rapidjson::StringBuffer documentBuffer;
|
||||
rapidjson::Writer documentWriter(documentBuffer);
|
||||
commandSwitchDocument.Accept(documentWriter);
|
||||
registry.MergeSettings(AZStd::string_view{ documentBuffer.GetString(), documentBuffer.GetSize() },
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch);
|
||||
|
||||
for (size_t switchIndex = 0; switchIndex < value.size(); ++switchIndex)
|
||||
{
|
||||
// Push an array for each positional entry
|
||||
switchKey += AZ::SettingsRegistryInterface::FixedValueString::format("/%zu", switchIndex);
|
||||
registry.Set(switchKey, value[switchIndex]);
|
||||
switchKey.resize(switchKeyRootSize);
|
||||
}
|
||||
AZ::SettingsRegistryInterface::FixedValueString commandLinePath{ CommandLineRootKey };
|
||||
const size_t commandLineRootSize = commandLinePath.size();
|
||||
size_t argumentIndex{};
|
||||
for (const CommandLine::CommandArgument& commandArgument : commandLine)
|
||||
{
|
||||
commandLinePath += AZ::SettingsRegistryInterface::FixedValueString::format("/%zu", argumentIndex);
|
||||
registry.Set(commandLinePath + "/Option", commandArgument.m_option);
|
||||
registry.Set(commandLinePath + "/Value", commandArgument.m_value);
|
||||
++argumentIndex;
|
||||
commandLinePath.resize(commandLineRootSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetCommandLineFromRegistry(SettingsRegistryInterface& registry, AZ::CommandLine& commandLine)
|
||||
{
|
||||
struct CommandLineVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type
|
||||
, AZStd::string_view value) override
|
||||
{
|
||||
if (valueName == "Option" && !value.empty())
|
||||
{
|
||||
m_arguments.push_back(AZStd::string::format("--%.*s", aznumeric_cast<int>(value.size()), value.data()));
|
||||
}
|
||||
else if (valueName == "Value" && !value.empty())
|
||||
{
|
||||
m_arguments.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
// The first parameter is skipped by the ComamndLine::Parse function so initialize
|
||||
// the container with one empty element
|
||||
AZ::CommandLine::ParamContainer m_arguments{ 1 };
|
||||
};
|
||||
|
||||
CommandLineVisitor commandLineVisitor;
|
||||
if (!registry.Visit(commandLineVisitor, AZ::SettingsRegistryMergeUtils::CommandLineRootKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
commandLine.Parse(commandLineVisitor.m_arguments);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSettingsRegistryToStream(SettingsRegistryInterface& registry, AZStd::string_view key,
|
||||
AZ::IO::GenericStream& stream, const DumperSettings& dumperSettings)
|
||||
{
|
||||
struct SettingsExportVisitor
|
||||
: SettingsRegistryInterface::Visitor
|
||||
{
|
||||
using SettingsWriter = AZStd::variant<
|
||||
rapidjson::PrettyWriter<AZ::IO::RapidJSONStreamWriter>,
|
||||
rapidjson::Writer<AZ::IO::RapidJSONStreamWriter>>;
|
||||
SettingsWriter m_writer;
|
||||
AZ::IO::RapidJSONStreamWriter m_rapidJsonStream;
|
||||
DumperSettings m_dumperSettings;
|
||||
AZStd::stack<bool> m_includeNameStack;
|
||||
bool m_includeName{};
|
||||
bool m_result{ true };
|
||||
|
||||
SettingsExportVisitor(AZ::IO::GenericStream& stream, const DumperSettings& dumperSettings)
|
||||
: m_rapidJsonStream{ &stream }
|
||||
, m_dumperSettings{ dumperSettings }
|
||||
, m_writer{ m_stringBuffer }
|
||||
{
|
||||
if (m_dumperSettings.m_prettifyOutput)
|
||||
{
|
||||
m_writer.emplace<rapidjson::PrettyWriter<AZ::IO::RapidJSONStreamWriter>>(m_rapidJsonStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_writer.emplace<rapidjson::Writer<AZ::IO::RapidJSONStreamWriter>>(m_rapidJsonStream);
|
||||
}
|
||||
}
|
||||
void WriteName(AZStd::string_view name)
|
||||
bool WriteName(AZStd::string_view name)
|
||||
{
|
||||
if (m_includeName)
|
||||
// Write the Key if the include name stack the top element is true
|
||||
if (!m_includeNameStack.empty() && m_includeNameStack.top())
|
||||
{
|
||||
AZStd::visit([&name](auto&& writer)
|
||||
{
|
||||
writer.Key(name.data(), aznumeric_caster(name.size()));
|
||||
}, m_writer);
|
||||
return m_writer.Key(name.data(), aznumeric_caster(name.size()), false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
AZ::SettingsRegistryInterface::VisitResponse Traverse(
|
||||
AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::VisitAction action,
|
||||
@@ -694,60 +859,43 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
|
||||
if (action == AZ::SettingsRegistryInterface::VisitAction::Begin)
|
||||
{
|
||||
AZ_Assert(type == AZ::SettingsRegistryInterface::Type::Object || type == AZ::SettingsRegistryInterface::Type::Array,
|
||||
"Unexpected type visited: %i.", type);
|
||||
WriteName(valueName);
|
||||
m_result = m_result && WriteName(valueName);
|
||||
if (type == AZ::SettingsRegistryInterface::Type::Object)
|
||||
{
|
||||
auto StartObject = [](auto&& writer)
|
||||
m_result = m_result && m_writer.StartObject();
|
||||
if (m_result)
|
||||
{
|
||||
return writer.StartObject();
|
||||
};
|
||||
m_result = m_result && AZStd::visit(StartObject, m_writer);
|
||||
m_includeNameStack.push(true);
|
||||
m_includeName = true;
|
||||
m_includeNameStack.push(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto StartArray = [](auto&& writer)
|
||||
m_result = m_result && m_writer.StartArray();
|
||||
if (m_result)
|
||||
{
|
||||
return writer.StartArray();
|
||||
};
|
||||
m_result = m_result && AZStd::visit(StartArray, m_writer);
|
||||
m_includeNameStack.push(false);
|
||||
m_includeName = false;
|
||||
m_includeNameStack.push(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (action == AZ::SettingsRegistryInterface::VisitAction::End)
|
||||
{
|
||||
if (type == AZ::SettingsRegistryInterface::Type::Object)
|
||||
{
|
||||
auto EndObject = [](auto&& writer)
|
||||
{
|
||||
return writer.EndObject();
|
||||
};
|
||||
m_result = m_result && AZStd::visit(EndObject, m_writer);
|
||||
m_result = m_result && m_writer.EndObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto EndArray = [](auto&& writer)
|
||||
{
|
||||
return writer.EndArray();
|
||||
};
|
||||
m_result = m_result && AZStd::visit(EndArray, m_writer);
|
||||
m_result = m_result && m_writer.EndArray();
|
||||
}
|
||||
AZ_Assert(!m_includeNameStack.empty(), "Attempting to close a json array or object that wasn't started.");
|
||||
m_includeNameStack.pop();
|
||||
m_includeName = !m_includeNameStack.empty() ? m_includeNameStack.top() : true;
|
||||
}
|
||||
else if (type == AZ::SettingsRegistryInterface::Type::Null)
|
||||
else
|
||||
{
|
||||
WriteName(valueName);
|
||||
auto WriteNull = [](auto&& writer)
|
||||
if (type == AZ::SettingsRegistryInterface::Type::Null)
|
||||
{
|
||||
return writer.Null();
|
||||
};
|
||||
m_result = m_result && AZStd::visit(WriteNull, m_writer);
|
||||
m_result = m_result && WriteName(valueName) && m_writer.Null();
|
||||
}
|
||||
}
|
||||
|
||||
return m_result ?
|
||||
@@ -757,42 +905,27 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value)
|
||||
{
|
||||
WriteName(valueName);
|
||||
auto WriteBool = [value](auto&& writer)
|
||||
{
|
||||
return writer.Bool(value);
|
||||
};
|
||||
m_result = m_result && AZStd::visit(WriteBool, m_writer);
|
||||
m_result = m_result && WriteName(valueName) && m_writer.Bool(value);
|
||||
}
|
||||
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value)
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) override
|
||||
{
|
||||
WriteName(valueName);
|
||||
auto WriteInt64 = [value](auto&& writer)
|
||||
{
|
||||
return writer.Int64(value);
|
||||
};
|
||||
m_result = m_result && AZStd::visit(WriteInt64, m_writer);
|
||||
m_result = m_result && WriteName(valueName) && m_writer.Int64(value);
|
||||
}
|
||||
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::u64 value) override
|
||||
{
|
||||
m_result = m_result && WriteName(valueName) && m_writer.Uint64(value);
|
||||
}
|
||||
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, double value)
|
||||
{
|
||||
WriteName(valueName);
|
||||
auto WriteDouble = [value](auto&& writer)
|
||||
{
|
||||
return writer.Double(value);
|
||||
};
|
||||
m_result = m_result && AZStd::visit(WriteDouble, m_writer);
|
||||
m_result = m_result && WriteName(valueName) && m_writer.Double(value);
|
||||
}
|
||||
|
||||
void Visit(AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value)
|
||||
{
|
||||
WriteName(valueName);
|
||||
auto WriteString = [&value](auto&& writer)
|
||||
{
|
||||
return writer.String(value.data(), aznumeric_caster(value.size()));
|
||||
};
|
||||
m_result = m_result && AZStd::visit(WriteString, m_writer);
|
||||
m_result = m_result && WriteName(valueName) && m_writer.String(value.data(), aznumeric_caster(value.size()));
|
||||
}
|
||||
|
||||
bool Finalize()
|
||||
@@ -802,8 +935,46 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
AZ_Assert(false, "m_includeNameStack is expected to be empty. This means that there was an object or array what wasn't closed.");
|
||||
return false;
|
||||
}
|
||||
return m_result;
|
||||
|
||||
// Root the JSON document underneath the JSON pointer prefix if non-empty
|
||||
// Parse non-anchored JSON data into a document and then re-root
|
||||
// that document under the prefix value
|
||||
rapidjson::Document document;
|
||||
document.Parse(m_stringBuffer.GetString(), m_stringBuffer.GetSize());
|
||||
|
||||
rapidjson::Document rootDocument;
|
||||
AZStd::string_view jsonPrefix{ m_dumperSettings.m_jsonPointerPrefix };
|
||||
if (!jsonPrefix.empty())
|
||||
{
|
||||
rapidjson::Pointer rootPointer(jsonPrefix.data(), jsonPrefix.size());
|
||||
rapidjson::SetValueByPointer(rootDocument, rootPointer, document);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootDocument = AZStd::move(document);
|
||||
}
|
||||
|
||||
if (m_dumperSettings.m_prettifyOutput)
|
||||
{
|
||||
rapidjson::PrettyWriter settingsWriter(m_rapidJsonStream);
|
||||
rootDocument.Accept(settingsWriter);
|
||||
}
|
||||
else
|
||||
{
|
||||
rapidjson::Writer settingsWriter(m_rapidJsonStream);
|
||||
rootDocument.Accept(settingsWriter);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
rapidjson::StringBuffer m_stringBuffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> m_writer;
|
||||
|
||||
AZ::IO::RapidJSONStreamWriter m_rapidJsonStream;
|
||||
DumperSettings m_dumperSettings;
|
||||
AZStd::stack<bool> m_includeNameStack;
|
||||
bool m_result{ true };
|
||||
};
|
||||
|
||||
SettingsExportVisitor visitor(stream, dumperSettings);
|
||||
|
||||
@@ -36,27 +36,45 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
inline static constexpr char FilePathsRootKey[] = "/Amazon/AzCore/Runtime/FilePaths";
|
||||
inline static constexpr char FilePathKey_BinaryFolder[] = "/Amazon/AzCore/Runtime/FilePaths/BinaryFolder";
|
||||
inline static constexpr char FilePathKey_EngineRootFolder[] = "/Amazon/AzCore/Runtime/FilePaths/EngineRootFolder";
|
||||
|
||||
//! Stores the absolute path to root of a project's cache. No asset platform in this path, this is where the asset database file lives.
|
||||
//! i.e. <ProjectPath>/Cache
|
||||
inline static constexpr char FilePathKey_CacheProjectRootFolder[] = "/Amazon/AzCore/Runtime/FilePaths/CacheProjectRootFolder";
|
||||
|
||||
//! Stores the absolute path to the cache root for an asset platform. This is the @root@ alias.
|
||||
//! i.e. <ProjectPath>/Cache/<assetplatform>
|
||||
inline static constexpr char FilePathKey_CacheRootFolder[] = "/Amazon/AzCore/Runtime/FilePaths/CacheRootFolder";
|
||||
inline static constexpr char FilePathKey_CacheGameFolder[] = "/Amazon/AzCore/Runtime/FilePaths/CacheGameFolder";
|
||||
inline static constexpr char FilePathKey_SourceGameFolder[] = "/Amazon/AzCore/Runtime/FilePaths/SourceGameFolder";
|
||||
//! Stores the filename of the Game Project Directory which is equivalent to the project name
|
||||
inline static constexpr char FilePathKey_SourceGameName[] = "/Amazon/AzCore/Runtime/FilePaths/SourceGameName";
|
||||
|
||||
//! Stores the absolute path of the Game Project Directory
|
||||
inline static constexpr char FilePathKey_ProjectPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectPath";
|
||||
|
||||
//! Store the absolute path to the Projects "user" directory, which is a transient directory where per user
|
||||
//! project settings can be stored
|
||||
inline static constexpr char FilePathKey_ProjectUserPath[] = "/Amazon/AzCore/Runtime/FilePaths/SourceProjectUserPath";
|
||||
|
||||
//! Development write storage path may be considered temporary or cache storage on some platforms
|
||||
inline static constexpr char FilePathKey_DevWriteStorage[] = "/Amazon/AzCore/Runtime/FilePaths/DevWriteStorage";
|
||||
|
||||
//! Root key for where command line are stored at witin the settings registry
|
||||
//! Root key for where command line are stored at within the settings registry
|
||||
inline static constexpr char CommandLineRootKey[] = "/Amazon/AzCore/Runtime/CommandLine";
|
||||
//! Root key for command line switches(arguments that start with "-" or "--")
|
||||
inline static constexpr char CommandLineSwitchRootKey[] = "/Amazon/AzCore/Runtime/CommandLine/Switches";
|
||||
//! Root key for command line positional arguments
|
||||
inline static constexpr char CommandLineMiscValuesRootKey[] = "/Amazon/AzCore/Runtime/CommandLine/MiscValues";
|
||||
|
||||
//! Examines the Settings Registry for a "/Amazon/CommandLine/Switches/app-root" key
|
||||
//! to use as an override for the Application Root.
|
||||
//! If that key is not found, it then checks the AZ::Utils::GetDefaultAppRootPath and returns that if it is value
|
||||
//! Root key where raw project settings (project.json) file is merged to settings registry
|
||||
inline static constexpr char ProjectSettingsRootKey[] = "/Amazon/Project/Settings";
|
||||
|
||||
//! Root key where raw engine manifest (o3de_manifest.json) file is merged to settings registry
|
||||
inline static constexpr char EngineManifestRootKey[] = "/Amazon/Engine/Manifest";
|
||||
|
||||
//! Root key where raw engine settings (engine.json) file is merged to settings registry
|
||||
inline static constexpr char EngineSettingsRootKey[] = "/Amazon/Engine/Settings";
|
||||
|
||||
//! Examines the Settings Registry for a "${BootstrapSettingsRootKey}/engine_path" key
|
||||
//! to use as an override for the Engine Root.
|
||||
//! Otherwise a directory walk upwards from the executable directory is performed
|
||||
//! to find the boostrap.cfg file which will be used as the app root
|
||||
AZ::IO::FixedMaxPath GetAppRoot(SettingsRegistryInterface* settingsRegistry = nullptr);
|
||||
//! to find the engine.json file which will be used as the engine root
|
||||
//! If it's still not found, attempt to find the project (by similar means) then reconcile the
|
||||
//! engine root by inspecting project.json and the engine manifest file.
|
||||
AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry);
|
||||
AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry);
|
||||
|
||||
//! Query the specializations that will be used when loading the Settings Registry.
|
||||
//! The SpecializationsRootKey is visited to retrieve any specializations stored within that section of that registry
|
||||
@@ -151,16 +169,18 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
void MergeSettingsToRegistry_ProjectRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
const SettingsRegistryInterface::Specializations& specializations, AZStd::vector<char>* scratchBuffer = nullptr);
|
||||
|
||||
//! Adds the development settings added by individual users to the Settings Registry.
|
||||
//! Adds the development settings added by individual users of the project to the Settings Registry.
|
||||
//! Note that this function is only called in development builds and is compiled out in release builds.
|
||||
void MergeSettingsToRegistry_DevRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
void MergeSettingsToRegistry_UserRegistry(SettingsRegistryInterface& registry, const AZStd::string_view platform,
|
||||
const SettingsRegistryInterface::Specializations& specializations, AZStd::vector<char>* scratchBuffer = nullptr);
|
||||
|
||||
//! Adds the settings set through the command line to the Settings Registry. This will also execute any Settings
|
||||
//! Registry related arguments. Note that --set will be run first and all other commands are run afterwards and only
|
||||
//! if executeCommands is true. The following options are supported:
|
||||
//! Registry related arguments. Note that --regset and -regremove will run in the order in which they are parsed
|
||||
//! --regset <arg> Sets a value in the registry. See MergeCommandLineArgument for options for <arg>
|
||||
//! example: --regset "/My/String/Value=String value set"
|
||||
//! --regremove <arg> Removes a value in the registry
|
||||
//! example: --regremove "/My/String/Value"
|
||||
//! only when executeCommands is true are the following options supported:
|
||||
//! --regdump <path> Dumps the content of the key at path and all it's content/children to output.
|
||||
//! example: --regdump /My/Array/With/Objects
|
||||
//! --regdumpall Dumps the entire settings registry to output.
|
||||
@@ -169,7 +189,11 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
|
||||
//! Stores the command line settings into the Setting Registry
|
||||
//! The arguments can be used later anywhere the command line is needed
|
||||
void MergeSettingsToRegistry_StoreCommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine);
|
||||
void StoreCommandLineToRegistry(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine);
|
||||
|
||||
//! Query the command line settings from the Setting Registry and stores them
|
||||
//! into the AZ::CommandLine instance
|
||||
bool GetCommandLineFromRegistry(SettingsRegistryInterface& registry, AZ::CommandLine& commandLine);
|
||||
|
||||
//! Structure for configuring how values should be dumped from the Settings Registry
|
||||
struct DumperSettings
|
||||
@@ -179,14 +203,25 @@ namespace AZ::SettingsRegistryMergeUtils
|
||||
//! Include filter which is used to indicate which paths of the Settings Registry
|
||||
//! should be traversed.
|
||||
//! If the include filter is empty then all paths underneath the JSON pointer path are included
|
||||
//! otherwise the include filter invoked and if it returns true does it proceed with traversal continues down the path
|
||||
//! otherwise the include filter invoked and if it returns true does it proceed with traversal down the path
|
||||
//! The supplied JSON pointer will be a complete path from the root of the registry
|
||||
AZStd::function<bool(AZStd::string_view path)> m_includeFilter;
|
||||
//! JSON pointer prefix to dump all settings underneath
|
||||
//! For example if the prefix is "/Amazon/Settings", then the dumped settings will be placed underneath
|
||||
//! an object at that path
|
||||
//! """
|
||||
//! {
|
||||
//! "Amazon":{
|
||||
//! "Settings":{ <Dumped values> }
|
||||
//! }
|
||||
//! }
|
||||
AZStd::string_view m_jsonPointerPrefix;
|
||||
};
|
||||
|
||||
//! Dumps supplied settings registry from the path specified by key if it exist the the AZ::IO::GenericStream
|
||||
//! key is a JSON pointer path to dumping settings recursively from
|
||||
//! stream is an AZ::IO::GenericStream that supports writing
|
||||
//! dumperSettings are used to determine how to format the dumped output
|
||||
//! @param key is a JSON pointer to recursively dump settings from
|
||||
//! @param stream is an AZ::IO::GenericStream that supports writing
|
||||
//! @param dumperSettings are used to determine how to format the dumped output
|
||||
bool DumpSettingsRegistryToStream(SettingsRegistryInterface& registry, AZStd::string_view key,
|
||||
AZ::IO::GenericStream& stream, const DumperSettings& dumperSettings);
|
||||
|
||||
|
||||
@@ -418,36 +418,37 @@ namespace AZ::StringFunc::Internal
|
||||
return Strip(inout, { &stripCharacter, 1 }, bCaseSensitive, bStripBeginning, bStripEnding);
|
||||
}
|
||||
|
||||
AZStd::string_view LStrip(AZStd::string_view in, AZStd::string_view stripCharacters)
|
||||
{
|
||||
if (size_t pos = in.find_first_not_of(stripCharacters); pos != AZStd::string_view::npos)
|
||||
{
|
||||
return in.substr(pos);
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
AZStd::string_view RStrip(AZStd::string_view in, AZStd::string_view stripCharacters)
|
||||
{
|
||||
if (size_t pos = in.find_last_not_of(stripCharacters); pos != AZStd::string_view::npos)
|
||||
{
|
||||
return in.substr(0, pos < in.size() ? pos + 1 : pos);
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
AZStd::string_view StripEnds(AZStd::string_view in, AZStd::string_view stripCharacters)
|
||||
{
|
||||
return LStrip(RStrip(in, stripCharacters), stripCharacters);
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace StringFunc
|
||||
{
|
||||
AZStd::string_view LStrip(AZStd::string_view in, AZStd::string_view stripCharacters)
|
||||
{
|
||||
if (size_t pos = in.find_first_not_of(stripCharacters); pos != AZStd::string_view::npos)
|
||||
{
|
||||
return in.substr(pos);
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
AZStd::string_view RStrip(AZStd::string_view in, AZStd::string_view stripCharacters)
|
||||
{
|
||||
if (size_t pos = in.find_last_not_of(stripCharacters); pos != AZStd::string_view::npos)
|
||||
{
|
||||
return in.substr(0, pos < in.size() ? pos + 1 : pos);
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
AZStd::string_view StripEnds(AZStd::string_view in, AZStd::string_view stripCharacters)
|
||||
{
|
||||
return LStrip(RStrip(in, stripCharacters), stripCharacters);
|
||||
};
|
||||
|
||||
bool Equal(const char* inA, const char* inB, bool bCaseSensitive /*= false*/, size_t n /*= 0*/)
|
||||
{
|
||||
if (!inA || !inB)
|
||||
@@ -483,6 +484,14 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
}
|
||||
bool Equal(AZStd::string_view inA, AZStd::string_view inB, bool bCaseSensitive)
|
||||
{
|
||||
const size_t maxCharsToCompare = inA.size();
|
||||
|
||||
return inA.size() == inB.size() && (bCaseSensitive
|
||||
? strncmp(inA.data(), inB.data(), maxCharsToCompare) == 0
|
||||
: azstrnicmp(inA.data(), inB.data(), maxCharsToCompare) == 0);
|
||||
}
|
||||
|
||||
bool StartsWith(AZStd::string_view sourceValue, AZStd::string_view prefixValue, bool bCaseSensitive)
|
||||
{
|
||||
@@ -496,9 +505,18 @@ namespace AZ
|
||||
&& Equal(sourceValue.substr(sourceValue.size() - suffixValue.size(), AZStd::string_view::npos).data(), suffixValue.data(), bCaseSensitive, suffixValue.size());
|
||||
}
|
||||
|
||||
size_t Find(const char* in, char c, size_t pos /*= 0*/, bool bReverse /*= false*/, bool bCaseSensitive /*= false*/)
|
||||
bool Contains(AZStd::string_view in, char ch, bool bCaseSensitive)
|
||||
{
|
||||
if (!in)
|
||||
return Find(in, ch, 0, false, bCaseSensitive) != AZStd::string_view::npos;
|
||||
}
|
||||
bool Contains(AZStd::string_view in, AZStd::string_view sv, bool bCaseSensitive)
|
||||
{
|
||||
return Find(in, sv, 0, false, bCaseSensitive) != AZStd::string_view::npos;
|
||||
}
|
||||
|
||||
size_t Find(AZStd::string_view in, char c, size_t pos /*= 0*/, bool bReverse /*= false*/, bool bCaseSensitive /*= false*/)
|
||||
{
|
||||
if (in.empty())
|
||||
{
|
||||
return AZStd::string::npos;
|
||||
}
|
||||
@@ -508,7 +526,7 @@ namespace AZ
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
size_t inLen = strlen(in);
|
||||
size_t inLen = in.size();
|
||||
if (inLen < pos)
|
||||
{
|
||||
return AZStd::string::npos;
|
||||
@@ -557,7 +575,13 @@ namespace AZ
|
||||
|
||||
size_t Find(AZStd::string_view in, AZStd::string_view s, size_t offset /*= 0*/, bool bReverse /*= false*/, bool bCaseSensitive /*= false*/)
|
||||
{
|
||||
if (in.empty() || s.empty())
|
||||
// Formally an empty string matches at the offset if it is <= to the size of the input string
|
||||
if (s.empty() && offset <= in.size())
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (in.empty())
|
||||
{
|
||||
return AZStd::string::npos;
|
||||
}
|
||||
@@ -773,7 +797,7 @@ namespace AZ
|
||||
bool bIsSpaces = false;
|
||||
if (!bIsEmpty)
|
||||
{
|
||||
AZStd::string_view strippedNextToken = Internal::StripEnds(*nextToken, " ");
|
||||
AZStd::string_view strippedNextToken = StripEnds(*nextToken, " ");
|
||||
bIsSpaces = strippedNextToken.empty();
|
||||
}
|
||||
|
||||
@@ -805,7 +829,7 @@ namespace AZ
|
||||
bool bIsSpaces = false;
|
||||
if (!bIsEmpty)
|
||||
{
|
||||
AZStd::string_view strippedNextToken = Internal::StripEnds(*nextToken, " ");
|
||||
AZStd::string_view strippedNextToken = StripEnds(*nextToken, " ");
|
||||
bIsSpaces = strippedNextToken.empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/IO/Path/Path_fwd.h>
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
@@ -107,6 +108,22 @@ namespace AZ
|
||||
StringFunc::Equal("Hello World", "Hello", true, 3) = true
|
||||
*/
|
||||
bool Equal(const char* inA, const char* inB, bool bCaseSensitive = false, size_t n = 0);
|
||||
bool Equal(AZStd::string_view inA, AZStd::string_view inB, bool bCaseSensitive = false);
|
||||
|
||||
//! Contains
|
||||
/*! Checks if the supplied character or string is contained within the @in parameter
|
||||
*
|
||||
Example: Case Insensitive contains finds character
|
||||
StringFunc::Contains("Hello", 'L') == true
|
||||
Example: Case Sensitive contains finds character
|
||||
StringFunc::Contains("Hello", 'l', true) = true
|
||||
Example: Case Insensitive contains does not find string
|
||||
StringFunc::Contains("Well Hello", "Mello") == false
|
||||
Example: Case Sensitive contains does not find character
|
||||
StringFunc::Contains("HeLlo", 'h', true) == false
|
||||
*/
|
||||
bool Contains(AZStd::string_view in, char ch, bool bCaseSensitive = false);
|
||||
bool Contains(AZStd::string_view in, AZStd::string_view sv, bool bCaseSensitive = false);
|
||||
|
||||
//! Find
|
||||
/*! Find for non AZStd::strings. Ease of use to find the first or last occurrence of a character or substring in a c-string with case sensitivity.
|
||||
@@ -119,7 +136,7 @@ namespace AZ
|
||||
Example: Case Sensitive find first occurrence of substring "Hello" a in a c-string
|
||||
StringFunc::Find("Well Hello", "Hello", false, true) == 5
|
||||
*/
|
||||
size_t Find(const char* in, char c, size_t pos = 0, bool bReverse = false, bool bCaseSensitive = false);
|
||||
size_t Find(AZStd::string_view in, char c, size_t pos = 0, bool bReverse = false, bool bCaseSensitive = false);
|
||||
size_t Find(AZStd::string_view in, AZStd::string_view str, size_t pos = 0, bool bReverse = false, bool bCaseSensitive = false);
|
||||
|
||||
//! First and Last Character
|
||||
@@ -196,6 +213,33 @@ namespace AZ
|
||||
*/
|
||||
AZStd::string& TrimWhiteSpace(AZStd::string& value, bool leading, bool trailing);
|
||||
|
||||
//! LStrip
|
||||
/*! Strips leading characters in the stripCharacters set
|
||||
* Example
|
||||
* Example: Case Insensitive Strip leading 'a' characters
|
||||
* StringFunc::LStrip(s = "Abracadabra", 'a'); s == "bracadabra"
|
||||
* Example: Case Sensitive Strip leading 'a' characters
|
||||
* StringFunc::LStrip(s = "Abracadabra", 'a'); s == "Abracadabra"
|
||||
*/
|
||||
//! RStrip
|
||||
/*! Strips trailing characters in the stripCharacters set
|
||||
* Example
|
||||
* Example: Case Insensitive Strip trailing 'a' characters
|
||||
* StringFunc::RStrip(s = "AbracadabrA", 'a'); s == "Abracadabr"
|
||||
* Example: Case Sensitive Strip trailing 'a' characters
|
||||
* StringFunc::RStrip(s = "AbracadabrA", 'a'); s == "AbracadabrA"
|
||||
*/
|
||||
//! StripEnds
|
||||
/*! Strips leading and trailing characters in the stripCharacters set
|
||||
Example: Case Insensitive Strip all 'a' characters
|
||||
StringFunc::StripEnds(s = "Abracadabra", 'a'); s == "bracadabr"
|
||||
Example: Case Sensitive Strip all 'a' characters
|
||||
StringFunc::StripEnds(s = "Abracadabra", 'a'); s == "Abracadabr"
|
||||
*/
|
||||
AZStd::string_view LStrip(AZStd::string_view in, AZStd::string_view stripCharacters = " ");
|
||||
AZStd::string_view RStrip(AZStd::string_view in, AZStd::string_view stripCharacters = " ");
|
||||
AZStd::string_view StripEnds(AZStd::string_view in, AZStd::string_view stripCharacters = " ");
|
||||
|
||||
//! Strip
|
||||
/*! Strip away the leading, trailing or all character(s) or substring(s) in a AZStd::string with
|
||||
*! case sensitivity.
|
||||
@@ -669,8 +713,7 @@ namespace AZ
|
||||
*/
|
||||
namespace Path
|
||||
{
|
||||
inline constexpr size_t MaxPathLength = 1024;
|
||||
using FixedString = AZStd::fixed_string<MaxPathLength>;
|
||||
using FixedString = AZ::IO::FixedMaxPathString;
|
||||
//! Normalize
|
||||
/*! Normalizes a path and returns returns StringFunc::Path::IsValid()
|
||||
*! strips all AZ_FILESYSTEM_INVALID_CHARACTERS
|
||||
@@ -791,7 +834,7 @@ namespace AZ
|
||||
|
||||
//! StripFullName
|
||||
/*! gets rid of the full file name if it has one, returns if it removed one or not
|
||||
*! EX: StringFunc::Path::StripFullName(a="C:\\p4\\game\\info\\some.file") == true; a=="C:\\p4\\game\\info\\"
|
||||
*! EX: StringFunc::Path::StripFullName(a="C:\\p4\\game\\info\\some.file") == true; a=="C:\\p4\\game\\info"
|
||||
*/
|
||||
void StripFullName(AZStd::string& out);
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace UnitTest
|
||||
MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
|
||||
MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
|
||||
MOCK_CONST_METHOD0(GetAppRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetEngineRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace AZ
|
||||
MOCK_CONST_METHOD2(ConvertToAlias, bool(AZ::IO::FixedMaxPath& aliasPath, const AZ::IO::PathView& path));
|
||||
MOCK_CONST_METHOD3(ResolvePath, bool(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize));
|
||||
MOCK_CONST_METHOD2(ResolvePath, bool(AZ::IO::FixedMaxPath& resolvedPath, const AZ::IO::PathView& path));
|
||||
MOCK_CONST_METHOD2(ReplaceAlias, bool(AZ::IO::FixedMaxPath& replacedAliasPath, const AZ::IO::PathView& path));
|
||||
MOCK_CONST_METHOD3(GetFilename, bool(HandleType fileHandle, char* filename, AZ::u64 filenameSize));
|
||||
using FileIOBase::ConvertToAlias;
|
||||
using FileIOBase::ResolvePath;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
|
||||
namespace AZ::Utils
|
||||
@@ -40,6 +42,47 @@ namespace AZ::Utils
|
||||
return result.m_pathStored;
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPathString GetEnginePath()
|
||||
{
|
||||
if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr)
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString settingsValue;
|
||||
if (registry->Get(settingsValue, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
|
||||
{
|
||||
return AZ::IO::FixedMaxPathString{settingsValue};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPathString GetProjectPath()
|
||||
{
|
||||
if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr)
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString settingsValue;
|
||||
if (registry->Get(settingsValue, AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath))
|
||||
{
|
||||
return AZ::IO::FixedMaxPathString{settingsValue};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString GetProjectName()
|
||||
{
|
||||
if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr)
|
||||
{
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectNameKey{ AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey };
|
||||
projectNameKey += "/project_name";
|
||||
AZ::SettingsRegistryInterface::FixedValueString settingsValue;
|
||||
if (registry->Get(settingsValue, projectNameKey))
|
||||
{
|
||||
return settingsValue;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath)
|
||||
{
|
||||
AZ::IO::FixedMaxPath filePathFixed = filePath; // Because FileIOStream requires a null-terminated string
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
@@ -24,9 +26,6 @@ namespace AZ
|
||||
{
|
||||
namespace Utils
|
||||
{
|
||||
// Common cross platform Utils go here
|
||||
inline constexpr size_t MaxPathLength = 1024;
|
||||
|
||||
//! Protects from allocating too much memory. The choice of a 1MB threshold is arbitrary.
|
||||
//! If you need to work with larger files, please use AZ::IO directly instead of these utility functions.
|
||||
inline constexpr size_t DefaultMaxFileSize = 1024 * 1024;
|
||||
@@ -77,10 +76,22 @@ namespace AZ
|
||||
//! @returns a result object that indicates if the executable directory was able to be stored within the buffer
|
||||
ExecutablePathResult GetExecutableDirectory(char* exeStorageBuffer, size_t exeStorageSize);
|
||||
|
||||
//! Retrieves the full path to the engine from settings registry
|
||||
AZ::IO::FixedMaxPathString GetEnginePath();
|
||||
|
||||
//! Retrieves the full path to the project from settings registry
|
||||
AZ::IO::FixedMaxPathString GetProjectPath();
|
||||
|
||||
//! Retrieves the project name from the settings registry
|
||||
AZ::SettingsRegistryInterface::FixedValueString GetProjectName();
|
||||
|
||||
//! Retrieves the full path where the manifest file lives, i.e. "<userhome>/.o3de/o3de_manifest.json"
|
||||
AZ::IO::FixedMaxPathString GetEngineManifestPath();
|
||||
|
||||
//! Retrieves the App root path to use on the current platform
|
||||
//! If the optional is not engaged the AppRootPath should be calculated based
|
||||
//! on the location of the bootstrap.cfg file
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath();
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath();
|
||||
|
||||
//! Retrieves the development write storage path to use on the current platform, may be considered
|
||||
//! temporary or cache storage
|
||||
@@ -88,7 +99,7 @@ namespace AZ
|
||||
|
||||
// Attempts the supplied path to an absolute path.
|
||||
//! Returns nullopt if path cannot be converted to an absolute path
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path);
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path);
|
||||
|
||||
//! Save a string to a file. Otherwise returns a failure with error message.
|
||||
AZ::Outcome<void, AZStd::string> WriteFile(AZStd::string_view content, AZStd::string_view filePath);
|
||||
|
||||
@@ -249,6 +249,11 @@ namespace AZStd
|
||||
|
||||
constexpr auto swap(basic_fixed_string& rhs) -> void;
|
||||
|
||||
// C++23 contains
|
||||
constexpr auto contains(const basic_fixed_string& other) const -> bool;
|
||||
constexpr auto contains(Element ch) const -> bool;
|
||||
constexpr auto contains(const_pointer s) const -> bool;
|
||||
|
||||
constexpr auto find(const basic_fixed_string& rhs, size_type offset = 0) const -> size_type;
|
||||
constexpr auto find(const_pointer ptr, size_type offset, size_type count) const -> size_type;
|
||||
constexpr auto find(const_pointer ptr, size_type offset = 0) const -> size_type;
|
||||
|
||||
@@ -1072,6 +1072,23 @@ namespace AZStd
|
||||
Traits::assign(rhs.m_buffer[rhs.m_size], Element{ 0 });
|
||||
}
|
||||
|
||||
// C++23 contains
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::contains(const basic_fixed_string& other) const -> bool
|
||||
{
|
||||
return find(other) != npos;
|
||||
}
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::contains(value_type c) const -> bool
|
||||
{
|
||||
return find(c) != npos;
|
||||
}
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::contains(const_pointer s) const -> bool
|
||||
{
|
||||
return find(s) != npos;
|
||||
}
|
||||
|
||||
template<class Element, size_t MaxElementCount, class Traits>
|
||||
inline constexpr auto basic_fixed_string<Element, MaxElementCount, Traits>::find(const basic_fixed_string& rhs, size_type offset) const -> size_type
|
||||
{
|
||||
|
||||
@@ -961,6 +961,22 @@ namespace AZStd
|
||||
}
|
||||
}
|
||||
|
||||
// C++23 contains
|
||||
bool contains(const basic_string& other) const
|
||||
{
|
||||
return find(other) != npos;
|
||||
}
|
||||
|
||||
bool contains(value_type c) const
|
||||
{
|
||||
return find(c) != npos;
|
||||
}
|
||||
|
||||
bool contains(const_pointer s) const
|
||||
{
|
||||
return find(s) != npos;
|
||||
}
|
||||
|
||||
inline size_type find(const this_type& rhs, size_type offset = 0) const
|
||||
{
|
||||
const_pointer rhsData = SSO_BUF_SIZE <= rhs.m_capacity ? rhs.m_data : rhs.m_buffer;
|
||||
|
||||
@@ -669,6 +669,22 @@ namespace AZStd
|
||||
return ends_with(basic_string_view(suffix));
|
||||
}
|
||||
|
||||
// C++23 contains
|
||||
constexpr bool contains(basic_string_view other) const
|
||||
{
|
||||
return find(other) != npos;
|
||||
}
|
||||
|
||||
constexpr bool contains(value_type c) const
|
||||
{
|
||||
return find(c) != npos;
|
||||
}
|
||||
|
||||
constexpr bool contains(const_pointer s) const
|
||||
{
|
||||
return find(s) != npos;
|
||||
}
|
||||
|
||||
// find
|
||||
constexpr size_type find(basic_string_view other, size_type pos = 0) const
|
||||
{
|
||||
|
||||
@@ -52,10 +52,10 @@ namespace AZ
|
||||
// in non-release builds.
|
||||
// If a bootstrap.cfg file is not found in the public storage, it is then searched for
|
||||
// within the APK itself
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
|
||||
{
|
||||
const char* appRoot = AZ::Android::Utils::FindAssetsDirectory();
|
||||
return appRoot ? AZStd::make_optional<AZStd::fixed_string<MaxPathLength>>(appRoot) : AZStd::nullopt;
|
||||
return appRoot ? AZStd::make_optional<AZ::IO::FixedMaxPathString>(appRoot) : AZStd::nullopt;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDevWriteStoragePath()
|
||||
@@ -64,10 +64,10 @@ namespace AZ
|
||||
return writeStorage ? AZStd::make_optional<AZ::IO::FixedMaxPathString>(writeStorage) : AZStd::nullopt;
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path)
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path)
|
||||
{
|
||||
AZStd::fixed_string<MaxPathLength> absolutePath;
|
||||
AZStd::fixed_string<MaxPathLength> srcPath{ path };
|
||||
AZ::IO::FixedMaxPathString absolutePath;
|
||||
AZ::IO::FixedMaxPathString srcPath{ path };
|
||||
if (AZ::Android::Utils::IsApkPath(srcPath.c_str()))
|
||||
{
|
||||
return srcPath;
|
||||
|
||||
@@ -64,6 +64,7 @@ set(FILES
|
||||
AzCore/Socket/AzSocket_Platform.h
|
||||
../Common/UnixLike/AzCore/std/time_UnixLike.cpp
|
||||
AzCore/Utils/Utils_Android.cpp
|
||||
../Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp
|
||||
../../AzCore/Android/AndroidEnv.cpp
|
||||
../../AzCore/Android/AndroidEnv.h
|
||||
../../AzCore/Android/APKFileHandler.cpp
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
namespace AZ::Utils
|
||||
{
|
||||
AZ::IO::FixedMaxPathString GetEngineManifestPath()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace AZ::Utils
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -25,10 +25,25 @@ namespace AZ
|
||||
|
||||
void NativeErrorMessageBox(const char*, const char*) {}
|
||||
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path)
|
||||
AZ::IO::FixedMaxPathString GetEngineManifestPath()
|
||||
{
|
||||
AZStd::fixed_string<MaxPathLength> absolutePath;
|
||||
AZStd::fixed_string<MaxPathLength> srcPath{ path };
|
||||
if (const char* homePath = std::getenv("HOME"); homePath != nullptr)
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{homePath};
|
||||
if (!path.empty())
|
||||
{
|
||||
path /= ".o3de";
|
||||
path /= "o3de_manifest.json";
|
||||
}
|
||||
return path.Native();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path)
|
||||
{
|
||||
AZ::IO::FixedMaxPathString absolutePath;
|
||||
AZ::IO::FixedMaxPathString srcPath{ path };
|
||||
|
||||
if (char* result = realpath(srcPath.c_str(), absolutePath.data()); result)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace AZ
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
|
||||
{
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
@@ -57,10 +57,10 @@ namespace AZ
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> ConvertToAbsolutePath(AZStd::string_view path)
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> ConvertToAbsolutePath(AZStd::string_view path)
|
||||
{
|
||||
AZStd::fixed_string<MaxPathLength> absolutePath;
|
||||
AZStd::fixed_string<MaxPathLength> srcPath{ path };
|
||||
AZ::IO::FixedMaxPathString absolutePath;
|
||||
AZ::IO::FixedMaxPathString srcPath{ path };
|
||||
char* result = _fullpath(absolutePath.data(), srcPath.c_str(), absolutePath.capacity());
|
||||
// Force update of the fixed_string size() value
|
||||
absolutePath.resize_no_construct(AZStd::char_traits<char>::length(absolutePath.data()));
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace AZ
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
|
||||
{
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace AZ::Utils
|
||||
{
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
|
||||
{
|
||||
return AZStd::nullopt;
|
||||
}
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ namespace AZ::IO
|
||||
hardwareInfo.m_profile = driveList.size() == 1 ? driveList.front().m_profile : "Generic";
|
||||
hardwareInfo.m_platformData = AZStd::make_any<DriveList>(AZStd::move(driveList));
|
||||
|
||||
return true;
|
||||
return !driveList.empty();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -15,13 +15,27 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace AZ
|
||||
namespace AZ::Utils
|
||||
{
|
||||
namespace Utils
|
||||
void NativeErrorMessageBox(const char* title, const char* message)
|
||||
{
|
||||
void NativeErrorMessageBox(const char* title, const char* message)
|
||||
::MessageBox(0, message, title, MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPathString GetEngineManifestPath()
|
||||
{
|
||||
char userProfileBuffer[AZ::IO::MaxPathLength] = {0};
|
||||
size_t variableSize = 0;
|
||||
auto err = getenv_s(&variableSize, userProfileBuffer, AZ::IO::MaxPathLength, "USERPROFILE");
|
||||
if (!err)
|
||||
{
|
||||
::MessageBox(0, message, title, MB_OK | MB_ICONERROR);
|
||||
AZ::IO::FixedMaxPath path{userProfileBuffer};
|
||||
path /= ".o3de";
|
||||
path /= "o3de_manifest.json";
|
||||
return path.Native();
|
||||
}
|
||||
} // namespace Utils
|
||||
} // namespace AZ
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace AZ::Utils
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
|
||||
namespace AZ::Utils
|
||||
{
|
||||
AZStd::optional<AZStd::fixed_string<MaxPathLength>> GetDefaultAppRootPath()
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDefaultAppRootPath()
|
||||
{
|
||||
const char* pathToResources = [[[NSBundle mainBundle] resourcePath] UTF8String];
|
||||
return AZStd::fixed_string<MaxPathLength>::format("%s/assets", pathToResources);
|
||||
return AZ::IO::FixedMaxPathString::format("%s/assets", pathToResources);
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> GetDevWriteStoragePath()
|
||||
|
||||
@@ -70,4 +70,5 @@ set(FILES
|
||||
AzCore/Utils/Utils_iOS.mm
|
||||
../Common/Apple/AzCore/Utils/Utils_Apple.cpp
|
||||
../Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp
|
||||
../Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp
|
||||
)
|
||||
|
||||
@@ -2391,6 +2391,27 @@ namespace UnitTest
|
||||
EXPECT_STREQ("AB BA", eraseIfTest.c_str());
|
||||
}
|
||||
|
||||
template <typename StringType>
|
||||
class ImmutableStringFunctionsFixture
|
||||
: public ScopedAllocatorSetupFixture
|
||||
{};
|
||||
using StringTypesToTest = ::testing::Types<AZStd::string_view, AZStd::string, AZStd::fixed_string<1024>>;
|
||||
TYPED_TEST_CASE(ImmutableStringFunctionsFixture, StringTypesToTest);
|
||||
|
||||
TYPED_TEST(ImmutableStringFunctionsFixture, Contains_Succeeds)
|
||||
{
|
||||
TypeParam testStrValue{ R"(C:\o3de\Assets\Materials\texture\image.png)" };
|
||||
EXPECT_TRUE(testStrValue.contains("Materials"));
|
||||
EXPECT_FALSE(testStrValue.contains("Animations"));
|
||||
EXPECT_TRUE(testStrValue.contains('o'));
|
||||
EXPECT_FALSE(testStrValue.contains('Q'));
|
||||
|
||||
TypeParam typeParamEntry{ R"(texture)" };
|
||||
TypeParam typeParamNoEntry{ R"(physics)" };
|
||||
EXPECT_TRUE(testStrValue.contains(typeParamEntry));
|
||||
EXPECT_FALSE(testStrValue.contains(typeParamNoEntry));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* GetFormatString()
|
||||
{
|
||||
|
||||
@@ -54,8 +54,9 @@ namespace UnitTest
|
||||
AZ::SerializeContext* GetSerializeContext() override { return nullptr; }
|
||||
AZ::BehaviorContext* GetBehaviorContext() override { return m_behaviorContext; }
|
||||
AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
|
||||
@@ -416,6 +416,11 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReplaceAlias(AZ::IO::FixedMaxPath&, const AZ::IO::PathView&) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetAlias(const char*, const char*) override
|
||||
{
|
||||
}
|
||||
|
||||
@@ -58,22 +58,22 @@ namespace UnitTest
|
||||
|
||||
TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnRelativePath_Succeeds)
|
||||
{
|
||||
AZStd::optional<AZStd::fixed_string<AZ::Utils::MaxPathLength>> absolutePath = AZ::Utils::ConvertToAbsolutePath("./");
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> absolutePath = AZ::Utils::ConvertToAbsolutePath("./");
|
||||
EXPECT_TRUE(absolutePath);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnAbsolutePath_Succeeds)
|
||||
{
|
||||
char executableDirectory[AZ::Utils::MaxPathLength];
|
||||
AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZ_ARRAY_SIZE(executableDirectory));
|
||||
char executableDirectory[AZ::IO::MaxPathLength];
|
||||
AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZStd::size(executableDirectory));
|
||||
EXPECT_EQ(AZ::Utils::ExecutablePathResult::Success, result);
|
||||
AZStd::optional<AZStd::fixed_string<AZ::Utils::MaxPathLength>> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory);
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory);
|
||||
ASSERT_TRUE(absolutePath);
|
||||
|
||||
// Note that ConvertToAbsolutePath will perform a realpath on the result. The result of AZ::Utils::GetExecutableDirectory
|
||||
// uses AZ::Android::AndroidEnv::Get()->GetAppPrivateStoragePath() which will retrieve the storage path, but that path could
|
||||
// be symlinked, so we need to perform a real path on it before comparison
|
||||
char realExecutableDirectory[AZ::Utils::MaxPathLength];
|
||||
char realExecutableDirectory[AZ::IO::MaxPathLength];
|
||||
ASSERT_TRUE(realpath(executableDirectory, realExecutableDirectory));
|
||||
|
||||
EXPECT_STRCASEEQ(realExecutableDirectory, absolutePath->c_str());
|
||||
|
||||
@@ -27,16 +27,16 @@ namespace UnitTest
|
||||
|
||||
TEST_F(UtilsUnixLikeTestFixture, ConvertToAbsolutePath_OnRelativePath_Succeeds)
|
||||
{
|
||||
AZStd::optional<AZStd::fixed_string<AZ::Utils::MaxPathLength>> absolutePath = AZ::Utils::ConvertToAbsolutePath("./");
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> absolutePath = AZ::Utils::ConvertToAbsolutePath("./");
|
||||
EXPECT_TRUE(absolutePath);
|
||||
}
|
||||
|
||||
TEST_F(UtilsUnixLikeTestFixture, ConvertToAbsolutePath_OnAbsolutePath_Succeeds)
|
||||
{
|
||||
char executableDirectory[AZ::Utils::MaxPathLength];
|
||||
char executableDirectory[AZ::IO::MaxPathLength];
|
||||
AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZ_ARRAY_SIZE(executableDirectory));
|
||||
EXPECT_EQ(AZ::Utils::ExecutablePathResult::Success, result);
|
||||
AZStd::optional<AZStd::fixed_string<AZ::Utils::MaxPathLength>> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory);
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory);
|
||||
ASSERT_TRUE(absolutePath);
|
||||
EXPECT_STRCASEEQ(executableDirectory, absolutePath->c_str());
|
||||
}
|
||||
|
||||
@@ -53,23 +53,23 @@ namespace UnitTest
|
||||
|
||||
TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnInvalidPath_Fails)
|
||||
{
|
||||
AZStd::fixed_string<AZ::Utils::MaxPathLength> invalidPath{ "Z:\\" };
|
||||
invalidPath.append(AZ::Utils::MaxPathLength - invalidPath.size(), '@');
|
||||
AZ::IO::FixedMaxPathString invalidPath{ "Z:\\" };
|
||||
invalidPath.append(invalidPath.max_size() - invalidPath.size(), '@');
|
||||
EXPECT_FALSE(AZ::Utils::ConvertToAbsolutePath(invalidPath));
|
||||
}
|
||||
|
||||
TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnRelativePath_Succeeds)
|
||||
{
|
||||
AZStd::optional<AZStd::fixed_string<AZ::Utils::MaxPathLength>> absolutePath = AZ::Utils::ConvertToAbsolutePath("./");
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> absolutePath = AZ::Utils::ConvertToAbsolutePath("./");
|
||||
EXPECT_TRUE(absolutePath);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTestFixture, ConvertToAbsolutePath_OnAbsolutePath_Succeeds)
|
||||
{
|
||||
char executableDirectory[AZ::Utils::MaxPathLength];
|
||||
char executableDirectory[AZ::IO::MaxPathLength];
|
||||
AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(executableDirectory, AZ_ARRAY_SIZE(executableDirectory));
|
||||
EXPECT_EQ(AZ::Utils::ExecutablePathResult::Success, result);
|
||||
AZStd::optional<AZStd::fixed_string<AZ::Utils::MaxPathLength>> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory);
|
||||
AZStd::optional<AZ::IO::FixedMaxPathString> absolutePath = AZ::Utils::ConvertToAbsolutePath(executableDirectory);
|
||||
ASSERT_TRUE(absolutePath);
|
||||
EXPECT_STRCASEEQ(executableDirectory, absolutePath->c_str());
|
||||
}
|
||||
|
||||
@@ -1237,8 +1237,9 @@ namespace UnitTest
|
||||
SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); }
|
||||
BehaviorContext* GetBehaviorContext() override { return nullptr; }
|
||||
JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Vector4.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/Serialization/Json/DoubleSerializer.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <Tests/Serialization/Json/BaseJsonSerializerFixture.h>
|
||||
@@ -142,6 +143,13 @@ namespace JsonSerializationTests
|
||||
constexpr static size_t ElementCount = 4;
|
||||
};
|
||||
|
||||
struct QuaternionDescriptor
|
||||
{
|
||||
using VectorType = AZ::Quaternion;
|
||||
using Serializer = AZ::JsonQuaternionSerializer;
|
||||
constexpr static size_t ElementCount = 4;
|
||||
};
|
||||
|
||||
using JsonMathVectorSerializerTypes = ::testing::Types <
|
||||
Vector2Descriptor, Vector3Descriptor, Vector4Descriptor>;
|
||||
TYPED_TEST_CASE(JsonMathVectorSerializerTests, JsonMathVectorSerializerTypes);
|
||||
|
||||
@@ -25,9 +25,11 @@ namespace UnitTest
|
||||
AZ::CommandLine cmd;
|
||||
EXPECT_FALSE(cmd.HasSwitch(""));
|
||||
EXPECT_EQ(cmd.GetNumSwitchValues("haha"), 0);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
EXPECT_EQ(cmd.GetSwitchValue("haha", 0), AZStd::string());
|
||||
EXPECT_EQ(cmd.GetNumMiscValues(), 0);
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
|
||||
EXPECT_EQ(cmd.GetNumMiscValues(), 0);
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
EXPECT_EQ(cmd.GetMiscValue(1), AZStd::string());
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
@@ -379,7 +381,6 @@ namespace UnitTest
|
||||
{
|
||||
AZ::CommandLine origCommandLine{ "-/" };
|
||||
|
||||
|
||||
const char* argValues[] =
|
||||
{
|
||||
"programname.exe", "/gamefolder", "/RemoteIp", "10.0.0.1", "-ScanFolders", R"(\a\b\c,\d\e\f)", "Foo", "Bat"
|
||||
@@ -396,20 +397,21 @@ namespace UnitTest
|
||||
for (const auto& commandLine : commandLines)
|
||||
{
|
||||
EXPECT_TRUE(commandLine.HasSwitch("gamefolder"));
|
||||
EXPECT_EQ(0, commandLine.GetNumSwitchValues("gamefolder"));
|
||||
EXPECT_EQ(1, commandLine.GetNumSwitchValues("gamefolder"));
|
||||
EXPECT_STREQ("", commandLine.GetSwitchValue("gamefolder", 0).c_str());
|
||||
|
||||
EXPECT_TRUE(commandLine.HasSwitch("remoteip"));
|
||||
EXPECT_EQ(1, commandLine.GetNumSwitchValues("remoteip"));
|
||||
EXPECT_EQ("10.0.0.1", commandLine.GetSwitchValue("remoteip", 0));
|
||||
EXPECT_STREQ("10.0.0.1", commandLine.GetSwitchValue("remoteip", 0).c_str());
|
||||
|
||||
EXPECT_TRUE(commandLine.HasSwitch("scanfolders"));
|
||||
EXPECT_EQ(2, commandLine.GetNumSwitchValues("scanfolders"));
|
||||
EXPECT_EQ(R"(\a\b\c)", commandLine.GetSwitchValue("scanfolders", 0));
|
||||
EXPECT_EQ(R"(\d\e\f)", commandLine.GetSwitchValue("scanfolders", 1));
|
||||
EXPECT_STREQ(R"(\a\b\c)", commandLine.GetSwitchValue("scanfolders", 0).c_str());
|
||||
EXPECT_STREQ(R"(\d\e\f)", commandLine.GetSwitchValue("scanfolders", 1).c_str());
|
||||
|
||||
EXPECT_EQ(2, commandLine.GetNumMiscValues());
|
||||
EXPECT_EQ("Foo", commandLine.GetMiscValue(0));
|
||||
EXPECT_EQ("Bat", commandLine.GetMiscValue(1));
|
||||
EXPECT_STREQ("Foo", commandLine.GetMiscValue(0).c_str());
|
||||
EXPECT_STREQ("Bat", commandLine.GetMiscValue(1).c_str());
|
||||
}
|
||||
}
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -82,23 +82,25 @@ namespace SettingsRegistryMergeUtilsTests
|
||||
DumpSettings,
|
||||
SettingsRegistryMergeUtilsParamFixture,
|
||||
::testing::Values(
|
||||
DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonPatch,
|
||||
R"( [
|
||||
{ "op": "add", "path": "/Test", "value": { "Object": {} } },
|
||||
|
||||
{ "op": "add", "path": "/Test/Object/NullType", "value": null },
|
||||
{ "op": "add", "path": "/Test/Object/TrueType", "value": true },
|
||||
{ "op": "add", "path": "/Test/Object/FalseType", "value": false },
|
||||
{ "op": "add", "path": "/Test/Object/IntType", "value": -42 },
|
||||
{ "op": "add", "path": "/Test/Object/UIntType", "value": 42 },
|
||||
{ "op": "add", "path": "/Test/Object/DoubleType", "value": 42.0 },
|
||||
{ "op": "add", "path": "/Test/Object/StringType", "value": "Hello world" },
|
||||
|
||||
{ "op": "add", "path": "/Test/Array", "value": [ null, true, false, -42, 42, 42.0, "Hello world" ] }
|
||||
])",
|
||||
DumpSettingsRegistryParams
|
||||
{
|
||||
AZ::SettingsRegistryInterface::Format::JsonPatch,
|
||||
R"([)" "\n"
|
||||
R"( { "op": "add", "path": "/Test", "value": { "Object": {} } },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/NullType", "value": null },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/TrueType", "value": true },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/FalseType", "value": false },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/IntType", "value": -42 },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/UIntType", "value": 42 },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/DoubleType", "value": 42.0 },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Object/StringType", "value": "Hello world" },)" "\n"
|
||||
R"( { "op": "add", "path": "/Test/Array", "value": [ null, true, false, -42, 42, 42.0, "Hello world" ] })" "\n"
|
||||
R"(])" "\n",
|
||||
R"({"Test":{"Object":{"NullType":null,"TrueType":true,"FalseType":false,"IntType":-42,"UIntType":42)"
|
||||
R"(,"DoubleType":42.0,"StringType":"Hello world"},"Array":[null,true,false,-42,42,42.0,"Hello world"]}})",
|
||||
{ false,
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings
|
||||
{
|
||||
false,
|
||||
[](AZStd::string_view path)
|
||||
{
|
||||
AZStd::string_view prefixPath("/Test");
|
||||
@@ -106,26 +108,30 @@ namespace SettingsRegistryMergeUtilsTests
|
||||
}
|
||||
}
|
||||
},
|
||||
DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({
|
||||
"Test":
|
||||
{
|
||||
"Array0": [ 142, 188 ],
|
||||
"Array1": [ 242, 288 ],
|
||||
"Array2": [ 342, 388 ]
|
||||
}
|
||||
})",
|
||||
DumpSettingsRegistryParams
|
||||
{
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({)" "\n"
|
||||
R"( "Test":)" "\n"
|
||||
R"( {)" "\n"
|
||||
R"( "Array0": [ 142, 188 ], )" "\n"
|
||||
R"( "Array1": [ 242, 288 ], )" "\n"
|
||||
R"( "Array2": [ 342, 388 ] )" "\n"
|
||||
R"( })" "\n"
|
||||
R"(})" "\n",
|
||||
R"({"Test":{"Array0":[142,188],"Array1":[242,288],"Array2":[342,388]}})",
|
||||
{ false,
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings{ false,
|
||||
[](AZStd::string_view path)
|
||||
{
|
||||
AZStd::string_view prefixPath("/Test");
|
||||
return prefixPath.starts_with(path.substr(0, prefixPath.size()));
|
||||
}
|
||||
}
|
||||
},
|
||||
DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({
|
||||
},
|
||||
DumpSettingsRegistryParams
|
||||
{
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({
|
||||
"Test":
|
||||
{
|
||||
"Array0": [ 142, 188 ],
|
||||
@@ -149,23 +155,27 @@ namespace SettingsRegistryMergeUtilsTests
|
||||
R"( ])""\n"
|
||||
R"( })""\n"
|
||||
R"(})",
|
||||
{ true,
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings
|
||||
{
|
||||
true,
|
||||
[](AZStd::string_view path)
|
||||
{
|
||||
AZStd::string_view prefixPath("/Test");
|
||||
return prefixPath.starts_with(path.substr(0, prefixPath.size()));
|
||||
}
|
||||
}
|
||||
},
|
||||
DumpSettingsRegistryParams{ AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({
|
||||
},
|
||||
DumpSettingsRegistryParams
|
||||
{
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({
|
||||
"Test":
|
||||
{
|
||||
"Array0": [ 142, 188 ],
|
||||
"Array1": [ 242, 288 ],
|
||||
"Array2": [ 342, 388 ]
|
||||
}
|
||||
})",
|
||||
})",
|
||||
R"({)""\n"
|
||||
R"( "Array0": [)""\n"
|
||||
R"( 142,)""\n"
|
||||
@@ -180,7 +190,9 @@ namespace SettingsRegistryMergeUtilsTests
|
||||
R"( 388)""\n"
|
||||
R"( ])""\n"
|
||||
R"(})",
|
||||
{ true,
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings
|
||||
{
|
||||
true,
|
||||
[](AZStd::string_view path)
|
||||
{
|
||||
AZStd::string_view prefixPath("/Test");
|
||||
@@ -188,8 +200,19 @@ namespace SettingsRegistryMergeUtilsTests
|
||||
}
|
||||
},
|
||||
"/Test"
|
||||
}
|
||||
)
|
||||
},
|
||||
DumpSettingsRegistryParams{
|
||||
AZ::SettingsRegistryInterface::Format::JsonMergePatch,
|
||||
R"({)" "\n"
|
||||
R"( "Test":)" "\n"
|
||||
R"( {)" "\n"
|
||||
R"( "Array0": [ 142, 188 ])" "\n"
|
||||
R"( })" "\n"
|
||||
R"(})",
|
||||
R"({"Root":{"Path":{"Test":{"Array0":[142,188]}}}})",
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings{ false, {}, "/Root/Path/Test" },
|
||||
"/Test"
|
||||
})
|
||||
);
|
||||
|
||||
//! ConfigFile MergeUtils Test
|
||||
@@ -281,9 +304,13 @@ namespace SettingsRegistryMergeUtilsTests
|
||||
AZ::SettingsRegistryMergeUtils::ConfigParserSettings parserSettings;
|
||||
parserSettings.m_commentPrefixFunc = [](AZStd::string_view line) -> AZStd::string_view
|
||||
{
|
||||
if (line.starts_with("--") || line.starts_with(';') || line.starts_with('#'))
|
||||
constexpr AZStd::string_view commentPrefixes[]{ "--", ";","#" };
|
||||
for (AZStd::string_view commentPrefix : commentPrefixes)
|
||||
{
|
||||
return {};
|
||||
if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos)
|
||||
{
|
||||
return line.substr(0, commentOffset);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
};
|
||||
@@ -330,7 +357,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
-- android, ios, mac, linux, windows, etc...
|
||||
-- or left unprefixed, to set all platforms not specified. The rules apply in the order they're declared
|
||||
|
||||
sys_game_folder=TestProject
|
||||
project_path=TestProject
|
||||
|
||||
-- remote_filesystem - enable Virtual File System (VFS)
|
||||
-- This feature allows a remote instance of the game to run off assets
|
||||
@@ -363,7 +390,7 @@ mac_assets = osx_gl
|
||||
-- Example: 192.168.1.0/24 will allow any address starting with 192.168.1.
|
||||
-- Example: 192.168.0.0/16 will allow any address starting with 192.168.
|
||||
-- Example: 192.168.0.0/8 will allow any address starting with 192.
|
||||
-- white_list =
|
||||
-- allowed_list =
|
||||
|
||||
-- IP address and optionally port of the asset processor.
|
||||
-- Set your PC IP here: (and uncomment the next line)
|
||||
@@ -405,7 +432,7 @@ mac_wait_for_connect=0
|
||||
|
||||
)"
|
||||
, AZStd::fixed_vector<ConfigFileParams::SettingsKeyValuePair, 20>{
|
||||
ConfigFileParams::SettingsKeyValuePair{"/sys_game_folder", AZStd::string_view{"TestProject"}},
|
||||
ConfigFileParams::SettingsKeyValuePair{"/project_path", AZStd::string_view{"TestProject"}},
|
||||
ConfigFileParams::SettingsKeyValuePair{"/remote_filesystem", AZ::s64{0}},
|
||||
ConfigFileParams::SettingsKeyValuePair{"/android_remote_filesystem", AZ::s64{0}},
|
||||
ConfigFileParams::SettingsKeyValuePair{"/ios_remote_filesystem", AZ::s64{0}},
|
||||
@@ -428,7 +455,7 @@ mac_wait_for_connect=0
|
||||
// Parses a fake AssetProcessorPlatformConfig file which contains sections headers
|
||||
// and does not end with a newline
|
||||
ConfigFileParams{ "fake_AssetProcessorPlatformConfig.ini", R"(
|
||||
; ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default.
|
||||
; ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default.
|
||||
|
||||
; PLATFORM DEFINITIONS
|
||||
; [Platform (unique identifier)]
|
||||
@@ -452,7 +479,7 @@ test_asset_processor_tag = test_value
|
||||
tags=tools,renderer,dx12,vulkan
|
||||
|
||||
[Platform es3]
|
||||
tags=android,mobile,renderer,vulkan
|
||||
tags=android,mobile,renderer,vulkan ; With Comments at the end
|
||||
|
||||
[Platform ios]
|
||||
tags=mobile,renderer,metal
|
||||
@@ -489,76 +516,30 @@ tags=tools,renderer,metal)"
|
||||
TEST_F(SettingsRegistryMergeUtilsCommandLineFixture, CommandLineArguments_MergeToSettingsRegistry_Success)
|
||||
{
|
||||
AZ::CommandLine commandLine;
|
||||
commandLine.Parse({ "programname.exe", "--gamefolder", "--RemoteIp", "10.0.0.1", "--ScanFolders", R"(\a\b\c,\d\e\f)", "Foo", "Bat" });
|
||||
commandLine.Parse({ "programname.exe", "--project-path", "--RemoteIp", "10.0.0.1", "--ScanFolders", R"(\a\b\c,\d\e\f)", "Foo", "Bat" });
|
||||
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_StoreCommandLine(*m_registry, commandLine);
|
||||
AZ::SettingsRegistryMergeUtils::StoreCommandLineToRegistry(*m_registry, commandLine);
|
||||
// Clear the CommandLine instance
|
||||
commandLine = {};
|
||||
|
||||
struct CommandLineVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPointer, AZStd::string_view,
|
||||
AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override
|
||||
{
|
||||
if (action == AZ::SettingsRegistryInterface::VisitAction::Begin)
|
||||
{
|
||||
// Strip off the last key of the jsonPointer and check if the path is the command line root switch key
|
||||
// i.e "/../CommandLine/Switches
|
||||
AZStd::optional<AZStd::string_view> optionName = AZ::StringFunc::TokenizeLast(jsonPointer, '/');
|
||||
if (jsonPointer == AZ::SettingsRegistryMergeUtils::CommandLineSwitchRootKey && optionName && !optionName->empty())
|
||||
{
|
||||
// Add a empty mapping of option name to values if it is not in the map already
|
||||
m_optionArguments[*optionName];
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(AZ::SettingsRegistryMergeUtils::GetCommandLineFromRegistry(*m_registry, commandLine));
|
||||
|
||||
return AZ::SettingsRegistryInterface::VisitResponse::Continue;
|
||||
}
|
||||
ASSERT_TRUE(commandLine.HasSwitch("project-path"));
|
||||
EXPECT_EQ(1, commandLine.GetNumSwitchValues("project-path"));
|
||||
EXPECT_STREQ("", commandLine.GetSwitchValue("project-path", 0).c_str());
|
||||
|
||||
void Visit(AZStd::string_view jsonPointer, AZStd::string_view, AZ::SettingsRegistryInterface::Type
|
||||
, AZStd::string_view value) override
|
||||
{
|
||||
// Strip off the last key from the jsonPointer and return that in the option name parameter
|
||||
AZStd::optional<AZStd::string_view> optionName = AZ::StringFunc::TokenizeLast(jsonPointer, '/');
|
||||
if (jsonPointer == AZ::SettingsRegistryMergeUtils::CommandLineMiscValuesRootKey)
|
||||
{
|
||||
m_positionalArguments.push_back(value);
|
||||
}
|
||||
else if (jsonPointer.starts_with(AZ::SettingsRegistryMergeUtils::CommandLineSwitchRootKey) && optionName)
|
||||
{
|
||||
// Option arguments are stored in array indices, underneath the option key
|
||||
// Therefore remove another token from the jsonPointer to retrieve the actual option name
|
||||
if (optionName = AZ::StringFunc::TokenizeLast(jsonPointer, '/'); optionName && !optionName->empty())
|
||||
{
|
||||
// Add an entry for the option with the specified value
|
||||
m_optionArguments[*optionName].push_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(commandLine.HasSwitch("remoteip"));
|
||||
ASSERT_EQ(1, commandLine.GetNumSwitchValues("remoteip"));
|
||||
EXPECT_STREQ("10.0.0.1", commandLine.GetSwitchValue("remoteip", 0).c_str());
|
||||
|
||||
AZ::CommandLine::ParamMap m_optionArguments;
|
||||
AZ::CommandLine::ParamContainer m_positionalArguments;
|
||||
};
|
||||
ASSERT_TRUE(commandLine.HasSwitch("scanfolders"));
|
||||
ASSERT_EQ(2, commandLine.GetNumSwitchValues("scanfolders"));
|
||||
EXPECT_STREQ(R"(\a\b\c)", commandLine.GetSwitchValue("scanfolders", 0).c_str());
|
||||
EXPECT_STREQ(R"(\d\e\f)", commandLine.GetSwitchValue("scanfolders", 1).c_str());
|
||||
|
||||
CommandLineVisitor commandLineVisitor;
|
||||
EXPECT_TRUE(m_registry->Visit(commandLineVisitor, AZ::SettingsRegistryMergeUtils::CommandLineRootKey));
|
||||
EXPECT_EQ(3, commandLineVisitor.m_optionArguments.size());
|
||||
auto optionIter = commandLineVisitor.m_optionArguments.find("gamefolder");
|
||||
ASSERT_NE(commandLineVisitor.m_optionArguments.end(), optionIter);
|
||||
EXPECT_EQ(0, optionIter->second.size());
|
||||
|
||||
optionIter = commandLineVisitor.m_optionArguments.find("remoteip");
|
||||
ASSERT_NE(commandLineVisitor.m_optionArguments.end(), optionIter);
|
||||
ASSERT_EQ(1, optionIter->second.size());
|
||||
EXPECT_STREQ("10.0.0.1", optionIter->second[0].c_str());
|
||||
|
||||
optionIter = commandLineVisitor.m_optionArguments.find("scanfolders");
|
||||
ASSERT_NE(commandLineVisitor.m_optionArguments.end(), optionIter);
|
||||
ASSERT_EQ(2, optionIter->second.size());
|
||||
EXPECT_STREQ(R"(\a\b\c)", optionIter->second[0].c_str());
|
||||
EXPECT_STREQ(R"(\d\e\f)", optionIter->second[1].c_str());
|
||||
|
||||
ASSERT_EQ(2, commandLineVisitor.m_positionalArguments.size());
|
||||
EXPECT_STREQ("Foo", commandLineVisitor.m_positionalArguments[0].c_str());
|
||||
EXPECT_STREQ("Bat", commandLineVisitor.m_positionalArguments[1].c_str());
|
||||
ASSERT_EQ(3, commandLine.GetNumMiscValues());
|
||||
EXPECT_STREQ("programname.exe", commandLine.GetMiscValue(0).c_str());
|
||||
EXPECT_STREQ("Foo", commandLine.GetMiscValue(1).c_str());
|
||||
EXPECT_STREQ("Bat", commandLine.GetMiscValue(2).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,6 +499,38 @@ namespace SettingsRegistryTests
|
||||
EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test/Object/Type"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsRegistryTest, VisitWithVisitor_EndOfPathArguments_MatchesValueNameArgument_ForAllIterations)
|
||||
{
|
||||
// Validate that every invocation of the Traverse and Visit command supplies a 'path' parameter
|
||||
// whose end matches that of the 'valueName' parameter
|
||||
AZStd::string json{
|
||||
R"({
|
||||
"Test":
|
||||
{
|
||||
"Object":{ "Type": "TestString" }
|
||||
}
|
||||
})"
|
||||
};
|
||||
ASSERT_TRUE(this->m_registry->MergeSettings(json.c_str(), AZ::SettingsRegistryInterface::Format::JsonMergePatch));
|
||||
|
||||
struct : public AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view path, AZStd::string_view valueName,
|
||||
AZ::SettingsRegistryInterface::VisitAction, AZ::SettingsRegistryInterface::Type) override
|
||||
{
|
||||
EXPECT_TRUE(path.ends_with(valueName));
|
||||
return AZ::SettingsRegistryInterface::VisitResponse::Continue;
|
||||
}
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type , AZStd::string_view)override
|
||||
{
|
||||
EXPECT_TRUE(path.ends_with(valueName));
|
||||
}
|
||||
} visitor;
|
||||
|
||||
EXPECT_TRUE(this->m_registry->Visit(visitor, ""));
|
||||
EXPECT_TRUE(this->m_registry->Visit(visitor, "/Test"));
|
||||
}
|
||||
|
||||
//
|
||||
// Object
|
||||
//
|
||||
@@ -730,7 +762,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Object", "Object", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Object/NullType", "NullType", SRI::Type::Null, SRI::VisitAction::Value),
|
||||
@@ -752,7 +784,7 @@ namespace SettingsRegistryTests
|
||||
RegistryEntry("/Test/Array/6", "6", SRI::Type::String, SRI::VisitAction::Value),
|
||||
RegistryEntry("/Test/Array", "Array", SRI::Type::Array, SRI::VisitAction::End),
|
||||
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::End)
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End)
|
||||
};
|
||||
|
||||
Visit(expected, "/Test");
|
||||
@@ -778,11 +810,11 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Layer1/Layer2", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Layer1/Layer2", "Layer2", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Layer1/Layer2/Layer3", "Layer3", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Layer1/Layer2/Layer3/StringType", "StringType", SRI::Type::String, SRI::VisitAction::Value),
|
||||
RegistryEntry("/Layer1/Layer2/Layer3", "Layer3", SRI::Type::Object, SRI::VisitAction::End),
|
||||
RegistryEntry("/Layer1/Layer2", "", SRI::Type::Object, SRI::VisitAction::End)
|
||||
RegistryEntry("/Layer1/Layer2", "Layer2", SRI::Type::Object, SRI::VisitAction::End)
|
||||
};
|
||||
|
||||
Visit(expected, "/Layer1/Layer2");
|
||||
@@ -806,9 +838,9 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Object/0/0", "", SRI::Type::Array, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Object/0/0", "0", SRI::Type::Array, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Object/0/0/0", "0", SRI::Type::String, SRI::VisitAction::Value),
|
||||
RegistryEntry("/Object/0/0", "", SRI::Type::Array, SRI::VisitAction::End)
|
||||
RegistryEntry("/Object/0/0", "0", SRI::Type::Array, SRI::VisitAction::End)
|
||||
};
|
||||
|
||||
Visit(expected, "/Object/0/0");
|
||||
@@ -830,7 +862,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
@@ -842,7 +874,7 @@ namespace SettingsRegistryTests
|
||||
RegistryEntry("/Test/Object2/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
RegistryEntry("/Test/Object2", "Object2", SRI::Type::Object, SRI::VisitAction::End),
|
||||
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::End)
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End)
|
||||
};
|
||||
|
||||
Visit(expected, "/Test");
|
||||
@@ -864,7 +896,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
@@ -878,7 +910,7 @@ namespace SettingsRegistryTests
|
||||
RegistryEntry("/Test/Array2/1", "1", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
RegistryEntry("/Test/Array2", "Array2", SRI::Type::Array, SRI::VisitAction::End),
|
||||
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::End)
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::End)
|
||||
};
|
||||
|
||||
Visit(expected, "/Test");
|
||||
@@ -900,7 +932,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
@@ -928,7 +960,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Object0", "Object0", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Object0/Field", "Field", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
@@ -954,7 +986,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
@@ -984,7 +1016,7 @@ namespace SettingsRegistryTests
|
||||
|
||||
AZStd::vector<RegistryEntry> expected =
|
||||
{
|
||||
RegistryEntry("/Test", "", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test", "Test", SRI::Type::Object, SRI::VisitAction::Begin),
|
||||
|
||||
RegistryEntry("/Test/Array0", "Array0", SRI::Type::Array, SRI::VisitAction::Begin),
|
||||
RegistryEntry("/Test/Array0/0", "0", SRI::Type::Integer, SRI::VisitAction::Value),
|
||||
@@ -1700,11 +1732,7 @@ namespace SettingsRegistryTests
|
||||
EXPECT_EQ(AZ::SettingsRegistryInterface::Type::String, m_registry->GetType(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/0/Path"));
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_MERGESETTINGSFOLDER_CONFLICTINGSPECIALIZATIONS
|
||||
TEST_F(SettingsRegistryTest, DISABLED_MergeSettingsFolder_ConflictingSpecializations_ReportsErrorAndReturnsFalse)
|
||||
#else
|
||||
TEST_F(SettingsRegistryTest, MergeSettingsFolder_ConflictingSpecializations_ReportsErrorAndReturnsFalse)
|
||||
#endif // AZ_TRAIT_DISABLE_FAILED_MERGESETTINGSFOLDER_CONFLICTINGSPECIALIZATIONS
|
||||
{
|
||||
CreateTestFile("Memory.test.editor.setreg", "{}");
|
||||
CreateTestFile("Memory.editor.test.setreg", "{}");
|
||||
|
||||
@@ -22,6 +22,35 @@ namespace AZ
|
||||
|
||||
using StringFuncTest = AllocatorsFixture;
|
||||
|
||||
TEST_F(StringFuncTest, Equal_CaseSensitive_OnNonNullTerminatedStringView_Success)
|
||||
{
|
||||
constexpr AZStd::string_view testString1 = "Hello World IceCream";
|
||||
constexpr AZStd::string_view testString2 = "IceCream World Hello";
|
||||
constexpr bool caseSensitive = true;
|
||||
EXPECT_TRUE(AZ::StringFunc::Equal(testString1.substr(6,5), testString2.substr(9,5), caseSensitive));
|
||||
}
|
||||
TEST_F(StringFuncTest, Equal_CaseInsensitive_OnNonNullTerminatedStringView_Success)
|
||||
{
|
||||
constexpr AZStd::string_view testString1 = "Hello World IceCream";
|
||||
constexpr AZStd::string_view testString2 = "IceCream woRLd Hello";
|
||||
constexpr bool caseSensitive = false;
|
||||
EXPECT_TRUE(AZ::StringFunc::Equal(testString1.substr(6, 5), testString2.substr(9, 5), caseSensitive));
|
||||
}
|
||||
TEST_F(StringFuncTest, Equal_CaseSensitive_OnNonNullTerminatedStringView_WithDifferentCases_Fails)
|
||||
{
|
||||
constexpr AZStd::string_view testString1 = "Hello World IceCream";
|
||||
constexpr AZStd::string_view testString2 = "IceCream woRLd Hello";
|
||||
constexpr bool caseSensitive = true;
|
||||
EXPECT_FALSE(AZ::StringFunc::Equal(testString1.substr(6, 5), testString2.substr(9, 5), caseSensitive));
|
||||
}
|
||||
TEST_F(StringFuncTest, Equal_OnNonNullTerminatedStringView_WithDifferentSize_Fails)
|
||||
{
|
||||
constexpr AZStd::string_view testString1 = "Hello World IceCream";
|
||||
constexpr AZStd::string_view testString2 = "IceCream World Hello";
|
||||
|
||||
EXPECT_FALSE(AZ::StringFunc::Equal(testString1.substr(6, 6), testString2.substr(9, 5)));
|
||||
}
|
||||
|
||||
// Strip out any trailing path separators
|
||||
|
||||
TEST_F(StringFuncTest, Strip_ValidInputExtraEndingPathSeparators_Success)
|
||||
|
||||
Reference in New Issue
Block a user