Asset Bundler GUI (#427)

The AssetBundler is a new ToolsApplication that allows users to work through the entire Asset Bundling process without ever touching a command line.

* Integrating github/AssetBundler through commit 1d65018

* Asset Bundler bug fixes: platform initialization and GUI styling (#5)

* fixed enabled platform initialization

* fixed the cached engine root. This fixed some of my Seeds tab data issues. The default Engine Seed List appeared, and was able to display the contents on screen.

* updated my notes of active bugs

* changed some casing in various include lines to hopefully fix my linux build

* another include fix for linux

* AssetBundler GUI is now compiling on Mac

* removed some things off of my todo list because the mac build fix actually fixed the visuals! everything's the right color again

* removed the word Lumberyard from the bundler

* Asset bundler bug fixes - Bundles, Gems, and Tests (#9)

* Fixed the Bundle loading and generation problem. Turned out to be a FileWatcher issue.

* turns out gem loading wasn't broken, there were just no existing SeedListFiles for any of the gems loaded by the AutomatedTesting project. I added a default SeedListFile for the PrimitiveAssets Gem.

* fixed some failing AssetBundler Gem tests

* Misunderstood the need to have default seed lists for asset-only gems. removing the previously created seed list file

* Asset bundler bug fixes: Seeds Tab display issues and _dependencies.xml loading (#10)

* Fixed the Project Source column in the Seeds tab

* The AssetBundler will no longer attempt to copy a template version of the ProjectName_dependencies.xml file into your active project. However, it will throw an error if you do not have one. A follow-up ticket has been cut to address this issue.

* updated the AssetBundler icon. This one matches the current style guides

* PR feedback: pass a const ref instead of a value

* PR feedback: safer conversion from a string_view to a QString

Co-authored-by: alexpete <alexpete@amazon.com>
This commit is contained in:
Zaladane
2021-04-30 15:42:10 -07:00
committed by GitHub
parent 4e3846e679
commit a5d4eb5d44
76 changed files with 10163 additions and 63 deletions
@@ -0,0 +1,386 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <source/utils/GUIApplicationManager.h>
#include <source/ui/MainWindow.h>
#include <source/utils/utils.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/Asset/AssetCatalog.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogBus.h>
#include <AzQtComponents/Components/ConfigHelpers.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
#include <QApplication>
#include <QLocale>
#include <QStringList>
// Forward declare platform-specific functions
namespace Platform
{
/// On Windows this will return the setting for our custom title bar
/// On other platforms this will return the setting for using platform default
/// This ensures that functions like Exit, Maximize, and Minimize appear in the right platform-specific style
AzQtComponents::WindowDecorationWrapper::Option GetWindowDecorationWrapperOption();
} // namespace Platform
const char AssetBundlingFolderName [] = "AssetBundling";
const char SeedListsFolderName [] = "SeedLists";
const char AssetListsFolderName [] = "AssetLists";
const char RulesFolderName[] = "Rules";
const char BundleSettingsFolderName [] = "BundleSettings";
const char BundlesFolderName [] = "Bundles";
namespace AssetBundler
{
GUIApplicationManager::Config GUIApplicationManager::loadConfig(QSettings& settings)
{
using namespace AzQtComponents;
Config config = defaultConfig();
// Error Log
{
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("ErrorLogDetails"));
ConfigHelpers::read<int>(settings, QStringLiteral("LogTypeColumnWidth"), config.logTypeColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("LogSourceColumnWidth"), config.logSourceColumnWidth);
}
// General File Tables
{
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("GeneralFileTableDetails"));
ConfigHelpers::read<int>(settings, QStringLiteral("FileTableWidth"), config.fileTableWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("FileNameColumnWidth"), config.fileNameColumnWidth);
}
// Seeds Tab
{
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("SeedsTabDetails"));
ConfigHelpers::read<int>(settings, QStringLiteral("CheckBoxColumnWidth"), config.checkBoxColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("SeedListFileNameColumnWidth"), config.seedListFileNameColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("ProjectNameColumnWidth"), config.projectNameColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("SeedListContentsNameColumnWidth"), config.seedListContentsNameColumnWidth);
}
// Asset Lists Tab
{
ConfigHelpers::GroupGuard details(&settings, QStringLiteral("AssetListsTabDetails"));
ConfigHelpers::read<int>(settings, QStringLiteral("AssetListFileNameColumnWidth"), config.assetListFileNameColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("AssetListPlatformColumnWidth"), config.assetListPlatformColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("ProductAssetNameColumnWidth"), config.productAssetNameColumnWidth);
ConfigHelpers::read<int>(settings, QStringLiteral("ProductAssetRelativePathColumnWidth"), config.productAssetRelativePathColumnWidth);
}
return config;
}
GUIApplicationManager::Config GUIApplicationManager::defaultConfig()
{
// These are used if the values can't be read from AssetBundlerConfig.ini.
Config config;
config.logTypeColumnWidth = 150;
config.logSourceColumnWidth = 150;
config.fileTableWidth = 250;
config.fileNameColumnWidth = 150;
config.checkBoxColumnWidth = 150;
config.seedListFileNameColumnWidth = 150;
config.projectNameColumnWidth = 150;
config.seedListContentsNameColumnWidth = 150;
config.assetListFileNameColumnWidth = 150;
config.assetListPlatformColumnWidth = 150;
config.productAssetNameColumnWidth = 150;
config.productAssetRelativePathColumnWidth = 150;
return config;
}
GUIApplicationManager::GUIApplicationManager(int* argc, char*** argv, QObject* parent)
: ApplicationManager(argc, argv, parent)
{
}
GUIApplicationManager::~GUIApplicationManager()
{
// Reset this before DestroyApplication, BusDisconnect needs to happen before Application::Stop() destroys the allocators.
m_platformCatalogManager.reset();
}
bool GUIApplicationManager::Init()
{
m_isInitializing = true;
// Initialize Asset Bundler Batch
ApplicationManager::Init();
AZ::IO::FixedMaxPath engineRoot = GetEngineRoot();
if (engineRoot.empty())
{
// Error has already been thrown
return false;
}
// Determine the name of the current project
auto projectOutcome = AssetBundler::GetCurrentProjectName();
if (!projectOutcome.IsSuccess())
{
AZ_Error("AssetBundler", false, projectOutcome.GetError().c_str());
return false;
}
m_currentProjectName = projectOutcome.GetValue();
// Set up paths to the Project folder, Project Cache folder, and determine enabled platforms
auto pathOutcome = InitializePaths();
if (!pathOutcome.IsSuccess())
{
AZ_Error("AssetBundler", false, pathOutcome.GetError().c_str());
return false;
}
// Set up platform-specific Asset Catalogs
m_platformCatalogManager = AZStd::make_unique<AzToolsFramework::PlatformAddressedAssetCatalogManager>();
// Define some application-level settings
QApplication::setOrganizationName("Amazon");
QApplication::setOrganizationDomain("amazon.com");
QApplication::setApplicationName("Asset Bundler");
QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
m_isInitializing = false;
// Create the actual Qt Application
m_qApp.reset(new QApplication(*GetArgC(), *GetArgV()));
// Create the Main Window
m_mainWindow.reset(new MainWindow(this));
return true;
}
bool GUIApplicationManager::Run()
{
// Set up the Style Manager
AzQtComponents::StyleManager styleManager(qApp);
styleManager.initialize(qApp, GetEngineRoot());
AZ::IO::FixedMaxPath engineRoot(GetEngineRoot());
QDir engineRootDir(engineRoot.c_str());
AzQtComponents::StyleManager::addSearchPaths(
QStringLiteral("style"),
engineRootDir.filePath(QStringLiteral("Code/Tools/AssetBundler/source/ui/style")),
QStringLiteral(":/AssetBundler/style"),
engineRoot);
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:AssetBundler.qss"));
AzQtComponents::ConfigHelpers::loadConfig<Config, GUIApplicationManager>(&m_fileWatcher, &m_config, QStringLiteral("style:AssetBundlerConfig.ini"), this, std::bind(&GUIApplicationManager::ApplyConfig, this));
ApplyConfig();
qApp->setWindowIcon(QIcon("style:AssetBundler-Icon-256x256@x2.ico"));
// Set up the Main Window
auto wrapper = new AzQtComponents::WindowDecorationWrapper(Platform::GetWindowDecorationWrapperOption());
wrapper->setGuest(m_mainWindow.data());
m_mainWindow->Activate();
wrapper->show();
m_mainWindow->show();
qApp->setQuitOnLastWindowClosed(true);
// Run the application
return qApp->exec();
}
void GUIApplicationManager::AddWatchedPath(const QString& folderPath)
{
m_fileWatcher.addPath(folderPath);
}
void GUIApplicationManager::AddWatchedPaths(const QSet<QString>& folderPaths)
{
m_fileWatcher.addPaths(folderPaths.values());
}
void GUIApplicationManager::RemoveWatchedPath(const QString& path)
{
m_fileWatcher.removePath(path);
}
void GUIApplicationManager::RemoveWatchedPaths(const QSet<QString>& paths)
{
// Check whether the list is empty to get rid of the warning from Qt
if (paths.isEmpty())
{
return;
}
m_fileWatcher.removePaths(paths.values());
}
bool GUIApplicationManager::OnPreError(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message)
{
// We want to display errors during initialization, then let the MainWindow handle errors during runtime
if (m_isInitializing)
{
// These are fatal initialization errors, and the application will shut down after the user closes the message box
m_qApp.reset(new QApplication(*GetArgC(), *GetArgV()));
QMessageBox errorMessageBox;
errorMessageBox.setWindowTitle("Asset Bundler");
errorMessageBox.setText(message);
errorMessageBox.setStandardButtons(QMessageBox::Ok);
errorMessageBox.setDefaultButton(QMessageBox::Ok);
errorMessageBox.exec();
return true;
}
return false;
}
bool GUIApplicationManager::OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/)
{
// Don't handle warnings, let the MainWindow print them
return false;
}
bool GUIApplicationManager::OnPrintf(const char* /*window*/, const char* /*message*/)
{
// This is disabled during initialization to prevent a lot of message spam printed to the CLI that gets generated on setup
return m_isInitializing;
}
AZ::Outcome<void, AZStd::string> GUIApplicationManager::InitializePaths()
{
// Calculate the path to the Cache for the current project
auto pathOutcome = AssetBundler::GetProjectCacheFolderPath();
if (!pathOutcome.IsSuccess())
{
return AZ::Failure(pathOutcome.GetError());
}
m_currentProjectCacheFolder = pathOutcome.GetValue().String();
// Calculate the path to the current project folder
pathOutcome = AssetBundler::GetProjectFolderPath();
if (!pathOutcome.IsSuccess())
{
return AZ::Failure(pathOutcome.GetError());
}
m_currentProjectFolder = pathOutcome.GetValue().String();
// Generate the AssetBundling folder inside the current project
AzFramework::StringFunc::Path::ConstructFull(m_currentProjectFolder.c_str(), AssetBundlingFolderName, m_assetBundlingFolder);
// Seed Lists folder
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), SeedListsFolderName, m_seedListsFolder);
AZ::Outcome<void, AZStd::string> createPathOutcome = AssetBundler::MakePath(m_seedListsFolder);
if (!createPathOutcome.IsSuccess())
{
return createPathOutcome;
}
// Asset Lists folder
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), AssetListsFolderName, m_assetListsFolder);
createPathOutcome = AssetBundler::MakePath(m_assetListsFolder);
if (!createPathOutcome.IsSuccess())
{
return createPathOutcome;
}
// Rules folder
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), RulesFolderName, m_rulesFolder);
createPathOutcome = AssetBundler::MakePath(m_rulesFolder);
if (!createPathOutcome.IsSuccess())
{
return createPathOutcome;
}
// Bundle Settings Folder
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), BundleSettingsFolderName, m_bundleSettingsFolder);
createPathOutcome = AssetBundler::MakePath(m_bundleSettingsFolder);
if (!createPathOutcome.IsSuccess())
{
return createPathOutcome;
}
// Bundles Folder
AzFramework::StringFunc::Path::ConstructFull(m_assetBundlingFolder.c_str(), BundlesFolderName, m_bundlesFolder);
createPathOutcome = AssetBundler::MakePath(m_bundlesFolder);
if (!createPathOutcome.IsSuccess())
{
return createPathOutcome;
}
// Determine the enabled platforms
const char* appRoot = nullptr;
AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot);
m_enabledPlatforms = GetEnabledPlatformFlags(GetEngineRoot(), appRoot, AZ::Utils::GetProjectPath().c_str());
// Determine which Gems are enabled for the current project
if (!AzFramework::GetGemsInfo(m_gemInfoList, *m_settingsRegistry))
{
return AZ::Failure(AZStd::string::format("Failed to read Gems for project: %s\n", m_currentProjectName.c_str()));
}
QObject::connect(&m_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &GUIApplicationManager::DirectoryChanged);
QObject::connect(&m_fileWatcher, &QFileSystemWatcher::fileChanged, this, &GUIApplicationManager::FileChanged);
return AZ::Success();
}
void GUIApplicationManager::DirectoryChanged(const QString& directory)
{
UpdateTab(directory.toUtf8().data());
}
void GUIApplicationManager::FileChanged(const QString& path)
{
// FileChanged will only be called when engine or gem seed files are updated
// Otherwilse DirectoryChanged should be triggered
AZStd::string extension;
AzFramework::StringFunc::Path::GetExtension(path.toUtf8().data(), extension);
extension = extension.starts_with(".") ? extension.substr(1) : extension;
if (extension == AzToolsFramework::AssetSeedManager::GetSeedFileExtension())
{
UpdateTab(GetSeedListsFolder());
}
// Many applications save an open file by writing a new file and then deleting the old one
// Add the file path back if it has been removed from the watcher file list
if (!m_fileWatcher.files().contains(path))
{
m_fileWatcher.addPath(path);
}
}
void GUIApplicationManager::ApplyConfig()
{
m_mainWindow->ApplyConfig();
}
} // namespace AssetBundler
#include <source/utils/moc_GUIApplicationManager.cpp>
@@ -0,0 +1,164 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <source/utils/applicationManager.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/containers/vector.h>
#include <AzFramework/Asset/AssetCatalog.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <QCoreApplication>
#include <QDir>
#include <QMap>
#include <QSettings>
#include <QSharedPointer>
#include <QString>
#include <QFileSystemWatcher>
#endif
namespace AssetBundler
{
enum AssetBundlingFileType : int
{
SeedListFileType = 0,
AssetListFileType,
BundleSettingsFileType,
BundleFileType,
RulesFileType,
NumBundlingFileTypes
};
class MainWindow;
class GUIApplicationManager
: public ApplicationManager
{
Q_OBJECT
public:
struct Config
{
// These default values are used if the values can't be read from AssetBundlerConfig.ini,
// and the call to defaultConfig fails.
// Error Log
int logTypeColumnWidth = -1;
int logSourceColumnWidth = -1;
// General File Tables
int fileTableWidth = -1;
int fileNameColumnWidth = -1;
// Seeds Tab
int checkBoxColumnWidth = -1;
int seedListFileNameColumnWidth = -1;
int projectNameColumnWidth = -1;
int seedListContentsNameColumnWidth = -1;
// Asset Lists Tab
int assetListFileNameColumnWidth = -1;
int assetListPlatformColumnWidth = -1;
int productAssetNameColumnWidth = -1;
int productAssetRelativePathColumnWidth = -1;
};
/*!
* Loads the button config data from a settings object.
*/
static Config loadConfig(QSettings& settings);
/*!
* Returns default button config data.
*/
static Config defaultConfig();
explicit GUIApplicationManager(int* argc, char*** argv, QObject* parent = 0);
virtual ~GUIApplicationManager();
bool Init() override;
bool Run() override;
AZStd::string GetCurrentProjectFolder() { return m_currentProjectFolder; }
AZStd::string GetAssetBundlingFolder() { return m_assetBundlingFolder; }
AZStd::string GetSeedListsFolder() { return m_seedListsFolder; }
AZStd::string GetAssetListsFolder() { return m_assetListsFolder; }
AZStd::string GetRulesFolder() { return m_rulesFolder; }
AZStd::string GetBundleSettingsFolder() { return m_bundleSettingsFolder; }
AZStd::string GetBundlesFolder() { return m_bundlesFolder; }
AZStd::string GetCurrentProjectCacheFolder() { return m_currentProjectCacheFolder; }
AzFramework::PlatformFlags GetEnabledPlatforms() { return m_enabledPlatforms; }
void AddWatchedPath(const QString& path);
void AddWatchedPaths(const QSet<QString>& paths);
void RemoveWatchedPath(const QString& path);
void RemoveWatchedPaths(const QSet<QString>& paths);
////////////////////////////////////////////////////////////////////////////////////////////
// Override the ApplicationManager TraceMessageBus methods so that messages go through MainWindow and not the CLI
bool OnPreError(const char* window, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* message) override;
bool OnPreWarning(const char* /*window*/, const char* /*fileName*/, int /*line*/, const char* /*func*/, const char* /*message*/) override;
bool OnPrintf(const char* /*window*/, const char* /*message*/) override;
////////////////////////////////////////////////////////////////////////////////////////////
const Config& GetConfig() { return m_config; }
Q_SIGNALS:
void ShowWindow();
void UpdateTab(const AZStd::string& directory);
void UpdateFiles(AssetBundlingFileType fileType, const AZStd::vector<AZStd::string>& absoluteFilePaths);
protected Q_SLOTS:
void DirectoryChanged(const QString& directory);
void FileChanged(const QString& path);
void ApplyConfig();
private:
/**
* Generates directory information for all paths used in this tool
* @return void on success, error message on failure
*/
AZ::Outcome<void, AZStd::string> InitializePaths();
QSharedPointer<QCoreApplication> m_qApp;
Config m_config;
QSharedPointer<MainWindow> m_mainWindow;
AZStd::string m_currentProjectFolder;
AZStd::string m_assetBundlingFolder;
AZStd::string m_seedListsFolder;
AZStd::string m_assetListsFolder;
AZStd::string m_rulesFolder;
AZStd::string m_bundleSettingsFolder;
AZStd::string m_bundlesFolder;
AZStd::string m_currentProjectCacheFolder;
AzFramework::PlatformFlags m_enabledPlatforms = AzFramework::PlatformFlags::Platform_NONE;
AZStd::unique_ptr<AzToolsFramework::PlatformAddressedAssetCatalogManager> m_platformCatalogManager;
bool m_isInitializing = false;
QFileSystemWatcher m_fileWatcher;
};
} // namespace AssetBundler
@@ -45,8 +45,16 @@ namespace AssetBundler
{
const char compareVariablePrefix = '$';
ApplicationManager::ApplicationManager(int* argc, char*** argv)
: AzToolsFramework::ToolsApplication(argc, argv)
GemInfo::GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath)
: m_gemName(name)
, m_relativeFilePath(relativeFilePath)
, m_absoluteFilePath(absoluteFilePath)
{
}
ApplicationManager::ApplicationManager(int* argc, char*** argv, QObject* parent)
: QObject(parent)
, AzToolsFramework::ToolsApplication(argc, argv)
{
}
@@ -55,7 +63,7 @@ namespace AssetBundler
DestroyApplication();
}
void ApplicationManager::Init()
bool ApplicationManager::Init()
{
AZ::Debug::TraceMessageBus::Handler::BusConnect();
Start(AzFramework::Application::Descriptor());
@@ -72,8 +80,11 @@ namespace AssetBundler
m_assetSeedManager = AZStd::make_unique<AzToolsFramework::AssetSeedManager>();
AZ_TracePrintf(AssetBundler::AppWindowName, "\n");
g_cachedEngineRoot = AZ::IO::FixedMaxPath(GetEngineRoot());
// There is no need to update the UserSettings file, so we can avoid a race condition by disabling save on shutdown
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
return true;
}
void ApplicationManager::DestroyApplication()
@@ -1522,7 +1533,7 @@ namespace AssetBundler
}
}
AZStd::vector<AZStd::string> defaultSeeds = GetDefaultSeeds(GetEngineRoot(), AZ::Utils::GetProjectPath(), m_currentProjectName);
AZStd::vector<AZStd::string> defaultSeeds = GetDefaultSeeds(AZ::Utils::GetProjectPath(), m_currentProjectName);
if (defaultSeeds.empty())
{
// Error has already been thrown
@@ -2847,3 +2858,4 @@ namespace AssetBundler
return !m_showVerboseOutput;
}
} // namespace AssetBundler
#include <source/utils/moc_applicationManager.cpp>
@@ -11,6 +11,7 @@
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/Asset/AssetSeedManager.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
@@ -22,7 +23,7 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <source/utils/utils.h>
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalogManager.h>
#endif
namespace AssetBundler
{
struct SeedsParams
@@ -161,16 +162,18 @@ namespace AssetBundler
};
class ApplicationManager
: public AZ::Debug::TraceMessageBus::Handler
: public QObject
, public AZ::Debug::TraceMessageBus::Handler
, public AzToolsFramework::ToolsApplication
{
Q_OBJECT
public:
explicit ApplicationManager(int* argc, char*** argv);
~ApplicationManager();
explicit ApplicationManager(int* argc, char*** argv, QObject* parent = 0);
virtual ~ApplicationManager();
void Init();
virtual bool Init();
void DestroyApplication();
bool Run();
virtual bool Run();
////////////////////////////////////////////////////////////////////////////////////////////
// AzFramework::Application overrides
+41 -35
View File
@@ -31,6 +31,7 @@ AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option")
#include <QDir>
#include <QString>
#include <QStringList>
#include <QJsonDocument>
AZ_POP_DISABLE_WARNING
namespace AssetBundler
@@ -108,6 +109,8 @@ namespace AssetBundler
const char* AssetCatalogFilename = "assetcatalog.xml";
AZ::IO::FixedMaxPath g_cachedEngineRoot;
const char EngineDirectoryName[] = "Engine";
const char RestrictedDirectoryName[] = "restricted";
@@ -128,7 +131,7 @@ namespace AssetBundler
AZStd::unordered_map<AZStd::string, AZStd::string>& defaultSeedLists,
AzFramework::PlatformFlags platformFlags)
{
AZ::IO::FixedMaxPath engineRoot(GetEngineRoot());
AZ::IO::FixedMaxPath engineRoot(GetCachedEngineRoot());
AZ::IO::FixedMaxPath engineRestrictedRoot = engineRoot / RestrictedDirectoryName;
AZ::IO::FixedMaxPath engineLocalPath = AZ::IO::PathView(engineDirectory.LexicallyRelative(engineRoot));
@@ -201,15 +204,10 @@ namespace AssetBundler
}
}
AZ::IO::FixedMaxPath GetEngineRoot()
AZ::IO::FixedMaxPath GetCachedEngineRoot()
{
AZ::IO::FixedMaxPath engineRootPath;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
}
return engineRootPath;
AZ_Error(AppWindowName, !g_cachedEngineRoot.empty(), "Cached Engine Root has not been initialized by the Bundler.");
return g_cachedEngineRoot;
}
void AddPlatformIdentifier(AZStd::string& filePath, const AZStd::string& platformIdentifier)
@@ -276,11 +274,11 @@ namespace AssetBundler
return defaultSeedLists;
}
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName)
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view projectPath, AZStd::string_view projectName)
{
AZStd::vector<AZStd::string> defaultSeeds;
defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(enginePath, projectPath, projectName));
defaultSeeds.emplace_back(GetProjectDependenciesAssetPath(projectPath, projectName));
return defaultSeeds;
}
@@ -294,34 +292,12 @@ namespace AssetBundler
return projectDependenciesFilePath.LexicallyNormal();
}
AZ::IO::Path GetProjectDependenciesFileTemplate(AZStd::string_view engineRoot)
{
AZ::IO::Path projectDependenciesFileTemplate = engineRoot;
projectDependenciesFileTemplate /= DefaultProjectTemplatePath;
projectDependenciesFileTemplate /= AZStd::string::format("%s%s", ProjectName, DependenciesFileSuffix);
projectDependenciesFileTemplate.ReplaceExtension(DependenciesFileExtension);
return projectDependenciesFileTemplate.LexicallyNormal();
}
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName)
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view projectPath, AZStd::string_view projectName)
{
AZ::IO::Path projectDependenciesFile = GetProjectDependenciesFile(projectPath, projectName);
if (!AZ::IO::FileIOBase::GetInstance()->Exists(projectDependenciesFile.c_str()))
{
AZ_TracePrintf(AssetBundler::AppWindowName, "Project dependencies file %s doesn't exist.\n", projectDependenciesFile.c_str());
AZ::IO::Path projectDependenciesFileTemplate = GetProjectDependenciesFileTemplate(enginePath);
if (AZ::IO::FileIOBase::GetInstance()->Copy(projectDependenciesFileTemplate.c_str(), projectDependenciesFile.c_str()))
{
AZ_TracePrintf(AssetBundler::AppWindowName, "Copied project dependencies file template %s to the current project.\n",
projectDependenciesFile.c_str());
}
else
{
AZ_Error(AppWindowName, false, "Failed to copy project dependencies file template %s from default project"
" template to the current project.\n", projectDependenciesFileTemplate.c_str());
return {};
}
AZ_Error(AssetBundler::AppWindowName, false, "Project dependencies file %s doesn't exist.\n", projectDependenciesFile.c_str());
}
// Turn the absolute path into a cache-relative path
@@ -538,6 +514,14 @@ namespace AssetBundler
return platformSpecificCacheFolderPath;
}
AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath)
{
AZStd::string key(absoluteFilePath);
AzFramework::StringFunc::Path::Normalize(key);
AzFramework::StringFunc::Path::StripDrive(key);
return key;
}
void ConvertToRelativePath(AZStd::string_view parentFolderPath, AZStd::string& absoluteFilePath)
{
absoluteFilePath = AZ::IO::PathView(absoluteFilePath).LexicallyRelative(parentFolderPath).String();
@@ -822,4 +806,26 @@ namespace AssetBundler
}
return false;
}
QJsonObject ReadJson(const AZStd::string& filePath)
{
QByteArray byteArray;
QFile jsonFile;
jsonFile.setFileName(filePath.c_str());
jsonFile.open(QIODevice::ReadOnly | QIODevice::Text);
byteArray = jsonFile.readAll();
jsonFile.close();
return QJsonDocument::fromJson(byteArray).object();
}
void SaveJson(const AZStd::string& filePath, const QJsonObject& jsonObject)
{
QFile jsonFile(filePath.c_str());
QJsonDocument JsonDocument;
JsonDocument.setObject(jsonObject);
jsonFile.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
jsonFile.write(JsonDocument.toJson());
jsonFile.close();
}
}
+24 -8
View File
@@ -19,7 +19,9 @@
#include <AzFramework/Platform/PlatformDefaults.h>
#include <AzToolsFramework/Asset/AssetBundler.h>
#include <AzToolsFramework/Asset/AssetUtils.h>
#include <QDir>
#include <QStringList>
#include <QJsonObject>
namespace AssetBundler
{
@@ -120,8 +122,20 @@ namespace AssetBundler
////////////////////////////////////////////////////////////////////////////////////////////
extern const char* AssetCatalogFilename;
extern AZ::IO::FixedMaxPath g_cachedEngineRoot;
static const size_t MaxErrorMessageLength = 4096;
//! This struct stores gem related information
struct GemInfo
{
AZ_CLASS_ALLOCATOR(GemInfo, AZ::SystemAllocator, 0);
GemInfo(AZStd::string name, AZStd::string relativeFilePath, AZStd::string absoluteFilePath);
GemInfo() = default;
AZStd::string m_gemName;
AZStd::string m_relativeFilePath;
AZStd::string m_absoluteFilePath;
};
// The Warning Absorber is used to absorb warnings
// One case that this is being used is during loading of the asset catalog.
@@ -137,8 +151,8 @@ namespace AssetBundler
bool OnPreWarning(const char* window, const char* fileName, int line, const char* func, const char* message) override;
};
// Returns the engine root
AZ::IO::FixedMaxPath GetEngineRoot();
// Returns the cached engine root. Throws an error if the cached path has not been initialized by the Bundler Application.
AZ::IO::FixedMaxPath GetCachedEngineRoot();
/**
* Determines the name of the currently enabled game project
@@ -192,6 +206,8 @@ namespace AssetBundler
*/
AZ::IO::Path GetPlatformSpecificCacheFolderPath();
AZStd::string GenerateKeyFromAbsolutePath(const AZStd::string& absoluteFilePath);
void ConvertToRelativePath(AZStd::string_view parentFolderPath, AZStd::string& absoluteFilePath);
AZ::Outcome<void, AZStd::string> MakePath(const AZStd::string& path);
@@ -207,16 +223,13 @@ namespace AssetBundler
const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
//! Returns a vector of relative paths to Assets that should be included as default Seeds, but are not already in a Seed List file.
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName);
AZStd::vector<AZStd::string> GetDefaultSeeds(AZStd::string_view projectPath, AZStd::string_view projectName);
//! Returns the absolute path of {ProjectName}_Dependencies.xml
AZ::IO::Path GetProjectDependenciesFile(AZStd::string_view productPath, AZStd::string_view projectName);
//! Returns the absolute path of the project dependencies file in the default project template
AZ::IO::Path GetProjectDependenciesFileTemplate(AZStd::string_view enginePath);
//! Creates the ProjectName_Dependencies.xml file if it does not exist, and adds returns the relative path to the asset in the Cache.
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view enginePath, AZStd::string_view projectPath, AZStd::string_view projectName);
AZ::IO::Path GetProjectDependenciesAssetPath(AZStd::string_view projectPath, AZStd::string_view projectName);
//! Returns the map from gem seed list file path to gem name
AZStd::unordered_map<AZStd::string, AZStd::string> GetGemSeedListFilePathToGemNameMap(const AZStd::vector<AzFramework::GemInfo>& gemInfoList, AzFramework::PlatformFlags platformFlags);
@@ -229,6 +242,9 @@ namespace AssetBundler
//! Please note that the game project could be in a different location to the engine therefore we need the assetRoot param.
AzFramework::PlatformFlags GetEnabledPlatformFlags(AZStd::string_view enginePath, AZStd::string_view assetRoot, AZStd::string_view projectPath);
QJsonObject ReadJson(const AZStd::string& filePath);
void SaveJson(const AZStd::string& filePath, const QJsonObject& jsonObject);
//! Filepath is a helper class that is used to find the absolute path of a file
//! if the inputted file path is an absolute path than it does nothing
//! if the inputted file path is a relative path than based on whether the user