Integrating latest from github/staging
Integrating up through commit 5e1bdae
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "native/utilities/ApplicationManager.h"
|
||||
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
@@ -83,7 +84,7 @@ namespace AssetProcessor
|
||||
// we are in a job thread - return early to make it so that the global log file does not get this message
|
||||
// there will also be a log listener in the actual job log thread which will get the message too, and that one
|
||||
// will write it to the individual log.
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
AzFramework::LogComponent::OutputMessage(severity, window, message);
|
||||
@@ -119,29 +120,14 @@ AssetProcessorAZApplication::AssetProcessorAZApplication(int* argc, char*** argv
|
||||
*AZ::SettingsRegistry::Get(), AssetProcessorBuildTarget::GetBuildTargetName());
|
||||
|
||||
// Adding the PreModuleLoad event to the AssetProcessor application for logging when a gem loads
|
||||
m_preModuleLoadHandler = AZ::ModuleManagerRequests::PreModuleLoadEvent::Handler{ []([[maybe_unused]] AZStd::string_view modulePath)
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Loading (Gem) Module '%.*s'...\n", aznumeric_cast<int>(modulePath.size()), modulePath.data());
|
||||
} };
|
||||
m_preModuleLoadHandler = AZ::ModuleManagerRequests::PreModuleLoadEvent::Handler{
|
||||
[]([[maybe_unused]] AZStd::string_view modulePath)
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Loading (Gem) Module '%.*s'...\n", aznumeric_cast<int>(modulePath.size()), modulePath.data());
|
||||
}
|
||||
};
|
||||
|
||||
m_preModuleLoadHandler.Connect(m_moduleManager->m_preModuleLoadEvent);
|
||||
|
||||
// Override the /Amazon/AzCore/Bootstrap/sys_game_folder entry in the Settings Registry using the -gamefolder parameter
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
if (m_commandLine.GetNumSwitchValues("gamefolder") > 0)
|
||||
{
|
||||
const AZStd::string& gameFolderOverride = m_commandLine.GetSwitchValue("gamefolder", 0);
|
||||
auto gameFolderCommandLineOverride = AZStd::string::format("--regset=%s/sys_game_folder=%s", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey,
|
||||
gameFolderOverride.c_str());
|
||||
|
||||
AZ::CommandLine::ParamContainer commandLineArgs;
|
||||
m_commandLine.Dump(commandLineArgs);
|
||||
commandLineArgs.emplace_back(gameFolderCommandLineOverride);
|
||||
m_commandLine.Parse(commandLineArgs);
|
||||
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*settingsRegistry, m_commandLine, false);
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*settingsRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::ComponentTypeList AssetProcessorAZApplication::GetRequiredSystemComponents() const
|
||||
@@ -155,7 +141,7 @@ AZ::ComponentTypeList AssetProcessorAZApplication::GetRequiredSystemComponents()
|
||||
|| *iter == AZ::Uuid("{624a7be2-3c7e-4119-aee2-1db2bdb6cc89}") // ScriptDebugAgent
|
||||
|| *iter == AZ::Uuid("{CAF3A025-FAC9-4537-B99E-0A800A9326DF}") // InputSystemComponent
|
||||
|| *iter == azrtti_typeid<AssetProcessor::ToolsAssetCatalogComponent>()
|
||||
)
|
||||
)
|
||||
{
|
||||
// AP does not require the above components to be active
|
||||
iter = components.erase(iter);
|
||||
@@ -274,7 +260,7 @@ void ApplicationManager::GetExternalBuilderFileList(QStringList& externalBuilder
|
||||
|
||||
if (externalBuilderModules.empty())
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "AssetProcessor was unable to locate any builders\n");
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "AssetProcessor was unable to locate any external builders\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,9 +270,16 @@ QDir ApplicationManager::GetSystemRoot() const
|
||||
{
|
||||
return m_systemRoot;
|
||||
}
|
||||
QString ApplicationManager::GetGameName() const
|
||||
QString ApplicationManager::GetProjectPath() const
|
||||
{
|
||||
return m_gameName;
|
||||
auto projectPath = AZ::Utils::GetProjectPath();
|
||||
if (!projectPath.empty())
|
||||
{
|
||||
return QString::fromUtf8(projectPath.c_str(), aznumeric_cast<int>(projectPath.size()));
|
||||
}
|
||||
|
||||
AZ_Warning("AssetUtils", false, "Unable to obtain the Project Path from the settings registry.");
|
||||
return {};
|
||||
}
|
||||
|
||||
QCoreApplication* ApplicationManager::GetQtApplication()
|
||||
@@ -451,7 +444,7 @@ void ApplicationManager::PopulateApplicationDependencies()
|
||||
m_filesOfInterest.push_back(applicationPath);
|
||||
|
||||
// add some known-dependent files (this can be removed when they are no longer a dependency)
|
||||
// Note that its not necessary for any of these files to actually exist. It is considered a "change" if they
|
||||
// Note that its not necessary for any of these files to actually exist. It is considered a "change" if they
|
||||
// change their file modtime, or if they go from existing to not existing, or if they go from not existing, to existing.
|
||||
// any of those should cause AP to drop.
|
||||
for (const QString& pathName : { "CrySystem",
|
||||
@@ -475,11 +468,10 @@ void ApplicationManager::PopulateApplicationDependencies()
|
||||
QDir assetRoot;
|
||||
AssetUtilities::ComputeAssetRoot(assetRoot);
|
||||
|
||||
QString globalConfigPath = assetRoot.filePath("AssetProcessorPlatformConfig.ini");
|
||||
QString globalConfigPath = assetRoot.filePath("AssetProcessorPlatformConfig.setreg");
|
||||
m_filesOfInterest.push_back(globalConfigPath);
|
||||
|
||||
QString gameName = AssetUtilities::ComputeGameName();
|
||||
QString gamePlatformConfigPath = assetRoot.filePath(gameName + "/AssetProcessorGamePlatformConfig.ini");
|
||||
QString gamePlatformConfigPath = QDir(AssetUtilities::ComputeProjectPath()).filePath("AssetProcessorGamePlatformConfig.setreg");
|
||||
m_filesOfInterest.push_back(gamePlatformConfigPath);
|
||||
|
||||
// add app modules
|
||||
@@ -510,43 +502,14 @@ void ApplicationManager::PopulateApplicationDependencies()
|
||||
}
|
||||
}
|
||||
|
||||
bool ApplicationManager::StartAZFramework(QString appRootOverride)
|
||||
bool ApplicationManager::StartAZFramework()
|
||||
{
|
||||
AzFramework::Application::Descriptor appDescriptor;
|
||||
AZ::ComponentApplication::StartupParameters params;
|
||||
|
||||
QString gameName = AssetUtilities::ComputeGameName();
|
||||
QString projectName = AssetUtilities::ComputeProjectName();
|
||||
AZ::SettingsRegistryInterface& registry = *AZ::SettingsRegistry::Get();
|
||||
// Add the supplied gameName as specialization key in the registry
|
||||
if (!gameName.isEmpty())
|
||||
{
|
||||
auto gameNameSpecialization = QString("%1/%2").arg(AZ::SettingsRegistryMergeUtils::SpecializationsRootKey).arg(gameName);
|
||||
QByteArray specializationByteArray = gameNameSpecialization.toUtf8();
|
||||
registry.Set(AZStd::string_view(specializationByteArray.data(), specializationByteArray.size()), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the project name as a registry specialization
|
||||
auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/sys_game_folder", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey);
|
||||
if (AZ::SettingsRegistryInterface::FixedValueString bootstrapProjectName; registry.Get(bootstrapProjectName, projectKey) && !bootstrapProjectName.empty())
|
||||
{
|
||||
registry.Set(AZ::SettingsRegistryInterface::FixedValueString::format("%s/%s",
|
||||
AZ::SettingsRegistryMergeUtils::SpecializationsRootKey, bootstrapProjectName.c_str()),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
// The application will live in a bin folder one level up from the app root.
|
||||
static char s_storageForRootPath[AZ_MAX_PATH_LEN] = { 0 };
|
||||
if (!appRootOverride.isEmpty())
|
||||
{
|
||||
azstrcpy(s_storageForRootPath, AZ_MAX_PATH_LEN, appRootOverride.toUtf8().data());
|
||||
params.m_appRootOverride = s_storageForRootPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
params.m_appRootOverride = nullptr;
|
||||
}
|
||||
// Prevent loading of gems in the Create method of the ComponentApplication
|
||||
params.m_loadDynamicModules = false;
|
||||
|
||||
@@ -556,31 +519,27 @@ bool ApplicationManager::StartAZFramework(QString appRootOverride)
|
||||
AZ::Debug::Trace::HandleExceptions(true);
|
||||
|
||||
m_frameworkApp.Start(appDescriptor, params);
|
||||
|
||||
|
||||
//Registering all the Components
|
||||
m_frameworkApp.RegisterComponentDescriptor(AzFramework::LogComponent::CreateDescriptor());
|
||||
|
||||
|
||||
|
||||
Reflect();
|
||||
|
||||
QDir engineRoot;
|
||||
AssetUtilities::ComputeEngineRoot(engineRoot);
|
||||
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@devroot@", engineRoot.absolutePath().toUtf8().data());
|
||||
|
||||
const AzFramework::CommandLine* commandLine = nullptr;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
|
||||
if (commandLine && commandLine->HasSwitch("logDir"))
|
||||
{
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@log@", commandLine->GetSwitchValue("logDir", 0).c_str());
|
||||
}
|
||||
else
|
||||
else if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
char executableDirectory[AZ_MAX_PATH_LEN];
|
||||
if (AZ::Utils::GetExecutableDirectory(executableDirectory, AZStd::size(executableDirectory)) == AZ::Utils::ExecutablePathResult::Success)
|
||||
{
|
||||
AZ::IO::FileIOBase::GetInstance()->SetAlias("@log@", executableDirectory);
|
||||
}
|
||||
AZ::IO::Path projectUserPath;
|
||||
settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath);
|
||||
|
||||
AZ::IO::Path logUserPath = projectUserPath / "log";
|
||||
auto fileIo = AZ::IO::FileIOBase::GetInstance();
|
||||
fileIo->SetAlias("@log@", logUserPath.c_str());
|
||||
}
|
||||
m_entity = aznew AZ::Entity("Application Entity");
|
||||
if (m_entity)
|
||||
@@ -622,7 +581,6 @@ bool ApplicationManager::ActivateModules()
|
||||
AZ_Error(AssetProcessor::ConsoleChannel, false, "Cannot compute the asset root folder. Is AssetProcessor being run from the appropriate folder?");
|
||||
return false;
|
||||
}
|
||||
assetRoot.cd(AssetUtilities::ComputeGameName());
|
||||
|
||||
m_frameworkApp.LoadDynamicModules();
|
||||
return true;
|
||||
@@ -633,89 +591,13 @@ void ApplicationManager::addRunningThread(AssetProcessor::ThreadWorker* thread)
|
||||
m_runningThreads.push_back(thread);
|
||||
}
|
||||
|
||||
QString ApplicationManager::ParseOptionAppRootArgument()
|
||||
{
|
||||
AZ_Assert(m_qApp!=nullptr,"m_qApp not initialized. QT application must be created before this call.")
|
||||
// Parse any parameters.
|
||||
static const char* app_root_parameter = "app-root";
|
||||
static const char* app_root_parameter_desc = "Optional external path outside of the current engine to set as the application root.";
|
||||
QCommandLineOption appRootPathOption(QString(app_root_parameter), tr(app_root_parameter_desc), QString("path"));
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("Asset Processor");
|
||||
parser.addOption(appRootPathOption);
|
||||
parser.parse(m_qApp->arguments());
|
||||
|
||||
QString appRootArgValue = parser.value(appRootPathOption);
|
||||
appRootArgValue.remove(QChar('\"'));
|
||||
return appRootArgValue.trimmed();
|
||||
}
|
||||
|
||||
bool ApplicationManager::ValidateExternalAppRoot(QString appRootPath) const
|
||||
{
|
||||
static const char* bootstrap_cfg_name = "bootstrap.cfg";
|
||||
|
||||
QDir testAppRootPath(appRootPath);
|
||||
|
||||
// Make sure the path exists
|
||||
if (!testAppRootPath.exists())
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. Directory does not exist.\n", appRootPath.toUtf8().data());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the path contains bootstrap.cfg
|
||||
if (!testAppRootPath.exists(bootstrap_cfg_name))
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. Directory does not contain %s.\n", appRootPath.toUtf8().data(), bootstrap_cfg_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we can read the 'sys_game_folder' settings from bootstrap.cfg
|
||||
QSettings settings(testAppRootPath.absoluteFilePath(bootstrap_cfg_name), QSettings::Format::IniFormat);
|
||||
static const char* sysGameFolderKeyName = "sys_game_folder";
|
||||
auto sysGameFolderSettings = settings.value(sysGameFolderKeyName);
|
||||
if (!sysGameFolderSettings.isValid() || sysGameFolderSettings.isNull())
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. %s in the path is not valid.\n", appRootPath.toUtf8().data(), bootstrap_cfg_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the 'sys_game_folder' value in the external bootstrap.cfg points to a valid subfolder in that path
|
||||
QString sysGameFolder = sysGameFolderSettings.toString();
|
||||
QDir gameFolderPath(appRootPath);
|
||||
if (!gameFolderPath.cd(sysGameFolder))
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, testAppRootPath.exists(), "Invalid Application Root path override (--app-root): %s. Configured Game folder %s in the path is not valid.\n", appRootPath.toUtf8().data(), sysGameFolder.toUtf8().data());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ApplicationManager::BeforeRunStatus ApplicationManager::BeforeRun()
|
||||
{
|
||||
// Create the Qt Application
|
||||
CreateQtApplication();
|
||||
|
||||
// Calculate the override app root path if provided and validate it before passing it along
|
||||
QString overrideAppRootPath = ParseOptionAppRootArgument();
|
||||
|
||||
if (!overrideAppRootPath.isEmpty())
|
||||
{
|
||||
if (ValidateExternalAppRoot(overrideAppRootPath))
|
||||
{
|
||||
QDir overrideAppRoot(overrideAppRootPath);
|
||||
QDir resultAppRoot;
|
||||
AssetUtilities::ComputeAssetRoot(resultAppRoot, &overrideAppRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(AssetProcessor::ConsoleChannel, false, "Invalid override app root folder '%s'.", overrideAppRootPath.toUtf8().data());
|
||||
return ApplicationManager::BeforeRunStatus::Status_Failure;
|
||||
}
|
||||
}
|
||||
|
||||
if (!StartAZFramework(overrideAppRootPath))
|
||||
if (!StartAZFramework())
|
||||
{
|
||||
return ApplicationManager::BeforeRunStatus::Status_Failure;
|
||||
}
|
||||
@@ -742,14 +624,13 @@ bool ApplicationManager::Activate()
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gameName = AssetUtilities::ComputeGameName();
|
||||
|
||||
if (m_gameName.isEmpty())
|
||||
auto projectName = AssetUtilities::ComputeProjectName();
|
||||
if (projectName.isEmpty())
|
||||
{
|
||||
AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable to detect name of current game project. Is bootstrap.cfg appropriately configured?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// the following controls what registry keys (or on mac or linux what entries in home folder) are used
|
||||
// so they should not be translated!
|
||||
qApp->setOrganizationName(GetOrganizationName());
|
||||
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
QCoreApplication* GetQtApplication();
|
||||
|
||||
QDir GetSystemRoot() const;
|
||||
QString GetGameName() const;
|
||||
QString GetProjectPath() const;
|
||||
|
||||
void RegisterComponentDescriptor(const AZ::ComponentDescriptor* descriptor);
|
||||
|
||||
@@ -163,9 +163,7 @@ protected:
|
||||
virtual const char* GetLogBaseName() = 0;
|
||||
virtual RegistryCheckInstructions PopupRegistryProblemsMessage(QString warningText) = 0;
|
||||
private:
|
||||
bool StartAZFramework(QString appRootOverride);
|
||||
bool ValidateExternalAppRoot(QString appRootPath) const;
|
||||
QString ParseOptionAppRootArgument();
|
||||
bool StartAZFramework();
|
||||
|
||||
// QuitPair - Object pointer and "is ready" boolean pair.
|
||||
typedef QPair<QObject*, bool> QuitPair;
|
||||
@@ -178,7 +176,6 @@ private:
|
||||
bool m_needRestart = false;
|
||||
bool m_queuedCheckQuit = false;
|
||||
QDir m_systemRoot;
|
||||
QString m_gameName;
|
||||
AZ::Entity* m_entity = nullptr;
|
||||
|
||||
};
|
||||
|
||||
@@ -337,13 +337,13 @@ bool ApplicationManagerBase::InitPlatformConfiguration()
|
||||
m_platformConfiguration = new AssetProcessor::PlatformConfiguration();
|
||||
QDir assetRoot;
|
||||
AssetUtilities::ComputeAssetRoot(assetRoot);
|
||||
return m_platformConfiguration->InitializeFromConfigFiles(GetSystemRoot().absolutePath(), assetRoot.absolutePath(), GetGameName());
|
||||
return m_platformConfiguration->InitializeFromConfigFiles(GetSystemRoot().absolutePath(), assetRoot.absolutePath(), GetProjectPath());
|
||||
}
|
||||
|
||||
bool ApplicationManagerBase::InitBuilderConfiguration()
|
||||
{
|
||||
m_builderConfig = AZStd::make_unique<AssetProcessor::BuilderConfigurationManager>();
|
||||
QString configFile = GetSystemRoot().absoluteFilePath(GetGameName() + "/" + AssetProcessor::BuilderConfigFile);
|
||||
QString configFile = QDir(GetProjectPath()).absoluteFilePath(AssetProcessor::BuilderConfigFile);
|
||||
|
||||
if (!QFile::exists(configFile))
|
||||
{
|
||||
@@ -1193,7 +1193,8 @@ bool ApplicationManagerBase::Activate()
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "AssetProcessor will process assets from gameproject %s.\n", AssetUtilities::ComputeGameName().toUtf8().data());
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel,
|
||||
"AssetProcessor will process assets from project root %s.\n", AssetUtilities::ComputeProjectPath().toUtf8().data());
|
||||
|
||||
// Shutdown if the disk has less than 128MB of free space
|
||||
if (!CheckSufficientDiskSpace(projectCache.absolutePath(), 128 * 1024 * 1024, true))
|
||||
@@ -1219,7 +1220,7 @@ bool ApplicationManagerBase::Activate()
|
||||
|
||||
if (!InitPlatformConfiguration())
|
||||
{
|
||||
AZ_Error("AssetProcessor", false, "Failed to Initialize from AssetProcessorPlatformConfig.ini - check the log files in the logs/ subfolder for more information.");
|
||||
AZ_Error("AssetProcessor", false, "Failed to Initialize from AssetProcessorPlatformConfig.setreg - check the log files in the logs/ subfolder for more information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1401,7 +1402,7 @@ bool ApplicationManagerBase::InitializeExternalBuilders()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApplicationManagerBase::WaitForBuilderExit(AzToolsFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds)
|
||||
bool ApplicationManagerBase::WaitForBuilderExit(AzFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds)
|
||||
{
|
||||
AZ::u32 exitCode = 0;
|
||||
bool finishedOK = false;
|
||||
|
||||
@@ -177,7 +177,7 @@ protected:
|
||||
|
||||
AssetProcessor::AssetCatalog* GetAssetCatalog() const { return m_assetCatalog; }
|
||||
|
||||
static bool WaitForBuilderExit(AzToolsFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds);
|
||||
static bool WaitForBuilderExit(AzFramework::ProcessWatcher* processWatcher, AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds);
|
||||
|
||||
ApplicationServer* m_applicationServer = nullptr;
|
||||
ConnectionManager* m_connectionManager = nullptr;
|
||||
|
||||
@@ -142,10 +142,6 @@ namespace AssetProcessor
|
||||
|
||||
bool Builder::Start()
|
||||
{
|
||||
// Get the app root to locate the builders
|
||||
AZStd::string appRootString;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRootString, &AzFramework::ApplicationRequests::GetAppRoot);
|
||||
|
||||
// Get the current BinXXX folder based on the current running AP
|
||||
QString applicationDir = QCoreApplication::instance()->applicationDirPath();
|
||||
|
||||
@@ -190,24 +186,26 @@ namespace AssetProcessor
|
||||
QDir projectCacheRoot;
|
||||
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
||||
|
||||
QString gameName = AssetUtilities::ComputeGameName();
|
||||
|
||||
AZStd::string appRootString;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRootString, &AzFramework::ApplicationRequests::GetAppRoot);
|
||||
QDir appRoot(QString(appRootString.c_str()));
|
||||
QString gameRoot = appRoot.absoluteFilePath(gameName);
|
||||
QString gameName = AssetUtilities::ComputeProjectName();
|
||||
QString projectPath = AssetUtilities::ComputeProjectPath();
|
||||
QDir engineRoot;
|
||||
AssetUtilities::ComputeEngineRoot(engineRoot);
|
||||
|
||||
int portNumber = 0;
|
||||
ApplicationServerBus::BroadcastResult(portNumber, &ApplicationServerBus::Events::GetServerListeningPort);
|
||||
|
||||
AZStd::string params;
|
||||
#if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
|
||||
params = AZStd::string::format(R"(-task=%s -id="%s" -gamename="%s" -gamecache="%s" -gameroot="%s" -port %d)",
|
||||
task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(), gameRoot.toUtf8().constData(), portNumber);
|
||||
#else
|
||||
params = AZStd::string::format(R"(-task=%s -id="%s" -gamename="\"%s\"" -gamecache="\"%s\"" -gameroot="\"%s\"" -port %d)",
|
||||
task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(), gameRoot.toUtf8().constData(), portNumber);
|
||||
#endif // !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
|
||||
#if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
|
||||
params = AZStd::string::format(
|
||||
R"(-task=%s -id="%s" -project-name="%s" -project-cache-path="%s" -project-path="%s" -engine-path="%s" -port %d)", task,
|
||||
builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(),
|
||||
projectPath.toUtf8().constData(), engineRoot.absolutePath().toUtf8().constData(), portNumber);
|
||||
#else
|
||||
params = AZStd::string::format(
|
||||
R"(-task=%s -id="%s" -project-name="\"%s\"" -project-cache-path="\"%s\"" -project-path="\"%s\"" -engine-path="\"%s\"" -port %d)",
|
||||
task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(),
|
||||
projectPath.toUtf8().constData(), engineRoot.absolutePath().toUtf8().constData(), portNumber);
|
||||
#endif // !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
|
||||
|
||||
if (moduleFilePath && moduleFilePath[0])
|
||||
{
|
||||
@@ -230,17 +228,17 @@ namespace AssetProcessor
|
||||
return params;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::ProcessWatcher> Builder::LaunchProcess(const char* fullExePath, const AZStd::string& params) const
|
||||
AZStd::unique_ptr<AzFramework::ProcessWatcher> Builder::LaunchProcess(const char* fullExePath, const AZStd::string& params) const
|
||||
{
|
||||
AzToolsFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
processLaunchInfo.m_processExecutableString = fullExePath;
|
||||
processLaunchInfo.m_commandlineParameters = AZStd::string::format("\"%s\" %s", fullExePath, params.c_str());
|
||||
processLaunchInfo.m_showWindow = false;
|
||||
processLaunchInfo.m_processPriority = AzToolsFramework::ProcessPriority::PROCESSPRIORITY_IDLE;
|
||||
processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_IDLE;
|
||||
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, "Executing AssetBuilder with parameters: %s\n", processLaunchInfo.m_commandlineParameters.c_str());
|
||||
|
||||
auto processWatcher = AZStd::unique_ptr<AzToolsFramework::ProcessWatcher>(AzToolsFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzToolsFramework::COMMUNICATOR_TYPE_STDINOUT));
|
||||
auto processWatcher = AZStd::unique_ptr<AzFramework::ProcessWatcher>(AzFramework::ProcessWatcher::LaunchProcess(processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT));
|
||||
|
||||
AZ_Error(AssetProcessor::ConsoleChannel, processWatcher, "Failed to start %s", fullExePath);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/parallel/binary_semaphore.h>
|
||||
#include <AzToolsFramework/Process/ProcessWatcher.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <QString>
|
||||
@@ -108,7 +108,7 @@ namespace AssetProcessor
|
||||
void SetConnection(AZ::u32 connId);
|
||||
|
||||
AZStd::string BuildParams(const char* task, const char* moduleFilePath, const AZStd::string& builderGuid, const AZStd::string& jobDescriptionFile, const AZStd::string& jobResponseFile) const;
|
||||
AZStd::unique_ptr<AzToolsFramework::ProcessWatcher> LaunchProcess(const char* fullExePath, const AZStd::string& params) const;
|
||||
AZStd::unique_ptr<AzFramework::ProcessWatcher> LaunchProcess(const char* fullExePath, const AZStd::string& params) const;
|
||||
|
||||
//! Waits for the builder exe to send the job response and pumps stdout/err
|
||||
BuilderRunJobOutcome WaitForBuilderResponse(AssetBuilderSDK::JobCancelListener* jobCancelListener, AZ::u32 processTimeoutLimitInSeconds, AZStd::binary_semaphore* waitEvent) const;
|
||||
@@ -128,7 +128,7 @@ namespace AssetProcessor
|
||||
AZStd::binary_semaphore m_connectionEvent;
|
||||
|
||||
//! Optional process watcher
|
||||
AZStd::unique_ptr<AzToolsFramework::ProcessWatcher> m_processWatcher = nullptr;
|
||||
AZStd::unique_ptr<AzFramework::ProcessWatcher> m_processWatcher = nullptr;
|
||||
|
||||
//! Optional communicator, only available if we have a process watcher
|
||||
AZStd::unique_ptr<CommunicatorTracePrinter> m_tracePrinter = nullptr;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "CommunicatorTracePrinter.h"
|
||||
|
||||
CommunicatorTracePrinter::CommunicatorTracePrinter(AzToolsFramework::ProcessCommunicator* communicator, const char* window) :
|
||||
CommunicatorTracePrinter::CommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window) :
|
||||
m_communicator(communicator),
|
||||
m_window(window)
|
||||
{
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Process/ProcessCommunicator.h>
|
||||
#include <AzFramework/Process/ProcessCommunicator.h>
|
||||
|
||||
//! CommunicatorTracePrinter listens to stderr and stdout of a running process and writes its output to the AZ_Trace system
|
||||
//! Importantly, it does not do any blocking operations.
|
||||
class CommunicatorTracePrinter
|
||||
{
|
||||
public:
|
||||
CommunicatorTracePrinter(AzToolsFramework::ProcessCommunicator* communicator, const char* window);
|
||||
CommunicatorTracePrinter(AzFramework::ProcessCommunicator* communicator, const char* window);
|
||||
~CommunicatorTracePrinter();
|
||||
|
||||
// call this periodically to drain the buffers and write them.
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
|
||||
private:
|
||||
AZStd::string m_window;
|
||||
AzToolsFramework::ProcessCommunicator* m_communicator;
|
||||
AzFramework::ProcessCommunicator* m_communicator;
|
||||
char m_streamBuffer[128];
|
||||
AZStd::string m_stringBeingConcatenated;
|
||||
AZStd::string m_errorStringBeingConcatenated;
|
||||
|
||||
@@ -130,37 +130,36 @@ ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun()
|
||||
m_qtFileWatcher.addPath(assetDbPath);
|
||||
|
||||
// if our Gems file changes, make sure we watch that, too.
|
||||
QString gameName = AssetUtilities::ComputeGameName();
|
||||
QString gemsConfigFile = devRoot.filePath(gameName + "/gems.json");
|
||||
|
||||
m_qtFileWatcher.addPath(gemsConfigFile);
|
||||
QString projectPath = AssetUtilities::ComputeProjectPath();
|
||||
|
||||
QObject::connect(&m_qtFileWatcher, &QFileSystemWatcher::fileChanged, this, &GUIApplicationManager::FileChanged);
|
||||
QObject::connect(&m_qtFileWatcher, &QFileSystemWatcher::directoryChanged, this, &GUIApplicationManager::DirectoryChanged);
|
||||
|
||||
// Register a notifier for when the sys_game_folder property changes within the SettingsRegistry
|
||||
// Register a notifier for when the project_path property changes within the SettingsRegistry
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
auto onBootStrapGameFolderChanged = [this, cachedGameName = gameName](AZStd::string_view path, AZ::SettingsRegistryInterface::Type type)
|
||||
// Needs to be updated to project_path.
|
||||
auto OnProjectPathChanged = [this, cachedProjectPath = projectPath](AZStd::string_view path, AZ::SettingsRegistryInterface::Type)
|
||||
{
|
||||
constexpr auto projectKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
|
||||
+ "/sys_game_folder";
|
||||
if (projectKey == path && type == AZ::SettingsRegistryInterface::Type::String)
|
||||
constexpr auto projectPathKey =
|
||||
AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
|
||||
+ "/project_path";
|
||||
if (projectPathKey == path)
|
||||
{
|
||||
auto registry = AZ::SettingsRegistry::Get();
|
||||
AZ::SettingsRegistryInterface::FixedValueString newGameName;
|
||||
if (registry->Get(newGameName, path))
|
||||
AZ::SettingsRegistryInterface::FixedValueString newProjectPath;
|
||||
if (auto registry = AZ::SettingsRegistry::Get(); registry && registry->Get(newProjectPath, path))
|
||||
{
|
||||
// we only have to quit if the actual project name has changed, not if just the bootstrap has changed.
|
||||
if (cachedGameName.compare(newGameName.c_str()) != 0)
|
||||
// we only have to quit if the project path has changed, not if just the bootstrap has changed.
|
||||
if (cachedProjectPath.compare(newProjectPath.c_str()) != 0)
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Bootstrap.cfg Game Name changed from %s to %s. Quitting\n", cachedGameName.toUtf8().constData(), newGameName.c_str());
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "bootstrap.cfg Project Path changed from %s to %s. Quitting\n",
|
||||
cachedProjectPath.toUtf8().constData(), newProjectPath.c_str());
|
||||
QMetaObject::invokeMethod(this, "QuitRequested", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
m_bootstrapGameFolderChangedHandler = settingsRegistry->RegisterNotifier(AZStd::move(onBootStrapGameFolderChanged));
|
||||
m_bootstrapGameFolderChangedHandler = settingsRegistry->RegisterNotifier(AZStd::move(OnProjectPathChanged));
|
||||
}
|
||||
|
||||
return ApplicationManager::BeforeRunStatus::Status_Success;
|
||||
@@ -189,8 +188,13 @@ bool GUIApplicationManager::Run()
|
||||
qRegisterMetaType<AZ::u32>("AZ::u32");
|
||||
qRegisterMetaType<AZ::Uuid>("AZ::Uuid");
|
||||
|
||||
AZ::IO::FixedMaxPath engineRootPath;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
}
|
||||
AzQtComponents::StyleManager* styleManager = new AzQtComponents::StyleManager(qApp);
|
||||
styleManager->Initialize(qApp);
|
||||
styleManager->initialize(qApp, engineRootPath);
|
||||
|
||||
QDir engineRoot;
|
||||
AssetUtilities::ComputeAssetRoot(engineRoot);
|
||||
@@ -198,7 +202,8 @@ bool GUIApplicationManager::Run()
|
||||
AzQtComponents::StyleManager::addSearchPaths(
|
||||
QStringLiteral("style"),
|
||||
engineRoot.filePath(QStringLiteral("Code/Tools/AssetProcessor/native/ui/style")),
|
||||
QStringLiteral(":/AssetProcessor/style"));
|
||||
QStringLiteral(":/AssetProcessor/style"),
|
||||
engineRootPath);
|
||||
|
||||
m_mainWindow = new MainWindow(this);
|
||||
auto wrapper = new AzQtComponents::WindowDecorationWrapper(
|
||||
@@ -485,7 +490,7 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
QVariant settingValue = loader.value("Game Projects/enabled_game_projects");
|
||||
QStringList compiledProjects = settingValue.toStringList();
|
||||
|
||||
if(compiledProjects.isEmpty())
|
||||
if (compiledProjects.isEmpty())
|
||||
{
|
||||
QByteArray byteArray;
|
||||
QFile jsonFile;
|
||||
@@ -497,12 +502,12 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
QJsonObject settingsObject = QJsonDocument::fromJson(byteArray).object();
|
||||
QJsonArray projectsArray = settingsObject["Game Projects"].toArray();
|
||||
|
||||
if(!projectsArray.isEmpty())
|
||||
if (!projectsArray.isEmpty())
|
||||
{
|
||||
auto projectObject = projectsArray[0].toObject();
|
||||
QString projects = projectObject["default_value"].toString();
|
||||
|
||||
if(!projects.isEmpty())
|
||||
if (!projects.isEmpty())
|
||||
{
|
||||
compiledProjects = projects.split(',');
|
||||
usingDefaults = true;
|
||||
@@ -515,13 +520,13 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
compiledProjects[i] = compiledProjects[i].trimmed();
|
||||
}
|
||||
|
||||
QString enabledProject = AssetUtilities::ComputeGameName();
|
||||
QString enabledProject = AssetUtilities::ComputeProjectName();
|
||||
|
||||
if(!compiledProjects.contains(enabledProject))
|
||||
if (!compiledProjects.contains(enabledProject))
|
||||
{
|
||||
QString projectSourceLine;
|
||||
|
||||
if(usingDefaults)
|
||||
if (usingDefaults)
|
||||
{
|
||||
projectSourceLine = QString("The currently compiled projects according to the defaults in %1 are '%2'").arg(defaultSettingsFile);
|
||||
}
|
||||
@@ -531,7 +536,6 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
}
|
||||
|
||||
projectSourceLine = projectSourceLine.arg(compiledProjects.join(", "));
|
||||
|
||||
friendlyErrorMessage = QString("An error occurred while loading gems.\n"
|
||||
"The enabled game project is not in the list of compiled projects.\n"
|
||||
"Please configure the enabled project to be compiled and rebuild or change the enabled project.\n"
|
||||
@@ -539,13 +543,12 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
"%2\n"
|
||||
"Full error text:\n"
|
||||
"%3"
|
||||
).arg(enabledProject).arg(projectSourceLine).arg(message).arg(AssetUtilities::GameFolderOverrideParameter);
|
||||
).arg(enabledProject).arg(projectSourceLine).arg(message).arg(AssetUtilities::ProjectPathOverrideParameter);
|
||||
}
|
||||
}
|
||||
|
||||
if(friendlyErrorMessage.isEmpty())
|
||||
if (friendlyErrorMessage.isEmpty())
|
||||
{
|
||||
|
||||
friendlyErrorMessage = QString("An error occurred while loading gems.\n"
|
||||
"This can happen when new gems are added to a project, but those gems need to be built in order to function.\n"
|
||||
"This can also happen when switching to a different project, one which uses gems which are not yet built.\n"
|
||||
@@ -631,34 +634,18 @@ void GUIApplicationManager::CreateQtApplication()
|
||||
m_qApp = new QApplication(*m_frameworkApp.GetArgC(), *m_frameworkApp.GetArgV());
|
||||
}
|
||||
|
||||
void GUIApplicationManager::DirectoryChanged(QString path)
|
||||
void GUIApplicationManager::DirectoryChanged([[maybe_unused]] QString path)
|
||||
{
|
||||
AZ_UNUSED(path);
|
||||
QDir devRoot = ApplicationManager::GetSystemRoot();
|
||||
QString cacheRoot = devRoot.filePath("Cache");
|
||||
if (!QDir(cacheRoot).exists())
|
||||
QDir projectCacheRoot;
|
||||
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
||||
if (!projectCacheRoot.exists() || !projectCacheRoot.exists("assetdb.sqlite"))
|
||||
{
|
||||
//Cache directory is removed we need to restart
|
||||
// If either the Cache directory or database file has been removed, we need to restart
|
||||
QTimer::singleShot(200, this, [this]()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
QDir projectCacheRoot;
|
||||
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
||||
QString assetDbPath = projectCacheRoot.filePath("assetdb.sqlite");
|
||||
|
||||
if (!QFile::exists(assetDbPath))
|
||||
{
|
||||
// even if cache directory exists but the the database file is missing we need to restart
|
||||
QTimer::singleShot(200, this, [this]()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUIApplicationManager::FileChanged(QString path)
|
||||
@@ -696,70 +683,6 @@ void GUIApplicationManager::FileChanged(QString path)
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (AssetUtilities::NormalizeFilePath(path).endsWith("gems.json", Qt::CaseInsensitive))
|
||||
{
|
||||
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> oldGemsList = GetPlatformConfiguration()->GetGemsInformation();
|
||||
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> newGemsList;
|
||||
QDir assetRoot;
|
||||
AssetUtilities::ComputeAssetRoot(assetRoot);
|
||||
AzToolsFramework::AssetUtils::GetGemsInfo(GetSystemRoot().absolutePath().toUtf8().constData(), assetRoot.absolutePath().toUtf8().constData(), GetGameName().toUtf8().constData(), newGemsList);
|
||||
|
||||
for (auto oldGemIter = oldGemsList.begin(); oldGemIter != oldGemsList.end();)
|
||||
{
|
||||
bool gemMatch = false;
|
||||
for (auto newGemIter = newGemsList.begin(); newGemIter != newGemsList.end();)
|
||||
{
|
||||
if (AzFramework::StringFunc::Equal(oldGemIter->m_identifier.c_str(), newGemIter->m_identifier.c_str()))
|
||||
{
|
||||
gemMatch = true;
|
||||
newGemIter = newGemsList.erase(newGemIter);
|
||||
break;
|
||||
}
|
||||
newGemIter++;
|
||||
}
|
||||
|
||||
if (gemMatch)
|
||||
{
|
||||
oldGemIter = oldGemsList.erase(oldGemIter);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldGemIter++;
|
||||
}
|
||||
}
|
||||
|
||||
// oldGemslist should contain the list of gems that got removed and newGemsList should contain the list of gems that were added to the project
|
||||
// if the project requires to be built again then we will quit otherwise we can restart
|
||||
bool exitApp = false;
|
||||
for (const AzToolsFramework::AssetUtils::GemInfo& gemInfo : newGemsList)
|
||||
{
|
||||
if (!gemInfo.m_assetOnly)
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Gem %s was added to the project and require building. Quitting\n", gemInfo.m_gemName.c_str());
|
||||
exitApp = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (exitApp)
|
||||
{
|
||||
QuitRequested();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oldGemsList.size() || newGemsList.size())
|
||||
{
|
||||
if (oldGemsList.size())
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, "Gem(s) were removed from the project. Restarting\n");
|
||||
}
|
||||
else if (newGemsList.size())
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, "Assets only gem(s) were added to the project. Restarting\n");
|
||||
}
|
||||
QMetaObject::invokeMethod(this, "Restart", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GUIApplicationManager::InitApplicationServer()
|
||||
|
||||
@@ -20,43 +20,48 @@ AZ_POP_DISABLE_WARNING
|
||||
#include "native/AssetDatabase/AssetDatabase.h"
|
||||
#include "native/assetprocessor.h"
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/FileTag/FileTagBus.h>
|
||||
#include <AzCore/std/string/wildcard.h>
|
||||
#include <AzCore/XML/rapidxml.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/FileTag/FileTag.h>
|
||||
#include <AzFramework/FileTag/FileTagBus.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
|
||||
namespace AssetProcessor
|
||||
{
|
||||
const char* EngineFolder = "Engine";
|
||||
|
||||
AZStd::string GetXMLDependenciesFile(const AZStd::string& fullPath, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AZStd::string& tokenName)
|
||||
AZStd::string GetXMLDependenciesFile(const AZStd::string& fullPath, const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AZStd::string& tokenName)
|
||||
{
|
||||
AZStd::string xmlDependenciesFileFullPath;
|
||||
AZ::IO::Path xmlDependenciesFileFullPath;
|
||||
tokenName = EngineFolder;
|
||||
for (const AzToolsFramework::AssetUtils::GemInfo& gemElement : gemInfoList)
|
||||
for (const AzFramework::GemInfo& gemElement : gemInfoList)
|
||||
{
|
||||
if (AzFramework::StringFunc::StartsWith(fullPath.c_str(), gemElement.m_absoluteFilePath.c_str()) || AzFramework::StringFunc::Equal(gemElement.m_absoluteFilePath.c_str(), fullPath.c_str()))
|
||||
for (const AZ::IO::Path& absoluteSourcePath : gemElement.m_absoluteSourcePaths)
|
||||
{
|
||||
AZStd::string fileName = AZStd::string::format("%s_Dependencies.xml", gemElement.m_gemName.c_str());
|
||||
AzFramework::StringFunc::Path::ConstructFull(gemElement.m_absoluteFilePath.c_str(), AzToolsFramework::AssetUtils::GemInfo::GetGemAssetFolder().c_str(), fileName.c_str() , "xml", xmlDependenciesFileFullPath);
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(xmlDependenciesFileFullPath.c_str()))
|
||||
if (AZ::StringFunc::StartsWith(fullPath, absoluteSourcePath.Native()) || AZ::StringFunc::Equal(absoluteSourcePath.Native(), fullPath))
|
||||
{
|
||||
tokenName = gemElement.m_gemName;
|
||||
return xmlDependenciesFileFullPath;
|
||||
xmlDependenciesFileFullPath /= AzFramework::GemInfo::GetGemAssetFolder();
|
||||
xmlDependenciesFileFullPath /= AZStd::string::format("%s_Dependencies.xml", gemElement.m_gemName.c_str());;
|
||||
if (AZ::IO::FileIOBase::GetInstance()->Exists(xmlDependenciesFileFullPath.c_str()))
|
||||
{
|
||||
tokenName = gemElement.m_gemName;
|
||||
return xmlDependenciesFileFullPath.Native();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we are here than either the %gemName%_Dependencies.xml file does not exists or the user inputted path is not inside a gems folder,
|
||||
// in both the cases we will return the engine dependencies file
|
||||
const char* devRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@");
|
||||
AzFramework::StringFunc::Path::ConstructFull(devRoot, EngineFolder, "Engine_Dependencies.xml", "xml", xmlDependenciesFileFullPath);
|
||||
xmlDependenciesFileFullPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@");
|
||||
xmlDependenciesFileFullPath /= EngineFolder;
|
||||
xmlDependenciesFileFullPath /= "Engine_Dependencies.xml";
|
||||
|
||||
return xmlDependenciesFileFullPath;
|
||||
return xmlDependenciesFileFullPath.Native();
|
||||
}
|
||||
|
||||
const int MissingDependencyScanner::DefaultMaxScanIteration = 800;
|
||||
@@ -731,7 +736,7 @@ namespace AssetProcessor
|
||||
}
|
||||
}
|
||||
|
||||
bool MissingDependencyScanner::PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AZStd::string& dependencyTokenName)
|
||||
bool MissingDependencyScanner::PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AZStd::string& dependencyTokenName)
|
||||
{
|
||||
AZStd::string xmlDependenciesFullFilePath = GetXMLDependenciesFile(scanFolderPath, gemInfoList, dependencyTokenName);
|
||||
if (xmlDependenciesFullFilePath.empty())
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace AssetProcessor
|
||||
|
||||
void RegisterSpecializedScanner(AZStd::shared_ptr<SpecializedDependencyScanner> scanner);
|
||||
|
||||
bool PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList, AZStd::string& dependencyTokenName);
|
||||
bool PopulateRulesForScanFolder(const AZStd::string& scanFolderPath, const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AZStd::string& dependencyTokenName);
|
||||
|
||||
protected:
|
||||
bool RunScan(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
||||
#include <QVector>
|
||||
#include <QSet>
|
||||
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <native/utilities/assetUtils.h>
|
||||
#include <native/AssetManager/assetScanFolderInfo.h>
|
||||
@@ -29,10 +30,15 @@
|
||||
#include <AzToolsFramework/Asset/AssetUtils.h>
|
||||
#endif
|
||||
|
||||
class QSettings;
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class SettingsRegistryInterface;
|
||||
}
|
||||
|
||||
namespace AssetProcessor
|
||||
{
|
||||
inline constexpr const char* AssetProcessorSettingsKey{ "/Amazon/AssetProcessor/Settings" };
|
||||
class PlatformConfiguration;
|
||||
class ScanFolderInfo;
|
||||
extern const char AssetConfigPlatformDir[];
|
||||
@@ -105,6 +111,73 @@ namespace AssetProcessor
|
||||
virtual const ExcludeRecognizerContainer& GetExcludeAssetRecognizerContainer() const = 0;
|
||||
};
|
||||
|
||||
//! Visitor for reading the "/Amazon/AssetProcessor/Settings/ScanFolder *" entries from the Settings Registry
|
||||
//! Expects the key to path to the visitor to be "/Amazon/AssetProcessor/Settings"
|
||||
struct ScanFolderVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName,
|
||||
AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override;
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) override;
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override;
|
||||
|
||||
struct ScanFolderInfo
|
||||
{
|
||||
AZStd::string m_scanFolderIdentifier;
|
||||
AZStd::string m_scanFolderDisplayName;
|
||||
AZ::IO::Path m_watchPath{ AZ::IO::PosixPathSeparator };
|
||||
AZStd::vector<AZStd::string> m_includeIdentifiers;
|
||||
AZStd::vector<AZStd::string> m_excludeIdentifiers;
|
||||
AZStd::string m_outputPrefix;
|
||||
int m_scanOrder{};
|
||||
bool m_isRecursive{};
|
||||
};
|
||||
AZStd::vector<ScanFolderInfo> m_scanFolderInfos;
|
||||
private:
|
||||
AZStd::stack<AZStd::string> m_scanFolderStack;
|
||||
};
|
||||
|
||||
struct ExcludeVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName,
|
||||
AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override;
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override;
|
||||
|
||||
AZStd::vector<ExcludeAssetRecognizer> m_excludeAssetRecognizers;
|
||||
private:
|
||||
AZStd::stack<AZStd::string> m_excludeNameStack;
|
||||
};
|
||||
|
||||
struct RCVisitor
|
||||
: AZ::SettingsRegistryInterface::Visitor
|
||||
{
|
||||
RCVisitor(const AZ::SettingsRegistryInterface& settingsRegistry, const AZStd::vector<AssetBuilderSDK::PlatformInfo>& enabledPlatforms)
|
||||
: m_registry(settingsRegistry)
|
||||
, m_enabledPlatforms(enabledPlatforms)
|
||||
{
|
||||
}
|
||||
AZ::SettingsRegistryInterface::VisitResponse Traverse(AZStd::string_view jsonPath, AZStd::string_view valueName,
|
||||
AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type) override;
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value) override;
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZ::s64 value) override;
|
||||
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, AZStd::string_view value) override;
|
||||
|
||||
struct RCAssetRecognizer
|
||||
{
|
||||
AssetRecognizer m_recognizer;
|
||||
AZStd::string m_defaultParams;
|
||||
bool m_ignore{};
|
||||
};
|
||||
AZStd::vector<RCAssetRecognizer> m_assetRecognizers;
|
||||
private:
|
||||
void ApplyParamsOverrides(AZStd::string_view path);
|
||||
|
||||
AZStd::stack<AZStd::string> m_rcNameStack;
|
||||
const AZ::SettingsRegistryInterface& m_registry;
|
||||
const AZStd::vector<AssetBuilderSDK::PlatformInfo>& m_enabledPlatforms;
|
||||
};
|
||||
|
||||
/** Reads the platform ini configuration file to determine
|
||||
* platforms for which assets needs to be build
|
||||
*/
|
||||
@@ -127,22 +200,23 @@ namespace AssetProcessor
|
||||
* Note that order of the config files is relevant - later files override settings in
|
||||
* files that are earlier.
|
||||
**/
|
||||
bool InitializeFromConfigFiles(QString absoluteSystemRoot, QString absoluteAssetRoot, QString gameName, bool addPlatformConfigs = true, bool addGemsConfigs = true);
|
||||
bool InitializeFromConfigFiles(const QString& absoluteSystemRoot, const QString& absoluteAssetRoot, const QString& projectPath, bool addPlatformConfigs = true, bool addGemsConfigs = true);
|
||||
|
||||
QString PlatformName(unsigned int platformCrc) const;
|
||||
QString RendererName(unsigned int rendererCrc) const;
|
||||
//! Merge an AssetProcessor*Config.ini path to the Settings Registry
|
||||
//! The settings are anchored underneath the AssetProcessor::AssetProcessorSettingsKey JSON pointer
|
||||
static bool MergeConfigFileToSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry, const AZ::IO::PathView& filePathView);
|
||||
|
||||
const AZStd::vector<AssetBuilderSDK::PlatformInfo>& GetEnabledPlatforms() const;
|
||||
const AssetBuilderSDK::PlatformInfo* const GetPlatformByIdentifier(const char* identifier) const;
|
||||
|
||||
//! Add AssetProcessor config files from platform specific folders
|
||||
bool AddPlatformConfigFilePaths(QStringList& configList);
|
||||
bool AddPlatformConfigFilePaths(AZStd::vector<AZ::IO::Path>& configList);
|
||||
|
||||
int MetaDataFileTypesCount() const { return m_metaDataFileTypes.count(); }
|
||||
// Metadata file types are (meta file extension, original file extension - or blank if its tacked on the end instead of replacing).
|
||||
// so for example if its
|
||||
// blah.tif + blah.tif.metadata, then its ("metadata", "")
|
||||
// but if its blah.tif + blah.metadata (rplacing tif, data is lost) then its ("metadata", "tif")
|
||||
// but if its blah.tif + blah.metadata (replacing tif, data is lost) then its ("metadata", "tif")
|
||||
QPair<QString, QString> GetMetaDataFileTypeAt(int pos) const;
|
||||
|
||||
// Metadata extensions can also be a real file, to create a dependency on file types if a specific file changes
|
||||
@@ -160,7 +234,7 @@ namespace AssetProcessor
|
||||
int GetScanFolderCount() const;
|
||||
|
||||
//! Return the gems info list
|
||||
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> GetGemsInformation() const;
|
||||
AZStd::vector<AzFramework::GemInfo> GetGemsInformation() const;
|
||||
|
||||
//! Retrieve the scan folder at a given index.
|
||||
AssetProcessor::ScanFolderInfo& GetScanFolderAt(int index);
|
||||
@@ -249,18 +323,18 @@ namespace AssetProcessor
|
||||
protected:
|
||||
|
||||
// call this first, to populate the list of platform informations
|
||||
void ReadPlatformInfosFromConfigFile(QString fileSource);
|
||||
void ReadPlatformInfosFromSettingsRegistry();
|
||||
// call this next, in order to find out what platforms are enabled
|
||||
void PopulateEnabledPlatforms(QStringList configFiles);
|
||||
// finaly, call this, in order to delete the platforminfos for non-enabled platforms
|
||||
void PopulateEnabledPlatforms();
|
||||
// finally, call this, in order to delete the platforminfos for non-enabled platforms
|
||||
void FinalizeEnabledPlatforms();
|
||||
|
||||
// iterate over all the gems and add their folders to the "scan folders" list as appropriate.
|
||||
void AddGemScanFolders(const AZStd::vector<AzToolsFramework::AssetUtils::GemInfo>& gemInfoList);
|
||||
void AddGemScanFolders(const AZStd::vector<AzFramework::GemInfo>& gemInfoList);
|
||||
|
||||
void ReadEnabledPlatformsFromConfigFile(QString fileSource);
|
||||
bool ReadRecognizersFromConfigFile(QString fileSource, bool skipScanFolders = false, QStringList scanFolderPatterns = QStringList() );
|
||||
void ReadMetaDataFromConfigFile(QString fileSource);
|
||||
void ReadEnabledPlatformsFromSettingsRegistry();
|
||||
bool ReadRecognizersFromSettingsRegistry(const QString& assetRoot, bool skipScanFolders = false, QStringList scanFolderPatterns = QStringList() );
|
||||
void ReadMetaDataFromSettingsRegistry();
|
||||
|
||||
private:
|
||||
AZStd::vector<AssetBuilderSDK::PlatformInfo> m_enabledPlatforms;
|
||||
@@ -269,15 +343,13 @@ namespace AssetProcessor
|
||||
AZStd::vector<AssetProcessor::ScanFolderInfo> m_scanFolders;
|
||||
QList<QPair<QString, QString> > m_metaDataFileTypes;
|
||||
QSet<QString> m_metaDataRealFiles;
|
||||
AZStd::vector<AzToolsFramework::AssetUtils::GemInfo> m_gemInfoList;
|
||||
AZStd::vector<AzFramework::GemInfo> m_gemInfoList;
|
||||
|
||||
int m_minJobs = 1;
|
||||
int m_maxJobs = 3;
|
||||
|
||||
// used only during file read, keeps the total running list of all the enabled platforms from all config files and command lines
|
||||
QStringList m_tempEnabledPlatforms;
|
||||
|
||||
bool ReadRecognizerFromConfig(AssetRecognizer& target, QSettings& loader); // assumes the group is already selected
|
||||
AZStd::vector<AZStd::string> m_tempEnabledPlatforms;
|
||||
|
||||
///! if non-empty, fatalError contains the error that occurred during read.
|
||||
///! it will be printed out to the log when
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QTemporaryDir>
|
||||
#include <QTextStream>
|
||||
#include <QSettings>
|
||||
#include <QTimeZone>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
@@ -38,7 +37,9 @@
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Platform/PlatformDefaults.h>
|
||||
#include <AzToolsFramework/UI/Logging/LogLine.h>
|
||||
#include <xxhash/xxhash.h>
|
||||
|
||||
@@ -77,7 +78,7 @@ namespace AssetUtilsInternal
|
||||
{
|
||||
if (waitTimeInSeconds < 0)
|
||||
{
|
||||
AZ_Warning("Asset Processor", waitTimeInSeconds >= 0, "Invalid timeout specified by the user")
|
||||
AZ_Warning("Asset Processor", waitTimeInSeconds >= 0, "Invalid timeout specified by the user");
|
||||
waitTimeInSeconds = 0;
|
||||
}
|
||||
bool failureOccurredOnce = false; // used for logging.
|
||||
@@ -152,12 +153,64 @@ namespace AssetUtilsInternal
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool DumpAssetProcessorUserSettingsToFile(AZ::SettingsRegistryInterface& settingsRegistry,
|
||||
const AZ::IO::FixedMaxPath& setregPath)
|
||||
{
|
||||
// The AssetProcessor settings are currently under the Bootstrap object(This may change in the future
|
||||
constexpr AZStd::string_view AssetProcessorUserSettingsRootKey = AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey;
|
||||
AZStd::string apSettingsJson;
|
||||
AZ::IO::ByteContainerStream apSettingsStream(&apSettingsJson);
|
||||
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings apDumperSettings;
|
||||
apDumperSettings.m_prettifyOutput = true;
|
||||
apDumperSettings.m_includeFilter = [&AssetProcessorUserSettingsRootKey](AZStd::string_view path)
|
||||
{
|
||||
// The AssetUtils only updates the following keys in the registry
|
||||
// Dump them all out to the setreg file
|
||||
auto allowedListKey = AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorUserSettingsRootKey)
|
||||
+ "/allowed_list";
|
||||
auto branchTokenKey = AZ::SettingsRegistryInterface::FixedValueString(AssetProcessorUserSettingsRootKey)
|
||||
+ "/assetProcessor_branch_token";
|
||||
// The objects leading up to the keys to dump must be included in order the keys to be dumped
|
||||
return allowedListKey.starts_with(path.substr(0, allowedListKey.size()))
|
||||
|| branchTokenKey.starts_with(path.substr(0, branchTokenKey.size()));
|
||||
};
|
||||
apDumperSettings.m_jsonPointerPrefix = AssetProcessorUserSettingsRootKey;
|
||||
|
||||
if (AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(settingsRegistry, AssetProcessorUserSettingsRootKey,
|
||||
apSettingsStream, apDumperSettings))
|
||||
{
|
||||
|
||||
constexpr auto modeFlags = AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE
|
||||
| AZ::IO::SystemFile::SF_OPEN_CREATE_PATH;
|
||||
if (AZ::IO::SystemFile apSetregFile; apSetregFile.Open(setregPath.c_str(), modeFlags))
|
||||
{
|
||||
size_t bytesWritten = apSetregFile.Write(apSettingsJson.data(), apSettingsJson.size());
|
||||
return bytesWritten == apSettingsJson.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to open AssetProcessor user setreg file (%s)\n", setregPath.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Dump of AssetProcessor User Settings failed at JSON pointer %.*s \n",
|
||||
aznumeric_cast<int>(AssetProcessorUserSettingsRootKey.size()), AssetProcessorUserSettingsRootKey.data());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace AssetUtilities
|
||||
{
|
||||
constexpr AZStd::string_view AssetProcessorUserSetregRelPath = "user/Registry/asset_processor.setreg";
|
||||
|
||||
// do not place Qt objects in global scope, they allocate and refcount threaded data.
|
||||
AZ::SettingsRegistryInterface::FixedValueString s_gameName;
|
||||
AZ::SettingsRegistryInterface::FixedValueString s_projectPath;
|
||||
AZ::SettingsRegistryInterface::FixedValueString s_projectName;
|
||||
AZ::SettingsRegistryInterface::FixedValueString s_assetRoot;
|
||||
AZ::SettingsRegistryInterface::FixedValueString s_assetServerAddress;
|
||||
AZ::SettingsRegistryInterface::FixedValueString s_cachedEngineRoot;
|
||||
@@ -191,7 +244,7 @@ namespace AssetUtilities
|
||||
|
||||
void ResetGameName()
|
||||
{
|
||||
s_gameName = {};
|
||||
s_projectName = {};
|
||||
}
|
||||
|
||||
bool CopyDirectory(QDir source, QDir destination)
|
||||
@@ -245,7 +298,7 @@ namespace AssetUtilities
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComputeAssetRoot(QDir& root, const QDir* appRootOverride)
|
||||
bool ComputeAssetRoot(QDir& root, const QDir* rootOverride)
|
||||
{
|
||||
if (!s_assetRoot.empty())
|
||||
{
|
||||
@@ -253,10 +306,10 @@ namespace AssetUtilities
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the appRoot if supplied is supplied and not an empty string
|
||||
if (appRootOverride && !appRootOverride->path().isEmpty())
|
||||
// Use the override if supplied and not an empty string
|
||||
if (rootOverride && !rootOverride->path().isEmpty())
|
||||
{
|
||||
root = *appRootOverride;
|
||||
root = *rootOverride;
|
||||
s_assetRoot = root.absolutePath().toUtf8().constData();
|
||||
return true;
|
||||
}
|
||||
@@ -288,7 +341,7 @@ namespace AssetUtilities
|
||||
return true;
|
||||
}
|
||||
|
||||
// The EngineRootFolder Key has not been found in the SettingsRegistry, log an warning about
|
||||
// The EngineRootFolder Key has not been found in the SettingsRegistry
|
||||
auto engineRootError = AZ::SettingsRegistryInterface::FixedValueString::format("The EngineRootFolder is not set in the SettingsRegistry at key %s.",
|
||||
AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
|
||||
AssetProcessor::MessageInfoBus::Broadcast(&AssetProcessor::MessageInfoBusTraits::OnErrorMessage, engineRootError.c_str());
|
||||
@@ -296,7 +349,7 @@ namespace AssetUtilities
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Get the engine root folder
|
||||
//! Get the external engine root folder if the engine is external to the current root folder.
|
||||
//! If the current root folder is also the engine folder, then this behaves the same as ComputeEngineRoot
|
||||
bool ComputeEngineRoot(QDir& root, const QDir* engineRootOverride)
|
||||
{
|
||||
@@ -312,6 +365,7 @@ namespace AssetUtilities
|
||||
AssetUtilities::ComputeAssetRoot(root, engineRootOverride);
|
||||
}
|
||||
|
||||
AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
// Use the engineRootOverride if supplied and not empty
|
||||
if (engineRootOverride && !engineRootOverride->path().isEmpty())
|
||||
{
|
||||
@@ -320,11 +374,11 @@ namespace AssetUtilities
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
if (settingsRegistry == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPathString engineRootFolder;
|
||||
if (settingsRegistry->Get(engineRootFolder, AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
|
||||
{
|
||||
@@ -336,7 +390,7 @@ namespace AssetUtilities
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MakeFileWritable(QString fileName)
|
||||
bool MakeFileWritable(const QString& fileName)
|
||||
{
|
||||
#if defined WIN32
|
||||
DWORD fileAttributes = GetFileAttributesA(fileName.toUtf8());
|
||||
@@ -386,7 +440,7 @@ namespace AssetUtilities
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CheckCanLock(QString fileName)
|
||||
bool CheckCanLock(const QString& fileName)
|
||||
{
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
AZStd::wstring usableFileName;
|
||||
@@ -419,42 +473,55 @@ namespace AssetUtilities
|
||||
#endif
|
||||
}
|
||||
|
||||
QString ComputeGameName(QString gameNameOverride, bool force)
|
||||
QString ComputeProjectName(QString gameNameOverride, bool force)
|
||||
{
|
||||
if (force || s_gameName.empty())
|
||||
if (force || s_projectName.empty())
|
||||
{
|
||||
// if its been specified on the command line, then ignore bootstrap:
|
||||
// Override Game Name if a non-empty override string has been supplied
|
||||
if (!gameNameOverride.isEmpty())
|
||||
{
|
||||
s_projectName = gameNameOverride.toUtf8().constData();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_projectName = AZ::Utils::GetProjectName();
|
||||
}
|
||||
}
|
||||
|
||||
return QString::fromUtf8(s_projectName.c_str(), aznumeric_cast<int>(s_projectName.size()));
|
||||
}
|
||||
|
||||
QString ComputeProjectPath()
|
||||
{
|
||||
if (s_projectPath.empty())
|
||||
{
|
||||
// Check command-line args first
|
||||
QStringList args = QCoreApplication::arguments();
|
||||
for (QString arg : args)
|
||||
{
|
||||
if (arg.contains(QString("/%1=").arg(GameFolderOverrideParameter), Qt::CaseInsensitive) || arg.contains(QString("--%1=").arg(GameFolderOverrideParameter), Qt::CaseInsensitive))
|
||||
if (arg.contains(QString("/%1=").arg(ProjectPathOverrideParameter), Qt::CaseInsensitive)
|
||||
|| arg.contains(QString("--%1=").arg(ProjectPathOverrideParameter), Qt::CaseInsensitive))
|
||||
{
|
||||
QString rawValueString = arg.split("=")[1].trimmed();
|
||||
if (!rawValueString.isEmpty())
|
||||
{
|
||||
s_gameName = rawValueString.toUtf8().constData();
|
||||
return rawValueString;
|
||||
QDir path(rawValueString);
|
||||
if (path.isAbsolute())
|
||||
{
|
||||
s_projectPath = rawValueString.toUtf8().constData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override Game Name if a non-empty override string has been supplied
|
||||
if (!gameNameOverride.isEmpty())
|
||||
{
|
||||
s_gameName = gameNameOverride.toUtf8().constData();
|
||||
}
|
||||
else
|
||||
{
|
||||
QDir engineRoot;
|
||||
if (!AssetUtilities::ComputeEngineRoot(engineRoot))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
s_gameName = ReadGameNameFromSettingsRegistry(engineRoot.absolutePath()).toUtf8().constData();
|
||||
}
|
||||
}
|
||||
|
||||
return QString::fromUtf8(s_gameName.c_str(), aznumeric_cast<int>(s_gameName.size()));
|
||||
if (s_projectPath.empty())
|
||||
{
|
||||
s_projectPath = AZ::Utils::GetProjectPath();
|
||||
}
|
||||
|
||||
return QString::fromUtf8(s_projectPath.c_str(), aznumeric_cast<int>(s_projectPath.size()));
|
||||
}
|
||||
|
||||
bool InServerMode()
|
||||
@@ -479,7 +546,7 @@ namespace AssetUtilities
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, "Invalid server address, please check the AssetProcessorPlatformConfig.ini file \
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, "Invalid server address, please check the AssetProcessorPlatformConfig.setreg file \
|
||||
to ensure that the address is correct. Asset Processor won't be running in server mode.");
|
||||
}
|
||||
|
||||
@@ -517,19 +584,18 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
}
|
||||
}
|
||||
|
||||
QDir engineRoot;
|
||||
ComputeEngineRoot(engineRoot);
|
||||
QString rootConfigFile = engineRoot.absoluteFilePath("AssetProcessorPlatformConfig.ini");
|
||||
|
||||
if (QFile::exists(rootConfigFile))
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
if (settingsRegistry)
|
||||
{
|
||||
QString address;
|
||||
QSettings loader(rootConfigFile, QSettings::IniFormat);
|
||||
loader.beginGroup("Server");
|
||||
address = loader.value("cacheServerAddress", QString()).toString();
|
||||
loader.endGroup();
|
||||
s_assetServerAddress = address.toUtf8().constData();
|
||||
return address;
|
||||
AZStd::string address;
|
||||
if (settingsRegistry->Get(address, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey)
|
||||
+ "/Server/cacheServerAddress"))
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, "Server Address: %s\n", address.c_str());
|
||||
}
|
||||
s_assetServerAddress = address;
|
||||
|
||||
return QString::fromUtf8(address.data(), aznumeric_cast<int>(address.size()));
|
||||
}
|
||||
|
||||
return QString();
|
||||
@@ -549,18 +615,12 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
return *s_fileHashSetting;
|
||||
}
|
||||
|
||||
QDir engineRoot;
|
||||
ComputeEngineRoot(engineRoot);
|
||||
QString rootConfigFile = engineRoot.absoluteFilePath("AssetProcessorPlatformConfig.ini");
|
||||
|
||||
if (QFile::exists(rootConfigFile))
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
if (settingsRegistry)
|
||||
{
|
||||
bool curValue;
|
||||
QSettings loader(rootConfigFile, QSettings::IniFormat);
|
||||
loader.beginGroup("Fingerprinting");
|
||||
curValue = loader.value("UseFileHashing", true).toBool();
|
||||
loader.endGroup();
|
||||
|
||||
bool curValue = true;
|
||||
settingsRegistry->Get(curValue, AZ::SettingsRegistryInterface::FixedValueString(AssetProcessor::AssetProcessorSettingsKey)
|
||||
+ "/Fingerprinting/UseFileHashing");
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, "UseFileHashing: %s\n", curValue ? "True" : "False");
|
||||
s_fileHashSetting = curValue;
|
||||
|
||||
@@ -573,46 +633,8 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
return *s_fileHashSetting;
|
||||
}
|
||||
|
||||
QString ReadGameNameFromSettingsRegistry(QString initialFolder /*= QString()*/)
|
||||
QString ReadAllowedlistFromSettingsRegistry([[maybe_unused]] QString initialFolder)
|
||||
{
|
||||
if (initialFolder.isEmpty())
|
||||
{
|
||||
QDir engineRoot;
|
||||
if (!AssetUtilities::ComputeEngineRoot(engineRoot))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
initialFolder = engineRoot.absolutePath();
|
||||
}
|
||||
|
||||
constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits<char>::length("/sys_game_folder");
|
||||
AZStd::fixed_string<BufferSize> projectKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey };
|
||||
projectKey += "/sys_game_folder";
|
||||
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectName;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry && settingsRegistry->Get(projectName, projectKey))
|
||||
{
|
||||
return QString::fromUtf8(projectName.c_str(), aznumeric_cast<int>(projectName.size()));
|
||||
}
|
||||
|
||||
AZ_Warning("AssetUtils", false, "Unable to find the Project Name(sys_game_folder) key in the settings registry");
|
||||
return {};
|
||||
}
|
||||
|
||||
QString ReadAllowedlistFromSettingsRegistry(QString initialFolder /*= QString()*/)
|
||||
{
|
||||
if (initialFolder.isEmpty())
|
||||
{
|
||||
QDir assetRoot;
|
||||
if (!AssetUtilities::ComputeAssetRoot(assetRoot))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
initialFolder = assetRoot.absolutePath();
|
||||
}
|
||||
|
||||
constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits<char>::length("/allowed_list");
|
||||
AZStd::fixed_string<BufferSize> allowedListKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey };
|
||||
allowedListKey += "/allowed_list";
|
||||
@@ -626,18 +648,8 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
return {};
|
||||
}
|
||||
|
||||
QString ReadRemoteIpFromSettingsRegistry(QString initialFolder /*= QString()*/)
|
||||
QString ReadRemoteIpFromSettingsRegistry([[maybe_unused]] QString initialFolder)
|
||||
{
|
||||
if (initialFolder.isEmpty())
|
||||
{
|
||||
QDir engineRoot;
|
||||
if (!AssetUtilities::ComputeEngineRoot(engineRoot))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
initialFolder = engineRoot.absolutePath();
|
||||
}
|
||||
constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits<char>::length("/remote_ip");
|
||||
AZStd::fixed_string<BufferSize> remoteIpKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey };
|
||||
remoteIpKey += "/remote_ip";
|
||||
@@ -651,159 +663,44 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
return {};
|
||||
}
|
||||
|
||||
bool WriteAllowedlistToBootstrap(QStringList newAllowedList)
|
||||
bool WriteAllowedlistToSettingsRegistry(const QStringList& newAllowedList)
|
||||
{
|
||||
QDir assetRoot;
|
||||
ComputeAssetRoot(assetRoot);
|
||||
QString bootstrapFilename = assetRoot.filePath("bootstrap.cfg");
|
||||
QFile bootstrapFile(bootstrapFilename);
|
||||
AZ::IO::FixedMaxPath assetProcessorUserSetregPath = AZ::Utils::GetProjectPath();
|
||||
assetProcessorUserSetregPath /= AssetProcessorUserSetregRelPath;
|
||||
|
||||
// do not alter the branch file unless we are able to obtain an exclusive lock. Other apps (such as NPP) may actually write 0 bytes first, then slowly spool out the remainder)
|
||||
if (!CheckCanLock(bootstrapFilename))
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
if (!settingsRegistry)
|
||||
{
|
||||
AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable access Settings Registry. Branch Token cannot be updated");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bootstrapFile.open(QIODevice::ReadOnly))
|
||||
auto allowedListKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey)
|
||||
+ "/allowed_list";
|
||||
AZStd::string currentAllowedList;
|
||||
if (settingsRegistry->Get(currentAllowedList, allowedListKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Split the current allowedList into an array and compare against the new allowed list
|
||||
AZStd::vector<AZStd::string_view> allowedListArray;
|
||||
auto AppendAllowedIpTokens = [&allowedListArray](AZStd::string_view token) { allowedListArray.emplace_back(token); };
|
||||
AZ::StringFunc::TokenizeVisitor(currentAllowedList, AppendAllowedIpTokens, ',');
|
||||
|
||||
// regexp that matches either the beginning of the file, some whitespace, and allowed_list, or,
|
||||
// matches a newline, then whitespace, then allowed_list it will not match comments.
|
||||
QRegExp allowedListPattern("(^|\\n)\\s*allowed_list\\s*=\\s*(.+)", Qt::CaseInsensitive, QRegExp::RegExp);
|
||||
|
||||
//read the file line by line and try to find the allowed_list line
|
||||
QString readAllowedList;
|
||||
QString allowedListline;
|
||||
while (!bootstrapFile.atEnd())
|
||||
{
|
||||
QString contents(bootstrapFile.readLine());
|
||||
int matchIdx = allowedListPattern.indexIn(contents);
|
||||
if (matchIdx != -1)
|
||||
auto CompareQListToAzVector = [](AZStd::string_view currentAllowedIp, const QString& newAllowedIp)
|
||||
{
|
||||
allowedListline = contents;
|
||||
readAllowedList = allowedListPattern.cap(2);
|
||||
break;
|
||||
return currentAllowedIp == newAllowedIp.toUtf8().constData();
|
||||
};
|
||||
if (AZStd::equal(allowedListArray.begin(), allowedListArray.end(), newAllowedList.begin(), newAllowedList.end(), CompareQListToAzVector))
|
||||
{
|
||||
// no need to update, remote_ip already matches
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//read the entire file into so we can do a buffer replacement
|
||||
bootstrapFile.seek(0);
|
||||
QString fileContents;
|
||||
fileContents = bootstrapFile.readAll();
|
||||
bootstrapFile.close();
|
||||
// Update Settings Registry with new token
|
||||
AZStd::string azNewAllowedList{ newAllowedList.join(', ').toUtf8().constData() };
|
||||
settingsRegistry->Set(allowedListKey, azNewAllowedList);
|
||||
|
||||
//format the new allowed list
|
||||
QString formattedNewAllowedList = newAllowedList.join(", ");
|
||||
|
||||
//if we didn't find a allowed_list entry then append one
|
||||
if (allowedListline.isEmpty())
|
||||
{
|
||||
fileContents.append("\nallowed_list = " + formattedNewAllowedList + "\n");
|
||||
}
|
||||
else if (QString::compare(formattedNewAllowedList, readAllowedList, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
// no need to update, they match
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Replace the found line with a new one
|
||||
fileContents.replace(allowedListline, "allowed_list = " + formattedNewAllowedList + "\n");
|
||||
}
|
||||
|
||||
// Make the bootstrap file writable
|
||||
if (!MakeFileWritable(bootstrapFilename))
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, "Failed to make the bootstrap file writable.")
|
||||
return false;
|
||||
}
|
||||
if (!bootstrapFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream output(&bootstrapFile);
|
||||
output << fileContents;
|
||||
bootstrapFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteRemoteIpToBootstrap(QString newRemoteIp)
|
||||
{
|
||||
QDir assetRoot;
|
||||
ComputeAssetRoot(assetRoot);
|
||||
QString bootstrapFilename = assetRoot.filePath("bootstrap.cfg");
|
||||
QFile bootstrapFile(bootstrapFilename);
|
||||
|
||||
// do not alter the branch file unless we are able to obtain an exclusive lock. Other apps (such as NPP) may actually write 0 bytes first, then slowly spool out the remainder)
|
||||
if (!CheckCanLock(bootstrapFilename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bootstrapFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// regexp that matches either the beginning of the file, and remote_ip, or,
|
||||
// matches a newline, then whitespace, then remote_ip it will not match comments.
|
||||
QRegExp remoteIpPattern("(^|\\n)\\s*remote_ip\\s*=\\s*(.+)", Qt::CaseInsensitive, QRegExp::RegExp);
|
||||
|
||||
//read the file line by line and try to find the remote_ip line
|
||||
QString readRemoteIp;
|
||||
QString remoteIpline;
|
||||
while (!bootstrapFile.atEnd())
|
||||
{
|
||||
QString contents(bootstrapFile.readLine());
|
||||
int matchIdx = remoteIpPattern.indexIn(contents);
|
||||
if (matchIdx != -1)
|
||||
{
|
||||
remoteIpline = contents;
|
||||
readRemoteIp = remoteIpPattern.cap(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//read the entire file into so we can do a buffer replacement
|
||||
bootstrapFile.seek(0);
|
||||
QString fileContents;
|
||||
fileContents = bootstrapFile.readAll();
|
||||
bootstrapFile.close();
|
||||
|
||||
//if we didn't find a remote_ip entry then append one
|
||||
if (remoteIpline.isEmpty())
|
||||
{
|
||||
fileContents.append("\nremote_ip = " + newRemoteIp + "\n");
|
||||
}
|
||||
else if (QString::compare(newRemoteIp, readRemoteIp, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
// no need to update, they match
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Replace the found line with a new one
|
||||
fileContents.replace(remoteIpline, "remote_ip = " + newRemoteIp + "\n");
|
||||
}
|
||||
|
||||
// Make the bootstrap file writable
|
||||
if (!MakeFileWritable(bootstrapFilename))
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, "Failed to make the bootstrap file writable.")
|
||||
return false;
|
||||
}
|
||||
if (!bootstrapFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream output(&bootstrapFile);
|
||||
output << fileContents;
|
||||
bootstrapFile.close();
|
||||
return true;
|
||||
return AssetUtilsInternal::DumpAssetProcessorUserSettingsToFile(*settingsRegistry, assetProcessorUserSetregPath);
|
||||
}
|
||||
|
||||
quint16 ReadListeningPortFromSettingsRegistry(QString initialFolder /*= QString()*/)
|
||||
@@ -923,23 +820,20 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
|
||||
bool ComputeProjectCacheRoot(QDir& projectCacheRoot)
|
||||
{
|
||||
QDir assetRoot;
|
||||
if (!ComputeAssetRoot(assetRoot))
|
||||
if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr)
|
||||
{
|
||||
return false; // failed to detect engine root
|
||||
AZ::SettingsRegistryInterface::FixedValueString projectCacheRootValue;
|
||||
if (registry->Get(projectCacheRootValue, AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder);
|
||||
!projectCacheRootValue.empty())
|
||||
{
|
||||
projectCacheRoot = QDir(QString::fromUtf8(projectCacheRootValue.c_str(), aznumeric_cast<int>(projectCacheRootValue.size())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QString gameDir = ComputeGameName(assetRoot.absolutePath());
|
||||
if (gameDir.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
projectCacheRoot = QDir(assetRoot.filePath("Cache/" + gameDir));
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ComputeFenceDirectory(QDir& fenceDir)
|
||||
{
|
||||
QDir cacheRoot;
|
||||
@@ -951,6 +845,25 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
return true;
|
||||
}
|
||||
|
||||
QString StripAssetPlatform(AZStd::string_view relativeProductPath)
|
||||
{
|
||||
// Skip over the assetPlatform path segment if it is matches one of the platform defaults
|
||||
// Otherwise return the path unchanged
|
||||
AZStd::string_view strippedProductPath{ relativeProductPath };
|
||||
if (AZStd::optional pathSegment = AZ::StringFunc::TokenizeNext(strippedProductPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR);
|
||||
pathSegment.has_value())
|
||||
{
|
||||
AZ::IO::FixedMaxPathString assetPlatformSegmentLower{ *pathSegment };
|
||||
AZStd::to_lower(assetPlatformSegmentLower.begin(), assetPlatformSegmentLower.end());
|
||||
if (AzFramework::PlatformHelper::GetPlatformIdFromName(assetPlatformSegmentLower) != AzFramework::PlatformId::Invalid)
|
||||
{
|
||||
return QString::fromUtf8(strippedProductPath.data(), aznumeric_cast<int>(strippedProductPath.size()));
|
||||
}
|
||||
}
|
||||
|
||||
return QString::fromUtf8(relativeProductPath.data(), aznumeric_cast<int>(relativeProductPath.size()));
|
||||
}
|
||||
|
||||
QString NormalizeFilePath(const QString& filePath)
|
||||
{
|
||||
// do NOT convert to absolute paths here, we just want to manipulate the string itself.
|
||||
@@ -1035,92 +948,41 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
|
||||
bool UpdateBranchToken()
|
||||
{
|
||||
QDir assetRoot;
|
||||
ComputeAssetRoot(assetRoot);
|
||||
QString bootstrapFilename = assetRoot.filePath("bootstrap.cfg");
|
||||
QFile bootstrapFile(bootstrapFilename);
|
||||
QString fileContents;
|
||||
|
||||
// do not alter the branch file unless we are able to obtain an exclusive lock. Other apps (such as NPP) may actually write 0 bytes first, then slowly spool out the remainder)
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
bool hasLock = false;
|
||||
do
|
||||
{
|
||||
if (CheckCanLock(bootstrapFilename))
|
||||
{
|
||||
hasLock = true;
|
||||
break;
|
||||
}
|
||||
|
||||
QThread::msleep(AssetUtilsInternal::g_RetryWaitInterval);
|
||||
|
||||
} while (!timer.hasExpired(10 * AssetUtilsInternal::g_RetryWaitInterval));
|
||||
if (!hasLock)
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to lock bootstrap file at: %s\n", bootstrapFilename.toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bootstrapFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to open bootstrap file at: %s\n", bootstrapFilename.toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
fileContents = bootstrapFile.readAll();
|
||||
bootstrapFile.close();
|
||||
AZ::IO::FixedMaxPath assetProcessorUserSetregPath = AZ::Utils::GetProjectPath();
|
||||
assetProcessorUserSetregPath /= AssetProcessorUserSetregRelPath;
|
||||
|
||||
AZStd::string appBranchToken;
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForAppRoot, appBranchToken);
|
||||
QString currentBranchToken(appBranchToken.c_str());
|
||||
QString readBranchToken;
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::CalculateBranchTokenForEngineRoot, appBranchToken);
|
||||
|
||||
// regexp that matches either the beginning of the file, some whitespace, and assetProcessor_branch_token, or,
|
||||
// matches a newline, then whitespace, then assetProcessor_branch_token
|
||||
// it will not match comments.
|
||||
QRegExp branchTokenPattern("(^|\\n)\\s*assetProcessor_branch_token\\s*=\\s*(\\S+)\\b", Qt::CaseInsensitive, QRegExp::RegExp);
|
||||
|
||||
int matchIdx = branchTokenPattern.indexIn(fileContents);
|
||||
if (matchIdx != -1)
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
if (!settingsRegistry)
|
||||
{
|
||||
readBranchToken = branchTokenPattern.cap(2);
|
||||
AZ_Error(AssetProcessor::ConsoleChannel, false, "Unable access Settings Registry. Branch Token cannot be updated");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (readBranchToken.isEmpty())
|
||||
AZStd::string registryBranchToken;
|
||||
auto branchTokenKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/assetProcessor_branch_token";
|
||||
if (settingsRegistry->Get(registryBranchToken, branchTokenKey))
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "adding branch token (%s) in (%s)\n", currentBranchToken.toUtf8().constData(), bootstrapFilename.toUtf8().constData());
|
||||
fileContents.append("\nassetProcessor_branch_token = " + currentBranchToken + "\n");
|
||||
}
|
||||
else if (QString::compare(currentBranchToken, readBranchToken, Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
// no need to update, branch token match
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Branch token (%s) is already correct in (%s)\n", currentBranchToken.toUtf8().constData(), bootstrapFilename.toUtf8().constData());
|
||||
return true;
|
||||
if (appBranchToken == registryBranchToken)
|
||||
{
|
||||
// no need to update, branch token match
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Branch token (%s) is already correct in (%s)\n", appBranchToken.c_str(), assetProcessorUserSetregPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Updating branch token (%s) in (%s)\n", appBranchToken.c_str(), assetProcessorUserSetregPath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
//Updating branch token
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Updating branch token (%s) in (%s)\n", currentBranchToken.toUtf8().constData(), bootstrapFilename.toUtf8().constData());
|
||||
fileContents.replace(branchTokenPattern.cap(0), "\nassetProcessor_branch_token = " + currentBranchToken + "\n");
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Adding branch token (%s) in (%s)\n", appBranchToken.c_str(), assetProcessorUserSetregPath.c_str());
|
||||
}
|
||||
|
||||
// Make the bootstrap file writable
|
||||
if (!MakeFileWritable(bootstrapFilename))
|
||||
{
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, "Failed to make the bootstrap file writable.")
|
||||
return false;
|
||||
}
|
||||
if (!bootstrapFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Unable to open bootstrap file (%s)\n", bootstrapFilename.toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
// Update Settings Registry with new token
|
||||
settingsRegistry->Set(branchTokenKey, appBranchToken);
|
||||
|
||||
QTextStream output(&bootstrapFile);
|
||||
output << fileContents;
|
||||
bootstrapFile.close();
|
||||
return true;
|
||||
return AssetUtilsInternal::DumpAssetProcessorUserSettingsToFile(*settingsRegistry, assetProcessorUserSetregPath);
|
||||
}
|
||||
|
||||
QString ComputeJobDescription(const AssetProcessor::AssetRecognizer* recognizer)
|
||||
@@ -1130,7 +992,7 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
|
||||
AZStd::string ComputeJobLogFolder()
|
||||
{
|
||||
return AZStd::string::format("@log@/logs/JobLogs");
|
||||
return AZStd::string::format("@log@/JobLogs");
|
||||
}
|
||||
|
||||
AZStd::string ComputeJobLogFileName(const AzToolsFramework::AssetSystem::JobInfo& jobInfo)
|
||||
@@ -1477,14 +1339,28 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
|
||||
bool CreateTempWorkspace(QString& result)
|
||||
{
|
||||
// Use the engine root as a temp workspace folder
|
||||
// this works better for numerous reasons
|
||||
// * Its on the same drive as the /Cache/ so we will be moving files instead of copying from drive to drive
|
||||
// Use the project user folder as a temp workspace folder
|
||||
// The benefits are
|
||||
// * It's on the same drive as the Cache/ so we will be moving files instead of copying from drive to drive
|
||||
// * It is discoverable by the user and thus deletable and we can also tell people to send us that folder without them having to go digging for it
|
||||
// * If you can't write to it you have much bigger problems
|
||||
|
||||
QDir rootDir;
|
||||
if (ComputeAssetRoot(rootDir))
|
||||
bool foundValidPath{};
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if (AZ::IO::Path userPath; settingsRegistry->Get(userPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath))
|
||||
{
|
||||
rootDir.setPath(QString::fromUtf8(userPath.c_str(), aznumeric_cast<int>(userPath.Native().size())));
|
||||
foundValidPath = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundValidPath)
|
||||
{
|
||||
foundValidPath = ComputeAssetRoot(rootDir);
|
||||
}
|
||||
|
||||
if (foundValidPath)
|
||||
{
|
||||
QString tempPath = rootDir.absolutePath();
|
||||
return CreateTempWorkspace(tempPath, result);
|
||||
@@ -1499,7 +1375,6 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
QString inputName;
|
||||
QString platformName;
|
||||
QString jobDescription;
|
||||
QString gameName = AssetUtilities::ComputeGameName();
|
||||
AZ::Uuid guid = AZ::Uuid::CreateNull();
|
||||
|
||||
using namespace AzToolsFramework::AssetDatabase;
|
||||
@@ -1513,16 +1388,16 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
platform = AzToolsFramework::AssetSystem::GetHostAssetPlatform();
|
||||
}
|
||||
|
||||
QString platformPrepend = QString("%1/%2/").arg(platform, gameName);
|
||||
QString productNameWithPlatformAndGameName = productName;
|
||||
QString platformPrepend = QString("%1/").arg(platform);
|
||||
QString productNameWithPlatform = productName;
|
||||
|
||||
if (!productName.startsWith(platformPrepend, Qt::CaseInsensitive))
|
||||
{
|
||||
productNameWithPlatformAndGameName = productName = QString("%1/%2/%3").arg(platform, gameName, productName);
|
||||
productNameWithPlatform = productName = QString("%1/%2").arg(platform, productName);
|
||||
}
|
||||
|
||||
ProductDatabaseEntryContainer products;
|
||||
if (databaseConnection->GetProductsByProductName(productNameWithPlatformAndGameName, products))
|
||||
if (databaseConnection->GetProductsByProductName(productNameWithPlatform, products))
|
||||
{
|
||||
// if we find stuff, then return immediately, productName is already a productName.
|
||||
return productName;
|
||||
@@ -1535,24 +1410,9 @@ to ensure that the address is correct. Asset Processor won't be running in serve
|
||||
return productName;
|
||||
}
|
||||
|
||||
if (!databaseConnection->GetProductsLikeProductName(productNameWithPlatformAndGameName, AssetDatabaseConnection::LikeType::StartsWith, products))
|
||||
if (!databaseConnection->GetProductsLikeProductName(productNameWithPlatform, AssetDatabaseConnection::LikeType::StartsWith, products))
|
||||
{
|
||||
//if we are here it means that the asset database does not know about this product,
|
||||
//we will now remove the gameName and try again ,so now the path will only have $PLATFORM/ in front of it
|
||||
int gameNameIndex = productName.indexOf(gameName, 0, Qt::CaseInsensitive);
|
||||
|
||||
if (gameNameIndex != -1)
|
||||
{
|
||||
//we will now remove the gameName and the separator
|
||||
productName.remove(gameNameIndex, gameName.length() + 1);// adding one for the native separator
|
||||
}
|
||||
|
||||
//Search the database for this product
|
||||
if (!databaseConnection->GetProductsLikeProductName(productName, AssetDatabaseConnection::LikeType::StartsWith, products))
|
||||
{
|
||||
//return empty string if the database still does not have any idea about the product
|
||||
productName = QString();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return productName.toLower();
|
||||
}
|
||||
|
||||
@@ -51,8 +51,7 @@ namespace AssetProcessor
|
||||
|
||||
namespace AssetUtilities
|
||||
{
|
||||
|
||||
inline constexpr char GameFolderOverrideParameter[] = "gamefolder";
|
||||
inline constexpr char ProjectPathOverrideParameter[] = "project-path";
|
||||
|
||||
//! Set precision fingerprint timestamps will be truncated to avoid mismatches across systems/packaging with different file timestamp precisions
|
||||
//! Timestamps default to milliseconds. A value of 1 will keep the default millisecond precision. A value of 1000 will reduce the precision to seconds
|
||||
@@ -79,10 +78,10 @@ namespace AssetUtilities
|
||||
|
||||
//! makes the file writable
|
||||
//! return true if operation is successful, otherwise return false
|
||||
bool MakeFileWritable(QString filename);
|
||||
bool MakeFileWritable(const QString& filename);
|
||||
|
||||
//! Check to see if we can Lock the file
|
||||
bool CheckCanLock(QString filename);
|
||||
bool CheckCanLock(const QString& filename);
|
||||
|
||||
//! Updates the branch token in the bootstrap file
|
||||
bool UpdateBranchToken();
|
||||
@@ -98,11 +97,14 @@ namespace AssetUtilities
|
||||
|
||||
bool ShouldUseFileHashing();
|
||||
|
||||
//! Determine the name of the current game - for example, SamplesProject
|
||||
//! Can be overridden by passing in a non-empty gameNameOverride
|
||||
//! The override will persist if the GameName wasn't set previously or
|
||||
//! Determine the name of the current project - for example, SamplesProject
|
||||
//! Can be overridden by passing in a non-empty projectNameOverride
|
||||
//! The override will persist if the project name wasn't set previously or
|
||||
//! force=true is supplied
|
||||
QString ComputeGameName(QString gameNameOverride = QString(), bool force = false);
|
||||
QString ComputeProjectName(QString projectNameOverride = QString(), bool force = false);
|
||||
|
||||
//! Determine the absolute path of the current project
|
||||
QString ComputeProjectPath();
|
||||
|
||||
//! Reads the allowed list directly from the bootstrap file
|
||||
QString ReadAllowedlistFromSettingsRegistry(QString initialFolder = QString());
|
||||
@@ -111,13 +113,7 @@ namespace AssetUtilities
|
||||
QString ReadRemoteIpFromSettingsRegistry(QString initialFolder = QString());
|
||||
|
||||
//! Writes the allowed list directly to the bootstrap file
|
||||
bool WriteAllowedlistToBootstrap(QStringList allowedList);
|
||||
|
||||
//! Writes the remote ip directly to the bootstrap file
|
||||
bool WriteRemoteIpToBootstrap(QString remoteIp);
|
||||
|
||||
//! Reads the game name directly from the bootstrap file
|
||||
QString ReadGameNameFromSettingsRegistry(QString initialFolder = QString());
|
||||
bool WriteAllowedlistToSettingsRegistry(const QStringList& allowedList);
|
||||
|
||||
//! Reads the listening port from the bootstrap file
|
||||
//! By default the listening port is 45643
|
||||
@@ -143,13 +139,24 @@ namespace AssetUtilities
|
||||
QString ComputeJobDescription(const AssetProcessor::AssetRecognizer* recognizer);
|
||||
|
||||
//! Compute the root of the cache for the current project.
|
||||
//! This is generally the "cache" folder, subfolder gamedir.
|
||||
//! This is generally the "<Project>/Cache" folder
|
||||
bool ComputeProjectCacheRoot(QDir& projectCacheRoot);
|
||||
|
||||
//! Compute the folder that will be used for fence files.
|
||||
bool ComputeFenceDirectory(QDir& fenceDir);
|
||||
|
||||
//! Converts all slashes to forward slashes, removes double slashes,
|
||||
//! Strips the first "asset platform" from the first path segment of a relative product path
|
||||
//! This is meant for removing the asset platform for paths such as "pc/MyAssetFolder/MyAsset.asset"
|
||||
//! Therefore the result here becomes "MyAssetFolder/MyAsset"
|
||||
//!
|
||||
//! Similarly invoking this function on relative path that begins with the "server" platform
|
||||
//! "server/AssetFolder/Server.asset2" -> "AssetFolder/Server.asset2"
|
||||
//! This function does not strip an asset platform from anywhere, but the first path segment
|
||||
//! Therefore invoking strip Asset on "MyProject/Cache/pc/MyAsset/MyAsset.asset"
|
||||
//! would return a copy of the relative path
|
||||
QString StripAssetPlatform(AZStd::string_view relativeProductPath);
|
||||
|
||||
//! Converts all slashes to forward slashes, removes double slashes,
|
||||
//! replaces all indirections such as '.' or '..' as appropriate.
|
||||
//! On windows, the drive letter (if present) is converted to uppercase.
|
||||
//! Besides that, all case is preserved.
|
||||
|
||||
Reference in New Issue
Block a user