From e76ed67e950e5abd375ccfef1b551eb334d9e060 Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 21 Sep 2021 18:34:15 -0700 Subject: [PATCH 01/11] Add no repositories added screen Signed-off-by: nggieber --- .../Resources/ProjectManager.qss | 11 +- .../Source/GemRepo/GemRepoAddDialog.cpp | 18 +++ .../Source/GemRepo/GemRepoAddDialog.h | 24 +++ .../Source/GemRepo/GemRepoScreen.cpp | 139 +++++++++++++----- .../Source/GemRepo/GemRepoScreen.h | 8 + .../project_manager_files.cmake | 2 + 6 files changed, 164 insertions(+), 38 deletions(-) create mode 100644 Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp create mode 100644 Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 30117d6636..52cc784336 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -556,17 +556,20 @@ QProgressBar::chunk { font-size: 12px; } +#gemRepoNoReposLabel { + font-size: 16px; +} + #gemRepoHeaderRefreshButton { background-color: transparent; qproperty-flat: true; qproperty-iconSize: 14px; } -#gemRepoHeaderAddButton { +#gemRepoAddButton { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #888888, stop: 1.0 #555555); qproperty-flat: true; - margin-right:30px; min-width:120px; max-width:120px; min-height:24px; @@ -576,11 +579,11 @@ QProgressBar::chunk { font-size:12px; font-weight:600; } -#gemRepoHeaderAddButton:hover { +#gemRepoAddButton:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #999999, stop: 1.0 #666666); } -#gemRepoHeaderAddButton:pressed { +#gemRepoAddButton:pressed { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #555555, stop: 1.0 #777777); } diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp new file mode 100644 index 0000000000..31e98a965b --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +namespace O3DE::ProjectManager +{ + GemRepoAddDialog::GemRepoAddDialog(QWidget* parent) + : QDialog(parent) + { + + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h new file mode 100644 index 0000000000..24c9b4b357 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + class GemRepoAddDialog + : public QDialog + { + public: + explicit GemRepoAddDialog(QWidget* parent = nullptr); + ~GemRepoAddDialog() = default; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 82de53a0d0..5838abf643 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include namespace O3DE::ProjectManager { @@ -31,12 +33,109 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); - setLayout(vLayout); + setLayout(vLayout); + + m_contentStack = new QStackedWidget(this); + + m_noRepoContent = CreateNoReposContent(); + m_contentStack->addWidget(m_noRepoContent); + + m_repoContent = CreateReposContent(); + m_contentStack->addWidget(m_repoContent); + + vLayout->addWidget(m_contentStack); + + Reinit(); + } + + void GemRepoScreen::Reinit() + { + m_gemRepoModel->clear(); + FillModel(); + + // If model contains any data show the repos + if (m_gemRepoModel->rowCount()) + { + m_contentStack->setCurrentWidget(m_repoContent); + } + else + { + m_contentStack->setCurrentWidget(m_noRepoContent); + } + + // Select the first entry after everything got correctly sized + QTimer::singleShot(200, [=]{ + QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); + m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + }); + } + + void GemRepoScreen::FillModel() + { + AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); + if (allGemRepoInfosResult.IsSuccess()) + { + // Add all available repos to the model + const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue(); + for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos) + { + m_gemRepoModel->AddGemRepo(gemRepoInfo); + } + } + else + { + QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); + } + } + + QFrame* GemRepoScreen::CreateNoReposContent() + { + QFrame* contentFrame = new QFrame(this); + + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setAlignment(Qt::AlignHCenter); + vLayout->setMargin(0); + vLayout->setSpacing(0); + contentFrame->setLayout(vLayout); + + vLayout->addStretch(); + + QLabel* noRepoLabel = new QLabel(tr("No repositories have been added yet."), this); + noRepoLabel->setObjectName("gemRepoNoReposLabel"); + vLayout->addWidget(noRepoLabel); + vLayout->setAlignment(noRepoLabel, Qt::AlignHCenter); + + vLayout->addSpacing(20); + + // Size hint for button is wrong so horizontal layout with stretch is used to center it + QHBoxLayout* hLayout = new QHBoxLayout(); + hLayout->setMargin(0); + hLayout->setSpacing(0); + + hLayout->addStretch(); + + m_AddRepoButton = new QPushButton(tr("Add Repository"), this); + m_AddRepoButton->setObjectName("gemRepoAddButton"); + m_AddRepoButton->setMinimumWidth(120); + hLayout->addWidget(m_AddRepoButton); + + hLayout->addStretch(); + + vLayout->addLayout(hLayout); + + vLayout->addStretch(); + + return contentFrame; + } + + QFrame* GemRepoScreen::CreateReposContent() + { + QFrame* contentFrame = new QFrame(this); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); hLayout->setSpacing(0); - vLayout->addLayout(hLayout); + contentFrame->setLayout(hLayout); hLayout->addSpacing(60); @@ -67,9 +166,11 @@ namespace O3DE::ProjectManager topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); m_AddRepoButton = new QPushButton(tr("Add Repository"), this); - m_AddRepoButton->setObjectName("gemRepoHeaderAddButton"); + m_AddRepoButton->setObjectName("gemRepoAddButton"); topMiddleHLayout->addWidget(m_AddRepoButton); + topMiddleHLayout->addSpacing(30); + middleVLayout->addLayout(topMiddleHLayout); middleVLayout->addSpacing(30); @@ -105,37 +206,7 @@ namespace O3DE::ProjectManager hLayout->addLayout(middleVLayout); hLayout->addWidget(m_gemRepoInspector); - Reinit(); - } - - void GemRepoScreen::Reinit() - { - m_gemRepoModel->clear(); - FillModel(); - - // Select the first entry after everything got correctly sized - QTimer::singleShot(200, [=]{ - QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); - m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); - }); - } - - void GemRepoScreen::FillModel() - { - AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); - if (allGemRepoInfosResult.IsSuccess()) - { - // Add all available repos to the model - const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue(); - for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos) - { - m_gemRepoModel->AddGemRepo(gemRepoInfo); - } - } - else - { - QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); - } + return contentFrame; } ProjectManagerScreen GemRepoScreen::GetScreenEnum() diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index b5316db84f..ab679ad39b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -16,6 +16,8 @@ QT_FORWARD_DECLARE_CLASS(QLabel) QT_FORWARD_DECLARE_CLASS(QPushButton) QT_FORWARD_DECLARE_CLASS(QHeaderView) QT_FORWARD_DECLARE_CLASS(QTableWidget) +QT_FORWARD_DECLARE_CLASS(QFrame) +QT_FORWARD_DECLARE_CLASS(QStackedWidget) namespace O3DE::ProjectManager { @@ -36,6 +38,12 @@ namespace O3DE::ProjectManager private: void FillModel(); + QFrame* CreateNoReposContent(); + QFrame* CreateReposContent(); + + QStackedWidget* m_contentStack = nullptr; + QFrame* m_noRepoContent; + QFrame* m_repoContent; QTableWidget* m_gemRepoHeaderTable = nullptr; QHeaderView* m_gemRepoListHeader = nullptr; diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 7a336972e0..31686faa2f 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -102,6 +102,8 @@ set(FILES Source/GemCatalog/GemSortFilterProxyModel.cpp Source/GemRepo/GemRepoScreen.h Source/GemRepo/GemRepoScreen.cpp + Source/GemRepo/GemRepoAddDialog.h + Source/GemRepo/GemRepoAddDialog.cpp Source/GemRepo/GemRepoInfo.h Source/GemRepo/GemRepoInfo.cpp Source/GemRepo/GemRepoItemDelegate.h From 536ef46e2bc1e5e20e1f4f46ff6377c58726187f Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 27 Sep 2021 07:12:10 -0700 Subject: [PATCH 02/11] Add Add Gem Repo Dialog Signed-off-by: nggieber --- .../Resources/ProjectManager.qss | 4 ++ .../Source/GemRepo/GemRepoAddDialog.cpp | 62 +++++++++++++++++++ .../Source/GemRepo/GemRepoAddDialog.h | 15 +++++ .../Source/GemRepo/GemRepoScreen.cpp | 45 +++++++++++--- .../Source/GemRepo/GemRepoScreen.h | 4 +- .../ProjectManager/Source/PythonBindings.cpp | 7 +++ .../ProjectManager/Source/PythonBindings.h | 1 + .../Source/PythonBindingsInterface.h | 7 +++ 8 files changed, 137 insertions(+), 8 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 52cc784336..8bfd647a56 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -600,3 +600,7 @@ QProgressBar::chunk { #gemRepoInspector { background: #444444; } + +#gemRepoAddDialogInstructionTitleLabel { + font-size:14px; +} diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 31e98a965b..4525abb16b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -7,12 +7,74 @@ */ #include +#include + +#include +#include +#include +#include namespace O3DE::ProjectManager { GemRepoAddDialog::GemRepoAddDialog(QWidget* parent) : QDialog(parent) { + setWindowTitle(tr("Add a User Repository")); + setModal(true); + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setContentsMargins(30, 30, 25, 10); + vLayout->setSpacing(0); + setLayout(vLayout); + + QLabel* instructionTitleLabel = new QLabel(tr("Enter a valid path to add a new user repository")); + instructionTitleLabel->setObjectName("gemRepoAddDialogInstructionTitleLabel"); + instructionTitleLabel->setAlignment(Qt::AlignLeft); + vLayout->addWidget(instructionTitleLabel); + + vLayout->addSpacing(10); + + QLabel* instructionContextLabel = new QLabel(tr("The path can be a Repository URL or a Local Path in your directory.")); + instructionContextLabel->setAlignment(Qt::AlignLeft); + vLayout->addWidget(instructionContextLabel); + + m_repoPath = new FormLineEditWidget(tr("Repository Path"), "", this); + m_repoPath->setFixedWidth(500); + vLayout->addWidget(m_repoPath); + + vLayout->addSpacing(40); + + QDialogButtonBox* dialogButtons = new QDialogButtonBox(); + dialogButtons->setObjectName("footer"); + vLayout->addWidget(dialogButtons); + + QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); + cancelButton->setProperty("secondary", true); + QPushButton* continueButton = dialogButtons->addButton(tr("Add"), QDialogButtonBox::ApplyRole); + + connect(cancelButton, &QPushButton::clicked, this, &GemRepoAddDialog::CancelButtonPressed); + connect(continueButton, &QPushButton::clicked, this, &GemRepoAddDialog::ContinueButtonPressed); + } + + QDialogButtonBox::ButtonRole GemRepoAddDialog::GetButtonResult() + { + return m_buttonResult; + } + + QString GemRepoAddDialog::GetRepoPath() + { + return m_repoPath->lineEdit()->text(); + } + + void GemRepoAddDialog::CancelButtonPressed() + { + m_buttonResult = QDialogButtonBox::RejectRole; + close(); + } + + void GemRepoAddDialog::ContinueButtonPressed() + { + m_buttonResult = QDialogButtonBox::ApplyRole; + close(); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h index 24c9b4b357..28530c5f0b 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -10,15 +10,30 @@ #if !defined(Q_MOC_RUN) #include + +#include #endif namespace O3DE::ProjectManager { + QT_FORWARD_DECLARE_CLASS(FormLineEditWidget) + class GemRepoAddDialog : public QDialog { public: explicit GemRepoAddDialog(QWidget* parent = nullptr); ~GemRepoAddDialog() = default; + + QDialogButtonBox::ButtonRole GetButtonResult(); + QString GetRepoPath(); + + private: + void CancelButtonPressed(); + void ContinueButtonPressed(); + + FormLineEditWidget* m_repoPath = nullptr; + + QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 5838abf643..5e533414b0 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,32 @@ namespace O3DE::ProjectManager }); } + void GemRepoScreen::HandleAddRepoButton() + { + GemRepoAddDialog* repoAddDialog = new GemRepoAddDialog(this); + repoAddDialog->exec(); + + if (repoAddDialog->GetButtonResult() == QDialogButtonBox::ApplyRole) + { + QString repoUrl = repoAddDialog->GetRepoPath(); + if (repoUrl.isEmpty()) + { + return; + } + + AZ::Outcome addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUrl); + if (addGemRepoResult.IsSuccess()) + { + Reinit(); + } + else + { + QMessageBox::critical(this, tr("Operation failed"), + QString("Failed to add gem repo: %1.\nError:\n%2").arg(repoUrl, addGemRepoResult.GetError().c_str())); + } + } + } + void GemRepoScreen::FillModel() { AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos(); @@ -114,10 +141,12 @@ namespace O3DE::ProjectManager hLayout->addStretch(); - m_AddRepoButton = new QPushButton(tr("Add Repository"), this); - m_AddRepoButton->setObjectName("gemRepoAddButton"); - m_AddRepoButton->setMinimumWidth(120); - hLayout->addWidget(m_AddRepoButton); + QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this); + addRepoButton->setObjectName("gemRepoAddButton"); + addRepoButton->setMinimumWidth(120); + hLayout->addWidget(addRepoButton); + + connect(addRepoButton, &QPushButton::clicked, this, &GemRepoScreen::HandleAddRepoButton); hLayout->addStretch(); @@ -165,9 +194,11 @@ namespace O3DE::ProjectManager topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); - m_AddRepoButton = new QPushButton(tr("Add Repository"), this); - m_AddRepoButton->setObjectName("gemRepoAddButton"); - topMiddleHLayout->addWidget(m_AddRepoButton); + QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this); + addRepoButton->setObjectName("gemRepoAddButton"); + topMiddleHLayout->addWidget(addRepoButton); + + connect(addRepoButton, &QPushButton::clicked, this, &GemRepoScreen::HandleAddRepoButton); topMiddleHLayout->addSpacing(30); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index ab679ad39b..fcbb59cceb 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -36,6 +36,9 @@ namespace O3DE::ProjectManager GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; } + public slots: + void HandleAddRepoButton(); + private: void FillModel(); QFrame* CreateNoReposContent(); @@ -53,6 +56,5 @@ namespace O3DE::ProjectManager QLabel* m_lastAllUpdateLabel; QPushButton* m_AllUpdateButton; - QPushButton* m_AddRepoButton; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 6f8ff9abce..aa3f957a2a 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -913,6 +913,13 @@ namespace O3DE::ProjectManager } } + AZ::Outcome PythonBindings::AddGemRepo(const QString& repoUri) + { + // o3de scripts need method added + (void)repoUri; + return AZ::Failure("Adding Gem Repo not implemented yet in o3de scripts."); + } + GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath) { /* Placeholder Logic */ diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 3b766c3797..c216be0acb 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -57,6 +57,7 @@ namespace O3DE::ProjectManager AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override; // Gem Repos + AZ::Outcome AddGemRepo(const QString& repoUri = {}) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; private: diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 9fd3002f93..4baab85145 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -159,6 +159,13 @@ namespace O3DE::ProjectManager // Gem Repos + /** + * A gem repo to engine. Registers this gem repo with the current engine. + * @param repoUri the absolute filesystem path or url to the gem repo manifest file. + * @return An outcome with the success flag as well as an error message in case of a failure. + */ + virtual AZ::Outcome AddGemRepo(const QString& repoUri = {}) = 0; + /** * Get all available gem repo infos. Gathers all repos registered with the engine. * @return A list of gem repo infos. From 690f8e6925a13f097ef17e5e60ec9babb4c465f1 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 27 Sep 2021 07:31:32 -0700 Subject: [PATCH 03/11] Minor merge fix Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 63f92466b5..0d0605f750 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include #include @@ -35,7 +35,7 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); - setLayout(vLayout); + setLayout(vLayout); m_contentStack = new QStackedWidget(this); From 0b5aaa297e69d123397c76f57075ef216f3f5f47 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 27 Sep 2021 07:40:33 -0700 Subject: [PATCH 04/11] Fix text alignment Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 0d0605f750..e2c03b6cc2 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -35,7 +35,7 @@ namespace O3DE::ProjectManager QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); - setLayout(vLayout); + setLayout(vLayout); m_contentStack = new QStackedWidget(this); From 16e66cfa7145d077af7a593cac51c75e6b871d83 Mon Sep 17 00:00:00 2001 From: nggieber Date: Tue, 28 Sep 2021 18:37:44 -0700 Subject: [PATCH 05/11] Addressed review feedback Signed-off-by: nggieber --- .../Resources/ProjectManager.qss | 4 +++ .../Source/GemRepo/GemRepoAddDialog.cpp | 27 +++++-------------- .../Source/GemRepo/GemRepoAddDialog.h | 8 ------ .../Source/GemRepo/GemRepoScreen.cpp | 7 +++-- .../ProjectManager/Source/PythonBindings.h | 2 +- .../Source/PythonBindingsInterface.h | 2 +- 6 files changed, 15 insertions(+), 35 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 8898a94652..eeed316cbc 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -617,6 +617,10 @@ QProgressBar::chunk { font-size:14px; } +#addGemRepoDialog #formFrame { + margin-left:0px; +} + /************** Gem Repo Inspector **************/ #gemRepoInspectorNameLabel { diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 4525abb16b..9e40a2b231 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace O3DE::ProjectManager @@ -21,6 +22,7 @@ namespace O3DE::ProjectManager { setWindowTitle(tr("Add a User Repository")); setModal(true); + setObjectName("addGemRepoDialog"); QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setContentsMargins(30, 30, 25, 10); @@ -39,7 +41,7 @@ namespace O3DE::ProjectManager vLayout->addWidget(instructionContextLabel); m_repoPath = new FormLineEditWidget(tr("Repository Path"), "", this); - m_repoPath->setFixedWidth(500); + m_repoPath->setFixedWidth(600); vLayout->addWidget(m_repoPath); vLayout->addSpacing(40); @@ -50,31 +52,14 @@ namespace O3DE::ProjectManager QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); cancelButton->setProperty("secondary", true); - QPushButton* continueButton = dialogButtons->addButton(tr("Add"), QDialogButtonBox::ApplyRole); + QPushButton* applyButton = dialogButtons->addButton(tr("Add"), QDialogButtonBox::ApplyRole); - connect(cancelButton, &QPushButton::clicked, this, &GemRepoAddDialog::CancelButtonPressed); - connect(continueButton, &QPushButton::clicked, this, &GemRepoAddDialog::ContinueButtonPressed); - } - - QDialogButtonBox::ButtonRole GemRepoAddDialog::GetButtonResult() - { - return m_buttonResult; + connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); + connect(applyButton, &QPushButton::clicked, this, &QDialog::accept); } QString GemRepoAddDialog::GetRepoPath() { return m_repoPath->lineEdit()->text(); } - - void GemRepoAddDialog::CancelButtonPressed() - { - m_buttonResult = QDialogButtonBox::RejectRole; - close(); - } - - void GemRepoAddDialog::ContinueButtonPressed() - { - m_buttonResult = QDialogButtonBox::ApplyRole; - close(); - } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h index 28530c5f0b..38b9bf68eb 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -10,8 +10,6 @@ #if !defined(Q_MOC_RUN) #include - -#include #endif namespace O3DE::ProjectManager @@ -25,15 +23,9 @@ namespace O3DE::ProjectManager explicit GemRepoAddDialog(QWidget* parent = nullptr); ~GemRepoAddDialog() = default; - QDialogButtonBox::ButtonRole GetButtonResult(); QString GetRepoPath(); private: - void CancelButtonPressed(); - void ContinueButtonPressed(); - FormLineEditWidget* m_repoPath = nullptr; - - QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index e2c03b6cc2..9c432884e6 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -75,9 +75,8 @@ namespace O3DE::ProjectManager void GemRepoScreen::HandleAddRepoButton() { GemRepoAddDialog* repoAddDialog = new GemRepoAddDialog(this); - repoAddDialog->exec(); - if (repoAddDialog->GetButtonResult() == QDialogButtonBox::ApplyRole) + if (repoAddDialog->exec() == QDialog::DialogCode::Accepted) { QString repoUrl = repoAddDialog->GetRepoPath(); if (repoUrl.isEmpty()) @@ -93,7 +92,7 @@ namespace O3DE::ProjectManager else { QMessageBox::critical(this, tr("Operation failed"), - QString("Failed to add gem repo: %1.\nError:\n%2").arg(repoUrl, addGemRepoResult.GetError().c_str())); + QString("Failed to add gem repo: %1.
Error:
%2").arg(repoUrl, addGemRepoResult.GetError().c_str())); } } } @@ -112,7 +111,7 @@ namespace O3DE::ProjectManager } else { - QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str())); + QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.
Error:
%2").arg(allGemRepoInfosResult.GetError().c_str())); } } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index c216be0acb..42f04ed6e6 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -57,7 +57,7 @@ namespace O3DE::ProjectManager AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override; // Gem Repos - AZ::Outcome AddGemRepo(const QString& repoUri = {}) override; + AZ::Outcome AddGemRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; private: diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 5a008c46df..92139f3df5 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -165,7 +165,7 @@ namespace O3DE::ProjectManager * @param repoUri the absolute filesystem path or url to the gem repo manifest file. * @return An outcome with the success flag as well as an error message in case of a failure. */ - virtual AZ::Outcome AddGemRepo(const QString& repoUri = {}) = 0; + virtual AZ::Outcome AddGemRepo(const QString& repoUri) = 0; /** * Get all available gem repo infos. Gathers all repos registered with the engine. From 6b75c3b9d71fcd454757ba119e94832a02c8f4fe Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 29 Sep 2021 08:55:04 -0700 Subject: [PATCH 06/11] Fixed non-unity compile error Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h index 38b9bf68eb..4ca469098e 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.h @@ -9,7 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace O3DE::ProjectManager From 02987d90102e361d179c4d20f8d83a0146c758c0 Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 29 Sep 2021 09:34:21 -0700 Subject: [PATCH 07/11] Fixed another non-unity build error Signed-off-by: nggieber --- Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp index 9e40a2b231..1839948e80 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoAddDialog.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include From b79c2f385d52afa5ff146f41a4ca3508bc12cf65 Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Wed, 29 Sep 2021 11:08:05 -0700 Subject: [PATCH 08/11] Adding a temporary Orphan function to the InstanceDatabase (#4297) * Adding a temporary Orphan function to the InstanceDatabase, which will remove an instance from the database so it will not be found using Find or FindOrCreate. The instance will still persist until its use-count drops to 0, at which point it will be deleted. This is to enable the model asset to remove existing buffer/modellod/model instances and replace them with new instances that have the up to date data. Added unit tests for testing. Signed-off-by: amzn-tommy * Fix an incorrect ceil and update ParallelInstance test cases for readability Signed-off-by: amzn-tommy --- .../AtomCore/AtomCore/Instance/InstanceData.h | 3 + .../AtomCore/Instance/InstanceDatabase.h | 30 ++++ .../AtomCore/Tests/InstanceDatabase.cpp | 169 +++++++++++++++--- 3 files changed, 179 insertions(+), 23 deletions(-) diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h index 33fc93c0f5..6b07d12e9c 100644 --- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h +++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h @@ -89,6 +89,9 @@ namespace AZ // Tracks the asset type used to create the instance. AssetType m_assetType; + + // Boolean to indicate if the instance has been orphaned from the instance database + bool m_isOrphaned = false; }; /// @cond EXCLUDE_DOCS diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h index ac97af3629..4b4ad572c2 100644 --- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h +++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h @@ -203,6 +203,16 @@ namespace AZ //! Calls FindOrCreate using a random InstanceId Data::Instance Create(const Asset& asset, const AZStd::any* param = nullptr); + /** + * Removes the instance data from the database. Does not release it. + * References to existing instances will remain valid, but new calls to Create/FindOrCreate will create a new instance + * This function is temporary, to provide functionality needed for Model hot-reloading, but will be removed + * once the Model class does not need it anymore. + * + * @param id The id of the instance to remove + */ + void TEMPOrphan(const InstanceId& id); + private: InstanceDatabase(const AssetType& assetType); ~InstanceDatabase(); @@ -356,6 +366,20 @@ namespace AZ return FindOrCreate(Data::InstanceId::CreateRandom(), asset, param); } + template + void InstanceDatabase::TEMPOrphan(const InstanceId& id) + { + AZStd::scoped_lock lock(m_databaseMutex); + // Check if the instance is still in the database, in case it was orphaned twice + auto instanceItr = m_database.find(id); + if (instanceItr != m_database.end()) + { + // Mark the instance as orphaned, and remove it from the database + instanceItr->second->m_isOrphaned = true; + m_database.erase(instanceItr); + } + } + template void InstanceDatabase::ReleaseInstance(InstanceData* instance, const InstanceId& instanceId) { @@ -374,6 +398,12 @@ namespace AZ m_database.erase(instance->GetId()); m_instanceHandler.m_deleteFunction(static_cast(instance)); } + else if (instance->m_isOrphaned && instance->m_useCount.compare_exchange_strong(expectedRefCount, -1)) + { + // If the instance was orphaned, it has already been removed from the database, + // but still needs to be deleted when the refcount drops to 0 + m_instanceHandler.m_deleteFunction(static_cast(instance)); + } } template diff --git a/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp b/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp index 5d1edc5a09..6a5c65ac7a 100644 --- a/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp +++ b/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp @@ -181,7 +181,76 @@ namespace UnitTest EXPECT_EQ(instance, instance3); } - void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, size_t durationSeconds) + TEST_F(InstanceDatabaseTest, InstanceOrphan) + { + auto& assetManager = AssetManager::Instance(); + auto& instanceDatabase = InstanceDatabase::Instance(); + + Asset someAsset = assetManager.CreateAsset(s_assetId0, AZ::Data::AssetLoadBehavior::Default); + + Instance orphanedInstance = instanceDatabase.FindOrCreate(s_instanceId0, someAsset); + EXPECT_NE(orphanedInstance, nullptr); + + instanceDatabase.TEMPOrphan(s_instanceId0); + // After orphan, the instance should not be found in the database, but it should still be valid + EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr); + EXPECT_NE(orphanedInstance, nullptr); + + instanceDatabase.TEMPOrphan(s_instanceId0); + // Orphaning twice should be a no-op + EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr); + EXPECT_NE(orphanedInstance, nullptr); + + Instance instance2 = instanceDatabase.FindOrCreate(s_instanceId0, someAsset); + // Creating another instance with the same id should return a different instance than the one that was orphaned + EXPECT_NE(orphanedInstance, instance2); + } + + enum class ParallelInstanceTestCases + { + Create, + CreateAndDeferRemoval, + CreateAndOrphan, + CreateDeferRemovalAndOrphan + }; + + enum class ParralleInstanceCurrentAction + { + Create, + DeferredRemoval, + Orphan + }; + + ParralleInstanceCurrentAction ParallelInstanceGetCurrentAction(ParallelInstanceTestCases testCase) + { + switch (testCase) + { + case ParallelInstanceTestCases::CreateAndDeferRemoval: + switch (rand() % 2) + { + case 0: return ParralleInstanceCurrentAction::Create; + case 1: return ParralleInstanceCurrentAction::DeferredRemoval; + } + case ParallelInstanceTestCases::CreateAndOrphan: + switch (rand() % 2) + { + case 0: return ParralleInstanceCurrentAction::Create; + case 1: return ParralleInstanceCurrentAction::Orphan; + } + case ParallelInstanceTestCases::CreateDeferRemovalAndOrphan: + switch (rand() % 3) + { + case 0: return ParralleInstanceCurrentAction::Create; + case 1: return ParralleInstanceCurrentAction::DeferredRemoval; + case 2: return ParralleInstanceCurrentAction::Orphan; + } + case ParallelInstanceTestCases::Create: + default: + return ParralleInstanceCurrentAction::Create; + } + } + + void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, float durationSeconds, ParallelInstanceTestCases testCase) { printf("Testing threads=%zu assetIds=%zu ... ", threadCountMax, assetIdCount); @@ -192,6 +261,7 @@ namespace UnitTest auto& instanceManager = InstanceDatabase::Instance(); AZStd::vector guids; + AZStd::vector> instances; AZStd::vector> assets; for (size_t i = 0; i < assetIdCount; ++i) @@ -199,6 +269,7 @@ namespace UnitTest Uuid guid = Uuid::CreateRandom(); guids.emplace_back(guid); + instances.emplace_back(nullptr); // Pre-create asset so we don't attempt to load it from the catalog. assets.emplace_back(assetManager.CreateAsset(guid, AZ::Data::AssetLoadBehavior::Default)); @@ -206,6 +277,7 @@ namespace UnitTest AZStd::vector threads; AZStd::mutex mutex; + AZStd::mutex referenceTableMutex; AZStd::atomic threadCount((int)threadCountMax); AZStd::condition_variable cv; AZStd::atomic_bool keepDispatching(true); @@ -225,11 +297,15 @@ namespace UnitTest for (size_t i = 0; i < threadCountMax; ++i) { threads.emplace_back( - [&instanceManager, &threadCount, &cv, &guids, &assets, &durationSeconds]() + [&instanceManager, &threadCount, &cv, &guids, &instances, &assets, &durationSeconds, &testCase, &referenceTableMutex]() { AZ::Debug::Timer timer; timer.Stamp(); + bool deferRemoval = testCase == ParallelInstanceTestCases::CreateAndDeferRemoval || + testCase == ParallelInstanceTestCases::CreateDeferRemovalAndOrphan + ? true : false; + while (timer.GetDeltaTimeInSeconds() < durationSeconds) { const size_t index = rand() % guids.size(); @@ -237,11 +313,36 @@ namespace UnitTest const InstanceId instanceId{ uuid }; const AssetId assetId{ uuid }; - Instance instance = - instanceManager.FindOrCreate(instanceId, Asset(assetId, azrtti_typeid())); - EXPECT_NE(instance, nullptr); - EXPECT_EQ(instance->GetId(), instanceId); - EXPECT_EQ(instance->m_asset, assets[index]); + ParralleInstanceCurrentAction currentAction = ParallelInstanceGetCurrentAction(testCase); + + if (currentAction == ParralleInstanceCurrentAction::Orphan) + { + // Orphan the instance, but don't decrease its refcount + instanceManager.TEMPOrphan(instanceId); + } + else if (currentAction == ParralleInstanceCurrentAction::DeferredRemoval) + { + // Drop the refcount to zero so the instance will be released + referenceTableMutex.lock(); + instances[index] = nullptr; + referenceTableMutex.unlock(); + } + else + { + // Otherwise, add a new instance + Instance instance = instanceManager.FindOrCreate(instanceId, assets[index]); + EXPECT_NE(instance, nullptr); + EXPECT_EQ(instance->GetId(), instanceId); + EXPECT_EQ(instance->m_asset, assets[index]); + + if (deferRemoval) + { + // Keep a reference to the instance alive so it can be removed later + referenceTableMutex.lock(); + instances[index] = instance; + referenceTableMutex.unlock(); + } + } } threadCount--; @@ -254,10 +355,12 @@ namespace UnitTest // Used to detect a deadlock. If we wait for more than 10 seconds, it's likely a deadlock has occurred while (threadCount > 0 && !timedOut) { + size_t durationSecondsRoundedUp = static_cast(std::ceil(durationSeconds)); + AZStd::unique_lock lock(mutex); timedOut = (AZStd::cv_status::timeout == - cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSeconds * 2))); + cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSecondsRoundedUp * 2))); } EXPECT_TRUE(threadCount == 0) << "One or more threads appear to be deadlocked at " << timer.GetDeltaTimeInSeconds() << " seconds"; @@ -273,11 +376,11 @@ namespace UnitTest printf("Took %f seconds\n", timer.GetDeltaTimeInSeconds()); } - TEST_F(InstanceDatabaseTest, ParallelInstanceCreate) + void ParallelCreateTest(ParallelInstanceTestCases testCase) { // This is the original test scenario from when InstanceDatabase was first implemented // threads, AssetIds, seconds - ParallelInstanceCreateHelper(8, 100, 5); + ParallelInstanceCreateHelper(8, 100, 5, testCase); // This value is checked in as 1 so this test doesn't take too much time, but can be increased locally to soak the test. const size_t attempts = 1; @@ -289,11 +392,11 @@ namespace UnitTest // The idea behind this series of tests is that there are two threads sharing one Instance, and both threads try to // create or release that instance at the same time. // At the time, this set of scenarios has something like a 10% failure rate. - const size_t duration = 2; + const float duration = 2.0f; // threads, AssetIds, seconds - ParallelInstanceCreateHelper(2, 1, duration); - ParallelInstanceCreateHelper(4, 1, duration); - ParallelInstanceCreateHelper(8, 1, duration); + ParallelInstanceCreateHelper(2, 1, duration, testCase); + ParallelInstanceCreateHelper(4, 1, duration, testCase); + ParallelInstanceCreateHelper(8, 1, duration, testCase); } for (size_t i = 0; i < attempts; ++i) @@ -301,19 +404,39 @@ namespace UnitTest printf("Attempt %zu of %zu... \n", i, attempts); // Here we try a bunch of different threadCount:assetCount ratios to be thorough - const size_t duration = 2; + const float duration = 2.0f; // threads, AssetIds, seconds - ParallelInstanceCreateHelper(2, 1, duration); - ParallelInstanceCreateHelper(4, 1, duration); - ParallelInstanceCreateHelper(4, 2, duration); - ParallelInstanceCreateHelper(4, 4, duration); - ParallelInstanceCreateHelper(8, 1, duration); - ParallelInstanceCreateHelper(8, 2, duration); - ParallelInstanceCreateHelper(8, 3, duration); - ParallelInstanceCreateHelper(8, 4, duration); + ParallelInstanceCreateHelper(2, 1, duration, testCase); + ParallelInstanceCreateHelper(4, 1, duration, testCase); + ParallelInstanceCreateHelper(4, 2, duration, testCase); + ParallelInstanceCreateHelper(4, 4, duration, testCase); + ParallelInstanceCreateHelper(8, 1, duration, testCase); + ParallelInstanceCreateHelper(8, 2, duration, testCase); + ParallelInstanceCreateHelper(8, 3, duration, testCase); + ParallelInstanceCreateHelper(8, 4, duration, testCase); } } + TEST_F(InstanceDatabaseTest, ParallelInstanceCreate) + { + ParallelCreateTest(ParallelInstanceTestCases::Create); + } + + TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndDeferRemoval) + { + ParallelCreateTest(ParallelInstanceTestCases::CreateAndDeferRemoval); + } + + TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndOrphan) + { + ParallelCreateTest(ParallelInstanceTestCases::CreateAndOrphan); + } + + TEST_F(InstanceDatabaseTest, ParallelInstanceCreateDeferRemovalAndOrphan) + { + ParallelCreateTest(ParallelInstanceTestCases::CreateDeferRemovalAndOrphan); + } + TEST_F(InstanceDatabaseTest, InstanceCreateNoDatabase) { bool m_deleted = false; From 0f4a9d70b523722d5c7dda2cbf63a9152bc29576 Mon Sep 17 00:00:00 2001 From: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> Date: Wed, 29 Sep 2021 15:46:35 -0700 Subject: [PATCH 09/11] Fix 3p path setting to the upper level (#4399) Signed-off-by: jiaweig --- cmake/Tools/Platform/Android/generate_android_project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/Tools/Platform/Android/generate_android_project.py b/cmake/Tools/Platform/Android/generate_android_project.py index a508329d02..d8f1021590 100755 --- a/cmake/Tools/Platform/Android/generate_android_project.py +++ b/cmake/Tools/Platform/Android/generate_android_project.py @@ -368,7 +368,6 @@ def main(args): if not third_party_path.is_dir(): raise common.LmbrCmdError(f"Invalid --third-party-path '{parsed_args.third_party_path}'.", common.ERROR_CODE_INVALID_PARAMETER) - third_party_path = third_party_path.parent build_dir = parsed_args.build_dir From 816a623c97aa9abef13557ba13ac5f7db73e1ad7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:49:02 -0500 Subject: [PATCH 10/11] Added missing EntityId.h include to FocusModeInterface.h (#4396) * Added missing EntityId.h include to FocusModeInterface.h Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Non-unity build fix Adding missing BehaviorContext.h includes to Multiplayer Gem Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added missing BehaviorContext.h include to NetworkCharacterComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzNetworking/Framework/NetworkingSystemComponent.cpp | 1 + .../AzToolsFramework/FocusMode/FocusModeInterface.h | 1 + .../Code/Source/Components/NetworkCharacterComponent.cpp | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp b/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp index 83588f4acb..16e4e26f67 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Framework/NetworkingSystemComponent.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace AzNetworking diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h index a4b90f95b7..a2b23fa8d6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp index 33eb26653a..9e15ae6ce0 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkCharacterComponent.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,7 @@ namespace Multiplayer { - + bool CollisionLayerBasedControllerFilter(const physx::PxController& controllerA, const physx::PxController& controllerB) { PHYSX_SCENE_READ_LOCK(controllerA.getActor()->getScene()); @@ -82,7 +83,7 @@ namespace Multiplayer return physx::PxQueryHitType::eNONE; } - + void NetworkCharacterComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -116,7 +117,7 @@ namespace Multiplayer callbackManager->SetObjectPreFilter(CollisionLayerBasedObjectPreFilter); } } - + if (!HasController()) { GetNetworkTransformComponent()->TranslationAddEvent(m_translationEventHandler); @@ -134,7 +135,7 @@ namespace Multiplayer } void NetworkCharacterComponent::OnSyncRewind() - { + { if (m_physicsCharacter == nullptr) { return; From 090aa8f05339fe7ce2988bc882b818c194c7a34b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 29 Sep 2021 18:13:37 -0500 Subject: [PATCH 11/11] Removed ununeeded includes from EBus EBus.h and Policies.h (#4256) * Removed ununeeded includes from EBus EBus.h and Policies.h Updated the locations which needed those includes Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Adding missing include for to AWsClientAuthBus.h Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove the while true loop in the EBusQueuePolicy Execute() function The while true loop in Execute was for allowing additional functions to be queued in the middle of execution of current list of functions. That functionality was dangerous, because if a queued function added itself during execution unconditionally, then it would result in an infinite loop Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AssetManager::DispatchEvents function to pump the AssetBus event queue until empty Queued Events on the AssetBus is able to queue additional events on that Bus during execution of those events. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the AssetManager::DispatchEvents function to only execute the AssetBus queued events once Changed the AssetJobsFloodTest.AssetWithNoLoadReference_LoadDependencies_BehaviorObeyed test to dispatch events until the OnAssetContainerReady callback is signaled. This happens after every asset load to make sure that the expiring AssetContainer instances are removed from `AssetManager::m_ownedAssetContainer` container before retrying to load the same asset. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added a MaxTimeoutSeconds constant for the maximum amount of the time to run a single DispatchEvents loop Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Asset/AssetManager.cpp | 8 ++ .../AzCore/AzCore/Component/Component.h | 1 + .../AzCore/AzCore/Debug/AssetTracking.h | 1 + Code/Framework/AzCore/AzCore/EBus/EBus.h | 17 ++- .../AzCore/AzCore/EBus/IEventScheduler.h | 1 + Code/Framework/AzCore/AzCore/EBus/Policies.h | 37 +++--- .../AzCore/AzCore/RTTI/BehaviorContext.h | 1 + .../Tests/Asset/AssetManagerLoadingTests.cpp | 116 ++++++++++++++---- Code/Framework/AzCore/Tests/UUIDTests.cpp | 1 + .../AzFramework/Archive/ZipDirCache.h | 1 + .../AzFramework/Logging/MissingAssetLogger.h | 1 + .../Render/GeometryIntersectionStructures.h | 1 + .../AzFramework/Windowing/NativeWindow.h | 1 + .../UdpTransport/UdpConnectionSet.h | 1 + .../Entries/AssetBrowserEntryCache.h | 1 + .../Entries/RootAssetBrowserEntry.h | 1 + .../Manipulators/BaseManipulator.h | 2 +- .../SourceControl/SourceControlAPI.h | 1 + .../AzToolsFramework/ViewportUi/ButtonGroup.h | 1 + .../unittests/AssetProcessorServerUnitTests.h | 1 + .../ProjectManager/Source/PythonBindings.cpp | 1 + .../Source/LUA/LUAEditorStyleMessages.h | 1 + .../Code/Include/Private/AWSClientAuthBus.h | 2 + .../Private/Editor/UI/AWSCoreEditorMenu.h | 1 + .../Code/Source/AssetMemoryAnalyzer.cpp | 1 + .../Include/Atom/RHI/ThreadLocalContext.h | 1 + .../Window/MaterialEditorWindowSettings.h | 1 + .../Atom/Utils/AssetCollectionAsyncLoader.h | 1 + .../Utils/StateControllers/StateController.h | 1 + .../EditorAutomation/EditorAutomationTest.h | 1 + 30 files changed, 148 insertions(+), 58 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 98182a9568..8eb620f69e 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -340,6 +340,14 @@ namespace AZ // (Load jobs will attempt to reuse blocked threads before spinning off new job threads) ProcessLoadJob(); } + + // Pump the AssetBus function queue once more after the load has completed in case additional + // functions have been queued between the last call to DispatchEvents and the completion + // of the current load job + if (m_shouldDispatchEvents) + { + AssetManager::Instance().DispatchEvents(); + } } void Finish() diff --git a/Code/Framework/AzCore/AzCore/Component/Component.h b/Code/Framework/AzCore/AzCore/Component/Component.h index 3cbb9b5a86..677517d896 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.h +++ b/Code/Framework/AzCore/AzCore/Component/Component.h @@ -22,6 +22,7 @@ #include #include // Used as the allocator for most components. #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h b/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h index 5c3c835271..615634c05a 100644 --- a/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h +++ b/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h index 58754ff9b8..ff8966e8e0 100644 --- a/Code/Framework/AzCore/AzCore/EBus/EBus.h +++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h @@ -19,14 +19,11 @@ #pragma once #include +#include #include #include - // Included for backwards compatibility purposes -#include -#include #include -// End backwards compat #include #include @@ -90,14 +87,14 @@ namespace AZ * For available settings, see AZ::EBusHandlerPolicy. * By default, an EBus supports any number of handlers. */ - static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple; + static constexpr EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple; /** * Defines how many addresses exist on the EBus. * For available settings, see AZ::EBusAddressPolicy. * By default, an EBus uses a single address. */ - static const EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; + static constexpr EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single; /** * The type of ID that is used to address the EBus. @@ -152,14 +149,14 @@ namespace AZ * `::ExecuteQueuedEvents()`. * By default, the event queue is disabled. */ - static const bool EnableEventQueue = false; + static constexpr bool EnableEventQueue = false; /** * Specifies whether the bus should accept queued messages by default or not. * If set to false, Bus::AllowFunctionQueuing(true) must be called before events are accepted. * Used only when #EnableEventQueue is true. */ - static const bool EventQueueingActiveByDefault = true; + static constexpr bool EventQueueingActiveByDefault = true; /** * Specifies whether the EBus supports queueing functions which take reference @@ -168,7 +165,7 @@ namespace AZ * You should only use this if you know that the data being passed as arguments will * outlive the dispatch of the queued event. */ - static const bool EnableQueuedReferences = false; + static constexpr bool EnableQueuedReferences = false; /** * Locking primitive that is used when adding and removing @@ -197,7 +194,7 @@ namespace AZ * to do. * By default, the standard policy is used, which locks around all dispatches */ - static const bool LocklessDispatch = false; + static constexpr bool LocklessDispatch = false; /** * Specifies where EBus data is stored. diff --git a/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h b/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h index 5c1bbf6dab..021e8edfab 100644 --- a/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h +++ b/Code/Framework/AzCore/AzCore/EBus/IEventScheduler.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/EBus/Policies.h b/Code/Framework/AzCore/AzCore/EBus/Policies.h index db11043ef8..86cbe5d02f 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Policies.h +++ b/Code/Framework/AzCore/AzCore/EBus/Policies.h @@ -18,9 +18,8 @@ #include #include #include +#include -#include -#include namespace AZ { @@ -251,29 +250,21 @@ namespace AZ void Execute() { AZ_Warning("System", m_isActive, "You are calling execute queued functions on a bus which has not activated its function queuing! Call YourBus::AllowFunctionQueuing(true)!"); - while (true) + + MessageQueueType localMessages; + + // Swap the current list of queue functions with a local instance { - BusMessageCall invoke; + AZStd::scoped_lock lock(m_messagesMutex); + AZStd::swap(localMessages, m_messages); + } - ////////////////////////////////////////////////////////////////////////// - // Pop element from the queue. - { - AZStd::lock_guard lock(m_messagesMutex); - size_t numMessages = m_messages.size(); - if (numMessages == 0) - { - break; - } - AZStd::swap(invoke, m_messages.front()); - m_messages.pop(); - if (numMessages == 1) - { - m_messages = {}; - } - } - ////////////////////////////////////////////////////////////////////////// - - invoke(); + // Execute the queue functions safely now that are owned by the function + while (!localMessages.empty()) + { + const BusMessageCall& localMessage = localMessages.front(); + localMessage(); + localMessages.pop(); } } diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h index 0a1af21213..7f48f301aa 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index caa4cda8f5..3e6376323c 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -366,6 +366,42 @@ namespace UnitTest }; + static constexpr AZStd::chrono::seconds MaxDispatchTimeoutSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds * 12; + + template + bool DispatchEventsUntilCondition(AZ::Data::AssetManager& assetManager, Pred&& conditionPredicate, + AZStd::chrono::seconds logIntervalSeconds = BaseAssetManagerTest::DefaultTimeoutSeconds, + AZStd::chrono::seconds maxTimeoutSeconds = MaxDispatchTimeoutSeconds) + { + // If the Max Timeout is hit the test will be marked as a failure + + AZStd::chrono::time_point dispatchEventTimeStart = AZStd::chrono::system_clock::now(); + AZStd::chrono::seconds dispatchEventNextLogTime = logIntervalSeconds; + + while (!conditionPredicate()) + { + AZStd::chrono::time_point currentTime = AZStd::chrono::system_clock::now(); + if (AZStd::chrono::seconds elapsedTime{ currentTime - dispatchEventTimeStart }; + elapsedTime >= dispatchEventNextLogTime) + { + const testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + AZ_Printf("AssetManagerLoadingTest", "The DispatchEventsUntiTimeout function has been waiting for %llu seconds" + " in test %s.%s", elapsedTime.count(), test_info->test_case_name(), test_info->name()); + // Update the next log time to be the next multiple of DefaultTimeout Seconds + // after current elapsed time + dispatchEventNextLogTime = elapsedTime + logIntervalSeconds - ((elapsedTime + logIntervalSeconds) % logIntervalSeconds); + if (elapsedTime >= maxTimeoutSeconds) + { + return false; + } + } + assetManager.DispatchEvents(); + AZStd::this_thread::yield(); + } + + return true; + } + #if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS || AZ_TRAIT_DISABLE_ASSET_MANAGER_FLOOD_TEST TEST_F(AssetJobsFloodTest, DISABLED_FloodTest) #else @@ -1358,42 +1394,74 @@ namespace UnitTest m_assetHandlerAndCatalog->m_numCreations = 0; m_assetHandlerAndCatalog->m_numDestructions = 0; { + ContainerReadyListener containerLoadingCompleteListener(NoLoadAssetId); OnAssetReadyListener readyListener(NoLoadAssetId, azrtti_typeid()); - OnAssetReadyListener depenencyListener(MyAsset2Id, azrtti_typeid()); + OnAssetReadyListener dependencyListener(MyAsset2Id, azrtti_typeid()); + + SCOPED_TRACE("LoadDependencies_BehaviorObeyed"); + + auto AssetOnlyReady = [&readyListener]() -> bool + { + return readyListener.m_ready; + }; + auto AssetAndDependencyReady = [&readyListener, &dependencyListener]() -> bool + { + return readyListener.m_ready && dependencyListener.m_ready; + }; + auto AssetContainerReady = [&containerLoadingCompleteListener]() -> bool + { + return containerLoadingCompleteListener.m_ready; + }; auto noLoadRef = m_testAssetManager->GetAsset(NoLoadAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); - auto maxTimeout = AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds; + // Dispatch AssetBus events until the NoLoadAssetId has signaled an OnAssetReady + // event or the timeout has been reached + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetOnlyReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; + + // Dispatch AssetBus events until the asset container used to load + // NoLoadAssetId has signaled an OnAssetContainerReady event + // or the timeout has been reached + // Wait until the current asset container has finished loading the NoLoadAssetId + // before trigger another load + // If the wait does not occur here, most likely what would occur is + // the AssetManager::m_ownedAssetContainers object is still loading the NoLoadAssetId + // using the default AssetLoadParameters + // If a call to GetAsset occurs at this point while the Asset is still loading + // it will ignore the new loadParams below and instead just re-use the existing + // AssetContainerReader instance, resulting in the dependent MyAsset2Id not + // being loaded + // The function that can return an existing AssetContainer instance is the + // AssetManager::GetAssetContainer. Since it can be in the middle of a load, + // updating the AssetLoadParams would have an effect on the current in progress + // load + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetContainerReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; + + // Reset the ContainerLoadingComplete ready status back to 0 + containerLoadingCompleteListener.m_ready = 0; - while (!readyListener.m_ready) - { - m_testAssetManager->DispatchEvents(); - if (AZStd::chrono::system_clock::now() > maxTimeout) - { - break; - } - AZStd::this_thread::yield(); - } - EXPECT_EQ(readyListener.m_ready, 1); - EXPECT_EQ(depenencyListener.m_ready, 0); - AZ::Data::AssetLoadParameters loadParams(nullptr, AZ::Data::AssetDependencyLoadRules::LoadAll); loadParams.m_reloadMissingDependencies = true; auto loadDependencyRef = m_testAssetManager->GetAsset(NoLoadAssetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default, loadParams); - while (!depenencyListener.m_ready || !readyListener.m_ready) - { - m_testAssetManager->DispatchEvents(); - if (AZStd::chrono::system_clock::now() > maxTimeout) - { - break; - } - AZStd::this_thread::yield(); - } + // Dispatch AssetBus events until the NoLoadAssetId and the MyAsset2Id has signaled + // an OnAssetReady event or the timeout has been reached + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetAndDependencyReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; + EXPECT_EQ(readyListener.m_ready, 1); - EXPECT_EQ(depenencyListener.m_ready, 1); + EXPECT_EQ(dependencyListener.m_ready, 1); + + EXPECT_TRUE(DispatchEventsUntilCondition(*m_testAssetManager, AssetContainerReady)) + << "The DispatchEventsUntiTimeout function has not completed in " + << MaxDispatchTimeoutSeconds.count() << " seconds. The test will be marked as a failure\n"; } CheckFinishedCreationsAndDestructions(); diff --git a/Code/Framework/AzCore/Tests/UUIDTests.cpp b/Code/Framework/AzCore/Tests/UUIDTests.cpp index 5d4fb7a711..a18dc33c4f 100644 --- a/Code/Framework/AzCore/Tests/UUIDTests.cpp +++ b/Code/Framework/AzCore/Tests/UUIDTests.cpp @@ -7,6 +7,7 @@ */ #include #include +#include using namespace AZ; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h index 646410f8db..ae1e3dfa9c 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h b/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h index 9434ca80ae..b49609d820 100644 --- a/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h +++ b/Code/Framework/AzFramework/AzFramework/Logging/MissingAssetLogger.h @@ -8,6 +8,7 @@ #pragma once +#include #include namespace AzFramework { class LogFile; } diff --git a/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h b/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h index 11c3fedb2b..9d6cd48102 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h +++ b/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionStructures.h @@ -11,6 +11,7 @@ #include #include #include +#include #include //! Common structures for Render geometry queries diff --git a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h index 7479b0d1e1..0eb699475f 100644 --- a/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h +++ b/Code/Framework/AzFramework/AzFramework/Windowing/NativeWindow.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h index 8594bf87db..7fa66b0470 100644 --- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h +++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpConnectionSet.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace AzNetworking { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h index e2929c0d3e..7b94108a91 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntryCache.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h index d765d4e1e5..685770dd20 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h index a2b004763b..06e9c82e55 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Manipulators/BaseManipulator.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h index df9b136752..5eb4a31ffb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/SourceControl/SourceControlAPI.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h index 0500a80c36..888be6b3e0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ButtonGroup.h @@ -8,6 +8,7 @@ #pragma once +#include #include namespace AzToolsFramework::ViewportUi::Internal diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h index 209897fd6e..8358bc3d2e 100644 --- a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h +++ b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorServerUnitTests.h @@ -11,6 +11,7 @@ #if !defined(Q_MOC_RUN) #include "UnitTestRunner.h" #include "native/utilities/IniConfiguration.h" +#include #include #endif diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 9ae3cc2c87..b9369b5bb0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h b/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h index 6ddc462e94..cf27245682 100644 --- a/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h +++ b/Code/Tools/Standalone/Source/LUA/LUAEditorStyleMessages.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h b/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h index 4e625a563c..63d5bb2a83 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h +++ b/Gems/AWSClientAuth/Code/Include/Private/AWSClientAuthBus.h @@ -9,6 +9,8 @@ #include +#include + namespace Aws { namespace CognitoIdentityProvider diff --git a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h index f0b9b45aff..39e96517a7 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h @@ -9,6 +9,7 @@ #include #include +#include #include diff --git a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp index f111b972e4..798da14aa1 100644 --- a/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp +++ b/Gems/AssetMemoryAnalyzer/Code/Source/AssetMemoryAnalyzer.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include /////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h index dbea45c54a..4d3534b845 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ThreadLocalContext.h @@ -11,6 +11,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h index dd42f79106..c56da58ff1 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #endif diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h index 2d05a68771..d1027daa36 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h index 053ed98978..54dccb8ae0 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Utils/StateControllers/StateController.h @@ -8,6 +8,7 @@ #pragma once #include +#include // A configurable queue that allows for multiple sources to try to control a single value in a configurable way // such that each object can control the object independently of the other systems, while still maintaining a reasonable state. diff --git a/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h b/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h index 4a3ba89832..1e4fb27831 100644 --- a/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h +++ b/Gems/ScriptCanvasDeveloper/Code/Editor/Include/ScriptCanvasDeveloperEditor/EditorAutomation/EditorAutomationTest.h @@ -11,6 +11,7 @@ #include #include +#include #include #include