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:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user