6d592d78cd
* This set of changes is work toward allowing release builds to work with asset bundler generated bundles and legacy, non-prefab levels. This requires some other in-flight changes before this work is complete.
Updated engine seed list + fixed automated test
ComponentApplicationLifecycle has the ability to automatically register events if asked to register a handler and the event doesn't exist. This is only intended for cases where you need to register a handler early in startup before the settings registry file is loaded.
Added two new lifecycle events: One after the system entity has been activated, and one after the system interface has been created.
If you load an archive before the system entity has been activated, archive.cpp caches information about those archives until that time, so it can finish registration. This is because the serialization system and BundlingSystemComponent both need to be available to do this registration, but the bundles have to be loaded before those are initialized so that the settings registry file can be loaded.
Fixed an error were mounted pak files were searching for levels.pak and not level.pak, and not finding them. I'm pretty sure this logic doesn't do anything functional either way, but I've been testing legacy levels with this change and they work now.
Moved wildcard pak loading to where engine.pak is loaded. This is because the settings registry file that defines the IO stack to spin up must be available early in application startup, and this file must be within a mounted pak file. If you're using asset bundler generated bundles, they need to be loaded at this time so that file can be loaded.
Atom's BootstrapSystemComponent.cpp no longer initializes on AssetCatalogLoaded, and instead initializes on the ApplicationLifecycle event SystemInterfaceCreated. This is because the base assetcatalog.xml file is really just a development time concept, this file should not be used in packaged release builds, because those builds will make use of delta catalogs in each bundle loaded. The asset catalog contains the list of all assets that were in the cache at development time, and this contains content that developers don't want to ship, and they may want to specifically hide from their customers, so data miners don't find secrets about upcoming game content.
Recovering from a branch that had incorrect DCO
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
* Fixed an incorrect ebus disconnect and removed an include that's no longer needed
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
* Fixed a copy and paste typo from trying to recover the previous pull request
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
* Updated product IDs for the settings registry builder to no longer collide with the JSON builder. Now they are based on a hash of the configuration.
Updated the engine default seed list to include the new asset ID info for the renamed bootstrap file
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
* Updated the path to the application lifecycle events, because runtime settings aren't included in the merged bootstrap file.
Addressed some feedback on printing out a string view on an error
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
* Removed a test that uses old assets that aren't relevant. We may not need this test anymore, but if we do we've backlogged a task to create a new test to cover this behavior without using old assets.
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
* Renamed SystemInterfaceCreated event to LegacySystemInterfaceCreated
Removed SystemEntityActivated event. Now that I have the rest of the fixes in this pull request, this new event wasn't needed, the already existing SystemComponentsActivated event does what I need.
Changed list to vector
Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com>
477 lines
22 KiB
C++
477 lines
22 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <limits>
|
|
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
|
#include <AzCore/Component/ComponentApplicationBus.h>
|
|
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
|
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
|
#include <AzCore/Utils/Utils.h>
|
|
#include <AzFramework/Platform/PlatformDefaults.h>
|
|
#include <AzFramework/StringFunc/StringFunc.h>
|
|
#include <native/InternalBuilders/SettingsRegistryBuilder.h>
|
|
#include <native/utilities/PlatformConfiguration.h>
|
|
|
|
namespace AssetProcessor
|
|
{
|
|
void SettingsRegistryBuilder::SettingsExporter::WriteName(AZStd::string_view name)
|
|
{
|
|
if (m_includeName)
|
|
{
|
|
m_writer.Key(name.data(), aznumeric_caster(name.length()));
|
|
}
|
|
}
|
|
|
|
SettingsRegistryBuilder::SettingsExporter::SettingsExporter(
|
|
rapidjson::StringBuffer& buffer, const AZStd::vector<AZStd::string>& excludes)
|
|
: m_writer(rapidjson::Writer<rapidjson::StringBuffer>(buffer))
|
|
, m_excludes(excludes)
|
|
{
|
|
}
|
|
|
|
AZ::SettingsRegistryInterface::VisitResponse SettingsRegistryBuilder::SettingsExporter::Traverse(
|
|
AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::VisitAction action,
|
|
AZ::SettingsRegistryInterface::Type type)
|
|
{
|
|
for (const AZStd::string& exclude : m_excludes)
|
|
{
|
|
if (exclude == path)
|
|
{
|
|
return AZ::SettingsRegistryInterface::VisitResponse::Skip;
|
|
}
|
|
}
|
|
|
|
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);
|
|
if (type == AZ::SettingsRegistryInterface::Type::Object)
|
|
{
|
|
m_result = m_result && m_writer.StartObject();
|
|
m_includeNameStack.push(true);
|
|
m_includeName = true;
|
|
}
|
|
else
|
|
{
|
|
m_result = m_result && m_writer.StartArray();
|
|
m_includeNameStack.push(false);
|
|
m_includeName = false;
|
|
}
|
|
}
|
|
else if (action == AZ::SettingsRegistryInterface::VisitAction::End)
|
|
{
|
|
if (type == AZ::SettingsRegistryInterface::Type::Object)
|
|
{
|
|
m_result = m_result && m_writer.EndObject();
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
WriteName(valueName);
|
|
m_result = m_result && m_writer.Null();
|
|
}
|
|
|
|
return m_result ?
|
|
AZ::SettingsRegistryInterface::VisitResponse::Continue :
|
|
AZ::SettingsRegistryInterface::VisitResponse::Done;
|
|
}
|
|
|
|
void SettingsRegistryBuilder::SettingsExporter::Visit(
|
|
AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value)
|
|
{
|
|
WriteName(valueName);
|
|
m_result = m_result && m_writer.Bool(value);
|
|
}
|
|
|
|
void SettingsRegistryBuilder::SettingsExporter::Visit(
|
|
AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value)
|
|
{
|
|
WriteName(valueName);
|
|
m_result = m_result && m_writer.Int64(value);
|
|
}
|
|
|
|
void SettingsRegistryBuilder::SettingsExporter::Visit(
|
|
AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::u64 value)
|
|
{
|
|
WriteName(valueName);
|
|
m_result = m_result && m_writer.Uint64(value);
|
|
}
|
|
|
|
void SettingsRegistryBuilder::SettingsExporter::Visit(
|
|
AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, double value)
|
|
{
|
|
WriteName(valueName);
|
|
m_result = m_result && m_writer.Double(value);
|
|
}
|
|
|
|
void SettingsRegistryBuilder::SettingsExporter::Visit(
|
|
AZStd::string_view, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value)
|
|
{
|
|
WriteName(valueName);
|
|
m_result = m_result && m_writer.String(value.data(), aznumeric_caster(value.length()));
|
|
}
|
|
|
|
bool SettingsRegistryBuilder::SettingsExporter::Finalize()
|
|
{
|
|
if (!m_includeNameStack.empty())
|
|
{
|
|
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;
|
|
}
|
|
|
|
void SettingsRegistryBuilder::SettingsExporter::Reset(rapidjson::StringBuffer& buffer)
|
|
{
|
|
m_writer.Reset(buffer);
|
|
m_includeName = false;
|
|
m_result = true;
|
|
}
|
|
|
|
|
|
|
|
SettingsRegistryBuilder::SettingsRegistryBuilder()
|
|
: m_builderId("{1BB18B28-2953-4922-A80B-E7375FCD7FC1}")
|
|
, m_assetType("{FEBB3C7B-9C8B-46C3-8AAF-3D132D811087}")
|
|
{
|
|
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusConnect(m_builderId);
|
|
}
|
|
|
|
bool SettingsRegistryBuilder::Initialize()
|
|
{
|
|
AssetBuilderSDK::AssetBuilderDesc builderDesc;
|
|
builderDesc.m_name = "Settings Registry Builder";
|
|
builderDesc.m_patterns.emplace_back("*/engine.json", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
|
|
builderDesc.m_builderType = AssetBuilderSDK::AssetBuilderDesc::AssetBuilderType::Internal;
|
|
builderDesc.m_busId = m_builderId;
|
|
builderDesc.m_createJobFunction = AZStd::bind(&SettingsRegistryBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
|
builderDesc.m_processJobFunction = AZStd::bind(&SettingsRegistryBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
|
builderDesc.m_version = 1;
|
|
|
|
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDesc);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SettingsRegistryBuilder::Uninitialize() {}
|
|
|
|
void SettingsRegistryBuilder::ShutDown()
|
|
{
|
|
m_isShuttingDown = true;
|
|
}
|
|
|
|
void SettingsRegistryBuilder::CreateJobs(
|
|
const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
|
|
{
|
|
if (m_isShuttingDown)
|
|
{
|
|
response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
|
|
return;
|
|
}
|
|
|
|
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
|
|
{
|
|
AssetBuilderSDK::JobDescriptor job;
|
|
job.m_jobKey = "Settings Registry";
|
|
// The settings are the very first thing the game reads so needs to available before anything else.
|
|
job.m_priority = std::numeric_limits<decltype(job.m_priority)>::max();
|
|
job.m_critical = true;
|
|
job.SetPlatformIdentifier(info.m_identifier.c_str());
|
|
response.m_createJobOutputs.push_back(AZStd::move(job));
|
|
}
|
|
|
|
AZ::IO::Path settingsRegistryWildcard = AZStd::string_view(AZ::Utils::GetEnginePath());
|
|
settingsRegistryWildcard /= AZ::SettingsRegistryInterface::RegistryFolder;
|
|
settingsRegistryWildcard /= "*.setreg";
|
|
response.m_sourceFileDependencyList.emplace_back(AZStd::move(settingsRegistryWildcard.Native()), AZ::Uuid::CreateNull(),
|
|
AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards);
|
|
|
|
auto projectPath = AZ::IO::Path(AZStd::string_view(AZ::Utils::GetProjectPath()));
|
|
response.m_sourceFileDependencyList.emplace_back(
|
|
AZStd::move((projectPath / AZ::SettingsRegistryInterface::RegistryFolder / "*.setreg").Native()),
|
|
AZ::Uuid::CreateNull(),
|
|
AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards);
|
|
response.m_sourceFileDependencyList.emplace_back(
|
|
AZStd::move((projectPath / AZ::SettingsRegistryInterface::DevUserRegistryFolder / "*.setreg").Native()),
|
|
AZ::Uuid::CreateNull(),
|
|
AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards);
|
|
|
|
if (auto settingsRegistry = AZ::Interface<AZ::SettingsRegistryInterface>::Get(); settingsRegistry != nullptr)
|
|
{
|
|
AZStd::vector<AzFramework::GemInfo> gemInfos;
|
|
if (AzFramework::GetGemsInfo(gemInfos, *settingsRegistry))
|
|
{
|
|
// Gather unique list of Settings Registry wildcard directories
|
|
AZStd::vector<AZ::IO::Path> gemSettingsRegistryWildcards;
|
|
for (const AzFramework::GemInfo& gemInfo : gemInfos)
|
|
{
|
|
for (const AZ::IO::Path& absoluteSourcePath : gemInfo.m_absoluteSourcePaths)
|
|
{
|
|
auto gemSettingsRegistryWildcard = absoluteSourcePath / AZ::SettingsRegistryInterface::RegistryFolder / "*.setreg";
|
|
if (auto foundIt = AZStd::find(gemSettingsRegistryWildcards.begin(), gemSettingsRegistryWildcards.end(), gemSettingsRegistryWildcard);
|
|
foundIt == gemSettingsRegistryWildcards.end())
|
|
{
|
|
gemSettingsRegistryWildcards.emplace_back(gemSettingsRegistryWildcard);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add to the Source File Dependency list
|
|
for (AZ::IO::Path& gemSettingsRegistryWildcard : gemSettingsRegistryWildcards)
|
|
{
|
|
response.m_sourceFileDependencyList.emplace_back(
|
|
AZStd::move(gemSettingsRegistryWildcard.Native()), AZ::Uuid::CreateNull(),
|
|
AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards);
|
|
}
|
|
}
|
|
}
|
|
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
|
}
|
|
|
|
void SettingsRegistryBuilder::ProcessJob(
|
|
const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response)
|
|
{
|
|
if (m_isShuttingDown)
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
|
|
return;
|
|
}
|
|
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
|
|
AZStd::vector<AZStd::string> excludes = ReadExcludesFromRegistry();
|
|
// Exclude the AssetProcessor settings from the game regsitry
|
|
excludes.emplace_back(AssetProcessor::AssetProcessorSettingsKey);
|
|
|
|
AZStd::vector<char> scratchBuffer;
|
|
scratchBuffer.reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
|
|
AZStd::fixed_vector<AZStd::string_view, AzFramework::MaxPlatformCodeNames> platformCodes;
|
|
AzFramework::PlatformHelper::AppendPlatformCodeNames(platformCodes, request.m_platformInfo.m_identifier);
|
|
AZ_Assert(platformCodes.size() <= 1, "A one-to-one mapping of asset type platform identifier"
|
|
" to platform codename is required in the SettingsRegistryBuilder."
|
|
" The bootstrap.game is now only produced per build configuration and doesn't take into account"
|
|
" different platforms names");
|
|
|
|
const AZStd::string& assetPlatformIdentifier = request.m_jobDescription.GetPlatformIdentifier();
|
|
// Determines the suffix that will be used for the launcher based on processing server vs non-server assets
|
|
const char* launcherType = assetPlatformIdentifier != AzFramework::PlatformHelper::GetPlatformName(AzFramework::PlatformId::SERVER)
|
|
? "_GameLauncher" : "_ServerLauncher";
|
|
|
|
AZ::SettingsRegistryInterface::Specializations specializations[] =
|
|
{
|
|
{ AZStd::string_view{"release"}, AZStd::string_view{"game"} },
|
|
{ AZStd::string_view{"profile"}, AZStd::string_view{"game"} },
|
|
{ AZStd::string_view{"debug"}, AZStd::string_view{"game"} }
|
|
};
|
|
|
|
// Add the project specific specializations
|
|
auto projectName = AZ::Utils::GetProjectName();
|
|
if (!projectName.empty())
|
|
{
|
|
for (AZ::SettingsRegistryInterface::Specializations& specialization : specializations)
|
|
{
|
|
specialization.Append(projectName);
|
|
// The Game Launcher normally has a build target name of <ProjectName>Launcher
|
|
// Add that as a specialization to pick up the gem dependencies files that are specialized
|
|
// on a the Game Launcher target if the asset platform isn't "server"
|
|
specialization.Append(projectName + launcherType);
|
|
}
|
|
}
|
|
|
|
AZStd::string outputPath;
|
|
AzFramework::StringFunc::Path::Join(request.m_tempDirPath.c_str(), "bootstrap.game.", outputPath);
|
|
size_t extensionOffset = outputPath.length();
|
|
|
|
rapidjson::StringBuffer outputBuffer;
|
|
outputBuffer.Reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
|
|
SettingsExporter exporter(outputBuffer, excludes);
|
|
|
|
if (!platformCodes.empty())
|
|
{
|
|
AZStd::string_view platform = platformCodes.front();
|
|
for (size_t i = 0; i < AZStd::size(specializations); ++i)
|
|
{
|
|
const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i];
|
|
if (m_isShuttingDown)
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
|
|
return;
|
|
}
|
|
|
|
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
|
|
// Placeholder Key used by the local Settings Registry for storing all Gems SourcePaths
|
|
// array entries.
|
|
constexpr auto PlaceholderGemKey = FixedValueString(AZ::SettingsRegistryMergeUtils::OrganizationRootKey)
|
|
+ "/Gems/__SettingsRegistryBuilderPlaceholder";
|
|
|
|
AZ::SettingsRegistryImpl registry;
|
|
|
|
// Seed the local settings registry using the AssetProcessor Settings Registry
|
|
if (auto settingsRegistry = AZ::Interface<AZ::SettingsRegistryInterface>::Get(); settingsRegistry != nullptr)
|
|
{
|
|
AZStd::array settingsToCopy{
|
|
AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey),
|
|
AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_BinaryFolder},
|
|
AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder},
|
|
AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath},
|
|
AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder},
|
|
AZStd::string{AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder},
|
|
};
|
|
|
|
for (const auto& settingsKey : settingsToCopy)
|
|
{
|
|
FixedValueString settingsValue;
|
|
[[maybe_unused]] bool settingsCopied = settingsRegistry->Get(settingsValue, settingsKey)
|
|
&& registry.Set(settingsKey, settingsValue);
|
|
AZ_Warning("Settings Registry Builder", settingsCopied, "Unable to copy setting %s from AssetProcessor settings registry"
|
|
" to local settings registry", settingsKey.c_str());
|
|
}
|
|
|
|
// The purpose of this section is to copy the Gem's SourcePaths from the Global Settings Registry
|
|
// the local SettingsRegistry. The reason this is needed is so that the call to
|
|
// `MergeSettingsToRegistry_GemRegistries` below is able to locate each gem's "<gem-root>/Registry" folder
|
|
// that will be merged into the bootstrap.game.<configuration>.setreg file
|
|
// This is used by the GameLauncher applications to read from a single merged .setreg file
|
|
// containing the settings needed to run a game/simulation without have access to the source code base registry
|
|
AZStd::vector<AzFramework::GemInfo> gemInfos;
|
|
size_t pathIndex{};
|
|
if (AzFramework::GetGemsInfo(gemInfos, *settingsRegistry))
|
|
{
|
|
AZStd::vector<AZ::IO::PathView> sourcePaths;
|
|
for (const AzFramework::GemInfo& gemInfo : gemInfos)
|
|
{
|
|
for (const AZ::IO::Path& absoluteSourcePath : gemInfo.m_absoluteSourcePaths)
|
|
{
|
|
if (auto foundIt = AZStd::find(sourcePaths.begin(), sourcePaths.end(), absoluteSourcePath);
|
|
foundIt == sourcePaths.end())
|
|
{
|
|
sourcePaths.emplace_back(absoluteSourcePath);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const AZ::IO::PathView& sourcePath : sourcePaths)
|
|
{
|
|
// Use JSON Pointer to append elements to the SourcePaths array
|
|
registry.Set(FixedValueString::format("%s/SourcePaths/%zu", PlaceholderGemKey.c_str(), pathIndex++),
|
|
sourcePath.Native());
|
|
}
|
|
}
|
|
}
|
|
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, platform, specialization, &scratchBuffer);
|
|
// This function iterates over each path for each the "/Amazon/Gems/<gem-name>/SourcePaths" key and attempts
|
|
// to merge the "Registry" directory in each path.
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, platform, specialization, &scratchBuffer);
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, platform, specialization, &scratchBuffer);
|
|
|
|
// The Placeholder Key is removed now that each gem's "<gem-root>/Registry" directory have been merged to
|
|
// the local Settings Registry instance via `MergeSettingsToRegistry_GemRegistries`
|
|
registry.Remove(PlaceholderGemKey);
|
|
|
|
// Merge the Project User and User home settings registry only in non-release builds
|
|
constexpr bool executeRegDumpCommands = false;
|
|
AZ::CommandLine* commandLine{};
|
|
AZ::ComponentApplicationBus::Broadcast([&commandLine](AZ::ComponentApplicationRequests* appRequests)
|
|
{
|
|
commandLine = appRequests->GetAzCommandLine();
|
|
});
|
|
|
|
if (!specialization.Contains("release"))
|
|
{
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, platform, specialization, &scratchBuffer);
|
|
if (commandLine)
|
|
{
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands);
|
|
}
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, platform, specialization, &scratchBuffer);
|
|
}
|
|
|
|
if (commandLine)
|
|
{
|
|
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, *commandLine, executeRegDumpCommands);
|
|
}
|
|
|
|
|
|
if (registry.Visit(exporter, ""))
|
|
{
|
|
if (!exporter.Finalize())
|
|
{
|
|
return;
|
|
}
|
|
|
|
AZStd::string_view specializationString(specialization.GetSpecialization(0));
|
|
outputPath += specializationString; // Append configuration
|
|
outputPath += ".setreg";
|
|
|
|
AZ::IO::SystemFile file;
|
|
if (!file.Open(outputPath.c_str(),
|
|
AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY))
|
|
{
|
|
AZ_Error("Settings Registry Builder", false, R"(Failed to open file "%s" for writing.)", outputPath.c_str());
|
|
return;
|
|
}
|
|
if (file.Write(outputBuffer.GetString(), outputBuffer.GetSize()) != outputBuffer.GetSize())
|
|
{
|
|
AZ_Error("Settings Registry Builder", false, R"(Failed to write settings registry to file "%s".)", outputPath.c_str());
|
|
return;
|
|
}
|
|
file.Close();
|
|
|
|
AZ::u32 hashedSpecialization = static_cast<AZ::u32>(AZStd::hash<AZStd::string_view>{}(specializationString));
|
|
AZ_Assert(hashedSpecialization != 0, "Product ID generation failed for specialization %.*s. This can result in a product ID collision with other builders for this asset.",
|
|
AZ_STRING_ARG(specializationString));
|
|
response.m_outputProducts.emplace_back(outputPath, m_assetType, hashedSpecialization);
|
|
response.m_outputProducts.back().m_dependenciesHandled = true;
|
|
|
|
outputPath.erase(extensionOffset);
|
|
}
|
|
|
|
outputBuffer.Clear();
|
|
exporter.Reset(outputBuffer);
|
|
}
|
|
}
|
|
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
}
|
|
|
|
AZStd::vector<AZStd::string> SettingsRegistryBuilder::ReadExcludesFromRegistry() const
|
|
{
|
|
AZStd::vector<AZStd::string> excludes;
|
|
auto builderRegistry = AZ::SettingsRegistry::Get();
|
|
AZStd::string path = "/Amazon/AssetBuilder/SettingsRegistry/Excludes/";
|
|
size_t offset = path.length();
|
|
size_t counter = 0;
|
|
do
|
|
{
|
|
path += AZStd::to_string(counter);
|
|
|
|
AZStd::string exclude;
|
|
if (builderRegistry->Get(exclude, path))
|
|
{
|
|
excludes.push_back(AZStd::move(exclude));
|
|
}
|
|
else
|
|
{
|
|
return excludes;
|
|
}
|
|
|
|
counter++;
|
|
path.erase(offset);
|
|
} while (true);
|
|
}
|
|
} // namespace AssetProcessor
|