From 781eaabd943ffb7852e5d9481a373a7d28cdd862 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 29 Oct 2021 12:05:42 -0700 Subject: [PATCH 01/66] Access gem repos from catalog non-destructively Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 23 ++++++++++++-- .../ProjectManager/Source/CreateProjectCtrl.h | 2 ++ .../Source/GemCatalog/GemCatalogScreen.cpp | 16 ---------- .../Source/UpdateProjectCtrl.cpp | 30 ++++++++++++++++--- .../ProjectManager/Source/UpdateProjectCtrl.h | 6 +++- 5 files changed, 54 insertions(+), 23 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 65e01803aa..c5325bfb42 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -47,8 +48,12 @@ namespace O3DE::ProjectManager m_gemCatalogScreen = new GemCatalogScreen(this); m_stack->addWidget(m_gemCatalogScreen); + + m_gemRepoScreen = new GemRepoScreen(this); + m_stack->addWidget(m_gemRepoScreen); vLayout->addWidget(m_stack); + connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); // When there are multiple project templates present, we re-gather the gems when changing the selected the project template. @@ -89,6 +94,9 @@ namespace O3DE::ProjectManager buttons->setObjectName("footer"); vLayout->addWidget(buttons); + m_primaryButton = buttons->addButton(tr("Create Project"), QDialogButtonBox::ApplyRole); + connect(m_primaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandlePrimaryButton); + #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED connect(m_newProjectSettingsScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); @@ -100,8 +108,6 @@ namespace O3DE::ProjectManager Update(); #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED - m_primaryButton = buttons->addButton(tr("Create Project"), QDialogButtonBox::ApplyRole); - connect(m_primaryButton, &QPushButton::clicked, this, &CreateProjectCtrl::HandlePrimaryButton); setLayout(vLayout); } @@ -160,12 +166,21 @@ namespace O3DE::ProjectManager { m_header->setSubTitle(tr("Configure project with Gems")); m_secondaryButton->setVisible(false); + m_primaryButton->setVisible(true); + } + else if (m_stack->currentWidget() == m_gemRepoScreen) + { + m_header->setSubTitle(tr("Gem Repositories")); + m_secondaryButton->setVisible(true); + m_secondaryButton->setText(tr("Back")); + m_primaryButton->setVisible(false); } else { m_header->setSubTitle(tr("Enter Project Details")); m_secondaryButton->setVisible(true); m_secondaryButton->setText(tr("Configure Gems")); + m_primaryButton->setVisible(true); } } @@ -175,6 +190,10 @@ namespace O3DE::ProjectManager { HandleSecondaryButton(); } + else if (screen == ProjectManagerScreen::GemRepos) + { + NextScreen(); + } else { emit ChangeScreenRequest(screen); diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h index 40ddb14b83..5352d58082 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h @@ -23,6 +23,7 @@ namespace O3DE::ProjectManager QT_FORWARD_DECLARE_CLASS(ScreenHeader) QT_FORWARD_DECLARE_CLASS(NewProjectSettingsScreen) QT_FORWARD_DECLARE_CLASS(GemCatalogScreen) + QT_FORWARD_DECLARE_CLASS(GemRepoScreen) class CreateProjectCtrl : public ScreenWidget @@ -67,6 +68,7 @@ namespace O3DE::ProjectManager NewProjectSettingsScreen* m_newProjectSettingsScreen = nullptr; GemCatalogScreen* m_gemCatalogScreen = nullptr; + GemRepoScreen* m_gemRepoScreen = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 98121d7cd2..1d238cf275 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -348,22 +348,6 @@ namespace O3DE::ProjectManager void GemCatalogScreen::HandleOpenGemRepo() { - QVector gemsToBeAdded = m_gemModel->GatherGemsToBeAdded(true); - QVector gemsToBeRemoved = m_gemModel->GatherGemsToBeRemoved(true); - - if (!gemsToBeAdded.empty() || !gemsToBeRemoved.empty()) - { - QMessageBox::StandardButton warningResult = QMessageBox::warning( - nullptr, "Pending Changes", - "There are some unsaved changes to the gem selection,
they will be lost if you change screens.
Are you sure?", - QMessageBox::No | QMessageBox::Yes); - - if (warningResult != QMessageBox::Yes) - { - return; - } - } - emit ChangeScreenRequest(ProjectManagerScreen::GemRepos); } diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 1c8f9a6931..5de3511f84 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -39,10 +40,9 @@ namespace O3DE::ProjectManager m_updateSettingsScreen = new UpdateProjectSettingsScreen(); m_gemCatalogScreen = new GemCatalogScreen(); + m_gemRepoScreen = new GemRepoScreen(this); - connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, [this](ProjectManagerScreen screen){ - emit ChangeScreenRequest(screen); - }); + connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest); m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); @@ -69,6 +69,7 @@ namespace O3DE::ProjectManager m_stack->addWidget(topBarFrameWidget); m_stack->addWidget(m_gemCatalogScreen); + m_stack->addWidget(m_gemRepoScreen); QDialogButtonBox* backNextButtons = new QDialogButtonBox(); backNextButtons->setObjectName("footer"); @@ -102,6 +103,19 @@ namespace O3DE::ProjectManager m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path); } + void UpdateProjectCtrl::OnChangeScreenRequest(ProjectManagerScreen screen) + { + if (screen == ProjectManagerScreen::GemRepos) + { + m_stack->setCurrentWidget(m_gemRepoScreen); + Update(); + } + else + { + emit ChangeScreenRequest(screen); + } + } + void UpdateProjectCtrl::HandleGemsButton() { if (UpdateProjectSettings(true)) @@ -181,18 +195,26 @@ namespace O3DE::ProjectManager void UpdateProjectCtrl::Update() { - if (m_stack->currentIndex() == ScreenOrder::Gems) + if (m_stack->currentIndex() == ScreenOrder::GemRepos) + { + m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); + m_header->setSubTitle(QString(tr("Gem Repositories"))); + m_nextButton->setVisible(false); + } + else if (m_stack->currentIndex() == ScreenOrder::Gems) { m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); m_header->setSubTitle(QString(tr("Configure Gems"))); m_nextButton->setText(tr("Save")); + m_nextButton->setVisible(true); } else { m_header->setTitle(""); m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.GetProjectDisplayName())); m_nextButton->setText(tr("Save")); + m_nextButton->setVisible(true); } } diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h index 3321fad638..5fef296ee7 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h @@ -22,6 +22,7 @@ namespace O3DE::ProjectManager QT_FORWARD_DECLARE_CLASS(ScreenHeader) QT_FORWARD_DECLARE_CLASS(UpdateProjectSettingsScreen) QT_FORWARD_DECLARE_CLASS(GemCatalogScreen) + QT_FORWARD_DECLARE_CLASS(GemRepoScreen) class UpdateProjectCtrl : public ScreenWidget { @@ -37,6 +38,7 @@ namespace O3DE::ProjectManager void HandleBackButton(); void HandleNextButton(); void HandleGemsButton(); + void OnChangeScreenRequest(ProjectManagerScreen screen); void UpdateCurrentProject(const QString& projectPath); private: @@ -47,13 +49,15 @@ namespace O3DE::ProjectManager enum ScreenOrder { Settings, - Gems + Gems, + GemRepos }; ScreenHeader* m_header = nullptr; QStackedWidget* m_stack = nullptr; UpdateProjectSettingsScreen* m_updateSettingsScreen = nullptr; GemCatalogScreen* m_gemCatalogScreen = nullptr; + GemRepoScreen* m_gemRepoScreen = nullptr; QPushButton* m_backButton = nullptr; QPushButton* m_nextButton = nullptr; From 259ee654aec3c1793d5e78cc4fdbe443747fa3f6 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:18:38 -0700 Subject: [PATCH 02/66] WIP refresh gem catalog in place Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 7 +++ .../Source/GemCatalog/GemCatalogScreen.cpp | 55 +++++++++++++++++++ .../Source/GemCatalog/GemCatalogScreen.h | 1 + .../Source/GemCatalog/GemModel.cpp | 11 ++++ .../Source/GemCatalog/GemModel.h | 3 + .../Source/GemRepo/GemRepoScreen.cpp | 4 ++ .../Source/GemRepo/GemRepoScreen.h | 4 ++ 7 files changed, 85 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index c5325bfb42..e33e9449fe 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -55,6 +55,13 @@ namespace O3DE::ProjectManager connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); + connect( + m_gemRepoScreen, &GemRepoScreen::OnRefresh, + [this]() + { + const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); + m_gemCatalogScreen->Refresh(projectTemplatePath + "/Template"); + }); // When there are multiple project templates present, we re-gather the gems when changing the selected the project template. connect(m_newProjectSettingsScreen, &NewProjectSettingsScreen::OnTemplateSelectionChanged, this, [=](int oldIndex, [[maybe_unused]] int newIndex) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 1d238cf275..fb78736a3c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include namespace O3DE::ProjectManager { @@ -145,6 +147,59 @@ namespace O3DE::ProjectManager } } + void GemCatalogScreen::Refresh(const QString& projectPath) + { + QHash gemInfoHash; + + AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); + if (allGemInfosResult.IsSuccess()) + { + QVector gemInfos = allGemInfosResult.GetValue(); + for (const GemInfo& gemInfo : gemInfos) + { + gemInfoHash.insert(gemInfo.m_name, gemInfo); + } + } + + AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + if (allRepoGemInfosResult.IsSuccess()) + { + const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + for (const GemInfo& gemInfo : allRepoGemInfos) + { + if (!gemInfoHash.contains(gemInfo.m_name)) + { + gemInfoHash.insert(gemInfo.m_name, gemInfo); + } + } + } + + // remove rows for gems that were removed and not project dependencies + int i = 0; + while (i < m_gemModel->rowCount()) + { + QModelIndex index = m_gemModel->index(i,0); + QString gemName = m_gemModel->GetName(index); + if (!gemInfoHash.contains(gemName) && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) + { + m_gemModel->removeRow(i); + } + else + { + gemInfoHash.remove(gemName); + i++; + } + } + + // add new rows + for(auto iter = gemInfoHash.begin(); iter != gemInfoHash.end(); ++iter) + { + m_gemModel->AddGem(iter.value()); + } + + m_gemModel->UpdateGemDependencies(); + } + void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) { if (m_notificationsEnabled) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 1b34019d1a..b866b2d3af 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -33,6 +33,7 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetScreenEnum() override; void ReinitForProject(const QString& projectPath); + void Refresh(const QString& projectPath); enum class EnableDisableGemsResult { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index fb228c0b4a..a059df4cbf 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -18,6 +18,7 @@ namespace O3DE::ProjectManager : QStandardItemModel(parent) { m_selectionModel = new QItemSelectionModel(this, parent); + connect(this, &QAbstractItemModel::rowsAboutToBeRemoved, this, &GemModel::OnRowsAboutToBeRemoved); } QItemSelectionModel* GemModel::GetSelectionModel() const @@ -359,6 +360,16 @@ namespace O3DE::ProjectManager gemModel->emit gemStatusChanged(gemName, numChangedDependencies); } + void GemModel::OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last) + { + for (int i = first; i <= last; ++i) + { + QModelIndex modelIndex = index(i, 0, parent); + const QString& gemName = GetName(modelIndex); + m_nameToIndexMap.remove(gemName); + } + } + void GemModel::SetIsAddedDependency(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded) { model.setData(modelIndex, isAdded, RoleIsAddedDependency); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 35231cc105..f4bc1ec502 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -80,6 +80,9 @@ namespace O3DE::ProjectManager signals: void gemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); + protected slots: + void OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last); + private: void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames); void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 0ddfe41434..30a57417d2 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -91,6 +91,7 @@ namespace O3DE::ProjectManager if (addGemRepoResult) { Reinit(); + emit OnRefresh(); } else { @@ -116,6 +117,7 @@ namespace O3DE::ProjectManager if (removeGemRepoResult) { Reinit(); + emit OnRefresh(); } else { @@ -130,6 +132,7 @@ namespace O3DE::ProjectManager { bool refreshResult = PythonBindingsInterface::Get()->RefreshAllGemRepos(); Reinit(); + emit OnRefresh(); if (!refreshResult) { @@ -146,6 +149,7 @@ namespace O3DE::ProjectManager if (refreshResult.IsSuccess()) { Reinit(); + emit OnRefresh(); } else { diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index 46a733362a..0516005eef 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -28,6 +28,7 @@ namespace O3DE::ProjectManager class GemRepoScreen : public ScreenWidget { + Q_OBJECT public: explicit GemRepoScreen(QWidget* parent = nullptr); ~GemRepoScreen() = default; @@ -37,6 +38,9 @@ namespace O3DE::ProjectManager GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; } + signals: + void OnRefresh(); + public slots: void HandleAddRepoButton(); void HandleRemoveRepoButton(const QModelIndex& modelIndex); From 99ef2735b74196d62921563f430beee6a055032e Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 2 Nov 2021 16:16:37 -0700 Subject: [PATCH 03/66] Create download UI once and update existing UI with progress Signed-off-by: AMZN-Phil --- .../Source/DownloadController.cpp | 8 +- .../Source/DownloadController.h | 6 +- .../GemCatalog/GemCatalogHeaderWidget.cpp | 185 +++++++++++------- .../GemCatalog/GemCatalogHeaderWidget.h | 10 + .../Source/GemCatalog/GemCatalogScreen.cpp | 5 +- 5 files changed, 141 insertions(+), 73 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index 224b90299c..00a7db5318 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -41,6 +41,8 @@ namespace O3DE::ProjectManager void DownloadController::AddGemDownload(const QString& gemName) { m_gemNames.push_back(gemName); + emit GemDownloadAdded(gemName); + if (m_gemNames.size() == 1) { m_worker->SetGemToDownload(m_gemNames[0], false); @@ -62,6 +64,7 @@ namespace O3DE::ProjectManager else { m_gemNames.erase(findResult); + emit GemDownloadRemoved(gemName); } } } @@ -69,7 +72,7 @@ namespace O3DE::ProjectManager void DownloadController::UpdateUIProgress(int progress) { m_lastProgress = progress; - emit GemDownloadProgress(progress); + emit GemDownloadProgress(*m_gemNames.begin(), progress); } void DownloadController::HandleResults(const QString& result) @@ -82,8 +85,9 @@ namespace O3DE::ProjectManager succeeded = false; } + QString gemName = *m_gemNames.begin(); m_gemNames.erase(m_gemNames.begin()); - emit Done(succeeded); + emit Done(gemName, succeeded); if (!m_gemNames.empty()) { diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h index 11ceaacddb..0bf0ae473c 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.h +++ b/Code/Tools/ProjectManager/Source/DownloadController.h @@ -58,8 +58,10 @@ namespace O3DE::ProjectManager signals: void StartGemDownload(const QString& gemName); - void Done(bool success = true); - void GemDownloadProgress(int percentage); + void Done(const QString& gemName, bool success = true); + void GemDownloadAdded(const QString& gemName); + void GemDownloadRemoved(const QString& gemName); + void GemDownloadProgress(const QString& gemName, int percentage); private: DownloadWorker* m_worker; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 5d65c740af..cfe69283ff 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -30,6 +30,7 @@ namespace O3DE::ProjectManager m_layout->setMargin(5); m_layout->setAlignment(Qt::AlignTop); setLayout(m_layout); + setMinimumHeight(400); QHBoxLayout* hLayout = new QHBoxLayout(); @@ -119,6 +120,12 @@ namespace O3DE::ProjectManager setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); } + CartOverlayWidget::~CartOverlayWidget() + { + // disconnect from all download controller signals + disconnect(m_downloadController, nullptr, this, nullptr); + } + void CartOverlayWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices) { QWidget* widget = new QWidget(); @@ -162,13 +169,13 @@ namespace O3DE::ProjectManager void CartOverlayWidget::CreateDownloadSection() { - QWidget* widget = new QWidget(); - widget->setFixedWidth(s_width); - m_layout->addWidget(widget); + m_downloadSectionWidget = new QWidget(); + m_downloadSectionWidget->setFixedWidth(s_width); + m_layout->addWidget(m_downloadSectionWidget); QVBoxLayout* layout = new QVBoxLayout(); layout->setAlignment(Qt::AlignTop); - widget->setLayout(layout); + m_downloadSectionWidget->setLayout(layout); QLabel* titleLabel = new QLabel(); titleLabel->setObjectName("GemCatalogCartOverlaySectionLabel"); @@ -187,82 +194,126 @@ namespace O3DE::ProjectManager QLabel* processingQueueLabel = new QLabel("Processing Queue"); gemDownloadLayout->addWidget(processingQueueLabel); - QWidget* downloadingItemWidget = new QWidget(); - downloadingItemWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG"); - gemDownloadLayout->addWidget(downloadingItemWidget); + m_downloadingListWidget = new QWidget(); + m_downloadingListWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG"); + gemDownloadLayout->addWidget(m_downloadingListWidget); QVBoxLayout* downloadingItemLayout = new QVBoxLayout(); downloadingItemLayout->setAlignment(Qt::AlignTop); - downloadingItemWidget->setLayout(downloadingItemLayout); + m_downloadingListWidget->setLayout(downloadingItemLayout); - auto update = [=](int downloadProgress) + QLabel* downloadsInProgessLabel = new QLabel(""); + downloadsInProgessLabel->setObjectName("NumDownloadsInProgressLabel"); + downloadingItemLayout->addWidget(downloadsInProgessLabel); + + if (m_downloadController->IsDownloadQueueEmpty()) + { + m_downloadSectionWidget->hide(); + } + else { - if (m_downloadController->IsDownloadQueueEmpty()) + // Setup gem download rows for gems that are already in the queue + const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + + for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) { - widget->hide(); + GemDownloadAdded(downloadQueue[downloadingGemNumber]); } - else - { - widget->setUpdatesEnabled(false); - // remove items - QLayoutItem* layoutItem = nullptr; - while ((layoutItem = downloadingItemLayout->takeAt(0)) != nullptr) - { - if (layoutItem->layout()) - { - // Gem info row - QLayoutItem* rowLayoutItem = nullptr; - while ((rowLayoutItem = layoutItem->layout()->takeAt(0)) != nullptr) - { - rowLayoutItem->widget()->deleteLater(); - } - layoutItem->layout()->deleteLater(); - } - if (layoutItem->widget()) - { - layoutItem->widget()->deleteLater(); - } - } + } - // Setup gem download rows - const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + // connect to download controller data changed + connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &CartOverlayWidget::GemDownloadAdded); + connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &CartOverlayWidget::GemDownloadRemoved); + connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &CartOverlayWidget::GemDownloadProgress); + connect(m_downloadController, &DownloadController::Done, this, &CartOverlayWidget::GemDownloadComplete); + } - QLabel* downloadsInProgessLabel = new QLabel(""); - downloadsInProgessLabel->setText( - QString("%1 %2").arg(downloadQueue.size()).arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); - downloadingItemLayout->addWidget(downloadsInProgessLabel); + void CartOverlayWidget::GemDownloadAdded(const QString& gemName) + { + QWidget* newGemDownloadWidget = new QWidget(); + newGemDownloadWidget->setObjectName(gemName); + QVBoxLayout* downloadingGemLayout = new QVBoxLayout(); + newGemDownloadWidget->setLayout(downloadingGemLayout); + QHBoxLayout* nameProgressLayout = new QHBoxLayout(); + TagWidget* newTag = new TagWidget(gemName); + nameProgressLayout->addWidget(newTag); + QLabel* progress = new QLabel(tr("Queued")); + progress->setObjectName("DownloadProgressLabel"); + nameProgressLayout->addWidget(progress); + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + nameProgressLayout->addSpacerItem(spacer); + QLabel* cancelText = new QLabel(QString("Cancel").arg(gemName)); + cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); + connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); + nameProgressLayout->addWidget(cancelText); + downloadingGemLayout->addLayout(nameProgressLayout); + QProgressBar* downloadProgessBar = new QProgressBar(); + downloadProgessBar->setObjectName("DownloadProgressBar"); + downloadingGemLayout->addWidget(downloadProgessBar); + downloadProgessBar->setValue(0); + + m_downloadingListWidget->layout()->addWidget(newGemDownloadWidget); + + const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + QLabel* numDownloads = m_downloadingListWidget->findChild("NumDownloadsInProgressLabel"); + numDownloads->setText(QString("%1 %2") + .arg(downloadQueue.size()) + .arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); + + m_downloadingListWidget->show(); + } - for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) - { - QHBoxLayout* nameProgressLayout = new QHBoxLayout(); - TagWidget* newTag = new TagWidget(downloadQueue[downloadingGemNumber]); - nameProgressLayout->addWidget(newTag); - QLabel* progress = new QLabel(downloadingGemNumber == 0? QString("%1%").arg(downloadProgress) : tr("Queued")); - nameProgressLayout->addWidget(progress); - QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); - nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel").arg(downloadQueue[downloadingGemNumber])); - cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); - connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); - nameProgressLayout->addWidget(cancelText); - downloadingItemLayout->addLayout(nameProgressLayout); - QProgressBar* downloadProgessBar = new QProgressBar(); - downloadingItemLayout->addWidget(downloadProgessBar); - downloadProgessBar->setValue(downloadingGemNumber == 0 ? downloadProgress : 0); - } + void CartOverlayWidget::GemDownloadRemoved(const QString& gemName) + { + QWidget* gemToRemove = m_downloadingListWidget->findChild(gemName); + QLayout* gemToRemoveLayout = gemToRemove ? gemToRemove->layout() : nullptr; - widget->setUpdatesEnabled(true); - widget->show(); + if (gemToRemoveLayout) + { + QLayoutItem* rowLayoutItem = nullptr; + while ((rowLayoutItem = gemToRemoveLayout->layout()->takeAt(0)) != nullptr) + { + rowLayoutItem->widget()->deleteLater(); } - }; + gemToRemoveLayout->layout()->deleteLater(); + gemToRemove->deleteLater(); + } - auto downloadEnded = [=](bool /*success*/) + const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); + + if (m_downloadController->IsDownloadQueueEmpty()) { - update(0); // update the list to remove the gem that has finished - }; - // connect to download controller data changed - connect(m_downloadController, &DownloadController::GemDownloadProgress, this, update); - connect(m_downloadController, &DownloadController::Done, this, downloadEnded); - update(0); + m_downloadSectionWidget->hide(); + } + else + { + QLabel* numDownloads = m_downloadingListWidget->findChild("NumDownloadsInProgressLabel"); + numDownloads->setText(QString("%1 %2") + .arg(downloadQueue.size()) + .arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); + } + } + + void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int percentage) + { + QWidget* gemToUpdate = m_downloadingListWidget->findChild(gemName); + if (gemToUpdate) + { + QLabel* progressLabel = gemToUpdate->findChild("DownloadProgressLabel"); + if (progressLabel) + { + progressLabel->setText(QString("%1%").arg(percentage)); + } + QProgressBar* progressBar = gemToUpdate->findChild("DownloadProgressBar"); + if (progressBar) + { + progressBar->setValue(percentage); + } + } + } + + void CartOverlayWidget::GemDownloadComplete(const QString& gemName, bool /*success*/) + { + GemDownloadRemoved(gemName); // update the list to remove the gem that has finished } QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector& gems) const diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 4d17259840..a8f50a5338 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -34,6 +34,13 @@ namespace O3DE::ProjectManager public: CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); + ~CartOverlayWidget(); + + public slots: + void GemDownloadAdded(const QString& gemName); + void GemDownloadRemoved(const QString& gemName); + void GemDownloadProgress(const QString& gemName, int percentage); + void GemDownloadComplete(const QString& gemName, bool success); private: QStringList ConvertFromModelIndices(const QVector& gems) const; @@ -47,6 +54,9 @@ namespace O3DE::ProjectManager GemModel* m_gemModel = nullptr; DownloadController* m_downloadController = nullptr; + QWidget* m_downloadSectionWidget = nullptr; + QWidget* m_downloadingListWidget = nullptr; + inline constexpr static int s_width = 240; }; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index a22f41d054..32cf35c04d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -145,7 +145,7 @@ namespace O3DE::ProjectManager } } - void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) + void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) { if (m_notificationsEnabled) { @@ -170,6 +170,7 @@ namespace O3DE::ProjectManager if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) { m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); + GemModel::SetDownloadStatus(*m_proxModel, modelIndex, GemInfo::DownloadStatus::Downloading); } } @@ -187,7 +188,7 @@ namespace O3DE::ProjectManager toastConfiguration.m_customIconImage = ":/gem.svg"; toastConfiguration.m_borderRadius = 4; toastConfiguration.m_duration = AZStd::chrono::milliseconds(3000); - m_notificationsView->ShowToastNotification(toastConfiguration); + //m_notificationsView->ShowToastNotification(toastConfiguration); } } From 27c7e715168973e5b7fc175f427844500afbb4b1 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Wed, 3 Nov 2021 12:22:26 -0700 Subject: [PATCH 04/66] WIP default gem sorting Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/GemCatalog/GemCatalogScreen.cpp | 6 +++ .../Source/GemCatalog/GemModel.h | 50 +++++++++---------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index fb78736a3c..c76735d4f2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -34,6 +34,9 @@ namespace O3DE::ProjectManager m_gemModel = new GemModel(this); m_proxModel = new GemSortFilterProxyModel(m_gemModel, this); + // default to sort by gem name + m_proxModel->setSortRole(GemModel::RoleName); + QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); vLayout->setSpacing(0); @@ -93,6 +96,8 @@ namespace O3DE::ProjectManager } m_proxModel->ResetFilters(); + m_proxModel->sort(/*column=*/0); + m_filterWidget = new GemFilterWidget(m_proxModel); m_filterWidgetLayout->addWidget(m_filterWidget); @@ -198,6 +203,7 @@ namespace O3DE::ProjectManager } m_gemModel->UpdateGemDependencies(); + m_proxModel->sort(/*column=*/0); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index f4bc1ec502..9fac47d18e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -26,6 +26,31 @@ namespace O3DE::ProjectManager explicit GemModel(QObject* parent = nullptr); QItemSelectionModel* GetSelectionModel() const; + enum UserRole + { + RoleName = Qt::UserRole, + RoleDisplayName, + RoleCreator, + RoleGemOrigin, + RolePlatforms, + RoleSummary, + RoleWasPreviouslyAdded, + RoleWasPreviouslyAddedDependency, + RoleIsAdded, + RoleIsAddedDependency, + RoleDirectoryLink, + RoleDocLink, + RoleDependingGems, + RoleVersion, + RoleLastUpdated, + RoleBinarySize, + RoleFeatures, + RoleTypes, + RolePath, + RoleRequirement, + RoleDownloadStatus + }; + void AddGem(const GemInfo& gemInfo); void Clear(); void UpdateGemDependencies(); @@ -88,31 +113,6 @@ namespace O3DE::ProjectManager void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); QStringList GetDependingGems(const QModelIndex& modelIndex); - enum UserRole - { - RoleName = Qt::UserRole, - RoleDisplayName, - RoleCreator, - RoleGemOrigin, - RolePlatforms, - RoleSummary, - RoleWasPreviouslyAdded, - RoleWasPreviouslyAddedDependency, - RoleIsAdded, - RoleIsAddedDependency, - RoleDirectoryLink, - RoleDocLink, - RoleDependingGems, - RoleVersion, - RoleLastUpdated, - RoleBinarySize, - RoleFeatures, - RoleTypes, - RolePath, - RoleRequirement, - RoleDownloadStatus - }; - QHash m_nameToIndexMap; QItemSelectionModel* m_selectionModel = nullptr; QHash> m_gemDependencyMap; From d8c2088d1dd2e9f3c9e2a70e3d2b60a95427f15f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Nov 2021 08:59:19 -0700 Subject: [PATCH 05/66] bugifx: resolve crash with project manager (#5151) - system allocator not configured in environment for AZQtComponents - WA_DeleteOnClose will destroy the toast dialog causing a crashing when ToastNotificationsView tries to access the pointer issue: https://github.com/o3de/o3de/issues/5129 Signed-off-by: Michael Pollind --- .../AzQtComponents/Components/ToastNotification.cpp | 1 - .../AzQtComponents/Components/ToastNotification.h | 3 +-- .../AzQtComponents/Components/ToastNotificationConfiguration.h | 1 - .../UI/Notifications/ToastNotificationsView.cpp | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp index 8831bef89c..11fd1e60d8 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp @@ -27,7 +27,6 @@ namespace AzQtComponents setProperty("HasNoWindowDecorations", true); setAttribute(Qt::WA_ShowWithoutActivating); - setAttribute(Qt::WA_DeleteOnClose); m_borderRadius = toastConfiguration.m_borderRadius; if (m_borderRadius > 0) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h index 4343f37df4..81b1cb4055 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h @@ -31,7 +31,6 @@ namespace AzQtComponents { Q_OBJECT public: - AZ_CLASS_ALLOCATOR(ToastNotification, AZ::SystemAllocator, 0); ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration); virtual ~ToastNotification(); @@ -73,7 +72,7 @@ namespace AzQtComponents AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING AZStd::chrono::milliseconds m_fadeDuration; - AZStd::unique_ptr m_ui; + QScopedPointer m_ui; AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING }; } // namespace AzQtComponents diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h index 5ace9d1be2..2db374640e 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h @@ -27,7 +27,6 @@ namespace AzQtComponents class AZ_QT_COMPONENTS_API ToastConfiguration { public: - AZ_CLASS_ALLOCATOR(ToastConfiguration, AZ::SystemAllocator, 0); ToastConfiguration(ToastType toastType, const QString& title, const QString& description); bool m_closeOnClick = true; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp index a88711a9ed..277d3fa3c5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp @@ -129,7 +129,7 @@ namespace AzToolsFramework ToastId ToastNotificationsView::CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration) { - AzQtComponents::ToastNotification* notification = aznew AzQtComponents::ToastNotification(parentWidget(), toastConfiguration); + AzQtComponents::ToastNotification* notification = new AzQtComponents::ToastNotification(this, toastConfiguration); ToastId toastId = AZ::Entity::MakeId(); m_notifications[toastId] = notification; From 861b29ffc7f6c829061e0c64f3cea975e57eef60 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Wed, 3 Nov 2021 13:45:40 -0700 Subject: [PATCH 06/66] Fix spelling change for member variable Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 08669d39a0..8234b80c8e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -92,7 +92,7 @@ namespace O3DE::ProjectManager FillModel(projectPath); m_proxyModel->ResetFilters(); - m_proxModel->sort(/*column=*/0); + m_proxyModel->sort(/*column=*/0); if (m_filterWidget) { @@ -150,6 +150,7 @@ namespace O3DE::ProjectManager { m_gemModel->AddGem(gemInfoResult.GetValue()); m_gemModel->UpdateGemDependencies(); + m_proxyModel->sort(/*column=*/0); } } } @@ -206,7 +207,7 @@ namespace O3DE::ProjectManager } m_gemModel->UpdateGemDependencies(); - m_proxModel->sort(/*column=*/0); + m_proxyModel->sort(/*column=*/0); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) From c9fb41d0e5abf036210563395a36f5cc48517aa6 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Wed, 3 Nov 2021 19:57:51 -0700 Subject: [PATCH 07/66] Fix Entity Outliner sort order with Prefabs enabled The EditorEntitySortComponent was relying on serialization callbacks not exposed to the JSON serializer to marshal data between its serialized state and its runtime state, which led to the outliner sort order becoming disrupted every time a prefab propagation occurs (and the component is subsequently serialized and deserialized). This change: - Forces `PrepareSave` and `PostLoad` for `EditorEntitySortComponent` to be called at update (direct descendant added or removed) and activation time respectively while prefabs are enabled. While this could be optimized, and this logic stands to be refactored once slices are fully removed, I was unable to gather any samples in which `PrepareSave` are called in a sampling profiler in a scene with 1000 top-level entities, so I don't anticipate this introducing a meaningful performance regression in the short term. - Disables updates in `EditorEntitySortComponent` during prefab propagation, as any detected changes do not signal authored intent at this time - Made `GetEntityChildOrder` in `EditorEntityHelpers` work with prefabs enabled, which restores the existing "Sort: A -> Z" and "Sort: Z -> A" behaviors (which have some preexisting issues this does not fix) - Adds a Python regression test to the Editor suite to validate this behavior - the test is currently in TestSuite_Main and not TestSuite_Main_Optimized because it requires an Editor launch with prefabs enabled, this can be fixed once AutomatedTesting is further migrated away from slices @AMZN-daimini has a larger change that improves the JSON serialization format (https://github.com/o3de/o3de/pull/1292) which we should absolutely bring in in the future to improve the legibility of the Prefab format, but this change fixes the functionality (including saving & reloading a level and keeping a consistent order) without altering the Prefab format - this lower impact radius fix is my preference for our stabilization period. Signed-off-by: nvsickle --- .../EntityOutliner_EntityOrdering.py | 145 ++++++++++++++++++ .../Gem/PythonTests/editor/TestSuite_Main.py | 12 ++ .../Entity/EditorEntityHelpers.cpp | 12 ++ .../Entity/EditorEntitySortComponent.cpp | 43 ++++++ .../Entity/EditorEntitySortComponent.h | 6 + 5 files changed, 218 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py new file mode 100644 index 0000000000..8b1e4763db --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py @@ -0,0 +1,145 @@ +""" +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 +""" + + +class Tests: + entities_sorted = ( + "Entities sorted in the expected order", + "Entities sorted in an incorrect order", + ) + + +def EntityOutliner_EntityOrdering(): + """ + Summary: + Verify that manual entity ordering in the entity outliner works and is stable. + + Expected Behavior: + Several entities are created, some are manually ordered, and their order + is maintained, even when new entities are added. + + Test Steps: + 1) Open the empty Prefab Base level + 2) Add 5 entities to the outliner + 3) Move "Entity1" to the top of the order + 4) Move "Entity4" to the bottom of the order + 5) Add another new entity, ensure the rest of the order is unchanged + """ + + import editor_python_test_tools.pyside_utils as pyside_utils + import azlmbr.legacy.general as general + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + from PySide2 import QtCore, QtWidgets, QtGui, QtTest + + # Grab the Editor, Entity Outliner, and Outliner Model + editor_window = pyside_utils.get_editor_main_window() + entity_outliner = pyside_utils.find_child_by_hierarchy( + editor_window, ..., "EntityOutlinerWidgetUI", ..., "m_objectTree" + ) + entity_outliner_model = entity_outliner.model() + + # Get the outliner index for the root prefab container entity + def get_prefab_container_index(): + return entity_outliner_model.index(0, 0) + + # Get the outlienr index for the top level entity of a given name + def index_for_name(name): + root_index = get_prefab_container_index() + for row in range(entity_outliner_model.rowCount(root_index)): + row_index = entity_outliner_model.index(row, 0, root_index) + if row_index.data() == name: + return row_index + return None + + # Validate that the outliner top level entity order matches the expected order + def verify_entities_sorted(expected_order): + actual_order = [] + root_index = get_prefab_container_index() + for row in range(entity_outliner_model.rowCount(root_index)): + row_index = entity_outliner_model.index(row, 0, root_index) + actual_order.append(row_index.data()) + + sorted_correctly = actual_order == expected_order + Report.result(Tests.entities_sorted, sorted_correctly) + if not sorted_correctly: + print(f"Expected entity order: {expected_order}") + print(f"Actual entity order: {actual_order}") + + # Creates an entity from the outliner context menu + def create_entity(): + pyside_utils.trigger_context_menu_entry( + entity_outliner, "Create entity", index=get_prefab_container_index() + ) + general.idle_wait(0.0) + + # Moves an entity (wrapped by move_entity_before and move_entity_after) + def _move_entity(source_name, target_name, move_after=False): + source_index = index_for_name(source_name) + target_index = index_for_name(target_name) + + target_row = target_index.row() + if move_after: + target_row += 1 + + # Generate MIME data and directly inject it into the model instead of + # generating mouse click operations, as it's more reliable and we're + # testing the underlying drag & drop logic as opposed to Qt's mouse + # handling here + mime_data = entity_outliner_model.mimeData([source_index]) + entity_outliner_model.dropMimeData( + mime_data, QtCore.Qt.MoveAction, target_row, 0, target_index.parent() + ) + QtWidgets.QApplication.processEvents() + + # Move an entity before another entity in the order by dragging the source above the target + move_entity_before = lambda source_name, target_name: _move_entity( + source_name, target_name, move_after=False + ) + # Move an entity after another entity in the order by dragging the source beloew the target + move_entity_after = lambda source_name, target_name: _move_entity( + source_name, target_name, move_after=True + ) + + expected_order = [] + + # 1) Open the empty Prefab Base level + helper.init_idle() + helper.open_level("Prefab", "Base") + + # 2) Add 5 entities to the outliner + ENTITIES_TO_ADD = 5 + for i in range(ENTITIES_TO_ADD): + create_entity() + + # Our new entity should be given a name with a number automatically + new_entity = f"Entity{i+1}" + # The new entity should be added to the top of its parent entity + expected_order = [new_entity] + expected_order + + verify_entities_sorted(expected_order) + + # 3) Move "Entity1" to the top of the order + move_entity_before("Entity1", "Entity5") + expected_order = ["Entity1", "Entity5", "Entity4", "Entity3", "Entity2"] + verify_entities_sorted(expected_order) + + # 4) Move "Entity4" to the bottom of the order + move_entity_after("Entity4", "Entity2") + expected_order = ["Entity1", "Entity5", "Entity3", "Entity2", "Entity4"] + verify_entities_sorted(expected_order) + + # 5) Add another new entity, ensure the rest of the order is unchanged + create_entity() + expected_order = ["Entity6", "Entity1", "Entity5", "Entity3", "Entity2", "Entity4"] + verify_entities_sorted(expected_order) + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + + Report.start_test(EntityOutliner_EntityOrdering) diff --git a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py index 26b254ae71..49069569eb 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main.py @@ -41,3 +41,15 @@ class TestAutomation(TestAutomationBase): from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False, use_null_renderer=False) + + def test_EntityOutlienr_EntityOrdering(self, request, workspace, editor, launcher_platform): + from .EditorScripts import EntityOutliner_EntityOrdering as test_module + self._run_test( + request, + workspace, + editor, + test_module, + batch_mode=False, + autotest_mode=True, + extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"] + ) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 28d6e2bc08..511f9dd580 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -468,6 +469,17 @@ namespace AzToolsFramework EntityIdList children; EditorEntityInfoRequestBus::EventResult(children, parentId, &EditorEntityInfoRequestBus::Events::GetChildren); + // If Prefabs are enabled, don't check the order for an invalid parent, just return its children (i.e. the root container entity) + if (!parentId.IsValid()) + { + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + if (isPrefabEnabled) + { + return children; + } + } + EntityIdList entityChildOrder; AZ::EntityId sortEntityId = GetEntityIdForSortInfo(parentId); EditorEntitySortRequestBus::EventResult(entityChildOrder, sortEntityId, &EditorEntitySortRequestBus::Events::GetChildEntityOrderArray); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp index b747469f4d..6936397187 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include static_assert(sizeof(AZ::u64) == sizeof(AZ::EntityId), "We use AZ::EntityId for Persistent ID, which is a u64 under the hood. These must be the same size otherwise the persistent id will have to be rewritten"); @@ -144,6 +146,12 @@ namespace AzToolsFramework bool EditorEntitySortComponent::AddChildEntityInternal(const AZ::EntityId& entityId, bool addToBack, EntityOrderArray::iterator insertPosition) { AZ_PROFILE_FUNCTION(AzToolsFramework); + + if (m_ignoreIncomingOrderChanges) + { + return true; + } + auto entityItr = m_childEntityOrderCache.find(entityId); if (entityItr == m_childEntityOrderCache.end()) { @@ -198,6 +206,12 @@ namespace AzToolsFramework bool EditorEntitySortComponent::RemoveChildEntity(const AZ::EntityId& entityId) { AZ_PROFILE_FUNCTION(AzToolsFramework); + + if (m_ignoreIncomingOrderChanges) + { + return true; + } + auto entityItr = m_childEntityOrderCache.find(entityId); if (entityItr != m_childEntityOrderCache.end()) { @@ -250,11 +264,30 @@ namespace AzToolsFramework } } + void EditorEntitySortComponent::OnPrefabInstancePropagationBegin() + { + m_ignoreIncomingOrderChanges = true; + } + + void EditorEntitySortComponent::OnPrefabInstancePropagationEnd() + { + m_ignoreIncomingOrderChanges = false; + } + void EditorEntitySortComponent::MarkDirtyAndSendChangedEvent() { // mark the order as dirty before sending the ChildEntityOrderArrayUpdated event in order for PrepareSave to be properly handled in the case // one of the event listeners needs to build the InstanceDataHierarchy m_entityOrderIsDirty = true; + + // Force an immediate update for prefabs, which won't receive PrepareSave + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + if (isPrefabEnabled) + { + PrepareSave(); + } EditorEntitySortNotificationBus::Event(GetEntityId(), &EditorEntitySortNotificationBus::Events::ChildEntityOrderArrayUpdated); } @@ -264,10 +297,20 @@ namespace AzToolsFramework // This is a special case for certain EditorComponents only! EditorEntitySortRequestBus::Handler::BusConnect(GetEntityId()); EditorEntityContextNotificationBus::Handler::BusConnect(); + AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); } void EditorEntitySortComponent::Activate() { + // Run the post-serialize handler if prefabs are enabled because PostLoad won't be called automatically + bool isPrefabEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + isPrefabEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + if (isPrefabEnabled) + { + PostLoad(); + } + // Send out that the order for our entity is now updated EditorEntitySortNotificationBus::Event(GetEntityId(), &EditorEntitySortNotificationBus::Events::ChildEntityOrderArrayUpdated); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h index d728191c64..806e903c96 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntitySortComponent.h @@ -10,6 +10,7 @@ #include "EditorEntitySortBus.h" #include #include +#include #include namespace AzToolsFramework @@ -20,6 +21,7 @@ namespace AzToolsFramework : public AzToolsFramework::Components::EditorComponentBase , public EditorEntitySortRequestBus::Handler , public EditorEntityContextNotificationBus::Handler + , public AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler { public: AZ_COMPONENT(EditorEntitySortComponent, "{6EA1E03D-68B2-466D-97F7-83998C8C27F0}", EditorComponentBase); @@ -45,6 +47,9 @@ namespace AzToolsFramework // EditorEntityContextNotificationBus::Handler void OnEntityStreamLoadSuccess() override; ////////////////////////////////////////////////////////////////////////// + + void OnPrefabInstancePropagationBegin() override; + void OnPrefabInstancePropagationEnd() override; private: void MarkDirtyAndSendChangedEvent(); bool AddChildEntityInternal(const AZ::EntityId& entityId, bool addToBack, EntityOrderArray::iterator insertPosition); @@ -106,6 +111,7 @@ namespace AzToolsFramework EntityOrderCache m_childEntityOrderCache; ///< The map of entity id to index for quick look up bool m_entityOrderIsDirty = true; ///< This flag indicates our stored serialization order data is out of date and must be rebuilt before serialization occurs + bool m_ignoreIncomingOrderChanges = false; ///< This is set when prefab propagation occurs so that non-authored order changes can be ignored }; } } // namespace AzToolsFramework From 2f8de3e797a40a4126d546c872f750ad55d76161 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 4 Nov 2021 09:37:26 -0700 Subject: [PATCH 08/66] Keep gem repos pages in sync Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 9 ++++---- .../Source/EngineScreenCtrl.cpp | 18 ++++++++++++++++ .../ProjectManager/Source/EngineScreenCtrl.h | 4 ++++ .../Source/GemCatalog/GemCatalogScreen.cpp | 21 +++++++++++++++---- .../Source/GemRepo/GemRepoScreen.cpp | 5 +++++ .../Source/GemRepo/GemRepoScreen.h | 3 +++ .../Source/UpdateProjectCtrl.cpp | 4 ++++ 7 files changed, 56 insertions(+), 8 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 6caa9b8a2b..1aad4a7206 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -51,13 +51,11 @@ namespace O3DE::ProjectManager m_gemRepoScreen = new GemRepoScreen(this); m_stack->addWidget(m_gemRepoScreen); - vLayout->addWidget(m_stack); + vLayout->addWidget(m_stack); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); - connect( - m_gemRepoScreen, &GemRepoScreen::OnRefresh, - [this]() + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this]() { const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); m_gemCatalogScreen->Refresh(projectTemplatePath + "/Template"); @@ -135,6 +133,9 @@ namespace O3DE::ProjectManager // Gather the enabled gems from the default project template when starting the create new project workflow. ReinitGemCatalogForSelectedTemplate(); + + // make sure the gem repo has the latest details + m_gemRepoScreen->Reinit(); } void CreateProjectCtrl::HandleBackButton() diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp index f30a8e0daa..9d9110922f 100644 --- a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp @@ -39,6 +39,10 @@ namespace O3DE::ProjectManager m_tabWidget->addTab(m_engineSettingsScreen, tr("General")); m_tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories")); + + // when tab changes, notify the current screen so it can refresh + connect(m_tabWidget, &QTabWidget::currentChanged, this, &EngineScreenCtrl::TabChanged); + topBarHLayout->addWidget(m_tabWidget); vLayout->addWidget(topBarFrameWidget); @@ -46,6 +50,11 @@ namespace O3DE::ProjectManager setLayout(vLayout); } + void EngineScreenCtrl::TabChanged([[maybe_unused]] int index) + { + NotifyCurrentScreen(); + } + ProjectManagerScreen EngineScreenCtrl::GetScreenEnum() { return ProjectManagerScreen::UpdateProject; @@ -71,6 +80,15 @@ namespace O3DE::ProjectManager return false; } + void EngineScreenCtrl::NotifyCurrentScreen() + { + ScreenWidget* screen = reinterpret_cast(m_tabWidget->currentWidget()); + if (screen) + { + screen->NotifyCurrentScreen(); + } + } + void EngineScreenCtrl::GoToScreen(ProjectManagerScreen screen) { if (screen == m_engineSettingsScreen->GetScreenEnum()) diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h index b7142ba226..cf0d2a24d0 100644 --- a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h +++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h @@ -30,6 +30,10 @@ namespace O3DE::ProjectManager bool IsTab() override; bool ContainsScreen(ProjectManagerScreen screen) override; void GoToScreen(ProjectManagerScreen screen) override; + void NotifyCurrentScreen() override; + + public slots: + void TabChanged(int index); QTabWidget* m_tabWidget = nullptr; EngineSettingsScreen* m_engineSettingsScreen = nullptr; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 8234b80c8e..915c837da4 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include namespace O3DE::ProjectManager @@ -160,6 +159,7 @@ namespace O3DE::ProjectManager { QHash gemInfoHash; + // create a hash with the gem name as key AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); if (allGemInfosResult.IsSuccess()) { @@ -170,6 +170,7 @@ namespace O3DE::ProjectManager } } + // add all the gem repos into the hash AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); if (allRepoGemInfosResult.IsSuccess()) { @@ -183,24 +184,32 @@ namespace O3DE::ProjectManager } } - // remove rows for gems that were removed and not project dependencies + // remove gems from the model that no longer exist in the hash and are not project dependencies int i = 0; while (i < m_gemModel->rowCount()) { QModelIndex index = m_gemModel->index(i,0); QString gemName = m_gemModel->GetName(index); - if (!gemInfoHash.contains(gemName) && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) + const bool gemFound = gemInfoHash.contains(gemName); + if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) { m_gemModel->removeRow(i); } else { + if (!gemFound && (m_gemModel->IsAdded(index) || !m_gemModel->IsAddedDependency(index))) + { + const QString error = tr("Gem %1 was removed or unregistered, but is still used by the project.").arg(gemName); + AZ_Warning("Project Manager", false, error.toUtf8().constData()); + QMessageBox::warning(this, tr("Gem not found"), error.toUtf8().constData()); + } + gemInfoHash.remove(gemName); i++; } } - // add new rows + // add all gems remaining in the hash that were not removed for(auto iter = gemInfoHash.begin(); iter != gemInfoHash.end(); ++iter) { m_gemModel->AddGem(iter.value()); @@ -208,6 +217,10 @@ namespace O3DE::ProjectManager m_gemModel->UpdateGemDependencies(); m_proxyModel->sort(/*column=*/0); + + // temporary, until we can refresh filter counts + m_proxyModel->ResetFilters(); + m_filterWidget->ResetAllFilters(); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 30a57417d2..794635a3e3 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -52,6 +52,11 @@ namespace O3DE::ProjectManager Reinit(); } + void GemRepoScreen::NotifyCurrentScreen() + { + Reinit(); + } + void GemRepoScreen::Reinit() { m_gemRepoModel->clear(); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h index 0516005eef..eed9a5ec4a 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h @@ -38,6 +38,8 @@ namespace O3DE::ProjectManager GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; } + void NotifyCurrentScreen() override; + signals: void OnRefresh(); @@ -47,6 +49,7 @@ namespace O3DE::ProjectManager void HandleRefreshAllButton(); void HandleRefreshRepoButton(const QModelIndex& modelIndex); + private: void FillModel(); QFrame* CreateNoReposContent(); diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 5de3511f84..e76b4093a9 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -43,6 +43,7 @@ namespace O3DE::ProjectManager m_gemRepoScreen = new GemRepoScreen(this); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest); + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this](){ m_gemCatalogScreen->Refresh(m_projectInfo.m_path); }); m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); @@ -101,6 +102,9 @@ namespace O3DE::ProjectManager // Gather the available gems that will be shown in the gem catalog. m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path); + + // make sure the gem repo has the latest repo details + m_gemRepoScreen->Reinit(); } void UpdateProjectCtrl::OnChangeScreenRequest(ProjectManagerScreen screen) From 774b7c2593ad7c9b03412b2915e9138a6da64278 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:03:36 -0700 Subject: [PATCH 09/66] Fixed minor logic issue with gem removal warning Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 915c837da4..4574e8509b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -197,7 +197,7 @@ namespace O3DE::ProjectManager } else { - if (!gemFound && (m_gemModel->IsAdded(index) || !m_gemModel->IsAddedDependency(index))) + if (!gemFound && (m_gemModel->IsAdded(index) || m_gemModel->IsAddedDependency(index))) { const QString error = tr("Gem %1 was removed or unregistered, but is still used by the project.").arg(gemName); AZ_Warning("Project Manager", false, error.toUtf8().constData()); From 52604d79f6d2de34f9b94b30daf08e518bfa6429 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Thu, 4 Nov 2021 12:05:46 -0700 Subject: [PATCH 10/66] Address some review feedback Signed-off-by: nvsickle --- .../EditorScripts/EntityOutliner_EntityOrdering.py | 11 ++++++----- .../AzToolsFramework/Entity/EditorEntityHelpers.cpp | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py index 8b1e4763db..e4575d4d17 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/EntityOutliner_EntityOrdering.py @@ -44,12 +44,12 @@ def EntityOutliner_EntityOrdering(): entity_outliner_model = entity_outliner.model() # Get the outliner index for the root prefab container entity - def get_prefab_container_index(): + def get_root_prefab_container_index(): return entity_outliner_model.index(0, 0) - # Get the outlienr index for the top level entity of a given name + # Get the outliner index for the top level entity of a given name def index_for_name(name): - root_index = get_prefab_container_index() + root_index = get_root_prefab_container_index() for row in range(entity_outliner_model.rowCount(root_index)): row_index = entity_outliner_model.index(row, 0, root_index) if row_index.data() == name: @@ -59,7 +59,7 @@ def EntityOutliner_EntityOrdering(): # Validate that the outliner top level entity order matches the expected order def verify_entities_sorted(expected_order): actual_order = [] - root_index = get_prefab_container_index() + root_index = get_root_prefab_container_index() for row in range(entity_outliner_model.rowCount(root_index)): row_index = entity_outliner_model.index(row, 0, root_index) actual_order.append(row_index.data()) @@ -73,8 +73,9 @@ def EntityOutliner_EntityOrdering(): # Creates an entity from the outliner context menu def create_entity(): pyside_utils.trigger_context_menu_entry( - entity_outliner, "Create entity", index=get_prefab_container_index() + entity_outliner, "Create entity", index=get_root_prefab_container_index() ) + # Wait a tick after entity creation to let events process general.idle_wait(0.0) # Moves an entity (wrapped by move_entity_before and move_entity_after) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 511f9dd580..3e256430a2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -470,6 +470,7 @@ namespace AzToolsFramework EditorEntityInfoRequestBus::EventResult(children, parentId, &EditorEntityInfoRequestBus::Events::GetChildren); // If Prefabs are enabled, don't check the order for an invalid parent, just return its children (i.e. the root container entity) + // There will currently always be one root container entity, so there's no order to retrieve if (!parentId.IsValid()) { bool isPrefabEnabled = false; From 047c5f2231dbba742363a2d9396170c23b572374 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 15:09:11 -0700 Subject: [PATCH 11/66] Add ability to overwrite o3de object when downloading, and to check the last_updated field to check for updates. Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/download.py | 103 ++++++++++++++++++++++++++++++---- scripts/o3de/o3de/utils.py | 9 ++- 2 files changed, 97 insertions(+), 15 deletions(-) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 98f5d051a4..5d15c4d0b3 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -20,6 +20,7 @@ import sys import urllib.parse import urllib.request import zipfile +from datetime import datetime from o3de import manifest, repo, utils, validation, register @@ -88,10 +89,9 @@ def get_downloadable(engine_name: str = None, search_func = lambda manifest_json_data: repo.search_repo(manifest_json_data, engine_name, project_name, gem_name, template_name) return repo.search_o3de_object(manifest_json, o3de_object_uris, search_func) - def download_o3de_object(object_name: str, default_folder_name: str, dest_path: str or pathlib.Path, object_type: str, downloadable_kwarg_key, skip_auto_register: bool, - download_progress_callback = None) -> int: + force_overwrite: bool, download_progress_callback = None) -> int: download_path = manifest.get_o3de_cache_folder() / default_folder_name / object_name download_path.mkdir(parents=True, exist_ok=True) @@ -124,9 +124,11 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: if not dest_path: logger.error(f'Destination path cannot be empty.') return 1 - if dest_path.exists(): + if dest_path.exists() and not force_overwrite: logger.error(f'Destination path {dest_path} already exists.') return 1 + elif dest_path.exists(): + shutil.rmtree(dest_path) dest_path.mkdir(exist_ok=True) @@ -149,38 +151,108 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: def download_engine(engine_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name', skip_auto_register, download_progress_callback) + return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name', skip_auto_register, force_overwrite, download_progress_callback) def download_project(project_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name', skip_auto_register, download_progress_callback) + return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name', skip_auto_register, force_overwrite, download_progress_callback) def download_gem(gem_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name', skip_auto_register, download_progress_callback) + return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name', skip_auto_register, force_overwrite, download_progress_callback) def download_template(template_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name', skip_auto_register, download_progress_callback) + return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name', skip_auto_register, force_overwrite, download_progress_callback) def download_restricted(restricted_name: str, dest_path: str or pathlib.Path, skip_auto_register: bool, + force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, download_progress_callback) + return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, force_overwrite, download_progress_callback) + +def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, current_date: datetime) -> bool: + downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) + if not downloadable_object_data: + logger.error(f'Downloadable o3de object {object_name} not found.') + return False + + repo_copy_updated_string = 0 + try: + repo_copy_updated_string = downloadable_object_data['last_updated'] + except KeyError: + logger.warn(f'last_updated field not found for {object_name}.') + return False + + try: + repo_copy_updated_date = datetime.fromisoformat(repo_copy_updated_string) + except ValueError: + logger.error(f'last_updated field in incorrect format for {object_name}.') + return False + + return repo_copy_updated_date > current_date +def is_o3de_engine_update_available(engine_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for engine {engine_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(engine_name, 'engine_name', current_updated_time) + +def is_o3de_project_update_available(project_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for project {project_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(project_name, 'project_name', current_updated_time) + +def is_o3de_gem_update_available(gem_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for gem {gem_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(gem_name, 'gem_name', current_updated_time) + +def is_o3de_template_update_available(template_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for template {template_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(template_name, 'template_name', current_updated_time) + +def is_o3de_restricted_update_available(restricted_name: str, local_last_updated: str): + try: + current_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for restricted {restricted_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + current_updated_time = datetime.min + return is_o3de_object_update_available(restricted_name, 'restricted_name', current_updated_time) def _run_download(args: argparse) -> int: if args.override_home_folder: @@ -189,19 +261,23 @@ def _run_download(args: argparse) -> int: if args.engine_name: return download_engine(args.engine_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) elif args.project_name: return download_project(args.project_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) elif args.gem_name: return download_gem(args.gem_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) elif args.template_name: return download_template(args.template_name, args.dest_path, - args.skip_auto_register) + args.skip_auto_register, + args.force_overwrite) return 1 @@ -230,6 +306,9 @@ def add_parser_args(parser): parser.add_argument('-sar', '--skip-auto-register', action='store_true', required=False, default=False, help = 'Skip the automatic registration of new object download') + parser.add_argument('-fce', '--force-overwrite', action='store_true', required=False, + default=False, + help = 'Force overwrite the current object') parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, help='By default the home folder is the user folder, override it to this folder.') diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 8663502a3f..df2ea67666 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -117,15 +117,18 @@ def backup_folder(folder: str or pathlib.Path) -> None: if backup_folder_name.is_dir(): renamed = True -def download_file(parsed_uri, download_path: pathlib.Path, download_progress_callback = None) -> int: +def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite, download_progress_callback = None) -> int: """ :param parsed_uri: uniform resource identifier to zip file to download :param download_path: location path on disk to download file :download_progress_callback: callback called with the download progress as a percentage, returns true to request to cancel the download """ - if download_path.is_file(): + if download_path.is_file() and not force_overwrite: logger.warn(f'File already downloaded to {download_path}.') - elif parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: + elif download_path.is_file(): + shutil.rmtree(download_path) + + if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: with urllib.request.urlopen(parsed_uri.geturl()) as s: download_file_size = 0 try: From 9d977e81da0b9d4c3135ad6f0d8e5aa9aec2298e Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 15:20:35 -0700 Subject: [PATCH 12/66] Uncomment temporary disabling of toast notifications Signed-off-by: AMZN-Phil --- .../Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 32cf35c04d..db34375db5 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -188,7 +188,7 @@ namespace O3DE::ProjectManager toastConfiguration.m_customIconImage = ":/gem.svg"; toastConfiguration.m_borderRadius = 4; toastConfiguration.m_duration = AZStd::chrono::milliseconds(3000); - //m_notificationsView->ShowToastNotification(toastConfiguration); + m_notificationsView->ShowToastNotification(toastConfiguration); } } From 31382d080e94548b5d71702e44de5e9951191dd8 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 17:07:02 -0700 Subject: [PATCH 13/66] Remove duplication, additional readability and added missed file Signed-off-by: AMZN-Phil --- .../ProjectManager/Source/PythonBindings.cpp | 1 + scripts/o3de/o3de/download.py | 79 +++++++------------ scripts/o3de/o3de/utils.py | 13 ++- 3 files changed, 40 insertions(+), 53 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 740393fec0..0be0d02ca0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -1173,6 +1173,7 @@ namespace O3DE::ProjectManager QString_To_Py_String(gemName), // gem name pybind11::none(), // destination path false, // skip auto register + false, // force pybind11::cpp_function( [this, gemProgressCallback](int progress) { diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 5d15c4d0b3..b6d6233559 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -124,11 +124,16 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: if not dest_path: logger.error(f'Destination path cannot be empty.') return 1 - if dest_path.exists() and not force_overwrite: - logger.error(f'Destination path {dest_path} already exists.') - return 1 - elif dest_path.exists(): - shutil.rmtree(dest_path) + if dest_path.exists(): + if not force_overwrite: + logger.error(f'Destination path {dest_path} already exists.') + return 1 + else: + try: + shutil.rmtree(dest_path) + except OSError: + logger.error(f'Could not remove existing destination path {dest_path}.') + return 1 dest_path.mkdir(exist_ok=True) @@ -188,71 +193,47 @@ def download_restricted(restricted_name: str, download_progress_callback = None) -> int: return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, force_overwrite, download_progress_callback) -def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, current_date: datetime) -> bool: +def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, local_last_updated: str) -> bool: downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) if not downloadable_object_data: logger.error(f'Downloadable o3de object {object_name} not found.') return False - repo_copy_updated_string = 0 try: repo_copy_updated_string = downloadable_object_data['last_updated'] except KeyError: logger.warn(f'last_updated field not found for {object_name}.') return False + try: + local_last_updated_time = datetime.fromisoformat(local_last_updated) + except ValueError: + logger.warn(f'last_updated field has incorrect format for local copy of {downloadable_kwarg_key} {object_name}.') + # Possible that an earlier version did not have this field so still want to check against cached downloadable version + local_last_updated_time = datetime.min + try: repo_copy_updated_date = datetime.fromisoformat(repo_copy_updated_string) except ValueError: - logger.error(f'last_updated field in incorrect format for {object_name}.') + logger.error(f'last_updated field in incorrect format for repository copy of {downloadable_kwarg_key} {object_name}.') return False - return repo_copy_updated_date > current_date + return repo_copy_updated_date > local_last_updated_time def is_o3de_engine_update_available(engine_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for engine {engine_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(engine_name, 'engine_name', current_updated_time) + return is_o3de_object_update_available(engine_name, 'engine_name', local_last_updated) def is_o3de_project_update_available(project_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for project {project_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(project_name, 'project_name', current_updated_time) + return is_o3de_object_update_available(project_name, 'project_name', local_last_updated) def is_o3de_gem_update_available(gem_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for gem {gem_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(gem_name, 'gem_name', current_updated_time) + return is_o3de_object_update_available(gem_name, 'gem_name', local_last_updated) def is_o3de_template_update_available(template_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for template {template_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(template_name, 'template_name', current_updated_time) + return is_o3de_object_update_available(template_name, 'template_name', local_last_updated) def is_o3de_restricted_update_available(restricted_name: str, local_last_updated: str): - try: - current_updated_time = datetime.fromisoformat(local_last_updated) - except ValueError: - logger.warn(f'last_updated field has incorrect format for restricted {restricted_name}.') - # Possible that an earlier version did not have this field so still want to check against cached downloadable version - current_updated_time = datetime.min - return is_o3de_object_update_available(restricted_name, 'restricted_name', current_updated_time) + return is_o3de_object_update_available(restricted_name, 'restricted_name', local_last_updated) def _run_download(args: argparse) -> int: if args.override_home_folder: @@ -262,22 +243,22 @@ def _run_download(args: argparse) -> int: return download_engine(args.engine_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) elif args.project_name: return download_project(args.project_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) elif args.gem_name: return download_gem(args.gem_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) elif args.template_name: return download_template(args.template_name, args.dest_path, args.skip_auto_register, - args.force_overwrite) + args.force) return 1 @@ -306,7 +287,7 @@ def add_parser_args(parser): parser.add_argument('-sar', '--skip-auto-register', action='store_true', required=False, default=False, help = 'Skip the automatic registration of new object download') - parser.add_argument('-fce', '--force-overwrite', action='store_true', required=False, + parser.add_argument('-f', '--force', action='store_true', required=False, default=False, help = 'Force overwrite the current object') parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index df2ea67666..56f9ae4bcd 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -123,10 +123,15 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite, down :param download_path: location path on disk to download file :download_progress_callback: callback called with the download progress as a percentage, returns true to request to cancel the download """ - if download_path.is_file() and not force_overwrite: - logger.warn(f'File already downloaded to {download_path}.') - elif download_path.is_file(): - shutil.rmtree(download_path) + if download_path.is_file(): + if not force_overwrite: + logger.warn(f'File already downloaded to {download_path}.') + else: + try: + shutil.rmtree(download_path) + except OSError: + logger.error(f'Could not remove existing download path {download_path}.') + return 1 if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: with urllib.request.urlopen(parsed_uri.geturl()) as s: From 81515b922f34cc5841a378fea3f47a8b50591e14 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 4 Nov 2021 17:10:44 -0700 Subject: [PATCH 14/66] Additional readability Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/download.py | 45 +++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index b6d6233559..9e576d64b5 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -158,7 +158,14 @@ def download_engine(engine_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(engine_name, + 'engines', + dest_path, + 'engine', + 'engine_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def download_project(project_name: str, @@ -166,7 +173,14 @@ def download_project(project_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(project_name, + 'projects', + dest_path, + 'project', + 'project_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def download_gem(gem_name: str, @@ -174,7 +188,14 @@ def download_gem(gem_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(gem_name, + 'gems', + dest_path, + 'gem', + 'gem_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def download_template(template_name: str, @@ -182,7 +203,14 @@ def download_template(template_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(template_name, + 'templates', + dest_path, + 'template', + 'template_name', + skip_auto_register, + force_overwrite, + download_progress_callback) @@ -191,7 +219,14 @@ def download_restricted(restricted_name: str, skip_auto_register: bool, force_overwrite: bool, download_progress_callback = None) -> int: - return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name', skip_auto_register, force_overwrite, download_progress_callback) + return download_o3de_object(restricted_name, + 'restricted', + dest_path, + 'restricted', + 'restricted_name', + skip_auto_register, + force_overwrite, + download_progress_callback) def is_o3de_object_update_available(object_name: str, downloadable_kwarg_key, local_last_updated: str) -> bool: downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) From fbc35a8169dfcadaf622acc862791d6a3744073f Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 4 Nov 2021 22:09:11 -0700 Subject: [PATCH 15/66] Applied a fix from @jeremyong-az to get ThinObject transmission working. Also added a new test material for ThinObject transmission. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Atom/Features/PBR/BackLighting.azsli | 9 ++++-- ...rfaceScattering_Transmission_Thin.material | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli index a4a747d42c..83cf79ed61 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/BackLighting.azsli @@ -50,8 +50,13 @@ float3 GetBackLighting(Surface surface, LightingData lightingData, float3 lightI // Thin object mode, using thin-film assumption proposed by Jimenez J. et al, 2010, "Real-Time Realistic Skin Translucency" // http://www.iryoku.com/translucency/downloads/Real-Time-Realistic-Skin-Translucency.pdf - result = shadowRatio ? float3(0.0, 0.0, 0.0) : TransmissionKernel(surface.transmission.thickness * transmissionParams.w, rcp(transmissionParams.xyz)) * - saturate(dot(-surface.normal, dirToLight)) * lightIntensity * shadowRatio; + float litRatio = 1.0 - shadowRatio; + if (litRatio) + { + result = TransmissionKernel(surface.transmission.thickness * transmissionParams.w, rcp(transmissionParams.xyz)) * + saturate(dot(-surface.normal, dirToLight)) * lightIntensity * litRatio; + } + break; } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material new file mode 100644 index 0000000000..ee9bb1f4a5 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission_Thin.material @@ -0,0 +1,29 @@ +{ + "description": "", + "parentMaterial": "", + "materialType": "Materials/Types/EnhancedPBR.materialtype", + "materialTypeVersion": 4, + "properties": { + "baseColor": { + "color": [ + 0.027664607390761375, + 0.1926604062318802, + 0.013916227966547012, + 1.0 + ] + }, + "general": { + "doubleSided": true + }, + "subsurfaceScattering": { + "thickness": 0.20000000298023224, + "transmissionMode": "ThinObject", + "transmissionTint": [ + 0.009140154346823692, + 0.19806210696697235, + 0.01095597818493843, + 1.0 + ] + } + } +} \ No newline at end of file From 060c2178522e0c9a5d3664370593a43ec81a17b6 Mon Sep 17 00:00:00 2001 From: Jonny Gallowy Date: Fri, 5 Nov 2021 15:00:35 -0500 Subject: [PATCH 16/66] Fixed .bat chain for launching maya for AtomContent gems Signed-off-by: Jonny Gallowy --- .../ReferenceMaterials/Tools/Launch_Cmd.bat | 9 +++-- .../ReferenceMaterials/Tools/Launch_Maya.bat | 11 +++---- .../ReferenceMaterials/Tools/Project_Env.bat | 33 +++++++++---------- Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat | 7 ++-- Gems/AtomContent/Sponza/Tools/Launch_Maya.bat | 8 +++-- Gems/AtomContent/Sponza/Tools/Project_Env.bat | 33 +++++++++---------- .../Tools/Dev/Windows/Env_Maya.bat | 2 +- 7 files changed, 48 insertions(+), 55 deletions(-) diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat index d100c9ddc7..0b94be5bea 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Cmd.bat @@ -1,4 +1,6 @@ @echo off +:: Keep changes local +SETLOCAL enableDelayedExpansion REM REM Copyright (c) Contributors to the Open 3D Engine Project @@ -13,7 +15,7 @@ REM :: Puts you in the CMD within the dev environment :: Set up window -TITLE O3DE Asset Gem Cmd +TITLE O3DE DCC Scripting Interface Cmd :: Use obvious color to prevent confusion (Grey with Yellow Text) COLOR 8E @@ -21,15 +23,12 @@ COLOR 8E cd %~dp0 PUSHD %~dp0 -:: Keep changes local -SETLOCAL enableDelayedExpansion - CALL %~dp0\Project_Env.bat echo. echo _____________________________________________________________________ echo. -echo ~ O3DE Asset Gem CMD ... +echo ~ O3DE %O3DE_PROJECT% Asset Gem CMD ... echo _____________________________________________________________________ echo. diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat index b9a6b399f3..c0f5f589d7 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat @@ -1,6 +1,3 @@ -:: Launches maya wityh a bunch of local hooks for Lumberyard -:: ToDo: move all of this to a .json data driven boostrapping system - @echo off REM @@ -37,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% @@ -47,8 +44,10 @@ echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... Set MAYA_VP2_DEVICE_OVERRIDE = VirtualDeviceDx11 :: Default to the right version of Maya if we can detect it... and launch -IF EXIST "%MAYA_LOCATION%\bin\Maya.exe" ( - start "" "%MAYA_LOCATION%\bin\Maya.exe" %* +echo MAYA_BIN_PATH = %MAYA_BIN_PATH% + +IF EXIST "%MAYA_BIN_PATH%\Maya.exe" ( + start "" "%MAYA_BIN_PATH%\Maya.exe" %* ) ELSE ( Where maya.exe 2> NUL IF ERRORLEVEL 1 ( diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat index 6e2c8b5914..134e238384 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat @@ -29,23 +29,23 @@ PUSHD %~dp0 set ABS_PATH=%~dp0 :: project name as a str tag -IF "%LY_PROJECT_NAME%"=="" ( - for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set LY_PROJECT_NAME=%%~nxJ +IF "%O3DE_PROJECT%"=="" ( + for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set O3DE_PROJECT=%%~nxJ ) echo. echo _____________________________________________________________________ echo. -echo ~ Setting up O3DE %LY_PROJECT_NAME% Environment ... +echo ~ Setting up O3DE %O3DE_PROJECT% Environment ... echo _____________________________________________________________________ echo. -echo LY_PROJECT_NAME = %LY_PROJECT_NAME% +echo O3DE_PROJECT = %O3DE_PROJECT% :: if the user has set up a custom env call it :: this should allow the user to locally -:: set env hooks like LY_DEV or LY_PROJECT +:: set env hooks like O3DE_DEV or O3DE_PROJECT_PATH IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat -echo LY_DEV = %LY_DEV% +echo O3DE_DEV = %O3DE_DEV% :: Constant Vars (Global) :: global debug flag (propogates) @@ -74,23 +74,20 @@ echo DCCSI_LOGLEVEL = %DCCSI_LOGLEVEL% IF "%DCCSI_MAYA_VERSION%"=="" (set DCCSI_MAYA_VERSION=2020) echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% -:: LY_PROJECT is ideally treated as a full path in the env launchers +:: O3DE_PROJECT_PATH is ideally treated as a full path in the env launchers :: do to changes in o3de, external engine/project/gem folder structures, etc. -IF "%LY_PROJECT%"=="" ( - for %%i in ("%~dp0..") do set "LY_PROJECT=%%~fi" +IF "%O3DE_PROJECT_PATH%"=="" ( + for %%i in ("%~dp0..") do set "O3DE_PROJECT_PATH=%%~fi" ) -echo LY_PROJECT = %LY_PROJECT% - -:: this is here for archaic reasons, WILL DEPRECATE -IF "%LY_PROJECT_PATH%"=="" (set LY_PROJECT_PATH=%LY_PROJECT%) -echo LY_PROJECT_PATH = %LY_PROJECT_PATH% +echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% :: Change to root Lumberyard dev dir -:: You must set this in a User_Env.bat to match youe engine repo location! -IF "%LY_DEV%"=="" (set LY_DEV=C:\Depot\o3de-engine) -echo LY_DEV = %LY_DEV% +IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! +IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine +IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) +echo O3DE_DEV = %O3DE_DEV% -CALL %LY_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Launchers\Windows\Env_Maya.bat +CALL %O3DE_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Tools\Dev\Windows\Env_Maya.bat :: Restore original directory popd diff --git a/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat b/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat index 99c2c12c51..0b94be5bea 100644 --- a/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat +++ b/Gems/AtomContent/Sponza/Tools/Launch_Cmd.bat @@ -1,4 +1,6 @@ @echo off +:: Keep changes local +SETLOCAL enableDelayedExpansion REM REM Copyright (c) Contributors to the Open 3D Engine Project @@ -21,15 +23,12 @@ COLOR 8E cd %~dp0 PUSHD %~dp0 -:: Keep changes local -SETLOCAL enableDelayedExpansion - CALL %~dp0\Project_Env.bat echo. echo _____________________________________________________________________ echo. -echo ~ LY DCC Scripting Interface CMD ... +echo ~ O3DE %O3DE_PROJECT% Asset Gem CMD ... echo _____________________________________________________________________ echo. diff --git a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat index d774adf79b..c0f5f589d7 100644 --- a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat @@ -34,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% @@ -44,8 +44,10 @@ echo Launching Maya %DCCSI_MAYA_VERSION% for Lumberyard... Set MAYA_VP2_DEVICE_OVERRIDE = VirtualDeviceDx11 :: Default to the right version of Maya if we can detect it... and launch -IF EXIST "%MAYA_LOCATION%\bin\Maya.exe" ( - start "" "%MAYA_LOCATION%\bin\Maya.exe" %* +echo MAYA_BIN_PATH = %MAYA_BIN_PATH% + +IF EXIST "%MAYA_BIN_PATH%\Maya.exe" ( + start "" "%MAYA_BIN_PATH%\Maya.exe" %* ) ELSE ( Where maya.exe 2> NUL IF ERRORLEVEL 1 ( diff --git a/Gems/AtomContent/Sponza/Tools/Project_Env.bat b/Gems/AtomContent/Sponza/Tools/Project_Env.bat index 6e2c8b5914..134e238384 100644 --- a/Gems/AtomContent/Sponza/Tools/Project_Env.bat +++ b/Gems/AtomContent/Sponza/Tools/Project_Env.bat @@ -29,23 +29,23 @@ PUSHD %~dp0 set ABS_PATH=%~dp0 :: project name as a str tag -IF "%LY_PROJECT_NAME%"=="" ( - for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set LY_PROJECT_NAME=%%~nxJ +IF "%O3DE_PROJECT%"=="" ( + for %%I in ("%~dp0.") do for %%J in ("%%~dpI.") do set O3DE_PROJECT=%%~nxJ ) echo. echo _____________________________________________________________________ echo. -echo ~ Setting up O3DE %LY_PROJECT_NAME% Environment ... +echo ~ Setting up O3DE %O3DE_PROJECT% Environment ... echo _____________________________________________________________________ echo. -echo LY_PROJECT_NAME = %LY_PROJECT_NAME% +echo O3DE_PROJECT = %O3DE_PROJECT% :: if the user has set up a custom env call it :: this should allow the user to locally -:: set env hooks like LY_DEV or LY_PROJECT +:: set env hooks like O3DE_DEV or O3DE_PROJECT_PATH IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat -echo LY_DEV = %LY_DEV% +echo O3DE_DEV = %O3DE_DEV% :: Constant Vars (Global) :: global debug flag (propogates) @@ -74,23 +74,20 @@ echo DCCSI_LOGLEVEL = %DCCSI_LOGLEVEL% IF "%DCCSI_MAYA_VERSION%"=="" (set DCCSI_MAYA_VERSION=2020) echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% -:: LY_PROJECT is ideally treated as a full path in the env launchers +:: O3DE_PROJECT_PATH is ideally treated as a full path in the env launchers :: do to changes in o3de, external engine/project/gem folder structures, etc. -IF "%LY_PROJECT%"=="" ( - for %%i in ("%~dp0..") do set "LY_PROJECT=%%~fi" +IF "%O3DE_PROJECT_PATH%"=="" ( + for %%i in ("%~dp0..") do set "O3DE_PROJECT_PATH=%%~fi" ) -echo LY_PROJECT = %LY_PROJECT% - -:: this is here for archaic reasons, WILL DEPRECATE -IF "%LY_PROJECT_PATH%"=="" (set LY_PROJECT_PATH=%LY_PROJECT%) -echo LY_PROJECT_PATH = %LY_PROJECT_PATH% +echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% :: Change to root Lumberyard dev dir -:: You must set this in a User_Env.bat to match youe engine repo location! -IF "%LY_DEV%"=="" (set LY_DEV=C:\Depot\o3de-engine) -echo LY_DEV = %LY_DEV% +IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! +IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine +IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) +echo O3DE_DEV = %O3DE_DEV% -CALL %LY_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Launchers\Windows\Env_Maya.bat +CALL %O3DE_DEV%\Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\Tools\Dev\Windows\Env_Maya.bat :: Restore original directory popd diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat index 5e3c600124..0ed46e9400 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Tools/Dev/Windows/Env_Maya.bat @@ -46,7 +46,7 @@ echo DCCSI_PY_VERSION_RELEASE = %DCCSI_PY_VERSION_RELEASE% echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% :::: Set Maya native project acess to this project -IF "%MAYA_PROJECT%"=="" (set MAYA_PROJECT=%O3DE_PROJECT%) +IF "%MAYA_PROJECT%"=="" (set MAYA_PROJECT=%O3DE_PROJECT_PATH%) echo MAYA_PROJECT = %MAYA_PROJECT% :: maya sdk path From 7d1e1474b5075e70064db25d22cce15509bddf22 Mon Sep 17 00:00:00 2001 From: Jonny Gallowy Date: Fri, 5 Nov 2021 15:50:54 -0500 Subject: [PATCH 17/66] fixed typo Signed-off-by: Jonny Gallowy --- Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat | 2 +- Gems/AtomContent/Sponza/Tools/Launch_Maya.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat index c0f5f589d7..0af25905a0 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Launch_Maya.bat @@ -34,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O3DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% diff --git a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat index c0f5f589d7..0af25905a0 100644 --- a/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat +++ b/Gems/AtomContent/Sponza/Tools/Launch_Maya.bat @@ -34,7 +34,7 @@ echo DCCSI_MAYA_VERSION = %DCCSI_MAYA_VERSION% IF EXIST "%~dp0Project_Env.bat" CALL %~dp0Project_Env.bat echo ________________________________ -echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O#DE_PROJECT%... +echo Launching Maya %DCCSI_MAYA_VERSION% for O3DE: %O3DE_PROJECT%... :::: Set Maya native project acess to this project ::set MAYA_PROJECT=%LY_PROJECT% From 5138170d8c037104b50b65dc15e116ef55528b2c Mon Sep 17 00:00:00 2001 From: Jonny Gallowy Date: Fri, 5 Nov 2021 15:54:57 -0500 Subject: [PATCH 18/66] fixed typo Signed-off-by: Jonny Gallowy --- Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat | 2 +- Gems/AtomContent/Sponza/Tools/Project_Env.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat index 134e238384..ddf934d206 100644 --- a/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat +++ b/Gems/AtomContent/ReferenceMaterials/Tools/Project_Env.bat @@ -81,7 +81,7 @@ IF "%O3DE_PROJECT_PATH%"=="" ( ) echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% -:: Change to root Lumberyard dev dir +:: Change to root O3DE dev dir IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) diff --git a/Gems/AtomContent/Sponza/Tools/Project_Env.bat b/Gems/AtomContent/Sponza/Tools/Project_Env.bat index 134e238384..ddf934d206 100644 --- a/Gems/AtomContent/Sponza/Tools/Project_Env.bat +++ b/Gems/AtomContent/Sponza/Tools/Project_Env.bat @@ -81,7 +81,7 @@ IF "%O3DE_PROJECT_PATH%"=="" ( ) echo O3DE_PROJECT_PATH = %O3DE_PROJECT_PATH% -:: Change to root Lumberyard dev dir +:: Change to root O3DE dev dir IF "%O3DE_DEV%"=="" echo ~ You must set O3DE_DEV in a User_Env.bat to match your local engine repo! IF "%O3DE_DEV%"=="" echo ~ Using default O3DE_DEV=C:\Depot\o3de-engine IF "%O3DE_DEV%"=="" (set O3DE_DEV=C:\Depot\o3de-engine) From c6e77f8e32c35d33fa639a00c6aea819b360ffbc Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Fri, 5 Nov 2021 14:21:10 -0700 Subject: [PATCH 19/66] Code readability improvements Signed-off-by: AMZN-Phil --- .../Source/DownloadController.cpp | 8 ++-- .../GemCatalog/GemCatalogHeaderWidget.cpp | 41 ++++++++----------- .../Source/GemCatalog/GemCatalogScreen.cpp | 2 +- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index 00a7db5318..6326b2fc11 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -45,7 +45,7 @@ namespace O3DE::ProjectManager if (m_gemNames.size() == 1) { - m_worker->SetGemToDownload(m_gemNames[0], false); + m_worker->SetGemToDownload(m_gemNames.front(), false); m_workerThread.start(); } } @@ -72,7 +72,7 @@ namespace O3DE::ProjectManager void DownloadController::UpdateUIProgress(int progress) { m_lastProgress = progress; - emit GemDownloadProgress(*m_gemNames.begin(), progress); + emit GemDownloadProgress(m_gemNames.front(), progress); } void DownloadController::HandleResults(const QString& result) @@ -85,13 +85,13 @@ namespace O3DE::ProjectManager succeeded = false; } - QString gemName = *m_gemNames.begin(); + QString gemName = m_gemNames.front(); m_gemNames.erase(m_gemNames.begin()); emit Done(gemName, succeeded); if (!m_gemNames.empty()) { - emit StartGemDownload(m_gemNames[0]); + emit StartGemDownload(m_gemNames.front()); } else { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index cfe69283ff..b0729c0047 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -214,9 +214,9 @@ namespace O3DE::ProjectManager // Setup gem download rows for gems that are already in the queue const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); - for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) + for (const QString& gemName : downloadQueue) { - GemDownloadAdded(downloadQueue[downloadingGemNumber]); + GemDownloadAdded(gemName); } } @@ -229,24 +229,28 @@ namespace O3DE::ProjectManager void CartOverlayWidget::GemDownloadAdded(const QString& gemName) { + // Containing widget for the current download item QWidget* newGemDownloadWidget = new QWidget(); newGemDownloadWidget->setObjectName(gemName); - QVBoxLayout* downloadingGemLayout = new QVBoxLayout(); + QVBoxLayout* downloadingGemLayout = new QVBoxLayout(newGemDownloadWidget); newGemDownloadWidget->setLayout(downloadingGemLayout); - QHBoxLayout* nameProgressLayout = new QHBoxLayout(); - TagWidget* newTag = new TagWidget(gemName); + + // Gem name, progress string, cancel + QHBoxLayout* nameProgressLayout = new QHBoxLayout(newGemDownloadWidget); + TagWidget* newTag = new TagWidget(gemName, newGemDownloadWidget); nameProgressLayout->addWidget(newTag); - QLabel* progress = new QLabel(tr("Queued")); + QLabel* progress = new QLabel(tr("Queued"), newGemDownloadWidget); progress->setObjectName("DownloadProgressLabel"); nameProgressLayout->addWidget(progress); - QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); - nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel").arg(gemName)); + nameProgressLayout->addStretch(); + QLabel* cancelText = new QLabel(tr("Cancel").arg(gemName), newGemDownloadWidget); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); downloadingGemLayout->addLayout(nameProgressLayout); - QProgressBar* downloadProgessBar = new QProgressBar(); + + // Progress bar + QProgressBar* downloadProgessBar = new QProgressBar(newGemDownloadWidget); downloadProgessBar->setObjectName("DownloadProgressBar"); downloadingGemLayout->addWidget(downloadProgessBar); downloadProgessBar->setValue(0); @@ -265,31 +269,22 @@ namespace O3DE::ProjectManager void CartOverlayWidget::GemDownloadRemoved(const QString& gemName) { QWidget* gemToRemove = m_downloadingListWidget->findChild(gemName); - QLayout* gemToRemoveLayout = gemToRemove ? gemToRemove->layout() : nullptr; - - if (gemToRemoveLayout) + if (gemToRemove) { - QLayoutItem* rowLayoutItem = nullptr; - while ((rowLayoutItem = gemToRemoveLayout->layout()->takeAt(0)) != nullptr) - { - rowLayoutItem->widget()->deleteLater(); - } - gemToRemoveLayout->layout()->deleteLater(); gemToRemove->deleteLater(); } - const AZStd::vector& downloadQueue = m_downloadController->GetDownloadQueue(); - if (m_downloadController->IsDownloadQueueEmpty()) { m_downloadSectionWidget->hide(); } else { + size_t downloadQueueSize = m_downloadController->GetDownloadQueue().size(); QLabel* numDownloads = m_downloadingListWidget->findChild("NumDownloadsInProgressLabel"); numDownloads->setText(QString("%1 %2") - .arg(downloadQueue.size()) - .arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress..."))); + .arg(downloadQueueSize) + .arg(downloadQueueSize == 1 ? tr("download in progress...") : tr("downloads in progress..."))); } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 9f5d4a70f2..f3e1da011a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -175,7 +175,7 @@ namespace O3DE::ProjectManager if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) { m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); - GemModel::SetDownloadStatus(*m_proxyModel, modelIndex, GemInfo::DownloadStatus::Downloading); + GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading); } } From 4ce39ea1675e6ba2b102bef02e4226f5b99ed081 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:17:11 -0700 Subject: [PATCH 20/66] Fix tags, downloads, and several vector copies Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/CreateProjectCtrl.cpp | 12 +-- .../Source/DownloadController.cpp | 3 +- .../Source/DownloadController.h | 2 +- .../GemCatalog/GemCatalogHeaderWidget.cpp | 24 +++--- .../GemCatalog/GemCatalogHeaderWidget.h | 2 +- .../Source/GemCatalog/GemCatalogScreen.cpp | 78 +++++++++++++++---- .../Source/GemCatalog/GemCatalogScreen.h | 4 +- .../Source/GemCatalog/GemInspector.cpp | 8 +- .../Source/GemCatalog/GemInspector.h | 2 +- .../Source/GemCatalog/GemModel.cpp | 32 ++++---- .../Source/GemCatalog/GemModel.h | 4 +- .../Source/GemRepo/GemRepoInspector.cpp | 2 +- .../Source/GemRepo/GemRepoModel.cpp | 12 +-- .../Source/GemRepo/GemRepoModel.h | 2 +- .../ProjectManager/Source/GemsSubWidget.cpp | 6 +- .../ProjectManager/Source/GemsSubWidget.h | 4 +- .../Tools/ProjectManager/Source/TagWidget.cpp | 37 ++++++--- Code/Tools/ProjectManager/Source/TagWidget.h | 22 +++++- .../Source/UpdateProjectCtrl.cpp | 3 +- .../ProjectManager/Source/UpdateProjectCtrl.h | 1 + 20 files changed, 170 insertions(+), 90 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index 1aad4a7206..6b19e839d7 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -55,11 +55,7 @@ namespace O3DE::ProjectManager vLayout->addWidget(m_stack); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &CreateProjectCtrl::OnChangeScreenRequest); - connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this]() - { - const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); - m_gemCatalogScreen->Refresh(projectTemplatePath + "/Template"); - }); + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, m_gemCatalogScreen, &GemCatalogScreen::Refresh); // When there are multiple project templates present, we re-gather the gems when changing the selected the project template. connect(m_newProjectSettingsScreen, &NewProjectSettingsScreen::OnTemplateSelectionChanged, this, [=](int oldIndex, [[maybe_unused]] int newIndex) @@ -257,6 +253,12 @@ namespace O3DE::ProjectManager { if (m_newProjectSettingsScreen->Validate()) { + if (!m_gemCatalogScreen->GetDownloadController()->IsDownloadQueueEmpty()) + { + QMessageBox::critical(this, tr("Gems downloading"), tr("You must wait for gems to finish downloading before continuing.")); + return; + } + ProjectInfo projectInfo = m_newProjectSettingsScreen->GetProjectInfo(); QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath(); diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index 224b90299c..a8eecffd78 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -82,8 +82,9 @@ namespace O3DE::ProjectManager succeeded = false; } + const QString gemName = m_gemNames[0]; m_gemNames.erase(m_gemNames.begin()); - emit Done(succeeded); + emit Done(succeeded, gemName); if (!m_gemNames.empty()) { diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h index 11ceaacddb..8afe8ef029 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.h +++ b/Code/Tools/ProjectManager/Source/DownloadController.h @@ -58,7 +58,7 @@ namespace O3DE::ProjectManager signals: void StartGemDownload(const QString& gemName); - void Done(bool success = true); + void Done(bool success, const QString& gemName); void GemDownloadProgress(int percentage); private: diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 5d65c740af..0db2b088c1 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -145,7 +145,7 @@ namespace O3DE::ProjectManager } else { - tagContainer->Update(ConvertFromModelIndices(tagIndices)); + tagContainer->Update(GetTagsFromModelIndices(tagIndices)); label->setText(QString("%1 %2").arg(tagIndices.size()).arg(tagIndices.size() == 1 ? singularTitle : pluralTitle)); widget->show(); } @@ -234,17 +234,23 @@ namespace O3DE::ProjectManager for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber) { QHBoxLayout* nameProgressLayout = new QHBoxLayout(); - TagWidget* newTag = new TagWidget(downloadQueue[downloadingGemNumber]); + + const QString& gemName = downloadQueue[downloadingGemNumber]; + TagWidget* newTag = new TagWidget({gemName, gemName}); nameProgressLayout->addWidget(newTag); + QLabel* progress = new QLabel(downloadingGemNumber == 0? QString("%1%").arg(downloadProgress) : tr("Queued")); nameProgressLayout->addWidget(progress); + QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel").arg(downloadQueue[downloadingGemNumber])); + + QLabel* cancelText = new QLabel(QString("Cancel")); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); downloadingItemLayout->addLayout(nameProgressLayout); + QProgressBar* downloadProgessBar = new QProgressBar(); downloadingItemLayout->addWidget(downloadProgessBar); downloadProgessBar->setValue(downloadingGemNumber == 0 ? downloadProgress : 0); @@ -255,7 +261,7 @@ namespace O3DE::ProjectManager } }; - auto downloadEnded = [=](bool /*success*/) + auto downloadEnded = [=](bool /*success*/, const QString& /*gemName*/) { update(0); // update the list to remove the gem that has finished }; @@ -265,15 +271,15 @@ namespace O3DE::ProjectManager update(0); } - QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector& gems) const + QVector CartOverlayWidget::GetTagsFromModelIndices(const QVector& gems) const { - QStringList gemNames; - gemNames.reserve(gems.size()); + QVector tags; + tags.reserve(gems.size()); for (const QModelIndex& modelIndex : gems) { - gemNames.push_back(GemModel::GetDisplayName(modelIndex)); + tags.push_back({ GemModel::GetDisplayName(modelIndex), GemModel::GetName(modelIndex) }); } - return gemNames; + return tags; } CartButton::CartButton(GemModel* gemModel, DownloadController* downloadController, QWidget* parent) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 4d17259840..6da78cce7a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -36,7 +36,7 @@ namespace O3DE::ProjectManager CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); private: - QStringList ConvertFromModelIndices(const QVector& gems) const; + QVector GetTagsFromModelIndices(const QVector& gems) const; using GetTagIndicesCallback = AZStd::function()>; void CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 4574e8509b..b0e4fa73e1 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -49,6 +49,7 @@ namespace O3DE::ProjectManager connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo); connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked); + connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); @@ -58,7 +59,7 @@ namespace O3DE::ProjectManager m_gemInspector = new GemInspector(m_gemModel, this); m_gemInspector->setFixedWidth(240); - connect(m_gemInspector, &GemInspector::TagClicked, this, &GemCatalogScreen::SelectGem); + connect(m_gemInspector, &GemInspector::TagClicked, [=](const Tag& tag) { SelectGem(tag.id); }); QWidget* filterWidget = new QWidget(this); filterWidget->setFixedWidth(240); @@ -86,6 +87,7 @@ namespace O3DE::ProjectManager void GemCatalogScreen::ReinitForProject(const QString& projectPath) { + m_projectPath = projectPath; m_gemModel->Clear(); m_gemsToRegisterWithProject.clear(); FillModel(projectPath); @@ -155,15 +157,15 @@ namespace O3DE::ProjectManager } } - void GemCatalogScreen::Refresh(const QString& projectPath) + void GemCatalogScreen::Refresh() { QHash gemInfoHash; // create a hash with the gem name as key - AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); + const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); if (allGemInfosResult.IsSuccess()) { - QVector gemInfos = allGemInfosResult.GetValue(); + const QVector& gemInfos = allGemInfosResult.GetValue(); for (const GemInfo& gemInfo : gemInfos) { gemInfoHash.insert(gemInfo.m_name, gemInfo); @@ -171,10 +173,10 @@ namespace O3DE::ProjectManager } // add all the gem repos into the hash - AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + const AZ::Outcome, AZStd::string>& allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); if (allRepoGemInfosResult.IsSuccess()) { - const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + const QVector& allRepoGemInfos = allRepoGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allRepoGemInfos) { if (!gemInfoHash.contains(gemInfo.m_name)) @@ -310,20 +312,22 @@ namespace O3DE::ProjectManager void GemCatalogScreen::FillModel(const QString& projectPath) { - AZ::Outcome, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); + m_projectPath = projectPath; + + const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath); if (allGemInfosResult.IsSuccess()) { // Add all available gems to the model. - const QVector allGemInfos = allGemInfosResult.GetValue(); + const QVector& allGemInfos = allGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allGemInfos) { m_gemModel->AddGem(gemInfo); } - AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + const AZ::Outcome, AZStd::string>& allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); if (allRepoGemInfosResult.IsSuccess()) { - const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + const QVector& allRepoGemInfos = allRepoGemInfosResult.GetValue(); for (const GemInfo& gemInfo : allRepoGemInfos) { // do not add gems that have already been downloaded @@ -342,10 +346,10 @@ namespace O3DE::ProjectManager m_notificationsEnabled = false; // Gather enabled gems for the given project. - auto enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath); + const auto& enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath); if (enabledGemNamesResult.IsSuccess()) { - const QVector enabledGemNames = enabledGemNamesResult.GetValue(); + const QVector& enabledGemNames = enabledGemNamesResult.GetValue(); for (const AZStd::string& enabledGemName : enabledGemNames) { const QModelIndex modelIndex = m_gemModel->FindIndexByNameString(enabledGemName.c_str()); @@ -405,12 +409,24 @@ namespace O3DE::ProjectManager for (const QModelIndex& modelIndex : toBeAdded) { - const QString gemPath = GemModel::GetPath(modelIndex); + const QString& gemPath = GemModel::GetPath(modelIndex); + + // make sure any remote gems we added were downloaded successfully + if (GemModel::GetGemOrigin(modelIndex) == GemInfo::Remote && GemModel::GetDownloadStatus(modelIndex) != GemInfo::Downloaded) + { + QMessageBox::critical( + nullptr, "Cannot add gem that isn't downloaded", + tr("Cannot add gem %1 to project because it isn't downloaded yet or failed to download.") + .arg(GemModel::GetDisplayName(modelIndex))); + + return EnableDisableGemsResult::Failed; + } + const AZ::Outcome result = pythonBindings->AddGemToProject(gemPath, projectPath); if (!result.IsSuccess()) { - QMessageBox::critical(nullptr, "Operation failed", - QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); + QMessageBox::critical(nullptr, "Failed to add gem to project", + tr("Cannot add gem %1 to project.

Error:
%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); return EnableDisableGemsResult::Failed; } @@ -428,8 +444,8 @@ namespace O3DE::ProjectManager const AZ::Outcome result = pythonBindings->RemoveGemFromProject(gemPath, projectPath); if (!result.IsSuccess()) { - QMessageBox::critical(nullptr, "Operation failed", - QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); + QMessageBox::critical(nullptr, "Failed to remove gem from project", + tr("Cannot remove gem %1 from project.

Error:
%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); return EnableDisableGemsResult::Failed; } @@ -443,6 +459,34 @@ namespace O3DE::ProjectManager emit ChangeScreenRequest(ProjectManagerScreen::GemRepos); } + void GemCatalogScreen::OnGemDownloadResult(bool succeeded, const QString& gemName) + { + if (succeeded) + { + // refresh the information for downloaded gems + const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); + if (allGemInfosResult.IsSuccess()) + { + // we should find the gem name now in all gem infos + for (const GemInfo& gemInfo : allGemInfosResult.GetValue()) + { + if (gemInfo.m_name == gemName) + { + QModelIndex index = m_gemModel->FindIndexByNameString(gemName); + if (index.isValid()) + { + m_gemModel->setData(index, GemInfo::Downloaded, GemModel::RoleDownloadStatus); + m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath); + m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink); + } + + return; + } + } + } + } + } + ProjectManagerScreen GemCatalogScreen::GetScreenEnum() { return ProjectManagerScreen::GemCatalog; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 69ec85586d..6acf43b3eb 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -33,7 +33,6 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetScreenEnum() override; void ReinitForProject(const QString& projectPath); - void Refresh(const QString& projectPath); enum class EnableDisableGemsResult { @@ -50,6 +49,8 @@ namespace O3DE::ProjectManager void OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); void OnAddGemClicked(); void SelectGem(const QString& gemName); + void OnGemDownloadResult(bool succeeded, const QString& gemName); + void Refresh(); protected: void hideEvent(QHideEvent* event) override; @@ -76,5 +77,6 @@ namespace O3DE::ProjectManager DownloadController* m_downloadController = nullptr; bool m_notificationsEnabled = true; QSet m_gemsToRegisterWithProject; + QString m_projectPath = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index b0b8cca29a..afbac189ad 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -106,10 +106,10 @@ namespace O3DE::ProjectManager } // Depending gems - QStringList dependingGems = m_model->GetDependingGemNames(modelIndex); - if (!dependingGems.isEmpty()) + const QVector& dependingGemTags = m_model->GetDependingGemTags(modelIndex); + if (!dependingGemTags.isEmpty()) { - m_dependingGems->Update(tr("Depending Gems"), tr("The following Gems will be automatically enabled with this Gem."), dependingGems); + m_dependingGems->Update(tr("Depending Gems"), tr("The following Gems will be automatically enabled with this Gem."), dependingGemTags); m_dependingGems->show(); } else @@ -222,7 +222,7 @@ namespace O3DE::ProjectManager // Depending gems m_dependingGems = new GemsSubWidget(); - connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); }); + connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [=](const Tag& tag){ emit TagClicked(tag); }); m_mainLayout->addWidget(m_dependingGems); m_mainLayout->addSpacing(20); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h index c6548527ab..9a6ad84dea 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h @@ -44,7 +44,7 @@ namespace O3DE::ProjectManager inline constexpr static const char* s_textColor = "#DDDDDD"; signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); private slots: void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 7c217db65b..88c54de0b3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -65,7 +65,6 @@ namespace O3DE::ProjectManager appendRow(item); const QModelIndex modelIndex = index(rowCount()-1, 0); - m_nameToIndexMap[gemInfo.m_displayName] = modelIndex; m_nameToIndexMap[gemInfo.m_name] = modelIndex; } @@ -178,18 +177,6 @@ namespace O3DE::ProjectManager return {}; } - void GemModel::FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames) - { - for (QString& name : inOutGemNames) - { - QModelIndex modelIndex = FindIndexByNameString(name); - if (modelIndex.isValid()) - { - name = GetDisplayName(modelIndex); - } - } - } - QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex) { return modelIndex.data(RoleDependingGems).toStringList(); @@ -209,16 +196,23 @@ namespace O3DE::ProjectManager } } - QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex) + QVector GemModel::GetDependingGemTags(const QModelIndex& modelIndex) { - QStringList result = GetDependingGems(modelIndex); - if (result.isEmpty()) + QVector tags; + + QStringList dependingGemNames = GetDependingGems(modelIndex); + tags.reserve(dependingGemNames.size()); + + for (QString& gemName : dependingGemNames) { - return {}; + const QModelIndex& dependingIndex = FindIndexByNameString(gemName); + if (dependingIndex.isValid()) + { + tags.push_back({ GetDisplayName(dependingIndex), GetName(dependingIndex) }); + } } - FindGemDisplayNamesByNameStrings(result); - return result; + return tags; } QString GemModel::GetVersion(const QModelIndex& modelIndex) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index e548d9d3f7..e25a1c7703 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -10,6 +10,7 @@ #if !defined(Q_MOC_RUN) #include +#include #include #include #include @@ -58,7 +59,7 @@ namespace O3DE::ProjectManager void UpdateGemDependencies(); QModelIndex FindIndexByNameString(const QString& nameString) const; - QStringList GetDependingGemNames(const QModelIndex& modelIndex); + QVector GetDependingGemTags(const QModelIndex& modelIndex); bool HasDependentGems(const QModelIndex& modelIndex) const; static QString GetName(const QModelIndex& modelIndex); @@ -113,7 +114,6 @@ namespace O3DE::ProjectManager void OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last); private: - void FindGemDisplayNamesByNameStrings(QStringList& inOutGemNames); void GetAllDependingGems(const QModelIndex& modelIndex, QSet& inOutGems); QStringList GetDependingGems(const QModelIndex& modelIndex); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp index 6655aef86d..f816e86733 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInspector.cpp @@ -86,7 +86,7 @@ namespace O3DE::ProjectManager } // Included Gems - m_includedGems->Update(tr("Included Gems"), "", m_model->GetIncludedGemNames(modelIndex)); + m_includedGems->Update(tr("Included Gems"), "", m_model->GetIncludedGemTags(modelIndex)); m_mainWidget->adjustSize(); m_mainWidget->show(); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp index 7a9617e6c1..6189b6d8bf 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp @@ -103,17 +103,17 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleIncludedGems).toStringList(); } - QStringList GemRepoModel::GetIncludedGemNames(const QModelIndex& modelIndex) + QVector GemRepoModel::GetIncludedGemTags(const QModelIndex& modelIndex) { - QStringList gemNames; - QVector gemInfos = GetIncludedGemInfos(modelIndex); - + QVector tags; + const QVector& gemInfos = GetIncludedGemInfos(modelIndex); + tags.reserve(gemInfos.size()); for (const GemInfo& gemInfo : gemInfos) { - gemNames.append(gemInfo.m_displayName); + tags.append({ gemInfo.m_displayName, gemInfo.m_name }); } - return gemNames; + return tags; } QVector GemRepoModel::GetIncludedGemInfos(const QModelIndex& modelIndex) diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h index f36b66ca48..66fe972a95 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h @@ -40,7 +40,7 @@ namespace O3DE::ProjectManager static QString GetPath(const QModelIndex& modelIndex); static QStringList GetIncludedGemPaths(const QModelIndex& modelIndex); - static QStringList GetIncludedGemNames(const QModelIndex& modelIndex); + static QVector GetIncludedGemTags(const QModelIndex& modelIndex); static QVector GetIncludedGemInfos(const QModelIndex& modelIndex); static bool IsEnabled(const QModelIndex& modelIndex); diff --git a/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp b/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp index 8b7b183008..2572a39db3 100644 --- a/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemsSubWidget.cpp @@ -33,14 +33,14 @@ namespace O3DE::ProjectManager m_layout->addWidget(m_textLabel); m_tagWidget = new TagContainerWidget(); - connect(m_tagWidget, &TagContainerWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); }); + connect(m_tagWidget, &TagContainerWidget::TagClicked, this, [=](const Tag& tag){ emit TagClicked(tag); }); m_layout->addWidget(m_tagWidget); } - void GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames) + void GemsSubWidget::Update(const QString& title, const QString& text, const QVector& tags) { m_titleLabel->setText(title); m_textLabel->setText(text); - m_tagWidget->Update(gemNames); + m_tagWidget->Update(tags); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemsSubWidget.h b/Code/Tools/ProjectManager/Source/GemsSubWidget.h index a9fabf5e92..5e670b930a 100644 --- a/Code/Tools/ProjectManager/Source/GemsSubWidget.h +++ b/Code/Tools/ProjectManager/Source/GemsSubWidget.h @@ -26,10 +26,10 @@ namespace O3DE::ProjectManager public: GemsSubWidget(QWidget* parent = nullptr); - void Update(const QString& title, const QString& text, const QStringList& gemNames); + void Update(const QString& title, const QString& text, const QVector& tags); signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); private: QLabel* m_titleLabel = nullptr; diff --git a/Code/Tools/ProjectManager/Source/TagWidget.cpp b/Code/Tools/ProjectManager/Source/TagWidget.cpp index 39231ace4b..007f0839d1 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.cpp +++ b/Code/Tools/ProjectManager/Source/TagWidget.cpp @@ -12,15 +12,16 @@ namespace O3DE::ProjectManager { - TagWidget::TagWidget(const QString& text, QWidget* parent) - : QLabel(text, parent) + TagWidget::TagWidget(const Tag& tag, QWidget* parent) + : QLabel(tag.text, parent) + , m_tag(tag) { setObjectName("TagWidget"); } void TagWidget::mousePressEvent([[maybe_unused]] QMouseEvent* event) { - emit(TagClicked(text())); + emit TagClicked(m_tag); } TagContainerWidget::TagContainerWidget(QWidget* parent) @@ -39,20 +40,34 @@ namespace O3DE::ProjectManager void TagContainerWidget::Update(const QStringList& tags) { - FlowLayout* flowLayout = static_cast(layout()); + Clear(); - // remove old tags - QLayoutItem* layoutItem = nullptr; - while ((layoutItem = layout()->takeAt(0)) != nullptr) + foreach (const QString& tag, tags) { - layoutItem->widget()->deleteLater(); + TagWidget* tagWidget = new TagWidget({tag, tag}); + connect(tagWidget, &TagWidget::TagClicked, this, [=](const Tag& clickedTag){ emit TagClicked(clickedTag); }); + layout()->addWidget(tagWidget); } + } - foreach (const QString& tag, tags) + void TagContainerWidget::Update(const QVector& tags) + { + Clear(); + + foreach (const Tag& tag, tags) { TagWidget* tagWidget = new TagWidget(tag); - connect(tagWidget, &TagWidget::TagClicked, this, [=](const QString& tag){ emit TagClicked(tag); }); - flowLayout->addWidget(tagWidget); + connect(tagWidget, &TagWidget::TagClicked, this, [=](const Tag& clickedTag){ emit TagClicked(clickedTag); }); + layout()->addWidget(tagWidget); + } + } + + void TagContainerWidget::Clear() + { + QLayoutItem* layoutItem = nullptr; + while ((layoutItem = layout()->takeAt(0)) != nullptr) + { + layoutItem->widget()->deleteLater(); } } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TagWidget.h b/Code/Tools/ProjectManager/Source/TagWidget.h index 7b4a5b1aaa..fce6eaf863 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.h +++ b/Code/Tools/ProjectManager/Source/TagWidget.h @@ -10,12 +10,19 @@ #if !defined(Q_MOC_RUN) #include -#include #include +#include +#include #endif namespace O3DE::ProjectManager { + struct Tag + { + QString text; + QString id; + }; + // Single tag class TagWidget : public QLabel @@ -23,14 +30,17 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit TagWidget(const QString& text, QWidget* parent = nullptr); + explicit TagWidget(const Tag& id, QWidget* parent = nullptr); ~TagWidget() = default; signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); protected: void mousePressEvent(QMouseEvent* event) override; + + private: + Tag m_tag; }; // Widget containing multiple tags, automatically wrapping based on the size @@ -43,9 +53,13 @@ namespace O3DE::ProjectManager explicit TagContainerWidget(QWidget* parent = nullptr); ~TagContainerWidget() = default; + void Update(const QVector& tags); void Update(const QStringList& tags); signals: - void TagClicked(const QString& tag); + void TagClicked(const Tag& tag); + + private: + void Clear(); }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index e76b4093a9..fb16484961 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -43,7 +43,7 @@ namespace O3DE::ProjectManager m_gemRepoScreen = new GemRepoScreen(this); connect(m_gemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest); - connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, [this](){ m_gemCatalogScreen->Refresh(m_projectInfo.m_path); }); + connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, m_gemCatalogScreen, &GemCatalogScreen::Refresh); m_stack = new QStackedWidget(this); m_stack->setObjectName("body"); @@ -163,6 +163,7 @@ namespace O3DE::ProjectManager QMessageBox::critical(this, tr("Gems downloading"), tr("You must wait for gems to finish downloading before continuing.")); return; } + // Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project. const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); if (result == GemCatalogScreen::EnableDisableGemsResult::Failed) diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h index 5fef296ee7..ee6fc792f2 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h @@ -26,6 +26,7 @@ namespace O3DE::ProjectManager class UpdateProjectCtrl : public ScreenWidget { + Q_OBJECT public: explicit UpdateProjectCtrl(QWidget* parent = nullptr); ~UpdateProjectCtrl() = default; From 21c02b195f9e5ee39b6e9d90aa8a41a69a50a7dd Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:24:08 -0700 Subject: [PATCH 21/66] Update signals/slots to match upstream changes Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/DownloadController.cpp | 6 +++--- Code/Tools/ProjectManager/Source/DownloadController.h | 2 +- .../Source/GemCatalog/GemCatalogHeaderWidget.cpp | 2 +- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 2 +- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp index a8eecffd78..d30e1bbc7c 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.cpp +++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp @@ -82,13 +82,13 @@ namespace O3DE::ProjectManager succeeded = false; } - const QString gemName = m_gemNames[0]; + QString gemName = m_gemNames.front(); m_gemNames.erase(m_gemNames.begin()); - emit Done(succeeded, gemName); + emit Done(gemName, succeeded); if (!m_gemNames.empty()) { - emit StartGemDownload(m_gemNames[0]); + emit StartGemDownload(m_gemNames.front()); } else { diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h index 8afe8ef029..5b2d230379 100644 --- a/Code/Tools/ProjectManager/Source/DownloadController.h +++ b/Code/Tools/ProjectManager/Source/DownloadController.h @@ -58,7 +58,7 @@ namespace O3DE::ProjectManager signals: void StartGemDownload(const QString& gemName); - void Done(bool success, const QString& gemName); + void Done(const QString& gemName, bool success = true); void GemDownloadProgress(int percentage); private: diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 0db2b088c1..71d5086fff 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -261,7 +261,7 @@ namespace O3DE::ProjectManager } }; - auto downloadEnded = [=](bool /*success*/, const QString& /*gemName*/) + auto downloadEnded = [=](const QString& /*gemName*/, bool /*success*/) { update(0); // update the list to remove the gem that has finished }; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index b0e4fa73e1..79935ed235 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -459,7 +459,7 @@ namespace O3DE::ProjectManager emit ChangeScreenRequest(ProjectManagerScreen::GemRepos); } - void GemCatalogScreen::OnGemDownloadResult(bool succeeded, const QString& gemName) + void GemCatalogScreen::OnGemDownloadResult(const QString& gemName, bool succeeded) { if (succeeded) { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 6acf43b3eb..da6d2efa7b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -49,7 +49,7 @@ namespace O3DE::ProjectManager void OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies); void OnAddGemClicked(); void SelectGem(const QString& gemName); - void OnGemDownloadResult(bool succeeded, const QString& gemName); + void OnGemDownloadResult(const QString& gemName, bool succeeded = true); void Refresh(); protected: From 0295aa7070154d53c00b8ac4680d23ebb9a4e202 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:31:01 -0700 Subject: [PATCH 22/66] revert change to cancel label href Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 71d5086fff..8c875e4846 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -245,7 +245,7 @@ namespace O3DE::ProjectManager QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); nameProgressLayout->addSpacerItem(spacer); - QLabel* cancelText = new QLabel(QString("Cancel")); + QLabel* cancelText = new QLabel(QString("Cancel").arg(gemName)); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); From 9481f8a488ec26196ae7a04f4ba2b5b114e6e857 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 5 Nov 2021 23:39:34 -0700 Subject: [PATCH 23/66] Updated 002_wrinkle_regression_test.material to avoid subsurface scattering artifacts. Having subsurface scattering into a completely back area is an unrealistic scenario and caused colored artifacts. I changed the material to mask out the black areas from applying SS. Corresponding changes will be made to the expceted screenshot in AtomSampleViewer as well. Note these artifacts were originally introduced at commit 19638c4697a2e95bcb9b12badd82980e92b4c5ac Fri Jul 2 01:18:09 where SS was fixed to work again where it bad previously been broken and didn't show up in this test case. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../SkinTestCases/002_wrinkle_regression_test.material | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material index 400044d29f..78f597b14f 100644 --- a/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material +++ b/Gems/Atom/TestData/TestData/Materials/SkinTestCases/002_wrinkle_regression_test.material @@ -33,7 +33,7 @@ }, "subsurfaceScattering": { "enableSubsurfaceScattering": true, - "influenceMap": "Objects/Lucy/Lucy_thickness.tif", + "influenceMap": "TestData/Textures/checker8x8_gray_512.png", "scatterDistance": 15.0, "subsurfaceScatterFactor": 0.4300000071525574, "thicknessMap": "Objects/Lucy/Lucy_thickness.tif", @@ -47,8 +47,7 @@ 0.3182879388332367, 0.16388189792633058, 1.0 - ], - "useInfluenceMap": false + ] }, "wrinkleLayers": { "baseColorMap1": "TestData/Textures/cc0/Lava004_1K_Color.jpg", @@ -61,4 +60,4 @@ "normalMap2": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_normal.png" } } -} +} \ No newline at end of file From 00cf9ebfd801b0fde709fdda3b9fe6219d1deefd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 7 Nov 2021 18:36:38 -0600 Subject: [PATCH 24/66] Queuing inspector invalidate all to boost performance opening/closing several documents Signed-off-by: Guthrie Adams --- .../Code/Source/Inspector/InspectorPropertyGroupWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp index 6b9aee17f7..af71954737 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorPropertyGroupWidget.cpp @@ -43,7 +43,7 @@ namespace AtomToolsFramework m_propertyEditor->Setup(context, instanceNotificationHandler, false); m_propertyEditor->AddInstance(instance, instanceClassId, nullptr, instanceToCompare); m_propertyEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - m_propertyEditor->InvalidateAll(); + m_propertyEditor->QueueInvalidation(AzToolsFramework::PropertyModificationRefreshLevel::Refresh_EntireTree); m_layout->addWidget(m_propertyEditor); setLayout(m_layout); From 14a120627415a0b295ba4d486b00467d71540b55 Mon Sep 17 00:00:00 2001 From: nggieber Date: Mon, 8 Nov 2021 08:17:28 -0800 Subject: [PATCH 25/66] Add additional info handling and proper display for gems Signed-off-by: nggieber --- .../Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp | 3 ++- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index b0b8cca29a..6c61e280f3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -120,7 +120,8 @@ namespace O3DE::ProjectManager // Additional information m_versionLabel->setText(tr("Gem Version: %1").arg(m_model->GetVersion(modelIndex))); m_lastUpdatedLabel->setText(tr("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex))); - m_binarySizeLabel->setText(tr("Binary Size: %1 KB").arg(m_model->GetBinarySizeInKB(modelIndex))); + const int binarySize = m_model->GetBinarySizeInKB(modelIndex); + m_binarySizeLabel->setText(tr("Binary Size: %1").arg(binarySize ? tr("%1 KB").arg(binarySize) : tr("Unknown"))); m_mainWidget->adjustSize(); m_mainWidget->show(); diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 905139a4f2..4a73b39ea0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -53,6 +53,8 @@ namespace Platform #define Py_To_String(obj) pybind11::str(obj).cast().c_str() #define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string +#define Py_To_Int(obj) obj.cast() +#define Py_To_Int_Optional(dict, key, default_int) dict.contains(key) ? Py_To_Int(dict[key]) : default_int #define QString_To_Py_String(value) pybind11::str(value.toStdString()) #define QString_To_Py_Path(value) m_pathlib.attr("Path")(value.toStdString()) @@ -705,7 +707,9 @@ namespace O3DE::ProjectManager // optional gemInfo.m_displayName = Py_To_String_Optional(data, "display_name", gemInfo.m_name); gemInfo.m_summary = Py_To_String_Optional(data, "summary", ""); - gemInfo.m_version = ""; + gemInfo.m_version = Py_To_String_Optional(data, "version", gemInfo.m_version); + gemInfo.m_lastUpdatedDate = Py_To_String_Optional(data, "last_updated", gemInfo.m_lastUpdatedDate); + gemInfo.m_binarySizeInKB = Py_To_Int_Optional(data, "binary_size", gemInfo.m_binarySizeInKB); gemInfo.m_requirement = Py_To_String_Optional(data, "requirements", ""); gemInfo.m_creator = Py_To_String_Optional(data, "origin", ""); gemInfo.m_documentationLink = Py_To_String_Optional(data, "documentation_url", ""); From 97bb01122fd0c02b5ba354ad41ba58dffaee873f Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 8 Nov 2021 11:01:02 -0600 Subject: [PATCH 26/66] Add missing runtime dependency to atom ly integration Signed-off-by: Guthrie Adams --- Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt index 95331a2f3f..7b685ece13 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt @@ -111,6 +111,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::Atom_RPI.Editor Gem::Atom_Feature_Common.Editor + Gem::AtomToolsFramework.Editor Legacy::EditorCommon ) From fe005c9c5050cd2e87ecf14719b0f03216ea2e9f Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Mon, 8 Nov 2021 16:11:30 -0700 Subject: [PATCH 27/66] Added exposure controls to the ReflectionProbe component Signed-off-by: dmcdiar --- .../Atom/Features/PBR/DefaultObjectSrg.azsli | 1 + .../Atom/Features/PBR/Lights/Ibl.azsli | 6 +++--- .../Atom/Features/Skin/SkinObjectSrg.azsli | 1 + .../ReflectionProbeRenderInner.azsl | 2 +- .../ReflectionProbeRenderObjectSrg.azsli | 1 + .../ReflectionProbeRenderOuter.azsl | 2 +- .../ReflectionProbeFeatureProcessor.h | 2 ++ ...ReflectionProbeFeatureProcessorInterface.h | 2 ++ .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 4 ++++ .../ReflectionProbe/ReflectionProbe.cpp | 17 ++++++++++++++-- .../Source/ReflectionProbe/ReflectionProbe.h | 11 ++++++++++ .../ReflectionProbeFeatureProcessor.cpp | 12 +++++++++++ .../EditorReflectionProbeComponent.cpp | 20 +++++++++++++++++++ .../EditorReflectionProbeComponent.h | 2 ++ .../ReflectionProbeComponentController.cpp | 19 ++++++++++++++++-- .../ReflectionProbeComponentController.h | 6 ++++++ 16 files changed, 99 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli index 10526597cb..9f40e7ab8f 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/DefaultObjectSrg.azsli @@ -37,6 +37,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_padding; bool m_useReflectionProbe; bool m_useParallaxCorrection; + float m_exposure; }; ReflectionProbeData m_reflectionProbeData; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli index d33a307dfe..31439de144 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli @@ -85,12 +85,12 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) if(useIbl) { - float iblExposureFactor = pow(2.0, SceneSrg::m_iblExposure); + float exposure = pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure); if(useDiffuseIbl) { float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse); - lightingData.diffuseLighting += (iblDiffuse * iblExposureFactor * lightingData.diffuseAmbientOcclusion); + lightingData.diffuseLighting += (iblDiffuse * exposure * lightingData.diffuseAmbientOcclusion); } if(useSpecularIbl) @@ -116,7 +116,7 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular; } - lightingData.specularLighting += (iblSpecular * iblExposureFactor); + lightingData.specularLighting += (iblSpecular * exposure); } } } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli index d0766c295d..99a32629ef 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Skin/SkinObjectSrg.azsli @@ -46,6 +46,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_padding; bool m_useReflectionProbe; bool m_useParallaxCorrection; + float m_exposure; }; ReflectionProbeData m_reflectionProbeData; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl index a0734caf02..e9333a4694 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderInner.azsl @@ -81,7 +81,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) } // apply exposure setting - specular *= pow(2.0, SceneSrg::m_iblExposure); + specular *= pow(2.0, ObjectSrg::m_exposure); PSOutput OUT; OUT.m_color = float4(specular, 1.0f); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli index 8151ed2fd5..366dc691ed 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderObjectSrg.azsli @@ -17,6 +17,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float3 m_outerObbHalfLengths; float3 m_innerObbHalfLengths; bool m_useParallaxCorrection; + float m_exposure; TextureCube m_reflectionCubeMap; float4x4 GetWorldMatrix() diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl index ac97172f1f..138d29398e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionProbeRenderOuter.azsl @@ -104,7 +104,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) blendWeight /= max(1.0f, blendWeightAllProbes); // apply exposure setting - specular *= pow(2.0, SceneSrg::m_iblExposure); + specular *= pow(2.0, ObjectSrg::m_exposure); // apply blend weight for additive blending specular *= blendWeight; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h index 5efd235a67..ded36f5496 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessor.h @@ -39,6 +39,8 @@ namespace AZ bool IsCubeMapReferenced(const AZStd::string& relativePath) override; bool IsValidProbeHandle(const ReflectionProbeHandle& probe) const override { return (probe.get() != nullptr); } void ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization) override; + void SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) override; + void SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) override; // FeatureProcessor overrides void Activate() override; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h index 4eb2130b1b..80c92281ea 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ReflectionProbe/ReflectionProbeFeatureProcessorInterface.h @@ -50,6 +50,8 @@ namespace AZ virtual bool IsCubeMapReferenced(const AZStd::string& relativePath) = 0; virtual bool IsValidProbeHandle(const ReflectionProbeHandle& probe) const = 0; virtual void ShowProbeVisualization(const ReflectionProbeHandle& probe, bool showVisualization) = 0; + virtual void SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) = 0; + virtual void SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index c7fb19bc5d..99f01ea630 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -1178,6 +1178,9 @@ namespace AZ AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection")); AZ_Error("MeshDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure")); + AZ_Error("MeshDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index"); + // retrieve probe cubemap index Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap"); RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = m_shaderResourceGroup->FindShaderInputImageIndex(reflectionCubeMapImageName); @@ -1198,6 +1201,7 @@ namespace AZ m_shaderResourceGroup->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbes[0]->GetInnerObbWs().GetHalfLengths()); m_shaderResourceGroup->SetConstant(useReflectionProbeConstantIndex, true); m_shaderResourceGroup->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbes[0]->GetUseParallaxCorrection()); + m_shaderResourceGroup->SetConstant(exposureConstantIndex, reflectionProbes[0]->GetRenderExposure()); m_shaderResourceGroup->SetImage(reflectionCubeMapImageIndex, reflectionProbes[0]->GetCubeMapImage()); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp index e86d91d387..c4ea3249d5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp @@ -127,8 +127,8 @@ namespace AZ } else { - // set exposure to 0.0 while baking the cubemap - sceneSrg->SetConstant(m_iblExposureConstantIndex, 0.0f); + // set exposure to the user specified value while baking the cubemap + sceneSrg->SetConstant(m_iblExposureConstantIndex, m_bakeExposure); } } @@ -162,6 +162,7 @@ namespace AZ m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths()); m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths()); m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection); + m_renderOuterSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure); m_renderOuterSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage); m_renderOuterSrg->Compile(); @@ -172,6 +173,7 @@ namespace AZ m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_outerObbHalfLengthsRenderConstantIndex, m_outerObbWs.GetHalfLengths()); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_innerObbHalfLengthsRenderConstantIndex, m_innerObbWs.GetHalfLengths()); m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_useParallaxCorrectionRenderConstantIndex, m_useParallaxCorrection); + m_renderInnerSrg->SetConstant(m_reflectionRenderData->m_exposureConstantIndex, m_renderExposure); m_renderInnerSrg->SetImage(m_reflectionRenderData->m_reflectionCubeMapRenderImageIndex, m_cubeMapImage); m_renderInnerSrg->Compile(); @@ -326,6 +328,17 @@ namespace AZ m_meshFeatureProcessor->SetVisible(m_visualizationMeshHandle, showVisualization); } + void ReflectionProbe::SetRenderExposure(float renderExposure) + { + m_renderExposure = renderExposure; + m_updateSrg = true; + } + + void ReflectionProbe::SetBakeExposure(float bakeExposure) + { + m_bakeExposure = bakeExposure; + } + const RHI::DrawPacket* ReflectionProbe::BuildDrawPacket( const Data::Instance& srg, const RPI::Ptr& pipelineState, diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h index bee304c5b9..485f380463 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h @@ -61,6 +61,7 @@ namespace AZ RHI::ShaderInputNameIndex m_outerObbHalfLengthsRenderConstantIndex = "m_outerObbHalfLengths"; RHI::ShaderInputNameIndex m_innerObbHalfLengthsRenderConstantIndex = "m_innerObbHalfLengths"; RHI::ShaderInputNameIndex m_useParallaxCorrectionRenderConstantIndex = "m_useParallaxCorrection"; + RHI::ShaderInputNameIndex m_exposureConstantIndex = "m_exposure"; RHI::ShaderInputNameIndex m_reflectionCubeMapRenderImageIndex = "m_reflectionCubeMap"; }; @@ -106,6 +107,14 @@ namespace AZ // enables or disables rendering of the visualization sphere void ShowVisualization(bool showVisualization); + // the exposure to use when rendering meshes with this probe's cubemap + void SetRenderExposure(float renderExposure); + float GetRenderExposure() const { return m_renderExposure; } + + // the exposure to use when baking the probe cubemap + void SetBakeExposure(float bakeExposure); + float GetBakeExposure() const { return m_bakeExposure; } + private: AZ_DISABLE_COPY_MOVE(ReflectionProbe); @@ -157,6 +166,8 @@ namespace AZ RHI::ConstPtr m_blendWeightDrawPacket; RHI::ConstPtr m_renderOuterDrawPacket; RHI::ConstPtr m_renderInnerDrawPacket; + float m_renderExposure = 0.0f; + float m_bakeExposure = 0.0f; bool m_updateSrg = false; const RHI::DrawItemSortKey InvalidSortKey = static_cast(-1); diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index 52d089ae0d..b1484ac8a8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -283,6 +283,18 @@ namespace AZ probe->ShowVisualization(showVisualization); } + void ReflectionProbeFeatureProcessor::SetRenderExposure(const ReflectionProbeHandle& probe, float renderExposure) + { + AZ_Assert(probe.get(), "SetRenderExposure called with an invalid handle"); + probe->SetRenderExposure(renderExposure); + } + + void ReflectionProbeFeatureProcessor::SetBakeExposure(const ReflectionProbeHandle& probe, float bakeExposure) + { + AZ_Assert(probe.get(), "SetBakeExposure called with an invalid handle"); + probe->SetBakeExposure(bakeExposure); + } + void ReflectionProbeFeatureProcessor::FindReflectionProbes(const Vector3& position, ReflectionProbeVector& reflectionProbes) { reflectionProbes.clear(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index 99e99abf4a..c14d2c320a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -40,6 +40,7 @@ namespace AZ ->Field("bakedCubeMapQualityLevel", &EditorReflectionProbeComponent::m_bakedCubeMapQualityLevel) ->Field("bakedCubeMapRelativePath", &EditorReflectionProbeComponent::m_bakedCubeMapRelativePath) ->Field("authoredCubeMapAsset", &EditorReflectionProbeComponent::m_authoredCubeMapAsset) + ->Field("bakeExposure", &EditorReflectionProbeComponent::m_bakeExposure) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -62,6 +63,13 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ButtonText, "Bake Reflection Probe") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::BakeReflectionProbe) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) + ->DataElement(AZ::Edit::UIHandlers::Slider, &EditorReflectionProbeComponent::m_bakeExposure, "Bake Exposure", "Exposure to use when baking the cubemap") + ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) + ->Attribute(AZ::Edit::Attributes::Min, -20.0f) + ->Attribute(AZ::Edit::Attributes::Max, 20.0f) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnBakeExposureChanged) + ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) ->ClassElement(AZ::Edit::ClassElements::Group, "Cubemap") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &EditorReflectionProbeComponent::m_useBakedCubemap, "Use Baked Cubemap", "Selects between a cubemap that captures the environment at location in the scene or a preauthored cubemap") @@ -111,6 +119,11 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement(AZ::Edit::UIHandlers::CheckBox, &ReflectionProbeComponentConfig::m_showVisualization, "Show Visualization", "Show the reflection probe visualization sphere") ->Attribute(AZ::Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->DataElement(AZ::Edit::UIHandlers::Slider, &ReflectionProbeComponentConfig::m_renderExposure, "Exposure", "Exposure to use when rendering meshes with the cubemap") + ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) + ->Attribute(AZ::Edit::Attributes::Min, -20.0f) + ->Attribute(AZ::Edit::Attributes::Max, 20.0f) ; } } @@ -275,6 +288,13 @@ namespace AZ return AZ::Edit::PropertyRefreshLevels::None; } + AZ::u32 EditorReflectionProbeComponent::OnBakeExposureChanged() + { + m_controller.SetBakeExposure(m_bakeExposure); + + return AZ::Edit::PropertyRefreshLevels::None; + } + AZ::u32 EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting() { // controls specific to baked cubemaps call this to determine their visibility diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h index 441da19e78..3cd017fd18 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.h @@ -55,6 +55,7 @@ namespace AZ // change notifications AZ::u32 OnUseBakedCubemapChanged(); AZ::u32 OnAuthoredCubemapChanged(); + AZ::u32 OnBakeExposureChanged(); // retrieves visibility for baked or authored cubemap controls AZ::u32 GetBakedCubemapVisibilitySetting(); @@ -77,6 +78,7 @@ namespace AZ AZStd::string m_bakedCubeMapRelativePath; Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; + float m_bakeExposure = 0.0f; // flag indicating if a cubemap bake is currently in progress AZStd::atomic_bool m_bakeInProgress = false; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp index 4022dfda9b..017f6c9cdf 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.cpp @@ -35,7 +35,7 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("OuterHeight", &ReflectionProbeComponentConfig::m_outerHeight) ->Field("OuterLength", &ReflectionProbeComponentConfig::m_outerLength) ->Field("OuterWidth", &ReflectionProbeComponentConfig::m_outerWidth) @@ -49,7 +49,9 @@ namespace AZ ->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset) ->Field("EntityId", &ReflectionProbeComponentConfig::m_entityId) ->Field("UseParallaxCorrection", &ReflectionProbeComponentConfig::m_useParallaxCorrection) - ->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization); + ->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization) + ->Field("RenderExposure", &ReflectionProbeComponentConfig::m_renderExposure) + ->Field("BakeExposure", &ReflectionProbeComponentConfig::m_bakeExposure); } } @@ -157,6 +159,9 @@ namespace AZ cubeMapAsset.QueueLoad(); Data::AssetBus::MultiHandler::BusConnect(cubeMapAsset.GetId()); } + + // set cubemap render exposure + m_featureProcessor->SetRenderExposure(m_handle, m_configuration.m_renderExposure); } void ReflectionProbeComponentController::Deactivate() @@ -284,6 +289,16 @@ namespace AZ m_configuration.m_innerHeight = AZStd::min(m_configuration.m_innerHeight, m_configuration.m_outerHeight); } + void ReflectionProbeComponentController::SetBakeExposure(float bakeExposure) + { + if (!m_featureProcessor) + { + return; + } + + m_featureProcessor->SetBakeExposure(m_handle, bakeExposure); + } + void ReflectionProbeComponentController::BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath) { if (!m_featureProcessor) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h index 18e13f023b..ad7d9f7f53 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/ReflectionProbeComponentController.h @@ -68,6 +68,9 @@ namespace AZ Data::Asset m_bakedCubeMapAsset; Data::Asset m_authoredCubeMapAsset; AZ::u64 m_entityId{ EntityId::InvalidEntityId }; + + float m_renderExposure = 0.0f; + float m_bakeExposure = 0.0f; }; class ReflectionProbeComponentController final @@ -99,6 +102,9 @@ namespace AZ // returns the outer extent Aabb for this reflection AZ::Aabb GetAabb() const; + // set the exposure to use when baking the cubemap + void SetBakeExposure(float bakeExposure); + // initiate the reflection probe bake, invokes callback when complete void BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath); From 898b1811e0be97b50e9b7845803765fda0635d5f Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 21 Oct 2021 16:04:38 -0500 Subject: [PATCH 28/66] material editor loads source data Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 25 ++- .../RPI.Edit/Material/MaterialSourceData.cpp | 167 +++++++++++++----- .../Material/MaterialTypeAssetCreator.cpp | 1 + .../Code/Source/Document/MaterialDocument.cpp | 2 +- 4 files changed, 151 insertions(+), 44 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index a67477f061..739c4341a9 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -31,6 +31,7 @@ namespace AZ static constexpr const char UvGroupName[] = "uvSets"; class MaterialAsset; + class MaterialAssetCreator; //! This is a simple data structure for serializing in/out material source files. class MaterialSourceData final @@ -78,15 +79,33 @@ namespace AZ //! Creates a MaterialAsset from the MaterialSourceData content. //! @param assetId ID for the MaterialAsset - //! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for resolving file-relative paths. + //! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for + //! resolving file-relative paths. //! @param elevateWarnings Indicates whether to treat warnings as errors //! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file Outcome> CreateMaterialAsset( Data::AssetId assetId, AZStd::string_view materialSourceFilePath = "", bool elevateWarnings = true, - bool includeMaterialPropertyNames = true - ) const; + bool includeMaterialPropertyNames = true) const; + + //! Creates a MaterialAsset from the MaterialSourceData content. + //! @param assetId ID for the MaterialAsset + //! @param materialSourceFilePath Indicates the path of the .material file that the MaterialSourceData represents. Used for + //! resolving file-relative paths. + //! @param elevateWarnings Indicates whether to treat warnings as errors + //! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file + Outcome> CreateMaterialAssetFromSourceData( + Data::AssetId assetId, + AZStd::string_view materialSourceFilePath = "", + bool elevateWarnings = true, + bool includeMaterialPropertyNames = true) const; + + private: + static void ApplyMaterialSourceDataPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, + const AZStd::string_view& materialSourceFilePath, + const MaterialSourceData& materialSourceData); }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 1467b017d5..2a76befdf4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -126,7 +127,8 @@ namespace AZ return changesWereApplied ? ApplyVersionUpdatesResult::UpdatesApplied : ApplyVersionUpdatesResult::NoUpdates; } - Outcome > MaterialSourceData::CreateMaterialAsset(Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const + Outcome> MaterialSourceData::CreateMaterialAsset( + Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const { MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); @@ -172,7 +174,95 @@ namespace AZ materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames); } - for (auto& group : m_properties) + ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + + Data::Asset material; + if (materialAssetCreator.End(material)) + { + return Success(material); + } + else + { + return Failure(); + } + } + + Outcome> MaterialSourceData::CreateMaterialAssetFromSourceData( + Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const + { + MaterialAssetCreator materialAssetCreator; + materialAssetCreator.SetElevateWarnings(elevateWarnings); + + MaterialTypeSourceData materialTypeSourceData; + AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) + { + return Failure(); + } + + materialTypeSourceData.ResolveUvEnums(); + + auto materialTypeAsset = + materialTypeSourceData.CreateMaterialTypeAsset(AZ::Uuid::CreateRandom(), materialTypeSourcePath, elevateWarnings); + if (!materialTypeAsset.IsSuccess()) + { + return Failure(); + } + + materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); + + AZStd::vector parentMaterialSourceDataVec; + + AZStd::string parentMaterialPath = m_parentMaterial; + AZStd::string parentMaterialSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentMaterialPath); + while (!parentMaterialPath.empty()) + { + MaterialSourceData parentMaterialSourceData; + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialSourcePath, parentMaterialSourceData)) + { + return Failure(); + } + + // Make sure the parent material has the same material type + auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0); + auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentMaterialSourcePath, parentMaterialSourceData.m_materialType, 0); + if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() || + materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue()) + { + AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type."); + return Failure(); + } + + parentMaterialPath = parentMaterialSourceData.m_parentMaterial; + parentMaterialSourcePath = AssetUtils::ResolvePathReference(parentMaterialSourcePath, parentMaterialPath); + parentMaterialSourceDataVec.push_back(parentMaterialSourceData); + } + + AZStd::reverse(parentMaterialSourceDataVec.begin(), parentMaterialSourceDataVec.end()); + for (const auto& parentMaterialSourceData : parentMaterialSourceDataVec) + { + ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, parentMaterialSourceData); + } + + ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + + Data::Asset material; + if (materialAssetCreator.End(material)) + { + return Success(material); + } + else + { + return Failure(); + } + } + + void MaterialSourceData::ApplyMaterialSourceDataPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, + const AZStd::string_view& materialSourceFilePath, + const MaterialSourceData& materialSourceData) + { + for (auto& group : materialSourceData.m_properties) { for (auto& property : group.second) { @@ -183,43 +273,49 @@ namespace AZ } else { - MaterialPropertyIndex propertyIndex = materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName()); + MaterialPropertyIndex propertyIndex = + materialAssetCreator.m_materialPropertiesLayout->FindPropertyIndex(propertyId.GetFullName()); if (propertyIndex.IsValid()) { - const MaterialPropertyDescriptor* propertyDescriptor = materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex); + const MaterialPropertyDescriptor* propertyDescriptor = + materialAssetCreator.m_materialPropertiesLayout->GetPropertyDescriptor(propertyIndex); switch (propertyDescriptor->GetDataType()) { case MaterialPropertyDataType::Image: - { - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialSourceFilePath, property.second.m_value.GetValue()); - - if (imageAssetResult.IsSuccess()) - { - auto& imageAsset = imageAssetResult.GetValue(); - // Load referenced images when load material - imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); - } - else { - materialAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.second.m_value.GetValue().data()); + Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference( + materialSourceFilePath, property.second.m_value.GetValue()); + + if (imageAssetResult.IsSuccess()) + { + auto& imageAsset = imageAssetResult.GetValue(); + // Load referenced images when load material + imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); + materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + } + else + { + materialAssetCreator.ReportError( + "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + property.second.m_value.GetValue().data()); + } } - } - break; + break; case MaterialPropertyDataType::Enum: - { - AZ::Name enumName = AZ::Name(property.second.m_value.GetValue()); - uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName); - if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) { - materialAssetCreator.ReportError("Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); + AZ::Name enumName = AZ::Name(property.second.m_value.GetValue()); + uint32_t enumValue = propertyDescriptor->GetEnumValue(enumName); + if (enumValue == MaterialPropertyDescriptor::InvalidEnumValue) + { + materialAssetCreator.ReportError( + "Enum value '%s' couldn't be found in the 'enumValues' list", enumName.GetCStr()); + } + else + { + materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); + } } - else - { - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); - } - } - break; + break; default: materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value); break; @@ -227,21 +323,12 @@ namespace AZ } else { - materialAssetCreator.ReportWarning("Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data()); + materialAssetCreator.ReportWarning( + "Can not find property id '%s' in MaterialPropertyLayout", propertyId.GetFullName().GetStringView().data()); } } } } - - Data::Asset material; - if (materialAssetCreator.End(material)) - { - return Success(material); - } - else - { - return Failure(); - } } } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp index 46086dfecc..c81cf31d09 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp @@ -43,6 +43,7 @@ namespace AZ return false; } + m_asset->PostLoadInit(); m_asset->SetReady(); m_materialShaderResourceGroupLayout = nullptr; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 98af749261..1dcef43577 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -722,7 +722,7 @@ namespace MaterialEditor // we can create the asset dynamically from the source data. // Long term, the material document should not be concerned with assets at all. The viewport window should be the // only thing concerned with assets or instances. - auto createResult = m_materialSourceData.CreateMaterialAsset(Uuid::CreateRandom(), m_absolutePath, true); + auto createResult = m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true); if (!createResult) { AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str()); From 30120b962607bba2698400d73b27036f3e5bfc63 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 22 Oct 2021 01:30:12 -0500 Subject: [PATCH 29/66] cleanup and setting asset preload flags Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 6 +-- .../RPI.Edit/Material/MaterialSourceData.cpp | 38 +++++++++---------- .../Material/MaterialTypeSourceData.cpp | 29 ++++++++------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index 739c4341a9..17dc4556fb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -102,10 +102,8 @@ namespace AZ bool includeMaterialPropertyNames = true) const; private: - static void ApplyMaterialSourceDataPropertiesToAssetCreator( - AZ::RPI::MaterialAssetCreator& materialAssetCreator, - const AZStd::string_view& materialSourceFilePath, - const MaterialSourceData& materialSourceData); + void ApplyPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 2a76befdf4..877e12ab2e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -174,7 +174,7 @@ namespace AZ materialAssetCreator.Begin(assetId, *parentMaterialAsset.GetValue().Get(), includeMaterialPropertyNames); } - ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); Data::Asset material; if (materialAssetCreator.End(material)) @@ -211,21 +211,21 @@ namespace AZ materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); - AZStd::vector parentMaterialSourceDataVec; + AZStd::vector parentSourceDataStack; - AZStd::string parentMaterialPath = m_parentMaterial; - AZStd::string parentMaterialSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentMaterialPath); - while (!parentMaterialPath.empty()) + AZStd::string parentSourceRelPath = m_parentMaterial; + AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath); + while (!parentSourceRelPath.empty()) { - MaterialSourceData parentMaterialSourceData; - if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialSourcePath, parentMaterialSourceData)) + MaterialSourceData parentSourceData; + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData)) { return Failure(); } // Make sure the parent material has the same material type auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0); - auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentMaterialSourcePath, parentMaterialSourceData.m_materialType, 0); + auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() || materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue()) { @@ -233,18 +233,18 @@ namespace AZ return Failure(); } - parentMaterialPath = parentMaterialSourceData.m_parentMaterial; - parentMaterialSourcePath = AssetUtils::ResolvePathReference(parentMaterialSourcePath, parentMaterialPath); - parentMaterialSourceDataVec.push_back(parentMaterialSourceData); + parentSourceDataStack.push_back(parentSourceData); + parentSourceRelPath = parentSourceData.m_parentMaterial; + parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath); } - AZStd::reverse(parentMaterialSourceDataVec.begin(), parentMaterialSourceDataVec.end()); - for (const auto& parentMaterialSourceData : parentMaterialSourceDataVec) + while (!parentSourceDataStack.empty()) { - ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, parentMaterialSourceData); + parentSourceDataStack.back().ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); + parentSourceDataStack.pop_back(); } - ApplyMaterialSourceDataPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath, *this); + ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); Data::Asset material; if (materialAssetCreator.End(material)) @@ -257,12 +257,10 @@ namespace AZ } } - void MaterialSourceData::ApplyMaterialSourceDataPropertiesToAssetCreator( - AZ::RPI::MaterialAssetCreator& materialAssetCreator, - const AZStd::string_view& materialSourceFilePath, - const MaterialSourceData& materialSourceData) + void MaterialSourceData::ApplyPropertiesToAssetCreator( + AZ::RPI::MaterialAssetCreator& materialAssetCreator, const AZStd::string_view& materialSourceFilePath) const { - for (auto& group : materialSourceData.m_properties) + for (auto& group : m_properties) { for (auto& property : group.second) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 08f57c7cd3..b20873141b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -393,11 +393,14 @@ namespace AZ for (const ShaderVariantReferenceData& shaderRef : m_shaderCollection) { const auto& shaderFile = shaderRef.m_shaderFilePath; - const auto& shaderAsset = AssetUtils::LoadAsset(materialTypeSourceFilePath, shaderFile, 0); + auto shaderAssetResult = AssetUtils::LoadAsset(materialTypeSourceFilePath, shaderFile, 0); - if (shaderAsset) + if (shaderAssetResult) { - auto optionsLayout = shaderAsset.GetValue()->GetShaderOptionGroupLayout(); + auto shaderAsset = shaderAssetResult.GetValue(); + shaderAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); + + auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout(); ShaderOptionGroup options{ optionsLayout }; for (auto& iter : shaderRef.m_shaderOptionValues) { @@ -408,12 +411,11 @@ namespace AZ } materialTypeAssetCreator.AddShader( - shaderAsset.GetValue(), options.GetShaderVariantId(), - shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString() : shaderRef.m_shaderTag - ); + shaderAsset, options.GetShaderVariantId(), + shaderRef.m_shaderTag.IsEmpty() ? Uuid::CreateRandom().ToString() : shaderRef.m_shaderTag); // Gather UV names - const ShaderInputContract& shaderInputContract = shaderAsset.GetValue()->GetInputContract(); + const ShaderInputContract& shaderInputContract = shaderAsset->GetInputContract(); for (const ShaderInputContract::StreamChannelInfo& channel : shaderInputContract.m_streamChannels) { const RHI::ShaderSemantic& semantic = channel.m_semantic; @@ -493,15 +495,20 @@ namespace AZ { case MaterialPropertyDataType::Image: { - Outcome> imageAssetResult = MaterialUtils::GetImageAssetReference(materialTypeSourceFilePath, property.m_value.GetValue()); + auto imageAssetResult = MaterialUtils::GetImageAssetReference( + materialTypeSourceFilePath, property.m_value.GetValue()); - if (imageAssetResult.IsSuccess()) + if (imageAssetResult) { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAssetResult.GetValue()); + auto imageAsset = imageAssetResult.GetValue(); + imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); + materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); } else { - materialTypeAssetCreator.ReportError("Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), property.m_value.GetValue().data()); + materialTypeAssetCreator.ReportError( + "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + property.m_value.GetValue().data()); } } break; From 0724403f9014708c9e34fa7382cc4fcf10c82e76 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 25 Oct 2021 12:35:19 -0500 Subject: [PATCH 30/66] adding ifdef to compare loading vs creating material type assets Signed-off-by: Guthrie Adams --- .../Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 877e12ab2e..f1a41d0548 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -193,6 +193,7 @@ namespace AZ MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); +#if 0 MaterialTypeSourceData materialTypeSourceData; AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) @@ -208,6 +209,13 @@ namespace AZ { return Failure(); } +#else + auto materialTypeAsset = AssetUtils::LoadAsset(materialSourceFilePath, m_materialType); + if (!materialTypeAsset.IsSuccess()) + { + return Failure(); + } +#endif materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); From e632dc3b3982900770bd120cfa1238e1543489dd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Tue, 26 Oct 2021 12:24:37 -0500 Subject: [PATCH 31/66] Moving material type asset PostInit call to be consistent with material asset Signed-off-by: Guthrie Adams --- .../Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp | 4 ++++ .../Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp index 76634201eb..48654d7769 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp @@ -188,6 +188,10 @@ namespace AZ void MaterialTypeAsset::SetReady() { m_status = AssetStatus::Ready; + + // If this was created dynamically using MaterialTypeAssetCreator (which is what calls SetReady()), + // we need to connect to the AssetBus for reloads. + PostLoadInit(); } bool MaterialTypeAsset::PostLoadInit() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp index c81cf31d09..46086dfecc 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAssetCreator.cpp @@ -43,7 +43,6 @@ namespace AZ return false; } - m_asset->PostLoadInit(); m_asset->SetReady(); m_materialShaderResourceGroupLayout = nullptr; From a5e11efda12c0d50df754b8999feac61ecaae516 Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 8 Nov 2021 16:21:35 -0800 Subject: [PATCH 32/66] Add a safety check to Prefab/PrefabPublicHandler (potential AR fix) Signed-off-by: nvsickle --- .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 5ac9f772dc..32600853fd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1144,6 +1144,10 @@ namespace AzToolsFramework AZ::EntityId firstEntityIdToDelete = entityIdsNoFocusContainer[0]; InstanceOptionalReference commonOwningInstance = GetOwnerInstanceByEntityId(firstEntityIdToDelete); + if (!commonOwningInstance.has_value()) + { + return AZ::Failure(AZStd::string("Cannot delete entities belonging to an invalid instance")); + } // If the first entity id is a container entity id, then we need to mark its parent as the common owning instance because you // cannot delete an instance from itself. From 48f3bb7d7a354c9b7340c69d7698e85fd9ada063 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 3 Nov 2021 23:56:59 -0700 Subject: [PATCH 33/66] Fixed missing initialization of ShaderCollection::Item::m_renderStatesOverlay. This RenderStates is used to override the values in the final draw packet, if the values are valid; it's supposed to be initialized to invalid values, but it wasn't. So the depth compare function was getting set to Less instead of GreaterEqual. This wasn't a problem when using serialized assets from disk, because the deserialization uses the default constructor which did initialize m_renderStatesOverlay. No all Item constructors initialize m_renderStatesOverlay. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> Signed-off-by: Guthrie Adams --- .../Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 2 +- .../Code/Source/RPI.Reflect/Material/ShaderCollection.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index f1a41d0548..7ff33b2d04 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -193,7 +193,7 @@ namespace AZ MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); -#if 0 +#if 1 MaterialTypeSourceData materialTypeSourceData; AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp index 87076891dd..16813cb6b7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/ShaderCollection.cpp @@ -126,8 +126,8 @@ namespace AZ } ShaderCollection::Item::Item() + : m_renderStatesOverlay(RHI::GetInvalidRenderStates()) { - m_renderStatesOverlay = RHI::GetInvalidRenderStates(); } ShaderCollection::Item& ShaderCollection::operator[](size_t i) @@ -156,7 +156,8 @@ namespace AZ } ShaderCollection::Item::Item(const Data::Asset& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId) - : m_shaderAsset(shaderAsset) + : m_renderStatesOverlay(RHI::GetInvalidRenderStates()) + , m_shaderAsset(shaderAsset) , m_shaderVariantId(variantId) , m_shaderTag(shaderTag) , m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId) @@ -164,7 +165,8 @@ namespace AZ } ShaderCollection::Item::Item(Data::Asset&& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId) - : m_shaderAsset(AZStd::move(shaderAsset)) + : m_renderStatesOverlay(RHI::GetInvalidRenderStates()) + , m_shaderAsset(AZStd::move(shaderAsset)) , m_shaderVariantId(variantId) , m_shaderTag(shaderTag) , m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId) From c0acbe7bd4cc17f1519efa9dee5a117c091d6be1 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 4 Nov 2021 12:27:18 -0500 Subject: [PATCH 34/66] =?UTF-8?q?Changed=20how=20asset=20creator=20generat?= =?UTF-8?q?es=20the=20asset=20instance.=20Instead=20of=20finding=20or=20cr?= =?UTF-8?q?eating=20the=20asset=20in=20the=20asset=20manager,=20one=20is?= =?UTF-8?q?=20directly=20instantiated=20and=20only=20added=20to=20the=20as?= =?UTF-8?q?set=20manager=20after=20creation=20is=20complete.=20This=20allo?= =?UTF-8?q?ws=20for=20reuse=20of=20previously=20loaded=20asset=20ids=20and?= =?UTF-8?q?=20will=20replace=20or=20=E2=80=9Creload=E2=80=9D=20a=20pre-exi?= =?UTF-8?q?sting=20asset=20with=20the=20newly=20created=20one.=20This=20al?= =?UTF-8?q?so=20sends=20although=20correct=20notifications.=20Changed=20ma?= =?UTF-8?q?terial=20document=20to=20load=20a=20source=20data=20are=20for?= =?UTF-8?q?=20the=20parent=20material=20as=20well.=20=20It=20was=20also=20?= =?UTF-8?q?a=20previously=20loading=20the=20parent=20material=20products?= =?UTF-8?q?=20asset=20which=20would=20be=20out=20of=20date=20compared=20to?= =?UTF-8?q?=20the=20source=20data.=20Changed=20material=20document=20to=20?= =?UTF-8?q?track=20source=20file=20dependency=20changes=20instead=20of=20p?= =?UTF-8?q?roduct=20asset=20changes.=20Fixed=20a=20bug=20or=20copy=20paste?= =?UTF-8?q?=20error=20in=20the=20document=20manager=20that=20was=20using?= =?UTF-8?q?=20the=20same=20container=20to=20track=20documents=20the=20modi?= =?UTF-8?q?fied=20externally=20and=20from=20other=20dependency=20changes.?= =?UTF-8?q?=20Returning=20source=20data=20dependencies=20when=20creating?= =?UTF-8?q?=20a=20material=20asset=20from=20source.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 3 +- .../Include/Atom/RPI.Reflect/AssetCreator.h | 3 +- .../RPI.Edit/Material/MaterialSourceData.cpp | 61 +++++++++++------- .../Material/MaterialTypeSourceData.cpp | 3 - .../AtomToolsDocumentSystemComponent.cpp | 14 +++-- .../AtomToolsDocumentSystemComponent.h | 4 +- .../Code/Source/Document/MaterialDocument.cpp | 63 ++++++++++--------- .../Code/Source/Document/MaterialDocument.h | 11 +--- 8 files changed, 86 insertions(+), 76 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index 17dc4556fb..77bf45023d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -99,7 +99,8 @@ namespace AZ Data::AssetId assetId, AZStd::string_view materialSourceFilePath = "", bool elevateWarnings = true, - bool includeMaterialPropertyNames = true) const; + bool includeMaterialPropertyNames = true, + AZStd::unordered_set* sourceDependencies = nullptr) const; private: void ApplyPropertiesToAssetCreator( diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h index abdbe9cdce..79d43d0b8d 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/AssetCreator.h @@ -118,7 +118,7 @@ namespace AZ ResetIssueCounts(); // Because the asset creator can be used multiple times - m_asset = Data::AssetManager::Instance().CreateAsset(assetId, AZ::Data::AssetLoadBehavior::PreLoad); + m_asset = Data::Asset(assetId, aznew AssetDataT, AZ::Data::AssetLoadBehavior::PreLoad); m_beginCalled = true; if (!m_asset) @@ -138,6 +138,7 @@ namespace AZ } else { + Data::AssetManager::Instance().AssignAssetData(m_asset); result = AZStd::move(m_asset); success = true; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 7ff33b2d04..c912826026 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -188,14 +188,20 @@ namespace AZ } Outcome> MaterialSourceData::CreateMaterialAssetFromSourceData( - Data::AssetId assetId, AZStd::string_view materialSourceFilePath, bool elevateWarnings, bool includeMaterialPropertyNames) const + Data::AssetId assetId, + AZStd::string_view materialSourceFilePath, + bool elevateWarnings, + bool includeMaterialPropertyNames, + AZStd::unordered_set* sourceDependencies) const { - MaterialAssetCreator materialAssetCreator; - materialAssetCreator.SetElevateWarnings(elevateWarnings); + const auto materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); + const auto materialTypeAssetId = AssetUtils::MakeAssetId(materialTypeSourcePath, 0); + if (!materialTypeAssetId.IsSuccess()) + { + return Failure(); + } -#if 1 MaterialTypeSourceData materialTypeSourceData; - AZStd::string materialTypeSourcePath = AssetUtils::ResolvePathReference(materialSourceFilePath, m_materialType); if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) { return Failure(); @@ -203,21 +209,16 @@ namespace AZ materialTypeSourceData.ResolveUvEnums(); - auto materialTypeAsset = - materialTypeSourceData.CreateMaterialTypeAsset(AZ::Uuid::CreateRandom(), materialTypeSourcePath, elevateWarnings); - if (!materialTypeAsset.IsSuccess()) - { - return Failure(); - } -#else - auto materialTypeAsset = AssetUtils::LoadAsset(materialSourceFilePath, m_materialType); + const auto materialTypeAsset = + materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings); if (!materialTypeAsset.IsSuccess()) { return Failure(); } -#endif - materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); + AZStd::unordered_set dependencies; + dependencies.insert(materialSourceFilePath); + dependencies.insert(materialTypeSourcePath); AZStd::vector parentSourceDataStack; @@ -225,6 +226,13 @@ namespace AZ AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath); while (!parentSourceRelPath.empty()) { + if (dependencies.find(parentSourceAbsPath) != dependencies.end()) + { + return Failure(); + } + + dependencies.insert(parentSourceAbsPath); + MaterialSourceData parentSourceData; if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData)) { @@ -232,20 +240,22 @@ namespace AZ } // Make sure the parent material has the same material type - auto materialTypeIdOutcome1 = AssetUtils::MakeAssetId(materialSourceFilePath, m_materialType, 0); - auto materialTypeIdOutcome2 = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); - if (!materialTypeIdOutcome1.IsSuccess() || !materialTypeIdOutcome2.IsSuccess() || - materialTypeIdOutcome1.GetValue() != materialTypeIdOutcome2.GetValue()) + const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); + if (!parentTypeAssetId || parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue()) { AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type."); return Failure(); } - parentSourceDataStack.push_back(parentSourceData); parentSourceRelPath = parentSourceData.m_parentMaterial; parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath); + parentSourceDataStack.emplace_back(AZStd::move(parentSourceData)); } + MaterialAssetCreator materialAssetCreator; + materialAssetCreator.SetElevateWarnings(elevateWarnings); + materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); + while (!parentSourceDataStack.empty()) { parentSourceDataStack.back().ApplyPropertiesToAssetCreator(materialAssetCreator, materialSourceFilePath); @@ -257,12 +267,15 @@ namespace AZ Data::Asset material; if (materialAssetCreator.End(material)) { + if (sourceDependencies) + { + sourceDependencies->insert(dependencies.begin(), dependencies.end()); + } + return Success(material); } - else - { - return Failure(); - } + + return Failure(); } void MaterialSourceData::ApplyPropertiesToAssetCreator( diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index b20873141b..396ba71e14 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -398,8 +398,6 @@ namespace AZ if (shaderAssetResult) { auto shaderAsset = shaderAssetResult.GetValue(); - shaderAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - auto optionsLayout = shaderAsset->GetShaderOptionGroupLayout(); ShaderOptionGroup options{ optionsLayout }; for (auto& iter : shaderRef.m_shaderOptionValues) @@ -501,7 +499,6 @@ namespace AZ if (imageAssetResult) { auto imageAsset = imageAssetResult.GetValue(); - imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); } else diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp index 5652e9fe23..00de2a7c4c 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp @@ -159,7 +159,7 @@ namespace AtomToolsFramework void AtomToolsDocumentSystemComponent::OnDocumentExternallyModified(const AZ::Uuid& documentId) { - m_documentIdsToReopen.insert(documentId); + m_documentIdsWithExternalChanges.insert(documentId); if (!AZ::TickBus::Handler::BusIsConnected()) { AZ::TickBus::Handler::BusConnect(); @@ -168,7 +168,7 @@ namespace AtomToolsFramework void AtomToolsDocumentSystemComponent::OnDocumentDependencyModified(const AZ::Uuid& documentId) { - m_documentIdsToReopen.insert(documentId); + m_documentIdsWithDependencyChanges.insert(documentId); if (!AZ::TickBus::Handler::BusIsConnected()) { AZ::TickBus::Handler::BusConnect(); @@ -177,7 +177,7 @@ namespace AtomToolsFramework void AtomToolsDocumentSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { - for (const AZ::Uuid& documentId : m_documentIdsToReopen) + for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges) { AZStd::string documentPath; AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); @@ -191,6 +191,8 @@ namespace AtomToolsFramework continue; } + m_documentIdsWithDependencyChanges.erase(documentId); + AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount); bool openResult = false; @@ -204,7 +206,7 @@ namespace AtomToolsFramework } } - for (const AZ::Uuid& documentId : m_documentIdsToReopen) + for (const AZ::Uuid& documentId : m_documentIdsWithDependencyChanges) { AZStd::string documentPath; AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); @@ -231,8 +233,8 @@ namespace AtomToolsFramework } } - m_documentIdsToReopen.clear(); - m_documentIdsToReopen.clear(); + m_documentIdsWithDependencyChanges.clear(); + m_documentIdsWithExternalChanges.clear(); AZ::TickBus::Handler::BusDisconnect(); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h index 9c556a07e7..a0f5eb085d 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.h @@ -85,8 +85,8 @@ namespace AtomToolsFramework AZStd::intrusive_ptr m_settings; AZStd::function m_documentCreator; AZStd::unordered_map> m_documentMap; - AZStd::unordered_set m_documentIdsToRebuild; - AZStd::unordered_set m_documentIdsToReopen; + AZStd::unordered_set m_documentIdsWithExternalChanges; + AZStd::unordered_set m_documentIdsWithDependencyChanges; const size_t m_maxMessageBoxLineCount = 15; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 1dcef43577..049d4c47ff 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -567,26 +567,26 @@ namespace MaterialEditor } } - void MaterialDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) + void MaterialDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid sourceUUID) { - if (m_sourceAssetId.m_guid == sourceUUID) + auto sourcePath = AZ::RPI::AssetUtils::ResolvePathReference(scanFolder, relativePath); + + if (m_absolutePath == sourcePath) { // ignore notifications caused by saving the open document if (!m_saveTriggeredInternally) { AZ_TracePrintf("MaterialDocument", "Material document changed externally: '%s'.\n", m_absolutePath.c_str()); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id); } m_saveTriggeredInternally = false; } - } - - void MaterialDocument::OnAssetReloaded(AZ::Data::Asset asset) - { - if (m_dependentAssetIds.find(asset->GetId()) != m_dependentAssetIds.end()) + else if (m_sourceDependencies.find(sourcePath) != m_sourceDependencies.end()) { AZ_TracePrintf("MaterialDocument", "Material document dependency changed: '%s'.\n", m_absolutePath.c_str()); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id); } } @@ -655,7 +655,6 @@ namespace MaterialEditor return false; } - m_sourceAssetId = sourceAssetInfo.m_assetId; m_relativePath = sourceAssetInfo.m_relativePath; if (!AzFramework::StringFunc::Path::Normalize(m_relativePath)) { @@ -722,14 +721,15 @@ namespace MaterialEditor // we can create the asset dynamically from the source data. // Long term, the material document should not be concerned with assets at all. The viewport window should be the // only thing concerned with assets or instances. - auto createResult = m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true); - if (!createResult) + auto materialAssetResult = + m_materialSourceData.CreateMaterialAssetFromSourceData(Uuid::CreateRandom(), m_absolutePath, true, true, &m_sourceDependencies); + if (!materialAssetResult) { AZ_Error("MaterialDocument", false, "Material asset could not be created from source data: '%s'.", m_absolutePath.c_str()); return false; } - m_materialAsset = createResult.GetValue(); + m_materialAsset = materialAssetResult.GetValue(); if (!m_materialAsset.IsReady()) { AZ_Error("MaterialDocument", false, "Material asset is not ready: '%s'.", m_absolutePath.c_str()); @@ -743,28 +743,35 @@ namespace MaterialEditor return false; } - // track material type asset to notify when dependencies change - m_dependentAssetIds.insert(materialTypeAsset->GetId()); - AZ::Data::AssetBus::MultiHandler::BusConnect(materialTypeAsset->GetId()); - AZStd::array_view parentPropertyValues = materialTypeAsset->GetDefaultPropertyValues(); AZ::Data::Asset parentMaterialAsset; if (!m_materialSourceData.m_parentMaterial.empty()) { - // There is a parent for this material - auto parentMaterialResult = AssetUtils::LoadAsset(m_absolutePath, m_materialSourceData.m_parentMaterial); - if (!parentMaterialResult) + AZ::RPI::MaterialSourceData parentMaterialSourceData; + const auto parentMaterialFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialFilePath, parentMaterialSourceData)) { - AZ_Error("MaterialDocument", false, "Parent material asset could not be loaded: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); + AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", parentMaterialFilePath.c_str()); return false; } - parentMaterialAsset = parentMaterialResult.GetValue(); - parentPropertyValues = parentMaterialAsset->GetPropertyValues(); + const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(parentMaterialFilePath, 0); + if (!parentMaterialAssetIdResult) + { + AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", parentMaterialFilePath.c_str()); + return false; + } - // track parent material asset to notify when dependencies change - m_dependentAssetIds.insert(parentMaterialAsset->GetId()); - AZ::Data::AssetBus::MultiHandler::BusConnect(parentMaterialAsset->GetId()); + auto parentMaterialAssetResult = m_materialSourceData.CreateMaterialAssetFromSourceData( + parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true, &m_sourceDependencies); + if (!parentMaterialAssetResult) + { + AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str()); + return false; + } + + parentMaterialAsset = parentMaterialAssetResult.GetValue(); + parentPropertyValues = parentMaterialAsset->GetPropertyValues(); } // Creating a material from a material asset will fail if a texture is referenced but not loaded @@ -913,15 +920,13 @@ namespace MaterialEditor void MaterialDocument::Clear() { AZ::TickBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::MultiHandler::BusDisconnect(); AzToolsFramework::AssetSystemBus::Handler::BusDisconnect(); m_materialAsset = {}; m_materialInstance = {}; m_absolutePath.clear(); m_relativePath.clear(); - m_sourceAssetId = {}; - m_dependentAssetIds.clear(); + m_sourceDependencies.clear(); m_saveTriggeredInternally = {}; m_compilePending = {}; m_properties.clear(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index 03997a2a91..452111f99a 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -29,7 +29,6 @@ namespace MaterialEditor : public AtomToolsFramework::AtomToolsDocument , public MaterialDocumentRequestBus::Handler , private AZ::TickBus::Handler - , private AZ::Data::AssetBus::MultiHandler , private AzToolsFramework::AssetSystemBus::Handler { public: @@ -105,11 +104,6 @@ namespace MaterialEditor void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override; ////////////////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////// - // AZ::Data::AssetBus::Router overrides... - void OnAssetReloaded(AZ::Data::Asset asset) override; - ////////////////////////////////////////////////////////////////////////// - bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); @@ -137,11 +131,8 @@ namespace MaterialEditor // Material instance being edited AZ::Data::Instance m_materialInstance; - // Asset used to open document - AZ::Data::AssetId m_sourceAssetId; - // Set of assets that can trigger a document reload - AZStd::unordered_set m_dependentAssetIds; + AZStd::unordered_set m_sourceDependencies; // Track if document saved itself last to skip external modification notification bool m_saveTriggeredInternally = false; From 5afd701e2389d244c3ea03c529a806b20dd95993 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 4 Nov 2021 18:20:27 -0500 Subject: [PATCH 35/66] updated comments and error messages Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/MaterialSourceData.h | 1 + .../RPI.Edit/Material/MaterialSourceData.cpp | 25 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h index 77bf45023d..53d3072370 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialSourceData.h @@ -95,6 +95,7 @@ namespace AZ //! resolving file-relative paths. //! @param elevateWarnings Indicates whether to treat warnings as errors //! @param includeMaterialPropertyNames Indicates whether to save material property names into the material asset file + //! @param sourceDependencies if not null, will be populated with a set of all of the loaded material and material type paths Outcome> CreateMaterialAssetFromSourceData( Data::AssetId assetId, AZStd::string_view materialSourceFilePath = "", diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index c912826026..7c37d894d4 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -198,12 +198,14 @@ namespace AZ const auto materialTypeAssetId = AssetUtils::MakeAssetId(materialTypeSourcePath, 0); if (!materialTypeAssetId.IsSuccess()) { + AZ_Error("MaterialSourceData", false, "Failed to create material type asset ID: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } MaterialTypeSourceData materialTypeSourceData; if (!AZ::RPI::JsonUtils::LoadObjectFromFile(materialTypeSourcePath, materialTypeSourceData)) { + AZ_Error("MaterialSourceData", false, "Failed to load MaterialTypeSourceData: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } @@ -213,45 +215,58 @@ namespace AZ materialTypeSourceData.CreateMaterialTypeAsset(materialTypeAssetId.GetValue(), materialTypeSourcePath, elevateWarnings); if (!materialTypeAsset.IsSuccess()) { + AZ_Error("MaterialSourceData", false, "Failed to create material type asset from source data: '%s'.", materialTypeSourcePath.c_str()); return Failure(); } + // Track all of the material and material type assets loaded while trying to create a material asset from source data. This will + // be used for evaluating circular dependencies and returned for external monitoring or other use. AZStd::unordered_set dependencies; dependencies.insert(materialSourceFilePath); dependencies.insert(materialTypeSourcePath); + // Load and build a stack of MaterialSourceData from all of the parent materials in the hierarchy. Properties from the source + // data will be applied in reverse to the asset creator. AZStd::vector parentSourceDataStack; AZStd::string parentSourceRelPath = m_parentMaterial; AZStd::string parentSourceAbsPath = AssetUtils::ResolvePathReference(materialSourceFilePath, parentSourceRelPath); while (!parentSourceRelPath.empty()) { - if (dependencies.find(parentSourceAbsPath) != dependencies.end()) + if (!dependencies.insert(parentSourceAbsPath).second) { + AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath, parentSourceAbsPath.c_str()); return Failure(); } - dependencies.insert(parentSourceAbsPath); - MaterialSourceData parentSourceData; if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentSourceAbsPath, parentSourceData)) { + AZ_Error("MaterialSourceData", false, "Failed to load MaterialSourceData for parent material: '%s'.", parentSourceAbsPath.c_str()); return Failure(); } - // Make sure the parent material has the same material type + // Make sure that all materials in the hierarchy share the same material type const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); - if (!parentTypeAssetId || parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue()) + if (!parentTypeAssetId) + { + AZ_Error("MaterialSourceData", false, "Parent material asset ID isn't valid: '%s'.", parentSourceAbsPath.c_str()); + return Failure(); + } + + if (parentTypeAssetId.GetValue() != materialTypeAssetId.GetValue()) { AZ_Error("MaterialSourceData", false, "This material and its parent material do not share the same material type."); return Failure(); } + // Get the location of the next parent material and push the source data onto the stack parentSourceRelPath = parentSourceData.m_parentMaterial; parentSourceAbsPath = AssetUtils::ResolvePathReference(parentSourceAbsPath, parentSourceRelPath); parentSourceDataStack.emplace_back(AZStd::move(parentSourceData)); } + // Create the material asset from all the previously loaded source data MaterialAssetCreator materialAssetCreator; materialAssetCreator.SetElevateWarnings(elevateWarnings); materialAssetCreator.Begin(assetId, *materialTypeAsset.GetValue().Get(), includeMaterialPropertyNames); From 791d11c8f96cd500164688e5df225148167ead93 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 5 Nov 2021 22:06:31 -0500 Subject: [PATCH 36/66] Fix parent material loading Signed-off-by: Guthrie Adams --- .../RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 2 +- .../MaterialEditor/Code/Source/Document/MaterialDocument.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index 7c37d894d4..e5466a173f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -235,7 +235,7 @@ namespace AZ { if (!dependencies.insert(parentSourceAbsPath).second) { - AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath, parentSourceAbsPath.c_str()); + AZ_Error("MaterialSourceData", false, "Detected circular dependency between materials: '%s' and '%s'.", materialSourceFilePath.data(), parentSourceAbsPath.c_str()); return Failure(); } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 049d4c47ff..ee58cbea3e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -762,8 +762,8 @@ namespace MaterialEditor return false; } - auto parentMaterialAssetResult = m_materialSourceData.CreateMaterialAssetFromSourceData( - parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true, &m_sourceDependencies); + auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData( + parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true); if (!parentMaterialAssetResult) { AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str()); From c372761f4e348bf63f7f7b6b0ee930f177bfd2da Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 7 Nov 2021 15:04:46 -0600 Subject: [PATCH 37/66] Changing lua material functor script loading code to pass the correct sub ID for a compiled script asset Signed-off-by: Guthrie Adams --- .../Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp index b230953f8c..37bd5a19f2 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp @@ -137,7 +137,7 @@ namespace AZ } else if (!m_luaSourceFile.empty()) { - auto loadOutcome = RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile); + auto loadOutcome = RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId); if (!loadOutcome) { AZ_Error("LuaMaterialFunctorSourceData", false, "Could not load script file '%s'", m_luaSourceFile.c_str()); From dcb3ac43375b15b1fde049e8c8b9d6a3907883cd Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Mon, 8 Nov 2021 17:53:03 -0700 Subject: [PATCH 38/66] Set skybox exposure during ReflectionProbe bake Signed-off-by: dmcdiar --- .../Source/ReflectionProbe/ReflectionProbe.cpp | 15 +++++++++------ .../Code/Source/ReflectionProbe/ReflectionProbe.h | 6 ++++-- .../EditorReflectionProbeComponent.cpp | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp index c4ea3249d5..4ac5782b04 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp @@ -120,15 +120,17 @@ namespace AZ m_scene->RemoveRenderPipeline(m_environmentCubeMapPipelineId); m_environmentCubeMapPass = nullptr; - // restore exposure - sceneSrg->SetConstant(m_iblExposureConstantIndex, m_previousExposure); + // restore exposures + sceneSrg->SetConstant(m_globalIblExposureConstantIndex, m_previousGlobalIblExposure); + sceneSrg->SetConstant(m_skyBoxExposureConstantIndex, m_previousSkyBoxExposure); m_buildingCubeMap = false; } else { - // set exposure to the user specified value while baking the cubemap - sceneSrg->SetConstant(m_iblExposureConstantIndex, m_bakeExposure); + // set exposures to the user specified value while baking the cubemap + sceneSrg->SetConstant(m_globalIblExposureConstantIndex, m_bakeExposure); + sceneSrg->SetConstant(m_skyBoxExposureConstantIndex, m_bakeExposure); } } @@ -305,9 +307,10 @@ namespace AZ const RPI::Ptr& rootPass = environmentCubeMapPipeline->GetRootPass(); rootPass->AddChild(m_environmentCubeMapPass); - // store the current IBL exposure value + // store the current IBL exposure values Data::Instance sceneSrg = m_scene->GetShaderResourceGroup(); - m_previousExposure = sceneSrg->GetConstant(m_iblExposureConstantIndex); + m_previousGlobalIblExposure = sceneSrg->GetConstant(m_globalIblExposureConstantIndex); + m_previousSkyBoxExposure = sceneSrg->GetConstant(m_skyBoxExposureConstantIndex); m_scene->AddRenderPipeline(environmentCubeMapPipeline); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h index 485f380463..17ef54367b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.h @@ -180,8 +180,10 @@ namespace AZ RPI::Ptr m_environmentCubeMapPass = nullptr; RPI::RenderPipelineId m_environmentCubeMapPipelineId; BuildCubeMapCallback m_callback; - RHI::ShaderInputNameIndex m_iblExposureConstantIndex = "m_iblExposure"; - float m_previousExposure = 0.0f; + RHI::ShaderInputNameIndex m_globalIblExposureConstantIndex = "m_iblExposure"; + RHI::ShaderInputNameIndex m_skyBoxExposureConstantIndex = "m_cubemapExposure"; + float m_previousGlobalIblExposure = 0.0f; + float m_previousSkyBoxExposure = 0.0f; bool m_buildingCubeMap = false; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index c7179587c0..578c6e9300 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -64,8 +64,8 @@ namespace AZ ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::BakeReflectionProbe) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorReflectionProbeComponent::GetBakedCubemapVisibilitySetting) ->DataElement(AZ::Edit::UIHandlers::Slider, &EditorReflectionProbeComponent::m_bakeExposure, "Bake Exposure", "Exposure to use when baking the cubemap") - ->Attribute(AZ::Edit::Attributes::SoftMin, -5.0f) - ->Attribute(AZ::Edit::Attributes::SoftMax, 5.0f) + ->Attribute(AZ::Edit::Attributes::SoftMin, -16.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 16.0f) ->Attribute(AZ::Edit::Attributes::Min, -20.0f) ->Attribute(AZ::Edit::Attributes::Max, 20.0f) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorReflectionProbeComponent::OnBakeExposureChanged) From 487ac2b516fd27b39e5cd18d68e44990afe9a9dd Mon Sep 17 00:00:00 2001 From: nvsickle Date: Mon, 8 Nov 2021 17:37:32 -0800 Subject: [PATCH 39/66] Force prefabs off for Editor smoke test Signed-off-by: nvsickle --- .../PythonTests/smoke/test_Editor_NewExistingLevels_Works.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py index 6f654b9107..72e548615c 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/test_Editor_NewExistingLevels_Works.py @@ -28,4 +28,4 @@ class TestAutomation(TestAutomationBase): from . import Editor_NewExistingLevels_Works as test_module - self._run_test(request, workspace, editor, test_module) + self._run_test(request, workspace, editor, test_module, extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=false"]) From c5cb90ddb79d94df5b663aec27311a70c9925209 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 8 Nov 2021 20:24:53 -0800 Subject: [PATCH 40/66] Merge pull request #4426 from aws-lumberyard-dev/Atom/santorac/FixSceneSrgTime Fixed potential render scene time precision issues. The timestamp was simply converted from GetTimeAtCurrentTick to a float. Since this value is backed by QueryPerformanceCounter which is 0 at boot, you could see broken animations on the GPU when your system has been on for a long time. So I simplified the RPI's time API (removed unused code), and subtracted the application start time each frame before converting the time value to a float. Also moved FindShaderInputConstantIndex("m_time") to be called only once, instead of every frame. Testing: Originally: I had a local material shader that did vertex animation and it wasn't working at all before, and now it works. More recently, I made local changes to StandardPBR to add a simple sin wave animation. I also modified GetTimeNowMicroSecond() to artificially add 30 days to the clock. This showed choppy animation before my changes, and smooth animation after. AtomSampleViewer passed dx12 and vulkan (other than pre-existing issues) Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Include/Atom/RPI.Public/RPISystem.h | 6 +++--- .../Include/Atom/RPI.Public/RenderPipeline.h | 3 +-- .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 15 +++++--------- .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 20 ++++++++++--------- .../Code/Source/RPI.Public/RenderPipeline.cpp | 2 +- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 17 ++++++++-------- 6 files changed, 30 insertions(+), 33 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h index 92370c5a82..9138c0b418 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h @@ -97,8 +97,7 @@ namespace AZ // SystemTickBus::OnTick void OnSystemTick() override; - // Fill system time and game time information for simulation or rendering - void FillTickTimeInfo(); + float GetCurrentTime(); // The set of core asset handlers registered by the system. AZStd::vector> m_assetHandlers; @@ -124,7 +123,8 @@ namespace AZ // The job policy used for feature processor's rendering prepare RHI::JobPolicy m_prepareRenderJobPolicy = RHI::JobPolicy::Parallel; - TickTimeInfo m_tickTime; + ScriptTimePoint m_startTime; + float m_currentSimulationTime = 0.0f; RPISystemDescriptor m_descriptor; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h index fcf812cc38..6cba0c774f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h @@ -32,7 +32,6 @@ namespace AZ namespace RPI { class Scene; - struct TickTimeInfo; class ShaderResourceGroup; class AnyAsset; class WindowContext; @@ -203,7 +202,7 @@ namespace AZ void OnRemovedFromScene(Scene* scene); // Called when this pipeline is about to be rendered - void OnStartFrame(const TickTimeInfo& tick); + void OnStartFrame(float time); // Called when the rendering of current frame is finished. void OnFrameEnd(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index f86383101a..1411a8d996 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -48,14 +48,6 @@ namespace AZ // Callback function to modify values of a ShaderResourceGroup using ShaderResourceGroupCallback = AZStd::function; - //! A structure for ticks which contains system time and game time. - struct TickTimeInfo - { - float m_currentGameTime; - float m_gameDeltaTime = 0; - }; - - class Scene final : public SceneRequestBus::Handler { @@ -179,12 +171,14 @@ namespace AZ // Cpu simulation which runs all active FeatureProcessor Simulate() functions. // @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's simulation. - void Simulate(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy); + // @param simulationTime the number of seconds since the application started + void Simulate(RHI::JobPolicy jobPolicy, float simulationTime); // Collect DrawPackets from FeatureProcessors // @param jobPolicy if it's JobPolicy::Parallel, the function will spawn a job thread for each FeatureProcessor's // PrepareRender. - void PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy); + // @param simulationTime the number of seconds since the application started; this is the same time value that was passed to Simulate() + void PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime); // Function called when the current frame is finished rendering. void OnFrameEnd(); @@ -267,6 +261,7 @@ namespace AZ // Registry which allocates draw filter tag for RenderPipeline RHI::Ptr m_drawFilterTagRegistry; + RHI::ShaderInputConstantIndex m_timeInputIndex; float m_simulationTime; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index 943966c13b..2b32503838 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -268,21 +268,23 @@ namespace AZ AssetInitBus::Broadcast(&AssetInitBus::Events::PostLoadInit); - // Update tick time info - FillTickTimeInfo(); + m_currentSimulationTime = GetCurrentTime(); for (auto& scene : m_scenes) { - scene->Simulate(m_tickTime, m_simulationJobPolicy); + scene->Simulate(m_simulationJobPolicy, m_currentSimulationTime); } } - void RPISystem::FillTickTimeInfo() + float RPISystem::GetCurrentTime() { - AZ::TickRequestBus::BroadcastResult(m_tickTime.m_gameDeltaTime, &AZ::TickRequestBus::Events::GetTickDeltaTime); - ScriptTimePoint currentTime; - AZ::TickRequestBus::BroadcastResult(currentTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick); - m_tickTime.m_currentGameTime = static_cast(currentTime.GetSeconds()); + ScriptTimePoint timeAtCurrentTick; + AZ::TickRequestBus::BroadcastResult(timeAtCurrentTick, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick); + + // We subtract the start time to maximize precision of the time value, since we will be converting it to a float. + double currentTime = timeAtCurrentTick.GetSeconds() - m_startTime.GetSeconds(); + + return aznumeric_cast(currentTime); } void RPISystem::RenderTick() @@ -301,7 +303,7 @@ namespace AZ // [GFX TODO] We may parallel scenes' prepare render. for (auto& scenePtr : m_scenes) { - scenePtr->PrepareRender(m_tickTime, m_prepareRenderJobPolicy); + scenePtr->PrepareRender(m_prepareRenderJobPolicy, m_currentSimulationTime); } m_rhiSystem.FrameUpdate( diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp index 6378a249a4..8d4303f187 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp @@ -375,7 +375,7 @@ namespace AZ m_scene->RemoveRenderPipeline(m_nameId); } - void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick) + void RenderPipeline::OnStartFrame([[maybe_unused]] float time) { AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame"); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 41fefda656..b27e3518e1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -44,6 +44,9 @@ namespace AZ { auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs(); scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName()); + + // Set value for constants defined in SceneTimeSrg.azsli + scene->m_timeInputIndex = scene->m_srg->FindShaderInputConstantIndex(Name{ "m_time" }); } scene->m_name = sceneDescriptor.m_nameId; @@ -410,11 +413,11 @@ namespace AZ //[GFX TODO]: the completion job should start here } - void Scene::Simulate([[maybe_unused]] const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) + void Scene::Simulate(RHI::JobPolicy jobPolicy, float simulationTime) { AZ_PROFILE_SCOPE(RPI, "Scene: Simulate"); - m_simulationTime = tickInfo.m_currentGameTime; + m_simulationTime = simulationTime; // If previous simulation job wasn't done, wait for it to finish. if (m_taskGraphActive) @@ -483,11 +486,9 @@ namespace AZ { if (m_srg) { - // Set value for constants defined in SceneTimeSrg.azsli - RHI::ShaderInputConstantIndex timeIndex = m_srg->FindShaderInputConstantIndex(Name{ "m_time" }); - if (timeIndex.IsValid()) + if (m_timeInputIndex.IsValid()) { - m_srg->SetConstant(timeIndex, m_simulationTime); + m_srg->SetConstant(m_timeInputIndex, m_simulationTime); } // signal any handlers to update values for their partial scene srg @@ -620,7 +621,7 @@ namespace AZ WaitAndCleanCompletionJob(finalizeDrawListsCompletion); } - void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy) + void Scene::PrepareRender(RHI::JobPolicy jobPolicy, float simulationTime) { AZ_PROFILE_SCOPE(RPI, "Scene: PrepareRender"); @@ -644,7 +645,7 @@ namespace AZ if (pipeline->NeedsRender()) { activePipelines.push_back(pipeline); - pipeline->OnStartFrame(tickInfo); + pipeline->OnStartFrame(simulationTime); } } } From af08cc5ab319c7275d367f6af9305d3107276099 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 9 Nov 2021 10:05:33 +0000 Subject: [PATCH 41/66] Various bug fixes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../TerrainSurfaceMaterialsListComponent.cpp | 13 +++++++++---- .../TerrainSurfaceMaterialsListComponent.h | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp index 271919070c..7da6130f7b 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp @@ -74,7 +74,7 @@ namespace Terrain ->DataElement( AZ::Edit::UIHandlers::Default, &TerrainSurfaceMaterialsListConfig::m_surfaceMaterials, - "Gradient to Material Mappings", "Maps surfaces to materials."); + "Material Mappings", "Maps surfaces to materials."); } } } @@ -112,6 +112,11 @@ namespace Terrain { } + TerrainSurfaceMaterialsListComponent ::~TerrainSurfaceMaterialsListComponent() + { + Deactivate(); + } + void TerrainSurfaceMaterialsListComponent::Activate() { m_cachedAabb = AZ::Aabb::CreateNull(); @@ -123,7 +128,7 @@ namespace Terrain { surfaceMaterialMapping.m_active = false; surfaceMaterialMapping.m_materialAsset.QueueLoad(); - AZ::Data::AssetBus::Handler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId()); + AZ::Data::AssetBus::MultiHandler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId()); } } } @@ -136,7 +141,7 @@ namespace Terrain { if (surfaceMaterialMapping.m_materialAsset.GetId().IsValid()) { - AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId()); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId()); surfaceMaterialMapping.m_materialAsset.Release(); surfaceMaterialMapping.m_materialInstance.reset(); surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId(); @@ -202,7 +207,7 @@ namespace Terrain // Don't disconnect from the AssetBus if this material is mapped more than once. if (CountMaterialIDInstances(surfaceMaterialMapping.m_activeMaterialAssetId) == 1) { - AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId); } surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId(); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h index 7c36033c41..a6650bf035 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h @@ -53,7 +53,7 @@ namespace Terrain class TerrainSurfaceMaterialsListComponent : public AZ::Component , private TerrainAreaMaterialRequestBus::Handler - , private AZ::Data::AssetBus::Handler + , private AZ::Data::AssetBus::MultiHandler , private LmbrCentral::ShapeComponentNotificationsBus::Handler { public: @@ -67,7 +67,7 @@ namespace Terrain TerrainSurfaceMaterialsListComponent(const TerrainSurfaceMaterialsListConfig& configuration); TerrainSurfaceMaterialsListComponent() = default; - ~TerrainSurfaceMaterialsListComponent() = default; + ~TerrainSurfaceMaterialsListComponent(); ////////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation From 1998c53882e725ba99e4abd4ec60702b67535f1f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 9 Nov 2021 04:19:04 -0600 Subject: [PATCH 42/66] Non MSVC Release build fix (#5428) Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 3668ab14fd..3902bd107c 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -668,7 +668,7 @@ namespace AZ::SettingsRegistryMergeUtils // NOTE: We make the project-path in the BootstrapSettingsRootKey absolute first AZ::IO::FixedMaxPath projectPath = FindProjectRoot(registry); - if (constexpr auto projectPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_path"; + if ([[maybe_unused]] constexpr auto projectPathKey = FixedValueString(BootstrapSettingsRootKey) + "/project_path"; !projectPath.empty()) { if (projectPath.IsRelative()) From 938899a49562da823c80063e14abc3018c0cef73 Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Tue, 9 Nov 2021 13:24:10 +0000 Subject: [PATCH 43/66] Minor fixups for terrain physics collide lyn 7692 (#5413) * First commit Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * completed changes Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> --- .../Source/Components/TerrainPhysicsColliderComponent.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index e9c235c1bd..9262937317 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -185,12 +185,12 @@ namespace Terrain void TerrainPhysicsColliderComponent::GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const { - AZ::Aabb heightfieldAabb = GetHeightfieldAabb(); + const AZ::Aabb heightfieldAabb = GetHeightfieldAabb(); // Because our terrain heights are relative to the center of the bounding box, the min and max allowable heights are also // relative to the center. They are also clamped to the size of the bounding box. - minHeightBounds = -(heightfieldAabb.GetZExtent() / 2.0f); maxHeightBounds = heightfieldAabb.GetZExtent() / 2.0f; + minHeightBounds = -maxHeightBounds; } AZ::Transform TerrainPhysicsColliderComponent::GetHeightfieldTransform() const @@ -199,9 +199,7 @@ namespace Terrain AZ::Vector3 translate; AZ::TransformBus::EventResult(translate, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation); - AZ::Transform transform = AZ::Transform::CreateTranslation(translate); - - return transform; + return AZ::Transform::CreateTranslation(translate); } void TerrainPhysicsColliderComponent::GenerateHeightsInBounds(AZStd::vector& heights) const From c35f74e9cea14d1e07200a143aae172962df19e6 Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:11:33 +0000 Subject: [PATCH 44/66] Physics/test axis aligned box shape configuration works #7378a (#5366) * Safety commit before merging Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Moved from Physics to Terrain Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Changes from PR + AR fix Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Fixed another AR bug Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Fixed another AR compilation bug Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * More PR changes Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Added virtual destructor Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Added TestSuite_main_Optimized.py Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Changes from PR Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Further fixes for PR Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Fix to editor_test.py Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Testing prefab level Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Testing slice level Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Testing prefab level Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> * Disabled orefab loading for the time being. Signed-off-by: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> --- AutomatedTesting/Gem/Code/enabled_gems.cmake | 1 + .../Gem/PythonTests/CMakeLists.txt | 3 + .../Gem/PythonTests/Terrain/CMakeLists.txt | 24 +++++ ...angesSizeWithAxisAlignedBoxShapeChanges.py | 90 +++++++++++++++++++ .../Gem/PythonTests/Terrain/TestSuite_Main.py | 25 ++++++ .../Gem/PythonTests/Terrain/__init__.py | 6 ++ AutomatedTesting/Levels/Base/Base.prefab | 53 +++++++++++ .../AzFramework/Application/Application.cpp | 3 + .../Physics/HeightfieldProviderBus.cpp | 46 ++++++++++ .../Physics/HeightfieldProviderBus.h | 33 +++++++ .../AzFramework/Physics/Material.cpp | 5 ++ .../AzFramework/azframework_files.cmake | 1 + .../MockPhysXHeightfieldProviderComponent.h | 4 + .../TerrainPhysicsColliderComponent.cpp | 34 +++++++ .../TerrainPhysicsColliderComponent.h | 4 + .../ly_test_tools/o3de/editor_test.py | 1 + system_windows_pc.cfg | 1 + 17 files changed, 334 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py create mode 100644 AutomatedTesting/Gem/PythonTests/Terrain/__init__.py create mode 100644 AutomatedTesting/Levels/Base/Base.prefab create mode 100644 Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index f653a54505..7d33a65bc7 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -54,5 +54,6 @@ set(ENABLED_GEMS AWSMetrics PrefabBuilder AudioSystem + Terrain Profiler ) diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index fd3222ba83..d2b7075e22 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -56,6 +56,9 @@ add_subdirectory(streaming) ## Smoke ## add_subdirectory(smoke) +## Terrain ## +add_subdirectory(Terrain) + ## AWS ## add_subdirectory(AWS) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt new file mode 100644 index 0000000000..9f8ba06829 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/CMakeLists.txt @@ -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 +# +# + +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_pytest( + NAME AutomatedTesting::TerrainTests_Main + TEST_SUITE main + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py + RUNTIME_DEPENDENCIES + Legacy::Editor + AZ::AssetProcessor + AutomatedTesting.Assets + COMPONENT + Terrain + ) + +endif() diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py new file mode 100644 index 0000000000..aba506ea20 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/EditorScripts/TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges.py @@ -0,0 +1,90 @@ +""" +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 +""" + +#fmt: off +class Tests(): + create_test_entity = ("Entity created successfully", "Failed to create Entity") + add_axis_aligned_box_shape = ("Axis Aligned Box Shape component added", "Failed to add Axis Aligned Box Shape component") + add_terrain_collider = ("Terrain Physics Heightfield Collider component added", "Failed to add a Terrain Physics Heightfield Collider component") + box_dimensions_changed = ("Aabb dimensions changed successfully", "Failed change Aabb dimensions") + configuration_changed = ("Terrain size changed successfully", "Failed terrain size change") + no_errors_and_warnings_found = ("No errors and warnings found", "Found errors and warnings") +#fmt: on + +def TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges(): + """ + Summary: + Test aspects of the TerrainHeightGradientList through the BehaviorContext and the Property Tree. + + Test Steps: + Expected Behavior: + The Editor is stable there are no warnings or errors. + + Test Steps: + 1) Load the base level + 2) Create test entity + 3) Start the Tracer to catch any errors and warnings + 4) Add the Axis Aligned Box Shape and Terrain Physics Heightfield Collider components + 5) Change the Axis Aligned Box Shape dimensions + 6) Check the Heightfield provider is returning the correct size + 7) Verify there are no errors and warnings in the logs + + + :return: None + """ + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer + import azlmbr.legacy.general as general + import azlmbr.physics as physics + import azlmbr.math as azmath + import azlmbr.bus as bus + import sys + import math + + SET_BOX_X_SIZE = 5.0 + SET_BOX_Y_SIZE = 6.0 + EXPECTED_COLUMN_SIZE = SET_BOX_X_SIZE + 1 + EXPECTED_ROW_SIZE = SET_BOX_Y_SIZE + 1 + helper.init_idle() + + # 1) Load the level + helper.open_level("", "Base") + + # 2) Create test entity + test_entity = EditorEntity.create_editor_entity("TestEntity") + Report.result(Tests.create_test_entity, test_entity.id.IsValid()) + + # 3) Start the Tracer to catch any errors and warnings + with Tracer() as section_tracer: + # 4) Add the Axis Aligned Box Shape and Terrain Physics Heightfield Collider components + aaBoxShape_component = test_entity.add_component("Axis Aligned Box Shape") + Report.result(Tests.add_axis_aligned_box_shape, test_entity.has_component("Axis Aligned Box Shape")) + terrainPhysics_component = test_entity.add_component("Terrain Physics Heightfield Collider") + Report.result(Tests.add_terrain_collider, test_entity.has_component("Terrain Physics Heightfield Collider")) + + # 5) Change the Axis Aligned Box Shape dimensions + aaBoxShape_component.set_component_property_value("Axis Aligned Box Shape|Box Configuration|Dimensions", azmath.Vector3(SET_BOX_X_SIZE, SET_BOX_Y_SIZE, 1.0)) + add_check = aaBoxShape_component.get_component_property_value("Axis Aligned Box Shape|Box Configuration|Dimensions") == azmath.Vector3(SET_BOX_X_SIZE, SET_BOX_Y_SIZE, 1.0) + Report.result(Tests.box_dimensions_changed, add_check) + + # 6) Check the Heightfield provider is returning the correct size + columns = physics.HeightfieldProviderRequestsBus(bus.Broadcast, "GetHeightfieldGridColumns") + rows = physics.HeightfieldProviderRequestsBus(bus.Broadcast, "GetHeightfieldGridRows") + Report.result(Tests.configuration_changed, math.isclose(columns, EXPECTED_COLUMN_SIZE) and math.isclose(rows, EXPECTED_ROW_SIZE)) + + helper.wait_for_condition(lambda: section_tracer.has_errors or section_tracer.has_asserts, 1.0) + for error_info in section_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in section_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges) diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py new file mode 100644 index 0000000000..620d84d7db --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/TestSuite_Main.py @@ -0,0 +1,25 @@ +""" +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 + +""" + +# This suite consists of all test cases that are passing and have been verified. + +import pytest +import os +import sys + +from ly_test_tools import LAUNCHERS +from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + #global_extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"] + + class test_AxisAlignedBoxShape_ConfigurationWorks(EditorSingleTest): + from .EditorScripts import TerrainPhysicsCollider_ChangesSizeWithAxisAlignedBoxShapeChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py b/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py new file mode 100644 index 0000000000..f5193b300e --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Terrain/__init__.py @@ -0,0 +1,6 @@ +""" +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 +""" diff --git a/AutomatedTesting/Levels/Base/Base.prefab b/AutomatedTesting/Levels/Base/Base.prefab new file mode 100644 index 0000000000..f7e42e7731 --- /dev/null +++ b/AutomatedTesting/Levels/Base/Base.prefab @@ -0,0 +1,53 @@ +{ + "ContainerEntity": { + "Id": "Entity_[1146574390643]", + "Name": "Level", + "Components": { + "Component_[10641544592923449938]": { + "$type": "EditorInspectorComponent", + "Id": 10641544592923449938 + }, + "Component_[12039882709170782873]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12039882709170782873 + }, + "Component_[12265484671603697631]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12265484671603697631 + }, + "Component_[14126657869720434043]": { + "$type": "EditorEntitySortComponent", + "Id": 14126657869720434043 + }, + "Component_[15230859088967841193]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15230859088967841193, + "Parent Entity": "" + }, + "Component_[16239496886950819870]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 16239496886950819870 + }, + "Component_[5688118765544765547]": { + "$type": "EditorEntityIconComponent", + "Id": 5688118765544765547 + }, + "Component_[6545738857812235305]": { + "$type": "SelectionComponent", + "Id": 6545738857812235305 + }, + "Component_[7247035804068349658]": { + "$type": "EditorPrefabComponent", + "Id": 7247035804068349658 + }, + "Component_[9307224322037797205]": { + "$type": "EditorLockComponent", + "Id": 9307224322037797205 + }, + "Component_[9562516168917670048]": { + "$type": "EditorVisibilityComponent", + "Id": 9562516168917670048 + } + } + } +} \ No newline at end of file diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index 323e834413..b6b09148eb 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include "Application.h" #include @@ -318,6 +319,8 @@ namespace AzFramework AzFramework::SurfaceData::SurfaceTagWeight::Reflect(context); AzFramework::SurfaceData::SurfacePoint::Reflect(context); AzFramework::Terrain::TerrainDataRequests::Reflect(context); + Physics::HeightfieldProviderRequests::Reflect(context); + Physics::HeightMaterialPoint::Reflect(context); if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) { diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp new file mode 100644 index 0000000000..38fac9655c --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.cpp @@ -0,0 +1,46 @@ +/* + * 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 "HeightfieldProviderBus.h" +#include +#include +#include + +namespace Physics +{ + void HeightfieldProviderRequests::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("HeightfieldProviderRequestsBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Module, "physics") + ->Attribute(AZ::Script::Attributes::Category, "PhysX") + ->Event("GetHeightfieldGridSpacing", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSpacing) + ->Event("GetHeightfieldAabb", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldAabb) + ->Event("GetHeightfieldTransform", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldTransform) + ->Event("GetMaterialList", &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList) + ->Event("GetHeights", &Physics::HeightfieldProviderRequestsBus::Events::GetHeights) + ->Event("GetHeightsAndMaterials", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials) + ->Event("GetHeightfieldMinHeight", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldMinHeight) + ->Event("GetHeightfieldMaxHeight", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldMaxHeight) + ->Event("GetHeightfieldGridColumns", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridColumns) + ->Event("GetHeightfieldGridRows", &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridRows) + ; + } + } + + void HeightMaterialPoint::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class()->Attribute(AZ::Script::Attributes::Category, "Physics"); + } + } + +} // namespace Physics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h index 73523ee1ba..da361f0a2b 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h @@ -26,10 +26,25 @@ namespace Physics struct HeightMaterialPoint { + HeightMaterialPoint( + float height = 0.0f, QuadMeshType type = QuadMeshType::SubdivideUpperLeftToBottomRight, uint8_t index = 0) + : m_height(height) + , m_quadMeshType(type) + , m_materialIndex(index) + , m_padding(0) + { + } + + virtual ~HeightMaterialPoint() = default; + + static void Reflect(AZ::ReflectContext* context); + + AZ_RTTI(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}"); float m_height{ 0.0f }; //!< Holds the height of this point in the heightfield relative to the heightfield entity location. QuadMeshType m_quadMeshType{ QuadMeshType::SubdivideUpperLeftToBottomRight }; //!< By default, create two triangles like this |\|, where this point is in the upper left corner. uint8_t m_materialIndex{ 0 }; //!< The surface material index for the upper left corner of this quad. uint16_t m_padding{ 0 }; //!< available for future use. + }; //! An interface to provide heightfield values. @@ -37,6 +52,8 @@ namespace Physics : public AZ::ComponentBus { public: + static void Reflect(AZ::ReflectContext* context); + //! Returns the distance between each height in the map. //! @return Vector containing Column Spacing, Rows Spacing. virtual AZ::Vector2 GetHeightfieldGridSpacing() const = 0; @@ -46,11 +63,27 @@ namespace Physics //! @param numRows contains the size of the grid in the y direction. virtual void GetHeightfieldGridSize(int32_t& numColumns, int32_t& numRows) const = 0; + //! Returns the height field gridsize columns. + //! @return the size of the grid in the x direction. + virtual int32_t GetHeightfieldGridColumns() const = 0; + + //! Returns the height field gridsize rows. + //! @return the size of the grid in the y direction. + virtual int32_t GetHeightfieldGridRows() const = 0; + //! Returns the height field min and max height bounds. //! @param minHeightBounds contains the minimum height that the heightfield can contain. //! @param maxHeightBounds contains the maximum height that the heightfield can contain. virtual void GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const = 0; + //! Returns the height field min height bounds. + //! @return the minimum height that the heightfield can contain. + virtual float GetHeightfieldMinHeight() const = 0; + + //! Returns the height field max height bounds. + //! @return the maximum height that the heightfield can contain. + virtual float GetHeightfieldMaxHeight() const = 0; + //! Returns the AABB of the heightfield. //! This is provided separately from the shape AABB because the heightfield might choose to modify the AABB bounds. //! @return AABB of the heightfield. diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp index 222bc48dda..d78d4e0943 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Material.cpp @@ -360,6 +360,11 @@ namespace Physics ->Field("MaterialId", &Physics::MaterialId::m_id) ; } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->Class()->Attribute(AZ::Script::Attributes::Category, "Physics"); + } } MaterialId MaterialId::Create() diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index e03d166cfc..13d9003031 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -229,6 +229,7 @@ set(FILES Physics/Configuration/SystemConfiguration.h Physics/Configuration/SystemConfiguration.cpp Physics/HeightfieldProviderBus.h + Physics/HeightfieldProviderBus.cpp Physics/SimulatedBodies/RigidBody.h Physics/SimulatedBodies/RigidBody.cpp Physics/SimulatedBodies/StaticRigidBody.h diff --git a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h index 7e500881c0..d462c30158 100644 --- a/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h +++ b/Gems/PhysX/Code/Mocks/PhysX/MockPhysXHeightfieldProviderComponent.h @@ -69,6 +69,10 @@ namespace UnitTest MOCK_CONST_METHOD1(UpdateHeights, AZStd::vector(const AZ::Aabb& dirtyRegion)); MOCK_CONST_METHOD1(UpdateHeightsAndMaterials, AZStd::vector(const AZ::Aabb& dirtyRegion)); MOCK_CONST_METHOD0(GetHeightfieldAabb, AZ::Aabb()); + MOCK_CONST_METHOD0(GetHeightfieldMinHeight, float()); + MOCK_CONST_METHOD0(GetHeightfieldMaxHeight, float()); + MOCK_CONST_METHOD0(GetHeightfieldGridColumns, int32_t()); + MOCK_CONST_METHOD0(GetHeightfieldGridRows, int32_t()); }; } // namespace UnitTest diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 9262937317..6c76e90fd0 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -193,6 +193,22 @@ namespace Terrain minHeightBounds = -maxHeightBounds; } + float TerrainPhysicsColliderComponent::GetHeightfieldMinHeight() const + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + GetHeightfieldHeightBounds(minHeightBounds, maxHeightBounds); + return minHeightBounds; + } + + float TerrainPhysicsColliderComponent::GetHeightfieldMaxHeight() const + { + float minHeightBounds{ 0.0f }; + float maxHeightBounds{ 0.0f }; + GetHeightfieldHeightBounds(minHeightBounds, maxHeightBounds); + return maxHeightBounds; + } + AZ::Transform TerrainPhysicsColliderComponent::GetHeightfieldTransform() const { // We currently don't support rotation of terrain heightfields. @@ -296,6 +312,24 @@ namespace Terrain numRows = aznumeric_cast((bounds.GetMax().GetY() - bounds.GetMin().GetY()) / gridResolution.GetY()); } + int32_t TerrainPhysicsColliderComponent::GetHeightfieldGridColumns() const + { + int32_t numColumns{ 0 }; + int32_t numRows{ 0 }; + + GetHeightfieldGridSize(numColumns, numRows); + return numColumns; + } + + int32_t TerrainPhysicsColliderComponent::GetHeightfieldGridRows() const + { + int32_t numColumns{ 0 }; + int32_t numRows{ 0 }; + + GetHeightfieldGridSize(numColumns, numRows); + return numRows; + } + AZStd::vector TerrainPhysicsColliderComponent::GetMaterialList() const { return AZStd::vector(); diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h index e268223689..6462909c89 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.h @@ -58,7 +58,11 @@ namespace Terrain // HeightfieldProviderRequestsBus AZ::Vector2 GetHeightfieldGridSpacing() const override; void GetHeightfieldGridSize(int32_t& numColumns, int32_t& numRows) const override; + int32_t GetHeightfieldGridColumns() const override; + int32_t GetHeightfieldGridRows() const override; void GetHeightfieldHeightBounds(float& minHeightBounds, float& maxHeightBounds) const override; + float GetHeightfieldMinHeight() const override; + float GetHeightfieldMaxHeight() const override; AZ::Aabb GetHeightfieldAabb() const override; AZ::Transform GetHeightfieldTransform() const override; AZStd::vector GetMaterialList() const override; diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 781977cf33..392838d180 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -634,6 +634,7 @@ class EditorTestSuite(): else: test_result = Result.Fail.create(test_spec, output, editor_log_content) except WaitTimeoutError: + output = editor.get_output() editor.kill() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) test_result = Result.Timeout.create(test_spec, output, test_spec.timeout, editor_log_content) diff --git a/system_windows_pc.cfg b/system_windows_pc.cfg index aa53ed9323..e34c35e581 100644 --- a/system_windows_pc.cfg +++ b/system_windows_pc.cfg @@ -15,3 +15,4 @@ r_ShadersAllowCompilation = 1 -- Localization Settings sys_localization_format=0 +log_RemoteConsoleAllowedAddresses=127.0.0.1 From bff8a2e147f66403b19f9658d556c5be9c6aaedc Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:00:26 +0000 Subject: [PATCH 45/66] improved fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Components/TerrainSurfaceMaterialsListComponent.cpp | 7 +------ .../Components/TerrainSurfaceMaterialsListComponent.h | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp index 7da6130f7b..1dbcbd1120 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp @@ -112,11 +112,6 @@ namespace Terrain { } - TerrainSurfaceMaterialsListComponent ::~TerrainSurfaceMaterialsListComponent() - { - Deactivate(); - } - void TerrainSurfaceMaterialsListComponent::Activate() { m_cachedAabb = AZ::Aabb::CreateNull(); @@ -243,7 +238,7 @@ namespace Terrain // All materials have been deactivated, stop listening for requests and notifications. m_cachedAabb = AZ::Aabb::CreateNull(); LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect(); - TerrainAreaMaterialRequestBus::Handler::BusConnect(GetEntityId()); + TerrainAreaMaterialRequestBus::Handler::BusDisconnect(); } } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h index a6650bf035..72eee5f68e 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h @@ -67,7 +67,7 @@ namespace Terrain TerrainSurfaceMaterialsListComponent(const TerrainSurfaceMaterialsListConfig& configuration); TerrainSurfaceMaterialsListComponent() = default; - ~TerrainSurfaceMaterialsListComponent(); + ~TerrainSurfaceMaterialsListComponent() = default; ////////////////////////////////////////////////////////////////////////// // AZ::Component interface implementation From d053a03b5f0675735327aaaf870d076e9ac4d4be Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 9 Nov 2021 09:38:23 -0800 Subject: [PATCH 46/66] Don't update status filter when filling gem model (#5427) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 79935ed235..542da87196 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -90,6 +90,13 @@ namespace O3DE::ProjectManager m_projectPath = projectPath; m_gemModel->Clear(); m_gemsToRegisterWithProject.clear(); + + if (m_filterWidget) + { + // disconnect so we don't update the status filter for every gem we add + disconnect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter); + } + FillModel(projectPath); m_proxyModel->ResetFilters(); From c182b213ad8a4f965fd2f6e786b05103b0ce4204 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Tue, 9 Nov 2021 10:02:11 -0800 Subject: [PATCH 47/66] Remove timeout in the mount step We no longer need a timeout here. A timeout mechanism was added to the mount script to raise an exeception if the EBS volume is not mounted in the configured timeframe. This also causes a bug with the retry mechanism where Jenkins will hit this timeout in the event the node goes offline during the setup stage instead of raising an exception. Signed-off-by: brianherrera --- scripts/build/Jenkins/Jenkinsfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 1388366661..34732a5fad 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -277,9 +277,7 @@ def HandleDriveMount(String snapshot, String repositoryName, String projectName, if(recreateVolume) { palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action delete --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Deleting volume', winSlashReplacement=false) } - timeout(5) { - palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --snapshot ${snapshot} --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume', winSlashReplacement=false) - } + palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --snapshot ${snapshot} --repository_name ${repositoryName} --project ${projectName} --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume', winSlashReplacement=false) if(env.IS_UNIX) { sh label: 'Setting volume\'s ownership', From 5fc4551ac0db22e2c57144ad43afaf69255a6a36 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 9 Nov 2021 12:03:52 -0600 Subject: [PATCH 48/66] [LYN-8041] Enable relocation of the Project Game Release Layout (#5380) * Enable relocation of the Project Game Release Layout Relocating the Project Game Release Layout to another directory on the file system failed due to the querying of the engine root failing due to the ComponentApplication::m_engineRoot not using the project path stored in the SettingsRegisry if the engine root cannot be detected Removed the ApplicationRequestBus GetEngineRoot function. The ComponentApplicationRequestBus has a function of the same name that returns the same path. Removed the deprecated GetAppRoot function. The path it returns has no defined value. It was not the engine root or the project root. Removed unused CFileUtil and CFileUtil_impl functions that were invoking the ApplicationREquestBus GetEngineRoot function. On the way to update the functions it was discovered that they aren't called Added a CalculateBranchToken overload that can populate a fixed_string to avoid heap allocations Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Protect against an empty list of artifacts to remove when generating the engine.pak Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 7 +- Code/Editor/Include/IFileUtil.h | 2 - Code/Editor/Util/FileUtil.cpp | 140 +----------------- Code/Editor/Util/FileUtil.h | 5 - Code/Editor/Util/FileUtil_impl.cpp | 10 -- Code/Editor/Util/FileUtil_impl.h | 2 - Code/Editor/Util/PathUtil.cpp | 6 +- .../WelcomeScreen/WelcomeScreenDialog.cpp | 5 - .../AzCore/Component/ComponentApplication.cpp | 52 +++---- .../AzCore/Component/ComponentApplication.h | 19 +-- .../Component/ComponentApplicationBus.h | 4 - .../Settings/SettingsRegistryMergeUtils.cpp | 4 +- .../AzCore/AzCore/StringFunc/StringFunc.cpp | 44 +++--- .../AzCore/AzCore/StringFunc/StringFunc.h | 5 +- .../UnitTest/MockComponentApplication.h | 1 - .../AzCore/Tests/BehaviorContextFixture.h | 1 - Code/Framework/AzCore/Tests/Components.cpp | 20 +-- Code/Framework/AzCore/Tests/Serialization.cpp | 1 - .../AzFramework/API/ApplicationAPI.h | 6 - .../AzFramework/Application/Application.cpp | 42 +----- .../AzFramework/Application/Application.h | 12 +- .../AzToolsFramework/Asset/AssetUtils.cpp | 20 +-- .../AzToolsFramework/Asset/AssetUtils.h | 2 +- .../Thumbnails/SourceThumbnail.cpp | 10 +- .../Thumbnails/SourceControlThumbnail.cpp | 18 +-- .../Tests/ComponentAddRemove.cpp | 1 - .../Tests/UI/EntityPropertyEditorTests.cpp | 5 - .../source/utils/GUIApplicationManager.cpp | 4 +- .../source/utils/applicationManager.cpp | 1 - .../Tools/AssetBundler/source/utils/utils.cpp | 3 +- Code/Tools/AssetBundler/source/utils/utils.h | 1 - Code/Tools/AssetBundler/tests/UtilsTests.cpp | 16 +- .../tests/applicationManagerTests.cpp | 11 +- .../platformconfigurationtests.cpp | 36 +++-- .../utilities/PlatformConfiguration.cpp | 2 +- .../source/Application.cpp | 1 - .../Tests/Containers/SceneBehaviorTests.cpp | 1 - .../Tools/SerializeContextTools/Converter.cpp | 8 +- Code/Tools/SerializeContextTools/Converter.h | 2 +- .../Code/Tests/AWSClientAuthGemMock.h | 1 - .../Source/AssetValidationSystemComponent.cpp | 21 +-- .../Code/Tests/AssetValidationTestShared.h | 9 +- .../Code/Tests/ImageProcessing_Test.cpp | 1 - .../Code/Source/LuxCore/LuxCoreRenderer.cpp | 9 +- .../Code/Tests.Builders/BuilderTestFixture.h | 1 - .../Tests/Common/AssetManagerTestFixture.h | 1 - .../Code/Source/Util/Util.cpp | 27 +--- .../Code/Include/Atom/Utils/ImGuiPassTree.inl | 9 +- .../Source/Editor/ImplementationManager.cpp | 6 - .../Code/Source/PythonSystemComponent.cpp | 5 +- .../Code/Tests/PythonTestingUtility.h | 4 - .../Code/Tests/Builders/SliceBuilderTests.cpp | 1 - .../Code/Tests/CommonBenchmarkSetup.h | 1 - Gems/Multiplayer/Code/Tests/MockInterfaces.h | 1 - Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp | 5 +- .../Code/Tests/ScriptCanvasBuilderTests.cpp | 1 - .../Framework/ScriptCanvasTestFixture.h | 8 - cmake/Projects.cmake | 4 +- 58 files changed, 168 insertions(+), 477 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 5cffedd774..0ea22e8ce3 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -3974,9 +3974,8 @@ void CCryEditApp::OpenLUAEditor(const char* files) } } - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot != nullptr, "Unable to communicate to AzFramework::ApplicationRequests::Bus"); + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Unable to query Engine Path"); AZStd::string_view exePath; AZ::ComponentApplicationBus::BroadcastResult(exePath, &AZ::ComponentApplicationRequests::GetExecutableFolder); @@ -3995,7 +3994,7 @@ void CCryEditApp::OpenLUAEditor(const char* files) #endif "%s", argumentQuoteString, aznumeric_cast(exePath.size()), exePath.data(), argumentQuoteString); - AZStd::string processArgs = AZStd::string::format("%s -engine-path \"%s\"", args.c_str(), engineRoot); + AZStd::string processArgs = AZStd::string::format("%s -engine-path \"%s\"", args.c_str(), engineRoot.c_str()); StartProcessDetached(process.c_str(), processArgs.c_str()); } diff --git a/Code/Editor/Include/IFileUtil.h b/Code/Editor/Include/IFileUtil.h index e179f892d9..4d5f6e23c4 100644 --- a/Code/Editor/Include/IFileUtil.h +++ b/Code/Editor/Include/IFileUtil.h @@ -114,9 +114,7 @@ struct IFileUtil virtual void ShowInExplorer(const QString& path) = 0; - virtual bool CompileLuaFile(const char* luaFilename) = 0; virtual bool ExtractFile(QString& file, bool bMsgBoxAskForExtraction = true, const char* pDestinationFilename = nullptr) = 0; - virtual void EditTextFile(const char* txtFile, int line = 0, ETextFileType fileType = FILE_TYPE_SCRIPT) = 0; virtual void EditTextureFile(const char* txtureFile, bool bUseGameFolder) = 0; //! dcc filename calculation and extraction sub-routines diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp index baca69d628..36c1879407 100644 --- a/Code/Editor/Util/FileUtil.cpp +++ b/Code/Editor/Util/FileUtil.cpp @@ -23,9 +23,9 @@ // AzCore #include #include +#include // AzFramework -#include // AzQtComponents #include @@ -62,84 +62,6 @@ CAutoRestorePrimaryCDRoot::~CAutoRestorePrimaryCDRoot() QDir::setCurrent(GetIEditor()->GetPrimaryCDFolder()); } -bool CFileUtil::CompileLuaFile(const char* luaFilename) -{ - QString luaFile = luaFilename; - - if (luaFile.isEmpty()) - { - return false; - } - - // Check if this file is in Archive. - { - CCryFile file; - if (file.Open(luaFilename, "rb")) - { - // Check if in pack. - if (file.IsInPak()) - { - return true; - } - } - } - - luaFile = Path::GamePathToFullPath(luaFilename); - - // First try compiling script and see if it have any errors. - QString LuaCompiler; - QString CompilerOutput; - - // Create the filepath of the lua compiler - QString szExeFileName = qApp->applicationFilePath(); - QString exePath = Path::GetPath(szExeFileName); - -#if defined(AZ_PLATFORM_WINDOWS) - const char* luaCompiler = "LuaCompiler.exe"; -#else - const char* luaCompiler = "lua"; -#endif - LuaCompiler = Path::AddPathSlash(exePath) + luaCompiler + " "; - - AZStd::string path = luaFile.toUtf8().data(); - EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, path); - - QString finalPath = path.c_str(); - finalPath = "\"" + finalPath + "\""; - - // Add the name of the Lua file - QString cmdLine = LuaCompiler + finalPath; - - // Execute the compiler and capture the output - if (!GetIEditor()->ExecuteConsoleApp(cmdLine, CompilerOutput)) - { - QMessageBox::critical(QApplication::activeWindow(), QString(), QObject::tr("Error while executing '%1', make sure the file is in" \ - " your Primary CD folder !").arg(luaCompiler)); - return false; - } - - // Check return string - if (!CompilerOutput.isEmpty()) - { - // Errors while compiling file. - - // Show output from Lua compiler - if (QMessageBox::critical(QApplication::activeWindow(), QObject::tr("Lua Compiler"), - QObject::tr("Error output from Lua compiler:\r\n%1\r\nDo you want to edit the file ?").arg(CompilerOutput), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) - { - int line = 0; - int index = CompilerOutput.indexOf("at line"); - if (index >= 0) - { - azsscanf(CompilerOutput.mid(index).toUtf8().data(), "at line %d", &line); - } - // Open the Lua file for editing - EditTextFile(luaFile.toUtf8().data(), line); - } - return false; - } - return true; -} ////////////////////////////////////////////////////////////////////////// bool CFileUtil::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const char* pDestinationFilename) { @@ -205,7 +127,7 @@ void CFileUtil::EditTextFile(const char* txtFile, int line, IFileUtil::ETextFile { QString file = txtFile; - QString fullPathName = Path::GamePathToFullPath(file); + QString fullPathName = Path::GamePathToFullPath(file); ExtractFile(fullPathName); QString cmd(fullPathName); #if defined (AZ_PLATFORM_WINDOWS) @@ -301,64 +223,6 @@ void CFileUtil::EditTextureFile(const char* textureFile, [[maybe_unused]] bool b } } -////////////////////////////////////////////////////////////////////////// -bool CFileUtil::EditMayaFile(const char* filepath, const bool bExtractFromPak, const bool bUseGameFolder) -{ - QString dosFilepath = PathUtil::ToDosPath(filepath).c_str(); - if (bExtractFromPak) - { - ExtractFile(dosFilepath); - } - - if (bUseGameFolder) - { - const QString sGameFolder = Path::GetEditingGameDataFolder().c_str(); - int nLength = sGameFolder.toUtf8().count(); - if (azstrnicmp(filepath, sGameFolder.toUtf8().data(), nLength) != 0) - { - dosFilepath = sGameFolder + '\\' + filepath; - } - - dosFilepath = PathUtil::ToDosPath(dosFilepath.toUtf8().data()).c_str(); - } - - const char* engineRoot; - EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - - const QString fullPath = QString(engineRoot) + '\\' + dosFilepath; - - if (gSettings.animEditor.isEmpty()) - { - AzQtComponents::ShowFileOnDesktop(fullPath); - } - else - { - if (!QProcess::startDetached(gSettings.animEditor, { fullPath })) - { - CryMessageBox("Can't open the file. You can specify a source editor in Sandbox Preferences or create an association in Windows.", "Cannot open file!", MB_OK | MB_ICONERROR); - } - } - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CFileUtil::EditFile(const char* filePath, const bool bExtrackFromPak, const bool bUseGameFolder) -{ - QString extension = filePath; - extension.remove(0, extension.lastIndexOf('.')); - - if (extension.compare(".ma") == 0) - { - return EditMayaFile(filePath, bExtrackFromPak, bUseGameFolder); - } - else if ((extension.compare(".bspace") == 0) || (extension.compare(".comb") == 0)) - { - EditTextFile(filePath, 0, IFileUtil::FILE_TYPE_BSPACE); - return true; - } - - return false; -} ////////////////////////////////////////////////////////////////////////// bool CFileUtil::CalculateDccFilename(const QString& assetFilename, QString& dccFilename) diff --git a/Code/Editor/Util/FileUtil.h b/Code/Editor/Util/FileUtil.h index 5820c32081..fc0fc942fe 100644 --- a/Code/Editor/Util/FileUtil.h +++ b/Code/Editor/Util/FileUtil.h @@ -25,14 +25,9 @@ public: static void ShowInExplorer(const QString& path); - // Try to compile the given lua file: returns true if compilation succeeded, false on failure. - static bool CompileLuaFile(const char* luaFilename); - static bool ExtractFile(QString& file, bool bMsgBoxAskForExtraction = true, const char* pDestinationFilename = nullptr); static void EditTextFile(const char* txtFile, int line = 0, IFileUtil::ETextFileType fileType = IFileUtil::FILE_TYPE_SCRIPT); static void EditTextureFile(const char* txtureFile, bool bUseGameFolder); - static bool EditMayaFile(const char* mayaFile, const bool bExtractFromPak, const bool bUseGameFolder); - static bool EditFile(const char* filePath, const bool bExtrackFromPak, const bool bUseGameFolder); //! dcc filename calculation and extraction sub-routines static bool CalculateDccFilename(const QString& assetFilename, QString& dccFilename); diff --git a/Code/Editor/Util/FileUtil_impl.cpp b/Code/Editor/Util/FileUtil_impl.cpp index 0dd3a0ca87..28090d28d5 100644 --- a/Code/Editor/Util/FileUtil_impl.cpp +++ b/Code/Editor/Util/FileUtil_impl.cpp @@ -20,21 +20,11 @@ void CFileUtil_impl::ShowInExplorer(const QString& path) CFileUtil::ShowInExplorer(path); } -bool CFileUtil_impl::CompileLuaFile(const char* luaFilename) -{ - return CFileUtil::CompileLuaFile(luaFilename); -} - bool CFileUtil_impl::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const char* pDestinationFilename) { return CFileUtil::ExtractFile(file, bMsgBoxAskForExtraction, pDestinationFilename); } -void CFileUtil_impl::EditTextFile(const char* txtFile, int line, ETextFileType fileType) -{ - CFileUtil::EditTextFile(txtFile, line, fileType); -} - void CFileUtil_impl::EditTextureFile(const char* txtureFile, bool bUseGameFolder) { CFileUtil::EditTextureFile(txtureFile, bUseGameFolder); diff --git a/Code/Editor/Util/FileUtil_impl.h b/Code/Editor/Util/FileUtil_impl.h index 04d9e829b9..aa8d0bf3b5 100644 --- a/Code/Editor/Util/FileUtil_impl.h +++ b/Code/Editor/Util/FileUtil_impl.h @@ -36,9 +36,7 @@ public: void ShowInExplorer(const QString& path) override; - bool CompileLuaFile(const char* luaFilename) override; bool ExtractFile(QString& file, bool bMsgBoxAskForExtraction = true, const char* pDestinationFilename = nullptr) override; - void EditTextFile(const char* txtFile, int line = 0, ETextFileType fileType = FILE_TYPE_SCRIPT) override; void EditTextureFile(const char* txtureFile, bool bUseGameFolder) override; //! dcc filename calculation and extraction sub-routines diff --git a/Code/Editor/Util/PathUtil.cpp b/Code/Editor/Util/PathUtil.cpp index ca3481ddae..8b745ee1bc 100644 --- a/Code/Editor/Util/PathUtil.cpp +++ b/Code/Editor/Util/PathUtil.cpp @@ -14,7 +14,6 @@ #include #include #include // for ebus events -#include #include #include @@ -175,9 +174,8 @@ namespace Path ////////////////////////////////////////////////////////////////////////// QString GetEngineRootPath() { - const char* engineRoot; - EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - return QString(engineRoot); + const AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + return QString::fromUtf8(engineRoot.c_str(), static_cast(engineRoot.size())); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp index 17f576b5ee..89dfcaffd1 100644 --- a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp +++ b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp @@ -25,8 +25,6 @@ #include -// AzFramework -#include // AzToolsFramework #include @@ -173,9 +171,6 @@ void WelcomeScreenDialog::SetRecentFileList(RecentFileList* pList) m_pRecentList = pList; - const char* engineRoot; - EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); - auto projectPath = AZ::Utils::GetProjectPath(); QString gamePath{projectPath.c_str()}; Path::ConvertSlashToBackSlash(gamePath); diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index ad7e44c2ae..bd225cf634 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -485,16 +485,6 @@ namespace AZ constexpr bool executeRegDumpCommands = false; SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); - // Query for the Executable Path using OS specific functions - CalculateExecutablePath(); - - // Determine the path to the engine - CalculateEngineRoot(); - - // If the current platform returns an engaged optional from Utils::GetDefaultAppRootPath(), that is used - // for the application root. - CalculateAppRoot(); - SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(*m_settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, {}); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry); @@ -614,7 +604,8 @@ namespace AZ { AZ_Assert(!m_isStarted, "Component application already started!"); - if (m_engineRoot.empty()) + using Type = AZ::SettingsRegistryInterface::Type; + if (m_settingsRegistry->GetType(SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder) == Type::NoType) { ReportBadEngineRoot(); return nullptr; @@ -1180,6 +1171,24 @@ namespace AZ return ReflectionEnvironment::GetReflectionManager() ? ReflectionEnvironment::GetReflectionManager()->GetReflectContext() : nullptr; } + /// Returns the path to the engine. + + const char* ComponentApplication::GetEngineRoot() const + { + static IO::FixedMaxPathString engineRoot; + engineRoot.clear(); + m_settingsRegistry->Get(engineRoot, SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + return engineRoot.c_str(); + } + + const char* ComponentApplication::GetExecutableFolder() const + { + static IO::FixedMaxPathString exeFolder; + exeFolder.clear(); + m_settingsRegistry->Get(exeFolder, SettingsRegistryMergeUtils::FilePathKey_BinaryFolder); + return exeFolder.c_str(); + } + //========================================================================= // CreateReflectionManager //========================================================================= @@ -1485,27 +1494,6 @@ namespace AZ } } - //========================================================================= - // CalculateExecutablePath - //========================================================================= - void ComponentApplication::CalculateExecutablePath() - { - m_exeDirectory = Utils::GetExecutableDirectory(); - } - - void ComponentApplication::CalculateAppRoot() - { - if (AZStd::optional appRootPath = Utils::GetDefaultAppRootPath(); appRootPath) - { - m_appRoot = AZStd::move(*appRootPath); - } - } - - void ComponentApplication::CalculateEngineRoot() - { - m_engineRoot = AZ::SettingsRegistryMergeUtils::FindEngineRoot(*m_settingsRegistry).Native(); - } - void ComponentApplication::ResolveModulePath([[maybe_unused]] AZ::OSString& modulePath) { // No special parsing of the Module Path is done by the Component Application anymore diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index 6df93aff4e..4e551b6c47 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -221,13 +221,10 @@ namespace AZ BehaviorContext* GetBehaviorContext() override; /// Returns the json registration context that has been registered with the app, if there is one. JsonRegistrationContext* GetJsonRegistrationContext() override; - /// Returns the working root folder that has been registered with the app, if there is one. - /// It's expected that derived applications will implement an application root. - const char* GetAppRoot() const override { return m_appRoot.c_str(); } /// Returns the path to the engine. - const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } + const char* GetEngineRoot() const override; /// Returns the path to the folder the executable is in. - const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); } + const char* GetExecutableFolder() const override; ////////////////////////////////////////////////////////////////////////// /// TickRequestBus @@ -352,15 +349,6 @@ namespace AZ /// Adds system components requested by modules and the application to the system entity. void AddRequiredSystemComponents(AZ::Entity* systemEntity); - /// Calculates the directory the application executable comes from. - void CalculateExecutablePath(); - - /// Calculates the root directory of the engine. - void CalculateEngineRoot(); - - /// Deprecated: The term "AppRoot" has no meaning - void CalculateAppRoot(); - template static void NormalizePath(Iterator begin, Iterator end, bool doLowercase = true) { @@ -388,9 +376,6 @@ namespace AZ void* m_fixedMemoryBlock{ nullptr }; //!< Pointer to the memory block allocator, so we can free it OnDestroy. IAllocatorAllocate* m_osAllocator{ nullptr }; EntitySetType m_entities; - AZ::IO::FixedMaxPath m_exeDirectory; - AZ::IO::FixedMaxPath m_engineRoot; - AZ::IO::FixedMaxPath m_appRoot; AZ::SettingsRegistryInterface::NotifyEventHandler m_projectPathChangedHandler; AZ::SettingsRegistryInterface::NotifyEventHandler m_projectNameChangedHandler; diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h index 0c0977384a..feefa95973 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationBus.h @@ -175,10 +175,6 @@ namespace AZ //! the serializers used by the best-effort json serialization. virtual class JsonRegistrationContext* GetJsonRegistrationContext() = 0; - //! Gets the name of the working root folder that was registered with the app. - //! @return a pointer to the name of the app's root folder, if a root folder was registered. - virtual const char* GetAppRoot() const = 0; - //! Gets the path of the working engine folder that the app is a part of. //! @return a pointer to the engine path. virtual const char* GetEngineRoot() const = 0; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 3902bd107c..975217a131 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -266,7 +266,8 @@ namespace AZ::SettingsRegistryMergeUtils // Step 3 locate the project root and attempt to find the engine root using the registered engine // for the project in the project.json file - AZ::IO::FixedMaxPath projectRoot = FindProjectRoot(settingsRegistry); + AZ::IO::FixedMaxPath projectRoot; + settingsRegistry.Get(projectRoot.Native(), FilePathKey_ProjectPath); if (projectRoot.empty()) { return {}; @@ -693,6 +694,7 @@ namespace AZ::SettingsRegistryMergeUtils R"(Project path isn't set in the Settings Registry at "%.*s".)" " Project-related filepaths will be set relative to the executable directory\n", AZ_STRING_ARG(projectPathKey)); + projectPath = exePath; registry.Set(FilePathKey_ProjectPath, exePath.Native()); } diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp index ff30291a70..a953d53c33 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.cpp @@ -1427,26 +1427,36 @@ namespace AZ namespace AssetPath { - void CalculateBranchToken(const AZStd::string& appRootPath, AZStd::string& token) + namespace Internal { - // Normalize the token to prepare for CRC32 calculation - AZStd::string normalized = appRootPath; - - // Strip out any trailing path separators - AZ::StringFunc::Strip(normalized, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING AZ_WRONG_FILESYSTEM_SEPARATOR_STRING,false, false, true); - - // Lower case always - AZStd::to_lower(normalized.begin(), normalized.end()); + AZ::u32 CalculateBranchTokenHash(AZStd::string_view engineRootPath) + { + // Normalize the token to prepare for CRC32 calculation + auto NormalizeEnginePath = [](const char element) -> char + { + // Substitute path separators with '_' and lower case + return element == AZ::IO::WindowsPathSeparator || element == AZ::IO::PosixPathSeparator + ? '_' : static_cast(std::tolower(element)); + }; - // Substitute path separators with '_' - AZStd::replace(normalized.begin(), normalized.end(), '\\', '_'); - AZStd::replace(normalized.begin(), normalized.end(), '/', '_'); + // Trim off trailing path separators + engineRootPath = RStrip(engineRootPath, AZ_CORRECT_AND_WRONG_FILESYSTEM_SEPARATOR); + AZ::IO::FixedMaxPathString enginePath; + AZStd::transform(engineRootPath.begin(), engineRootPath.end(), + AZStd::back_inserter(enginePath), AZStd::move(NormalizeEnginePath)); - // Perform the CRC32 calculation - const AZ::Crc32 branchTokenCrc(normalized.c_str(), normalized.size(), true); - char branchToken[12]; - azsnprintf(branchToken, AZ_ARRAY_SIZE(branchToken), "0x%08X", static_cast(branchTokenCrc)); - token = AZStd::string(branchToken); + // Perform the CRC32 calculation + constexpr bool forceLowercase = true; + return static_cast(AZ::Crc32(enginePath.c_str(), enginePath.size(), forceLowercase)); + } + } + void CalculateBranchToken(AZStd::string_view engineRootPath, AZStd::string& token) + { + token = AZStd::string::format("0x%08X", Internal::CalculateBranchTokenHash(engineRootPath)); + } + void CalculateBranchToken(AZStd::string_view engineRootPath, AZ::IO::FixedMaxPathString& token) + { + token = AZ::IO::FixedMaxPathString::format("0x%08X", Internal::CalculateBranchTokenHash(engineRootPath)); } } diff --git a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h index 1e651afc93..55236a0fff 100644 --- a/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h +++ b/Code/Framework/AzCore/AzCore/StringFunc/StringFunc.h @@ -485,10 +485,11 @@ namespace AZ //! CalculateBranchToken /*! Calculate the branch token that is used for asset processor connection negotiations * - * \param appRootPath - The absolute path of the app root to base the token calculation on + * \param engineRootPath - The absolute path to the engine root to base the token calculation on * \param token - The result of the branch token calculation */ - void CalculateBranchToken(const AZStd::string& appRootPath, AZStd::string& token); + void CalculateBranchToken(AZStd::string_view engineRootPath, AZStd::string& token); + void CalculateBranchToken(AZStd::string_view engineRootPath, AZ::IO::FixedMaxPathString& token); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h index 8f069da9dd..190fa09cb7 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/MockComponentApplication.h @@ -41,7 +41,6 @@ namespace UnitTest MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char* ()); MOCK_CONST_METHOD0(GetEngineRoot, const char* ()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&)); diff --git a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h index 1895f2e35b..3c6d48add7 100644 --- a/Code/Framework/AzCore/Tests/BehaviorContextFixture.h +++ b/Code/Framework/AzCore/Tests/BehaviorContextFixture.h @@ -59,7 +59,6 @@ namespace UnitTest AZ::SerializeContext* GetSerializeContext() override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return m_behaviorContext; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Code/Framework/AzCore/Tests/Components.cpp b/Code/Framework/AzCore/Tests/Components.cpp index 55b1c193b3..013d998c52 100644 --- a/Code/Framework/AzCore/Tests/Components.cpp +++ b/Code/Framework/AzCore/Tests/Components.cpp @@ -1060,26 +1060,21 @@ namespace UnitTest /** * UserSettingsComponent test */ - class UserSettingsTestApp - : public ComponentApplication - , public UserSettingsFileLocatorBus::Handler - { - public: - void SetExecutableFolder(const char* path) - { - m_exeDirectory = path; - } - + class UserSettingsTestApp + : public ComponentApplication + , public UserSettingsFileLocatorBus::Handler + { + public: AZStd::string ResolveFilePath(u32 providerId) override { AZStd::string filePath; if (providerId == UserSettings::CT_GLOBAL) { - filePath = (m_exeDirectory / "GlobalUserSettings.xml").String(); + filePath = (AZ::IO::Path(GetTestFolderPath()) / "GlobalUserSettings.xml").Native(); } else if (providerId == UserSettings::CT_LOCAL) { - filePath = (m_exeDirectory / "LocalUserSettings.xml").String(); + filePath = (AZ::IO::Path(GetTestFolderPath()) / "LocalUserSettings.xml").Native(); } return filePath; } @@ -1117,7 +1112,6 @@ namespace UnitTest ComponentApplication::Descriptor appDesc; appDesc.m_memoryBlocksByteSize = 10 * 1024 * 1024; Entity* systemEntity = app.Create(appDesc); - app.SetExecutableFolder(GetTestFolderPath().c_str()); app.UserSettingsFileLocatorBus::Handler::BusConnect(); // Make sure user settings file does not exist at this point diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index f1d5edc490..219744a480 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -1240,7 +1240,6 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h b/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h index 1c5db0a82b..e536082d61 100644 --- a/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h +++ b/Code/Framework/AzFramework/AzFramework/API/ApplicationAPI.h @@ -67,12 +67,6 @@ namespace AzFramework /// Make path relative to the provided root. virtual void MakePathRelative(AZStd::string& /*fullPath*/, const char* /*rootPath*/) {} - /// Gets the engine root path where the modules for the current engine are located. - virtual const char* GetEngineRoot() const { return nullptr; } - - /// Retrieves the app root path for the application. - virtual const char* GetAppRoot() const { return nullptr; } - /// Get the Command Line arguments passed in. virtual const CommandLine* GetCommandLine() { return nullptr; } diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index b6b09148eb..768ef1f0b6 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -225,13 +225,6 @@ namespace AzFramework } } - void Application::PreModuleLoad() - { - SetRootPath(RootPathType::EngineRoot, m_engineRoot.c_str()); - AZ_TracePrintf(s_azFrameworkWarningWindow, "Engine Path: %s\n", m_engineRoot.c_str()); - } - - void Application::Stop() { if (m_isStarted) @@ -397,11 +390,6 @@ namespace AzFramework outModules.emplace_back(aznew AzFrameworkModule()); } - const char* Application::GetAppRoot() const - { - return m_appRoot.c_str(); - } - const char* Application::GetCurrentConfigurationName() const { #if defined(_RELEASE) @@ -437,19 +425,19 @@ namespace AzFramework void Application::ResolveEnginePath(AZStd::string& engineRelativePath) const { - AZ::IO::FixedMaxPath fullPath = m_engineRoot / engineRelativePath; + auto fullPath = AZ::IO::FixedMaxPath(GetEngineRoot()) / engineRelativePath; engineRelativePath = fullPath.String(); } void Application::CalculateBranchTokenForEngineRoot(AZStd::string& token) const { - AzFramework::StringFunc::AssetPath::CalculateBranchToken(m_engineRoot.String(), token); + AZ::StringFunc::AssetPath::CalculateBranchToken(GetEngineRoot(), token); } //////////////////////////////////////////////////////////////////////////// void Application::MakePathRootRelative(AZStd::string& fullPath) { - MakePathRelative(fullPath, m_engineRoot.c_str()); + MakePathRelative(fullPath, GetEngineRoot()); } //////////////////////////////////////////////////////////////////////////// @@ -585,30 +573,6 @@ namespace AzFramework } } - void Application::SetRootPath(RootPathType type, const char* source) - { - [[maybe_unused]] const size_t sourceLen = strlen(source); - - // Copy the source path to the intended root path and correct the path separators as well - switch (type) - { - case RootPathType::AppRoot: - { - AZ_Assert(sourceLen < m_appRoot.Native().max_size(), "String overflow for App Root: %s", source); - m_appRoot = AZ::IO::PathView(source).LexicallyNormal(); - } - break; - case RootPathType::EngineRoot: - { - AZ_Assert(sourceLen < m_engineRoot.Native().max_size(), "String overflow for Engine Root: %s", source); - m_engineRoot = AZ::IO::PathView(source).LexicallyNormal(); - } - break; - default: - AZ_Assert(false, "Invalid RootPathType (%d)", static_cast(type)); - } - } - struct DeprecatedAliasesKeyVisitor : AZ::SettingsRegistryInterface::Visitor { diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.h b/Code/Framework/AzFramework/AzFramework/Application/Application.h index c6b1dfeaae..a318ede4a2 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.h +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.h @@ -95,8 +95,6 @@ namespace AzFramework ////////////////////////////////////////////////////////////////////////// //! ApplicationRequests::Bus::Handler - const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } - const char* GetAppRoot() const override; void ResolveEnginePath(AZStd::string& engineRelativePath) const override; void CalculateBranchTokenForEngineRoot(AZStd::string& token) const override; bool IsPrefabSystemEnabled() const override; @@ -146,8 +144,6 @@ namespace AzFramework */ void SetFileIOAliases(); - void PreModuleLoad() override; - ////////////////////////////////////////////////////////////////////////// //! AZ::ComponentApplication void RegisterCoreComponents() override; @@ -181,13 +177,7 @@ namespace AzFramework bool m_ownsConsole = false; bool m_exitMainLoopRequested = false; - - enum class RootPathType - { - AppRoot, - EngineRoot - }; - void SetRootPath(RootPathType type, const char* source); + }; } // namespace AzFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp index 139bbb563c..6fd881dbb9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -205,7 +205,7 @@ namespace AzToolsFramework::AssetUtils return platformConfigFilePathsAdded; } - AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath, + AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view projectPath, bool addPlatformConfigs, bool addGemsConfigs, AZ::SettingsRegistryInterface* settingsRegistry) { constexpr const char* AssetProcessorGamePlatformConfigFileName = "AssetProcessorGamePlatformConfig.ini"; @@ -232,14 +232,13 @@ namespace AzToolsFramework::AssetUtils Internal::AddGemConfigFiles(gemInfoList, configFiles); } - AZ::IO::Path assetRootDir(assetRoot); - assetRootDir /= projectPath; + AZ::IO::Path projectRoot(projectPath); - AZ::IO::Path projectConfigFile = assetRootDir / AssetProcessorGamePlatformConfigFileName; + AZ::IO::Path projectConfigFile = projectRoot / AssetProcessorGamePlatformConfigFileName; configFiles.push_back(projectConfigFile); // Add a file entry for the Project AssetProcessor setreg file - projectConfigFile = assetRootDir / AssetProcessorGamePlatformConfigSetreg; + projectConfigFile = projectRoot / AssetProcessorGamePlatformConfigSetreg; configFiles.push_back(projectConfigFile); return configFiles; @@ -251,10 +250,10 @@ namespace AzToolsFramework::AssetUtils AZStd::vector tokens; AZ::StringFunc::Tokenize(relPathFromRoot.c_str(), tokens, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING); - AZStd::string validatedPath; + AZ::IO::FixedMaxPath validatedPath; if (rootPath.empty()) { - AzFramework::ApplicationRequests::Bus::BroadcastResult(validatedPath, &AzFramework::ApplicationRequests::GetEngineRoot); + validatedPath = AZ::Utils::GetEnginePath(); } else { @@ -299,10 +298,7 @@ namespace AzToolsFramework::AssetUtils break; } - AZStd::string absoluteFilePath; - AZ::StringFunc::Path::ConstructFull(validatedPath.c_str(), element.c_str(), absoluteFilePath); - - validatedPath = absoluteFilePath; // go one step deeper. + validatedPath /= element; // go one step deeper. } if (success) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h index 39aab4d3fb..31ee9dcf60 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h @@ -40,7 +40,7 @@ namespace AzToolsFramework::AssetUtils //! Also note that if the project has any "game project gems", then those will also be inserted last, //! and thus have a higher priority than the root or non - project gems. //! Also note that the game project could be in a different location to the engine therefore we need the assetRoot param. - AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view assetRoot, AZStd::string_view projectPath, + AZStd::vector GetConfigFiles(AZStd::string_view engineRoot, AZStd::string_view projectPath, bool addPlatformConfigs = true, bool addGemsConfigs = true, AZ::SettingsRegistryInterface* settingsRegistry = nullptr); //! A utility function which checks the given path starting at the root and updates the relative path to be the actual case correct path. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp index a5206c9608..4869e0d09f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.cpp @@ -9,11 +9,11 @@ #include #include #include +#include #include #include #include #include -#include #include namespace AzToolsFramework @@ -113,11 +113,9 @@ namespace AzToolsFramework if (iconPathToUse.isEmpty()) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot, "Engine Root not initialized"); - AZStd::string iconPath = AZStd::string::format("%s%s", engineRoot, DefaultFileIconPath); - iconPathToUse = iconPath.c_str(); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Engine Root not initialized"); + iconPathToUse = (engineRoot / DefaultFileIconPath).c_str(); } m_pixmap.load(iconPathToUse); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp index 655fd27a0f..c2636d6d52 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Thumbnails/SourceControlThumbnail.cpp @@ -6,10 +6,10 @@ * */ -#include +#include +#include #include #include -#include namespace AzToolsFramework { @@ -68,12 +68,12 @@ namespace AzToolsFramework SourceControlThumbnail::SourceControlThumbnail(SharedThumbnailKey key) : Thumbnail(key) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot, "Engine Root not initialized"); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Engine Root not initialized"); + + m_writableIconPath = (engineRoot / WRITABLE_ICON_PATH).String(); + m_nonWritableIconPath = (engineRoot / NONWRITABLE_ICON_PATH).String(); - AzFramework::StringFunc::Path::Join(engineRoot, WRITABLE_ICON_PATH, m_writableIconPath); - AzFramework::StringFunc::Path::Join(engineRoot, NONWRITABLE_ICON_PATH, m_nonWritableIconPath); BusConnect(); } @@ -90,8 +90,8 @@ namespace AzToolsFramework AZ_Assert(sourceControlKey, "Incorrect key type, excpected SourceControlThumbnailKey"); AZStd::string myFileName(sourceControlKey->GetFileName()); - AzFramework::StringFunc::Path::Normalize(myFileName); - if (AzFramework::StringFunc::Equal(myFileName.c_str(), filename)) + AZ::StringFunc::Path::Normalize(myFileName); + if (AZ::StringFunc::Equal(myFileName.c_str(), filename)) { Update(); } diff --git a/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp b/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp index 9d6c8a4bff..06353b17c5 100644 --- a/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ComponentAddRemove.cpp @@ -1116,7 +1116,6 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext.get(); } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp index c24bab9299..a3c6666a40 100644 --- a/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/UI/EntityPropertyEditorTests.cpp @@ -36,11 +36,6 @@ namespace UnitTest : public ComponentApplication { public: - void SetExecutableFolder(const char* path) - { - m_exeDirectory = path; - } - void SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) override { ComponentApplication::SetSettingsRegistrySpecializations(specializations); diff --git a/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp b/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp index b17832526f..17e621f7d6 100644 --- a/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp +++ b/Code/Tools/AssetBundler/source/utils/GUIApplicationManager.cpp @@ -346,9 +346,7 @@ namespace AssetBundler } // 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()); + m_enabledPlatforms = GetEnabledPlatformFlags(GetEngineRoot(), AZStd::string_view(AZ::Utils::GetProjectPath())); // Determine which Gems are enabled for the current project if (!AzFramework::GetGemsInfo(m_gemInfoList, *m_settingsRegistry)) diff --git a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp index 0388570fdd..2df9e64ac5 100644 --- a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp +++ b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp @@ -1401,7 +1401,6 @@ namespace AssetBundler // If no platform was specified, defaulting to platforms specified in the asset processor config files AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags( - AZStd::string_view{ AZ::Utils::GetEnginePath() }, AZStd::string_view{ AZ::Utils::GetEnginePath() }, AZStd::string_view{ AZ::Utils::GetProjectPath() }); [[maybe_unused]] auto platformsString = AzFramework::PlatformHelper::GetCommaSeparatedPlatformList(platformFlags); diff --git a/Code/Tools/AssetBundler/source/utils/utils.cpp b/Code/Tools/AssetBundler/source/utils/utils.cpp index 6daf3c571b..7e56f5450e 100644 --- a/Code/Tools/AssetBundler/source/utils/utils.cpp +++ b/Code/Tools/AssetBundler/source/utils/utils.cpp @@ -377,7 +377,6 @@ namespace AssetBundler AzFramework::PlatformFlags GetEnabledPlatformFlags( AZStd::string_view engineRoot, - AZStd::string_view assetRoot, AZStd::string_view projectPath) { auto settingsRegistry = AZ::SettingsRegistry::Get(); @@ -387,7 +386,7 @@ namespace AssetBundler return AzFramework::PlatformFlags::Platform_NONE; } - auto configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(engineRoot, assetRoot, projectPath, true, true, settingsRegistry); + auto configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(engineRoot, projectPath, true, true, settingsRegistry); auto enabledPlatformList = AzToolsFramework::AssetUtils::GetEnabledPlatforms(*settingsRegistry, configFiles); AzFramework::PlatformFlags platformFlags = AzFramework::PlatformFlags::Platform_NONE; for (const auto& enabledPlatform : enabledPlatformList) diff --git a/Code/Tools/AssetBundler/source/utils/utils.h b/Code/Tools/AssetBundler/source/utils/utils.h index bfdf252014..0986d70ca8 100644 --- a/Code/Tools/AssetBundler/source/utils/utils.h +++ b/Code/Tools/AssetBundler/source/utils/utils.h @@ -221,7 +221,6 @@ 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); diff --git a/Code/Tools/AssetBundler/tests/UtilsTests.cpp b/Code/Tools/AssetBundler/tests/UtilsTests.cpp index 560d399613..60fc79579b 100644 --- a/Code/Tools/AssetBundler/tests/UtilsTests.cpp +++ b/Code/Tools/AssetBundler/tests/UtilsTests.cpp @@ -67,7 +67,7 @@ namespace AssetBundler void NormalizePathKeepCase(AZStd::string& /*path*/) override {} void CalculateBranchTokenForEngineRoot(AZStd::string& /*token*/) const override {} - const char* GetEngineRoot() const override + const char* GetTempDir() const { return m_tempDir->GetDirectory(); } @@ -83,7 +83,7 @@ namespace AssetBundler TEST_F(MockUtilsTest, DISABLED_TestFilePath_StartsWithAFileSeparator_Valid) { AZ::IO::Path relFilePath = "Foo/foo.xml"; - AZ::IO::Path absoluteFilePath = AZ::IO::PathView(GetEngineRoot()).RootPath(); + AZ::IO::Path absoluteFilePath = AZ::IO::PathView(GetTempDir()).RootPath(); absoluteFilePath /= relFilePath; absoluteFilePath = absoluteFilePath.LexicallyNormal(); @@ -95,7 +95,7 @@ namespace AssetBundler TEST_F(MockUtilsTest, TestFilePath_RelativePath_Valid) { AZ::IO::Path relFilePath = "Foo\\foo.xml"; - AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); + AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); FilePath filePath(relFilePath.Native()); EXPECT_EQ(AZ::IO::PathView{ filePath.AbsolutePath() }, absoluteFilePath); } @@ -107,8 +107,8 @@ namespace AssetBundler AZ::IO::Path relFilePath = "Foo\\Foo.xml"; AZ::IO::Path wrongCaseRelFilePath = "Foo\\foo.xml"; - AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); - AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / wrongCaseRelFilePath).LexicallyNormal(); + AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); + AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / wrongCaseRelFilePath).LexicallyNormal(); AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; AZ::IO::FileIOBase::GetInstance()->Open(correctAbsoluteFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath, fileHandle); @@ -121,7 +121,7 @@ namespace AssetBundler TEST_F(MockUtilsTest, TestFilePath_NoFileExists_NoError_valid) { AZ::IO::Path relFilePath = "Foo\\Foo.xml"; - AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); + AZ::IO::Path absoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); FilePath filePath(absoluteFilePath.Native(), true, false); EXPECT_TRUE(filePath.IsValid()); @@ -132,8 +132,8 @@ namespace AssetBundler { AZStd::string relFilePath = "Foo\\Foo.xml"; AZStd::string wrongCaseRelFilePath = "Foo\\foo.xml"; - AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / relFilePath).LexicallyNormal(); - AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetEngineRoot()) / wrongCaseRelFilePath).LexicallyNormal(); + AZ::IO::Path correctAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / relFilePath).LexicallyNormal(); + AZ::IO::Path wrongCaseAbsoluteFilePath = (AZ::IO::Path(GetTempDir()) / wrongCaseRelFilePath).LexicallyNormal(); AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; AZ::IO::FileIOBase::GetInstance()->Open(correctAbsoluteFilePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath, fileHandle); diff --git a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp index 07eae67a81..fd587195af 100644 --- a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp +++ b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -84,10 +85,9 @@ namespace AssetBundler // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - ASSERT_TRUE(engineRoot) << "Unable to locate engine root.\n"; - AzFramework::StringFunc::Path::Join(engineRoot, RelativeTestFolder, m_data->m_testEngineRoot); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + ASSERT_TRUE(!engineRoot.empty()) << "Unable to locate engine root.\n"; + m_data->m_testEngineRoot = (engineRoot / RelativeTestFolder).String(); m_data->m_localFileIO = aznew AZ::IO::LocalFileIO(); m_data->m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); @@ -150,7 +150,8 @@ namespace AssetBundler EXPECT_EQ(0, gemsNameMap.size()); - AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(m_data->m_testEngineRoot.c_str(), m_data->m_testEngineRoot.c_str(), DummyProjectName); + const auto testProjectPath = AZ::IO::Path(m_data->m_testEngineRoot) / DummyProjectName; + AzFramework::PlatformFlags platformFlags = GetEnabledPlatformFlags(m_data->m_testEngineRoot, testProjectPath.Native()); AzFramework::PlatformFlags hostPlatformFlag = AzFramework::PlatformHelper::GetPlatformFlag(AzToolsFramework::AssetSystem::GetHostAssetPlatform()); AzFramework::PlatformFlags expectedFlags = AzFramework::PlatformFlags::Platform_ANDROID | AzFramework::PlatformFlags::Platform_IOS | AzFramework::PlatformFlags::Platform_PROVO | hostPlatformFlag; ASSERT_EQ(platformFlags, expectedFlags); diff --git a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp index 69397745f1..e519f48ce5 100644 --- a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp @@ -52,11 +52,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_BadPlatform) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_badplatform"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -67,11 +68,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_NoPlatform) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_noplatform"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -81,11 +83,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_NoScanFolders) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_noscans"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -95,11 +98,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_BrokenRecognizers) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_broken_recognizers"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); } @@ -109,11 +113,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Regular_Platforms) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); // verify the data. @@ -322,12 +327,13 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolder) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); AssetUtilities::ComputeProjectName(EmptyDummyProjectName, true); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 3); // the two, and then the one that has the same data as prior but different identifier. @@ -356,11 +362,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularScanfolderP using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular_platform_scanfolder"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_EQ(config.GetScanFolderCount(), 5); @@ -402,11 +409,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_TRUE(config.IsFileExcluded("blahblah/$tmp_01.test")); @@ -427,11 +435,12 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Recognizers) #endif const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -518,12 +527,13 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Overrides) using namespace AzToolsFramework::AssetSystem; using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / DummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), DummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -625,11 +635,12 @@ TEST_F(PlatformConfigurationUnitTests, ReadCheckServer_FromConfig_Valid) using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); const AssetProcessor::RecognizerContainer& recogs = config.GetAssetRecognizerContainer(); @@ -674,11 +685,12 @@ TEST_F(PlatformConfigurationUnitTests, Test_MetaFileTypes_AssetImporterExtension using namespace AssetProcessor; const auto testExeFolder = AZ::IO::FileIOBase::GetInstance()->ResolvePath(TestAppRoot); + const AZ::IO::FixedMaxPath projectPath = (*testExeFolder) / EmptyDummyProjectName; auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_metadata"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; m_absorber.Clear(); - ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); + ASSERT_FALSE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), projectPath.c_str(), false, false)); ASSERT_GT(m_absorber.m_numErrorsAbsorbed, 0); ASSERT_TRUE(config.MetaDataFileTypesCount() == 2); diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp index 9a60bf3110..483d5a46aa 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp @@ -749,7 +749,7 @@ namespace AssetProcessor } AZStd::vector configFiles = AzToolsFramework::AssetUtils::GetConfigFiles(absoluteSystemRoot.toUtf8().constData(), - absoluteAssetRoot.toUtf8().constData(), projectPath.toUtf8().constData(), + projectPath.toUtf8().constData(), addPlatformConfigs, addGemsConfigs && !noGemScanFolders, settingsRegistry); // First Merge all Engine, Gem and Project specific AssetProcessor*Config.setreg/.inifiles diff --git a/Code/Tools/PythonBindingsExample/source/Application.cpp b/Code/Tools/PythonBindingsExample/source/Application.cpp index ab1d1b5acf..cfb28d8e09 100644 --- a/Code/Tools/PythonBindingsExample/source/Application.cpp +++ b/Code/Tools/PythonBindingsExample/source/Application.cpp @@ -39,7 +39,6 @@ namespace PythonBindingsExample AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusConnect(); // prepare the Python binding gem(s) - CalculateExecutablePath(); Start(Descriptor()); AZ::SerializeContext* context; diff --git a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp index 3bf75e2d9b..0478e6cdb2 100644 --- a/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Tests/Containers/SceneBehaviorTests.cpp @@ -368,7 +368,6 @@ namespace AZ::SceneAPI::Containers MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char*()); MOCK_CONST_METHOD0(GetEngineRoot, const char*()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&)); diff --git a/Code/Tools/SerializeContextTools/Converter.cpp b/Code/Tools/SerializeContextTools/Converter.cpp index 6a8bebdbfc..294bf941ac 100644 --- a/Code/Tools/SerializeContextTools/Converter.cpp +++ b/Code/Tools/SerializeContextTools/Converter.cpp @@ -202,8 +202,6 @@ namespace AZ bool skipSystem = commandLine->HasSwitch("skipsystem"); bool isDryRun = commandLine->HasSwitch("dryrun"); - const char* appRoot = const_cast(application).GetAppRoot(); - PathDocumentContainer documents; bool result = true; const AZStd::string& filePath = application.GetConfigFilePath(); @@ -230,7 +228,7 @@ namespace AZ } auto callback = - [&result, skipGems, skipSystem, &configurationName, sourceGameFolder, &appRoot, &documents, &convertSettings, &verifySettings] + [&result, skipGems, skipSystem, &configurationName, sourceGameFolder, &documents, &convertSettings, &verifySettings] (void* classPtr, const Uuid& classId, SerializeContext* context) { if (classId == azrtti_typeid()) @@ -238,7 +236,7 @@ namespace AZ if (!skipSystem) { result = ConvertSystemSettings(documents, *reinterpret_cast(classPtr), - configurationName, sourceGameFolder, appRoot) && result; + configurationName, sourceGameFolder) && result; } // Cleanup the Serialized Element to allow any classes within the element's hierarchy to delete @@ -443,7 +441,7 @@ namespace AZ } bool Converter::ConvertSystemSettings(PathDocumentContainer& documents, const ComponentApplication::Descriptor& descriptor, - const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder, [[maybe_unused]] const AZStd::string& applicationRoot) + const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder) { AZ::IO::FixedMaxPath memoryFilePath{ projectFolder }; memoryFilePath /= "Registry"; diff --git a/Code/Tools/SerializeContextTools/Converter.h b/Code/Tools/SerializeContextTools/Converter.h index 6c8f6c70fb..7d30ca2a3a 100644 --- a/Code/Tools/SerializeContextTools/Converter.h +++ b/Code/Tools/SerializeContextTools/Converter.h @@ -43,7 +43,7 @@ namespace AZ using PathDocumentContainer = AZStd::vector; static bool ConvertSystemSettings(PathDocumentContainer& documents, const ComponentApplication::Descriptor& descriptor, - const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder, const AZStd::string& applicationRoot); + const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder); static bool ConvertSystemComponents(PathDocumentContainer& documents, const Entity& entity, const AZStd::string& configurationName, const AZ::IO::PathView& projectFolder, const JsonSerializerSettings& convertSettings, const JsonDeserializerSettings& verifySettings); diff --git a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h index 1d2e8bad42..19314035c4 100644 --- a/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h +++ b/Gems/AWSClientAuth/Code/Tests/AWSClientAuthGemMock.h @@ -608,7 +608,6 @@ namespace AWSClientAuthUnitTest AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {} diff --git a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp index 56f28856af..8f8fb48212 100644 --- a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp +++ b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp @@ -439,13 +439,6 @@ namespace AssetValidation bool GetDefaultSeedListFiles(AZStd::vector& defaultSeedListFiles) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetAppRoot); - - auto settingsRegistry = AZ::SettingsRegistry::Get(); AZ::SettingsRegistryInterface::FixedValueString gameFolder; auto projectKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey); @@ -509,30 +502,28 @@ namespace AssetValidation AZ::Outcome AssetValidationSystemComponent::LoadSeedList(const char* seedPath, AZStd::string& seedListPath) { - AZStd::string absoluteSeedPath = seedPath; + AZ::IO::Path absoluteSeedPath = seedPath; if (AZ::StringFunc::Path::IsRelative(seedPath)) { - const char* appRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(appRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); - if (!appRoot) + if (engineRoot.empty()) { return AZ::Failure(AZStd::string("Couldn't get engine root")); } - absoluteSeedPath = AZStd::string::format("%s/%s", appRoot, seedPath); + absoluteSeedPath = (engineRoot / seedPath).String(); } - AzFramework::StringFunc::Path::Normalize(absoluteSeedPath); AzFramework::AssetSeedList seedList; - if (!AZ::Utils::LoadObjectFromFileInPlace(absoluteSeedPath, seedList)) + if (!AZ::Utils::LoadObjectFromFileInPlace(absoluteSeedPath.Native(), seedList)) { return AZ::Failure(AZStd::string::format("Failed to load seed list %s", absoluteSeedPath.c_str())); } - seedListPath = absoluteSeedPath; + seedListPath = AZStd::move(absoluteSeedPath.Native()); return AZ::Success(seedList); } diff --git a/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h b/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h index c4872ab425..8da3ae1b34 100644 --- a/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h +++ b/Gems/AssetValidation/Code/Tests/AssetValidationTestShared.h @@ -150,13 +150,13 @@ struct AssetValidationTest auto projectPathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; - m_registry.Set(projectPathKey, (AZ::IO::FixedMaxPath(GetEngineRoot()) / "AutomatedTesting").Native()); + m_registry.Set(projectPathKey, (AZ::IO::FixedMaxPath(m_tempDir.GetDirectory()) / "AutomatedTesting").Native()); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); // Set the engine root to the temporary directory and re-update the runtime file paths auto enginePathKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/engine_path"; - m_registry.Set(enginePathKey, GetEngineRoot()); + m_registry.Set(enginePathKey, m_tempDir.GetDirectory()); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); } } @@ -176,11 +176,6 @@ struct AssetValidationTest AZ_Assert(false, "Not implemented"); } - const char* GetEngineRoot() const override - { - return m_tempDir.GetDirectory(); - } - void SetUp() override { using namespace ::testing; diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index d5b795a1fa..d0029ffc86 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -111,7 +111,6 @@ namespace UnitTest AZ::SerializeContext* GetSerializeContext() override { return m_context.get(); } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return m_jsonRegistrationContext.get(); } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const AZ::ComponentApplicationRequests::EntityCallback& /*callback*/) override {} diff --git a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp index c753079d5b..ef3f33d1c3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreRenderer.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -295,14 +296,12 @@ namespace AZ } // Run luxcoreui.exe - AZStd::string luxCoreExeFullPath; - AzFramework::ApplicationRequests::Bus::BroadcastResult(luxCoreExeFullPath, &AzFramework::ApplicationRequests::GetAppRoot); - luxCoreExeFullPath = luxCoreExeFullPath + AZ_TRAIT_LUXCORE_EXEPATH; - AzFramework::StringFunc::Path::Normalize(luxCoreExeFullPath); + AZ::IO::FixedMaxPath luxCoreExeFullPath = AZ::Utils::GetEnginePath(); + luxCoreExeFullPath /= AZ_TRAIT_LUXCORE_EXEPATH; AZStd::string commandLine = "-o " + AZStd::string(resolvedPath) + "/render.cfg"; - LuxCoreUI::LaunchLuxCoreUI(luxCoreExeFullPath, commandLine); + LuxCoreUI::LaunchLuxCoreUI(luxCoreExeFullPath.String(), commandLine); } } } diff --git a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h index 31c1bc6715..02e69e732c 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests.Builders/BuilderTestFixture.h @@ -46,7 +46,6 @@ namespace UnitTest bool DeleteEntity(const AZ::EntityId&) override { return false; } AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h index ee3ad94d4f..fb88e62617 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.h @@ -44,7 +44,6 @@ namespace UnitTest AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp index be112345a9..d3bce34af3 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/Util.cpp @@ -133,29 +133,12 @@ namespace AtomToolsFramework bool LaunchTool(const QString& baseName, const QString& extension, const QStringList& arguments) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot != nullptr, "AzFramework::ApplicationRequests::GetEngineRoot failed"); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); + AZ_Assert(!engineRoot.empty(), "Cannot query Engine Path"); - char binFolderName[AZ_MAX_PATH_LEN] = {}; - AZ::Utils::GetExecutablePathReturnType ret = AZ::Utils::GetExecutablePath(binFolderName, AZ_MAX_PATH_LEN); + AZ::IO::FixedMaxPath launchPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) + / (baseName + extension).toUtf8().constData(); - // If it contains the filename, zero out the last path separator character... - if (ret.m_pathIncludesFilename) - { - char* lastSlash = strrchr(binFolderName, AZ_CORRECT_FILESYSTEM_SEPARATOR); - if (lastSlash) - { - *lastSlash = '\0'; - } - } - - const QString path = QString("%1%2%3%4") - .arg(binFolderName) - .arg(AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING) - .arg(baseName) - .arg(extension); - - return QProcess::startDetached(path, arguments, engineRoot); + return QProcess::startDetached(launchPath.c_str(), arguments, engineRoot.c_str()); } } diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl index 55e457926a..5a8aaf7ded 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiPassTree.inl @@ -19,11 +19,11 @@ #include -#include #include #include #include +#include #ifndef SCRIPTABLE_IMGUI #define Scriptable_ImGui ImGui @@ -334,11 +334,10 @@ namespace AZ::Render if (m_engineRoot.empty()) { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - if (engineRoot) + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + if (!engineRoot.empty()) { - m_engineRoot = AZStd::string(engineRoot); + m_engineRoot = AZStd::string_view(engineRoot); } } diff --git a/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp b/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp index bee5c1dd51..f339ff8bb3 100644 --- a/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/ImplementationManager.cpp @@ -9,8 +9,6 @@ #include -#include - #include #include #include @@ -32,10 +30,6 @@ bool CImplementationManager::LoadImplementation() // release the loaded implementation (if any) Release(); - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot != nullptr, "Unable to communicate with AzFramework::ApplicationRequests::Bus"); - AudioControlsEditor::EditorImplPluginEventBus::Broadcast(&AudioControlsEditor::EditorImplPluginEventBus::Events::InitializeEditorImplPlugin); } else diff --git a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp index 876ef19803..fe9156013f 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp @@ -597,11 +597,10 @@ namespace EditorPythonBindings { AZStd::unordered_set pyPackageSites(pythonPathStack.begin(), pythonPathStack.end()); - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); // set PYTHON_HOME - AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, engineRoot); + AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, engineRoot.c_str()); if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str())) { AZ_Warning("python", false, "Python home path must exist! path:%s", pyBasePath.c_str()); diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h index 143863b4c8..e2b3d1eadd 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h +++ b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h @@ -135,10 +135,6 @@ namespace UnitTest void NormalizePath(AZStd::string& ) override {} void NormalizePathKeepCase(AZStd::string& ) override {} void CalculateBranchTokenForEngineRoot(AZStd::string& ) const override {} - // Gets the engine root path for testing - const char* GetEngineRoot() const override { return m_engineRoot.c_str(); } - // Retrieves the app root path for testing - const char* GetAppRoot() const override { return m_engineRoot.c_str(); } AZ::ComponentApplication m_app; AZStd::unique_ptr m_fileIOHelper; diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp index 73ef7143c8..0965991dfa 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SliceBuilderTests.cpp @@ -311,7 +311,6 @@ namespace UnitTest SerializeContext* GetSerializeContext() override { return m_serializeContext; } BehaviorContext* GetBehaviorContext() override { return nullptr; } JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const EntityCallback& /*callback*/) override {} diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h index 3c3d77e011..238e652b52 100644 --- a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -41,7 +41,6 @@ namespace Multiplayer AZ::SerializeContext* GetSerializeContext() override { return {}; } AZ::BehaviorContext* GetBehaviorContext() override { return {}; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return {}; } - const char* GetAppRoot() const override { return {}; } const char* GetEngineRoot() const override { return {}; } const char* GetExecutableFolder() const override { return {}; } void QueryApplicationType([[maybe_unused]] AZ::ApplicationTypeQuery& appType) const override {} diff --git a/Gems/Multiplayer/Code/Tests/MockInterfaces.h b/Gems/Multiplayer/Code/Tests/MockInterfaces.h index 8cebf280b9..8fd32bd79b 100644 --- a/Gems/Multiplayer/Code/Tests/MockInterfaces.h +++ b/Gems/Multiplayer/Code/Tests/MockInterfaces.h @@ -146,7 +146,6 @@ namespace UnitTest MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ()); MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ()); MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ()); - MOCK_CONST_METHOD0(GetAppRoot, const char* ()); MOCK_CONST_METHOD0(GetEngineRoot, const char* ()); MOCK_CONST_METHOD0(GetExecutableFolder, const char* ()); MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ()); diff --git a/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp b/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp index bc9265a92a..fb8e61289d 100644 --- a/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp +++ b/Gems/PhysX/Code/Source/Debug/PhysXDebug.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace PhysX { @@ -108,8 +108,7 @@ namespace PhysX AzFramework::StringFunc::Append(filename, m_config.m_pvdConfigurationData.m_fileName.c_str()); AzFramework::StringFunc::Append(filename, ".pxd2"); - AZStd::string rootDirectory; - AZ::ComponentApplicationBus::BroadcastResult(rootDirectory, &AZ::ComponentApplicationRequests::GetAppRoot); + AZStd::string rootDirectory{ AZStd::string_view(AZ::Utils::GetEnginePath()) }; // Create the full filepath. AZStd::string safeFilePath; diff --git a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp index cba14feac6..33982bbcd7 100644 --- a/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp +++ b/Gems/ScriptCanvas/Code/Tests/ScriptCanvasBuilderTests.cpp @@ -89,7 +89,6 @@ protected: AZ::SerializeContext* GetSerializeContext() override { return m_serializeContext; } AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; } AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; } - const char* GetAppRoot() const override { return nullptr; } const char* GetEngineRoot() const override { return nullptr; } const char* GetExecutableFolder() const override { return nullptr; } void EnumerateEntities(const AZ::ComponentApplicationRequests::EntityCallback& /*callback*/) override {} diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h index f45b74d4f1..6e38f71eec 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestFixture.h @@ -91,14 +91,6 @@ namespace ScriptCanvasTests AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "SC unit tests require filehandling"); - if (!fileIO->GetAlias("@engroot@")) - { - const char* engineRoot = nullptr; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - AZ_Assert(engineRoot, "null engine root"); - fileIO->SetAlias("@engroot@", engineRoot); - } - s_setupSucceeded = fileIO->GetAlias("@engroot@") != nullptr; AZ::TickBus::AllowFunctionQueuing(true); diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 2c42533e35..13161c9e0f 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -183,7 +183,9 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") cmake_path(GET gem_source_path_setreg FILENAME setreg_filename) list(APPEND artifacts_to_remove "${cache_product_path}/registry/${setreg_filename}") endforeach() - file(REMOVE ${artifacts_to_remove}) + if (artifacts_to_remove) + file(REMOVE ${artifacts_to_remove}) + endif() endif() ]=]) From eb60dd404b4ba9286981bc24d901ee4cfbc80786 Mon Sep 17 00:00:00 2001 From: dmcdiar Date: Tue, 9 Nov 2021 12:17:58 -0700 Subject: [PATCH 49/66] Moved probe exposure to specular only, since it's not used by the diffuse Signed-off-by: dmcdiar --- .../Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli index 31439de144..3254b8e4ed 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/Ibl.azsli @@ -85,12 +85,12 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) if(useIbl) { - float exposure = pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure); + float globalIblExposure = pow(2.0, SceneSrg::m_iblExposure); if(useDiffuseIbl) { float3 iblDiffuse = GetIblDiffuse(surface.normal, surface.albedo, lightingData.diffuseResponse); - lightingData.diffuseLighting += (iblDiffuse * exposure * lightingData.diffuseAmbientOcclusion); + lightingData.diffuseLighting += (iblDiffuse * globalIblExposure * lightingData.diffuseAmbientOcclusion); } if(useSpecularIbl) @@ -116,6 +116,7 @@ void ApplyIBL(Surface surface, inout LightingData lightingData) iblSpecular = iblSpecular * (1.0 - clearCoatResponse) * (1.0 - clearCoatResponse) + clearCoatIblSpecular; } + float exposure = ObjectSrg::m_reflectionProbeData.m_useReflectionProbe ? pow(2.0, ObjectSrg::m_reflectionProbeData.m_exposure) : globalIblExposure; lightingData.specularLighting += (iblSpecular * exposure); } } From e3b1c4b7d09b63bea6503c66f9686b6f9fa4556e Mon Sep 17 00:00:00 2001 From: jiaweig <51759646+jiaweig-amzn@users.noreply.github.com> Date: Tue, 9 Nov 2021 11:27:32 -0800 Subject: [PATCH 50/66] Move swapchain and image recreation to the end of the frame (#5388) Signed-off-by: jiaweig --- .../RHI/Code/Include/Atom/RHI/SwapChain.h | 11 ++ .../RHI/FrameGraphAttachmentDatabase.cpp | 8 +- Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp | 145 ++++++++---------- .../RHI/Vulkan/Code/Source/RHI/SwapChain.cpp | 22 ++- .../RHI/Vulkan/Code/Source/RHI/SwapChain.h | 1 + 5 files changed, 101 insertions(+), 86 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h index 97ac3baa90..abad1fb263 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/SwapChain.h @@ -75,6 +75,9 @@ namespace AZ //! Return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise. virtual bool SetExclusiveFullScreenState([[maybe_unused]]bool fullScreenState) { return false; } + //! Recreate the swapchain if it becomes invalid during presenting. This should happen at the end of the frame + //! due to images being used as attachments in the frame graph. + virtual void ProcessRecreation() {}; protected: SwapChain(); @@ -98,6 +101,14 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// + //! Shutdown and clear all the images. + void ShutdownImages(); + + //! Initialized all the images. + ResultCode InitImages(); + + //! Flag indicating if swapchain recreation is needed at the end of the frame. + bool m_pendingRecreation = false; private: bool ValidateDescriptor(const SwapChainDescriptor& descriptor) const; diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp index 6bac2b8c7d..388277ff59 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/FrameGraphAttachmentDatabase.cpp @@ -134,7 +134,6 @@ namespace AZ m_scopeAttachmentLookup.clear(); m_imageAttachments.clear(); m_bufferAttachments.clear(); - m_swapChainAttachments.clear(); m_importedImageAttachments.clear(); m_importedBufferAttachments.clear(); m_transientImageAttachments.clear(); @@ -153,6 +152,13 @@ namespace AZ delete attachment; } m_attachments.clear(); + + for (auto swapchainAttachment : m_swapChainAttachments) + { + swapchainAttachment->GetSwapChain()->ProcessRecreation(); + } + + m_swapChainAttachments.clear(); } ImageDescriptor FrameGraphAttachmentDatabase::GetImageDescriptor(const AttachmentId& attachmentId) const diff --git a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp index ff1f0e69a6..074eedf1b6 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/SwapChain.cpp @@ -58,43 +58,68 @@ namespace AZ // Overwrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal. m_descriptor.m_dimensions = nativeDimensions; - m_images.reserve(m_descriptor.m_dimensions.m_imageCount); + resultCode = InitImages(); + } - for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx) - { - m_images.emplace_back(RHI::Factory::Get().CreateImage()); - } + return resultCode; + } - InitImageRequest request; + void SwapChain::ShutdownImages() + { + // Shutdown existing set of images. + uint32_t imageSize = aznumeric_cast(m_images.size()); + for (uint32_t imageIdx = 0; imageIdx < imageSize; ++imageIdx) + { + m_images[imageIdx]->Shutdown(); + } - RHI::ImageDescriptor& imageDescriptor = request.m_descriptor; - imageDescriptor.m_dimension = RHI::ImageDimension::Image2D; - imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color; - imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth; - imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight; - imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat; + m_images.clear(); + } - for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx) - { - request.m_image = m_images[imageIdx].get(); - request.m_imageIndex = imageIdx; + ResultCode SwapChain::InitImages() + { + ResultCode resultCode = ResultCode::Success; + + m_images.reserve(m_descriptor.m_dimensions.m_imageCount); + + // If the new display mode has more buffers, add them. + for (uint32_t i = 0; i < m_descriptor.m_dimensions.m_imageCount; ++i) + { + m_images.emplace_back(RHI::Factory::Get().CreateImage()); + } + + InitImageRequest request; + + RHI::ImageDescriptor& imageDescriptor = request.m_descriptor; + imageDescriptor.m_dimension = RHI::ImageDimension::Image2D; + imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color; + imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth; + imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight; + imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat; - resultCode = ImagePoolBase::InitImage( - request.m_image, - imageDescriptor, - [this, &request]() + for (uint32_t imageIdx = 0; imageIdx < m_descriptor.m_dimensions.m_imageCount; ++imageIdx) + { + request.m_image = m_images[imageIdx].get(); + request.m_imageIndex = imageIdx; + + resultCode = ImagePoolBase::InitImage( + request.m_image, imageDescriptor, + [this, &request]() { return InitImageInternal(request); }); - if (resultCode != ResultCode::Success) - { - Shutdown(); - break; - } + if (resultCode != ResultCode::Success) + { + AZ_Error("Swapchain", false, "Failed to initialize images."); + Shutdown(); + break; } } + // Reset the current index back to 0 so we match the platform swap chain. + m_currentImageIndex = 0; + return resultCode; } @@ -105,63 +130,15 @@ namespace AZ } ResultCode SwapChain::Resize(const RHI::SwapChainDimensions& dimensions) - { - // Shutdown existing set of images. - for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx) - { - m_images[imageIdx]->Shutdown(); - } + { + ShutdownImages(); SwapChainDimensions nativeDimensions = dimensions; ResultCode resultCode = ResizeInternal(dimensions, &nativeDimensions); if (resultCode == ResultCode::Success) { m_descriptor.m_dimensions = nativeDimensions; - m_images.reserve(m_descriptor.m_dimensions.m_imageCount); - - // If the new display mode has more buffers, add them. - while (m_images.size() < static_cast(m_descriptor.m_dimensions.m_imageCount)) - { - m_images.emplace_back(RHI::Factory::Get().CreateImage()); - } - - // If it has fewer, trim down. - while (m_images.size() > static_cast(m_descriptor.m_dimensions.m_imageCount)) - { - m_images.pop_back(); - } - - InitImageRequest request; - - RHI::ImageDescriptor& imageDescriptor = request.m_descriptor; - imageDescriptor.m_dimension = RHI::ImageDimension::Image2D; - imageDescriptor.m_bindFlags = RHI::ImageBindFlags::Color; - imageDescriptor.m_size.m_width = m_descriptor.m_dimensions.m_imageWidth; - imageDescriptor.m_size.m_height = m_descriptor.m_dimensions.m_imageHeight; - imageDescriptor.m_format = m_descriptor.m_dimensions.m_imageFormat; - - for (uint32_t imageIdx = 0; imageIdx < GetImageCount(); ++imageIdx) - { - request.m_image = m_images[imageIdx].get(); - request.m_imageIndex = imageIdx; - - resultCode = ImagePoolBase::InitImage( - request.m_image, - imageDescriptor, - [this, &request]() - { - return InitImageInternal(request); - }); - - if (resultCode != ResultCode::Success) - { - Shutdown(); - break; - } - } - - // Reset the current index back to 0 so we match the platform swap chain. - m_currentImageIndex = 0; + resultCode = InitImages(); } return resultCode; @@ -188,7 +165,7 @@ namespace AZ uint32_t SwapChain::GetImageCount() const { - return static_cast(m_images.size()); + return aznumeric_cast(m_images.size()); } uint32_t SwapChain::GetCurrentImageIndex() const @@ -209,8 +186,18 @@ namespace AZ void SwapChain::Present() { AZ_TRACE_METHOD(); - m_currentImageIndex = PresentInternal(); - AZ_Assert(m_currentImageIndex < m_images.size(), "Invalid image index"); + // Due to swapchain recreation, the images are refreshed. + // There is no need to present swapchain for this frame. + const uint32_t imageCount = aznumeric_cast(m_images.size()); + if (imageCount == 0) + { + return; + } + else + { + m_currentImageIndex = PresentInternal(); + AZ_Assert(m_currentImageIndex < imageCount, "Invalid image index"); + } } } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp index bef2b154e1..19c88ec34f 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp @@ -59,6 +59,19 @@ namespace AZ m_swapChainBarrier.m_isValid = true; } + void SwapChain::ProcessRecreation() + { + if (m_pendingRecreation) + { + ShutdownImages(); + InvalidateNativeSwapChain(); + CreateSwapchain(); + InitImages(); + + m_pendingRecreation = false; + } + } + void SwapChain::SetVerticalSyncIntervalInternal(uint32_t previousVsyncInterval) { if (GetDescriptor().m_verticalSyncInterval == 0 || previousVsyncInterval == 0) @@ -231,8 +244,7 @@ namespace AZ // VK_SUBOPTIMAL_KHR is treated as success, but we better update the surface info as well. if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { - InvalidateNativeSwapChain(); - CreateSwapchain(); + m_pendingRecreation = true; } else { @@ -246,18 +258,16 @@ namespace AZ } }; - m_presentationQueue->QueueCommand(AZStd::move(presentCommand)); - uint32_t acquiredImageIndex = GetCurrentImageIndex(); RHI::ResultCode result = AcquireNewImage(&acquiredImageIndex); if (result == RHI::ResultCode::Fail) { - InvalidateNativeSwapChain(); - CreateSwapchain(); + m_pendingRecreation = true; return 0; } else { + m_presentationQueue->QueueCommand(AZStd::move(presentCommand)); return acquiredImageIndex; } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h index ee2ff3c207..68abc97b2d 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h @@ -51,6 +51,7 @@ namespace AZ void QueueBarrier(const VkPipelineStageFlags src, const VkPipelineStageFlags dst, const VkImageMemoryBarrier& imageBarrier); + void ProcessRecreation() override; private: SwapChain() = default; From 7cc9c584b78a1c66e714a95d046a1123849f4f10 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Tue, 9 Nov 2021 13:53:04 -0600 Subject: [PATCH 51/66] Ensure QtForPython is a proper dependency for the PythonToolGem. Signed-off-by: Chris Galvan --- Templates/PythonToolGem/Template/Code/CMakeLists.txt | 2 ++ Templates/PythonToolGem/Template/gem.json | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Templates/PythonToolGem/Template/Code/CMakeLists.txt b/Templates/PythonToolGem/Template/Code/CMakeLists.txt index a6044e717b..b90f2d7703 100644 --- a/Templates/PythonToolGem/Template/Code/CMakeLists.txt +++ b/Templates/PythonToolGem/Template/Code/CMakeLists.txt @@ -53,6 +53,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PUBLIC Gem::${Name}.Editor.Static + RUNTIME_DEPENDENCIES + Gem::QtForPython.Editor ) # By default, we will specify that the above target ${Name} would be used by diff --git a/Templates/PythonToolGem/Template/gem.json b/Templates/PythonToolGem/Template/gem.json index d4ff637bee..84f5b65a3e 100644 --- a/Templates/PythonToolGem/Template/gem.json +++ b/Templates/PythonToolGem/Template/gem.json @@ -13,5 +13,8 @@ "${Name}" ], "icon_path": "preview.png", - "requirements": "" + "requirements": "", + "dependencies": [ + "QtForPython" + ] } From caf1c18fbe8bd84d6788615323ac6e9f23732738 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Tue, 9 Nov 2021 12:40:56 -0800 Subject: [PATCH 52/66] Prevent track editor view's default size to be zero (#5453) * Prevent track editor view's default size to be zero Signed-off-by: chiyteng * minor rewording Signed-off-by: chiyteng --- Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp b/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp index e6c2dda74c..9ad9a50aa5 100644 --- a/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp +++ b/Gems/LyShine/Code/Editor/Animation/UiAnimViewDialog.cpp @@ -257,6 +257,7 @@ BOOL CUiAnimViewDialog::OnInitDialog() m_wndSplitter->addWidget(m_wndDopeSheet); m_wndSplitter->setStretchFactor(0, 1); m_wndSplitter->setStretchFactor(1, 10); + m_wndSplitter->setChildrenCollapsible(false); l->addWidget(m_wndSplitter); w->setLayout(l); setCentralWidget(w); @@ -283,6 +284,11 @@ BOOL CUiAnimViewDialog::OnInitDialog() m_wndCurveEditorDock->setVisible(false); m_wndCurveEditorDock->setEnabled(false); + // In order to prevent the track editor view from collapsing and becoming invisible, we use the + // minimum size of the curve editor for the track editor as well. Since both editors use the same + // view widget in the UI animation editor when not in 'Both' mode, the sizes can be identical. + m_wndDopeSheet->setMinimumSize(m_wndCurveEditor->minimumSizeHint()); + InitSequences(); m_lazyInitDone = false; From 461b63c61a4c4f8a45687ec1959ffe1a2401eb92 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 9 Nov 2021 14:14:13 -0800 Subject: [PATCH 53/66] Temporarily disable the platform filter (#5454) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index b608445d0f..acea6ce378 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -221,7 +221,6 @@ namespace O3DE::ProjectManager ResetGemStatusFilter(); ResetGemOriginFilter(); ResetTypeFilter(); - ResetPlatformFilter(); ResetFeatureFilter(); } From 15586ee53e0e8a627cee52bc54905e772ee4cbfc Mon Sep 17 00:00:00 2001 From: moraaar Date: Tue, 9 Nov 2021 23:42:01 +0000 Subject: [PATCH 54/66] Adding missing pragma once at XcbInputDeviceMouse.h (#5448) Signed-off-by: moraaar --- .../Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h index a69a8a9ec5..f5b805a7a5 100644 --- a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h +++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceMouse.h @@ -6,6 +6,8 @@ * */ +#pragma once + #include #include #include From 31439eb7c85c91d39835f43c79d904e3375f5afe Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Tue, 9 Nov 2021 17:52:26 -0600 Subject: [PATCH 55/66] Adding m_exposure field to terrain's object srg to sync it with the default object srg. (#5462) Signed-off-by: Ken Pruiksma --- Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli index cd680f721a..52d0e0a6cc 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli @@ -56,6 +56,7 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject float m_padding; bool m_useReflectionProbe; bool m_useParallaxCorrection; + float m_exposure; }; ReflectionProbeData m_reflectionProbeData; From 0e3df14ea2f1b2e36c3d64cf6ff72b52eb2d2f5a Mon Sep 17 00:00:00 2001 From: John Date: Wed, 10 Nov 2021 11:59:28 +0000 Subject: [PATCH 56/66] Add missing bus connection/disconnection. Signed-off-by: John --- .../UI/PropertyEditor/EntityPropertyEditor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 9ffe8021e3..a449fa0055 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -606,6 +606,7 @@ namespace AzToolsFramework AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( AzToolsFramework::GetEntityContextId()); + ViewportEditorModeNotificationsBus::Handler::BusConnect(GetEntityContextId()); } EntityPropertyEditor::~EntityPropertyEditor() @@ -618,7 +619,8 @@ namespace AzToolsFramework AZ::EntitySystemBus::Handler::BusDisconnect(); EditorEntityContextNotificationBus::Handler::BusDisconnect(); AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); - + ViewportEditorModeNotificationsBus::Handler::BusDisconnect(); + for (auto& entityId : m_overrideSelectedEntityIds) { DisconnectFromEntityBuses(entityId); From 027b0f86ae5bac33ae04967eb66bf5927df1face Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Wed, 10 Nov 2021 14:41:59 +0100 Subject: [PATCH 57/66] Activate AssetBrowserTableView feature (#5367) Signed-off-by: igarri --- .../AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp index acf935e6dc..c6772ea2d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.cpp @@ -20,7 +20,7 @@ AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING AZ_CVAR( - bool, ed_useNewAssetBrowserTableView, false, nullptr, AZ::ConsoleFunctorFlags::Null, + bool, ed_useNewAssetBrowserTableView, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Use the new AssetBrowser TableView for searching assets."); namespace AzToolsFramework { From 847e13154f2b95947561b07ad00b8420764916de Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Wed, 10 Nov 2021 09:55:49 -0600 Subject: [PATCH 58/66] Updated some Script Canvas node slot names to EntityID for consistency. Signed-off-by: Chris Galvan --- Assets/Editor/Translation/scriptcanvas_en_us.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts index 7b8361c879..6d436b7caf 100644 --- a/Assets/Editor/Translation/scriptcanvas_en_us.ts +++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts @@ -62164,7 +62164,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP @@ -62202,7 +62202,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityId HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP @@ -81852,7 +81852,7 @@ The element is removed from its current parent and added as a child of the new p HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP @@ -89198,7 +89198,7 @@ The element is removed from its current parent and added as a child of the new p HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP @@ -89236,7 +89236,7 @@ The element is removed from its current parent and added as a child of the new p HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME Simple Type: EntityID C++ Type: const EntityId& - Entity + EntityID HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP From f0b4eb17127534ca0919cb9eb372439e2739f5de Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 10 Nov 2021 10:54:53 -0600 Subject: [PATCH 59/66] update comment and error message Signed-off-by: Guthrie Adams --- .../RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp | 5 ++++- .../RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp index 37bd5a19f2..14ef3bb17d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/LuaMaterialFunctorSourceData.cpp @@ -137,7 +137,10 @@ namespace AZ } else if (!m_luaSourceFile.empty()) { - auto loadOutcome = RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId); + // The sub ID for script assets must be explicit. + // LUA source files output a compiled as well as an uncompiled asset, sub Ids of 1 and 2. + auto loadOutcome = + RPI::AssetUtils::LoadAsset(materialTypeSourceFilePath, m_luaSourceFile, ScriptAsset::CompiledAssetSubId); if (!loadOutcome) { AZ_Error("LuaMaterialFunctorSourceData", false, "Could not load script file '%s'", m_luaSourceFile.c_str()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index e5466a173f..d6308ec655 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -250,7 +250,7 @@ namespace AZ const auto parentTypeAssetId = AssetUtils::MakeAssetId(parentSourceAbsPath, parentSourceData.m_materialType, 0); if (!parentTypeAssetId) { - AZ_Error("MaterialSourceData", false, "Parent material asset ID isn't valid: '%s'.", parentSourceAbsPath.c_str()); + AZ_Error("MaterialSourceData", false, "Parent material asset ID wasn't found: '%s'.", parentSourceAbsPath.c_str()); return Failure(); } From 7159e3fe575378254983e09dabe44a9ef52e53c7 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Wed, 10 Nov 2021 17:22:55 +0000 Subject: [PATCH 60/66] Moving to stabilization Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp | 162 +++++++++--------- 1 file changed, 82 insertions(+), 80 deletions(-) diff --git a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp index 3778ba860f..9de441eecf 100644 --- a/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp +++ b/Gems/Terrain/Code/Tests/LayerSpawnerTests.cpp @@ -6,15 +6,13 @@ * */ +#include + #include #include #include -#include - #include -#include -#include #include #include @@ -23,21 +21,12 @@ using ::testing::NiceMock; using ::testing::AtLeast; using ::testing::_; -using ::testing::NiceMock; -using ::testing::AtLeast; -using ::testing::_; - class LayerSpawnerComponentTest : public ::testing::Test { protected: AZ::ComponentApplication m_app; - AZStd::unique_ptr m_entity; - Terrain::TerrainLayerSpawnerComponent* m_layerSpawnerComponent; - UnitTest::MockAxisAlignedBoxShapeComponent* m_shapeComponent; - AZStd::unique_ptr> m_terrainSystem; - void SetUp() override { AZ::ComponentApplication::Descriptor appDesc; @@ -50,78 +39,86 @@ protected: void TearDown() override { - m_entity.reset(); - m_terrainSystem.reset(); m_app.Destroy(); } - void CreateEntity() + AZStd::unique_ptr CreateEntity() { - m_entity = AZStd::make_unique(); - m_entity->Init(); + auto entity = AZStd::make_unique(); + entity->Init(); - ASSERT_TRUE(m_entity); - } - - void AddLayerSpawnerAndShapeComponentToEntity() - { - AddLayerSpawnerAndShapeComponentToEntity(Terrain::TerrainLayerSpawnerConfig()); + return entity; } - void AddLayerSpawnerAndShapeComponentToEntity(const Terrain::TerrainLayerSpawnerConfig& config) + Terrain::TerrainLayerSpawnerComponent* AddLayerSpawnerToEntity(AZ::Entity* entity, const Terrain::TerrainLayerSpawnerConfig& config) { - m_layerSpawnerComponent = m_entity->CreateComponent(config); - m_app.RegisterComponentDescriptor(m_layerSpawnerComponent->CreateDescriptor()); + auto layerSpawnerComponent = entity->CreateComponent(config); + m_app.RegisterComponentDescriptor(layerSpawnerComponent->CreateDescriptor()); - m_shapeComponent = m_entity->CreateComponent(); - m_app.RegisterComponentDescriptor(m_shapeComponent->CreateDescriptor()); - - ASSERT_TRUE(m_layerSpawnerComponent); - ASSERT_TRUE(m_shapeComponent); + return layerSpawnerComponent; } - void CreateMockTerrainSystem() + UnitTest::MockAxisAlignedBoxShapeComponent* AddShapeComponentToEntity(AZ::Entity* entity) { - m_terrainSystem = AZStd::make_unique>(); + UnitTest::MockAxisAlignedBoxShapeComponent* shapeComponent = entity->CreateComponent(); + m_app.RegisterComponentDescriptor(shapeComponent->CreateDescriptor()); + + return shapeComponent; } }; -TEST_F(LayerSpawnerComponentTest, ActivatEntityActivateSuccess) +TEST_F(LayerSpawnerComponentTest, ActivateEntityWithoutShapeFails) +{ + auto entity = CreateEntity(); + + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + + const AZ::Entity::DependencySortOutcome sortOutcome = entity->EvaluateDependenciesGetDetails(); + EXPECT_FALSE(sortOutcome.IsSuccess()); + + entity.reset(); +} + +TEST_F(LayerSpawnerComponentTest, ActivateEntityActivateSuccess) { - CreateEntity(); - AddLayerSpawnerAndShapeComponentToEntity(); + auto entity = CreateEntity(); + + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); - EXPECT_EQ(m_entity->GetState(), AZ::Entity::State::Active); - - m_entity->Deactivate(); + entity->Activate(); + EXPECT_EQ(entity->GetState(), AZ::Entity::State::Active); + + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerDefaultValuesCorrect) { - CreateEntity(); - AddLayerSpawnerAndShapeComponentToEntity(); + auto entity = CreateEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); AZ::u32 priority = 999, layer = 999; - Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); + Terrain::TerrainSpawnerRequestBus::Event(entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); EXPECT_EQ(0, priority); EXPECT_EQ(1, layer); bool useGroundPlane = false; - Terrain::TerrainSpawnerRequestBus::EventResult(useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + Terrain::TerrainSpawnerRequestBus::EventResult( + useGroundPlane, entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); EXPECT_TRUE(useGroundPlane); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) { - CreateEntity(); + auto entity = CreateEntity(); constexpr static AZ::u32 testPriority = 15; constexpr static AZ::u32 testLayer = 0; @@ -131,12 +128,13 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) config.m_priority = testPriority; config.m_useGroundPlane = false; - AddLayerSpawnerAndShapeComponentToEntity(config); + AddLayerSpawnerToEntity(entity.get(), config); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); AZ::u32 priority = 999, layer = 999; - Terrain::TerrainSpawnerRequestBus::Event(m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); + Terrain::TerrainSpawnerRequestBus::Event(entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetPriority, layer, priority); EXPECT_EQ(testPriority, priority); EXPECT_EQ(testLayer, layer); @@ -144,82 +142,86 @@ TEST_F(LayerSpawnerComponentTest, LayerSpawnerConfigValuesCorrect) bool useGroundPlane = true; Terrain::TerrainSpawnerRequestBus::EventResult( - useGroundPlane, m_entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); + useGroundPlane, entity->GetId(), &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane); EXPECT_FALSE(useGroundPlane); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerRegisterAreaUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The Activate call should register the area. - EXPECT_CALL(*m_terrainSystem, RegisterArea(_)).Times(1); + EXPECT_CALL(terrainSystem, RegisterArea(_)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerUnregisterAreaUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The Deactivate call should unregister the area. - EXPECT_CALL(*m_terrainSystem, UnregisterArea(_)).Times(1); + EXPECT_CALL(terrainSystem, UnregisterArea(_)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerTransformChangedUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The TransformChanged call should refresh the area. - EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1); + EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); // The component gets transform change notifications via the shape bus. LmbrCentral::ShapeComponentNotificationsBus::Event( - m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, + entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::TransformChanged); - m_entity->Deactivate(); + entity.reset(); } TEST_F(LayerSpawnerComponentTest, LayerSpawnerShapeChangedUpdatesTerrainSystem) { - CreateEntity(); + auto entity = CreateEntity(); - CreateMockTerrainSystem(); + NiceMock terrainSystem; // The ShapeChanged call should refresh the area. - EXPECT_CALL(*m_terrainSystem, RefreshArea(_, _)).Times(1); + EXPECT_CALL(terrainSystem, RefreshArea(_, _)).Times(1); - AddLayerSpawnerAndShapeComponentToEntity(); + AddLayerSpawnerToEntity(entity.get(), Terrain::TerrainLayerSpawnerConfig()); + AddShapeComponentToEntity(entity.get()); - m_entity->Activate(); + entity->Activate(); - LmbrCentral::ShapeComponentNotificationsBus::Event( - m_entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, + LmbrCentral::ShapeComponentNotificationsBus::Event( + entity->GetId(), &LmbrCentral::ShapeComponentNotificationsBus::Events::OnShapeChanged, LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged); - m_entity->Deactivate(); + entity.reset(); } From 0c546828d642b5a71e2762a8dbe419acbf3a3400 Mon Sep 17 00:00:00 2001 From: SJ Date: Wed, 10 Nov 2021 09:31:59 -0800 Subject: [PATCH 61/66] 1. Add nullptr checks to prevent crashes when non-critical shaders fail to compile. (#5451) 2. Add a higher "launch_ap_timeout" for Mac because launching a newly built/downloaded AP can take a while. Signed-off-by: amzn-sj --- .../PostProcessing/BlendColorGradingLutsPass.cpp | 6 +++++- .../ReflectionProbeFeatureProcessor.cpp | 7 ++++++- .../RPI.Public/Pass/FullscreenTrianglePass.cpp | 6 ++++++ Registry/Platform/Mac/bootstrap_overrides.setreg | 12 ++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 Registry/Platform/Mac/bootstrap_overrides.setreg diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp index f74837bd9a..ca93898d5e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp @@ -46,7 +46,11 @@ namespace AZ void BlendColorGradingLutsPass::InitializeShaderVariant() { - AZ_Assert(m_shader != nullptr, "BlendColorGradingLutsPass %s has a null shader when calling InitializeShaderVariant.", GetPathName().GetCStr()); + if (m_shader == nullptr) + { + AZ_Assert(false, "BlendColorGradingLutsPass %s has a null shader when calling InitializeShaderVariant.", GetPathName().GetCStr()); + return; + } // Total variations is MaxBlendLuts plus one for the fallback case that none of the LUTs are found, // and hence zero LUTs are blended resulting in an identity LUT. diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index b1484ac8a8..e9038858ad 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -443,7 +443,12 @@ namespace AZ { // load shader shader = RPI::LoadCriticalShader(filePath); - AZ_Error("ReflectionProbeFeatureProcessor", shader, "Failed to find asset for shader [%s]", filePath); + + if (shader == nullptr) + { + AZ_Error("ReflectionProbeFeatureProcessor", false, "Failed to find asset for shader [%s]", filePath); + return; + } // store drawlist tag drawListTag = shader->GetDrawListTag(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp index 40dce7d138..828966f377 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp @@ -136,6 +136,12 @@ namespace AZ RHI::DrawLinear draw = RHI::DrawLinear(); draw.m_vertexCount = 3; + if (m_shader == nullptr) + { + AZ_Error("PassSystem", false, "[FullscreenTrianglePass]: Shader not loaded!"); + return; + } + RHI::PipelineStateDescriptorForDraw pipelineStateDescriptor; // [GFX TODO][ATOM-872] The pass should be able to drive the shader variant diff --git a/Registry/Platform/Mac/bootstrap_overrides.setreg b/Registry/Platform/Mac/bootstrap_overrides.setreg new file mode 100644 index 0000000000..4e1ca76724 --- /dev/null +++ b/Registry/Platform/Mac/bootstrap_overrides.setreg @@ -0,0 +1,12 @@ +{ + "Amazon": { + "AzCore": { + "Bootstrap": { + // The first time an application is launched on MacOS, each + // dynamic library is inspected by the OS before being loaded. + // This can take a while on some Macs. + "launch_ap_timeout": 300 + } + } + } +} From 576248a870fb7aab37949822a54a9b3969a6a6b1 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Wed, 10 Nov 2021 10:26:44 -0800 Subject: [PATCH 62/66] Merge Jenkinsfile from development to stabilization (#5391) Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 45 ++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 34732a5fad..beb4a21620 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -16,7 +16,7 @@ EMPTY_JSON = readJSON text: '{}' ENGINE_REPOSITORY_NAME = 'o3de' // Branches with build snapshots -BUILD_SNAPSHOTS = ['development', 'stabilization/2106'] +BUILD_SNAPSHOTS = ['development', 'stabilization/2110'] // Build snapshots with empty snapshot (for use with 'SNAPSHOT' pipeline paramater) BUILD_SNAPSHOTS_WITH_EMPTY = BUILD_SNAPSHOTS + '' @@ -102,6 +102,10 @@ def IsJobEnabled(branchName, buildTypeMap, pipelineName, platformName) { } } +def IsAPLogUpload(branchName, jobName) { + return !IsPullRequest(branchName) && jobName.toLowerCase().contains('asset') && env.AP_LOGS_S3_BUCKET +} + def GetRunningPipelineName(JENKINS_JOB_NAME) { // If the job name has an underscore def job_parts = JENKINS_JOB_NAME.tokenize('/')[0].tokenize('_') @@ -267,7 +271,7 @@ def CheckoutRepo(boolean disableSubmodules = false) { palRm('commitdate') } -def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) { +def HandleDriveMount(String snapshot, String repositoryName, String projectName, String pipeline, String branchName, String platform, String buildType, String workspace, boolean recreateVolume = false) { unstash name: 'incremental_build_script' def pythonCmd = '' @@ -429,6 +433,27 @@ def ExportTestScreenshots(Map options, String branchName, String platformName, S } } +def UploadAPLogs(Map options, String branchName, String platformName, String jobName, String workspace, Map params) { + dir("${workspace}/${ENGINE_REPOSITORY_NAME}") { + projects = params.CMAKE_LY_PROJECTS.split(",") + projects.each{ project -> + def apLogsPath = "${project}/user/log" + def s3UploadScriptPath = "scripts/build/tools/upload_to_s3.py" + if(env.IS_UNIX) { + pythonPath = "${options.PYTHON_DIR}/python.sh" + } + else { + pythonPath = "${options.PYTHON_DIR}/python.cmd" + } + def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + + "--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${platformName}/${jobName} " + + '--extra_args {\\"ACL\\":\\"bucket-owner-full-control\\"}' + palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) + } + } + } + def PostBuildCommonSteps(String workspace, boolean mount = true) { echo 'Starting post-build common steps...' @@ -492,6 +517,14 @@ def CreateExportTestScreenshotsStage(Map pipelineConfig, String branchName, Stri } } +def CreateUploadAPLogsStage(Map pipelineConfig, String branchName, String platformName, String jobName, String workspace, Map params) { + return { + stage("${jobName}_upload_ap_logs") { + UploadAPLogs(pipelineConfig, branchName, platformName, jobName, workspace, params) + } + } +} + def CreateTeardownStage(Map environmentVars) { return { stage('Teardown') { @@ -516,9 +549,11 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar CreateSetupStage(pipelineConfig, snapshot, repositoryName, projectName, pipelineName, branchName, platform.key, build_job.key, envVars, onlyMountEBSVolume).call() if(build_job.value.steps) { //this is a pipe with many steps so create all the build stages + pipelineEnvVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName) build_job.value.steps.each { build_step -> build_job_name = build_step - envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName) + // This addition of maps makes it that the right operand will override entries if they overlap with the left operand + envVars = pipelineEnvVars + GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, platform.value.build_types[build_step].PIPELINE_ENV ?: EMPTY_JSON, pipelineName) try { CreateBuildStage(pipelineConfig, platform.key, build_step, envVars).call() } @@ -541,6 +576,9 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar error "Node disconnected during build: ${e}" // Error raised to retry stage on a new node } } + if (IsAPLogUpload(branchName, build_job_name)) { + CreateUploadAPLogsStage(pipelineConfig, branchName, platform.key, build_job_name, envVars['WORKSPACE'], platform.value.build_types[build_job_name].PARAMETERS).call() + } // All other errors will be raised outside the retry block currentResult = envVars['ON_FAILURE_MARK'] ?: 'FAILURE' currentException = e.toString() @@ -768,6 +806,7 @@ try { platform.value.build_types.each { build_job -> if (IsJobEnabled(branchName, build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline def envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName) + envVars['JENKINS_JOB_NAME'] = env.JOB_NAME // Save original Jenkins job name to JENKINS_JOB_NAME envVars['JOB_NAME'] = "${branchName}_${platform.key}_${build_job.key}" // backwards compatibility, some scripts rely on this someBuildHappened = true From f2e191ea77c64232fb1fabf8f02ac235c3704518 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Wed, 10 Nov 2021 10:28:32 -0800 Subject: [PATCH 63/66] Fix trying to remove a cache file Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 56f9ae4bcd..9872c0779b 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -128,7 +128,7 @@ def download_file(parsed_uri, download_path: pathlib.Path, force_overwrite, down logger.warn(f'File already downloaded to {download_path}.') else: try: - shutil.rmtree(download_path) + os.unlink(download_path) except OSError: logger.error(f'Could not remove existing download path {download_path}.') return 1 From e0cc86e8985b93e836a72772910ae304ef26cc3c Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:21:42 -0600 Subject: [PATCH 64/66] Remove AssetProcessorManagerTest AssertAbsorber and update test to use the one from the base class instead (#5216) (#5381) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> (cherry picked from commit b3301414ad1f76161fa88eaf8650f42bfb94617c) # Conflicts: # Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp --- .../AssetProcessorManagerTest.cpp | 32 +++++++++---------- .../assetmanager/AssetProcessorManagerTest.h | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index f8d758e092..1a6063cff0 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -243,7 +243,7 @@ void AssetProcessorManagerTest::SetUp() m_mockApplicationManager->BusConnect(); m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get())); - m_assertAbsorber.Clear(); + m_errorAbsorber->Clear(); m_isIdling = false; @@ -334,9 +334,9 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess) EXPECT_STRCASEEQ(relFileName.toUtf8().data(), response.m_jobList[0].m_sourceFile.c_str()); EXPECT_STRCASEEQ(tempPath.filePath("subfolder1").toUtf8().data(), response.m_jobList[0].m_watchFolder.c_str()); - ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0); } TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase) @@ -388,9 +388,9 @@ TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToD ASSERT_EQ(response.m_jobList[0].m_warningCount, 11); ASSERT_EQ(response.m_jobList[0].m_errorCount, 22); - ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0); } @@ -1312,8 +1312,8 @@ void PathDependencyTest::SetUp() void PathDependencyTest::TearDown() { - ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0); - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0); AssetProcessorManagerTest::TearDown(); } @@ -1617,7 +1617,7 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency mainFile.m_products.push_back(productAssetId); // tell the APM that the asset has been processed and allow it to bubble through its event queue: - m_assertAbsorber.Clear(); + m_errorAbsorber->Clear(); m_assetProcessorManager->AssetProcessed(jobDetails.m_jobEntry, processJobResponse); ASSERT_TRUE(BlockUntilIdle(5000)); @@ -1627,8 +1627,8 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency ASSERT_TRUE(dependencyContainer.empty()); // We are testing 2 different dependencies, so we should get 2 warnings - ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 2); - m_assertAbsorber.Clear(); + ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 2); + m_errorAbsorber->Clear(); } // This test shows the process of deferring resolution of a path dependency works. @@ -1945,8 +1945,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludePathsExisting_ResolveCorr ); // Test asset PrimaryFile1 has 4 conflict dependencies - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 4); - m_assertAbsorber.Clear(); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 4); + m_errorAbsorber->Clear(); } TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly) @@ -2093,8 +2093,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludedPathDeferred_ResolveCorr // Test asset PrimaryFile1 has 4 conflict dependencies // After test assets dep2 and dep3 are processed, // another 2 errors will be raised because of the confliction - ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 6); - m_assertAbsorber.Clear(); + ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 6); + m_errorAbsorber->Clear(); } void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h index 3443a4c519..2f0121485e 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h @@ -58,7 +58,6 @@ protected: AZStd::unique_ptr m_assetProcessorManager; AZStd::unique_ptr m_mockApplicationManager; AZStd::unique_ptr m_config; - UnitTestUtils::AssertAbsorber m_assertAbsorber; // absorb asserts/warnings/errors so that the unit test output is not cluttered QString m_gameName; QDir m_normalizedCacheRootDir; AZStd::atomic_bool m_isIdling; From cf58398c6c31e10bfea1c134328e585efcaab05b Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:05:32 -0800 Subject: [PATCH 65/66] [AWSMetrics] Fail to build the project when include AWSMetricsBus header in the project C++ code (#5468) --- .../Code/Include/{Private => Public}/MetricsAttribute.h | 0 Gems/AWSMetrics/Code/awsmetrics_files.cmake | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Gems/AWSMetrics/Code/Include/{Private => Public}/MetricsAttribute.h (100%) diff --git a/Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h b/Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h similarity index 100% rename from Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h rename to Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h diff --git a/Gems/AWSMetrics/Code/awsmetrics_files.cmake b/Gems/AWSMetrics/Code/awsmetrics_files.cmake index b51235c957..b1a3a647df 100644 --- a/Gems/AWSMetrics/Code/awsmetrics_files.cmake +++ b/Gems/AWSMetrics/Code/awsmetrics_files.cmake @@ -8,6 +8,7 @@ set(FILES Include/Public/AWSMetricsBus.h + Include/Public/MetricsAttribute.h Include/Private/AWSMetricsConstant.h Include/Private/AWSMetricsServiceApi.h Include/Private/AWSMetricsSystemComponent.h @@ -15,7 +16,6 @@ set(FILES Include/Private/DefaultClientIdProvider.h Include/Private/GlobalStatistics.h Include/Private/IdentityProvider.h - Include/Private/MetricsAttribute.h Include/Private/MetricsEvent.h Include/Private/MetricsEventBuilder.h Include/Private/MetricsManager.h From 21a254e9dca5262dcde7a1cebd41ef7dcf8df09c Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Wed, 10 Nov 2021 13:15:04 -0800 Subject: [PATCH 66/66] Fixed a type with pass filter (#5506) Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> --- .../Source/CoreLights/DirectionalLightFeatureProcessor.cpp | 2 +- Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h | 4 ++-- Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index b6c6910fd3..410c80dbdc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1056,7 +1056,7 @@ namespace AZ // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, // to filter out shadows from objects that are excluded from the cubemap RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); - passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene + passFilter.SetOwnerScene(GetParentScene()); // only handles passes for this scene RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { usageFlags |= RPI::View::UsageReflectiveCubeMap; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h index c42991725e..b93458113b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h @@ -56,8 +56,8 @@ namespace AZ OwnerRenderPipeline = AZ_BIT(5) }; - void SetOwenrScene(const Scene* scene); - void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline); + void SetOwnerScene(const Scene* scene); + void SetOwnerRenderPipeline(const RenderPipeline* renderPipeline); void SetPassName(Name passName); void SetTemplateName(Name passTemplateName); void SetPassClass(TypeId passClassTypeId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp index d9e458c615..d172abd81f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp @@ -90,13 +90,13 @@ namespace AZ return filter; } - void PassFilter::SetOwenrScene(const Scene* scene) + void PassFilter::SetOwnerScene(const Scene* scene) { m_ownerScene = scene; UpdateFilterOptions(); } - void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline) + void PassFilter::SetOwnerRenderPipeline(const RenderPipeline* renderPipeline) { m_ownerRenderPipeline = renderPipeline; UpdateFilterOptions();